From 36097cf468c8e44a912718933e72dd8197b95e9b Mon Sep 17 00:00:00 2001 From: "F. Jason Park" 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