net/dns/resolver: add live reconfig, plumb through to ipnlocal.

The resolver still only supports a single upstream config, and
ipn/wgengine still have to split up the DNS config, but this moves
closer to unifying the DNS configs.

As a handy side-effect of the refactor, IPv6 MagicDNS records exist
now.

Signed-off-by: David Anderson <danderson@tailscale.com>
This commit is contained in:
David Anderson
2021-04-01 01:33:58 -07:00
parent caeafc4a32
commit 90f82b6946
10 changed files with 215 additions and 541 deletions
+35 -89
View File
@@ -8,7 +8,6 @@ import (
"bytes"
"errors"
"net"
"sync"
"testing"
dns "golang.org/x/net/dns/dnsmessage"
@@ -24,13 +23,13 @@ var testipv6 = netaddr.IPv6Raw([16]byte{
0x0c, 0x0d, 0x0e, 0x0f,
})
var dnsMap = NewMap(
map[string]netaddr.IP{
"test1.ipn.dev.": testipv4,
"test2.ipn.dev.": testipv6,
var dnsCfg = Config{
Hosts: map[string][]netaddr.IP{
"test1.ipn.dev.": []netaddr.IP{testipv4},
"test2.ipn.dev.": []netaddr.IP{testipv6},
},
[]string{"ipn.dev."},
)
LocalDomains: []string{"ipn.dev."},
}
func dnspacket(domain string, tp dns.Type) []byte {
var dnsHeader dns.Header
@@ -192,14 +191,14 @@ func TestRDNSNameToIPv6(t *testing.T) {
}
}
func TestResolve(t *testing.T) {
func TestResolveLocal(t *testing.T) {
r, err := New(t.Logf, nil)
if err != nil {
t.Fatalf("start: %v", err)
}
defer r.Close()
r.SetMap(dnsMap)
r.SetConfig(dnsCfg)
tests := []struct {
name string
@@ -223,10 +222,7 @@ func TestResolve(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
ip, code, err := r.resolve(tt.qname, tt.qtype)
if err != nil {
t.Errorf("err = %v; want nil", err)
}
ip, code := r.resolveLocal(tt.qname, tt.qtype)
if code != tt.code {
t.Errorf("code = %v; want %v", code, tt.code)
}
@@ -238,14 +234,14 @@ func TestResolve(t *testing.T) {
}
}
func TestResolveReverse(t *testing.T) {
func TestResolveLocalReverse(t *testing.T) {
r, err := New(t.Logf, nil)
if err != nil {
t.Fatalf("start: %v", err)
}
defer r.Close()
r.SetMap(dnsMap)
r.SetConfig(dnsCfg)
tests := []struct {
name string
@@ -260,10 +256,7 @@ func TestResolveReverse(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
name, code, err := r.resolveReverse(tt.ip)
if err != nil {
t.Errorf("err = %v; want nil", err)
}
name, code := r.resolveLocalReverse(tt.ip)
if code != tt.code {
t.Errorf("code = %v; want %v", code, tt.code)
}
@@ -323,11 +316,14 @@ func TestDelegate(t *testing.T) {
}
defer r.Close()
r.SetMap(dnsMap)
r.SetUpstreams([]net.Addr{
v4server.PacketConn.LocalAddr(),
v6server.PacketConn.LocalAddr(),
})
cfg := dnsCfg
cfg.Routes = map[string][]netaddr.IPPort{
".": {
netaddr.MustParseIPPort(v4server.PacketConn.LocalAddr().String()),
netaddr.MustParseIPPort(v6server.PacketConn.LocalAddr().String()),
},
}
r.SetConfig(cfg)
tests := []struct {
title string
@@ -402,8 +398,13 @@ func TestDelegateCollision(t *testing.T) {
}
defer r.Close()
r.SetMap(dnsMap)
r.SetUpstreams([]net.Addr{server.PacketConn.LocalAddr()})
cfg := dnsCfg
cfg.Routes = map[string][]netaddr.IPPort{
".": {
netaddr.MustParseIPPort(server.PacketConn.LocalAddr().String()),
},
}
r.SetConfig(cfg)
packets := []struct {
qname string
@@ -460,65 +461,6 @@ func TestDelegateCollision(t *testing.T) {
}
}
func TestConcurrentSetMap(t *testing.T) {
r, err := New(t.Logf, nil)
if err != nil {
t.Fatalf("start: %v", err)
}
defer r.Close()
// This is purely to ensure that Resolve does not race with SetMap.
var wg sync.WaitGroup
wg.Add(2)
go func() {
defer wg.Done()
r.SetMap(dnsMap)
}()
go func() {
defer wg.Done()
r.resolve("test1.ipn.dev", dns.TypeA)
}()
wg.Wait()
}
func TestConcurrentSetUpstreams(t *testing.T) {
dnsHandleFunc("test.site.", resolveToIP(testipv4, testipv6, "dns.test.site."))
server, errch := serveDNS(t, "127.0.0.1:0")
defer func() {
if err := <-errch; err != nil {
t.Errorf("server error: %v", err)
}
}()
if server == nil {
return
}
defer server.Shutdown()
r, err := New(t.Logf, nil)
if err != nil {
t.Fatalf("start: %v", err)
}
defer r.Close()
r.SetMap(dnsMap)
packet := dnspacket("test.site.", dns.TypeA)
// This is purely to ensure that delegation does not race with SetUpstreams.
var wg sync.WaitGroup
wg.Add(2)
go func() {
defer wg.Done()
r.SetUpstreams([]net.Addr{server.PacketConn.LocalAddr()})
}()
go func() {
defer wg.Done()
syncRespond(r, packet)
}()
wg.Wait()
}
var allResponse = []byte{
0x00, 0x00, // transaction id: 0
0x84, 0x00, // flags: response, authoritative, no error
@@ -673,7 +615,7 @@ func TestFull(t *testing.T) {
}
defer r.Close()
r.SetMap(dnsMap)
r.SetConfig(dnsCfg)
// One full packet and one error packet
tests := []struct {
@@ -711,7 +653,7 @@ func TestAllocs(t *testing.T) {
t.Fatalf("start: %v", err)
}
defer r.Close()
r.SetMap(dnsMap)
r.SetConfig(dnsCfg)
// It is seemingly pointless to test allocs in the delegate path,
// as dialer.Dial -> Read -> Write alone comprise 12 allocs.
@@ -780,8 +722,12 @@ func BenchmarkFull(b *testing.B) {
}
defer r.Close()
r.SetMap(dnsMap)
r.SetUpstreams([]net.Addr{server.PacketConn.LocalAddr()})
cfg := dnsCfg
cfg.Routes = map[string][]netaddr.IPPort{
".": {
netaddr.MustParseIPPort(server.PacketConn.LocalAddr().String()),
},
}
tests := []struct {
name string