wgengine{,tsdns}: rebind MagicDNS forwarders on link change

Fixes #1480

Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
pull/1487/head
Brad Fitzpatrick 4 years ago committed by Brad Fitzpatrick
parent bdb91a20eb
commit f9f3b67f3a

@ -163,6 +163,14 @@ func (f *forwarder) Close() {
f.wg.Wait() f.wg.Wait()
} }
func (f *forwarder) rebindFromNetworkChange() {
for _, c := range f.conns {
c.mu.Lock()
c.reconnectLocked()
c.mu.Unlock()
}
}
func (f *forwarder) setUpstreams(upstreams []net.Addr) { func (f *forwarder) setUpstreams(upstreams []net.Addr) {
f.mu.Lock() f.mu.Lock()
f.upstreams = upstreams f.upstreams = upstreams

@ -16,8 +16,10 @@ import (
dns "golang.org/x/net/dns/dnsmessage" dns "golang.org/x/net/dns/dnsmessage"
"inet.af/netaddr" "inet.af/netaddr"
"tailscale.com/net/interfaces"
"tailscale.com/types/logger" "tailscale.com/types/logger"
"tailscale.com/util/dnsname" "tailscale.com/util/dnsname"
"tailscale.com/wgengine/monitor"
) )
// maxResponseBytes is the maximum size of a response from a Resolver. // maxResponseBytes is the maximum size of a response from a Resolver.
@ -58,7 +60,9 @@ type Packet struct {
// If it is asked to resolve a domain that is not of that form, // If it is asked to resolve a domain that is not of that form,
// it delegates to upstream nameservers if any are set. // it delegates to upstream nameservers if any are set.
type Resolver struct { type Resolver struct {
logf logger.Logf logf logger.Logf
linkMon *monitor.Mon // or nil
unregLinkMon func() // or nil
// forwarder forwards requests to upstream nameservers. // forwarder forwards requests to upstream nameservers.
forwarder *forwarder forwarder *forwarder
@ -86,6 +90,10 @@ type ResolverConfig struct {
// Forward determines whether the resolver will forward packets to // Forward determines whether the resolver will forward packets to
// nameservers set with SetUpstreams if the domain name is not of a Tailscale node. // nameservers set with SetUpstreams if the domain name is not of a Tailscale node.
Forward bool Forward bool
// LinkMonitor optionally provides a link monitor to use to rebind
// connections on link changes.
// If nil, rebinds are not performend.
LinkMonitor *monitor.Mon
} }
// NewResolver constructs a resolver associated with the given root domain. // NewResolver constructs a resolver associated with the given root domain.
@ -93,6 +101,7 @@ type ResolverConfig struct {
func NewResolver(config ResolverConfig) *Resolver { func NewResolver(config ResolverConfig) *Resolver {
r := &Resolver{ r := &Resolver{
logf: logger.WithPrefix(config.Logf, "tsdns: "), logf: logger.WithPrefix(config.Logf, "tsdns: "),
linkMon: config.LinkMonitor,
queue: make(chan Packet, queueSize), queue: make(chan Packet, queueSize),
responses: make(chan Packet), responses: make(chan Packet),
errors: make(chan error), errors: make(chan error),
@ -102,6 +111,9 @@ func NewResolver(config ResolverConfig) *Resolver {
if config.Forward { if config.Forward {
r.forwarder = newForwarder(r.logf, r.responses) r.forwarder = newForwarder(r.logf, r.responses)
} }
if r.linkMon != nil {
r.unregLinkMon = r.linkMon.RegisterChangeCallback(r.onLinkMonitorChange)
}
return r return r
} }
@ -130,6 +142,10 @@ func (r *Resolver) Close() {
} }
close(r.closed) close(r.closed)
if r.unregLinkMon != nil {
r.unregLinkMon()
}
if r.forwarder != nil { if r.forwarder != nil {
r.forwarder.Close() r.forwarder.Close()
} }
@ -137,6 +153,15 @@ func (r *Resolver) Close() {
r.wg.Wait() r.wg.Wait()
} }
func (r *Resolver) onLinkMonitorChange(changed bool, state *interfaces.State) {
if !changed {
return
}
if r.forwarder != nil {
r.forwarder.rebindFromNetworkChange()
}
}
// SetMap sets the resolver's DNS map, taking ownership of it. // SetMap sets the resolver's DNS map, taking ownership of it.
func (r *Resolver) SetMap(m *Map) { func (r *Resolver) SetMap(m *Map) {
r.mu.Lock() r.mu.Lock()

@ -219,18 +219,13 @@ func newUserspaceEngine(logf logger.Logf, rawTUNDev tun.Device, conf Config) (_
tsTUNDev := tstun.WrapTUN(logf, rawTUNDev) tsTUNDev := tstun.WrapTUN(logf, rawTUNDev)
closePool.add(tsTUNDev) closePool.add(tsTUNDev)
rconf := tsdns.ResolverConfig{
Logf: logf,
Forward: true,
}
e := &userspaceEngine{ e := &userspaceEngine{
timeNow: time.Now, timeNow: time.Now,
logf: logf, logf: logf,
reqCh: make(chan struct{}, 1), reqCh: make(chan struct{}, 1),
waitCh: make(chan struct{}), waitCh: make(chan struct{}),
tundev: tsTUNDev, tundev: tsTUNDev,
resolver: tsdns.NewResolver(rconf), pingers: make(map[wgkey.Key]*pinger),
pingers: make(map[wgkey.Key]*pinger),
} }
e.localAddrs.Store(map[netaddr.IP]bool{}) e.localAddrs.Store(map[netaddr.IP]bool{})
@ -246,6 +241,12 @@ func newUserspaceEngine(logf logger.Logf, rawTUNDev tun.Device, conf Config) (_
e.linkMonOwned = true e.linkMonOwned = true
} }
e.resolver = tsdns.NewResolver(tsdns.ResolverConfig{
Logf: logf,
Forward: true,
LinkMonitor: e.linkMon,
})
logf("link state: %+v", e.linkMon.InterfaceState()) logf("link state: %+v", e.linkMon.InterfaceState())
unregisterMonWatch := e.linkMon.RegisterChangeCallback(func(changed bool, st *interfaces.State) { unregisterMonWatch := e.linkMon.RegisterChangeCallback(func(changed bool, st *interfaces.State) {

Loading…
Cancel
Save