Patchwork SOCKS5 proxy support

login
register
mail settings
Submitter heisenbug
Date April 6, 2014, 2:47 p.m.
Message ID <53416910.6090109@zoho.com>
Download mbox | patch
Permalink /patch/4267/
State Deferred
Headers show

Comments

heisenbug - April 6, 2014, 2:47 p.m.
# HG changeset patch
# User Bug Heisen <heisenbug@zoho.com>
# Date 1396793762 -7200
#      Sun Apr 06 16:16:02 2014 +0200
# Node ID 3f58227755ed42a2c891fa5bc75c286c3d35791c
# Parent  12f161f08d744f0e4b6eef9c905670afb5c24dd4
socks proxy: socks5 proxy support for http(s) protocol

This patch adds support for a SOCKS5 proxy, using the 'socks'
module from the SocksiPy projects (needs to be installed separately).
Because it is the 'proxyhandler' function that is modified, it will
only work for HTTP/HTTPS protocols. For the SSH protocol, using a SOCKS
proxy can easily be done outside of Mercurial, by specifying the
'ProxyCommand' option.

The patch has the SOCKS5 version hardcoded in it, but the 'socks'
module should support other versions as well. So other SOCKS versions
are possible in the same way, but the code would require modification
to support them.

For testing purposes, it's good to know that SSH can create a SOCKS5
proxy using the `-D` command line flag. Using Tor also generates such
a proxy, typically either on port 9050 or 9150.
Augie Fackler - April 12, 2014, 3:55 p.m.
On Sun, Apr 06, 2014 at 02:47:44PM +0000, heisenbug wrote:
> # HG changeset patch
> # User Bug Heisen <heisenbug@zoho.com>
> # Date 1396793762 -7200
> #      Sun Apr 06 16:16:02 2014 +0200
> # Node ID 3f58227755ed42a2c891fa5bc75c286c3d35791c
> # Parent  12f161f08d744f0e4b6eef9c905670afb5c24dd4
> socks proxy: socks5 proxy support for http(s) protocol

I'm worried that this is a relatively large amount of complexity for a
comparitively small win in terms of potential users, especially for
functionality without tests.

Is it possible this could be done as an out-of-tree extension?

>
> This patch adds support for a SOCKS5 proxy, using the 'socks'
> module from the SocksiPy projects (needs to be installed separately).
> Because it is the 'proxyhandler' function that is modified, it will
> only work for HTTP/HTTPS protocols. For the SSH protocol, using a SOCKS
> proxy can easily be done outside of Mercurial, by specifying the
> 'ProxyCommand' option.
>
> The patch has the SOCKS5 version hardcoded in it, but the 'socks'
> module should support other versions as well. So other SOCKS versions
> are possible in the same way, but the code would require modification
> to support them.
>
> For testing purposes, it's good to know that SSH can create a SOCKS5
> proxy using the `-D` command line flag. Using Tor also generates such
> a proxy, typically either on port 9050 or 9150.
>
> diff -r 12f161f08d74 -r 3f58227755ed mercurial/url.py
> --- a/mercurial/url.py	Tue Apr 01 23:41:32 2014 -0700
> +++ b/mercurial/url.py	Sun Apr 06 16:16:02 2014 +0200
> @@ -63,6 +63,44 @@
>
>  class proxyhandler(urllib2.ProxyHandler):
>      def __init__(self, ui):
> +
> +        # First, check if a SOCKS5 proxy is set, using a line 'host = ...' in
> +        # the [socks_proxy] section of the config file.
> +
> +        proxyurl = ui.config("socks_proxy", "host")
> +
> +        if proxyurl:
> +            idx = proxyurl.find(":")
> +            if idx < 0:
> +                raise util.Abort(_("host in socks_proxy should be "
> +                                   "hostname:port"))
> +
> +            host = proxyurl[:idx]
> +            portstr = proxyurl[idx+1:]
> +            try:
> +                port = int(portstr)
> +            except ValueError:
> +                raise util.Abort(_("Cannot interpret '%s' in the socks_proxy "
> +                                   "host line as an integer port number")
> +                                   % portstr)
> +
> +            if port <= 0 or port > 65535:
> +                raise util.Abort(_("Port number in socks_proxy host line "
> +                                   "must lie between 1 and 65535, but is "
> +                                   "%d") % port)
> +
> +            ui.note("Setting SOCKS5 proxy to %s:%d\n" % (host, port))
> +
> +            try:
> +                import socks
> +                socks.setdefaultproxy(socks.PROXY_TYPE_SOCKS5, host, port)
> +                socket.socket = socks.socksocket
> +            except ImportError:
> +                raise util.Abort(_("The SocksiPy socks module is needed for "
> +                                   "SOCKS support"))
> +
> +        # Then check for a http/https proxy
> +
>          proxyurl = ui.config("http_proxy", "host") or os.getenv('http_proxy')
>          # XXX proxyauthinfo = None
>
>
> _______________________________________________
> Mercurial-devel mailing list
> Mercurial-devel@selenic.com
> http://selenic.com/mailman/listinfo/mercurial-devel
heisenbug - April 13, 2014, 8:47 a.m.
On 04/12/2014 03:55 PM, Augie Fackler wrote:
> On Sun, Apr 06, 2014 at 02:47:44PM +0000, heisenbug wrote:
>> # HG changeset patch
>> # User Bug Heisen <heisenbug@zoho.com>
>> # Date 1396793762 -7200
>> #      Sun Apr 06 16:16:02 2014 +0200
>> # Node ID 3f58227755ed42a2c891fa5bc75c286c3d35791c
>> # Parent  12f161f08d744f0e4b6eef9c905670afb5c24dd4
>> socks proxy: socks5 proxy support for http(s) protocol
> 
> I'm worried that this is a relatively large amount of complexity for a
> comparitively small win in terms of potential users, especially for
> functionality without tests.
> 
> Is it possible this could be done as an out-of-tree extension?
> 

Yes, I think was able to do this: 
https://bitbucket.org/bugheisen/socks_proxy/

I'm not entirely sure if this is the way to go though, so feedback
is appreciated.

Cheers,
bug

Patch

diff -r 12f161f08d74 -r 3f58227755ed mercurial/url.py
--- a/mercurial/url.py	Tue Apr 01 23:41:32 2014 -0700
+++ b/mercurial/url.py	Sun Apr 06 16:16:02 2014 +0200
@@ -63,6 +63,44 @@ 
 
 class proxyhandler(urllib2.ProxyHandler):
     def __init__(self, ui):
+
+        # First, check if a SOCKS5 proxy is set, using a line 'host = ...' in 
+        # the [socks_proxy] section of the config file.
+
+        proxyurl = ui.config("socks_proxy", "host")
+
+        if proxyurl:
+            idx = proxyurl.find(":")
+            if idx < 0:
+                raise util.Abort(_("host in socks_proxy should be "
+                                   "hostname:port"))
+
+            host = proxyurl[:idx]
+            portstr = proxyurl[idx+1:]
+            try:
+                port = int(portstr)
+            except ValueError:
+                raise util.Abort(_("Cannot interpret '%s' in the socks_proxy "
+                                   "host line as an integer port number") 
+                                   % portstr)
+
+            if port <= 0 or port > 65535:
+                raise util.Abort(_("Port number in socks_proxy host line "
+                                   "must lie between 1 and 65535, but is "
+                                   "%d") % port)
+
+            ui.note("Setting SOCKS5 proxy to %s:%d\n" % (host, port))
+                    
+            try:
+                import socks
+                socks.setdefaultproxy(socks.PROXY_TYPE_SOCKS5, host, port)
+                socket.socket = socks.socksocket
+            except ImportError:
+                raise util.Abort(_("The SocksiPy socks module is needed for "
+                                   "SOCKS support"))
+
+        # Then check for a http/https proxy
+        
         proxyurl = ui.config("http_proxy", "host") or os.getenv('http_proxy')
         # XXX proxyauthinfo = None