net/netns: move SOCKS dialing to netns for now

This lets control & logs also use SOCKS dials.

Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:
Brad Fitzpatrick 2020-06-01 10:50:37 -07:00 committed by Brad Fitzpatrick
parent cf0d19f0ab
commit 24009241bf
5 changed files with 57 additions and 34 deletions

View File

@ -135,7 +135,7 @@ func NewDirect(opts Options) (*Direct, error) {
httpc := opts.HTTPTestClient
if httpc == nil {
dialer := netns.Dialer()
dialer := netns.NewDialer()
tr := http.DefaultTransport.(*http.Transport).Clone()
tr.DialContext = dialer.DialContext
tr.ForceAttemptHTTP2 = true

View File

@ -103,11 +103,6 @@ func NewClient(privateKey key.Private, serverURL string, logf logger.Logf) (*Cli
return c, nil
}
type dialer interface {
Dial(network, address string) (net.Conn, error)
DialContext(ctx context.Context, network, address string) (net.Conn, error)
}
// Connect connects or reconnects to the server, unless already connected.
// It returns nil if there was already a good connection, or if one was made.
func (c *Client) Connect(ctx context.Context) error {
@ -297,18 +292,14 @@ func (c *Client) dialURL(ctx context.Context) (net.Conn, error) {
host := c.url.Hostname()
hostOrIP := host
var stdDialer dialer = netns.Dialer()
var dialer = stdDialer
if wrapDialer != nil {
dialer = wrapDialer(dialer)
}
dialer := netns.NewDialer()
if c.DNSCache != nil {
ip, err := c.DNSCache.LookupIP(ctx, host)
if err == nil {
hostOrIP = ip.String()
}
if err != nil && dialer == stdDialer {
if err != nil && netns.IsSOCKSDialer(dialer) {
// Return an error if we're not using a dial
// proxy that can do DNS lookups for us.
return nil, err
@ -387,12 +378,7 @@ func (c *Client) DialRegionTLS(ctx context.Context, reg *tailcfg.DERPRegion) (tl
}
func (c *Client) dialContext(ctx context.Context, proto, addr string) (net.Conn, error) {
var stdDialer dialer = netns.Dialer()
var dialer = stdDialer
if wrapDialer != nil {
dialer = wrapDialer(dialer)
}
return dialer.DialContext(ctx, proto, addr)
return netns.NewDialer().DialContext(ctx, proto, addr)
}
// shouldDialProto reports whether an explicitly provided IPv4 or IPv6
@ -559,7 +545,3 @@ func (c *Client) closeForReconnect(brokenClient *derp.Client) {
}
var ErrClientClosed = errors.New("derphttp.Client closed")
// wrapDialer, if non-nil, specifies a function to wrap a dialer in a
// SOCKS-using dialer. It's set conditionally by socks.go.
var wrapDialer func(dialer) dialer

View File

@ -250,9 +250,10 @@ func newLogtailTransport(host string) *http.Transport {
// Log whenever we dial:
tr.DialContext = func(ctx context.Context, netw, addr string) (net.Conn, error) {
nd := netns.Dialer()
nd.Timeout = 30 * time.Second
nd.KeepAlive = 30 * time.Second
nd := netns.FromDialer(&net.Dialer{
Timeout: 30 * time.Second,
KeepAlive: 30 * time.Second,
})
t0 := time.Now()
c, err := nd.DialContext(ctx, netw, addr)
d := time.Since(t0).Round(time.Millisecond)

View File

@ -9,9 +9,15 @@
//
// Despite the name netns, the exact mechanism used differs by
// operating system, and perhaps even by version of the OS.
//
// The netns package also handles connecting via SOCKS proxies when
// configured by the environment.
package netns
import "net"
import (
"context"
"net"
)
// Listener returns a new net.Listener with its Control hook func
// initialized as necessary to run in logical network namespace that
@ -20,9 +26,43 @@ func Listener() *net.ListenConfig {
return &net.ListenConfig{Control: control}
}
// Dialer returns a new net.Dialer with its Control hook func
// initialized as necessary to run in a logical network namespace that
// doesn't route back into Tailscale.
func Dialer() *net.Dialer {
return &net.Dialer{Control: control}
// NewDialer returns a new Dialer using a net.Dialer with its Control
// hook func initialized as necessary to run in a logical network
// namespace that doesn't route back into Tailscale. It also handles
// using a SOCKS if configured in the environment with ALL_PROXY.
func NewDialer() Dialer {
return FromDialer(new(net.Dialer))
}
// FromDialer returns sets d.Control as necessary to run in a logical
// network namespace that doesn't route back into Tailscale. It also
// handles using a SOCKS if configured in the environment with
// ALL_PROXY.
func FromDialer(d *net.Dialer) Dialer {
d.Control = control
if wrapDialer != nil {
return wrapDialer(d)
}
return d
}
// IsSOCKSDialer reports whether d is SOCKS-proxying dialer as returned by
// NewDialer or FromDialer.
func IsSOCKSDialer(d Dialer) bool {
if d == nil {
return false
}
_, ok := d.(*net.Dialer)
return !ok
}
// wrapDialer, if non-nil, specifies a function to wrap a dialer in a
// SOCKS-using dialer. It's set conditionally by socks.go.
var wrapDialer func(Dialer) Dialer
// Dialer is the interface for a dialer that can dial with or without a context.
// It's the type implemented both by net.Dialer and the Go SOCKS dialer.
type Dialer interface {
Dial(network, address string) (net.Conn, error)
DialContext(ctx context.Context, network, address string) (net.Conn, error)
}

View File

@ -4,7 +4,7 @@
// +build !ios
package derphttp
package netns
import "golang.org/x/net/proxy"
@ -12,8 +12,8 @@ func init() {
wrapDialer = wrapSocks
}
func wrapSocks(d dialer) dialer {
if cd, ok := proxy.FromEnvironmentUsing(d).(dialer); ok {
func wrapSocks(d Dialer) Dialer {
if cd, ok := proxy.FromEnvironmentUsing(d).(Dialer); ok {
return cd
}
return d