| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154 | #!/usr/bin/python#$Id$import socketimport structimport sysdef socks4AResolveRequest(hostname):    version = 4    command = 0xF0    port = 0    addr = 0x0000001    username = ""    reqheader = struct.pack("!BBHL", version, command, port, addr)    return "%s%s\x00%s\x00"%(reqheader,username,hostname)def socks4AParseResponse(response):    RESPONSE_LEN = 8    if len(response) < RESPONSE_LEN:        return None    assert len(response) >= RESPONSE_LEN    version,status,port = struct.unpack("!BBH",response[:4])    assert version == 0    assert port == 0    if status == 90:        return "%d.%d.%d.%d"%tuple(map(ord, response[4:]))    else:        return "ERROR (status %d)"%statusdef socks5Hello():    return "\x05\x01\x00"def socks5ParseHello(response):    if response != "\x05\x00":        raise ValueError("Bizarre socks5 response")def socks5ResolveRequest(hostname, atype=0x03, command=0xF0):    version = 5    rsv = 0    port = 0    reqheader = struct.pack("!BBBB",version, command, rsv, atype)    if atype == 0x03:        reqheader += struct.pack("!B", len(hostname))    portstr = struct.pack("!H",port)    return "%s%s%s"%(reqheader,hostname,portstr)def socks5ParseResponse(r):    if len(r)<8:        return None    version, reply, rsv, atype = struct.unpack("!BBBB",r[:4])    assert version==5    assert rsv==0    if reply != 0x00:        return "ERROR",reply    assert atype in (0x01,0x03,0x04)    if atype != 0x03:        expected_len = 4 + ({1:4,4:16}[atype]) + 2        if len(r) < expected_len:            return None        elif len(r) > expected_len:            raise ValueError("Overlong socks5 reply!")        addr = r[4:-2]        if atype == 0x01:            return "%d.%d.%d.%d"%tuple(map(ord,addr))        else:            # not really the right way to format IPv6            return "IPv6: %s"%(":".join([hex(ord(c)) for c in addr]))    else:        hlen, = struct.unpack("!B", r[4])        expected_len = 5 + hlen + 2        if len(r) < expected_len:            return None        return r[5:-2]def socks5ResolvePTRRequest(hostname):    return socks5ResolveRequest(socket.inet_aton(hostname),                                atype=1, command = 0xF1)def parseHostAndPort(h):    host, port = "localhost", 9050    if ":" in h:        i = h.index(":")        host = h[:i]        try:            port = int(h[i+1:])        except ValueError:            print "Bad hostname %r"%h            sys.exit(1)    elif h:        try:            port = int(h)        except ValueError:            host = h    return host, portdef resolve(hostname, sockshost, socksport, socksver=4, reverse=0):    assert socksver in (4,5)    if socksver == 4:        fmt = socks4AResolveRequest        parse = socks4AParseResponse    elif not reverse:        fmt = socks5ResolveRequest        parse = socks5ParseResponse    else:        fmt = socks5ResolvePTRRequest        parse = socks5ParseResponse    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)    s.connect((sockshost,socksport))    if socksver == 5:        s.send(socks5Hello())        socks5ParseHello(s.recv(2))    s.send(fmt(hostname))    answer = s.recv(6)    result = parse(answer)    while result is None:        more = s.recv(1)        if not more:            return None        answer += more        result = parse(answer)    print "Got answer",result    m = s.recv(1)    if m:        print "Got extra data too: %r"%m    return resultif __name__ == '__main__':    if len(sys.argv) not in (2,3,4):        print "Syntax: resolve.py [-4|-5] hostname [sockshost:socksport]"        sys.exit(0)    socksver = 4    reverse = 0    while sys.argv[1][0] == '-':        if sys.argv[1] in ("-4", "-5"):            socksver = int(sys.argv[1][1])            del sys.argv[1]        elif sys.argv[1] == '-x':            reverse = 1            del sys.argv[1]        elif sys.argv[1] == '--':            break    if len(sys.argv) >= 4:        print "Syntax: resolve.py [-x] [-4|-5] hostname [sockshost:socksport]"        sys.exit(0)    if len(sys.argv) == 3:        sh,sp = parseHostAndPort(sys.argv[2])    else:        sh,sp = parseHostAndPort("")    if reverse and socksver == 4:        socksver = 5    resolve(sys.argv[1], sh, sp, socksver, reverse)
 |