OSDN Git Service

new repo
[bytom/vapor.git] / vendor / github.com / btcsuite / btcd / connmgr / tor.go
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.
4
5 package connmgr
6
7 import (
8         "encoding/binary"
9         "errors"
10         "net"
11 )
12
13 const (
14         torSucceeded         = 0x00
15         torGeneralError      = 0x01
16         torNotAllowed        = 0x02
17         torNetUnreachable    = 0x03
18         torHostUnreachable   = 0x04
19         torConnectionRefused = 0x05
20         torTTLExpired        = 0x06
21         torCmdNotSupported   = 0x07
22         torAddrNotSupported  = 0x08
23 )
24
25 var (
26         // ErrTorInvalidAddressResponse indicates an invalid address was
27         // returned by the Tor DNS resolver.
28         ErrTorInvalidAddressResponse = errors.New("invalid address response")
29
30         // ErrTorInvalidProxyResponse indicates the Tor proxy returned a
31         // response in an unexpected format.
32         ErrTorInvalidProxyResponse = errors.New("invalid proxy response")
33
34         // ErrTorUnrecognizedAuthMethod indicates the authentication method
35         // provided is not recognized.
36         ErrTorUnrecognizedAuthMethod = errors.New("invalid proxy authentication method")
37
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"),
48         }
49 )
50
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
53 // doesn't either.
54 func TorLookupIP(host, proxy string) ([]net.IP, error) {
55         conn, err := net.Dial("tcp", proxy)
56         if err != nil {
57                 return nil, err
58         }
59         defer conn.Close()
60
61         buf := []byte{'\x05', '\x01', '\x00'}
62         _, err = conn.Write(buf)
63         if err != nil {
64                 return nil, err
65         }
66
67         buf = make([]byte, 2)
68         _, err = conn.Read(buf)
69         if err != nil {
70                 return nil, err
71         }
72         if buf[0] != '\x05' {
73                 return nil, ErrTorInvalidProxyResponse
74         }
75         if buf[1] != '\x00' {
76                 return nil, ErrTorUnrecognizedAuthMethod
77         }
78
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))
85         copy(buf[5:], host)
86         buf[5+len(host)] = 0 // Port 0
87
88         _, err = conn.Write(buf)
89         if err != nil {
90                 return nil, err
91         }
92
93         buf = make([]byte, 4)
94         _, err = conn.Read(buf)
95         if err != nil {
96                 return nil, err
97         }
98         if buf[0] != 5 {
99                 return nil, ErrTorInvalidProxyResponse
100         }
101         if buf[1] != 0 {
102                 if int(buf[1]) >= len(torStatusErrors) {
103                         return nil, ErrTorInvalidProxyResponse
104                 } else if err := torStatusErrors[buf[1]]; err != nil {
105                         return nil, err
106                 }
107                 return nil, ErrTorInvalidProxyResponse
108         }
109         if buf[3] != 1 {
110                 err := torStatusErrors[torGeneralError]
111                 return nil, err
112         }
113
114         buf = make([]byte, 4)
115         bytes, err := conn.Read(buf)
116         if err != nil {
117                 return nil, err
118         }
119         if bytes != 4 {
120                 return nil, ErrTorInvalidAddressResponse
121         }
122
123         r := binary.BigEndian.Uint32(buf)
124
125         addr := make([]net.IP, 1)
126         addr[0] = net.IPv4(byte(r>>24), byte(r>>16), byte(r>>8), byte(r))
127
128         return addr, nil
129 }