NM-116: Acl Fixes (#3652)

* handle all resources tag on gw

* add egress domain ranges to node acls

* simplify extclient egress alloweips, handle nil acl rule

* fix static node status check for gw acls

* skip ns ip if contains network cidr

* skip ns ip if contains network cidr

* skip ns ip if contains network cidr
This commit is contained in:
Abhishek K
2025-09-18 22:27:49 +05:30
committed by GitHub
parent 061ae11bac
commit aa913d6870
6 changed files with 107 additions and 28 deletions

View File

@@ -50,16 +50,31 @@ func GetFwRulesOnIngressGateway(node models.Node) (rules []models.FwRule) {
if defaultDevicePolicy.Enabled { if defaultDevicePolicy.Enabled {
return return
} }
defer func() {
if len(rules) == 0 && IsNodeAllowedToCommunicateWithAllRsrcs(node) {
if node.NetworkRange.IP != nil {
rules = append(rules, models.FwRule{
SrcIP: node.NetworkRange,
Allow: true,
})
}
if node.NetworkRange6.IP != nil {
rules = append(rules, models.FwRule{
SrcIP: node.NetworkRange6,
Allow: true,
})
}
return
}
}()
for _, nodeI := range nodes { for _, nodeI := range nodes {
if !nodeI.IsStatic || nodeI.IsUserNode { if !nodeI.IsStatic || nodeI.IsUserNode {
continue continue
} }
if !node.StaticNode.Enabled { if !nodeI.StaticNode.Enabled {
continue continue
} }
// if nodeI.StaticNode.IngressGatewayID != node.ID.String() {
// continue
// }
if IsNodeAllowedToCommunicateWithAllRsrcs(nodeI) { if IsNodeAllowedToCommunicateWithAllRsrcs(nodeI) {
if nodeI.Address.IP != nil { if nodeI.Address.IP != nil {
rules = append(rules, models.FwRule{ rules = append(rules, models.FwRule{
@@ -525,7 +540,18 @@ func GetAclRulesForNode(targetnodeI *models.Node) (rules map[string]models.AclRu
continue continue
} }
if _, ok := eI.Nodes[targetnode.ID.String()]; ok { if _, ok := eI.Nodes[targetnode.ID.String()]; ok {
if eI.Range != "" { if servercfg.IsPro && eI.Domain != "" && len(eI.DomainAns) > 0 {
for _, domainAnsI := range eI.DomainAns {
ip, cidr, err := net.ParseCIDR(domainAnsI)
if err == nil {
if ip.To4() != nil {
egressRanges4 = append(egressRanges4, *cidr)
} else {
egressRanges6 = append(egressRanges6, *cidr)
}
}
}
} else if eI.Range != "" {
_, cidr, err := net.ParseCIDR(eI.Range) _, cidr, err := net.ParseCIDR(eI.Range)
if err == nil { if err == nil {
if cidr.IP.To4() != nil { if cidr.IP.To4() != nil {
@@ -535,6 +561,7 @@ func GetAclRulesForNode(targetnodeI *models.Node) (rules map[string]models.AclRu
} }
} }
} }
dstTags[targetnode.ID.String()] = struct{}{}
} }
} }
break break
@@ -544,7 +571,18 @@ func GetAclRulesForNode(targetnodeI *models.Node) (rules map[string]models.AclRu
err := e.Get(db.WithContext(context.TODO())) err := e.Get(db.WithContext(context.TODO()))
if err == nil && e.Status && len(e.Nodes) > 0 { if err == nil && e.Status && len(e.Nodes) > 0 {
if _, ok := e.Nodes[targetnode.ID.String()]; ok { if _, ok := e.Nodes[targetnode.ID.String()]; ok {
if e.Range != "" { if servercfg.IsPro && e.Domain != "" && len(e.DomainAns) > 0 {
for _, domainAnsI := range e.DomainAns {
ip, cidr, err := net.ParseCIDR(domainAnsI)
if err == nil {
if ip.To4() != nil {
egressRanges4 = append(egressRanges4, *cidr)
} else {
egressRanges6 = append(egressRanges6, *cidr)
}
}
}
} else if e.Range != "" {
_, cidr, err := net.ParseCIDR(e.Range) _, cidr, err := net.ParseCIDR(e.Range)
if err == nil { if err == nil {
if cidr.IP.To4() != nil { if cidr.IP.To4() != nil {
@@ -554,6 +592,7 @@ func GetAclRulesForNode(targetnodeI *models.Node) (rules map[string]models.AclRu
} }
} }
} }
dstTags[targetnode.ID.String()] = struct{}{}
} }
} }
@@ -800,10 +839,10 @@ func GetEgressRulesForNode(targetnode models.Node) (rules map[string]models.AclR
if node.ID == targetnode.ID { if node.ID == targetnode.ID {
continue continue
} }
if node.Address.IP != nil { if !node.IsStatic && node.Address.IP != nil {
aclRule.IPList = append(aclRule.IPList, node.AddressIPNet4()) aclRule.IPList = append(aclRule.IPList, node.AddressIPNet4())
} }
if node.Address6.IP != nil { if !node.IsStatic && node.Address6.IP != nil {
aclRule.IP6List = append(aclRule.IP6List, node.AddressIPNet6()) aclRule.IP6List = append(aclRule.IP6List, node.AddressIPNet6())
} }
if node.IsStatic && node.StaticNode.Address != "" { if node.IsStatic && node.StaticNode.Address != "" {

View File

@@ -434,6 +434,25 @@ func validateNameserverReq(ns schema.Nameserver) error {
if len(ns.Servers) == 0 { if len(ns.Servers) == 0 {
return errors.New("atleast one nameserver should be specified") return errors.New("atleast one nameserver should be specified")
} }
network, err := GetNetwork(ns.NetworkID)
if err != nil {
return errors.New("invalid network id")
}
_, cidr, err4 := net.ParseCIDR(network.AddressRange)
_, cidr6, err6 := net.ParseCIDR(network.AddressRange6)
for _, nsIPStr := range ns.Servers {
nsIP := net.ParseIP(nsIPStr)
if nsIP == nil {
return errors.New("invalid nameserver " + nsIPStr)
}
if err4 == nil && nsIP.To4() != nil {
if cidr.Contains(nsIP) {
return errors.New("cannot use netmaker IP as nameserver")
}
} else if err6 == nil && cidr6.Contains(nsIP) {
return errors.New("cannot use netmaker IP as nameserver")
}
}
if !ns.MatchAll && len(ns.MatchDomains) == 0 { if !ns.MatchAll && len(ns.MatchDomains) == 0 {
return errors.New("atleast one match domain is required") return errors.New("atleast one match domain is required")
} }

View File

@@ -70,23 +70,12 @@ func storeExtClientInCache(key string, extclient models.ExtClient) {
func GetEgressRangesOnNetwork(client *models.ExtClient) ([]string, error) { func GetEgressRangesOnNetwork(client *models.ExtClient) ([]string, error) {
var result []string var result []string
networkNodes, err := GetNetworkNodes(client.Network)
if err != nil {
return []string{}, err
}
eli, _ := (&schema.Egress{Network: client.Network}).ListByNetwork(db.WithContext(context.TODO())) eli, _ := (&schema.Egress{Network: client.Network}).ListByNetwork(db.WithContext(context.TODO()))
acls, _ := ListAclsByNetwork(models.NetworkID(client.Network)) for _, eI := range eli {
// clientNode := client.ConvertToStaticNode() if !eI.Status || eI.Range == "" {
for _, currentNode := range networkNodes {
if currentNode.Network != client.Network {
continue continue
} }
GetNodeEgressInfo(&currentNode, eli, acls) result = append(result, eI.Range)
if currentNode.EgressDetails.IsEgressGateway { // add the egress gateway range(s) to the result
if len(currentNode.EgressDetails.EgressGatewayRanges) > 0 {
result = append(result, currentNode.EgressDetails.EgressGatewayRanges...)
}
}
} }
extclients, _ := GetNetworkExtClients(client.Network) extclients, _ := GetNetworkExtClients(client.Network)
for _, extclient := range extclients { for _, extclient := range extclients {

View File

@@ -149,11 +149,12 @@ func GetPeerUpdateForHost(network string, host *models.Host, allNodes []models.N
} }
defer func() { defer func() {
if !hostPeerUpdate.FwUpdate.AllowAll { if !hostPeerUpdate.FwUpdate.AllowAll {
if len(hostPeerUpdate.FwUpdate.AllowedNetworks) > 0 {
hostPeerUpdate.FwUpdate.EgressInfo["allowed-network-rules"] = models.EgressInfo{ hostPeerUpdate.FwUpdate.EgressInfo["allowed-network-rules"] = models.EgressInfo{
EgressID: "allowed-network-rules", EgressID: "allowed-network-rules",
EgressFwRules: make(map[string]models.AclRule), EgressFwRules: make(map[string]models.AclRule),
} }
}
for _, aclRule := range hostPeerUpdate.FwUpdate.AllowedNetworks { for _, aclRule := range hostPeerUpdate.FwUpdate.AllowedNetworks {
hostPeerUpdate.FwUpdate.AclRules[aclRule.ID] = aclRule hostPeerUpdate.FwUpdate.AclRules[aclRule.ID] = aclRule
hostPeerUpdate.FwUpdate.EgressInfo["allowed-network-rules"].EgressFwRules[aclRule.ID] = aclRule hostPeerUpdate.FwUpdate.EgressInfo["allowed-network-rules"].EgressFwRules[aclRule.ID] = aclRule

View File

@@ -5,6 +5,7 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"log" "log"
"net"
"os" "os"
"time" "time"
@@ -63,6 +64,10 @@ func migrateNameservers() {
} }
for _, netI := range nets { for _, netI := range nets {
_, cidr, err := net.ParseCIDR(netI.AddressRange)
if err != nil {
continue
}
if len(netI.NameServers) > 0 { if len(netI.NameServers) > 0 {
ns := schema.Nameserver{ ns := schema.Nameserver{
ID: uuid.NewString(), ID: uuid.NewString(),
@@ -78,8 +83,14 @@ func migrateNameservers() {
Status: true, Status: true,
CreatedBy: user.UserName, CreatedBy: user.UserName,
} }
for _, ip := range netI.NameServers {
ns.Servers = append(ns.Servers, ip) for _, nsIP := range netI.NameServers {
if net.ParseIP(nsIP) == nil {
continue
}
if !cidr.Contains(net.ParseIP(nsIP)) {
ns.Servers = append(ns.Servers, nsIP)
}
} }
ns.Create(db.WithContext(context.TODO())) ns.Create(db.WithContext(context.TODO()))
netI.NameServers = []string{} netI.NameServers = []string{}

View File

@@ -3,6 +3,7 @@ package logic
import ( import (
"context" "context"
"errors" "errors"
"net"
"github.com/gravitl/netmaker/db" "github.com/gravitl/netmaker/db"
"github.com/gravitl/netmaker/logic" "github.com/gravitl/netmaker/logic"
@@ -20,6 +21,25 @@ func ValidateNameserverReq(ns schema.Nameserver) error {
if len(ns.Servers) == 0 { if len(ns.Servers) == 0 {
return errors.New("atleast one nameserver should be specified") return errors.New("atleast one nameserver should be specified")
} }
network, err := logic.GetNetwork(ns.NetworkID)
if err != nil {
return errors.New("invalid network id")
}
_, cidr, err4 := net.ParseCIDR(network.AddressRange)
_, cidr6, err6 := net.ParseCIDR(network.AddressRange6)
for _, nsIPStr := range ns.Servers {
nsIP := net.ParseIP(nsIPStr)
if nsIP == nil {
return errors.New("invalid nameserver " + nsIPStr)
}
if err4 == nil && nsIP.To4() != nil {
if cidr.Contains(nsIP) {
return errors.New("cannot use netmaker IP as nameserver")
}
} else if err6 == nil && cidr6.Contains(nsIP) {
return errors.New("cannot use netmaker IP as nameserver")
}
}
if !ns.MatchAll && len(ns.MatchDomains) == 0 { if !ns.MatchAll && len(ns.MatchDomains) == 0 {
return errors.New("atleast one match domain is required") return errors.New("atleast one match domain is required")
} }