...
Run Format

Source file src/net/http/socks_bundle.go

Documentation: net/http

     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
     3  
     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  //
    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)) // 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")
    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  // A Command represents a SOCKS command.
   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  // An AuthMethod represents a SOCKS authentication method.
   191  type socksAuthMethod int
   192  
   193  // A Reply represents a SOCKS command reply code.
   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  // Wire protocol constants.
   222  const (
   223  	socksVersion5 = 0x05
   224  
   225  	socksAddrTypeIPv4 = 0x01
   226  	socksAddrTypeFQDN = 0x03
   227  	socksAddrTypeIPv6 = 0x04
   228  
   229  	socksCmdConnect socksCommand = 0x01 // establishes an active-open forward proxy connection
   230  	sockscmdBind    socksCommand = 0x02 // establishes a passive-open forward proxy connection
   231  
   232  	socksAuthMethodNotRequired         socksAuthMethod = 0x00 // no authentication required
   233  	socksAuthMethodUsernamePassword    socksAuthMethod = 0x02 // use username/password
   234  	socksAuthMethodNoAcceptableMethods socksAuthMethod = 0xff // no acceptable authentication methods
   235  
   236  	socksStatusSucceeded socksReply = 0x00
   237  )
   238  
   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
   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  // A Conn represents a forward proxy connection.
   261  type socksConn struct {
   262  	net.Conn
   263  
   264  	boundAddr net.Addr
   265  }
   266  
   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
   272  	}
   273  	return c.boundAddr
   274  }
   275  
   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
   281  
   282  	// ProxyDial specifies the optional dial function for
   283  	// establishing the transport connection.
   284  	ProxyDial func(context.Context, string, string) (net.Conn, error)
   285  
   286  	// AuthMethods specifies the list of request authention
   287  	// methods.
   288  	// If empty, SOCKS client requests only AuthMethodNotRequired.
   289  	AuthMethods []socksAuthMethod
   290  
   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
   295  }
   296  
   297  // DialContext connects to the provided address on the provided
   298  // network.
   299  //
   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.
   304  //
   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}
   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  // 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.
   340  //
   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}
   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  // Dial connects to the provided address on the provided network.
   361  //
   362  // Unlike DialContext, it returns a raw transport connection instead
   363  // of a forward proxy connection.
   364  //
   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}
   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  		return nil, err
   384  	}
   385  	return c, nil
   386  }
   387  
   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")
   393  	}
   394  	switch d.cmd {
   395  	case socksCmdConnect, sockscmdBind:
   396  	default:
   397  		return errors.New("command not implemented")
   398  	}
   399  	return nil
   400  }
   401  
   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
   407  		}
   408  		a := &socksAddr{Port: port}
   409  		a.IP = net.ParseIP(host)
   410  		if a.IP == nil {
   411  			a.Name = host
   412  		}
   413  		if i == 0 {
   414  			proxy = a
   415  		} else {
   416  			dst = a
   417  		}
   418  	}
   419  	return
   420  }
   421  
   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}
   426  }
   427  
   428  const (
   429  	socksauthUsernamePasswordVersion = 0x01
   430  	socksauthStatusSucceeded         = 0x00
   431  )
   432  
   433  // UsernamePassword are the credentials for the username/password
   434  // authentication method.
   435  type socksUsernamePassword struct {
   436  	Username string
   437  	Password string
   438  }
   439  
   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")
   449  		}
   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
   459  		}
   460  		if _, err := io.ReadFull(rw, b[:2]); err != nil {
   461  			return err
   462  		}
   463  		if b[0] != socksauthUsernamePasswordVersion {
   464  			return errors.New("invalid username/password version")
   465  		}
   466  		if b[1] != socksauthStatusSucceeded {
   467  			return errors.New("username/password authentication failed")
   468  		}
   469  		return nil
   470  	}
   471  	return errors.New("unsupported authentication method " + strconv.Itoa(int(auth)))
   472  }
   473  

View as plain text