wgengine{,tsdns}: rebind MagicDNS forwarders on link change
Fixes #1480 Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>pull/1487/head
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.
|
||||||
|
@ -59,6 +61,8 @@ type Packet struct {
|
||||||
// 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,17 +219,12 @@ 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…
Reference in New Issue