Browse Source

add gw rules func to pro

abhishek9686 3 months ago
parent
commit
e32a3c3e41
5 changed files with 362 additions and 363 deletions
  1. 2 0
      logic/acls.go
  2. 0 360
      logic/extpeers.go
  3. 1 3
      logic/peers.go
  4. 2 0
      pro/initialize.go
  5. 357 0
      pro/logic/acls.go

+ 2 - 0
logic/acls.go

@@ -21,6 +21,8 @@ import (
 // TODO: Write Diff Funcs
 
 var IsNodeAllowedToCommunicate = isNodeAllowedToCommunicate
+var GetStaticNodeIps = func(node models.Node) (ips []net.IP) { return }
+var GetFwRulesOnIngressGateway = func(node models.Node) (rules []models.FwRule) { return }
 var MigrateToGws = func() {
 
 	nodes, err := GetAllNodes()

+ 0 - 360
logic/extpeers.go

@@ -1,24 +1,20 @@
 package logic
 
 import (
-	"context"
 	"encoding/json"
 	"errors"
 	"fmt"
 	"net"
 	"reflect"
-	"sort"
 	"strings"
 	"sync"
 	"time"
 
 	"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"
@@ -493,362 +489,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 = 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 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

+ 1 - 3
logic/peers.go

@@ -433,9 +433,7 @@ func GetPeerUpdateForHost(network string, host *models.Host, allNodes []models.N
 			hostPeerUpdate.FwUpdate.IsIngressGw = true
 			extPeers, extPeerIDAndAddrs, egressRoutes, err = GetExtPeers(&node, &node)
 			if err == nil {
-				if !((defaultDevicePolicy.Enabled && defaultUserPolicy.Enabled) ||
-					(!anyUniDirectionPolicy && !anyActiveEgressPolicy) ||
-					nodeHasAccessToAllRsrcs) {
+				if !defaultDevicePolicy.Enabled || !defaultUserPolicy.Enabled {
 					ingFwUpdate := models.IngressInfo{
 						IngressID:     node.ID.String(),
 						Network:       node.NetworkRange,

+ 2 - 0
pro/initialize.go

@@ -161,6 +161,8 @@ func InitPro() {
 	logic.CheckIfAnyPolicyisUniDirectional = proLogic.CheckIfAnyPolicyisUniDirectional
 	logic.MigrateToGws = proLogic.MigrateToGws
 	logic.IsNodeAllowedToCommunicate = proLogic.IsNodeAllowedToCommunicate
+	logic.GetStaticNodeIps = proLogic.GetStaticNodeIps
+	logic.GetFwRulesOnIngressGateway = proLogic.GetFwRulesOnIngressGateway
 
 }
 

+ 357 - 0
pro/logic/acls.go

@@ -5,6 +5,7 @@ import (
 	"errors"
 	"maps"
 	"net"
+	"sort"
 
 	"github.com/gravitl/netmaker/db"
 	"github.com/gravitl/netmaker/logic"
@@ -23,6 +24,362 @@ ranges should be replaced by egress identifier
 
 */
 
+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: