forked from shelvenzhou/btgd
-
Notifications
You must be signed in to change notification settings - Fork 1
/
tor.go
129 lines (112 loc) · 3.26 KB
/
tor.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
// Copyright (c) 2013-2016 The btcsuite developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package connmgr
import (
"encoding/binary"
"errors"
"net"
)
const (
torSucceeded = 0x00
torGeneralError = 0x01
torNotAllowed = 0x02
torNetUnreachable = 0x03
torHostUnreachable = 0x04
torConnectionRefused = 0x05
torTTLExpired = 0x06
torCmdNotSupported = 0x07
torAddrNotSupported = 0x08
)
var (
// ErrTorInvalidAddressResponse indicates an invalid address was
// returned by the Tor DNS resolver.
ErrTorInvalidAddressResponse = errors.New("invalid address response")
// ErrTorInvalidProxyResponse indicates the Tor proxy returned a
// response in an unexpected format.
ErrTorInvalidProxyResponse = errors.New("invalid proxy response")
// ErrTorUnrecognizedAuthMethod indicates the authentication method
// provided is not recognized.
ErrTorUnrecognizedAuthMethod = errors.New("invalid proxy authentication method")
torStatusErrors = map[byte]error{
torSucceeded: errors.New("tor succeeded"),
torGeneralError: errors.New("tor general error"),
torNotAllowed: errors.New("tor not allowed"),
torNetUnreachable: errors.New("tor network is unreachable"),
torHostUnreachable: errors.New("tor host is unreachable"),
torConnectionRefused: errors.New("tor connection refused"),
torTTLExpired: errors.New("tor TTL expired"),
torCmdNotSupported: errors.New("tor command not supported"),
torAddrNotSupported: errors.New("tor address type not supported"),
}
)
// TorLookupIP uses Tor to resolve DNS via the SOCKS extension they provide for
// resolution over the Tor network. Tor itself doesn't support ipv6 so this
// doesn't either.
func TorLookupIP(host, proxy string) ([]net.IP, error) {
conn, err := net.Dial("tcp", proxy)
if err != nil {
return nil, err
}
defer conn.Close()
buf := []byte{'\x05', '\x01', '\x00'}
_, err = conn.Write(buf)
if err != nil {
return nil, err
}
buf = make([]byte, 2)
_, err = conn.Read(buf)
if err != nil {
return nil, err
}
if buf[0] != '\x05' {
return nil, ErrTorInvalidProxyResponse
}
if buf[1] != '\x00' {
return nil, ErrTorUnrecognizedAuthMethod
}
buf = make([]byte, 7+len(host))
buf[0] = 5 // protocol version
buf[1] = '\xF0' // Tor Resolve
buf[2] = 0 // reserved
buf[3] = 3 // Tor Resolve
buf[4] = byte(len(host))
copy(buf[5:], host)
buf[5+len(host)] = 0 // Port 0
_, err = conn.Write(buf)
if err != nil {
return nil, err
}
buf = make([]byte, 4)
_, err = conn.Read(buf)
if err != nil {
return nil, err
}
if buf[0] != 5 {
return nil, ErrTorInvalidProxyResponse
}
if buf[1] != 0 {
if int(buf[1]) >= len(torStatusErrors) {
return nil, ErrTorInvalidProxyResponse
} else if err := torStatusErrors[buf[1]]; err != nil {
return nil, err
}
return nil, ErrTorInvalidProxyResponse
}
if buf[3] != 1 {
err := torStatusErrors[torGeneralError]
return nil, err
}
buf = make([]byte, 4)
bytes, err := conn.Read(buf)
if err != nil {
return nil, err
}
if bytes != 4 {
return nil, ErrTorInvalidAddressResponse
}
r := binary.BigEndian.Uint32(buf)
addr := make([]net.IP, 1)
addr[0] = net.IPv4(byte(r>>24), byte(r>>16), byte(r>>8), byte(r))
return addr, nil
}