tor-resolve.py 4.1 KB

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