Anorov/PySocks

Crashes when connecting to IPv6 services

Closed this issue · 2 comments

pde commented

Trying one of the use cases described in the docs (in this case socksifying through tor)

In [1]: import socks
In [2]: import socket
In [3]: import urllib2
In [4]: socks.set_default_proxy(socks.SOCKS5, "localhost", 9050)
In [5]: socket.socket = socks.socksocket
In [6]: urllib2.urlopen("https://google.com")

Produces the following error:

---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-6-728442f30dba> in <module>()
----> 1 urllib2.urlopen("https://google.com")

/usr/lib/python2.7/urllib2.pyc in urlopen(url, data, timeout, cafile, capath, cadefault, context)
    152     else:
    153         opener = _opener
--> 154     return opener.open(url, data, timeout)
    155 
    156 def install_opener(opener):

/usr/lib/python2.7/urllib2.pyc in open(self, fullurl, data, timeout)
    429             req = meth(req)
    430 
--> 431         response = self._open(req, data)
    432 
    433         # post-process response

/usr/lib/python2.7/urllib2.pyc in _open(self, req, data)
    447         protocol = req.get_type()
    448         result = self._call_chain(self.handle_open, protocol, protocol +
--> 449                                   '_open', req)
    450         if result:
    451             return result

/usr/lib/python2.7/urllib2.pyc in _call_chain(self, chain, kind, meth_name, *args)
    407             func = getattr(handler, meth_name)
    408 
--> 409             result = func(*args)
    410             if result is not None:
    411                 return result

/usr/lib/python2.7/urllib2.pyc in https_open(self, req)
   1238         def https_open(self, req):
   1239             return self.do_open(httplib.HTTPSConnection, req,
-> 1240                 context=self._context)
   1241 
   1242         https_request = AbstractHTTPHandler.do_request_

/usr/lib/python2.7/urllib2.pyc in do_open(self, http_class, req, **http_conn_args)
   1192 
   1193         try:
-> 1194             h.request(req.get_method(), req.get_selector(), req.data, headers)
   1195         except socket.error, err: # XXX what error?
   1196             h.close()

/usr/lib/python2.7/httplib.pyc in request(self, method, url, body, headers)
    999     def request(self, method, url, body=None, headers={}):
   1000         """Send a complete request to the server."""
-> 1001         self._send_request(method, url, body, headers)
   1002 
   1003     def _set_content_length(self, body):

/usr/lib/python2.7/httplib.pyc in _send_request(self, method, url, body, headers)
   1033         for hdr, value in headers.iteritems():
   1034             self.putheader(hdr, value)
-> 1035         self.endheaders(body)
   1036 
   1037     def getresponse(self, buffering=False):

/usr/lib/python2.7/httplib.pyc in endheaders(self, message_body)
    995         else:
    996             raise CannotSendHeader()
--> 997         self._send_output(message_body)
    998 
    999     def request(self, method, url, body=None, headers={}):

/usr/lib/python2.7/httplib.pyc in _send_output(self, message_body)
    848             msg += message_body
    849             message_body = None
--> 850         self.send(msg)
    851         if message_body is not None:
    852             #message_body was not a string (i.e. it is a file) and

/usr/lib/python2.7/httplib.pyc in send(self, data)
    810         if self.sock is None:
    811             if self.auto_open:
--> 812                 self.connect()
    813             else:
    814                 raise NotConnected()

/usr/lib/python2.7/httplib.pyc in connect(self)
   1202             "Connect to a host on a given (SSL) port."
   1203 
-> 1204             HTTPConnection.connect(self)
   1205 
   1206             if self._tunnel_host:

/usr/lib/python2.7/httplib.pyc in connect(self)
    791         """Connect to the host and port specified in __init__."""
    792         self.sock = self._create_connection((self.host,self.port),
--> 793                                            self.timeout, self.source_address)
    794 
    795         if self._tunnel_host:

/usr/lib/python2.7/socket.pyc in create_connection(address, timeout, source_address)
    561                 sock.bind(source_address)
    562             print "SA is", sa
--> 563             sock.connect(sa)
    564             return sock
    565 

/usr/local/lib/python2.7/dist-packages/socks.pyc in connect(self, dest_pair)
    626         dest_pair - 2-tuple of (IP/hostname, port).
    627         """
--> 628         dest_addr, dest_port = dest_pair
    629 
    630         if self.type == socket.SOCK_DGRAM:

ValueError: too many values to unpack

It seems that socks's connect() method is being called with a 4-tuple, ('2607:f8b0:4005:802::1000', 443, 0, 0) in this case.

pde commented

That's expected; the sa argument that's passed in is a sockaddr from getaddrinfo, which is different in IPv4 and IPv6. The call site is here.

lvh commented

Maybe this should synchronously raise a socket.error so that socket.create_connection will succeed the second time it tries to connect (using IPv4).