mapper, app: ship MagicDNS Routes as empty slices, not nil
policyChangeResponse already includes everything else; carry DNSConfig
too so the client's netmap DNS is anchored on every policy change
rather than relying on the previous snapshot.
Send the MagicDNS root domains as empty non-nil Resolver slices instead
of nil values. tailcfg.DNSConfig.Clone and net/dns.Config.Clone in
tailscale drop map entries whose value is nil (tailcfg_clone.go and
dns_clone.go both contain `if sv == nil { continue }`). On a major
LinkChange the client's wgengine handler clones lastDNSConfig and
re-applies it; with nil values the cloned config has Routes:{}, dns.Set
wipes Nameservers in /etc/resolv.conf, and curl-by-FQDN fails until
the next route-changing netmap, typically about six minutes later.
Empty slice survives Clone and carries the same "resolve locally"
semantics for Routes entries.
This commit is contained in:
parent
dfcc96d808
commit
a345a22a3b
@ -219,7 +219,19 @@ func NewHeadscale(cfg *types.Config) (*Headscale, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, d := range magicDNSDomains {
|
for _, d := range magicDNSDomains {
|
||||||
app.cfg.TailcfgDNSConfig.Routes[d.WithoutTrailingDot()] = nil
|
// Empty non-nil slice rather than nil: tailcfg.DNSConfig.Clone
|
||||||
|
// and dns.Config.Clone in tailscale drop map entries whose
|
||||||
|
// value is nil (see tailscale.com/tailcfg/tailcfg_clone.go and
|
||||||
|
// tailscale.com/net/dns/dns_clone.go: `if sv == nil { continue }`).
|
||||||
|
// Sending nil here caused the client's wgengine LinkChange:major
|
||||||
|
// handler to clobber /etc/resolv.conf on every tunnel-IP rebind
|
||||||
|
// — the handler reapplies a Clone of lastDNSConfig and the magic
|
||||||
|
// DNS routes vanish, taking the resolver with them for ~6 min
|
||||||
|
// until the next route-changing netmap. Empty slice survives
|
||||||
|
// Clone and carries the same "resolve locally" semantics
|
||||||
|
// (tailscale.com/ipn/ipnlocal/node_backend.go:869 documents the
|
||||||
|
// empty-resolver Routes form for Issue 2706).
|
||||||
|
app.cfg.TailcfgDNSConfig.Routes[d.WithoutTrailingDot()] = []*dnstype.Resolver{}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -314,11 +314,18 @@ func (m *mapper) selfMapResponse(
|
|||||||
|
|
||||||
// policyChangeResponse creates a MapResponse for policy changes.
|
// policyChangeResponse creates a MapResponse for policy changes.
|
||||||
// It sends:
|
// It sends:
|
||||||
// - PeersRemoved for peers that are no longer visible after the policy change
|
// - PeersRemoved for peers that are no longer visible after the policy change
|
||||||
// - PeersChanged for remaining peers (their AllowedIPs may have changed due to policy)
|
// - PeersChanged for remaining peers (their AllowedIPs may have changed due to policy)
|
||||||
// - Updated PacketFilters
|
// - Updated PacketFilters
|
||||||
// - Updated SSHPolicy (SSH rules may reference users/groups that changed)
|
// - Updated SSHPolicy (SSH rules may reference users/groups that changed)
|
||||||
// - Optionally, the node's own self info (when includeSelf is true)
|
// - DNSConfig so the client's resolver state stays anchored even when a
|
||||||
|
// policy-triggered wgengine reconfigure races a netmon LinkChange (the
|
||||||
|
// LinkChange handler reapplies dns.Manager.Set with the engine's
|
||||||
|
// lastDNSConfig; if that snapshot is stale, the OS resolver loses the
|
||||||
|
// MagicDNS reverse-DNS routes and Nameservers and curl-by-FQDN stops
|
||||||
|
// resolving for the rest of the policy window).
|
||||||
|
// - Optionally, the node's own self info (when includeSelf is true)
|
||||||
|
//
|
||||||
// This avoids the issue where an empty Peers slice is interpreted by Tailscale
|
// This avoids the issue where an empty Peers slice is interpreted by Tailscale
|
||||||
// clients as "no change" rather than "no peers".
|
// clients as "no change" rather than "no peers".
|
||||||
// When includeSelf is true, the node's self info is included so that a node
|
// When includeSelf is true, the node's self info is included so that a node
|
||||||
@ -334,6 +341,7 @@ func (m *mapper) policyChangeResponse(
|
|||||||
builder := m.NewMapResponseBuilder(nodeID).
|
builder := m.NewMapResponseBuilder(nodeID).
|
||||||
WithDebugType(policyResponseDebug).
|
WithDebugType(policyResponseDebug).
|
||||||
WithCapabilityVersion(capVer).
|
WithCapabilityVersion(capVer).
|
||||||
|
WithDNSConfig().
|
||||||
WithPacketFilters().
|
WithPacketFilters().
|
||||||
WithSSHPolicy()
|
WithSSHPolicy()
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user