Ticket #3886 (closed enhancement: fixed)
Fixing the Socks4 proxy to be Socksv4a compliant
Description
Socks4a is a common extension to Socks4 where domain names are appended to the end so DNS queries are resolved at the host.
It looked like the previous author attempted to implement it, but did not complete it as evidenced by the commenting out of "server=gethostbyname(server)". I uncommented it and implemented several additional fixes. (Note that you will eventually like to switch this to an asynchronous DNS query, but that would take a large overhaul, and this fix seems to be ok for now.)
The main bug I found after enabling DNS resolution, is that Firefox doesn't always send the handshake in a single packet.
Good: '\x04\x01\x00P\x00\x00\x00\x01MOZ\x00en.wikipedia.org\x00' Bad: '\x04\x01\x00P\x00\x00\x00\x01MOZ\x00'
'en.wikipedia.org\x00'
The previous version of the socks proxy will choke on the "Bad" input. This is solved by returning if the IP address is invalid and there is no domain name at the end.
--- C:\temp\socks.py-revBASE.svn003.tmp.py Fri Jun 19 01:48:00 2009
+++ C:\Twisted\twisted\protocols\socks.py Fri Jun 19 01:47:56 2009
@@ -69,16 +69,22 @@
self.otherConn.write(data)
return
self.buf=self.buf+data
+ complete_buffer = self.buf
if '\000' in self.buf[8:]:
head,self.buf=self.buf[:8],self.buf[8:]
try:
version,code,port=struct.unpack("!BBH",head[:4])
except struct.error:
raise RuntimeError, "struct error with head='%s' and buf='%s'"%(repr(head),repr(self.buf))
- user,self.buf=string.split(self.buf,"\000",1)
+ user,self.buf=self.buf.split("\000",1)
if head[4:7]=="\000\000\000": # domain is after
- server,self.buf=string.split(self.buf,'\000',1)
- #server=gethostbyname(server)
+ # if the IP is invalid, and the Domain name is not present, we restore the buffer and wait for it
+ if self.buf == "":
+ self.buf = complete_buffer
+ return
+ server,self.buf=self.buf.split("\000",1)
+ server = socket.gethostbyname(server) # we need to resolve the host name since the IP is invalid
+ # you probably will want to use asynchronous DNS, but its a big change.
else:
server=socket.inet_ntoa(head[4:8])
assert version==4, "Bad version code: %s"%version

