|
@@ -0,0 +1,1813 @@
|
|
|
|
+package logic
|
|
|
|
+
|
|
|
|
+import (
|
|
|
|
+ "context"
|
|
|
|
+ "errors"
|
|
|
|
+ "fmt"
|
|
|
|
+ "maps"
|
|
|
|
+ "net"
|
|
|
|
+ "sort"
|
|
|
|
+ "time"
|
|
|
|
+
|
|
|
|
+ "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 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 {
|
|
|
|
+ req.InetNodeClientIDs = append(req.InetNodeClientIDs, node.ID.String())
|
|
|
|
+ }
|
|
|
|
+ } else if srcI.ID == models.NodeID {
|
|
|
|
+ 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 = 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
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// CreateDefaultAclNetworkPolicies - create default acl network policies
|
|
|
|
+func CreateDefaultAclNetworkPolicies(netID models.NetworkID) {
|
|
|
|
+ if netID.String() == "" {
|
|
|
|
+ return
|
|
|
|
+ }
|
|
|
|
+ _, _ = logic.ListAclsByNetwork(netID)
|
|
|
|
+ if !logic.IsAclExists(fmt.Sprintf("%s.%s", netID, "all-nodes")) {
|
|
|
|
+ defaultDeviceAcl := models.Acl{
|
|
|
|
+ ID: fmt.Sprintf("%s.%s", netID, "all-nodes"),
|
|
|
|
+ Name: "All Nodes",
|
|
|
|
+ MetaData: "This Policy allows all nodes in the network to communicate with each other",
|
|
|
|
+ Default: true,
|
|
|
|
+ NetworkID: netID,
|
|
|
|
+ Proto: models.ALL,
|
|
|
|
+ ServiceType: models.Any,
|
|
|
|
+ Port: []string{},
|
|
|
|
+ RuleType: models.DevicePolicy,
|
|
|
|
+ Src: []models.AclPolicyTag{
|
|
|
|
+ {
|
|
|
|
+ ID: models.NodeTagID,
|
|
|
|
+ Value: "*",
|
|
|
|
+ }},
|
|
|
|
+ Dst: []models.AclPolicyTag{
|
|
|
|
+ {
|
|
|
|
+ ID: models.NodeTagID,
|
|
|
|
+ Value: "*",
|
|
|
|
+ }},
|
|
|
|
+ AllowedDirection: models.TrafficDirectionBi,
|
|
|
|
+ Enabled: true,
|
|
|
|
+ CreatedBy: "auto",
|
|
|
|
+ CreatedAt: time.Now().UTC(),
|
|
|
|
+ }
|
|
|
|
+ logic.InsertAcl(defaultDeviceAcl)
|
|
|
|
+ }
|
|
|
|
+ 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", netID, "all-gateways")) {
|
|
|
|
+ defaultUserAcl := models.Acl{
|
|
|
|
+ ID: fmt.Sprintf("%s.%s", netID, "all-gateways"),
|
|
|
|
+ Default: true,
|
|
|
|
+ Name: "All Gateways",
|
|
|
|
+ NetworkID: netID,
|
|
|
|
+ Proto: models.ALL,
|
|
|
|
+ ServiceType: models.Any,
|
|
|
|
+ Port: []string{},
|
|
|
|
+ RuleType: models.DevicePolicy,
|
|
|
|
+ Src: []models.AclPolicyTag{
|
|
|
|
+ {
|
|
|
|
+ ID: models.NodeTagID,
|
|
|
|
+ Value: fmt.Sprintf("%s.%s", netID, models.GwTagName),
|
|
|
|
+ },
|
|
|
|
+ },
|
|
|
|
+ Dst: []models.AclPolicyTag{
|
|
|
|
+ {
|
|
|
|
+ ID: models.NodeTagID,
|
|
|
|
+ Value: "*",
|
|
|
|
+ },
|
|
|
|
+ },
|
|
|
|
+ AllowedDirection: models.TrafficDirectionBi,
|
|
|
|
+ Enabled: true,
|
|
|
|
+ CreatedBy: "auto",
|
|
|
|
+ CreatedAt: time.Now().UTC(),
|
|
|
|
+ }
|
|
|
|
+ logic.InsertAcl(defaultUserAcl)
|
|
|
|
+ }
|
|
|
|
+ CreateDefaultUserPolicies(netID)
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// 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
|
|
|
|
+ }
|
|
|
|
+ peerTags[models.TagID(peerId)] = 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.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 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)
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+func checkTagGroupPolicy(srcMap, dstMap map[string]struct{}, node, peer models.Node,
|
|
|
|
+ nodeTags, peerTags map[models.TagID]struct{}) bool {
|
|
|
|
+ // check for node ID
|
|
|
|
+ if _, ok := srcMap[node.ID.String()]; ok {
|
|
|
|
+ if _, ok = dstMap[peer.ID.String()]; ok {
|
|
|
|
+ return true
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+ if _, ok := dstMap[node.ID.String()]; ok {
|
|
|
|
+ if _, ok = srcMap[peer.ID.String()]; ok {
|
|
|
|
+ return true
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ for tagID := range nodeTags {
|
|
|
|
+ if _, ok := dstMap[tagID.String()]; ok {
|
|
|
|
+ if _, ok := srcMap["*"]; ok {
|
|
|
|
+ return true
|
|
|
|
+ }
|
|
|
|
+ for tagID := range peerTags {
|
|
|
|
+ if _, ok := srcMap[tagID.String()]; ok {
|
|
|
|
+ return true
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ if _, ok := srcMap[tagID.String()]; ok {
|
|
|
|
+ if _, ok := dstMap["*"]; ok {
|
|
|
|
+ return true
|
|
|
|
+ }
|
|
|
|
+ for tagID := range peerTags {
|
|
|
|
+ if _, ok := dstMap[tagID.String()]; ok {
|
|
|
|
+ return true
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ for tagID := range peerTags {
|
|
|
|
+ if _, ok := dstMap[tagID.String()]; ok {
|
|
|
|
+ if _, ok := srcMap["*"]; ok {
|
|
|
|
+ return true
|
|
|
|
+ }
|
|
|
|
+ for tagID := range nodeTags {
|
|
|
|
+
|
|
|
|
+ if _, ok := srcMap[tagID.String()]; ok {
|
|
|
|
+ return true
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ if _, ok := srcMap[tagID.String()]; ok {
|
|
|
|
+ if _, ok := dstMap["*"]; ok {
|
|
|
|
+ return true
|
|
|
|
+ }
|
|
|
|
+ for tagID := range nodeTags {
|
|
|
|
+ if _, ok := dstMap[tagID.String()]; ok {
|
|
|
|
+ return true
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ return false
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// IsNodeAllowedToCommunicate - check node is allowed to communicate with the peer // ADD ALLOWED DIRECTION - 0 => node -> peer, 1 => peer-> node,
|
|
|
|
+func IsNodeAllowedToCommunicateV1(node, peer models.Node, checkDefaultPolicy bool) (bool, []models.Acl) {
|
|
|
|
+ var nodeId, peerId string
|
|
|
|
+ if 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.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 = UniqueIPNetList(aclRule.IPList)
|
|
|
|
+ aclRule.IP6List = UniqueIPNetList(aclRule.IP6List)
|
|
|
|
+ rules[acl.ID] = aclRule
|
|
|
|
+ } else {
|
|
|
|
+ r.IPList = UniqueIPNetList(r.IPList)
|
|
|
|
+ r.IP6List = 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 {
|
|
|
|
+ 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{}{}
|
|
|
|
+ }
|
|
|
|
+ dstTags[e.Range] = struct{}{}
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ for nodeTag := range targetNodeTags {
|
|
|
|
+ if acl.RuleType == models.DevicePolicy && acl.AllowedDirection == models.TrafficDirectionBi {
|
|
|
|
+ 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 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 checkIfNodeHasAccessToAllResources(targetnode *models.Node) bool {
|
|
|
|
+ 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)
|
|
|
|
+ _, srcAll := srcTags["*"]
|
|
|
|
+ _, dstAll := dstTags["*"]
|
|
|
|
+ for nodeTag := range targetNodeTags {
|
|
|
|
+
|
|
|
|
+ var existsInSrcTag bool
|
|
|
|
+ var existsInDstTag bool
|
|
|
|
+
|
|
|
|
+ if _, ok := srcTags[nodeTag.String()]; ok {
|
|
|
|
+ existsInSrcTag = true
|
|
|
|
+ }
|
|
|
|
+ if _, ok := srcTags[targetnode.ID.String()]; ok {
|
|
|
|
+ existsInSrcTag = true
|
|
|
|
+ }
|
|
|
|
+ if _, ok := dstTags[nodeTag.String()]; ok {
|
|
|
|
+ existsInDstTag = true
|
|
|
|
+ }
|
|
|
|
+ if _, ok := dstTags[targetnode.ID.String()]; ok {
|
|
|
|
+ existsInDstTag = true
|
|
|
|
+ }
|
|
|
|
+ if acl.AllowedDirection == models.TrafficDirectionBi {
|
|
|
|
+ if existsInSrcTag && dstAll || existsInDstTag && srcAll {
|
|
|
|
+ return true
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ if existsInDstTag && srcAll {
|
|
|
|
+ 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 = UniqueIPNetList(aclRule.IPList)
|
|
|
|
+ aclRule.IP6List = 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 = UniqueIPNetList(aclRule.IPList)
|
|
|
|
+ aclRule.IP6List = UniqueIPNetList(aclRule.IP6List)
|
|
|
|
+ rules[acl.ID] = aclRule
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+ return
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// Compare two IPs and return true if ip1 < ip2
|
|
|
|
+func lessIP(ip1, ip2 net.IP) bool {
|
|
|
|
+ ip1 = ip1.To16() // Ensure IPv4 is converted to IPv6-mapped format
|
|
|
|
+ ip2 = ip2.To16()
|
|
|
|
+ return string(ip1) < string(ip2)
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// Sort by IP first, then by prefix length
|
|
|
|
+func sortIPNets(ipNets []net.IPNet) {
|
|
|
|
+ sort.Slice(ipNets, func(i, j int) bool {
|
|
|
|
+ ip1, ip2 := ipNets[i].IP, ipNets[j].IP
|
|
|
|
+ mask1, _ := ipNets[i].Mask.Size()
|
|
|
|
+ mask2, _ := ipNets[j].Mask.Size()
|
|
|
|
+
|
|
|
|
+ // Compare IPs first
|
|
|
|
+ if ip1.Equal(ip2) {
|
|
|
|
+ return mask1 < mask2 // If same IP, sort by subnet mask size
|
|
|
|
+ }
|
|
|
|
+ return lessIP(ip1, ip2)
|
|
|
|
+ })
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+func UniqueIPNetList(ipnets []net.IPNet) []net.IPNet {
|
|
|
|
+ uniqueMap := make(map[string]net.IPNet)
|
|
|
|
+
|
|
|
|
+ for _, ipnet := range ipnets {
|
|
|
|
+ key := ipnet.String() // Uses CIDR notation as a unique key
|
|
|
|
+ if _, exists := uniqueMap[key]; !exists {
|
|
|
|
+ uniqueMap[key] = ipnet
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // Convert map back to slice
|
|
|
|
+ uniqueList := make([]net.IPNet, 0, len(uniqueMap))
|
|
|
|
+ for _, ipnet := range uniqueMap {
|
|
|
|
+ uniqueList = append(uniqueList, ipnet)
|
|
|
|
+ }
|
|
|
|
+ sortIPNets(uniqueList)
|
|
|
|
+ return uniqueList
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+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)
|
|
|
|
+ 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 = ""
|
|
|
|
+ }
|
|
|
|
+}
|