1 // Copyright (c) 2013-2016 The btcsuite developers
2 // Use of this source code is governed by an ISC
3 // license that can be found in the LICENSE file.
15 torGeneralError = 0x01
17 torNetUnreachable = 0x03
18 torHostUnreachable = 0x04
19 torConnectionRefused = 0x05
21 torCmdNotSupported = 0x07
22 torAddrNotSupported = 0x08
26 // ErrTorInvalidAddressResponse indicates an invalid address was
27 // returned by the Tor DNS resolver.
28 ErrTorInvalidAddressResponse = errors.New("invalid address response")
30 // ErrTorInvalidProxyResponse indicates the Tor proxy returned a
31 // response in an unexpected format.
32 ErrTorInvalidProxyResponse = errors.New("invalid proxy response")
34 // ErrTorUnrecognizedAuthMethod indicates the authentication method
35 // provided is not recognized.
36 ErrTorUnrecognizedAuthMethod = errors.New("invalid proxy authentication method")
38 torStatusErrors = map[byte]error{
39 torSucceeded: errors.New("tor succeeded"),
40 torGeneralError: errors.New("tor general error"),
41 torNotAllowed: errors.New("tor not allowed"),
42 torNetUnreachable: errors.New("tor network is unreachable"),
43 torHostUnreachable: errors.New("tor host is unreachable"),
44 torConnectionRefused: errors.New("tor connection refused"),
45 torTTLExpired: errors.New("tor TTL expired"),
46 torCmdNotSupported: errors.New("tor command not supported"),
47 torAddrNotSupported: errors.New("tor address type not supported"),
51 // TorLookupIP uses Tor to resolve DNS via the SOCKS extension they provide for
52 // resolution over the Tor network. Tor itself doesn't support ipv6 so this
54 func TorLookupIP(host, proxy string) ([]net.IP, error) {
55 conn, err := net.Dial("tcp", proxy)
61 buf := []byte{'\x05', '\x01', '\x00'}
62 _, err = conn.Write(buf)
68 _, err = conn.Read(buf)
73 return nil, ErrTorInvalidProxyResponse
76 return nil, ErrTorUnrecognizedAuthMethod
79 buf = make([]byte, 7+len(host))
80 buf[0] = 5 // protocol version
81 buf[1] = '\xF0' // Tor Resolve
82 buf[2] = 0 // reserved
83 buf[3] = 3 // Tor Resolve
84 buf[4] = byte(len(host))
86 buf[5+len(host)] = 0 // Port 0
88 _, err = conn.Write(buf)
94 _, err = conn.Read(buf)
99 return nil, ErrTorInvalidProxyResponse
102 if int(buf[1]) >= len(torStatusErrors) {
103 return nil, ErrTorInvalidProxyResponse
104 } else if err := torStatusErrors[buf[1]]; err != nil {
107 return nil, ErrTorInvalidProxyResponse
110 err := torStatusErrors[torGeneralError]
114 buf = make([]byte, 4)
115 bytes, err := conn.Read(buf)
120 return nil, ErrTorInvalidAddressResponse
123 r := binary.BigEndian.Uint32(buf)
125 addr := make([]net.IP, 1)
126 addr[0] = net.IPv4(byte(r>>24), byte(r>>16), byte(r>>8), byte(r))