/
socks.go
148 lines (138 loc) · 3.36 KB
/
socks.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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
package proxy
import (
"errors"
"io"
"net"
"strconv"
)
var (
errorNoIPs = errors.New("no IP addresses")
errorNoIPv4s = errors.New("no IPv4 addresses")
errorNotIPv4 = errors.New("not an IPv4 address")
errorShortRead = errors.New("short read")
errorShortWrite = errors.New("short write")
errorUnsupportedTransport = errors.New("unsupported transport")
errorRequestRejected = errors.New("request rejected")
errorNoIdentd = errors.New("no client identd")
errorUserIdNotConfirmed = errors.New("user ID not confirmed")
errorUnknownResponseCode = errors.New("unknown response code")
)
type socksDialer struct {
dialer *net.Dialer
proxyAddress string
proxyDNS bool
udpSupported bool
}
func (d *socksDialer) Dial(network, address string) (net.Conn, error) {
switch network {
case "tcp":
return d.dialTCP(address)
case "udp":
}
return nil, errorUnsupportedTransport
}
func (d *socksDialer) dialTCP(address string) (net.Conn, error) {
host, portStr, err := net.SplitHostPort(address)
if err != nil {
return nil, err
}
port, err := strconv.ParseUint(portStr, 10, 16)
if err != nil {
return nil, err
}
var request []byte
if ip := net.ParseIP(host); ip != nil {
if request, err = makeSocks4IpRequest(ip, uint16(port)); err != nil {
return nil, err
}
} else if d.proxyDNS {
if request, err = makeSocks4aRequest(host, uint16(port)); err != nil {
return nil, err
}
} else {
if request, err = makeSocks4Request(host, uint16(port)); err != nil {
return nil, err
}
}
if conn, err := d.dialer.Dial("tcp", d.proxyAddress); err != nil {
return nil, err
} else {
if nWritten, err := conn.Write(request); err != nil {
conn.Close()
return nil, err
} else if nWritten < len(request) {
conn.Close()
return nil, errorShortWrite
}
if err := readSocks4Response(conn); err != nil {
conn.Close()
return nil, err
}
return conn, nil
}
}
func makeSocks4aRequest(host string, port uint16) ([]byte, error) {
request := make([]byte, 10+len(host))
request[0] = 0x04
request[1] = 0x01
request[2] = byte(port >> 8)
request[3] = byte(port & 0xff)
request[7] = 0xff
copy(request[9:], host)
return request, nil
}
func makeSocks4IpRequest(ip net.IP, port uint16) ([]byte, error) {
if ip = ip.To4(); ip == nil {
return nil, errorNoIPv4s
}
request := make([]byte, 9)
request[0] = 0x04
request[1] = 0x01
request[2] = byte(port >> 8)
request[3] = byte(port & 0xff)
request[4] = ip[0]
request[5] = ip[1]
request[6] = ip[2]
request[7] = ip[3]
return request, nil
}
func makeSocks4Request(host string, port uint16) ([]byte, error) {
ips, err := net.LookupIP(host)
if err != nil {
return nil, err
}
if len(ips) < 1 {
return nil, errorNoIPs
}
var ip4 net.IP
for _, ip := range ips {
if ip4 = ip.To4(); ip4 != nil {
break
}
}
if len(ip4) != 4 {
return nil, errorNoIPv4s
}
return makeSocks4IpRequest(ip4, port)
}
func readSocks4Response(reader io.Reader) error {
response := make([]byte, 8)
if nRead, err := reader.Read(response); err != nil {
return err
} else if nRead < len(response) {
return errorShortRead
} else {
switch response[1] {
case 0x5a:
return nil
case 0x5b:
return errorRequestRejected
case 0x5c:
return errorNoIdentd
case 0x5d:
return errorUserIdNotConfirmed
default:
return errorUnknownResponseCode
}
}
}