Subject: 30.0.50; ERC 5.6: Document how to connect over SOCKS
From: "J.P." <[email-masked]>
To: [email-masked]
Date: Tue, 23 May 2023 06:44:13 -0700
List-Id: <debbugs-submit.debbugs.gnu.org>

Tags: patch

For whatever reason, new and would-be users come around seeking guidance
on this particular topic with some regularity. The belated proposal
before you is intended to help stem this tide and hopefully reduce the
many man-hours spent fielding such questions on IRC.

In GNU Emacs 30.0.50 (build 1, x86_64-pc-linux-gnu, GTK+ Version
 3.24.37, cairo version 1.17.6) of 2023-05-23 built on localhost
Repository revision: d4ff1d74209e97730c52ddd50c4d643c79087a33
Repository branch: master
Windowing system distributor 'The X.Org Foundation', version 11.0.12014000
System Description: Fedora Linux 37 (Workstation Edition)

Configured using:
 'configure --enable-check-lisp-object-type --enable-checking=yes,glyphs
 'CFLAGS=-O0 -g3'
 PKG_CONFIG_PATH=:/usr/lib64/pkgconfig:/usr/share/pkgconfig'

Configured features:
ACL CAIRO DBUS FREETYPE GIF GLIB GMP GNUTLS GPM GSETTINGS HARFBUZZ JPEG
JSON LCMS2 LIBOTF LIBSELINUX LIBSYSTEMD LIBXML2 M17N_FLT MODULES NOTIFY
INOTIFY PDUMPER PNG RSVG SECCOMP SOUND SQLITE3 THREADS TIFF
TOOLKIT_SCROLL_BARS WEBP X11 XDBE XIM XINPUT2 XPM GTK3 ZLIB

Important settings:
  value of $LANG: en_US.UTF-8
  value of $XMODIFIERS: @im=ibus
  locale-coding-system: utf-8-unix

Major mode: Lisp Interaction

Minor modes in effect:
  tooltip-mode: t
  global-eldoc-mode: t
  eldoc-mode: t
  show-paren-mode: t
  electric-indent-mode: t
  mouse-wheel-mode: t
  tool-bar-mode: t
  menu-bar-mode: t
  file-name-shadow-mode: t
  global-font-lock-mode: t
  font-lock-mode: t
  blink-cursor-mode: t
  line-number-mode: t
  indent-tabs-mode: t
  transient-mark-mode: t
  auto-composition-mode: t
  auto-encryption-mode: t
  auto-compression-mode: t

Load-path shadows:
None found.

Features:
(shadow sort mail-extr emacsbug message mailcap yank-media puny dired
dired-loaddefs rfc822 mml mml-sec epa epg rfc6068 epg-config gnus-util
text-property-search time-date mm-decode mm-bodies mm-encode mail-parse
rfc2231 mailabbrev gmm-utils mailheader sendmail rfc2047 rfc2045
ietf-drums mm-util mail-prsvr mail-utils erc derived auth-source eieio
eieio-core password-cache json map format-spec erc-backend erc-networks
easy-mmode byte-opt bytecomp byte-compile erc-common inline erc-compat
cl-seq cl-macs gv pcase rx subr-x cl-loaddefs cl-lib erc-loaddefs rmc
iso-transl tooltip cconv eldoc paren electric uniquify ediff-hook
vc-hooks lisp-float-type elisp-mode mwheel term/x-win x-win
term/common-win x-dnd tool-bar dnd fontset image regexp-opt fringe
tabulated-list replace newcomment text-mode lisp-mode prog-mode register
page tab-bar menu-bar rfn-eshadow isearch easymenu timer select
scroll-bar mouse jit-lock font-lock syntax font-core term/tty-colors
frame minibuffer nadvice seq simple cl-generic indonesian philippine
cham georgian utf-8-lang misc-lang vietnamese tibetan thai tai-viet lao
korean japanese eucjp-ms cp51932 hebrew greek romanian slovak czech
european ethiopic indian cyrillic chinese composite emoji-zwj charscript
charprop case-table epa-hook jka-cmpr-hook help abbrev obarray oclosure
cl-preloaded button loaddefs theme-loaddefs faces cus-face macroexp
files window text-properties overlay sha1 md5 base64 format env
code-pages mule custom widget keymap hashtable-print-readable backquote
threads dbusbind inotify lcms2 dynamic-setting system-font-setting
font-render-setting cairo move-toolbar gtk x-toolkit xinput2 x multi-tty
make-network-process emacs)

Memory information:
((conses 16 117635 9315)
 (symbols 48 9931 0)
 (strings 32 24344 2099)
 (string-bytes 1 808855)
 (vectors 16 13426)
 (vector-slots 8 195576 8096)
 (floats 8 24 23)
 (intervals 56 228 0)
 (buffers 976 10))

From 36097cf468c8e44a912718933e72dd8197b95e9b Mon Sep 17 00:00:00 2001
From: "F. Jason Park" <[email-masked]>
Date: Mon, 22 May 2023 21:43:29 -0700
Subject: [PATCH] [5.6] Document recommended way to use ERC over Tor

* doc/misc/erc.texi: Add new SOCKS section to the chapter on
Integrations.  Also bump version in front matter.
* lisp/erc/erc.el (erc-open-socks-tls-stream): New convenience
function to connect over Tor via SOCKS proxy.
---
 doc/misc/erc.texi | 53 ++++++++++++++++++++++++++++++++++++++++++++++-
 lisp/erc/erc.el   | 18 ++++++++++++++++
 2 files changed, 70 insertions(+), 1 deletion(-)

diff --git a/doc/misc/erc.texi b/doc/misc/erc.texi
index 1f343fc8529..c4bf6831976 100644
--- a/doc/misc/erc.texi
+++ b/doc/misc/erc.texi
@@ -2,7 +2,7 @@
 @c %**start of header
 @setfilename ../../info/erc.info
 @settitle ERC Manual
-@set ERCVER 5.5
+@set ERCVER 5.6
 @set ERCDIST as distributed with Emacs @value{EMACSVER}
 @include docstyle.texi
 @syncodeindex fn cp
@@ -611,6 +611,7 @@ Advanced Usage
 Integrations
 
 * URL::                         Opening IRC URLs in ERC.
+* SOCKS::                       Connecting to IRC with a SOCKS proxy.
 * auth-source::                 Retrieving auth-source entries with ERC.
 
 @end detailmenu
@@ -1252,6 +1253,56 @@ Integrations
 @noindent
 Users on Emacs 28 and below may need to use @code{browse-url} instead.
 
+@anchor{SOCKS}
+@subsection SOCKS
+@cindex SOCKS
+
+People wanting to connect to IRC through a @acronym{SOCKS} proxy are
+most likely interested in doing so over @acronym{TOR} (The Onion
+Router).  If that's @emph{not} you, please adapt these instructions
+accordingly.  Otherwise, keep in mind that support for Tor is
+experimental and thus insufficient for safeguarding a user's identity
+and location, especially in the case of targeted individuals.
+
+ERC's preferred Tor setup works by accessing a local Tor service
+through the built-in @file{socks.el} library that ships with Emacs.
+Other means of accessing Tor, such as via @command{torsocks}, are not
+supported.  Before getting started, check to ensure your Tor service
+is up and running.  You can do that with the following command:
+
+@example
+curl --proxy socks5h://localhost:9050 https://check.torproject.org | \
+  grep 'Congratulations'
+@end example
+
+Networks and servers differ in how they expose Tor endpoints.  In all
+cases, you'll want to first set the option @code{socks-server} to
+something appropriate, like @code{("tor" "127.0.0.1" 9050 5)}.  For
+some networks, setting @code{erc-server-connect-function} to
+@code{socks-open-network-stream} might be enough.  Others, like
+@samp{Libera.Chat}, involve additional setup.  At the time of writing,
+connecting to @samp{Libera.Chat} requires both @acronym{TLS} and a
+non-@samp{PLAIN} @acronym{SASL} mechanism (@pxref{SASL}).  One way to
+achieve that is by using the @samp{EXTERNAL} mechanism, as shown in
+the following example:
+
+@lisp
+(require 'socks)
+
+(let* ((socks-password "")
+       (socks-server '("tor" "localhost" 9050 5))
+       (erc-modules (cons 'sasl erc-modules))
+       (erc-sasl-mechanism 'external)
+       (erc-server-connect-function #'erc-open-socks-tls-stream))
+  (erc-tls
+   :server "libera75jm6of4wxpxt4aynol3xjmbtxgfyjpu34ss4d7r7q2v5zrpyd.onion"
+   :port 6697
+   :nick "jrh"
+   :user "jrandomhacker"
+   :full-name "J. Random Hacker"
+   :client-certificate (list "/home/jrh/key.pem" "/home/jrh/cert.pem")))
+@end lisp
+
 @node auth-source
 @subsection auth-source
 @cindex auth-source
diff --git a/lisp/erc/erc.el b/lisp/erc/erc.el
index 495e25212ce..0be9eb69432 100644
--- a/lisp/erc/erc.el
+++ b/lisp/erc/erc.el
@@ -144,6 +144,8 @@ gtk-version-string
 (declare-function word-at-point "thingatpt" (&optional no-properties))
 (autoload 'word-at-point "thingatpt") ; for hl-nicks
 
+(declare-function gnutls-negotiate "gnutls" (&rest rest))
+(declare-function socks-open-network-stream "socks" (name buffer host service))
 (declare-function url-host "url-parse" (cl-x))
 (declare-function url-password "url-parse" (cl-x))
 (declare-function url-portspec "url-parse" (cl-x))
@@ -2598,6 +2600,22 @@ erc-open-tls-stream
     (setq args `(,name ,buffer ,host ,port ,@p))
     (apply #'open-network-stream args)))
 
+(defun erc-open-socks-tls-stream (name buffer host service &rest parameters)
+  "Connect to an IRC server via SOCKS proxy over TLS.
+Bind `erc-server-connect-function' to this function around calls
+to `erc-tls'.  See `erc-open-network-stream' for the meaning of
+NAME and BUFFER.  HOST should be a \".onion\" URL, SERVICE a TLS
+port number, and PARAMETERS a sequence of key/value pairs, per
+`open-network-stream'.  See Info node `(erc) SOCKS' for more
+info."
+  (require 'gnutls)
+  (require 'socks)
+  (let ((proc (socks-open-network-stream name buffer host service))
+        (cert-info (plist-get parameters :client-certificate)))
+    (gnutls-negotiate :process proc
+                      :hostname host
+                      :keylist (and cert-info (list cert-info)))))
+
 ;;; Displaying error messages
 
 (defun erc-error (&rest args)
-- 
2.40.0