Merge branch 'main' into embedded-vnc

This commit is contained in:
Viktor Liu
2026-09-02 19:10:03 +02:00
153 changed files with 9089 additions and 1934 deletions
@@ -3,10 +3,7 @@ package networkmapdb
import (
"context"
"fmt"
"net/netip"
"strings"
"github.com/miekg/dns"
log "github.com/sirupsen/logrus"
"golang.org/x/exp/maps"
@@ -48,7 +45,7 @@ func (s *NetworkMapDBStoreImpl) GetNetworkMapData(ctx context.Context, accountId
if err != nil {
return rollbackAndReturnError(ctx, tx, fmt.Errorf("failed to get network: %w", err))
}
peers, proxyPeers, err := tx.GetPeers(ctx, accountId)
peers, _, err := tx.GetPeers(ctx, accountId)
if err != nil {
return rollbackAndReturnError(ctx, tx, fmt.Errorf("failed to get peers: %w", err))
}
@@ -80,10 +77,6 @@ func (s *NetworkMapDBStoreImpl) GetNetworkMapData(ctx context.Context, accountId
if err != nil {
return rollbackAndReturnError(ctx, tx, err)
}
services, err := tx.GetPrivateServices(ctx, accountId)
if err != nil {
return rollbackAndReturnError(ctx, tx, err)
}
proxyTargetedDomainResourceIDs, err := tx.GetProxyTargetedDomainResourceIDs(ctx, accountId)
if err != nil {
return rollbackAndReturnError(ctx, tx, fmt.Errorf("failed to get proxy targeted domain resources: %w", err))
@@ -113,7 +106,7 @@ func (s *NetworkMapDBStoreImpl) GetNetworkMapData(ctx context.Context, accountId
GroupIDToUserIDs: groupsToUserIds,
NetworkXIDToPublicID: networkXIDToPublicID, // TODO (dmitri) maybe we can switch to public ids everywhere?
AppliedZoneCandidates: dnsZones,
PrivateServiceCandidates: buildPrivateServiceCandidates(services, domains, proxyPeers),
Domains: TwinProxyDomains(domains),
PostureCheckXIDToPublicID: postureCheckXIDToPublicID,
ProxyTargetedDomainResourceIDs: proxyTargetedDomainResourceIDs,
}
@@ -154,94 +147,6 @@ func toSliceOfPtrs[T any](all []T) []*T {
return toret
}
func serviceDomainZone(svc Service, ds []Domain) string {
if domainFromSuffix(svc.Domain.String, svc.ProxyCluster.String) {
return svc.ProxyCluster.String
}
var zoneName string
for _, domain := range ds {
if domain.TargetCluster.String != svc.ProxyCluster.String {
continue
}
if domainFromSuffix(svc.Domain.String, domain.Domain.String) && len(domain.Domain.String) > len(zoneName) {
zoneName = domain.Domain.String
}
}
return zoneName
}
func domainFromSuffix(domain, suffix string) bool {
if suffix == "" {
return false
}
return domain == suffix || strings.HasSuffix(domain, "."+suffix)
}
func buildPrivateServiceCandidates(svcs []Service, domains []Domain, proxyPeersByCluster map[string][]*nmdata.Peer) []networkmap.PrivateServiceCandidate {
var out []networkmap.PrivateServiceCandidate
if len(proxyPeersByCluster) == 0 {
return out
}
for _, svc := range svcs {
if !svc.Enabled.Bool || !svc.Private.Bool {
continue
}
if len(svc.AccessGroups) == 0 {
continue
}
domainZone := serviceDomainZone(svc, domains)
if domainZone == "" {
continue
}
// this is implied when domainZone != "", but for maintainability's sake the check is explicit
// TODO (dmitri) make this an invariant
if svc.Domain.String == "" {
continue
}
var records []nmdata.SimpleRecord
for _, proxyPeer := range proxyPeersByCluster[svc.ProxyCluster.String] {
if record, ok := recordForProxyPeer(svc.Domain.String, proxyPeer.IP); ok {
records = append(records, record)
}
}
if len(records) == 0 {
continue
}
out = append(out, networkmap.PrivateServiceCandidate{
AccessGroups: svc.AccessGroups,
Zone: nmdata.CustomZone{
Domain: dns.Fqdn(domainZone),
Records: records,
NonAuthoritative: true,
SearchDomainDisabled: true,
},
})
}
return out
}
func recordForProxyPeer(fqdn string, ip netip.Addr) (nmdata.SimpleRecord, bool) {
if !ip.IsValid() {
return nmdata.SimpleRecord{}, false
}
return nmdata.SimpleRecord{
Name: dns.Fqdn(fqdn),
Type: int(dns.TypeA),
Class: "IN",
TTL: 5,
RData: ip.String(),
}, true
}
func buildResourcePolicies(networkResources []nmdata.NetworkResource,
policies []nmdata.Policy,
resourceToGroupIdx map[string]map[string]any,
@@ -1,253 +1,12 @@
package networkmapdb
import (
"database/sql"
"net/netip"
"testing"
"github.com/netbirdio/netbird/shared/management/networkmap"
"github.com/netbirdio/netbird/shared/management/networkmap/nmdata"
"github.com/stretchr/testify/assert"
)
func TestDomainFromSuffix(t *testing.T) {
assert.False(t, domainFromSuffix("test", ""))
assert.False(t, domainFromSuffix("test", "suffix")) // domain != suffix
assert.True(t, domainFromSuffix("test", "test")) // domain == suffix
assert.False(t, domainFromSuffix("test.anothersuffix", "suffix")) // domain doesn't contain suffix
assert.True(t, domainFromSuffix("test.suffix", "suffix")) // domain contains suffix
}
func TestServiceDomainZone(t *testing.T) {
// shortcut -- service's domain is a subomain of proxy cluster
assert.Equal(t, "cluster",
serviceDomainZone(
Service{
Domain: sql.NullString{Valid: true, String: "test.cluster"},
ProxyCluster: sql.NullString{Valid: true, String: "cluster"}},
[]Domain{}))
assert.Equal(t, "a.b", serviceDomainZone(
Service{
Domain: sql.NullString{Valid: true, String: "test.a.b"},
ProxyCluster: sql.NullString{Valid: true, String: "cluster"}},
[]Domain{
{TargetCluster: sql.NullString{Valid: true, String: "a-cluster"}},
{TargetCluster: sql.NullString{Valid: true, String: "cluster"},
Domain: sql.NullString{Valid: true, String: "b"}},
{TargetCluster: sql.NullString{Valid: true, String: "cluster"},
Domain: sql.NullString{Valid: true, String: "a.b"}}, // should return this domain, as it's the longest match
{TargetCluster: sql.NullString{Valid: true, String: "b-cluster"}},
}))
// service and domain clusters don't match
assert.Empty(t, serviceDomainZone(
Service{
Domain: sql.NullString{Valid: true, String: "test.a.b"},
ProxyCluster: sql.NullString{Valid: true, String: "c-cluster"}},
[]Domain{
{TargetCluster: sql.NullString{Valid: true, String: "cluster"},
Domain: sql.NullString{Valid: true, String: "a.b"}},
}))
// service domain is empty
assert.Empty(t, serviceDomainZone(
Service{
Domain: sql.NullString{Valid: false, String: ""},
ProxyCluster: sql.NullString{Valid: true, String: "cluster"}},
[]Domain{
{TargetCluster: sql.NullString{Valid: true, String: "cluster"},
Domain: sql.NullString{Valid: true, String: "a.b"}},
}))
}
func TestRecordForProxyPeer(t *testing.T) {
record, ok := recordForProxyPeer("test.cluster", netip.MustParseAddr("127.0.0.1"))
assert.True(t, ok)
assert.Equal(t, nmdata.SimpleRecord{
Name: "test.cluster.",
Type: 1,
Class: "IN",
TTL: 5,
RData: "127.0.0.1",
}, record)
// invalid address
var addr netip.Addr
_, ok = recordForProxyPeer("test.cluster", addr)
assert.False(t, ok)
}
var empty []networkmap.PrivateServiceCandidate
// empty proxyPeersByCluster results in empty []PrivateServiceCandidates
func TestBuildPrivateServiceCandidates_EmptyProxyPeers(t *testing.T) {
assert.Equal(t, empty, buildPrivateServiceCandidates([]Service{}, []Domain{}, nil))
}
// disabled service returns an empty result
func TestBuildPrivateServiceCandidates_DisabledService(t *testing.T) {
assert.Equal(t, empty,
buildPrivateServiceCandidates([]Service{
{Enabled: sql.NullBool{Valid: true, Bool: false},
Private: sql.NullBool{Valid: true, Bool: true},
AccessGroups: []string{"group-1", "group-2"},
Domain: sql.NullString{Valid: true, String: "test.a.b"},
ProxyCluster: sql.NullString{Valid: true, String: "cluster"}},
}, []Domain{
{TargetCluster: sql.NullString{Valid: true, String: "cluster"},
Domain: sql.NullString{Valid: true, String: "a.b"}},
},
map[string][]*nmdata.Peer{
"cluster": {&nmdata.Peer{IP: netip.MustParseAddr("127.0.0.1")}, &nmdata.Peer{IP: netip.MustParseAddr("127.0.0.2")}},
"a-cluster": {&nmdata.Peer{IP: netip.MustParseAddr("127.0.0.3")}, &nmdata.Peer{IP: netip.MustParseAddr("127.0.0.4")}},
}))
}
// non-private service results in empty []PrivateServiceCandidates
func TestBuildPrivateServiceCandidates_PublicService(t *testing.T) {
assert.Equal(t, empty,
buildPrivateServiceCandidates([]Service{
{Enabled: sql.NullBool{Valid: true, Bool: true},
Private: sql.NullBool{Valid: true, Bool: false},
AccessGroups: []string{"group-1", "group-2"},
Domain: sql.NullString{Valid: true, String: "test.a.b"},
ProxyCluster: sql.NullString{Valid: true, String: "cluster"}},
}, []Domain{
{TargetCluster: sql.NullString{Valid: true, String: "cluster"},
Domain: sql.NullString{Valid: true, String: "a.b"}},
},
map[string][]*nmdata.Peer{
"cluster": {&nmdata.Peer{IP: netip.MustParseAddr("127.0.0.1")}, &nmdata.Peer{IP: netip.MustParseAddr("127.0.0.2")}},
"a-cluster": {&nmdata.Peer{IP: netip.MustParseAddr("127.0.0.3")}, &nmdata.Peer{IP: netip.MustParseAddr("127.0.0.4")}},
}))
}
// empty AccessList results in empty []PrivateServiceCandidates
func TestBuildPrivateServiceCandidates_EmptyAccessList(t *testing.T) {
assert.Equal(t, empty,
buildPrivateServiceCandidates([]Service{
{Enabled: sql.NullBool{Valid: true, Bool: true},
Private: sql.NullBool{Valid: true, Bool: true},
Domain: sql.NullString{Valid: true, String: "test.a.b"},
ProxyCluster: sql.NullString{Valid: true, String: "cluster"}},
}, []Domain{
{TargetCluster: sql.NullString{Valid: true, String: "cluster"},
Domain: sql.NullString{Valid: true, String: "a.b"}},
},
map[string][]*nmdata.Peer{
"cluster": {&nmdata.Peer{IP: netip.MustParseAddr("127.0.0.1")}, &nmdata.Peer{IP: netip.MustParseAddr("127.0.0.2")}},
"a-cluster": {&nmdata.Peer{IP: netip.MustParseAddr("127.0.0.3")}, &nmdata.Peer{IP: netip.MustParseAddr("127.0.0.4")}},
}))
}
// empty TragetCluster results in empty []PrivateServiceCandidates
func TestBuildPrivateServiceCandidates_EmptyTargetCluster(t *testing.T) {
assert.Equal(t, empty,
buildPrivateServiceCandidates([]Service{
{Enabled: sql.NullBool{Valid: true, Bool: true},
Private: sql.NullBool{Valid: true, Bool: true},
AccessGroups: []string{"group-1", "group-2"},
Domain: sql.NullString{Valid: true, String: "test.a.b"},
ProxyCluster: sql.NullString{Valid: true, String: "cluster"}},
}, []Domain{
{TargetCluster: sql.NullString{Valid: true, String: ""},
Domain: sql.NullString{Valid: true, String: "a.b"}},
},
map[string][]*nmdata.Peer{
"cluster": {&nmdata.Peer{IP: netip.MustParseAddr("127.0.0.1")}, &nmdata.Peer{IP: netip.MustParseAddr("127.0.0.2")}},
"a-cluster": {&nmdata.Peer{IP: netip.MustParseAddr("127.0.0.3")}, &nmdata.Peer{IP: netip.MustParseAddr("127.0.0.4")}},
}))
}
func TestBuildPrivateServiceCandidates_EmptyServiceDomain(t *testing.T) {
assert.Equal(t, empty,
buildPrivateServiceCandidates([]Service{
{Enabled: sql.NullBool{Valid: true, Bool: true},
Private: sql.NullBool{Valid: true, Bool: true},
Domain: sql.NullString{Valid: true, String: ""},
ProxyCluster: sql.NullString{Valid: true, String: "cluster"}},
}, []Domain{
{TargetCluster: sql.NullString{Valid: true, String: "cluster"},
Domain: sql.NullString{Valid: true, String: "a.b"}},
},
map[string][]*nmdata.Peer{
"cluster": {&nmdata.Peer{IP: netip.MustParseAddr("127.0.0.1")}, &nmdata.Peer{IP: netip.MustParseAddr("127.0.0.2")}},
"a-cluster": {&nmdata.Peer{IP: netip.MustParseAddr("127.0.0.3")}, &nmdata.Peer{IP: netip.MustParseAddr("127.0.0.4")}},
}))
}
func TestBuildPrivateServiceCandidates_HappyPath(t *testing.T) {
assert.Equal(t, []networkmap.PrivateServiceCandidate{
{
AccessGroups: []string{"group-1", "group-2"},
Zone: nmdata.CustomZone{
Domain: "a.b.",
SearchDomainDisabled: true,
NonAuthoritative: true,
Records: []nmdata.SimpleRecord{
{
Name: "test.a.b.",
Type: 1,
Class: "IN",
TTL: 5,
RData: "127.0.0.1",
},
{
Name: "test.a.b.",
Type: 1,
Class: "IN",
TTL: 5,
RData: "127.0.0.2",
},
},
},
},
{
AccessGroups: []string{"group-1", "group-2"},
Zone: nmdata.CustomZone{
Domain: "c.d.",
SearchDomainDisabled: true,
NonAuthoritative: true,
Records: []nmdata.SimpleRecord{
{
Name: "test.c.d.",
Type: 1,
Class: "IN",
TTL: 5,
RData: "127.0.0.3",
},
{
Name: "test.c.d.",
Type: 1,
Class: "IN",
TTL: 5,
RData: "127.0.0.4",
},
},
},
},
},
buildPrivateServiceCandidates([]Service{
{Enabled: sql.NullBool{Valid: true, Bool: true},
Private: sql.NullBool{Valid: true, Bool: true},
AccessGroups: []string{"group-1", "group-2"},
Domain: sql.NullString{Valid: true, String: "test.a.b"},
ProxyCluster: sql.NullString{Valid: true, String: "cluster"}},
{Enabled: sql.NullBool{Valid: true, Bool: true},
Private: sql.NullBool{Valid: true, Bool: true},
AccessGroups: []string{"group-1", "group-2"},
Domain: sql.NullString{Valid: true, String: "test.c.d"},
ProxyCluster: sql.NullString{Valid: true, String: "a-cluster"}},
}, []Domain{
{TargetCluster: sql.NullString{Valid: true, String: "cluster"},
Domain: sql.NullString{Valid: true, String: "a.b"}},
{TargetCluster: sql.NullString{Valid: true, String: "a-cluster"},
Domain: sql.NullString{Valid: true, String: "c.d"}},
},
map[string][]*nmdata.Peer{
"cluster": {&nmdata.Peer{IP: netip.MustParseAddr("127.0.0.1")}, &nmdata.Peer{IP: netip.MustParseAddr("127.0.0.2")}},
"a-cluster": {&nmdata.Peer{IP: netip.MustParseAddr("127.0.0.3")}, &nmdata.Peer{IP: netip.MustParseAddr("127.0.0.4")}},
}))
}
// disabled network resource shouldn't be in the resulting map
func TestBuildResourcePolicies_DisabledNetworkResource(t *testing.T) {
networkResources := []nmdata.NetworkResource{
@@ -304,6 +304,7 @@ func ConvertToNmdataPeers(peers []Peer) ([]nmdata.Peer, map[string][]*nmdata.Pee
}
dp.ProxyMeta.Cluster = p.ProxyMetaCluster.String
// This is only used to build private service candidates, not connected peers are skipped
dp.Connected = p.PeerStatusConnected.Bool
if dp.ProxyMeta.Embedded && p.PeerStatusConnected.Bool {
clusterToPeerIdx[p.ProxyMetaCluster.String] = append(clusterToPeerIdx[p.ProxyMetaCluster.String], &dp)
}
@@ -481,3 +482,16 @@ func decodePolicyRuleColumns(p Policy, pr func() *nmdata.PolicyRule, resourceIdx
}
return nil
}
// TwinProxyDomains converts registered reverse-proxy domain rows to their slim
// twins, so private-service zone apex resolution runs on the twin.
func TwinProxyDomains(domains []Domain) []nmdata.ProxyDomain {
if len(domains) == 0 {
return nil
}
out := make([]nmdata.ProxyDomain, 0, len(domains))
for _, d := range domains {
out = append(out, nmdata.ProxyDomain{Domain: d.Domain.String, TargetCluster: d.TargetCluster.String})
}
return out
}