Skip to content

Commit 932e329

Browse files
authored
Don't delete static host mappings for non-primary IPs (#1464)
* Don't delete a vpnaddr if it's part of a certificate that contains a vpnaddr that's in the static host map * remove unused arg from ConnectionManager.shouldSwapPrimary()
1 parent 4bea299 commit 932e329

3 files changed

Lines changed: 145 additions & 13 deletions

File tree

connection_manager.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -356,7 +356,7 @@ func (cm *connectionManager) makeTrafficDecision(localIndex uint32, now time.Tim
356356
decision = tryRehandshake
357357

358358
} else {
359-
if cm.shouldSwapPrimary(hostinfo, primary) {
359+
if cm.shouldSwapPrimary(hostinfo) {
360360
decision = swapPrimary
361361
} else {
362362
// migrate the relays to the primary, if in use.
@@ -447,7 +447,7 @@ func (cm *connectionManager) isInactive(hostinfo *HostInfo, now time.Time) (time
447447
return inactiveDuration, true
448448
}
449449

450-
func (cm *connectionManager) shouldSwapPrimary(current, primary *HostInfo) bool {
450+
func (cm *connectionManager) shouldSwapPrimary(current *HostInfo) bool {
451451
// The primary tunnel is the most recent handshake to complete locally and should work entirely fine.
452452
// If we are here then we have multiple tunnels for a host pair and neither side believes the same tunnel is primary.
453453
// Let's sort this out.

lighthouse.go

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -519,11 +519,15 @@ func (lh *LightHouse) queryAndPrepMessage(vpnAddr netip.Addr, f func(*cache) (in
519519
}
520520

521521
func (lh *LightHouse) DeleteVpnAddrs(allVpnAddrs []netip.Addr) {
522-
// First we check the static mapping
523-
// and do nothing if it is there
524-
if _, ok := lh.GetStaticHostList()[allVpnAddrs[0]]; ok {
525-
return
522+
// First we check the static host map. If any of the VpnAddrs to be deleted are present, do nothing.
523+
staticList := lh.GetStaticHostList()
524+
for _, addr := range allVpnAddrs {
525+
if _, ok := staticList[addr]; ok {
526+
return
527+
}
526528
}
529+
530+
// None of the VpnAddrs were present. Now we can do the deletes.
527531
lh.Lock()
528532
rm, ok := lh.addrMap[allVpnAddrs[0]]
529533
if ok {
@@ -627,16 +631,24 @@ func (lh *LightHouse) addCalculatedRemotes(vpnAddr netip.Addr) bool {
627631
return len(calculatedV4) > 0 || len(calculatedV6) > 0
628632
}
629633

630-
// unlockedGetRemoteList
631-
// assumes you have the lh lock
634+
// unlockedGetRemoteList assumes you have the lh lock
632635
func (lh *LightHouse) unlockedGetRemoteList(allAddrs []netip.Addr) *RemoteList {
633-
am, ok := lh.addrMap[allAddrs[0]]
634-
if !ok {
635-
am = NewRemoteList(allAddrs, func(a netip.Addr) bool { return lh.shouldAdd(allAddrs[0], a) })
636-
for _, addr := range allAddrs {
637-
lh.addrMap[addr] = am
636+
// before we go and make a new remotelist, we need to make sure we don't have one for any of this set of vpnaddrs yet
637+
for i, addr := range allAddrs {
638+
am, ok := lh.addrMap[addr]
639+
if ok {
640+
if i != 0 {
641+
lh.addrMap[allAddrs[0]] = am
642+
}
643+
return am
638644
}
639645
}
646+
647+
//TODO lighthouse.remote_allow_ranges is almost certainly broken in a multiple-address-per-cert scenario
648+
am := NewRemoteList(allAddrs, func(a netip.Addr) bool { return lh.shouldAdd(allAddrs[0], a) })
649+
for _, addr := range allAddrs {
650+
lh.addrMap[addr] = am
651+
}
640652
return am
641653
}
642654

lighthouse_test.go

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -493,3 +493,123 @@ func Test_findNetworkUnion(t *testing.T) {
493493
out, ok = findNetworkUnion([]netip.Prefix{fc00}, []netip.Addr{a1, afe81})
494494
assert.False(t, ok)
495495
}
496+
497+
func TestLighthouse_Dont_Delete_Static_Hosts(t *testing.T) {
498+
l := test.NewLogger()
499+
500+
myUdpAddr2 := netip.MustParseAddrPort("1.2.3.4:4242")
501+
502+
testSameHostNotStatic := netip.MustParseAddr("10.128.0.41")
503+
testStaticHost := netip.MustParseAddr("10.128.0.42")
504+
//myVpnIp := netip.MustParseAddr("10.128.0.2")
505+
506+
c := config.NewC(l)
507+
lh1 := "10.128.0.2"
508+
c.Settings["lighthouse"] = map[string]any{
509+
"hosts": []any{lh1},
510+
"interval": "1s",
511+
}
512+
513+
c.Settings["listen"] = map[string]any{"port": 4242}
514+
c.Settings["static_host_map"] = map[string]any{
515+
lh1: []any{"1.1.1.1:4242"},
516+
"10.128.0.42": []any{"1.2.3.4:4242"},
517+
}
518+
519+
myVpnNet := netip.MustParsePrefix("10.128.0.1/24")
520+
nt := new(bart.Lite)
521+
nt.Insert(myVpnNet)
522+
cs := &CertState{
523+
myVpnNetworks: []netip.Prefix{myVpnNet},
524+
myVpnNetworksTable: nt,
525+
}
526+
lh, err := NewLightHouseFromConfig(context.Background(), l, c, cs, nil, nil)
527+
require.NoError(t, err)
528+
lh.ifce = &mockEncWriter{}
529+
530+
//test that we actually have the static entry:
531+
out := lh.Query(testStaticHost)
532+
assert.NotNil(t, out)
533+
assert.Equal(t, out.vpnAddrs[0], testStaticHost)
534+
out.Rebuild([]netip.Prefix{}) //why tho
535+
assert.Equal(t, out.addrs[0], myUdpAddr2)
536+
537+
//bolt on a lower numbered primary IP
538+
am := lh.unlockedGetRemoteList([]netip.Addr{testStaticHost})
539+
am.vpnAddrs = []netip.Addr{testSameHostNotStatic, testStaticHost}
540+
lh.addrMap[testSameHostNotStatic] = am
541+
out.Rebuild([]netip.Prefix{}) //???
542+
543+
//test that we actually have the static entry:
544+
out = lh.Query(testStaticHost)
545+
assert.NotNil(t, out)
546+
assert.Equal(t, out.vpnAddrs[0], testSameHostNotStatic)
547+
assert.Equal(t, out.vpnAddrs[1], testStaticHost)
548+
assert.Equal(t, out.addrs[0], myUdpAddr2)
549+
550+
//test that we actually have the static entry for BOTH:
551+
out2 := lh.Query(testSameHostNotStatic)
552+
assert.Same(t, out2, out)
553+
554+
//now do the delete
555+
lh.DeleteVpnAddrs([]netip.Addr{testSameHostNotStatic, testStaticHost})
556+
//verify
557+
out = lh.Query(testSameHostNotStatic)
558+
assert.NotNil(t, out)
559+
if out == nil {
560+
t.Fatal("expected non-nil query for the static host")
561+
}
562+
assert.Equal(t, out.vpnAddrs[0], testSameHostNotStatic)
563+
assert.Equal(t, out.vpnAddrs[1], testStaticHost)
564+
assert.Equal(t, out.addrs[0], myUdpAddr2)
565+
}
566+
567+
func TestLighthouse_DeletesWork(t *testing.T) {
568+
l := test.NewLogger()
569+
570+
myUdpAddr2 := netip.MustParseAddrPort("1.2.3.4:4242")
571+
testHost := netip.MustParseAddr("10.128.0.42")
572+
573+
c := config.NewC(l)
574+
lh1 := "10.128.0.2"
575+
c.Settings["lighthouse"] = map[string]any{
576+
"hosts": []any{lh1},
577+
"interval": "1s",
578+
}
579+
580+
c.Settings["listen"] = map[string]any{"port": 4242}
581+
c.Settings["static_host_map"] = map[string]any{
582+
lh1: []any{"1.1.1.1:4242"},
583+
}
584+
585+
myVpnNet := netip.MustParsePrefix("10.128.0.1/24")
586+
nt := new(bart.Lite)
587+
nt.Insert(myVpnNet)
588+
cs := &CertState{
589+
myVpnNetworks: []netip.Prefix{myVpnNet},
590+
myVpnNetworksTable: nt,
591+
}
592+
lh, err := NewLightHouseFromConfig(context.Background(), l, c, cs, nil, nil)
593+
require.NoError(t, err)
594+
lh.ifce = &mockEncWriter{}
595+
596+
//insert the host
597+
am := lh.unlockedGetRemoteList([]netip.Addr{testHost})
598+
am.vpnAddrs = []netip.Addr{testHost}
599+
am.addrs = []netip.AddrPort{myUdpAddr2}
600+
lh.addrMap[testHost] = am
601+
am.Rebuild([]netip.Prefix{}) //???
602+
603+
//test that we actually have the entry:
604+
out := lh.Query(testHost)
605+
assert.NotNil(t, out)
606+
assert.Equal(t, out.vpnAddrs[0], testHost)
607+
out.Rebuild([]netip.Prefix{}) //why tho
608+
assert.Equal(t, out.addrs[0], myUdpAddr2)
609+
610+
//now do the delete
611+
lh.DeleteVpnAddrs([]netip.Addr{testHost})
612+
//verify
613+
out = lh.Query(testHost)
614+
assert.Nil(t, out)
615+
}

0 commit comments

Comments
 (0)