// Code generated by golang.org/x/tools/cmd/bundle. DO NOT EDIT.
//go:generate bundle -o socks_bundle.go -prefix socks 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 (
	
	
	
	
	
	
)

var (
	socksnoDeadline   = time.Time{}
	socksaLongTimeAgo = time.Unix(1, 0)
)

func ( *socksDialer) ( context.Context,  net.Conn,  string) ( net.Addr,  error) {
	, ,  := sockssplitHostPort()
	if  != nil {
		return nil, 
	}
	if ,  := .Deadline();  && !.IsZero() {
		.SetDeadline()
		defer .SetDeadline(socksnoDeadline)
	}
	if  != context.Background() {
		 := make(chan error, 1)
		 := make(chan struct{})
		defer func() {
			close()
			if  == nil {
				 = <-
			}
		}()
		go func() {
			select {
			case <-.Done():
				.SetDeadline(socksaLongTimeAgo)
				 <- .Err()
			case <-:
				 <- nil
			}
		}()
	}

	 := make([]byte, 0, 6+len()) // the size here is just an estimate
	 = append(, socksVersion5)
	if len(.AuthMethods) == 0 || .Authenticate == nil {
		 = append(, 1, byte(socksAuthMethodNotRequired))
	} else {
		 := .AuthMethods
		if len() > 255 {
			return nil, errors.New("too many authentication methods")
		}
		 = append(, byte(len()))
		for ,  := range  {
			 = append(, byte())
		}
	}
	if _,  = .Write();  != nil {
		return
	}

	if _,  = io.ReadFull(, [:2]);  != nil {
		return
	}
	if [0] != socksVersion5 {
		return nil, errors.New("unexpected protocol version " + strconv.Itoa(int([0])))
	}
	 := socksAuthMethod([1])
	if  == socksAuthMethodNoAcceptableMethods {
		return nil, errors.New("no acceptable authentication methods")
	}
	if .Authenticate != nil {
		if  = .Authenticate(, , );  != nil {
			return
		}
	}

	 = [:0]
	 = append(, socksVersion5, byte(.cmd), 0)
	if  := net.ParseIP();  != nil {
		if  := .To4();  != nil {
			 = append(, socksAddrTypeIPv4)
			 = append(, ...)
		} else if  := .To16();  != nil {
			 = append(, socksAddrTypeIPv6)
			 = append(, ...)
		} else {
			return nil, errors.New("unknown address type")
		}
	} else {
		if len() > 255 {
			return nil, errors.New("FQDN too long")
		}
		 = append(, socksAddrTypeFQDN)
		 = append(, byte(len()))
		 = append(, ...)
	}
	 = append(, byte(>>8), byte())
	if _,  = .Write();  != nil {
		return
	}

	if _,  = io.ReadFull(, [:4]);  != nil {
		return
	}
	if [0] != socksVersion5 {
		return nil, errors.New("unexpected protocol version " + strconv.Itoa(int([0])))
	}
	if  := socksReply([1]);  != socksStatusSucceeded {
		return nil, errors.New("unknown error " + .String())
	}
	if [2] != 0 {
		return nil, errors.New("non-zero reserved field")
	}
	 := 2
	var  socksAddr
	switch [3] {
	case socksAddrTypeIPv4:
		 += net.IPv4len
		.IP = make(net.IP, net.IPv4len)
	case socksAddrTypeIPv6:
		 += net.IPv6len
		.IP = make(net.IP, net.IPv6len)
	case socksAddrTypeFQDN:
		if ,  := io.ReadFull(, [:1]);  != nil {
			return nil, 
		}
		 += int([0])
	default:
		return nil, errors.New("unknown address type " + strconv.Itoa(int([3])))
	}
	if cap() <  {
		 = make([]byte, )
	} else {
		 = [:]
	}
	if _,  = io.ReadFull(, );  != nil {
		return
	}
	if .IP != nil {
		copy(.IP, )
	} else {
		.Name = string([:len()-2])
	}
	.Port = int([len()-2])<<8 | int([len()-1])
	return &, nil
}

func sockssplitHostPort( string) (string, int, error) {
	, ,  := net.SplitHostPort()
	if  != nil {
		return "", 0, 
	}
	,  := strconv.Atoi()
	if  != nil {
		return "", 0, 
	}
	if 1 >  ||  > 0xffff {
		return "", 0, errors.New("port number out of range " + )
	}
	return , , nil
}

// A Command represents a SOCKS command.
type socksCommand int

func ( socksCommand) () string {
	switch  {
	case socksCmdConnect:
		return "socks connect"
	case sockscmdBind:
		return "socks bind"
	default:
		return "socks " + strconv.Itoa(int())
	}
}

// An AuthMethod represents a SOCKS authentication method.
type socksAuthMethod int

// A Reply represents a SOCKS command reply code.
type socksReply int

func ( socksReply) () string {
	switch  {
	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())
	}
}

// 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 ( *socksAddr) () string { return "socks" }

func ( *socksAddr) () string {
	if  == nil {
		return "<nil>"
	}
	 := strconv.Itoa(.Port)
	if .IP == nil {
		return net.JoinHostPort(.Name, )
	}
	return net.JoinHostPort(.IP.String(), )
}

// 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 ( *socksConn) () net.Addr {
	if  == nil {
		return nil
	}
	return .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 authentication
	// 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 ( *socksDialer) ( context.Context, ,  string) (net.Conn, error) {
	if  := .validateTarget(, );  != nil {
		, ,  := .pathAddrs()
		return nil, &net.OpError{Op: .cmd.String(), Net: , Source: , Addr: , Err: }
	}
	if  == nil {
		, ,  := .pathAddrs()
		return nil, &net.OpError{Op: .cmd.String(), Net: , Source: , Addr: , Err: errors.New("nil context")}
	}
	var  error
	var  net.Conn
	if .ProxyDial != nil {
		,  = .ProxyDial(, .proxyNetwork, .proxyAddress)
	} else {
		var  net.Dialer
		,  = .DialContext(, .proxyNetwork, .proxyAddress)
	}
	if  != nil {
		, ,  := .pathAddrs()
		return nil, &net.OpError{Op: .cmd.String(), Net: , Source: , Addr: , Err: }
	}
	,  := .connect(, , )
	if  != nil {
		.Close()
		, ,  := .pathAddrs()
		return nil, &net.OpError{Op: .cmd.String(), Net: , Source: , Addr: , Err: }
	}
	return &socksConn{Conn: , boundAddr: }, 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 ( *socksDialer) ( context.Context,  net.Conn, ,  string) (net.Addr, error) {
	if  := .validateTarget(, );  != nil {
		, ,  := .pathAddrs()
		return nil, &net.OpError{Op: .cmd.String(), Net: , Source: , Addr: , Err: }
	}
	if  == nil {
		, ,  := .pathAddrs()
		return nil, &net.OpError{Op: .cmd.String(), Net: , Source: , Addr: , Err: errors.New("nil context")}
	}
	,  := .connect(, , )
	if  != nil {
		, ,  := .pathAddrs()
		return nil, &net.OpError{Op: .cmd.String(), Net: , Source: , Addr: , Err: }
	}
	return , 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 ( *socksDialer) (,  string) (net.Conn, error) {
	if  := .validateTarget(, );  != nil {
		, ,  := .pathAddrs()
		return nil, &net.OpError{Op: .cmd.String(), Net: , Source: , Addr: , Err: }
	}
	var  error
	var  net.Conn
	if .ProxyDial != nil {
		,  = .ProxyDial(context.Background(), .proxyNetwork, .proxyAddress)
	} else {
		,  = net.Dial(.proxyNetwork, .proxyAddress)
	}
	if  != nil {
		, ,  := .pathAddrs()
		return nil, &net.OpError{Op: .cmd.String(), Net: , Source: , Addr: , Err: }
	}
	if ,  := .DialWithConn(context.Background(), , , );  != nil {
		.Close()
		return nil, 
	}
	return , nil
}

func ( *socksDialer) (,  string) error {
	switch  {
	case "tcp", "tcp6", "tcp4":
	default:
		return errors.New("network not implemented")
	}
	switch .cmd {
	case socksCmdConnect, sockscmdBind:
	default:
		return errors.New("command not implemented")
	}
	return nil
}

func ( *socksDialer) ( string) (,  net.Addr,  error) {
	for ,  := range []string{.proxyAddress, } {
		, ,  := sockssplitHostPort()
		if  != nil {
			return nil, nil, 
		}
		 := &socksAddr{Port: }
		.IP = net.ParseIP()
		if .IP == nil {
			.Name = 
		}
		if  == 0 {
			 = 
		} else {
			 = 
		}
	}
	return
}

// NewDialer returns a new Dialer that dials through the provided
// proxy server's network and address.
func socksNewDialer(,  string) *socksDialer {
	return &socksDialer{proxyNetwork: , proxyAddress: , 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 ( *socksUsernamePassword) ( context.Context,  io.ReadWriter,  socksAuthMethod) error {
	switch  {
	case socksAuthMethodNotRequired:
		return nil
	case socksAuthMethodUsernamePassword:
		if len(.Username) == 0 || len(.Username) > 255 || len(.Password) == 0 || len(.Password) > 255 {
			return errors.New("invalid username/password")
		}
		 := []byte{socksauthUsernamePasswordVersion}
		 = append(, byte(len(.Username)))
		 = append(, .Username...)
		 = append(, byte(len(.Password)))
		 = append(, .Password...)
		// TODO(mikio): handle IO deadlines and cancelation if
		// necessary
		if ,  := .Write();  != nil {
			return 
		}
		if ,  := io.ReadFull(, [:2]);  != nil {
			return 
		}
		if [0] != socksauthUsernamePasswordVersion {
			return errors.New("invalid username/password version")
		}
		if [1] != socksauthStatusSucceeded {
			return errors.New("username/password authentication failed")
		}
		return nil
	}
	return errors.New("unsupported authentication method " + strconv.Itoa(int()))
}