Mikio Hara has uploaded this change for review.
net/http: replace SOCKS client implementation
DO NOT SUBMIT
UNTIL CL 38278 LANDS
This change replaces the vendored socks client implementation with the
golang.org/x/net/internal/socks package which contains fixes for 19354
and 11682.
golang.org/x/net/internal/socks becomes vendor/golang_org/x/net/socks.
At git rev NNNNNN.
Updates #18508.
Updates #19354.
Fixes #19688.
Change-Id: I8cf6c3f5eb87c24685a7592be015729f84fbed77
---
M src/go/build/deps_test.go
M src/net/http/transport.go
M src/net/http/transport_test.go
D src/vendor/golang_org/x/net/proxy/direct.go
D src/vendor/golang_org/x/net/proxy/per_host.go
D src/vendor/golang_org/x/net/proxy/per_host_test.go
D src/vendor/golang_org/x/net/proxy/proxy.go
D src/vendor/golang_org/x/net/proxy/proxy_test.go
D src/vendor/golang_org/x/net/proxy/socks5.go
A src/vendor/golang_org/x/net/socks/client.go
A src/vendor/golang_org/x/net/socks/dial_test.go
A src/vendor/golang_org/x/net/socks/socks.go
12 files changed, 679 insertions(+), 692 deletions(-)
diff --git a/src/go/build/deps_test.go b/src/go/build/deps_test.go
index c197489..b95a77f 100644
--- a/src/go/build/deps_test.go
+++ b/src/go/build/deps_test.go
@@ -394,7 +394,7 @@
"golang_org/x/net/http2/hpack",
"golang_org/x/net/idna",
"golang_org/x/net/lex/httplex",
- "golang_org/x/net/proxy",
+ "golang_org/x/net/socks",
"golang_org/x/text/unicode/norm",
"golang_org/x/text/width",
"internal/nettrace",
diff --git a/src/net/http/transport.go b/src/net/http/transport.go
index 425db36..2e9a20e 100644
--- a/src/net/http/transport.go
+++ b/src/net/http/transport.go
@@ -29,7 +29,7 @@
"time"
"golang_org/x/net/lex/httplex"
- "golang_org/x/net/proxy"
+ "golang_org/x/net/socks"
)
// DefaultTransport is the default implementation of Transport and is
@@ -981,23 +981,6 @@
}
}
-type oneConnDialer <-chan net.Conn
-
-func newOneConnDialer(c net.Conn) proxy.Dialer {
- ch := make(chan net.Conn, 1)
- ch <- c
- return oneConnDialer(ch)
-}
-
-func (d oneConnDialer) Dial(network, addr string) (net.Conn, error) {
- select {
- case c := <-d:
- return c, nil
- default:
- return nil, io.EOF
- }
-}
-
func (t *Transport) dialConn(ctx context.Context, cm connectMethod) (*persistConn, error) {
pconn := &persistConn{
t: t,
@@ -1056,18 +1039,26 @@
// Do nothing. Not using a proxy.
case cm.proxyURL.Scheme == "socks5":
conn := pconn.conn
- var auth *proxy.Auth
- if u := cm.proxyURL.User; u != nil {
- auth = &proxy.Auth{}
- auth.User = u.Username()
- auth.Password, _ = u.Password()
- }
- p, err := proxy.SOCKS5("", cm.addr(), auth, newOneConnDialer(conn))
+ d, err := socks.NewDialer("tcp", conn.RemoteAddr().String(), socks.CmdConnect)
if err != nil {
conn.Close()
return nil, err
}
- if _, err := p.Dial("tcp", cm.targetAddr); err != nil {
+ d.ProxyDial = func(_ context.Context, _, _ string) (net.Conn, error) {
+ return conn, nil
+ }
+ if u := cm.proxyURL.User; u != nil {
+ auth := &socks.UsernamePassword{
+ Username: u.Username(),
+ }
+ auth.Password, _ = u.Password()
+ d.AuthMethods = []socks.AuthMethod{
+ socks.AuthMethodNotRequired,
+ socks.AuthMethodUsernamePassword,
+ }
+ d.Authenticate = auth.Authenticate
+ }
+ if _, err := d.DialContext(ctx, "tcp", cm.targetAddr); err != nil {
conn.Close()
return nil, err
}
diff --git a/src/net/http/transport_test.go b/src/net/http/transport_test.go
index 8e211aa..e97100a 100644
--- a/src/net/http/transport_test.go
+++ b/src/net/http/transport_test.go
@@ -930,7 +930,7 @@
}
}
-func TestSocks5Proxy(t *testing.T) {
+func TestSOCKS5Proxy(t *testing.T) {
defer afterTest(t)
ch := make(chan string, 1)
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
@@ -971,9 +971,9 @@
var ipLen int
switch buf[3] {
case 1:
- ipLen = 4
+ ipLen = net.IPv4len
case 4:
- ipLen = 16
+ ipLen = net.IPv6len
default:
t.Fatalf("socks5 proxy second read: unexpected address type %v", buf[4])
}
diff --git a/src/vendor/golang_org/x/net/proxy/direct.go b/src/vendor/golang_org/x/net/proxy/direct.go
deleted file mode 100644
index 4c5ad88..0000000
--- a/src/vendor/golang_org/x/net/proxy/direct.go
+++ /dev/null
@@ -1,18 +0,0 @@
-// 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 (
- "net"
-)
-
-type direct struct{}
-
-// Direct is a direct proxy: one that makes network connections directly.
-var Direct = direct{}
-
-func (direct) Dial(network, addr string) (net.Conn, error) {
- return net.Dial(network, addr)
-}
diff --git a/src/vendor/golang_org/x/net/proxy/per_host.go b/src/vendor/golang_org/x/net/proxy/per_host.go
deleted file mode 100644
index f540b19..0000000
--- a/src/vendor/golang_org/x/net/proxy/per_host.go
+++ /dev/null
@@ -1,140 +0,0 @@
-// 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 (
- "net"
- "strings"
-)
-
-// A PerHost directs connections to a default Dialer unless the hostname
-// 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)
-}
-
-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 hostname
-// (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 hostname 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/src/vendor/golang_org/x/net/proxy/per_host_test.go b/src/vendor/golang_org/x/net/proxy/per_host_test.go
deleted file mode 100644
index a7d8095..0000000
--- a/src/vendor/golang_org/x/net/proxy/per_host_test.go
+++ /dev/null
@@ -1,55 +0,0 @@
-// 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 (
- "errors"
- "net"
- "reflect"
- "testing"
-)
-
-type recordingProxy struct {
- addrs []string
-}
-
-func (r *recordingProxy) Dial(network, addr string) (net.Conn, error) {
- r.addrs = append(r.addrs, addr)
- return nil, errors.New("recordingProxy")
-}
-
-func TestPerHost(t *testing.T) {
- var def, bypass recordingProxy
- perHost := NewPerHost(&def, &bypass)
- perHost.AddFromString("localhost,*.zone,127.0.0.1,10.0.0.1/8,1000::/16")
-
- expectedDef := []string{
- "example.com:123",
- "1.2.3.4:123",
- "[1001::]:123",
- }
- expectedBypass := []string{
- "localhost:123",
- "zone:123",
- "foo.zone:123",
- "127.0.0.1:123",
- "10.1.2.3:123",
- "[1000::]:123",
- }
-
- for _, addr := range expectedDef {
- perHost.Dial("tcp", addr)
- }
- for _, addr := range expectedBypass {
- perHost.Dial("tcp", addr)
- }
-
- if !reflect.DeepEqual(expectedDef, def.addrs) {
- t.Errorf("Hosts which went to the default proxy didn't match. Got %v, want %v", def.addrs, expectedDef)
- }
- if !reflect.DeepEqual(expectedBypass, bypass.addrs) {
- t.Errorf("Hosts which went to the bypass proxy didn't match. Got %v, want %v", bypass.addrs, expectedBypass)
- }
-}
diff --git a/src/vendor/golang_org/x/net/proxy/proxy.go b/src/vendor/golang_org/x/net/proxy/proxy.go
deleted file mode 100644
index 78a8b7b..0000000
--- a/src/vendor/golang_org/x/net/proxy/proxy.go
+++ /dev/null
@@ -1,94 +0,0 @@
-// 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"
-)
-
-// A Dialer is a means to establish a connection.
-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.
-func FromEnvironment() Dialer {
- allProxy := os.Getenv("all_proxy")
- if len(allProxy) == 0 {
- return Direct
- }
-
- proxyURL, err := url.Parse(allProxy)
- if err != nil {
- return Direct
- }
- proxy, err := FromURL(proxyURL, Direct)
- if err != nil {
- return Direct
- }
-
- noProxy := os.Getenv("no_proxy")
- if len(noProxy) == 0 {
- return proxy
- }
-
- perHost := NewPerHost(proxy, Direct)
- 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":
- return SOCKS5("tcp", u.Host, 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)
-}
diff --git a/src/vendor/golang_org/x/net/proxy/proxy_test.go b/src/vendor/golang_org/x/net/proxy/proxy_test.go
deleted file mode 100644
index c19a5c0..0000000
--- a/src/vendor/golang_org/x/net/proxy/proxy_test.go
+++ /dev/null
@@ -1,142 +0,0 @@
-// 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 (
- "io"
- "net"
- "net/url"
- "strconv"
- "sync"
- "testing"
-)
-
-func TestFromURL(t *testing.T) {
- endSystem, err := net.Listen("tcp", "127.0.0.1:0")
- if err != nil {
- t.Fatalf("net.Listen failed: %v", err)
- }
- defer endSystem.Close()
- gateway, err := net.Listen("tcp", "127.0.0.1:0")
- if err != nil {
- t.Fatalf("net.Listen failed: %v", err)
- }
- defer gateway.Close()
-
- var wg sync.WaitGroup
- wg.Add(1)
- go socks5Gateway(t, gateway, endSystem, socks5Domain, &wg)
-
- url, err := url.Parse("socks5://user:password@" + gateway.Addr().String())
- if err != nil {
- t.Fatalf("url.Parse failed: %v", err)
- }
- proxy, err := FromURL(url, Direct)
- if err != nil {
- t.Fatalf("FromURL failed: %v", err)
- }
- _, port, err := net.SplitHostPort(endSystem.Addr().String())
- if err != nil {
- t.Fatalf("net.SplitHostPort failed: %v", err)
- }
- if c, err := proxy.Dial("tcp", "localhost:"+port); err != nil {
- t.Fatalf("FromURL.Dial failed: %v", err)
- } else {
- c.Close()
- }
-
- wg.Wait()
-}
-
-func TestSOCKS5(t *testing.T) {
- endSystem, err := net.Listen("tcp", "127.0.0.1:0")
- if err != nil {
- t.Fatalf("net.Listen failed: %v", err)
- }
- defer endSystem.Close()
- gateway, err := net.Listen("tcp", "127.0.0.1:0")
- if err != nil {
- t.Fatalf("net.Listen failed: %v", err)
- }
- defer gateway.Close()
-
- var wg sync.WaitGroup
- wg.Add(1)
- go socks5Gateway(t, gateway, endSystem, socks5IP4, &wg)
-
- proxy, err := SOCKS5("tcp", gateway.Addr().String(), nil, Direct)
- if err != nil {
- t.Fatalf("SOCKS5 failed: %v", err)
- }
- if c, err := proxy.Dial("tcp", endSystem.Addr().String()); err != nil {
- t.Fatalf("SOCKS5.Dial failed: %v", err)
- } else {
- c.Close()
- }
-
- wg.Wait()
-}
-
-func socks5Gateway(t *testing.T, gateway, endSystem net.Listener, typ byte, wg *sync.WaitGroup) {
- defer wg.Done()
-
- c, err := gateway.Accept()
- if err != nil {
- t.Errorf("net.Listener.Accept failed: %v", err)
- return
- }
- defer c.Close()
-
- b := make([]byte, 32)
- var n int
- if typ == socks5Domain {
- n = 4
- } else {
- n = 3
- }
- if _, err := io.ReadFull(c, b[:n]); err != nil {
- t.Errorf("io.ReadFull failed: %v", err)
- return
- }
- if _, err := c.Write([]byte{socks5Version, socks5AuthNone}); err != nil {
- t.Errorf("net.Conn.Write failed: %v", err)
- return
- }
- if typ == socks5Domain {
- n = 16
- } else {
- n = 10
- }
- if _, err := io.ReadFull(c, b[:n]); err != nil {
- t.Errorf("io.ReadFull failed: %v", err)
- return
- }
- if b[0] != socks5Version || b[1] != socks5Connect || b[2] != 0x00 || b[3] != typ {
- t.Errorf("got an unexpected packet: %#02x %#02x %#02x %#02x", b[0], b[1], b[2], b[3])
- return
- }
- if typ == socks5Domain {
- copy(b[:5], []byte{socks5Version, 0x00, 0x00, socks5Domain, 9})
- b = append(b, []byte("localhost")...)
- } else {
- copy(b[:4], []byte{socks5Version, 0x00, 0x00, socks5IP4})
- }
- host, port, err := net.SplitHostPort(endSystem.Addr().String())
- if err != nil {
- t.Errorf("net.SplitHostPort failed: %v", err)
- return
- }
- b = append(b, []byte(net.ParseIP(host).To4())...)
- p, err := strconv.Atoi(port)
- if err != nil {
- t.Errorf("strconv.Atoi failed: %v", err)
- return
- }
- b = append(b, []byte{byte(p >> 8), byte(p)}...)
- if _, err := c.Write(b); err != nil {
- t.Errorf("net.Conn.Write failed: %v", err)
- return
- }
-}
diff --git a/src/vendor/golang_org/x/net/proxy/socks5.go b/src/vendor/golang_org/x/net/proxy/socks5.go
deleted file mode 100644
index 973f57f..0000000
--- a/src/vendor/golang_org/x/net/proxy/socks5.go
+++ /dev/null
@@ -1,213 +0,0 @@
-// 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 (
- "errors"
- "io"
- "net"
- "strconv"
-)
-
-// SOCKS5 returns a Dialer that makes SOCKSv5 connections to the given address
-// with an optional username and password. See RFC 1928.
-func SOCKS5(network, addr string, auth *Auth, forward Dialer) (Dialer, error) {
- s := &socks5{
- network: network,
- addr: addr,
- forward: forward,
- }
- if auth != nil {
- s.user = auth.User
- s.password = auth.Password
- }
-
- return s, nil
-}
-
-type socks5 struct {
- user, password string
- network, addr string
- forward Dialer
-}
-
-const socks5Version = 5
-
-const (
- socks5AuthNone = 0
- socks5AuthPassword = 2
-)
-
-const socks5Connect = 1
-
-const (
- socks5IP4 = 1
- socks5Domain = 3
- socks5IP6 = 4
-)
-
-var socks5Errors = []string{
- "",
- "general failure",
- "connection forbidden",
- "network unreachable",
- "host unreachable",
- "connection refused",
- "TTL expired",
- "command not supported",
- "address type not supported",
-}
-
-// Dial connects to the address addr on the network net via the SOCKS5 proxy.
-func (s *socks5) Dial(network, addr string) (net.Conn, error) {
- switch network {
- case "tcp", "tcp6", "tcp4":
- default:
- return nil, errors.New("proxy: no support for SOCKS5 proxy connections of type " + network)
- }
-
- conn, err := s.forward.Dial(s.network, s.addr)
- if err != nil {
- return nil, err
- }
- if err := s.connect(conn, addr); err != nil {
- conn.Close()
- return nil, err
- }
- return conn, nil
-}
-
-// connect takes an existing connection to a socks5 proxy server,
-// and commands the server to extend that connection to target,
-// which must be a canonical address with a host and port.
-func (s *socks5) connect(conn net.Conn, target string) error {
- host, portStr, err := net.SplitHostPort(target)
- if err != nil {
- return err
- }
-
- port, err := strconv.Atoi(portStr)
- if err != nil {
- return errors.New("proxy: failed to parse port number: " + portStr)
- }
- if port < 1 || port > 0xffff {
- return errors.New("proxy: port number out of range: " + portStr)
- }
-
- // the size here is just an estimate
- buf := make([]byte, 0, 6+len(host))
-
- buf = append(buf, socks5Version)
- if len(s.user) > 0 && len(s.user) < 256 && len(s.password) < 256 {
- buf = append(buf, 2 /* num auth methods */, socks5AuthNone, socks5AuthPassword)
- } else {
- buf = append(buf, 1 /* num auth methods */, socks5AuthNone)
- }
-
- if _, err := conn.Write(buf); err != nil {
- return errors.New("proxy: failed to write greeting to SOCKS5 proxy at " + s.addr + ": " + err.Error())
- }
-
- if _, err := io.ReadFull(conn, buf[:2]); err != nil {
- return errors.New("proxy: failed to read greeting from SOCKS5 proxy at " + s.addr + ": " + err.Error())
- }
- if buf[0] != 5 {
- return errors.New("proxy: SOCKS5 proxy at " + s.addr + " has unexpected version " + strconv.Itoa(int(buf[0])))
- }
- if buf[1] == 0xff {
- return errors.New("proxy: SOCKS5 proxy at " + s.addr + " requires authentication")
- }
-
- if buf[1] == socks5AuthPassword {
- buf = buf[:0]
- buf = append(buf, 1 /* password protocol version */)
- buf = append(buf, uint8(len(s.user)))
- buf = append(buf, s.user...)
- buf = append(buf, uint8(len(s.password)))
- buf = append(buf, s.password...)
-
- if _, err := conn.Write(buf); err != nil {
- return errors.New("proxy: failed to write authentication request to SOCKS5 proxy at " + s.addr + ": " + err.Error())
- }
-
- if _, err := io.ReadFull(conn, buf[:2]); err != nil {
- return errors.New("proxy: failed to read authentication reply from SOCKS5 proxy at " + s.addr + ": " + err.Error())
- }
-
- if buf[1] != 0 {
- return errors.New("proxy: SOCKS5 proxy at " + s.addr + " rejected username/password")
- }
- }
-
- buf = buf[:0]
- buf = append(buf, socks5Version, socks5Connect, 0 /* reserved */)
-
- if ip := net.ParseIP(host); ip != nil {
- if ip4 := ip.To4(); ip4 != nil {
- buf = append(buf, socks5IP4)
- ip = ip4
- } else {
- buf = append(buf, socks5IP6)
- }
- buf = append(buf, ip...)
- } else {
- if len(host) > 255 {
- return errors.New("proxy: destination hostname too long: " + host)
- }
- buf = append(buf, socks5Domain)
- buf = append(buf, byte(len(host)))
- buf = append(buf, host...)
- }
- buf = append(buf, byte(port>>8), byte(port))
-
- if _, err := conn.Write(buf); err != nil {
- return errors.New("proxy: failed to write connect request to SOCKS5 proxy at " + s.addr + ": " + err.Error())
- }
-
- if _, err := io.ReadFull(conn, buf[:4]); err != nil {
- return errors.New("proxy: failed to read connect reply from SOCKS5 proxy at " + s.addr + ": " + err.Error())
- }
-
- failure := "unknown error"
- if int(buf[1]) < len(socks5Errors) {
- failure = socks5Errors[buf[1]]
- }
-
- if len(failure) > 0 {
- return errors.New("proxy: SOCKS5 proxy at " + s.addr + " failed to connect: " + failure)
- }
-
- bytesToDiscard := 0
- switch buf[3] {
- case socks5IP4:
- bytesToDiscard = net.IPv4len
- case socks5IP6:
- bytesToDiscard = net.IPv6len
- case socks5Domain:
- _, err := io.ReadFull(conn, buf[:1])
- if err != nil {
- return errors.New("proxy: failed to read domain length from SOCKS5 proxy at " + s.addr + ": " + err.Error())
- }
- bytesToDiscard = int(buf[0])
- default:
- return errors.New("proxy: got unknown address type " + strconv.Itoa(int(buf[3])) + " from SOCKS5 proxy at " + s.addr)
- }
-
- if cap(buf) < bytesToDiscard {
- buf = make([]byte, bytesToDiscard)
- } else {
- buf = buf[:bytesToDiscard]
- }
- if _, err := io.ReadFull(conn, buf); err != nil {
- return errors.New("proxy: failed to read address from SOCKS5 proxy at " + s.addr + ": " + err.Error())
- }
-
- // Also need to discard the port number
- if _, err := io.ReadFull(conn, buf[:2]); err != nil {
- return errors.New("proxy: failed to read port from SOCKS5 proxy at " + s.addr + ": " + err.Error())
- }
-
- return nil
-}
diff --git a/src/vendor/golang_org/x/net/socks/client.go b/src/vendor/golang_org/x/net/socks/client.go
new file mode 100644
index 0000000..795fe80
--- /dev/null
+++ b/src/vendor/golang_org/x/net/socks/client.go
@@ -0,0 +1,185 @@
+// Copyright 2017 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, 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)
+ }
+ ctxErrCh := make(chan error, 1)
+ ctxErr := func() error {
+ if ctx != context.Background() {
+ if err, ok := <-ctxErrCh; ok && err != nil {
+ return err
+ }
+ }
+ return nil
+ }
+ if ctx != context.Background() {
+ done := make(chan struct{})
+ go func() {
+ select {
+ case <-ctx.Done():
+ ctxErrCh <- ctx.Err()
+ c.SetDeadline(aLongTimeAgo)
+ case <-done:
+ }
+ }()
+ }
+
+ b := make([]byte, 0, 6+len(host)) // the size here is just an estimate
+ b = append(b, protocolVersion5)
+ if len(d.AuthMethods) == 0 || d.Authenticate == nil {
+ b = append(b, 1, byte(AuthMethodNotRequired))
+ } else {
+ ams := d.AuthMethods
+ if len(ams) > 255 {
+ ams = ams[:255]
+ }
+ b = append(b, byte(len(ams)))
+ for _, am := range ams {
+ b = append(b, byte(am))
+ }
+ }
+ if _, err := c.Write(b); err != nil {
+ if cerr := ctxErr(); cerr != nil {
+ err = cerr
+ }
+ return nil, err
+ }
+
+ if _, err := io.ReadFull(c, b[:2]); err != nil {
+ if cerr := ctxErr(); cerr != nil {
+ err = cerr
+ }
+ return nil, err
+ }
+ if b[0] != protocolVersion5 {
+ 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 err := d.Authenticate(ctx, c, am); err != nil {
+ if cerr := ctxErr(); cerr != nil {
+ err = cerr
+ }
+ return nil, err
+ }
+ }
+
+ b = b[:0]
+ b = append(b, protocolVersion5, byte(CmdConnect), 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 _, err := c.Write(b); err != nil {
+ if cerr := ctxErr(); cerr != nil {
+ err = cerr
+ }
+ return nil, err
+ }
+
+ if _, err := io.ReadFull(c, b[:4]); err != nil {
+ if cerr := ctxErr(); cerr != nil {
+ err = cerr
+ }
+ return nil, err
+ }
+ cmdErr := int(b[1])
+ if cmdErr != statusSucceeded {
+ if cmdErr < len(cmdErrors) {
+ return nil, errors.New(cmdErrors[cmdErr])
+ }
+ return nil, errors.New("unknown error " + strconv.Itoa(cmdErr))
+ }
+ 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 _, err := io.ReadFull(c, b); err != nil {
+ if cerr := ctxErr(); cerr != nil {
+ err = cerr
+ }
+ return nil, err
+ }
+ 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/src/vendor/golang_org/x/net/socks/dial_test.go b/src/vendor/golang_org/x/net/socks/dial_test.go
new file mode 100644
index 0000000..98e8297
--- /dev/null
+++ b/src/vendor/golang_org/x/net/socks/dial_test.go
@@ -0,0 +1,214 @@
+// Copyright 2017 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"
+ "fmt"
+ "io"
+ "net"
+ "os"
+ "strconv"
+ "sync"
+ "testing"
+ "time"
+)
+
+const (
+ targetHostname = "fqdn.doesnotexist"
+ targetHostIP = "2001:db8::1"
+ targetPort = "5963"
+)
+
+func TestDial(t *testing.T) {
+ var wg sync.WaitGroup
+
+ ln, err := net.Listen("tcp", "127.0.0.1:0")
+ if err != nil {
+ ln, err = net.Listen("tcp", "[::1]:0")
+ }
+ if err != nil {
+ t.Fatal(err)
+ }
+ srvErr := make(chan error, 10)
+ defer func() {
+ ln.Close()
+ wg.Wait()
+ close(srvErr)
+ for {
+ err, ok := <-srvErr
+ if !ok {
+ return
+ }
+ if err != nil {
+ //t.Log(err)
+ }
+ }
+ }()
+
+ t.Run("Connect", func(t *testing.T) {
+ wg.Add(1)
+ go proxyServer(ln, srvErr, &wg)
+ d, err := NewDialer(ln.Addr().Network(), ln.Addr().String(), CmdConnect)
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ d.AuthMethods = []AuthMethod{
+ AuthMethodNotRequired,
+ AuthMethodUsernamePassword,
+ }
+ d.Authenticate = (&UsernamePassword{"username", "password"}).Authenticate
+ dialErr := make(chan error)
+ go func() {
+ c, err := d.Dial(ln.Addr().Network(), net.JoinHostPort(targetHostIP, targetPort))
+ if err == nil {
+ t.Log(c.(*Conn).BoundAddr())
+ c.Close()
+ }
+ dialErr <- err
+ }()
+ if err := <-dialErr; err != nil {
+ t.Error(err)
+ return
+ }
+ })
+ t.Run("Cancel", func(t *testing.T) {
+ wg.Add(1)
+ go blackholeProxyServer(ln, srvErr, &wg)
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+ d, err := NewDialer(ln.Addr().Network(), ln.Addr().String(), CmdConnect)
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ dialErr := make(chan error)
+ go func() {
+ c, err := d.DialContext(ctx, ln.Addr().Network(), net.JoinHostPort(targetHostname, targetPort))
+ if err == nil {
+ c.Close()
+ }
+ dialErr <- err
+ }()
+ cancel()
+ err = <-dialErr
+ if perr, nerr := parseDialError(err); perr != context.Canceled && nerr == nil {
+ t.Errorf("got %v; want context.Canceled or equivalent", err)
+ return
+ }
+ })
+ t.Run("Deadline", func(t *testing.T) {
+ wg.Add(1)
+ go blackholeProxyServer(ln, srvErr, &wg)
+ ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(100*time.Millisecond))
+ defer cancel()
+ d, err := NewDialer(ln.Addr().Network(), ln.Addr().String(), CmdBind)
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ dialErr := make(chan error)
+ go func() {
+ c, err := d.DialContext(ctx, ln.Addr().Network(), net.JoinHostPort(targetHostname, targetPort))
+ if err == nil {
+ c.Close()
+ }
+ dialErr <- err
+ }()
+ err = <-dialErr
+ if perr, nerr := parseDialError(err); perr != context.DeadlineExceeded && nerr == nil {
+ t.Errorf("got %v; want context.DeadlineExceeded or equivalent", err)
+ return
+ }
+ })
+}
+
+func proxyServer(ln net.Listener, ch chan<- error, wg *sync.WaitGroup) {
+ defer wg.Done()
+ c, err := ln.Accept()
+ if err != nil {
+ ch <- err
+ return
+ }
+ defer c.Close()
+ b := make([]byte, 257)
+ if _, err := io.ReadFull(c, b[:2]); err != nil {
+ ch <- err
+ return
+ }
+ io.ReadFull(c, b[:b[1]])
+ b[0] = protocolVersion5
+ b[1] = byte(AuthMethodNotRequired)
+ if _, err := c.Write(b[:2]); err != nil {
+ ch <- err
+ return
+ }
+ if _, err := io.ReadFull(c, b[:6+net.IPv6len]); err != nil {
+ ch <- err
+ return
+ }
+ if b[0] != protocolVersion5 || Command(b[1]) != CmdConnect || b[2] != 0x00 || b[3] != addrTypeIPv6 {
+ ch <- fmt.Errorf("got unexpected message: %#02x %#02x %#02x %#02x", b[0], b[1], b[2], b[3])
+ return
+ }
+ b = b[:0]
+ b = append(b, protocolVersion5, statusSucceeded, 0x00, addrTypeIPv6)
+ b = append(b, net.ParseIP(targetHostIP)...)
+ port, err := strconv.Atoi(targetPort)
+ if err != nil {
+ ch <- err
+ return
+ }
+ b = append(b, byte(port>>8), byte(port))
+ if _, err := c.Write(b); err != nil {
+ ch <- err
+ return
+ }
+}
+
+func blackholeProxyServer(ln net.Listener, ch chan<- error, wg *sync.WaitGroup) {
+ defer wg.Done()
+ c, err := ln.Accept()
+ if err != nil {
+ ch <- err
+ return
+ }
+ defer c.Close()
+ b := make([]byte, 257)
+ if _, err := io.ReadFull(c, b[:2]); err != nil {
+ ch <- err
+ return
+ }
+ io.ReadFull(c, b[:b[1]])
+ b[0] = protocolVersion5
+ b[1] = byte(AuthMethodNotRequired)
+ if _, err := c.Write(b[:2]); err != nil {
+ ch <- err
+ return
+ }
+ if _, err := io.ReadFull(c, b[:6+1+len(targetHostname)]); err != nil {
+ ch <- err
+ return
+ }
+ for {
+ if _, err := c.Read(b); err != nil {
+ ch <- err
+ return
+ }
+ }
+}
+
+func parseDialError(err error) (perr, nerr error) {
+ if e, ok := err.(*net.OpError); ok {
+ err = e.Err
+ nerr = e
+ }
+ if e, ok := err.(*os.SyscallError); ok {
+ err = e.Err
+ }
+ perr = err
+ return
+}
diff --git a/src/vendor/golang_org/x/net/socks/socks.go b/src/vendor/golang_org/x/net/socks/socks.go
new file mode 100644
index 0000000..7318f4f
--- /dev/null
+++ b/src/vendor/golang_org/x/net/socks/socks.go
@@ -0,0 +1,259 @@
+// Copyright 2017 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
+
+// This package is supposed to be used by the net/http package of
+// standard library and proxy package of golang.org/x/net repository.
+
+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
+
+const (
+ protocolVersion5 = 0x05
+
+ CmdConnect Command = 0x01 // establishes an active-open forward proxy connection
+ CmdBind Command = 0x02 // establishes a passive-open forward proxy connection
+
+ addrTypeIPv4 = 0x01
+ addrTypeFQDN = 0x03
+ addrTypeIPv6 = 0x04
+
+ AuthMethodNotRequired AuthMethod = 0x00 // no authentication required
+ AuthMethodUsernamePassword AuthMethod = 0x02 // use username/password
+ AuthMethodNoAcceptableMethods AuthMethod = 0xff // no acceptable authetication methods
+
+ statusSucceeded = 0x00
+)
+
+var cmdErrors = [...]string{
+ "succeeded",
+ "general SOCKS server failure",
+ "connection not allowed by ruleset",
+ "network unreachable",
+ "host unreachable",
+ "connection refused",
+ "TTL expired",
+ "command not supported",
+ "address type not supported",
+}
+
+// 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 server bound address defined in RFC 1928.
+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 authention
+ // 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's the authentication function's responsibility to handle
+ // the given context except IO on the given io.ReadWriter.
+ Authenticate func(context.Context, io.ReadWriter, AuthMethod) error
+}
+
+// DialContext connects to the provided address on the provided
+// network.
+//
+// When d is for CmdConnect, address must specify the pair of address
+// and port number of the final destination.
+// When d is for CmdBind, address must specify the pair of address and
+// port number on the proxy server.
+//
+// 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) {
+ switch network {
+ case "tcp", "tcp6", "tcp4":
+ default:
+ proxy, dst, _ := d.pathAddrs(network, address)
+ return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: errors.New("network not implemented")}
+ }
+ switch d.cmd {
+ case CmdConnect, CmdBind:
+ default:
+ proxy, dst, _ := d.pathAddrs(network, address)
+ return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: errors.New("command not implemented")}
+ }
+ if ctx == nil {
+ ctx = context.Background()
+ }
+ 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(network, 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(network, address)
+ return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err}
+ }
+ return &Conn{Conn: c, boundAddr: a}, nil
+}
+
+// Dial connects to the provided address on the provided network.
+//
+// Deprecated: Use DialContext instead.
+func (d *Dialer) Dial(network, address string) (net.Conn, error) {
+ return d.DialContext(context.Background(), network, address)
+}
+
+func (d *Dialer) pathAddrs(network, address string) (proxy, dst net.Addr, err error) {
+ proxy, err = net.ResolveTCPAddr(d.proxyNetwork, d.proxyAddress)
+ if err != nil {
+ return nil, nil, err
+ }
+ host, port, err := net.SplitHostPort(address)
+ if err != nil {
+ return nil, nil, err
+ }
+ portnum, err := strconv.Atoi(port)
+ if err != nil {
+ return nil, nil, err
+ }
+ a := &Addr{Port: portnum}
+ // The final destination address can be unresolvable on the
+ // session initiator.
+ a.IP = net.ParseIP(host)
+ if a.IP == nil {
+ a.Name = host
+ }
+ return proxy, a, nil
+}
+
+// NewDialer returns a new Dialer.
+//
+// The provided network and address must specify a proxy server.
+func NewDialer(network, address string, cmd Command) (*Dialer, error) {
+ return &Dialer{proxyNetwork: network, proxyAddress: address, cmd: cmd}, nil
+}
+
+const (
+ authUsernamePasswordVersion = 0x01
+ authStatusSucceeded = 0x00
+)
+
+// A UsernamePassword holds information for 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) == 0 || 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...)
+ 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
+ default:
+ return errors.New("unsupported authentication method " + strconv.Itoa(int(auth)))
+ }
+}
To view, visit change 41031. To unsubscribe, visit settings.
Mikio Hara posted comments on this change.
Patch set 1:Run-TryBot +1
Gobot Gobot posted comments on this change.
Patch set 1:
TryBots beginning. Status page: https://farmer.golang.org/try?commit=c80550a0
Gobot Gobot posted comments on this change.
Patch set 1:TryBot-Result +1
TryBots are happy.
Mikio Hara posted comments on this change.
Patch set 2:Run-TryBot +1
Gobot Gobot posted comments on this change.
Patch set 2:
TryBots beginning. Status page: https://farmer.golang.org/try?commit=2ed01120
Gobot Gobot posted comments on this change.
Patch set 2:TryBot-Result +1
TryBots are happy.
Benchmark results for linux-amd64 are available at:
https://perf.golang.org/search?q=cl:41031+try:Ta44a32a99
Brad Fitzpatrick posted comments on this change.
Patch set 2:Code-Review -2
Temporary -2 until upstream is figured out.
(1 comment)
File src/net/http/transport.go:
Patch Set #2, Line 32: "golang_org/x/net/socks"
But it's x/net/INTERNAL/socks upstream. So this import path is misleading.
To view, visit change 41031. To unsubscribe, visit settings.
Mikio Hara posted comments on this change.
Patch Set #2, Line 32: "golang_org/x/net/socks"
But it's x/net/INTERNAL/socks upstream. So this import path is misleading.
yup, but i don't want to touch package visibility control, for both "vendor" and "internal", in go1.9. suggestions? (use internal_ instead of internal?)
To view, visit change 41031. To unsubscribe, visit settings.
Mikio Hara uploaded patch set #3 to this change.
net/http: replace SOCKS client implementation
DO NOT SUBMIT
UNTIL CL 38278 LANDS
This change replaces the vendored socks client implementation with the
bundle of golang.org/x/net/internal/socks package which contains fixes
for 19354 and 11682.
golang.org/x/net/internal/socks becomes socks_bundle.go.
At git rev NNNNNN.
Updates #18508.
Updates #19354.
Fixes #19688.
Change-Id: I8cf6c3f5eb87c24685a7592be015729f84fbed77
---
M src/go/build/deps_test.go
A src/net/http/socks_bundle.go
M src/net/http/transport.go
M src/net/http/transport_test.go
D src/vendor/golang_org/x/net/proxy/direct.go
D src/vendor/golang_org/x/net/proxy/per_host.go
D src/vendor/golang_org/x/net/proxy/per_host_test.go
D src/vendor/golang_org/x/net/proxy/proxy.go
D src/vendor/golang_org/x/net/proxy/proxy_test.go
D src/vendor/golang_org/x/net/proxy/socks5.go
10 files changed, 443 insertions(+), 692 deletions(-)
To view, visit change 41031. To unsubscribe, visit settings.
Mikio Hara posted comments on this change.
Patch set 3:Run-TryBot +1
Gobot Gobot posted comments on this change.
Patch set 3:TryBot-Result +1
TryBots are happy.
Benchmark results for linux-amd64 are available at:
https://perf.golang.org/search?q=cl:41031+try:T8a6646399
Brad Fitzpatrick posted comments on this change.
Patch set 3:
R=go1.10
Mikio Hara abandoned this change.
To view, visit change 41031. To unsubscribe, visit settings.
Mikio Hara posted comments on this change.
Patch set 3:
not abandoned, just suspended for go1.10 or above
Mikio Hara restored this change.
To view, visit change 41031. To unsubscribe, or for help writing mail filters, visit settings.
Mikio Hara uploaded patch set #4 to this change.
net/http: replace SOCKS client implementation
DO NOT SUBMIT
UNTIL CL 38278 LANDS
This change replaces the vendored socks client implementation with the
bundle of golang.org/x/net/internal/socks package which contains fixes
for 19354 and 11682.
golang.org/x/net/internal/socks becomes socks_bundle.go.
At git rev NNNNNN.
Updates #11682.
Updates #18508.
Updates #19354.
Fixes #19688.
Updates #21333.
Change-Id: I8cf6c3f5eb87c24685a7592be015729f84fbed77
---
M src/go/build/deps_test.go
A src/net/http/socks_bundle.go
M src/net/http/transport.go
M src/net/http/transport_test.go
D src/vendor/golang_org/x/net/proxy/direct.go
D src/vendor/golang_org/x/net/proxy/per_host.go
D src/vendor/golang_org/x/net/proxy/per_host_test.go
D src/vendor/golang_org/x/net/proxy/proxy.go
D src/vendor/golang_org/x/net/proxy/proxy_test.go
D src/vendor/golang_org/x/net/proxy/socks5.go
10 files changed, 459 insertions(+), 692 deletions(-)
To view, visit change 41031. To unsubscribe, or for help writing mail filters, visit settings.
Uploaded patch set 4.
To view, visit change 41031. To unsubscribe, or for help writing mail filters, visit settings.
resuming
Patch set 4:Run-TryBot +1
To view, visit change 41031. To unsubscribe, or for help writing mail filters, visit settings.
TryBots beginning. Status page: https://farmer.golang.org/try?commit=8c37f150
To view, visit change 41031. To unsubscribe, or for help writing mail filters, visit settings.
TryBots are happy.
Patch set 4:TryBot-Result +1
To view, visit change 41031. To unsubscribe, or for help writing mail filters, visit settings.
Uploaded patch set 5.
To view, visit change 41031. To unsubscribe, or for help writing mail filters, visit settings.
Mikio Hara uploaded patch set #5 to this change.
net/http: replace SOCKS client implementation
DO NOT SUBMIT
UNTIL CL 38278 LANDS
This change replaces the vendored socks client implementation with the
bundle of golang.org/x/net/internal/socks package which contains fixes
for 19354 and 11682.
golang.org/x/net/internal/socks becomes socks_bundle.go.
At git rev NNNNNN.
Updates #11682.
Updates #18508.
Updates #19354.
Fixes #19688.
Updates #21333.
Change-Id: I8cf6c3f5eb87c24685a7592be015729f84fbed77
---
M src/go/build/deps_test.go
A src/net/http/socks_bundle.go
M src/net/http/transport.go
M src/net/http/transport_test.go
D src/vendor/golang_org/x/net/proxy/direct.go
D src/vendor/golang_org/x/net/proxy/per_host.go
D src/vendor/golang_org/x/net/proxy/per_host_test.go
D src/vendor/golang_org/x/net/proxy/proxy.go
D src/vendor/golang_org/x/net/proxy/proxy_test.go
D src/vendor/golang_org/x/net/proxy/socks5.go
10 files changed, 440 insertions(+), 692 deletions(-)
To view, visit change 41031. To unsubscribe, or for help writing mail filters, visit settings.
Patch set 5:Run-TryBot +1
To view, visit change 41031. To unsubscribe, or for help writing mail filters, visit settings.
TryBots beginning. Status page: https://farmer.golang.org/try?commit=0a400df9
To view, visit change 41031. To unsubscribe, or for help writing mail filters, visit settings.
TryBots are happy.
Patch set 5:TryBot-Result +1
Mikio Hara uploaded patch set #6 to this change.
To view, visit change 41031. To unsubscribe, or for help writing mail filters, visit settings.
Uploaded patch set 6.
Patch set 6:Run-TryBot +1
TryBots beginning. Status page: https://farmer.golang.org/try?commit=a2468025
TryBots are happy.
Patch set 6:TryBot-Result +1
R=go1.11
Mikio Hara uploaded patch set #7 to this change.
net/http: replace SOCKS client implementation
This change replaces the vendored socks client implementation with the
bundle of golang.org/x/net/internal/socks package which contains fixes
for 19354 and 11682.
golang.org/x/net/internal/socks becomes socks_bundle.go.
At git rev 61147c4. (golang.org/cl/38278)
Updates #11682.
Updates #18508.
Updates #19354.
Fixes #19688.
Updates #21333.
Change-Id: I8cf6c3f5eb87c24685a7592be015729f84fbed77
---
M src/go/build/deps_test.go
A src/net/http/socks_bundle.go
M src/net/http/transport.go
M src/net/http/transport_test.go
D src/vendor/golang_org/x/net/proxy/direct.go
D src/vendor/golang_org/x/net/proxy/per_host.go
D src/vendor/golang_org/x/net/proxy/per_host_test.go
D src/vendor/golang_org/x/net/proxy/proxy.go
D src/vendor/golang_org/x/net/proxy/proxy_test.go
D src/vendor/golang_org/x/net/proxy/socks5.go
10 files changed, 440 insertions(+), 692 deletions(-)
To view, visit change 41031. To unsubscribe, or for help writing mail filters, visit settings.
Uploaded patch set 7.
Patch set 7:Run-TryBot +1
TryBots beginning. Status page: https://farmer.golang.org/try?commit=a878159b
Build is still in progress...
This change failed on misc-compile-mips:
See https://storage.googleapis.com/go-build-log/a878159b/misc-compile-mips_d72a5332.log
Consult https://build.golang.org/ to see whether it's a new failure. Other builds still in progress; subsequent failure notices suppressed until final report.
17 of 17 TryBots failed:
Failed on misc-compile-mips: https://storage.googleapis.com/go-build-log/a878159b/misc-compile-mips_d72a5332.log
Failed on linux-amd64: https://storage.googleapis.com/go-build-log/a878159b/linux-amd64_d82eac1b.log
Failed on nacl-amd64p32: https://storage.googleapis.com/go-build-log/a878159b/nacl-amd64p32_7512edbe.log
Failed on misc-compile-openbsd: https://storage.googleapis.com/go-build-log/a878159b/misc-compile-openbsd_9b6255b6.log
Failed on linux-amd64-race: https://storage.googleapis.com/go-build-log/a878159b/linux-amd64-race_5247b8ca.log
Failed on misc-compile: https://storage.googleapis.com/go-build-log/a878159b/misc-compile_7e361090.log
Failed on nacl-386: https://storage.googleapis.com/go-build-log/a878159b/nacl-386_beb1342b.log
Failed on misc-vet-vetall: https://storage.googleapis.com/go-build-log/a878159b/misc-vet-vetall_dbcbddf1.log
Failed on misc-compile-ppc: https://storage.googleapis.com/go-build-log/a878159b/misc-compile-ppc_de617290.log
Failed on misc-compile-netbsd: https://storage.googleapis.com/go-build-log/a878159b/misc-compile-netbsd_c10d209c.log
Failed on misc-compile-plan9: https://storage.googleapis.com/go-build-log/a878159b/misc-compile-plan9_71983fe4.log
Failed on misc-compile-freebsd: https://storage.googleapis.com/go-build-log/a878159b/misc-compile-freebsd_9be2f4a6.log
Failed on linux-386: https://storage.googleapis.com/go-build-log/a878159b/linux-386_8a5503eb.log
Failed on freebsd-amd64-11_1: https://storage.googleapis.com/go-build-log/a878159b/freebsd-amd64-11_1_c1f5e08f.log
Failed on windows-386-2008: https://storage.googleapis.com/go-build-log/a878159b/windows-386-2008_6500f87e.log
Failed on openbsd-amd64-62: https://storage.googleapis.com/go-build-log/a878159b/openbsd-amd64-62_b06b741a.log
Failed on windows-amd64-2016: https://storage.googleapis.com/go-build-log/a878159b/windows-amd64-2016_5560ccc9.log
Consult https://build.golang.org/ to see whether they are new failures.
Patch set 7:TryBot-Result -1
Patch set 7:-Run-TryBot
Uploaded patch set 8.
Mikio Hara uploaded patch set #8 to this change.
net/http: replace SOCKS client implementation
This change replaces the vendored socks client implementation with the
bundle of golang.org/x/net/internal/socks package which contains fixes
for 19354 and 11682.
golang.org/x/net/internal/socks becomes socks_bundle.go.
At git rev 61147c4. (golang.org/cl/38278)
Updates #11682.
Updates #18508.
Updates #19354.
Fixes #19688.
Updates #21333.
Change-Id: I8cf6c3f5eb87c24685a7592be015729f84fbed77
---
M src/go/build/deps_test.go
A src/net/http/socks_bundle.go
M src/net/http/transport.go
M src/net/http/transport_test.go
D src/vendor/golang_org/x/net/proxy/direct.go
D src/vendor/golang_org/x/net/proxy/per_host.go
D src/vendor/golang_org/x/net/proxy/per_host_test.go
D src/vendor/golang_org/x/net/proxy/proxy.go
D src/vendor/golang_org/x/net/proxy/proxy_test.go
D src/vendor/golang_org/x/net/proxy/socks5.go
10 files changed, 437 insertions(+), 693 deletions(-)
To view, visit change 41031. To unsubscribe, or for help writing mail filters, visit settings.
Patch set 8:Run-TryBot +1
TryBots beginning. Status page: https://farmer.golang.org/try?commit=3f146fe8
TryBots are happy.
Patch set 8:TryBot-Result +1
Patch set 8:Code-Review +2
Brad Fitzpatrick merged this change.
net/http: replace SOCKS client implementation
This change replaces the vendored socks client implementation with the
bundle of golang.org/x/net/internal/socks package which contains fixes
for 19354 and 11682.
golang.org/x/net/internal/socks becomes socks_bundle.go.
At git rev 61147c4. (golang.org/cl/38278)
Updates #11682.
Updates #18508.
Updates #19354.
Fixes #19688.
Updates #21333.
Change-Id: I8cf6c3f5eb87c24685a7592be015729f84fbed77
Reviewed-on: https://go-review.googlesource.com/41031
Run-TryBot: Mikio Hara <mikioh...@gmail.com>
TryBot-Result: Gobot Gobot <go...@golang.org>
Reviewed-by: Brad Fitzpatrick <brad...@golang.org>
---
M src/go/build/deps_test.go
A src/net/http/socks_bundle.go
M src/net/http/transport.go
M src/net/http/transport_test.go
D src/vendor/golang_org/x/net/proxy/direct.go
D src/vendor/golang_org/x/net/proxy/per_host.go
D src/vendor/golang_org/x/net/proxy/per_host_test.go
D src/vendor/golang_org/x/net/proxy/proxy.go
D src/vendor/golang_org/x/net/proxy/proxy_test.go
D src/vendor/golang_org/x/net/proxy/socks5.go
10 files changed, 437 insertions(+), 693 deletions(-)
diff --git a/src/go/build/deps_test.go b/src/go/build/deps_test.go
index 9387625..1105de1 100644
--- a/src/go/build/deps_test.go
+++ b/src/go/build/deps_test.go
@@ -403,7 +403,6 @@
"golang_org/x/net/http2/hpack",
"golang_org/x/net/idna",
"golang_org/x/net/lex/httplex",
- "golang_org/x/net/proxy",
"golang_org/x/text/unicode/norm",
"golang_org/x/text/width",
"internal/nettrace",
diff --git a/src/net/http/socks_bundle.go b/src/net/http/socks_bundle.go
new file mode 100644
index 0000000..5c3830a
--- /dev/null
+++ b/src/net/http/socks_bundle.go
@@ -0,0 +1,421 @@
+// Code generated by golang.org/x/tools/cmd/bundle. DO NOT EDIT.
+//go:generate bundle -o socks_bundle.go -dst http -prefix socks -underscore 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 (
+ "context"
+ "errors"
+ "io"
+ "net"
+ "strconv"
+ "time"
+)
+
+var (
+ socksnoDeadline = time.Time{}
+ socksaLongTimeAgo = time.Unix(1, 0)
+)
+
+func (d *socksDialer) connect(ctx context.Context, c net.Conn, address string) (_ net.Addr, ctxErr error) {
+ host, port, err := sockssplitHostPort(address)
+ if err != nil {
+ return nil, err
+ }
+ if deadline, ok := ctx.Deadline(); ok && !deadline.IsZero() {
+ c.SetDeadline(deadline)
+ defer c.SetDeadline(socksnoDeadline)
+ }
+ 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(socksaLongTimeAgo)
+ errCh <- ctx.Err()
+ case <-done:
+ errCh <- nil
+ }
+ }()
+ }
+
+ b := make([]byte, 0, 6+len(host)) // the size here is just an estimate
+ b = append(b, socksVersion5)
+ if len(d.AuthMethods) == 0 || d.Authenticate == nil {
+ b = append(b, 1, byte(socksAuthMethodNotRequired))
+ } 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] != socksVersion5 {
+ return nil, errors.New("unexpected protocol version " + strconv.Itoa(int(b[0])))
+ }
+ am := socksAuthMethod(b[1])
+ if am == socksAuthMethodNoAcceptableMethods {
+ 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, socksVersion5, byte(d.cmd), 0)
+ if ip := net.ParseIP(host); ip != nil {
+ if ip4 := ip.To4(); ip4 != nil {
+ b = append(b, socksAddrTypeIPv4)
+ b = append(b, ip4...)
+ } else if ip6 := ip.To16(); ip6 != nil {
+ b = append(b, socksAddrTypeIPv6)
+ 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, socksAddrTypeFQDN)
+ 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] != socksVersion5 {
+ return nil, errors.New("unexpected protocol version " + strconv.Itoa(int(b[0])))
+ }
+ if cmdErr := socksReply(b[1]); cmdErr != socksStatusSucceeded {
+ return nil, errors.New("unknown error " + cmdErr.String())
+ }
+ if b[2] != 0 {
+ return nil, errors.New("non-zero reserved field")
+ }
+ l := 2
+ var a socksAddr
+ switch b[3] {
+ case socksAddrTypeIPv4:
+ l += net.IPv4len
+ a.IP = make(net.IP, net.IPv4len)
+ case socksAddrTypeIPv6:
+ l += net.IPv6len
+ a.IP = make(net.IP, net.IPv6len)
+ case socksAddrTypeFQDN:
+ 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 sockssplitHostPort(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
+}
+
+// A Command represents a SOCKS command.
+type socksCommand int
+
+func (cmd socksCommand) String() string {
+ switch cmd {
+ case socksCmdConnect:
+ return "socks connect"
+ case sockscmdBind:
+ return "socks bind"
+ default:
+ return "socks " + strconv.Itoa(int(cmd))
+ }
+}
+
+// An AuthMethod represents a SOCKS authentication method.
+type socksAuthMethod int
+
+// A Reply represents a SOCKS command reply code.
+type socksReply int
+
+func (code socksReply) String() string {
+ switch code {
+ 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(code))
+ }
+}
+
+// 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 authetication 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 (a *socksAddr) Network() string { return "socks" }
+
+func (a *socksAddr) 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 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 (c *socksConn) BoundAddr() net.Addr {
+ if c == nil {
+ return nil
+ }
+ return c.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 authention
+ // 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 (d *socksDialer) DialContext(ctx context.Context, network, address string) (net.Conn, error) {
+ switch network {
+ case "tcp", "tcp6", "tcp4":
+ default:
+ proxy, dst, _ := d.pathAddrs(address)
+ return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: errors.New("network not implemented")}
+ }
+ switch d.cmd {
+ case socksCmdConnect, sockscmdBind:
+ default:
+ proxy, dst, _ := d.pathAddrs(address)
+ return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: errors.New("command not implemented")}
+ }
+ if ctx == nil {
+ ctx = context.Background()
+ }
+ 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 &socksConn{Conn: c, boundAddr: a}, nil
+}
+
+// Dial connects to the provided address on the provided network.
+//
+// Deprecated: Use DialContext instead.
+func (d *socksDialer) Dial(network, address string) (net.Conn, error) {
+ return d.DialContext(context.Background(), network, address)
+}
+
+func (d *socksDialer) pathAddrs(address string) (proxy, dst net.Addr, err error) {
+ for i, s := range []string{d.proxyAddress, address} {
+ host, port, err := sockssplitHostPort(s)
+ if err != nil {
+ return nil, nil, err
+ }
+ a := &socksAddr{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 socksNewDialer(network, address string) *socksDialer {
+ return &socksDialer{proxyNetwork: network, proxyAddress: address, 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 (up *socksUsernamePassword) Authenticate(ctx context.Context, rw io.ReadWriter, auth socksAuthMethod) error {
+ switch auth {
+ case socksAuthMethodNotRequired:
+ return nil
+ case socksAuthMethodUsernamePassword:
+ if len(up.Username) == 0 || len(up.Username) > 255 || len(up.Password) == 0 || len(up.Password) > 255 {
+ return errors.New("invalid username/password")
+ }
+ b := []byte{socksauthUsernamePasswordVersion}
+ 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] != socksauthUsernamePasswordVersion {
+ return errors.New("invalid username/password version")
+ }
+ if b[1] != socksauthStatusSucceeded {
+ return errors.New("username/password authentication failed")
+ }
+ return nil
+ }
+ return errors.New("unsupported authentication method " + strconv.Itoa(int(auth)))
+}
diff --git a/src/net/http/transport.go b/src/net/http/transport.go
index dbfef80..b19f7ce 100644
--- a/src/net/http/transport.go
+++ b/src/net/http/transport.go
@@ -29,7 +29,6 @@
"time"
"golang_org/x/net/lex/httplex"
- "golang_org/x/net/proxy"
)
// DefaultTransport is the default implementation of Transport and is
@@ -1013,23 +1012,6 @@
}
}
-type oneConnDialer <-chan net.Conn
-
-func newOneConnDialer(c net.Conn) proxy.Dialer {
- ch := make(chan net.Conn, 1)
- ch <- c
- return oneConnDialer(ch)
-}
-
-func (d oneConnDialer) Dial(network, addr string) (net.Conn, error) {
- select {
- case c := <-d:
- return c, nil
- default:
- return nil, io.EOF
- }
-}
-
// The connect method and the transport can both specify a TLS
// Host name. The transport's name takes precedence if present.
func chooseTLSHost(cm connectMethod, t *Transport) string {
@@ -1156,18 +1138,22 @@
// Do nothing. Not using a proxy.
case cm.proxyURL.Scheme == "socks5":
conn := pconn.conn
- var auth *proxy.Auth
+ d := socksNewDialer("tcp", conn.RemoteAddr().String())
+ d.ProxyDial = func(_ context.Context, _, _ string) (net.Conn, error) {
+ return conn, nil
+ }
if u := cm.proxyURL.User; u != nil {
- auth = &proxy.Auth{}
- auth.User = u.Username()
+ auth := &socksUsernamePassword{
+ Username: u.Username(),
+ }
auth.Password, _ = u.Password()
+ d.AuthMethods = []socksAuthMethod{
+ socksAuthMethodNotRequired,
+ socksAuthMethodUsernamePassword,
+ }
+ d.Authenticate = auth.Authenticate
}
- p, err := proxy.SOCKS5("", cm.addr(), auth, newOneConnDialer(conn))
- if err != nil {
- conn.Close()
- return nil, err
- }
- if _, err := p.Dial("tcp", cm.targetAddr); err != nil {
+ if _, err := d.DialContext(ctx, "tcp", cm.targetAddr); err != nil {
conn.Close()
return nil, err
}
diff --git a/src/net/http/transport_test.go b/src/net/http/transport_test.go
index f69d71a..a48e61e 100644
--- a/src/net/http/transport_test.go
+++ b/src/net/http/transport_test.go
@@ -959,7 +959,7 @@
}
}
-func TestSocks5Proxy(t *testing.T) {
+func TestSOCKS5Proxy(t *testing.T) {
defer afterTest(t)
ch := make(chan string, 1)
l := newLocalListener(t)
@@ -996,9 +996,9 @@
var ipLen int
switch buf[3] {
case 1:
- ipLen = 4
+ ipLen = net.IPv4len
case 4:
- ipLen = 16
+ ipLen = net.IPv6len
default:
t.Errorf("socks5 proxy second read: unexpected address type %v", buf[4])
return
diff --git a/src/vendor/golang_org/x/net/proxy/direct.go b/src/vendor/golang_org/x/net/proxy/direct.go
deleted file mode 100644
index 4c5ad88..0000000
--- a/src/vendor/golang_org/x/net/proxy/direct.go
+++ /dev/null
@@ -1,18 +0,0 @@
-// 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 (
- "net"
-)
-
-type direct struct{}
-
-// Direct is a direct proxy: one that makes network connections directly.
-var Direct = direct{}
-
-func (direct) Dial(network, addr string) (net.Conn, error) {
- return net.Dial(network, addr)
-}
diff --git a/src/vendor/golang_org/x/net/proxy/per_host.go b/src/vendor/golang_org/x/net/proxy/per_host.go
deleted file mode 100644
index f540b19..0000000
--- a/src/vendor/golang_org/x/net/proxy/per_host.go
+++ /dev/null
@@ -1,140 +0,0 @@
-// 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 (
- "net"
- "strings"
-)
-
-// A PerHost directs connections to a default Dialer unless the hostname
-// 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)
-}
-
-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 hostname
-// (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 hostname 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/src/vendor/golang_org/x/net/proxy/per_host_test.go b/src/vendor/golang_org/x/net/proxy/per_host_test.go
deleted file mode 100644
index a7d8095..0000000
--- a/src/vendor/golang_org/x/net/proxy/per_host_test.go
+++ /dev/null
@@ -1,55 +0,0 @@
-// 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 (
- "errors"
- "net"
- "reflect"
- "testing"
-)
-
-type recordingProxy struct {
- addrs []string
-}
-
-func (r *recordingProxy) Dial(network, addr string) (net.Conn, error) {
- r.addrs = append(r.addrs, addr)
- return nil, errors.New("recordingProxy")
-}
-
-func TestPerHost(t *testing.T) {
- var def, bypass recordingProxy
- perHost := NewPerHost(&def, &bypass)
- perHost.AddFromString("localhost,*.zone,127.0.0.1,10.0.0.1/8,1000::/16")
-
- expectedDef := []string{
- "example.com:123",
- "1.2.3.4:123",
- "[1001::]:123",
- }
- expectedBypass := []string{
- "localhost:123",
- "zone:123",
- "foo.zone:123",
- "127.0.0.1:123",
- "10.1.2.3:123",
- "[1000::]:123",
- }
-
- for _, addr := range expectedDef {
- perHost.Dial("tcp", addr)
- }
- for _, addr := range expectedBypass {
- perHost.Dial("tcp", addr)
- }
-
- if !reflect.DeepEqual(expectedDef, def.addrs) {
- t.Errorf("Hosts which went to the default proxy didn't match. Got %v, want %v", def.addrs, expectedDef)
- }
- if !reflect.DeepEqual(expectedBypass, bypass.addrs) {
- t.Errorf("Hosts which went to the bypass proxy didn't match. Got %v, want %v", bypass.addrs, expectedBypass)
- }
-}
diff --git a/src/vendor/golang_org/x/net/proxy/proxy.go b/src/vendor/golang_org/x/net/proxy/proxy.go
deleted file mode 100644
index 78a8b7b..0000000
--- a/src/vendor/golang_org/x/net/proxy/proxy.go
+++ /dev/null
@@ -1,94 +0,0 @@
-// 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"
-)
-
-// A Dialer is a means to establish a connection.
-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.
-func FromEnvironment() Dialer {
- allProxy := os.Getenv("all_proxy")
- if len(allProxy) == 0 {
- return Direct
- }
-
- proxyURL, err := url.Parse(allProxy)
- if err != nil {
- return Direct
- }
- proxy, err := FromURL(proxyURL, Direct)
- if err != nil {
- return Direct
- }
-
- noProxy := os.Getenv("no_proxy")
- if len(noProxy) == 0 {
- return proxy
- }
-
- perHost := NewPerHost(proxy, Direct)
- 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":
- return SOCKS5("tcp", u.Host, 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)
-}
diff --git a/src/vendor/golang_org/x/net/proxy/proxy_test.go b/src/vendor/golang_org/x/net/proxy/proxy_test.go
deleted file mode 100644
index c19a5c0..0000000
--- a/src/vendor/golang_org/x/net/proxy/proxy_test.go
+++ /dev/null
@@ -1,142 +0,0 @@
-// 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 (
- "io"
- "net"
- "net/url"
- "strconv"
- "sync"
- "testing"
-)
-
-func TestFromURL(t *testing.T) {
- endSystem, err := net.Listen("tcp", "127.0.0.1:0")
- if err != nil {
- t.Fatalf("net.Listen failed: %v", err)
- }
- defer endSystem.Close()
- gateway, err := net.Listen("tcp", "127.0.0.1:0")
- if err != nil {
- t.Fatalf("net.Listen failed: %v", err)
- }
- defer gateway.Close()
-
- var wg sync.WaitGroup
- wg.Add(1)
- go socks5Gateway(t, gateway, endSystem, socks5Domain, &wg)
-
- url, err := url.Parse("socks5://user:password@" + gateway.Addr().String())
- if err != nil {
- t.Fatalf("url.Parse failed: %v", err)
- }
- proxy, err := FromURL(url, Direct)
- if err != nil {
- t.Fatalf("FromURL failed: %v", err)
- }
- _, port, err := net.SplitHostPort(endSystem.Addr().String())
- if err != nil {
- t.Fatalf("net.SplitHostPort failed: %v", err)
- }
- if c, err := proxy.Dial("tcp", "localhost:"+port); err != nil {
- t.Fatalf("FromURL.Dial failed: %v", err)
- } else {
- c.Close()
- }
-
- wg.Wait()
-}
-
-func TestSOCKS5(t *testing.T) {
- endSystem, err := net.Listen("tcp", "127.0.0.1:0")
- if err != nil {
- t.Fatalf("net.Listen failed: %v", err)
- }
- defer endSystem.Close()
- gateway, err := net.Listen("tcp", "127.0.0.1:0")
- if err != nil {
- t.Fatalf("net.Listen failed: %v", err)
- }
- defer gateway.Close()
-
- var wg sync.WaitGroup
- wg.Add(1)
- go socks5Gateway(t, gateway, endSystem, socks5IP4, &wg)
-
- proxy, err := SOCKS5("tcp", gateway.Addr().String(), nil, Direct)
- if err != nil {
- t.Fatalf("SOCKS5 failed: %v", err)
- }
- if c, err := proxy.Dial("tcp", endSystem.Addr().String()); err != nil {
- t.Fatalf("SOCKS5.Dial failed: %v", err)
- } else {
- c.Close()
- }
-
- wg.Wait()
-}
-
-func socks5Gateway(t *testing.T, gateway, endSystem net.Listener, typ byte, wg *sync.WaitGroup) {
- defer wg.Done()
-
- c, err := gateway.Accept()
- if err != nil {
- t.Errorf("net.Listener.Accept failed: %v", err)
- return
- }
- defer c.Close()
-
- b := make([]byte, 32)
- var n int
- if typ == socks5Domain {
- n = 4
- } else {
- n = 3
- }
- if _, err := io.ReadFull(c, b[:n]); err != nil {
- t.Errorf("io.ReadFull failed: %v", err)
- return
- }
- if _, err := c.Write([]byte{socks5Version, socks5AuthNone}); err != nil {
- t.Errorf("net.Conn.Write failed: %v", err)
- return
- }
- if typ == socks5Domain {
- n = 16
- } else {
- n = 10
- }
- if _, err := io.ReadFull(c, b[:n]); err != nil {
- t.Errorf("io.ReadFull failed: %v", err)
- return
- }
- if b[0] != socks5Version || b[1] != socks5Connect || b[2] != 0x00 || b[3] != typ {
- t.Errorf("got an unexpected packet: %#02x %#02x %#02x %#02x", b[0], b[1], b[2], b[3])
- return
- }
- if typ == socks5Domain {
- copy(b[:5], []byte{socks5Version, 0x00, 0x00, socks5Domain, 9})
- b = append(b, []byte("localhost")...)
- } else {
- copy(b[:4], []byte{socks5Version, 0x00, 0x00, socks5IP4})
- }
- host, port, err := net.SplitHostPort(endSystem.Addr().String())
- if err != nil {
- t.Errorf("net.SplitHostPort failed: %v", err)
- return
- }
- b = append(b, []byte(net.ParseIP(host).To4())...)
- p, err := strconv.Atoi(port)
- if err != nil {
- t.Errorf("strconv.Atoi failed: %v", err)
- return
- }
- b = append(b, []byte{byte(p >> 8), byte(p)}...)
- if _, err := c.Write(b); err != nil {
- t.Errorf("net.Conn.Write failed: %v", err)
- return
- }
-}
diff --git a/src/vendor/golang_org/x/net/proxy/socks5.go b/src/vendor/golang_org/x/net/proxy/socks5.go
deleted file mode 100644
index 973f57f..0000000
--- a/src/vendor/golang_org/x/net/proxy/socks5.go
+++ /dev/null
@@ -1,213 +0,0 @@
-// 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 (
- "errors"
- "io"
- "net"
- "strconv"
-)
-
-// SOCKS5 returns a Dialer that makes SOCKSv5 connections to the given address
-// with an optional username and password. See RFC 1928.
-func SOCKS5(network, addr string, auth *Auth, forward Dialer) (Dialer, error) {
- s := &socks5{
- network: network,
- addr: addr,
- forward: forward,
- }
- if auth != nil {
- s.user = auth.User
- s.password = auth.Password
- }
-
- return s, nil
-}
-
-type socks5 struct {
- user, password string
- network, addr string
- forward Dialer
-}
-
-const socks5Version = 5
-
-const (
- socks5AuthNone = 0
- socks5AuthPassword = 2
-)
-
-const socks5Connect = 1
-
-const (
- socks5IP4 = 1
- socks5Domain = 3
- socks5IP6 = 4
-)
-
-var socks5Errors = []string{
- "",
- "general failure",
- "connection forbidden",
- "network unreachable",
- "host unreachable",
- "connection refused",
- "TTL expired",
- "command not supported",
- "address type not supported",
-}
-
-// Dial connects to the address addr on the network net via the SOCKS5 proxy.
-func (s *socks5) Dial(network, addr string) (net.Conn, error) {
- switch network {
- case "tcp", "tcp6", "tcp4":
- default:
- return nil, errors.New("proxy: no support for SOCKS5 proxy connections of type " + network)
- }
-
- conn, err := s.forward.Dial(s.network, s.addr)
- if err != nil {
- return nil, err
- }
- if err := s.connect(conn, addr); err != nil {
- conn.Close()
- return nil, err
- }
- return conn, nil
-}
-
-// connect takes an existing connection to a socks5 proxy server,
-// and commands the server to extend that connection to target,
-// which must be a canonical address with a host and port.
-func (s *socks5) connect(conn net.Conn, target string) error {
- host, portStr, err := net.SplitHostPort(target)
- if err != nil {
- return err
- }
-
- port, err := strconv.Atoi(portStr)
- if err != nil {
- return errors.New("proxy: failed to parse port number: " + portStr)
- }
- if port < 1 || port > 0xffff {
- return errors.New("proxy: port number out of range: " + portStr)
- }
-
- // the size here is just an estimate
- buf := make([]byte, 0, 6+len(host))
-
- buf = append(buf, socks5Version)
- if len(s.user) > 0 && len(s.user) < 256 && len(s.password) < 256 {
- buf = append(buf, 2 /* num auth methods */, socks5AuthNone, socks5AuthPassword)
- } else {
- buf = append(buf, 1 /* num auth methods */, socks5AuthNone)
- }
-
- if _, err := conn.Write(buf); err != nil {
- return errors.New("proxy: failed to write greeting to SOCKS5 proxy at " + s.addr + ": " + err.Error())
- }
-
- if _, err := io.ReadFull(conn, buf[:2]); err != nil {
- return errors.New("proxy: failed to read greeting from SOCKS5 proxy at " + s.addr + ": " + err.Error())
- }
- if buf[0] != 5 {
- return errors.New("proxy: SOCKS5 proxy at " + s.addr + " has unexpected version " + strconv.Itoa(int(buf[0])))
- }
- if buf[1] == 0xff {
- return errors.New("proxy: SOCKS5 proxy at " + s.addr + " requires authentication")
- }
-
- if buf[1] == socks5AuthPassword {
- buf = buf[:0]
- buf = append(buf, 1 /* password protocol version */)
- buf = append(buf, uint8(len(s.user)))
- buf = append(buf, s.user...)
- buf = append(buf, uint8(len(s.password)))
- buf = append(buf, s.password...)
-
- if _, err := conn.Write(buf); err != nil {
- return errors.New("proxy: failed to write authentication request to SOCKS5 proxy at " + s.addr + ": " + err.Error())
- }
-
- if _, err := io.ReadFull(conn, buf[:2]); err != nil {
- return errors.New("proxy: failed to read authentication reply from SOCKS5 proxy at " + s.addr + ": " + err.Error())
- }
-
- if buf[1] != 0 {
- return errors.New("proxy: SOCKS5 proxy at " + s.addr + " rejected username/password")
- }
- }
-
- buf = buf[:0]
- buf = append(buf, socks5Version, socks5Connect, 0 /* reserved */)
-
- if ip := net.ParseIP(host); ip != nil {
- if ip4 := ip.To4(); ip4 != nil {
- buf = append(buf, socks5IP4)
- ip = ip4
- } else {
- buf = append(buf, socks5IP6)
- }
- buf = append(buf, ip...)
- } else {
- if len(host) > 255 {
- return errors.New("proxy: destination hostname too long: " + host)
- }
- buf = append(buf, socks5Domain)
- buf = append(buf, byte(len(host)))
- buf = append(buf, host...)
- }
- buf = append(buf, byte(port>>8), byte(port))
-
- if _, err := conn.Write(buf); err != nil {
- return errors.New("proxy: failed to write connect request to SOCKS5 proxy at " + s.addr + ": " + err.Error())
- }
-
- if _, err := io.ReadFull(conn, buf[:4]); err != nil {
- return errors.New("proxy: failed to read connect reply from SOCKS5 proxy at " + s.addr + ": " + err.Error())
- }
-
- failure := "unknown error"
- if int(buf[1]) < len(socks5Errors) {
- failure = socks5Errors[buf[1]]
- }
-
- if len(failure) > 0 {
- return errors.New("proxy: SOCKS5 proxy at " + s.addr + " failed to connect: " + failure)
- }
-
- bytesToDiscard := 0
- switch buf[3] {
- case socks5IP4:
- bytesToDiscard = net.IPv4len
- case socks5IP6:
- bytesToDiscard = net.IPv6len
- case socks5Domain:
- _, err := io.ReadFull(conn, buf[:1])
- if err != nil {
- return errors.New("proxy: failed to read domain length from SOCKS5 proxy at " + s.addr + ": " + err.Error())
- }
- bytesToDiscard = int(buf[0])
- default:
- return errors.New("proxy: got unknown address type " + strconv.Itoa(int(buf[3])) + " from SOCKS5 proxy at " + s.addr)
- }
-
- if cap(buf) < bytesToDiscard {
- buf = make([]byte, bytesToDiscard)
- } else {
- buf = buf[:bytesToDiscard]
- }
- if _, err := io.ReadFull(conn, buf); err != nil {
- return errors.New("proxy: failed to read address from SOCKS5 proxy at " + s.addr + ": " + err.Error())
- }
-
- // Also need to discard the port number
- if _, err := io.ReadFull(conn, buf[:2]); err != nil {
- return errors.New("proxy: failed to read port from SOCKS5 proxy at " + s.addr + ": " + err.Error())
- }
-
- return nil
-}
To view, visit change 41031. To unsubscribe, or for help writing mail filters, visit settings.