configure DNS even when router.Set fails (#20488)
* wgengine: configure DNS even when router.Set fails
Reconfig configured the router first and returned on any router.Set error,
before the DNS block ran. On a host where router config fails on every
reconfig -- e.g. a tun MTU below 1280 that breaks IPv6, or a kernel missing
netfilter features -- the OS resolver was never told about MagicDNS or the
tailnet search domain, so tailnet names failed to resolve with no DNS error
in the logs.
Record the router error and continue instead of returning on it, still
attempt dns.Set, and join the router, DNS, and VPN-reconfigure errors into
the return value. DNS stays after router config (still needed: some DNS
managers refuse to apply settings before the device has an address); only
the error coupling is broken. Fixes a regression from 84430cdfa (v1.8.0).
Updates #20447
Signed-off-by: Brendan Creane <bcreane@gmail.com>
* wgengine/router/osrouter: gate IPv6 on per-interface support, not just global
getV6Available reported IPv6 usable whenever the netfilter runner reported
global IPv6 support, missing the case where the kernel has IPv6 but has not
enabled it on tailscale0 specifically -- e.g. when the tun MTU is below the
1280-byte IPv6 minimum, so /proc/sys/net/ipv6/conf/tailscale0 never exists
and the v6 address and route adds fail, aborting the whole Set. See #20447.
AND a per-interface check into getV6Available, evaluated per call so a later
Set picks up v6 if the interface gains it. All v6-gated operations funnel
through getV6Available, so Set now skips v6 gracefully instead of erroring.
Also remove the dead r.v6Available field that masked this with its global
name.
Updates #20447
Signed-off-by: Brendan Creane <bcreane@gmail.com>
---------
Signed-off-by: Brendan Creane <bcreane@gmail.com>
This commit is contained in:
+21
-16
@@ -884,12 +884,15 @@ func (e *userspaceEngine) Reconfig(cfg *wgcfg.Config, routerCfg *router.Config,
|
||||
// per peer by [Engine.SyncDevicePeer]), and its private key is set
|
||||
// above when it changes.
|
||||
|
||||
// A router.Set error is recorded but must not abort the reconfig: DNS
|
||||
// configuration below must be attempted independently. See #20447.
|
||||
var routerErr error
|
||||
if routerChanged {
|
||||
e.logf("wgengine: Reconfig: configuring router")
|
||||
err := e.router.Set(routerCfg)
|
||||
e.health.SetRouterHealth(err)
|
||||
if err != nil {
|
||||
return err
|
||||
routerErr = e.router.Set(routerCfg)
|
||||
e.health.SetRouterHealth(routerErr)
|
||||
if routerErr != nil {
|
||||
e.logf("wgengine: Reconfig: router config failed (%v); continuing to DNS config so name resolution still works", routerErr)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -902,6 +905,7 @@ func (e *userspaceEngine) Reconfig(cfg *wgcfg.Config, routerCfg *router.Config,
|
||||
// TODO(bradfitz): try to do the "configuring DNS" part below only if
|
||||
// dnsChanged, not routerChanged. The "resolver.ShouldUseRoutes" part
|
||||
// probably needs to keep happening for both.
|
||||
var dnsErr, vpnErr error
|
||||
if buildfeatures.HasDNS && (routerChanged || dnsChanged) {
|
||||
if resolver.ShouldUseRoutes(e.controlKnobs) {
|
||||
e.logf("wgengine: Reconfig: user dialer")
|
||||
@@ -914,31 +918,32 @@ func (e *userspaceEngine) Reconfig(cfg *wgcfg.Config, routerCfg *router.Config,
|
||||
// DNS managers refuse to apply settings if the device has no
|
||||
// assigned address.
|
||||
e.logf("wgengine: Reconfig: configuring DNS")
|
||||
err := e.dns.Set(*dnsCfg)
|
||||
e.health.SetDNSHealth(err)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := e.reconfigureVPNIfNecessary(); err != nil {
|
||||
return err
|
||||
dnsErr = e.dns.Set(*dnsCfg)
|
||||
e.health.SetDNSHealth(dnsErr)
|
||||
if dnsErr == nil {
|
||||
vpnErr = e.reconfigureVPNIfNecessary()
|
||||
}
|
||||
}
|
||||
|
||||
// Let the network flow logger finish reacting after the router is
|
||||
// configured, so that a stopping logger captures final packets.
|
||||
// Let the network flow logger finish reacting, pairing the Reconfig
|
||||
// call near the top of this function. This runs regardless of router
|
||||
// or DNS errors above: skipping it would leave a stopping logger
|
||||
// running until the next successful reconfig.
|
||||
// This may block to flush pending log messages.
|
||||
if e.netlogger != nil {
|
||||
e.netlogger.ReconfigDone()
|
||||
}
|
||||
|
||||
// Let the BIRD integration apply any protocol state change now,
|
||||
// after the router is configured.
|
||||
// Let the BIRD integration apply any protocol state change computed by
|
||||
// its Reconfig call above. As with the netlogger, this runs even if
|
||||
// router/DNS config failed, so BIRD's protocol state still tracks the
|
||||
// primary-subnet-router transition.
|
||||
if e.bird != nil {
|
||||
e.bird.ReconfigDone()
|
||||
}
|
||||
|
||||
e.logf("[v1] wgengine: Reconfig done")
|
||||
return nil
|
||||
return errors.Join(routerErr, dnsErr, vpnErr)
|
||||
}
|
||||
|
||||
func (e *userspaceEngine) GetFilter() *filter.Filter {
|
||||
|
||||
Reference in New Issue
Block a user