cmd/tailscaled: let SOCKS5 dial non-Tailscale addrs in userspace mode

Fixes #1617

Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:
Brad Fitzpatrick 2021-04-16 13:46:13 -07:00 committed by Brad Fitzpatrick
parent b85d80b37f
commit eb6115e295

View File

@ -29,10 +29,12 @@
"time" "time"
"github.com/go-multierror/multierror" "github.com/go-multierror/multierror"
"inet.af/netaddr"
"tailscale.com/ipn/ipnserver" "tailscale.com/ipn/ipnserver"
"tailscale.com/logpolicy" "tailscale.com/logpolicy"
"tailscale.com/net/dns" "tailscale.com/net/dns"
"tailscale.com/net/socks5" "tailscale.com/net/socks5"
"tailscale.com/net/tsaddr"
"tailscale.com/net/tstun" "tailscale.com/net/tstun"
"tailscale.com/paths" "tailscale.com/paths"
"tailscale.com/types/flagtype" "tailscale.com/types/flagtype"
@ -239,31 +241,32 @@ func run() error {
srv := &socks5.Server{ srv := &socks5.Server{
Logf: logger.WithPrefix(logf, "socks5: "), Logf: logger.WithPrefix(logf, "socks5: "),
} }
// TODO: also consider wrapNetstack, where dials can go to either Tailscale var (
// or non-Tailscale targets. But that's also basically what mu sync.Mutex // guards the following field
// https://github.com/tailscale/tailscale/issues/1617 is about, so do them dns netstack.DNSMap
// both at the same time. )
if useNetstack {
srv.Dialer = func(ctx context.Context, network, addr string) (net.Conn, error) {
return ns.DialContextTCP(ctx, addr)
}
} else {
var mu sync.Mutex
var dns netstack.DNSMap
e.AddNetworkMapCallback(func(nm *netmap.NetworkMap) { e.AddNetworkMapCallback(func(nm *netmap.NetworkMap) {
mu.Lock() mu.Lock()
defer mu.Unlock() defer mu.Unlock()
dns = netstack.DNSMapFromNetworkMap(nm) dns = netstack.DNSMapFromNetworkMap(nm)
}) })
useNetstackForIP := func(ip netaddr.IP) bool {
// TODO(bradfitz): this isn't exactly right.
// We should also support subnets when the
// prefs are configured as such.
return tsaddr.IsTailscaleIP(ip)
}
srv.Dialer = func(ctx context.Context, network, addr string) (net.Conn, error) { srv.Dialer = func(ctx context.Context, network, addr string) (net.Conn, error) {
ipp, err := dns.Resolve(ctx, addr) ipp, err := dns.Resolve(ctx, addr)
if err != nil { if err != nil {
return nil, err return nil, err
} }
if ns != nil && useNetstackForIP(ipp.IP) {
return ns.DialContextTCP(ctx, addr)
}
var d net.Dialer var d net.Dialer
return d.DialContext(ctx, network, ipp.String()) return d.DialContext(ctx, network, ipp.String())
} }
}
go func() { go func() {
log.Fatalf("SOCKS5 server exited: %v", srv.Serve(socksListener)) log.Fatalf("SOCKS5 server exited: %v", srv.Serve(socksListener))
}() }()