mirror of
https://github.com/tailscale/tailscale.git
synced 2025-02-19 19:38:40 +00:00
ipn/ipnlocal: refresh node key without blocking if cap enabled (#10529)
Updates tailscale/corp#16016 Signed-off-by: James Sanderson <jsanderson@tailscale.com> Co-authored-by: Maisem Ali <maisem@tailscale.com>
This commit is contained in:
parent
3a9450bc06
commit
10c595d962
@ -64,6 +64,11 @@ type Knobs struct {
|
|||||||
// LinuxForceNfTables is whether the node should use nftables for Linux
|
// LinuxForceNfTables is whether the node should use nftables for Linux
|
||||||
// netfiltering, unless overridden by the user.
|
// netfiltering, unless overridden by the user.
|
||||||
LinuxForceNfTables atomic.Bool
|
LinuxForceNfTables atomic.Bool
|
||||||
|
|
||||||
|
// SeamlessKeyRenewal is whether to enable the alpha functionality of
|
||||||
|
// renewing node keys without breaking connections.
|
||||||
|
// http://go/seamless-key-renewal
|
||||||
|
SeamlessKeyRenewal atomic.Bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateFromNodeAttributes updates k (if non-nil) based on the provided self
|
// UpdateFromNodeAttributes updates k (if non-nil) based on the provided self
|
||||||
@ -89,6 +94,7 @@ func (k *Knobs) UpdateFromNodeAttributes(selfNodeAttrs []tailcfg.NodeCapability,
|
|||||||
silentDisco = has(tailcfg.NodeAttrSilentDisco)
|
silentDisco = has(tailcfg.NodeAttrSilentDisco)
|
||||||
forceIPTables = has(tailcfg.NodeAttrLinuxMustUseIPTables)
|
forceIPTables = has(tailcfg.NodeAttrLinuxMustUseIPTables)
|
||||||
forceNfTables = has(tailcfg.NodeAttrLinuxMustUseNfTables)
|
forceNfTables = has(tailcfg.NodeAttrLinuxMustUseNfTables)
|
||||||
|
seamlessKeyRenewal = has(tailcfg.NodeAttrSeamlessKeyRenewal)
|
||||||
)
|
)
|
||||||
|
|
||||||
if has(tailcfg.NodeAttrOneCGNATEnable) {
|
if has(tailcfg.NodeAttrOneCGNATEnable) {
|
||||||
@ -109,6 +115,7 @@ func (k *Knobs) UpdateFromNodeAttributes(selfNodeAttrs []tailcfg.NodeCapability,
|
|||||||
k.SilentDisco.Store(silentDisco)
|
k.SilentDisco.Store(silentDisco)
|
||||||
k.LinuxForceIPTables.Store(forceIPTables)
|
k.LinuxForceIPTables.Store(forceIPTables)
|
||||||
k.LinuxForceNfTables.Store(forceNfTables)
|
k.LinuxForceNfTables.Store(forceNfTables)
|
||||||
|
k.SeamlessKeyRenewal.Store(seamlessKeyRenewal)
|
||||||
}
|
}
|
||||||
|
|
||||||
// AsDebugJSON returns k as something that can be marshalled with json.Marshal
|
// AsDebugJSON returns k as something that can be marshalled with json.Marshal
|
||||||
@ -130,5 +137,6 @@ func (k *Knobs) AsDebugJSON() map[string]any {
|
|||||||
"SilentDisco": k.SilentDisco.Load(),
|
"SilentDisco": k.SilentDisco.Load(),
|
||||||
"LinuxForceIPTables": k.LinuxForceIPTables.Load(),
|
"LinuxForceIPTables": k.LinuxForceIPTables.Load(),
|
||||||
"LinuxForceNfTables": k.LinuxForceNfTables.Load(),
|
"LinuxForceNfTables": k.LinuxForceNfTables.Load(),
|
||||||
|
"SeamlessKeyRenewal": k.SeamlessKeyRenewal.Load(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1074,9 +1074,11 @@ func (b *LocalBackend) SetControlClientStatus(c controlclient.Client, st control
|
|||||||
b.blockEngineUpdates(false)
|
b.blockEngineUpdates(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
if st.LoginFinished() && wasBlocked {
|
if st.LoginFinished() && (wasBlocked || b.seamlessRenewalEnabled()) {
|
||||||
// Auth completed, unblock the engine
|
if wasBlocked {
|
||||||
b.blockEngineUpdates(false)
|
// Auth completed, unblock the engine
|
||||||
|
b.blockEngineUpdates(false)
|
||||||
|
}
|
||||||
b.authReconfig()
|
b.authReconfig()
|
||||||
b.send(ipn.Notify{LoginFinished: &empty.Message{}})
|
b.send(ipn.Notify{LoginFinished: &empty.Message{}})
|
||||||
}
|
}
|
||||||
@ -1108,7 +1110,7 @@ func (b *LocalBackend) SetControlClientStatus(c controlclient.Client, st control
|
|||||||
b.authURL = st.URL
|
b.authURL = st.URL
|
||||||
b.authURLSticky = st.URL
|
b.authURLSticky = st.URL
|
||||||
}
|
}
|
||||||
if wasBlocked && st.LoginFinished() {
|
if (wasBlocked || b.seamlessRenewalEnabled()) && st.LoginFinished() {
|
||||||
// Interactive login finished successfully (URL visited).
|
// Interactive login finished successfully (URL visited).
|
||||||
// After an interactive login, the user always wants
|
// After an interactive login, the user always wants
|
||||||
// WantRunning.
|
// WantRunning.
|
||||||
@ -2456,8 +2458,10 @@ func (b *LocalBackend) popBrowserAuthNow() {
|
|||||||
|
|
||||||
b.logf("popBrowserAuthNow: url=%v", url != "")
|
b.logf("popBrowserAuthNow: url=%v", url != "")
|
||||||
|
|
||||||
b.blockEngineUpdates(true)
|
if !b.seamlessRenewalEnabled() {
|
||||||
b.stopEngineAndWait()
|
b.blockEngineUpdates(true)
|
||||||
|
b.stopEngineAndWait()
|
||||||
|
}
|
||||||
b.tellClientToBrowseToURL(url)
|
b.tellClientToBrowseToURL(url)
|
||||||
if b.State() == ipn.Running {
|
if b.State() == ipn.Running {
|
||||||
b.enterState(ipn.Starting)
|
b.enterState(ipn.Starting)
|
||||||
@ -4176,6 +4180,9 @@ func (b *LocalBackend) enterStateLockedOnEntry(newState ipn.State) {
|
|||||||
switch newState {
|
switch newState {
|
||||||
case ipn.NeedsLogin:
|
case ipn.NeedsLogin:
|
||||||
systemd.Status("Needs login: %s", authURL)
|
systemd.Status("Needs login: %s", authURL)
|
||||||
|
if b.seamlessRenewalEnabled() {
|
||||||
|
break
|
||||||
|
}
|
||||||
b.blockEngineUpdates(true)
|
b.blockEngineUpdates(true)
|
||||||
fallthrough
|
fallthrough
|
||||||
case ipn.Stopped:
|
case ipn.Stopped:
|
||||||
@ -5801,6 +5808,14 @@ func (b *LocalBackend) AdvertiseRoute(ipp netip.Prefix) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// seamlessRenewalEnabled reports whether seamless key renewals are enabled
|
||||||
|
// (i.e. we saw our self node with the SeamlessKeyRenewal attr in a netmap).
|
||||||
|
// This enables beta functionality of renewing node keys without breaking
|
||||||
|
// connections.
|
||||||
|
func (b *LocalBackend) seamlessRenewalEnabled() bool {
|
||||||
|
return b.ControlKnobs().SeamlessKeyRenewal.Load()
|
||||||
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
disallowedAddrs = []netip.Addr{
|
disallowedAddrs = []netip.Addr{
|
||||||
netip.MustParseAddr("::1"),
|
netip.MustParseAddr("::1"),
|
||||||
|
@ -124,7 +124,8 @@ type CapabilityVersion int
|
|||||||
// - 81: 2023-11-17: MapResponse.PacketFilters (incremental packet filter updates)
|
// - 81: 2023-11-17: MapResponse.PacketFilters (incremental packet filter updates)
|
||||||
// - 82: 2023-12-01: Client understands NodeAttrLinuxMustUseIPTables, NodeAttrLinuxMustUseNfTables, c2n /netfilter-kind
|
// - 82: 2023-12-01: Client understands NodeAttrLinuxMustUseIPTables, NodeAttrLinuxMustUseNfTables, c2n /netfilter-kind
|
||||||
// - 83: 2023-12-18: Client understands DefaultAutoUpdate
|
// - 83: 2023-12-18: Client understands DefaultAutoUpdate
|
||||||
const CurrentCapabilityVersion CapabilityVersion = 83
|
// - 84: 2024-01-04: Client understands SeamlessKeyRenewal
|
||||||
|
const CurrentCapabilityVersion CapabilityVersion = 84
|
||||||
|
|
||||||
type StableID string
|
type StableID string
|
||||||
|
|
||||||
@ -2190,6 +2191,10 @@ const (
|
|||||||
// netfilter management.
|
// netfilter management.
|
||||||
// This cannot be set simultaneously with NodeAttrLinuxMustUseIPTables.
|
// This cannot be set simultaneously with NodeAttrLinuxMustUseIPTables.
|
||||||
NodeAttrLinuxMustUseNfTables NodeCapability = "linux-netfilter?v=nftables"
|
NodeAttrLinuxMustUseNfTables NodeCapability = "linux-netfilter?v=nftables"
|
||||||
|
|
||||||
|
// NodeAttrSeamlessKeyRenewal makes clients enable beta functionality
|
||||||
|
// of renewing node keys without breaking connections.
|
||||||
|
NodeAttrSeamlessKeyRenewal NodeCapability = "seamless-key-renewal"
|
||||||
)
|
)
|
||||||
|
|
||||||
// SetDNSRequest is a request to add a DNS record.
|
// SetDNSRequest is a request to add a DNS record.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user