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 <danderson@tailscale.com>
This commit is contained in:
David Anderson 2021-12-01 15:33:14 -08:00 committed by Denton Gentry
parent caf0da3628
commit 47975d373f

View File

@ -588,6 +588,11 @@ func (b *LocalBackend) setClientStatus(st controlclient.Status) {
// findExitNodeIDLocked updates b.prefs to reference an exit node by ID, // findExitNodeIDLocked updates b.prefs to reference an exit node by ID,
// rather than by IP. It returns whether prefs was mutated. // rather than by IP. It returns whether prefs was mutated.
func (b *LocalBackend) findExitNodeIDLocked(nm *netmap.NetworkMap) (prefsChanged bool) { 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 // If we have a desired IP on file, try to find the corresponding
// node. // node.
if b.prefs.ExitNodeIP.IsZero() { 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 // 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) { func (b *LocalBackend) setPrefsLockedOnEntry(caller string, newp *ipn.Prefs) {
netMap := b.netMap netMap := b.netMap
stateKey := b.stateKey stateKey := b.stateKey
@ -1659,6 +1664,10 @@ func (b *LocalBackend) setPrefsLockedOnEntry(caller string, newp *ipn.Prefs) {
oldp := b.prefs oldp := b.prefs
newp.Persist = oldp.Persist // caller isn't allowed to override this newp.Persist = oldp.Persist // caller isn't allowed to override this
b.prefs = newp 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 b.inServerMode = newp.ForceDaemon
// We do this to avoid holding the lock while doing everything else. // We do this to avoid holding the lock while doing everything else.
newp = b.prefs.Clone() newp = b.prefs.Clone()