From 47975d373fb4798e3e78f1e2291d8e9dd0c7aec8 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Wed, 1 Dec 2021 15:33:14 -0800 Subject: [PATCH] ipn/ipnlocal: resolve exit node IP to ID at EditPrefs time. Without this, enabling an exit node immediately blackholes all traffic, but doesn't correctly let it flow to the exit node until the next netmap update. Fixes #3447 Signed-off-by: David Anderson --- ipn/ipnlocal/local.go | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/ipn/ipnlocal/local.go b/ipn/ipnlocal/local.go index 8f766bdbb..8644636b1 100644 --- a/ipn/ipnlocal/local.go +++ b/ipn/ipnlocal/local.go @@ -588,6 +588,11 @@ func (b *LocalBackend) setClientStatus(st controlclient.Status) { // findExitNodeIDLocked updates b.prefs to reference an exit node by ID, // rather than by IP. It returns whether prefs was mutated. func (b *LocalBackend) findExitNodeIDLocked(nm *netmap.NetworkMap) (prefsChanged bool) { + if nm == nil { + // No netmap, can't resolve anything. + return false + } + // If we have a desired IP on file, try to find the corresponding // node. if b.prefs.ExitNodeIP.IsZero() { @@ -1651,7 +1656,7 @@ func (b *LocalBackend) SetPrefs(newp *ipn.Prefs) { } // setPrefsLockedOnEntry requires b.mu be held to call it, but it -// unlocks b.mu when done. +// unlocks b.mu when done. newp ownership passes to this function. func (b *LocalBackend) setPrefsLockedOnEntry(caller string, newp *ipn.Prefs) { netMap := b.netMap stateKey := b.stateKey @@ -1659,6 +1664,10 @@ func (b *LocalBackend) setPrefsLockedOnEntry(caller string, newp *ipn.Prefs) { oldp := b.prefs newp.Persist = oldp.Persist // caller isn't allowed to override this b.prefs = newp + // findExitNodeIDLocked returns whether it updated b.prefs, but + // everything in this function treats b.prefs as completely new + // anyway. No-op if no exit node resolution is needed. + b.findExitNodeIDLocked(netMap) b.inServerMode = newp.ForceDaemon // We do this to avoid holding the lock while doing everything else. newp = b.prefs.Clone()