From 037f6f6aa314a43fa229a9b88bbb1a1010a6f48c Mon Sep 17 00:00:00 2001 From: maggie44 <64841595+maggie44@users.noreply.github.com> Date: Sat, 16 Nov 2024 12:40:34 +0000 Subject: [PATCH 1/3] Add iterators for fetching hostmaps --- control.go | 45 +++++++++++++++++++++++++ control_test.go | 88 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 133 insertions(+) diff --git a/control.go b/control.go index 20dd7fe39..fbfa056f9 100644 --- a/control.go +++ b/control.go @@ -2,6 +2,7 @@ package nebula import ( "context" + "iter" "net/netip" "os" "os/signal" @@ -120,6 +121,15 @@ func (c *Control) ListHostmapHosts(pendingMap bool) []ControlHostInfo { } } +// ListHostmapHostsIter returns an iter with details about the actual or pending (handshaking) hostmap by vpn ip +func (c *Control) ListHostmapHostsIter(pendingMap bool) iter.Seq[*ControlHostInfo] { + if pendingMap { + return listHostMapHostsIter(c.f.handshakeManager) + } else { + return listHostMapHostsIter(c.f.hostMap) + } +} + // ListHostmapIndexes returns details about the actual or pending (handshaking) hostmap by local index id func (c *Control) ListHostmapIndexes(pendingMap bool) []ControlHostInfo { if pendingMap { @@ -129,6 +139,15 @@ func (c *Control) ListHostmapIndexes(pendingMap bool) []ControlHostInfo { } } +// ListHostmapIndexesIter returns an iter with details about the actual or pending (handshaking) hostmap by local index id +func (c *Control) ListHostmapIndexesIter(pendingMap bool) iter.Seq[*ControlHostInfo] { + if pendingMap { + return listHostMapIndexesIter(c.f.handshakeManager) + } else { + return listHostMapIndexesIter(c.f.hostMap) + } +} + // GetCertByVpnIp returns the authenticated certificate of the given vpn IP, or nil if not found func (c *Control) GetCertByVpnIp(vpnIp netip.Addr) cert.Certificate { _, found := c.f.myVpnAddrsTable.Lookup(vpnIp) @@ -306,6 +325,19 @@ func listHostMapHosts(hl controlHostLister) []ControlHostInfo { return hosts } +func listHostMapHostsIter(hl controlHostLister) iter.Seq[*ControlHostInfo] { + pr := hl.GetPreferredRanges() + + return iter.Seq[*ControlHostInfo](func(yield func(*ControlHostInfo) bool) { + hl.ForEachVpnIp(func(hostinfo *HostInfo) { + host := copyHostInfo(hostinfo, pr) + if !yield(&host) { + return // Stop iteration early if yield returns false + } + }) + }) +} + func listHostMapIndexes(hl controlHostLister) []ControlHostInfo { hosts := make([]ControlHostInfo, 0) pr := hl.GetPreferredRanges() @@ -314,3 +346,16 @@ func listHostMapIndexes(hl controlHostLister) []ControlHostInfo { }) return hosts } + +func listHostMapIndexesIter(hl controlHostLister) iter.Seq[*ControlHostInfo] { + pr := hl.GetPreferredRanges() + + return iter.Seq[*ControlHostInfo](func(yield func(*ControlHostInfo) bool) { + hl.ForEachIndex(func(hostinfo *HostInfo) { + host := copyHostInfo(hostinfo, pr) + if !yield(&host) { + return // Stop iteration early if yield returns false + } + }) + }) +} diff --git a/control_test.go b/control_test.go index 6ce708388..d2c455c09 100644 --- a/control_test.go +++ b/control_test.go @@ -110,6 +110,94 @@ func TestControl_GetHostInfoByVpnIp(t *testing.T) { }) } +func TestListHostMapHostsIter(t *testing.T) { + l := logrus.New() + hm := newHostMap(l, netip.Prefix{}) + hm.preferredRanges.Store(&[]netip.Prefix{}) + + hosts := []struct { + vpnIp netip.Addr + remoteAddr netip.AddrPort + localIndexId uint32 + remoteIndexId uint32 + }{ + {vpnIp: netip.MustParseAddr("0.0.0.2"), remoteAddr: netip.MustParseAddrPort("0.0.0.101:4445"), localIndexId: 202, remoteIndexId: 201}, + {vpnIp: netip.MustParseAddr("0.0.0.3"), remoteAddr: netip.MustParseAddrPort("0.0.0.102:4446"), localIndexId: 203, remoteIndexId: 202}, + {vpnIp: netip.MustParseAddr("0.0.0.4"), remoteAddr: netip.MustParseAddrPort("0.0.0.103:4447"), localIndexId: 204, remoteIndexId: 203}, + } + + for _, h := range hosts { + hm.unlockedAddHostInfo(&HostInfo{ + remote: h.remoteAddr, + ConnectionState: &ConnectionState{ + peerCert: nil, + }, + localIndexId: h.localIndexId, + remoteIndexId: h.remoteIndexId, + vpnIp: h.vpnIp, + }, &Interface{}) + } + + iter := listHostMapHostsIter(hm) + var results []ControlHostInfo + + for h := range iter { + results = append(results, *h) + } + + assert.Equal(t, len(hosts), len(results), "expected number of hosts in iterator") + for i, h := range hosts { + assert.Equal(t, h.vpnIp, results[i].VpnIp) + assert.Equal(t, h.localIndexId, results[i].LocalIndex) + assert.Equal(t, h.remoteIndexId, results[i].RemoteIndex) + assert.Equal(t, h.remoteAddr, results[i].CurrentRemote) + } +} + +func TestListHostMapIndexesIter(t *testing.T) { + l := logrus.New() + hm := newHostMap(l, netip.Prefix{}) + hm.preferredRanges.Store(&[]netip.Prefix{}) + + hosts := []struct { + vpnIp netip.Addr + remoteAddr netip.AddrPort + localIndexId uint32 + remoteIndexId uint32 + }{ + {vpnIp: netip.MustParseAddr("0.0.0.2"), remoteAddr: netip.MustParseAddrPort("0.0.0.101:4445"), localIndexId: 202, remoteIndexId: 201}, + {vpnIp: netip.MustParseAddr("0.0.0.3"), remoteAddr: netip.MustParseAddrPort("0.0.0.102:4446"), localIndexId: 203, remoteIndexId: 202}, + {vpnIp: netip.MustParseAddr("0.0.0.4"), remoteAddr: netip.MustParseAddrPort("0.0.0.103:4447"), localIndexId: 204, remoteIndexId: 203}, + } + + for _, h := range hosts { + hm.unlockedAddHostInfo(&HostInfo{ + remote: h.remoteAddr, + ConnectionState: &ConnectionState{ + peerCert: nil, + }, + localIndexId: h.localIndexId, + remoteIndexId: h.remoteIndexId, + vpnIp: h.vpnIp, + }, &Interface{}) + } + + iter := listHostMapIndexesIter(hm) + var results []ControlHostInfo + + for h := range iter { + results = append(results, *h) + } + + assert.Equal(t, len(hosts), len(results), "expected number of hosts in iterator") + for i, h := range hosts { + assert.Equal(t, h.vpnIp, results[i].VpnIp) + assert.Equal(t, h.localIndexId, results[i].LocalIndex) + assert.Equal(t, h.remoteIndexId, results[i].RemoteIndex) + assert.Equal(t, h.remoteAddr, results[i].CurrentRemote) + } +} + func assertFields(t *testing.T, expected []string, actualStruct interface{}) { val := reflect.ValueOf(actualStruct).Elem() fields := make([]string, val.NumField()) From cc39173b88443ad8e478247b554ac6e6c0fb8b17 Mon Sep 17 00:00:00 2001 From: maggie44 <64841595+maggie44@users.noreply.github.com> Date: Fri, 7 Mar 2025 20:57:26 +0000 Subject: [PATCH 2/3] Rename vpnIp to vpnAddrs in host map functions and tests --- control.go | 2 +- control_test.go | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/control.go b/control.go index fbfa056f9..f57cc32f1 100644 --- a/control.go +++ b/control.go @@ -329,7 +329,7 @@ func listHostMapHostsIter(hl controlHostLister) iter.Seq[*ControlHostInfo] { pr := hl.GetPreferredRanges() return iter.Seq[*ControlHostInfo](func(yield func(*ControlHostInfo) bool) { - hl.ForEachVpnIp(func(hostinfo *HostInfo) { + hl.ForEachVpnAddr(func(hostinfo *HostInfo) { host := copyHostInfo(hostinfo, pr) if !yield(&host) { return // Stop iteration early if yield returns false diff --git a/control_test.go b/control_test.go index d2c455c09..6632197ee 100644 --- a/control_test.go +++ b/control_test.go @@ -112,7 +112,7 @@ func TestControl_GetHostInfoByVpnIp(t *testing.T) { func TestListHostMapHostsIter(t *testing.T) { l := logrus.New() - hm := newHostMap(l, netip.Prefix{}) + hm := newHostMap(l) hm.preferredRanges.Store(&[]netip.Prefix{}) hosts := []struct { @@ -134,7 +134,7 @@ func TestListHostMapHostsIter(t *testing.T) { }, localIndexId: h.localIndexId, remoteIndexId: h.remoteIndexId, - vpnIp: h.vpnIp, + vpnAddrs: []netip.Addr{h.vpnIp}, }, &Interface{}) } @@ -147,7 +147,7 @@ func TestListHostMapHostsIter(t *testing.T) { assert.Equal(t, len(hosts), len(results), "expected number of hosts in iterator") for i, h := range hosts { - assert.Equal(t, h.vpnIp, results[i].VpnIp) + assert.Equal(t, h.vpnIp, results[i].VpnAddrs[0]) assert.Equal(t, h.localIndexId, results[i].LocalIndex) assert.Equal(t, h.remoteIndexId, results[i].RemoteIndex) assert.Equal(t, h.remoteAddr, results[i].CurrentRemote) @@ -156,7 +156,7 @@ func TestListHostMapHostsIter(t *testing.T) { func TestListHostMapIndexesIter(t *testing.T) { l := logrus.New() - hm := newHostMap(l, netip.Prefix{}) + hm := newHostMap(l) hm.preferredRanges.Store(&[]netip.Prefix{}) hosts := []struct { @@ -178,7 +178,7 @@ func TestListHostMapIndexesIter(t *testing.T) { }, localIndexId: h.localIndexId, remoteIndexId: h.remoteIndexId, - vpnIp: h.vpnIp, + vpnAddrs: []netip.Addr{h.vpnIp}, }, &Interface{}) } @@ -191,7 +191,7 @@ func TestListHostMapIndexesIter(t *testing.T) { assert.Equal(t, len(hosts), len(results), "expected number of hosts in iterator") for i, h := range hosts { - assert.Equal(t, h.vpnIp, results[i].VpnIp) + assert.Equal(t, h.vpnIp, results[i].VpnAddrs[0]) assert.Equal(t, h.localIndexId, results[i].LocalIndex) assert.Equal(t, h.remoteIndexId, results[i].RemoteIndex) assert.Equal(t, h.remoteAddr, results[i].CurrentRemote) From 3f47b62a662f1f9a3db1e750fad93480df38c286 Mon Sep 17 00:00:00 2001 From: maggie44 <64841595+maggie44@users.noreply.github.com> Date: Sat, 15 Mar 2025 16:17:01 +0000 Subject: [PATCH 3/3] Sort host map results by VPN addresses in iteration tests --- control_test.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/control_test.go b/control_test.go index 6632197ee..6537e6edc 100644 --- a/control_test.go +++ b/control_test.go @@ -4,6 +4,7 @@ import ( "net" "net/netip" "reflect" + "sort" "testing" "github.com/sirupsen/logrus" @@ -145,6 +146,10 @@ func TestListHostMapHostsIter(t *testing.T) { results = append(results, *h) } + sort.Slice(results, func(i, j int) bool { + return results[i].VpnAddrs[0].Less(results[j].VpnAddrs[0]) + }) + assert.Equal(t, len(hosts), len(results), "expected number of hosts in iterator") for i, h := range hosts { assert.Equal(t, h.vpnIp, results[i].VpnAddrs[0]) @@ -189,6 +194,10 @@ func TestListHostMapIndexesIter(t *testing.T) { results = append(results, *h) } + sort.Slice(results, func(i, j int) bool { + return results[i].VpnAddrs[0].Less(results[j].VpnAddrs[0]) + }) + assert.Equal(t, len(hosts), len(results), "expected number of hosts in iterator") for i, h := range hosts { assert.Equal(t, h.vpnIp, results[i].VpnAddrs[0])