Update
This commit is contained in:
1 parent
3530afb854
commit
6903fcff27
2146 files changed
+112256
-190703
No files matched your search
+103
-57
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) Tailscale Inc & AUTHORS
|
||||
// Copyright (c) Tailscale Inc & contributors
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
// Package controlknobs contains client options configurable from control which can be turned on
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
|
||||
"tailscale.com/syncs"
|
||||
"tailscale.com/tailcfg"
|
||||
"tailscale.com/tailcfg/nodecap"
|
||||
"tailscale.com/types/opt"
|
||||
)
|
||||
|
||||
@@ -21,16 +22,11 @@ type Knobs struct {
|
||||
// DisableUPnP indicates whether to attempt UPnP mapping.
|
||||
DisableUPnP atomic.Bool
|
||||
|
||||
// KeepFullWGConfig is whether we should disable the lazy wireguard
|
||||
// programming and instead give WireGuard the full netmap always, even for
|
||||
// idle peers.
|
||||
KeepFullWGConfig atomic.Bool
|
||||
|
||||
// RandomizeClientPort is whether control says we should randomize
|
||||
// the client port.
|
||||
RandomizeClientPort atomic.Bool
|
||||
|
||||
// OneCGNAT is whether the the node should make one big CGNAT route
|
||||
// OneCGNAT is whether the node should make one big CGNAT route
|
||||
// in the OS rather than one /32 per peer.
|
||||
OneCGNAT syncs.AtomicValue[opt.Bool]
|
||||
|
||||
@@ -62,12 +58,6 @@ type Knobs struct {
|
||||
// netfiltering, unless overridden by the user.
|
||||
LinuxForceNfTables atomic.Bool
|
||||
|
||||
// SeamlessKeyRenewal is whether to renew node keys without breaking connections.
|
||||
// This is enabled by default in 1.90 and later, but we but we can remotely disable
|
||||
// it from the control plane if there's a problem.
|
||||
// http://go/seamless-key-renewal
|
||||
SeamlessKeyRenewal atomic.Bool
|
||||
|
||||
// ProbeUDPLifetime is whether the node should probe UDP path lifetime on
|
||||
// the tail end of an active direct connection in magicsock.
|
||||
ProbeUDPLifetime atomic.Bool
|
||||
@@ -107,6 +97,57 @@ type Knobs struct {
|
||||
// of queued netmap.NetworkMap between the controlclient and LocalBackend.
|
||||
// See tailscale/tailscale#14768.
|
||||
DisableSkipStatusQueue atomic.Bool
|
||||
|
||||
// DisableHostsFileUpdates indicates that the node's DNS manager should not create
|
||||
// hosts file entries when it normally would, such as when we're not the primary
|
||||
// resolver on Windows or when the host is domain-joined and its primary domain
|
||||
// takes precedence over MagicDNS. As of 2026-02-13, it is only used on Windows.
|
||||
DisableHostsFileUpdates atomic.Bool
|
||||
|
||||
// ForceRegisterMagicDNSIPv4Only is whether the node should only register
|
||||
// its IPv4 MagicDNS service IP and not its IPv6 one. The IPv6 one,
|
||||
// tsaddr.TailscaleServiceIPv6String, still works in either case. This knob
|
||||
// controls only whether we tell systemd/etc about the IPv6 one.
|
||||
// See https://github.com/tailscale/tailscale/issues/15404.
|
||||
// TODO(bradfitz): remove this a few releases after 2026-02-16.
|
||||
ForceRegisterMagicDNSIPv4Only atomic.Bool
|
||||
|
||||
// EmitRuntimeMetrics is whether the node should poll and emit [runtime/metrics]
|
||||
// as [tailscale.com/util/clientmetric]'s.
|
||||
EmitRuntimeMetrics atomic.Bool
|
||||
|
||||
// DisableUDPGRO disables UDP GRO on the magicsock UDP socket. See
|
||||
// [tailcfg.NodeAttrDisableUDPGRO].
|
||||
DisableUDPGRO atomic.Bool
|
||||
|
||||
// DisableUDPGSO disables UDP GSO on the magicsock UDP socket. See
|
||||
// [tailcfg.NodeAttrDisableUDPGSO].
|
||||
DisableUDPGSO atomic.Bool
|
||||
|
||||
// DisableTUNUDPGRO disables UDP GRO on the Tailscale TUN device. See
|
||||
// [tailcfg.NodeAttrDisableTUNUDPGRO].
|
||||
DisableTUNUDPGRO atomic.Bool
|
||||
|
||||
// DisableTUNTCPGRO disables TCP GRO on the Tailscale TUN device. See
|
||||
// [tailcfg.NodeAttrDisableTUNTCPGRO].
|
||||
DisableTUNTCPGRO atomic.Bool
|
||||
|
||||
// NeverGSOEqualTail enables a UDP GSO sentinel-tail workaround in the
|
||||
// underlay UDP packet TX path on Linux. Applies to magicsock and peer relay
|
||||
// UDP sockets. See [tailcfg.NodeAttrNeverGSOEqualTail].
|
||||
NeverGSOEqualTail atomic.Bool
|
||||
|
||||
// CacheNetworkMaps is whether the node should persistently cache network
|
||||
// maps and use them to establish peer connectivity on start, if doing so
|
||||
// is supported by the client and storage is available.
|
||||
CacheNetworkMaps atomic.Bool
|
||||
|
||||
// ScopeQuad100OnMacOS lets sandboxed macOS scope quad-100 for simple DNS
|
||||
// configs, so public queries can use the OS resolver (including DoH).
|
||||
// Custom split resolvers or unrouted forward/PTR records still require
|
||||
// quad-100 as primary. Off by default; has no effect on other platforms.
|
||||
// See tailscale/corp#45534 and tailscale/corp#48693.
|
||||
ScopeQuad100OnMacOS atomic.Bool
|
||||
}
|
||||
|
||||
// UpdateFromNodeAttributes updates k (if non-nil) based on the provided self
|
||||
@@ -117,35 +158,41 @@ func (k *Knobs) UpdateFromNodeAttributes(capMap tailcfg.NodeCapMap) {
|
||||
}
|
||||
has := capMap.Contains
|
||||
var (
|
||||
keepFullWG = has(tailcfg.NodeAttrDebugDisableWGTrim)
|
||||
disableUPnP = has(tailcfg.NodeAttrDisableUPnP)
|
||||
randomizeClientPort = has(tailcfg.NodeAttrRandomizeClientPort)
|
||||
disableDeltaUpdates = has(tailcfg.NodeAttrDisableDeltaUpdates)
|
||||
disableUPnP = has(nodecap.DisableUPnP)
|
||||
randomizeClientPort = has(nodecap.RandomizeClientPort)
|
||||
disableDeltaUpdates = has(nodecap.DisableDeltaUpdates)
|
||||
oneCGNAT opt.Bool
|
||||
forceBackgroundSTUN = has(tailcfg.NodeAttrDebugForceBackgroundSTUN)
|
||||
peerMTUEnable = has(tailcfg.NodeAttrPeerMTUEnable)
|
||||
dnsForwarderDisableTCPRetries = has(tailcfg.NodeAttrDNSForwarderDisableTCPRetries)
|
||||
silentDisco = has(tailcfg.NodeAttrSilentDisco)
|
||||
forceIPTables = has(tailcfg.NodeAttrLinuxMustUseIPTables)
|
||||
forceNfTables = has(tailcfg.NodeAttrLinuxMustUseNfTables)
|
||||
seamlessKeyRenewal = has(tailcfg.NodeAttrSeamlessKeyRenewal)
|
||||
disableSeamlessKeyRenewal = has(tailcfg.NodeAttrDisableSeamlessKeyRenewal)
|
||||
probeUDPLifetime = has(tailcfg.NodeAttrProbeUDPLifetime)
|
||||
appCStoreRoutes = has(tailcfg.NodeAttrStoreAppCRoutes)
|
||||
userDialUseRoutes = has(tailcfg.NodeAttrUserDialUseRoutes)
|
||||
disableSplitDNSWhenNoCustomResolvers = has(tailcfg.NodeAttrDisableSplitDNSWhenNoCustomResolvers)
|
||||
disableLocalDNSOverrideViaNRPT = has(tailcfg.NodeAttrDisableLocalDNSOverrideViaNRPT)
|
||||
disableCaptivePortalDetection = has(tailcfg.NodeAttrDisableCaptivePortalDetection)
|
||||
disableSkipStatusQueue = has(tailcfg.NodeAttrDisableSkipStatusQueue)
|
||||
forceBackgroundSTUN = has(nodecap.DebugForceBackgroundSTUN)
|
||||
peerMTUEnable = has(nodecap.PeerMTUEnable)
|
||||
dnsForwarderDisableTCPRetries = has(nodecap.DNSForwarderDisableTCPRetries)
|
||||
silentDisco = has(nodecap.SilentDisco)
|
||||
forceIPTables = has(nodecap.LinuxMustUseIPTables)
|
||||
forceNfTables = has(nodecap.LinuxMustUseNfTables)
|
||||
probeUDPLifetime = has(nodecap.ProbeUDPLifetime)
|
||||
appCStoreRoutes = has(nodecap.StoreAppCRoutes)
|
||||
userDialUseRoutes = has(nodecap.UserDialUseRoutes)
|
||||
disableSplitDNSWhenNoCustomResolvers = has(nodecap.DisableSplitDNSWhenNoCustomResolvers)
|
||||
disableLocalDNSOverrideViaNRPT = has(nodecap.DisableLocalDNSOverrideViaNRPT)
|
||||
disableCaptivePortalDetection = has(nodecap.DisableCaptivePortalDetection)
|
||||
disableSkipStatusQueue = has(nodecap.DisableSkipStatusQueue)
|
||||
disableHostsFileUpdates = has(nodecap.DisableHostsFileUpdates)
|
||||
forceRegisterMagicDNSIPv4Only = has(nodecap.ForceRegisterMagicDNSIPv4Only)
|
||||
emitRuntimeMetrics = has(nodecap.EmitRuntimeMetrics)
|
||||
disableUDPGRO = has(nodecap.DisableUDPGRO)
|
||||
disableUDPGSO = has(nodecap.DisableUDPGSO)
|
||||
disableTUNUDPGRO = has(nodecap.DisableTUNUDPGRO)
|
||||
disableTUNTCPGRO = has(nodecap.DisableTUNTCPGRO)
|
||||
neverGSOEqualTail = has(nodecap.NeverGSOEqualTail)
|
||||
cacheNetworkMaps = has(nodecap.CacheNetworkMaps)
|
||||
scopeQuad100OnMacOS = has(nodecap.ScopeQuad100OnMacOS)
|
||||
)
|
||||
|
||||
if has(tailcfg.NodeAttrOneCGNATEnable) {
|
||||
if has(nodecap.OneCGNATEnable) {
|
||||
oneCGNAT.Set(true)
|
||||
} else if has(tailcfg.NodeAttrOneCGNATDisable) {
|
||||
} else if has(nodecap.OneCGNATDisable) {
|
||||
oneCGNAT.Set(false)
|
||||
}
|
||||
|
||||
k.KeepFullWGConfig.Store(keepFullWG)
|
||||
k.DisableUPnP.Store(disableUPnP)
|
||||
k.RandomizeClientPort.Store(randomizeClientPort)
|
||||
k.OneCGNAT.Store(oneCGNAT)
|
||||
@@ -163,21 +210,16 @@ func (k *Knobs) UpdateFromNodeAttributes(capMap tailcfg.NodeCapMap) {
|
||||
k.DisableLocalDNSOverrideViaNRPT.Store(disableLocalDNSOverrideViaNRPT)
|
||||
k.DisableCaptivePortalDetection.Store(disableCaptivePortalDetection)
|
||||
k.DisableSkipStatusQueue.Store(disableSkipStatusQueue)
|
||||
|
||||
// If both attributes are present, then "enable" should win. This reflects
|
||||
// the history of seamless key renewal.
|
||||
//
|
||||
// Before 1.90, seamless was a private alpha, opt-in feature. Devices would
|
||||
// only seamless do if customers opted in using the seamless renewal attr.
|
||||
//
|
||||
// In 1.90 and later, seamless is the default behaviour, and devices will use
|
||||
// seamless unless explicitly told not to by control (e.g. if we discover
|
||||
// a bug and want clients to use the prior behaviour).
|
||||
//
|
||||
// If a customer has opted in to the pre-1.90 seamless implementation, we
|
||||
// don't want to switch it off for them -- we only want to switch it off for
|
||||
// devices that haven't opted in.
|
||||
k.SeamlessKeyRenewal.Store(seamlessKeyRenewal || !disableSeamlessKeyRenewal)
|
||||
k.DisableHostsFileUpdates.Store(disableHostsFileUpdates)
|
||||
k.ForceRegisterMagicDNSIPv4Only.Store(forceRegisterMagicDNSIPv4Only)
|
||||
k.EmitRuntimeMetrics.Store(emitRuntimeMetrics)
|
||||
k.DisableUDPGRO.Store(disableUDPGRO)
|
||||
k.DisableUDPGSO.Store(disableUDPGSO)
|
||||
k.DisableTUNUDPGRO.Store(disableTUNUDPGRO)
|
||||
k.DisableTUNTCPGRO.Store(disableTUNTCPGRO)
|
||||
k.NeverGSOEqualTail.Store(neverGSOEqualTail)
|
||||
k.CacheNetworkMaps.Store(cacheNetworkMaps)
|
||||
k.ScopeQuad100OnMacOS.Store(scopeQuad100OnMacOS)
|
||||
}
|
||||
|
||||
// AsDebugJSON returns k as something that can be marshalled with json.Marshal
|
||||
@@ -187,18 +229,22 @@ func (k *Knobs) AsDebugJSON() map[string]any {
|
||||
return nil
|
||||
}
|
||||
ret := map[string]any{}
|
||||
rt := reflect.TypeFor[Knobs]()
|
||||
rv := reflect.ValueOf(k).Elem() // of *k
|
||||
for i := 0; i < rt.NumField(); i++ {
|
||||
name := rt.Field(i).Name
|
||||
switch v := rv.Field(i).Addr().Interface().(type) {
|
||||
for sf, fv := range rv.Fields() {
|
||||
switch v := fv.Addr().Interface().(type) {
|
||||
case *atomic.Bool:
|
||||
ret[name] = v.Load()
|
||||
ret[sf.Name] = v.Load()
|
||||
case *syncs.AtomicValue[opt.Bool]:
|
||||
ret[name] = v.Load()
|
||||
ret[sf.Name] = v.Load()
|
||||
default:
|
||||
panic(fmt.Sprintf("unknown field type %T for %v", v, name))
|
||||
panic(fmt.Sprintf("unknown field type %T for %v", v, sf.Name))
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
// ShouldForceRegisterMagicDNSIPv4Only reports the value of
|
||||
// ForceRegisterMagicDNSIPv4Only, or false if k is nil.
|
||||
func (k *Knobs) ShouldForceRegisterMagicDNSIPv4Only() bool {
|
||||
return k != nil && k.ForceRegisterMagicDNSIPv4Only.Load()
|
||||
}
|
||||
Reference in new issue
Block a user