From 999e230ac17390f8e1dd917db1769c447b10585b Mon Sep 17 00:00:00 2001 From: Mikio Hara Date: Sat, 28 Apr 2018 12:27:53 +0900 Subject: [PATCH] net/http: use DialWithConn method of socks.Dialer This change uses the DialWithConn method of socks.Dialer to ensure that the bundled SOCKS client implementation is agnostic to the behavior and capabilities of transport connections. Also updates the bundled golang.org/x/net/internal/socks at git rev 7594486. (golang.org/cl/110135) Updates #25104. Change-Id: I87c2e99eeb857f182ea5d8ef569181d4f45f2e5d Reviewed-on: https://go-review.googlesource.com/110136 Run-TryBot: Mikio Hara TryBot-Result: Gobot Gobot Reviewed-by: Brad Fitzpatrick --- src/net/http/socks_bundle.go | 79 +++++++++++++++++++++++++++++------- src/net/http/transport.go | 5 +-- 2 files changed, 66 insertions(+), 18 deletions(-) diff --git a/src/net/http/socks_bundle.go b/src/net/http/socks_bundle.go index 8b347898e8..e4314b4128 100644 --- a/src/net/http/socks_bundle.go +++ b/src/net/http/socks_bundle.go @@ -1,5 +1,5 @@ // 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 +//go:generate bundle -o socks_bundle.go -dst net/http -prefix socks -underscore golang.org/x/net/internal/socks // Package socks provides a SOCKS version 5 client implementation. // @@ -305,20 +305,13 @@ type socksDialer struct { // 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: + 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: 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")} + return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err} } if ctx == nil { - ctx = context.Background() + 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 @@ -341,11 +334,69 @@ func (d *socksDialer) DialContext(ctx context.Context, network, address string) return &socksConn{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 *socksDialer) 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. // -// Deprecated: Use DialContext instead. +// Unlike DialContext, it returns a raw transport connection instead +// of a forward proxy connection. +// +// Deprecated: Use DialContext or DialWithConn instead. func (d *socksDialer) Dial(network, address string) (net.Conn, error) { - return d.DialContext(context.Background(), network, address) + 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 { + return nil, err + } + return c, nil +} + +func (d *socksDialer) validateTarget(network, address string) error { + switch network { + case "tcp", "tcp6", "tcp4": + default: + return errors.New("network not implemented") + } + switch d.cmd { + case socksCmdConnect, sockscmdBind: + default: + return errors.New("command not implemented") + } + return nil } func (d *socksDialer) pathAddrs(address string) (proxy, dst net.Addr, err error) { diff --git a/src/net/http/transport.go b/src/net/http/transport.go index 731bf176a8..ba2c00e067 100644 --- a/src/net/http/transport.go +++ b/src/net/http/transport.go @@ -1086,9 +1086,6 @@ func (t *Transport) dialConn(ctx context.Context, cm connectMethod) (*persistCon case cm.proxyURL.Scheme == "socks5": conn := pconn.conn 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 := &socksUsernamePassword{ Username: u.Username(), @@ -1100,7 +1097,7 @@ func (t *Transport) dialConn(ctx context.Context, cm connectMethod) (*persistCon } d.Authenticate = auth.Authenticate } - if _, err := d.DialContext(ctx, "tcp", cm.targetAddr); err != nil { + if _, err := d.DialWithConn(ctx, conn, "tcp", cm.targetAddr); err != nil { conn.Close() return nil, err }