mirror of
				https://github.com/gravitl/netmaker.git
				synced 2025-11-01 04:32:40 +08:00 
			
		
		
		
	NET-1910: Acl controls for Egress Traffic (#3377)
* add support for egress ranges on acl policy * add egress ranges to acl rules * add egress ranges to acl policies * Add egress ranges to acl rules * add egress ranges to fw update * fetch acl rules for egress networks * apply egress policies for devices * configure user policies for egresss routes * fix gw tag name migration * fix egress acl rules for static nodes * add egress ranges for static nodes on ingress gw * fileter acl IPs to be unique * cleanup IOT logic from peer update * make acl Rule Dst List * cleanup egress ranges from acl policies * create user group default acl policy for gateways * remove remote access name ids * rm egress ranges removal from acl policies * simplify user permissions on nodes * add additional nameservers to extclient dns * remove debug logs * fix static checks
This commit is contained in:
		| @@ -4,7 +4,7 @@ ARG tags | |||||||
| WORKDIR /app | WORKDIR /app | ||||||
| COPY . . | COPY . . | ||||||
|  |  | ||||||
| RUN GOOS=linux CGO_ENABLED=1 go build -ldflags="-s -w " -tags ${tags} . | RUN GOOS=linux CGO_ENABLED=1 go build -race -ldflags="-s -w " -tags ${tags} . | ||||||
| # RUN go build -tags=ee . -o netmaker main.go | # RUN go build -tags=ee . -o netmaker main.go | ||||||
| FROM alpine:3.21.2 | FROM alpine:3.21.2 | ||||||
|  |  | ||||||
|   | |||||||
| @@ -51,6 +51,7 @@ func aclPolicyTypes(w http.ResponseWriter, r *http.Request) { | |||||||
| 		DstGroupTypes: []models.AclGroupType{ | 		DstGroupTypes: []models.AclGroupType{ | ||||||
| 			models.NodeTagID, | 			models.NodeTagID, | ||||||
| 			models.NodeID, | 			models.NodeID, | ||||||
|  | 			models.EgressRange, | ||||||
| 			// models.NetmakerIPAclID, | 			// models.NetmakerIPAclID, | ||||||
| 			// models.NetmakerSubNetRangeAClID, | 			// models.NetmakerSubNetRangeAClID, | ||||||
| 		}, | 		}, | ||||||
|   | |||||||
| @@ -475,7 +475,18 @@ func getExtClientHAConf(w http.ResponseWriter, r *http.Request) { | |||||||
| 	// 	models.RemoteAccessTagName))] = struct{}{} | 	// 	models.RemoteAccessTagName))] = struct{}{} | ||||||
| 	// set extclient dns to ingressdns if extclient dns is not explicitly set | 	// set extclient dns to ingressdns if extclient dns is not explicitly set | ||||||
| 	if (extclient.DNS == "") && (gwnode.IngressDNS != "") { | 	if (extclient.DNS == "") && (gwnode.IngressDNS != "") { | ||||||
| 		extclient.DNS = gwnode.IngressDNS | 		network, _ := logic.GetNetwork(gwnode.Network) | ||||||
|  | 		dns := gwnode.IngressDNS | ||||||
|  | 		if len(network.NameServers) > 0 { | ||||||
|  | 			if dns == "" { | ||||||
|  | 				dns = strings.Join(network.NameServers, ",") | ||||||
|  | 			} else { | ||||||
|  | 				dns += "," + strings.Join(network.NameServers, ",") | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 		} | ||||||
|  | 		extclient.DNS = dns | ||||||
|  |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	listenPort := logic.GetPeerListenPort(host) | 	listenPort := logic.GetPeerListenPort(host) | ||||||
|   | |||||||
| @@ -140,61 +140,13 @@ func upgradeHost(w http.ResponseWriter, r *http.Request) { | |||||||
| // @Failure     500 {object} models.ErrorResponse | // @Failure     500 {object} models.ErrorResponse | ||||||
| func getHosts(w http.ResponseWriter, r *http.Request) { | func getHosts(w http.ResponseWriter, r *http.Request) { | ||||||
| 	w.Header().Set("Content-Type", "application/json") | 	w.Header().Set("Content-Type", "application/json") | ||||||
| 	currentHosts := []models.Host{} |  | ||||||
| 	var err error |  | ||||||
| 	if r.Header.Get("ismaster") == "yes" { |  | ||||||
| 		currentHosts, err = logic.GetAllHosts() |  | ||||||
| 		if err != nil { |  | ||||||
| 			logger.Log(0, r.Header.Get("user"), "failed to fetch hosts: ", err.Error()) |  | ||||||
| 			logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal")) |  | ||||||
| 			return |  | ||||||
| 		} |  | ||||||
| 	} else { |  | ||||||
| 		username := r.Header.Get("user") |  | ||||||
| 		user, err := logic.GetUser(username) |  | ||||||
| 		if err != nil { |  | ||||||
| 			return |  | ||||||
| 		} |  | ||||||
| 		userPlatformRole, err := logic.GetRole(user.PlatformRoleID) |  | ||||||
| 		if err != nil { |  | ||||||
| 			return |  | ||||||
| 		} |  | ||||||
| 		respHostsMap := make(map[string]struct{}) |  | ||||||
| 		if !userPlatformRole.FullAccess { |  | ||||||
| 			nodes, err := logic.GetAllNodes() |  | ||||||
| 			if err != nil { |  | ||||||
| 				logger.Log(0, "error fetching all nodes info: ", err.Error()) |  | ||||||
| 				logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal")) |  | ||||||
| 				return |  | ||||||
| 			} |  | ||||||
| 			filteredNodes := logic.GetFilteredNodesByUserAccess(*user, nodes) |  | ||||||
| 			if len(filteredNodes) > 0 { |  | ||||||
| 				currentHostsMap, err := logic.GetHostsMap() |  | ||||||
| 				if err != nil { |  | ||||||
| 					logger.Log(0, r.Header.Get("user"), "failed to fetch hosts: ", err.Error()) |  | ||||||
| 					logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal")) |  | ||||||
| 					return |  | ||||||
| 				} |  | ||||||
| 				for _, node := range filteredNodes { |  | ||||||
| 					if _, ok := respHostsMap[node.HostID.String()]; ok { |  | ||||||
| 						continue |  | ||||||
| 					} |  | ||||||
| 					if host, ok := currentHostsMap[node.HostID.String()]; ok { |  | ||||||
| 						currentHosts = append(currentHosts, host) |  | ||||||
| 						respHostsMap[host.ID.String()] = struct{}{} |  | ||||||
| 					} |  | ||||||
| 				} |  | ||||||
|  |  | ||||||
| 			} | 	currentHosts, err := logic.GetAllHosts() | ||||||
| 		} else { |  | ||||||
| 			currentHosts, err = logic.GetAllHosts() |  | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		logger.Log(0, r.Header.Get("user"), "failed to fetch hosts: ", err.Error()) | 		logger.Log(0, r.Header.Get("user"), "failed to fetch hosts: ", err.Error()) | ||||||
| 		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal")) | 		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal")) | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	apiHosts := logic.GetAllHostsAPI(currentHosts[:]) | 	apiHosts := logic.GetAllHostsAPI(currentHosts[:]) | ||||||
| 	logger.Log(2, r.Header.Get("user"), "fetched all hosts") | 	logger.Log(2, r.Header.Get("user"), "fetched all hosts") | ||||||
|   | |||||||
| @@ -41,6 +41,7 @@ func networkHandlers(r *mux.Router) { | |||||||
| 		Methods(http.MethodPut) | 		Methods(http.MethodPut) | ||||||
| 	r.HandleFunc("/api/networks/{networkname}/acls", logic.SecurityCheck(true, http.HandlerFunc(getNetworkACL))). | 	r.HandleFunc("/api/networks/{networkname}/acls", logic.SecurityCheck(true, http.HandlerFunc(getNetworkACL))). | ||||||
| 		Methods(http.MethodGet) | 		Methods(http.MethodGet) | ||||||
|  | 	r.HandleFunc("/api/networks/{networkname}/egress_routes", logic.SecurityCheck(true, http.HandlerFunc(getNetworkEgressRoutes))) | ||||||
| } | } | ||||||
|  |  | ||||||
| // @Summary     Lists all networks | // @Summary     Lists all networks | ||||||
| @@ -429,6 +430,33 @@ func getNetworkACL(w http.ResponseWriter, r *http.Request) { | |||||||
| 	json.NewEncoder(w).Encode(networkACL) | 	json.NewEncoder(w).Encode(networkACL) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // @Summary     Get a network Egress routes | ||||||
|  | // @Router      /api/networks/{networkname}/egress_routes [get] | ||||||
|  | // @Tags        Networks | ||||||
|  | // @Security    oauth | ||||||
|  | // @Param       networkname path string true "Network name" | ||||||
|  | // @Produce     json | ||||||
|  | // @Success     200 {object} acls.SuccessResponse | ||||||
|  | // @Failure     500 {object} models.ErrorResponse | ||||||
|  | func getNetworkEgressRoutes(w http.ResponseWriter, r *http.Request) { | ||||||
|  | 	var params = mux.Vars(r) | ||||||
|  | 	netname := params["networkname"] | ||||||
|  | 	// check if network exists | ||||||
|  | 	_, err := logic.GetNetwork(netname) | ||||||
|  | 	if err != nil { | ||||||
|  | 		logger.Log(0, r.Header.Get("user"), | ||||||
|  | 			fmt.Sprintf("failed to fetch ACLs for network [%s]: %v", netname, err)) | ||||||
|  | 		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest")) | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	nodeEgressRoutes, _, err := logic.GetEgressRanges(models.NetworkID(netname)) | ||||||
|  | 	if err != nil { | ||||||
|  | 		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest")) | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	logic.ReturnSuccessResponseWithJson(w, r, nodeEgressRoutes, "fetched network egress routes") | ||||||
|  | } | ||||||
|  |  | ||||||
| // @Summary     Delete a network | // @Summary     Delete a network | ||||||
| // @Router      /api/networks/{networkname} [delete] | // @Router      /api/networks/{networkname} [delete] | ||||||
| // @Tags        Networks | // @Tags        Networks | ||||||
|   | |||||||
							
								
								
									
										590
									
								
								logic/acls.go
									
									
									
									
									
								
							
							
						
						
									
										590
									
								
								logic/acls.go
									
									
									
									
									
								
							| @@ -5,6 +5,7 @@ import ( | |||||||
| 	"errors" | 	"errors" | ||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"maps" | 	"maps" | ||||||
|  | 	"net" | ||||||
| 	"sort" | 	"sort" | ||||||
| 	"sync" | 	"sync" | ||||||
| 	"time" | 	"time" | ||||||
| @@ -222,6 +223,104 @@ func IsAclExists(aclID string) bool { | |||||||
| 	_, err := GetAcl(aclID) | 	_, err := GetAcl(aclID) | ||||||
| 	return err == nil | 	return err == nil | ||||||
| } | } | ||||||
|  | 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.IsEgressGateway { // add the egress gateway range(s) to the result | ||||||
|  | 			if len(currentNode.EgressGatewayRanges) > 0 { | ||||||
|  | 				nodeEgressMap[currentNode.ID.String()] = currentNode.EgressGatewayRanges | ||||||
|  | 				for _, egressRangeI := range currentNode.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 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func checkIfAclTagisValid(t models.AclPolicyTag, netID models.NetworkID, policyType models.AclPolicyType, isSrc bool) bool { | ||||||
|  | 	switch t.ID { | ||||||
|  | 	case models.NodeTagID: | ||||||
|  | 		if policyType == models.UserPolicy && isSrc { | ||||||
|  | 			return false | ||||||
|  | 		} | ||||||
|  | 		// check if tag is valid | ||||||
|  | 		_, err := GetTag(models.TagID(t.Value)) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return false | ||||||
|  | 		} | ||||||
|  | 	case models.NodeID: | ||||||
|  | 		if policyType == models.UserPolicy && isSrc { | ||||||
|  | 			return false | ||||||
|  | 		} | ||||||
|  | 		_, nodeErr := GetNodeByID(t.Value) | ||||||
|  | 		if nodeErr != nil { | ||||||
|  | 			_, staticNodeErr := GetExtClient(t.Value, netID.String()) | ||||||
|  | 			if staticNodeErr != nil { | ||||||
|  | 				return false | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	case models.EgressRange: | ||||||
|  | 		if isSrc { | ||||||
|  | 			return false | ||||||
|  | 		} | ||||||
|  | 		// _, rangesMap, err := GetEgressRanges(netID) | ||||||
|  | 		// if err != nil { | ||||||
|  | 		// 	return false | ||||||
|  | 		// } | ||||||
|  | 		// if _, ok := rangesMap[t.Value]; !ok { | ||||||
|  | 		// 	return false | ||||||
|  | 		// } | ||||||
|  | 	case models.UserAclID: | ||||||
|  | 		if policyType == models.DevicePolicy { | ||||||
|  | 			return false | ||||||
|  | 		} | ||||||
|  | 		if !isSrc { | ||||||
|  | 			return false | ||||||
|  | 		} | ||||||
|  | 		_, err := GetUser(t.Value) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return false | ||||||
|  | 		} | ||||||
|  | 	case models.UserGroupAclID: | ||||||
|  | 		if policyType == models.DevicePolicy { | ||||||
|  | 			return false | ||||||
|  | 		} | ||||||
|  | 		if !isSrc { | ||||||
|  | 			return false | ||||||
|  | 		} | ||||||
|  | 		err := IsGroupValid(models.UserGroupID(t.Value)) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return false | ||||||
|  | 		} | ||||||
|  | 		// check if group belongs to this network | ||||||
|  | 		netGrps := GetUserGroupsInNetwork(netID) | ||||||
|  | 		if _, ok := netGrps[models.UserGroupID(t.Value)]; !ok { | ||||||
|  | 			return false | ||||||
|  | 		} | ||||||
|  | 	default: | ||||||
|  | 		return false | ||||||
|  | 	} | ||||||
|  | 	return true | ||||||
|  | } | ||||||
|  |  | ||||||
| // IsAclPolicyValid - validates if acl policy is valid | // IsAclPolicyValid - validates if acl policy is valid | ||||||
| func IsAclPolicyValid(acl models.Acl) bool { | func IsAclPolicyValid(acl models.Acl) bool { | ||||||
| @@ -235,116 +334,44 @@ func IsAclPolicyValid(acl models.Acl) bool { | |||||||
| 		// src list should only contain users | 		// src list should only contain users | ||||||
| 		for _, srcI := range acl.Src { | 		for _, srcI := range acl.Src { | ||||||
|  |  | ||||||
| 			if srcI.ID == "" || srcI.Value == "" { |  | ||||||
| 				return false |  | ||||||
| 			} |  | ||||||
| 			if srcI.Value == "*" { | 			if srcI.Value == "*" { | ||||||
| 				continue | 				continue | ||||||
| 			} | 			} | ||||||
| 			if srcI.ID != models.UserAclID && srcI.ID != models.UserGroupAclID { |  | ||||||
| 				return false |  | ||||||
| 			} |  | ||||||
| 			// check if user group is valid | 			// check if user group is valid | ||||||
| 			if srcI.ID == models.UserAclID { | 			if !checkIfAclTagisValid(srcI, acl.NetworkID, acl.RuleType, true) { | ||||||
| 				_, err := GetUser(srcI.Value) |  | ||||||
| 				if err != nil { |  | ||||||
| 				return false | 				return false | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| 			} else if srcI.ID == models.UserGroupAclID { |  | ||||||
| 				err := IsGroupValid(models.UserGroupID(srcI.Value)) |  | ||||||
| 				if err != nil { |  | ||||||
| 					return false |  | ||||||
| 				} |  | ||||||
| 				// check if group belongs to this network |  | ||||||
| 				netGrps := GetUserGroupsInNetwork(acl.NetworkID) |  | ||||||
| 				if _, ok := netGrps[models.UserGroupID(srcI.Value)]; !ok { |  | ||||||
| 					return false |  | ||||||
| 				} |  | ||||||
| 			} |  | ||||||
|  |  | ||||||
| 		} | 		} | ||||||
| 		for _, dstI := range acl.Dst { | 		for _, dstI := range acl.Dst { | ||||||
|  |  | ||||||
| 			if dstI.ID == "" || dstI.Value == "" { |  | ||||||
| 				return false |  | ||||||
| 			} |  | ||||||
| 			if dstI.ID != models.NodeTagID && dstI.ID != models.NodeID { |  | ||||||
| 				return false |  | ||||||
| 			} |  | ||||||
| 			if dstI.Value == "*" { | 			if dstI.Value == "*" { | ||||||
| 				continue | 				continue | ||||||
| 			} | 			} | ||||||
| 			if dstI.ID == models.NodeTagID { |  | ||||||
| 				// check if tag is valid | 			// check if user group is valid | ||||||
| 				_, err := GetTag(models.TagID(dstI.Value)) | 			if !checkIfAclTagisValid(dstI, acl.NetworkID, acl.RuleType, false) { | ||||||
| 				if err != nil { |  | ||||||
| 				return false | 				return false | ||||||
| 			} | 			} | ||||||
| 			} else { |  | ||||||
| 				_, nodeErr := GetNodeByID(dstI.Value) |  | ||||||
| 				if nodeErr != nil { |  | ||||||
| 					_, staticNodeErr := GetExtClient(dstI.Value, acl.NetworkID.String()) |  | ||||||
| 					if staticNodeErr != nil { |  | ||||||
| 						return false |  | ||||||
| 					} |  | ||||||
| 				} |  | ||||||
| 			} |  | ||||||
| 		} | 		} | ||||||
| 	case models.DevicePolicy: | 	case models.DevicePolicy: | ||||||
| 		for _, srcI := range acl.Src { | 		for _, srcI := range acl.Src { | ||||||
| 			if srcI.ID == "" || srcI.Value == "" { |  | ||||||
| 				return false |  | ||||||
| 			} |  | ||||||
| 			if srcI.ID != models.NodeTagID && srcI.ID != models.NodeID { |  | ||||||
| 				return false |  | ||||||
| 			} |  | ||||||
| 			if srcI.Value == "*" { | 			if srcI.Value == "*" { | ||||||
| 				continue | 				continue | ||||||
| 			} | 			} | ||||||
| 			if srcI.ID == models.NodeTagID { | 			// check if user group is valid | ||||||
| 				// check if tag is valid | 			if !checkIfAclTagisValid(srcI, acl.NetworkID, acl.RuleType, true) { | ||||||
| 				_, err := GetTag(models.TagID(srcI.Value)) |  | ||||||
| 				if err != nil { |  | ||||||
| 				return false | 				return false | ||||||
| 			} | 			} | ||||||
| 			} else { |  | ||||||
| 				_, nodeErr := GetNodeByID(srcI.Value) |  | ||||||
| 				if nodeErr != nil { |  | ||||||
| 					_, staticNodeErr := GetExtClient(srcI.Value, acl.NetworkID.String()) |  | ||||||
| 					if staticNodeErr != nil { |  | ||||||
| 						return false |  | ||||||
| 					} |  | ||||||
| 				} |  | ||||||
| 			} |  | ||||||
|  |  | ||||||
| 		} | 		} | ||||||
| 		for _, dstI := range acl.Dst { | 		for _, dstI := range acl.Dst { | ||||||
|  |  | ||||||
| 			if dstI.ID == "" || dstI.Value == "" { |  | ||||||
| 				return false |  | ||||||
| 			} |  | ||||||
| 			if dstI.ID != models.NodeTagID && dstI.ID != models.NodeID { |  | ||||||
| 				return false |  | ||||||
| 			} |  | ||||||
| 			if dstI.Value == "*" { | 			if dstI.Value == "*" { | ||||||
| 				continue | 				continue | ||||||
| 			} | 			} | ||||||
| 			if dstI.ID == models.NodeTagID { | 			// check if user group is valid | ||||||
| 				// check if tag is valid | 			if !checkIfAclTagisValid(dstI, acl.NetworkID, acl.RuleType, false) { | ||||||
| 				_, err := GetTag(models.TagID(dstI.Value)) |  | ||||||
| 				if err != nil { |  | ||||||
| 				return false | 				return false | ||||||
| 			} | 			} | ||||||
| 			} else { |  | ||||||
| 				_, nodeErr := GetNodeByID(dstI.Value) |  | ||||||
| 				if nodeErr != nil { |  | ||||||
| 					_, staticNodeErr := GetExtClient(dstI.Value, acl.NetworkID.String()) |  | ||||||
| 					if staticNodeErr != nil { |  | ||||||
| 						return false |  | ||||||
| 					} |  | ||||||
| 				} |  | ||||||
| 			} |  | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	return true | 	return true | ||||||
| @@ -688,8 +715,8 @@ func RemoveUserFromAclPolicy(userName string) { | |||||||
| 		delete := false | 		delete := false | ||||||
| 		update := false | 		update := false | ||||||
| 		if acl.RuleType == models.UserPolicy { | 		if acl.RuleType == models.UserPolicy { | ||||||
| 			for i, srcI := range acl.Src { | 			for i := len(acl.Src) - 1; i >= 0; i-- { | ||||||
| 				if srcI.ID == models.UserAclID && srcI.Value == userName { | 				if acl.Src[i].ID == models.UserAclID && acl.Src[i].Value == userName { | ||||||
| 					if len(acl.Src) == 1 { | 					if len(acl.Src) == 1 { | ||||||
| 						// delete policy | 						// delete policy | ||||||
| 						delete = true | 						delete = true | ||||||
| @@ -723,8 +750,8 @@ func RemoveNodeFromAclPolicy(node models.Node) { | |||||||
| 		delete := false | 		delete := false | ||||||
| 		update := false | 		update := false | ||||||
| 		if acl.RuleType == models.DevicePolicy { | 		if acl.RuleType == models.DevicePolicy { | ||||||
| 			for i, srcI := range acl.Src { | 			for i := len(acl.Src) - 1; i >= 0; i-- { | ||||||
| 				if srcI.ID == models.NodeID && srcI.Value == nodeID { | 				if acl.Src[i].ID == models.NodeID && acl.Src[i].Value == nodeID { | ||||||
| 					if len(acl.Src) == 1 { | 					if len(acl.Src) == 1 { | ||||||
| 						// delete policy | 						// delete policy | ||||||
| 						delete = true | 						delete = true | ||||||
| @@ -739,8 +766,8 @@ func RemoveNodeFromAclPolicy(node models.Node) { | |||||||
| 				DeleteAcl(acl) | 				DeleteAcl(acl) | ||||||
| 				continue | 				continue | ||||||
| 			} | 			} | ||||||
| 			for i, dstI := range acl.Dst { | 			for i := len(acl.Dst) - 1; i >= 0; i-- { | ||||||
| 				if dstI.ID == models.NodeID && dstI.Value == nodeID { | 				if acl.Dst[i].ID == models.NodeID && acl.Dst[i].Value == nodeID { | ||||||
| 					if len(acl.Dst) == 1 { | 					if len(acl.Dst) == 1 { | ||||||
| 						// delete policy | 						// delete policy | ||||||
| 						delete = true | 						delete = true | ||||||
| @@ -761,8 +788,8 @@ func RemoveNodeFromAclPolicy(node models.Node) { | |||||||
|  |  | ||||||
| 		} | 		} | ||||||
| 		if acl.RuleType == models.UserPolicy { | 		if acl.RuleType == models.UserPolicy { | ||||||
| 			for i, dstI := range acl.Dst { | 			for i := len(acl.Dst) - 1; i >= 0; i-- { | ||||||
| 				if dstI.ID == models.NodeID && dstI.Value == nodeID { | 				if acl.Dst[i].ID == models.NodeID && acl.Dst[i].Value == nodeID { | ||||||
| 					if len(acl.Dst) == 1 { | 					if len(acl.Dst) == 1 { | ||||||
| 						// delete policy | 						// delete policy | ||||||
| 						delete = true | 						delete = true | ||||||
| @@ -1239,17 +1266,17 @@ func RemoveDeviceTagFromAclPolicies(tagID models.TagID, netID models.NetworkID) | |||||||
| 	acls := listDevicePolicies(netID) | 	acls := listDevicePolicies(netID) | ||||||
| 	update := false | 	update := false | ||||||
| 	for _, acl := range acls { | 	for _, acl := range acls { | ||||||
| 		for i, srcTagI := range acl.Src { | 		for i := len(acl.Src) - 1; i >= 0; i-- { | ||||||
| 			if srcTagI.ID == models.NodeTagID { | 			if acl.Src[i].ID == models.NodeTagID { | ||||||
| 				if tagID.String() == srcTagI.Value { | 				if tagID.String() == acl.Src[i].Value { | ||||||
| 					acl.Src = append(acl.Src[:i], acl.Src[i+1:]...) | 					acl.Src = append(acl.Src[:i], acl.Src[i+1:]...) | ||||||
| 					update = true | 					update = true | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 		for i, dstTagI := range acl.Dst { | 		for i := len(acl.Dst) - 1; i >= 0; i-- { | ||||||
| 			if dstTagI.ID == models.NodeTagID { | 			if acl.Dst[i].ID == models.NodeTagID { | ||||||
| 				if tagID.String() == dstTagI.Value { | 				if tagID.String() == acl.Dst[i].Value { | ||||||
| 					acl.Dst = append(acl.Dst[:i], acl.Dst[i+1:]...) | 					acl.Dst = append(acl.Dst[:i], acl.Dst[i+1:]...) | ||||||
| 					update = true | 					update = true | ||||||
| 				} | 				} | ||||||
| @@ -1262,19 +1289,16 @@ func RemoveDeviceTagFromAclPolicies(tagID models.TagID, netID models.NetworkID) | |||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
|  |  | ||||||
| func getUserAclRulesForNode(targetnode *models.Node, | func getEgressUserRulesForNode(targetnode *models.Node, | ||||||
| 	rules map[string]models.AclRule) map[string]models.AclRule { | 	rules map[string]models.AclRule) map[string]models.AclRule { | ||||||
| 	userNodes := GetStaticUserNodesByNetwork(models.NetworkID(targetnode.Network)) | 	userNodes := GetStaticUserNodesByNetwork(models.NetworkID(targetnode.Network)) | ||||||
| 	userGrpMap := GetUserGrpMap() | 	userGrpMap := GetUserGrpMap() | ||||||
| 	allowedUsers := make(map[string][]models.Acl) | 	allowedUsers := make(map[string][]models.Acl) | ||||||
| 	acls := listUserPolicies(models.NetworkID(targetnode.Network)) | 	acls := listUserPolicies(models.NetworkID(targetnode.Network)) | ||||||
| 	var targetNodeTags = make(map[models.TagID]struct{}) | 	var targetNodeTags = make(map[models.TagID]struct{}) | ||||||
| 	if targetnode.Mutex != nil { | 	targetNodeTags["*"] = struct{}{} | ||||||
| 		targetnode.Mutex.Lock() | 	for _, rangeI := range targetnode.EgressGatewayRanges { | ||||||
| 		targetNodeTags = maps.Clone(targetnode.Tags) | 		targetNodeTags[models.TagID(rangeI)] = struct{}{} | ||||||
| 		targetnode.Mutex.Unlock() |  | ||||||
| 	} else { |  | ||||||
| 		targetNodeTags = maps.Clone(targetnode.Tags) |  | ||||||
| 	} | 	} | ||||||
| 	for _, acl := range acls { | 	for _, acl := range acls { | ||||||
| 		if !acl.Enabled { | 		if !acl.Enabled { | ||||||
| @@ -1285,12 +1309,11 @@ func getUserAclRulesForNode(targetnode *models.Node, | |||||||
| 		addUsers := false | 		addUsers := false | ||||||
| 		if !all { | 		if !all { | ||||||
| 			for nodeTag := range targetNodeTags { | 			for nodeTag := range targetNodeTags { | ||||||
| 				if _, ok := dstTags[nodeTag.String()]; !ok { | 				if _, ok := dstTags[nodeTag.String()]; ok { | ||||||
| 					if _, ok = dstTags[targetnode.ID.String()]; !ok { | 					addUsers = true | ||||||
| 					break | 					break | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 			} |  | ||||||
| 		} else { | 		} else { | ||||||
| 			addUsers = true | 			addUsers = true | ||||||
| 		} | 		} | ||||||
| @@ -1326,7 +1349,110 @@ func getUserAclRulesForNode(targetnode *models.Node, | |||||||
| 			if !acl.Enabled { | 			if !acl.Enabled { | ||||||
| 				continue | 				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.EgressRange { | ||||||
|  | 					ip, cidr, err := net.ParseCIDR(dstI.Value) | ||||||
|  | 					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 := 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) | ||||||
|  | 	} | ||||||
|  | 	targetNodeTags[models.TagID(targetnode.ID.String())] = struct{}{} | ||||||
|  | 	for _, acl := range acls { | ||||||
|  | 		if !acl.Enabled { | ||||||
|  | 			continue | ||||||
|  | 		} | ||||||
|  | 		dstTags := convAclTagToValueMap(acl.Dst) | ||||||
|  | 		_, all := dstTags["*"] | ||||||
|  | 		addUsers := false | ||||||
|  | 		if !all { | ||||||
|  | 			for nodeTag := range targetNodeTags { | ||||||
|  | 				if _, ok := dstTags[nodeTag.String()]; ok { | ||||||
|  | 					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{ | 			r := models.AclRule{ | ||||||
| 				ID:              acl.ID, | 				ID:              acl.ID, | ||||||
| 				AllowedProtocol: acl.Proto, | 				AllowedProtocol: acl.Proto, | ||||||
| @@ -1354,7 +1480,16 @@ func getUserAclRulesForNode(targetnode *models.Node, | |||||||
| } | } | ||||||
|  |  | ||||||
| func checkIfAnyPolicyisUniDirectional(targetNode models.Node) bool { | func checkIfAnyPolicyisUniDirectional(targetNode models.Node) bool { | ||||||
| 	targetNode.Tags[models.TagID(targetNode.ID.String())] = struct{}{} | 	var targetNodeTags = make(map[models.TagID]struct{}) | ||||||
|  | 	if targetNode.Mutex != nil { | ||||||
|  | 		targetNode.Mutex.Lock() | ||||||
|  | 		targetNodeTags = maps.Clone(targetNode.Tags) | ||||||
|  | 		targetNode.Mutex.Unlock() | ||||||
|  | 	} else { | ||||||
|  | 		targetNodeTags = maps.Clone(targetNode.Tags) | ||||||
|  | 	} | ||||||
|  | 	targetNodeTags[models.TagID(targetNode.ID.String())] = struct{}{} | ||||||
|  | 	targetNodeTags["*"] = struct{}{} | ||||||
| 	acls := listDevicePolicies(models.NetworkID(targetNode.Network)) | 	acls := listDevicePolicies(models.NetworkID(targetNode.Network)) | ||||||
| 	for _, acl := range acls { | 	for _, acl := range acls { | ||||||
| 		if !acl.Enabled { | 		if !acl.Enabled { | ||||||
| @@ -1363,9 +1498,12 @@ func checkIfAnyPolicyisUniDirectional(targetNode models.Node) bool { | |||||||
| 		if acl.AllowedDirection == models.TrafficDirectionBi { | 		if acl.AllowedDirection == models.TrafficDirectionBi { | ||||||
| 			continue | 			continue | ||||||
| 		} | 		} | ||||||
|  | 		if acl.Proto != models.ALL || acl.ServiceType != models.Any { | ||||||
|  | 			return true | ||||||
|  | 		} | ||||||
| 		srcTags := convAclTagToValueMap(acl.Src) | 		srcTags := convAclTagToValueMap(acl.Src) | ||||||
| 		dstTags := convAclTagToValueMap(acl.Dst) | 		dstTags := convAclTagToValueMap(acl.Dst) | ||||||
| 		for nodeTag := range targetNode.Tags { | 		for nodeTag := range targetNodeTags { | ||||||
| 			if _, ok := srcTags[nodeTag.String()]; ok { | 			if _, ok := srcTags[nodeTag.String()]; ok { | ||||||
| 				return true | 				return true | ||||||
| 			} | 			} | ||||||
| @@ -1385,12 +1523,10 @@ func checkIfAnyPolicyisUniDirectional(targetNode models.Node) bool { | |||||||
|  |  | ||||||
| func GetAclRulesForNode(targetnodeI *models.Node) (rules map[string]models.AclRule) { | func GetAclRulesForNode(targetnodeI *models.Node) (rules map[string]models.AclRule) { | ||||||
| 	targetnode := *targetnodeI | 	targetnode := *targetnodeI | ||||||
| 	targetnode.Tags[models.TagID(targetnode.ID.String())] = struct{}{} |  | ||||||
| 	defer func() { | 	defer func() { | ||||||
| 		if !targetnode.IsIngressGateway { | 		if !targetnode.IsIngressGateway { | ||||||
| 			rules = getUserAclRulesForNode(&targetnode, rules) | 			rules = getUserAclRulesForNode(&targetnode, rules) | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 	}() | 	}() | ||||||
| 	rules = make(map[string]models.AclRule) | 	rules = make(map[string]models.AclRule) | ||||||
| 	var taggedNodes map[models.TagID][]models.Node | 	var taggedNodes map[models.TagID][]models.Node | ||||||
| @@ -1409,8 +1545,8 @@ func GetAclRulesForNode(targetnodeI *models.Node) (rules map[string]models.AclRu | |||||||
| 	} else { | 	} else { | ||||||
| 		targetNodeTags = maps.Clone(targetnode.Tags) | 		targetNodeTags = maps.Clone(targetnode.Tags) | ||||||
| 	} | 	} | ||||||
|  | 	targetNodeTags[models.TagID(targetnode.ID.String())] = struct{}{} | ||||||
| 	targetNodeTags["*"] = struct{}{} | 	targetNodeTags["*"] = struct{}{} | ||||||
|  |  | ||||||
| 	for _, acl := range acls { | 	for _, acl := range acls { | ||||||
| 		if !acl.Enabled { | 		if !acl.Enabled { | ||||||
| 			continue | 			continue | ||||||
| @@ -1593,9 +1729,245 @@ func GetAclRulesForNode(targetnodeI *models.Node) (rules map[string]models.AclRu | |||||||
| 			} | 			} | ||||||
|  |  | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		if len(aclRule.IPList) > 0 || len(aclRule.IP6List) > 0 { | 		if len(aclRule.IPList) > 0 || len(aclRule.IP6List) > 0 { | ||||||
|  | 			aclRule.IPList = UniqueIPNetList(aclRule.IPList) | ||||||
|  | 			aclRule.IP6List = UniqueIPNetList(aclRule.IP6List) | ||||||
| 			rules[acl.ID] = aclRule | 			rules[acl.ID] = aclRule | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	return rules | 	return rules | ||||||
| } | } | ||||||
|  | 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) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return uniqueList | ||||||
|  | } | ||||||
|  |  | ||||||
|  | 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 := 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 | ||||||
|  | 			fetches all the nodes in that policy and add rules | ||||||
|  | 	*/ | ||||||
|  |  | ||||||
|  | 	for _, rangeI := range targetnode.EgressGatewayRanges { | ||||||
|  | 		targetNodeTags[models.TagID(rangeI)] = struct{}{} | ||||||
|  | 	} | ||||||
|  | 	for _, acl := range acls { | ||||||
|  | 		if !acl.Enabled { | ||||||
|  | 			continue | ||||||
|  | 		} | ||||||
|  | 		srcTags := convAclTagToValueMap(acl.Src) | ||||||
|  | 		dstTags := convAclTagToValueMap(acl.Dst) | ||||||
|  | 		_, srcAll := srcTags["*"] | ||||||
|  | 		_, dstAll := dstTags["*"] | ||||||
|  | 		for nodeTag := range targetNodeTags { | ||||||
|  | 			aclRule := models.AclRule{ | ||||||
|  | 				ID:              acl.ID, | ||||||
|  | 				AllowedProtocol: acl.Proto, | ||||||
|  | 				AllowedPorts:    acl.Port, | ||||||
|  | 				Direction:       acl.AllowedDirection, | ||||||
|  | 				Allowed:         true, | ||||||
|  | 			} | ||||||
|  | 			if nodeTag != "*" { | ||||||
|  | 				ip, cidr, err := net.ParseCIDR(nodeTag.String()) | ||||||
|  | 				if err != nil { | ||||||
|  | 					continue | ||||||
|  | 				} | ||||||
|  | 				if ip.To4() != nil { | ||||||
|  | 					aclRule.Dst = append(aclRule.Dst, *cidr) | ||||||
|  | 				} else { | ||||||
|  | 					aclRule.Dst6 = append(aclRule.Dst6, *cidr) | ||||||
|  | 				} | ||||||
|  |  | ||||||
|  | 			} else { | ||||||
|  | 				aclRule.Dst = append(aclRule.Dst, net.IPNet{ | ||||||
|  | 					IP:   net.IPv4zero,        // 0.0.0.0 | ||||||
|  | 					Mask: net.CIDRMask(0, 32), // /0 means match all IPv4 | ||||||
|  | 				}) | ||||||
|  | 				aclRule.Dst6 = append(aclRule.Dst6, net.IPNet{ | ||||||
|  | 					IP:   net.IPv6zero,         // :: | ||||||
|  | 					Mask: net.CIDRMask(0, 128), // /0 means match all IPv6 | ||||||
|  | 				}) | ||||||
|  | 			} | ||||||
|  | 			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 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 := 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 := 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 := 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.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.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 | ||||||
|  | } | ||||||
|   | |||||||
| @@ -591,96 +591,64 @@ func getFwRulesForNodeAndPeerOnGw(node, peer models.Node, allowedPolicies []mode | |||||||
| 			} | 			} | ||||||
|  |  | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
|  | 		// add egress range rules | ||||||
|  | 		for _, dstI := range policy.Dst { | ||||||
|  | 			if dstI.ID == models.EgressRange { | ||||||
|  | 				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 | 	return | ||||||
| } | } | ||||||
|  |  | ||||||
| func GetFwRulesOnIngressGateway(node models.Node) (rules []models.FwRule) { | func getFwRulesForUserNodesOnGw(node models.Node, nodes []models.Node) (rules []models.FwRule) { | ||||||
| 	// fetch user access to static clients via policies |  | ||||||
| 	defaultUserPolicy, _ := GetDefaultPolicy(models.NetworkID(node.Network), models.UserPolicy) | 	defaultUserPolicy, _ := GetDefaultPolicy(models.NetworkID(node.Network), models.UserPolicy) | ||||||
| 	defaultDevicePolicy, _ := GetDefaultPolicy(models.NetworkID(node.Network), models.DevicePolicy) |  | ||||||
| 	nodes, _ := GetNetworkNodes(node.Network) |  | ||||||
| 	nodes = append(nodes, GetStaticNodesByNetwork(models.NetworkID(node.Network), true)...) |  | ||||||
| 	userNodes := GetStaticUserNodesByNetwork(models.NetworkID(node.Network)) | 	userNodes := GetStaticUserNodesByNetwork(models.NetworkID(node.Network)) | ||||||
| 	for _, userNodeI := range userNodes { | 	for _, userNodeI := range userNodes { | ||||||
| 		for _, peer := range nodes { | 		for _, peer := range nodes { | ||||||
| 			if peer.IsUserNode { | 			if peer.IsUserNode { | ||||||
| 				continue | 				continue | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| 			if ok, allowedPolicies := IsUserAllowedToCommunicate(userNodeI.StaticNode.OwnerID, peer); ok { | 			if ok, allowedPolicies := IsUserAllowedToCommunicate(userNodeI.StaticNode.OwnerID, peer); ok { | ||||||
| 				if peer.IsStatic { | 				if peer.IsStatic { | ||||||
|  | 					peer = peer.StaticNode.ConvertToStaticNode() | ||||||
|  | 				} | ||||||
|  | 				if !defaultUserPolicy.Enabled { | ||||||
|  | 					for _, policy := range allowedPolicies { | ||||||
| 						if userNodeI.StaticNode.Address != "" { | 						if userNodeI.StaticNode.Address != "" { | ||||||
| 						if !defaultUserPolicy.Enabled { |  | ||||||
| 							for _, policy := range allowedPolicies { |  | ||||||
| 								rules = append(rules, models.FwRule{ |  | ||||||
| 									SrcIP:           userNodeI.StaticNode.AddressIPNet4(), |  | ||||||
| 									DstIP:           peer.StaticNode.AddressIPNet4(), |  | ||||||
| 									AllowedProtocol: policy.Proto, |  | ||||||
| 									AllowedPorts:    policy.Port, |  | ||||||
| 									Allow:           true, |  | ||||||
| 								}) |  | ||||||
| 								rules = append(rules, models.FwRule{ |  | ||||||
| 									SrcIP:           peer.StaticNode.AddressIPNet4(), |  | ||||||
| 									DstIP:           userNodeI.StaticNode.AddressIPNet4(), |  | ||||||
| 									AllowedProtocol: policy.Proto, |  | ||||||
| 									AllowedPorts:    policy.Port, |  | ||||||
| 									Allow:           true, |  | ||||||
| 								}) |  | ||||||
| 							} |  | ||||||
| 						} |  | ||||||
|  |  | ||||||
| 					} |  | ||||||
| 					if userNodeI.StaticNode.Address6 != "" { |  | ||||||
| 						if !defaultUserPolicy.Enabled { |  | ||||||
| 							for _, policy := range allowedPolicies { |  | ||||||
| 								rules = append(rules, models.FwRule{ |  | ||||||
| 									SrcIP:           userNodeI.StaticNode.AddressIPNet6(), |  | ||||||
| 									DstIP:           peer.StaticNode.AddressIPNet6(), |  | ||||||
| 									Allow:           true, |  | ||||||
| 									AllowedProtocol: policy.Proto, |  | ||||||
| 									AllowedPorts:    policy.Port, |  | ||||||
| 								}) |  | ||||||
| 								rules = append(rules, models.FwRule{ |  | ||||||
| 									SrcIP:           peer.StaticNode.AddressIPNet6(), |  | ||||||
| 									DstIP:           userNodeI.StaticNode.AddressIPNet6(), |  | ||||||
| 									AllowedProtocol: policy.Proto, |  | ||||||
| 									AllowedPorts:    policy.Port, |  | ||||||
| 									Allow:           true, |  | ||||||
| 								}) |  | ||||||
|  |  | ||||||
| 							} |  | ||||||
| 						} |  | ||||||
|  |  | ||||||
| 					} |  | ||||||
| 					if len(peer.StaticNode.ExtraAllowedIPs) > 0 { |  | ||||||
| 						for _, additionalAllowedIPNet := range peer.StaticNode.ExtraAllowedIPs { |  | ||||||
| 							_, ipNet, err := net.ParseCIDR(additionalAllowedIPNet) |  | ||||||
| 							if err != nil { |  | ||||||
| 								continue |  | ||||||
| 							} |  | ||||||
| 							if ipNet.IP.To4() != nil { |  | ||||||
| 								rules = append(rules, models.FwRule{ |  | ||||||
| 									SrcIP: userNodeI.StaticNode.AddressIPNet4(), |  | ||||||
| 									DstIP: *ipNet, |  | ||||||
| 									Allow: true, |  | ||||||
| 								}) |  | ||||||
| 							} else { |  | ||||||
| 								rules = append(rules, models.FwRule{ |  | ||||||
| 									SrcIP: userNodeI.StaticNode.AddressIPNet6(), |  | ||||||
| 									DstIP: *ipNet, |  | ||||||
| 									Allow: true, |  | ||||||
| 								}) |  | ||||||
| 							} |  | ||||||
|  |  | ||||||
| 						} |  | ||||||
|  |  | ||||||
| 					} |  | ||||||
| 				} else { |  | ||||||
|  |  | ||||||
| 					if userNodeI.StaticNode.Address != "" { |  | ||||||
| 						if !defaultUserPolicy.Enabled { |  | ||||||
| 							for _, policy := range allowedPolicies { |  | ||||||
| 							rules = append(rules, models.FwRule{ | 							rules = append(rules, models.FwRule{ | ||||||
| 								SrcIP: userNodeI.StaticNode.AddressIPNet4(), | 								SrcIP: userNodeI.StaticNode.AddressIPNet4(), | ||||||
| 								DstIP: net.IPNet{ | 								DstIP: net.IPNet{ | ||||||
| @@ -692,13 +660,7 @@ func GetFwRulesOnIngressGateway(node models.Node) (rules []models.FwRule) { | |||||||
| 								Allow:           true, | 								Allow:           true, | ||||||
| 							}) | 							}) | ||||||
| 						} | 						} | ||||||
|  |  | ||||||
| 						} |  | ||||||
| 					} |  | ||||||
|  |  | ||||||
| 						if userNodeI.StaticNode.Address6 != "" { | 						if userNodeI.StaticNode.Address6 != "" { | ||||||
| 						if !defaultUserPolicy.Enabled { |  | ||||||
| 							for _, policy := range allowedPolicies { |  | ||||||
| 							rules = append(rules, models.FwRule{ | 							rules = append(rules, models.FwRule{ | ||||||
| 								SrcIP: userNodeI.StaticNode.AddressIPNet6(), | 								SrcIP: userNodeI.StaticNode.AddressIPNet6(), | ||||||
| 								DstIP: net.IPNet{ | 								DstIP: net.IPNet{ | ||||||
| @@ -710,13 +672,49 @@ func GetFwRulesOnIngressGateway(node models.Node) (rules []models.FwRule) { | |||||||
| 								Allow:           true, | 								Allow:           true, | ||||||
| 							}) | 							}) | ||||||
| 						} | 						} | ||||||
| 						} |  | ||||||
| 					} | 						// add egress ranges | ||||||
|  | 						for _, dstI := range policy.Dst { | ||||||
|  | 							if dstI.ID == models.EgressRange { | ||||||
|  | 								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 | ||||||
|  |  | ||||||
|  | 	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 { | 	if defaultDevicePolicy.Enabled { | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| @@ -739,17 +737,34 @@ func GetFwRulesOnIngressGateway(node models.Node) (rules []models.FwRule) { | |||||||
| 			if peer.IsStatic { | 			if peer.IsStatic { | ||||||
| 				peer = peer.StaticNode.ConvertToStaticNode() | 				peer = peer.StaticNode.ConvertToStaticNode() | ||||||
| 			} | 			} | ||||||
| 			if ok, allowedPolicies := IsNodeAllowedToCommunicateV1(nodeI.StaticNode.ConvertToStaticNode(), peer, true); ok { | 			var allowedPolicies1 []models.Acl | ||||||
| 				rules = append(rules, getFwRulesForNodeAndPeerOnGw(nodeI.StaticNode.ConvertToStaticNode(), peer, allowedPolicies)...) | 			var ok bool | ||||||
|  | 			if ok, allowedPolicies1 = IsNodeAllowedToCommunicateV1(nodeI.StaticNode.ConvertToStaticNode(), peer, true); ok { | ||||||
|  | 				rules = append(rules, getFwRulesForNodeAndPeerOnGw(nodeI.StaticNode.ConvertToStaticNode(), peer, allowedPolicies1)...) | ||||||
| 			} | 			} | ||||||
| 			if ok, allowedPolicies := IsNodeAllowedToCommunicateV1(peer, nodeI.StaticNode.ConvertToStaticNode(), true); ok { | 			if ok, allowedPolicies2 := IsNodeAllowedToCommunicateV1(peer, nodeI.StaticNode.ConvertToStaticNode(), true); ok { | ||||||
| 				rules = append(rules, getFwRulesForNodeAndPeerOnGw(peer, nodeI.StaticNode.ConvertToStaticNode(), allowedPolicies)...) | 				rules = append(rules, | ||||||
|  | 					getFwRulesForNodeAndPeerOnGw(peer, nodeI.StaticNode.ConvertToStaticNode(), | ||||||
|  | 						GetUniquePolicies(allowedPolicies1, allowedPolicies2))...) | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	return | 	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) { | func GetExtPeers(node, peer *models.Node) ([]wgtypes.PeerConfig, []models.IDandAddr, []models.EgressNetworkRoutes, error) { | ||||||
| 	var peers []wgtypes.PeerConfig | 	var peers []wgtypes.PeerConfig | ||||||
| 	var idsAndAddr []models.IDandAddr | 	var idsAndAddr []models.IDandAddr | ||||||
| @@ -764,13 +779,11 @@ func GetExtPeers(node, peer *models.Node) ([]wgtypes.PeerConfig, []models.IDandA | |||||||
| 	} | 	} | ||||||
| 	for _, extPeer := range extPeers { | 	for _, extPeer := range extPeers { | ||||||
| 		extPeer := extPeer | 		extPeer := extPeer | ||||||
| 		fmt.Println("=====> checking EXT peer: ", extPeer.ClientID) |  | ||||||
| 		if !IsClientNodeAllowed(&extPeer, peer.ID.String()) { | 		if !IsClientNodeAllowed(&extPeer, peer.ID.String()) { | ||||||
| 			continue | 			continue | ||||||
| 		} | 		} | ||||||
| 		if extPeer.RemoteAccessClientID == "" { | 		if extPeer.RemoteAccessClientID == "" { | ||||||
| 			if ok := IsPeerAllowed(extPeer.ConvertToStaticNode(), *peer, true); !ok { | 			if ok := IsPeerAllowed(extPeer.ConvertToStaticNode(), *peer, true); !ok { | ||||||
| 				fmt.Println("=====>1 checking EXT peer: ", extPeer.ClientID) |  | ||||||
| 				continue | 				continue | ||||||
| 			} | 			} | ||||||
| 		} else { | 		} else { | ||||||
| @@ -934,16 +947,11 @@ func GetStaticUserNodesByNetwork(network models.NetworkID) (staticNode []models. | |||||||
| 	for _, extI := range extClients { | 	for _, extI := range extClients { | ||||||
| 		if extI.Network == network.String() { | 		if extI.Network == network.String() { | ||||||
| 			if extI.RemoteAccessClientID != "" { | 			if extI.RemoteAccessClientID != "" { | ||||||
| 				n := models.Node{ | 				n := extI.ConvertToStaticNode() | ||||||
| 					IsStatic:   true, |  | ||||||
| 					StaticNode: extI, |  | ||||||
| 					IsUserNode: extI.RemoteAccessClientID != "", |  | ||||||
| 				} |  | ||||||
| 				staticNode = append(staticNode, n) | 				staticNode = append(staticNode, n) | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	return | 	return | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -866,6 +866,9 @@ func GetTagMapWithNodesByNetwork(netID models.NetworkID, withStaticNodes bool) ( | |||||||
| 			nodeI.Mutex.Lock() | 			nodeI.Mutex.Lock() | ||||||
| 		} | 		} | ||||||
| 		for nodeTagID := range nodeI.Tags { | 		for nodeTagID := range nodeI.Tags { | ||||||
|  | 			if nodeTagID == models.TagID(nodeI.ID.String()) { | ||||||
|  | 				continue | ||||||
|  | 			} | ||||||
| 			tagNodesMap[nodeTagID] = append(tagNodesMap[nodeTagID], nodeI) | 			tagNodesMap[nodeTagID] = append(tagNodesMap[nodeTagID], nodeI) | ||||||
| 		} | 		} | ||||||
| 		if nodeI.Mutex != nil { | 		if nodeI.Mutex != nil { | ||||||
| @@ -903,6 +906,9 @@ func AddTagMapWithStaticNodes(netID models.NetworkID, | |||||||
| 			extclient.Mutex.Lock() | 			extclient.Mutex.Lock() | ||||||
| 		} | 		} | ||||||
| 		for tagID := range extclient.Tags { | 		for tagID := range extclient.Tags { | ||||||
|  | 			if tagID == models.TagID(extclient.ClientID) { | ||||||
|  | 				continue | ||||||
|  | 			} | ||||||
| 			tagNodesMap[tagID] = append(tagNodesMap[tagID], extclient.ConvertToStaticNode()) | 			tagNodesMap[tagID] = append(tagNodesMap[tagID], extclient.ConvertToStaticNode()) | ||||||
| 			tagNodesMap["*"] = append(tagNodesMap["*"], extclient.ConvertToStaticNode()) | 			tagNodesMap["*"] = append(tagNodesMap["*"], extclient.ConvertToStaticNode()) | ||||||
| 		} | 		} | ||||||
|   | |||||||
| @@ -181,6 +181,7 @@ func GetPeerUpdateForHost(network string, host *models.Host, allNodes []models.N | |||||||
| 	slog.Debug("peer update for host", "hostId", host.ID.String()) | 	slog.Debug("peer update for host", "hostId", host.ID.String()) | ||||||
| 	peerIndexMap := make(map[string]int) | 	peerIndexMap := make(map[string]int) | ||||||
| 	for _, nodeID := range host.Nodes { | 	for _, nodeID := range host.Nodes { | ||||||
|  | 		networkAllowAll := true | ||||||
| 		nodeID := nodeID | 		nodeID := nodeID | ||||||
| 		node, err := GetNodeByID(nodeID) | 		node, err := GetNodeByID(nodeID) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| @@ -190,60 +191,6 @@ func GetPeerUpdateForHost(network string, host *models.Host, allNodes []models.N | |||||||
| 		if !node.Connected || node.PendingDelete || node.Action == models.NODE_DELETE { | 		if !node.Connected || node.PendingDelete || node.Action == models.NODE_DELETE { | ||||||
| 			continue | 			continue | ||||||
| 		} | 		} | ||||||
| 		if host.OS == models.OS_Types.IoT { |  | ||||||
| 			hostPeerUpdate.NodeAddrs = append(hostPeerUpdate.NodeAddrs, node.PrimaryAddressIPNet()) |  | ||||||
| 			if node.IsRelayed { |  | ||||||
| 				relayNode, err := GetNodeByID(node.RelayedBy) |  | ||||||
| 				if err != nil { |  | ||||||
| 					continue |  | ||||||
| 				} |  | ||||||
| 				relayHost, err := GetHost(relayNode.HostID.String()) |  | ||||||
| 				if err != nil { |  | ||||||
| 					continue |  | ||||||
| 				} |  | ||||||
| 				relayPeer := wgtypes.PeerConfig{ |  | ||||||
| 					PublicKey:                   relayHost.PublicKey, |  | ||||||
| 					PersistentKeepaliveInterval: &relayHost.PersistentKeepalive, |  | ||||||
| 					ReplaceAllowedIPs:           true, |  | ||||||
| 					AllowedIPs:                  GetAllowedIPs(&node, &relayNode, nil), |  | ||||||
| 				} |  | ||||||
| 				uselocal := false |  | ||||||
| 				if host.EndpointIP.String() == relayHost.EndpointIP.String() { |  | ||||||
| 					// peer is on same network |  | ||||||
| 					// set to localaddress |  | ||||||
| 					uselocal = true |  | ||||||
| 					if node.LocalAddress.IP == nil { |  | ||||||
| 						// use public endpint |  | ||||||
| 						uselocal = false |  | ||||||
| 					} |  | ||||||
| 					if node.LocalAddress.String() == relayNode.LocalAddress.String() { |  | ||||||
| 						uselocal = false |  | ||||||
| 					} |  | ||||||
| 				} |  | ||||||
| 				relayPeer.Endpoint = &net.UDPAddr{ |  | ||||||
| 					IP:   relayHost.EndpointIP, |  | ||||||
| 					Port: GetPeerListenPort(relayHost), |  | ||||||
| 				} |  | ||||||
|  |  | ||||||
| 				if uselocal { |  | ||||||
| 					relayPeer.Endpoint.IP = relayNode.LocalAddress.IP |  | ||||||
| 					relayPeer.Endpoint.Port = relayHost.ListenPort |  | ||||||
| 				} |  | ||||||
|  |  | ||||||
| 				hostPeerUpdate.Peers = append(hostPeerUpdate.Peers, relayPeer) |  | ||||||
| 			} else if deletedNode != nil && deletedNode.IsRelay { |  | ||||||
| 				relayHost, err := GetHost(deletedNode.HostID.String()) |  | ||||||
| 				if err != nil { |  | ||||||
| 					continue |  | ||||||
| 				} |  | ||||||
| 				relayPeer := wgtypes.PeerConfig{ |  | ||||||
| 					PublicKey: relayHost.PublicKey, |  | ||||||
| 					Remove:    true, |  | ||||||
| 				} |  | ||||||
| 				hostPeerUpdate.Peers = append(hostPeerUpdate.Peers, relayPeer) |  | ||||||
| 			} |  | ||||||
| 			continue |  | ||||||
| 		} |  | ||||||
| 		hostPeerUpdate = SetDefaultGw(node, hostPeerUpdate) | 		hostPeerUpdate = SetDefaultGw(node, hostPeerUpdate) | ||||||
| 		if !hostPeerUpdate.IsInternetGw { | 		if !hostPeerUpdate.IsInternetGw { | ||||||
| 			hostPeerUpdate.IsInternetGw = IsInternetGw(node) | 			hostPeerUpdate.IsInternetGw = IsInternetGw(node) | ||||||
| @@ -259,6 +206,7 @@ func GetPeerUpdateForHost(network string, host *models.Host, allNodes []models.N | |||||||
| 				hostPeerUpdate.FwUpdate.AllowedNetworks = append(hostPeerUpdate.FwUpdate.AllowedNetworks, node.NetworkRange6) | 				hostPeerUpdate.FwUpdate.AllowedNetworks = append(hostPeerUpdate.FwUpdate.AllowedNetworks, node.NetworkRange6) | ||||||
| 			} | 			} | ||||||
| 		} else { | 		} else { | ||||||
|  | 			networkAllowAll = false | ||||||
| 			hostPeerUpdate.FwUpdate.AllowAll = false | 			hostPeerUpdate.FwUpdate.AllowAll = false | ||||||
| 			rules := GetAclRulesForNode(&node) | 			rules := GetAclRulesForNode(&node) | ||||||
| 			if len(hostPeerUpdate.FwUpdate.AclRules) == 0 { | 			if len(hostPeerUpdate.FwUpdate.AclRules) == 0 { | ||||||
| @@ -370,7 +318,6 @@ func GetPeerUpdateForHost(network string, host *models.Host, allNodes []models.N | |||||||
| 			} | 			} | ||||||
|  |  | ||||||
| 			if uselocal { | 			if uselocal { | ||||||
| 				peerConfig.Endpoint.IP = peer.LocalAddress.IP |  | ||||||
| 				peerConfig.Endpoint.Port = peerHost.ListenPort | 				peerConfig.Endpoint.Port = peerHost.ListenPort | ||||||
| 			} | 			} | ||||||
| 			var allowedToComm bool | 			var allowedToComm bool | ||||||
| @@ -438,7 +385,6 @@ func GetPeerUpdateForHost(network string, host *models.Host, allNodes []models.N | |||||||
| 						IngressID:     node.ID.String(), | 						IngressID:     node.ID.String(), | ||||||
| 						Network:       node.NetworkRange, | 						Network:       node.NetworkRange, | ||||||
| 						Network6:      node.NetworkRange6, | 						Network6:      node.NetworkRange6, | ||||||
| 						AllowAll:      defaultDevicePolicy.Enabled && defaultUserPolicy.Default, |  | ||||||
| 						StaticNodeIps: GetStaticNodeIps(node), | 						StaticNodeIps: GetStaticNodeIps(node), | ||||||
| 						Rules:         GetFwRulesOnIngressGateway(node), | 						Rules:         GetFwRulesOnIngressGateway(node), | ||||||
| 					} | 					} | ||||||
| @@ -473,9 +419,22 @@ func GetPeerUpdateForHost(network string, host *models.Host, allNodes []models.N | |||||||
| 					Mask: getCIDRMaskFromAddr(node.Address6.IP.String()), | 					Mask: getCIDRMaskFromAddr(node.Address6.IP.String()), | ||||||
| 				}, | 				}, | ||||||
| 				EgressGWCfg:   node.EgressGatewayRequest, | 				EgressGWCfg:   node.EgressGatewayRequest, | ||||||
|  | 				EgressFwRules: make(map[string]models.AclRule), | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| 		} | 		} | ||||||
|  | 		if node.IsEgressGateway { | ||||||
|  | 			if !networkAllowAll { | ||||||
|  | 				egressInfo := hostPeerUpdate.FwUpdate.EgressInfo[node.ID.String()] | ||||||
|  | 				if egressInfo.EgressFwRules == nil { | ||||||
|  | 					egressInfo.EgressFwRules = make(map[string]models.AclRule) | ||||||
|  | 				} | ||||||
|  | 				egressInfo.EgressFwRules = GetEgressRulesForNode(node) | ||||||
|  | 				hostPeerUpdate.FwUpdate.EgressInfo[node.ID.String()] = egressInfo | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 		} | ||||||
|  |  | ||||||
| 		if IsInternetGw(node) { | 		if IsInternetGw(node) { | ||||||
| 			hostPeerUpdate.FwUpdate.IsEgressGw = true | 			hostPeerUpdate.FwUpdate.IsEgressGw = true | ||||||
| 			egressrange := []string{"0.0.0.0/0"} | 			egressrange := []string{"0.0.0.0/0"} | ||||||
|   | |||||||
| @@ -278,7 +278,7 @@ func CheckIDSyntax(id string) error { | |||||||
| } | } | ||||||
|  |  | ||||||
| func CreateDefaultTags(netID models.NetworkID) { | func CreateDefaultTags(netID models.NetworkID) { | ||||||
| 	// create tag for remote access gws in the network | 	// create tag for gws in the network | ||||||
| 	tag := models.Tag{ | 	tag := models.Tag{ | ||||||
| 		ID:        models.TagID(fmt.Sprintf("%s.%s", netID.String(), models.GwTagName)), | 		ID:        models.TagID(fmt.Sprintf("%s.%s", netID.String(), models.GwTagName)), | ||||||
| 		TagName:   models.GwTagName, | 		TagName:   models.GwTagName, | ||||||
| @@ -292,7 +292,7 @@ func CreateDefaultTags(netID models.NetworkID) { | |||||||
| 	} | 	} | ||||||
| 	err = InsertTag(tag) | 	err = InsertTag(tag) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		slog.Error("failed to create remote access gw tag", "error", err.Error()) | 		slog.Error("failed to create gw tag", "error", err.Error()) | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|   | |||||||
| @@ -468,14 +468,14 @@ func migrateToGws() { | |||||||
| 		upsert := false | 		upsert := false | ||||||
| 		for i, srcI := range acl.Src { | 		for i, srcI := range acl.Src { | ||||||
| 			if srcI.ID == models.NodeTagID && srcI.Value == fmt.Sprintf("%s.%s", acl.NetworkID.String(), models.OldRemoteAccessTagName) { | 			if srcI.ID == models.NodeTagID && srcI.Value == fmt.Sprintf("%s.%s", acl.NetworkID.String(), models.OldRemoteAccessTagName) { | ||||||
| 				srcI.Value = models.GwTagName | 				srcI.Value = fmt.Sprintf("%s.%s", acl.NetworkID.String(), models.GwTagName) | ||||||
| 				acl.Src[i] = srcI | 				acl.Src[i] = srcI | ||||||
| 				upsert = true | 				upsert = true | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 		for i, dstI := range acl.Dst { | 		for i, dstI := range acl.Dst { | ||||||
| 			if dstI.ID == models.NodeTagID && dstI.Value == fmt.Sprintf("%s.%s", acl.NetworkID.String(), models.OldRemoteAccessTagName) { | 			if dstI.ID == models.NodeTagID && dstI.Value == fmt.Sprintf("%s.%s", acl.NetworkID.String(), models.OldRemoteAccessTagName) { | ||||||
| 				dstI.Value = models.GwTagName | 				dstI.Value = fmt.Sprintf("%s.%s", acl.NetworkID.String(), models.GwTagName) | ||||||
| 				acl.Dst[i] = dstI | 				acl.Dst[i] = dstI | ||||||
| 				upsert = true | 				upsert = true | ||||||
| 			} | 			} | ||||||
|   | |||||||
| @@ -117,5 +117,7 @@ type AclRule struct { | |||||||
| 	AllowedProtocol Protocol                `json:"allowed_protocols"` // tcp, udp, etc. | 	AllowedProtocol Protocol                `json:"allowed_protocols"` // tcp, udp, etc. | ||||||
| 	AllowedPorts    []string                `json:"allowed_ports"` | 	AllowedPorts    []string                `json:"allowed_ports"` | ||||||
| 	Direction       AllowedTrafficDirection `json:"direction"` // single or two-way | 	Direction       AllowedTrafficDirection `json:"direction"` // single or two-way | ||||||
|  | 	Dst             []net.IPNet             `json:"dst"` | ||||||
|  | 	Dst6            []net.IPNet             `json:"dst6"` | ||||||
| 	Allowed         bool | 	Allowed         bool | ||||||
| } | } | ||||||
|   | |||||||
| @@ -60,6 +60,7 @@ func (ext *ExtClient) ConvertToStaticNode() Node { | |||||||
| 		Tags:       ext.Tags, | 		Tags:       ext.Tags, | ||||||
| 		IsStatic:   true, | 		IsStatic:   true, | ||||||
| 		StaticNode: *ext, | 		StaticNode: *ext, | ||||||
|  | 		IsUserNode: ext.RemoteAccessClientID != "", | ||||||
| 		Mutex:      ext.Mutex, | 		Mutex:      ext.Mutex, | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|   | |||||||
| @@ -53,7 +53,6 @@ type IngressInfo struct { | |||||||
| 	Network6      net.IPNet   `json:"network6"` | 	Network6      net.IPNet   `json:"network6"` | ||||||
| 	StaticNodeIps []net.IP    `json:"static_node_ips"` | 	StaticNodeIps []net.IP    `json:"static_node_ips"` | ||||||
| 	Rules         []FwRule    `json:"rules"` | 	Rules         []FwRule    `json:"rules"` | ||||||
| 	AllowAll      bool        `json:"allow_all"` |  | ||||||
| 	EgressRanges  []net.IPNet `json:"egress_ranges"` | 	EgressRanges  []net.IPNet `json:"egress_ranges"` | ||||||
| 	EgressRanges6 []net.IPNet `json:"egress_ranges6"` | 	EgressRanges6 []net.IPNet `json:"egress_ranges6"` | ||||||
| } | } | ||||||
| @@ -66,6 +65,7 @@ type EgressInfo struct { | |||||||
| 	Network6      net.IPNet            `json:"network6" yaml:"network6"` | 	Network6      net.IPNet            `json:"network6" yaml:"network6"` | ||||||
| 	EgressGwAddr6 net.IPNet            `json:"egress_gw_addr6" yaml:"egress_gw_addr6"` | 	EgressGwAddr6 net.IPNet            `json:"egress_gw_addr6" yaml:"egress_gw_addr6"` | ||||||
| 	EgressGWCfg   EgressGatewayRequest `json:"egress_gateway_cfg" yaml:"egress_gateway_cfg"` | 	EgressGWCfg   EgressGatewayRequest `json:"egress_gateway_cfg" yaml:"egress_gateway_cfg"` | ||||||
|  | 	EgressFwRules map[string]AclRule   `json:"egress_fw_rules"` | ||||||
| } | } | ||||||
|  |  | ||||||
| // EgressNetworkRoutes - struct for egress network routes for adding routes to peer's interface | // EgressNetworkRoutes - struct for egress network routes for adding routes to peer's interface | ||||||
|   | |||||||
| @@ -98,7 +98,7 @@ var oauthNotConfigured = fmt.Sprintf(htmlBaseTemplate, `<h2>Your Netmaker server | |||||||
| var oauthStateInvalid = fmt.Sprintf(htmlBaseTemplate, `<h2>Invalid OAuth Session. Please re-try again.</h2>`) | var oauthStateInvalid = fmt.Sprintf(htmlBaseTemplate, `<h2>Invalid OAuth Session. Please re-try again.</h2>`) | ||||||
|  |  | ||||||
| var userNotAllowed = fmt.Sprintf(htmlBaseTemplate, `<h2>Your account does not have access to the dashboard. Please contact your administrator for more information about your account.</h2> | var userNotAllowed = fmt.Sprintf(htmlBaseTemplate, `<h2>Your account does not have access to the dashboard. Please contact your administrator for more information about your account.</h2> | ||||||
| <p>Non-Admins can access the netmaker networks using <a href="https://docs.netmaker.io/docs/remote-access-client-rac#downloadinstallation" target="_blank" rel="noopener">our Remote Access Client.</a></p>`) | <p>Non-Admins can access the netmaker networks using <a href="https://docs.netmaker.io/docs/remote-access-client-rac#downloadinstallation" target="_blank" rel="noopener">our Netmaker Desktop App.</a></p>`) | ||||||
|  |  | ||||||
| var userFirstTimeSignUp = fmt.Sprintf(htmlBaseTemplate, `<h2>Thank you for signing up. Please contact your administrator for access.</h2>`) | var userFirstTimeSignUp = fmt.Sprintf(htmlBaseTemplate, `<h2>Thank you for signing up. Please contact your administrator for access.</h2>`) | ||||||
|  |  | ||||||
|   | |||||||
| @@ -8,7 +8,9 @@ import ( | |||||||
| 	"net/http" | 	"net/http" | ||||||
| 	"net/url" | 	"net/url" | ||||||
| 	"strings" | 	"strings" | ||||||
|  | 	"time" | ||||||
|  |  | ||||||
|  | 	"github.com/google/uuid" | ||||||
| 	"github.com/gorilla/mux" | 	"github.com/gorilla/mux" | ||||||
| 	"github.com/gravitl/netmaker/database" | 	"github.com/gravitl/netmaker/database" | ||||||
| 	"github.com/gravitl/netmaker/logger" | 	"github.com/gravitl/netmaker/logger" | ||||||
| @@ -411,6 +413,44 @@ func createUserGroup(w http.ResponseWriter, r *http.Request) { | |||||||
| 		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal")) | 		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal")) | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
|  | 	networks, err := logic.GetNetworks() | ||||||
|  | 	if err != nil { | ||||||
|  | 		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal")) | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	for _, network := range networks { | ||||||
|  | 		acl := models.Acl{ | ||||||
|  | 			ID:          uuid.New().String(), | ||||||
|  | 			Name:        fmt.Sprintf("%s group", userGroupReq.Group.Name), | ||||||
|  | 			MetaData:    "This Policy allows user group to communicate with all gateways", | ||||||
|  | 			Default:     true, | ||||||
|  | 			ServiceType: models.Any, | ||||||
|  | 			NetworkID:   models.NetworkID(network.NetID), | ||||||
|  | 			Proto:       models.ALL, | ||||||
|  | 			RuleType:    models.UserPolicy, | ||||||
|  | 			Src: []models.AclPolicyTag{ | ||||||
|  | 				{ | ||||||
|  | 					ID:    models.UserGroupAclID, | ||||||
|  | 					Value: userGroupReq.Group.ID.String(), | ||||||
|  | 				}, | ||||||
|  | 			}, | ||||||
|  | 			Dst: []models.AclPolicyTag{ | ||||||
|  | 				{ | ||||||
|  | 					ID:    models.NodeTagID, | ||||||
|  | 					Value: fmt.Sprintf("%s.%s", models.NetworkID(network.NetID), models.GwTagName), | ||||||
|  | 				}}, | ||||||
|  | 			AllowedDirection: models.TrafficDirectionUni, | ||||||
|  | 			Enabled:          true, | ||||||
|  | 			CreatedBy:        "auto", | ||||||
|  | 			CreatedAt:        time.Now().UTC(), | ||||||
|  | 		} | ||||||
|  | 		err = logic.InsertAcl(acl) | ||||||
|  | 		if err != nil { | ||||||
|  | 			logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal")) | ||||||
|  | 			return | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	for _, userID := range userGroupReq.Members { | 	for _, userID := range userGroupReq.Members { | ||||||
| 		user, err := logic.GetUser(userID) | 		user, err := logic.GetUser(userID) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
|   | |||||||
| @@ -2,6 +2,7 @@ package email | |||||||
|  |  | ||||||
| import ( | import ( | ||||||
| 	"fmt" | 	"fmt" | ||||||
|  |  | ||||||
| 	"github.com/gravitl/netmaker/models" | 	"github.com/gravitl/netmaker/models" | ||||||
| 	proLogic "github.com/gravitl/netmaker/pro/logic" | 	proLogic "github.com/gravitl/netmaker/pro/logic" | ||||||
| 	"github.com/gravitl/netmaker/servercfg" | 	"github.com/gravitl/netmaker/servercfg" | ||||||
| @@ -31,11 +32,11 @@ func (invite UserInvitedMail) GetBody(info Notification) string { | |||||||
|  |  | ||||||
| 	content := invite.BodyBuilder. | 	content := invite.BodyBuilder. | ||||||
| 		WithParagraph("Hi,"). | 		WithParagraph("Hi,"). | ||||||
| 		WithParagraph("You've been invited to access a secure network via Netmaker's Remote Access Client (RAC). Follow these simple steps to get connected:"). | 		WithParagraph("You've been invited to access a secure network via Netmaker Desktop App. Follow these simple steps to get connected:"). | ||||||
| 		WithHtml("<ol>"). | 		WithHtml("<ol>"). | ||||||
| 		WithHtml(fmt.Sprintf("<li>Click <a href=\"%s\">here</a> to accept your invitation and setup your account.</li>", invite.InviteURL)). | 		WithHtml(fmt.Sprintf("<li>Click <a href=\"%s\">here</a> to accept your invitation and setup your account.</li>", invite.InviteURL)). | ||||||
| 		WithHtml("<br>"). | 		WithHtml("<br>"). | ||||||
| 		WithHtml(fmt.Sprintf("<li><a href=\"%s\">Download the Remote Access Client (RAC)</a>.</li>", downloadLink)) | 		WithHtml(fmt.Sprintf("<li><a href=\"%s\">Download the Netmaker Desktop App</a>.</li>", downloadLink)) | ||||||
|  |  | ||||||
| 	if invite.PlatformRoleID == models.AdminRole.String() || invite.PlatformRoleID == models.PlatformUser.String() { | 	if invite.PlatformRoleID == models.AdminRole.String() || invite.PlatformRoleID == models.PlatformUser.String() { | ||||||
| 		content = content. | 		content = content. | ||||||
|   | |||||||
| @@ -40,7 +40,7 @@ var NetworkAdminAllPermissionTemplate = models.UserRolePermissionTemplate{ | |||||||
| var NetworkUserAllPermissionTemplate = models.UserRolePermissionTemplate{ | var NetworkUserAllPermissionTemplate = models.UserRolePermissionTemplate{ | ||||||
| 	ID:         models.UserRoleID(fmt.Sprintf("global-%s", models.NetworkUser)), | 	ID:         models.UserRoleID(fmt.Sprintf("global-%s", models.NetworkUser)), | ||||||
| 	Name:       "Network Users", | 	Name:       "Network Users", | ||||||
| 	MetaData:   "Can connect to nodes in your networks via Remote Access Client.", | 	MetaData:   "Can connect to nodes in your networks via Netmaker Desktop App.", | ||||||
| 	Default:    true, | 	Default:    true, | ||||||
| 	FullAccess: false, | 	FullAccess: false, | ||||||
| 	NetworkID:  models.AllNetworks, | 	NetworkID:  models.AllNetworks, | ||||||
| @@ -131,7 +131,7 @@ func UserGroupsInit() { | |||||||
| 				models.UserRoleID(fmt.Sprintf("global-%s", models.NetworkUser)): {}, | 				models.UserRoleID(fmt.Sprintf("global-%s", models.NetworkUser)): {}, | ||||||
| 			}, | 			}, | ||||||
| 		}, | 		}, | ||||||
| 		MetaData: "Provides read-only dashboard access to platform users and allows connection to network nodes via the Remote Access Client.", | 		MetaData: "Provides read-only dashboard access to platform users and allows connection to network nodes via the Netmaker Desktop App.", | ||||||
| 	} | 	} | ||||||
| 	d, _ := json.Marshal(NetworkGlobalAdminGroup) | 	d, _ := json.Marshal(NetworkGlobalAdminGroup) | ||||||
| 	database.Insert(NetworkGlobalAdminGroup.ID.String(), string(d), database.USER_GROUPS_TABLE_NAME) | 	database.Insert(NetworkGlobalAdminGroup.ID.String(), string(d), database.USER_GROUPS_TABLE_NAME) | ||||||
| @@ -156,7 +156,7 @@ func CreateDefaultNetworkRolesAndGroups(netID models.NetworkID) { | |||||||
| 	var NetworkUserPermissionTemplate = models.UserRolePermissionTemplate{ | 	var NetworkUserPermissionTemplate = models.UserRolePermissionTemplate{ | ||||||
| 		ID:                  models.UserRoleID(fmt.Sprintf("%s-%s", netID, models.NetworkUser)), | 		ID:                  models.UserRoleID(fmt.Sprintf("%s-%s", netID, models.NetworkUser)), | ||||||
| 		Name:                fmt.Sprintf("%s User", netID), | 		Name:                fmt.Sprintf("%s User", netID), | ||||||
| 		MetaData:            fmt.Sprintf("Can connect to nodes in your network `%s` via Remote Access Client.", netID), | 		MetaData:            fmt.Sprintf("Can connect to nodes in your network `%s` via Netmaker Desktop App.", netID), | ||||||
| 		Default:             true, | 		Default:             true, | ||||||
| 		FullAccess:          false, | 		FullAccess:          false, | ||||||
| 		NetworkID:           netID, | 		NetworkID:           netID, | ||||||
| @@ -235,7 +235,7 @@ func CreateDefaultNetworkRolesAndGroups(netID models.NetworkID) { | |||||||
| 				models.UserRoleID(fmt.Sprintf("%s-%s", netID, models.NetworkUser)): {}, | 				models.UserRoleID(fmt.Sprintf("%s-%s", netID, models.NetworkUser)): {}, | ||||||
| 			}, | 			}, | ||||||
| 		}, | 		}, | ||||||
| 		MetaData: fmt.Sprintf("Can connect to nodes in your network `%s` via Remote Access Client. Platform users will have read-only access to the the dashboard.", netID), | 		MetaData: fmt.Sprintf("Can connect to nodes in your network `%s` via Netmaker Desktop App. Platform users will have read-only access to the the dashboard.", netID), | ||||||
| 	} | 	} | ||||||
| 	d, _ = json.Marshal(NetworkAdminGroup) | 	d, _ = json.Marshal(NetworkAdminGroup) | ||||||
| 	database.Insert(NetworkAdminGroup.ID.String(), string(d), database.USER_GROUPS_TABLE_NAME) | 	database.Insert(NetworkAdminGroup.ID.String(), string(d), database.USER_GROUPS_TABLE_NAME) | ||||||
| @@ -810,87 +810,7 @@ func GetUserNetworkRolesWithRemoteVPNAccess(user models.User) (gwAccess map[mode | |||||||
| } | } | ||||||
|  |  | ||||||
| func GetFilteredNodesByUserAccess(user models.User, nodes []models.Node) (filteredNodes []models.Node) { | func GetFilteredNodesByUserAccess(user models.User, nodes []models.Node) (filteredNodes []models.Node) { | ||||||
|  | 	return filteredNodes | ||||||
| 	nodesMap := make(map[string]struct{}) |  | ||||||
| 	allNetworkRoles := make(map[models.UserRoleID]struct{}) |  | ||||||
| 	defer func() { |  | ||||||
| 		filteredNodes = logic.AddStaticNodestoList(filteredNodes) |  | ||||||
| 	}() |  | ||||||
| 	if len(user.NetworkRoles) > 0 { |  | ||||||
| 		for _, netRoles := range user.NetworkRoles { |  | ||||||
| 			for netRoleI := range netRoles { |  | ||||||
| 				allNetworkRoles[netRoleI] = struct{}{} |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	if _, ok := user.NetworkRoles[models.AllNetworks]; ok { |  | ||||||
| 		filteredNodes = nodes |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
| 	if len(user.UserGroups) > 0 { |  | ||||||
| 		for userGID := range user.UserGroups { |  | ||||||
| 			userG, err := GetUserGroup(userGID) |  | ||||||
| 			if err == nil { |  | ||||||
| 				if len(userG.NetworkRoles) > 0 { |  | ||||||
| 					if _, ok := userG.NetworkRoles[models.AllNetworks]; ok { |  | ||||||
| 						filteredNodes = nodes |  | ||||||
| 						return |  | ||||||
| 					} |  | ||||||
| 					for _, netRoles := range userG.NetworkRoles { |  | ||||||
| 						for netRoleI := range netRoles { |  | ||||||
| 							allNetworkRoles[netRoleI] = struct{}{} |  | ||||||
| 						} |  | ||||||
| 					} |  | ||||||
| 				} |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	for networkRoleID := range allNetworkRoles { |  | ||||||
| 		userPermTemplate, err := logic.GetRole(networkRoleID) |  | ||||||
| 		if err != nil { |  | ||||||
| 			continue |  | ||||||
| 		} |  | ||||||
| 		networkNodes := logic.GetNetworkNodesMemory(nodes, userPermTemplate.NetworkID.String()) |  | ||||||
| 		if userPermTemplate.FullAccess { |  | ||||||
| 			for _, node := range networkNodes { |  | ||||||
| 				if _, ok := nodesMap[node.ID.String()]; ok { |  | ||||||
| 					continue |  | ||||||
| 				} |  | ||||||
| 				nodesMap[node.ID.String()] = struct{}{} |  | ||||||
| 				filteredNodes = append(filteredNodes, node) |  | ||||||
| 			} |  | ||||||
|  |  | ||||||
| 			continue |  | ||||||
| 		} |  | ||||||
| 		if rsrcPerms, ok := userPermTemplate.NetworkLevelAccess[models.RemoteAccessGwRsrc]; ok { |  | ||||||
| 			if _, ok := rsrcPerms[models.AllRemoteAccessGwRsrcID]; ok { |  | ||||||
| 				for _, node := range networkNodes { |  | ||||||
| 					if _, ok := nodesMap[node.ID.String()]; ok { |  | ||||||
| 						continue |  | ||||||
| 					} |  | ||||||
| 					if node.IsIngressGateway { |  | ||||||
| 						nodesMap[node.ID.String()] = struct{}{} |  | ||||||
| 						filteredNodes = append(filteredNodes, node) |  | ||||||
| 					} |  | ||||||
| 				} |  | ||||||
| 			} else { |  | ||||||
| 				for gwID, scope := range rsrcPerms { |  | ||||||
| 					if _, ok := nodesMap[gwID.String()]; ok { |  | ||||||
| 						continue |  | ||||||
| 					} |  | ||||||
| 					if scope.Read { |  | ||||||
| 						gwNode, err := logic.GetNodeByID(gwID.String()) |  | ||||||
| 						if err == nil && gwNode.IsIngressGateway { |  | ||||||
| 							nodesMap[gwNode.ID.String()] = struct{}{} |  | ||||||
| 							filteredNodes = append(filteredNodes, gwNode) |  | ||||||
| 						} |  | ||||||
| 					} |  | ||||||
| 				} |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 	} |  | ||||||
| 	return |  | ||||||
| } | } | ||||||
|  |  | ||||||
| func FilterNetworksByRole(allnetworks []models.Network, user models.User) []models.Network { | func FilterNetworksByRole(allnetworks []models.Network, user models.User) []models.Network { | ||||||
| @@ -1211,7 +1131,7 @@ func CreateDefaultUserPolicies(netID models.NetworkID) { | |||||||
| 		defaultUserAcl := models.Acl{ | 		defaultUserAcl := models.Acl{ | ||||||
| 			ID:          fmt.Sprintf("%s.%s-grp", netID, models.NetworkAdmin), | 			ID:          fmt.Sprintf("%s.%s-grp", netID, models.NetworkAdmin), | ||||||
| 			Name:        "Network Admin", | 			Name:        "Network Admin", | ||||||
| 			MetaData:    "This Policy allows all network admins to communicate with all remote access gateways", | 			MetaData:    "This Policy allows all network admins to communicate with all gateways", | ||||||
| 			Default:     true, | 			Default:     true, | ||||||
| 			ServiceType: models.Any, | 			ServiceType: models.Any, | ||||||
| 			NetworkID:   netID, | 			NetworkID:   netID, | ||||||
| @@ -1244,7 +1164,7 @@ func CreateDefaultUserPolicies(netID models.NetworkID) { | |||||||
| 		defaultUserAcl := models.Acl{ | 		defaultUserAcl := models.Acl{ | ||||||
| 			ID:          fmt.Sprintf("%s.%s-grp", netID, models.NetworkUser), | 			ID:          fmt.Sprintf("%s.%s-grp", netID, models.NetworkUser), | ||||||
| 			Name:        "Network User", | 			Name:        "Network User", | ||||||
| 			MetaData:    "This Policy allows all network users to communicate with all remote access gateways", | 			MetaData:    "This Policy allows all network users to communicate with all gateways", | ||||||
| 			Default:     true, | 			Default:     true, | ||||||
| 			ServiceType: models.Any, | 			ServiceType: models.Any, | ||||||
| 			NetworkID:   netID, | 			NetworkID:   netID, | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Abhishek K
					Abhishek K