do not send resource policies map over the wire

Signed-off-by: Dmitri Dolguikh <dmitri.external@netbird.io>
This commit is contained in:
Dmitri Dolguikh
2026-07-27 19:00:30 +02:00
parent a6603a2e0a
commit 2af3a5fba5
7 changed files with 743 additions and 469 deletions
+81 -6
View File
@@ -5,6 +5,7 @@ import (
"fmt"
"net"
"net/netip"
"slices"
"strconv"
"time"
@@ -98,9 +99,21 @@ func DecodeEnvelope(env *proto.NetworkMapEnvelope) (*types.NetworkMapComponents,
log.WithField("peer idx", idx).Error("unrecognized peer idx during decoding")
}
}
fromCompactResources := func() []nmdata.Resource {
var toret []nmdata.Resource
for _, r := range gc.Resources {
toret = append(toret, resourceFromProto(r, peerIDByIndex))
}
return toret
}
group := &nmdata.Group{
PublicID: gc.Id,
Peers: peerIDs,
PublicID: gc.Id,
Peers: peerIDs,
Resources: fromCompactResources(),
}
if gc.IsAll {
group.Name = types.GroupAllName
@@ -190,6 +203,15 @@ func DecodeEnvelope(env *proto.NetworkMapEnvelope) (*types.NetworkMapComponents,
}
}
// Phase 8: rebuild resource_policies_map
for _, r := range c.NetworkResources {
policies := policiesForNetworkResource(r.ID, c.Policies, c.Groups)
if len(policies) == 0 {
continue
}
c.ResourcePoliciesMap[r.ID] = policies
}
// Phase 9: group_id_to_user_ids — wire keys are seq ids, synth to strings.
for groupId, list := range full.GroupIdToUserIds {
c.GroupIDToUserIDs[groupId] = append([]string(nil), list.UserIds...)
@@ -225,6 +247,43 @@ func DecodeEnvelope(env *proto.NetworkMapEnvelope) (*types.NetworkMapComponents,
return c, nil
}
func networkResourceGroups(resourceId string, groups map[string]*nmdata.Group) []string {
var toret []string
for _, group := range groups {
for _, resource := range group.Resources {
if resource.ID == resourceId {
toret = append(toret, group.PublicID)
}
}
}
return toret
}
func policiesForNetworkResource(resourceId string, allPolicies []*nmdata.Policy, groups map[string]*nmdata.Group) []*nmdata.Policy {
var toret []*nmdata.Policy
networkResourceGroups := networkResourceGroups(resourceId, groups)
for _, p := range allPolicies {
if p == nil || !p.Enabled {
continue
}
// there's always only one rule in each policy
if p.Rules[0].DestinationResource.ID == resourceId {
toret = append(toret, p)
continue
}
for _, groupId := range networkResourceGroups {
if slices.Contains(p.Rules[0].Destinations, groupId) {
toret = append(toret, p)
break
}
}
}
return toret
}
func decodeAccountNetwork(an *proto.AccountNetwork) *nmdata.Network {
if an == nil {
return nil
@@ -341,11 +400,27 @@ func resourceFromProto(r *proto.ResourceCompact, peerIDByIndex []string) nmdata.
if r == nil {
return nmdata.Resource{}
}
out := nmdata.Resource{Type: r.Type}
if r.PeerIndexSet && int(r.PeerIndex) < len(peerIDByIndex) {
out.ID = peerIDByIndex[r.PeerIndex]
t, ok := proto.ResourceCompactType_name[int32(r.Type)]
if !ok || r.Type == proto.ResourceCompactType_unknown_type {
return nmdata.Resource{}
}
if r.Type == proto.ResourceCompactType_peer && int(r.GetPeerIndex()) >= len(peerIDByIndex) {
return nmdata.Resource{}
}
if r.Type == proto.ResourceCompactType_peer && int(r.GetPeerIndex()) < len(peerIDByIndex) {
return nmdata.Resource{
Type: "peer",
ID: peerIDByIndex[int(r.GetPeerIndex())],
}
}
return nmdata.Resource{
Type: t,
ID: r.GetId(),
}
return out
}
// authorizedGroupsFromProto inverts encodeAuthorizedGroups: the wire form
@@ -0,0 +1,40 @@
package networkmap
import (
"testing"
"github.com/netbirdio/netbird/shared/management/networkmap/nmdata"
"github.com/netbirdio/netbird/shared/management/proto"
"github.com/stretchr/testify/assert"
)
func TestDecodePolicy(t *testing.T) {
assert.Equal(t,
resourceFromProto(
&proto.ResourceCompact{Type: proto.ResourceCompactType_peer, ResourceId: &proto.ResourceCompact_PeerIndex{PeerIndex: uint32(1)}},
[]string{"invalid-id-0", "valid-id", "invalid-id-2"}),
nmdata.Resource{Type: "peer", ID: "valid-id"})
// check invalid peer index returns an empty resource
assert.Equal(t,
resourceFromProto(
&proto.ResourceCompact{Type: proto.ResourceCompactType_peer, ResourceId: &proto.ResourceCompact_PeerIndex{PeerIndex: uint32(100)}},
[]string{"invalid-id-0", "valid-id", "invalid-id-2"}),
nmdata.Resource{})
assert.Equal(t,
resourceFromProto(
&proto.ResourceCompact{Type: proto.ResourceCompactType_domain, ResourceId: &proto.ResourceCompact_Id{Id: "domain"}}, []string{}),
nmdata.Resource{Type: "domain", ID: "domain"})
assert.Equal(t,
resourceFromProto(
&proto.ResourceCompact{Type: proto.ResourceCompactType_host, ResourceId: &proto.ResourceCompact_Id{Id: "host"}}, []string{}),
nmdata.Resource{Type: "host", ID: "host"})
assert.Equal(t,
resourceFromProto(
&proto.ResourceCompact{Type: proto.ResourceCompactType_subnet, ResourceId: &proto.ResourceCompact_Id{Id: "subnet"}}, []string{}),
nmdata.Resource{Type: "subnet", ID: "subnet"})
// an unknown resource type return an empty resource
assert.Equal(t,
resourceFromProto(
&proto.ResourceCompact{Type: proto.ResourceCompactType_unknown_type, ResourceId: &proto.ResourceCompact_Id{Id: "boom"}}, []string{}),
nmdata.Resource{})
}
+4 -3
View File
@@ -6,9 +6,10 @@ const groupAllName = "All"
// Group is the slim twin of types.Group.
type Group struct {
Name string
PublicID string
Peers []string
Name string
PublicID string
Peers []string
Resources []Resource
}
func (g *Group) IsGroupAll() bool {
File diff suppressed because it is too large Load Diff
+15 -6
View File
@@ -1066,16 +1066,23 @@ message PolicyCompact {
repeated string source_posture_check_ids = 13;
}
enum ResourceCompactType {
unknown_type = 0; //placeholder
peer = 1;
domain = 2;
host = 3;
subnet = 4;
}
// ResourceCompact mirrors types.Resource. Used by PolicyCompact to carry
// rule.SourceResource / rule.DestinationResource when the rule targets a
// specific resource (typically a peer) rather than groups.
// peer_index_set tells whether peer_index is valid (proto3 uint32 cannot
// disambiguate "0" from "unset"); set only when type == "peer".
message ResourceCompact {
string type = 1;
bool peer_index_set = 2;
uint32 peer_index = 3;
reserved 4; // future: host/subnet/domain references when needed
ResourceCompactType type = 1;
oneof resource_id {
string id = 2; // for domain/host/subnet resources
uint32 peer_index = 3; // for peers
}
}
// UserNameList is a list of local-user names — used as the value type in
@@ -1099,6 +1106,8 @@ message GroupCompact {
// groups lose that property and the two sides expand policy
// destinations differently.
bool is_all = 3;
repeated ResourceCompact resources = 4;
}
// DNSSettingsCompact mirrors types.DNSSettings.