3 # Future imports for Python 2.7, mandatory in 3.0
4 from __future__
import division
5 from __future__
import print_function
6 from __future__
import unicode_literals
12 def socks4AResolveRequest(hostname
):
18 reqheader
= struct
.pack("!BBHL", version
, command
, port
, addr
)
19 return "%s%s\x00%s\x00"%(reqheader
,username
,hostname
)
21 def socks4AParseResponse(response
):
23 if len(response
) < RESPONSE_LEN
:
25 assert len(response
) >= RESPONSE_LEN
26 version
,status
,port
= struct
.unpack("!BBH",response
[:4])
30 return "%d.%d.%d.%d"%tuple(map(ord, response
[4:]))
32 return "ERROR (status %d)"%status
36 def socks5ParseHello(response
):
37 if response
!= "\x05\x00":
38 raise ValueError("Bizarre socks5 response")
39 def socks5ResolveRequest(hostname
, atype
=0x03, command
=0xF0):
43 reqheader
= struct
.pack("!BBBB",version
, command
, rsv
, atype
)
45 reqheader
+= struct
.pack("!B", len(hostname
))
46 portstr
= struct
.pack("!H",port
)
47 return "%s%s%s"%(reqheader
,hostname
,portstr
)
49 def socks5ParseResponse(r
):
52 version
, reply
, rsv
, atype
= struct
.unpack("!BBBB",r
[:4])
57 assert atype
in (0x01,0x03,0x04)
59 expected_len
= 4 + ({1:4,4:16}[atype
]) + 2
60 if len(r
) < expected_len
:
62 elif len(r
) > expected_len
:
63 raise ValueError("Overlong socks5 reply!")
66 return "%d.%d.%d.%d"%tuple(map(ord,addr
))
68 # not really the right way to format IPv6
69 return "IPv6: %s"%(":".join([hex(ord(c
)) for c
in addr
]))
71 hlen
, = struct
.unpack("!B", r
[4])
72 expected_len
= 5 + hlen
+ 2
73 if len(r
) < expected_len
:
77 def socks5ResolvePTRRequest(hostname
):
78 return socks5ResolveRequest(socket
.inet_aton(hostname
),
79 atype
=1, command
= 0xF1)
82 def parseHostAndPort(h
):
83 host
, port
= "localhost", 9050
90 print("Bad hostname %r"%h
)
100 def resolve(hostname
, sockshost
, socksport
, socksver
=4, reverse
=0):
101 assert socksver
in (4,5)
103 fmt
= socks4AResolveRequest
104 parse
= socks4AParseResponse
106 fmt
= socks5ResolveRequest
107 parse
= socks5ParseResponse
109 fmt
= socks5ResolvePTRRequest
110 parse
= socks5ParseResponse
112 s
= socket
.socket(socket
.AF_INET
, socket
.SOCK_STREAM
)
113 s
.connect((sockshost
,socksport
))
115 s
.send(socks5Hello())
116 socks5ParseHello(s
.recv(2))
117 s
.send(fmt(hostname
))
119 result
= parse(answer
)
120 while result
is None:
125 result
= parse(answer
)
126 print("Got answer",result
)
129 print("Got extra data too: %r"%m
)
132 if __name__
== '__main__':
133 if len(sys
.argv
) not in (2,3,4):
134 print("Syntax: resolve.py [-4|-5] hostname [sockshost:socksport]")
138 while sys
.argv
[1][0] == '-':
139 if sys
.argv
[1] in ("-4", "-5"):
140 socksver
= int(sys
.argv
[1][1])
142 elif sys
.argv
[1] == '-x':
145 elif sys
.argv
[1] == '--':
148 if len(sys
.argv
) >= 4:
149 print("Syntax: resolve.py [-x] [-4|-5] hostname [sockshost:socksport]")
151 if len(sys
.argv
) == 3:
152 sh
,sp
= parseHostAndPort(sys
.argv
[2])
154 sh
,sp
= parseHostAndPort("")
156 if reverse
and socksver
== 4:
158 resolve(sys
.argv
[1], sh
, sp
, socksver
, reverse
)