tor-resolve.py (4516B)
1 #!/usr/bin/env python 2 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 7 8 import socket 9 import struct 10 import sys 11 12 def socks4AResolveRequest(hostname): 13 version = 4 14 command = 0xF0 15 port = 0 16 addr = 0x0000001 17 username = "" 18 reqheader = struct.pack("!BBHL", version, command, port, addr) 19 return "%s%s\x00%s\x00"%(reqheader,username,hostname) 20 21 def socks4AParseResponse(response): 22 RESPONSE_LEN = 8 23 if len(response) < RESPONSE_LEN: 24 return None 25 assert len(response) >= RESPONSE_LEN 26 version,status,port = struct.unpack("!BBH",response[:4]) 27 assert version == 0 28 assert port == 0 29 if status == 90: 30 return "%d.%d.%d.%d"%tuple(map(ord, response[4:])) 31 else: 32 return "ERROR (status %d)"%status 33 34 def socks5Hello(): 35 return "\x05\x01\x00" 36 def socks5ParseHello(response): 37 if response != "\x05\x00": 38 raise ValueError("Bizarre socks5 response") 39 def socks5ResolveRequest(hostname, atype=0x03, command=0xF0): 40 version = 5 41 rsv = 0 42 port = 0 43 reqheader = struct.pack("!BBBB",version, command, rsv, atype) 44 if atype == 0x03: 45 reqheader += struct.pack("!B", len(hostname)) 46 portstr = struct.pack("!H",port) 47 return "%s%s%s"%(reqheader,hostname,portstr) 48 49 def socks5ParseResponse(r): 50 if len(r)<8: 51 return None 52 version, reply, rsv, atype = struct.unpack("!BBBB",r[:4]) 53 assert version==5 54 assert rsv==0 55 if reply != 0x00: 56 return "ERROR",reply 57 assert atype in (0x01,0x03,0x04) 58 if atype != 0x03: 59 expected_len = 4 + ({1:4,4:16}[atype]) + 2 60 if len(r) < expected_len: 61 return None 62 elif len(r) > expected_len: 63 raise ValueError("Overlong socks5 reply!") 64 addr = r[4:-2] 65 if atype == 0x01: 66 return "%d.%d.%d.%d"%tuple(map(ord,addr)) 67 else: 68 # not really the right way to format IPv6 69 return "IPv6: %s"%(":".join([hex(ord(c)) for c in addr])) 70 else: 71 hlen, = struct.unpack("!B", r[4]) 72 expected_len = 5 + hlen + 2 73 if len(r) < expected_len: 74 return None 75 return r[5:-2] 76 77 def socks5ResolvePTRRequest(hostname): 78 return socks5ResolveRequest(socket.inet_aton(hostname), 79 atype=1, command = 0xF1) 80 81 82 def parseHostAndPort(h): 83 host, port = "localhost", 9050 84 if ":" in h: 85 i = h.index(":") 86 host = h[:i] 87 try: 88 port = int(h[i+1:]) 89 except ValueError: 90 print("Bad hostname %r"%h) 91 sys.exit(1) 92 elif h: 93 try: 94 port = int(h) 95 except ValueError: 96 host = h 97 98 return host, port 99 100 def resolve(hostname, sockshost, socksport, socksver=4, reverse=0): 101 assert socksver in (4,5) 102 if socksver == 4: 103 fmt = socks4AResolveRequest 104 parse = socks4AParseResponse 105 elif not reverse: 106 fmt = socks5ResolveRequest 107 parse = socks5ParseResponse 108 else: 109 fmt = socks5ResolvePTRRequest 110 parse = socks5ParseResponse 111 112 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 113 s.connect((sockshost,socksport)) 114 if socksver == 5: 115 s.send(socks5Hello()) 116 socks5ParseHello(s.recv(2)) 117 s.send(fmt(hostname)) 118 answer = s.recv(6) 119 result = parse(answer) 120 while result is None: 121 more = s.recv(1) 122 if not more: 123 return None 124 answer += more 125 result = parse(answer) 126 print("Got answer",result) 127 m = s.recv(1) 128 if m: 129 print("Got extra data too: %r"%m) 130 return result 131 132 if __name__ == '__main__': 133 if len(sys.argv) not in (2,3,4): 134 print("Syntax: resolve.py [-4|-5] hostname [sockshost:socksport]") 135 sys.exit(0) 136 socksver = 4 137 reverse = 0 138 while sys.argv[1][0] == '-': 139 if sys.argv[1] in ("-4", "-5"): 140 socksver = int(sys.argv[1][1]) 141 del sys.argv[1] 142 elif sys.argv[1] == '-x': 143 reverse = 1 144 del sys.argv[1] 145 elif sys.argv[1] == '--': 146 break 147 148 if len(sys.argv) >= 4: 149 print("Syntax: resolve.py [-x] [-4|-5] hostname [sockshost:socksport]") 150 sys.exit(0) 151 if len(sys.argv) == 3: 152 sh,sp = parseHostAndPort(sys.argv[2]) 153 else: 154 sh,sp = parseHostAndPort("") 155 156 if reverse and socksver == 4: 157 socksver = 5 158 resolve(sys.argv[1], sh, sp, socksver, reverse)