Skip to content

Commit dc30dca

Browse files
authored
[management] Filter DNS records to include only peers to connect (#4517)
DNS record filtering to only include peers that a peer can connect to, reducing unnecessary DNS data in the peer's network map. - Adds a new `filterZoneRecordsForPeers` function to filter DNS records based on peer connectivity - Modifies `GetPeerNetworkMap` to use filtered DNS records instead of all records in the custom zone - Includes comprehensive test coverage for the new filtering functionality
1 parent 2c87fa6 commit dc30dca

File tree

2 files changed

+135
-1
lines changed

2 files changed

+135
-1
lines changed

management/server/types/account.go

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -302,7 +302,11 @@ func (a *Account) GetPeerNetworkMap(
302302
var zones []nbdns.CustomZone
303303

304304
if peersCustomZone.Domain != "" {
305-
zones = append(zones, peersCustomZone)
305+
records := filterZoneRecordsForPeers(peer, peersCustomZone, peersToConnect)
306+
zones = append(zones, nbdns.CustomZone{
307+
Domain: peersCustomZone.Domain,
308+
Records: records,
309+
})
306310
}
307311
dnsUpdate.CustomZones = zones
308312
dnsUpdate.NameServerGroups = getPeerNSGroups(a, peerID)
@@ -1651,3 +1655,24 @@ func peerSupportsPortRanges(peerVer string) bool {
16511655
meetMinVer, err := posture.MeetsMinVersion(firewallRuleMinPortRangesVer, peerVer)
16521656
return err == nil && meetMinVer
16531657
}
1658+
1659+
// filterZoneRecordsForPeers filters DNS records to only include peers to connect.
1660+
func filterZoneRecordsForPeers(peer *nbpeer.Peer, customZone nbdns.CustomZone, peersToConnect []*nbpeer.Peer) []nbdns.SimpleRecord {
1661+
filteredRecords := make([]nbdns.SimpleRecord, 0, len(customZone.Records))
1662+
peerIPs := make(map[string]struct{})
1663+
1664+
// Add peer's own IP to include its own DNS records
1665+
peerIPs[peer.IP.String()] = struct{}{}
1666+
1667+
for _, peerToConnect := range peersToConnect {
1668+
peerIPs[peerToConnect.IP.String()] = struct{}{}
1669+
}
1670+
1671+
for _, record := range customZone.Records {
1672+
if _, exists := peerIPs[record.RData]; exists {
1673+
filteredRecords = append(filteredRecords, record)
1674+
}
1675+
}
1676+
1677+
return filteredRecords
1678+
}

management/server/types/account_test.go

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,17 @@ package types
22

33
import (
44
"context"
5+
"fmt"
56
"net"
67
"net/netip"
78
"slices"
89
"testing"
910

11+
"github.com/miekg/dns"
1012
"github.com/stretchr/testify/assert"
1113
"github.com/stretchr/testify/require"
1214

15+
nbdns "github.com/netbirdio/netbird/dns"
1316
resourceTypes "github.com/netbirdio/netbird/management/server/networks/resources/types"
1417
routerTypes "github.com/netbirdio/netbird/management/server/networks/routers/types"
1518
networkTypes "github.com/netbirdio/netbird/management/server/networks/types"
@@ -835,3 +838,109 @@ func Test_NetworksNetMapGenShouldExcludeOtherRouters(t *testing.T) {
835838
assert.Len(t, networkResourcesRoutes, 1, "expected network resource route don't match")
836839
assert.Len(t, sourcePeers, 2, "expected source peers don't match")
837840
}
841+
842+
func Test_FilterZoneRecordsForPeers(t *testing.T) {
843+
tests := []struct {
844+
name string
845+
peer *nbpeer.Peer
846+
customZone nbdns.CustomZone
847+
peersToConnect []*nbpeer.Peer
848+
expectedRecords []nbdns.SimpleRecord
849+
}{
850+
{
851+
name: "empty peers to connect",
852+
customZone: nbdns.CustomZone{
853+
Domain: "netbird.cloud.",
854+
Records: []nbdns.SimpleRecord{
855+
{Name: "peer1.netbird.cloud", Type: int(dns.TypeA), Class: nbdns.DefaultClass, TTL: 300, RData: "10.0.0.1"},
856+
{Name: "router.netbird.cloud", Type: int(dns.TypeA), Class: nbdns.DefaultClass, TTL: 300, RData: "10.0.0.100"},
857+
},
858+
},
859+
peersToConnect: []*nbpeer.Peer{},
860+
peer: &nbpeer.Peer{ID: "router", IP: net.ParseIP("10.0.0.100")},
861+
expectedRecords: []nbdns.SimpleRecord{
862+
{Name: "router.netbird.cloud", Type: int(dns.TypeA), Class: nbdns.DefaultClass, TTL: 300, RData: "10.0.0.100"},
863+
},
864+
},
865+
{
866+
name: "multiple peers multiple records match",
867+
customZone: nbdns.CustomZone{
868+
Domain: "netbird.cloud.",
869+
Records: func() []nbdns.SimpleRecord {
870+
var records []nbdns.SimpleRecord
871+
for i := 1; i <= 100; i++ {
872+
records = append(records, nbdns.SimpleRecord{
873+
Name: fmt.Sprintf("peer%d.netbird.cloud", i),
874+
Type: int(dns.TypeA),
875+
Class: nbdns.DefaultClass,
876+
TTL: 300,
877+
RData: fmt.Sprintf("10.0.%d.%d", i/256, i%256),
878+
})
879+
}
880+
return records
881+
}(),
882+
},
883+
peersToConnect: func() []*nbpeer.Peer {
884+
var peers []*nbpeer.Peer
885+
for _, i := range []int{1, 5, 10, 25, 50, 75, 100} {
886+
peers = append(peers, &nbpeer.Peer{
887+
ID: fmt.Sprintf("peer%d", i),
888+
IP: net.ParseIP(fmt.Sprintf("10.0.%d.%d", i/256, i%256)),
889+
})
890+
}
891+
return peers
892+
}(),
893+
peer: &nbpeer.Peer{ID: "router", IP: net.ParseIP("10.0.0.100")},
894+
expectedRecords: func() []nbdns.SimpleRecord {
895+
var records []nbdns.SimpleRecord
896+
for _, i := range []int{1, 5, 10, 25, 50, 75, 100} {
897+
records = append(records, nbdns.SimpleRecord{
898+
Name: fmt.Sprintf("peer%d.netbird.cloud", i),
899+
Type: int(dns.TypeA),
900+
Class: nbdns.DefaultClass,
901+
TTL: 300,
902+
RData: fmt.Sprintf("10.0.%d.%d", i/256, i%256),
903+
})
904+
}
905+
return records
906+
}(),
907+
},
908+
{
909+
name: "peers with multiple DNS labels",
910+
customZone: nbdns.CustomZone{
911+
Domain: "netbird.cloud.",
912+
Records: []nbdns.SimpleRecord{
913+
{Name: "peer1.netbird.cloud", Type: int(dns.TypeA), Class: nbdns.DefaultClass, TTL: 300, RData: "10.0.0.1"},
914+
{Name: "peer1-alt.netbird.cloud", Type: int(dns.TypeA), Class: nbdns.DefaultClass, TTL: 300, RData: "10.0.0.1"},
915+
{Name: "peer1-backup.netbird.cloud", Type: int(dns.TypeA), Class: nbdns.DefaultClass, TTL: 300, RData: "10.0.0.1"},
916+
{Name: "peer2.netbird.cloud", Type: int(dns.TypeA), Class: nbdns.DefaultClass, TTL: 300, RData: "10.0.0.2"},
917+
{Name: "peer2-service.netbird.cloud", Type: int(dns.TypeA), Class: nbdns.DefaultClass, TTL: 300, RData: "10.0.0.2"},
918+
{Name: "peer3.netbird.cloud", Type: int(dns.TypeA), Class: nbdns.DefaultClass, TTL: 300, RData: "10.0.0.3"},
919+
{Name: "peer3-alt.netbird.cloud", Type: int(dns.TypeA), Class: nbdns.DefaultClass, TTL: 300, RData: "10.0.0.3"},
920+
{Name: "router.netbird.cloud", Type: int(dns.TypeA), Class: nbdns.DefaultClass, TTL: 300, RData: "10.0.0.100"},
921+
},
922+
},
923+
peersToConnect: []*nbpeer.Peer{
924+
{ID: "peer1", IP: net.ParseIP("10.0.0.1"), DNSLabel: "peer1", ExtraDNSLabels: []string{"peer1-alt", "peer1-backup"}},
925+
{ID: "peer2", IP: net.ParseIP("10.0.0.2"), DNSLabel: "peer2", ExtraDNSLabels: []string{"peer2-service"}},
926+
},
927+
peer: &nbpeer.Peer{ID: "router", IP: net.ParseIP("10.0.0.100")},
928+
expectedRecords: []nbdns.SimpleRecord{
929+
{Name: "peer1.netbird.cloud", Type: int(dns.TypeA), Class: nbdns.DefaultClass, TTL: 300, RData: "10.0.0.1"},
930+
{Name: "peer1-alt.netbird.cloud", Type: int(dns.TypeA), Class: nbdns.DefaultClass, TTL: 300, RData: "10.0.0.1"},
931+
{Name: "peer1-backup.netbird.cloud", Type: int(dns.TypeA), Class: nbdns.DefaultClass, TTL: 300, RData: "10.0.0.1"},
932+
{Name: "peer2.netbird.cloud", Type: int(dns.TypeA), Class: nbdns.DefaultClass, TTL: 300, RData: "10.0.0.2"},
933+
{Name: "peer2-service.netbird.cloud", Type: int(dns.TypeA), Class: nbdns.DefaultClass, TTL: 300, RData: "10.0.0.2"},
934+
{Name: "router.netbird.cloud", Type: int(dns.TypeA), Class: nbdns.DefaultClass, TTL: 300, RData: "10.0.0.100"},
935+
},
936+
},
937+
}
938+
939+
for _, tt := range tests {
940+
t.Run(tt.name, func(t *testing.T) {
941+
result := filterZoneRecordsForPeers(tt.peer, tt.customZone, tt.peersToConnect)
942+
assert.Equal(t, len(tt.expectedRecords), len(result))
943+
assert.ElementsMatch(t, tt.expectedRecords, result)
944+
})
945+
}
946+
}

0 commit comments

Comments
 (0)