mirror of
https://github.com/tailscale/tailscale.git
synced 2025-12-03 10:31:59 +00:00
tsdns: dual resolution mode, IPv6 support (#526)
This change adds to tsdns the ability to delegate lookups to upstream nameservers. This is crucial for setting Magic DNS as the system resolver. Signed-off-by: Dmytro Shynkevych <dmytro@tailscale.com>
This commit is contained in:
committed by
GitHub
parent
ce1b52bb71
commit
67ebba90e1
@@ -25,6 +25,7 @@ import (
|
||||
"github.com/tailscale/wireguard-go/tun"
|
||||
"github.com/tailscale/wireguard-go/wgcfg"
|
||||
"go4.org/mem"
|
||||
"inet.af/netaddr"
|
||||
"tailscale.com/control/controlclient"
|
||||
"tailscale.com/internal/deepprint"
|
||||
"tailscale.com/ipn/ipnstate"
|
||||
@@ -51,6 +52,11 @@ import (
|
||||
// discovery.
|
||||
const minimalMTU = 1280
|
||||
|
||||
const (
|
||||
magicDNSIP = 0x64646464 // 100.100.100.100
|
||||
magicDNSPort = 53
|
||||
)
|
||||
|
||||
type userspaceEngine struct {
|
||||
logf logger.Logf
|
||||
reqCh chan struct{}
|
||||
@@ -100,7 +106,7 @@ type EngineConfig struct {
|
||||
// EchoRespondToAll determines whether ICMP Echo requests incoming from Tailscale peers
|
||||
// will be intercepted and responded to, regardless of the source host.
|
||||
EchoRespondToAll bool
|
||||
// UseTailscaleDNS determines whether DNS requests for names of the form *.ipn.dev
|
||||
// UseTailscaleDNS determines whether DNS requests for names of the form <mynode>.<mydomain>.<root>
|
||||
// directed to the designated Taislcale DNS address (see wgengine/tsdns)
|
||||
// will be intercepted and resolved by a tsdns.Resolver.
|
||||
UseTailscaleDNS bool
|
||||
@@ -174,7 +180,7 @@ func newUserspaceEngineAdvanced(conf EngineConfig) (_ Engine, reterr error) {
|
||||
reqCh: make(chan struct{}, 1),
|
||||
waitCh: make(chan struct{}),
|
||||
tundev: tstun.WrapTUN(logf, conf.TUN),
|
||||
resolver: tsdns.NewResolver(logf),
|
||||
resolver: tsdns.NewResolver(logf, "tailscale.us"),
|
||||
useTailscaleDNS: conf.UseTailscaleDNS,
|
||||
pingers: make(map[wgcfg.Key]*pinger),
|
||||
}
|
||||
@@ -308,6 +314,9 @@ func newUserspaceEngineAdvanced(conf EngineConfig) (_ Engine, reterr error) {
|
||||
e.linkMon.Start()
|
||||
e.magicConn.Start()
|
||||
|
||||
e.resolver.Start()
|
||||
go e.pollResolver()
|
||||
|
||||
return e, nil
|
||||
}
|
||||
|
||||
@@ -360,22 +369,52 @@ func (e *userspaceEngine) isLocalAddr(ip packet.IP) bool {
|
||||
|
||||
// handleDNS is an outbound pre-filter resolving Tailscale domains.
|
||||
func (e *userspaceEngine) handleDNS(p *packet.ParsedPacket, t *tstun.TUN) filter.Response {
|
||||
if e.resolver.AcceptsPacket(p) {
|
||||
// TODO(dmytro): avoid this allocation without having tsdns know tstun quirks.
|
||||
buf := make([]byte, tstun.MaxPacketSize)
|
||||
offset := tstun.PacketStartOffset
|
||||
response, err := e.resolver.Respond(p, buf[offset:])
|
||||
if err != nil {
|
||||
e.logf("DNS resolver error: %v", err)
|
||||
} else {
|
||||
t.InjectInboundDirect(buf[:offset+len(response)], offset)
|
||||
if p.DstIP == magicDNSIP && p.DstPort == magicDNSPort && p.IPProto == packet.UDP {
|
||||
request := tsdns.Packet{
|
||||
Payload: p.Payload(),
|
||||
Addr: netaddr.IPPort{IP: p.SrcIP.Netaddr(), Port: p.SrcPort},
|
||||
}
|
||||
err := e.resolver.EnqueueRequest(request)
|
||||
if err != nil {
|
||||
e.logf("tsdns: enqueue: %v", err)
|
||||
}
|
||||
// We already handled it, stop.
|
||||
return filter.Drop
|
||||
}
|
||||
return filter.Accept
|
||||
}
|
||||
|
||||
// pollResolver reads responses from the DNS resolver and injects them inbound.
|
||||
func (e *userspaceEngine) pollResolver() {
|
||||
for {
|
||||
resp, err := e.resolver.NextResponse()
|
||||
if err == tsdns.ErrClosed {
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
e.logf("tsdns: error: %v", err)
|
||||
continue
|
||||
}
|
||||
|
||||
h := packet.UDPHeader{
|
||||
IPHeader: packet.IPHeader{
|
||||
SrcIP: packet.IP(magicDNSIP),
|
||||
DstIP: packet.IPFromNetaddr(resp.Addr.IP),
|
||||
},
|
||||
SrcPort: magicDNSPort,
|
||||
DstPort: resp.Addr.Port,
|
||||
}
|
||||
hlen := h.Len()
|
||||
|
||||
// TODO(dmytro): avoid this allocation without importing tstun quirks into tsdns.
|
||||
const offset = tstun.PacketStartOffset
|
||||
buf := make([]byte, offset+hlen+len(resp.Payload))
|
||||
copy(buf[offset+hlen:], resp.Payload)
|
||||
h.Marshal(buf[offset:])
|
||||
|
||||
e.tundev.InjectInboundDirect(buf, offset)
|
||||
}
|
||||
}
|
||||
|
||||
// pinger sends ping packets for a few seconds.
|
||||
//
|
||||
// These generated packets are used to ensure we trigger the spray logic in
|
||||
@@ -759,6 +798,7 @@ func (e *userspaceEngine) Close() {
|
||||
|
||||
r := bufio.NewReader(strings.NewReader(""))
|
||||
e.wgdev.IpcSetOperation(r)
|
||||
e.resolver.Close()
|
||||
e.magicConn.Close()
|
||||
e.linkMon.Close()
|
||||
e.router.Close()
|
||||
|
||||
Reference in New Issue
Block a user