...

Source file src/pkg/net/http/socks_bundle.go

     1	// Code generated by golang.org/x/tools/cmd/bundle. DO NOT EDIT.
     2	//go:generate bundle -o socks_bundle.go -prefix socks 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			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	// NewDialer returns a new Dialer that dials through the provided
   424	// proxy server's network and address.
   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	// UsernamePassword are the credentials for the username/password
   435	// authentication method.
   436	type socksUsernamePassword struct {
   437		Username string
   438		Password string
   439	}
   440	
   441	// Authenticate authenticates a pair of username and password with the
   442	// proxy server.
   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			// TODO(mikio): handle IO deadlines and cancelation if
   457			// necessary
   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