...

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 -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 authentication
	 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