tor-resolve.py 4.2 KB

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