| // Code generated by golang.org/x/tools/cmd/bundle. DO NOT EDIT. | 
 | //go:generate bundle -o socks_bundle.go -dst net/http -prefix socks -underscore golang.org/x/net/internal/socks | 
 |  | 
 | // Package socks provides a SOCKS version 5 client implementation. | 
 | // | 
 | // SOCKS protocol version 5 is defined in RFC 1928. | 
 | // Username/Password authentication for SOCKS version 5 is defined in | 
 | // RFC 1929. | 
 | // | 
 |  | 
 | package http | 
 |  | 
 | import ( | 
 | 	"context" | 
 | 	"errors" | 
 | 	"io" | 
 | 	"net" | 
 | 	"strconv" | 
 | 	"time" | 
 | ) | 
 |  | 
 | var ( | 
 | 	socksnoDeadline   = time.Time{} | 
 | 	socksaLongTimeAgo = time.Unix(1, 0) | 
 | ) | 
 |  | 
 | func (d *socksDialer) connect(ctx context.Context, c net.Conn, address string) (_ net.Addr, ctxErr error) { | 
 | 	host, port, err := sockssplitHostPort(address) | 
 | 	if err != nil { | 
 | 		return nil, err | 
 | 	} | 
 | 	if deadline, ok := ctx.Deadline(); ok && !deadline.IsZero() { | 
 | 		c.SetDeadline(deadline) | 
 | 		defer c.SetDeadline(socksnoDeadline) | 
 | 	} | 
 | 	if ctx != context.Background() { | 
 | 		errCh := make(chan error, 1) | 
 | 		done := make(chan struct{}) | 
 | 		defer func() { | 
 | 			close(done) | 
 | 			if ctxErr == nil { | 
 | 				ctxErr = <-errCh | 
 | 			} | 
 | 		}() | 
 | 		go func() { | 
 | 			select { | 
 | 			case <-ctx.Done(): | 
 | 				c.SetDeadline(socksaLongTimeAgo) | 
 | 				errCh <- ctx.Err() | 
 | 			case <-done: | 
 | 				errCh <- nil | 
 | 			} | 
 | 		}() | 
 | 	} | 
 |  | 
 | 	b := make([]byte, 0, 6+len(host)) // the size here is just an estimate | 
 | 	b = append(b, socksVersion5) | 
 | 	if len(d.AuthMethods) == 0 || d.Authenticate == nil { | 
 | 		b = append(b, 1, byte(socksAuthMethodNotRequired)) | 
 | 	} else { | 
 | 		ams := d.AuthMethods | 
 | 		if len(ams) > 255 { | 
 | 			return nil, errors.New("too many authentication methods") | 
 | 		} | 
 | 		b = append(b, byte(len(ams))) | 
 | 		for _, am := range ams { | 
 | 			b = append(b, byte(am)) | 
 | 		} | 
 | 	} | 
 | 	if _, ctxErr = c.Write(b); ctxErr != nil { | 
 | 		return | 
 | 	} | 
 |  | 
 | 	if _, ctxErr = io.ReadFull(c, b[:2]); ctxErr != nil { | 
 | 		return | 
 | 	} | 
 | 	if b[0] != socksVersion5 { | 
 | 		return nil, errors.New("unexpected protocol version " + strconv.Itoa(int(b[0]))) | 
 | 	} | 
 | 	am := socksAuthMethod(b[1]) | 
 | 	if am == socksAuthMethodNoAcceptableMethods { | 
 | 		return nil, errors.New("no acceptable authentication methods") | 
 | 	} | 
 | 	if d.Authenticate != nil { | 
 | 		if ctxErr = d.Authenticate(ctx, c, am); ctxErr != nil { | 
 | 			return | 
 | 		} | 
 | 	} | 
 |  | 
 | 	b = b[:0] | 
 | 	b = append(b, socksVersion5, byte(d.cmd), 0) | 
 | 	if ip := net.ParseIP(host); ip != nil { | 
 | 		if ip4 := ip.To4(); ip4 != nil { | 
 | 			b = append(b, socksAddrTypeIPv4) | 
 | 			b = append(b, ip4...) | 
 | 		} else if ip6 := ip.To16(); ip6 != nil { | 
 | 			b = append(b, socksAddrTypeIPv6) | 
 | 			b = append(b, ip6...) | 
 | 		} else { | 
 | 			return nil, errors.New("unknown address type") | 
 | 		} | 
 | 	} else { | 
 | 		if len(host) > 255 { | 
 | 			return nil, errors.New("FQDN too long") | 
 | 		} | 
 | 		b = append(b, socksAddrTypeFQDN) | 
 | 		b = append(b, byte(len(host))) | 
 | 		b = append(b, host...) | 
 | 	} | 
 | 	b = append(b, byte(port>>8), byte(port)) | 
 | 	if _, ctxErr = c.Write(b); ctxErr != nil { | 
 | 		return | 
 | 	} | 
 |  | 
 | 	if _, ctxErr = io.ReadFull(c, b[:4]); ctxErr != nil { | 
 | 		return | 
 | 	} | 
 | 	if b[0] != socksVersion5 { | 
 | 		return nil, errors.New("unexpected protocol version " + strconv.Itoa(int(b[0]))) | 
 | 	} | 
 | 	if cmdErr := socksReply(b[1]); cmdErr != socksStatusSucceeded { | 
 | 		return nil, errors.New("unknown error " + cmdErr.String()) | 
 | 	} | 
 | 	if b[2] != 0 { | 
 | 		return nil, errors.New("non-zero reserved field") | 
 | 	} | 
 | 	l := 2 | 
 | 	var a socksAddr | 
 | 	switch b[3] { | 
 | 	case socksAddrTypeIPv4: | 
 | 		l += net.IPv4len | 
 | 		a.IP = make(net.IP, net.IPv4len) | 
 | 	case socksAddrTypeIPv6: | 
 | 		l += net.IPv6len | 
 | 		a.IP = make(net.IP, net.IPv6len) | 
 | 	case socksAddrTypeFQDN: | 
 | 		if _, err := io.ReadFull(c, b[:1]); err != nil { | 
 | 			return nil, err | 
 | 		} | 
 | 		l += int(b[0]) | 
 | 	default: | 
 | 		return nil, errors.New("unknown address type " + strconv.Itoa(int(b[3]))) | 
 | 	} | 
 | 	if cap(b) < l { | 
 | 		b = make([]byte, l) | 
 | 	} else { | 
 | 		b = b[:l] | 
 | 	} | 
 | 	if _, ctxErr = io.ReadFull(c, b); ctxErr != nil { | 
 | 		return | 
 | 	} | 
 | 	if a.IP != nil { | 
 | 		copy(a.IP, b) | 
 | 	} else { | 
 | 		a.Name = string(b[:len(b)-2]) | 
 | 	} | 
 | 	a.Port = int(b[len(b)-2])<<8 | int(b[len(b)-1]) | 
 | 	return &a, nil | 
 | } | 
 |  | 
 | func sockssplitHostPort(address string) (string, int, error) { | 
 | 	host, port, err := net.SplitHostPort(address) | 
 | 	if err != nil { | 
 | 		return "", 0, err | 
 | 	} | 
 | 	portnum, err := strconv.Atoi(port) | 
 | 	if err != nil { | 
 | 		return "", 0, err | 
 | 	} | 
 | 	if 1 > portnum || portnum > 0xffff { | 
 | 		return "", 0, errors.New("port number out of range " + port) | 
 | 	} | 
 | 	return host, portnum, nil | 
 | } | 
 |  | 
 | // A Command represents a SOCKS command. | 
 | type socksCommand int | 
 |  | 
 | func (cmd socksCommand) String() string { | 
 | 	switch cmd { | 
 | 	case socksCmdConnect: | 
 | 		return "socks connect" | 
 | 	case sockscmdBind: | 
 | 		return "socks bind" | 
 | 	default: | 
 | 		return "socks " + strconv.Itoa(int(cmd)) | 
 | 	} | 
 | } | 
 |  | 
 | // An AuthMethod represents a SOCKS authentication method. | 
 | type socksAuthMethod int | 
 |  | 
 | // A Reply represents a SOCKS command reply code. | 
 | type socksReply int | 
 |  | 
 | func (code socksReply) String() string { | 
 | 	switch code { | 
 | 	case socksStatusSucceeded: | 
 | 		return "succeeded" | 
 | 	case 0x01: | 
 | 		return "general SOCKS server failure" | 
 | 	case 0x02: | 
 | 		return "connection not allowed by ruleset" | 
 | 	case 0x03: | 
 | 		return "network unreachable" | 
 | 	case 0x04: | 
 | 		return "host unreachable" | 
 | 	case 0x05: | 
 | 		return "connection refused" | 
 | 	case 0x06: | 
 | 		return "TTL expired" | 
 | 	case 0x07: | 
 | 		return "command not supported" | 
 | 	case 0x08: | 
 | 		return "address type not supported" | 
 | 	default: | 
 | 		return "unknown code: " + strconv.Itoa(int(code)) | 
 | 	} | 
 | } | 
 |  | 
 | // Wire protocol constants. | 
 | const ( | 
 | 	socksVersion5 = 0x05 | 
 |  | 
 | 	socksAddrTypeIPv4 = 0x01 | 
 | 	socksAddrTypeFQDN = 0x03 | 
 | 	socksAddrTypeIPv6 = 0x04 | 
 |  | 
 | 	socksCmdConnect socksCommand = 0x01 // establishes an active-open forward proxy connection | 
 | 	sockscmdBind    socksCommand = 0x02 // establishes a passive-open forward proxy connection | 
 |  | 
 | 	socksAuthMethodNotRequired         socksAuthMethod = 0x00 // no authentication required | 
 | 	socksAuthMethodUsernamePassword    socksAuthMethod = 0x02 // use username/password | 
 | 	socksAuthMethodNoAcceptableMethods socksAuthMethod = 0xff // no acceptable authentication methods | 
 |  | 
 | 	socksStatusSucceeded socksReply = 0x00 | 
 | ) | 
 |  | 
 | // An Addr represents a SOCKS-specific address. | 
 | // Either Name or IP is used exclusively. | 
 | type socksAddr struct { | 
 | 	Name string // fully-qualified domain name | 
 | 	IP   net.IP | 
 | 	Port int | 
 | } | 
 |  | 
 | func (a *socksAddr) Network() string { return "socks" } | 
 |  | 
 | func (a *socksAddr) String() string { | 
 | 	if a == nil { | 
 | 		return "<nil>" | 
 | 	} | 
 | 	port := strconv.Itoa(a.Port) | 
 | 	if a.IP == nil { | 
 | 		return net.JoinHostPort(a.Name, port) | 
 | 	} | 
 | 	return net.JoinHostPort(a.IP.String(), port) | 
 | } | 
 |  | 
 | // A Conn represents a forward proxy connection. | 
 | type socksConn struct { | 
 | 	net.Conn | 
 |  | 
 | 	boundAddr net.Addr | 
 | } | 
 |  | 
 | // BoundAddr returns the address assigned by the proxy server for | 
 | // connecting to the command target address from the proxy server. | 
 | func (c *socksConn) BoundAddr() net.Addr { | 
 | 	if c == nil { | 
 | 		return nil | 
 | 	} | 
 | 	return c.boundAddr | 
 | } | 
 |  | 
 | // A Dialer holds SOCKS-specific options. | 
 | type socksDialer struct { | 
 | 	cmd          socksCommand // either CmdConnect or cmdBind | 
 | 	proxyNetwork string       // network between a proxy server and a client | 
 | 	proxyAddress string       // proxy server address | 
 |  | 
 | 	// ProxyDial specifies the optional dial function for | 
 | 	// establishing the transport connection. | 
 | 	ProxyDial func(context.Context, string, string) (net.Conn, error) | 
 |  | 
 | 	// AuthMethods specifies the list of request authention | 
 | 	// methods. | 
 | 	// If empty, SOCKS client requests only AuthMethodNotRequired. | 
 | 	AuthMethods []socksAuthMethod | 
 |  | 
 | 	// Authenticate specifies the optional authentication | 
 | 	// function. It must be non-nil when AuthMethods is not empty. | 
 | 	// It must return an error when the authentication is failed. | 
 | 	Authenticate func(context.Context, io.ReadWriter, socksAuthMethod) error | 
 | } | 
 |  | 
 | // DialContext connects to the provided address on the provided | 
 | // network. | 
 | // | 
 | // The returned error value may be a net.OpError. When the Op field of | 
 | // net.OpError contains "socks", the Source field contains a proxy | 
 | // server address and the Addr field contains a command target | 
 | // address. | 
 | // | 
 | // See func Dial of the net package of standard library for a | 
 | // description of the network and address parameters. | 
 | func (d *socksDialer) DialContext(ctx context.Context, network, address string) (net.Conn, error) { | 
 | 	if err := d.validateTarget(network, address); err != nil { | 
 | 		proxy, dst, _ := d.pathAddrs(address) | 
 | 		return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err} | 
 | 	} | 
 | 	if ctx == nil { | 
 | 		proxy, dst, _ := d.pathAddrs(address) | 
 | 		return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: errors.New("nil context")} | 
 | 	} | 
 | 	var err error | 
 | 	var c net.Conn | 
 | 	if d.ProxyDial != nil { | 
 | 		c, err = d.ProxyDial(ctx, d.proxyNetwork, d.proxyAddress) | 
 | 	} else { | 
 | 		var dd net.Dialer | 
 | 		c, err = dd.DialContext(ctx, d.proxyNetwork, d.proxyAddress) | 
 | 	} | 
 | 	if err != nil { | 
 | 		proxy, dst, _ := d.pathAddrs(address) | 
 | 		return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err} | 
 | 	} | 
 | 	a, err := d.connect(ctx, c, address) | 
 | 	if err != nil { | 
 | 		c.Close() | 
 | 		proxy, dst, _ := d.pathAddrs(address) | 
 | 		return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err} | 
 | 	} | 
 | 	return &socksConn{Conn: c, boundAddr: a}, nil | 
 | } | 
 |  | 
 | // DialWithConn initiates a connection from SOCKS server to the target | 
 | // network and address using the connection c that is already | 
 | // connected to the SOCKS server. | 
 | // | 
 | // It returns the connection's local address assigned by the SOCKS | 
 | // server. | 
 | func (d *socksDialer) DialWithConn(ctx context.Context, c net.Conn, network, address string) (net.Addr, error) { | 
 | 	if err := d.validateTarget(network, address); err != nil { | 
 | 		proxy, dst, _ := d.pathAddrs(address) | 
 | 		return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err} | 
 | 	} | 
 | 	if ctx == nil { | 
 | 		proxy, dst, _ := d.pathAddrs(address) | 
 | 		return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: errors.New("nil context")} | 
 | 	} | 
 | 	a, err := d.connect(ctx, c, address) | 
 | 	if err != nil { | 
 | 		proxy, dst, _ := d.pathAddrs(address) | 
 | 		return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err} | 
 | 	} | 
 | 	return a, nil | 
 | } | 
 |  | 
 | // Dial connects to the provided address on the provided network. | 
 | // | 
 | // Unlike DialContext, it returns a raw transport connection instead | 
 | // of a forward proxy connection. | 
 | // | 
 | // Deprecated: Use DialContext or DialWithConn instead. | 
 | func (d *socksDialer) Dial(network, address string) (net.Conn, error) { | 
 | 	if err := d.validateTarget(network, address); err != nil { | 
 | 		proxy, dst, _ := d.pathAddrs(address) | 
 | 		return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err} | 
 | 	} | 
 | 	var err error | 
 | 	var c net.Conn | 
 | 	if d.ProxyDial != nil { | 
 | 		c, err = d.ProxyDial(context.Background(), d.proxyNetwork, d.proxyAddress) | 
 | 	} else { | 
 | 		c, err = net.Dial(d.proxyNetwork, d.proxyAddress) | 
 | 	} | 
 | 	if err != nil { | 
 | 		proxy, dst, _ := d.pathAddrs(address) | 
 | 		return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err} | 
 | 	} | 
 | 	if _, err := d.DialWithConn(context.Background(), c, network, address); err != nil { | 
 | 		return nil, err | 
 | 	} | 
 | 	return c, nil | 
 | } | 
 |  | 
 | func (d *socksDialer) validateTarget(network, address string) error { | 
 | 	switch network { | 
 | 	case "tcp", "tcp6", "tcp4": | 
 | 	default: | 
 | 		return errors.New("network not implemented") | 
 | 	} | 
 | 	switch d.cmd { | 
 | 	case socksCmdConnect, sockscmdBind: | 
 | 	default: | 
 | 		return errors.New("command not implemented") | 
 | 	} | 
 | 	return nil | 
 | } | 
 |  | 
 | func (d *socksDialer) pathAddrs(address string) (proxy, dst net.Addr, err error) { | 
 | 	for i, s := range []string{d.proxyAddress, address} { | 
 | 		host, port, err := sockssplitHostPort(s) | 
 | 		if err != nil { | 
 | 			return nil, nil, err | 
 | 		} | 
 | 		a := &socksAddr{Port: port} | 
 | 		a.IP = net.ParseIP(host) | 
 | 		if a.IP == nil { | 
 | 			a.Name = host | 
 | 		} | 
 | 		if i == 0 { | 
 | 			proxy = a | 
 | 		} else { | 
 | 			dst = a | 
 | 		} | 
 | 	} | 
 | 	return | 
 | } | 
 |  | 
 | // NewDialer returns a new Dialer that dials through the provided | 
 | // proxy server's network and address. | 
 | func socksNewDialer(network, address string) *socksDialer { | 
 | 	return &socksDialer{proxyNetwork: network, proxyAddress: address, cmd: socksCmdConnect} | 
 | } | 
 |  | 
 | const ( | 
 | 	socksauthUsernamePasswordVersion = 0x01 | 
 | 	socksauthStatusSucceeded         = 0x00 | 
 | ) | 
 |  | 
 | // UsernamePassword are the credentials for the username/password | 
 | // authentication method. | 
 | type socksUsernamePassword struct { | 
 | 	Username string | 
 | 	Password string | 
 | } | 
 |  | 
 | // Authenticate authenticates a pair of username and password with the | 
 | // proxy server. | 
 | func (up *socksUsernamePassword) Authenticate(ctx context.Context, rw io.ReadWriter, auth socksAuthMethod) error { | 
 | 	switch auth { | 
 | 	case socksAuthMethodNotRequired: | 
 | 		return nil | 
 | 	case socksAuthMethodUsernamePassword: | 
 | 		if len(up.Username) == 0 || len(up.Username) > 255 || len(up.Password) == 0 || len(up.Password) > 255 { | 
 | 			return errors.New("invalid username/password") | 
 | 		} | 
 | 		b := []byte{socksauthUsernamePasswordVersion} | 
 | 		b = append(b, byte(len(up.Username))) | 
 | 		b = append(b, up.Username...) | 
 | 		b = append(b, byte(len(up.Password))) | 
 | 		b = append(b, up.Password...) | 
 | 		// TODO(mikio): handle IO deadlines and cancelation if | 
 | 		// necessary | 
 | 		if _, err := rw.Write(b); err != nil { | 
 | 			return err | 
 | 		} | 
 | 		if _, err := io.ReadFull(rw, b[:2]); err != nil { | 
 | 			return err | 
 | 		} | 
 | 		if b[0] != socksauthUsernamePasswordVersion { | 
 | 			return errors.New("invalid username/password version") | 
 | 		} | 
 | 		if b[1] != socksauthStatusSucceeded { | 
 | 			return errors.New("username/password authentication failed") | 
 | 		} | 
 | 		return nil | 
 | 	} | 
 | 	return errors.New("unsupported authentication method " + strconv.Itoa(int(auth))) | 
 | } |