mirror of
https://github.com/tailscale/tailscale.git
synced 2025-05-04 22:52:11 +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/logtail/filch from tailscale.com/logpolicy
|
||||||
tailscale.com/metrics from tailscale.com/derp
|
tailscale.com/metrics from tailscale.com/derp
|
||||||
tailscale.com/net/dns from tailscale.com/ipn/ipnlocal+
|
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/dnscache from tailscale.com/control/controlclient+
|
||||||
tailscale.com/net/dnsfallback from tailscale.com/control/controlclient
|
tailscale.com/net/dnsfallback from tailscale.com/control/controlclient
|
||||||
tailscale.com/net/flowtrack from tailscale.com/wgengine/filter+
|
tailscale.com/net/flowtrack from tailscale.com/wgengine/filter+
|
||||||
|
@ -43,32 +43,3 @@ type OSConfig struct {
|
|||||||
// Domains are the search domains to use.
|
// Domains are the search domains to use.
|
||||||
Domains []string
|
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 @@ package dns
|
|||||||
import (
|
import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"inet.af/netaddr"
|
||||||
|
"tailscale.com/net/dns/resolver"
|
||||||
|
"tailscale.com/net/tsaddr"
|
||||||
"tailscale.com/types/logger"
|
"tailscale.com/types/logger"
|
||||||
|
"tailscale.com/wgengine/monitor"
|
||||||
)
|
)
|
||||||
|
|
||||||
// We use file-ignore below instead of ignore because on some platforms,
|
// We use file-ignore below instead of ignore because on some platforms,
|
||||||
@ -27,16 +31,18 @@ const reconfigTimeout = time.Second
|
|||||||
type Manager struct {
|
type Manager struct {
|
||||||
logf logger.Logf
|
logf logger.Logf
|
||||||
|
|
||||||
|
resolver *resolver.Resolver
|
||||||
os OSConfigurator
|
os OSConfigurator
|
||||||
|
|
||||||
config OSConfig
|
config Config
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewManagers created a new manager from the given 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: ")
|
logf = logger.WithPrefix(logf, "dns: ")
|
||||||
m := &Manager{
|
m := &Manager{
|
||||||
logf: logf,
|
logf: logf,
|
||||||
|
resolver: resolver.New(logf, linkMon),
|
||||||
os: oscfg,
|
os: oscfg,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -44,37 +50,63 @@ func NewManager(logf logger.Logf, oscfg OSConfigurator) *Manager {
|
|||||||
return m
|
return m
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Manager) Set(config OSConfig) error {
|
func (m *Manager) Set(cfg Config) error {
|
||||||
if config.Equal(m.config) {
|
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{}
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
m.logf("Set: %+v", config)
|
func (m *Manager) EnqueueRequest(bs []byte, from netaddr.IPPort) error {
|
||||||
|
return m.resolver.EnqueueRequest(bs, from)
|
||||||
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
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
err := m.os.Set(config)
|
func (m *Manager) NextResponse() ([]byte, netaddr.IPPort, error) {
|
||||||
// If we save the config, we will not retry next time. Only do this on success.
|
return m.resolver.NextResponse()
|
||||||
if err == nil {
|
|
||||||
m.config = config
|
|
||||||
}
|
|
||||||
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Manager) Up() error {
|
|
||||||
return m.os.Set(m.config)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Manager) Down() error {
|
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
|
// 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.
|
// No other state needs to be instantiated before this runs.
|
||||||
func Cleanup(logf logger.Logf, interfaceName string) {
|
func Cleanup(logf logger.Logf, interfaceName string) {
|
||||||
oscfg := NewOSConfigurator(logf, interfaceName)
|
oscfg := NewOSConfigurator(logf, interfaceName)
|
||||||
dns := NewManager(logf, oscfg)
|
dns := NewManager(logf, oscfg, nil)
|
||||||
if err := dns.Down(); err != nil {
|
if err := dns.Down(); err != nil {
|
||||||
logf("dns down: %v", err)
|
logf("dns down: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -85,7 +85,6 @@ type userspaceEngine struct {
|
|||||||
wgdev *device.Device
|
wgdev *device.Device
|
||||||
router router.Router
|
router router.Router
|
||||||
dns *dns.Manager
|
dns *dns.Manager
|
||||||
resolver *resolver.Resolver
|
|
||||||
magicConn *magicsock.Conn
|
magicConn *magicsock.Conn
|
||||||
linkMon *monitor.Mon
|
linkMon *monitor.Mon
|
||||||
linkMonOwned bool // whether we created linkMon (and thus need to close it)
|
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{}),
|
waitCh: make(chan struct{}),
|
||||||
tundev: tsTUNDev,
|
tundev: tsTUNDev,
|
||||||
router: conf.Router,
|
router: conf.Router,
|
||||||
dns: dns.NewManager(logf, conf.DNS),
|
|
||||||
pingers: make(map[wgkey.Key]*pinger),
|
pingers: make(map[wgkey.Key]*pinger),
|
||||||
}
|
}
|
||||||
e.isLocalAddr.Store(genLocalAddrFunc(nil))
|
e.isLocalAddr.Store(genLocalAddrFunc(nil))
|
||||||
@ -230,7 +228,7 @@ func NewUserspaceEngine(logf logger.Logf, conf Config) (_ Engine, reterr error)
|
|||||||
e.linkMonOwned = true
|
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())
|
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.
|
// handleDNS is an outbound pre-filter resolving Tailscale domains.
|
||||||
func (e *userspaceEngine) handleDNS(p *packet.Parsed, t *tstun.Wrapper) filter.Response {
|
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 {
|
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 {
|
if err != nil {
|
||||||
e.logf("dns: enqueue: %v", err)
|
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.
|
// pollResolver reads responses from the DNS resolver and injects them inbound.
|
||||||
func (e *userspaceEngine) pollResolver() {
|
func (e *userspaceEngine) pollResolver() {
|
||||||
for {
|
for {
|
||||||
bs, to, err := e.resolver.NextResponse()
|
bs, to, err := e.dns.NextResponse()
|
||||||
if err == resolver.ErrClosed {
|
if err == resolver.ErrClosed {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -992,37 +990,8 @@ func (e *userspaceEngine) Reconfig(cfg *wgcfg.Config, routerCfg *router.Config,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if routerChanged {
|
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")
|
e.logf("wgengine: Reconfig: configuring DNS")
|
||||||
err := e.resolver.SetConfig(resolverCfg)
|
err := e.dns.Set(*dnsCfg)
|
||||||
health.SetDNSHealth(err)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
err = e.dns.Set(osCfg)
|
|
||||||
health.SetDNSHealth(err)
|
health.SetDNSHealth(err)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -1241,12 +1210,12 @@ func (e *userspaceEngine) Close() {
|
|||||||
|
|
||||||
r := bufio.NewReader(strings.NewReader(""))
|
r := bufio.NewReader(strings.NewReader(""))
|
||||||
e.wgdev.IpcSetOperation(r)
|
e.wgdev.IpcSetOperation(r)
|
||||||
e.resolver.Close()
|
|
||||||
e.magicConn.Close()
|
e.magicConn.Close()
|
||||||
e.linkMonUnregister()
|
e.linkMonUnregister()
|
||||||
if e.linkMonOwned {
|
if e.linkMonOwned {
|
||||||
e.linkMon.Close()
|
e.linkMon.Close()
|
||||||
}
|
}
|
||||||
|
e.dns.Down()
|
||||||
e.router.Close()
|
e.router.Close()
|
||||||
e.wgdev.Close()
|
e.wgdev.Close()
|
||||||
e.tundev.Close()
|
e.tundev.Close()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user