Patchwork socks proxy: socks5 proxy support for http(s) protocol

login
register
mail settings
Submitter heisenbug
Date April 8, 2014, 8:25 a.m.
Message ID <5343B291.6090905@zoho.com>
Download mbox | patch
Permalink /patch/4274/
State Deferred
Headers show

Comments

heisenbug - April 8, 2014, 8:25 a.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.
Mads Kiilerich - April 8, 2014, 11:31 a.m.
On 04/08/2014 10:25 AM, 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

Hi

My personal opinion: This looks like a fine feature. I have no doubt 
that it solves a real problem.

I also think socks proxies are used less these days than they used to. I 
think most setups with socks proxies also have http proxies ... and http 
proxies might be a better option for proxying http.

I think this functionality would be valuable as a separate extension but 
do not think it is relevant to include it in core mercurial.

There is also some minor coding style issues and lack of tests ... but 
that is less relevant in this context.

/Mads
heisenbug - April 8, 2014, 3:51 p.m.
Hi Mads,


> Hi
> 
> My personal opinion: This looks like a fine feature. I have no doubt
> that it solves a real problem.
> 
> I also think socks proxies are used less these days than they used
> to. I think most setups with socks proxies also have http proxies ...
> and http proxies might be a better option for proxying http.
> 
> I think this functionality would be valuable as a separate extension
> but do not think it is relevant to include it in core mercurial.
> 
> There is also some minor coding style issues and lack of tests ...
> but that is less relevant in this context.
> 
> /Mads
> 

Thank you for your feedback. I have tried to convert this patch into an
extension which I've made available here:
https://bitbucket.org/bugheisen/socks_proxy/

Since I have no idea if this is the correct way to handle this, feedback
is more than welcome.

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