]> git.eshelyaron.com Git - emacs.git/commitdiff
Document recommended way to use ERC over Tor
authorF. Jason Park <jp@neverwas.me>
Tue, 23 May 2023 04:43:29 +0000 (21:43 -0700)
committerF. Jason Park <jp@neverwas.me>
Tue, 30 May 2023 04:42:33 +0000 (21:42 -0700)
* 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
lisp/erc/erc.el

index 1f343fc85290d8aeeb8d6c1783da6b933d7656e7..14c6a457654faa055fd577be0a326c5b16e9106e 100644 (file)
@@ -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 @@ And unlike global toggles, none of these ever mutates
 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,57 @@ need a function as well:
 @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 that 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 'erc)
+(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
index 495e25212ce273efbae8d1c877fef536a450adb9..0be9eb69432c7b8e1cbe147b7fbb9fa67aec2207 100644 (file)
@@ -144,6 +144,8 @@ concerning buffers."
 (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 @@ PARAMETERS should be a sequence of keywords and values, per
     (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)