From 44d0c1ab064cf52de14d94f6bd534c52ed425ed4 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 2ebb3e18d..01ef51f84 100644 --- a/ipn/ipnlocal/local.go +++ b/ipn/ipnlocal/local.go @@ -620,6 +620,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() { @@ -1688,7 +1693,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 @@ -1696,6 +1701,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()