mirror of https://github.com/tailscale/tailscale/
net/dns: add tests for DNS config generation.
Part of #953. Signed-off-by: David Anderson <danderson@tailscale.com>pull/1677/head
parent
0ba6d03768
commit
fe9cd61d71
@ -0,0 +1,397 @@
|
||||
// Copyright (c) 2021 Tailscale Inc & AUTHORS All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package dns
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/google/go-cmp/cmp/cmpopts"
|
||||
"inet.af/netaddr"
|
||||
"tailscale.com/net/dns/resolver"
|
||||
)
|
||||
|
||||
type fakeOSConfigurator struct {
|
||||
SplitDNS bool
|
||||
|
||||
OSConfig OSConfig
|
||||
ResolverConfig resolver.Config
|
||||
}
|
||||
|
||||
func (c *fakeOSConfigurator) SetDNS(cfg OSConfig) error {
|
||||
if !c.SplitDNS && len(cfg.MatchDomains) > 0 {
|
||||
panic("split DNS config passed to non-split OSConfigurator")
|
||||
}
|
||||
c.OSConfig = cfg
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *fakeOSConfigurator) SetResolver(cfg resolver.Config) {
|
||||
c.ResolverConfig = cfg
|
||||
}
|
||||
|
||||
func (c *fakeOSConfigurator) SupportsSplitDNS() bool {
|
||||
return c.SplitDNS
|
||||
}
|
||||
|
||||
func (c *fakeOSConfigurator) Close() error { return nil }
|
||||
|
||||
func TestManager(t *testing.T) {
|
||||
// Note: these tests assume that it's safe to switch the
|
||||
// OSConfigurator's split-dns support on and off between Set
|
||||
// calls. Empirically this is currently true, because we reprobe
|
||||
// the support every time we generate configs. It would be
|
||||
// reasonable to make this unsupported as well, in which case
|
||||
// these tests will need tweaking.
|
||||
tests := []struct {
|
||||
name string
|
||||
in Config
|
||||
split bool
|
||||
os OSConfig
|
||||
rs resolver.Config
|
||||
}{
|
||||
{
|
||||
name: "empty",
|
||||
},
|
||||
{
|
||||
name: "search-only",
|
||||
in: Config{
|
||||
SearchDomains: strs("tailscale.com", "universe.tf"),
|
||||
},
|
||||
os: OSConfig{
|
||||
SearchDomains: strs("tailscale.com", "universe.tf"),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "corp",
|
||||
in: Config{
|
||||
DefaultResolvers: mustIPPs("1.1.1.1:53", "9.9.9.9:53"),
|
||||
SearchDomains: strs("tailscale.com", "universe.tf"),
|
||||
},
|
||||
os: OSConfig{
|
||||
Nameservers: mustIPs("1.1.1.1", "9.9.9.9"),
|
||||
SearchDomains: strs("tailscale.com", "universe.tf"),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "corp-split",
|
||||
in: Config{
|
||||
DefaultResolvers: mustIPPs("1.1.1.1:53", "9.9.9.9:53"),
|
||||
SearchDomains: strs("tailscale.com", "universe.tf"),
|
||||
},
|
||||
split: true,
|
||||
os: OSConfig{
|
||||
Nameservers: mustIPs("1.1.1.1", "9.9.9.9"),
|
||||
SearchDomains: strs("tailscale.com", "universe.tf"),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "corp-magic",
|
||||
in: Config{
|
||||
DefaultResolvers: mustIPPs("1.1.1.1:53", "9.9.9.9:53"),
|
||||
SearchDomains: strs("tailscale.com", "universe.tf"),
|
||||
Hosts: hosts(
|
||||
"dave.ts.com.", "1.2.3.4",
|
||||
"bradfitz.ts.com.", "2.3.4.5"),
|
||||
AuthoritativeSuffixes: strs("ts.com"),
|
||||
},
|
||||
os: OSConfig{
|
||||
Nameservers: mustIPs("100.100.100.100"),
|
||||
SearchDomains: strs("tailscale.com", "universe.tf"),
|
||||
},
|
||||
rs: resolver.Config{
|
||||
Routes: upstreams(".", "1.1.1.1:53", "9.9.9.9:53"),
|
||||
Hosts: hosts(
|
||||
"dave.ts.com.", "1.2.3.4",
|
||||
"bradfitz.ts.com.", "2.3.4.5"),
|
||||
LocalDomains: strs("ts.com."),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "corp-magic-split",
|
||||
in: Config{
|
||||
DefaultResolvers: mustIPPs("1.1.1.1:53", "9.9.9.9:53"),
|
||||
SearchDomains: strs("tailscale.com", "universe.tf"),
|
||||
Hosts: hosts(
|
||||
"dave.ts.com.", "1.2.3.4",
|
||||
"bradfitz.ts.com.", "2.3.4.5"),
|
||||
AuthoritativeSuffixes: strs("ts.com"),
|
||||
},
|
||||
split: true,
|
||||
os: OSConfig{
|
||||
Nameservers: mustIPs("100.100.100.100"),
|
||||
SearchDomains: strs("tailscale.com", "universe.tf"),
|
||||
},
|
||||
rs: resolver.Config{
|
||||
Routes: upstreams(".", "1.1.1.1:53", "9.9.9.9:53"),
|
||||
Hosts: hosts(
|
||||
"dave.ts.com.", "1.2.3.4",
|
||||
"bradfitz.ts.com.", "2.3.4.5"),
|
||||
LocalDomains: strs("ts.com."),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "corp-routes",
|
||||
in: Config{
|
||||
DefaultResolvers: mustIPPs("1.1.1.1:53", "9.9.9.9:53"),
|
||||
Routes: upstreams("corp.com", "2.2.2.2:53"),
|
||||
SearchDomains: strs("tailscale.com", "universe.tf"),
|
||||
},
|
||||
os: OSConfig{
|
||||
Nameservers: mustIPs("100.100.100.100"),
|
||||
SearchDomains: strs("tailscale.com", "universe.tf"),
|
||||
},
|
||||
rs: resolver.Config{
|
||||
Routes: upstreams(
|
||||
".", "1.1.1.1:53", "9.9.9.9:53",
|
||||
"corp.com.", "2.2.2.2:53"),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "corp-routes-split",
|
||||
in: Config{
|
||||
DefaultResolvers: mustIPPs("1.1.1.1:53", "9.9.9.9:53"),
|
||||
Routes: upstreams("corp.com", "2.2.2.2:53"),
|
||||
SearchDomains: strs("tailscale.com", "universe.tf"),
|
||||
},
|
||||
split: true,
|
||||
os: OSConfig{
|
||||
Nameservers: mustIPs("100.100.100.100"),
|
||||
SearchDomains: strs("tailscale.com", "universe.tf"),
|
||||
},
|
||||
rs: resolver.Config{
|
||||
Routes: upstreams(
|
||||
".", "1.1.1.1:53", "9.9.9.9:53",
|
||||
"corp.com.", "2.2.2.2:53"),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "routes",
|
||||
in: Config{
|
||||
Routes: upstreams("corp.com", "2.2.2.2:53"),
|
||||
SearchDomains: strs("tailscale.com", "universe.tf"),
|
||||
},
|
||||
os: OSConfig{
|
||||
Nameservers: mustIPs("100.100.100.100"),
|
||||
SearchDomains: strs("tailscale.com", "universe.tf"),
|
||||
},
|
||||
rs: resolver.Config{
|
||||
Routes: upstreams(
|
||||
".", "8.8.8.8:53",
|
||||
"corp.com.", "2.2.2.2:53"),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "routes-split",
|
||||
in: Config{
|
||||
Routes: upstreams("corp.com", "2.2.2.2:53"),
|
||||
SearchDomains: strs("tailscale.com", "universe.tf"),
|
||||
},
|
||||
split: true,
|
||||
os: OSConfig{
|
||||
Nameservers: mustIPs("2.2.2.2"),
|
||||
SearchDomains: strs("tailscale.com", "universe.tf"),
|
||||
MatchDomains: strs("corp.com"),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "routes-multi",
|
||||
in: Config{
|
||||
Routes: upstreams(
|
||||
"corp.com", "2.2.2.2:53",
|
||||
"bigco.net", "3.3.3.3:53"),
|
||||
SearchDomains: strs("tailscale.com", "universe.tf"),
|
||||
},
|
||||
os: OSConfig{
|
||||
Nameservers: mustIPs("100.100.100.100"),
|
||||
SearchDomains: strs("tailscale.com", "universe.tf"),
|
||||
},
|
||||
rs: resolver.Config{
|
||||
Routes: upstreams(
|
||||
".", "8.8.8.8:53",
|
||||
"corp.com.", "2.2.2.2:53",
|
||||
"bigco.net.", "3.3.3.3:53"),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "routes-multi-split",
|
||||
in: Config{
|
||||
Routes: upstreams(
|
||||
"corp.com", "2.2.2.2:53",
|
||||
"bigco.net", "3.3.3.3:53"),
|
||||
SearchDomains: strs("tailscale.com", "universe.tf"),
|
||||
},
|
||||
split: true,
|
||||
os: OSConfig{
|
||||
Nameservers: mustIPs("100.100.100.100"),
|
||||
SearchDomains: strs("tailscale.com", "universe.tf"),
|
||||
MatchDomains: strs("corp.com", "bigco.net"),
|
||||
},
|
||||
rs: resolver.Config{
|
||||
Routes: upstreams(
|
||||
"corp.com.", "2.2.2.2:53",
|
||||
"bigco.net.", "3.3.3.3:53"),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "magic",
|
||||
in: Config{
|
||||
Hosts: hosts(
|
||||
"dave.ts.com.", "1.2.3.4",
|
||||
"bradfitz.ts.com.", "2.3.4.5"),
|
||||
AuthoritativeSuffixes: strs("ts.com"),
|
||||
SearchDomains: strs("tailscale.com", "universe.tf"),
|
||||
},
|
||||
os: OSConfig{
|
||||
Nameservers: mustIPs("100.100.100.100"),
|
||||
SearchDomains: strs("tailscale.com", "universe.tf"),
|
||||
},
|
||||
rs: resolver.Config{
|
||||
Routes: upstreams(".", "8.8.8.8:53"),
|
||||
Hosts: hosts(
|
||||
"dave.ts.com.", "1.2.3.4",
|
||||
"bradfitz.ts.com.", "2.3.4.5"),
|
||||
LocalDomains: strs("ts.com."),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "magic-split",
|
||||
in: Config{
|
||||
Hosts: hosts(
|
||||
"dave.ts.com.", "1.2.3.4",
|
||||
"bradfitz.ts.com.", "2.3.4.5"),
|
||||
AuthoritativeSuffixes: strs("ts.com"),
|
||||
SearchDomains: strs("tailscale.com", "universe.tf"),
|
||||
},
|
||||
split: true,
|
||||
os: OSConfig{
|
||||
Nameservers: mustIPs("100.100.100.100"),
|
||||
SearchDomains: strs("tailscale.com", "universe.tf"),
|
||||
MatchDomains: strs("ts.com"),
|
||||
},
|
||||
rs: resolver.Config{
|
||||
Hosts: hosts(
|
||||
"dave.ts.com.", "1.2.3.4",
|
||||
"bradfitz.ts.com.", "2.3.4.5"),
|
||||
LocalDomains: strs("ts.com."),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "routes-magic",
|
||||
in: Config{
|
||||
Routes: upstreams("corp.com", "2.2.2.2:53"),
|
||||
Hosts: hosts(
|
||||
"dave.ts.com.", "1.2.3.4",
|
||||
"bradfitz.ts.com.", "2.3.4.5"),
|
||||
AuthoritativeSuffixes: strs("ts.com"),
|
||||
SearchDomains: strs("tailscale.com", "universe.tf"),
|
||||
},
|
||||
os: OSConfig{
|
||||
Nameservers: mustIPs("100.100.100.100"),
|
||||
SearchDomains: strs("tailscale.com", "universe.tf"),
|
||||
},
|
||||
rs: resolver.Config{
|
||||
Routes: upstreams(
|
||||
"corp.com.", "2.2.2.2:53",
|
||||
".", "8.8.8.8:53"),
|
||||
Hosts: hosts(
|
||||
"dave.ts.com.", "1.2.3.4",
|
||||
"bradfitz.ts.com.", "2.3.4.5"),
|
||||
LocalDomains: strs("ts.com."),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "routes-magic-split",
|
||||
in: Config{
|
||||
Routes: upstreams("corp.com", "2.2.2.2:53"),
|
||||
Hosts: hosts(
|
||||
"dave.ts.com.", "1.2.3.4",
|
||||
"bradfitz.ts.com.", "2.3.4.5"),
|
||||
AuthoritativeSuffixes: strs("ts.com"),
|
||||
SearchDomains: strs("tailscale.com", "universe.tf"),
|
||||
},
|
||||
split: true,
|
||||
os: OSConfig{
|
||||
Nameservers: mustIPs("100.100.100.100"),
|
||||
SearchDomains: strs("tailscale.com", "universe.tf"),
|
||||
MatchDomains: strs("ts.com", "corp.com"),
|
||||
},
|
||||
rs: resolver.Config{
|
||||
Routes: upstreams("corp.com.", "2.2.2.2:53"),
|
||||
Hosts: hosts(
|
||||
"dave.ts.com.", "1.2.3.4",
|
||||
"bradfitz.ts.com.", "2.3.4.5"),
|
||||
LocalDomains: strs("ts.com."),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
f := fakeOSConfigurator{SplitDNS: test.split}
|
||||
m := NewManager(t.Logf, &f, nil)
|
||||
m.resolver.TestOnlySetHook(f.SetResolver)
|
||||
|
||||
if err := m.Set(test.in); err != nil {
|
||||
t.Fatalf("m.Set: %v", err)
|
||||
}
|
||||
tr := cmp.Transformer("ipStr", func(ip netaddr.IP) string { return ip.String() })
|
||||
if diff := cmp.Diff(f.OSConfig, test.os, tr, cmpopts.EquateEmpty()); diff != "" {
|
||||
t.Errorf("wrong OSConfig (-got+want)\n%s", diff)
|
||||
}
|
||||
if diff := cmp.Diff(f.ResolverConfig, test.rs, tr, cmpopts.EquateEmpty()); diff != "" {
|
||||
t.Errorf("wrong resolver.Config (-got+want)\n%s", diff)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func mustIPs(strs ...string) (ret []netaddr.IP) {
|
||||
for _, s := range strs {
|
||||
ret = append(ret, netaddr.MustParseIP(s))
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func mustIPPs(strs ...string) (ret []netaddr.IPPort) {
|
||||
for _, s := range strs {
|
||||
ret = append(ret, netaddr.MustParseIPPort(s))
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func strs(strs ...string) []string { return strs }
|
||||
|
||||
func hosts(strs ...string) (ret map[string][]netaddr.IP) {
|
||||
var key string
|
||||
ret = map[string][]netaddr.IP{}
|
||||
for _, s := range strs {
|
||||
if ip, err := netaddr.ParseIP(s); err == nil {
|
||||
if key == "" {
|
||||
panic("IP provided before name")
|
||||
}
|
||||
ret[key] = append(ret[key], ip)
|
||||
} else {
|
||||
key = s
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func upstreams(strs ...string) (ret map[string][]netaddr.IPPort) {
|
||||
var key string
|
||||
ret = map[string][]netaddr.IPPort{}
|
||||
for _, s := range strs {
|
||||
if ipp, err := netaddr.ParseIPPort(s); err == nil {
|
||||
if key == "" {
|
||||
panic("IPPort provided before suffix")
|
||||
}
|
||||
ret[key] = append(ret[key], ipp)
|
||||
} else {
|
||||
key = s
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
Loading…
Reference in New Issue