Skip to content

Commit 8673386

Browse files
authored
don't make new relay state on a just-discarded tunnel (#1796)
1 parent ab736e4 commit 8673386

2 files changed

Lines changed: 14 additions & 3 deletions

File tree

hostmap.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -448,13 +448,15 @@ func (hm *HostMap) MakePrimary(hostinfo *HostInfo) {
448448
hm.unlockedMakePrimary(hostinfo)
449449
}
450450

451-
func (hm *HostMap) unlockedMakePrimary(hostinfo *HostInfo) {
451+
// unlockedMakePrimary reports whether hostinfo is (now) the primary for each of its addresses,
452+
// false only when it is no longer in the hostmap at all.
453+
func (hm *HostMap) unlockedMakePrimary(hostinfo *HostInfo) bool {
452454
// A hostinfo that is no longer in the hostmap must not be re-inserted here. Callers can race
453455
// tunnel teardown, deciding to promote under the read lock and only taking the write lock
454456
// after a delete fully unlinked the hostinfo (connection manager swapPrimary, AddRelay). Every
455457
// live hostinfo is registered in Indexes by unlockedAddHostInfo, so this is a membership test.
456458
if hm.Indexes[hostinfo.localIndexId] != hostinfo {
457-
return
459+
return false
458460
}
459461

460462
// Move hostinfo to the front (primary) of each of its address lists. The lists are
@@ -469,6 +471,7 @@ func (hm *HostMap) unlockedMakePrimary(hostinfo *HostInfo) {
469471
list = append([]*HostInfo{hostinfo}, list...)
470472
hm.unlockedSetHostsForAddr(addr, list)
471473
}
474+
return true
472475
}
473476

474477
// unlockedDeleteHostInfo removes hostinfo from every one of its address lists and from the index

relay_manager.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,10 @@ func (rm *relayManager) StartRelays(f *Interface, vpnIp netip.Addr, hh *Handshak
107107
if relayHostInfo.GetRemote().IsValid() {
108108
idx, err := AddRelay(rm.l, relayHostInfo, rm.hostmap, vpnIp, nil, TerminalType, Requested)
109109
if err != nil {
110+
// No local relay state was installed, so a CreateRelayRequest would hand the
111+
// peer an index we could never resolve. Skip it.
110112
hl.Info("Failed to add relay to hostmap", "relay", relay.String(), "error", err)
113+
continue
111114
}
112115

113116
m := NebulaControl{
@@ -237,7 +240,12 @@ func AddRelay(l *slog.Logger, relayHostInfo *HostInfo, hm *HostMap, vpnIp netip.
237240
// Avoid standing up a relay that can't be used since only the primary hostinfo
238241
// will be pointed to by the relay logic
239242
//TODO: if there was an existing primary and it had relay state, should we merge?
240-
hm.unlockedMakePrimary(relayHostInfo)
243+
if !hm.unlockedMakePrimary(relayHostInfo) {
244+
// The tunnel was torn down after the caller grabbed relayHostInfo. A relay standing
245+
// on an unlinked hostinfo would never carry traffic, and its Relays entry could
246+
// never be reclaimed since the delete-time cleanup has already run.
247+
return 0, errors.New("relay hostinfo is no longer in the hostmap")
248+
}
241249

242250
hm.Relays[index] = relayHostInfo
243251
newRelay := Relay{

0 commit comments

Comments
 (0)