>From 52a7f3269992166074ebe277f6905c219885d7cf Mon Sep 17 00:00:00 2001 From: "F. Jason Park" Date: Thu, 10 Mar 2022 00:18:09 -0800 Subject: [PATCH 0/6] *** SUBJECT HERE *** *** BLURB HERE *** F. Jason Park (6): Simplify network-stream opener in socks.el ; * lisp/url/url-gw.el (url-open-stream): Honor socks gateway-method Fix string encoding bug in socks tests Add support for SOCKS 4a Support SOCKS resolve extension [POC] Demo SOCKS resolve with HTTPS lisp/net/socks.el | 157 +++++++++++++++++++++++++------- lisp/url/url-gw.el | 2 + test/lisp/net/socks-tests.el | 168 ++++++++++++++++++++++++++++++++--- 3 files changed, 285 insertions(+), 42 deletions(-) Interdiff: diff --git a/lisp/net/socks.el b/lisp/net/socks.el index 9285cbf805..9ce23b517e 100644 --- a/lisp/net/socks.el +++ b/lisp/net/socks.el @@ -319,7 +319,8 @@ socks-filter ((pred (= socks-address-type-name)) (if (< (length string) 5) 255 - (+ 1 (aref string 4))))))) + (+ 1 (aref string 4)))) + (0 0)))) (if (< (length string) desired-len) nil ; Need to spin some more (process-put proc 'socks-state socks-state-connected) @@ -469,7 +470,7 @@ socks-send-command (let ((no (or (process-get proc 'socks-reply) 1))) (if (eq version 5) (nth no socks-errors) - (nth (+ 90 no) socks--errors-4))))) + (nth (- no 90) socks--errors-4))))) proc)) @@ -692,19 +693,11 @@ socks--extract-resolve-response (declare-function puny-encode-domain "puny" (domain)) -(defun socks-tor-resolve (name &optional _family) - "Return list of one vector IPv4 address for domain NAME. -Or return nil on failure. See `network-lookup-address-info' for format -of return value. Server must support the Tor RESOLVE command." - (let* ((socks-password (or socks-password "")) - (host (if (string-match "\\`[[:ascii:]]+\\'" name) - name - (require 'puny) - (puny-encode-domain name))) - (port 80) ; unused for now - (route (socks-find-route host nil)) - proc - ip) +(defun socks--tor-resolve (host) + (let ((socks-password (or socks-password "")) + (route (socks-find-route host nil)) + proc + ip) (cl-assert route) ;; "Host unreachable" may be raised when the lookup fails (unwind-protect @@ -714,13 +707,30 @@ socks-tor-resolve socks-resolve-command socks-address-type-name host - port) - (cl-assert (eq (process-get proc 'socks-state) - socks-state-connected)) + 0) (setq ip (socks--extract-resolve-response proc))) (when proc (delete-process proc))) - (list (vconcat ip [0])))) + ip)) + +(defun socks-tor-resolve (name &optional _family) + "Return list of one IPv4 address for domain NAME. +See `network-lookup-address-info' for format of return value. Return +nil on failure. + +SOCKS server must support the Tor RESOLVE command. Note that using this +in place of `network-lookup-address-info' may not be enough to prevent a +DNS leak. For example, see `url-gateway-broken-resolution'." + (unless (string-match "\\`[[:ascii:]]+\\'" name) + (require 'puny) + (setq name (puny-encode-domain name))) + (condition-case err + (when-let ((ip (socks--tor-resolve name))) + (list (vconcat ip [0]))) + (error + (unless (member (cadr err) + '("SOCKS: Host unreachable" "SOCKS: Rejected or failed")) + (signal (car err) (cdr err)))))) (provide 'socks) diff --git a/test/lisp/net/socks-tests.el b/test/lisp/net/socks-tests.el index 402ccf979d..0c58fcc863 100644 --- a/test/lisp/net/socks-tests.el +++ b/test/lisp/net/socks-tests.el @@ -133,7 +133,8 @@ socks-tests-canned-server-patterns (defun socks-tests-canned-server-create () "Create and return a fake SOCKS server." (let* ((port (nth 2 socks-server)) - (name (format "socks-server:%d" port)) + (name (format "socks-server:%s" + (or (numberp port) (ert-test-name (ert-running-test))))) (pats socks-tests-canned-server-patterns) (filt (lambda (proc line) (pcase-let ((`(,pat . ,resp) (pop pats))) @@ -152,8 +153,10 @@ socks-tests-canned-server-create :family 'ipv4 :host 'local :coding 'binary - :service port))) + :service (or port t)))) (set-process-query-on-exit-flag serv nil) + (unless (numberp (nth 2 socks-server)) + (setf (nth 2 socks-server) (process-contact serv :service))) serv)) (defvar socks-tests--hello-world-http-request-pattern @@ -192,7 +195,7 @@ socks-tests-perform-hello-world-http-request (ert-deftest socks-tests-v4-basic () "Show correct preparation of SOCKS4 connect command (Bug#46342)." - (let ((socks-server '("server" "127.0.0.1" 10079 4)) + (let ((socks-server '("server" "127.0.0.1" t 4)) (url-user-agent "Test/4-basic") (socks-tests-canned-server-patterns `(([4 1 0 80 93 184 216 34 ?f ?o ?o 0] . [0 90 0 0 0 0 0 0]) @@ -209,7 +212,7 @@ socks-tests-v4-basic (ert-deftest socks-tests-v4a-basic () "Show correct preparation of SOCKS4a connect command." - (let ((socks-server '("server" "127.0.0.1" 10083 4a)) + (let ((socks-server '("server" "127.0.0.1" t 4a)) (url-user-agent "Test/4a-basic") (socks-tests-canned-server-patterns `(([4 1 0 80 0 0 0 1 ?f ?o ?o 0 ?e ?x ?a ?m ?p ?l ?e ?. ?c ?o ?m 0] @@ -227,7 +230,7 @@ socks-tests-v4a-basic (ert-deftest socks-tests-v5-auth-user-pass () "Verify correct handling of SOCKS5 user/pass authentication." (should (assq 2 socks-authentication-methods)) - (let ((socks-server '("server" "127.0.0.1" 10080 5)) + (let ((socks-server '("server" "127.0.0.1" t 5)) (socks-username "foo") (socks-password "bar") (url-user-agent "Test/auth-user-pass") @@ -261,7 +264,7 @@ socks-tests-v5-auth-user-pass (ert-deftest socks-tests-v5-auth-user-pass-blank () "Verify correct SOCKS5 user/pass authentication with empty pass." (should (assq 2 socks-authentication-methods)) - (let ((socks-server '("server" "127.0.0.1" 10081 5)) + (let ((socks-server '("server" "127.0.0.1" t 5)) (socks-username "foo") ; defaults to (user-login-name) (socks-password "") ; simulate user hitting enter when prompted (url-user-agent "Test/auth-user-pass-blank") @@ -280,7 +283,7 @@ socks-tests-v5-auth-user-pass-blank (ert-deftest socks-tests-v5-auth-none () "Verify correct handling of SOCKS5 when auth method 0 requested." - (let ((socks-server '("server" "127.0.0.1" 10082 5)) + (let ((socks-server '("server" "127.0.0.1" t 5)) (socks-authentication-methods (append socks-authentication-methods nil)) (url-user-agent "Test/auth-none") @@ -297,9 +300,9 @@ socks-tests-v5-auth-none (ert-deftest tor-resolve-4a () "Make request to TOR resolve service over SOCKS4a" - (let* ((socks-server '("server" "127.0.0.1" 19050 4a)) + (let* ((socks-server '("server" "127.0.0.1" t 4a)) (socks-tests-canned-server-patterns - '(([4 #xf0 0 80 0 0 0 1 ?f ?o ?o 0 ?e ?x ?a ?m ?p ?l ?e ?. ?c ?o ?m 0] + '(([4 #xf0 0 0 0 0 0 1 ?f ?o ?o 0 ?e ?x ?a ?m ?p ?l ?e ?. ?c ?o ?m 0] . [0 90 0 0 93 184 216 34]))) (inhibit-message noninteractive) (server (socks-tests-canned-server-create))) @@ -311,9 +314,40 @@ tor-resolve-4a (kill-buffer (process-buffer server)) (delete-process server))) +(ert-deftest tor-resolve-4a-fail () + (let* ((socks-server '("server" "127.0.0.1" t 4a)) + (socks-tests-canned-server-patterns + '(([4 #xf0 0 0 0 0 0 1 ?f ?o ?o 0 ?e ?x ?a ?m ?p ?l ?e ?. ?c ?o ?m 0] + . [0 91 0 0 0 0 0 0]))) + (inhibit-message noninteractive) + (server (socks-tests-canned-server-create))) + (ert-info ("Query TOR RESOLVE service over SOCKS4") + (cl-letf (((symbol-function 'user-full-name) + (lambda (&optional _) "foo"))) + (should-not (socks-tor-resolve "example.com")))) + (kill-buffer (process-buffer server)) + (delete-process server))) + +(ert-deftest tor-resolve-5-fail () + (let* ((socks-server '("server" "127.0.0.1" t 5)) + (socks-username "") + (socks-authentication-methods (copy-sequence + socks-authentication-methods)) + (inhibit-message noninteractive) + (socks-tests-canned-server-patterns + '(([5 2 0 2] . [5 2]) + ([1 0 0] . [1 0]) + ([5 #xf0 0 3 11 ?e ?x ?a ?m ?p ?l ?e ?. ?c ?o ?m 0 0] + . [5 4 0 0 0 0 0 0 0 0]))) + (server (socks-tests-canned-server-create))) + (ert-info ("Query TOR RESOLVE service over SOCKS5") + (should-not (socks-tor-resolve "example.com"))) + (kill-buffer (process-buffer server)) + (delete-process server))) + (ert-deftest tor-resolve-5 () "Make request to TOR resolve service over SOCKS5" - (let* ((socks-server '("server" "127.0.0.1" 19051 5)) + (let* ((socks-server '("server" "127.0.0.1" t 5)) (socks-username "foo") (socks-authentication-methods (append socks-authentication-methods nil)) @@ -321,7 +355,7 @@ tor-resolve-5 (socks-tests-canned-server-patterns '(([5 2 0 2] . [5 2]) ([1 3 ?f ?o ?o 0] . [1 0]) - ([5 #xf0 0 3 11 ?e ?x ?a ?m ?p ?l ?e ?. ?c ?o ?m 0 80] + ([5 #xf0 0 3 11 ?e ?x ?a ?m ?p ?l ?e ?. ?c ?o ?m 0 0] . [5 0 0 1 93 184 216 34 0 0]))) (server (socks-tests-canned-server-create))) (ert-info ("Query TOR RESOLVE service over SOCKS5") @@ -341,6 +375,15 @@ test-socks-service verify-flags verify-error verify-hostname-error &allow-other-keys)) +(ert-deftest test-socks-resolve-fail () + :tags '(:unstable) + (unless test-socks-service (ert-skip "SOCKS service missing")) + (let* ((socks-server `("tor" ,@test-socks-service 5)) ; also try 4a + (socks-username "") + (socks-password "")) + (ert-info ("Connect to HTTP endpoint over Tor SOCKS proxy") + (should-not (socks-tor-resolve "test-socks-resolve-fail--fake.com"))))) + (ert-deftest test-socks-https-poc () :tags '(:unstable) (unless test-socks-service (ert-skip "SOCKS service missing")) -- 2.35.1