net/socks5/tssocks: add a SOCKS5 dialer type, method-ifying code

https://twitter.com/bradfitz/status/1409605220376580097

Prep for #1970, #2264, #2268

Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:
Brad Fitzpatrick 2021-06-28 13:12:42 -07:00
parent 3910c1edaf
commit 15677d8a0e

View File

@ -27,34 +27,53 @@
// //
// If ns is non-nil, it is used for dialing when needed. // If ns is non-nil, it is used for dialing when needed.
func NewServer(logf logger.Logf, e wgengine.Engine, ns *netstack.Impl) *socks5.Server { func NewServer(logf logger.Logf, e wgengine.Engine, ns *netstack.Impl) *socks5.Server {
srv := &socks5.Server{ d := &dialer{ns: ns}
Logf: logf, e.AddNetworkMapCallback(d.onNewNetmap)
return &socks5.Server{
Logf: logf,
Dialer: d.DialContext,
} }
var ( }
mu sync.Mutex // guards the following field
dns netstack.DNSMap // dialer is the Tailscale SOCKS5 dialer.
) type dialer struct {
e.AddNetworkMapCallback(func(nm *netmap.NetworkMap) { ns *netstack.Impl
mu.Lock()
defer mu.Unlock() mu sync.Mutex
dns = netstack.DNSMapFromNetworkMap(nm) dns netstack.DNSMap
}) }
useNetstackForIP := func(ip netaddr.IP) bool {
// TODO(bradfitz): this isn't exactly right. func (d *dialer) onNewNetmap(nm *netmap.NetworkMap) {
// We should also support subnets when the d.mu.Lock()
// prefs are configured as such. defer d.mu.Unlock()
return tsaddr.IsTailscaleIP(ip) d.dns = netstack.DNSMapFromNetworkMap(nm)
} }
srv.Dialer = func(ctx context.Context, network, addr string) (net.Conn, error) {
ipp, err := dns.Resolve(ctx, addr) func (d *dialer) resolve(ctx context.Context, addr string) (netaddr.IPPort, error) {
if err != nil { d.mu.Lock()
return nil, err dns := d.dns
} d.mu.Unlock()
if ns != nil && useNetstackForIP(ipp.IP()) { return dns.Resolve(ctx, addr)
return ns.DialContextTCP(ctx, addr) }
}
var d net.Dialer func (d *dialer) DialContext(ctx context.Context, network, addr string) (net.Conn, error) {
return d.DialContext(ctx, network, ipp.String()) ipp, err := d.resolve(ctx, addr)
} if err != nil {
return srv return nil, err
}
if d.ns != nil && d.useNetstackForIP(ipp.IP()) {
return d.ns.DialContextTCP(ctx, ipp.String())
}
var stdDialer net.Dialer
return stdDialer.DialContext(ctx, network, ipp.String())
}
func (d *dialer) useNetstackForIP(ip netaddr.IP) bool {
if d.ns == nil {
return false
}
// TODO(bradfitz): this isn't exactly right.
// We should also support subnets when the
// prefs are configured as such.
return tsaddr.IsTailscaleIP(ip)
} }