Parcourir la source

Merge pull request #3342 from gravitl/NET-1911

NET-1911: ACL policy improvements, add colors to tags
Abhishek K il y a 6 mois
Parent
commit
92806a0210
16 fichiers modifiés avec 879 ajouts et 267 suppressions
  1. 48 8
      controllers/acls.go
  2. 9 0
      controllers/tags.go
  3. 583 105
      logic/acls.go
  4. 1 0
      logic/auth.go
  5. 152 124
      logic/extpeers.go
  6. 2 2
      logic/gateway.go
  7. 21 1
      logic/nodes.go
  8. 1 2
      logic/peers.go
  9. 10 2
      logic/tags.go
  10. 32 10
      migrate/migrate.go
  11. 4 3
      models/acl.go
  12. 3 1
      models/extclient.go
  13. 5 1
      models/tags.go
  14. 3 3
      pro/logic/status.go
  15. 4 4
      pro/logic/user_mgmt.go
  16. 1 1
      scripts/nm-quick.sh

+ 48 - 8
controllers/acls.go

@@ -45,10 +45,12 @@ func aclPolicyTypes(w http.ResponseWriter, r *http.Request) {
 		SrcGroupTypes: []models.AclGroupType{
 			models.UserAclID,
 			models.UserGroupAclID,
-			models.DeviceAclID,
+			models.NodeTagID,
+			models.NodeID,
 		},
 		DstGroupTypes: []models.AclGroupType{
-			models.DeviceAclID,
+			models.NodeTagID,
+			models.NodeID,
 			// models.NetmakerIPAclID,
 			// models.NetmakerSubNetRangeAClID,
 		},
@@ -117,6 +119,13 @@ func aclPolicyTypes(w http.ResponseWriter, r *http.Request) {
 				},
 				PortRange: "",
 			},
+			{
+				Name: models.SSH,
+				AllowedProtocols: []models.Protocol{
+					models.TCP,
+				},
+				PortRange: "22",
+			},
 			{
 				Name: models.Custom,
 				AllowedProtocols: []models.Protocol{
@@ -134,18 +143,49 @@ func aclPolicyTypes(w http.ResponseWriter, r *http.Request) {
 func aclDebug(w http.ResponseWriter, r *http.Request) {
 	nodeID, _ := url.QueryUnescape(r.URL.Query().Get("node"))
 	peerID, _ := url.QueryUnescape(r.URL.Query().Get("peer"))
+	peerIsStatic, _ := url.QueryUnescape(r.URL.Query().Get("peer_is_static"))
 	node, err := logic.GetNodeByID(nodeID)
 	if err != nil {
 		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
 		return
 	}
-	peer, err := logic.GetNodeByID(peerID)
-	if err != nil {
-		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
-		return
+	var peer models.Node
+	if peerIsStatic == "true" {
+		extclient, err := logic.GetExtClient(peerID, node.Network)
+		if err != nil {
+			logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
+			return
+		}
+		peer = extclient.ConvertToStaticNode()
+
+	} else {
+		peer, err = logic.GetNodeByID(peerID)
+		if err != nil {
+			logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
+			return
+		}
+	}
+	type resp struct {
+		IsNodeAllowed bool
+		IsPeerAllowed bool
+		Policies      []models.Acl
+		IngressRules  []models.FwRule
+	}
+
+	allowed, ps := logic.IsNodeAllowedToCommunicateV1(node, peer, true)
+	isallowed := logic.IsPeerAllowed(node, peer, true)
+	re := resp{
+		IsNodeAllowed: allowed,
+		IsPeerAllowed: isallowed,
+		Policies:      ps,
+	}
+	if peerIsStatic == "true" {
+		ingress, err := logic.GetNodeByID(peer.StaticNode.IngressGatewayID)
+		if err == nil {
+			re.IngressRules = logic.GetFwRulesOnIngressGateway(ingress)
+		}
 	}
-	allowed, _ := logic.IsNodeAllowedToCommunicate(node, peer, true)
-	logic.ReturnSuccessResponseWithJson(w, r, allowed, "fetched all acls in the network ")
+	logic.ReturnSuccessResponseWithJson(w, r, re, "fetched all acls in the network ")
 }
 
 // @Summary     List Acls in a network

+ 9 - 0
controllers/tags.go

@@ -88,6 +88,7 @@ func createTag(w http.ResponseWriter, r *http.Request) {
 		TagName:   req.TagName,
 		Network:   req.Network,
 		CreatedBy: user.UserName,
+		ColorCode: req.ColorCode,
 		CreatedAt: time.Now(),
 	}
 	_, err = logic.GetTag(tag.ID)
@@ -182,6 +183,14 @@ func updateTag(w http.ResponseWriter, r *http.Request) {
 		// delete old Tag entry
 		logic.DeleteTag(updateTag.ID, false)
 	}
+	if updateTag.ColorCode != "" && updateTag.ColorCode != tag.ColorCode {
+		tag.ColorCode = updateTag.ColorCode
+		err = logic.UpsertTag(tag)
+		if err != nil {
+			logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
+			return
+		}
+	}
 	go func() {
 		logic.UpdateTag(updateTag, newID)
 		if updateTag.NewName != "" {

+ 583 - 105
logic/acls.go

@@ -51,12 +51,12 @@ func CreateDefaultAclNetworkPolicies(netID models.NetworkID) {
 			RuleType:    models.DevicePolicy,
 			Src: []models.AclPolicyTag{
 				{
-					ID:    models.DeviceAclID,
+					ID:    models.NodeTagID,
 					Value: "*",
 				}},
 			Dst: []models.AclPolicyTag{
 				{
-					ID:    models.DeviceAclID,
+					ID:    models.NodeTagID,
 					Value: "*",
 				}},
 			AllowedDirection: models.TrafficDirectionBi,
@@ -84,7 +84,7 @@ func CreateDefaultAclNetworkPolicies(netID models.NetworkID) {
 				},
 			},
 			Dst: []models.AclPolicyTag{{
-				ID:    models.DeviceAclID,
+				ID:    models.NodeTagID,
 				Value: "*",
 			}},
 			AllowedDirection: models.TrafficDirectionUni,
@@ -95,11 +95,11 @@ func CreateDefaultAclNetworkPolicies(netID models.NetworkID) {
 		InsertAcl(defaultUserAcl)
 	}
 
-	if !IsAclExists(fmt.Sprintf("%s.%s", netID, "all-remote-access-gws")) {
+	if !IsAclExists(fmt.Sprintf("%s.%s", netID, "all-gateways")) {
 		defaultUserAcl := models.Acl{
-			ID:          fmt.Sprintf("%s.%s", netID, "all-remote-access-gws"),
+			ID:          fmt.Sprintf("%s.%s", netID, "all-gateways"),
 			Default:     true,
-			Name:        "All Remote Access Gateways",
+			Name:        "All Gateways",
 			NetworkID:   netID,
 			Proto:       models.ALL,
 			ServiceType: models.Any,
@@ -107,13 +107,13 @@ func CreateDefaultAclNetworkPolicies(netID models.NetworkID) {
 			RuleType:    models.DevicePolicy,
 			Src: []models.AclPolicyTag{
 				{
-					ID:    models.DeviceAclID,
-					Value: fmt.Sprintf("%s.%s", netID, models.RemoteAccessTagName),
+					ID:    models.NodeTagID,
+					Value: fmt.Sprintf("%s.%s", netID, models.GwTagName),
 				},
 			},
 			Dst: []models.AclPolicyTag{
 				{
-					ID:    models.DeviceAclID,
+					ID:    models.NodeTagID,
 					Value: "*",
 				},
 			},
@@ -269,16 +269,26 @@ func IsAclPolicyValid(acl models.Acl) bool {
 			if dstI.ID == "" || dstI.Value == "" {
 				return false
 			}
-			if dstI.ID != models.DeviceAclID {
+			if dstI.ID != models.NodeTagID && dstI.ID != models.NodeID {
 				return false
 			}
 			if dstI.Value == "*" {
 				continue
 			}
-			// check if tag is valid
-			_, err := GetTag(models.TagID(dstI.Value))
-			if err != nil {
-				return false
+			if dstI.ID == models.NodeTagID {
+				// check if tag is valid
+				_, err := GetTag(models.TagID(dstI.Value))
+				if err != nil {
+					return false
+				}
+			} else {
+				_, nodeErr := GetNodeByID(dstI.Value)
+				if nodeErr != nil {
+					_, staticNodeErr := GetExtClient(dstI.Value, acl.NetworkID.String())
+					if staticNodeErr != nil {
+						return false
+					}
+				}
 			}
 		}
 	case models.DevicePolicy:
@@ -286,33 +296,54 @@ func IsAclPolicyValid(acl models.Acl) bool {
 			if srcI.ID == "" || srcI.Value == "" {
 				return false
 			}
-			if srcI.ID != models.DeviceAclID {
+			if srcI.ID != models.NodeTagID && srcI.ID != models.NodeID {
 				return false
 			}
 			if srcI.Value == "*" {
 				continue
 			}
-			// check if tag is valid
-			_, err := GetTag(models.TagID(srcI.Value))
-			if err != nil {
-				return false
+			if srcI.ID == models.NodeTagID {
+				// check if tag is valid
+				_, err := GetTag(models.TagID(srcI.Value))
+				if err != nil {
+					return false
+				}
+			} else {
+				_, nodeErr := GetNodeByID(srcI.Value)
+				if nodeErr != nil {
+					_, staticNodeErr := GetExtClient(srcI.Value, acl.NetworkID.String())
+					if staticNodeErr != nil {
+						return false
+					}
+				}
 			}
+
 		}
 		for _, dstI := range acl.Dst {
 
 			if dstI.ID == "" || dstI.Value == "" {
 				return false
 			}
-			if dstI.ID != models.DeviceAclID {
+			if dstI.ID != models.NodeTagID && dstI.ID != models.NodeID {
 				return false
 			}
 			if dstI.Value == "*" {
 				continue
 			}
-			// check if tag is valid
-			_, err := GetTag(models.TagID(dstI.Value))
-			if err != nil {
-				return false
+			if dstI.ID == models.NodeTagID {
+				// check if tag is valid
+				_, err := GetTag(models.TagID(dstI.Value))
+				if err != nil {
+					return false
+				}
+			} else {
+				_, nodeErr := GetNodeByID(dstI.Value)
+				if nodeErr != nil {
+					_, staticNodeErr := GetExtClient(dstI.Value, acl.NetworkID.String())
+					if staticNodeErr != nil {
+						return false
+					}
+				}
 			}
 		}
 	}
@@ -532,9 +563,23 @@ func convAclTagToValueMap(acltags []models.AclPolicyTag) map[string]struct{} {
 
 // IsUserAllowedToCommunicate - check if user is allowed to communicate with peer
 func IsUserAllowedToCommunicate(userName string, peer models.Node) (bool, []models.Acl) {
+	var peerId string
 	if peer.IsStatic {
+		peerId = peer.StaticNode.ClientID
 		peer = peer.StaticNode.ConvertToStaticNode()
+	} else {
+		peerId = peer.ID.String()
 	}
+
+	var peerTags map[models.TagID]struct{}
+	if peer.Mutex != nil {
+		peer.Mutex.Lock()
+		peerTags = maps.Clone(peer.Tags)
+		peer.Mutex.Unlock()
+	} else {
+		peerTags = peer.Tags
+	}
+	peerTags[models.TagID(peerId)] = struct{}{}
 	acl, _ := GetDefaultPolicy(models.NetworkID(peer.Network), models.UserPolicy)
 	if acl.Enabled {
 		return true, []models.Acl{acl}
@@ -554,7 +599,11 @@ func IsUserAllowedToCommunicate(userName string, peer models.Node) (bool, []mode
 			allowedPolicies = append(allowedPolicies, policy)
 			continue
 		}
-		for tagID := range peer.Tags {
+		if _, ok := dstMap[peer.ID.String()]; ok {
+			allowedPolicies = append(allowedPolicies, policy)
+			continue
+		}
+		for tagID := range peerTags {
 			if _, ok := dstMap[tagID.String()]; ok {
 				allowedPolicies = append(allowedPolicies, policy)
 				break
@@ -570,12 +619,20 @@ func IsUserAllowedToCommunicate(userName string, peer models.Node) (bool, []mode
 
 // IsPeerAllowed - checks if peer needs to be added to the interface
 func IsPeerAllowed(node, peer models.Node, checkDefaultPolicy bool) bool {
+	var nodeId, peerId string
 	if node.IsStatic {
+		nodeId = node.StaticNode.ClientID
 		node = node.StaticNode.ConvertToStaticNode()
+	} else {
+		nodeId = node.ID.String()
 	}
 	if peer.IsStatic {
+		peerId = peer.StaticNode.ClientID
 		peer = peer.StaticNode.ConvertToStaticNode()
+	} else {
+		peerId = peer.ID.String()
 	}
+
 	var nodeTags, peerTags map[models.TagID]struct{}
 	if node.Mutex != nil {
 		node.Mutex.Lock()
@@ -591,7 +648,8 @@ func IsPeerAllowed(node, peer models.Node, checkDefaultPolicy bool) bool {
 	} else {
 		peerTags = peer.Tags
 	}
-
+	nodeTags[models.TagID(nodeId)] = struct{}{}
+	peerTags[models.TagID(peerId)] = struct{}{}
 	if checkDefaultPolicy {
 		// check default policy if all allowed return true
 		defaultPolicy, err := GetDefaultPolicy(models.NetworkID(node.Network), models.DevicePolicy)
@@ -616,64 +674,363 @@ func IsPeerAllowed(node, peer models.Node, checkDefaultPolicy bool) bool {
 		}
 		srcMap = convAclTagToValueMap(policy.Src)
 		dstMap = convAclTagToValueMap(policy.Dst)
-		for tagID := range nodeTags {
-			if _, ok := dstMap[tagID.String()]; ok {
-				if _, ok := srcMap["*"]; ok {
-					return true
+		if checkTagGroupPolicy(srcMap, dstMap, node, peer, nodeTags, peerTags) {
+			return true
+		}
+
+	}
+	return false
+}
+
+func RemoveUserFromAclPolicy(userName string) {
+	acls := ListAcls()
+	for _, acl := range acls {
+		delete := false
+		update := false
+		if acl.RuleType == models.UserPolicy {
+			for i, srcI := range acl.Src {
+				if srcI.ID == models.UserAclID && srcI.Value == userName {
+					if len(acl.Src) == 1 {
+						// delete policy
+						delete = true
+						break
+					} else {
+						acl.Src = append(acl.Src[:i], acl.Src[i+1:]...)
+						update = true
+					}
 				}
-				for tagID := range peerTags {
-					if _, ok := srcMap[tagID.String()]; ok {
-						return true
+			}
+			if delete {
+				DeleteAcl(acl)
+				continue
+			}
+			if update {
+				UpsertAcl(acl)
+			}
+		}
+	}
+}
+
+func RemoveNodeFromAclPolicy(node models.Node) {
+	var nodeID string
+	if node.IsStatic {
+		nodeID = node.StaticNode.ClientID
+	} else {
+		nodeID = node.ID.String()
+	}
+	acls, _ := ListAclsByNetwork(models.NetworkID(node.Network))
+	for _, acl := range acls {
+		delete := false
+		update := false
+		if acl.RuleType == models.DevicePolicy {
+			for i, srcI := range acl.Src {
+				if srcI.ID == models.NodeID && srcI.Value == nodeID {
+					if len(acl.Src) == 1 {
+						// delete policy
+						delete = true
+						break
+					} else {
+						acl.Src = append(acl.Src[:i], acl.Src[i+1:]...)
+						update = true
 					}
 				}
 			}
-			if _, ok := srcMap[tagID.String()]; ok {
-				if _, ok := dstMap["*"]; ok {
-					return true
+			if delete {
+				DeleteAcl(acl)
+				continue
+			}
+			for i, dstI := range acl.Dst {
+				if dstI.ID == models.NodeID && dstI.Value == nodeID {
+					if len(acl.Dst) == 1 {
+						// delete policy
+						delete = true
+						break
+					} else {
+						acl.Dst = append(acl.Dst[:i], acl.Dst[i+1:]...)
+						update = true
+					}
 				}
-				for tagID := range peerTags {
-					if _, ok := dstMap[tagID.String()]; ok {
-						return true
+			}
+			if delete {
+				DeleteAcl(acl)
+				continue
+			}
+			if update {
+				UpsertAcl(acl)
+			}
+
+		}
+		if acl.RuleType == models.UserPolicy {
+			for i, dstI := range acl.Dst {
+				if dstI.ID == models.NodeID && dstI.Value == nodeID {
+					if len(acl.Dst) == 1 {
+						// delete policy
+						delete = true
+						break
+					} else {
+						acl.Dst = append(acl.Dst[:i], acl.Dst[i+1:]...)
+						update = true
 					}
 				}
 			}
+			if delete {
+				DeleteAcl(acl)
+				continue
+			}
+			if update {
+				UpsertAcl(acl)
+			}
 		}
+	}
+}
 
-		for tagID := range peerTags {
-			if _, ok := dstMap[tagID.String()]; ok {
-				if _, ok := srcMap["*"]; ok {
+func checkTagGroupPolicy(srcMap, dstMap map[string]struct{}, node, peer models.Node,
+	nodeTags, peerTags map[models.TagID]struct{}) bool {
+	// check for node ID
+	if _, ok := srcMap[node.ID.String()]; ok {
+		if _, ok = dstMap[peer.ID.String()]; ok {
+			return true
+		}
+
+	}
+	if _, ok := dstMap[node.ID.String()]; ok {
+		if _, ok = srcMap[peer.ID.String()]; ok {
+			return true
+		}
+	}
+
+	for tagID := range nodeTags {
+		if _, ok := dstMap[tagID.String()]; ok {
+			if _, ok := srcMap["*"]; ok {
+				return true
+			}
+			for tagID := range peerTags {
+				if _, ok := srcMap[tagID.String()]; ok {
 					return true
 				}
-				for tagID := range nodeTags {
+			}
+		}
+		if _, ok := srcMap[tagID.String()]; ok {
+			if _, ok := dstMap["*"]; ok {
+				return true
+			}
+			for tagID := range peerTags {
+				if _, ok := dstMap[tagID.String()]; ok {
+					return true
+				}
+			}
+		}
+	}
+	for tagID := range peerTags {
+		if _, ok := dstMap[tagID.String()]; ok {
+			if _, ok := srcMap["*"]; ok {
+				return true
+			}
+			for tagID := range nodeTags {
 
-					if _, ok := srcMap[tagID.String()]; ok {
-						return true
-					}
+				if _, ok := srcMap[tagID.String()]; ok {
+					return true
 				}
 			}
-			if _, ok := srcMap[tagID.String()]; ok {
-				if _, ok := dstMap["*"]; ok {
+		}
+		if _, ok := srcMap[tagID.String()]; ok {
+			if _, ok := dstMap["*"]; ok {
+				return true
+			}
+			for tagID := range nodeTags {
+				if _, ok := dstMap[tagID.String()]; ok {
 					return true
 				}
+			}
+		}
+	}
+	return false
+}
+func uniquePolicies(items []models.Acl) []models.Acl {
+	if len(items) == 0 {
+		return items
+	}
+	seen := make(map[string]bool)
+	var result []models.Acl
+	for _, item := range items {
+		if !seen[item.ID] {
+			seen[item.ID] = true
+			result = append(result, item)
+		}
+	}
+
+	return result
+}
+
+// IsNodeAllowedToCommunicate - check node is allowed to communicate with the peer // ADD ALLOWED DIRECTION - 0 => node -> peer, 1 => peer-> node,
+func IsNodeAllowedToCommunicateV1(node, peer models.Node, checkDefaultPolicy bool) (bool, []models.Acl) {
+	var nodeId, peerId string
+	if node.IsStatic {
+		nodeId = node.StaticNode.ClientID
+		node = node.StaticNode.ConvertToStaticNode()
+	} else {
+		nodeId = node.ID.String()
+	}
+	if peer.IsStatic {
+		peerId = peer.StaticNode.ClientID
+		peer = peer.StaticNode.ConvertToStaticNode()
+	} else {
+		peerId = peer.ID.String()
+	}
+
+	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
+	}
+	nodeTags[models.TagID(nodeId)] = struct{}{}
+	peerTags[models.TagID(peerId)] = struct{}{}
+	if checkDefaultPolicy {
+		// check default policy if all allowed return true
+		defaultPolicy, err := GetDefaultPolicy(models.NetworkID(node.Network), models.DevicePolicy)
+		if err == nil {
+			if defaultPolicy.Enabled {
+				return true, []models.Acl{defaultPolicy}
+			}
+		}
+	}
+	allowedPolicies := []models.Acl{}
+	defer func() {
+		allowedPolicies = uniquePolicies(allowedPolicies)
+	}()
+	// list device policies
+	policies := listDevicePolicies(models.NetworkID(peer.Network))
+	srcMap := make(map[string]struct{})
+	dstMap := make(map[string]struct{})
+	defer func() {
+		srcMap = nil
+		dstMap = nil
+	}()
+	for _, policy := range policies {
+		if !policy.Enabled {
+			continue
+		}
+		allowed := false
+		srcMap = convAclTagToValueMap(policy.Src)
+		dstMap = convAclTagToValueMap(policy.Dst)
+		_, srcAll := srcMap["*"]
+		_, dstAll := dstMap["*"]
+		if policy.AllowedDirection == models.TrafficDirectionBi {
+			if _, ok := srcMap[nodeId]; ok || srcAll {
+				if _, ok := dstMap[peerId]; ok || dstAll {
+					allowedPolicies = append(allowedPolicies, policy)
+					continue
+				}
+
+			}
+			if _, ok := dstMap[nodeId]; ok || dstAll {
+				if _, ok := srcMap[peerId]; ok || srcAll {
+					allowedPolicies = append(allowedPolicies, policy)
+					continue
+				}
+			}
+		}
+		if _, ok := dstMap[peerId]; ok || dstAll {
+			if _, ok := srcMap[nodeId]; ok || srcAll {
+				allowedPolicies = append(allowedPolicies, policy)
+				continue
+			}
+		}
+		if policy.AllowedDirection == models.TrafficDirectionBi {
+
+			for tagID := range nodeTags {
+
+				if _, ok := dstMap[tagID.String()]; ok || dstAll {
+					if srcAll {
+						allowed = true
+						break
+					}
+					for tagID := range peerTags {
+						if _, ok := srcMap[tagID.String()]; ok {
+							allowed = true
+							break
+						}
+					}
+				}
+				if allowed {
+					allowedPolicies = append(allowedPolicies, policy)
+					break
+				}
+				if _, ok := srcMap[tagID.String()]; ok || srcAll {
+					if dstAll {
+						allowed = true
+						break
+					}
+					for tagID := range peerTags {
+						if _, ok := dstMap[tagID.String()]; ok {
+							allowed = true
+							break
+						}
+					}
+				}
+				if allowed {
+					break
+				}
+			}
+			if allowed {
+				allowedPolicies = append(allowedPolicies, policy)
+				continue
+			}
+		}
+		for tagID := range peerTags {
+			if _, ok := dstMap[tagID.String()]; ok || dstAll {
+				if srcAll {
+					allowed = true
+					break
+				}
 				for tagID := range nodeTags {
-					if _, ok := dstMap[tagID.String()]; ok {
-						return true
+					if _, ok := srcMap[tagID.String()]; ok {
+						allowed = true
+						break
 					}
 				}
 			}
+			if allowed {
+				break
+			}
+		}
+		if allowed {
+			allowedPolicies = append(allowedPolicies, policy)
 		}
 	}
-	return false
+
+	if len(allowedPolicies) > 0 {
+		return true, allowedPolicies
+	}
+	return false, allowedPolicies
 }
 
 // IsNodeAllowedToCommunicate - check node is allowed to communicate with the peer
 func IsNodeAllowedToCommunicate(node, peer models.Node, checkDefaultPolicy bool) (bool, []models.Acl) {
+	var nodeId, peerId string
 	if node.IsStatic {
+		nodeId = node.StaticNode.ClientID
 		node = node.StaticNode.ConvertToStaticNode()
+	} else {
+		nodeId = node.ID.String()
 	}
 	if peer.IsStatic {
+		peerId = peer.StaticNode.ClientID
 		peer = peer.StaticNode.ConvertToStaticNode()
+	} else {
+		peerId = peer.ID.String()
 	}
+
 	var nodeTags, peerTags map[models.TagID]struct{}
 	if node.Mutex != nil {
 		node.Mutex.Lock()
@@ -689,6 +1046,8 @@ func IsNodeAllowedToCommunicate(node, peer models.Node, checkDefaultPolicy bool)
 	} else {
 		peerTags = peer.Tags
 	}
+	nodeTags[models.TagID(nodeId)] = struct{}{}
+	peerTags[models.TagID(peerId)] = struct{}{}
 	if checkDefaultPolicy {
 		// check default policy if all allowed return true
 		defaultPolicy, err := GetDefaultPolicy(models.NetworkID(node.Network), models.DevicePolicy)
@@ -713,10 +1072,33 @@ func IsNodeAllowedToCommunicate(node, peer models.Node, checkDefaultPolicy bool)
 		}
 		srcMap = convAclTagToValueMap(policy.Src)
 		dstMap = convAclTagToValueMap(policy.Dst)
+		_, srcAll := srcMap["*"]
+		_, dstAll := dstMap["*"]
+		if policy.AllowedDirection == models.TrafficDirectionBi {
+			if _, ok := srcMap[nodeId]; ok || srcAll {
+				if _, ok := dstMap[peerId]; ok || dstAll {
+					allowedPolicies = append(allowedPolicies, policy)
+					continue
+				}
+
+			}
+			if _, ok := dstMap[nodeId]; ok || dstAll {
+				if _, ok := srcMap[peerId]; ok || srcAll {
+					allowedPolicies = append(allowedPolicies, policy)
+					continue
+				}
+			}
+		}
+		if _, ok := dstMap[nodeId]; ok || dstAll {
+			if _, ok := srcMap[peerId]; ok || srcAll {
+				allowedPolicies = append(allowedPolicies, policy)
+				continue
+			}
+		}
 		for tagID := range nodeTags {
 			allowed := false
-			if _, ok := dstMap[tagID.String()]; policy.AllowedDirection == models.TrafficDirectionBi && ok {
-				if _, ok := srcMap["*"]; ok {
+			if _, ok := dstMap[tagID.String()]; policy.AllowedDirection == models.TrafficDirectionBi && ok || dstAll {
+				if srcAll {
 					allowed = true
 					allowedPolicies = append(allowedPolicies, policy)
 					break
@@ -732,8 +1114,8 @@ func IsNodeAllowedToCommunicate(node, peer models.Node, checkDefaultPolicy bool)
 				allowedPolicies = append(allowedPolicies, policy)
 				break
 			}
-			if _, ok := srcMap[tagID.String()]; ok {
-				if _, ok := dstMap["*"]; ok {
+			if _, ok := srcMap[tagID.String()]; ok || srcAll {
+				if dstAll {
 					allowed = true
 					allowedPolicies = append(allowedPolicies, policy)
 					break
@@ -752,15 +1134,15 @@ func IsNodeAllowedToCommunicate(node, peer models.Node, checkDefaultPolicy bool)
 		}
 		for tagID := range peerTags {
 			allowed := false
-			if _, ok := dstMap[tagID.String()]; ok {
-				if _, ok := srcMap["*"]; ok {
+			if _, ok := dstMap[tagID.String()]; ok || dstAll {
+				if srcAll {
 					allowed = true
 					allowedPolicies = append(allowedPolicies, policy)
 					break
 				}
 				for tagID := range nodeTags {
 
-					if _, ok := srcMap[tagID.String()]; ok {
+					if _, ok := srcMap[tagID.String()]; ok || srcAll {
 						allowed = true
 						break
 					}
@@ -771,8 +1153,8 @@ func IsNodeAllowedToCommunicate(node, peer models.Node, checkDefaultPolicy bool)
 				break
 			}
 
-			if _, ok := srcMap[tagID.String()]; policy.AllowedDirection == models.TrafficDirectionBi && ok {
-				if _, ok := dstMap["*"]; ok {
+			if _, ok := srcMap[tagID.String()]; policy.AllowedDirection == models.TrafficDirectionBi && ok || srcAll {
+				if dstAll {
 					allowed = true
 					allowedPolicies = append(allowedPolicies, policy)
 					break
@@ -810,7 +1192,7 @@ func UpdateDeviceTag(OldID, newID models.TagID, netID models.NetworkID) {
 	update := false
 	for _, acl := range acls {
 		for i, srcTagI := range acl.Src {
-			if srcTagI.ID == models.DeviceAclID {
+			if srcTagI.ID == models.NodeTagID {
 				if OldID.String() == srcTagI.Value {
 					acl.Src[i].Value = newID.String()
 					update = true
@@ -818,7 +1200,7 @@ func UpdateDeviceTag(OldID, newID models.TagID, netID models.NetworkID) {
 			}
 		}
 		for i, dstTagI := range acl.Dst {
-			if dstTagI.ID == models.DeviceAclID {
+			if dstTagI.ID == models.NodeTagID {
 				if OldID.String() == dstTagI.Value {
 					acl.Dst[i].Value = newID.String()
 					update = true
@@ -835,14 +1217,14 @@ func CheckIfTagAsActivePolicy(tagID models.TagID, netID models.NetworkID) bool {
 	acls := listDevicePolicies(netID)
 	for _, acl := range acls {
 		for _, srcTagI := range acl.Src {
-			if srcTagI.ID == models.DeviceAclID {
+			if srcTagI.ID == models.NodeTagID {
 				if tagID.String() == srcTagI.Value {
 					return true
 				}
 			}
 		}
 		for _, dstTagI := range acl.Dst {
-			if dstTagI.ID == models.DeviceAclID {
+			if dstTagI.ID == models.NodeTagID {
 				if tagID.String() == dstTagI.Value {
 					return true
 				}
@@ -858,7 +1240,7 @@ func RemoveDeviceTagFromAclPolicies(tagID models.TagID, netID models.NetworkID)
 	update := false
 	for _, acl := range acls {
 		for i, srcTagI := range acl.Src {
-			if srcTagI.ID == models.DeviceAclID {
+			if srcTagI.ID == models.NodeTagID {
 				if tagID.String() == srcTagI.Value {
 					acl.Src = append(acl.Src[:i], acl.Src[i+1:]...)
 					update = true
@@ -866,7 +1248,7 @@ func RemoveDeviceTagFromAclPolicies(tagID models.TagID, netID models.NetworkID)
 			}
 		}
 		for i, dstTagI := range acl.Dst {
-			if dstTagI.ID == models.DeviceAclID {
+			if dstTagI.ID == models.NodeTagID {
 				if tagID.String() == dstTagI.Value {
 					acl.Dst = append(acl.Dst[:i], acl.Dst[i+1:]...)
 					update = true
@@ -894,29 +1276,41 @@ func getUserAclRulesForNode(targetnode *models.Node,
 	} else {
 		targetNodeTags = maps.Clone(targetnode.Tags)
 	}
-	for nodeTag := range targetNodeTags {
-		for _, acl := range acls {
-			if !acl.Enabled {
-				continue
+	for _, acl := range acls {
+		if !acl.Enabled {
+			continue
+		}
+		dstTags := convAclTagToValueMap(acl.Dst)
+		_, all := dstTags["*"]
+		addUsers := false
+		if !all {
+			for nodeTag := range targetNodeTags {
+				if _, ok := dstTags[nodeTag.String()]; !ok {
+					if _, ok = dstTags[targetnode.ID.String()]; !ok {
+						break
+					}
+				}
 			}
-			dstTags := convAclTagToValueMap(acl.Dst)
-			if _, ok := dstTags[nodeTag.String()]; ok {
-				// get all src tags
-				for _, srcAcl := range acl.Src {
-					if srcAcl.ID == models.UserAclID {
-						allowedUsers[srcAcl.Value] = append(allowedUsers[srcAcl.Value], acl)
-					} else if srcAcl.ID == models.UserGroupAclID {
-						// fetch all users in the group
-						if usersMap, ok := userGrpMap[models.UserGroupID(srcAcl.Value)]; ok {
-							for userName := range usersMap {
-								allowedUsers[userName] = append(allowedUsers[userName], acl)
-							}
+		} else {
+			addUsers = true
+		}
+
+		if addUsers {
+			// get all src tags
+			for _, srcAcl := range acl.Src {
+				if srcAcl.ID == models.UserAclID {
+					allowedUsers[srcAcl.Value] = append(allowedUsers[srcAcl.Value], acl)
+				} else if srcAcl.ID == models.UserGroupAclID {
+					// fetch all users in the group
+					if usersMap, ok := userGrpMap[models.UserGroupID(srcAcl.Value)]; ok {
+						for userName := range usersMap {
+							allowedUsers[userName] = append(allowedUsers[userName], acl)
 						}
 					}
 				}
-
 			}
 		}
+
 	}
 
 	for _, userNode := range userNodes {
@@ -959,10 +1353,42 @@ func getUserAclRulesForNode(targetnode *models.Node,
 	return rules
 }
 
-func GetAclRulesForNode(targetnode *models.Node) (rules map[string]models.AclRule) {
+func checkIfAnyPolicyisUniDirectional(targetNode models.Node) bool {
+	targetNode.Tags[models.TagID(targetNode.ID.String())] = struct{}{}
+	acls := listDevicePolicies(models.NetworkID(targetNode.Network))
+	for _, acl := range acls {
+		if !acl.Enabled {
+			continue
+		}
+		if acl.AllowedDirection == models.TrafficDirectionBi {
+			continue
+		}
+		srcTags := convAclTagToValueMap(acl.Src)
+		dstTags := convAclTagToValueMap(acl.Dst)
+		for nodeTag := range targetNode.Tags {
+			if _, ok := srcTags[nodeTag.String()]; ok {
+				return true
+			}
+			if _, ok := srcTags[targetNode.ID.String()]; ok {
+				return true
+			}
+			if _, ok := dstTags[nodeTag.String()]; ok {
+				return true
+			}
+			if _, ok := dstTags[targetNode.ID.String()]; ok {
+				return true
+			}
+		}
+	}
+	return false
+}
+
+func GetAclRulesForNode(targetnodeI *models.Node) (rules map[string]models.AclRule) {
+	targetnode := *targetnodeI
+	targetnode.Tags[models.TagID(targetnode.ID.String())] = struct{}{}
 	defer func() {
 		if !targetnode.IsIngressGateway {
-			rules = getUserAclRulesForNode(targetnode, rules)
+			rules = getUserAclRulesForNode(&targetnode, rules)
 		}
 
 	}()
@@ -975,7 +1401,6 @@ func GetAclRulesForNode(targetnode *models.Node) (rules map[string]models.AclRul
 	}
 
 	acls := listDevicePolicies(models.NetworkID(targetnode.Network))
-
 	var targetNodeTags = make(map[models.TagID]struct{})
 	if targetnode.Mutex != nil {
 		targetnode.Mutex.Lock()
@@ -985,28 +1410,37 @@ func GetAclRulesForNode(targetnode *models.Node) (rules map[string]models.AclRul
 		targetNodeTags = maps.Clone(targetnode.Tags)
 	}
 	targetNodeTags["*"] = struct{}{}
-	for nodeTag := range targetNodeTags {
-		for _, acl := range acls {
-			if !acl.Enabled {
-				continue
-			}
-			srcTags := convAclTagToValueMap(acl.Src)
-			dstTags := convAclTagToValueMap(acl.Dst)
-			aclRule := models.AclRule{
-				ID:              acl.ID,
-				AllowedProtocol: acl.Proto,
-				AllowedPorts:    acl.Port,
-				Direction:       acl.AllowedDirection,
-				Allowed:         true,
-			}
+
+	for _, acl := range acls {
+		if !acl.Enabled {
+			continue
+		}
+		srcTags := convAclTagToValueMap(acl.Src)
+		dstTags := convAclTagToValueMap(acl.Dst)
+		_, srcAll := srcTags["*"]
+		_, dstAll := dstTags["*"]
+		aclRule := models.AclRule{
+			ID:              acl.ID,
+			AllowedProtocol: acl.Proto,
+			AllowedPorts:    acl.Port,
+			Direction:       acl.AllowedDirection,
+			Allowed:         true,
+		}
+		for nodeTag := range targetNodeTags {
 			if acl.AllowedDirection == models.TrafficDirectionBi {
 				var existsInSrcTag bool
 				var existsInDstTag bool
 
-				if _, ok := srcTags[nodeTag.String()]; ok {
+				if _, ok := srcTags[nodeTag.String()]; ok || srcAll {
 					existsInSrcTag = true
 				}
-				if _, ok := dstTags[nodeTag.String()]; ok {
+				if _, ok := srcTags[targetnode.ID.String()]; ok || srcAll {
+					existsInSrcTag = true
+				}
+				if _, ok := dstTags[nodeTag.String()]; ok || dstAll {
+					existsInDstTag = true
+				}
+				if _, ok := dstTags[targetnode.ID.String()]; ok || dstAll {
 					existsInDstTag = true
 				}
 
@@ -1018,10 +1452,20 @@ func GetAclRulesForNode(targetnode *models.Node) (rules map[string]models.AclRul
 						}
 						// Get peers in the tags and add allowed rules
 						nodes := taggedNodes[models.TagID(dst)]
+						if dst != targetnode.ID.String() {
+							node, err := GetNodeByID(dst)
+							if err == nil {
+								nodes = append(nodes, node)
+							}
+						}
+
 						for _, node := range nodes {
 							if node.ID == targetnode.ID {
 								continue
 							}
+							if node.IsStatic && node.StaticNode.IngressGatewayID == targetnode.ID.String() {
+								continue
+							}
 							if node.Address.IP != nil {
 								aclRule.IPList = append(aclRule.IPList, node.AddressIPNet4())
 							}
@@ -1045,10 +1489,19 @@ func GetAclRulesForNode(targetnode *models.Node) (rules map[string]models.AclRul
 						}
 						// Get peers in the tags and add allowed rules
 						nodes := taggedNodes[models.TagID(src)]
+						if src != targetnode.ID.String() {
+							node, err := GetNodeByID(src)
+							if err == nil {
+								nodes = append(nodes, node)
+							}
+						}
 						for _, node := range nodes {
 							if node.ID == targetnode.ID {
 								continue
 							}
+							if node.IsStatic && node.StaticNode.IngressGatewayID == targetnode.ID.String() {
+								continue
+							}
 							if node.Address.IP != nil {
 								aclRule.IPList = append(aclRule.IPList, node.AddressIPNet4())
 							}
@@ -1066,10 +1519,31 @@ func GetAclRulesForNode(targetnode *models.Node) (rules map[string]models.AclRul
 				}
 				if existsInDstTag && existsInSrcTag {
 					nodes := taggedNodes[nodeTag]
+					for srcID := range srcTags {
+						if srcID == targetnode.ID.String() {
+							continue
+						}
+						node, err := GetNodeByID(srcID)
+						if err == nil {
+							nodes = append(nodes, node)
+						}
+					}
+					for dstID := range dstTags {
+						if dstID == targetnode.ID.String() {
+							continue
+						}
+						node, err := GetNodeByID(dstID)
+						if err == nil {
+							nodes = append(nodes, node)
+						}
+					}
 					for _, node := range nodes {
 						if node.ID == targetnode.ID {
 							continue
 						}
+						if node.IsStatic && node.StaticNode.IngressGatewayID == targetnode.ID.String() {
+							continue
+						}
 						if node.Address.IP != nil {
 							aclRule.IPList = append(aclRule.IPList, node.AddressIPNet4())
 						}
@@ -1098,6 +1572,9 @@ func GetAclRulesForNode(targetnode *models.Node) (rules map[string]models.AclRul
 							if node.ID == targetnode.ID {
 								continue
 							}
+							if node.IsStatic && node.StaticNode.IngressGatewayID == targetnode.ID.String() {
+								continue
+							}
 							if node.Address.IP != nil {
 								aclRule.IPList = append(aclRule.IPList, node.AddressIPNet4())
 							}
@@ -1114,9 +1591,10 @@ func GetAclRulesForNode(targetnode *models.Node) (rules map[string]models.AclRul
 					}
 				}
 			}
-			if len(aclRule.IPList) > 0 || len(aclRule.IP6List) > 0 {
-				rules[acl.ID] = aclRule
-			}
+
+		}
+		if len(aclRule.IPList) > 0 || len(aclRule.IP6List) > 0 {
+			rules[acl.ID] = aclRule
 		}
 	}
 	return rules

+ 1 - 0
logic/auth.go

@@ -359,6 +359,7 @@ func DeleteUser(user string) (bool, error) {
 	if err != nil {
 		return false, err
 	}
+	go RemoveUserFromAclPolicy(user)
 
 	return true, nil
 }

+ 152 - 124
logic/extpeers.go

@@ -115,6 +115,7 @@ func DeleteExtClient(network string, clientid string) error {
 		}
 		deleteExtClientFromCache(key)
 	}
+	go RemoveNodeFromAclPolicy(extClient.ConvertToStaticNode())
 	return nil
 }
 
@@ -464,9 +465,139 @@ func GetStaticNodeIps(node models.Node) (ips []net.IP) {
 	return
 }
 
+func getFwRulesForNodeAndPeerOnGw(node, peer models.Node, allowedPolicies []models.Acl) (rules []models.FwRule) {
+
+	for _, policy := range allowedPolicies {
+		// if static peer dst rule not for ingress node -> skip
+		if node.Address.IP != nil {
+			rules = append(rules, models.FwRule{
+				SrcIP: net.IPNet{
+					IP:   node.Address.IP,
+					Mask: net.CIDRMask(32, 32),
+				},
+				DstIP: net.IPNet{
+					IP:   peer.Address.IP,
+					Mask: net.CIDRMask(32, 32),
+				},
+				AllowedProtocol: policy.Proto,
+				AllowedPorts:    policy.Port,
+				Allow:           true,
+			})
+		}
+
+		if node.Address6.IP != nil {
+			rules = append(rules, models.FwRule{
+				SrcIP: net.IPNet{
+					IP:   node.Address6.IP,
+					Mask: net.CIDRMask(128, 128),
+				},
+				DstIP: net.IPNet{
+					IP:   peer.Address6.IP,
+					Mask: net.CIDRMask(128, 128),
+				},
+				AllowedProtocol: policy.Proto,
+				AllowedPorts:    policy.Port,
+				Allow:           true,
+			})
+		}
+		if policy.AllowedDirection == models.TrafficDirectionBi {
+			if node.Address.IP != nil {
+				rules = append(rules, models.FwRule{
+					SrcIP: net.IPNet{
+						IP:   peer.Address.IP,
+						Mask: net.CIDRMask(32, 32),
+					},
+					DstIP: net.IPNet{
+						IP:   node.Address.IP,
+						Mask: net.CIDRMask(32, 32),
+					},
+					AllowedProtocol: policy.Proto,
+					AllowedPorts:    policy.Port,
+					Allow:           true,
+				})
+			}
+
+			if node.Address6.IP != nil {
+				rules = append(rules, models.FwRule{
+					SrcIP: net.IPNet{
+						IP:   peer.Address6.IP,
+						Mask: net.CIDRMask(128, 128),
+					},
+					DstIP: net.IPNet{
+						IP:   node.Address6.IP,
+						Mask: net.CIDRMask(128, 128),
+					},
+					AllowedProtocol: policy.Proto,
+					AllowedPorts:    policy.Port,
+					Allow:           true,
+				})
+			}
+		}
+		if len(node.StaticNode.ExtraAllowedIPs) > 0 {
+			for _, additionalAllowedIPNet := range node.StaticNode.ExtraAllowedIPs {
+				_, ipNet, err := net.ParseCIDR(additionalAllowedIPNet)
+				if err != nil {
+					continue
+				}
+				if ipNet.IP.To4() != nil && peer.Address.IP != nil {
+					rules = append(rules, models.FwRule{
+						SrcIP: net.IPNet{
+							IP:   peer.Address.IP,
+							Mask: net.CIDRMask(32, 32),
+						},
+						DstIP: *ipNet,
+						Allow: true,
+					})
+				} else if peer.Address6.IP != nil {
+					rules = append(rules, models.FwRule{
+						SrcIP: net.IPNet{
+							IP:   peer.Address6.IP,
+							Mask: net.CIDRMask(128, 128),
+						},
+						DstIP: *ipNet,
+						Allow: true,
+					})
+				}
+
+			}
+
+		}
+		if len(peer.StaticNode.ExtraAllowedIPs) > 0 {
+			for _, additionalAllowedIPNet := range peer.StaticNode.ExtraAllowedIPs {
+				_, ipNet, err := net.ParseCIDR(additionalAllowedIPNet)
+				if err != nil {
+					continue
+				}
+				if ipNet.IP.To4() != nil && node.Address.IP != nil {
+					rules = append(rules, models.FwRule{
+						SrcIP: net.IPNet{
+							IP:   node.Address.IP,
+							Mask: net.CIDRMask(32, 32),
+						},
+						DstIP: *ipNet,
+						Allow: true,
+					})
+				} else if node.Address6.IP != nil {
+					rules = append(rules, models.FwRule{
+						SrcIP: net.IPNet{
+							IP:   node.Address6.IP,
+							Mask: net.CIDRMask(128, 128),
+						},
+						DstIP: *ipNet,
+						Allow: true,
+					})
+				}
+
+			}
+
+		}
+	}
+
+	return
+}
+
 func GetFwRulesOnIngressGateway(node models.Node) (rules []models.FwRule) {
 	// fetch user access to static clients via policies
-
 	defaultUserPolicy, _ := GetDefaultPolicy(models.NetworkID(node.Network), models.UserPolicy)
 	defaultDevicePolicy, _ := GetDefaultPolicy(models.NetworkID(node.Network), models.DevicePolicy)
 	nodes, _ := GetNetworkNodes(node.Network)
@@ -593,131 +724,26 @@ func GetFwRulesOnIngressGateway(node models.Node) (rules []models.FwRule) {
 		if !nodeI.IsStatic || nodeI.IsUserNode {
 			continue
 		}
+		// if nodeI.StaticNode.IngressGatewayID != node.ID.String() {
+		// 	continue
+		// }
 		for _, peer := range nodes {
 			if peer.StaticNode.ClientID == nodeI.StaticNode.ClientID || peer.IsUserNode {
 				continue
 			}
-			if ok, allowedPolicies := IsNodeAllowedToCommunicate(nodeI, peer, true); ok {
-				if peer.IsStatic {
-					if nodeI.StaticNode.Address != "" {
-						for _, policy := range allowedPolicies {
-							rules = append(rules, models.FwRule{
-								SrcIP:           nodeI.StaticNode.AddressIPNet4(),
-								DstIP:           peer.StaticNode.AddressIPNet4(),
-								AllowedProtocol: policy.Proto,
-								AllowedPorts:    policy.Port,
-								Allow:           true,
-							})
-							if policy.AllowedDirection == models.TrafficDirectionBi {
-								rules = append(rules, models.FwRule{
-									SrcIP:           peer.StaticNode.AddressIPNet4(),
-									DstIP:           nodeI.StaticNode.AddressIPNet4(),
-									AllowedProtocol: policy.Proto,
-									AllowedPorts:    policy.Port,
-									Allow:           true,
-								})
-							}
-						}
-
-					}
-					if nodeI.StaticNode.Address6 != "" {
-						for _, policy := range allowedPolicies {
-							rules = append(rules, models.FwRule{
-								SrcIP:           nodeI.StaticNode.AddressIPNet6(),
-								DstIP:           peer.StaticNode.AddressIPNet6(),
-								AllowedProtocol: policy.Proto,
-								AllowedPorts:    policy.Port,
-								Allow:           true,
-							})
-							if policy.AllowedDirection == models.TrafficDirectionBi {
-								rules = append(rules, models.FwRule{
-									SrcIP:           peer.StaticNode.AddressIPNet6(),
-									DstIP:           nodeI.StaticNode.AddressIPNet6(),
-									AllowedProtocol: policy.Proto,
-									AllowedPorts:    policy.Port,
-									Allow:           true,
-								})
-							}
-						}
-					}
-					if len(peer.StaticNode.ExtraAllowedIPs) > 0 {
-						for _, additionalAllowedIPNet := range peer.StaticNode.ExtraAllowedIPs {
-							_, ipNet, err := net.ParseCIDR(additionalAllowedIPNet)
-							if err != nil {
-								continue
-							}
-							if ipNet.IP.To4() != nil {
-								rules = append(rules, models.FwRule{
-									SrcIP: nodeI.StaticNode.AddressIPNet4(),
-									DstIP: *ipNet,
-									Allow: true,
-								})
-							} else {
-								rules = append(rules, models.FwRule{
-									SrcIP: nodeI.StaticNode.AddressIPNet6(),
-									DstIP: *ipNet,
-									Allow: true,
-								})
-							}
-
-						}
-
-					}
-				} else {
-					if nodeI.StaticNode.Address != "" {
-						for _, policy := range allowedPolicies {
-							rules = append(rules, models.FwRule{
-								SrcIP: nodeI.StaticNode.AddressIPNet4(),
-								DstIP: net.IPNet{
-									IP:   peer.Address.IP,
-									Mask: net.CIDRMask(32, 32),
-								},
-								AllowedProtocol: policy.Proto,
-								AllowedPorts:    policy.Port,
-								Allow:           true,
-							})
-							if policy.AllowedDirection == models.TrafficDirectionBi {
-								rules = append(rules, models.FwRule{
-									SrcIP: net.IPNet{
-										IP:   peer.Address.IP,
-										Mask: net.CIDRMask(32, 32),
-									},
-									DstIP:           nodeI.StaticNode.AddressIPNet4(),
-									AllowedProtocol: policy.Proto,
-									AllowedPorts:    policy.Port,
-									Allow:           true,
-								})
-							}
-						}
-					}
-					if nodeI.StaticNode.Address6 != "" {
-						for _, policy := range allowedPolicies {
-							rules = append(rules, models.FwRule{
-								SrcIP: nodeI.StaticNode.AddressIPNet6(),
-								DstIP: net.IPNet{
-									IP:   peer.Address6.IP,
-									Mask: net.CIDRMask(128, 128),
-								},
-								AllowedProtocol: policy.Proto,
-								AllowedPorts:    policy.Port,
-								Allow:           true,
-							})
-							if policy.AllowedDirection == models.TrafficDirectionBi {
-								rules = append(rules, models.FwRule{
-									SrcIP: net.IPNet{
-										IP:   peer.Address6.IP,
-										Mask: net.CIDRMask(128, 128),
-									},
-									DstIP:           nodeI.StaticNode.AddressIPNet6(),
-									AllowedProtocol: policy.Proto,
-									AllowedPorts:    policy.Port,
-									Allow:           true,
-								})
-							}
-						}
-					}
-				}
-
+			if nodeI.StaticNode.IngressGatewayID != node.ID.String() &&
+				((!peer.IsStatic && peer.ID.String() != node.ID.String()) ||
+					(peer.IsStatic && peer.StaticNode.IngressGatewayID != node.ID.String())) {
+				continue
+			}
+			if peer.IsStatic {
+				peer = peer.StaticNode.ConvertToStaticNode()
+			}
+			if ok, allowedPolicies := IsNodeAllowedToCommunicateV1(nodeI.StaticNode.ConvertToStaticNode(), peer, true); ok {
+				rules = append(rules, getFwRulesForNodeAndPeerOnGw(nodeI.StaticNode.ConvertToStaticNode(), peer, allowedPolicies)...)
+			}
+			if ok, allowedPolicies := IsNodeAllowedToCommunicateV1(peer, nodeI.StaticNode.ConvertToStaticNode(), true); ok {
+				rules = append(rules, getFwRulesForNodeAndPeerOnGw(peer, nodeI.StaticNode.ConvertToStaticNode(), allowedPolicies)...)
 			}
 		}
 	}
@@ -738,11 +764,13 @@ func GetExtPeers(node, peer *models.Node) ([]wgtypes.PeerConfig, []models.IDandA
 	}
 	for _, extPeer := range extPeers {
 		extPeer := extPeer
+		fmt.Println("=====> checking EXT peer: ", extPeer.ClientID)
 		if !IsClientNodeAllowed(&extPeer, peer.ID.String()) {
 			continue
 		}
 		if extPeer.RemoteAccessClientID == "" {
 			if ok := IsPeerAllowed(extPeer.ConvertToStaticNode(), *peer, true); !ok {
+				fmt.Println("=====>1 checking EXT peer: ", extPeer.ClientID)
 				continue
 			}
 		} else {
@@ -831,7 +859,7 @@ func getExtpeerEgressRanges(node models.Node) (ranges, ranges6 []net.IPNet) {
 		if len(extPeer.ExtraAllowedIPs) == 0 {
 			continue
 		}
-		if ok, _ := IsNodeAllowedToCommunicate(extPeer.ConvertToStaticNode(), node, true); !ok {
+		if ok, _ := IsNodeAllowedToCommunicateV1(extPeer.ConvertToStaticNode(), node, true); !ok {
 			continue
 		}
 		for _, allowedRange := range extPeer.ExtraAllowedIPs {
@@ -858,7 +886,7 @@ func getExtpeersExtraRoutes(node models.Node) (egressRoutes []models.EgressNetwo
 		if len(extPeer.ExtraAllowedIPs) == 0 {
 			continue
 		}
-		if ok, _ := IsNodeAllowedToCommunicate(extPeer.ConvertToStaticNode(), node, true); !ok {
+		if ok, _ := IsNodeAllowedToCommunicateV1(extPeer.ConvertToStaticNode(), node, true); !ok {
 			continue
 		}
 		egressRoutes = append(egressRoutes, getExtPeerEgressRoute(node, extPeer)...)

+ 2 - 2
logic/gateway.go

@@ -220,7 +220,7 @@ func CreateIngressGateway(netid string, nodeid string, ingress models.IngressReq
 	if node.Tags == nil {
 		node.Tags = make(map[models.TagID]struct{})
 	}
-	node.Tags[models.TagID(fmt.Sprintf("%s.%s", netid, models.RemoteAccessTagName))] = struct{}{}
+	node.Tags[models.TagID(fmt.Sprintf("%s.%s", netid, models.GwTagName))] = struct{}{}
 	err = UpsertNode(&node)
 	if err != nil {
 		return models.Node{}, err
@@ -272,7 +272,7 @@ func DeleteIngressGateway(nodeid string) (models.Node, []models.ExtClient, error
 	if !servercfg.IsPro {
 		node.IsInternetGateway = false
 	}
-	delete(node.Tags, models.TagID(fmt.Sprintf("%s.%s", node.Network, models.RemoteAccessTagName)))
+	delete(node.Tags, models.TagID(fmt.Sprintf("%s.%s", node.Network, models.GwTagName)))
 	node.IngressGatewayRange = ""
 	node.Metadata = ""
 	err = UpsertNode(&node)

+ 21 - 1
logic/nodes.go

@@ -320,6 +320,7 @@ func DeleteNode(node *models.Node, purge bool) error {
 	if err := DissasociateNodeFromHost(node, host); err != nil {
 		return err
 	}
+	go RemoveNodeFromAclPolicy(*node)
 
 	return nil
 }
@@ -855,6 +856,9 @@ func GetTagMapWithNodesByNetwork(netID models.NetworkID, withStaticNodes bool) (
 	tagNodesMap = make(map[models.TagID][]models.Node)
 	nodes, _ := GetNetworkNodes(netID.String())
 	for _, nodeI := range nodes {
+		tagNodesMap[models.TagID(nodeI.ID.String())] = []models.Node{
+			nodeI,
+		}
 		if nodeI.Tags == nil {
 			continue
 		}
@@ -882,9 +886,19 @@ func AddTagMapWithStaticNodes(netID models.NetworkID,
 		return tagNodesMap
 	}
 	for _, extclient := range extclients {
-		if extclient.Tags == nil || extclient.RemoteAccessClientID != "" {
+		if extclient.RemoteAccessClientID != "" {
+			continue
+		}
+		tagNodesMap[models.TagID(extclient.ClientID)] = []models.Node{
+			{
+				IsStatic:   true,
+				StaticNode: extclient,
+			},
+		}
+		if extclient.Tags == nil {
 			continue
 		}
+
 		if extclient.Mutex != nil {
 			extclient.Mutex.Lock()
 		}
@@ -906,6 +920,12 @@ func AddTagMapWithStaticNodesWithUsers(netID models.NetworkID,
 		return tagNodesMap
 	}
 	for _, extclient := range extclients {
+		tagNodesMap[models.TagID(extclient.ClientID)] = []models.Node{
+			{
+				IsStatic:   true,
+				StaticNode: extclient,
+			},
+		}
 		if extclient.Tags == nil {
 			continue
 		}

+ 1 - 2
logic/peers.go

@@ -251,14 +251,13 @@ func GetPeerUpdateForHost(network string, host *models.Host, allNodes []models.N
 		defaultUserPolicy, _ := GetDefaultPolicy(models.NetworkID(node.Network), models.UserPolicy)
 		defaultDevicePolicy, _ := GetDefaultPolicy(models.NetworkID(node.Network), models.DevicePolicy)
 
-		if defaultDevicePolicy.Enabled && defaultUserPolicy.Enabled {
+		if (defaultDevicePolicy.Enabled && defaultUserPolicy.Enabled) || !checkIfAnyPolicyisUniDirectional(node) {
 			if node.NetworkRange.IP != nil {
 				hostPeerUpdate.FwUpdate.AllowedNetworks = append(hostPeerUpdate.FwUpdate.AllowedNetworks, node.NetworkRange)
 			}
 			if node.NetworkRange6.IP != nil {
 				hostPeerUpdate.FwUpdate.AllowedNetworks = append(hostPeerUpdate.FwUpdate.AllowedNetworks, node.NetworkRange6)
 			}
-
 		} else {
 			hostPeerUpdate.FwUpdate.AllowAll = false
 			rules := GetAclRulesForNode(&node)

+ 10 - 2
logic/tags.go

@@ -30,6 +30,14 @@ func GetTag(tagID models.TagID) (models.Tag, error) {
 	return tag, nil
 }
 
+func UpsertTag(tag models.Tag) error {
+	d, err := json.Marshal(tag)
+	if err != nil {
+		return err
+	}
+	return database.Insert(tag.ID.String(), string(d), database.TAG_TABLE_NAME)
+}
+
 // InsertTag - creates new tag
 func InsertTag(tag models.Tag) error {
 	tagMutex.Lock()
@@ -272,8 +280,8 @@ func CheckIDSyntax(id string) error {
 func CreateDefaultTags(netID models.NetworkID) {
 	// create tag for remote access gws in the network
 	tag := models.Tag{
-		ID:        models.TagID(fmt.Sprintf("%s.%s", netID.String(), models.RemoteAccessTagName)),
-		TagName:   models.RemoteAccessTagName,
+		ID:        models.TagID(fmt.Sprintf("%s.%s", netID.String(), models.GwTagName)),
+		TagName:   models.GwTagName,
 		Network:   netID,
 		CreatedBy: "auto",
 		CreatedAt: time.Now(),

+ 32 - 10
migrate/migrate.go

@@ -204,15 +204,6 @@ func updateNodes() {
 			logic.UpsertNode(&node)
 		}
 		if node.IsIngressGateway {
-			tagID := models.TagID(fmt.Sprintf("%s.%s", node.Network,
-				models.RemoteAccessTagName))
-			if node.Tags == nil {
-				node.Tags = make(map[models.TagID]struct{})
-			}
-			if _, ok := node.Tags[tagID]; !ok {
-				node.Tags[tagID] = struct{}{}
-				logic.UpsertNode(&node)
-			}
 			host, err := logic.GetHost(node.HostID.String())
 			if err == nil {
 				go logic.DeleteRole(models.GetRAGRoleID(node.Network, host.ID.String()), true)
@@ -448,7 +439,8 @@ func createDefaultTagsAndPolicies() {
 	for _, network := range networks {
 		logic.CreateDefaultTags(models.NetworkID(network.NetID))
 		logic.CreateDefaultAclNetworkPolicies(models.NetworkID(network.NetID))
-
+		// delete old remote access gws policy
+		logic.DeleteAcl(models.Acl{ID: fmt.Sprintf("%s.%s", network.NetID, "all-remote-access-gws")})
 	}
 	logic.MigrateAclPolicies()
 }
@@ -463,7 +455,37 @@ func migrateToGws() {
 			node.IsGw = true
 			node.IsIngressGateway = true
 			node.IsRelay = true
+			if node.Tags == nil {
+				node.Tags = make(map[models.TagID]struct{})
+			}
+			node.Tags[models.TagID(fmt.Sprintf("%s.%s", node.Network, models.GwTagName))] = struct{}{}
+			delete(node.Tags, models.TagID(fmt.Sprintf("%s.%s", node.Network, models.OldRemoteAccessTagName)))
 			logic.UpsertNode(&node)
 		}
 	}
+	acls := logic.ListAcls()
+	for _, acl := range acls {
+		upsert := false
+		for i, srcI := range acl.Src {
+			if srcI.ID == models.NodeTagID && srcI.Value == fmt.Sprintf("%s.%s", acl.NetworkID.String(), models.OldRemoteAccessTagName) {
+				srcI.Value = models.GwTagName
+				acl.Src[i] = srcI
+				upsert = true
+			}
+		}
+		for i, dstI := range acl.Dst {
+			if dstI.ID == models.NodeTagID && dstI.Value == fmt.Sprintf("%s.%s", acl.NetworkID.String(), models.OldRemoteAccessTagName) {
+				dstI.Value = models.GwTagName
+				acl.Dst[i] = dstI
+				upsert = true
+			}
+		}
+		if upsert {
+			logic.UpsertAcl(acl)
+		}
+	}
+	nets, _ := logic.GetNetworks()
+	for _, netI := range nets {
+		logic.DeleteTag(models.TagID(fmt.Sprintf("%s.%s", netI.NetID, models.OldRemoteAccessTagName)), true)
+	}
 }

+ 4 - 3
models/acl.go

@@ -25,14 +25,13 @@ const (
 	ICMP Protocol = "icmp"
 )
 
-type ServiceType string
-
 const (
 	Http        = "HTTP"
 	Https       = "HTTPS"
 	AllTCP      = "All TCP"
 	AllUDP      = "All UDP"
 	ICMPService = "ICMP"
+	SSH         = "SSH"
 	Custom      = "Custom"
 	Any         = "Any"
 )
@@ -58,7 +57,9 @@ type AclGroupType string
 const (
 	UserAclID                AclGroupType = "user"
 	UserGroupAclID           AclGroupType = "user-group"
-	DeviceAclID              AclGroupType = "tag"
+	NodeTagID                AclGroupType = "tag"
+	NodeID                   AclGroupType = "device"
+	EgressRange              AclGroupType = "egress-range"
 	NetmakerIPAclID          AclGroupType = "ip"
 	NetmakerSubNetRangeAClID AclGroupType = "ipset"
 )

+ 3 - 1
models/extclient.go

@@ -53,7 +53,9 @@ func (ext *ExtClient) ConvertToStaticNode() Node {
 
 	return Node{
 		CommonNode: CommonNode{
-			Network: ext.Network,
+			Network:  ext.Network,
+			Address:  ext.AddressIPNet4(),
+			Address6: ext.AddressIPNet6(),
 		},
 		Tags:       ext.Tags,
 		IsStatic:   true,

+ 5 - 1
models/tags.go

@@ -8,7 +8,8 @@ import (
 type TagID string
 
 const (
-	RemoteAccessTagName = "remote-access-gws"
+	OldRemoteAccessTagName = "remote-access-gws"
+	GwTagName              = "gateways"
 )
 
 func (id TagID) String() string {
@@ -23,6 +24,7 @@ type Tag struct {
 	ID        TagID     `json:"id"`
 	TagName   string    `json:"tag_name"`
 	Network   NetworkID `json:"network"`
+	ColorCode string    `json:"color_code"`
 	CreatedBy string    `json:"created_by"`
 	CreatedAt time.Time `json:"created_at"`
 }
@@ -30,6 +32,7 @@ type Tag struct {
 type CreateTagReq struct {
 	TagName     string    `json:"tag_name"`
 	Network     NetworkID `json:"network"`
+	ColorCode   string    `json:"color_code"`
 	TaggedNodes []ApiNode `json:"tagged_nodes"`
 }
 
@@ -48,5 +51,6 @@ type TagListRespNodes struct {
 type UpdateTagReq struct {
 	Tag
 	NewName     string    `json:"new_name"`
+	ColorCode   string    `json:"color_code"`
 	TaggedNodes []ApiNode `json:"tagged_nodes"`
 }

+ 3 - 3
pro/logic/status.go

@@ -41,7 +41,7 @@ func GetNodeStatus(node *models.Node, defaultEnabledPolicy bool) {
 			return
 		}
 		if !defaultEnabledPolicy {
-			allowed, _ := logic.IsNodeAllowedToCommunicate(*node, ingNode, false)
+			allowed, _ := logic.IsNodeAllowedToCommunicateV1(*node, ingNode, false)
 			if !allowed {
 				node.Status = models.OnlineSt
 				return
@@ -161,7 +161,7 @@ func checkPeerStatus(node *models.Node, defaultAclPolicy bool) {
 		}
 
 		if !defaultAclPolicy {
-			allowed, _ := logic.IsNodeAllowedToCommunicate(*node, peer, false)
+			allowed, _ := logic.IsNodeAllowedToCommunicateV1(*node, peer, false)
 			if !allowed {
 				continue
 			}
@@ -199,7 +199,7 @@ func checkPeerConnectivity(node *models.Node, metrics *models.Metrics, defaultAc
 		}
 
 		if !defaultAclPolicy {
-			allowed, _ := logic.IsNodeAllowedToCommunicate(*node, peer, false)
+			allowed, _ := logic.IsNodeAllowedToCommunicateV1(*node, peer, false)
 			if !allowed {
 				continue
 			}

+ 4 - 4
pro/logic/user_mgmt.go

@@ -1229,8 +1229,8 @@ func CreateDefaultUserPolicies(netID models.NetworkID) {
 			},
 			Dst: []models.AclPolicyTag{
 				{
-					ID:    models.DeviceAclID,
-					Value: fmt.Sprintf("%s.%s", netID, models.RemoteAccessTagName),
+					ID:    models.NodeTagID,
+					Value: fmt.Sprintf("%s.%s", netID, models.GwTagName),
 				}},
 			AllowedDirection: models.TrafficDirectionUni,
 			Enabled:          true,
@@ -1263,8 +1263,8 @@ func CreateDefaultUserPolicies(netID models.NetworkID) {
 
 			Dst: []models.AclPolicyTag{
 				{
-					ID:    models.DeviceAclID,
-					Value: fmt.Sprintf("%s.%s", netID, models.RemoteAccessTagName),
+					ID:    models.NodeTagID,
+					Value: fmt.Sprintf("%s.%s", netID, models.GwTagName),
 				}},
 			AllowedDirection: models.TrafficDirectionUni,
 			Enabled:          true,

+ 1 - 1
scripts/nm-quick.sh

@@ -253,7 +253,7 @@ save_config() { (
 	fi
 	# copy entries from the previous config
 	local toCopy=("SERVER_HOST" "SERVER_HOST6" "MASTER_KEY" "MQ_USERNAME" "MQ_PASSWORD" "LICENSE_KEY" "NETMAKER_TENANT_ID"
-		"INSTALL_TYPE" "NODE_ID" "DNS_MODE" "NETCLIENT_AUTO_UPDATE" "API_PORT"
+		"INSTALL_TYPE" "NODE_ID" "DNS_MODE" "NETCLIENT_AUTO_UPDATE" "API_PORT" "MANAGE_DNS" "DEFAULT_DOMAIN"
 		"CORS_ALLOWED_ORIGIN" "DISPLAY_KEYS" "DATABASE" "SERVER_BROKER_ENDPOINT" "VERBOSITY"
 		"DEBUG_MODE"  "REST_BACKEND" "DISABLE_REMOTE_IP_CHECK" "TELEMETRY" "ALLOWED_EMAIL_DOMAINS" "AUTH_PROVIDER" "CLIENT_ID" "CLIENT_SECRET"
 		"FRONTEND_URL" "AZURE_TENANT" "OIDC_ISSUER" "EXPORTER_API_PORT" "JWT_VALIDITY_DURATION" "RAC_AUTO_DISABLE" "CACHING_ENABLED" "ENDPOINT_DETECTION"