mirror of
https://github.com/tailscale/tailscale.git
synced 2025-08-12 05:37:32 +00:00
wgengine/netstack: add Magic DNS + DNS resolution to SOCKS5 dialing
Updates #707 Updates #504 Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:

committed by
Brad Fitzpatrick

parent
34188d93d4
commit
d74cddcc56
@@ -15,7 +15,9 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"log"
|
"log"
|
||||||
"net"
|
"net"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
|
|
||||||
"gvisor.dev/gvisor/pkg/tcpip"
|
"gvisor.dev/gvisor/pkg/tcpip"
|
||||||
"gvisor.dev/gvisor/pkg/tcpip/adapters/gonet"
|
"gvisor.dev/gvisor/pkg/tcpip/adapters/gonet"
|
||||||
@@ -34,6 +36,7 @@ import (
|
|||||||
"tailscale.com/net/socks5"
|
"tailscale.com/net/socks5"
|
||||||
"tailscale.com/types/logger"
|
"tailscale.com/types/logger"
|
||||||
"tailscale.com/types/netmap"
|
"tailscale.com/types/netmap"
|
||||||
|
"tailscale.com/util/dnsname"
|
||||||
"tailscale.com/wgengine"
|
"tailscale.com/wgengine"
|
||||||
"tailscale.com/wgengine/filter"
|
"tailscale.com/wgengine/filter"
|
||||||
"tailscale.com/wgengine/magicsock"
|
"tailscale.com/wgengine/magicsock"
|
||||||
@@ -50,6 +53,9 @@ type Impl struct {
|
|||||||
e wgengine.Engine
|
e wgengine.Engine
|
||||||
mc *magicsock.Conn
|
mc *magicsock.Conn
|
||||||
logf logger.Logf
|
logf logger.Logf
|
||||||
|
|
||||||
|
mu sync.Mutex
|
||||||
|
dns map[string]netaddr.IP // Magic DNS names (both base + FQDN) => first IP
|
||||||
}
|
}
|
||||||
|
|
||||||
const nicID = 1
|
const nicID = 1
|
||||||
@@ -120,7 +126,33 @@ func (ns *Impl) Start() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ns *Impl) updateDNS(nm *netmap.NetworkMap) {
|
||||||
|
ns.mu.Lock()
|
||||||
|
defer ns.mu.Unlock()
|
||||||
|
ns.dns = make(map[string]netaddr.IP)
|
||||||
|
suffix := nm.MagicDNSSuffix()
|
||||||
|
|
||||||
|
if nm.Name != "" && len(nm.Addresses) > 0 {
|
||||||
|
ip := nm.Addresses[0].IP
|
||||||
|
ns.dns[strings.TrimRight(nm.Name, ".")] = ip
|
||||||
|
if dnsname.HasSuffix(nm.Name, suffix) {
|
||||||
|
ns.dns[dnsname.TrimSuffix(nm.Name, suffix)] = ip
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, p := range nm.Peers {
|
||||||
|
if p.Name != "" && len(p.Addresses) > 0 {
|
||||||
|
ip := p.Addresses[0].IP
|
||||||
|
ns.dns[strings.TrimRight(p.Name, ".")] = ip
|
||||||
|
if dnsname.HasSuffix(p.Name, suffix) {
|
||||||
|
ns.dns[dnsname.TrimSuffix(p.Name, suffix)] = ip
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (ns *Impl) updateIPs(nm *netmap.NetworkMap) {
|
func (ns *Impl) updateIPs(nm *netmap.NetworkMap) {
|
||||||
|
ns.updateDNS(nm)
|
||||||
|
|
||||||
oldIPs := make(map[tcpip.Address]bool)
|
oldIPs := make(map[tcpip.Address]bool)
|
||||||
for _, ip := range ns.ipstack.AllAddresses()[nicID] {
|
for _, ip := range ns.ipstack.AllAddresses()[nicID] {
|
||||||
oldIPs[ip.AddressWithPrefix.Address] = true
|
oldIPs[ip.AddressWithPrefix.Address] = true
|
||||||
@@ -166,10 +198,54 @@ func (ns *Impl) updateIPs(nm *netmap.NetworkMap) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ns *Impl) dialContextTCP(ctx context.Context, address string) (*gonet.TCPConn, error) {
|
// resolve resolves addr into an IP:port.
|
||||||
remoteIPPort, err := netaddr.ParseIPPort(address)
|
func (ns *Impl) resolve(ctx context.Context, addr string) (netaddr.IPPort, error) {
|
||||||
|
ipp, pippErr := netaddr.ParseIPPort(addr)
|
||||||
|
if pippErr == nil {
|
||||||
|
return ipp, nil
|
||||||
|
}
|
||||||
|
host, port, err := net.SplitHostPort(addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("could not parse IP:port: %w", err)
|
// addr is malformed.
|
||||||
|
return netaddr.IPPort{}, err
|
||||||
|
}
|
||||||
|
if net.ParseIP(host) != nil {
|
||||||
|
// The host part of addr was an IP, so the netaddr.ParseIPPort above should've
|
||||||
|
// passed. Must've been a bad port number. Return the original error.
|
||||||
|
return netaddr.IPPort{}, pippErr
|
||||||
|
}
|
||||||
|
port16, err := strconv.ParseUint(port, 10, 16)
|
||||||
|
if err != nil {
|
||||||
|
return netaddr.IPPort{}, fmt.Errorf("invalid port in address %q", addr)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Host is not an IP, so assume it's a DNS name.
|
||||||
|
|
||||||
|
// Try MagicDNS first, else otherwise a real DNS lookup.
|
||||||
|
ns.mu.Lock()
|
||||||
|
ip := ns.dns[host]
|
||||||
|
ns.mu.Unlock()
|
||||||
|
if !ip.IsZero() {
|
||||||
|
return netaddr.IPPort{IP: ip, Port: uint16(port16)}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// No Magic DNS name so try real DNS.
|
||||||
|
var r net.Resolver
|
||||||
|
ips, err := r.LookupIP(ctx, "ip", host)
|
||||||
|
if err != nil {
|
||||||
|
return netaddr.IPPort{}, err
|
||||||
|
}
|
||||||
|
if len(ips) == 0 {
|
||||||
|
return netaddr.IPPort{}, fmt.Errorf("DNS lookup returned no results for %q", host)
|
||||||
|
}
|
||||||
|
ip, _ = netaddr.FromStdIP(ips[0])
|
||||||
|
return netaddr.IPPort{IP: ip, Port: uint16(port16)}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ns *Impl) dialContextTCP(ctx context.Context, addr string) (*gonet.TCPConn, error) {
|
||||||
|
remoteIPPort, err := ns.resolve(ctx, addr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
remoteAddress := tcpip.FullAddress{
|
remoteAddress := tcpip.FullAddress{
|
||||||
NIC: nicID,
|
NIC: nicID,
|
||||||
|
Reference in New Issue
Block a user