mirror of
https://github.com/tailscale/tailscale.git
synced 2025-01-05 14:57:49 +00:00
net/dns: unify the OS manager and internal resolver.
Signed-off-by: David Anderson <danderson@tailscale.com>
This commit is contained in:
parent
1bf91c8123
commit
7d84ee6c98
@ -92,7 +92,7 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
|
||||
tailscale.com/logtail/filch from tailscale.com/logpolicy
|
||||
tailscale.com/metrics from tailscale.com/derp
|
||||
tailscale.com/net/dns from tailscale.com/ipn/ipnlocal+
|
||||
tailscale.com/net/dns/resolver from tailscale.com/wgengine
|
||||
tailscale.com/net/dns/resolver from tailscale.com/wgengine+
|
||||
tailscale.com/net/dnscache from tailscale.com/control/controlclient+
|
||||
tailscale.com/net/dnsfallback from tailscale.com/control/controlclient
|
||||
tailscale.com/net/flowtrack from tailscale.com/wgengine/filter+
|
||||
|
@ -43,32 +43,3 @@ type OSConfig struct {
|
||||
// Domains are the search domains to use.
|
||||
Domains []string
|
||||
}
|
||||
|
||||
// Equal determines whether its argument and receiver
|
||||
// represent equivalent DNS configurations (then DNS reconfig is a no-op).
|
||||
func (lhs OSConfig) Equal(rhs OSConfig) bool {
|
||||
if len(lhs.Nameservers) != len(rhs.Nameservers) {
|
||||
return false
|
||||
}
|
||||
|
||||
if len(lhs.Domains) != len(rhs.Domains) {
|
||||
return false
|
||||
}
|
||||
|
||||
// With how we perform resolution order shouldn't matter,
|
||||
// but it is unlikely that we will encounter different orders.
|
||||
for i, server := range lhs.Nameservers {
|
||||
if rhs.Nameservers[i] != server {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// The order of domains, on the other hand, is significant.
|
||||
for i, domain := range lhs.Domains {
|
||||
if rhs.Domains[i] != domain {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
@ -7,7 +7,11 @@
|
||||
import (
|
||||
"time"
|
||||
|
||||
"inet.af/netaddr"
|
||||
"tailscale.com/net/dns/resolver"
|
||||
"tailscale.com/net/tsaddr"
|
||||
"tailscale.com/types/logger"
|
||||
"tailscale.com/wgengine/monitor"
|
||||
)
|
||||
|
||||
// We use file-ignore below instead of ignore because on some platforms,
|
||||
@ -27,54 +31,82 @@
|
||||
type Manager struct {
|
||||
logf logger.Logf
|
||||
|
||||
os OSConfigurator
|
||||
resolver *resolver.Resolver
|
||||
os OSConfigurator
|
||||
|
||||
config OSConfig
|
||||
config Config
|
||||
}
|
||||
|
||||
// NewManagers created a new manager from the given config.
|
||||
func NewManager(logf logger.Logf, oscfg OSConfigurator) *Manager {
|
||||
func NewManager(logf logger.Logf, oscfg OSConfigurator, linkMon *monitor.Mon) *Manager {
|
||||
logf = logger.WithPrefix(logf, "dns: ")
|
||||
m := &Manager{
|
||||
logf: logf,
|
||||
os: oscfg,
|
||||
logf: logf,
|
||||
resolver: resolver.New(logf, linkMon),
|
||||
os: oscfg,
|
||||
}
|
||||
|
||||
m.logf("using %T", m.os)
|
||||
return m
|
||||
}
|
||||
|
||||
func (m *Manager) Set(config OSConfig) error {
|
||||
if config.Equal(m.config) {
|
||||
return nil
|
||||
func (m *Manager) Set(cfg Config) error {
|
||||
m.logf("Set: %+v", cfg)
|
||||
|
||||
if len(cfg.DefaultResolvers) == 0 {
|
||||
// TODO: make other settings work even if you didn't set a
|
||||
// default resolver. For now, no default resolvers == no
|
||||
// managed DNS config.
|
||||
cfg = Config{}
|
||||
}
|
||||
|
||||
m.logf("Set: %+v", config)
|
||||
|
||||
if len(config.Nameservers) == 0 {
|
||||
err := m.os.Set(OSConfig{})
|
||||
// If we save the config, we will not retry next time. Only do this on success.
|
||||
if err == nil {
|
||||
m.config = config
|
||||
resolverCfg := resolver.Config{
|
||||
Hosts: cfg.Hosts,
|
||||
LocalDomains: cfg.AuthoritativeSuffixes,
|
||||
Routes: map[string][]netaddr.IPPort{},
|
||||
}
|
||||
osCfg := OSConfig{
|
||||
Domains: cfg.SearchDomains,
|
||||
}
|
||||
// We must proxy through quad-100 if MagicDNS hosts are in
|
||||
// use, or there are any per-domain routes.
|
||||
mustProxy := len(cfg.Hosts) > 0 || len(cfg.Routes) > 0
|
||||
if mustProxy {
|
||||
osCfg.Nameservers = []netaddr.IP{tsaddr.TailscaleServiceIP()}
|
||||
resolverCfg.Routes["."] = cfg.DefaultResolvers
|
||||
for suffix, resolvers := range cfg.Routes {
|
||||
resolverCfg.Routes[suffix] = resolvers
|
||||
}
|
||||
} else {
|
||||
for _, resolver := range cfg.DefaultResolvers {
|
||||
osCfg.Nameservers = append(osCfg.Nameservers, resolver.IP)
|
||||
}
|
||||
}
|
||||
|
||||
if err := m.resolver.SetConfig(resolverCfg); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := m.os.Set(osCfg); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err := m.os.Set(config)
|
||||
// If we save the config, we will not retry next time. Only do this on success.
|
||||
if err == nil {
|
||||
m.config = config
|
||||
}
|
||||
|
||||
return err
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Manager) Up() error {
|
||||
return m.os.Set(m.config)
|
||||
func (m *Manager) EnqueueRequest(bs []byte, from netaddr.IPPort) error {
|
||||
return m.resolver.EnqueueRequest(bs, from)
|
||||
}
|
||||
|
||||
func (m *Manager) NextResponse() ([]byte, netaddr.IPPort, error) {
|
||||
return m.resolver.NextResponse()
|
||||
}
|
||||
|
||||
func (m *Manager) Down() error {
|
||||
return m.os.Close()
|
||||
if err := m.os.Close(); err != nil {
|
||||
return err
|
||||
}
|
||||
m.resolver.Close()
|
||||
return nil
|
||||
}
|
||||
|
||||
// Cleanup restores the system DNS configuration to its original state
|
||||
@ -82,7 +114,7 @@ func (m *Manager) Down() error {
|
||||
// No other state needs to be instantiated before this runs.
|
||||
func Cleanup(logf logger.Logf, interfaceName string) {
|
||||
oscfg := NewOSConfigurator(logf, interfaceName)
|
||||
dns := NewManager(logf, oscfg)
|
||||
dns := NewManager(logf, oscfg, nil)
|
||||
if err := dns.Down(); err != nil {
|
||||
logf("dns down: %v", err)
|
||||
}
|
||||
|
@ -85,7 +85,6 @@ type userspaceEngine struct {
|
||||
wgdev *device.Device
|
||||
router router.Router
|
||||
dns *dns.Manager
|
||||
resolver *resolver.Resolver
|
||||
magicConn *magicsock.Conn
|
||||
linkMon *monitor.Mon
|
||||
linkMonOwned bool // whether we created linkMon (and thus need to close it)
|
||||
@ -213,7 +212,6 @@ func NewUserspaceEngine(logf logger.Logf, conf Config) (_ Engine, reterr error)
|
||||
waitCh: make(chan struct{}),
|
||||
tundev: tsTUNDev,
|
||||
router: conf.Router,
|
||||
dns: dns.NewManager(logf, conf.DNS),
|
||||
pingers: make(map[wgkey.Key]*pinger),
|
||||
}
|
||||
e.isLocalAddr.Store(genLocalAddrFunc(nil))
|
||||
@ -230,7 +228,7 @@ func NewUserspaceEngine(logf logger.Logf, conf Config) (_ Engine, reterr error)
|
||||
e.linkMonOwned = true
|
||||
}
|
||||
|
||||
e.resolver = resolver.New(logf, e.linkMon)
|
||||
e.dns = dns.NewManager(logf, conf.DNS, e.linkMon)
|
||||
|
||||
logf("link state: %+v", e.linkMon.InterfaceState())
|
||||
|
||||
@ -443,7 +441,7 @@ func (e *userspaceEngine) handleLocalPackets(p *packet.Parsed, t *tstun.Wrapper)
|
||||
// handleDNS is an outbound pre-filter resolving Tailscale domains.
|
||||
func (e *userspaceEngine) handleDNS(p *packet.Parsed, t *tstun.Wrapper) filter.Response {
|
||||
if p.Dst.IP == magicDNSIP && p.Dst.Port == magicDNSPort && p.IPProto == ipproto.UDP {
|
||||
err := e.resolver.EnqueueRequest(append([]byte(nil), p.Payload()...), p.Src)
|
||||
err := e.dns.EnqueueRequest(append([]byte(nil), p.Payload()...), p.Src)
|
||||
if err != nil {
|
||||
e.logf("dns: enqueue: %v", err)
|
||||
}
|
||||
@ -455,7 +453,7 @@ func (e *userspaceEngine) handleDNS(p *packet.Parsed, t *tstun.Wrapper) filter.R
|
||||
// pollResolver reads responses from the DNS resolver and injects them inbound.
|
||||
func (e *userspaceEngine) pollResolver() {
|
||||
for {
|
||||
bs, to, err := e.resolver.NextResponse()
|
||||
bs, to, err := e.dns.NextResponse()
|
||||
if err == resolver.ErrClosed {
|
||||
return
|
||||
}
|
||||
@ -992,37 +990,8 @@ func (e *userspaceEngine) Reconfig(cfg *wgcfg.Config, routerCfg *router.Config,
|
||||
}
|
||||
|
||||
if routerChanged {
|
||||
resolverCfg := resolver.Config{
|
||||
Hosts: dnsCfg.Hosts,
|
||||
LocalDomains: dnsCfg.AuthoritativeSuffixes,
|
||||
Routes: map[string][]netaddr.IPPort{},
|
||||
}
|
||||
osCfg := dns.OSConfig{
|
||||
Domains: dnsCfg.SearchDomains,
|
||||
}
|
||||
// We must proxy through quad-100 if MagicDNS hosts are in
|
||||
// use, or there are any per-domain routes.
|
||||
mustProxy := len(dnsCfg.Hosts) > 0 || len(dnsCfg.Routes) > 0
|
||||
if mustProxy {
|
||||
osCfg.Nameservers = []netaddr.IP{tsaddr.TailscaleServiceIP()}
|
||||
resolverCfg.Routes["."] = dnsCfg.DefaultResolvers
|
||||
for suffix, resolvers := range dnsCfg.Routes {
|
||||
resolverCfg.Routes[suffix] = resolvers
|
||||
}
|
||||
} else {
|
||||
for _, resolver := range dnsCfg.DefaultResolvers {
|
||||
osCfg.Nameservers = append(osCfg.Nameservers, resolver.IP)
|
||||
}
|
||||
}
|
||||
osCfg.Domains = dnsCfg.SearchDomains
|
||||
|
||||
e.logf("wgengine: Reconfig: configuring DNS")
|
||||
err := e.resolver.SetConfig(resolverCfg)
|
||||
health.SetDNSHealth(err)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = e.dns.Set(osCfg)
|
||||
err := e.dns.Set(*dnsCfg)
|
||||
health.SetDNSHealth(err)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -1241,12 +1210,12 @@ func (e *userspaceEngine) Close() {
|
||||
|
||||
r := bufio.NewReader(strings.NewReader(""))
|
||||
e.wgdev.IpcSetOperation(r)
|
||||
e.resolver.Close()
|
||||
e.magicConn.Close()
|
||||
e.linkMonUnregister()
|
||||
if e.linkMonOwned {
|
||||
e.linkMon.Close()
|
||||
}
|
||||
e.dns.Down()
|
||||
e.router.Close()
|
||||
e.wgdev.Close()
|
||||
e.tundev.Close()
|
||||
|
Loading…
x
Reference in New Issue
Block a user