Parcourir la source

Merge pull request #3358 from gravitl/master

Master
Abhishek K il y a 6 mois
Parent
commit
1ad8b8b7b4
11 fichiers modifiés avec 293 ajouts et 71 suppressions
  1. 1 1
      controllers/network.go
  2. 52 12
      logic/acls.go
  3. 24 14
      logic/extpeers.go
  4. 122 2
      logic/networks.go
  5. 74 41
      logic/nodes.go
  6. 4 0
      models/extclient.go
  7. 2 0
      models/node.go
  8. 6 0
      pro/auth/auth.go
  9. 4 0
      pro/auth/azure-ad.go
  10. 3 0
      pro/controllers/users.go
  11. 1 1
      pro/email/email.go

+ 1 - 1
controllers/network.go

@@ -559,7 +559,7 @@ func createNetwork(w http.ResponseWriter, r *http.Request) {
 	logic.CreateDefaultNetworkRolesAndGroups(models.NetworkID(network.NetID))
 	logic.CreateDefaultAclNetworkPolicies(models.NetworkID(network.NetID))
 	logic.CreateDefaultTags(models.NetworkID(network.NetID))
-	//add new network to allocated ip map
+
 	go logic.AddNetworkToAllocatedIpMap(network.NetID)
 
 	go func() {

+ 52 - 12
logic/acls.go

@@ -17,7 +17,6 @@ import (
 var (
 	aclCacheMutex = &sync.RWMutex{}
 	aclCacheMap   = make(map[string]models.Acl)
-	aclTagsMutex  = &sync.RWMutex{}
 )
 
 func MigrateAclPolicies() {
@@ -577,10 +576,22 @@ func IsPeerAllowed(node, peer models.Node, checkDefaultPolicy bool) bool {
 	if peer.IsStatic {
 		peer = peer.StaticNode.ConvertToStaticNode()
 	}
-	aclTagsMutex.RLock()
-	peerTags := maps.Clone(peer.Tags)
-	nodeTags := maps.Clone(node.Tags)
-	aclTagsMutex.RUnlock()
+	var nodeTags, peerTags map[models.TagID]struct{}
+	if node.Mutex != nil {
+		node.Mutex.Lock()
+		nodeTags = maps.Clone(node.Tags)
+		node.Mutex.Unlock()
+	} else {
+		nodeTags = node.Tags
+	}
+	if peer.Mutex != nil {
+		peer.Mutex.Lock()
+		peerTags = maps.Clone(peer.Tags)
+		peer.Mutex.Unlock()
+	} else {
+		peerTags = peer.Tags
+	}
+
 	if checkDefaultPolicy {
 		// check default policy if all allowed return true
 		defaultPolicy, err := GetDefaultPolicy(models.NetworkID(node.Network), models.DevicePolicy)
@@ -663,10 +674,21 @@ func IsNodeAllowedToCommunicate(node, peer models.Node, checkDefaultPolicy bool)
 	if peer.IsStatic {
 		peer = peer.StaticNode.ConvertToStaticNode()
 	}
-	aclTagsMutex.RLock()
-	peerTags := maps.Clone(peer.Tags)
-	nodeTags := maps.Clone(node.Tags)
-	aclTagsMutex.RUnlock()
+	var nodeTags, peerTags map[models.TagID]struct{}
+	if node.Mutex != nil {
+		node.Mutex.Lock()
+		nodeTags = maps.Clone(node.Tags)
+		node.Mutex.Unlock()
+	} else {
+		nodeTags = node.Tags
+	}
+	if peer.Mutex != nil {
+		peer.Mutex.Lock()
+		peerTags = maps.Clone(peer.Tags)
+		peer.Mutex.Unlock()
+	} else {
+		peerTags = peer.Tags
+	}
 	if checkDefaultPolicy {
 		// check default policy if all allowed return true
 		defaultPolicy, err := GetDefaultPolicy(models.NetworkID(node.Network), models.DevicePolicy)
@@ -864,7 +886,15 @@ func getUserAclRulesForNode(targetnode *models.Node,
 	userGrpMap := GetUserGrpMap()
 	allowedUsers := make(map[string][]models.Acl)
 	acls := listUserPolicies(models.NetworkID(targetnode.Network))
-	for nodeTag := range targetnode.Tags {
+	var targetNodeTags = make(map[models.TagID]struct{})
+	if targetnode.Mutex != nil {
+		targetnode.Mutex.Lock()
+		targetNodeTags = maps.Clone(targetnode.Tags)
+		targetnode.Mutex.Unlock()
+	} else {
+		targetNodeTags = maps.Clone(targetnode.Tags)
+	}
+	for nodeTag := range targetNodeTags {
 		for _, acl := range acls {
 			if !acl.Enabled {
 				continue
@@ -888,6 +918,7 @@ func getUserAclRulesForNode(targetnode *models.Node,
 			}
 		}
 	}
+
 	for _, userNode := range userNodes {
 		if !userNode.StaticNode.Enabled {
 			continue
@@ -944,8 +975,17 @@ func GetAclRulesForNode(targetnode *models.Node) (rules map[string]models.AclRul
 	}
 
 	acls := listDevicePolicies(models.NetworkID(targetnode.Network))
-	targetnode.Tags["*"] = struct{}{}
-	for nodeTag := range targetnode.Tags {
+
+	var targetNodeTags = make(map[models.TagID]struct{})
+	if targetnode.Mutex != nil {
+		targetnode.Mutex.Lock()
+		targetNodeTags = maps.Clone(targetnode.Tags)
+		targetnode.Mutex.Unlock()
+	} else {
+		targetNodeTags = maps.Clone(targetnode.Tags)
+	}
+	targetNodeTags["*"] = struct{}{}
+	for nodeTag := range targetNodeTags {
 		for _, acl := range acls {
 			if !acl.Enabled {
 				continue

+ 24 - 14
logic/extpeers.go

@@ -28,6 +28,9 @@ var (
 func getAllExtClientsFromCache() (extClients []models.ExtClient) {
 	extClientCacheMutex.RLock()
 	for _, extclient := range extClientCacheMap {
+		if extclient.Mutex == nil {
+			extclient.Mutex = &sync.Mutex{}
+		}
 		extClients = append(extClients, extclient)
 	}
 	extClientCacheMutex.RUnlock()
@@ -43,12 +46,18 @@ func deleteExtClientFromCache(key string) {
 func getExtClientFromCache(key string) (extclient models.ExtClient, ok bool) {
 	extClientCacheMutex.RLock()
 	extclient, ok = extClientCacheMap[key]
+	if extclient.Mutex == nil {
+		extclient.Mutex = &sync.Mutex{}
+	}
 	extClientCacheMutex.RUnlock()
 	return
 }
 
 func storeExtClientInCache(key string, extclient models.ExtClient) {
 	extClientCacheMutex.Lock()
+	if extclient.Mutex == nil {
+		extclient.Mutex = &sync.Mutex{}
+	}
 	extClientCacheMap[key] = extclient
 	extClientCacheMutex.Unlock()
 }
@@ -96,14 +105,14 @@ func DeleteExtClient(network string, clientid string) error {
 	if err != nil {
 		return err
 	}
-	//recycle ip address
-	if extClient.Address != "" {
-		RemoveIpFromAllocatedIpMap(network, extClient.Address)
-	}
-	if extClient.Address6 != "" {
-		RemoveIpFromAllocatedIpMap(network, extClient.Address6)
-	}
 	if servercfg.CacheEnabled() {
+		// recycle ip address
+		if extClient.Address != "" {
+			RemoveIpFromAllocatedIpMap(network, extClient.Address)
+		}
+		if extClient.Address6 != "" {
+			RemoveIpFromAllocatedIpMap(network, extClient.Address6)
+		}
 		deleteExtClientFromCache(key)
 	}
 	return nil
@@ -333,15 +342,16 @@ func SaveExtClient(extclient *models.ExtClient) error {
 	}
 	if servercfg.CacheEnabled() {
 		storeExtClientInCache(key, *extclient)
-	}
-	if _, ok := allocatedIpMap[extclient.Network]; ok {
-		if extclient.Address != "" {
-			AddIpToAllocatedIpMap(extclient.Network, net.ParseIP(extclient.Address))
-		}
-		if extclient.Address6 != "" {
-			AddIpToAllocatedIpMap(extclient.Network, net.ParseIP(extclient.Address6))
+		if _, ok := allocatedIpMap[extclient.Network]; ok {
+			if extclient.Address != "" {
+				AddIpToAllocatedIpMap(extclient.Network, net.ParseIP(extclient.Address))
+			}
+			if extclient.Address6 != "" {
+				AddIpToAllocatedIpMap(extclient.Network, net.ParseIP(extclient.Address6))
+			}
 		}
 	}
+
 	return SetNetworkNodesLastModified(extclient.Network)
 }
 

+ 122 - 2
logic/networks.go

@@ -30,6 +30,9 @@ var (
 
 // SetAllocatedIpMap - set allocated ip map for networks
 func SetAllocatedIpMap() error {
+	if !servercfg.CacheEnabled() {
+		return nil
+	}
 	logger.Log(0, "start setting up allocated ip map")
 	if allocatedIpMap == nil {
 		allocatedIpMap = map[string]map[string]net.IP{}
@@ -84,16 +87,25 @@ func SetAllocatedIpMap() error {
 
 // ClearAllocatedIpMap - set allocatedIpMap to nil
 func ClearAllocatedIpMap() {
+	if !servercfg.CacheEnabled() {
+		return
+	}
 	allocatedIpMap = nil
 }
 
 func AddIpToAllocatedIpMap(networkName string, ip net.IP) {
+	if !servercfg.CacheEnabled() {
+		return
+	}
 	networkCacheMutex.Lock()
 	allocatedIpMap[networkName][ip.String()] = ip
 	networkCacheMutex.Unlock()
 }
 
 func RemoveIpFromAllocatedIpMap(networkName string, ip string) {
+	if !servercfg.CacheEnabled() {
+		return
+	}
 	networkCacheMutex.Lock()
 	delete(allocatedIpMap[networkName], ip)
 	networkCacheMutex.Unlock()
@@ -101,6 +113,10 @@ func RemoveIpFromAllocatedIpMap(networkName string, ip string) {
 
 // AddNetworkToAllocatedIpMap - add network to allocated ip map when network is added
 func AddNetworkToAllocatedIpMap(networkName string) {
+	//add new network to allocated ip map
+	if !servercfg.CacheEnabled() {
+		return
+	}
 	networkCacheMutex.Lock()
 	allocatedIpMap[networkName] = make(map[string]net.IP)
 	networkCacheMutex.Unlock()
@@ -108,6 +124,9 @@ func AddNetworkToAllocatedIpMap(networkName string) {
 
 // RemoveNetworkFromAllocatedIpMap - remove network from allocated ip map when network is deleted
 func RemoveNetworkFromAllocatedIpMap(networkName string) {
+	if !servercfg.CacheEnabled() {
+		return
+	}
 	networkCacheMutex.Lock()
 	delete(allocatedIpMap, networkName)
 	networkCacheMutex.Unlock()
@@ -354,7 +373,7 @@ func GetNetworkSettings(networkname string) (models.Network, error) {
 }
 
 // UniqueAddress - get a unique ipv4 address
-func UniqueAddress(networkName string, reverse bool) (net.IP, error) {
+func UniqueAddressCache(networkName string, reverse bool) (net.IP, error) {
 	add := net.IP{}
 	var network models.Network
 	network, err := GetParentNetwork(networkName)
@@ -396,6 +415,49 @@ func UniqueAddress(networkName string, reverse bool) (net.IP, error) {
 	return add, errors.New("ERROR: No unique addresses available. Check network subnet")
 }
 
+// UniqueAddress - get a unique ipv4 address
+func UniqueAddressDB(networkName string, reverse bool) (net.IP, error) {
+	add := net.IP{}
+	var network models.Network
+	network, err := GetParentNetwork(networkName)
+	if err != nil {
+		logger.Log(0, "UniqueAddressServer encountered  an error")
+		return add, err
+	}
+
+	if network.IsIPv4 == "no" {
+		return add, fmt.Errorf("IPv4 not active on network " + networkName)
+	}
+	//ensure AddressRange is valid
+	if _, _, err := net.ParseCIDR(network.AddressRange); err != nil {
+		logger.Log(0, "UniqueAddress encountered  an error")
+		return add, err
+	}
+	net4 := iplib.Net4FromStr(network.AddressRange)
+	newAddrs := net4.FirstAddress()
+
+	if reverse {
+		newAddrs = net4.LastAddress()
+	}
+
+	for {
+		if IsIPUnique(networkName, newAddrs.String(), database.NODES_TABLE_NAME, false) &&
+			IsIPUnique(networkName, newAddrs.String(), database.EXT_CLIENT_TABLE_NAME, false) {
+			return newAddrs, nil
+		}
+		if reverse {
+			newAddrs, err = net4.PreviousIP(newAddrs)
+		} else {
+			newAddrs, err = net4.NextIP(newAddrs)
+		}
+		if err != nil {
+			break
+		}
+	}
+
+	return add, errors.New("ERROR: No unique addresses available. Check network subnet")
+}
+
 // IsIPUnique - checks if an IP is unique
 func IsIPUnique(network string, ip string, tableName string, isIpv6 bool) bool {
 
@@ -439,9 +501,67 @@ func IsIPUnique(network string, ip string, tableName string, isIpv6 bool) bool {
 
 	return isunique
 }
+func UniqueAddress(networkName string, reverse bool) (net.IP, error) {
+	if servercfg.CacheEnabled() {
+		return UniqueAddressCache(networkName, reverse)
+	}
+	return UniqueAddressDB(networkName, reverse)
+}
 
-// UniqueAddress6 - see if ipv6 address is unique
 func UniqueAddress6(networkName string, reverse bool) (net.IP, error) {
+	if servercfg.CacheEnabled() {
+		return UniqueAddress6Cache(networkName, reverse)
+	}
+	return UniqueAddress6DB(networkName, reverse)
+}
+
+// UniqueAddress6DB - see if ipv6 address is unique
+func UniqueAddress6DB(networkName string, reverse bool) (net.IP, error) {
+	add := net.IP{}
+	var network models.Network
+	network, err := GetParentNetwork(networkName)
+	if err != nil {
+		fmt.Println("Network Not Found")
+		return add, err
+	}
+	if network.IsIPv6 == "no" {
+		return add, fmt.Errorf("IPv6 not active on network " + networkName)
+	}
+
+	//ensure AddressRange is valid
+	if _, _, err := net.ParseCIDR(network.AddressRange6); err != nil {
+		return add, err
+	}
+	net6 := iplib.Net6FromStr(network.AddressRange6)
+
+	newAddrs, err := net6.NextIP(net6.FirstAddress())
+	if reverse {
+		newAddrs, err = net6.PreviousIP(net6.LastAddress())
+	}
+	if err != nil {
+		return add, err
+	}
+
+	for {
+		if IsIPUnique(networkName, newAddrs.String(), database.NODES_TABLE_NAME, true) &&
+			IsIPUnique(networkName, newAddrs.String(), database.EXT_CLIENT_TABLE_NAME, true) {
+			return newAddrs, nil
+		}
+		if reverse {
+			newAddrs, err = net6.PreviousIP(newAddrs)
+		} else {
+			newAddrs, err = net6.NextIP(newAddrs)
+		}
+		if err != nil {
+			break
+		}
+	}
+
+	return add, errors.New("ERROR: No unique IPv6 addresses available. Check network subnet")
+}
+
+// UniqueAddress6Cache - see if ipv6 address is unique using cache
+func UniqueAddress6Cache(networkName string, reverse bool) (net.IP, error) {
 	add := net.IP{}
 	var network models.Network
 	network, err := GetParentNetwork(networkName)

+ 74 - 41
logic/nodes.go

@@ -35,12 +35,20 @@ var (
 func getNodeFromCache(nodeID string) (node models.Node, ok bool) {
 	nodeCacheMutex.RLock()
 	node, ok = nodesCacheMap[nodeID]
+	if node.Mutex == nil {
+		node.Mutex = &sync.Mutex{}
+	}
 	nodeCacheMutex.RUnlock()
 	return
 }
 func getNodesFromCache() (nodes []models.Node) {
 	nodeCacheMutex.RLock()
-	nodes = slices.Collect(maps.Values(nodesCacheMap))
+	for _, node := range nodesCacheMap {
+		if node.Mutex == nil {
+			node.Mutex = &sync.Mutex{}
+		}
+		nodes = append(nodes, node)
+	}
 	nodeCacheMutex.RUnlock()
 	return
 }
@@ -356,12 +364,15 @@ func DeleteNodeByID(node *models.Node) error {
 		logger.Log(1, "unable to remove metrics from DB for node", node.ID.String(), err.Error())
 	}
 	//recycle ip address
-	if node.Address.IP != nil {
-		RemoveIpFromAllocatedIpMap(node.Network, node.Address.IP.String())
-	}
-	if node.Address6.IP != nil {
-		RemoveIpFromAllocatedIpMap(node.Network, node.Address6.IP.String())
+	if servercfg.CacheEnabled() {
+		if node.Address.IP != nil {
+			RemoveIpFromAllocatedIpMap(node.Network, node.Address.IP.String())
+		}
+		if node.Address6.IP != nil {
+			RemoveIpFromAllocatedIpMap(node.Network, node.Address6.IP.String())
+		}
 	}
+
 	return nil
 }
 
@@ -423,6 +434,9 @@ func GetAllNodes() ([]models.Node, error) {
 		}
 		// add node to our array
 		nodes = append(nodes, node)
+		if node.Mutex == nil {
+			node.Mutex = &sync.Mutex{}
+		}
 		nodesMap[node.ID.String()] = node
 	}
 
@@ -698,15 +712,16 @@ func createNode(node *models.Node) error {
 	if servercfg.CacheEnabled() {
 		storeNodeInCache(*node)
 		storeNodeInNetworkCache(*node, node.Network)
-	}
-	if _, ok := allocatedIpMap[node.Network]; ok {
-		if node.Address.IP != nil {
-			AddIpToAllocatedIpMap(node.Network, node.Address.IP)
-		}
-		if node.Address6.IP != nil {
-			AddIpToAllocatedIpMap(node.Network, node.Address6.IP)
+		if _, ok := allocatedIpMap[node.Network]; ok {
+			if node.Address.IP != nil {
+				AddIpToAllocatedIpMap(node.Network, node.Address.IP)
+			}
+			if node.Address6.IP != nil {
+				AddIpToAllocatedIpMap(node.Network, node.Address6.IP)
+			}
 		}
 	}
+
 	_, err = nodeacls.CreateNodeACL(nodeacls.NetworkID(node.Network), nodeacls.NodeID(node.ID.String()), defaultACLVal)
 	if err != nil {
 		logger.Log(1, "failed to create node ACL for node,", node.ID.String(), "err:", err.Error())
@@ -752,16 +767,14 @@ func ValidateParams(nodeid, netid string) (models.Node, error) {
 func ValidateNodeIp(currentNode *models.Node, newNode *models.ApiNode) error {
 
 	if currentNode.Address.IP != nil && currentNode.Address.String() != newNode.Address {
-		newIp, _, _ := net.ParseCIDR(newNode.Address)
-		ipAllocated := allocatedIpMap[currentNode.Network]
-		if _, ok := ipAllocated[newIp.String()]; ok {
+		if !IsIPUnique(newNode.Network, newNode.Address, database.NODES_TABLE_NAME, false) ||
+			!IsIPUnique(newNode.Network, newNode.Address, database.EXT_CLIENT_TABLE_NAME, false) {
 			return errors.New("ip specified is already allocated:  " + newNode.Address)
 		}
 	}
 	if currentNode.Address6.IP != nil && currentNode.Address6.String() != newNode.Address6 {
-		newIp, _, _ := net.ParseCIDR(newNode.Address6)
-		ipAllocated := allocatedIpMap[currentNode.Network]
-		if _, ok := ipAllocated[newIp.String()]; ok {
+		if !IsIPUnique(newNode.Network, newNode.Address6, database.NODES_TABLE_NAME, false) ||
+			!IsIPUnique(newNode.Network, newNode.Address6, database.EXT_CLIENT_TABLE_NAME, false) {
 			return errors.New("ip specified is already allocated:  " + newNode.Address6)
 		}
 	}
@@ -824,9 +837,16 @@ func GetTagMapWithNodes() (tagNodesMap map[models.TagID][]models.Node) {
 		if nodeI.Tags == nil {
 			continue
 		}
+		if nodeI.Mutex != nil {
+			nodeI.Mutex.Lock()
+		}
 		for nodeTagID := range nodeI.Tags {
 			tagNodesMap[nodeTagID] = append(tagNodesMap[nodeTagID], nodeI)
 		}
+		if nodeI.Mutex != nil {
+			nodeI.Mutex.Unlock()
+		}
+
 	}
 	return
 }
@@ -838,9 +858,15 @@ func GetTagMapWithNodesByNetwork(netID models.NetworkID, withStaticNodes bool) (
 		if nodeI.Tags == nil {
 			continue
 		}
+		if nodeI.Mutex != nil {
+			nodeI.Mutex.Lock()
+		}
 		for nodeTagID := range nodeI.Tags {
 			tagNodesMap[nodeTagID] = append(tagNodesMap[nodeTagID], nodeI)
 		}
+		if nodeI.Mutex != nil {
+			nodeI.Mutex.Unlock()
+		}
 	}
 	tagNodesMap["*"] = nodes
 	if !withStaticNodes {
@@ -859,17 +885,16 @@ func AddTagMapWithStaticNodes(netID models.NetworkID,
 		if extclient.Tags == nil || extclient.RemoteAccessClientID != "" {
 			continue
 		}
+		if extclient.Mutex != nil {
+			extclient.Mutex.Lock()
+		}
 		for tagID := range extclient.Tags {
-			tagNodesMap[tagID] = append(tagNodesMap[tagID], models.Node{
-				IsStatic:   true,
-				StaticNode: extclient,
-			})
-			tagNodesMap["*"] = append(tagNodesMap["*"], models.Node{
-				IsStatic:   true,
-				StaticNode: extclient,
-			})
+			tagNodesMap[tagID] = append(tagNodesMap[tagID], extclient.ConvertToStaticNode())
+			tagNodesMap["*"] = append(tagNodesMap["*"], extclient.ConvertToStaticNode())
+		}
+		if extclient.Mutex != nil {
+			extclient.Mutex.Unlock()
 		}
-
 	}
 	return tagNodesMap
 }
@@ -884,11 +909,14 @@ func AddTagMapWithStaticNodesWithUsers(netID models.NetworkID,
 		if extclient.Tags == nil {
 			continue
 		}
+		if extclient.Mutex != nil {
+			extclient.Mutex.Lock()
+		}
 		for tagID := range extclient.Tags {
-			tagNodesMap[tagID] = append(tagNodesMap[tagID], models.Node{
-				IsStatic:   true,
-				StaticNode: extclient,
-			})
+			tagNodesMap[tagID] = append(tagNodesMap[tagID], extclient.ConvertToStaticNode())
+		}
+		if extclient.Mutex != nil {
+			extclient.Mutex.Unlock()
 		}
 
 	}
@@ -906,9 +934,15 @@ func GetNodesWithTag(tagID models.TagID) map[string]models.Node {
 		if nodeI.Tags == nil {
 			continue
 		}
+		if nodeI.Mutex != nil {
+			nodeI.Mutex.Lock()
+		}
 		if _, ok := nodeI.Tags[tagID]; ok {
 			nMap[nodeI.ID.String()] = nodeI
 		}
+		if nodeI.Mutex != nil {
+			nodeI.Mutex.Unlock()
+		}
 	}
 	return AddStaticNodesWithTag(tag, nMap)
 }
@@ -922,13 +956,15 @@ func AddStaticNodesWithTag(tag models.Tag, nMap map[string]models.Node) map[stri
 		if extclient.RemoteAccessClientID != "" {
 			continue
 		}
+		if extclient.Mutex != nil {
+			extclient.Mutex.Lock()
+		}
 		if _, ok := extclient.Tags[tag.ID]; ok {
-			nMap[extclient.ClientID] = models.Node{
-				IsStatic:   true,
-				StaticNode: extclient,
-			}
+			nMap[extclient.ClientID] = extclient.ConvertToStaticNode()
+		}
+		if extclient.Mutex != nil {
+			extclient.Mutex.Unlock()
 		}
-
 	}
 	return nMap
 }
@@ -944,10 +980,7 @@ func GetStaticNodeWithTag(tagID models.TagID) map[string]models.Node {
 		return nMap
 	}
 	for _, extclient := range extclients {
-		nMap[extclient.ClientID] = models.Node{
-			IsStatic:   true,
-			StaticNode: extclient,
-		}
+		nMap[extclient.ClientID] = extclient.ConvertToStaticNode()
 	}
 	return nMap
 }

+ 4 - 0
models/extclient.go

@@ -1,5 +1,7 @@
 package models
 
+import "sync"
+
 // ExtClient - struct for external clients
 type ExtClient struct {
 	ClientID               string              `json:"clientid" bson:"clientid"`
@@ -25,6 +27,7 @@ type ExtClient struct {
 	DeviceName             string              `json:"device_name"`
 	PublicEndpoint         string              `json:"public_endpoint"`
 	Country                string              `json:"country"`
+	Mutex                  *sync.Mutex         `json:"-"`
 }
 
 // CustomExtClient - struct for CustomExtClient params
@@ -55,5 +58,6 @@ func (ext *ExtClient) ConvertToStaticNode() Node {
 		Tags:       ext.Tags,
 		IsStatic:   true,
 		StaticNode: *ext,
+		Mutex:      ext.Mutex,
 	}
 }

+ 2 - 0
models/node.go

@@ -5,6 +5,7 @@ import (
 	"math/rand"
 	"net"
 	"strings"
+	"sync"
 	"time"
 
 	"github.com/google/uuid"
@@ -119,6 +120,7 @@ type Node struct {
 	IsUserNode        bool                `json:"is_user_node"`
 	StaticNode        ExtClient           `json:"static_node"`
 	Status            NodeStatus          `json:"node_status"`
+	Mutex             *sync.Mutex         `json:"-"`
 }
 
 // LegacyNode - legacy struct for node model

+ 6 - 0
pro/auth/auth.go

@@ -245,6 +245,12 @@ func getUserEmailFromClaims(token string) string {
 		return ""
 	}
 	claims, _ := accessToken.Claims.(jwt.MapClaims)
+	if claims == nil {
+		return ""
+	}
+	if claims["email"] == nil {
+		return ""
+	}
 	return claims["email"].(string)
 }
 

+ 4 - 0
pro/auth/azure-ad.go

@@ -199,6 +199,10 @@ func getAzureUserInfo(state string, code string) (*OAuthUser, error) {
 	if userInfo.Email == "" {
 		userInfo.Email = getUserEmailFromClaims(token.AccessToken)
 	}
+	if userInfo.Email == "" && userInfo.UserPrincipalName != "" {
+		userInfo.Email = userInfo.UserPrincipalName
+
+	}
 	if userInfo.Email == "" {
 		err = errors.New("failed to fetch user email from SSO state")
 		return userInfo, err

+ 3 - 0
pro/controllers/users.go

@@ -1108,6 +1108,9 @@ func getUserRemoteAccessGwsV1(w http.ResponseWriter, r *http.Request) {
 			}
 
 			gws := userGws[node.Network]
+			if extClient.DNS == "" {
+				extClient.DNS = node.IngressDNS
+			}
 			extClient.AllowedIPs = logic.GetExtclientAllowedIPs(extClient)
 			gws = append(gws, models.UserRemoteGws{
 				GwID:              node.ID.String(),

+ 1 - 1
pro/email/email.go

@@ -55,6 +55,6 @@ func GetClient() (e EmailSender) {
 }
 
 func IsValid(email string) bool {
-	emailRegex := regexp.MustCompile(`^[a-z0-9._%+\-]+@[a-z0-9.\-]+\.[a-z]{2,4}$`)
+	emailRegex := regexp.MustCompile(`^[a-z0-9._%+\-]+@[a-z0-9.\-]+\.[a-z]{2,}$`)
 	return emailRegex.MatchString(email)
 }