mirror of
https://github.com/netbirdio/netbird.git
synced 2026-04-18 08:16:39 +00:00
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:
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
152
management/server/dns.go
Normal 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 ""
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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"`
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
},
|
||||
},
|
||||
{
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user