Feature/dns protocol (#543)

Added DNS update protocol message

Added sync to clients

Update nameserver API with new fields

Added default NS groups

Added new dns-name flag for the management service append to peer DNS label
This commit is contained in:
Maycon Santos
2022-11-07 15:38:21 +01:00
committed by GitHub
parent d0c6d88971
commit 270f0e4ce8
29 changed files with 1316 additions and 242 deletions

View File

@@ -114,6 +114,8 @@ type DefaultAccountManager struct {
singleAccountMode bool
// singleAccountModeDomain is a domain to use in singleAccountMode setup
singleAccountModeDomain string
// dnsDomain is used for peer resolution. This is appended to the peer's name
dnsDomain string
}
// Account represents a unique account of the system
@@ -279,6 +281,17 @@ func (a *Account) FindUser(userID string) (*User, error) {
return user, nil
}
// getPeerDNSLabels return the account's peers' dns labels
func (a *Account) getPeerDNSLabels() lookupMap {
existingLabels := make(lookupMap)
for _, peer := range a.Peers {
if peer.DNSLabel != "" {
existingLabels[peer.DNSLabel] = struct{}{}
}
}
return existingLabels
}
func (a *Account) Copy() *Account {
peers := map[string]*Peer{}
for id, peer := range a.Peers {
@@ -343,7 +356,7 @@ func (a *Account) GetGroupAll() (*Group, error) {
// BuildManager creates a new DefaultAccountManager with a provided Store
func BuildManager(store Store, peersUpdateManager *PeersUpdateManager, idpManager idp.Manager,
singleAccountModeDomain string) (*DefaultAccountManager, error) {
singleAccountModeDomain string, dnsDomain string) (*DefaultAccountManager, error) {
am := &DefaultAccountManager{
Store: store,
mux: sync.Mutex{},
@@ -352,6 +365,7 @@ func BuildManager(store Store, peersUpdateManager *PeersUpdateManager, idpManage
ctx: context.Background(),
cacheMux: sync.Mutex{},
cacheLoading: map[string]chan struct{}{},
dnsDomain: dnsDomain,
}
allAccounts := store.GetAllAccounts()
// enable single account mode only if configured by user and number of existing accounts is not grater than 1
@@ -367,10 +381,23 @@ func BuildManager(store Store, peersUpdateManager *PeersUpdateManager, idpManage
// we create 'all' group and add all peers into it
// also we create default rule with source as destination
for _, account := range allAccounts {
shouldSave := false
_, err := account.GetGroupAll()
if err != nil {
addAllGroup(account)
if err := store.SaveAccount(account); err != nil {
shouldSave = true
}
existingLabels := account.getPeerDNSLabels()
if len(existingLabels) != len(account.Peers) {
addPeerLabelsToAccount(account, existingLabels)
shouldSave = true
}
if shouldSave {
err = store.SaveAccount(account)
if err != nil {
return nil, err
}
}

View File

@@ -1124,7 +1124,7 @@ func createManager(t *testing.T) (*DefaultAccountManager, error) {
if err != nil {
return nil, err
}
return BuildManager(store, NewPeersUpdateManager(), nil, "")
return BuildManager(store, NewPeersUpdateManager(), nil, "", "")
}
func createStore(t *testing.T) (Store, error) {

152
management/server/dns.go Normal file
View File

@@ -0,0 +1,152 @@
package server
import (
"fmt"
"github.com/miekg/dns"
nbdns "github.com/netbirdio/netbird/dns"
"github.com/netbirdio/netbird/management/proto"
log "github.com/sirupsen/logrus"
"strconv"
)
type lookupMap map[string]struct{}
const defaultTTL = 300
func toProtocolDNSConfig(update nbdns.Config) *proto.DNSConfig {
protoUpdate := &proto.DNSConfig{ServiceEnable: update.ServiceEnable}
for _, zone := range update.CustomZones {
protoZone := &proto.CustomZone{Domain: zone.Domain}
for _, record := range zone.Records {
protoZone.Records = append(protoZone.Records, &proto.SimpleRecord{
Name: record.Name,
Type: int64(record.Type),
Class: record.Class,
TTL: int64(record.TTL),
RData: record.RData,
})
}
protoUpdate.CustomZones = append(protoUpdate.CustomZones, protoZone)
}
for _, nsGroup := range update.NameServerGroups {
protoGroup := &proto.NameServerGroup{
Primary: nsGroup.Primary,
Domains: nsGroup.Domains,
}
for _, ns := range nsGroup.NameServers {
protoNS := &proto.NameServer{
IP: ns.IP.String(),
Port: int64(ns.Port),
NSType: int64(ns.NSType),
}
protoGroup.NameServers = append(protoGroup.NameServers, protoNS)
}
protoUpdate.NameServerGroups = append(protoUpdate.NameServerGroups, protoGroup)
}
return protoUpdate
}
func getPeersCustomZone(account *Account, dnsDomain string) nbdns.CustomZone {
if dnsDomain == "" {
log.Errorf("no dns domain is set, returning empty zone")
return nbdns.CustomZone{}
}
customZone := nbdns.CustomZone{
Domain: dns.Fqdn(dnsDomain),
}
for _, peer := range account.Peers {
if peer.DNSLabel == "" {
log.Errorf("found a peer with empty dns label. It was probably caused by a invalid character in its name. Peer Name: %s", peer.Name)
continue
}
customZone.Records = append(customZone.Records, nbdns.SimpleRecord{
Name: dns.Fqdn(peer.DNSLabel + "." + dnsDomain),
Type: int(dns.TypeA),
Class: nbdns.DefaultClass,
TTL: defaultTTL,
RData: peer.IP.String(),
})
}
return customZone
}
func getPeerNSGroups(account *Account, peerID string) []*nbdns.NameServerGroup {
groupList := make(lookupMap)
for groupID, group := range account.Groups {
for _, id := range group.Peers {
if id == peerID {
groupList[groupID] = struct{}{}
break
}
}
}
var peerNSGroups []*nbdns.NameServerGroup
for _, nsGroup := range account.NameServerGroups {
if !nsGroup.Enabled {
continue
}
for _, gID := range nsGroup.Groups {
_, found := groupList[gID]
if found {
peerNSGroups = append(peerNSGroups, nsGroup.Copy())
break
}
}
}
return peerNSGroups
}
func addPeerLabelsToAccount(account *Account, peerLabels lookupMap) {
for _, peer := range account.Peers {
label, err := getPeerHostLabel(peer.Name, peerLabels)
if err != nil {
log.Errorf("got an error while generating a peer host label. Peer name %s, error: %v. Trying with the peer's meta hostname", peer.Name, err)
label, err = getPeerHostLabel(peer.Meta.Hostname, peerLabels)
if err != nil {
log.Errorf("got another error while generating a peer host label with hostname. Peer hostname %s, error: %v. Skiping", peer.Meta.Hostname, err)
continue
}
}
peer.DNSLabel = label
peerLabels[label] = struct{}{}
}
}
func getPeerHostLabel(name string, peerLabels lookupMap) (string, error) {
label, err := nbdns.GetParsedDomainLabel(name)
if err != nil {
return "", err
}
uniqueLabel := getUniqueHostLabel(label, peerLabels)
if uniqueLabel == "" {
return "", fmt.Errorf("couldn't find a unique valid lavel for %s, parsed label %s", name, label)
}
return uniqueLabel, nil
}
// getUniqueHostLabel look for a unique host label, and if doesn't find add a suffix up to 999
func getUniqueHostLabel(name string, peerLabels lookupMap) string {
_, found := peerLabels[name]
if !found {
return name
}
for i := 1; i < 1000; i++ {
nameWithSuffix := name + "-" + strconv.Itoa(i)
_, found = peerLabels[nameWithSuffix]
if !found {
return nameWithSuffix
}
}
return ""
}

View File

@@ -4,7 +4,6 @@ import (
"context"
"fmt"
"github.com/netbirdio/netbird/management/server/telemetry"
"github.com/netbirdio/netbird/route"
gPeer "google.golang.org/grpc/peer"
"strings"
"time"
@@ -253,17 +252,15 @@ func (s *GRPCServer) registerPeer(peerKey wgtypes.Key, req *proto.LoginRequest)
if err != nil {
return nil, status.Errorf(codes.Internal, "unable to fetch network map after registering peer, error: %v", err)
}
// notify other peers of our registration
for _, remotePeer := range networkMap.Peers {
// exclude notified peer and add ourselves
peersToSend := []*Peer{peer}
for _, p := range networkMap.Peers {
if remotePeer.Key != p.Key {
peersToSend = append(peersToSend, p)
}
// todo update this once we have store v2 to avoid lock/peer
remotePeerNetworkMap, err := s.accountManager.GetNetworkMap(remotePeer.Key)
if err != nil {
return nil, status.Errorf(codes.Internal, "unable to fetch network map after registering peer, error: %v", err)
}
update := toSyncResponse(s.config, remotePeer, peersToSend, networkMap.Routes, nil, networkMap.Network.CurrentSerial(), networkMap.Network)
update := toSyncResponse(s.config, remotePeer, nil, remotePeerNetworkMap)
err = s.peersUpdateManager.SendUpdate(remotePeer.Key, &UpdateMessage{Update: update})
if err != nil {
// todo rethink if we should keep this return
@@ -451,14 +448,16 @@ func toRemotePeerConfig(peers []*Peer) []*proto.RemotePeerConfig {
return remotePeers
}
func toSyncResponse(config *Config, peer *Peer, peers []*Peer, routes []*route.Route, turnCredentials *TURNCredentials, serial uint64, network *Network) *proto.SyncResponse {
func toSyncResponse(config *Config, peer *Peer, turnCredentials *TURNCredentials, networkMap *NetworkMap) *proto.SyncResponse {
wtConfig := toWiretrusteeConfig(config, turnCredentials)
pConfig := toPeerConfig(peer, network)
pConfig := toPeerConfig(peer, networkMap.Network)
remotePeers := toRemotePeerConfig(peers)
remotePeers := toRemotePeerConfig(networkMap.Peers)
routesUpdate := toProtocolRoutes(routes)
routesUpdate := toProtocolRoutes(networkMap.Routes)
dnsUpdate := toProtocolDNSConfig(networkMap.DNSConfig)
return &proto.SyncResponse{
WiretrusteeConfig: wtConfig,
@@ -466,11 +465,12 @@ func toSyncResponse(config *Config, peer *Peer, peers []*Peer, routes []*route.R
RemotePeers: remotePeers,
RemotePeersIsEmpty: len(remotePeers) == 0,
NetworkMap: &proto.NetworkMap{
Serial: serial,
Serial: networkMap.Network.CurrentSerial(),
PeerConfig: pConfig,
RemotePeers: remotePeers,
RemotePeersIsEmpty: len(remotePeers) == 0,
Routes: routesUpdate,
DNSConfig: dnsUpdate,
},
}
}
@@ -496,7 +496,7 @@ func (s *GRPCServer) sendInitialSync(peerKey wgtypes.Key, peer *Peer, srv proto.
} else {
turnCredentials = nil
}
plainResp := toSyncResponse(s.config, peer, networkMap.Peers, networkMap.Routes, turnCredentials, networkMap.Network.CurrentSerial(), networkMap.Network)
plainResp := toSyncResponse(s.config, peer, turnCredentials, networkMap)
encryptedResp, err := encryption.EncryptMessage(peerKey, s.wgKey, plainResp)
if err != nil {

View File

@@ -136,6 +136,9 @@ components:
ui_version:
description: Peer's desktop UI version
type: string
dns_label:
description: Peer's DNS label is the parsed peer name for domain resolution. It is used to form an FQDN by appending the account's domain to the peer label. e.g. peer-dns-label.netbird.cloud
type: string
required:
- ip
- connected
@@ -145,6 +148,7 @@ components:
- groups
- ssh_enabled
- hostname
- dns_label
SetupKey:
type: object
properties:
@@ -480,7 +484,7 @@ components:
path:
description: Nameserver group field to update in form /<field>
type: string
enum: [ "name","description","enabled","groups","nameservers" ]
enum: [ "name", "description", "enabled", "groups", "nameservers", "primary", "domains" ]
required:
- path

View File

@@ -39,10 +39,12 @@ const (
// Defines values for NameserverGroupPatchOperationPath.
const (
NameserverGroupPatchOperationPathDescription NameserverGroupPatchOperationPath = "description"
NameserverGroupPatchOperationPathDomains NameserverGroupPatchOperationPath = "domains"
NameserverGroupPatchOperationPathEnabled NameserverGroupPatchOperationPath = "enabled"
NameserverGroupPatchOperationPathGroups NameserverGroupPatchOperationPath = "groups"
NameserverGroupPatchOperationPathName NameserverGroupPatchOperationPath = "name"
NameserverGroupPatchOperationPathNameservers NameserverGroupPatchOperationPath = "nameservers"
NameserverGroupPatchOperationPathPrimary NameserverGroupPatchOperationPath = "primary"
)
// Defines values for PatchMinimumOp.
@@ -240,6 +242,9 @@ type Peer struct {
// Connected Peer to Management connection status
Connected bool `json:"connected"`
// DnsLabel Peer's DNS label is the parsed peer name for domain resolution. It is used to form an FQDN by appending the account's domain to the peer label. e.g. peer-dns-label.netbird.cloud
DnsLabel string `json:"dns_label"`
// Groups Groups that the peer belongs to
Groups []GroupMinimum `json:"groups"`

View File

@@ -113,6 +113,8 @@ func (h *Nameservers) UpdateNameserverGroupHandler(w http.ResponseWriter, r *htt
ID: nsGroupID,
Name: req.Name,
Description: req.Description,
Primary: req.Primary,
Domains: req.Domains,
NameServers: nsList,
Groups: req.Groups,
Enabled: req.Enabled,
@@ -168,6 +170,16 @@ func (h *Nameservers) PatchNameserverGroupHandler(w http.ResponseWriter, r *http
Type: server.UpdateNameServerGroupDescription,
Values: patch.Value,
})
case api.NameserverGroupPatchOperationPathPrimary:
operations = append(operations, server.NameServerGroupUpdateOperation{
Type: server.UpdateNameServerGroupPrimary,
Values: patch.Value,
})
case api.NameserverGroupPatchOperationPathDomains:
operations = append(operations, server.NameServerGroupUpdateOperation{
Type: server.UpdateNameServerGroupDomains,
Values: patch.Value,
})
case api.NameserverGroupPatchOperationPathNameservers:
operations = append(operations, server.NameServerGroupUpdateOperation{
Type: server.UpdateNameServerGroupNameServers,
@@ -279,6 +291,8 @@ func toNameserverGroupResponse(serverNSGroup *nbdns.NameServerGroup) *api.Namese
Id: serverNSGroup.ID,
Name: serverNSGroup.Name,
Description: serverNSGroup.Description,
Primary: serverNSGroup.Primary,
Domains: serverNSGroup.Domains,
Groups: serverNSGroup.Groups,
Nameservers: nsList,
Enabled: serverNSGroup.Enabled,

View File

@@ -172,6 +172,7 @@ func TestNameserversHandlers(t *testing.T) {
},
Groups: []string{"group"},
Enabled: true,
Primary: true,
},
},
{
@@ -204,6 +205,7 @@ func TestNameserversHandlers(t *testing.T) {
},
Groups: []string{"group"},
Enabled: true,
Primary: true,
},
},
{
@@ -238,6 +240,7 @@ func TestNameserversHandlers(t *testing.T) {
Nameservers: toNameserverGroupResponse(baseExistingNSGroup).Nameservers,
Groups: baseExistingNSGroup.Groups,
Enabled: baseExistingNSGroup.Enabled,
Primary: baseExistingNSGroup.Primary,
},
},
{

View File

@@ -152,5 +152,6 @@ func toPeerResponse(peer *server.Peer, account *server.Account) *api.Peer {
Hostname: peer.Meta.Hostname,
UserId: &peer.UserID,
UiVersion: &peer.Meta.UIVersion,
DnsLabel: peer.DNSLabel,
}
}

View File

@@ -403,7 +403,7 @@ func startManagement(t *testing.T, port int, config *Config) (*grpc.Server, erro
return nil, err
}
peersUpdateManager := NewPeersUpdateManager()
accountManager, err := BuildManager(store, peersUpdateManager, nil, "")
accountManager, err := BuildManager(store, peersUpdateManager, nil, "", "")
if err != nil {
return nil, err
}

View File

@@ -493,7 +493,7 @@ func startServer(config *server.Config) (*grpc.Server, net.Listener) {
log.Fatalf("failed creating a store: %s: %v", config.Datadir, err)
}
peersUpdateManager := server.NewPeersUpdateManager()
accountManager, err := server.BuildManager(store, peersUpdateManager, nil, "")
accountManager, err := server.BuildManager(store, peersUpdateManager, nil, "", "")
if err != nil {
log.Fatalf("failed creating a manager: %v", err)
}

View File

@@ -4,6 +4,7 @@ import (
"github.com/miekg/dns"
nbdns "github.com/netbirdio/netbird/dns"
"github.com/rs/xid"
log "github.com/sirupsen/logrus"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"strconv"
@@ -113,6 +114,12 @@ func (am *DefaultAccountManager) CreateNameServerGroup(accountID string, name, d
return nil, err
}
err = am.updateAccountPeers(account)
if err != nil {
log.Error(err)
return newNSGroup.Copy(), status.Errorf(codes.Unavailable, "failed to update peers after create nameserver %s", name)
}
return newNSGroup.Copy(), nil
}
@@ -143,6 +150,12 @@ func (am *DefaultAccountManager) SaveNameServerGroup(accountID string, nsGroupTo
return err
}
err = am.updateAccountPeers(account)
if err != nil {
log.Error(err)
return status.Errorf(codes.Unavailable, "failed to update peers after update nameserver %s", nsGroupToSave.Name)
}
return nil
}
@@ -239,6 +252,12 @@ func (am *DefaultAccountManager) UpdateNameServerGroup(accountID, nsGroupID stri
return nil, err
}
err = am.updateAccountPeers(account)
if err != nil {
log.Error(err)
return newNSGroup.Copy(), status.Errorf(codes.Unavailable, "failed to update peers after update nameserver %s", newNSGroup.Name)
}
return newNSGroup.Copy(), nil
}
@@ -260,6 +279,12 @@ func (am *DefaultAccountManager) DeleteNameServerGroup(accountID, nsGroupID stri
return err
}
err = am.updateAccountPeers(account)
if err != nil {
log.Error(err)
return status.Errorf(codes.Unavailable, "failed to update peers after deleting nameserver %s", nsGroupID)
}
return nil
}

View File

@@ -471,7 +471,7 @@ func TestSaveNameServerGroup(t *testing.T) {
expectedNSGroup *nbdns.NameServerGroup
}{
{
name: "Should Update Name Server Group",
name: "Should Config Name Server Group",
existingNSGroup: existingNSGroup,
newName: &validName,
newGroups: validGroups,
@@ -492,77 +492,77 @@ func TestSaveNameServerGroup(t *testing.T) {
},
},
{
name: "Should Not Update If Name Is Small",
name: "Should Not Config If Name Is Small",
existingNSGroup: existingNSGroup,
newName: &invalidNameSmall,
errFunc: require.Error,
shouldCreate: false,
},
{
name: "Should Not Update If Name Is Large",
name: "Should Not Config If Name Is Large",
existingNSGroup: existingNSGroup,
newName: &invalidNameLarge,
errFunc: require.Error,
shouldCreate: false,
},
{
name: "Should Not Update If Name Exists",
name: "Should Not Config If Name Exists",
existingNSGroup: existingNSGroup,
newName: &invalidNameExisting,
errFunc: require.Error,
shouldCreate: false,
},
{
name: "Should Not Update If ID Don't Exist",
name: "Should Not Config If ID Don't Exist",
existingNSGroup: existingNSGroup,
newID: &invalidID,
errFunc: require.Error,
shouldCreate: false,
},
{
name: "Should Not Update If Nameserver List Is Small",
name: "Should Not Config If Nameserver List Is Small",
existingNSGroup: existingNSGroup,
newNSList: []nbdns.NameServer{},
errFunc: require.Error,
shouldCreate: false,
},
{
name: "Should Not Update If Nameserver List Is Large",
name: "Should Not Config If Nameserver List Is Large",
existingNSGroup: existingNSGroup,
newNSList: invalidNameServerListLarge,
errFunc: require.Error,
shouldCreate: false,
},
{
name: "Should Not Update If Groups List Is Empty",
name: "Should Not Config If Groups List Is Empty",
existingNSGroup: existingNSGroup,
newGroups: []string{},
errFunc: require.Error,
shouldCreate: false,
},
{
name: "Should Not Update If Groups List Has Empty ID",
name: "Should Not Config If Groups List Has Empty ID",
existingNSGroup: existingNSGroup,
newGroups: []string{""},
errFunc: require.Error,
shouldCreate: false,
},
{
name: "Should Not Update If Groups List Has Non Existing Group ID",
name: "Should Not Config If Groups List Has Non Existing Group ID",
existingNSGroup: existingNSGroup,
newGroups: invalidGroups,
errFunc: require.Error,
shouldCreate: false,
},
{
name: "Should Not Update If Domains List Is Empty",
name: "Should Not Config If Domains List Is Empty",
existingNSGroup: existingNSGroup,
newPrimary: &disabledPrimary,
errFunc: require.Error,
shouldCreate: false,
},
{
name: "Should Not Update If Primary And Domains",
name: "Should Not Config If Primary And Domains",
existingNSGroup: existingNSGroup,
newPrimary: &existingNSGroup.Primary,
newDomains: validDomains,
@@ -570,7 +570,7 @@ func TestSaveNameServerGroup(t *testing.T) {
shouldCreate: false,
},
{
name: "Should Not Update If Domains List Is Invalid",
name: "Should Not Config If Domains List Is Invalid",
existingNSGroup: existingNSGroup,
newPrimary: &disabledPrimary,
newDomains: invalidDomains,
@@ -685,7 +685,7 @@ func TestUpdateNameServerGroup(t *testing.T) {
expectedNSGroup *nbdns.NameServerGroup
}{
{
name: "Should Update Single Property",
name: "Should Config Single Property",
existingNSGroup: existingNSGroup,
nsGroupID: existingNSGroup.ID,
operations: []NameServerGroupUpdateOperation{
@@ -718,7 +718,7 @@ func TestUpdateNameServerGroup(t *testing.T) {
},
},
{
name: "Should Update Multiple Properties",
name: "Should Config Multiple Properties",
existingNSGroup: existingNSGroup,
nsGroupID: existingNSGroup.ID,
operations: []NameServerGroupUpdateOperation{
@@ -776,20 +776,20 @@ func TestUpdateNameServerGroup(t *testing.T) {
},
},
{
name: "Should Not Update On Invalid ID",
name: "Should Not Config On Invalid ID",
existingNSGroup: existingNSGroup,
nsGroupID: "nonExistingNSGroup",
errFunc: require.Error,
},
{
name: "Should Not Update On Empty Operations",
name: "Should Not Config On Empty Operations",
existingNSGroup: existingNSGroup,
nsGroupID: existingNSGroup.ID,
operations: []NameServerGroupUpdateOperation{},
errFunc: require.Error,
},
{
name: "Should Not Update On Empty Values",
name: "Should Not Config On Empty Values",
existingNSGroup: existingNSGroup,
nsGroupID: existingNSGroup.ID,
operations: []NameServerGroupUpdateOperation{
@@ -800,7 +800,7 @@ func TestUpdateNameServerGroup(t *testing.T) {
errFunc: require.Error,
},
{
name: "Should Not Update On Empty String",
name: "Should Not Config On Empty String",
existingNSGroup: existingNSGroup,
nsGroupID: existingNSGroup.ID,
operations: []NameServerGroupUpdateOperation{
@@ -812,7 +812,7 @@ func TestUpdateNameServerGroup(t *testing.T) {
errFunc: require.Error,
},
{
name: "Should Not Update On Invalid Name Large String",
name: "Should Not Config On Invalid Name Large String",
existingNSGroup: existingNSGroup,
nsGroupID: existingNSGroup.ID,
operations: []NameServerGroupUpdateOperation{
@@ -824,7 +824,7 @@ func TestUpdateNameServerGroup(t *testing.T) {
errFunc: require.Error,
},
{
name: "Should Not Update On Invalid On Existing Name",
name: "Should Not Config On Invalid On Existing Name",
existingNSGroup: existingNSGroup,
nsGroupID: existingNSGroup.ID,
operations: []NameServerGroupUpdateOperation{
@@ -836,7 +836,7 @@ func TestUpdateNameServerGroup(t *testing.T) {
errFunc: require.Error,
},
{
name: "Should Not Update On Invalid On Multiple Name Values",
name: "Should Not Config On Invalid On Multiple Name Values",
existingNSGroup: existingNSGroup,
nsGroupID: existingNSGroup.ID,
operations: []NameServerGroupUpdateOperation{
@@ -848,7 +848,7 @@ func TestUpdateNameServerGroup(t *testing.T) {
errFunc: require.Error,
},
{
name: "Should Not Update On Invalid Boolean",
name: "Should Not Config On Invalid Boolean",
existingNSGroup: existingNSGroup,
nsGroupID: existingNSGroup.ID,
operations: []NameServerGroupUpdateOperation{
@@ -860,7 +860,7 @@ func TestUpdateNameServerGroup(t *testing.T) {
errFunc: require.Error,
},
{
name: "Should Not Update On Invalid Nameservers Wrong Schema",
name: "Should Not Config On Invalid Nameservers Wrong Schema",
existingNSGroup: existingNSGroup,
nsGroupID: existingNSGroup.ID,
operations: []NameServerGroupUpdateOperation{
@@ -872,7 +872,7 @@ func TestUpdateNameServerGroup(t *testing.T) {
errFunc: require.Error,
},
{
name: "Should Not Update On Invalid Nameservers Wrong IP",
name: "Should Not Config On Invalid Nameservers Wrong IP",
existingNSGroup: existingNSGroup,
nsGroupID: existingNSGroup.ID,
operations: []NameServerGroupUpdateOperation{
@@ -884,7 +884,7 @@ func TestUpdateNameServerGroup(t *testing.T) {
errFunc: require.Error,
},
{
name: "Should Not Update On Large Number Of Nameservers",
name: "Should Not Config On Large Number Of Nameservers",
existingNSGroup: existingNSGroup,
nsGroupID: existingNSGroup.ID,
operations: []NameServerGroupUpdateOperation{
@@ -896,7 +896,7 @@ func TestUpdateNameServerGroup(t *testing.T) {
errFunc: require.Error,
},
{
name: "Should Not Update On Invalid GroupID",
name: "Should Not Config On Invalid GroupID",
existingNSGroup: existingNSGroup,
nsGroupID: existingNSGroup.ID,
operations: []NameServerGroupUpdateOperation{
@@ -908,7 +908,7 @@ func TestUpdateNameServerGroup(t *testing.T) {
errFunc: require.Error,
},
{
name: "Should Not Update On Invalid Domains",
name: "Should Not Config On Invalid Domains",
existingNSGroup: existingNSGroup,
nsGroupID: existingNSGroup.ID,
operations: []NameServerGroupUpdateOperation{
@@ -920,7 +920,7 @@ func TestUpdateNameServerGroup(t *testing.T) {
errFunc: require.Error,
},
{
name: "Should Not Update On Invalid Primary Status",
name: "Should Not Config On Invalid Primary Status",
existingNSGroup: existingNSGroup,
nsGroupID: existingNSGroup.ID,
operations: []NameServerGroupUpdateOperation{
@@ -1056,7 +1056,7 @@ func createNSManager(t *testing.T) (*DefaultAccountManager, error) {
if err != nil {
return nil, err
}
return BuildManager(store, NewPeersUpdateManager(), nil, "")
return BuildManager(store, NewPeersUpdateManager(), nil, "", "")
}
func createNSStore(t *testing.T) (Store, error) {

View File

@@ -2,6 +2,7 @@ package server
import (
"github.com/c-robinson/iplib"
nbdns "github.com/netbirdio/netbird/dns"
"github.com/netbirdio/netbird/route"
"github.com/rs/xid"
"google.golang.org/grpc/codes"
@@ -23,9 +24,10 @@ const (
)
type NetworkMap struct {
Peers []*Peer
Network *Network
Routes []*route.Route
Peers []*Peer
Network *Network
Routes []*route.Route
DNSConfig nbdns.Config
}
type Network struct {

View File

@@ -1,6 +1,7 @@
package server
import (
nbdns "github.com/netbirdio/netbird/dns"
"net"
"strings"
"time"
@@ -43,7 +44,11 @@ type Peer struct {
// Meta is a Peer system meta data
Meta PeerSystemMeta
// Name is peer's name (machine name)
Name string
Name string
// DNSLabel is the parsed peer name for domain resolution. It is used to form an FQDN by appending the account's
// domain to the peer label. e.g. peer-dns-label.netbird.cloud
DNSLabel string
// Status peer's management connection status
Status *PeerStatus
// The user ID that registered the peer
UserID string
@@ -65,6 +70,7 @@ func (p *Peer) Copy() *Peer {
UserID: p.UserID,
SSHKey: p.SSHKey,
SSHEnabled: p.SSHEnabled,
DNSLabel: p.DNSLabel,
}
}
@@ -156,6 +162,15 @@ func (am *DefaultAccountManager) UpdatePeer(accountID string, update *Peer) (*Pe
}
peer.SSHEnabled = update.SSHEnabled
existingLabels := account.getPeerDNSLabels()
newLabel, err := getPeerHostLabel(peer.Name, existingLabels)
if err != nil {
return nil, err
}
peer.DNSLabel = newLabel
account.UpdatePeer(peer)
err = am.Store.SaveAccount(account)
@@ -252,10 +267,26 @@ func (am *DefaultAccountManager) GetNetworkMap(peerPubKey string) (*NetworkMap,
aclPeers := am.getPeersByACL(account, peerPubKey)
routesUpdate := account.GetPeersRoutes(append(aclPeers, account.Peers[peerPubKey]))
// todo extract this with the store v2
// this should become part of the method parameters
// to prevent slow performance when called in a parent loop
var zones []nbdns.CustomZone
peersCustomZone := getPeersCustomZone(account, am.dnsDomain)
if peersCustomZone.Domain != "" {
zones = append(zones, peersCustomZone)
}
dnsUpdate := nbdns.Config{
ServiceEnable: true,
CustomZones: zones,
NameServerGroups: getPeerNSGroups(account, peerPubKey),
}
return &NetworkMap{
Peers: aclPeers,
Network: account.Network.Copy(),
Routes: routesUpdate,
Peers: aclPeers,
Network: account.Network.Copy(),
Routes: routesUpdate,
DNSConfig: dnsUpdate,
}, err
}
@@ -337,10 +368,21 @@ func (am *DefaultAccountManager) AddPeer(setupKey string, userID string, peer *P
}
var takenIps []net.IP
for _, peer := range account.Peers {
takenIps = append(takenIps, peer.IP)
existingLabels := make(lookupMap)
for _, existingPeer := range account.Peers {
takenIps = append(takenIps, existingPeer.IP)
if existingPeer.DNSLabel != "" {
existingLabels[existingPeer.DNSLabel] = struct{}{}
}
}
newLabel, err := getPeerHostLabel(peer.Name, existingLabels)
if err != nil {
return nil, err
}
peer.DNSLabel = newLabel
network := account.Network
nextIp, err := AllocatePeerIP(network.Net, takenIps)
if err != nil {
@@ -353,6 +395,7 @@ func (am *DefaultAccountManager) AddPeer(setupKey string, userID string, peer *P
IP: nextIp,
Meta: peer.Meta,
Name: peer.Name,
DNSLabel: newLabel,
UserID: userID,
Status: &PeerStatus{Connected: false, LastSeen: time.Now()},
SSHEnabled: false,
@@ -517,11 +560,21 @@ func (am *DefaultAccountManager) updateAccountPeers(account *Account) error {
// notify other peers of the change
peers := account.GetPeers()
network := account.Network.Copy()
var zones []nbdns.CustomZone
peersCustomZone := getPeersCustomZone(account, am.dnsDomain)
if peersCustomZone.Domain != "" {
zones = append(zones, peersCustomZone)
}
for _, peer := range peers {
aclPeers := am.getPeersByACL(account, peer.Key)
peersUpdate := toRemotePeerConfig(aclPeers)
routesUpdate := toProtocolRoutes(account.GetPeersRoutes(append(aclPeers, peer)))
dnsUpdate := toProtocolDNSConfig(nbdns.Config{
ServiceEnable: true,
CustomZones: zones,
NameServerGroups: getPeerNSGroups(account, peer.Key),
})
err := am.peersUpdateManager.SendUpdate(peer.Key,
&UpdateMessage{
Update: &proto.SyncResponse{
@@ -535,6 +588,7 @@ func (am *DefaultAccountManager) updateAccountPeers(account *Account) error {
RemotePeersIsEmpty: len(peersUpdate) == 0,
PeerConfig: toPeerConfig(peer, network),
Routes: routesUpdate,
DNSConfig: dnsUpdate,
},
},
})

View File

@@ -783,7 +783,7 @@ func createRouterManager(t *testing.T) (*DefaultAccountManager, error) {
if err != nil {
return nil, err
}
return BuildManager(store, NewPeersUpdateManager(), nil, "")
return BuildManager(store, NewPeersUpdateManager(), nil, "", "")
}
func createRouterStore(t *testing.T) (Store, error) {