libgo: update to Go 1.11
[official-gcc.git] / libgo / go / net / http / socks_bundle.go
blobe4314b4128306a414f022d5fcd6c86efed42238c
1 // Code generated by golang.org/x/tools/cmd/bundle. DO NOT EDIT.
2 //go:generate bundle -o socks_bundle.go -dst net/http -prefix socks -underscore golang.org/x/net/internal/socks
4 // Package socks provides a SOCKS version 5 client implementation.
5 //
6 // SOCKS protocol version 5 is defined in RFC 1928.
7 // Username/Password authentication for SOCKS version 5 is defined in
8 // RFC 1929.
9 //
11 package http
13 import (
14 "context"
15 "errors"
16 "io"
17 "net"
18 "strconv"
19 "time"
22 var (
23 socksnoDeadline = time.Time{}
24 socksaLongTimeAgo = time.Unix(1, 0)
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
32 if deadline, ok := ctx.Deadline(); ok && !deadline.IsZero() {
33 c.SetDeadline(deadline)
34 defer c.SetDeadline(socksnoDeadline)
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
44 }()
45 go func() {
46 select {
47 case <-ctx.Done():
48 c.SetDeadline(socksaLongTimeAgo)
49 errCh <- ctx.Err()
50 case <-done:
51 errCh <- nil
53 }()
56 b := make([]byte, 0, 6+len(host)) // the size here is just an estimate
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")
65 b = append(b, byte(len(ams)))
66 for _, am := range ams {
67 b = append(b, byte(am))
70 if _, ctxErr = c.Write(b); ctxErr != nil {
71 return
74 if _, ctxErr = io.ReadFull(c, b[:2]); ctxErr != nil {
75 return
77 if b[0] != socksVersion5 {
78 return nil, errors.New("unexpected protocol version " + strconv.Itoa(int(b[0])))
80 am := socksAuthMethod(b[1])
81 if am == socksAuthMethodNoAcceptableMethods {
82 return nil, errors.New("no acceptable authentication methods")
84 if d.Authenticate != nil {
85 if ctxErr = d.Authenticate(ctx, c, am); ctxErr != nil {
86 return
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")
102 } else {
103 if len(host) > 255 {
104 return nil, errors.New("FQDN too long")
106 b = append(b, socksAddrTypeFQDN)
107 b = append(b, byte(len(host)))
108 b = append(b, host...)
110 b = append(b, byte(port>>8), byte(port))
111 if _, ctxErr = c.Write(b); ctxErr != nil {
112 return
115 if _, ctxErr = io.ReadFull(c, b[:4]); ctxErr != nil {
116 return
118 if b[0] != socksVersion5 {
119 return nil, errors.New("unexpected protocol version " + strconv.Itoa(int(b[0])))
121 if cmdErr := socksReply(b[1]); cmdErr != socksStatusSucceeded {
122 return nil, errors.New("unknown error " + cmdErr.String())
124 if b[2] != 0 {
125 return nil, errors.New("non-zero reserved field")
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
140 l += int(b[0])
141 default:
142 return nil, errors.New("unknown address type " + strconv.Itoa(int(b[3])))
144 if cap(b) < l {
145 b = make([]byte, l)
146 } else {
147 b = b[:l]
149 if _, ctxErr = io.ReadFull(c, b); ctxErr != nil {
150 return
152 if a.IP != nil {
153 copy(a.IP, b)
154 } else {
155 a.Name = string(b[:len(b)-2])
157 a.Port = int(b[len(b)-2])<<8 | int(b[len(b)-1])
158 return &a, nil
161 func sockssplitHostPort(address string) (string, int, error) {
162 host, port, err := net.SplitHostPort(address)
163 if err != nil {
164 return "", 0, err
166 portnum, err := strconv.Atoi(port)
167 if err != nil {
168 return "", 0, err
170 if 1 > portnum || portnum > 0xffff {
171 return "", 0, errors.New("port number out of range " + port)
173 return host, portnum, nil
176 // A Command represents a SOCKS command.
177 type socksCommand int
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))
190 // An AuthMethod represents a SOCKS authentication method.
191 type socksAuthMethod int
193 // A Reply represents a SOCKS command reply code.
194 type socksReply int
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))
221 // Wire protocol constants.
222 const (
223 socksVersion5 = 0x05
225 socksAddrTypeIPv4 = 0x01
226 socksAddrTypeFQDN = 0x03
227 socksAddrTypeIPv6 = 0x04
229 socksCmdConnect socksCommand = 0x01 // establishes an active-open forward proxy connection
230 sockscmdBind socksCommand = 0x02 // establishes a passive-open forward proxy connection
232 socksAuthMethodNotRequired socksAuthMethod = 0x00 // no authentication required
233 socksAuthMethodUsernamePassword socksAuthMethod = 0x02 // use username/password
234 socksAuthMethodNoAcceptableMethods socksAuthMethod = 0xff // no acceptable authentication methods
236 socksStatusSucceeded socksReply = 0x00
239 // An Addr represents a SOCKS-specific address.
240 // Either Name or IP is used exclusively.
241 type socksAddr struct {
242 Name string // fully-qualified domain name
243 IP net.IP
244 Port int
247 func (a *socksAddr) Network() string { return "socks" }
249 func (a *socksAddr) String() string {
250 if a == nil {
251 return "<nil>"
253 port := strconv.Itoa(a.Port)
254 if a.IP == nil {
255 return net.JoinHostPort(a.Name, port)
257 return net.JoinHostPort(a.IP.String(), port)
260 // A Conn represents a forward proxy connection.
261 type socksConn struct {
262 net.Conn
264 boundAddr net.Addr
267 // BoundAddr returns the address assigned by the proxy server for
268 // connecting to the command target address from the proxy server.
269 func (c *socksConn) BoundAddr() net.Addr {
270 if c == nil {
271 return nil
273 return c.boundAddr
276 // A Dialer holds SOCKS-specific options.
277 type socksDialer struct {
278 cmd socksCommand // either CmdConnect or cmdBind
279 proxyNetwork string // network between a proxy server and a client
280 proxyAddress string // proxy server address
282 // ProxyDial specifies the optional dial function for
283 // establishing the transport connection.
284 ProxyDial func(context.Context, string, string) (net.Conn, error)
286 // AuthMethods specifies the list of request authention
287 // methods.
288 // If empty, SOCKS client requests only AuthMethodNotRequired.
289 AuthMethods []socksAuthMethod
291 // Authenticate specifies the optional authentication
292 // function. It must be non-nil when AuthMethods is not empty.
293 // It must return an error when the authentication is failed.
294 Authenticate func(context.Context, io.ReadWriter, socksAuthMethod) error
297 // DialContext connects to the provided address on the provided
298 // network.
300 // The returned error value may be a net.OpError. When the Op field of
301 // net.OpError contains "socks", the Source field contains a proxy
302 // server address and the Addr field contains a command target
303 // address.
305 // See func Dial of the net package of standard library for a
306 // description of the network and address parameters.
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}
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")}
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)
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}
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}
334 return &socksConn{Conn: c, boundAddr: a}, nil
337 // DialWithConn initiates a connection from SOCKS server to the target
338 // network and address using the connection c that is already
339 // connected to the SOCKS server.
341 // It returns the connection's local address assigned by the SOCKS
342 // server.
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}
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")}
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}
357 return a, nil
360 // Dial connects to the provided address on the provided network.
362 // Unlike DialContext, it returns a raw transport connection instead
363 // of a forward proxy connection.
365 // Deprecated: Use DialContext or DialWithConn instead.
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}
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)
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}
382 if _, err := d.DialWithConn(context.Background(), c, network, address); err != nil {
383 return nil, err
385 return c, nil
388 func (d *socksDialer) validateTarget(network, address string) error {
389 switch network {
390 case "tcp", "tcp6", "tcp4":
391 default:
392 return errors.New("network not implemented")
394 switch d.cmd {
395 case socksCmdConnect, sockscmdBind:
396 default:
397 return errors.New("command not implemented")
399 return nil
402 func (d *socksDialer) pathAddrs(address string) (proxy, dst net.Addr, err error) {
403 for i, s := range []string{d.proxyAddress, address} {
404 host, port, err := sockssplitHostPort(s)
405 if err != nil {
406 return nil, nil, err
408 a := &socksAddr{Port: port}
409 a.IP = net.ParseIP(host)
410 if a.IP == nil {
411 a.Name = host
413 if i == 0 {
414 proxy = a
415 } else {
416 dst = a
419 return
422 // NewDialer returns a new Dialer that dials through the provided
423 // proxy server's network and address.
424 func socksNewDialer(network, address string) *socksDialer {
425 return &socksDialer{proxyNetwork: network, proxyAddress: address, cmd: socksCmdConnect}
428 const (
429 socksauthUsernamePasswordVersion = 0x01
430 socksauthStatusSucceeded = 0x00
433 // UsernamePassword are the credentials for the username/password
434 // authentication method.
435 type socksUsernamePassword struct {
436 Username string
437 Password string
440 // Authenticate authenticates a pair of username and password with the
441 // proxy server.
442 func (up *socksUsernamePassword) Authenticate(ctx context.Context, rw io.ReadWriter, auth socksAuthMethod) error {
443 switch auth {
444 case socksAuthMethodNotRequired:
445 return nil
446 case socksAuthMethodUsernamePassword:
447 if len(up.Username) == 0 || len(up.Username) > 255 || len(up.Password) == 0 || len(up.Password) > 255 {
448 return errors.New("invalid username/password")
450 b := []byte{socksauthUsernamePasswordVersion}
451 b = append(b, byte(len(up.Username)))
452 b = append(b, up.Username...)
453 b = append(b, byte(len(up.Password)))
454 b = append(b, up.Password...)
455 // TODO(mikio): handle IO deadlines and cancelation if
456 // necessary
457 if _, err := rw.Write(b); err != nil {
458 return err
460 if _, err := io.ReadFull(rw, b[:2]); err != nil {
461 return err
463 if b[0] != socksauthUsernamePasswordVersion {
464 return errors.New("invalid username/password version")
466 if b[1] != socksauthStatusSucceeded {
467 return errors.New("username/password authentication failed")
469 return nil
471 return errors.New("unsupported authentication method " + strconv.Itoa(int(auth)))