|
|
|
|
@ -7,7 +7,11 @@ package dns |
|
|
|
|
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 @@ const reconfigTimeout = time.Second |
|
|
|
|
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) |
|
|
|
|
|
|
|
|
|
m.logf("Set: %+v", config) |
|
|
|
|
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{} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
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) |
|
|
|
|
} |
|
|
|
|
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 |
|
|
|
|
if err := m.resolver.SetConfig(resolverCfg); err != nil { |
|
|
|
|
return err |
|
|
|
|
} |
|
|
|
|
if err := m.os.Set(osCfg); err != nil { |
|
|
|
|
return err |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return err |
|
|
|
|
func (m *Manager) EnqueueRequest(bs []byte, from netaddr.IPPort) error { |
|
|
|
|
return m.resolver.EnqueueRequest(bs, from) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (m *Manager) Up() error { |
|
|
|
|
return m.os.Set(m.config) |
|
|
|
|
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) |
|
|
|
|
} |
|
|
|
|
|