Source file
src/net/http/socks_bundle.go
1
2
3
4
5
6
7
8
9
10
11 package http
12
13 import (
14 "context"
15 "errors"
16 "io"
17 "net"
18 "strconv"
19 "time"
20 )
21
22 var (
23 socksnoDeadline = time.Time{}
24 socksaLongTimeAgo = time.Unix(1, 0)
25 )
26
27 func (d *socksDialer) connect(ctx context.Context, c net.Conn, address string) (_ net.Addr, ctxErr error) {
28 host, port, err := sockssplitHostPort(address)
29 if err != nil {
30 return nil, err
31 }
32 if deadline, ok := ctx.Deadline(); ok && !deadline.IsZero() {
33 c.SetDeadline(deadline)
34 defer c.SetDeadline(socksnoDeadline)
35 }
36 if ctx != context.Background() {
37 errCh := make(chan error, 1)
38 done := make(chan struct{})
39 defer func() {
40 close(done)
41 if ctxErr == nil {
42 ctxErr = <-errCh
43 }
44 }()
45 go func() {
46 select {
47 case <-ctx.Done():
48 c.SetDeadline(socksaLongTimeAgo)
49 errCh <- ctx.Err()
50 case <-done:
51 errCh <- nil
52 }
53 }()
54 }
55
56 b := make([]byte, 0, 6+len(host))
57 b = append(b, socksVersion5)
58 if len(d.AuthMethods) == 0 || d.Authenticate == nil {
59 b = append(b, 1, byte(socksAuthMethodNotRequired))
60 } else {
61 ams := d.AuthMethods
62 if len(ams) > 255 {
63 return nil, errors.New("too many authentication methods")
64 }
65 b = append(b, byte(len(ams)))
66 for _, am := range ams {
67 b = append(b, byte(am))
68 }
69 }
70 if _, ctxErr = c.Write(b); ctxErr != nil {
71 return
72 }
73
74 if _, ctxErr = io.ReadFull(c, b[:2]); ctxErr != nil {
75 return
76 }
77 if b[0] != socksVersion5 {
78 return nil, errors.New("unexpected protocol version " + strconv.Itoa(int(b[0])))
79 }
80 am := socksAuthMethod(b[1])
81 if am == socksAuthMethodNoAcceptableMethods {
82 return nil, errors.New("no acceptable authentication methods")
83 }
84 if d.Authenticate != nil {
85 if ctxErr = d.Authenticate(ctx, c, am); ctxErr != nil {
86 return
87 }
88 }
89
90 b = b[:0]
91 b = append(b, socksVersion5, byte(d.cmd), 0)
92 if ip := net.ParseIP(host); ip != nil {
93 if ip4 := ip.To4(); ip4 != nil {
94 b = append(b, socksAddrTypeIPv4)
95 b = append(b, ip4...)
96 } else if ip6 := ip.To16(); ip6 != nil {
97 b = append(b, socksAddrTypeIPv6)
98 b = append(b, ip6...)
99 } else {
100 return nil, errors.New("unknown address type")
101 }
102 } else {
103 if len(host) > 255 {
104 return nil, errors.New("FQDN too long")
105 }
106 b = append(b, socksAddrTypeFQDN)
107 b = append(b, byte(len(host)))
108 b = append(b, host...)
109 }
110 b = append(b, byte(port>>8), byte(port))
111 if _, ctxErr = c.Write(b); ctxErr != nil {
112 return
113 }
114
115 if _, ctxErr = io.ReadFull(c, b[:4]); ctxErr != nil {
116 return
117 }
118 if b[0] != socksVersion5 {
119 return nil, errors.New("unexpected protocol version " + strconv.Itoa(int(b[0])))
120 }
121 if cmdErr := socksReply(b[1]); cmdErr != socksStatusSucceeded {
122 return nil, errors.New("unknown error " + cmdErr.String())
123 }
124 if b[2] != 0 {
125 return nil, errors.New("non-zero reserved field")
126 }
127 l := 2
128 var a socksAddr
129 switch b[3] {
130 case socksAddrTypeIPv4:
131 l += net.IPv4len
132 a.IP = make(net.IP, net.IPv4len)
133 case socksAddrTypeIPv6:
134 l += net.IPv6len
135 a.IP = make(net.IP, net.IPv6len)
136 case socksAddrTypeFQDN:
137 if _, err := io.ReadFull(c, b[:1]); err != nil {
138 return nil, err
139 }
140 l += int(b[0])
141 default:
142 return nil, errors.New("unknown address type " + strconv.Itoa(int(b[3])))
143 }
144 if cap(b) < l {
145 b = make([]byte, l)
146 } else {
147 b = b[:l]
148 }
149 if _, ctxErr = io.ReadFull(c, b); ctxErr != nil {
150 return
151 }
152 if a.IP != nil {
153 copy(a.IP, b)
154 } else {
155 a.Name = string(b[:len(b)-2])
156 }
157 a.Port = int(b[len(b)-2])<<8 | int(b[len(b)-1])
158 return &a, nil
159 }
160
161 func sockssplitHostPort(address string) (string, int, error) {
162 host, port, err := net.SplitHostPort(address)
163 if err != nil {
164 return "", 0, err
165 }
166 portnum, err := strconv.Atoi(port)
167 if err != nil {
168 return "", 0, err
169 }
170 if 1 > portnum || portnum > 0xffff {
171 return "", 0, errors.New("port number out of range " + port)
172 }
173 return host, portnum, nil
174 }
175
176
177 type socksCommand int
178
179 func (cmd socksCommand) String() string {
180 switch cmd {
181 case socksCmdConnect:
182 return "socks connect"
183 case sockscmdBind:
184 return "socks bind"
185 default:
186 return "socks " + strconv.Itoa(int(cmd))
187 }
188 }
189
190
191 type socksAuthMethod int
192
193
194 type socksReply int
195
196 func (code socksReply) String() string {
197 switch code {
198 case socksStatusSucceeded:
199 return "succeeded"
200 case 0x01:
201 return "general SOCKS server failure"
202 case 0x02:
203 return "connection not allowed by ruleset"
204 case 0x03:
205 return "network unreachable"
206 case 0x04:
207 return "host unreachable"
208 case 0x05:
209 return "connection refused"
210 case 0x06:
211 return "TTL expired"
212 case 0x07:
213 return "command not supported"
214 case 0x08:
215 return "address type not supported"
216 default:
217 return "unknown code: " + strconv.Itoa(int(code))
218 }
219 }
220
221
222 const (
223 socksVersion5 = 0x05
224
225 socksAddrTypeIPv4 = 0x01
226 socksAddrTypeFQDN = 0x03
227 socksAddrTypeIPv6 = 0x04
228
229 socksCmdConnect socksCommand = 0x01
230 sockscmdBind socksCommand = 0x02
231
232 socksAuthMethodNotRequired socksAuthMethod = 0x00
233 socksAuthMethodUsernamePassword socksAuthMethod = 0x02
234 socksAuthMethodNoAcceptableMethods socksAuthMethod = 0xff
235
236 socksStatusSucceeded socksReply = 0x00
237 )
238
239
240
241 type socksAddr struct {
242 Name string
243 IP net.IP
244 Port int
245 }
246
247 func (a *socksAddr) Network() string { return "socks" }
248
249 func (a *socksAddr) String() string {
250 if a == nil {
251 return "<nil>"
252 }
253 port := strconv.Itoa(a.Port)
254 if a.IP == nil {
255 return net.JoinHostPort(a.Name, port)
256 }
257 return net.JoinHostPort(a.IP.String(), port)
258 }
259
260
261 type socksConn struct {
262 net.Conn
263
264 boundAddr net.Addr
265 }
266
267
268
269 func (c *socksConn) BoundAddr() net.Addr {
270 if c == nil {
271 return nil
272 }
273 return c.boundAddr
274 }
275
276
277 type socksDialer struct {
278 cmd socksCommand
279 proxyNetwork string
280 proxyAddress string
281
282
283
284 ProxyDial func(context.Context, string, string) (net.Conn, error)
285
286
287
288
289 AuthMethods []socksAuthMethod
290
291
292
293
294 Authenticate func(context.Context, io.ReadWriter, socksAuthMethod) error
295 }
296
297
298
299
300
301
302
303
304
305
306
307 func (d *socksDialer) DialContext(ctx context.Context, network, address string) (net.Conn, error) {
308 if err := d.validateTarget(network, address); err != nil {
309 proxy, dst, _ := d.pathAddrs(address)
310 return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err}
311 }
312 if ctx == nil {
313 proxy, dst, _ := d.pathAddrs(address)
314 return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: errors.New("nil context")}
315 }
316 var err error
317 var c net.Conn
318 if d.ProxyDial != nil {
319 c, err = d.ProxyDial(ctx, d.proxyNetwork, d.proxyAddress)
320 } else {
321 var dd net.Dialer
322 c, err = dd.DialContext(ctx, d.proxyNetwork, d.proxyAddress)
323 }
324 if err != nil {
325 proxy, dst, _ := d.pathAddrs(address)
326 return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err}
327 }
328 a, err := d.connect(ctx, c, address)
329 if err != nil {
330 c.Close()
331 proxy, dst, _ := d.pathAddrs(address)
332 return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err}
333 }
334 return &socksConn{Conn: c, boundAddr: a}, nil
335 }
336
337
338
339
340
341
342
343 func (d *socksDialer) DialWithConn(ctx context.Context, c net.Conn, network, address string) (net.Addr, error) {
344 if err := d.validateTarget(network, address); err != nil {
345 proxy, dst, _ := d.pathAddrs(address)
346 return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err}
347 }
348 if ctx == nil {
349 proxy, dst, _ := d.pathAddrs(address)
350 return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: errors.New("nil context")}
351 }
352 a, err := d.connect(ctx, c, address)
353 if err != nil {
354 proxy, dst, _ := d.pathAddrs(address)
355 return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err}
356 }
357 return a, nil
358 }
359
360
361
362
363
364
365
366 func (d *socksDialer) Dial(network, address string) (net.Conn, error) {
367 if err := d.validateTarget(network, address); err != nil {
368 proxy, dst, _ := d.pathAddrs(address)
369 return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err}
370 }
371 var err error
372 var c net.Conn
373 if d.ProxyDial != nil {
374 c, err = d.ProxyDial(context.Background(), d.proxyNetwork, d.proxyAddress)
375 } else {
376 c, err = net.Dial(d.proxyNetwork, d.proxyAddress)
377 }
378 if err != nil {
379 proxy, dst, _ := d.pathAddrs(address)
380 return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err}
381 }
382 if _, err := d.DialWithConn(context.Background(), c, network, address); err != nil {
383 c.Close()
384 return nil, err
385 }
386 return c, nil
387 }
388
389 func (d *socksDialer) validateTarget(network, address string) error {
390 switch network {
391 case "tcp", "tcp6", "tcp4":
392 default:
393 return errors.New("network not implemented")
394 }
395 switch d.cmd {
396 case socksCmdConnect, sockscmdBind:
397 default:
398 return errors.New("command not implemented")
399 }
400 return nil
401 }
402
403 func (d *socksDialer) pathAddrs(address string) (proxy, dst net.Addr, err error) {
404 for i, s := range []string{d.proxyAddress, address} {
405 host, port, err := sockssplitHostPort(s)
406 if err != nil {
407 return nil, nil, err
408 }
409 a := &socksAddr{Port: port}
410 a.IP = net.ParseIP(host)
411 if a.IP == nil {
412 a.Name = host
413 }
414 if i == 0 {
415 proxy = a
416 } else {
417 dst = a
418 }
419 }
420 return
421 }
422
423
424
425 func socksNewDialer(network, address string) *socksDialer {
426 return &socksDialer{proxyNetwork: network, proxyAddress: address, cmd: socksCmdConnect}
427 }
428
429 const (
430 socksauthUsernamePasswordVersion = 0x01
431 socksauthStatusSucceeded = 0x00
432 )
433
434
435
436 type socksUsernamePassword struct {
437 Username string
438 Password string
439 }
440
441
442
443 func (up *socksUsernamePassword) Authenticate(ctx context.Context, rw io.ReadWriter, auth socksAuthMethod) error {
444 switch auth {
445 case socksAuthMethodNotRequired:
446 return nil
447 case socksAuthMethodUsernamePassword:
448 if len(up.Username) == 0 || len(up.Username) > 255 || len(up.Password) == 0 || len(up.Password) > 255 {
449 return errors.New("invalid username/password")
450 }
451 b := []byte{socksauthUsernamePasswordVersion}
452 b = append(b, byte(len(up.Username)))
453 b = append(b, up.Username...)
454 b = append(b, byte(len(up.Password)))
455 b = append(b, up.Password...)
456
457
458 if _, err := rw.Write(b); err != nil {
459 return err
460 }
461 if _, err := io.ReadFull(rw, b[:2]); err != nil {
462 return err
463 }
464 if b[0] != socksauthUsernamePasswordVersion {
465 return errors.New("invalid username/password version")
466 }
467 if b[1] != socksauthStatusSucceeded {
468 return errors.New("username/password authentication failed")
469 }
470 return nil
471 }
472 return errors.New("unsupported authentication method " + strconv.Itoa(int(auth)))
473 }
474
View as plain text