瀏覽代碼

NET-1932: sort out acls into CE and PRO (#3460)

* move relevant acl and tag code to CE and Pro pkgs

* intialise pro acl funcs

* list gateways by user access

* check user gw access by policies

* filter out user policies on CE

* filter out tagged policies on CE

* fix ce acl comms

* allow gateways tag

* allow gateway tag  on CE, remove failover and gw check on acl policy

* add gw rules func to pro

* add inet gw support on CE

* add egress acl API

* add egress acl API

* fix(go): set is_gw when converting api node to server node;

* fix(go): set is_gw when converting api node to server node;

* fix policy validity checker for inet gws

* move dns option to host model

* fix node removal from egress policy on delete

* add migration logic for ManageDNS

* fix dns json field

* fix nil error on node tags

* add egress info to relayed nodes

---------

Co-authored-by: Vishal Dalwadi <[email protected]>
Abhishek K 3 月之前
父節點
當前提交
5849e0e2e1

+ 34 - 1
controllers/acls.go

@@ -9,15 +9,19 @@ import (
 
 	"github.com/google/uuid"
 	"github.com/gorilla/mux"
+	"github.com/gravitl/netmaker/db"
 	"github.com/gravitl/netmaker/logger"
 	"github.com/gravitl/netmaker/logic"
 	"github.com/gravitl/netmaker/models"
 	"github.com/gravitl/netmaker/mq"
+	"github.com/gravitl/netmaker/schema"
 )
 
 func aclHandlers(r *mux.Router) {
 	r.HandleFunc("/api/v1/acls", logic.SecurityCheck(true, http.HandlerFunc(getAcls))).
 		Methods(http.MethodGet)
+	r.HandleFunc("/api/v1/acls/egress", logic.SecurityCheck(true, http.HandlerFunc(getEgressAcls))).
+		Methods(http.MethodGet)
 	r.HandleFunc("/api/v1/acls/policy_types", logic.SecurityCheck(true, http.HandlerFunc(aclPolicyTypes))).
 		Methods(http.MethodGet)
 	r.HandleFunc("/api/v1/acls", logic.SecurityCheck(true, http.HandlerFunc(createAcl))).
@@ -174,7 +178,7 @@ func aclDebug(w http.ResponseWriter, r *http.Request) {
 		NodeAllPolicy bool
 	}
 
-	allowed, ps := logic.IsNodeAllowedToCommunicateV1(node, peer, true)
+	allowed, ps := logic.IsNodeAllowedToCommunicate(node, peer, true)
 	isallowed := logic.IsPeerAllowed(node, peer, true)
 	re := resp{
 		IsNodeAllowed: allowed,
@@ -218,6 +222,35 @@ func getAcls(w http.ResponseWriter, r *http.Request) {
 	logic.ReturnSuccessResponseWithJson(w, r, acls, "fetched all acls in the network "+netID)
 }
 
+// @Summary     List Egress Acls in a network
+// @Router      /api/v1/acls [get]
+// @Tags        ACL
+// @Accept      json
+// @Success     200 {array} models.SuccessResponse
+// @Failure     500 {object} models.ErrorResponse
+func getEgressAcls(w http.ResponseWriter, r *http.Request) {
+	eID := r.URL.Query().Get("egress_id")
+	if eID == "" {
+		logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("egress id param is missing"), "badrequest"))
+		return
+	}
+	e := schema.Egress{ID: eID}
+	// check if network exists
+	err := e.Get(db.WithContext(r.Context()))
+	if err != nil {
+		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
+		return
+	}
+	acls, err := logic.ListEgressAcls(eID)
+	if err != nil {
+		logger.Log(0, r.Header.Get("user"), "failed to get all network acl entries: ", err.Error())
+		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
+		return
+	}
+	logic.SortAclEntrys(acls[:])
+	logic.ReturnSuccessResponseWithJson(w, r, acls, "fetched acls for egress"+e.Name)
+}
+
 // @Summary     Create Acl
 // @Router      /api/v1/acls [post]
 // @Tags        ACL

+ 2 - 2
controllers/controller.go

@@ -3,13 +3,14 @@ package controller
 import (
 	"context"
 	"fmt"
-	"github.com/gravitl/netmaker/db"
 	"net/http"
 	"os"
 	"strings"
 	"sync"
 	"time"
 
+	"github.com/gravitl/netmaker/db"
+
 	"github.com/gorilla/handlers"
 	"github.com/gorilla/mux"
 	"github.com/gravitl/netmaker/logger"
@@ -37,7 +38,6 @@ var HttpHandlers = []interface{}{
 	loggerHandlers,
 	hostHandlers,
 	enrollmentKeyHandlers,
-	tagHandlers,
 	aclHandlers,
 	egressHandlers,
 	legacyHandlers,

+ 0 - 2
controllers/dns_test.go

@@ -65,7 +65,6 @@ func TestGetNodeDNS(t *testing.T) {
 			ID:      uuid.New(),
 			Network: "skynet",
 			Address: *ipnet,
-			DNSOn:   true,
 		}
 		createnode := models.Node{
 			CommonNode: tmpCNode,
@@ -82,7 +81,6 @@ func TestGetNodeDNS(t *testing.T) {
 			ID:      uuid.New(),
 			Network: "skynet",
 			Address: *ipnet,
-			DNSOn:   true,
 		}
 		createnode := models.Node{
 			CommonNode: tmpCNode,

+ 2 - 0
controllers/gateway.go

@@ -109,6 +109,8 @@ func createGateway(w http.ResponseWriter, r *http.Request) {
 		},
 		Origin: models.Dashboard,
 	})
+	host.IsStaticPort = true
+	logic.UpsertHost(host)
 	w.WriteHeader(http.StatusOK)
 	json.NewEncoder(w).Encode(apiNode)
 	go func() {

+ 0 - 1
controllers/migrate.go

@@ -207,7 +207,6 @@ func convertLegacyNode(legacy models.LegacyNode, hostID uuid.UUID) models.Node {
 	node.IsRelayed = false
 	node.IsRelay = false
 	node.RelayedNodes = []string{}
-	node.DNSOn = models.ParseBool(legacy.DNSOn)
 	node.LastModified = time.Now().UTC()
 	node.ExpirationDateTime = time.Unix(legacy.ExpirationDateTime, 0)
 	node.EgressGatewayNatEnabled = models.ParseBool(legacy.EgressGatewayNatEnabled)

+ 0 - 1
controllers/node_test.go

@@ -143,7 +143,6 @@ func createNodeWithParams(network, address string) *models.Node {
 		ID:      uuid.New(),
 		Network: "skynet",
 		Address: *ipnet,
-		DNSOn:   true,
 	}
 	if len(network) > 0 {
 		tmpCNode.Network = network

文件差異過大導致無法顯示
+ 499 - 471
logic/acls.go


+ 39 - 91
logic/egress.go

@@ -63,93 +63,6 @@ func ValidateEgressReq(e *schema.Egress) error {
 	return nil
 }
 
-func GetInetClientsFromAclPolicies(eID string) (inetClientIDs []string) {
-	e := schema.Egress{ID: eID}
-	err := e.Get(db.WithContext(context.TODO()))
-	if err != nil || !e.Status {
-		return
-	}
-	acls, _ := ListAclsByNetwork(models.NetworkID(e.Network))
-	for _, acl := range acls {
-		for _, dstI := range acl.Dst {
-			if dstI.ID == models.EgressID {
-				if dstI.Value != eID {
-					continue
-				}
-				for _, srcI := range acl.Src {
-					if srcI.Value == "*" {
-						continue
-					}
-					if srcI.ID == models.NodeID {
-						inetClientIDs = append(inetClientIDs, srcI.Value)
-					}
-					if srcI.ID == models.NodeTagID {
-						inetClientIDs = append(inetClientIDs, GetNodeIDsWithTag(models.TagID(srcI.Value))...)
-					}
-				}
-			}
-		}
-	}
-	return
-}
-
-func isNodeUsingInternetGw(node *models.Node) {
-	host, err := GetHost(node.HostID.String())
-	if err != nil {
-		return
-	}
-	if host.IsDefault || node.IsFailOver {
-		return
-	}
-	nodeTags := maps.Clone(node.Tags)
-	nodeTags[models.TagID(node.ID.String())] = struct{}{}
-	acls, _ := ListAclsByNetwork(models.NetworkID(node.Network))
-	var isUsing bool
-	for _, acl := range acls {
-		if !acl.Enabled {
-			continue
-		}
-		srcVal := convAclTagToValueMap(acl.Src)
-		for _, dstI := range acl.Dst {
-			if dstI.ID == models.EgressID {
-				e := schema.Egress{ID: dstI.Value}
-				err := e.Get(db.WithContext(context.TODO()))
-				if err != nil || !e.Status {
-					continue
-				}
-
-				if e.IsInetGw {
-					if _, ok := srcVal[node.ID.String()]; ok {
-						for nodeID := range e.Nodes {
-							if nodeID == node.ID.String() {
-								continue
-							}
-							node.EgressDetails.InternetGwID = nodeID
-							isUsing = true
-							return
-						}
-					}
-					for tagID := range nodeTags {
-						if _, ok := srcVal[tagID.String()]; ok {
-							for nodeID := range e.Nodes {
-								if nodeID == node.ID.String() {
-									continue
-								}
-								node.EgressDetails.InternetGwID = nodeID
-								isUsing = true
-								return
-							}
-						}
-					}
-				}
-			}
-		}
-	}
-	if !isUsing {
-		node.EgressDetails.InternetGwID = ""
-	}
-}
-
 func DoesNodeHaveAccessToEgress(node *models.Node, e *schema.Egress) bool {
 	nodeTags := maps.Clone(node.Tags)
 	nodeTags[models.TagID(node.ID.String())] = struct{}{}
@@ -167,7 +80,7 @@ func DoesNodeHaveAccessToEgress(node *models.Node, e *schema.Egress) bool {
 		if !acl.Enabled {
 			continue
 		}
-		srcVal := convAclTagToValueMap(acl.Src)
+		srcVal := ConvAclTagToValueMap(acl.Src)
 		if !e.IsInetGw && acl.AllowedDirection == models.TrafficDirectionBi {
 			if _, ok := srcVal["*"]; ok {
 				return true
@@ -216,7 +129,7 @@ func AddEgressInfoToPeerByAccess(node, targetNode *models.Node) {
 		if targetNode.Mutex != nil {
 			targetNode.Mutex.Lock()
 		}
-		isNodeUsingInternetGw(targetNode)
+		IsNodeUsingInternetGw(targetNode)
 		if targetNode.Mutex != nil {
 			targetNode.Mutex.Unlock()
 		}
@@ -296,7 +209,7 @@ func GetNodeEgressInfo(targetNode *models.Node) {
 		if targetNode.Mutex != nil {
 			targetNode.Mutex.Lock()
 		}
-		isNodeUsingInternetGw(targetNode)
+		IsNodeUsingInternetGw(targetNode)
 		if targetNode.Mutex != nil {
 			targetNode.Mutex.Unlock()
 		}
@@ -355,7 +268,9 @@ func GetNodeEgressInfo(targetNode *models.Node) {
 }
 
 func RemoveNodeFromEgress(node models.Node) {
-	egs, _ := (&schema.Egress{}).ListByNetwork(db.WithContext(context.TODO()))
+	egs, _ := (&schema.Egress{
+		Network: node.Network,
+	}).ListByNetwork(db.WithContext(context.TODO()))
 	for _, egI := range egs {
 		if _, ok := egI.Nodes[node.ID.String()]; ok {
 			delete(egI.Nodes, node.ID.String())
@@ -364,3 +279,36 @@ func RemoveNodeFromEgress(node models.Node) {
 	}
 
 }
+
+func GetEgressRanges(netID models.NetworkID) (map[string][]string, map[string]struct{}, error) {
+
+	resultMap := make(map[string]struct{})
+	nodeEgressMap := make(map[string][]string)
+	networkNodes, err := GetNetworkNodes(netID.String())
+	if err != nil {
+		return nil, nil, err
+	}
+	for _, currentNode := range networkNodes {
+		if currentNode.Network != netID.String() {
+			continue
+		}
+		if currentNode.EgressDetails.IsEgressGateway { // add the egress gateway range(s) to the result
+			if len(currentNode.EgressDetails.EgressGatewayRanges) > 0 {
+				nodeEgressMap[currentNode.ID.String()] = currentNode.EgressDetails.EgressGatewayRanges
+				for _, egressRangeI := range currentNode.EgressDetails.EgressGatewayRanges {
+					resultMap[egressRangeI] = struct{}{}
+				}
+			}
+		}
+	}
+	extclients, _ := GetNetworkExtClients(netID.String())
+	for _, extclient := range extclients {
+		if len(extclient.ExtraAllowedIPs) > 0 {
+			nodeEgressMap[extclient.ClientID] = extclient.ExtraAllowedIPs
+			for _, extraAllowedIP := range extclient.ExtraAllowedIPs {
+				resultMap[extraAllowedIP] = struct{}{}
+			}
+		}
+	}
+	return nodeEgressMap, resultMap, nil
+}

+ 26 - 363
logic/extpeers.go

@@ -1,7 +1,6 @@
 package logic
 
 import (
-	"context"
 	"encoding/json"
 	"errors"
 	"fmt"
@@ -14,11 +13,9 @@ import (
 
 	"github.com/goombaio/namegenerator"
 	"github.com/gravitl/netmaker/database"
-	"github.com/gravitl/netmaker/db"
 	"github.com/gravitl/netmaker/logger"
 	"github.com/gravitl/netmaker/logic/acls"
 	"github.com/gravitl/netmaker/models"
-	"github.com/gravitl/netmaker/schema"
 	"github.com/gravitl/netmaker/servercfg"
 	"golang.org/x/exp/slog"
 	"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
@@ -84,7 +81,6 @@ func GetEgressRangesOnNetwork(client *models.ExtClient) ([]string, error) {
 			continue
 		}
 		if currentNode.EgressDetails.IsEgressGateway { // add the egress gateway range(s) to the result
-			fmt.Println("EGRESSS EXTCLEINT: ", currentNode.EgressDetails)
 			if len(currentNode.EgressDetails.EgressGatewayRanges) > 0 {
 				result = append(result, currentNode.EgressDetails.EgressGatewayRanges...)
 			}
@@ -98,7 +94,30 @@ func GetEgressRangesOnNetwork(client *models.ExtClient) ([]string, error) {
 		result = append(result, extclient.ExtraAllowedIPs...)
 	}
 
-	return result, nil
+	return UniqueIPNetStrList(result), nil
+}
+
+// UniqueIPNetList deduplicates and sorts a list of CIDR strings.
+func UniqueIPNetStrList(ipnets []string) []string {
+	uniqueMap := make(map[string]struct{})
+
+	for _, cidr := range ipnets {
+		_, ipnet, err := net.ParseCIDR(cidr)
+		if err != nil {
+			continue // skip invalid CIDR strings
+		}
+		key := ipnet.String() // normalized CIDR
+		uniqueMap[key] = struct{}{}
+	}
+
+	// Convert map keys to slice
+	uniqueList := make([]string, 0, len(uniqueMap))
+	for cidr := range uniqueMap {
+		uniqueList = append(uniqueList, cidr)
+	}
+
+	sort.Strings(uniqueList)
+	return uniqueList
 }
 
 // DeleteExtClient - deletes an existing ext client
@@ -493,362 +512,6 @@ func ToggleExtClientConnectivity(client *models.ExtClient, enable bool) (models.
 	return newClient, nil
 }
 
-// Sort a slice of net.IP addresses
-func sortIPs(ips []net.IP) {
-	sort.Slice(ips, func(i, j int) bool {
-		ip1, ip2 := ips[i].To16(), ips[j].To16()
-		return string(ip1) < string(ip2) // Compare as byte slices
-	})
-}
-
-func GetStaticNodeIps(node models.Node) (ips []net.IP) {
-	defer func() {
-		sortIPs(ips)
-	}()
-	defaultUserPolicy, _ := GetDefaultPolicy(models.NetworkID(node.Network), models.UserPolicy)
-	defaultDevicePolicy, _ := GetDefaultPolicy(models.NetworkID(node.Network), models.DevicePolicy)
-
-	extclients := GetStaticNodesByNetwork(models.NetworkID(node.Network), false)
-	for _, extclient := range extclients {
-		if extclient.IsUserNode && defaultUserPolicy.Enabled {
-			continue
-		}
-		if !extclient.IsUserNode && defaultDevicePolicy.Enabled {
-			continue
-		}
-		if extclient.StaticNode.Address != "" {
-			ips = append(ips, extclient.StaticNode.AddressIPNet4().IP)
-		}
-		if extclient.StaticNode.Address6 != "" {
-			ips = append(ips, extclient.StaticNode.AddressIPNet6().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,
-					})
-				}
-
-			}
-
-		}
-
-		// add egress range rules
-		for _, dstI := range policy.Dst {
-			if dstI.ID == models.EgressID {
-
-				e := schema.Egress{ID: dstI.Value}
-				err := e.Get(db.WithContext(context.TODO()))
-				if err != nil {
-					continue
-				}
-				dstI.Value = e.Range
-
-				ip, cidr, err := net.ParseCIDR(dstI.Value)
-				if err == nil {
-					if ip.To4() != nil {
-						if node.Address.IP != nil {
-							rules = append(rules, models.FwRule{
-								SrcIP: net.IPNet{
-									IP:   node.Address.IP,
-									Mask: net.CIDRMask(32, 32),
-								},
-								DstIP:           *cidr,
-								AllowedProtocol: policy.Proto,
-								AllowedPorts:    policy.Port,
-								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:           *cidr,
-								AllowedProtocol: policy.Proto,
-								AllowedPorts:    policy.Port,
-								Allow:           true,
-							})
-						}
-					}
-
-				}
-			}
-		}
-	}
-
-	return
-}
-
-func getFwRulesForUserNodesOnGw(node models.Node, nodes []models.Node) (rules []models.FwRule) {
-	defaultUserPolicy, _ := GetDefaultPolicy(models.NetworkID(node.Network), models.UserPolicy)
-	userNodes := GetStaticUserNodesByNetwork(models.NetworkID(node.Network))
-	for _, userNodeI := range userNodes {
-		for _, peer := range nodes {
-			if peer.IsUserNode {
-				continue
-			}
-
-			if ok, allowedPolicies := IsUserAllowedToCommunicate(userNodeI.StaticNode.OwnerID, peer); ok {
-				if peer.IsStatic {
-					peer = peer.StaticNode.ConvertToStaticNode()
-				}
-				if !defaultUserPolicy.Enabled {
-					for _, policy := range allowedPolicies {
-						if userNodeI.StaticNode.Address != "" {
-							rules = append(rules, models.FwRule{
-								SrcIP: userNodeI.StaticNode.AddressIPNet4(),
-								DstIP: net.IPNet{
-									IP:   peer.Address.IP,
-									Mask: net.CIDRMask(32, 32),
-								},
-								AllowedProtocol: policy.Proto,
-								AllowedPorts:    policy.Port,
-								Allow:           true,
-							})
-						}
-						if userNodeI.StaticNode.Address6 != "" {
-							rules = append(rules, models.FwRule{
-								SrcIP: userNodeI.StaticNode.AddressIPNet6(),
-								DstIP: net.IPNet{
-									IP:   peer.Address6.IP,
-									Mask: net.CIDRMask(128, 128),
-								},
-								AllowedProtocol: policy.Proto,
-								AllowedPorts:    policy.Port,
-								Allow:           true,
-							})
-						}
-
-						// add egress ranges
-						for _, dstI := range policy.Dst {
-							if dstI.ID == models.EgressID {
-
-								e := schema.Egress{ID: dstI.Value}
-								err := e.Get(db.WithContext(context.TODO()))
-								if err != nil {
-									continue
-								}
-								dstI.Value = e.Range
-
-								ip, cidr, err := net.ParseCIDR(dstI.Value)
-								if err == nil {
-									if ip.To4() != nil && userNodeI.StaticNode.Address != "" {
-										rules = append(rules, models.FwRule{
-											SrcIP:           userNodeI.StaticNode.AddressIPNet4(),
-											DstIP:           *cidr,
-											AllowedProtocol: policy.Proto,
-											AllowedPorts:    policy.Port,
-											Allow:           true,
-										})
-									} else if ip.To16() != nil && userNodeI.StaticNode.Address6 != "" {
-										rules = append(rules, models.FwRule{
-											SrcIP:           userNodeI.StaticNode.AddressIPNet6(),
-											DstIP:           *cidr,
-											AllowedProtocol: policy.Proto,
-											AllowedPorts:    policy.Port,
-											Allow:           true,
-										})
-									}
-								}
-							}
-						}
-
-					}
-				}
-
-			}
-		}
-	}
-	return
-}
-
-func GetFwRulesOnIngressGateway(node models.Node) (rules []models.FwRule) {
-	// fetch user access to static clients via policies
-	defer func() {
-		sort.Slice(rules, func(i, j int) bool {
-			if !rules[i].SrcIP.IP.Equal(rules[j].SrcIP.IP) {
-				return string(rules[i].SrcIP.IP.To16()) < string(rules[j].SrcIP.IP.To16())
-			}
-			return string(rules[i].DstIP.IP.To16()) < string(rules[j].DstIP.IP.To16())
-		})
-	}()
-	defaultDevicePolicy, _ := GetDefaultPolicy(models.NetworkID(node.Network), models.DevicePolicy)
-	nodes, _ := GetNetworkNodes(node.Network)
-	nodes = append(nodes, GetStaticNodesByNetwork(models.NetworkID(node.Network), true)...)
-	rules = getFwRulesForUserNodesOnGw(node, nodes)
-	if defaultDevicePolicy.Enabled {
-		return
-	}
-	for _, nodeI := range nodes {
-		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 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()
-			}
-			var allowedPolicies1 []models.Acl
-			var ok bool
-			if ok, allowedPolicies1 = IsNodeAllowedToCommunicateV1(nodeI.StaticNode.ConvertToStaticNode(), peer, true); ok {
-				rules = append(rules, getFwRulesForNodeAndPeerOnGw(nodeI.StaticNode.ConvertToStaticNode(), peer, allowedPolicies1)...)
-			}
-			if ok, allowedPolicies2 := IsNodeAllowedToCommunicateV1(peer, nodeI.StaticNode.ConvertToStaticNode(), true); ok {
-				rules = append(rules,
-					getFwRulesForNodeAndPeerOnGw(peer, nodeI.StaticNode.ConvertToStaticNode(),
-						GetUniquePolicies(allowedPolicies1, allowedPolicies2))...)
-			}
-		}
-	}
-	return
-}
-
-func GetUniquePolicies(policies1, policies2 []models.Acl) []models.Acl {
-	policies1Map := make(map[string]struct{})
-	for _, policy1I := range policies1 {
-		policies1Map[policy1I.ID] = struct{}{}
-	}
-	for i := len(policies2) - 1; i >= 0; i-- {
-		if _, ok := policies1Map[policies2[i].ID]; ok {
-			policies2 = append(policies2[:i], policies2[i+1:]...)
-		}
-	}
-	return policies2
-}
-
 func GetExtPeers(node, peer *models.Node) ([]wgtypes.PeerConfig, []models.IDandAddr, []models.EgressNetworkRoutes, error) {
 	var peers []wgtypes.PeerConfig
 	var idsAndAddr []models.IDandAddr
@@ -964,7 +627,7 @@ func getExtpeerEgressRanges(node models.Node) (ranges, ranges6 []net.IPNet) {
 		if len(extPeer.ExtraAllowedIPs) == 0 {
 			continue
 		}
-		if ok, _ := IsNodeAllowedToCommunicateV1(extPeer.ConvertToStaticNode(), node, true); !ok {
+		if ok, _ := IsNodeAllowedToCommunicate(extPeer.ConvertToStaticNode(), node, true); !ok {
 			continue
 		}
 		for _, allowedRange := range extPeer.ExtraAllowedIPs {
@@ -991,7 +654,7 @@ func getExtpeersExtraRoutes(node models.Node) (egressRoutes []models.EgressNetwo
 		if len(extPeer.ExtraAllowedIPs) == 0 {
 			continue
 		}
-		if ok, _ := IsNodeAllowedToCommunicateV1(extPeer.ConvertToStaticNode(), node, true); !ok {
+		if ok, _ := IsNodeAllowedToCommunicate(extPeer.ConvertToStaticNode(), node, true); !ok {
 			continue
 		}
 		egressRoutes = append(egressRoutes, getExtPeerEgressRoute(node, extPeer)...)

+ 6 - 0
logic/hosts.go

@@ -229,6 +229,12 @@ func CreateHost(h *models.Host) error {
 	}
 	h.HostPass = string(hash)
 	h.AutoUpdate = AutoUpdateEnabled()
+
+	if GetServerSettings().ManageDNS {
+		h.DNS = "on"
+	} else {
+		h.DNS = "off"
+	}
 	checkForZombieHosts(h)
 	return UpsertHost(h)
 }

+ 111 - 167
logic/nodes.go

@@ -30,6 +30,8 @@ var (
 	nodeNetworkCacheMutex = &sync.RWMutex{}
 	nodesCacheMap         = make(map[string]models.Node)
 	nodesNetworkCacheMap  = make(map[string]map[string]models.Node)
+	IPv4Network           = "0.0.0.0/0"
+	IPv6Network           = "::/0"
 )
 
 func getNodeFromCache(nodeID string) (node models.Node, ok bool) {
@@ -641,14 +643,6 @@ func createNode(node *models.Node) error {
 		return err
 	}
 
-	if !node.DNSOn {
-		if servercfg.IsDNSMode() {
-			node.DNSOn = true
-		} else {
-			node.DNSOn = false
-		}
-	}
-
 	SetNodeDefaults(node, true)
 
 	defaultACLVal := acls.Allowed
@@ -833,206 +827,156 @@ func GetAllFailOvers() ([]models.Node, error) {
 	return igs, nil
 }
 
-func GetTagMapWithNodes() (tagNodesMap map[models.TagID][]models.Node) {
-	tagNodesMap = make(map[models.TagID][]models.Node)
-	nodes, _ := GetAllNodes()
-	for _, nodeI := range nodes {
-		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()
-		}
-
+func ValidateInetGwReq(inetNode models.Node, req models.InetNodeReq, update bool) error {
+	inetHost, err := GetHost(inetNode.HostID.String())
+	if err != nil {
+		return err
+	}
+	if inetHost.FirewallInUse == models.FIREWALL_NONE {
+		return errors.New("iptables or nftables needs to be installed")
+	}
+	if inetNode.EgressDetails.InternetGwID != "" {
+		return fmt.Errorf("node %s is using a internet gateway already", inetHost.Name)
+	}
+	if inetNode.IsRelayed {
+		return fmt.Errorf("node %s is being relayed", inetHost.Name)
 	}
-	return
-}
 
-func GetTagMapWithNodesByNetwork(netID models.NetworkID, withStaticNodes bool) (tagNodesMap map[models.TagID][]models.Node) {
-	tagNodesMap = make(map[models.TagID][]models.Node)
-	nodes, _ := GetNetworkNodes(netID.String())
-	for _, nodeI := range nodes {
-		tagNodesMap[models.TagID(nodeI.ID.String())] = []models.Node{
-			nodeI,
+	for _, clientNodeID := range req.InetNodeClientIDs {
+		clientNode, err := GetNodeByID(clientNodeID)
+		if err != nil {
+			return err
 		}
-		if nodeI.Tags == nil {
-			continue
+		if clientNode.IsFailOver {
+			return errors.New("failover node cannot be set to use internet gateway")
 		}
-		if nodeI.Mutex != nil {
-			nodeI.Mutex.Lock()
+		clientHost, err := GetHost(clientNode.HostID.String())
+		if err != nil {
+			return err
 		}
-		for nodeTagID := range nodeI.Tags {
-			if nodeTagID == models.TagID(nodeI.ID.String()) {
-				continue
-			}
-			tagNodesMap[nodeTagID] = append(tagNodesMap[nodeTagID], nodeI)
+		if clientHost.IsDefault {
+			return errors.New("default host cannot be set to use internet gateway")
 		}
-		if nodeI.Mutex != nil {
-			nodeI.Mutex.Unlock()
+		if clientHost.OS != models.OS_Types.Linux && clientHost.OS != models.OS_Types.Windows {
+			return errors.New("can only attach linux or windows machine to a internet gateway")
 		}
-	}
-	tagNodesMap["*"] = nodes
-	if !withStaticNodes {
-		return
-	}
-	return AddTagMapWithStaticNodes(netID, tagNodesMap)
-}
-
-func AddTagMapWithStaticNodes(netID models.NetworkID,
-	tagNodesMap map[models.TagID][]models.Node) map[models.TagID][]models.Node {
-	extclients, err := GetNetworkExtClients(netID.String())
-	if err != nil {
-		return tagNodesMap
-	}
-	for _, extclient := range extclients {
-		if extclient.RemoteAccessClientID != "" {
-			continue
+		if clientNode.EgressDetails.IsInternetGateway {
+			return fmt.Errorf("node %s acting as internet gateway cannot use another internet gateway", clientHost.Name)
 		}
-		tagNodesMap[models.TagID(extclient.ClientID)] = []models.Node{
-			{
-				IsStatic:   true,
-				StaticNode: extclient,
-			},
+		if update {
+			if clientNode.EgressDetails.InternetGwID != "" && clientNode.EgressDetails.InternetGwID != inetNode.ID.String() {
+				return fmt.Errorf("node %s is already using a internet gateway", clientHost.Name)
+			}
+		} else {
+			if clientNode.EgressDetails.InternetGwID != "" {
+				return fmt.Errorf("node %s is already using a internet gateway", clientHost.Name)
+			}
 		}
-		if extclient.Tags == nil {
-			continue
+		if clientNode.FailedOverBy != uuid.Nil {
+			ResetFailedOverPeer(&clientNode)
 		}
 
-		if extclient.Mutex != nil {
-			extclient.Mutex.Lock()
+		if clientNode.IsRelayed && clientNode.RelayedBy != inetNode.ID.String() {
+			return fmt.Errorf("node %s is being relayed", clientHost.Name)
 		}
-		for tagID := range extclient.Tags {
-			if tagID == models.TagID(extclient.ClientID) {
+
+		for _, nodeID := range clientHost.Nodes {
+			node, err := GetNodeByID(nodeID)
+			if err != nil {
 				continue
 			}
-			tagNodesMap[tagID] = append(tagNodesMap[tagID], extclient.ConvertToStaticNode())
-			tagNodesMap["*"] = append(tagNodesMap["*"], extclient.ConvertToStaticNode())
-		}
-		if extclient.Mutex != nil {
-			extclient.Mutex.Unlock()
+			if node.EgressDetails.InternetGwID != "" && node.EgressDetails.InternetGwID != inetNode.ID.String() {
+				return errors.New("nodes on same host cannot use different internet gateway")
+			}
+
 		}
 	}
-	return tagNodesMap
+	return nil
 }
 
-func AddTagMapWithStaticNodesWithUsers(netID models.NetworkID,
-	tagNodesMap map[models.TagID][]models.Node) map[models.TagID][]models.Node {
-	extclients, err := GetNetworkExtClients(netID.String())
-	if err != nil {
-		return tagNodesMap
-	}
-	for _, extclient := range extclients {
-		tagNodesMap[models.TagID(extclient.ClientID)] = []models.Node{
-			{
-				IsStatic:   true,
-				StaticNode: extclient,
-			},
-		}
-		if extclient.Tags == nil {
+// SetInternetGw - sets the node as internet gw based on flag bool
+func SetInternetGw(node *models.Node, req models.InetNodeReq) {
+	node.EgressDetails.IsInternetGateway = true
+	node.EgressDetails.InetNodeReq = req
+	for _, clientNodeID := range req.InetNodeClientIDs {
+		clientNode, err := GetNodeByID(clientNodeID)
+		if err != nil {
 			continue
 		}
-		if extclient.Mutex != nil {
-			extclient.Mutex.Lock()
-		}
-		for tagID := range extclient.Tags {
-			tagNodesMap[tagID] = append(tagNodesMap[tagID], extclient.ConvertToStaticNode())
-		}
-		if extclient.Mutex != nil {
-			extclient.Mutex.Unlock()
-		}
-
+		clientNode.EgressDetails.InternetGwID = node.ID.String()
+		UpsertNode(&clientNode)
 	}
-	return tagNodesMap
-}
 
-func GetNodeIDsWithTag(tagID models.TagID) (ids []string) {
+}
 
-	tag, err := GetTag(tagID)
+func UnsetInternetGw(node *models.Node) {
+	nodes, err := GetNetworkNodes(node.Network)
 	if err != nil {
+		slog.Error("failed to get network nodes", "network", node.Network, "error", err)
 		return
 	}
-	nodes, _ := GetNetworkNodes(tag.Network.String())
-	for _, nodeI := range nodes {
-		if nodeI.Tags == nil {
-			continue
-		}
-		if nodeI.Mutex != nil {
-			nodeI.Mutex.Lock()
-		}
-		if _, ok := nodeI.Tags[tagID]; ok {
-			ids = append(ids, nodeI.ID.String())
-		}
-		if nodeI.Mutex != nil {
-			nodeI.Mutex.Unlock()
+	for _, clientNode := range nodes {
+		if node.ID.String() == clientNode.EgressDetails.InternetGwID {
+			clientNode.EgressDetails.InternetGwID = ""
+			UpsertNode(&clientNode)
 		}
+
 	}
-	return
+	node.EgressDetails.IsInternetGateway = false
+	node.EgressDetails.InetNodeReq = models.InetNodeReq{}
+
 }
 
-func GetNodesWithTag(tagID models.TagID) map[string]models.Node {
-	nMap := make(map[string]models.Node)
-	tag, err := GetTag(tagID)
-	if err != nil {
-		return nMap
-	}
-	nodes, _ := GetNetworkNodes(tag.Network.String())
-	for _, nodeI := range nodes {
-		if nodeI.Tags == nil {
-			continue
-		}
-		if nodeI.Mutex != nil {
-			nodeI.Mutex.Lock()
-		}
-		if _, ok := nodeI.Tags[tagID]; ok {
-			nMap[nodeI.ID.String()] = nodeI
+func SetDefaultGwForRelayedUpdate(relayed, relay models.Node, peerUpdate models.HostPeerUpdate) models.HostPeerUpdate {
+	if relay.EgressDetails.InternetGwID != "" {
+		relayedHost, err := GetHost(relayed.HostID.String())
+		if err != nil {
+			return peerUpdate
 		}
-		if nodeI.Mutex != nil {
-			nodeI.Mutex.Unlock()
+		peerUpdate.ChangeDefaultGw = true
+		peerUpdate.DefaultGwIp = relay.Address.IP
+		if peerUpdate.DefaultGwIp == nil || relayedHost.EndpointIP == nil {
+			peerUpdate.DefaultGwIp = relay.Address6.IP
 		}
+
 	}
-	return AddStaticNodesWithTag(tag, nMap)
+	return peerUpdate
 }
 
-func AddStaticNodesWithTag(tag models.Tag, nMap map[string]models.Node) map[string]models.Node {
-	extclients, err := GetNetworkExtClients(tag.Network.String())
-	if err != nil {
-		return nMap
-	}
-	for _, extclient := range extclients {
-		if extclient.RemoteAccessClientID != "" {
-			continue
-		}
-		if extclient.Mutex != nil {
-			extclient.Mutex.Lock()
+func SetDefaultGw(node models.Node, peerUpdate models.HostPeerUpdate) models.HostPeerUpdate {
+	if node.EgressDetails.InternetGwID != "" {
+
+		inetNode, err := GetNodeByID(node.EgressDetails.InternetGwID)
+		if err != nil {
+			return peerUpdate
 		}
-		if _, ok := extclient.Tags[tag.ID]; ok {
-			nMap[extclient.ClientID] = extclient.ConvertToStaticNode()
+		host, err := GetHost(node.HostID.String())
+		if err != nil {
+			return peerUpdate
 		}
-		if extclient.Mutex != nil {
-			extclient.Mutex.Unlock()
+
+		peerUpdate.ChangeDefaultGw = true
+		peerUpdate.DefaultGwIp = inetNode.Address.IP
+		if peerUpdate.DefaultGwIp == nil || host.EndpointIP == nil {
+			peerUpdate.DefaultGwIp = inetNode.Address6.IP
 		}
 	}
-	return nMap
+	return peerUpdate
 }
 
-func GetStaticNodeWithTag(tagID models.TagID) map[string]models.Node {
-	nMap := make(map[string]models.Node)
-	tag, err := GetTag(tagID)
-	if err != nil {
-		return nMap
-	}
-	extclients, err := GetNetworkExtClients(tag.Network.String())
-	if err != nil {
-		return nMap
+// GetAllowedIpForInetNodeClient - get inet cidr for node using a inet gw
+func GetAllowedIpForInetNodeClient(node, peer *models.Node) []net.IPNet {
+	var allowedips = []net.IPNet{}
+
+	if peer.Address.IP != nil {
+		_, ipnet, _ := net.ParseCIDR(IPv4Network)
+		allowedips = append(allowedips, *ipnet)
 	}
-	for _, extclient := range extclients {
-		nMap[extclient.ClientID] = extclient.ConvertToStaticNode()
+
+	if peer.Address6.IP != nil {
+		_, ipnet, _ := net.ParseCIDR(IPv6Network)
+		allowedips = append(allowedips, *ipnet)
 	}
-	return nMap
+
+	return allowedips
 }

+ 11 - 29
logic/peers.go

@@ -39,29 +39,6 @@ var (
 	CreateFailOver = func(node models.Node) error {
 		return nil
 	}
-
-	// SetDefaulGw
-	SetDefaultGw = func(node models.Node, peerUpdate models.HostPeerUpdate) models.HostPeerUpdate {
-		return peerUpdate
-	}
-	SetDefaultGwForRelayedUpdate = func(relayed, relay models.Node, peerUpdate models.HostPeerUpdate) models.HostPeerUpdate {
-		return peerUpdate
-	}
-	// UnsetInternetGw
-	UnsetInternetGw = func(node *models.Node) {
-		node.EgressDetails.IsInternetGateway = false
-	}
-	// SetInternetGw
-	SetInternetGw = func(node *models.Node, req models.InetNodeReq) {
-		node.EgressDetails.IsInternetGateway = true
-	}
-	// GetAllowedIpForInetNodeClient
-	GetAllowedIpForInetNodeClient = func(node, peer *models.Node) []net.IPNet {
-		return []net.IPNet{}
-	}
-	ValidateInetGwReq = func(inetNode models.Node, req models.InetNodeReq, update bool) error {
-		return nil
-	}
 )
 
 // GetHostPeerInfo - fetches required peer info per network
@@ -111,7 +88,7 @@ func GetHostPeerInfo(host *models.Host) (models.HostPeerInfo, error) {
 				!peer.PendingDelete &&
 				peer.Connected &&
 				nodeacls.AreNodesAllowed(nodeacls.NetworkID(node.Network), nodeacls.NodeID(node.ID.String()), nodeacls.NodeID(peer.ID.String())) &&
-				(defaultDevicePolicy.Enabled || allowedToComm) {
+				(allowedToComm) {
 
 				networkPeersInfo[peerHost.PublicKey.String()] = models.IDandAddr{
 					ID:         peer.ID.String(),
@@ -164,6 +141,9 @@ func GetPeerUpdateForHost(network string, host *models.Host, allNodes []models.N
 		HostNetworkInfo: models.HostInfoMap{},
 		ServerConfig:    GetServerInfo(),
 	}
+	if host.DNS == "off" {
+		hostPeerUpdate.ManageDNS = false
+	}
 	defer func() {
 		if !hostPeerUpdate.FwUpdate.AllowAll {
 
@@ -203,10 +183,12 @@ 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)
-
+		anyActiveEgressPolicy := CheckIfAnyActiveEgressPolicy(node)
+		nodeHasAccessToAllRsrcs := CheckIfNodeHasAccessToAllResources(&node)
+		anyUniDirectionPolicy := CheckIfAnyPolicyisUniDirectional(node)
 		if (defaultDevicePolicy.Enabled && defaultUserPolicy.Enabled) ||
-			(!checkIfAnyPolicyisUniDirectional(node) && !checkIfAnyActiveEgressPolicy(node)) ||
-			checkIfNodeHasAccessToAllResources(&node) {
+			(!anyUniDirectionPolicy && !anyActiveEgressPolicy) ||
+			nodeHasAccessToAllRsrcs {
 			aclRule := models.AclRule{
 				ID:              fmt.Sprintf("%s-allowed-network-rules", node.ID.String()),
 				AllowedProtocol: models.ALL,
@@ -371,8 +353,8 @@ func GetPeerUpdateForHost(network string, host *models.Host, allNodes []models.N
 				!peer.PendingDelete &&
 				peer.Connected &&
 				nodeacls.AreNodesAllowed(nodeacls.NetworkID(node.Network), nodeacls.NodeID(node.ID.String()), nodeacls.NodeID(peer.ID.String())) &&
-				(defaultDevicePolicy.Enabled || allowedToComm) &&
-				(deletedNode == nil || (deletedNode != nil && peer.ID.String() != deletedNode.ID.String())) {
+				(allowedToComm) &&
+				(deletedNode == nil || (peer.ID.String() != deletedNode.ID.String())) {
 				peerConfig.AllowedIPs = GetAllowedIPs(&node, &peer, nil) // only append allowed IPs if valid connection
 			}
 

+ 4 - 0
logic/relay.go

@@ -222,6 +222,10 @@ func GetAllowedIpsForRelayed(relayed, relay *models.Node) (allowedIPs []net.IPNe
 		if peer.ID == relayed.ID || peer.ID == relay.ID {
 			continue
 		}
+		if !IsPeerAllowed(*relayed, peer, true) {
+			continue
+		}
+		GetNodeEgressInfo(&peer)
 		if nodeacls.AreNodesAllowed(nodeacls.NetworkID(relayed.Network), nodeacls.NodeID(relayed.ID.String()), nodeacls.NodeID(peer.ID.String())) {
 			allowedIPs = append(allowedIPs, GetAllowedIPs(relayed, &peer, nil)...)
 		}

+ 0 - 19
logic/user_mgmt.go

@@ -102,25 +102,6 @@ func ListPlatformRoles() ([]models.UserRolePermissionTemplate, error) {
 	return userRoles, nil
 }
 
-func GetUserGrpMap() map[models.UserGroupID]map[string]struct{} {
-	grpUsersMap := make(map[models.UserGroupID]map[string]struct{})
-	users, _ := GetUsersDB()
-	for _, user := range users {
-		for gID := range user.UserGroups {
-			if grpUsers, ok := grpUsersMap[gID]; ok {
-				grpUsers[user.UserName] = struct{}{}
-				grpUsersMap[gID] = grpUsers
-			} else {
-				grpUsersMap[gID] = make(map[string]struct{})
-				grpUsersMap[gID][user.UserName] = struct{}{}
-			}
-		}
-
-	}
-
-	return grpUsersMap
-}
-
 func userRolesInit() {
 	d, _ := json.Marshal(SuperAdminPermissionTemplate)
 	database.Insert(SuperAdminPermissionTemplate.ID.String(), string(d), database.USER_PERMISSIONS_TABLE_NAME)

+ 8 - 46
migrate/migrate.go

@@ -34,7 +34,7 @@ func Run() {
 	updateHosts()
 	updateNodes()
 	updateAcls()
-	migrateToGws()
+	logic.MigrateToGws()
 	migrateToEgressV1()
 }
 
@@ -196,6 +196,13 @@ func updateHosts() {
 				continue
 			}
 		}
+		if host.DNS == "" {
+			if logic.GetServerSettings().ManageDNS {
+				host.DNS = "on"
+			} else {
+				host.DNS = "off"
+			}
+		}
 	}
 }
 
@@ -465,51 +472,6 @@ func createDefaultTagsAndPolicies() {
 	logic.MigrateAclPolicies()
 }
 
-func migrateToGws() {
-	nodes, err := logic.GetAllNodes()
-	if err != nil {
-		return
-	}
-	for _, node := range nodes {
-		if node.IsIngressGateway || node.IsRelay {
-			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 = fmt.Sprintf("%s.%s", acl.NetworkID.String(), 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 = fmt.Sprintf("%s.%s", acl.NetworkID.String(), 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)
-	}
-}
-
 func migrateToEgressV1() {
 	nodes, _ := logic.GetAllNodes()
 	user, err := logic.GetSuperAdmin()

+ 3 - 0
models/api_host.go

@@ -31,6 +31,7 @@ type ApiHost struct {
 	NatType             string     `json:"nat_type"              yaml:"nat_type"`
 	PersistentKeepalive int        `json:"persistentkeepalive"   yaml:"persistentkeepalive"`
 	AutoUpdate          bool       `json:"autoupdate"              yaml:"autoupdate"`
+	DNS                 string     `json:"dns"               yaml:"dns"`
 }
 
 // ApiIface - the interface struct for API usage
@@ -78,6 +79,7 @@ func (h *Host) ConvertNMHostToAPI() *ApiHost {
 	a.NatType = h.NatType
 	a.PersistentKeepalive = int(h.PersistentKeepalive.Seconds())
 	a.AutoUpdate = h.AutoUpdate
+	a.DNS = h.DNS
 	return &a
 }
 
@@ -123,5 +125,6 @@ func (a *ApiHost) ConvertAPIHostToNMHost(currentHost *Host) *Host {
 	h.TurnEndpoint = currentHost.TurnEndpoint
 	h.PersistentKeepalive = time.Duration(a.PersistentKeepalive) * time.Second
 	h.AutoUpdate = a.AutoUpdate
+	h.DNS = a.DNS
 	return &h
 }

+ 9 - 4
models/api_node.go

@@ -32,6 +32,7 @@ type ApiNode struct {
 	NetworkRange6                 string              `json:"networkrange6"`
 	IsRelayed                     bool                `json:"isrelayed"`
 	IsRelay                       bool                `json:"isrelay"`
+	IsGw                          bool                `json:"is_gw"`
 	RelayedBy                     string              `json:"relayedby" bson:"relayedby" yaml:"relayedby"`
 	RelayedNodes                  []string            `json:"relaynodes" yaml:"relayedNodes"`
 	IsEgressGateway               bool                `json:"isegressgateway"`
@@ -72,17 +73,16 @@ func (a *ApiNode) ConvertToServerNode(currentNode *Node) *Node {
 	convertedNode.Connected = a.Connected
 	convertedNode.ID, _ = uuid.Parse(a.ID)
 	convertedNode.HostID, _ = uuid.Parse(a.HostID)
-	convertedNode.IsRelay = a.IsRelay
+	//convertedNode.IsRelay = a.IsRelay
 	convertedNode.IsRelayed = a.IsRelayed
 	convertedNode.RelayedBy = a.RelayedBy
 	convertedNode.RelayedNodes = a.RelayedNodes
 	convertedNode.PendingDelete = a.PendingDelete
 	convertedNode.FailedOverBy = currentNode.FailedOverBy
 	convertedNode.FailOverPeers = currentNode.FailOverPeers
-	convertedNode.IsIngressGateway = a.IsIngressGateway
+	//convertedNode.IsIngressGateway = a.IsIngressGateway
 	convertedNode.IngressGatewayRange = currentNode.IngressGatewayRange
 	convertedNode.IngressGatewayRange6 = currentNode.IngressGatewayRange6
-	convertedNode.DNSOn = a.DNSOn
 	convertedNode.IngressDNS = a.IngressDns
 	convertedNode.IngressPersistentKeepalive = a.IngressPersistentKeepalive
 	convertedNode.IngressMTU = a.IngressMTU
@@ -132,6 +132,11 @@ func (a *ApiNode) ConvertToServerNode(currentNode *Node) *Node {
 		convertedNode.AdditionalRagIps = append(convertedNode.AdditionalRagIps, ragIp)
 	}
 	convertedNode.Tags = a.Tags
+	convertedNode.IsGw = a.IsGw
+	if convertedNode.IsGw {
+		convertedNode.IsRelay = true
+		convertedNode.IsIngressGateway = true
+	}
 	return &convertedNode
 }
 
@@ -180,10 +185,10 @@ func (nm *Node) ConvertToAPINode() *ApiNode {
 	}
 	apiNode.IsRelayed = nm.IsRelayed
 	apiNode.IsRelay = nm.IsRelay
+	apiNode.IsGw = nm.IsGw
 	apiNode.RelayedBy = nm.RelayedBy
 	apiNode.RelayedNodes = nm.RelayedNodes
 	apiNode.IsIngressGateway = nm.IsIngressGateway
-	apiNode.DNSOn = nm.DNSOn
 	apiNode.IngressDns = nm.IngressDNS
 	apiNode.IngressPersistentKeepalive = nm.IngressPersistentKeepalive
 	apiNode.IngressMTU = nm.IngressMTU

+ 1 - 0
models/host.go

@@ -69,6 +69,7 @@ type Host struct {
 	IsStaticPort        bool             `json:"isstaticport"            yaml:"isstaticport"`
 	IsStatic            bool             `json:"isstatic"        yaml:"isstatic"`
 	IsDefault           bool             `json:"isdefault"               yaml:"isdefault"`
+	DNS                 string           `json:"dns_status"               yaml:"dns_status"`
 	NatType             string           `json:"nat_type,omitempty"      yaml:"nat_type,omitempty"`
 	TurnEndpoint        *netip.AddrPort  `json:"turn_endpoint,omitempty" yaml:"turn_endpoint,omitempty"`
 	PersistentKeepalive time.Duration    `json:"persistentkeepalive" swaggertype:"primitive,integer" format:"int64" yaml:"persistentkeepalive"`

+ 6 - 3
models/node.go

@@ -87,7 +87,6 @@ type CommonNode struct {
 	IsGw                bool      `json:"is_gw"             yaml:"is_gw"`
 	RelayedNodes        []string  `json:"relaynodes"          yaml:"relayedNodes"`
 	IngressDNS          string    `json:"ingressdns"          yaml:"ingressdns"`
-	DNSOn               bool      `json:"dnson"               yaml:"dnson"`
 }
 
 // Node - a model of a network node
@@ -482,6 +481,12 @@ func (newNode *Node) Fill(
 	if newNode.IsFailOver != currentNode.IsFailOver {
 		newNode.IsFailOver = currentNode.IsFailOver
 	}
+	if newNode.Tags == nil {
+		if currentNode.Tags == nil {
+			currentNode.Tags = make(map[TagID]struct{})
+		}
+		newNode.Tags = currentNode.Tags
+	}
 }
 
 // StringWithCharset - returns random string inside defined charset
@@ -572,7 +577,6 @@ func (ln *LegacyNode) ConvertToNewNode() (*Host, *Node) {
 	}
 	node.Action = ln.Action
 	node.IsIngressGateway = parseBool(ln.IsIngressGateway)
-	node.DNSOn = parseBool(ln.DNSOn)
 
 	return &host, &node
 }
@@ -613,7 +617,6 @@ func (n *Node) Legacy(h *Host, s *ServerConfig, net *Network) *LegacyNode {
 	//l.IngressGatewayRange6 = n.IngressGatewayRange6
 	l.IsStatic = formatBool(h.IsStatic)
 	l.UDPHolePunch = formatBool(true)
-	l.DNSOn = formatBool(n.DNSOn)
 	l.Action = n.Action
 	l.IPForwarding = formatBool(h.IPForwarding)
 	l.OS = h.OS

+ 6 - 6
pro/controllers/inet_gws.go

@@ -70,12 +70,12 @@ func createInternetGw(w http.ResponseWriter, r *http.Request) {
 		)
 		return
 	}
-	err = proLogic.ValidateInetGwReq(node, request, false)
+	err = logic.ValidateInetGwReq(node, request, false)
 	if err != nil {
 		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
 		return
 	}
-	proLogic.SetInternetGw(&node, request)
+	logic.SetInternetGw(&node, request)
 	if servercfg.IsPro {
 		if _, exists := proLogic.FailOverExists(node.Network); exists {
 			go func() {
@@ -140,13 +140,13 @@ func updateInternetGw(w http.ResponseWriter, r *http.Request) {
 		)
 		return
 	}
-	err = proLogic.ValidateInetGwReq(node, request, true)
+	err = logic.ValidateInetGwReq(node, request, true)
 	if err != nil {
 		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
 		return
 	}
-	proLogic.UnsetInternetGw(&node)
-	proLogic.SetInternetGw(&node, request)
+	logic.UnsetInternetGw(&node)
+	logic.SetInternetGw(&node, request)
 	err = logic.UpsertNode(&node)
 	if err != nil {
 		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
@@ -185,7 +185,7 @@ func deleteInternetGw(w http.ResponseWriter, r *http.Request) {
 		return
 	}
 
-	proLogic.UnsetInternetGw(&node)
+	logic.UnsetInternetGw(&node)
 	err = logic.UpsertNode(&node)
 	if err != nil {
 		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))

+ 19 - 18
controllers/tags.go → pro/controllers/tags.go

@@ -1,4 +1,4 @@
-package controller
+package controllers
 
 import (
 	"encoding/json"
@@ -14,9 +14,10 @@ import (
 	"github.com/gravitl/netmaker/logic"
 	"github.com/gravitl/netmaker/models"
 	"github.com/gravitl/netmaker/mq"
+	proLogic "github.com/gravitl/netmaker/pro/logic"
 )
 
-func tagHandlers(r *mux.Router) {
+func TagHandlers(r *mux.Router) {
 	r.HandleFunc("/api/v1/tags", logic.SecurityCheck(true, http.HandlerFunc(getTags))).
 		Methods(http.MethodGet)
 	r.HandleFunc("/api/v1/tags", logic.SecurityCheck(true, http.HandlerFunc(createTag))).
@@ -46,13 +47,13 @@ func getTags(w http.ResponseWriter, r *http.Request) {
 		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
 		return
 	}
-	tags, err := logic.ListTagsWithNodes(models.NetworkID(netID))
+	tags, err := proLogic.ListTagsWithNodes(models.NetworkID(netID))
 	if err != nil {
 		logger.Log(0, r.Header.Get("user"), "failed to get all network tag entries: ", err.Error())
 		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
 		return
 	}
-	logic.SortTagEntrys(tags[:])
+	proLogic.SortTagEntrys(tags[:])
 	logic.ReturnSuccessResponseWithJson(w, r, tags, "fetched all tags in the network "+netID)
 }
 
@@ -91,18 +92,18 @@ func createTag(w http.ResponseWriter, r *http.Request) {
 		ColorCode: req.ColorCode,
 		CreatedAt: time.Now().UTC(),
 	}
-	_, err = logic.GetTag(tag.ID)
+	_, err = proLogic.GetTag(tag.ID)
 	if err == nil {
 		logic.ReturnErrorResponse(w, r, logic.FormatError(fmt.Errorf("tag with id %s exists already", tag.TagName), "badrequest"))
 		return
 	}
 	// validate name
-	err = logic.CheckIDSyntax(tag.TagName)
+	err = proLogic.CheckIDSyntax(tag.TagName)
 	if err != nil {
 		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
 		return
 	}
-	err = logic.InsertTag(tag)
+	err = proLogic.InsertTag(tag)
 	if err != nil {
 		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
 		return
@@ -174,7 +175,7 @@ func updateTag(w http.ResponseWriter, r *http.Request) {
 		return
 	}
 
-	tag, err := logic.GetTag(updateTag.ID)
+	tag, err := proLogic.GetTag(updateTag.ID)
 	if err != nil {
 		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
 		return
@@ -202,7 +203,7 @@ func updateTag(w http.ResponseWriter, r *http.Request) {
 	var newID models.TagID
 	if updateTag.NewName != "" {
 		// validate name
-		err = logic.CheckIDSyntax(updateTag.NewName)
+		err = proLogic.CheckIDSyntax(updateTag.NewName)
 		if err != nil {
 			logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
 			return
@@ -210,26 +211,26 @@ func updateTag(w http.ResponseWriter, r *http.Request) {
 		newID = models.TagID(fmt.Sprintf("%s.%s", tag.Network, updateTag.NewName))
 		tag.ID = newID
 		tag.TagName = updateTag.NewName
-		err = logic.InsertTag(tag)
+		err = proLogic.InsertTag(tag)
 		if err != nil {
 			logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
 			return
 		}
 		// delete old Tag entry
-		logic.DeleteTag(updateTag.ID, false)
+		proLogic.DeleteTag(updateTag.ID, false)
 	}
 	if updateTag.ColorCode != "" && updateTag.ColorCode != tag.ColorCode {
 		tag.ColorCode = updateTag.ColorCode
-		err = logic.UpsertTag(tag)
+		err = proLogic.UpsertTag(tag)
 		if err != nil {
 			logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
 			return
 		}
 	}
 	go func() {
-		logic.UpdateTag(updateTag, newID)
+		proLogic.UpdateTag(updateTag, newID)
 		if updateTag.NewName != "" {
-			logic.UpdateDeviceTag(updateTag.ID, newID, tag.Network)
+			proLogic.UpdateDeviceTag(updateTag.ID, newID, tag.Network)
 		}
 		mq.PublishPeerUpdate(false)
 	}()
@@ -256,24 +257,24 @@ func deleteTag(w http.ResponseWriter, r *http.Request) {
 		logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("role is required"), "badrequest"))
 		return
 	}
-	tag, err := logic.GetTag(models.TagID(tagID))
+	tag, err := proLogic.GetTag(models.TagID(tagID))
 	if err != nil {
 		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
 		return
 	}
 	// check if active policy is using the tag
-	if logic.CheckIfTagAsActivePolicy(tag.ID, tag.Network) {
+	if proLogic.CheckIfTagAsActivePolicy(tag.ID, tag.Network) {
 		logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("tag is currently in use by an active policy"), "badrequest"))
 		return
 	}
-	err = logic.DeleteTag(models.TagID(tagID), true)
+	err = proLogic.DeleteTag(models.TagID(tagID), true)
 	if err != nil {
 		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
 		return
 	}
 
 	go func() {
-		logic.RemoveDeviceTagFromAclPolicies(tag.ID, tag.Network)
+		proLogic.RemoveDeviceTagFromAclPolicies(tag.ID, tag.Network)
 		logic.RemoveTagFromEnrollmentKeys(tag.ID)
 		mq.PublishPeerUpdate(false)
 	}()

+ 18 - 6
pro/initialize.go

@@ -35,6 +35,7 @@ func InitPro() {
 		proControllers.InetHandlers,
 		proControllers.RacHandlers,
 		proControllers.EventHandlers,
+		proControllers.TagHandlers,
 	)
 	controller.ListRoles = proControllers.ListRoles
 	logic.EnterpriseCheckFuncs = append(logic.EnterpriseCheckFuncs, func() {
@@ -112,12 +113,6 @@ func InitPro() {
 	logic.UpdateMetrics = proLogic.UpdateMetrics
 	logic.DeleteMetrics = proLogic.DeleteMetrics
 	logic.GetTrialEndDate = getTrialEndDate
-	logic.SetDefaultGw = proLogic.SetDefaultGw
-	logic.ValidateInetGwReq = proLogic.ValidateInetGwReq
-	logic.SetDefaultGwForRelayedUpdate = proLogic.SetDefaultGwForRelayedUpdate
-	logic.UnsetInternetGw = proLogic.UnsetInternetGw
-	logic.SetInternetGw = proLogic.SetInternetGw
-	logic.GetAllowedIpForInetNodeClient = proLogic.GetAllowedIpForInetNodeClient
 	mq.UpdateMetrics = proLogic.MQUpdateMetrics
 	mq.UpdateMetricsFallBack = proLogic.MQUpdateMetricsFallBack
 	logic.GetFilteredNodesByUserAccess = proLogic.GetFilteredNodesByUserAccess
@@ -146,6 +141,23 @@ func InitPro() {
 	logic.ResetIDPSyncHook = auth.ResetIDPSyncHook
 	logic.EmailInit = email.Init
 	logic.LogEvent = proLogic.LogEvent
+	logic.RemoveUserFromAclPolicy = proLogic.RemoveUserFromAclPolicy
+	logic.IsUserAllowedToCommunicate = proLogic.IsUserAllowedToCommunicate
+	logic.DeleteAllNetworkTags = proLogic.DeleteAllNetworkTags
+	logic.CreateDefaultTags = proLogic.CreateDefaultTags
+	logic.IsNodeUsingInternetGw = proLogic.IsNodeUsingInternetGw
+	logic.GetInetClientsFromAclPolicies = proLogic.GetInetClientsFromAclPolicies
+	logic.IsPeerAllowed = proLogic.IsPeerAllowed
+	logic.IsAclPolicyValid = proLogic.IsAclPolicyValid
+	logic.GetEgressRulesForNode = proLogic.GetEgressRulesForNode
+	logic.GetAclRulesForNode = proLogic.GetAclRulesForNode
+	logic.CheckIfAnyActiveEgressPolicy = proLogic.CheckIfAnyActiveEgressPolicy
+	logic.CheckIfAnyPolicyisUniDirectional = proLogic.CheckIfAnyPolicyisUniDirectional
+	logic.MigrateToGws = proLogic.MigrateToGws
+	logic.IsNodeAllowedToCommunicate = proLogic.IsNodeAllowedToCommunicate
+	logic.GetStaticNodeIps = proLogic.GetStaticNodeIps
+	logic.GetFwRulesOnIngressGateway = proLogic.GetFwRulesOnIngressGateway
+
 }
 
 func retrieveProLogo() string {

+ 1930 - 0
pro/logic/acls.go

@@ -0,0 +1,1930 @@
+package logic
+
+import (
+	"context"
+	"errors"
+	"maps"
+	"net"
+	"sort"
+
+	"github.com/google/uuid"
+	"github.com/gravitl/netmaker/db"
+	"github.com/gravitl/netmaker/logic"
+	"github.com/gravitl/netmaker/models"
+	"github.com/gravitl/netmaker/schema"
+)
+
+/*
+TODO: EGRESS
+1. allow only selection of egress ranges in a policy
+ranges should be replaced by egress identifier
+
+2. check logic required for MAC exit node
+
+3.
+
+*/
+
+func getFwRulesForUserNodesOnGw(node models.Node, nodes []models.Node) (rules []models.FwRule) {
+	defaultUserPolicy, _ := logic.GetDefaultPolicy(models.NetworkID(node.Network), models.UserPolicy)
+	userNodes := logic.GetStaticUserNodesByNetwork(models.NetworkID(node.Network))
+	for _, userNodeI := range userNodes {
+		for _, peer := range nodes {
+			if peer.IsUserNode {
+				continue
+			}
+
+			if ok, allowedPolicies := IsUserAllowedToCommunicate(userNodeI.StaticNode.OwnerID, peer); ok {
+				if peer.IsStatic {
+					peer = peer.StaticNode.ConvertToStaticNode()
+				}
+				if !defaultUserPolicy.Enabled {
+					for _, policy := range allowedPolicies {
+						if userNodeI.StaticNode.Address != "" {
+							rules = append(rules, models.FwRule{
+								SrcIP: userNodeI.StaticNode.AddressIPNet4(),
+								DstIP: net.IPNet{
+									IP:   peer.Address.IP,
+									Mask: net.CIDRMask(32, 32),
+								},
+								AllowedProtocol: policy.Proto,
+								AllowedPorts:    policy.Port,
+								Allow:           true,
+							})
+						}
+						if userNodeI.StaticNode.Address6 != "" {
+							rules = append(rules, models.FwRule{
+								SrcIP: userNodeI.StaticNode.AddressIPNet6(),
+								DstIP: net.IPNet{
+									IP:   peer.Address6.IP,
+									Mask: net.CIDRMask(128, 128),
+								},
+								AllowedProtocol: policy.Proto,
+								AllowedPorts:    policy.Port,
+								Allow:           true,
+							})
+						}
+
+						// add egress ranges
+						for _, dstI := range policy.Dst {
+							if dstI.ID == models.EgressID {
+
+								e := schema.Egress{ID: dstI.Value}
+								err := e.Get(db.WithContext(context.TODO()))
+								if err != nil {
+									continue
+								}
+								dstI.Value = e.Range
+
+								ip, cidr, err := net.ParseCIDR(dstI.Value)
+								if err == nil {
+									if ip.To4() != nil && userNodeI.StaticNode.Address != "" {
+										rules = append(rules, models.FwRule{
+											SrcIP:           userNodeI.StaticNode.AddressIPNet4(),
+											DstIP:           *cidr,
+											AllowedProtocol: policy.Proto,
+											AllowedPorts:    policy.Port,
+											Allow:           true,
+										})
+									} else if ip.To16() != nil && userNodeI.StaticNode.Address6 != "" {
+										rules = append(rules, models.FwRule{
+											SrcIP:           userNodeI.StaticNode.AddressIPNet6(),
+											DstIP:           *cidr,
+											AllowedProtocol: policy.Proto,
+											AllowedPorts:    policy.Port,
+											Allow:           true,
+										})
+									}
+								}
+							}
+						}
+
+					}
+				}
+
+			}
+		}
+	}
+	return
+}
+
+func GetFwRulesOnIngressGateway(node models.Node) (rules []models.FwRule) {
+	// fetch user access to static clients via policies
+	defer func() {
+		sort.Slice(rules, func(i, j int) bool {
+			if !rules[i].SrcIP.IP.Equal(rules[j].SrcIP.IP) {
+				return string(rules[i].SrcIP.IP.To16()) < string(rules[j].SrcIP.IP.To16())
+			}
+			return string(rules[i].DstIP.IP.To16()) < string(rules[j].DstIP.IP.To16())
+		})
+	}()
+	defaultDevicePolicy, _ := logic.GetDefaultPolicy(models.NetworkID(node.Network), models.DevicePolicy)
+	nodes, _ := logic.GetNetworkNodes(node.Network)
+	nodes = append(nodes, logic.GetStaticNodesByNetwork(models.NetworkID(node.Network), true)...)
+	rules = getFwRulesForUserNodesOnGw(node, nodes)
+	if defaultDevicePolicy.Enabled {
+		return
+	}
+	for _, nodeI := range nodes {
+		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 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()
+			}
+			var allowedPolicies1 []models.Acl
+			var ok bool
+			if ok, allowedPolicies1 = IsNodeAllowedToCommunicate(nodeI.StaticNode.ConvertToStaticNode(), peer, true); ok {
+				rules = append(rules, getFwRulesForNodeAndPeerOnGw(nodeI.StaticNode.ConvertToStaticNode(), peer, allowedPolicies1)...)
+			}
+			if ok, allowedPolicies2 := IsNodeAllowedToCommunicate(peer, nodeI.StaticNode.ConvertToStaticNode(), true); ok {
+				rules = append(rules,
+					getFwRulesForNodeAndPeerOnGw(peer, nodeI.StaticNode.ConvertToStaticNode(),
+						getUniquePolicies(allowedPolicies1, allowedPolicies2))...)
+			}
+		}
+	}
+	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,
+					})
+				}
+
+			}
+
+		}
+
+		// add egress range rules
+		for _, dstI := range policy.Dst {
+			if dstI.ID == models.EgressID {
+
+				e := schema.Egress{ID: dstI.Value}
+				err := e.Get(db.WithContext(context.TODO()))
+				if err != nil {
+					continue
+				}
+				dstI.Value = e.Range
+
+				ip, cidr, err := net.ParseCIDR(dstI.Value)
+				if err == nil {
+					if ip.To4() != nil {
+						if node.Address.IP != nil {
+							rules = append(rules, models.FwRule{
+								SrcIP: net.IPNet{
+									IP:   node.Address.IP,
+									Mask: net.CIDRMask(32, 32),
+								},
+								DstIP:           *cidr,
+								AllowedProtocol: policy.Proto,
+								AllowedPorts:    policy.Port,
+								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:           *cidr,
+								AllowedProtocol: policy.Proto,
+								AllowedPorts:    policy.Port,
+								Allow:           true,
+							})
+						}
+					}
+
+				}
+			}
+		}
+	}
+
+	return
+}
+
+func getUniquePolicies(policies1, policies2 []models.Acl) []models.Acl {
+	policies1Map := make(map[string]struct{})
+	for _, policy1I := range policies1 {
+		policies1Map[policy1I.ID] = struct{}{}
+	}
+	for i := len(policies2) - 1; i >= 0; i-- {
+		if _, ok := policies1Map[policies2[i].ID]; ok {
+			policies2 = append(policies2[:i], policies2[i+1:]...)
+		}
+	}
+	return policies2
+}
+
+func GetStaticNodeIps(node models.Node) (ips []net.IP) {
+	defer func() {
+		sortIPs(ips)
+	}()
+	defaultUserPolicy, _ := logic.GetDefaultPolicy(models.NetworkID(node.Network), models.UserPolicy)
+	defaultDevicePolicy, _ := logic.GetDefaultPolicy(models.NetworkID(node.Network), models.DevicePolicy)
+
+	extclients := logic.GetStaticNodesByNetwork(models.NetworkID(node.Network), false)
+	for _, extclient := range extclients {
+		if extclient.IsUserNode && defaultUserPolicy.Enabled {
+			continue
+		}
+		if !extclient.IsUserNode && defaultDevicePolicy.Enabled {
+			continue
+		}
+		if extclient.StaticNode.Address != "" {
+			ips = append(ips, extclient.StaticNode.AddressIPNet4().IP)
+		}
+		if extclient.StaticNode.Address6 != "" {
+			ips = append(ips, extclient.StaticNode.AddressIPNet6().IP)
+		}
+	}
+	return
+}
+
+// Sort a slice of net.IP addresses
+func sortIPs(ips []net.IP) {
+	sort.Slice(ips, func(i, j int) bool {
+		ip1, ip2 := ips[i].To16(), ips[j].To16()
+		return string(ip1) < string(ip2) // Compare as byte slices
+	})
+}
+
+func checkIfAclTagisValid(a models.Acl, t models.AclPolicyTag, isSrc bool) (err error) {
+	switch t.ID {
+	case models.NodeTagID:
+		if a.RuleType == models.UserPolicy && isSrc {
+			return errors.New("user policy source mismatch")
+		}
+		// check if tag is valid
+		_, err := GetTag(models.TagID(t.Value))
+		if err != nil {
+			return errors.New("invalid tag " + t.Value)
+		}
+	case models.NodeID:
+		if a.RuleType == models.UserPolicy && isSrc {
+			return errors.New("user policy source mismatch")
+		}
+		_, nodeErr := logic.GetNodeByID(t.Value)
+		if nodeErr != nil {
+			_, staticNodeErr := logic.GetExtClient(t.Value, a.NetworkID.String())
+			if staticNodeErr != nil {
+				return errors.New("invalid node " + t.Value)
+			}
+		}
+	case models.EgressID, models.EgressRange:
+		e := schema.Egress{
+			ID: t.Value,
+		}
+		err := e.Get(db.WithContext(context.TODO()))
+		if err != nil {
+			return errors.New("invalid egress")
+		}
+		if e.IsInetGw {
+			req := models.InetNodeReq{}
+			for _, srcI := range a.Src {
+				if srcI.ID == models.NodeTagID {
+					nodesMap := GetNodesWithTag(models.TagID(srcI.Value))
+					for _, node := range nodesMap {
+						if node.ID != uuid.Nil {
+							req.InetNodeClientIDs = append(req.InetNodeClientIDs, node.ID.String())
+						}
+					}
+				} else if srcI.ID == models.NodeID {
+					_, nodeErr := logic.GetNodeByID(srcI.Value)
+					if nodeErr != nil {
+						_, staticNodeErr := logic.GetExtClient(srcI.Value, a.NetworkID.String())
+						if staticNodeErr != nil {
+							return errors.New("invalid node " + srcI.Value)
+						}
+					} else {
+						req.InetNodeClientIDs = append(req.InetNodeClientIDs, srcI.Value)
+					}
+
+				}
+			}
+			if len(e.Nodes) > 0 {
+				for k := range e.Nodes {
+					inetNode, err := logic.GetNodeByID(k)
+					if err != nil {
+						return errors.New("invalid node " + t.Value)
+					}
+					if err = logic.ValidateInetGwReq(inetNode, req, false); err != nil {
+						return err
+					}
+				}
+
+			}
+
+		}
+
+	case models.UserAclID:
+		if a.RuleType == models.DevicePolicy {
+			return errors.New("device policy source mismatch")
+		}
+		if !isSrc {
+			return errors.New("user cannot be added to destination")
+		}
+		_, err := logic.GetUser(t.Value)
+		if err != nil {
+			return errors.New("invalid user " + t.Value)
+		}
+	case models.UserGroupAclID:
+		if a.RuleType == models.DevicePolicy {
+			return errors.New("device policy source mismatch")
+		}
+		if !isSrc {
+			return errors.New("user cannot be added to destination")
+		}
+		err := IsGroupValid(models.UserGroupID(t.Value))
+		if err != nil {
+			return errors.New("invalid user group " + t.Value)
+		}
+		// check if group belongs to this network
+		netGrps := GetUserGroupsInNetwork(a.NetworkID)
+		if _, ok := netGrps[models.UserGroupID(t.Value)]; !ok {
+			return errors.New("invalid user group " + t.Value)
+		}
+	default:
+		return errors.New("invalid policy")
+	}
+	return nil
+}
+
+// IsAclPolicyValid - validates if acl policy is valid
+func IsAclPolicyValid(acl models.Acl) (err error) {
+	//check if src and dst are valid
+	if acl.AllowedDirection != models.TrafficDirectionBi &&
+		acl.AllowedDirection != models.TrafficDirectionUni {
+		return errors.New("invalid traffic direction")
+	}
+	switch acl.RuleType {
+	case models.UserPolicy:
+		// src list should only contain users
+		for _, srcI := range acl.Src {
+
+			if srcI.Value == "*" {
+				continue
+			}
+			// check if user group is valid
+			if err = checkIfAclTagisValid(acl, srcI, true); err != nil {
+				return
+			}
+		}
+		for _, dstI := range acl.Dst {
+
+			if dstI.Value == "*" {
+				continue
+			}
+
+			// check if user group is valid
+			if err = checkIfAclTagisValid(acl, dstI, false); err != nil {
+				return
+			}
+		}
+	case models.DevicePolicy:
+		for _, srcI := range acl.Src {
+			if srcI.Value == "*" {
+				continue
+			}
+			// check if user group is valid
+			if err = checkIfAclTagisValid(acl, srcI, true); err != nil {
+				return err
+			}
+		}
+		for _, dstI := range acl.Dst {
+
+			if dstI.Value == "*" {
+				continue
+			}
+			// check if user group is valid
+			if err = checkIfAclTagisValid(acl, dstI, false); err != nil {
+				return
+			}
+		}
+	}
+	return nil
+}
+
+// ListUserPolicies - lists all acl policies enforced on an user
+func ListUserPolicies(u models.User) []models.Acl {
+	allAcls := logic.ListAcls()
+	userAcls := []models.Acl{}
+	for _, acl := range allAcls {
+
+		if acl.RuleType == models.UserPolicy {
+			srcMap := logic.ConvAclTagToValueMap(acl.Src)
+			if _, ok := srcMap[u.UserName]; ok {
+				userAcls = append(userAcls, acl)
+			} else {
+				// check for user groups
+				for gID := range u.UserGroups {
+					if _, ok := srcMap[gID.String()]; ok {
+						userAcls = append(userAcls, acl)
+						break
+					}
+				}
+			}
+
+		}
+	}
+	return userAcls
+}
+
+// listPoliciesOfUser - lists all user acl policies applied to user in an network
+func listPoliciesOfUser(user models.User, netID models.NetworkID) []models.Acl {
+	allAcls := logic.ListAcls()
+	userAcls := []models.Acl{}
+	for _, acl := range allAcls {
+		if acl.NetworkID == netID && acl.RuleType == models.UserPolicy {
+			srcMap := logic.ConvAclTagToValueMap(acl.Src)
+			if _, ok := srcMap[user.UserName]; ok {
+				userAcls = append(userAcls, acl)
+				continue
+			}
+			for netRole := range user.NetworkRoles {
+				if _, ok := srcMap[netRole.String()]; ok {
+					userAcls = append(userAcls, acl)
+					continue
+				}
+			}
+			for userG := range user.UserGroups {
+				if _, ok := srcMap[userG.String()]; ok {
+					userAcls = append(userAcls, acl)
+					continue
+				}
+			}
+
+		}
+	}
+	return userAcls
+}
+
+// listUserPolicies - lists all user policies in a network
+func listUserPolicies(netID models.NetworkID) []models.Acl {
+	allAcls := logic.ListAcls()
+	deviceAcls := []models.Acl{}
+	for _, acl := range allAcls {
+		if acl.NetworkID == netID && acl.RuleType == models.UserPolicy {
+			deviceAcls = append(deviceAcls, acl)
+		}
+	}
+	return deviceAcls
+}
+
+// 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
+	}
+	if peerTags == nil {
+		peerTags = make(map[models.TagID]struct{})
+	}
+	peerTags[models.TagID(peerId)] = struct{}{}
+	peerTags[models.TagID("*")] = struct{}{}
+	acl, _ := logic.GetDefaultPolicy(models.NetworkID(peer.Network), models.UserPolicy)
+	if acl.Enabled {
+		return true, []models.Acl{acl}
+	}
+	user, err := logic.GetUser(userName)
+	if err != nil {
+		return false, []models.Acl{}
+	}
+	allowedPolicies := []models.Acl{}
+	policies := listPoliciesOfUser(*user, models.NetworkID(peer.Network))
+	for _, policy := range policies {
+		if !policy.Enabled {
+			continue
+		}
+		dstMap := logic.ConvAclTagToValueMap(policy.Dst)
+		for _, dst := range policy.Dst {
+			if dst.ID == models.EgressID {
+				e := schema.Egress{ID: dst.Value}
+				err := e.Get(db.WithContext(context.TODO()))
+				if err == nil && e.Status {
+					for nodeID := range e.Nodes {
+						dstMap[nodeID] = struct{}{}
+					}
+				}
+			}
+		}
+		if _, ok := dstMap["*"]; ok {
+			allowedPolicies = append(allowedPolicies, policy)
+			continue
+		}
+		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
+			}
+		}
+
+	}
+	if len(allowedPolicies) > 0 {
+		return true, allowedPolicies
+	}
+	return false, []models.Acl{}
+}
+
+// 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 peer.IsFailOver && node.FailedOverBy != uuid.Nil && node.FailedOverBy == peer.ID {
+	// 	return true
+	// }
+	// if node.IsFailOver && peer.FailedOverBy != uuid.Nil && peer.FailedOverBy == node.ID {
+	// 	return true
+	// }
+	// if node.IsGw && peer.IsRelayed && peer.RelayedBy == node.ID.String() {
+	// 	return true
+	// }
+	// if peer.IsGw && node.IsRelayed && node.RelayedBy == peer.ID.String() {
+	// 	return true
+	// }
+	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
+	}
+	if nodeTags == nil {
+		nodeTags = make(map[models.TagID]struct{})
+	}
+	if peerTags == nil {
+		peerTags = make(map[models.TagID]struct{})
+	}
+	nodeTags[models.TagID(nodeId)] = struct{}{}
+	peerTags[models.TagID(peerId)] = struct{}{}
+	if checkDefaultPolicy {
+		// check default policy if all allowed return true
+		defaultPolicy, err := logic.GetDefaultPolicy(models.NetworkID(node.Network), models.DevicePolicy)
+		if err == nil {
+			if defaultPolicy.Enabled {
+				return true
+			}
+		}
+
+	}
+	// list device policies
+	policies := logic.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
+		}
+
+		srcMap = logic.ConvAclTagToValueMap(policy.Src)
+		dstMap = logic.ConvAclTagToValueMap(policy.Dst)
+		for _, dst := range policy.Dst {
+			if dst.ID == models.EgressID {
+				e := schema.Egress{ID: dst.Value}
+				err := e.Get(db.WithContext(context.TODO()))
+				if err == nil && e.Status {
+					for nodeID := range e.Nodes {
+						dstMap[nodeID] = struct{}{}
+					}
+				}
+			}
+		}
+		if logic.CheckTagGroupPolicy(srcMap, dstMap, node, peer, nodeTags, peerTags) {
+			return true
+		}
+
+	}
+	return false
+}
+
+func RemoveUserFromAclPolicy(userName string) {
+	acls := logic.ListAcls()
+	for _, acl := range acls {
+		delete := false
+		update := false
+		if acl.RuleType == models.UserPolicy {
+			for i := len(acl.Src) - 1; i >= 0; i-- {
+				if acl.Src[i].ID == models.UserAclID && acl.Src[i].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
+					}
+				}
+			}
+			if delete {
+				logic.DeleteAcl(acl)
+				continue
+			}
+			if update {
+				logic.UpsertAcl(acl)
+			}
+		}
+	}
+}
+
+// IsNodeAllowedToCommunicate - check node is allowed to communicate with the peer // ADD ALLOWED DIRECTION - 0 => node -> peer, 1 => peer-> node,
+func IsNodeAllowedToCommunicate(node, peer models.Node, checkDefaultPolicy bool) (bool, []models.Acl) {
+	var nodeId, peerId string
+	// if peer.IsFailOver && node.FailedOverBy != uuid.Nil && node.FailedOverBy == peer.ID {
+	// 	return true, []models.Acl{}
+	// }
+	// if node.IsFailOver && peer.FailedOverBy != uuid.Nil && peer.FailedOverBy == node.ID {
+	// 	return true, []models.Acl{}
+	// }
+	// if node.IsGw && peer.IsRelayed && peer.RelayedBy == node.ID.String() {
+	// 	return true, []models.Acl{}
+	// }
+	// if peer.IsGw && node.IsRelayed && node.RelayedBy == peer.ID.String() {
+	// 	return true, []models.Acl{}
+	// }
+	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
+	}
+	if nodeTags == nil {
+		nodeTags = make(map[models.TagID]struct{})
+	}
+	if peerTags == nil {
+		peerTags = make(map[models.TagID]struct{})
+	}
+	nodeTags[models.TagID(nodeId)] = struct{}{}
+	peerTags[models.TagID(peerId)] = struct{}{}
+	if checkDefaultPolicy {
+		// check default policy if all allowed return true
+		defaultPolicy, err := logic.GetDefaultPolicy(models.NetworkID(node.Network), models.DevicePolicy)
+		if err == nil {
+			if defaultPolicy.Enabled {
+				return true, []models.Acl{defaultPolicy}
+			}
+		}
+	}
+	allowedPolicies := []models.Acl{}
+	defer func() {
+		allowedPolicies = logic.UniquePolicies(allowedPolicies)
+	}()
+	// list device policies
+	policies := logic.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 = logic.ConvAclTagToValueMap(policy.Src)
+		dstMap = logic.ConvAclTagToValueMap(policy.Dst)
+		for _, dst := range policy.Dst {
+			if dst.ID == models.EgressID {
+				e := schema.Egress{ID: dst.Value}
+				err := e.Get(db.WithContext(context.TODO()))
+				if err == nil && e.Status {
+					for nodeID := range e.Nodes {
+						dstMap[nodeID] = struct{}{}
+					}
+				}
+			}
+		}
+		_, 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 := srcMap[tagID.String()]; ok {
+						allowed = true
+						break
+					}
+				}
+			}
+			if allowed {
+				break
+			}
+		}
+		if allowed {
+			allowedPolicies = append(allowedPolicies, policy)
+		}
+	}
+
+	if len(allowedPolicies) > 0 {
+		return true, allowedPolicies
+	}
+	return false, allowedPolicies
+}
+
+// UpdateDeviceTag - updates device tag on acl policies
+func UpdateDeviceTag(OldID, newID models.TagID, netID models.NetworkID) {
+	acls := logic.ListDevicePolicies(netID)
+	update := false
+	for _, acl := range acls {
+		for i, srcTagI := range acl.Src {
+			if srcTagI.ID == models.NodeTagID {
+				if OldID.String() == srcTagI.Value {
+					acl.Src[i].Value = newID.String()
+					update = true
+				}
+			}
+		}
+		for i, dstTagI := range acl.Dst {
+			if dstTagI.ID == models.NodeTagID {
+				if OldID.String() == dstTagI.Value {
+					acl.Dst[i].Value = newID.String()
+					update = true
+				}
+			}
+		}
+		if update {
+			logic.UpsertAcl(acl)
+		}
+	}
+}
+
+func CheckIfTagAsActivePolicy(tagID models.TagID, netID models.NetworkID) bool {
+	acls := logic.ListDevicePolicies(netID)
+	for _, acl := range acls {
+		for _, srcTagI := range acl.Src {
+			if srcTagI.ID == models.NodeTagID {
+				if tagID.String() == srcTagI.Value {
+					return true
+				}
+			}
+		}
+		for _, dstTagI := range acl.Dst {
+			if dstTagI.ID == models.NodeTagID {
+				if tagID.String() == dstTagI.Value {
+					return true
+				}
+			}
+		}
+	}
+	return false
+}
+
+// RemoveDeviceTagFromAclPolicies - remove device tag from acl policies
+func RemoveDeviceTagFromAclPolicies(tagID models.TagID, netID models.NetworkID) error {
+	acls := logic.ListDevicePolicies(netID)
+	update := false
+	for _, acl := range acls {
+		for i := len(acl.Src) - 1; i >= 0; i-- {
+			if acl.Src[i].ID == models.NodeTagID {
+				if tagID.String() == acl.Src[i].Value {
+					acl.Src = append(acl.Src[:i], acl.Src[i+1:]...)
+					update = true
+				}
+			}
+		}
+		for i := len(acl.Dst) - 1; i >= 0; i-- {
+			if acl.Dst[i].ID == models.NodeTagID {
+				if tagID.String() == acl.Dst[i].Value {
+					acl.Dst = append(acl.Dst[:i], acl.Dst[i+1:]...)
+					update = true
+				}
+			}
+		}
+		if update {
+			logic.UpsertAcl(acl)
+		}
+	}
+	return nil
+}
+
+func getEgressUserRulesForNode(targetnode *models.Node,
+	rules map[string]models.AclRule) map[string]models.AclRule {
+	userNodes := logic.GetStaticUserNodesByNetwork(models.NetworkID(targetnode.Network))
+	userGrpMap := GetUserGrpMap()
+	allowedUsers := make(map[string][]models.Acl)
+	acls := listUserPolicies(models.NetworkID(targetnode.Network))
+	var targetNodeTags = make(map[models.TagID]struct{})
+	targetNodeTags["*"] = struct{}{}
+	for _, rangeI := range targetnode.EgressDetails.EgressGatewayRanges {
+		targetNodeTags[models.TagID(rangeI)] = struct{}{}
+	}
+	for _, acl := range acls {
+		if !acl.Enabled {
+			continue
+		}
+		dstTags := logic.ConvAclTagToValueMap(acl.Dst)
+		for _, dst := range acl.Dst {
+			if dst.ID == models.EgressID {
+				e := schema.Egress{ID: dst.Value}
+				err := e.Get(db.WithContext(context.TODO()))
+				if err == nil && e.Status {
+					for nodeID := range e.Nodes {
+						dstTags[nodeID] = struct{}{}
+					}
+					dstTags[e.Range] = struct{}{}
+				}
+			}
+		}
+		_, all := dstTags["*"]
+		addUsers := false
+		if !all {
+			for nodeTag := range targetNodeTags {
+				if _, ok := dstTags[nodeTag.String()]; ok {
+					addUsers = true
+					break
+				}
+			}
+		} 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 {
+		if !userNode.StaticNode.Enabled {
+			continue
+		}
+		acls, ok := allowedUsers[userNode.StaticNode.OwnerID]
+		if !ok {
+			continue
+		}
+		for _, acl := range acls {
+
+			if !acl.Enabled {
+				continue
+			}
+			r := models.AclRule{
+				ID:              acl.ID,
+				AllowedProtocol: acl.Proto,
+				AllowedPorts:    acl.Port,
+				Direction:       acl.AllowedDirection,
+				Allowed:         true,
+			}
+			// Get peers in the tags and add allowed rules
+			if userNode.StaticNode.Address != "" {
+				r.IPList = append(r.IPList, userNode.StaticNode.AddressIPNet4())
+			}
+			if userNode.StaticNode.Address6 != "" {
+				r.IP6List = append(r.IP6List, userNode.StaticNode.AddressIPNet6())
+			}
+			for _, dstI := range acl.Dst {
+				if dstI.ID == models.EgressID {
+					e := schema.Egress{ID: dstI.Value}
+					err := e.Get(db.WithContext(context.TODO()))
+					if err != nil {
+						continue
+					}
+					if e.IsInetGw {
+						r.Dst = append(r.Dst, net.IPNet{
+							IP:   net.IPv4zero,
+							Mask: net.CIDRMask(0, 32),
+						})
+						r.Dst6 = append(r.Dst6, net.IPNet{
+							IP:   net.IPv6zero,
+							Mask: net.CIDRMask(0, 128),
+						})
+
+					} else {
+						ip, cidr, err := net.ParseCIDR(e.Range)
+						if err == nil {
+							if ip.To4() != nil {
+								r.Dst = append(r.Dst, *cidr)
+							} else {
+								r.Dst6 = append(r.Dst6, *cidr)
+							}
+
+						}
+					}
+
+				}
+
+			}
+			if aclRule, ok := rules[acl.ID]; ok {
+				aclRule.IPList = append(aclRule.IPList, r.IPList...)
+				aclRule.IP6List = append(aclRule.IP6List, r.IP6List...)
+				rules[acl.ID] = aclRule
+			} else {
+				rules[acl.ID] = r
+			}
+		}
+	}
+	return rules
+}
+
+func getUserAclRulesForNode(targetnode *models.Node,
+	rules map[string]models.AclRule) map[string]models.AclRule {
+	userNodes := logic.GetStaticUserNodesByNetwork(models.NetworkID(targetnode.Network))
+	userGrpMap := GetUserGrpMap()
+	allowedUsers := make(map[string][]models.Acl)
+	acls := listUserPolicies(models.NetworkID(targetnode.Network))
+	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)
+	}
+	if targetNodeTags == nil {
+		targetNodeTags = make(map[models.TagID]struct{})
+	}
+	targetNodeTags[models.TagID(targetnode.ID.String())] = struct{}{}
+	for _, acl := range acls {
+		if !acl.Enabled {
+			continue
+		}
+		dstTags := logic.ConvAclTagToValueMap(acl.Dst)
+		_, all := dstTags["*"]
+		addUsers := false
+		if !all {
+			for nodeTag := range targetNodeTags {
+				if _, ok := dstTags[nodeTag.String()]; ok {
+					addUsers = true
+					break
+				}
+			}
+		} 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 {
+		if !userNode.StaticNode.Enabled {
+			continue
+		}
+		acls, ok := allowedUsers[userNode.StaticNode.OwnerID]
+		if !ok {
+			continue
+		}
+		for _, acl := range acls {
+
+			if !acl.Enabled {
+				continue
+			}
+			r := models.AclRule{
+				ID:              acl.ID,
+				AllowedProtocol: acl.Proto,
+				AllowedPorts:    acl.Port,
+				Direction:       acl.AllowedDirection,
+				Allowed:         true,
+			}
+			// Get peers in the tags and add allowed rules
+			if userNode.StaticNode.Address != "" {
+				r.IPList = append(r.IPList, userNode.StaticNode.AddressIPNet4())
+			}
+			if userNode.StaticNode.Address6 != "" {
+				r.IP6List = append(r.IP6List, userNode.StaticNode.AddressIPNet6())
+			}
+			if aclRule, ok := rules[acl.ID]; ok {
+				aclRule.IPList = append(aclRule.IPList, r.IPList...)
+				aclRule.IP6List = append(aclRule.IP6List, r.IP6List...)
+				aclRule.IPList = logic.UniqueIPNetList(aclRule.IPList)
+				aclRule.IP6List = logic.UniqueIPNetList(aclRule.IP6List)
+				rules[acl.ID] = aclRule
+			} else {
+				r.IPList = logic.UniqueIPNetList(r.IPList)
+				r.IP6List = logic.UniqueIPNetList(r.IP6List)
+				rules[acl.ID] = r
+			}
+		}
+	}
+	return rules
+}
+
+func CheckIfAnyActiveEgressPolicy(targetNode models.Node) bool {
+	if !targetNode.EgressDetails.IsEgressGateway {
+		return false
+	}
+	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)
+	}
+	if targetNodeTags == nil {
+		targetNodeTags = make(map[models.TagID]struct{})
+	}
+	targetNodeTags[models.TagID(targetNode.ID.String())] = struct{}{}
+	targetNodeTags["*"] = struct{}{}
+	acls, _ := logic.ListAclsByNetwork(models.NetworkID(targetNode.Network))
+	for _, acl := range acls {
+		if !acl.Enabled || acl.RuleType != models.DevicePolicy {
+			continue
+		}
+		srcTags := logic.ConvAclTagToValueMap(acl.Src)
+		for _, dst := range acl.Dst {
+			if dst.ID == models.EgressID {
+				e := schema.Egress{ID: dst.Value}
+				err := e.Get(db.WithContext(context.TODO()))
+				if err == nil && e.Status {
+					for nodeTag := range targetNodeTags {
+						if _, ok := srcTags[nodeTag.String()]; ok {
+							return true
+						}
+						if _, ok := srcTags[targetNode.ID.String()]; ok {
+							return true
+						}
+					}
+				}
+			}
+		}
+	}
+	return false
+}
+
+func CheckIfAnyPolicyisUniDirectional(targetNode models.Node) bool {
+	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)
+	}
+	if targetNodeTags == nil {
+		targetNodeTags = make(map[models.TagID]struct{})
+	}
+	targetNodeTags[models.TagID(targetNode.ID.String())] = struct{}{}
+	targetNodeTags["*"] = struct{}{}
+	acls, _ := logic.ListAclsByNetwork(models.NetworkID(targetNode.Network))
+	for _, acl := range acls {
+		if !acl.Enabled {
+			continue
+		}
+		if acl.AllowedDirection == models.TrafficDirectionBi && acl.Proto == models.ALL && acl.ServiceType == models.Any {
+			continue
+		}
+		if acl.Proto != models.ALL || acl.ServiceType != models.Any {
+			return true
+		}
+		srcTags := logic.ConvAclTagToValueMap(acl.Src)
+		dstTags := logic.ConvAclTagToValueMap(acl.Dst)
+		for nodeTag := range targetNodeTags {
+			if acl.RuleType == models.DevicePolicy {
+				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
+	defer func() {
+		if !targetnode.IsIngressGateway {
+			rules = getUserAclRulesForNode(&targetnode, rules)
+		}
+	}()
+	rules = make(map[string]models.AclRule)
+	var taggedNodes map[models.TagID][]models.Node
+	if targetnode.IsIngressGateway {
+		taggedNodes = GetTagMapWithNodesByNetwork(models.NetworkID(targetnode.Network), false)
+	} else {
+		taggedNodes = GetTagMapWithNodesByNetwork(models.NetworkID(targetnode.Network), true)
+	}
+	acls := logic.ListDevicePolicies(models.NetworkID(targetnode.Network))
+	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)
+	}
+	if targetNodeTags == nil {
+		targetNodeTags = make(map[models.TagID]struct{})
+	}
+	targetNodeTags[models.TagID(targetnode.ID.String())] = struct{}{}
+	targetNodeTags["*"] = struct{}{}
+	for _, acl := range acls {
+		if !acl.Enabled {
+			continue
+		}
+		srcTags := logic.ConvAclTagToValueMap(acl.Src)
+		dstTags := logic.ConvAclTagToValueMap(acl.Dst)
+		for _, dst := range acl.Dst {
+			if dst.ID == models.EgressID {
+				e := schema.Egress{ID: dst.Value}
+				err := e.Get(db.WithContext(context.TODO()))
+				if err == nil && e.Status {
+					for nodeID := range e.Nodes {
+						dstTags[nodeID] = struct{}{}
+					}
+				}
+			}
+		}
+		_, 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 || srcAll {
+					existsInSrcTag = true
+				}
+				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
+				}
+
+				if existsInSrcTag /* && !existsInDstTag*/ {
+					// get all dst tags
+					for dst := range dstTags {
+						if dst == nodeTag.String() {
+							continue
+						}
+						// Get peers in the tags and add allowed rules
+						nodes := taggedNodes[models.TagID(dst)]
+						if dst != targetnode.ID.String() {
+							node, err := logic.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())
+							}
+							if node.Address6.IP != nil {
+								aclRule.IP6List = append(aclRule.IP6List, node.AddressIPNet6())
+							}
+							if node.IsStatic && node.StaticNode.Address != "" {
+								aclRule.IPList = append(aclRule.IPList, node.StaticNode.AddressIPNet4())
+							}
+							if node.IsStatic && node.StaticNode.Address6 != "" {
+								aclRule.IP6List = append(aclRule.IP6List, node.StaticNode.AddressIPNet6())
+							}
+						}
+					}
+				}
+				if existsInDstTag /*&& !existsInSrcTag*/ {
+					// get all src tags
+					for src := range srcTags {
+						if src == nodeTag.String() {
+							continue
+						}
+						// Get peers in the tags and add allowed rules
+						nodes := taggedNodes[models.TagID(src)]
+						if src != targetnode.ID.String() {
+							node, err := logic.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())
+							}
+							if node.Address6.IP != nil {
+								aclRule.IP6List = append(aclRule.IP6List, node.AddressIPNet6())
+							}
+							if node.IsStatic && node.StaticNode.Address != "" {
+								aclRule.IPList = append(aclRule.IPList, node.StaticNode.AddressIPNet4())
+							}
+							if node.IsStatic && node.StaticNode.Address6 != "" {
+								aclRule.IP6List = append(aclRule.IP6List, node.StaticNode.AddressIPNet6())
+							}
+						}
+					}
+				}
+				// 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())
+				// 		}
+				// 		if node.Address6.IP != nil {
+				// 			aclRule.IP6List = append(aclRule.IP6List, node.AddressIPNet6())
+				// 		}
+				// 		if node.IsStatic && node.StaticNode.Address != "" {
+				// 			aclRule.IPList = append(aclRule.IPList, node.StaticNode.AddressIPNet4())
+				// 		}
+				// 		if node.IsStatic && node.StaticNode.Address6 != "" {
+				// 			aclRule.IP6List = append(aclRule.IP6List, node.StaticNode.AddressIPNet6())
+				// 		}
+				// 	}
+				// }
+			} else {
+				_, all := dstTags["*"]
+				if _, ok := dstTags[nodeTag.String()]; ok || all {
+					// get all src tags
+					for src := range srcTags {
+						if src == nodeTag.String() {
+							continue
+						}
+						// Get peers in the tags and add allowed rules
+						nodes := taggedNodes[models.TagID(src)]
+						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())
+							}
+							if node.Address6.IP != nil {
+								aclRule.IP6List = append(aclRule.IP6List, node.AddressIPNet6())
+							}
+							if node.IsStatic && node.StaticNode.Address != "" {
+								aclRule.IPList = append(aclRule.IPList, node.StaticNode.AddressIPNet4())
+							}
+							if node.IsStatic && node.StaticNode.Address6 != "" {
+								aclRule.IP6List = append(aclRule.IP6List, node.StaticNode.AddressIPNet6())
+							}
+						}
+					}
+				}
+			}
+
+		}
+
+		if len(aclRule.IPList) > 0 || len(aclRule.IP6List) > 0 {
+			aclRule.IPList = logic.UniqueIPNetList(aclRule.IPList)
+			aclRule.IP6List = logic.UniqueIPNetList(aclRule.IP6List)
+			rules[acl.ID] = aclRule
+		}
+	}
+	return rules
+}
+
+func GetEgressRulesForNode(targetnode models.Node) (rules map[string]models.AclRule) {
+	rules = make(map[string]models.AclRule)
+	defer func() {
+		rules = getEgressUserRulesForNode(&targetnode, rules)
+	}()
+	taggedNodes := GetTagMapWithNodesByNetwork(models.NetworkID(targetnode.Network), true)
+
+	acls := logic.ListDevicePolicies(models.NetworkID(targetnode.Network))
+	var targetNodeTags = make(map[models.TagID]struct{})
+	targetNodeTags["*"] = struct{}{}
+
+	/*
+		 if target node is egress gateway
+			if acl policy has egress route and it is present in target node egress ranges
+			fetch all the nodes in that policy and add rules
+	*/
+	egs, _ := (&schema.Egress{Network: targetnode.Network}).ListByNetwork(db.WithContext(context.TODO()))
+	if len(egs) == 0 {
+		return
+	}
+	for _, egI := range egs {
+		if !egI.Status {
+			continue
+		}
+		if _, ok := egI.Nodes[targetnode.ID.String()]; ok {
+			if egI.Range == "*" {
+				targetNodeTags[models.TagID("0.0.0.0/0")] = struct{}{}
+				targetNodeTags[models.TagID("::/0")] = struct{}{}
+			} else {
+				targetNodeTags[models.TagID(egI.Range)] = struct{}{}
+			}
+			targetNodeTags[models.TagID(egI.ID)] = struct{}{}
+		}
+	}
+	for _, acl := range acls {
+		if !acl.Enabled {
+			continue
+		}
+		srcTags := logic.ConvAclTagToValueMap(acl.Src)
+		dstTags := logic.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 nodeTag != "*" {
+				ip, cidr, err := net.ParseCIDR(nodeTag.String())
+				if err == nil {
+					if ip.To4() != nil {
+						aclRule.Dst = append(aclRule.Dst, *cidr)
+					} else {
+						aclRule.Dst6 = append(aclRule.Dst6, *cidr)
+					}
+				}
+			}
+			if acl.AllowedDirection == models.TrafficDirectionBi {
+				var existsInSrcTag bool
+				var existsInDstTag bool
+				if _, ok := srcTags[nodeTag.String()]; ok || srcAll {
+					existsInSrcTag = true
+				}
+				if _, ok := dstTags[nodeTag.String()]; ok || dstAll {
+					existsInDstTag = true
+				}
+				if srcAll || dstAll {
+					if targetnode.NetworkRange.IP != nil {
+						aclRule.IPList = append(aclRule.IPList, targetnode.NetworkRange)
+					}
+					if targetnode.NetworkRange6.IP != nil {
+						aclRule.IP6List = append(aclRule.IP6List, targetnode.NetworkRange6)
+					}
+					break
+				}
+				if existsInSrcTag && !existsInDstTag {
+					// get all dst tags
+					for dst := range dstTags {
+						if dst == nodeTag.String() {
+							continue
+						}
+						// Get peers in the tags and add allowed rules
+						nodes := taggedNodes[models.TagID(dst)]
+						if dst != targetnode.ID.String() {
+							node, err := logic.GetNodeByID(dst)
+							if err == nil {
+								nodes = append(nodes, node)
+							}
+						}
+
+						for _, node := range nodes {
+							if node.ID == targetnode.ID {
+								continue
+							}
+							if node.Address.IP != nil {
+								aclRule.IPList = append(aclRule.IPList, node.AddressIPNet4())
+							}
+							if node.Address6.IP != nil {
+								aclRule.IP6List = append(aclRule.IP6List, node.AddressIPNet6())
+							}
+							if node.IsStatic && node.StaticNode.Address != "" {
+								aclRule.IPList = append(aclRule.IPList, node.StaticNode.AddressIPNet4())
+							}
+							if node.IsStatic && node.StaticNode.Address6 != "" {
+								aclRule.IP6List = append(aclRule.IP6List, node.StaticNode.AddressIPNet6())
+							}
+						}
+					}
+				}
+				if existsInDstTag && !existsInSrcTag {
+					// get all src tags
+					for src := range srcTags {
+						if src == nodeTag.String() {
+							continue
+						}
+						// Get peers in the tags and add allowed rules
+						nodes := taggedNodes[models.TagID(src)]
+						if src != targetnode.ID.String() {
+							node, err := logic.GetNodeByID(src)
+							if err == nil {
+								nodes = append(nodes, node)
+							}
+						}
+						for _, node := range nodes {
+							if node.ID == targetnode.ID {
+								continue
+							}
+							if node.Address.IP != nil {
+								aclRule.IPList = append(aclRule.IPList, node.AddressIPNet4())
+							}
+							if node.Address6.IP != nil {
+								aclRule.IP6List = append(aclRule.IP6List, node.AddressIPNet6())
+							}
+							if node.IsStatic && node.StaticNode.Address != "" {
+								aclRule.IPList = append(aclRule.IPList, node.StaticNode.AddressIPNet4())
+							}
+							if node.IsStatic && node.StaticNode.Address6 != "" {
+								aclRule.IP6List = append(aclRule.IP6List, node.StaticNode.AddressIPNet6())
+							}
+						}
+					}
+				}
+				if existsInDstTag && existsInSrcTag {
+					nodes := taggedNodes[nodeTag]
+					for srcID := range srcTags {
+						if srcID == targetnode.ID.String() {
+							continue
+						}
+						node, err := logic.GetNodeByID(srcID)
+						if err == nil {
+							nodes = append(nodes, node)
+						}
+					}
+					for dstID := range dstTags {
+						if dstID == targetnode.ID.String() {
+							continue
+						}
+						node, err := logic.GetNodeByID(dstID)
+						if err == nil {
+							nodes = append(nodes, node)
+						}
+					}
+					for _, node := range nodes {
+						if node.ID == targetnode.ID {
+							continue
+						}
+						if node.Address.IP != nil {
+							aclRule.IPList = append(aclRule.IPList, node.AddressIPNet4())
+						}
+						if node.Address6.IP != nil {
+							aclRule.IP6List = append(aclRule.IP6List, node.AddressIPNet6())
+						}
+						if node.IsStatic && node.StaticNode.Address != "" {
+							aclRule.IPList = append(aclRule.IPList, node.StaticNode.AddressIPNet4())
+						}
+						if node.IsStatic && node.StaticNode.Address6 != "" {
+							aclRule.IP6List = append(aclRule.IP6List, node.StaticNode.AddressIPNet6())
+						}
+					}
+				}
+			} else {
+				if dstAll {
+					if targetnode.NetworkRange.IP != nil {
+						aclRule.IPList = append(aclRule.IPList, targetnode.NetworkRange)
+					}
+					if targetnode.NetworkRange6.IP != nil {
+						aclRule.IP6List = append(aclRule.IP6List, targetnode.NetworkRange6)
+					}
+					break
+				}
+				if _, ok := dstTags[nodeTag.String()]; ok || dstAll {
+					// get all src tags
+					for src := range srcTags {
+						if src == nodeTag.String() {
+							continue
+						}
+						// Get peers in the tags and add allowed rules
+						nodes := taggedNodes[models.TagID(src)]
+						for _, node := range nodes {
+							if node.ID == targetnode.ID {
+								continue
+							}
+							if node.Address.IP != nil {
+								aclRule.IPList = append(aclRule.IPList, node.AddressIPNet4())
+							}
+							if node.Address6.IP != nil {
+								aclRule.IP6List = append(aclRule.IP6List, node.AddressIPNet6())
+							}
+							if node.IsStatic && node.StaticNode.Address != "" {
+								aclRule.IPList = append(aclRule.IPList, node.StaticNode.AddressIPNet4())
+							}
+							if node.IsStatic && node.StaticNode.Address6 != "" {
+								aclRule.IP6List = append(aclRule.IP6List, node.StaticNode.AddressIPNet6())
+							}
+						}
+					}
+				}
+			}
+
+		}
+		if len(aclRule.IPList) > 0 || len(aclRule.IP6List) > 0 {
+			aclRule.IPList = logic.UniqueIPNetList(aclRule.IPList)
+			aclRule.IP6List = logic.UniqueIPNetList(aclRule.IP6List)
+			rules[acl.ID] = aclRule
+		}
+
+	}
+	return
+}
+
+func GetInetClientsFromAclPolicies(eID string) (inetClientIDs []string) {
+	e := schema.Egress{ID: eID}
+	err := e.Get(db.WithContext(context.TODO()))
+	if err != nil || !e.Status {
+		return
+	}
+	acls, _ := logic.ListAclsByNetwork(models.NetworkID(e.Network))
+	for _, acl := range acls {
+		for _, dstI := range acl.Dst {
+			if dstI.ID == models.EgressID {
+				if dstI.Value != eID {
+					continue
+				}
+				for _, srcI := range acl.Src {
+					if srcI.Value == "*" {
+						continue
+					}
+					if srcI.ID == models.NodeID {
+						inetClientIDs = append(inetClientIDs, srcI.Value)
+					}
+					if srcI.ID == models.NodeTagID {
+						inetClientIDs = append(inetClientIDs, GetNodeIDsWithTag(models.TagID(srcI.Value))...)
+					}
+				}
+			}
+		}
+	}
+	return
+}
+
+func IsNodeUsingInternetGw(node *models.Node) {
+	host, err := logic.GetHost(node.HostID.String())
+	if err != nil {
+		return
+	}
+	if host.IsDefault || node.IsFailOver {
+		return
+	}
+	nodeTags := maps.Clone(node.Tags)
+	if nodeTags == nil {
+		nodeTags = make(map[models.TagID]struct{})
+	}
+	nodeTags[models.TagID(node.ID.String())] = struct{}{}
+	acls, _ := logic.ListAclsByNetwork(models.NetworkID(node.Network))
+	var isUsing bool
+	for _, acl := range acls {
+		if !acl.Enabled {
+			continue
+		}
+		srcVal := logic.ConvAclTagToValueMap(acl.Src)
+		for _, dstI := range acl.Dst {
+			if dstI.ID == models.EgressID {
+				e := schema.Egress{ID: dstI.Value}
+				err := e.Get(db.WithContext(context.TODO()))
+				if err != nil || !e.Status {
+					continue
+				}
+
+				if e.IsInetGw {
+					if _, ok := srcVal[node.ID.String()]; ok {
+						for nodeID := range e.Nodes {
+							if nodeID == node.ID.String() {
+								continue
+							}
+							node.EgressDetails.InternetGwID = nodeID
+							isUsing = true
+							return
+						}
+					}
+					for tagID := range nodeTags {
+						if _, ok := srcVal[tagID.String()]; ok {
+							for nodeID := range e.Nodes {
+								if nodeID == node.ID.String() {
+									continue
+								}
+								node.EgressDetails.InternetGwID = nodeID
+								isUsing = true
+								return
+							}
+						}
+					}
+				}
+			}
+		}
+	}
+	if !isUsing {
+		node.EgressDetails.InternetGwID = ""
+	}
+}

+ 47 - 0
pro/logic/migrate.go

@@ -2,6 +2,8 @@ package logic
 
 import (
 	"encoding/json"
+	"fmt"
+
 	"github.com/google/uuid"
 	"github.com/gravitl/netmaker/database"
 
@@ -254,3 +256,48 @@ func MigrateUserRoleAndGroups(user models.User) {
 	}
 	logic.UpsertUser(user)
 }
+
+func MigrateToGws() {
+	nodes, err := logic.GetAllNodes()
+	if err != nil {
+		return
+	}
+	for _, node := range nodes {
+		if node.IsIngressGateway || node.IsRelay {
+			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 = fmt.Sprintf("%s.%s", acl.NetworkID.String(), 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 = fmt.Sprintf("%s.%s", acl.NetworkID.String(), models.GwTagName)
+				acl.Dst[i] = dstI
+				upsert = true
+			}
+		}
+		if upsert {
+			logic.UpsertAcl(acl)
+		}
+	}
+	nets, _ := logic.GetNetworks()
+	for _, netI := range nets {
+		DeleteTag(models.TagID(fmt.Sprintf("%s.%s", netI.NetID, models.OldRemoteAccessTagName)), true)
+	}
+}

+ 167 - 128
pro/logic/nodes.go

@@ -1,186 +1,225 @@
 package logic
 
 import (
-	"errors"
-	"fmt"
-	"net"
-
-	"github.com/google/uuid"
 	"github.com/gravitl/netmaker/logic"
 	"github.com/gravitl/netmaker/models"
-	"golang.org/x/exp/slog"
-)
-
-const (
-	IPv4Network = "0.0.0.0/0"
-	IPv6Network = "::/0"
 )
 
-func ValidateInetGwReq(inetNode models.Node, req models.InetNodeReq, update bool) error {
-	inetHost, err := logic.GetHost(inetNode.HostID.String())
+// GetNetworkIngresses - gets the gateways of a network
+func GetNetworkIngresses(network string) ([]models.Node, error) {
+	var ingresses []models.Node
+	netNodes, err := logic.GetNetworkNodes(network)
 	if err != nil {
-		return err
-	}
-	if inetHost.FirewallInUse == models.FIREWALL_NONE {
-		return errors.New("iptables or nftables needs to be installed")
-	}
-	if inetNode.EgressDetails.InternetGwID != "" {
-		return fmt.Errorf("node %s is using a internet gateway already", inetHost.Name)
+		return []models.Node{}, err
 	}
-	if inetNode.IsRelayed {
-		return fmt.Errorf("node %s is being relayed", inetHost.Name)
+	for i := range netNodes {
+		if netNodes[i].IsIngressGateway {
+			ingresses = append(ingresses, netNodes[i])
+		}
 	}
+	return ingresses, nil
+}
 
-	for _, clientNodeID := range req.InetNodeClientIDs {
-		clientNode, err := logic.GetNodeByID(clientNodeID)
-		if err != nil {
-			return err
+func GetTagMapWithNodes() (tagNodesMap map[models.TagID][]models.Node) {
+	tagNodesMap = make(map[models.TagID][]models.Node)
+	nodes, _ := logic.GetAllNodes()
+	for _, nodeI := range nodes {
+		if nodeI.Tags == nil {
+			continue
+		}
+		if nodeI.Mutex != nil {
+			nodeI.Mutex.Lock()
 		}
-		if clientNode.IsFailOver {
-			return errors.New("failover node cannot be set to use internet gateway")
+		for nodeTagID := range nodeI.Tags {
+			tagNodesMap[nodeTagID] = append(tagNodesMap[nodeTagID], nodeI)
 		}
-		clientHost, err := logic.GetHost(clientNode.HostID.String())
-		if err != nil {
-			return err
+		if nodeI.Mutex != nil {
+			nodeI.Mutex.Unlock()
 		}
-		if clientHost.IsDefault {
-			return errors.New("default host cannot be set to use internet gateway")
+
+	}
+	return
+}
+
+func GetTagMapWithNodesByNetwork(netID models.NetworkID, withStaticNodes bool) (tagNodesMap map[models.TagID][]models.Node) {
+	tagNodesMap = make(map[models.TagID][]models.Node)
+	nodes, _ := logic.GetNetworkNodes(netID.String())
+	for _, nodeI := range nodes {
+		tagNodesMap[models.TagID(nodeI.ID.String())] = []models.Node{
+			nodeI,
 		}
-		if clientHost.OS != models.OS_Types.Linux && clientHost.OS != models.OS_Types.Windows {
-			return errors.New("can only attach linux or windows machine to a internet gateway")
+		if nodeI.Tags == nil {
+			continue
 		}
-		if clientNode.EgressDetails.IsInternetGateway {
-			return fmt.Errorf("node %s acting as internet gateway cannot use another internet gateway", clientHost.Name)
+		if nodeI.Mutex != nil {
+			nodeI.Mutex.Lock()
 		}
-		if update {
-			if clientNode.EgressDetails.InternetGwID != "" && clientNode.EgressDetails.InternetGwID != inetNode.ID.String() {
-				return fmt.Errorf("node %s is already using a internet gateway", clientHost.Name)
-			}
-		} else {
-			if clientNode.EgressDetails.InternetGwID != "" {
-				return fmt.Errorf("node %s is already using a internet gateway", clientHost.Name)
+		for nodeTagID := range nodeI.Tags {
+			if nodeTagID == models.TagID(nodeI.ID.String()) {
+				continue
 			}
+			tagNodesMap[nodeTagID] = append(tagNodesMap[nodeTagID], nodeI)
 		}
-		if clientNode.FailedOverBy != uuid.Nil {
-			ResetFailedOverPeer(&clientNode)
+		if nodeI.Mutex != nil {
+			nodeI.Mutex.Unlock()
 		}
+	}
+	tagNodesMap["*"] = nodes
+	if !withStaticNodes {
+		return
+	}
+	return AddTagMapWithStaticNodes(netID, tagNodesMap)
+}
 
-		if clientNode.IsRelayed && clientNode.RelayedBy != inetNode.ID.String() {
-			return fmt.Errorf("node %s is being relayed", clientHost.Name)
+func AddTagMapWithStaticNodes(netID models.NetworkID,
+	tagNodesMap map[models.TagID][]models.Node) map[models.TagID][]models.Node {
+	extclients, err := logic.GetNetworkExtClients(netID.String())
+	if err != nil {
+		return tagNodesMap
+	}
+	for _, extclient := range extclients {
+		if extclient.RemoteAccessClientID != "" {
+			continue
+		}
+		tagNodesMap[models.TagID(extclient.ClientID)] = []models.Node{
+			{
+				IsStatic:   true,
+				StaticNode: extclient,
+			},
+		}
+		if extclient.Tags == nil {
+			continue
 		}
 
-		for _, nodeID := range clientHost.Nodes {
-			node, err := logic.GetNodeByID(nodeID)
-			if err != nil {
+		if extclient.Mutex != nil {
+			extclient.Mutex.Lock()
+		}
+		for tagID := range extclient.Tags {
+			if tagID == models.TagID(extclient.ClientID) {
 				continue
 			}
-			if node.EgressDetails.InternetGwID != "" && node.EgressDetails.InternetGwID != inetNode.ID.String() {
-				return errors.New("nodes on same host cannot use different internet gateway")
-			}
-
+			tagNodesMap[tagID] = append(tagNodesMap[tagID], extclient.ConvertToStaticNode())
+			tagNodesMap["*"] = append(tagNodesMap["*"], extclient.ConvertToStaticNode())
+		}
+		if extclient.Mutex != nil {
+			extclient.Mutex.Unlock()
 		}
 	}
-	return nil
+	return tagNodesMap
 }
 
-// SetInternetGw - sets the node as internet gw based on flag bool
-func SetInternetGw(node *models.Node, req models.InetNodeReq) {
-	node.EgressDetails.IsInternetGateway = true
-	node.EgressDetails.InetNodeReq = req
-	for _, clientNodeID := range req.InetNodeClientIDs {
-		clientNode, err := logic.GetNodeByID(clientNodeID)
-		if err != nil {
+func AddTagMapWithStaticNodesWithUsers(netID models.NetworkID,
+	tagNodesMap map[models.TagID][]models.Node) map[models.TagID][]models.Node {
+	extclients, err := logic.GetNetworkExtClients(netID.String())
+	if err != nil {
+		return tagNodesMap
+	}
+	for _, extclient := range extclients {
+		tagNodesMap[models.TagID(extclient.ClientID)] = []models.Node{
+			{
+				IsStatic:   true,
+				StaticNode: extclient,
+			},
+		}
+		if extclient.Tags == nil {
 			continue
 		}
-		clientNode.EgressDetails.InternetGwID = node.ID.String()
-		logic.UpsertNode(&clientNode)
-	}
+		if extclient.Mutex != nil {
+			extclient.Mutex.Lock()
+		}
+		for tagID := range extclient.Tags {
+			tagNodesMap[tagID] = append(tagNodesMap[tagID], extclient.ConvertToStaticNode())
+		}
+		if extclient.Mutex != nil {
+			extclient.Mutex.Unlock()
+		}
 
+	}
+	return tagNodesMap
 }
 
-func UnsetInternetGw(node *models.Node) {
-	nodes, err := logic.GetNetworkNodes(node.Network)
+func GetNodeIDsWithTag(tagID models.TagID) (ids []string) {
+
+	tag, err := GetTag(tagID)
 	if err != nil {
-		slog.Error("failed to get network nodes", "network", node.Network, "error", err)
 		return
 	}
-	for _, clientNode := range nodes {
-		if node.ID.String() == clientNode.EgressDetails.InternetGwID {
-			clientNode.EgressDetails.InternetGwID = ""
-			logic.UpsertNode(&clientNode)
+	nodes, _ := logic.GetNetworkNodes(tag.Network.String())
+	for _, nodeI := range nodes {
+		if nodeI.Tags == nil {
+			continue
 		}
-
-	}
-	node.EgressDetails.IsInternetGateway = false
-	node.EgressDetails.InetNodeReq = models.InetNodeReq{}
-
-}
-
-func SetDefaultGwForRelayedUpdate(relayed, relay models.Node, peerUpdate models.HostPeerUpdate) models.HostPeerUpdate {
-	if relay.EgressDetails.InternetGwID != "" {
-		relayedHost, err := logic.GetHost(relayed.HostID.String())
-		if err != nil {
-			return peerUpdate
+		if nodeI.Mutex != nil {
+			nodeI.Mutex.Lock()
 		}
-		peerUpdate.ChangeDefaultGw = true
-		peerUpdate.DefaultGwIp = relay.Address.IP
-		if peerUpdate.DefaultGwIp == nil || relayedHost.EndpointIP == nil {
-			peerUpdate.DefaultGwIp = relay.Address6.IP
+		if _, ok := nodeI.Tags[tagID]; ok {
+			ids = append(ids, nodeI.ID.String())
+		}
+		if nodeI.Mutex != nil {
+			nodeI.Mutex.Unlock()
 		}
-
 	}
-	return peerUpdate
+	return
 }
 
-func SetDefaultGw(node models.Node, peerUpdate models.HostPeerUpdate) models.HostPeerUpdate {
-	if node.EgressDetails.InternetGwID != "" {
-
-		inetNode, err := logic.GetNodeByID(node.EgressDetails.InternetGwID)
-		if err != nil {
-			return peerUpdate
+func GetNodesWithTag(tagID models.TagID) map[string]models.Node {
+	nMap := make(map[string]models.Node)
+	tag, err := GetTag(tagID)
+	if err != nil {
+		return nMap
+	}
+	nodes, _ := logic.GetNetworkNodes(tag.Network.String())
+	for _, nodeI := range nodes {
+		if nodeI.Tags == nil {
+			continue
 		}
-		host, err := logic.GetHost(node.HostID.String())
-		if err != nil {
-			return peerUpdate
+		if nodeI.Mutex != nil {
+			nodeI.Mutex.Lock()
 		}
-
-		peerUpdate.ChangeDefaultGw = true
-		peerUpdate.DefaultGwIp = inetNode.Address.IP
-		if peerUpdate.DefaultGwIp == nil || host.EndpointIP == nil {
-			peerUpdate.DefaultGwIp = inetNode.Address6.IP
+		if _, ok := nodeI.Tags[tagID]; ok {
+			nMap[nodeI.ID.String()] = nodeI
+		}
+		if nodeI.Mutex != nil {
+			nodeI.Mutex.Unlock()
 		}
 	}
-	return peerUpdate
+	return AddStaticNodesWithTag(tag, nMap)
 }
 
-// GetNetworkIngresses - gets the gateways of a network
-func GetNetworkIngresses(network string) ([]models.Node, error) {
-	var ingresses []models.Node
-	netNodes, err := logic.GetNetworkNodes(network)
+func AddStaticNodesWithTag(tag models.Tag, nMap map[string]models.Node) map[string]models.Node {
+	extclients, err := logic.GetNetworkExtClients(tag.Network.String())
 	if err != nil {
-		return []models.Node{}, err
+		return nMap
 	}
-	for i := range netNodes {
-		if netNodes[i].IsIngressGateway {
-			ingresses = append(ingresses, netNodes[i])
+	for _, extclient := range extclients {
+		if extclient.RemoteAccessClientID != "" {
+			continue
+		}
+		if extclient.Mutex != nil {
+			extclient.Mutex.Lock()
+		}
+		if _, ok := extclient.Tags[tag.ID]; ok {
+			nMap[extclient.ClientID] = extclient.ConvertToStaticNode()
+		}
+		if extclient.Mutex != nil {
+			extclient.Mutex.Unlock()
 		}
 	}
-	return ingresses, nil
+	return nMap
 }
 
-// GetAllowedIpForInetNodeClient - get inet cidr for node using a inet gw
-func GetAllowedIpForInetNodeClient(node, peer *models.Node) []net.IPNet {
-	var allowedips = []net.IPNet{}
-
-	if peer.Address.IP != nil {
-		_, ipnet, _ := net.ParseCIDR(IPv4Network)
-		allowedips = append(allowedips, *ipnet)
+func GetStaticNodeWithTag(tagID models.TagID) map[string]models.Node {
+	nMap := make(map[string]models.Node)
+	tag, err := GetTag(tagID)
+	if err != nil {
+		return nMap
 	}
-
-	if peer.Address6.IP != nil {
-		_, ipnet, _ := net.ParseCIDR(IPv6Network)
-		allowedips = append(allowedips, *ipnet)
+	extclients, err := logic.GetNetworkExtClients(tag.Network.String())
+	if err != nil {
+		return nMap
 	}
-
-	return allowedips
+	for _, extclient := range extclients {
+		nMap[extclient.ClientID] = extclient.ConvertToStaticNode()
+	}
+	return nMap
 }

+ 3 - 3
pro/logic/status.go

@@ -41,7 +41,7 @@ func GetNodeStatus(node *models.Node, defaultEnabledPolicy bool) {
 			return
 		}
 		if !defaultEnabledPolicy {
-			allowed, _ := logic.IsNodeAllowedToCommunicateV1(*node, ingNode, false)
+			allowed, _ := logic.IsNodeAllowedToCommunicate(*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.IsNodeAllowedToCommunicateV1(*node, peer, false)
+			allowed, _ := logic.IsNodeAllowedToCommunicate(*node, peer, false)
 			if !allowed {
 				continue
 			}
@@ -199,7 +199,7 @@ func checkPeerConnectivity(node *models.Node, metrics *models.Metrics, defaultAc
 		}
 
 		if !defaultAclPolicy {
-			allowed, _ := logic.IsNodeAllowedToCommunicateV1(*node, peer, false)
+			allowed, _ := logic.IsNodeAllowedToCommunicate(*node, peer, false)
 			if !allowed {
 				continue
 			}

+ 18 - 17
logic/tags.go → pro/logic/tags.go

@@ -10,6 +10,7 @@ import (
 	"time"
 
 	"github.com/gravitl/netmaker/database"
+	"github.com/gravitl/netmaker/logic"
 	"github.com/gravitl/netmaker/models"
 	"golang.org/x/exp/slog"
 )
@@ -62,7 +63,7 @@ func DeleteTag(tagID models.TagID, removeFromPolicy bool) error {
 	if err != nil {
 		return err
 	}
-	nodes, err := GetNetworkNodes(tag.Network.String())
+	nodes, err := logic.GetNetworkNodes(tag.Network.String())
 	if err != nil {
 		return err
 	}
@@ -70,18 +71,18 @@ func DeleteTag(tagID models.TagID, removeFromPolicy bool) error {
 		nodeI := nodeI
 		if _, ok := nodeI.Tags[tagID]; ok {
 			delete(nodeI.Tags, tagID)
-			UpsertNode(&nodeI)
+			logic.UpsertNode(&nodeI)
 		}
 	}
 	if removeFromPolicy {
 		// remove tag used on acl policy
 		go RemoveDeviceTagFromAclPolicies(tagID, tag.Network)
 	}
-	extclients, _ := GetNetworkExtClients(tag.Network.String())
+	extclients, _ := logic.GetNetworkExtClients(tag.Network.String())
 	for _, extclient := range extclients {
 		if _, ok := extclient.Tags[tagID]; ok {
 			delete(extclient.Tags, tagID)
-			SaveExtClient(&extclient)
+			logic.SaveExtClient(&extclient)
 		}
 	}
 	return database.DeleteRecord(database.TAG_TABLE_NAME, tagID.String())
@@ -99,7 +100,7 @@ func ListTagsWithNodes(netID models.NetworkID) ([]models.TagListResp, error) {
 		tagRespI := models.TagListResp{
 			Tag:         tagI,
 			UsedByCnt:   len(tagsNodeMap[tagI.ID]),
-			TaggedNodes: GetAllNodesAPI(tagsNodeMap[tagI.ID]),
+			TaggedNodes: logic.GetAllNodesAPI(tagsNodeMap[tagI.ID]),
 		}
 		resp = append(resp, tagRespI)
 	}
@@ -168,7 +169,7 @@ func UpdateTag(req models.UpdateTagReq, newID models.TagID) {
 			if apiNode.StaticNode.RemoteAccessClientID != "" {
 				continue
 			}
-			extclient, err := GetExtClient(apiNode.StaticNode.ClientID, apiNode.StaticNode.Network)
+			extclient, err := logic.GetExtClient(apiNode.StaticNode.ClientID, apiNode.StaticNode.Network)
 			if err != nil {
 				continue
 			}
@@ -176,7 +177,7 @@ func UpdateTag(req models.UpdateTagReq, newID models.TagID) {
 			nodeID = extclient.ClientID
 			node.StaticNode = extclient
 		} else {
-			node, err = GetNodeByID(apiNode.ID)
+			node, err = logic.GetNodeByID(apiNode.ID)
 			if err != nil {
 				continue
 			}
@@ -193,19 +194,19 @@ func UpdateTag(req models.UpdateTagReq, newID models.TagID) {
 			if newID != "" {
 				if node.IsStatic {
 					node.StaticNode.Tags[newID] = struct{}{}
-					SaveExtClient(&node.StaticNode)
+					logic.SaveExtClient(&node.StaticNode)
 				} else {
 					node.Tags[newID] = struct{}{}
-					UpsertNode(&node)
+					logic.UpsertNode(&node)
 				}
 
 			} else {
 				if node.IsStatic {
 					node.StaticNode.Tags[req.ID] = struct{}{}
-					SaveExtClient(&node.StaticNode)
+					logic.SaveExtClient(&node.StaticNode)
 				} else {
 					node.Tags[req.ID] = struct{}{}
-					UpsertNode(&node)
+					logic.UpsertNode(&node)
 				}
 			}
 		} else {
@@ -214,10 +215,10 @@ func UpdateTag(req models.UpdateTagReq, newID models.TagID) {
 				delete(node.StaticNode.Tags, req.ID)
 				if node.IsStatic {
 					node.StaticNode.Tags[newID] = struct{}{}
-					SaveExtClient(&node.StaticNode)
+					logic.SaveExtClient(&node.StaticNode)
 				} else {
 					node.Tags[newID] = struct{}{}
-					UpsertNode(&node)
+					logic.UpsertNode(&node)
 				}
 			}
 			delete(tagNodesMap, nodeID)
@@ -228,9 +229,9 @@ func UpdateTag(req models.UpdateTagReq, newID models.TagID) {
 		delete(deletedTaggedNode.Tags, req.ID)
 		delete(deletedTaggedNode.StaticNode.Tags, req.ID)
 		if deletedTaggedNode.IsStatic {
-			SaveExtClient(&deletedTaggedNode.StaticNode)
+			logic.SaveExtClient(&deletedTaggedNode.StaticNode)
 		} else {
-			UpsertNode(&deletedTaggedNode)
+			logic.UpsertNode(&deletedTaggedNode)
 		}
 	}
 	go func(req models.UpdateTagReq) {
@@ -249,9 +250,9 @@ func UpdateTag(req models.UpdateTagReq, newID models.TagID) {
 				nodeI.Tags[newID] = struct{}{}
 				nodeI.StaticNode.Tags[newID] = struct{}{}
 				if nodeI.IsStatic {
-					SaveExtClient(&nodeI.StaticNode)
+					logic.SaveExtClient(&nodeI.StaticNode)
 				} else {
-					UpsertNode(&nodeI)
+					logic.UpsertNode(&nodeI)
 				}
 			}
 		}

+ 77 - 4
pro/logic/user_mgmt.go

@@ -4,9 +4,10 @@ import (
 	"encoding/json"
 	"errors"
 	"fmt"
-	"github.com/google/uuid"
 	"time"
 
+	"github.com/google/uuid"
+
 	"github.com/gravitl/netmaker/database"
 	"github.com/gravitl/netmaker/logic"
 	"github.com/gravitl/netmaker/models"
@@ -688,8 +689,8 @@ func GetUserRAGNodesV1(user models.User) (gws map[string]models.Node) {
 
 		}
 	}
-	tagNodesMap := logic.GetTagMapWithNodes()
-	accessPolices := logic.ListUserPolicies(user)
+	tagNodesMap := GetTagMapWithNodes()
+	accessPolices := ListUserPolicies(user)
 	for _, policyI := range accessPolices {
 		if !policyI.Enabled {
 			continue
@@ -722,9 +723,33 @@ func GetUserRAGNodes(user models.User) (gws map[string]models.Node) {
 	if err != nil {
 		return
 	}
+
 	for _, node := range nodes {
-		if ok, _ := logic.IsUserAllowedToCommunicate(user.UserName, node); ok {
+		if !node.IsGw {
+			continue
+		}
+		if user.PlatformRoleID == models.AdminRole || user.PlatformRoleID == models.SuperAdminRole {
 			gws[node.ID.String()] = node
+		} else {
+			// check if user has network role assigned
+			if roles, ok := user.NetworkRoles[models.NetworkID(node.Network)]; ok && len(roles) > 0 {
+				if ok, _ := IsUserAllowedToCommunicate(user.UserName, node); ok {
+					gws[node.ID.String()] = node
+					continue
+				}
+			}
+			for groupID := range user.UserGroups {
+				userGrp, err := logic.GetUserGroup(groupID)
+				if err == nil {
+					if roles, ok := userGrp.NetworkRoles[models.NetworkID(node.Network)]; ok && len(roles) > 0 {
+						if ok, _ := IsUserAllowedToCommunicate(user.UserName, node); ok {
+							gws[node.ID.String()] = node
+							break
+						}
+					}
+				}
+			}
+
 		}
 	}
 	return
@@ -1169,6 +1194,35 @@ func CreateDefaultUserPolicies(netID models.NetworkID) {
 		return
 	}
 
+	if !logic.IsAclExists(fmt.Sprintf("%s.%s", netID, "all-users")) {
+		defaultUserAcl := models.Acl{
+			ID:          fmt.Sprintf("%s.%s", netID, "all-users"),
+			Default:     true,
+			Name:        "All Users",
+			MetaData:    "This policy gives access to everything in the network for an user",
+			NetworkID:   netID,
+			Proto:       models.ALL,
+			ServiceType: models.Any,
+			Port:        []string{},
+			RuleType:    models.UserPolicy,
+			Src: []models.AclPolicyTag{
+				{
+					ID:    models.UserAclID,
+					Value: "*",
+				},
+			},
+			Dst: []models.AclPolicyTag{{
+				ID:    models.NodeTagID,
+				Value: "*",
+			}},
+			AllowedDirection: models.TrafficDirectionUni,
+			Enabled:          true,
+			CreatedBy:        "auto",
+			CreatedAt:        time.Now().UTC(),
+		}
+		logic.InsertAcl(defaultUserAcl)
+	}
+
 	if !logic.IsAclExists(fmt.Sprintf("%s.%s-grp", netID, models.NetworkAdmin)) {
 		networkAdminGroupID := GetDefaultNetworkAdminGroupID(netID)
 
@@ -1268,3 +1322,22 @@ func AddGlobalNetRolesToAdmins(u *models.User) {
 
 	u.UserGroups[globalNetworksAdminGroupID] = struct{}{}
 }
+
+func GetUserGrpMap() map[models.UserGroupID]map[string]struct{} {
+	grpUsersMap := make(map[models.UserGroupID]map[string]struct{})
+	users, _ := logic.GetUsersDB()
+	for _, user := range users {
+		for gID := range user.UserGroups {
+			if grpUsers, ok := grpUsersMap[gID]; ok {
+				grpUsers[user.UserName] = struct{}{}
+				grpUsersMap[gID] = grpUsers
+			} else {
+				grpUsersMap[gID] = make(map[string]struct{})
+				grpUsersMap[gID][user.UserName] = struct{}{}
+			}
+		}
+
+	}
+
+	return grpUsersMap
+}

+ 1 - 1
servercfg/serverconf.go

@@ -685,7 +685,7 @@ func GetMetricInterval() string {
 
 // GetManageDNS - if manage DNS enabled or not
 func GetManageDNS() bool {
-	enabled := false
+	enabled := true
 	if os.Getenv("MANAGE_DNS") != "" {
 		enabled = os.Getenv("MANAGE_DNS") == "true"
 	}

部分文件因文件數量過多而無法顯示