Use Peer.ID instead of Peer.Key as peer identifier (#664)

Replace Peer.Key as internal identifier with a randomly generated Peer.ID 
in the Management service.
Every group now references peers by ID instead of a public key.
Every route now references peers by ID instead of a public key.
FileStore does store.json file migration on startup by generating Peer.ID and replacing
all Peer.Key identifier references .
This commit is contained in:
Misha Bragin 2023-02-03 10:33:28 +01:00 committed by GitHub
parent 9e408b5bbc
commit 9adadfade4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 485 additions and 359 deletions

View File

@ -50,24 +50,24 @@ type AccountManager interface {
GetAccountFromToken(claims jwtclaims.AuthorizationClaims) (*Account, *User, error) GetAccountFromToken(claims jwtclaims.AuthorizationClaims) (*Account, *User, error)
IsUserAdmin(claims jwtclaims.AuthorizationClaims) (bool, error) IsUserAdmin(claims jwtclaims.AuthorizationClaims) (bool, error)
AccountExists(accountId string) (*bool, error) AccountExists(accountId string) (*bool, error)
GetPeer(peerKey string) (*Peer, error) GetPeerByKey(peerKey string) (*Peer, error)
GetPeers(accountID, userID string) ([]*Peer, error) GetPeers(accountID, userID string) ([]*Peer, error)
MarkPeerConnected(peerKey string, connected bool) error MarkPeerConnected(peerKey string, connected bool) error
DeletePeer(accountID, peerKey, userID string) (*Peer, error) DeletePeer(accountID, peerID, userID string) (*Peer, error)
GetPeerByIP(accountId string, peerIP string) (*Peer, error) GetPeerByIP(accountId string, peerIP string) (*Peer, error)
UpdatePeer(accountID, userID string, peer *Peer) (*Peer, error) UpdatePeer(accountID, userID string, peer *Peer) (*Peer, error)
GetNetworkMap(peerKey string) (*NetworkMap, error) GetNetworkMap(peerID string) (*NetworkMap, error)
GetPeerNetwork(peerKey string) (*Network, error) GetPeerNetwork(peerID string) (*Network, error)
AddPeer(setupKey, userID string, peer *Peer) (*Peer, error) AddPeer(setupKey, userID string, peer *Peer) (*Peer, error)
UpdatePeerMeta(peerKey string, meta PeerSystemMeta) error UpdatePeerMeta(peerID string, meta PeerSystemMeta) error
UpdatePeerSSHKey(peerKey string, sshKey string) error UpdatePeerSSHKey(peerID string, sshKey string) error
GetUsersFromAccount(accountID, userID string) ([]*UserInfo, error) GetUsersFromAccount(accountID, userID string) ([]*UserInfo, error)
GetGroup(accountId, groupID string) (*Group, error) GetGroup(accountId, groupID string) (*Group, error)
SaveGroup(accountID, userID string, group *Group) error SaveGroup(accountID, userID string, group *Group) error
UpdateGroup(accountID string, groupID string, operations []GroupUpdateOperation) (*Group, error) UpdateGroup(accountID string, groupID string, operations []GroupUpdateOperation) (*Group, error)
DeleteGroup(accountId, groupID string) error DeleteGroup(accountId, groupID string) error
ListGroups(accountId string) ([]*Group, error) ListGroups(accountId string) ([]*Group, error)
GroupAddPeer(accountId, groupID, peerKey string) error GroupAddPeer(accountId, groupID, peerID string) error
GroupDeletePeer(accountId, groupID, peerKey string) error GroupDeletePeer(accountId, groupID, peerKey string) error
GroupListPeers(accountId, groupID string) ([]*Peer, error) GroupListPeers(accountId, groupID string) ([]*Peer, error)
GetRule(accountID, ruleID, userID string) (*Rule, error) GetRule(accountID, ruleID, userID string) (*Rule, error)
@ -76,7 +76,7 @@ type AccountManager interface {
DeleteRule(accountID, ruleID, userID string) error DeleteRule(accountID, ruleID, userID string) error
ListRules(accountID, userID string) ([]*Rule, error) ListRules(accountID, userID string) ([]*Rule, error)
GetRoute(accountID, routeID, userID string) (*route.Route, error) GetRoute(accountID, routeID, userID string) (*route.Route, error)
CreateRoute(accountID string, prefix, peerIP, description, netID string, masquerade bool, metric int, groups []string, enabled bool, userID string) (*route.Route, error) CreateRoute(accountID string, prefix, peerID, description, netID string, masquerade bool, metric int, groups []string, enabled bool, userID string) (*route.Route, error)
SaveRoute(accountID, userID string, route *route.Route) error SaveRoute(accountID, userID string, route *route.Route) error
UpdateRoute(accountID, routeID string, operations []RouteUpdateOperation) (*route.Route, error) UpdateRoute(accountID, routeID string, operations []RouteUpdateOperation) (*route.Route, error)
DeleteRoute(accountID, routeID, userID string) error DeleteRoute(accountID, routeID, userID string) error
@ -144,7 +144,8 @@ type UserInfo struct {
} }
// getRoutesToSync returns the enabled routes for the peer ID and the routes // getRoutesToSync returns the enabled routes for the peer ID and the routes
// from the ACL peers that have distribution groups associated with the peer ID // from the ACL peers that have distribution groups associated with the peer ID.
// Please mind, that the returned route.Route objects will contain Peer.Key instead of Peer.ID.
func (a *Account) getRoutesToSync(peerID string, aclPeers []*Peer) []*route.Route { func (a *Account) getRoutesToSync(peerID string, aclPeers []*Peer) []*route.Route {
routes, peerDisabledRoutes := a.getEnabledAndDisabledRoutesByPeer(peerID) routes, peerDisabledRoutes := a.getEnabledAndDisabledRoutesByPeer(peerID)
peerRoutesMembership := make(lookupMap) peerRoutesMembership := make(lookupMap)
@ -154,7 +155,7 @@ func (a *Account) getRoutesToSync(peerID string, aclPeers []*Peer) []*route.Rout
groupListMap := a.getPeerGroups(peerID) groupListMap := a.getPeerGroups(peerID)
for _, peer := range aclPeers { for _, peer := range aclPeers {
activeRoutes, _ := a.getEnabledAndDisabledRoutesByPeer(peer.Key) activeRoutes, _ := a.getEnabledAndDisabledRoutesByPeer(peer.ID)
groupFilteredRoutes := a.filterRoutesByGroups(activeRoutes, groupListMap) groupFilteredRoutes := a.filterRoutesByGroups(activeRoutes, groupListMap)
filteredRoutes := a.filterRoutesFromPeersOfSameHAGroup(groupFilteredRoutes, peerRoutesMembership) filteredRoutes := a.filterRoutesFromPeersOfSameHAGroup(groupFilteredRoutes, peerRoutesMembership)
routes = append(routes, filteredRoutes...) routes = append(routes, filteredRoutes...)
@ -190,18 +191,27 @@ func (a *Account) filterRoutesByGroups(routes []*route.Route, groupListMap looku
return filteredRoutes return filteredRoutes
} }
// getEnabledAndDisabledRoutesByPeer returns the enabled and disabled lists of routes that belong to a peer // getEnabledAndDisabledRoutesByPeer returns the enabled and disabled lists of routes that belong to a peer.
func (a *Account) getEnabledAndDisabledRoutesByPeer(peerPubKey string) ([]*route.Route, []*route.Route) { // Please mind, that the returned route.Route objects will contain Peer.Key instead of Peer.ID.
//TODO Peer.ID migration: we will need to replace search by Peer.ID here func (a *Account) getEnabledAndDisabledRoutesByPeer(peerID string) ([]*route.Route, []*route.Route) {
var enabledRoutes []*route.Route var enabledRoutes []*route.Route
var disabledRoutes []*route.Route var disabledRoutes []*route.Route
for _, r := range a.Routes { for _, r := range a.Routes {
if r.Peer == peerPubKey { if r.Peer == peerID {
if r.Enabled { // We need to set Peer.Key instead of Peer.ID because this object will be sent to agents as part of a network map.
enabledRoutes = append(enabledRoutes, r) // Ideally we should have a separate field for that, but fine for now.
peer := a.GetPeer(peerID)
if peer == nil {
log.Errorf("route %s has peer %s that doesn't exist under account %s", r.ID, peerID, a.Id)
continue continue
} }
disabledRoutes = append(disabledRoutes, r) raut := r.Copy()
raut.Peer = peer.Key
if r.Enabled {
enabledRoutes = append(enabledRoutes, raut)
continue
}
disabledRoutes = append(disabledRoutes, raut)
} }
} }
return enabledRoutes, disabledRoutes return enabledRoutes, disabledRoutes
@ -232,7 +242,7 @@ func (a *Account) GetPeerByIP(peerIP string) *Peer {
} }
// GetPeerRules returns a list of source or destination rules of a given peer. // GetPeerRules returns a list of source or destination rules of a given peer.
func (a *Account) GetPeerRules(peerPubKey string) (srcRules []*Rule, dstRules []*Rule) { func (a *Account) GetPeerRules(peerID string) (srcRules []*Rule, dstRules []*Rule) {
// Rules are group based so there is no direct access to peers. // Rules are group based so there is no direct access to peers.
// First, find all groups that the given peer belongs to // First, find all groups that the given peer belongs to
@ -240,7 +250,7 @@ func (a *Account) GetPeerRules(peerPubKey string) (srcRules []*Rule, dstRules []
for s, group := range a.Groups { for s, group := range a.Groups {
for _, peer := range group.Peers { for _, peer := range group.Peers {
if peerPubKey == peer { if peerID == peer {
peerGroups[s] = struct{}{} peerGroups[s] = struct{}{}
break break
} }
@ -284,18 +294,15 @@ func (a *Account) GetPeers() []*Peer {
// UpdatePeer saves new or replaces existing peer // UpdatePeer saves new or replaces existing peer
func (a *Account) UpdatePeer(update *Peer) { func (a *Account) UpdatePeer(update *Peer) {
//TODO Peer.ID migration: we will need to replace search by Peer.ID here a.Peers[update.ID] = update
a.Peers[update.Key] = update
} }
// DeletePeer deletes peer from the account cleaning up all the references // DeletePeer deletes peer from the account cleaning up all the references
func (a *Account) DeletePeer(peerPubKey string) { func (a *Account) DeletePeer(peerID string) {
// TODO Peer.ID migration: we will need to replace search by Peer.ID here
// delete peer from groups // delete peer from groups
for _, g := range a.Groups { for _, g := range a.Groups {
for i, pk := range g.Peers { for i, pk := range g.Peers {
if pk == peerPubKey { if pk == peerID {
g.Peers = append(g.Peers[:i], g.Peers[i+1:]...) g.Peers = append(g.Peers[:i], g.Peers[i+1:]...)
break break
} }
@ -303,13 +310,13 @@ func (a *Account) DeletePeer(peerPubKey string) {
} }
for _, r := range a.Routes { for _, r := range a.Routes {
if r.Peer == peerPubKey { if r.Peer == peerID {
r.Enabled = false r.Enabled = false
r.Peer = "" r.Peer = ""
} }
} }
delete(a.Peers, peerPubKey) delete(a.Peers, peerID)
a.Network.IncSerial() a.Network.IncSerial()
} }
@ -476,6 +483,11 @@ func (a *Account) GetGroupAll() (*Group, error) {
return nil, fmt.Errorf("no group ALL found") return nil, fmt.Errorf("no group ALL found")
} }
// GetPeer looks up a Peer by ID
func (a *Account) GetPeer(peerID string) *Peer {
return a.Peers[peerID]
}
// BuildManager creates a new DefaultAccountManager with a provided Store // BuildManager creates a new DefaultAccountManager with a provided Store
func BuildManager(store Store, peersUpdateManager *PeersUpdateManager, idpManager idp.Manager, func BuildManager(store Store, peersUpdateManager *PeersUpdateManager, idpManager idp.Manager,
singleAccountModeDomain string, dnsDomain string, eventStore activity.Store) (*DefaultAccountManager, error) { singleAccountModeDomain string, dnsDomain string, eventStore activity.Store) (*DefaultAccountManager, error) {
@ -1015,7 +1027,7 @@ func addAllGroup(account *Account) {
Name: "All", Name: "All",
} }
for _, peer := range account.Peers { for _, peer := range account.Peers {
allGroup.Peers = append(allGroup.Peers, peer.Key) allGroup.Peers = append(allGroup.Peers, peer.ID)
} }
account.Groups = map[string]*Group{allGroup.ID: allGroup} account.Groups = map[string]*Group{allGroup.ID: allGroup}

View File

@ -493,8 +493,8 @@ func TestAccountManager_GetAccount(t *testing.T) {
} }
for _, peer := range account.Peers { for _, peer := range account.Peers {
if _, ok := getAccount.Peers[peer.Key]; !ok { if _, ok := getAccount.Peers[peer.ID]; !ok {
t.Errorf("expected account to have peer %s, not found", peer.Key) t.Errorf("expected account to have peer %s, not found", peer.ID)
} }
} }
@ -580,7 +580,7 @@ func TestAccountManager_AddPeer(t *testing.T) {
assert.Equal(t, peer.Name, ev.Meta["name"]) assert.Equal(t, peer.Name, ev.Meta["name"])
assert.Equal(t, peer.FQDN(account.Domain), ev.Meta["fqdn"]) assert.Equal(t, peer.FQDN(account.Domain), ev.Meta["fqdn"])
assert.Equal(t, setupKey.Id, ev.InitiatorID) assert.Equal(t, setupKey.Id, ev.InitiatorID)
assert.Equal(t, peer.IP.String(), ev.TargetID) assert.Equal(t, peer.ID, ev.TargetID)
assert.Equal(t, peer.IP.String(), fmt.Sprint(ev.Meta["ip"])) assert.Equal(t, peer.IP.String(), fmt.Sprint(ev.Meta["ip"]))
} }
@ -650,7 +650,7 @@ func TestAccountManager_AddPeerWithUserID(t *testing.T) {
assert.Equal(t, peer.Name, ev.Meta["name"]) assert.Equal(t, peer.Name, ev.Meta["name"])
assert.Equal(t, peer.FQDN(account.Domain), ev.Meta["fqdn"]) assert.Equal(t, peer.FQDN(account.Domain), ev.Meta["fqdn"])
assert.Equal(t, userID, ev.InitiatorID) assert.Equal(t, userID, ev.InitiatorID)
assert.Equal(t, peer.IP.String(), ev.TargetID) assert.Equal(t, peer.ID, ev.TargetID)
assert.Equal(t, peer.IP.String(), fmt.Sprint(ev.Meta["ip"])) assert.Equal(t, peer.IP.String(), fmt.Sprint(ev.Meta["ip"]))
} }
@ -717,13 +717,13 @@ func TestAccountManager_NetworkUpdates(t *testing.T) {
return return
} }
updMsg := manager.peersUpdateManager.CreateChannel(peer1.Key) updMsg := manager.peersUpdateManager.CreateChannel(peer1.ID)
defer manager.peersUpdateManager.CloseChannel(peer1.Key) defer manager.peersUpdateManager.CloseChannel(peer1.ID)
group := Group{ group := Group{
ID: "group-id", ID: "group-id",
Name: "GroupA", Name: "GroupA",
Peers: []string{peer1.Key, peer2.Key, peer3.Key}, Peers: []string{peer1.ID, peer2.ID, peer3.ID},
} }
rule := Rule{ rule := Rule{
@ -810,7 +810,7 @@ func TestAccountManager_NetworkUpdates(t *testing.T) {
} }
}() }()
if _, err := manager.DeletePeer(account.Id, peer3.Key, userID); err != nil { if _, err := manager.DeletePeer(account.Id, peer3.ID, userID); err != nil {
t.Errorf("delete peer: %v", err) t.Errorf("delete peer: %v", err)
return return
} }
@ -1001,13 +1001,13 @@ func TestAccountManager_UpdatePeerMeta(t *testing.T) {
OS: "new-OS", OS: "new-OS",
WtVersion: "new-WtVersion", WtVersion: "new-WtVersion",
} }
err = manager.UpdatePeerMeta(peer.Key, newMeta) err = manager.UpdatePeerMeta(peer.ID, newMeta)
if err != nil { if err != nil {
t.Error(err) t.Error(err)
return return
} }
p, err := manager.GetPeer(peer.Key) p, err := manager.GetPeerByKey(peer.Key)
if err != nil { if err != nil {
return return
} }

View File

@ -147,7 +147,17 @@ func TestGetNetworkMap_DNSConfigSync(t *testing.T) {
t.Error("failed to init testing account") t.Error("failed to init testing account")
} }
newAccountDNSConfig, err := am.GetNetworkMap(dnsPeer1Key) peer1, err := account.FindPeerByPubKey(dnsPeer1Key)
if err != nil {
t.Error("failed to init testing account")
}
peer2, err := account.FindPeerByPubKey(dnsPeer2Key)
if err != nil {
t.Error("failed to init testing account")
}
newAccountDNSConfig, err := am.GetNetworkMap(peer1.ID)
require.NoError(t, err) require.NoError(t, err)
require.Len(t, newAccountDNSConfig.DNSConfig.CustomZones, 1, "default DNS config should have one custom zone for peers") require.Len(t, newAccountDNSConfig.DNSConfig.CustomZones, 1, "default DNS config should have one custom zone for peers")
require.True(t, newAccountDNSConfig.DNSConfig.ServiceEnable, "default DNS config should have local DNS service enabled") require.True(t, newAccountDNSConfig.DNSConfig.ServiceEnable, "default DNS config should have local DNS service enabled")
@ -158,12 +168,12 @@ func TestGetNetworkMap_DNSConfigSync(t *testing.T) {
err = am.Store.SaveAccount(account) err = am.Store.SaveAccount(account)
require.NoError(t, err) require.NoError(t, err)
updatedAccountDNSConfig, err := am.GetNetworkMap(dnsPeer1Key) updatedAccountDNSConfig, err := am.GetNetworkMap(peer1.ID)
require.NoError(t, err) require.NoError(t, err)
require.Len(t, updatedAccountDNSConfig.DNSConfig.CustomZones, 0, "updated DNS config should have no custom zone when peer belongs to a disabled group") require.Len(t, updatedAccountDNSConfig.DNSConfig.CustomZones, 0, "updated DNS config should have no custom zone when peer belongs to a disabled group")
require.False(t, updatedAccountDNSConfig.DNSConfig.ServiceEnable, "updated DNS config should have local DNS service disabled when peer belongs to a disabled group") require.False(t, updatedAccountDNSConfig.DNSConfig.ServiceEnable, "updated DNS config should have local DNS service disabled when peer belongs to a disabled group")
peer2AccountDNSConfig, err := am.GetNetworkMap(dnsPeer2Key) peer2AccountDNSConfig, err := am.GetNetworkMap(peer2.ID)
require.NoError(t, err) require.NoError(t, err)
require.Len(t, peer2AccountDNSConfig.DNSConfig.CustomZones, 1, "DNS config should have one custom zone for peers not in the disabled group") require.Len(t, peer2AccountDNSConfig.DNSConfig.CustomZones, 1, "DNS config should have one custom zone for peers not in the disabled group")
require.True(t, peer2AccountDNSConfig.DNSConfig.ServiceEnable, "DNS config should have DNS service enabled for peers not in the disabled group") require.True(t, peer2AccountDNSConfig.DNSConfig.ServiceEnable, "DNS config should have DNS service enabled for peers not in the disabled group")
@ -234,9 +244,33 @@ func initTestDNSAccount(t *testing.T, am *DefaultAccountManager) (*Account, erro
return nil, err return nil, err
} }
_, err = am.AddPeer("", dnsAdminUserID, peer1)
if err != nil {
return nil, err
}
_, err = am.AddPeer("", dnsAdminUserID, peer2)
if err != nil {
return nil, err
}
account, err = am.Store.GetAccount(account.Id)
if err != nil {
return nil, err
}
peer1, err = account.FindPeerByPubKey(peer1.Key)
if err != nil {
return nil, err
}
_, err = account.FindPeerByPubKey(peer2.Key)
if err != nil {
return nil, err
}
newGroup1 := &Group{ newGroup1 := &Group{
ID: dnsGroup1ID, ID: dnsGroup1ID,
Peers: []string{peer1.Key}, Peers: []string{peer1.ID},
Name: dnsGroup1ID, Name: dnsGroup1ID,
} }
@ -253,14 +287,5 @@ func initTestDNSAccount(t *testing.T, am *DefaultAccountManager) (*Account, erro
return nil, err return nil, err
} }
_, err = am.AddPeer("", dnsAdminUserID, peer1) return am.Store.GetAccount(account.Id)
if err != nil {
return nil, err
}
_, err = am.AddPeer("", dnsAdminUserID, peer2)
if err != nil {
return nil, err
}
return account, nil
} }

View File

@ -2,6 +2,7 @@ package server
import ( import (
"github.com/netbirdio/netbird/management/server/status" "github.com/netbirdio/netbird/management/server/status"
"github.com/rs/xid"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
"os" "os"
"path/filepath" "path/filepath"
@ -20,6 +21,7 @@ type FileStore struct {
Accounts map[string]*Account Accounts map[string]*Account
SetupKeyID2AccountID map[string]string `json:"-"` SetupKeyID2AccountID map[string]string `json:"-"`
PeerKeyID2AccountID map[string]string `json:"-"` PeerKeyID2AccountID map[string]string `json:"-"`
PeerID2AccountID map[string]string `json:"-"`
UserID2AccountID map[string]string `json:"-"` UserID2AccountID map[string]string `json:"-"`
PrivateDomain2AccountID map[string]string `json:"-"` PrivateDomain2AccountID map[string]string `json:"-"`
InstallationID string InstallationID string
@ -53,6 +55,7 @@ func restore(file string) (*FileStore, error) {
PeerKeyID2AccountID: make(map[string]string), PeerKeyID2AccountID: make(map[string]string),
UserID2AccountID: make(map[string]string), UserID2AccountID: make(map[string]string),
PrivateDomain2AccountID: make(map[string]string), PrivateDomain2AccountID: make(map[string]string),
PeerID2AccountID: make(map[string]string),
storeFile: file, storeFile: file,
} }
@ -75,6 +78,7 @@ func restore(file string) (*FileStore, error) {
store.PeerKeyID2AccountID = make(map[string]string) store.PeerKeyID2AccountID = make(map[string]string)
store.UserID2AccountID = make(map[string]string) store.UserID2AccountID = make(map[string]string)
store.PrivateDomain2AccountID = make(map[string]string) store.PrivateDomain2AccountID = make(map[string]string)
store.PeerID2AccountID = make(map[string]string)
for accountID, account := range store.Accounts { for accountID, account := range store.Accounts {
for setupKeyId := range account.SetupKeys { for setupKeyId := range account.SetupKeys {
@ -83,6 +87,7 @@ func restore(file string) (*FileStore, error) {
for _, peer := range account.Peers { for _, peer := range account.Peers {
store.PeerKeyID2AccountID[peer.Key] = accountID store.PeerKeyID2AccountID[peer.Key] = accountID
store.PeerID2AccountID[peer.ID] = accountID
// reset all peers to status = Disconnected // reset all peers to status = Disconnected
if peer.Status != nil && peer.Status.Connected { if peer.Status != nil && peer.Status.Connected {
peer.Status.Connected = false peer.Status.Connected = false
@ -118,6 +123,47 @@ func restore(file string) (*FileStore, error) {
route.Groups = []string{allGroup.ID} route.Groups = []string{allGroup.ID}
} }
} }
// migration to Peer.ID from Peer.Key.
// Old peers that require migration have an empty Peer.ID in the store.json.
// Generate new ID with xid for these peers.
// Set the Peer.ID to the newly generated value.
// Replace all the mentions of Peer.Key as ID (groups and routes).
// Swap Peer.Key with Peer.ID in the Account.Peers map.
migrationPeers := make(map[string]*Peer) // key to Peer
for key, peer := range account.Peers {
if peer.ID != "" {
continue
}
id := xid.New().String()
peer.ID = id
migrationPeers[key] = peer
}
if len(migrationPeers) > 0 {
// swap Peer.Key with Peer.ID in the Account.Peers map.
for key, peer := range migrationPeers {
delete(account.Peers, key)
account.Peers[peer.ID] = peer
store.PeerID2AccountID[peer.ID] = accountID
}
// detect groups that have Peer.Key as a reference and replace it with ID.
for _, group := range account.Groups {
for i, peer := range group.Peers {
if p, ok := migrationPeers[peer]; ok {
group.Peers[i] = p.ID
}
}
}
// detect routes that have Peer.Key as a reference and replace it with ID.
for _, route := range account.Routes {
if peer, ok := migrationPeers[route.Peer]; ok {
route.Peer = peer.ID
}
}
}
} }
// we need this persist to apply changes we made to account.Peers (we set them to Disconnected) // we need this persist to apply changes we made to account.Peers (we set them to Disconnected)
@ -183,6 +229,7 @@ func (s *FileStore) SaveAccount(account *Account) error {
// enforce peer to account index and delete peer to route indexes for rebuild // enforce peer to account index and delete peer to route indexes for rebuild
for _, peer := range accountCopy.Peers { for _, peer := range accountCopy.Peers {
s.PeerKeyID2AccountID[peer.Key] = accountCopy.Id s.PeerKeyID2AccountID[peer.Key] = accountCopy.Id
s.PeerID2AccountID[peer.ID] = accountCopy.Id
} }
for _, user := range accountCopy.Users { for _, user := range accountCopy.Users {
@ -284,6 +331,24 @@ func (s *FileStore) GetAccountByUser(userID string) (*Account, error) {
return account.Copy(), nil return account.Copy(), nil
} }
// GetAccountByPeerID returns an account for a given peer ID
func (s *FileStore) GetAccountByPeerID(peerID string) (*Account, error) {
s.mux.Lock()
defer s.mux.Unlock()
accountID, accountIDFound := s.PeerID2AccountID[peerID]
if !accountIDFound {
return nil, status.Errorf(status.NotFound, "provided peer ID doesn't exists %s", peerID)
}
account, err := s.getAccount(accountID)
if err != nil {
return nil, err
}
return account.Copy(), nil
}
// GetAccountByPeerPubKey returns an account for a given peer WireGuard public key // GetAccountByPeerPubKey returns an account for a given peer WireGuard public key
func (s *FileStore) GetAccountByPeerPubKey(peerKey string) (*Account, error) { func (s *FileStore) GetAccountByPeerPubKey(peerKey string) (*Account, error) {
s.mux.Lock() s.mux.Lock()
@ -319,7 +384,7 @@ func (s *FileStore) SaveInstallationID(ID string) error {
// SavePeerStatus stores the PeerStatus in memory. It doesn't attempt to persist data to speed up things. // SavePeerStatus stores the PeerStatus in memory. It doesn't attempt to persist data to speed up things.
// PeerStatus will be saved eventually when some other changes occur. // PeerStatus will be saved eventually when some other changes occur.
func (s *FileStore) SavePeerStatus(accountID, peerKey string, peerStatus PeerStatus) error { func (s *FileStore) SavePeerStatus(accountID, peerID string, peerStatus PeerStatus) error {
s.mux.Lock() s.mux.Lock()
defer s.mux.Unlock() defer s.mux.Unlock()
@ -328,9 +393,9 @@ func (s *FileStore) SavePeerStatus(accountID, peerKey string, peerStatus PeerSta
return err return err
} }
peer := account.Peers[peerKey] peer := account.Peers[peerID]
if peer == nil { if peer == nil {
return status.Errorf(status.NotFound, "peer %s not found", peerKey) return status.Errorf(status.NotFound, "peer %s not found", peerID)
} }
peer.Status = &peerStatus peer.Status = &peerStatus

View File

@ -244,6 +244,7 @@ func TestFileStore_SavePeerStatus(t *testing.T) {
// save new status of existing peer // save new status of existing peer
account.Peers["testpeer"] = &Peer{ account.Peers["testpeer"] = &Peer{
Key: "peerkey", Key: "peerkey",
ID: "testpeer",
SetupKey: "peerkeysetupkey", SetupKey: "peerkeysetupkey",
IP: net.IP{127, 0, 0, 1}, IP: net.IP{127, 0, 0, 1},
Meta: PeerSystemMeta{}, Meta: PeerSystemMeta{},

View File

@ -88,6 +88,13 @@ func (am *DefaultAccountManager) SaveGroup(accountID, userID string, newGroup *G
return err return err
} }
err = am.updateAccountPeers(account)
if err != nil {
return err
}
// the following snippet tracks the activity and stores the group events in the event store.
// It has to happen after all the operations have been successfully performed.
addedPeers := make([]string, 0) addedPeers := make([]string, 0)
removedPeers := make([]string, 0) removedPeers := make([]string, 0)
if exists { if exists {
@ -104,7 +111,7 @@ func (am *DefaultAccountManager) SaveGroup(accountID, userID string, newGroup *G
log.Errorf("peer %s not found under account %s while saving group", p, accountID) log.Errorf("peer %s not found under account %s while saving group", p, accountID)
continue continue
} }
am.storeEvent(userID, peer.IP.String(), accountID, activity.GroupAddedToPeer, am.storeEvent(userID, peer.ID, accountID, activity.GroupAddedToPeer,
map[string]any{"group": newGroup.Name, "group_id": newGroup.ID, "peer_ip": peer.IP.String(), map[string]any{"group": newGroup.Name, "group_id": newGroup.ID, "peer_ip": peer.IP.String(),
"peer_fqdn": peer.FQDN(am.GetDNSDomain())}) "peer_fqdn": peer.FQDN(am.GetDNSDomain())})
} }
@ -115,12 +122,12 @@ func (am *DefaultAccountManager) SaveGroup(accountID, userID string, newGroup *G
log.Errorf("peer %s not found under account %s while saving group", p, accountID) log.Errorf("peer %s not found under account %s while saving group", p, accountID)
continue continue
} }
am.storeEvent(userID, peer.IP.String(), accountID, activity.GroupRemovedFromPeer, am.storeEvent(userID, peer.ID, accountID, activity.GroupRemovedFromPeer,
map[string]any{"group": newGroup.Name, "group_id": newGroup.ID, "peer_ip": peer.IP.String(), map[string]any{"group": newGroup.Name, "group_id": newGroup.ID, "peer_ip": peer.IP.String(),
"peer_fqdn": peer.FQDN(am.GetDNSDomain())}) "peer_fqdn": peer.FQDN(am.GetDNSDomain())})
} }
return am.updateAccountPeers(account) return nil
} }
// difference returns the elements in `a` that aren't in `b`. // difference returns the elements in `a` that aren't in `b`.
@ -230,7 +237,7 @@ func (am *DefaultAccountManager) ListGroups(accountID string) ([]*Group, error)
} }
// GroupAddPeer appends peer to the group // GroupAddPeer appends peer to the group
func (am *DefaultAccountManager) GroupAddPeer(accountID, groupID, peerKey string) error { func (am *DefaultAccountManager) GroupAddPeer(accountID, groupID, peerID string) error {
unlock := am.Store.AcquireAccountLock(accountID) unlock := am.Store.AcquireAccountLock(accountID)
defer unlock() defer unlock()
@ -247,13 +254,13 @@ func (am *DefaultAccountManager) GroupAddPeer(accountID, groupID, peerKey string
add := true add := true
for _, itemID := range group.Peers { for _, itemID := range group.Peers {
if itemID == peerKey { if itemID == peerID {
add = false add = false
break break
} }
} }
if add { if add {
group.Peers = append(group.Peers, peerKey) group.Peers = append(group.Peers, peerID)
} }
account.Network.IncSerial() account.Network.IncSerial()

View File

@ -111,7 +111,7 @@ func (s *GRPCServer) Sync(req *proto.EncryptedMessage, srv proto.ManagementServi
return status.Errorf(codes.InvalidArgument, "provided wgPubKey %s is invalid", peerKey.String()) return status.Errorf(codes.InvalidArgument, "provided wgPubKey %s is invalid", peerKey.String())
} }
peer, err := s.accountManager.GetPeer(peerKey.String()) peer, err := s.accountManager.GetPeerByKey(peerKey.String())
if err != nil { if err != nil {
p, _ := gPeer.FromContext(srv.Context()) p, _ := gPeer.FromContext(srv.Context())
msg := status.Errorf(codes.PermissionDenied, "provided peer with the key wgPubKey %s is not registered, remote addr is %s", peerKey.String(), p.Addr.String()) msg := status.Errorf(codes.PermissionDenied, "provided peer with the key wgPubKey %s is not registered, remote addr is %s", peerKey.String(), p.Addr.String())
@ -134,14 +134,14 @@ func (s *GRPCServer) Sync(req *proto.EncryptedMessage, srv proto.ManagementServi
return err return err
} }
updates := s.peersUpdateManager.CreateChannel(peerKey.String()) updates := s.peersUpdateManager.CreateChannel(peer.ID)
err = s.accountManager.MarkPeerConnected(peerKey.String(), true) err = s.accountManager.MarkPeerConnected(peerKey.String(), true)
if err != nil { if err != nil {
log.Warnf("failed marking peer as connected %s %v", peerKey, err) log.Warnf("failed marking peer as connected %s %v", peerKey, err)
} }
if s.config.TURNConfig.TimeBasedCredentials { if s.config.TURNConfig.TimeBasedCredentials {
s.turnCredentialsManager.SetupRefresh(peerKey.String()) s.turnCredentialsManager.SetupRefresh(peer.ID)
} }
// keep a connection to the peer and send updates when available // keep a connection to the peer and send updates when available
for { for {
@ -171,7 +171,7 @@ func (s *GRPCServer) Sync(req *proto.EncryptedMessage, srv proto.ManagementServi
case <-srv.Context().Done(): case <-srv.Context().Done():
// happens when connection drops, e.g. client disconnects // happens when connection drops, e.g. client disconnects
log.Debugf("stream of peer %s has been closed", peerKey.String()) log.Debugf("stream of peer %s has been closed", peerKey.String())
s.peersUpdateManager.CloseChannel(peerKey.String()) s.peersUpdateManager.CloseChannel(peer.ID)
s.turnCredentialsManager.CancelRefresh(peerKey.String()) s.turnCredentialsManager.CancelRefresh(peerKey.String())
err = s.accountManager.MarkPeerConnected(peerKey.String(), false) err = s.accountManager.MarkPeerConnected(peerKey.String(), false)
if err != nil { if err != nil {
@ -252,19 +252,19 @@ func (s *GRPCServer) registerPeer(peerKey wgtypes.Key, req *proto.LoginRequest)
} }
// todo move to DefaultAccountManager the code below // todo move to DefaultAccountManager the code below
networkMap, err := s.accountManager.GetNetworkMap(peer.Key) networkMap, err := s.accountManager.GetNetworkMap(peer.ID)
if err != nil { if err != nil {
return nil, status.Errorf(codes.Internal, "unable to fetch network map after registering peer, error: %v", err) return nil, status.Errorf(codes.Internal, "unable to fetch network map after registering peer, error: %v", err)
} }
// notify other peers of our registration // notify other peers of our registration
for _, remotePeer := range networkMap.Peers { for _, remotePeer := range networkMap.Peers {
remotePeerNetworkMap, err := s.accountManager.GetNetworkMap(remotePeer.Key) remotePeerNetworkMap, err := s.accountManager.GetNetworkMap(remotePeer.ID)
if err != nil { if err != nil {
return nil, status.Errorf(codes.Internal, "unable to fetch network map after registering peer, error: %v", err) return nil, status.Errorf(codes.Internal, "unable to fetch network map after registering peer, error: %v", err)
} }
update := toSyncResponse(s.config, remotePeer, nil, remotePeerNetworkMap, s.accountManager.GetDNSDomain()) update := toSyncResponse(s.config, remotePeer, nil, remotePeerNetworkMap, s.accountManager.GetDNSDomain())
err = s.peersUpdateManager.SendUpdate(remotePeer.Key, &UpdateMessage{Update: update}) err = s.peersUpdateManager.SendUpdate(remotePeer.ID, &UpdateMessage{Update: update})
if err != nil { if err != nil {
// todo rethink if we should keep this return // todo rethink if we should keep this return
return nil, status.Errorf(codes.Internal, "unable to send update after registering peer, error: %v", err) return nil, status.Errorf(codes.Internal, "unable to send update after registering peer, error: %v", err)
@ -299,7 +299,7 @@ func (s *GRPCServer) Login(ctx context.Context, req *proto.EncryptedMessage) (*p
return nil, status.Errorf(codes.InvalidArgument, "invalid request message") return nil, status.Errorf(codes.InvalidArgument, "invalid request message")
} }
peer, err := s.accountManager.GetPeer(peerKey.String()) peer, err := s.accountManager.GetPeerByKey(peerKey.String())
if err != nil { if err != nil {
if errStatus, ok := internalStatus.FromError(err); ok && errStatus.Type() == internalStatus.NotFound { if errStatus, ok := internalStatus.FromError(err); ok && errStatus.Type() == internalStatus.NotFound {
// peer doesn't exist -> check if setup key was provided // peer doesn't exist -> check if setup key was provided
@ -324,7 +324,7 @@ func (s *GRPCServer) Login(ctx context.Context, req *proto.EncryptedMessage) (*p
} }
} else if loginReq.GetMeta() != nil { } else if loginReq.GetMeta() != nil {
// update peer's system meta data on Login // update peer's system meta data on Login
err = s.accountManager.UpdatePeerMeta(peerKey.String(), PeerSystemMeta{ err = s.accountManager.UpdatePeerMeta(peer.ID, PeerSystemMeta{
Hostname: loginReq.GetMeta().GetHostname(), Hostname: loginReq.GetMeta().GetHostname(),
GoOS: loginReq.GetMeta().GetGoOS(), GoOS: loginReq.GetMeta().GetGoOS(),
Kernel: loginReq.GetMeta().GetKernel(), Kernel: loginReq.GetMeta().GetKernel(),
@ -347,13 +347,13 @@ func (s *GRPCServer) Login(ctx context.Context, req *proto.EncryptedMessage) (*p
} }
if len(sshKey) > 0 { if len(sshKey) > 0 {
err = s.accountManager.UpdatePeerSSHKey(peerKey.String(), string(sshKey)) err = s.accountManager.UpdatePeerSSHKey(peer.ID, string(sshKey))
if err != nil { if err != nil {
return nil, err return nil, err
} }
} }
network, err := s.accountManager.GetPeerNetwork(peer.Key) network, err := s.accountManager.GetPeerNetwork(peer.ID)
if err != nil { if err != nil {
return nil, status.Errorf(codes.Internal, "failed getting peer network on login") return nil, status.Errorf(codes.Internal, "failed getting peer network on login")
} }
@ -491,9 +491,9 @@ func (s *GRPCServer) IsHealthy(ctx context.Context, req *proto.Empty) (*proto.Em
// sendInitialSync sends initial proto.SyncResponse to the peer requesting synchronization // sendInitialSync sends initial proto.SyncResponse to the peer requesting synchronization
func (s *GRPCServer) sendInitialSync(peerKey wgtypes.Key, peer *Peer, srv proto.ManagementService_SyncServer) error { func (s *GRPCServer) sendInitialSync(peerKey wgtypes.Key, peer *Peer, srv proto.ManagementService_SyncServer) error {
networkMap, err := s.accountManager.GetNetworkMap(peer.Key) networkMap, err := s.accountManager.GetNetworkMap(peer.ID)
if err != nil { if err != nil {
log.Warnf("error getting a list of peers for a peer %s", peer.Key) log.Warnf("error getting a list of peers for a peer %s", peer.ID)
return err return err
} }

View File

@ -96,10 +96,16 @@ func (h *Groups) UpdateGroupHandler(w http.ResponseWriter, r *http.Request) {
return return
} }
var peers []string
if req.Peers == nil {
peers = make([]string, 0)
} else {
peers = *req.Peers
}
group := server.Group{ group := server.Group{
ID: groupID, ID: groupID,
Name: *req.Name, Name: *req.Name,
Peers: peerIPsToKeys(account, req.Peers), Peers: peers,
} }
if err := h.accountManager.SaveGroup(account.Id, user.Id, &group); err != nil { if err := h.accountManager.SaveGroup(account.Id, user.Id, &group); err != nil {
@ -191,10 +197,9 @@ func (h *Groups) PatchGroupHandler(w http.ResponseWriter, r *http.Request) {
Values: peerKeys, Values: peerKeys,
}) })
case api.GroupPatchOperationOpAdd: case api.GroupPatchOperationOpAdd:
peerKeys := peerIPsToKeys(account, &patch.Value)
operations = append(operations, server.GroupUpdateOperation{ operations = append(operations, server.GroupUpdateOperation{
Type: server.InsertPeersToGroup, Type: server.InsertPeersToGroup,
Values: peerKeys, Values: patch.Value,
}) })
default: default:
util.WriteError(status.Errorf(status.InvalidArgument, util.WriteError(status.Errorf(status.InvalidArgument,
@ -237,10 +242,16 @@ func (h *Groups) CreateGroupHandler(w http.ResponseWriter, r *http.Request) {
return return
} }
var peers []string
if req.Peers == nil {
peers = make([]string, 0)
} else {
peers = *req.Peers
}
group := server.Group{ group := server.Group{
ID: xid.New().String(), ID: xid.New().String(),
Name: req.Name, Name: req.Name,
Peers: peerIPsToKeys(account, req.Peers), Peers: peers,
} }
err = h.accountManager.SaveGroup(account.Id, user.Id, &group) err = h.accountManager.SaveGroup(account.Id, user.Id, &group)
@ -359,7 +370,7 @@ func toGroupResponse(account *server.Account, group *server.Group) *api.Group {
continue continue
} }
peerResp := api.PeerMinimum{ peerResp := api.PeerMinimum{
Id: peer.IP.String(), Id: peer.ID,
Name: peer.Name, Name: peer.Name,
} }
cache[pid] = peerResp cache[pid] = peerResp

View File

@ -22,8 +22,8 @@ import (
) )
var TestPeers = map[string]*server.Peer{ var TestPeers = map[string]*server.Peer{
"A": {Key: "A", IP: net.ParseIP("100.100.100.100")}, "A": {Key: "A", ID: "peer-A-ID", IP: net.ParseIP("100.100.100.100")},
"B": {Key: "B", IP: net.ParseIP("200.200.200.200")}, "B": {Key: "B", ID: "peer-B-ID", IP: net.ParseIP("200.200.200.200")},
} }
func initGroupTestData(user *server.User, groups ...*server.Group) *Groups { func initGroupTestData(user *server.User, groups ...*server.Group) *Groups {
@ -269,8 +269,8 @@ func TestWriteGroup(t *testing.T) {
Id: "id-existed", Id: "id-existed",
PeersCount: 2, PeersCount: 2,
Peers: []api.PeerMinimum{ Peers: []api.PeerMinimum{
{Id: "100.100.100.100"}, {Id: "peer-A-ID"},
{Id: "200.200.200.200"}}, {Id: "peer-B-ID"}},
}, },
}, },
} }

View File

@ -27,7 +27,7 @@ func NewPeers(accountManager server.AccountManager, authAudience string) *Peers
} }
} }
func (h *Peers) updatePeer(account *server.Account, user *server.User, peer *server.Peer, w http.ResponseWriter, r *http.Request) { func (h *Peers) updatePeer(account *server.Account, user *server.User, peerID string, w http.ResponseWriter, r *http.Request) {
req := &api.PutApiPeersIdJSONBody{} req := &api.PutApiPeersIdJSONBody{}
err := json.NewDecoder(r.Body).Decode(&req) err := json.NewDecoder(r.Body).Decode(&req)
if err != nil { if err != nil {
@ -35,8 +35,8 @@ func (h *Peers) updatePeer(account *server.Account, user *server.User, peer *ser
return return
} }
update := &server.Peer{Key: peer.Key, SSHEnabled: req.SshEnabled, Name: req.Name} update := &server.Peer{ID: peerID, SSHEnabled: req.SshEnabled, Name: req.Name}
peer, err = h.accountManager.UpdatePeer(account.Id, user.Id, update) peer, err := h.accountManager.UpdatePeer(account.Id, user.Id, update)
if err != nil { if err != nil {
util.WriteError(err, w) util.WriteError(err, w)
return return
@ -45,8 +45,8 @@ func (h *Peers) updatePeer(account *server.Account, user *server.User, peer *ser
util.WriteJSONObject(w, toPeerResponse(peer, account, dnsDomain)) util.WriteJSONObject(w, toPeerResponse(peer, account, dnsDomain))
} }
func (h *Peers) deletePeer(accountID, userID string, peer *server.Peer, w http.ResponseWriter, r *http.Request) { func (h *Peers) deletePeer(accountID, userID string, peerID string, w http.ResponseWriter) {
_, err := h.accountManager.DeletePeer(accountID, peer.Key, userID) _, err := h.accountManager.DeletePeer(accountID, peerID, userID)
if err != nil { if err != nil {
util.WriteError(err, w) util.WriteError(err, w)
return return
@ -62,31 +62,19 @@ func (h *Peers) HandlePeer(w http.ResponseWriter, r *http.Request) {
return return
} }
vars := mux.Vars(r) vars := mux.Vars(r)
peerId := vars["id"] //effectively peer IP address peerID := vars["id"]
if len(peerId) == 0 { if len(peerID) == 0 {
util.WriteError(status.Errorf(status.InvalidArgument, "invalid peer ID"), w) util.WriteError(status.Errorf(status.InvalidArgument, "invalid peer ID"), w)
return return
} }
peer, err := h.accountManager.GetPeerByIP(account.Id, peerId)
if err != nil {
util.WriteError(err, w)
return
}
dnsDomain := h.accountManager.GetDNSDomain()
switch r.Method { switch r.Method {
case http.MethodDelete: case http.MethodDelete:
h.deletePeer(account.Id, user.Id, peer, w, r) h.deletePeer(account.Id, user.Id, peerID, w)
return return
case http.MethodPut: case http.MethodPut:
h.updatePeer(account, user, peer, w, r) h.updatePeer(account, user, peerID, w, r)
return return
case http.MethodGet:
util.WriteJSONObject(w, toPeerResponse(peer, account, dnsDomain))
return
default: default:
util.WriteError(status.Errorf(status.NotFound, "unknown METHOD"), w) util.WriteError(status.Errorf(status.NotFound, "unknown METHOD"), w)
} }
@ -132,7 +120,7 @@ func toPeerResponse(peer *server.Peer, account *server.Account, dnsDomain string
} }
groupsChecked[group.ID] = struct{}{} groupsChecked[group.ID] = struct{}{}
for _, pk := range group.Peers { for _, pk := range group.Peers {
if pk == peer.Key { if pk == peer.ID {
info := api.GroupMinimum{ info := api.GroupMinimum{
Id: group.ID, Id: group.ID,
Name: group.Name, Name: group.Name,
@ -149,7 +137,7 @@ func toPeerResponse(peer *server.Peer, account *server.Account, dnsDomain string
fqdn = peer.DNSLabel fqdn = peer.DNSLabel
} }
return &api.Peer{ return &api.Peer{
Id: peer.IP.String(), Id: peer.ID,
Name: peer.Name, Name: peer.Name,
Ip: peer.IP.String(), Ip: peer.IP.String(),
Connected: peer.Status.Connected, Connected: peer.Status.Connected,

View File

@ -45,7 +45,7 @@ func (h *Routes) GetAllRoutesHandler(w http.ResponseWriter, r *http.Request) {
} }
apiRoutes := make([]*api.Route, 0) apiRoutes := make([]*api.Route, 0)
for _, r := range routes { for _, r := range routes {
apiRoutes = append(apiRoutes, toRouteResponse(account, r)) apiRoutes = append(apiRoutes, toRouteResponse(r))
} }
util.WriteJSONObject(w, apiRoutes) util.WriteJSONObject(w, apiRoutes)
@ -85,7 +85,7 @@ func (h *Routes) CreateRouteHandler(w http.ResponseWriter, r *http.Request) {
return return
} }
resp := toRouteResponse(account, newRoute) resp := toRouteResponse(newRoute)
util.WriteJSONObject(w, &resp) util.WriteJSONObject(w, &resp)
} }
@ -126,16 +126,6 @@ func (h *Routes) UpdateRouteHandler(w http.ResponseWriter, r *http.Request) {
return return
} }
peerKey := req.Peer
if req.Peer != "" {
peer := account.GetPeerByIP(req.Peer)
if peer == nil {
util.WriteError(status.Errorf(status.NotFound, "peer %s not found", req.Peer), w)
return
}
peerKey = peer.Key
}
if utf8.RuneCountInString(req.NetworkId) > route.MaxNetIDChar || req.NetworkId == "" { if utf8.RuneCountInString(req.NetworkId) > route.MaxNetIDChar || req.NetworkId == "" {
util.WriteError(status.Errorf(status.InvalidArgument, util.WriteError(status.Errorf(status.InvalidArgument,
"identifier should be between 1 and %d", route.MaxNetIDChar), w) "identifier should be between 1 and %d", route.MaxNetIDChar), w)
@ -148,7 +138,7 @@ func (h *Routes) UpdateRouteHandler(w http.ResponseWriter, r *http.Request) {
NetID: req.NetworkId, NetID: req.NetworkId,
NetworkType: prefixType, NetworkType: prefixType,
Masquerade: req.Masquerade, Masquerade: req.Masquerade,
Peer: peerKey, Peer: req.Peer,
Metric: req.Metric, Metric: req.Metric,
Description: req.Description, Description: req.Description,
Enabled: req.Enabled, Enabled: req.Enabled,
@ -161,7 +151,7 @@ func (h *Routes) UpdateRouteHandler(w http.ResponseWriter, r *http.Request) {
return return
} }
resp := toRouteResponse(account, newRoute) resp := toRouteResponse(newRoute)
util.WriteJSONObject(w, &resp) util.WriteJSONObject(w, &resp)
} }
@ -245,18 +235,9 @@ func (h *Routes) PatchRouteHandler(w http.ResponseWriter, r *http.Request) {
"value field only accepts 1 value, got %d", len(patch.Value)), w) "value field only accepts 1 value, got %d", len(patch.Value)), w)
return return
} }
peerValue := patch.Value
if patch.Value[0] != "" {
peer, err := h.accountManager.GetPeerByIP(account.Id, patch.Value[0])
if err != nil {
util.WriteError(err, w)
return
}
peerValue = []string{peer.Key}
}
operations = append(operations, server.RouteUpdateOperation{ operations = append(operations, server.RouteUpdateOperation{
Type: server.UpdateRoutePeer, Type: server.UpdateRoutePeer,
Values: peerValue, Values: patch.Value,
}) })
case api.RoutePatchOperationPathMetric: case api.RoutePatchOperationPathMetric:
if patch.Op != api.RoutePatchOperationOpReplace { if patch.Op != api.RoutePatchOperationOpReplace {
@ -305,13 +286,13 @@ func (h *Routes) PatchRouteHandler(w http.ResponseWriter, r *http.Request) {
} }
} }
route, err := h.accountManager.UpdateRoute(account.Id, routeID, operations) root, err := h.accountManager.UpdateRoute(account.Id, routeID, operations)
if err != nil { if err != nil {
util.WriteError(err, w) util.WriteError(err, w)
return return
} }
resp := toRouteResponse(account, route) resp := toRouteResponse(root)
util.WriteJSONObject(w, &resp) util.WriteJSONObject(w, &resp)
} }
@ -361,25 +342,16 @@ func (h *Routes) GetRouteHandler(w http.ResponseWriter, r *http.Request) {
return return
} }
util.WriteJSONObject(w, toRouteResponse(account, foundRoute)) util.WriteJSONObject(w, toRouteResponse(foundRoute))
} }
func toRouteResponse(account *server.Account, serverRoute *route.Route) *api.Route { func toRouteResponse(serverRoute *route.Route) *api.Route {
var peerIP string
if serverRoute.Peer != "" {
peer, found := account.Peers[serverRoute.Peer]
if !found {
panic("peer ID not found")
}
peerIP = peer.IP.String()
}
return &api.Route{ return &api.Route{
Id: serverRoute.ID, Id: serverRoute.ID,
Description: serverRoute.Description, Description: serverRoute.Description,
NetworkId: serverRoute.NetID, NetworkId: serverRoute.NetID,
Enabled: serverRoute.Enabled, Enabled: serverRoute.Enabled,
Peer: peerIP, Peer: serverRoute.Peer,
Network: serverRoute.Network.String(), Network: serverRoute.Network.String(),
NetworkType: serverRoute.NetworkType.String(), NetworkType: serverRoute.NetworkType.String(),
Masquerade: serverRoute.Masquerade, Masquerade: serverRoute.Masquerade,

View File

@ -24,8 +24,9 @@ import (
const ( const (
existingRouteID = "existingRouteID" existingRouteID = "existingRouteID"
notFoundRouteID = "notFoundRouteID" notFoundRouteID = "notFoundRouteID"
existingPeerID = "100.64.0.100" existingPeerIP = "100.64.0.100"
notFoundPeerID = "100.64.0.200" existingPeerID = "peer-id"
notFoundPeerID = "nonExistingPeer"
existingPeerKey = "existingPeerKey" existingPeerKey = "existingPeerKey"
testAccountID = "test_id" testAccountID = "test_id"
existingGroupID = "testGroup" existingGroupID = "testGroup"
@ -47,9 +48,10 @@ var testingAccount = &server.Account{
Id: testAccountID, Id: testAccountID,
Domain: "hotmail.com", Domain: "hotmail.com",
Peers: map[string]*server.Peer{ Peers: map[string]*server.Peer{
existingPeerKey: { existingPeerID: {
Key: existingPeerKey, Key: existingPeerKey,
IP: netip.MustParseAddr(existingPeerID).AsSlice(), IP: netip.MustParseAddr(existingPeerIP).AsSlice(),
ID: existingPeerID,
}, },
}, },
Users: map[string]*server.User{ Users: map[string]*server.User{
@ -66,18 +68,15 @@ func initRoutesTestData() *Routes {
} }
return nil, status.Errorf(status.NotFound, "route with ID %s not found", routeID) return nil, status.Errorf(status.NotFound, "route with ID %s not found", routeID)
}, },
CreateRouteFunc: func(accountID string, network, peerIP, description, netID string, masquerade bool, metric int, groups []string, enabled bool, _ string) (*route.Route, error) { CreateRouteFunc: func(accountID string, network, peerID, description, netID string, masquerade bool, metric int, groups []string, enabled bool, _ string) (*route.Route, error) {
if peerID == notFoundPeerID {
peer := testingAccount.GetPeerByIP(peerIP) return nil, status.Errorf(status.InvalidArgument, "peer with ID %s not found", peerID)
if peer == nil {
return nil, status.Errorf(status.NotFound, "peer %s not found", peerIP)
} }
networkType, p, _ := route.ParseNetwork(network) networkType, p, _ := route.ParseNetwork(network)
return &route.Route{ return &route.Route{
ID: existingRouteID, ID: existingRouteID,
NetID: netID, NetID: netID,
Peer: peer.Key, Peer: peerID,
Network: p, Network: p,
NetworkType: networkType, NetworkType: networkType,
Description: description, Description: description,
@ -86,7 +85,10 @@ func initRoutesTestData() *Routes {
Groups: groups, Groups: groups,
}, nil }, nil
}, },
SaveRouteFunc: func(_, _ string, _ *route.Route) error { SaveRouteFunc: func(_, _ string, r *route.Route) error {
if r.Peer == notFoundPeerID {
return status.Errorf(status.InvalidArgument, "peer with ID %s not found", r.Peer)
}
return nil return nil
}, },
DeleteRouteFunc: func(_ string, routeID string, _ string) error { DeleteRouteFunc: func(_ string, routeID string, _ string) error {
@ -119,6 +121,9 @@ func initRoutesTestData() *Routes {
routeToUpdate.NetID = operation.Values[0] routeToUpdate.NetID = operation.Values[0]
case server.UpdateRoutePeer: case server.UpdateRoutePeer:
routeToUpdate.Peer = operation.Values[0] routeToUpdate.Peer = operation.Values[0]
if routeToUpdate.Peer == notFoundPeerID {
return nil, status.Errorf(status.InvalidArgument, "peer with ID %s not found", routeToUpdate.Peer)
}
case server.UpdateRouteMetric: case server.UpdateRouteMetric:
routeToUpdate.Metric, _ = strconv.Atoi(operation.Values[0]) routeToUpdate.Metric, _ = strconv.Atoi(operation.Values[0])
case server.UpdateRouteMasquerade: case server.UpdateRouteMasquerade:
@ -166,7 +171,7 @@ func TestRoutesHandlers(t *testing.T) {
requestPath: "/api/routes/" + existingRouteID, requestPath: "/api/routes/" + existingRouteID,
expectedStatus: http.StatusOK, expectedStatus: http.StatusOK,
expectedBody: true, expectedBody: true,
expectedRoute: toRouteResponse(testingAccount, baseExistingRoute), expectedRoute: toRouteResponse(baseExistingRoute),
}, },
{ {
name: "Get Not Existing Route", name: "Get Not Existing Route",
@ -212,7 +217,7 @@ func TestRoutesHandlers(t *testing.T) {
requestType: http.MethodPost, requestType: http.MethodPost,
requestPath: "/api/routes", requestPath: "/api/routes",
requestBody: bytes.NewBufferString(fmt.Sprintf("{\"Description\":\"Post\",\"Network\":\"192.168.0.0/16\",\"network_id\":\"awesomeNet\",\"Peer\":\"%s\",\"groups\":[\"%s\"]}", notFoundPeerID, existingGroupID)), requestBody: bytes.NewBufferString(fmt.Sprintf("{\"Description\":\"Post\",\"Network\":\"192.168.0.0/16\",\"network_id\":\"awesomeNet\",\"Peer\":\"%s\",\"groups\":[\"%s\"]}", notFoundPeerID, existingGroupID)),
expectedStatus: http.StatusNotFound, expectedStatus: http.StatusUnprocessableEntity,
expectedBody: false, expectedBody: false,
}, },
{ {
@ -263,7 +268,7 @@ func TestRoutesHandlers(t *testing.T) {
requestType: http.MethodPut, requestType: http.MethodPut,
requestPath: "/api/routes/" + existingRouteID, requestPath: "/api/routes/" + existingRouteID,
requestBody: bytes.NewBufferString(fmt.Sprintf("{\"Description\":\"Post\",\"Network\":\"192.168.0.0/16\",\"network_id\":\"awesomeNet\",\"Peer\":\"%s\",\"groups\":[\"%s\"]}", notFoundPeerID, existingGroupID)), requestBody: bytes.NewBufferString(fmt.Sprintf("{\"Description\":\"Post\",\"Network\":\"192.168.0.0/16\",\"network_id\":\"awesomeNet\",\"Peer\":\"%s\",\"groups\":[\"%s\"]}", notFoundPeerID, existingGroupID)),
expectedStatus: http.StatusNotFound, expectedStatus: http.StatusUnprocessableEntity,
expectedBody: false, expectedBody: false,
}, },
{ {
@ -326,7 +331,7 @@ func TestRoutesHandlers(t *testing.T) {
requestType: http.MethodPatch, requestType: http.MethodPatch,
requestPath: "/api/routes/" + existingRouteID, requestPath: "/api/routes/" + existingRouteID,
requestBody: bytes.NewBufferString(fmt.Sprintf("[{\"op\":\"replace\",\"path\":\"peer\",\"value\":[\"%s\"]}]", notFoundPeerID)), requestBody: bytes.NewBufferString(fmt.Sprintf("[{\"op\":\"replace\",\"path\":\"peer\",\"value\":[\"%s\"]}]", notFoundPeerID)),
expectedStatus: http.StatusNotFound, expectedStatus: http.StatusUnprocessableEntity,
expectedBody: false, expectedBody: false,
}, },
{ {

View File

@ -207,7 +207,7 @@ func (w *Worker) generateProperties() properties {
osUIClients[uiOSKey] = osUICount + 1 osUIClients[uiOSKey] = osUICount + 1
} }
_, connected := connections[peer.Key] _, connected := connections[peer.ID]
if connected || peer.Status.LastSeen.After(w.lastRun) { if connected || peer.Status.LastSeen.After(w.lastRun) {
activePeersLastDay++ activePeersLastDay++
osActiveKey := osKey + "_active" osActiveKey := osKey + "_active"

View File

@ -42,8 +42,8 @@ type MockAccountManager struct {
DeleteRuleFunc func(accountID, ruleID, userID string) error DeleteRuleFunc func(accountID, ruleID, userID string) error
ListRulesFunc func(accountID, userID string) ([]*server.Rule, error) ListRulesFunc func(accountID, userID string) ([]*server.Rule, error)
GetUsersFromAccountFunc func(accountID, userID string) ([]*server.UserInfo, error) GetUsersFromAccountFunc func(accountID, userID string) ([]*server.UserInfo, error)
UpdatePeerMetaFunc func(peerKey string, meta server.PeerSystemMeta) error UpdatePeerMetaFunc func(peerID string, meta server.PeerSystemMeta) error
UpdatePeerSSHKeyFunc func(peerKey string, sshKey string) error UpdatePeerSSHKeyFunc func(peerID string, sshKey string) error
UpdatePeerFunc func(accountID, userID string, peer *server.Peer) (*server.Peer, error) UpdatePeerFunc func(accountID, userID string, peer *server.Peer) (*server.Peer, error)
CreateRouteFunc func(accountID string, prefix, peer, description, netID string, masquerade bool, metric int, groups []string, enabled bool, userID string) (*route.Route, error) CreateRouteFunc func(accountID string, prefix, peer, description, netID string, masquerade bool, metric int, groups []string, enabled bool, userID string) (*route.Route, error)
GetRouteFunc func(accountID, routeID, userID string) (*route.Route, error) GetRouteFunc func(accountID, routeID, userID string) (*route.Route, error)
@ -77,9 +77,9 @@ func (am *MockAccountManager) GetUsersFromAccount(accountID string, userID strin
} }
// DeletePeer mock implementation of DeletePeer from server.AccountManager interface // DeletePeer mock implementation of DeletePeer from server.AccountManager interface
func (am *MockAccountManager) DeletePeer(accountID, peerKey, userID string) (*server.Peer, error) { func (am *MockAccountManager) DeletePeer(accountID, peerID, userID string) (*server.Peer, error) {
if am.DeletePeerFunc != nil { if am.DeletePeerFunc != nil {
return am.DeletePeerFunc(accountID, peerKey, userID) return am.DeletePeerFunc(accountID, peerID, userID)
} }
return nil, status.Errorf(codes.Unimplemented, "method DeletePeer is not implemented") return nil, status.Errorf(codes.Unimplemented, "method DeletePeer is not implemented")
} }
@ -143,11 +143,11 @@ func (am *MockAccountManager) AccountExists(accountId string) (*bool, error) {
} }
// GetPeer mock implementation of GetPeer from server.AccountManager interface // GetPeer mock implementation of GetPeer from server.AccountManager interface
func (am *MockAccountManager) GetPeer(peerKey string) (*server.Peer, error) { func (am *MockAccountManager) GetPeerByKey(peerKey string) (*server.Peer, error) {
if am.GetPeerFunc != nil { if am.GetPeerFunc != nil {
return am.GetPeerFunc(peerKey) return am.GetPeerFunc(peerKey)
} }
return nil, status.Errorf(codes.Unimplemented, "method GetPeer is not implemented") return nil, status.Errorf(codes.Unimplemented, "method GetPeerByKey is not implemented")
} }
// MarkPeerConnected mock implementation of MarkPeerConnected from server.AccountManager interface // MarkPeerConnected mock implementation of MarkPeerConnected from server.AccountManager interface
@ -299,9 +299,9 @@ func (am *MockAccountManager) ListRules(accountID, userID string) ([]*server.Rul
} }
// UpdatePeerMeta mock implementation of UpdatePeerMeta from server.AccountManager interface // UpdatePeerMeta mock implementation of UpdatePeerMeta from server.AccountManager interface
func (am *MockAccountManager) UpdatePeerMeta(peerKey string, meta server.PeerSystemMeta) error { func (am *MockAccountManager) UpdatePeerMeta(peerID string, meta server.PeerSystemMeta) error {
if am.UpdatePeerMetaFunc != nil { if am.UpdatePeerMetaFunc != nil {
return am.UpdatePeerMetaFunc(peerKey, meta) return am.UpdatePeerMetaFunc(peerID, meta)
} }
return status.Errorf(codes.Unimplemented, "method UpdatePeerMetaFunc is not implemented") return status.Errorf(codes.Unimplemented, "method UpdatePeerMetaFunc is not implemented")
} }
@ -315,9 +315,9 @@ func (am *MockAccountManager) IsUserAdmin(claims jwtclaims.AuthorizationClaims)
} }
// UpdatePeerSSHKey mocks UpdatePeerSSHKey function of the account manager // UpdatePeerSSHKey mocks UpdatePeerSSHKey function of the account manager
func (am *MockAccountManager) UpdatePeerSSHKey(peerKey string, sshKey string) error { func (am *MockAccountManager) UpdatePeerSSHKey(peerID string, sshKey string) error {
if am.UpdatePeerSSHKeyFunc != nil { if am.UpdatePeerSSHKeyFunc != nil {
return am.UpdatePeerSSHKeyFunc(peerKey, sshKey) return am.UpdatePeerSSHKeyFunc(peerID, sshKey)
} }
return status.Errorf(codes.Unimplemented, "method UpdatePeerSSHKey is is not implemented") return status.Errorf(codes.Unimplemented, "method UpdatePeerSSHKey is is not implemented")
} }
@ -331,9 +331,9 @@ func (am *MockAccountManager) UpdatePeer(accountID, userID string, peer *server.
} }
// CreateRoute mock implementation of CreateRoute from server.AccountManager interface // CreateRoute mock implementation of CreateRoute from server.AccountManager interface
func (am *MockAccountManager) CreateRoute(accountID string, network, peerIP, description, netID string, masquerade bool, metric int, groups []string, enabled bool, userID string) (*route.Route, error) { func (am *MockAccountManager) CreateRoute(accountID string, network, peerID, description, netID string, masquerade bool, metric int, groups []string, enabled bool, userID string) (*route.Route, error) {
if am.CreateRouteFunc != nil { if am.CreateRouteFunc != nil {
return am.CreateRouteFunc(accountID, network, peerIP, description, netID, masquerade, metric, groups, enabled, userID) return am.CreateRouteFunc(accountID, network, peerID, description, netID, masquerade, metric, groups, enabled, userID)
} }
return nil, status.Errorf(codes.Unimplemented, "method CreateRoute is not implemented") return nil, status.Errorf(codes.Unimplemented, "method CreateRoute is not implemented")
} }

View File

@ -5,6 +5,7 @@ import (
nbdns "github.com/netbirdio/netbird/dns" nbdns "github.com/netbirdio/netbird/dns"
"github.com/netbirdio/netbird/management/server/activity" "github.com/netbirdio/netbird/management/server/activity"
"github.com/netbirdio/netbird/management/server/status" "github.com/netbirdio/netbird/management/server/status"
"github.com/rs/xid"
"net" "net"
"strings" "strings"
"time" "time"
@ -34,9 +35,11 @@ type PeerStatus struct {
} }
// Peer represents a machine connected to the network. // Peer represents a machine connected to the network.
// The Peer is a Wireguard peer identified by a public key // The Peer is a WireGuard peer identified by a public key
type Peer struct { type Peer struct {
// Wireguard public key // ID is an internal ID of the peer
ID string
// WireGuard public key
Key string Key string
// A setup key this peer was registered with // A setup key this peer was registered with
SetupKey string SetupKey string
@ -62,6 +65,7 @@ type Peer struct {
// Copy copies Peer object // Copy copies Peer object
func (p *Peer) Copy() *Peer { func (p *Peer) Copy() *Peer {
return &Peer{ return &Peer{
ID: p.ID,
Key: p.Key, Key: p.Key,
SetupKey: p.SetupKey, SetupKey: p.SetupKey,
IP: p.IP, IP: p.IP,
@ -97,7 +101,7 @@ func (p *PeerStatus) Copy() *PeerStatus {
} }
// GetPeer looks up peer by its public WireGuard key // GetPeer looks up peer by its public WireGuard key
func (am *DefaultAccountManager) GetPeer(peerPubKey string) (*Peer, error) { func (am *DefaultAccountManager) GetPeerByKey(peerPubKey string) (*Peer, error) {
account, err := am.Store.GetAccountByPeerPubKey(peerPubKey) account, err := am.Store.GetAccountByPeerPubKey(peerPubKey)
if err != nil { if err != nil {
@ -130,14 +134,14 @@ func (am *DefaultAccountManager) GetPeers(accountID, userID string) ([]*Peer, er
} }
p := peer.Copy() p := peer.Copy()
peers = append(peers, p) peers = append(peers, p)
peersMap[peer.Key] = p peersMap[peer.ID] = p
} }
// fetch all the peers that have access to the user's peers // fetch all the peers that have access to the user's peers
for _, peer := range peers { for _, peer := range peers {
aclPeers := account.getPeersByACL(peer.Key) aclPeers := account.getPeersByACL(peer.ID)
for _, p := range aclPeers { for _, p := range aclPeers {
peersMap[p.Key] = p peersMap[p.ID] = p
} }
} }
@ -177,7 +181,7 @@ func (am *DefaultAccountManager) MarkPeerConnected(peerPubKey string, connected
peer.Status = newStatus peer.Status = newStatus
account.UpdatePeer(peer) account.UpdatePeer(peer)
err = am.Store.SavePeerStatus(account.Id, peerPubKey, *newStatus) err = am.Store.SavePeerStatus(account.Id, peer.ID, *newStatus)
if err != nil { if err != nil {
return err return err
} }
@ -195,10 +199,9 @@ func (am *DefaultAccountManager) UpdatePeer(accountID, userID string, update *Pe
return nil, err return nil, err
} }
//TODO Peer.ID migration: we will need to replace search by ID here peer := account.GetPeer(update.ID)
peer, err := account.FindPeerByPubKey(update.Key) if peer == nil {
if err != nil { return nil, status.Errorf(status.NotFound, "peer %s not found", update.ID)
return nil, err
} }
if peer.SSHEnabled != update.SSHEnabled { if peer.SSHEnabled != update.SSHEnabled {
@ -222,7 +225,7 @@ func (am *DefaultAccountManager) UpdatePeer(accountID, userID string, update *Pe
peer.DNSLabel = newLabel peer.DNSLabel = newLabel
am.storeEvent(userID, peer.IP.String(), accountID, activity.PeerRenamed, peer.EventMeta(am.GetDNSDomain())) am.storeEvent(userID, peer.ID, accountID, activity.PeerRenamed, peer.EventMeta(am.GetDNSDomain()))
} }
account.UpdatePeer(peer) account.UpdatePeer(peer)
@ -241,7 +244,7 @@ func (am *DefaultAccountManager) UpdatePeer(accountID, userID string, update *Pe
} }
// DeletePeer removes peer from the account by its IP // DeletePeer removes peer from the account by its IP
func (am *DefaultAccountManager) DeletePeer(accountID, peerPubKey, userID string) (*Peer, error) { func (am *DefaultAccountManager) DeletePeer(accountID, peerID, userID string) (*Peer, error) {
unlock := am.Store.AcquireAccountLock(accountID) unlock := am.Store.AcquireAccountLock(accountID)
defer unlock() defer unlock()
@ -251,19 +254,19 @@ func (am *DefaultAccountManager) DeletePeer(accountID, peerPubKey, userID string
return nil, err return nil, err
} }
peer, err := account.FindPeerByPubKey(peerPubKey) peer := account.GetPeer(peerID)
if err != nil { if peer == nil {
return nil, err return nil, status.Errorf(status.NotFound, "peer %s not found", peerID)
} }
account.DeletePeer(peerPubKey) account.DeletePeer(peerID)
err = am.Store.SaveAccount(account) err = am.Store.SaveAccount(account)
if err != nil { if err != nil {
return nil, err return nil, err
} }
err = am.peersUpdateManager.SendUpdate(peerPubKey, err = am.peersUpdateManager.SendUpdate(peer.ID,
&UpdateMessage{ &UpdateMessage{
Update: &proto.SyncResponse{ Update: &proto.SyncResponse{
// fill those field for backward compatibility // fill those field for backward compatibility
@ -281,13 +284,12 @@ func (am *DefaultAccountManager) DeletePeer(accountID, peerPubKey, userID string
return nil, err return nil, err
} }
// TODO Peer.ID migration: we will need to replace search by Peer.ID here
if err := am.updateAccountPeers(account); err != nil { if err := am.updateAccountPeers(account); err != nil {
return nil, err return nil, err
} }
am.peersUpdateManager.CloseChannel(peerPubKey) am.peersUpdateManager.CloseChannel(peerID)
am.storeEvent(userID, peer.IP.String(), account.Id, activity.PeerRemovedByUser, peer.EventMeta(am.GetDNSDomain())) am.storeEvent(userID, peer.ID, account.Id, activity.PeerRemovedByUser, peer.EventMeta(am.GetDNSDomain()))
return peer, nil return peer, nil
} }
@ -312,17 +314,23 @@ func (am *DefaultAccountManager) GetPeerByIP(accountID string, peerIP string) (*
} }
// GetNetworkMap returns Network map for a given peer (omits original peer from the Peers result) // GetNetworkMap returns Network map for a given peer (omits original peer from the Peers result)
func (am *DefaultAccountManager) GetNetworkMap(peerPubKey string) (*NetworkMap, error) { func (am *DefaultAccountManager) GetNetworkMap(peerID string) (*NetworkMap, error) {
account, err := am.Store.GetAccountByPeerPubKey(peerPubKey) account, err := am.Store.GetAccountByPeerID(peerID)
if err != nil { if err != nil {
return nil, err return nil, err
} }
aclPeers := account.getPeersByACL(peerPubKey) peer := account.GetPeer(peerID)
routesUpdate := account.getRoutesToSync(peerPubKey, aclPeers) if peer == nil {
return nil, status.Errorf(status.NotFound, "peer with ID %s not found", peerID)
}
dnsManagementStatus := account.getPeerDNSManagementStatus(peerPubKey) aclPeers := account.getPeersByACL(peerID)
// Please mind, that the returned route.Route objects will contain Peer.Key instead of Peer.ID.
routesUpdate := account.getRoutesToSync(peerID, aclPeers)
dnsManagementStatus := account.getPeerDNSManagementStatus(peerID)
dnsUpdate := nbdns.Config{ dnsUpdate := nbdns.Config{
ServiceEnable: dnsManagementStatus, ServiceEnable: dnsManagementStatus,
} }
@ -334,7 +342,7 @@ func (am *DefaultAccountManager) GetNetworkMap(peerPubKey string) (*NetworkMap,
zones = append(zones, peersCustomZone) zones = append(zones, peersCustomZone)
} }
dnsUpdate.CustomZones = zones dnsUpdate.CustomZones = zones
dnsUpdate.NameServerGroups = getPeerNSGroups(account, peerPubKey) dnsUpdate.NameServerGroups = getPeerNSGroups(account, peerID)
} }
return &NetworkMap{ return &NetworkMap{
@ -346,9 +354,9 @@ func (am *DefaultAccountManager) GetNetworkMap(peerPubKey string) (*NetworkMap,
} }
// GetPeerNetwork returns the Network for a given peer // GetPeerNetwork returns the Network for a given peer
func (am *DefaultAccountManager) GetPeerNetwork(peerPubKey string) (*Network, error) { func (am *DefaultAccountManager) GetPeerNetwork(peerID string) (*Network, error) {
account, err := am.Store.GetAccountByPeerPubKey(peerPubKey) account, err := am.Store.GetAccountByPeerID(peerID)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -357,7 +365,7 @@ func (am *DefaultAccountManager) GetPeerNetwork(peerPubKey string) (*Network, er
} }
// AddPeer adds a new peer to the Store. // AddPeer adds a new peer to the Store.
// Each Account has a list of pre-authorised SetupKey and if no Account has a given key err wit ha code codes.Unauthenticated // Each Account has a list of pre-authorised SetupKey and if no Account has a given key err with a code codes.Unauthenticated
// will be returned, meaning the key is invalid // will be returned, meaning the key is invalid
// If a User ID is provided, it means that we passed the authentication using JWT, then we look for account by User ID and register the peer // If a User ID is provided, it means that we passed the authentication using JWT, then we look for account by User ID and register the peer
// to it. We also add the User ID to the peer metadata to identify registrant. // to it. We also add the User ID to the peer metadata to identify registrant.
@ -428,6 +436,7 @@ func (am *DefaultAccountManager) AddPeer(setupKey, userID string, peer *Peer) (*
} }
newPeer := &Peer{ newPeer := &Peer{
ID: xid.New().String(),
Key: peer.Key, Key: peer.Key,
SetupKey: upperKey, SetupKey: upperKey,
IP: nextIp, IP: nextIp,
@ -445,7 +454,7 @@ func (am *DefaultAccountManager) AddPeer(setupKey, userID string, peer *Peer) (*
if err != nil { if err != nil {
return nil, err return nil, err
} }
group.Peers = append(group.Peers, newPeer.Key) group.Peers = append(group.Peers, newPeer.ID)
var groupsToAdd []string var groupsToAdd []string
if addedByUser { if addedByUser {
@ -463,19 +472,19 @@ func (am *DefaultAccountManager) AddPeer(setupKey, userID string, peer *Peer) (*
if len(groupsToAdd) > 0 { if len(groupsToAdd) > 0 {
for _, s := range groupsToAdd { for _, s := range groupsToAdd {
if g, ok := account.Groups[s]; ok && g.Name != "All" { if g, ok := account.Groups[s]; ok && g.Name != "All" {
g.Peers = append(g.Peers, newPeer.Key) g.Peers = append(g.Peers, newPeer.ID)
} }
} }
} }
account.Peers[newPeer.Key] = newPeer account.Peers[newPeer.ID] = newPeer
account.Network.IncSerial() account.Network.IncSerial()
err = am.Store.SaveAccount(account) err = am.Store.SaveAccount(account)
if err != nil { if err != nil {
return nil, err return nil, err
} }
opEvent.TargetID = newPeer.IP.String() opEvent.TargetID = newPeer.ID
opEvent.Meta = newPeer.EventMeta(am.GetDNSDomain()) opEvent.Meta = newPeer.EventMeta(am.GetDNSDomain())
am.storeEvent(opEvent.InitiatorID, opEvent.TargetID, opEvent.AccountID, opEvent.Activity, opEvent.Meta) am.storeEvent(opEvent.InitiatorID, opEvent.TargetID, opEvent.AccountID, opEvent.Activity, opEvent.Meta)
@ -483,14 +492,14 @@ func (am *DefaultAccountManager) AddPeer(setupKey, userID string, peer *Peer) (*
} }
// UpdatePeerSSHKey updates peer's public SSH key // UpdatePeerSSHKey updates peer's public SSH key
func (am *DefaultAccountManager) UpdatePeerSSHKey(peerPubKey string, sshKey string) error { func (am *DefaultAccountManager) UpdatePeerSSHKey(peerID string, sshKey string) error {
if sshKey == "" { if sshKey == "" {
log.Debugf("empty SSH key provided for peer %s, skipping update", peerPubKey) log.Debugf("empty SSH key provided for peer %s, skipping update", peerID)
return nil return nil
} }
account, err := am.Store.GetAccountByPeerPubKey(peerPubKey) account, err := am.Store.GetAccountByPeerID(peerID)
if err != nil { if err != nil {
return err return err
} }
@ -504,13 +513,13 @@ func (am *DefaultAccountManager) UpdatePeerSSHKey(peerPubKey string, sshKey stri
return err return err
} }
peer, err := account.FindPeerByPubKey(peerPubKey) peer := account.GetPeer(peerID)
if err != nil { if peer == nil {
return err return status.Errorf(status.NotFound, "peer with ID %s not found", peerID)
} }
if peer.SSHKey == sshKey { if peer.SSHKey == sshKey {
log.Debugf("same SSH key provided for peer %s, skipping update", peerPubKey) log.Debugf("same SSH key provided for peer %s, skipping update", peerID)
return nil return nil
} }
@ -527,9 +536,9 @@ func (am *DefaultAccountManager) UpdatePeerSSHKey(peerPubKey string, sshKey stri
} }
// UpdatePeerMeta updates peer's system metadata // UpdatePeerMeta updates peer's system metadata
func (am *DefaultAccountManager) UpdatePeerMeta(peerPubKey string, meta PeerSystemMeta) error { func (am *DefaultAccountManager) UpdatePeerMeta(peerID string, meta PeerSystemMeta) error {
account, err := am.Store.GetAccountByPeerPubKey(peerPubKey) account, err := am.Store.GetAccountByPeerID(peerID)
if err != nil { if err != nil {
return err return err
} }
@ -537,9 +546,9 @@ func (am *DefaultAccountManager) UpdatePeerMeta(peerPubKey string, meta PeerSyst
unlock := am.Store.AcquireAccountLock(account.Id) unlock := am.Store.AcquireAccountLock(account.Id)
defer unlock() defer unlock()
peer, err := account.FindPeerByPubKey(peerPubKey) peer := account.GetPeer(peerID)
if err != nil { if peer == nil {
return err return status.Errorf(status.NotFound, "peer with ID %s not found", peerID)
} }
// Avoid overwriting UIVersion if the update was triggered sole by the CLI client // Avoid overwriting UIVersion if the update was triggered sole by the CLI client
@ -558,9 +567,9 @@ func (am *DefaultAccountManager) UpdatePeerMeta(peerPubKey string, meta PeerSyst
} }
// getPeersByACL returns all peers that given peer has access to. // getPeersByACL returns all peers that given peer has access to.
func (a *Account) getPeersByACL(peerPubKey string) []*Peer { func (a *Account) getPeersByACL(peerID string) []*Peer {
var peers []*Peer var peers []*Peer
srcRules, dstRules := a.GetPeerRules(peerPubKey) srcRules, dstRules := a.GetPeerRules(peerID)
groups := map[string]*Group{} groups := map[string]*Group{}
for _, r := range srcRules { for _, r := range srcRules {
@ -603,8 +612,8 @@ func (a *Account) getPeersByACL(peerPubKey string) []*Peer {
continue continue
} }
// exclude original peer // exclude original peer
if _, ok := peersSet[peer.Key]; peer.Key != peerPubKey && !ok { if _, ok := peersSet[peer.ID]; peer.ID != peerID && !ok {
peersSet[peer.Key] = struct{}{} peersSet[peer.ID] = struct{}{}
peers = append(peers, peer.Copy()) peers = append(peers, peer.Copy())
} }
} }
@ -619,13 +628,13 @@ func (am *DefaultAccountManager) updateAccountPeers(account *Account) error {
peers := account.GetPeers() peers := account.GetPeers()
for _, peer := range peers { for _, peer := range peers {
remotePeerNetworkMap, err := am.GetNetworkMap(peer.Key) remotePeerNetworkMap, err := am.GetNetworkMap(peer.ID)
if err != nil { if err != nil {
return err return err
} }
update := toSyncResponse(nil, peer, nil, remotePeerNetworkMap, am.GetDNSDomain()) update := toSyncResponse(nil, peer, nil, remotePeerNetworkMap, am.GetDNSDomain())
err = am.peersUpdateManager.SendUpdate(peer.Key, &UpdateMessage{Update: update}) err = am.peersUpdateManager.SendUpdate(peer.ID, &UpdateMessage{Update: update})
if err != nil { if err != nil {
return err return err
} }

View File

@ -34,7 +34,7 @@ func TestAccountManager_GetNetworkMap(t *testing.T) {
return return
} }
_, err = manager.AddPeer(setupKey.Key, "", &Peer{ peer1, err := manager.AddPeer(setupKey.Key, "", &Peer{
Key: peerKey1.PublicKey().String(), Key: peerKey1.PublicKey().String(),
Meta: PeerSystemMeta{}, Meta: PeerSystemMeta{},
Name: "test-peer-2", Name: "test-peer-2",
@ -61,7 +61,7 @@ func TestAccountManager_GetNetworkMap(t *testing.T) {
return return
} }
networkMap, err := manager.GetNetworkMap(peerKey1.PublicKey().String()) networkMap, err := manager.GetNetworkMap(peer1.ID)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
return return
@ -107,7 +107,7 @@ func TestAccountManager_GetNetworkMapWithRule(t *testing.T) {
return return
} }
_, err = manager.AddPeer(setupKey.Key, "", &Peer{ peer1, err := manager.AddPeer(setupKey.Key, "", &Peer{
Key: peerKey1.PublicKey().String(), Key: peerKey1.PublicKey().String(),
Meta: PeerSystemMeta{}, Meta: PeerSystemMeta{},
Name: "test-peer-2", Name: "test-peer-2",
@ -123,7 +123,7 @@ func TestAccountManager_GetNetworkMapWithRule(t *testing.T) {
t.Fatal(err) t.Fatal(err)
return return
} }
_, err = manager.AddPeer(setupKey.Key, "", &Peer{ peer2, err := manager.AddPeer(setupKey.Key, "", &Peer{
Key: peerKey2.PublicKey().String(), Key: peerKey2.PublicKey().String(),
Meta: PeerSystemMeta{}, Meta: PeerSystemMeta{},
Name: "test-peer-2", Name: "test-peer-2",
@ -156,8 +156,8 @@ func TestAccountManager_GetNetworkMapWithRule(t *testing.T) {
group1.Name = "src" group1.Name = "src"
group2.Name = "dst" group2.Name = "dst"
rule.ID = xid.New().String() rule.ID = xid.New().String()
group1.Peers = append(group1.Peers, peerKey1.PublicKey().String()) group1.Peers = append(group1.Peers, peer1.ID)
group2.Peers = append(group2.Peers, peerKey2.PublicKey().String()) group2.Peers = append(group2.Peers, peer2.ID)
err = manager.SaveGroup(account.Id, userID, &group1) err = manager.SaveGroup(account.Id, userID, &group1)
if err != nil { if err != nil {
@ -180,7 +180,7 @@ func TestAccountManager_GetNetworkMapWithRule(t *testing.T) {
return return
} }
networkMap1, err := manager.GetNetworkMap(peerKey1.PublicKey().String()) networkMap1, err := manager.GetNetworkMap(peer1.ID)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
return return
@ -203,7 +203,7 @@ func TestAccountManager_GetNetworkMapWithRule(t *testing.T) {
) )
} }
networkMap2, err := manager.GetNetworkMap(peerKey2.PublicKey().String()) networkMap2, err := manager.GetNetworkMap(peer2.ID)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
return return
@ -228,7 +228,7 @@ func TestAccountManager_GetNetworkMapWithRule(t *testing.T) {
return return
} }
networkMap1, err = manager.GetNetworkMap(peerKey1.PublicKey().String()) networkMap1, err = manager.GetNetworkMap(peer1.ID)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
return return
@ -243,7 +243,7 @@ func TestAccountManager_GetNetworkMapWithRule(t *testing.T) {
return return
} }
networkMap2, err = manager.GetNetworkMap(peerKey2.PublicKey().String()) networkMap2, err = manager.GetNetworkMap(peer2.ID)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
return return
@ -281,7 +281,7 @@ func TestAccountManager_GetPeerNetwork(t *testing.T) {
return return
} }
_, err = manager.AddPeer(setupKey.Key, "", &Peer{ peer1, err := manager.AddPeer(setupKey.Key, "", &Peer{
Key: peerKey1.PublicKey().String(), Key: peerKey1.PublicKey().String(),
Meta: PeerSystemMeta{}, Meta: PeerSystemMeta{},
Name: "test-peer-2", Name: "test-peer-2",
@ -308,7 +308,7 @@ func TestAccountManager_GetPeerNetwork(t *testing.T) {
return return
} }
network, err := manager.GetPeerNetwork(peerKey1.PublicKey().String()) network, err := manager.GetPeerNetwork(peer1.ID)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
return return

View File

@ -91,9 +91,9 @@ func (am *DefaultAccountManager) GetRoute(accountID, routeID, userID string) (*r
} }
// checkPrefixPeerExists checks the combination of prefix and peer id, if it exists returns an error, otherwise returns nil // checkPrefixPeerExists checks the combination of prefix and peer id, if it exists returns an error, otherwise returns nil
func (am *DefaultAccountManager) checkPrefixPeerExists(accountID, peer string, prefix netip.Prefix) error { func (am *DefaultAccountManager) checkPrefixPeerExists(accountID, peerID string, prefix netip.Prefix) error {
if peer == "" { if peerID == "" {
return nil return nil
} }
@ -111,15 +111,15 @@ func (am *DefaultAccountManager) checkPrefixPeerExists(accountID, peer string, p
return status.Errorf(status.InvalidArgument, "failed to parse prefix %s", prefix.String()) return status.Errorf(status.InvalidArgument, "failed to parse prefix %s", prefix.String())
} }
for _, prefixRoute := range routesWithPrefix { for _, prefixRoute := range routesWithPrefix {
if prefixRoute.Peer == peer { if prefixRoute.Peer == peerID {
return status.Errorf(status.AlreadyExists, "failed a route with prefix %s and peer already exist", prefix.String()) return status.Errorf(status.AlreadyExists, "failed to add route with prefix %s - peer already has this route", prefix.String())
} }
} }
return nil return nil
} }
// CreateRoute creates and saves a new route // CreateRoute creates and saves a new route
func (am *DefaultAccountManager) CreateRoute(accountID string, network, peerIP, description, netID string, masquerade bool, metric int, groups []string, enabled bool, userID string) (*route.Route, error) { func (am *DefaultAccountManager) CreateRoute(accountID string, network, peerID, description, netID string, masquerade bool, metric int, groups []string, enabled bool, userID string) (*route.Route, error) {
unlock := am.Store.AcquireAccountLock(accountID) unlock := am.Store.AcquireAccountLock(accountID)
defer unlock() defer unlock()
@ -128,13 +128,11 @@ func (am *DefaultAccountManager) CreateRoute(accountID string, network, peerIP,
return nil, err return nil, err
} }
peerKey := "" if peerID != "" {
if peerIP != "" { peer := account.GetPeer(peerID)
peer := account.GetPeerByIP(peerIP)
if peer == nil { if peer == nil {
return nil, status.Errorf(status.NotFound, "peer %s not found", peerIP) return nil, status.Errorf(status.InvalidArgument, "peer with ID %s not found", peerID)
} }
peerKey = peer.Key
} }
var newRoute route.Route var newRoute route.Route
@ -142,7 +140,7 @@ func (am *DefaultAccountManager) CreateRoute(accountID string, network, peerIP,
if err != nil { if err != nil {
return nil, status.Errorf(status.InvalidArgument, "failed to parse IP %s", network) return nil, status.Errorf(status.InvalidArgument, "failed to parse IP %s", network)
} }
err = am.checkPrefixPeerExists(accountID, peerKey, newPrefix) err = am.checkPrefixPeerExists(accountID, peerID, newPrefix)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -160,7 +158,7 @@ func (am *DefaultAccountManager) CreateRoute(accountID string, network, peerIP,
return nil, err return nil, err
} }
newRoute.Peer = peerKey newRoute.Peer = peerID
newRoute.ID = xid.New().String() newRoute.ID = xid.New().String()
newRoute.Network = newPrefix newRoute.Network = newPrefix
newRoute.NetworkType = prefixType newRoute.NetworkType = prefixType
@ -220,9 +218,9 @@ func (am *DefaultAccountManager) SaveRoute(accountID, userID string, routeToSave
} }
if routeToSave.Peer != "" { if routeToSave.Peer != "" {
_, peerExist := account.Peers[routeToSave.Peer] peer := account.GetPeer(routeToSave.Peer)
if !peerExist { if peer == nil {
return status.Errorf(status.InvalidArgument, "failed to find Peer %s", routeToSave.Peer) return status.Errorf(status.InvalidArgument, "peer with ID %s not found", routeToSave.Peer)
} }
} }
@ -238,9 +236,14 @@ func (am *DefaultAccountManager) SaveRoute(accountID, userID string, routeToSave
return err return err
} }
err = am.updateAccountPeers(account)
if err != nil {
return err
}
am.storeEvent(userID, routeToSave.ID, accountID, activity.RouteUpdated, routeToSave.EventMeta()) am.storeEvent(userID, routeToSave.ID, accountID, activity.RouteUpdated, routeToSave.EventMeta())
return am.updateAccountPeers(account) return nil
} }
// UpdateRoute updates existing route with set of operations // UpdateRoute updates existing route with set of operations
@ -287,9 +290,9 @@ func (am *DefaultAccountManager) UpdateRoute(accountID, routeID string, operatio
newRoute.NetworkType = prefixType newRoute.NetworkType = prefixType
case UpdateRoutePeer: case UpdateRoutePeer:
if operation.Values[0] != "" { if operation.Values[0] != "" {
_, peerExist := account.Peers[operation.Values[0]] peer := account.GetPeer(operation.Values[0])
if !peerExist { if peer == nil {
return nil, status.Errorf(status.InvalidArgument, "failed to find Peer %s", operation.Values[0]) return nil, status.Errorf(status.InvalidArgument, "peer with ID %s not found", operation.Values[0])
} }
} }

View File

@ -12,6 +12,8 @@ import (
const ( const (
peer1Key = "BhRPtynAAYRDy08+q4HTMsos8fs4plTP4NOSh7C1ry8=" peer1Key = "BhRPtynAAYRDy08+q4HTMsos8fs4plTP4NOSh7C1ry8="
peer2Key = "/yF0+vCfv+mRR5k0dca0TrGdO/oiNeAI58gToZm5NyI=" peer2Key = "/yF0+vCfv+mRR5k0dca0TrGdO/oiNeAI58gToZm5NyI="
peer1ID = "peer-1-id"
peer2ID = "peer-2-id"
routeGroup1 = "routeGroup1" routeGroup1 = "routeGroup1"
routeGroup2 = "routeGroup2" routeGroup2 = "routeGroup2"
routeInvalidGroup1 = "routeInvalidGroup1" routeInvalidGroup1 = "routeInvalidGroup1"
@ -23,7 +25,7 @@ func TestCreateRoute(t *testing.T) {
type input struct { type input struct {
network string network string
netID string netID string
peer string peerKey string
description string description string
masquerade bool masquerade bool
metric int metric int
@ -43,7 +45,7 @@ func TestCreateRoute(t *testing.T) {
inputArgs: input{ inputArgs: input{
network: "192.168.0.0/16", network: "192.168.0.0/16",
netID: "happy", netID: "happy",
peer: peer1Key, peerKey: peer1ID,
description: "super", description: "super",
masquerade: false, masquerade: false,
metric: 9999, metric: 9999,
@ -56,7 +58,7 @@ func TestCreateRoute(t *testing.T) {
Network: netip.MustParsePrefix("192.168.0.0/16"), Network: netip.MustParsePrefix("192.168.0.0/16"),
NetworkType: route.IPv4Network, NetworkType: route.IPv4Network,
NetID: "happy", NetID: "happy",
Peer: peer1Key, Peer: peer1ID,
Description: "super", Description: "super",
Masquerade: false, Masquerade: false,
Metric: 9999, Metric: 9999,
@ -69,7 +71,7 @@ func TestCreateRoute(t *testing.T) {
inputArgs: input{ inputArgs: input{
network: "192.168.0.0/34", network: "192.168.0.0/34",
netID: "happy", netID: "happy",
peer: peer1Key, peerKey: peer1ID,
description: "super", description: "super",
masquerade: false, masquerade: false,
metric: 9999, metric: 9999,
@ -84,7 +86,7 @@ func TestCreateRoute(t *testing.T) {
inputArgs: input{ inputArgs: input{
network: "192.168.0.0/16", network: "192.168.0.0/16",
netID: "happy", netID: "happy",
peer: "notExistingPeer", peerKey: "notExistingPeer",
description: "super", description: "super",
masquerade: false, masquerade: false,
metric: 9999, metric: 9999,
@ -99,7 +101,7 @@ func TestCreateRoute(t *testing.T) {
inputArgs: input{ inputArgs: input{
network: "192.168.0.0/16", network: "192.168.0.0/16",
netID: "happy", netID: "happy",
peer: "", peerKey: "",
description: "super", description: "super",
masquerade: false, masquerade: false,
metric: 9999, metric: 9999,
@ -124,7 +126,7 @@ func TestCreateRoute(t *testing.T) {
name: "Large Metric Should Fail", name: "Large Metric Should Fail",
inputArgs: input{ inputArgs: input{
network: "192.168.0.0/16", network: "192.168.0.0/16",
peer: peer1Key, peerKey: peer1ID,
netID: "happy", netID: "happy",
description: "super", description: "super",
masquerade: false, masquerade: false,
@ -140,7 +142,7 @@ func TestCreateRoute(t *testing.T) {
inputArgs: input{ inputArgs: input{
network: "192.168.0.0/16", network: "192.168.0.0/16",
netID: "happy", netID: "happy",
peer: peer1Key, peerKey: peer1ID,
description: "super", description: "super",
masquerade: false, masquerade: false,
metric: 0, metric: 0,
@ -154,7 +156,7 @@ func TestCreateRoute(t *testing.T) {
name: "Large NetID Should Fail", name: "Large NetID Should Fail",
inputArgs: input{ inputArgs: input{
network: "192.168.0.0/16", network: "192.168.0.0/16",
peer: peer1Key, peerKey: peer1ID,
netID: "12345678901234567890qwertyuiopqwertyuiop1", netID: "12345678901234567890qwertyuiopqwertyuiop1",
description: "super", description: "super",
masquerade: false, masquerade: false,
@ -170,7 +172,7 @@ func TestCreateRoute(t *testing.T) {
inputArgs: input{ inputArgs: input{
network: "192.168.0.0/16", network: "192.168.0.0/16",
netID: "", netID: "",
peer: peer1Key, peerKey: peer1ID,
description: "", description: "",
masquerade: false, masquerade: false,
metric: 9999, metric: 9999,
@ -185,7 +187,7 @@ func TestCreateRoute(t *testing.T) {
inputArgs: input{ inputArgs: input{
network: "192.168.0.0/16", network: "192.168.0.0/16",
netID: "NewId", netID: "NewId",
peer: peer1Key, peerKey: peer1ID,
description: "", description: "",
masquerade: false, masquerade: false,
metric: 9999, metric: 9999,
@ -200,7 +202,7 @@ func TestCreateRoute(t *testing.T) {
inputArgs: input{ inputArgs: input{
network: "192.168.0.0/16", network: "192.168.0.0/16",
netID: "NewId", netID: "NewId",
peer: peer1Key, peerKey: peer1ID,
description: "", description: "",
masquerade: false, masquerade: false,
metric: 9999, metric: 9999,
@ -215,7 +217,7 @@ func TestCreateRoute(t *testing.T) {
inputArgs: input{ inputArgs: input{
network: "192.168.0.0/16", network: "192.168.0.0/16",
netID: "NewId", netID: "NewId",
peer: peer1Key, peerKey: peer1ID,
description: "", description: "",
masquerade: false, masquerade: false,
metric: 9999, metric: 9999,
@ -238,18 +240,10 @@ func TestCreateRoute(t *testing.T) {
t.Error("failed to init testing account") t.Error("failed to init testing account")
} }
peerIP := "99.99.99.99"
peer := account.Peers[testCase.inputArgs.peer]
if testCase.inputArgs.peer == "" {
peerIP = ""
} else if peer != nil {
peerIP = peer.IP.String()
}
outRoute, err := am.CreateRoute( outRoute, err := am.CreateRoute(
account.Id, account.Id,
testCase.inputArgs.network, testCase.inputArgs.network,
peerIP, testCase.inputArgs.peerKey,
testCase.inputArgs.description, testCase.inputArgs.description,
testCase.inputArgs.netID, testCase.inputArgs.netID,
testCase.inputArgs.masquerade, testCase.inputArgs.masquerade,
@ -278,7 +272,7 @@ func TestCreateRoute(t *testing.T) {
func TestSaveRoute(t *testing.T) { func TestSaveRoute(t *testing.T) {
validPeer := peer2Key validPeer := peer2ID
invalidPeer := "nonExisting" invalidPeer := "nonExisting"
validPrefix := netip.MustParsePrefix("192.168.0.0/24") validPrefix := netip.MustParsePrefix("192.168.0.0/24")
invalidPrefix, _ := netip.ParsePrefix("192.168.0.0/34") invalidPrefix, _ := netip.ParsePrefix("192.168.0.0/34")
@ -306,7 +300,7 @@ func TestSaveRoute(t *testing.T) {
Network: netip.MustParsePrefix("192.168.0.0/16"), Network: netip.MustParsePrefix("192.168.0.0/16"),
NetID: validNetID, NetID: validNetID,
NetworkType: route.IPv4Network, NetworkType: route.IPv4Network,
Peer: peer1Key, Peer: peer1ID,
Description: "super", Description: "super",
Masquerade: false, Masquerade: false,
Metric: 9999, Metric: 9999,
@ -339,7 +333,7 @@ func TestSaveRoute(t *testing.T) {
Network: netip.MustParsePrefix("192.168.0.0/16"), Network: netip.MustParsePrefix("192.168.0.0/16"),
NetID: validNetID, NetID: validNetID,
NetworkType: route.IPv4Network, NetworkType: route.IPv4Network,
Peer: peer1Key, Peer: peer1ID,
Description: "super", Description: "super",
Masquerade: false, Masquerade: false,
Metric: 9999, Metric: 9999,
@ -356,7 +350,7 @@ func TestSaveRoute(t *testing.T) {
Network: netip.MustParsePrefix("192.168.0.0/16"), Network: netip.MustParsePrefix("192.168.0.0/16"),
NetID: validNetID, NetID: validNetID,
NetworkType: route.IPv4Network, NetworkType: route.IPv4Network,
Peer: peer1Key, Peer: peer1ID,
Description: "super", Description: "super",
Masquerade: false, Masquerade: false,
Metric: 9999, Metric: 9999,
@ -373,7 +367,7 @@ func TestSaveRoute(t *testing.T) {
Network: netip.MustParsePrefix("192.168.0.0/16"), Network: netip.MustParsePrefix("192.168.0.0/16"),
NetID: validNetID, NetID: validNetID,
NetworkType: route.IPv4Network, NetworkType: route.IPv4Network,
Peer: peer1Key, Peer: peer1ID,
Description: "super", Description: "super",
Masquerade: false, Masquerade: false,
Metric: 9999, Metric: 9999,
@ -390,7 +384,7 @@ func TestSaveRoute(t *testing.T) {
Network: netip.MustParsePrefix("192.168.0.0/16"), Network: netip.MustParsePrefix("192.168.0.0/16"),
NetID: invalidNetID, NetID: invalidNetID,
NetworkType: route.IPv4Network, NetworkType: route.IPv4Network,
Peer: peer1Key, Peer: peer1ID,
Description: "super", Description: "super",
Masquerade: false, Masquerade: false,
Metric: 9999, Metric: 9999,
@ -407,7 +401,7 @@ func TestSaveRoute(t *testing.T) {
Network: netip.MustParsePrefix("192.168.0.0/16"), Network: netip.MustParsePrefix("192.168.0.0/16"),
NetID: validNetID, NetID: validNetID,
NetworkType: route.IPv4Network, NetworkType: route.IPv4Network,
Peer: peer1Key, Peer: peer1ID,
Description: "super", Description: "super",
Masquerade: false, Masquerade: false,
Metric: 9999, Metric: 9999,
@ -424,7 +418,7 @@ func TestSaveRoute(t *testing.T) {
Network: netip.MustParsePrefix("192.168.0.0/16"), Network: netip.MustParsePrefix("192.168.0.0/16"),
NetID: validNetID, NetID: validNetID,
NetworkType: route.IPv4Network, NetworkType: route.IPv4Network,
Peer: peer1Key, Peer: peer1ID,
Description: "super", Description: "super",
Masquerade: false, Masquerade: false,
Metric: 9999, Metric: 9999,
@ -441,7 +435,7 @@ func TestSaveRoute(t *testing.T) {
Network: netip.MustParsePrefix("192.168.0.0/16"), Network: netip.MustParsePrefix("192.168.0.0/16"),
NetID: validNetID, NetID: validNetID,
NetworkType: route.IPv4Network, NetworkType: route.IPv4Network,
Peer: peer1Key, Peer: peer1ID,
Description: "super", Description: "super",
Masquerade: false, Masquerade: false,
Metric: 9999, Metric: 9999,
@ -458,7 +452,7 @@ func TestSaveRoute(t *testing.T) {
Network: netip.MustParsePrefix("192.168.0.0/16"), Network: netip.MustParsePrefix("192.168.0.0/16"),
NetID: validNetID, NetID: validNetID,
NetworkType: route.IPv4Network, NetworkType: route.IPv4Network,
Peer: peer1Key, Peer: peer1ID,
Description: "super", Description: "super",
Masquerade: false, Masquerade: false,
Metric: 9999, Metric: 9999,
@ -495,7 +489,6 @@ func TestSaveRoute(t *testing.T) {
if testCase.newPeer != nil { if testCase.newPeer != nil {
routeToSave.Peer = *testCase.newPeer routeToSave.Peer = *testCase.newPeer
} }
if testCase.newMetric != nil { if testCase.newMetric != nil {
routeToSave.Metric = *testCase.newMetric routeToSave.Metric = *testCase.newMetric
} }
@ -541,7 +534,7 @@ func TestUpdateRoute(t *testing.T) {
Network: netip.MustParsePrefix("192.168.0.0/16"), Network: netip.MustParsePrefix("192.168.0.0/16"),
NetID: "superRoute", NetID: "superRoute",
NetworkType: route.IPv4Network, NetworkType: route.IPv4Network,
Peer: peer1Key, Peer: peer1ID,
Description: "super", Description: "super",
Masquerade: false, Masquerade: false,
Metric: 9999, Metric: 9999,
@ -563,7 +556,7 @@ func TestUpdateRoute(t *testing.T) {
operations: []RouteUpdateOperation{ operations: []RouteUpdateOperation{
{ {
Type: UpdateRoutePeer, Type: UpdateRoutePeer,
Values: []string{peer2Key}, Values: []string{peer2ID},
}, },
}, },
errFunc: require.NoError, errFunc: require.NoError,
@ -573,7 +566,7 @@ func TestUpdateRoute(t *testing.T) {
Network: netip.MustParsePrefix("192.168.0.0/16"), Network: netip.MustParsePrefix("192.168.0.0/16"),
NetID: "superRoute", NetID: "superRoute",
NetworkType: route.IPv4Network, NetworkType: route.IPv4Network,
Peer: peer2Key, Peer: peer2ID,
Description: "super", Description: "super",
Masquerade: false, Masquerade: false,
Metric: 9999, Metric: 9999,
@ -595,7 +588,7 @@ func TestUpdateRoute(t *testing.T) {
}, },
{ {
Type: UpdateRoutePeer, Type: UpdateRoutePeer,
Values: []string{peer2Key}, Values: []string{peer2ID},
}, },
{ {
Type: UpdateRouteMetric, Type: UpdateRouteMetric,
@ -625,7 +618,7 @@ func TestUpdateRoute(t *testing.T) {
Network: netip.MustParsePrefix("192.168.0.0/24"), Network: netip.MustParsePrefix("192.168.0.0/24"),
NetID: "megaRoute", NetID: "megaRoute",
NetworkType: route.IPv4Network, NetworkType: route.IPv4Network,
Peer: peer2Key, Peer: peer2ID,
Description: "great", Description: "great",
Masquerade: true, Masquerade: true,
Metric: 3030, Metric: 3030,
@ -649,7 +642,7 @@ func TestUpdateRoute(t *testing.T) {
operations: []RouteUpdateOperation{ operations: []RouteUpdateOperation{
{ {
Type: UpdateRoutePeer, Type: UpdateRoutePeer,
Values: []string{peer2Key, peer1Key}, Values: []string{peer2ID, peer1ID},
}, },
}, },
errFunc: require.Error, errFunc: require.Error,
@ -847,7 +840,7 @@ func TestGetNetworkMap_RouteSync(t *testing.T) {
Network: netip.MustParsePrefix("192.168.0.0/16"), Network: netip.MustParsePrefix("192.168.0.0/16"),
NetID: "superNet", NetID: "superNet",
NetworkType: route.IPv4Network, NetworkType: route.IPv4Network,
Peer: peer1Key, Peer: peer1ID,
Description: "super", Description: "super",
Masquerade: false, Masquerade: false,
Metric: 9999, Metric: 9999,
@ -865,39 +858,42 @@ func TestGetNetworkMap_RouteSync(t *testing.T) {
t.Error("failed to init testing account") t.Error("failed to init testing account")
} }
newAccountRoutes, err := am.GetNetworkMap(peer1Key) newAccountRoutes, err := am.GetNetworkMap(peer1ID)
require.NoError(t, err) require.NoError(t, err)
require.Len(t, newAccountRoutes.Routes, 0, "new accounts should have no routes") require.Len(t, newAccountRoutes.Routes, 0, "new accounts should have no routes")
peer := account.Peers[baseRoute.Peer]
createdRoute, err := am.CreateRoute(account.Id, baseRoute.Network.String(), peer.IP.String(), createdRoute, err := am.CreateRoute(account.Id, baseRoute.Network.String(), peer1ID,
baseRoute.Description, baseRoute.NetID, baseRoute.Masquerade, baseRoute.Metric, baseRoute.Groups, false, baseRoute.Description, baseRoute.NetID, baseRoute.Masquerade, baseRoute.Metric, baseRoute.Groups, false,
userID) userID)
require.NoError(t, err) require.NoError(t, err)
noDisabledRoutes, err := am.GetNetworkMap(peer1Key) noDisabledRoutes, err := am.GetNetworkMap(peer1ID)
require.NoError(t, err) require.NoError(t, err)
require.Len(t, noDisabledRoutes.Routes, 0, "no routes for disabled routes") require.Len(t, noDisabledRoutes.Routes, 0, "no routes for disabled routes")
enabledRoute := createdRoute.Copy() enabledRoute := createdRoute.Copy()
enabledRoute.Enabled = true enabledRoute.Enabled = true
// network map contains route.Route objects that have Route.Peer field filled with Peer.Key instead of Peer.ID
expectedRoute := enabledRoute.Copy()
expectedRoute.Peer = peer1Key
err = am.SaveRoute(account.Id, userID, enabledRoute) err = am.SaveRoute(account.Id, userID, enabledRoute)
require.NoError(t, err) require.NoError(t, err)
peer1Routes, err := am.GetNetworkMap(peer1Key) peer1Routes, err := am.GetNetworkMap(peer1ID)
require.NoError(t, err) require.NoError(t, err)
require.Len(t, peer1Routes.Routes, 1, "we should receive one route for peer1") require.Len(t, peer1Routes.Routes, 1, "we should receive one route for peer1")
require.True(t, enabledRoute.IsEqual(peer1Routes.Routes[0]), "received route should be equal") require.True(t, expectedRoute.IsEqual(peer1Routes.Routes[0]), "received route should be equal")
peer2Routes, err := am.GetNetworkMap(peer2Key) peer2Routes, err := am.GetNetworkMap(peer2ID)
require.NoError(t, err) require.NoError(t, err)
require.Len(t, peer2Routes.Routes, 0, "no routes for peers not in the distribution group") require.Len(t, peer2Routes.Routes, 0, "no routes for peers not in the distribution group")
err = am.GroupAddPeer(account.Id, routeGroup1, peer2Key) err = am.GroupAddPeer(account.Id, routeGroup1, peer2ID)
require.NoError(t, err) require.NoError(t, err)
peer2Routes, err = am.GetNetworkMap(peer2Key) peer2Routes, err = am.GetNetworkMap(peer2ID)
require.NoError(t, err) require.NoError(t, err)
require.Len(t, peer2Routes.Routes, 1, "we should receive one route") require.Len(t, peer2Routes.Routes, 1, "we should receive one route")
require.True(t, peer1Routes.Routes[0].IsEqual(peer2Routes.Routes[0]), "routes should be the same for peers in the same group") require.True(t, peer1Routes.Routes[0].IsEqual(peer2Routes.Routes[0]), "routes should be the same for peers in the same group")
@ -905,7 +901,7 @@ func TestGetNetworkMap_RouteSync(t *testing.T) {
newGroup := &Group{ newGroup := &Group{
ID: xid.New().String(), ID: xid.New().String(),
Name: "peer1 group", Name: "peer1 group",
Peers: []string{peer1Key}, Peers: []string{peer1ID},
} }
err = am.SaveGroup(account.Id, userID, newGroup) err = am.SaveGroup(account.Id, userID, newGroup)
require.NoError(t, err) require.NoError(t, err)
@ -926,18 +922,18 @@ func TestGetNetworkMap_RouteSync(t *testing.T) {
err = am.DeleteRule(account.Id, defaultRule.ID, userID) err = am.DeleteRule(account.Id, defaultRule.ID, userID)
require.NoError(t, err) require.NoError(t, err)
peer1GroupRoutes, err := am.GetNetworkMap(peer1Key) peer1GroupRoutes, err := am.GetNetworkMap(peer1ID)
require.NoError(t, err) require.NoError(t, err)
require.Len(t, peer1GroupRoutes.Routes, 1, "we should receive one route for peer1") require.Len(t, peer1GroupRoutes.Routes, 1, "we should receive one route for peer1")
peer2GroupRoutes, err := am.GetNetworkMap(peer2Key) peer2GroupRoutes, err := am.GetNetworkMap(peer2ID)
require.NoError(t, err) require.NoError(t, err)
require.Len(t, peer2GroupRoutes.Routes, 0, "we should not receive routes for peer2") require.Len(t, peer2GroupRoutes.Routes, 0, "we should not receive routes for peer2")
err = am.DeleteRoute(account.Id, enabledRoute.ID, userID) err = am.DeleteRoute(account.Id, enabledRoute.ID, userID)
require.NoError(t, err) require.NoError(t, err)
peer1DeletedRoute, err := am.GetNetworkMap(peer1Key) peer1DeletedRoute, err := am.GetNetworkMap(peer1ID)
require.NoError(t, err) require.NoError(t, err)
require.Len(t, peer1DeletedRoute.Routes, 0, "we should receive one route for peer1") require.Len(t, peer1DeletedRoute.Routes, 0, "we should receive one route for peer1")
@ -964,9 +960,27 @@ func createRouterStore(t *testing.T) (Store, error) {
func initTestRouteAccount(t *testing.T, am *DefaultAccountManager) (*Account, error) { func initTestRouteAccount(t *testing.T, am *DefaultAccountManager) (*Account, error) {
accountID := "testingAcc"
domain := "example.com"
account := newAccountWithId(accountID, userID, domain)
err := am.Store.SaveAccount(account)
if err != nil {
return nil, err
}
ips := account.getTakenIPs()
peer1IP, err := AllocatePeerIP(account.Network.Net, ips)
if err != nil {
return nil, err
}
peer1 := &Peer{ peer1 := &Peer{
Key: peer1Key, IP: peer1IP,
Name: "test-host1@netbird.io", ID: peer1ID,
Key: peer1Key,
Name: "test-host1@netbird.io",
UserID: userID,
Meta: PeerSystemMeta{ Meta: PeerSystemMeta{
Hostname: "test-host1@netbird.io", Hostname: "test-host1@netbird.io",
GoOS: "linux", GoOS: "linux",
@ -978,9 +992,20 @@ func initTestRouteAccount(t *testing.T, am *DefaultAccountManager) (*Account, er
UIVersion: "development", UIVersion: "development",
}, },
} }
account.Peers[peer1.ID] = peer1
ips = account.getTakenIPs()
peer2IP, err := AllocatePeerIP(account.Network.Net, ips)
if err != nil {
return nil, err
}
peer2 := &Peer{ peer2 := &Peer{
Key: peer2Key, IP: peer2IP,
Name: "test-host2@netbird.io", ID: peer2ID,
Key: peer2Key,
Name: "test-host2@netbird.io",
UserID: userID,
Meta: PeerSystemMeta{ Meta: PeerSystemMeta{
Hostname: "test-host2@netbird.io", Hostname: "test-host2@netbird.io",
GoOS: "linux", GoOS: "linux",
@ -992,28 +1017,29 @@ func initTestRouteAccount(t *testing.T, am *DefaultAccountManager) (*Account, er
UIVersion: "development", UIVersion: "development",
}, },
} }
account.Peers[peer2.ID] = peer2
accountID := "testingAcc" err = am.Store.SaveAccount(account)
domain := "example.com" if err != nil {
return nil, err
account := newAccountWithId(accountID, userID, domain) }
err := am.Store.SaveAccount(account) groupAll, err := account.GetGroupAll()
if err != nil {
return nil, err
}
err = am.GroupAddPeer(accountID, groupAll.ID, peer1ID)
if err != nil {
return nil, err
}
err = am.GroupAddPeer(accountID, groupAll.ID, peer2ID)
if err != nil { if err != nil {
return nil, err return nil, err
} }
_, err = am.AddPeer("", userID, peer1)
if err != nil {
return nil, err
}
_, err = am.AddPeer("", userID, peer2)
if err != nil {
return nil, err
}
newGroup := &Group{ newGroup := &Group{
ID: routeGroup1, ID: routeGroup1,
Name: routeGroup1, Name: routeGroup1,
Peers: []string{peer1Key}, Peers: []string{peer1.ID},
} }
err = am.SaveGroup(accountID, userID, newGroup) err = am.SaveGroup(accountID, userID, newGroup)
if err != nil { if err != nil {
@ -1023,7 +1049,7 @@ func initTestRouteAccount(t *testing.T, am *DefaultAccountManager) (*Account, er
newGroup = &Group{ newGroup = &Group{
ID: routeGroup2, ID: routeGroup2,
Name: routeGroup2, Name: routeGroup2,
Peers: []string{peer1Key}, Peers: []string{peer2.ID},
} }
err = am.SaveGroup(accountID, userID, newGroup) err = am.SaveGroup(accountID, userID, newGroup)

View File

@ -5,6 +5,7 @@ type Store interface {
GetAccount(accountID string) (*Account, error) GetAccount(accountID string) (*Account, error)
GetAccountByUser(userID string) (*Account, error) GetAccountByUser(userID string) (*Account, error)
GetAccountByPeerPubKey(peerKey string) (*Account, error) GetAccountByPeerPubKey(peerKey string) (*Account, error)
GetAccountByPeerID(peerID string) (*Account, error)
GetAccountBySetupKey(setupKey string) (*Account, error) //todo use key hash later GetAccountBySetupKey(setupKey string) (*Account, error) //todo use key hash later
GetAccountByPrivateDomain(domain string) (*Account, error) GetAccountByPrivateDomain(domain string) (*Account, error)
SaveAccount(account *Account) error SaveAccount(account *Account) error
@ -14,7 +15,7 @@ type Store interface {
AcquireAccountLock(accountID string) func() AcquireAccountLock(accountID string) func()
// AcquireGlobalLock should attempt to acquire a global lock and return a function that releases the lock // AcquireGlobalLock should attempt to acquire a global lock and return a function that releases the lock
AcquireGlobalLock() func() AcquireGlobalLock() func()
SavePeerStatus(accountID, peerKey string, status PeerStatus) error SavePeerStatus(accountID, peerID string, status PeerStatus) error
// Close should close the store persisting all unsaved data. // Close should close the store persisting all unsaved data.
Close() error Close() error
} }

View File

@ -11,14 +11,14 @@ import (
"time" "time"
) )
//TURNCredentialsManager used to manage TURN credentials // TURNCredentialsManager used to manage TURN credentials
type TURNCredentialsManager interface { type TURNCredentialsManager interface {
GenerateCredentials() TURNCredentials GenerateCredentials() TURNCredentials
SetupRefresh(peerKey string) SetupRefresh(peerKey string)
CancelRefresh(peerKey string) CancelRefresh(peerKey string)
} }
//TimeBasedAuthSecretsManager generates credentials with TTL and using pre-shared secret known to TURN server // TimeBasedAuthSecretsManager generates credentials with TTL and using pre-shared secret known to TURN server
type TimeBasedAuthSecretsManager struct { type TimeBasedAuthSecretsManager struct {
mux sync.Mutex mux sync.Mutex
config *TURNConfig config *TURNConfig
@ -40,7 +40,7 @@ func NewTimeBasedAuthSecretsManager(updateManager *PeersUpdateManager, config *T
} }
} }
//GenerateCredentials generates new time-based secret credentials - basically username is a unix timestamp and password is a HMAC hash of a timestamp with a preshared TURN secret // GenerateCredentials generates new time-based secret credentials - basically username is a unix timestamp and password is a HMAC hash of a timestamp with a preshared TURN secret
func (m *TimeBasedAuthSecretsManager) GenerateCredentials() TURNCredentials { func (m *TimeBasedAuthSecretsManager) GenerateCredentials() TURNCredentials {
mac := hmac.New(sha1.New, []byte(m.config.Secret)) mac := hmac.New(sha1.New, []byte(m.config.Secret))
@ -70,22 +70,22 @@ func (m *TimeBasedAuthSecretsManager) cancel(peerKey string) {
} }
} }
//CancelRefresh cancels scheduled peer credentials refresh // CancelRefresh cancels scheduled peer credentials refresh
func (m *TimeBasedAuthSecretsManager) CancelRefresh(peerKey string) { func (m *TimeBasedAuthSecretsManager) CancelRefresh(peerKey string) {
m.mux.Lock() m.mux.Lock()
defer m.mux.Unlock() defer m.mux.Unlock()
m.cancel(peerKey) m.cancel(peerKey)
} }
//SetupRefresh starts peer credentials refresh. Since credentials are expiring (TTL) it is necessary to always generate them and send to the peer. // SetupRefresh starts peer credentials refresh. Since credentials are expiring (TTL) it is necessary to always generate them and send to the peer.
//A goroutine is created and put into TimeBasedAuthSecretsManager.cancelMap. This routine should be cancelled if peer is gone. // A goroutine is created and put into TimeBasedAuthSecretsManager.cancelMap. This routine should be cancelled if peer is gone.
func (m *TimeBasedAuthSecretsManager) SetupRefresh(peerKey string) { func (m *TimeBasedAuthSecretsManager) SetupRefresh(peerID string) {
m.mux.Lock() m.mux.Lock()
defer m.mux.Unlock() defer m.mux.Unlock()
m.cancel(peerKey) m.cancel(peerID)
cancel := make(chan struct{}, 1) cancel := make(chan struct{}, 1)
m.cancelMap[peerKey] = cancel m.cancelMap[peerID] = cancel
log.Debugf("starting turn refresh for %s", peerKey) log.Debugf("starting turn refresh for %s", peerID)
go func() { go func() {
//we don't want to regenerate credentials right on expiration, so we do it slightly before (at 3/4 of TTL) //we don't want to regenerate credentials right on expiration, so we do it slightly before (at 3/4 of TTL)
@ -94,7 +94,7 @@ func (m *TimeBasedAuthSecretsManager) SetupRefresh(peerKey string) {
for { for {
select { select {
case <-cancel: case <-cancel:
log.Debugf("stopping turn refresh for %s", peerKey) log.Debugf("stopping turn refresh for %s", peerID)
return return
case <-ticker.C: case <-ticker.C:
c := m.GenerateCredentials() c := m.GenerateCredentials()
@ -115,9 +115,9 @@ func (m *TimeBasedAuthSecretsManager) SetupRefresh(peerKey string) {
Turns: turns, Turns: turns,
}, },
} }
err := m.updateManager.SendUpdate(peerKey, &UpdateMessage{Update: update}) err := m.updateManager.SendUpdate(peerID, &UpdateMessage{Update: update})
if err != nil { if err != nil {
log.Errorf("error while sending TURN update to peer %s %v", peerKey, err) log.Errorf("error while sending TURN update to peer %s %v", peerID, err)
// todo maybe continue trying? // todo maybe continue trying?
} }
} }

View File

@ -13,6 +13,7 @@ type UpdateMessage struct {
} }
type PeersUpdateManager struct { type PeersUpdateManager struct {
// peerChannels is an update channel indexed by Peer.ID
peerChannels map[string]chan *UpdateMessage peerChannels map[string]chan *UpdateMessage
channelsMux *sync.Mutex channelsMux *sync.Mutex
} }
@ -26,49 +27,49 @@ func NewPeersUpdateManager() *PeersUpdateManager {
} }
// SendUpdate sends update message to the peer's channel // SendUpdate sends update message to the peer's channel
func (p *PeersUpdateManager) SendUpdate(peer string, update *UpdateMessage) error { func (p *PeersUpdateManager) SendUpdate(peerID string, update *UpdateMessage) error {
p.channelsMux.Lock() p.channelsMux.Lock()
defer p.channelsMux.Unlock() defer p.channelsMux.Unlock()
if channel, ok := p.peerChannels[peer]; ok { if channel, ok := p.peerChannels[peerID]; ok {
select { select {
case channel <- update: case channel <- update:
log.Infof("update was sent to channel for peer %s", peer) log.Infof("update was sent to channel for peer %s", peerID)
default: default:
log.Warnf("channel for peer %s is %d full", peer, len(channel)) log.Warnf("channel for peer %s is %d full", peerID, len(channel))
} }
return nil return nil
} }
log.Debugf("peer %s has no channel", peer) log.Debugf("peer %s has no channel", peerID)
return nil return nil
} }
// CreateChannel creates a go channel for a given peer used to deliver updates relevant to the peer. // CreateChannel creates a go channel for a given peer used to deliver updates relevant to the peer.
func (p *PeersUpdateManager) CreateChannel(peerKey string) chan *UpdateMessage { func (p *PeersUpdateManager) CreateChannel(peerID string) chan *UpdateMessage {
p.channelsMux.Lock() p.channelsMux.Lock()
defer p.channelsMux.Unlock() defer p.channelsMux.Unlock()
if channel, ok := p.peerChannels[peerKey]; ok { if channel, ok := p.peerChannels[peerID]; ok {
delete(p.peerChannels, peerKey) delete(p.peerChannels, peerID)
close(channel) close(channel)
} }
//mbragin: todo shouldn't it be more? or configurable? //mbragin: todo shouldn't it be more? or configurable?
channel := make(chan *UpdateMessage, channelBufferSize) channel := make(chan *UpdateMessage, channelBufferSize)
p.peerChannels[peerKey] = channel p.peerChannels[peerID] = channel
log.Debugf("opened updates channel for a peer %s", peerKey) log.Debugf("opened updates channel for a peer %s", peerID)
return channel return channel
} }
// CloseChannel closes updates channel of a given peer // CloseChannel closes updates channel of a given peer
func (p *PeersUpdateManager) CloseChannel(peerKey string) { func (p *PeersUpdateManager) CloseChannel(peerID string) {
p.channelsMux.Lock() p.channelsMux.Lock()
defer p.channelsMux.Unlock() defer p.channelsMux.Unlock()
if channel, ok := p.peerChannels[peerKey]; ok { if channel, ok := p.peerChannels[peerID]; ok {
delete(p.peerChannels, peerKey) delete(p.peerChannels, peerID)
close(channel) close(channel)
} }
log.Debugf("closed updates channel of a peer %s", peerKey) log.Debugf("closed updates channel of a peer %s", peerID)
} }
// GetAllConnectedPeers returns a copy of the connected peers map // GetAllConnectedPeers returns a copy of the connected peers map
@ -76,8 +77,8 @@ func (p *PeersUpdateManager) GetAllConnectedPeers() map[string]struct{} {
p.channelsMux.Lock() p.channelsMux.Lock()
defer p.channelsMux.Unlock() defer p.channelsMux.Unlock()
m := make(map[string]struct{}) m := make(map[string]struct{})
for key := range p.peerChannels { for ID := range p.peerChannels {
m[key] = struct{}{} m[ID] = struct{}{}
} }
return m return m
} }

View File

@ -78,7 +78,7 @@ type Route struct {
// EventMeta returns activity event meta related to the route // EventMeta returns activity event meta related to the route
func (r *Route) EventMeta() map[string]any { func (r *Route) EventMeta() map[string]any {
return map[string]any{"name": r.NetID, "network_range": r.Network.String()} return map[string]any{"name": r.NetID, "network_range": r.Network.String(), "peer_id": r.Peer}
} }
// Copy copies a route object // Copy copies a route object