mirror of
https://github.com/netbirdio/netbird.git
synced 2026-08-27 01:51:30 +02:00
Guard network map component encoding when the target peer is absent
This commit is contained in:
@@ -58,14 +58,22 @@ func EncodeNetworkMapEnvelope(in ComponentsEnvelopeInput) *proto.NetworkMapEnvel
|
||||
// Match legacy missing-peer minimum: a NetworkMap with only Network
|
||||
// populated. The receiver gets enough to bootstrap (Network
|
||||
// identifier, dns_domain, account_settings) and the peer itself.
|
||||
//
|
||||
// components.Peers carries the target peer unless the peer vanished
|
||||
// from the account mid-sync, in which case there is nothing to send
|
||||
// for it and the slice stays empty rather than holding a nil entry.
|
||||
var peers []*proto.PeerCompact
|
||||
if target := toPeerCompact(c.Peers[c.PeerID]); target != nil {
|
||||
peers = []*proto.PeerCompact{target}
|
||||
}
|
||||
|
||||
return &proto.NetworkMapEnvelope{
|
||||
Payload: &proto.NetworkMapEnvelope_Full{
|
||||
Full: &proto.NetworkMapComponentsFull{
|
||||
Serial: networkSerial(c.Network),
|
||||
Network: toAccountNetwork(c.Network),
|
||||
PeerConfig: in.PeerConfig,
|
||||
// components.Peers always contains the target peer
|
||||
Peers: []*proto.PeerCompact{toPeerCompact(c.Peers[c.PeerID])},
|
||||
Serial: networkSerial(c.Network),
|
||||
Network: toAccountNetwork(c.Network),
|
||||
PeerConfig: in.PeerConfig,
|
||||
Peers: peers,
|
||||
DnsDomain: in.DNSDomain,
|
||||
DnsForwarderPort: in.DNSForwarderPort,
|
||||
UserIdClaim: in.UserIDClaim,
|
||||
@@ -692,6 +700,9 @@ func toAccountNetwork(n *types.Network) *proto.AccountNetwork {
|
||||
}
|
||||
|
||||
func toPeerCompact(p *types.ComponentPeer) *proto.PeerCompact {
|
||||
if p == nil {
|
||||
return nil
|
||||
}
|
||||
pc := &proto.PeerCompact{
|
||||
WgPubKey: decodeWgKey(p.Key),
|
||||
SshPubKey: []byte(p.SSHKey),
|
||||
|
||||
@@ -20,9 +20,11 @@ import (
|
||||
"github.com/netbirdio/netbird/shared/management/proto"
|
||||
)
|
||||
|
||||
const testWgKeyA = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopq="
|
||||
const testWgKeyB = "BBCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopq="
|
||||
const testWgKeyC = "CBCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopq="
|
||||
const (
|
||||
testWgKeyA = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopq="
|
||||
testWgKeyB = "BBCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopq="
|
||||
testWgKeyC = "CBCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopq="
|
||||
)
|
||||
|
||||
// canonicalize rewrites a NetworkMapComponentsFull in place into a canonical
|
||||
// form: peers reordered by wg_pub_key, with the rest of the message rewritten
|
||||
@@ -367,7 +369,7 @@ func TestEncodeNetworkMapEnvelope_MalformedWgKey(t *testing.T) {
|
||||
|
||||
require.Len(t, full.Peers, 3)
|
||||
|
||||
var byLabel = map[string]*proto.PeerCompact{}
|
||||
byLabel := map[string]*proto.PeerCompact{}
|
||||
for _, p := range full.Peers {
|
||||
byLabel[p.DnsLabel] = p
|
||||
}
|
||||
@@ -788,3 +790,40 @@ func emptyNetworkMapComponents() *types.NetworkMapComponents {
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
func TestEncodeNetworkMapEnvelope_EmptyComponentsMissingTargetPeer(t *testing.T) {
|
||||
for name, peers := range map[string]map[string]*types.ComponentPeer{
|
||||
"absent entry": {},
|
||||
"nil entry": {"peer-id": nil},
|
||||
} {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
c := types.EmptyNetworkMapComponents(&types.NetworkMapComponents{
|
||||
PeerID: "peer-id",
|
||||
Peers: peers,
|
||||
Network: &types.Network{
|
||||
Identifier: "net-empty",
|
||||
Net: net.IPNet{IP: net.IP{100, 64, 0, 0}, Mask: net.CIDRMask(10, 32)},
|
||||
Serial: 9,
|
||||
},
|
||||
})
|
||||
|
||||
full := EncodeNetworkMapEnvelope(ComponentsEnvelopeInput{
|
||||
Components: c,
|
||||
DNSDomain: "netbird.cloud",
|
||||
}).GetFull()
|
||||
|
||||
require.NotNil(t, full)
|
||||
assert.Empty(t, full.Peers, "a missing target peer must not become a nil entry on the wire")
|
||||
require.NotNil(t, full.Network, "the account Network floor still applies")
|
||||
assert.Equal(t, "net-empty", full.Network.Identifier)
|
||||
assert.Equal(t, uint64(9), full.Serial)
|
||||
require.NotNil(t, full.AccountSettings)
|
||||
|
||||
wire, err := goproto.Marshal(&proto.NetworkMapEnvelope{
|
||||
Payload: &proto.NetworkMapEnvelope_Full{Full: full},
|
||||
})
|
||||
require.NoError(t, err, "envelope must stay marshalable")
|
||||
assert.NotEmpty(t, wire)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -109,11 +109,13 @@ func (a *Account) GetPeerNetworkMapComponents(
|
||||
// TODO (dmitri) maybe consider using invariants?
|
||||
if peer == nil {
|
||||
log.WithField("peer id", peerID).Error("NetworkMapComponents are computed for a peer missing from the account")
|
||||
// The peer is gone from the account, so there is nothing to carry
|
||||
// for it. The client resolves its own identity from PeerConfig and
|
||||
// tolerates a peers list without it.
|
||||
return EmptyNetworkMapComponents(&NetworkMapComponents{
|
||||
PeerID: peerID,
|
||||
Network: a.Network.Copy(),
|
||||
// must include the target peer as it's required on the client
|
||||
Peers: map[string]*ComponentPeer{peerID: peer.ToComponent()},
|
||||
Peers: map[string]*ComponentPeer{},
|
||||
})
|
||||
}
|
||||
|
||||
@@ -506,7 +508,8 @@ func (a *Account) getPeersGroupsPoliciesRoutes(
|
||||
}
|
||||
|
||||
func (a *Account) getPeersFromGroups(ctx context.Context, groups []string, peerID string, sourcePostureChecksIDs []string,
|
||||
validatedPeersMap map[string]struct{}, postureFailedPeers *map[string]map[string]struct{}) ([]string, bool) {
|
||||
validatedPeersMap map[string]struct{}, postureFailedPeers *map[string]map[string]struct{},
|
||||
) ([]string, bool) {
|
||||
peerInGroups := false
|
||||
var filteredPeerIDs []string
|
||||
var seenPeerIds map[string]struct{}
|
||||
@@ -705,7 +708,7 @@ func peerPassesPostureChecks(ctx context.Context, checks []posture.Check, peer *
|
||||
return true
|
||||
}
|
||||
|
||||
func (a *Account) getPostureValidPeersSaveFailed(inputPeers []string, postureChecksIDs []string, validatedPeersMap map[string]struct{}, postureFailedPeers *map[string]map[string]struct{}) []string {
|
||||
func (a *Account) getPostureValidPeersSaveFailed(inputPeers, postureChecksIDs []string, validatedPeersMap map[string]struct{}, postureFailedPeers *map[string]map[string]struct{}) []string {
|
||||
var dest []string
|
||||
for _, peerID := range inputPeers {
|
||||
if _, validated := validatedPeersMap[peerID]; !validated {
|
||||
|
||||
Reference in New Issue
Block a user