diff options
Diffstat (limited to 'vendor/golang.org/x/net')
| -rw-r--r-- | vendor/golang.org/x/net/internal/socks/client.go | 168 | ||||
| -rw-r--r-- | vendor/golang.org/x/net/internal/socks/socks.go | 317 | ||||
| -rw-r--r-- | vendor/golang.org/x/net/proxy/dial.go | 54 | ||||
| -rw-r--r-- | vendor/golang.org/x/net/proxy/direct.go | 31 | ||||
| -rw-r--r-- | vendor/golang.org/x/net/proxy/per_host.go | 155 | ||||
| -rw-r--r-- | vendor/golang.org/x/net/proxy/proxy.go | 149 | ||||
| -rw-r--r-- | vendor/golang.org/x/net/proxy/socks5.go | 42 | 
7 files changed, 916 insertions, 0 deletions
diff --git a/vendor/golang.org/x/net/internal/socks/client.go b/vendor/golang.org/x/net/internal/socks/client.go new file mode 100644 index 000000000..3d6f516a5 --- /dev/null +++ b/vendor/golang.org/x/net/internal/socks/client.go @@ -0,0 +1,168 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package socks + +import ( +	"context" +	"errors" +	"io" +	"net" +	"strconv" +	"time" +) + +var ( +	noDeadline   = time.Time{} +	aLongTimeAgo = time.Unix(1, 0) +) + +func (d *Dialer) connect(ctx context.Context, c net.Conn, address string) (_ net.Addr, ctxErr error) { +	host, port, err := splitHostPort(address) +	if err != nil { +		return nil, err +	} +	if deadline, ok := ctx.Deadline(); ok && !deadline.IsZero() { +		c.SetDeadline(deadline) +		defer c.SetDeadline(noDeadline) +	} +	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(aLongTimeAgo) +				errCh <- ctx.Err() +			case <-done: +				errCh <- nil +			} +		}() +	} + +	b := make([]byte, 0, 6+len(host)) // the size here is just an estimate +	b = append(b, Version5) +	if len(d.AuthMethods) == 0 || d.Authenticate == nil { +		b = append(b, 1, byte(AuthMethodNotRequired)) +	} 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] != Version5 { +		return nil, errors.New("unexpected protocol version " + strconv.Itoa(int(b[0]))) +	} +	am := AuthMethod(b[1]) +	if am == AuthMethodNoAcceptableMethods { +		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, Version5, byte(d.cmd), 0) +	if ip := net.ParseIP(host); ip != nil { +		if ip4 := ip.To4(); ip4 != nil { +			b = append(b, AddrTypeIPv4) +			b = append(b, ip4...) +		} else if ip6 := ip.To16(); ip6 != nil { +			b = append(b, AddrTypeIPv6) +			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, AddrTypeFQDN) +		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] != Version5 { +		return nil, errors.New("unexpected protocol version " + strconv.Itoa(int(b[0]))) +	} +	if cmdErr := Reply(b[1]); cmdErr != StatusSucceeded { +		return nil, errors.New("unknown error " + cmdErr.String()) +	} +	if b[2] != 0 { +		return nil, errors.New("non-zero reserved field") +	} +	l := 2 +	var a Addr +	switch b[3] { +	case AddrTypeIPv4: +		l += net.IPv4len +		a.IP = make(net.IP, net.IPv4len) +	case AddrTypeIPv6: +		l += net.IPv6len +		a.IP = make(net.IP, net.IPv6len) +	case AddrTypeFQDN: +		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 splitHostPort(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 +} diff --git a/vendor/golang.org/x/net/internal/socks/socks.go b/vendor/golang.org/x/net/internal/socks/socks.go new file mode 100644 index 000000000..84fcc32b6 --- /dev/null +++ b/vendor/golang.org/x/net/internal/socks/socks.go @@ -0,0 +1,317 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// 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 socks + +import ( +	"context" +	"errors" +	"io" +	"net" +	"strconv" +) + +// A Command represents a SOCKS command. +type Command int + +func (cmd Command) String() string { +	switch cmd { +	case CmdConnect: +		return "socks connect" +	case cmdBind: +		return "socks bind" +	default: +		return "socks " + strconv.Itoa(int(cmd)) +	} +} + +// An AuthMethod represents a SOCKS authentication method. +type AuthMethod int + +// A Reply represents a SOCKS command reply code. +type Reply int + +func (code Reply) String() string { +	switch code { +	case StatusSucceeded: +		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 ( +	Version5 = 0x05 + +	AddrTypeIPv4 = 0x01 +	AddrTypeFQDN = 0x03 +	AddrTypeIPv6 = 0x04 + +	CmdConnect Command = 0x01 // establishes an active-open forward proxy connection +	cmdBind    Command = 0x02 // establishes a passive-open forward proxy connection + +	AuthMethodNotRequired         AuthMethod = 0x00 // no authentication required +	AuthMethodUsernamePassword    AuthMethod = 0x02 // use username/password +	AuthMethodNoAcceptableMethods AuthMethod = 0xff // no acceptable authentication methods + +	StatusSucceeded Reply = 0x00 +) + +// An Addr represents a SOCKS-specific address. +// Either Name or IP is used exclusively. +type Addr struct { +	Name string // fully-qualified domain name +	IP   net.IP +	Port int +} + +func (a *Addr) Network() string { return "socks" } + +func (a *Addr) 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 Conn 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 *Conn) BoundAddr() net.Addr { +	if c == nil { +		return nil +	} +	return c.boundAddr +} + +// A Dialer holds SOCKS-specific options. +type Dialer struct { +	cmd          Command // 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 []AuthMethod + +	// 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, AuthMethod) 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 *Dialer) 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 &Conn{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 *Dialer) 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 *Dialer) 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 { +		c.Close() +		return nil, err +	} +	return c, nil +} + +func (d *Dialer) validateTarget(network, address string) error { +	switch network { +	case "tcp", "tcp6", "tcp4": +	default: +		return errors.New("network not implemented") +	} +	switch d.cmd { +	case CmdConnect, cmdBind: +	default: +		return errors.New("command not implemented") +	} +	return nil +} + +func (d *Dialer) pathAddrs(address string) (proxy, dst net.Addr, err error) { +	for i, s := range []string{d.proxyAddress, address} { +		host, port, err := splitHostPort(s) +		if err != nil { +			return nil, nil, err +		} +		a := &Addr{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 NewDialer(network, address string) *Dialer { +	return &Dialer{proxyNetwork: network, proxyAddress: address, cmd: CmdConnect} +} + +const ( +	authUsernamePasswordVersion = 0x01 +	authStatusSucceeded         = 0x00 +) + +// UsernamePassword are the credentials for the username/password +// authentication method. +type UsernamePassword struct { +	Username string +	Password string +} + +// Authenticate authenticates a pair of username and password with the +// proxy server. +func (up *UsernamePassword) Authenticate(ctx context.Context, rw io.ReadWriter, auth AuthMethod) error { +	switch auth { +	case AuthMethodNotRequired: +		return nil +	case AuthMethodUsernamePassword: +		if len(up.Username) == 0 || len(up.Username) > 255 || len(up.Password) > 255 { +			return errors.New("invalid username/password") +		} +		b := []byte{authUsernamePasswordVersion} +		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] != authUsernamePasswordVersion { +			return errors.New("invalid username/password version") +		} +		if b[1] != authStatusSucceeded { +			return errors.New("username/password authentication failed") +		} +		return nil +	} +	return errors.New("unsupported authentication method " + strconv.Itoa(int(auth))) +} diff --git a/vendor/golang.org/x/net/proxy/dial.go b/vendor/golang.org/x/net/proxy/dial.go new file mode 100644 index 000000000..811c2e4e9 --- /dev/null +++ b/vendor/golang.org/x/net/proxy/dial.go @@ -0,0 +1,54 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package proxy + +import ( +	"context" +	"net" +) + +// A ContextDialer dials using a context. +type ContextDialer interface { +	DialContext(ctx context.Context, network, address string) (net.Conn, error) +} + +// Dial works like DialContext on net.Dialer but using a dialer returned by FromEnvironment. +// +// The passed ctx is only used for returning the Conn, not the lifetime of the Conn. +// +// Custom dialers (registered via RegisterDialerType) that do not implement ContextDialer +// can leak a goroutine for as long as it takes the underlying Dialer implementation to timeout. +// +// A Conn returned from a successful Dial after the context has been cancelled will be immediately closed. +func Dial(ctx context.Context, network, address string) (net.Conn, error) { +	d := FromEnvironment() +	if xd, ok := d.(ContextDialer); ok { +		return xd.DialContext(ctx, network, address) +	} +	return dialContext(ctx, d, network, address) +} + +// WARNING: this can leak a goroutine for as long as the underlying Dialer implementation takes to timeout +// A Conn returned from a successful Dial after the context has been cancelled will be immediately closed. +func dialContext(ctx context.Context, d Dialer, network, address string) (net.Conn, error) { +	var ( +		conn net.Conn +		done = make(chan struct{}, 1) +		err  error +	) +	go func() { +		conn, err = d.Dial(network, address) +		close(done) +		if conn != nil && ctx.Err() != nil { +			conn.Close() +		} +	}() +	select { +	case <-ctx.Done(): +		err = ctx.Err() +	case <-done: +	} +	return conn, err +} diff --git a/vendor/golang.org/x/net/proxy/direct.go b/vendor/golang.org/x/net/proxy/direct.go new file mode 100644 index 000000000..3d66bdef9 --- /dev/null +++ b/vendor/golang.org/x/net/proxy/direct.go @@ -0,0 +1,31 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package proxy + +import ( +	"context" +	"net" +) + +type direct struct{} + +// Direct implements Dialer by making network connections directly using net.Dial or net.DialContext. +var Direct = direct{} + +var ( +	_ Dialer        = Direct +	_ ContextDialer = Direct +) + +// Dial directly invokes net.Dial with the supplied parameters. +func (direct) Dial(network, addr string) (net.Conn, error) { +	return net.Dial(network, addr) +} + +// DialContext instantiates a net.Dialer and invokes its DialContext receiver with the supplied parameters. +func (direct) DialContext(ctx context.Context, network, addr string) (net.Conn, error) { +	var d net.Dialer +	return d.DialContext(ctx, network, addr) +} diff --git a/vendor/golang.org/x/net/proxy/per_host.go b/vendor/golang.org/x/net/proxy/per_host.go new file mode 100644 index 000000000..573fe79e8 --- /dev/null +++ b/vendor/golang.org/x/net/proxy/per_host.go @@ -0,0 +1,155 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package proxy + +import ( +	"context" +	"net" +	"strings" +) + +// A PerHost directs connections to a default Dialer unless the host name +// requested matches one of a number of exceptions. +type PerHost struct { +	def, bypass Dialer + +	bypassNetworks []*net.IPNet +	bypassIPs      []net.IP +	bypassZones    []string +	bypassHosts    []string +} + +// NewPerHost returns a PerHost Dialer that directs connections to either +// defaultDialer or bypass, depending on whether the connection matches one of +// the configured rules. +func NewPerHost(defaultDialer, bypass Dialer) *PerHost { +	return &PerHost{ +		def:    defaultDialer, +		bypass: bypass, +	} +} + +// Dial connects to the address addr on the given network through either +// defaultDialer or bypass. +func (p *PerHost) Dial(network, addr string) (c net.Conn, err error) { +	host, _, err := net.SplitHostPort(addr) +	if err != nil { +		return nil, err +	} + +	return p.dialerForRequest(host).Dial(network, addr) +} + +// DialContext connects to the address addr on the given network through either +// defaultDialer or bypass. +func (p *PerHost) DialContext(ctx context.Context, network, addr string) (c net.Conn, err error) { +	host, _, err := net.SplitHostPort(addr) +	if err != nil { +		return nil, err +	} +	d := p.dialerForRequest(host) +	if x, ok := d.(ContextDialer); ok { +		return x.DialContext(ctx, network, addr) +	} +	return dialContext(ctx, d, network, addr) +} + +func (p *PerHost) dialerForRequest(host string) Dialer { +	if ip := net.ParseIP(host); ip != nil { +		for _, net := range p.bypassNetworks { +			if net.Contains(ip) { +				return p.bypass +			} +		} +		for _, bypassIP := range p.bypassIPs { +			if bypassIP.Equal(ip) { +				return p.bypass +			} +		} +		return p.def +	} + +	for _, zone := range p.bypassZones { +		if strings.HasSuffix(host, zone) { +			return p.bypass +		} +		if host == zone[1:] { +			// For a zone ".example.com", we match "example.com" +			// too. +			return p.bypass +		} +	} +	for _, bypassHost := range p.bypassHosts { +		if bypassHost == host { +			return p.bypass +		} +	} +	return p.def +} + +// AddFromString parses a string that contains comma-separated values +// specifying hosts that should use the bypass proxy. Each value is either an +// IP address, a CIDR range, a zone (*.example.com) or a host name +// (localhost). A best effort is made to parse the string and errors are +// ignored. +func (p *PerHost) AddFromString(s string) { +	hosts := strings.Split(s, ",") +	for _, host := range hosts { +		host = strings.TrimSpace(host) +		if len(host) == 0 { +			continue +		} +		if strings.Contains(host, "/") { +			// We assume that it's a CIDR address like 127.0.0.0/8 +			if _, net, err := net.ParseCIDR(host); err == nil { +				p.AddNetwork(net) +			} +			continue +		} +		if ip := net.ParseIP(host); ip != nil { +			p.AddIP(ip) +			continue +		} +		if strings.HasPrefix(host, "*.") { +			p.AddZone(host[1:]) +			continue +		} +		p.AddHost(host) +	} +} + +// AddIP specifies an IP address that will use the bypass proxy. Note that +// this will only take effect if a literal IP address is dialed. A connection +// to a named host will never match an IP. +func (p *PerHost) AddIP(ip net.IP) { +	p.bypassIPs = append(p.bypassIPs, ip) +} + +// AddNetwork specifies an IP range that will use the bypass proxy. Note that +// this will only take effect if a literal IP address is dialed. A connection +// to a named host will never match. +func (p *PerHost) AddNetwork(net *net.IPNet) { +	p.bypassNetworks = append(p.bypassNetworks, net) +} + +// AddZone specifies a DNS suffix that will use the bypass proxy. A zone of +// "example.com" matches "example.com" and all of its subdomains. +func (p *PerHost) AddZone(zone string) { +	if strings.HasSuffix(zone, ".") { +		zone = zone[:len(zone)-1] +	} +	if !strings.HasPrefix(zone, ".") { +		zone = "." + zone +	} +	p.bypassZones = append(p.bypassZones, zone) +} + +// AddHost specifies a host name that will use the bypass proxy. +func (p *PerHost) AddHost(host string) { +	if strings.HasSuffix(host, ".") { +		host = host[:len(host)-1] +	} +	p.bypassHosts = append(p.bypassHosts, host) +} diff --git a/vendor/golang.org/x/net/proxy/proxy.go b/vendor/golang.org/x/net/proxy/proxy.go new file mode 100644 index 000000000..9ff4b9a77 --- /dev/null +++ b/vendor/golang.org/x/net/proxy/proxy.go @@ -0,0 +1,149 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package proxy provides support for a variety of protocols to proxy network +// data. +package proxy // import "golang.org/x/net/proxy" + +import ( +	"errors" +	"net" +	"net/url" +	"os" +	"sync" +) + +// A Dialer is a means to establish a connection. +// Custom dialers should also implement ContextDialer. +type Dialer interface { +	// Dial connects to the given address via the proxy. +	Dial(network, addr string) (c net.Conn, err error) +} + +// Auth contains authentication parameters that specific Dialers may require. +type Auth struct { +	User, Password string +} + +// FromEnvironment returns the dialer specified by the proxy-related +// variables in the environment and makes underlying connections +// directly. +func FromEnvironment() Dialer { +	return FromEnvironmentUsing(Direct) +} + +// FromEnvironmentUsing returns the dialer specify by the proxy-related +// variables in the environment and makes underlying connections +// using the provided forwarding Dialer (for instance, a *net.Dialer +// with desired configuration). +func FromEnvironmentUsing(forward Dialer) Dialer { +	allProxy := allProxyEnv.Get() +	if len(allProxy) == 0 { +		return forward +	} + +	proxyURL, err := url.Parse(allProxy) +	if err != nil { +		return forward +	} +	proxy, err := FromURL(proxyURL, forward) +	if err != nil { +		return forward +	} + +	noProxy := noProxyEnv.Get() +	if len(noProxy) == 0 { +		return proxy +	} + +	perHost := NewPerHost(proxy, forward) +	perHost.AddFromString(noProxy) +	return perHost +} + +// proxySchemes is a map from URL schemes to a function that creates a Dialer +// from a URL with such a scheme. +var proxySchemes map[string]func(*url.URL, Dialer) (Dialer, error) + +// RegisterDialerType takes a URL scheme and a function to generate Dialers from +// a URL with that scheme and a forwarding Dialer. Registered schemes are used +// by FromURL. +func RegisterDialerType(scheme string, f func(*url.URL, Dialer) (Dialer, error)) { +	if proxySchemes == nil { +		proxySchemes = make(map[string]func(*url.URL, Dialer) (Dialer, error)) +	} +	proxySchemes[scheme] = f +} + +// FromURL returns a Dialer given a URL specification and an underlying +// Dialer for it to make network requests. +func FromURL(u *url.URL, forward Dialer) (Dialer, error) { +	var auth *Auth +	if u.User != nil { +		auth = new(Auth) +		auth.User = u.User.Username() +		if p, ok := u.User.Password(); ok { +			auth.Password = p +		} +	} + +	switch u.Scheme { +	case "socks5", "socks5h": +		addr := u.Hostname() +		port := u.Port() +		if port == "" { +			port = "1080" +		} +		return SOCKS5("tcp", net.JoinHostPort(addr, port), auth, forward) +	} + +	// If the scheme doesn't match any of the built-in schemes, see if it +	// was registered by another package. +	if proxySchemes != nil { +		if f, ok := proxySchemes[u.Scheme]; ok { +			return f(u, forward) +		} +	} + +	return nil, errors.New("proxy: unknown scheme: " + u.Scheme) +} + +var ( +	allProxyEnv = &envOnce{ +		names: []string{"ALL_PROXY", "all_proxy"}, +	} +	noProxyEnv = &envOnce{ +		names: []string{"NO_PROXY", "no_proxy"}, +	} +) + +// envOnce looks up an environment variable (optionally by multiple +// names) once. It mitigates expensive lookups on some platforms +// (e.g. Windows). +// (Borrowed from net/http/transport.go) +type envOnce struct { +	names []string +	once  sync.Once +	val   string +} + +func (e *envOnce) Get() string { +	e.once.Do(e.init) +	return e.val +} + +func (e *envOnce) init() { +	for _, n := range e.names { +		e.val = os.Getenv(n) +		if e.val != "" { +			return +		} +	} +} + +// reset is used by tests +func (e *envOnce) reset() { +	e.once = sync.Once{} +	e.val = "" +} diff --git a/vendor/golang.org/x/net/proxy/socks5.go b/vendor/golang.org/x/net/proxy/socks5.go new file mode 100644 index 000000000..c91651f96 --- /dev/null +++ b/vendor/golang.org/x/net/proxy/socks5.go @@ -0,0 +1,42 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package proxy + +import ( +	"context" +	"net" + +	"golang.org/x/net/internal/socks" +) + +// SOCKS5 returns a Dialer that makes SOCKSv5 connections to the given +// address with an optional username and password. +// See RFC 1928 and RFC 1929. +func SOCKS5(network, address string, auth *Auth, forward Dialer) (Dialer, error) { +	d := socks.NewDialer(network, address) +	if forward != nil { +		if f, ok := forward.(ContextDialer); ok { +			d.ProxyDial = func(ctx context.Context, network string, address string) (net.Conn, error) { +				return f.DialContext(ctx, network, address) +			} +		} else { +			d.ProxyDial = func(ctx context.Context, network string, address string) (net.Conn, error) { +				return dialContext(ctx, forward, network, address) +			} +		} +	} +	if auth != nil { +		up := socks.UsernamePassword{ +			Username: auth.User, +			Password: auth.Password, +		} +		d.AuthMethods = []socks.AuthMethod{ +			socks.AuthMethodNotRequired, +			socks.AuthMethodUsernamePassword, +		} +		d.Authenticate = up.Authenticate +	} +	return d, nil +}  | 
