NET-2061: revert Inet gws, fix extclient comms with user policies (#3482)

* revert inet gws from acl policies

* add egress range with metric for inet gw

* link pro inet funcs

* fix extclient comms with users

* remove TODO comments
This commit is contained in:
Abhishek K 2025-06-05 22:42:16 +05:30 committed by GitHub
parent 0ff216dabd
commit 0f884d4f36
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
20 changed files with 316 additions and 775 deletions

View file

@ -181,12 +181,10 @@ func aclDebug(w http.ResponseWriter, r *http.Request) {
allowed, ps := logic.IsNodeAllowedToCommunicate(node, peer, true)
isallowed := logic.IsPeerAllowed(node, peer, true)
acls, _ := logic.ListAclsByNetwork(models.NetworkID(node.Network))
re := resp{
IsNodeAllowed: allowed,
IsPeerAllowed: isallowed,
Policies: ps,
EgressNets: logic.GetNetworkEgressInfo(models.NetworkID(node.Network), acls),
}
if peerIsStatic == "true" {
ingress, err := logic.GetNodeByID(peer.StaticNode.IngressGatewayID)

View file

@ -62,7 +62,6 @@ func createEgress(w http.ResponseWriter, r *http.Request) {
Description: req.Description,
Range: egressRange,
Nat: req.Nat,
IsInetGw: req.IsInetGw,
Nodes: make(datatypes.JSONMap),
Tags: make(datatypes.JSONMap),
Status: true,
@ -85,23 +84,6 @@ func createEgress(w http.ResponseWriter, r *http.Request) {
)
return
}
if e.IsInetGw {
for nodeID := range req.Nodes {
node, err := logic.GetNodeByID(nodeID)
if err == nil && !node.IsGw {
node.IsGw = true
node.IsIngressGateway = true
node.IsRelay = true
if node.Address.IP != nil {
node.IngressDNS = node.Address.IP.String()
} else {
node.IngressDNS = node.Address6.IP.String()
}
logic.UpsertNode(&node)
}
}
}
logic.LogEvent(&models.Event{
Action: models.Create,
Source: models.Subject{
@ -196,14 +178,10 @@ func updateEgress(w http.ResponseWriter, r *http.Request) {
return
}
var updateNat bool
var updateInetGw bool
var updateStatus bool
if req.Nat != e.Nat {
updateNat = true
}
if req.IsInetGw != e.IsInetGw {
updateInetGw = true
}
if req.Status != e.Status {
updateStatus = true
}
@ -236,7 +214,6 @@ func updateEgress(w http.ResponseWriter, r *http.Request) {
e.Name = req.Name
e.Nat = req.Nat
e.Status = req.Status
e.IsInetGw = req.IsInetGw
e.UpdatedAt = time.Now().UTC()
if err := logic.ValidateEgressReq(&e); err != nil {
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
@ -255,10 +232,6 @@ func updateEgress(w http.ResponseWriter, r *http.Request) {
e.Nat = req.Nat
e.UpdateNatStatus(db.WithContext(context.TODO()))
}
if updateInetGw {
e.IsInetGw = req.IsInetGw
e.UpdateINetGwStatus(db.WithContext(context.TODO()))
}
if updateStatus {
e.Status = req.Status
e.UpdateEgressStatus(db.WithContext(context.TODO()))

View file

@ -546,7 +546,7 @@ func getExtClientHAConf(w http.ResponseWriter, r *http.Request) {
keepalive = "PersistentKeepalive = " + strconv.Itoa(int(gwnode.IngressPersistentKeepalive))
}
var newAllowedIPs string
if logic.IsInternetGw(gwnode) || gwnode.EgressDetails.InternetGwID != "" {
if logic.IsInternetGw(gwnode) || gwnode.InternetGwID != "" {
egressrange := "0.0.0.0/0"
if gwnode.Address6.IP != nil && client.Address6 != "" {
egressrange += "," + "::/0"

View file

@ -608,35 +608,6 @@ func checkIfAclTagisValid(a models.Acl, t models.AclPolicyTag, isSrc bool) (err
if err != nil {
return errors.New("invalid egress")
}
if e.IsInetGw {
req := models.InetNodeReq{}
for _, srcI := range a.Src {
if srcI.ID == models.NodeID {
_, nodeErr := GetNodeByID(srcI.Value)
if nodeErr != nil {
_, staticNodeErr := GetExtClient(srcI.Value, a.NetworkID.String())
if staticNodeErr != nil {
return errors.New("invalid node " + srcI.Value)
}
} else {
req.InetNodeClientIDs = append(req.InetNodeClientIDs, srcI.Value)
}
}
}
if len(e.Nodes) > 0 {
for k := range e.Nodes {
inetNode, err := GetNodeByID(k)
if err != nil {
return errors.New("invalid node " + k)
}
if err = ValidateInetGwReq(inetNode, req, false); err != nil {
return err
}
}
}
}
default:
return errors.New("invalid policy")
}
@ -846,47 +817,6 @@ var GetInetClientsFromAclPolicies = func(eID string) (inetClientIDs []string) {
return
}
var IsNodeUsingInternetGw = func(node *models.Node, acls []models.Acl) {
host, err := GetHost(node.HostID.String())
if err != nil {
return
}
if host.IsDefault || node.IsFailOver {
return
}
var isUsing bool
for _, acl := range acls {
if !acl.Enabled {
continue
}
srcVal := ConvAclTagToValueMap(acl.Src)
for _, dstI := range acl.Dst {
if dstI.ID == models.EgressID {
e := schema.Egress{ID: dstI.Value}
err := e.Get(db.WithContext(context.TODO()))
if err != nil || !e.Status {
continue
}
if e.IsInetGw {
if _, ok := srcVal[node.ID.String()]; ok {
for nodeID := range e.Nodes {
if nodeID == node.ID.String() {
continue
}
node.EgressDetails.InternetGwID = nodeID
isUsing = true
return
}
}
}
}
}
}
if !isUsing {
node.EgressDetails.InternetGwID = ""
}
}
var (
CreateDefaultTags = func(netID models.NetworkID) {}

View file

@ -5,7 +5,6 @@ import (
"encoding/json"
"errors"
"maps"
"net"
"github.com/gravitl/netmaker/db"
"github.com/gravitl/netmaker/models"
@ -20,41 +19,12 @@ func ValidateEgressReq(e *schema.Egress) error {
if err != nil {
return errors.New("failed to get network " + err.Error())
}
if !e.IsInetGw {
if e.Range == "" {
return errors.New("egress range is empty")
}
_, _, err = net.ParseCIDR(e.Range)
if err != nil {
return errors.New("invalid egress range " + err.Error())
}
err = ValidateEgressRange(e.Network, []string{e.Range})
if err != nil {
return errors.New("invalid egress range " + err.Error())
}
} else {
if len(e.Nodes) > 1 {
return errors.New("can only set one internet routing node")
}
acls, _ := ListAclsByNetwork(models.NetworkID(e.Network))
req := models.InetNodeReq{}
eli, _ := (&schema.Egress{Network: e.Network}).ListByNetwork(db.WithContext(context.TODO()))
for k := range e.Nodes {
inetNode, err := GetNodeByID(k)
if err != nil {
return errors.New("invalid routing node " + err.Error())
}
// check if node is acting as egress gw already
GetNodeEgressInfo(&inetNode, eli, acls)
if err := ValidateInetGwReq(inetNode, req, false); err != nil {
return err
}
}
if len(e.Nodes) > 1 {
return errors.New("can only set one internet routing node")
}
if len(e.Nodes) != 0 {
if len(e.Nodes) > 0 {
for k := range e.Nodes {
_, err := GetNodeByID(k)
if err != nil {
@ -68,29 +38,19 @@ func ValidateEgressReq(e *schema.Egress) error {
func DoesNodeHaveAccessToEgress(node *models.Node, e *schema.Egress, acls []models.Acl) bool {
nodeTags := maps.Clone(node.Tags)
nodeTags[models.TagID(node.ID.String())] = struct{}{}
if !e.IsInetGw {
nodeTags[models.TagID("*")] = struct{}{}
}
if !e.IsInetGw {
defaultDevicePolicy, _ := GetDefaultPolicy(models.NetworkID(node.Network), models.DevicePolicy)
if defaultDevicePolicy.Enabled {
return true
}
}
for _, acl := range acls {
if !acl.Enabled {
continue
}
srcVal := ConvAclTagToValueMap(acl.Src)
if !e.IsInetGw && acl.AllowedDirection == models.TrafficDirectionBi {
if acl.AllowedDirection == models.TrafficDirectionBi {
if _, ok := srcVal["*"]; ok {
return true
}
}
for _, dstI := range acl.Dst {
if !e.IsInetGw && dstI.ID == models.NodeTagID && dstI.Value == "*" {
if dstI.ID == models.NodeTagID && dstI.Value == "*" {
return true
}
if dstI.ID == models.EgressID && dstI.Value == e.ID {
@ -127,21 +87,11 @@ func AddEgressInfoToPeerByAccess(node, targetNode *models.Node, eli []schema.Egr
NodeID: targetNode.ID.String(),
NetID: targetNode.Network,
}
defer func() {
if targetNode.Mutex != nil {
targetNode.Mutex.Lock()
}
IsNodeUsingInternetGw(targetNode, acls)
if targetNode.Mutex != nil {
targetNode.Mutex.Unlock()
}
}()
for _, e := range eli {
if !e.Status || e.Network != targetNode.Network {
continue
}
if !isDefaultPolicyActive || e.IsInetGw {
if !isDefaultPolicyActive {
if !DoesNodeHaveAccessToEgress(node, &e, acls) {
if node.IsRelayed && node.RelayedBy == targetNode.ID.String() {
if !DoesNodeHaveAccessToEgress(targetNode, &e, acls) {
@ -155,37 +105,17 @@ func AddEgressInfoToPeerByAccess(node, targetNode *models.Node, eli []schema.Egr
}
if metric, ok := e.Nodes[targetNode.ID.String()]; ok {
if e.IsInetGw {
targetNode.EgressDetails.IsInternetGateway = true
targetNode.EgressDetails.InetNodeReq = models.InetNodeReq{
InetNodeClientIDs: GetInetClientsFromAclPolicies(e.ID),
}
req.Ranges = append(req.Ranges, "0.0.0.0/0")
req.RangesWithMetric = append(req.RangesWithMetric, models.EgressRangeMetric{
Network: "0.0.0.0/0",
Nat: true,
RouteMetric: 256,
})
req.Ranges = append(req.Ranges, "::/0")
req.RangesWithMetric = append(req.RangesWithMetric, models.EgressRangeMetric{
Network: "::/0",
Nat: true,
RouteMetric: 256,
})
} else {
m64, err := metric.(json.Number).Int64()
if err != nil {
m64 = 256
}
m := uint32(m64)
req.Ranges = append(req.Ranges, e.Range)
req.RangesWithMetric = append(req.RangesWithMetric, models.EgressRangeMetric{
Network: e.Range,
Nat: e.Nat,
RouteMetric: m,
})
m64, err := metric.(json.Number).Int64()
if err != nil {
m64 = 256
}
m := uint32(m64)
req.Ranges = append(req.Ranges, e.Range)
req.RangesWithMetric = append(req.RangesWithMetric, models.EgressRangeMetric{
Network: e.Range,
Nat: e.Nat,
RouteMetric: m,
})
}
}
if targetNode.Mutex != nil {
@ -205,132 +135,28 @@ func AddEgressInfoToPeerByAccess(node, targetNode *models.Node, eli []schema.Egr
}
}
// TODO
func GetNetworkEgressInfo(network models.NetworkID, acls []models.Acl) (egressNodes map[string]models.Node) {
eli, _ := (&schema.Egress{Network: network.String()}).ListByNetwork(db.WithContext(context.TODO()))
egressNodes = make(map[string]models.Node)
var err error
for _, e := range eli {
if !e.Status || e.Nodes == nil {
continue
}
for nodeID, metric := range e.Nodes {
targetNode, ok := egressNodes[nodeID]
if !ok {
targetNode, err = GetNodeByID(nodeID)
if err != nil {
continue
}
}
req := models.EgressGatewayRequest{
NodeID: targetNode.ID.String(),
NetID: targetNode.Network,
}
IsNodeUsingInternetGw(&targetNode, acls)
if e.IsInetGw {
targetNode.EgressDetails.IsInternetGateway = true
targetNode.EgressDetails.InetNodeReq = models.InetNodeReq{
InetNodeClientIDs: GetInetClientsFromAclPolicies(e.ID),
}
req.Ranges = append(req.Ranges, "0.0.0.0/0")
req.RangesWithMetric = append(req.RangesWithMetric, models.EgressRangeMetric{
Network: "0.0.0.0/0",
Nat: true,
RouteMetric: 256,
})
req.Ranges = append(req.Ranges, "::/0")
req.RangesWithMetric = append(req.RangesWithMetric, models.EgressRangeMetric{
Network: "::/0",
Nat: true,
RouteMetric: 256,
})
} else {
m64, err := metric.(json.Number).Int64()
if err != nil {
m64 = 256
}
m := uint32(m64)
req.Ranges = append(req.Ranges, e.Range)
req.RangesWithMetric = append(req.RangesWithMetric, models.EgressRangeMetric{
Network: e.Range,
Nat: e.Nat,
RouteMetric: m,
})
}
if targetNode.Mutex != nil {
targetNode.Mutex.Lock()
}
if len(req.Ranges) > 0 {
targetNode.EgressDetails.IsEgressGateway = true
targetNode.EgressDetails.EgressGatewayRanges = append(targetNode.EgressDetails.EgressGatewayRanges, req.Ranges...)
targetNode.EgressDetails.EgressGatewayRequest.Ranges = append(targetNode.EgressDetails.EgressGatewayRequest.Ranges, req.Ranges...)
targetNode.EgressDetails.EgressGatewayRequest.RangesWithMetric = append(targetNode.EgressDetails.EgressGatewayRequest.RangesWithMetric,
req.RangesWithMetric...)
targetNode.EgressDetails.EgressGatewayRequest = req
egressNodes[targetNode.ID.String()] = targetNode
}
if targetNode.Mutex != nil {
targetNode.Mutex.Unlock()
}
}
}
return
}
func GetNodeEgressInfo(targetNode *models.Node, eli []schema.Egress, acls []models.Acl) {
req := models.EgressGatewayRequest{
NodeID: targetNode.ID.String(),
NetID: targetNode.Network,
}
defer func() {
if targetNode.Mutex != nil {
targetNode.Mutex.Lock()
}
IsNodeUsingInternetGw(targetNode, acls)
if targetNode.Mutex != nil {
targetNode.Mutex.Unlock()
}
}()
for _, e := range eli {
if !e.Status || e.Network != targetNode.Network {
continue
}
if metric, ok := e.Nodes[targetNode.ID.String()]; ok {
if e.IsInetGw {
targetNode.EgressDetails.IsInternetGateway = true
targetNode.EgressDetails.InetNodeReq = models.InetNodeReq{
InetNodeClientIDs: GetInetClientsFromAclPolicies(e.ID),
}
req.Ranges = append(req.Ranges, "0.0.0.0/0")
req.RangesWithMetric = append(req.RangesWithMetric, models.EgressRangeMetric{
Network: "0.0.0.0/0",
Nat: true,
RouteMetric: 256,
})
req.Ranges = append(req.Ranges, "::/0")
req.RangesWithMetric = append(req.RangesWithMetric, models.EgressRangeMetric{
Network: "::/0",
Nat: true,
RouteMetric: 256,
})
} else {
m64, err := metric.(json.Number).Int64()
if err != nil {
m64 = 256
}
m := uint32(m64)
req.Ranges = append(req.Ranges, e.Range)
req.RangesWithMetric = append(req.RangesWithMetric, models.EgressRangeMetric{
Network: e.Range,
Nat: e.Nat,
RouteMetric: m,
})
m64, err := metric.(json.Number).Int64()
if err != nil {
m64 = 256
}
m := uint32(m64)
req.Ranges = append(req.Ranges, e.Range)
req.RangesWithMetric = append(req.RangesWithMetric, models.EgressRangeMetric{
Network: e.Range,
Nat: e.Nat,
RouteMetric: m,
})
}
}

View file

@ -84,17 +84,7 @@ func GetEgressRangesOnNetwork(client *models.ExtClient) ([]string, error) {
GetNodeEgressInfo(&currentNode, eli, acls)
if currentNode.EgressDetails.IsEgressGateway { // add the egress gateway range(s) to the result
if len(currentNode.EgressDetails.EgressGatewayRanges) > 0 {
if currentNode.EgressDetails.IsInternetGateway && client.IngressGatewayID != currentNode.ID.String() {
for _, rangeI := range currentNode.EgressDetails.EgressGatewayRanges {
if rangeI == "0.0.0.0/0" || rangeI == "::/0" {
continue
} else {
result = append(result, rangeI)
}
}
} else {
result = append(result, currentNode.EgressDetails.EgressGatewayRanges...)
}
result = append(result, currentNode.EgressDetails.EgressGatewayRanges...)
}
}
}

View file

@ -1,7 +1,6 @@
package logic
import (
"context"
"errors"
"fmt"
"slices"
@ -9,27 +8,14 @@ import (
"time"
"github.com/gravitl/netmaker/database"
"github.com/gravitl/netmaker/db"
"github.com/gravitl/netmaker/logger"
"github.com/gravitl/netmaker/models"
"github.com/gravitl/netmaker/schema"
"github.com/gravitl/netmaker/servercfg"
)
// IsInternetGw - checks if node is acting as internet gw
func IsInternetGw(node models.Node) bool {
e := schema.Egress{
Network: node.Network,
}
egList, _ := e.ListByNetwork(db.WithContext(context.TODO()))
for _, egI := range egList {
if egI.IsInetGw {
if _, ok := egI.Nodes[node.ID.String()]; ok {
return true
}
}
}
return false
return node.IsInternetGateway
}
// GetInternetGateways - gets all the nodes that are internet gateways
@ -40,7 +26,7 @@ func GetInternetGateways() ([]models.Node, error) {
}
igs := make([]models.Node, 0)
for _, node := range nodes {
if node.EgressDetails.IsInternetGateway {
if node.IsInternetGateway {
igs = append(igs, node)
}
}
@ -205,12 +191,12 @@ func CreateIngressGateway(netid string, nodeid string, ingress models.IngressReq
node.IsIngressGateway = true
node.IsGw = true
if !servercfg.IsPro {
node.EgressDetails.IsInternetGateway = ingress.IsInternetGateway
node.IsInternetGateway = ingress.IsInternetGateway
}
node.IngressGatewayRange = network.AddressRange
node.IngressGatewayRange6 = network.AddressRange6
node.IngressDNS = ingress.ExtclientDNS
if node.EgressDetails.IsInternetGateway && node.IngressDNS == "" {
if node.IsInternetGateway && node.IngressDNS == "" {
node.IngressDNS = "1.1.1.1"
}
node.IngressPersistentKeepalive = 20
@ -284,7 +270,7 @@ func DeleteIngressGateway(nodeid string) (models.Node, []models.ExtClient, error
node.LastModified = time.Now().UTC()
node.IsIngressGateway = false
if !servercfg.IsPro {
node.EgressDetails.IsInternetGateway = false
node.IsInternetGateway = false
}
delete(node.Tags, models.TagID(fmt.Sprintf("%s.%s", node.Network, models.GwTagName)))
node.IngressGatewayRange = ""

View file

@ -30,8 +30,6 @@ var (
nodeNetworkCacheMutex = &sync.RWMutex{}
nodesCacheMap = make(map[string]models.Node)
nodesNetworkCacheMap = make(map[string]map[string]models.Node)
IPv4Network = "0.0.0.0/0"
IPv6Network = "::/0"
)
func getNodeFromCache(nodeID string) (node models.Node, ok bool) {
@ -283,21 +281,21 @@ func DeleteNode(node *models.Node, purge bool) error {
// unset all the relayed nodes
SetRelayedNodes(false, node.ID.String(), node.RelayedNodes)
}
if node.EgressDetails.InternetGwID != "" {
inetNode, err := GetNodeByID(node.EgressDetails.InternetGwID)
if node.InternetGwID != "" {
inetNode, err := GetNodeByID(node.InternetGwID)
if err == nil {
clientNodeIDs := []string{}
for _, inetNodeClientID := range inetNode.EgressDetails.InetNodeReq.InetNodeClientIDs {
for _, inetNodeClientID := range inetNode.InetNodeReq.InetNodeClientIDs {
if inetNodeClientID == node.ID.String() {
continue
}
clientNodeIDs = append(clientNodeIDs, inetNodeClientID)
}
inetNode.EgressDetails.InetNodeReq.InetNodeClientIDs = clientNodeIDs
inetNode.InetNodeReq.InetNodeClientIDs = clientNodeIDs
UpsertNode(&inetNode)
}
}
if node.EgressDetails.IsInternetGateway {
if node.IsInternetGateway {
UnsetInternetGw(node)
}
if !purge && !alreadyDeleted {
@ -826,157 +824,3 @@ func GetAllFailOvers() ([]models.Node, error) {
}
return igs, nil
}
func ValidateInetGwReq(inetNode models.Node, req models.InetNodeReq, update bool) error {
inetHost, err := GetHost(inetNode.HostID.String())
if err != nil {
return err
}
if inetHost.FirewallInUse == models.FIREWALL_NONE {
return errors.New("iptables or nftables needs to be installed")
}
if inetNode.EgressDetails.InternetGwID != "" {
return fmt.Errorf("node %s is using a internet gateway already", inetHost.Name)
}
if inetNode.IsRelayed {
return fmt.Errorf("node %s is being relayed", inetHost.Name)
}
for _, clientNodeID := range req.InetNodeClientIDs {
clientNode, err := GetNodeByID(clientNodeID)
if err != nil {
return err
}
if clientNode.IsFailOver {
return errors.New("failover node cannot be set to use internet gateway")
}
clientHost, err := GetHost(clientNode.HostID.String())
if err != nil {
return err
}
if clientHost.IsDefault {
return errors.New("default host cannot be set to use internet gateway")
}
if clientHost.OS != models.OS_Types.Linux && clientHost.OS != models.OS_Types.Windows {
return errors.New("can only attach linux or windows machine to a internet gateway")
}
if clientNode.EgressDetails.IsInternetGateway {
return fmt.Errorf("node %s acting as internet gateway cannot use another internet gateway", clientHost.Name)
}
if update {
if clientNode.EgressDetails.InternetGwID != "" && clientNode.EgressDetails.InternetGwID != inetNode.ID.String() {
return fmt.Errorf("node %s is already using a internet gateway", clientHost.Name)
}
} else {
if clientNode.EgressDetails.InternetGwID != "" {
return fmt.Errorf("node %s is already using a internet gateway", clientHost.Name)
}
}
if clientNode.FailedOverBy != uuid.Nil {
ResetFailedOverPeer(&clientNode)
}
if clientNode.IsRelayed && clientNode.RelayedBy != inetNode.ID.String() {
return fmt.Errorf("node %s is being relayed", clientHost.Name)
}
for _, nodeID := range clientHost.Nodes {
node, err := GetNodeByID(nodeID)
if err != nil {
continue
}
if node.EgressDetails.InternetGwID != "" && node.EgressDetails.InternetGwID != inetNode.ID.String() {
return errors.New("nodes on same host cannot use different internet gateway")
}
}
}
return nil
}
// SetInternetGw - sets the node as internet gw based on flag bool
func SetInternetGw(node *models.Node, req models.InetNodeReq) {
node.EgressDetails.IsInternetGateway = true
node.EgressDetails.InetNodeReq = req
for _, clientNodeID := range req.InetNodeClientIDs {
clientNode, err := GetNodeByID(clientNodeID)
if err != nil {
continue
}
clientNode.EgressDetails.InternetGwID = node.ID.String()
UpsertNode(&clientNode)
}
}
func UnsetInternetGw(node *models.Node) {
nodes, err := GetNetworkNodes(node.Network)
if err != nil {
slog.Error("failed to get network nodes", "network", node.Network, "error", err)
return
}
for _, clientNode := range nodes {
if node.ID.String() == clientNode.EgressDetails.InternetGwID {
clientNode.EgressDetails.InternetGwID = ""
UpsertNode(&clientNode)
}
}
node.EgressDetails.IsInternetGateway = false
node.EgressDetails.InetNodeReq = models.InetNodeReq{}
}
func SetDefaultGwForRelayedUpdate(relayed, relay models.Node, peerUpdate models.HostPeerUpdate) models.HostPeerUpdate {
if relay.EgressDetails.InternetGwID != "" {
relayedHost, err := GetHost(relayed.HostID.String())
if err != nil {
return peerUpdate
}
peerUpdate.ChangeDefaultGw = true
peerUpdate.DefaultGwIp = relay.Address.IP
if peerUpdate.DefaultGwIp == nil || relayedHost.EndpointIP == nil {
peerUpdate.DefaultGwIp = relay.Address6.IP
}
}
return peerUpdate
}
func SetDefaultGw(node models.Node, peerUpdate models.HostPeerUpdate) models.HostPeerUpdate {
if node.EgressDetails.InternetGwID != "" {
inetNode, err := GetNodeByID(node.EgressDetails.InternetGwID)
if err != nil {
return peerUpdate
}
host, err := GetHost(node.HostID.String())
if err != nil {
return peerUpdate
}
peerUpdate.ChangeDefaultGw = true
peerUpdate.DefaultGwIp = inetNode.Address.IP
if peerUpdate.DefaultGwIp == nil || host.EndpointIP == nil {
peerUpdate.DefaultGwIp = inetNode.Address6.IP
}
}
return peerUpdate
}
// GetAllowedIpForInetNodeClient - get inet cidr for node using a inet gw
func GetAllowedIpForInetNodeClient(node, peer *models.Node) []net.IPNet {
var allowedips = []net.IPNet{}
if peer.Address.IP != nil {
_, ipnet, _ := net.ParseCIDR(IPv4Network)
allowedips = append(allowedips, *ipnet)
}
if peer.Address6.IP != nil {
_, ipnet, _ := net.ParseCIDR(IPv6Network)
allowedips = append(allowedips, *ipnet)
}
return allowedips
}

View file

@ -42,6 +42,25 @@ var (
CreateFailOver = func(node models.Node) error {
return nil
}
// SetDefaulGw
SetDefaultGw = func(node models.Node, peerUpdate models.HostPeerUpdate) models.HostPeerUpdate {
return peerUpdate
}
SetDefaultGwForRelayedUpdate = func(relayed, relay models.Node, peerUpdate models.HostPeerUpdate) models.HostPeerUpdate {
return peerUpdate
}
// UnsetInternetGw
UnsetInternetGw = func(node *models.Node) {
node.IsInternetGateway = false
}
// SetInternetGw
SetInternetGw = func(node *models.Node, req models.InetNodeReq) {
node.IsInternetGateway = true
}
// GetAllowedIpForInetNodeClient
GetAllowedIpForInetNodeClient = func(node, peer *models.Node) []net.IPNet {
return []net.IPNet{}
}
)
// GetHostPeerInfo - fetches required peer info per network
@ -468,6 +487,14 @@ func GetPeerUpdateForHost(network string, host *models.Host, allNodes []models.N
if node.Address6.IP != nil {
egressrange = append(egressrange, "::/0")
}
rangeWithMetric := []models.EgressRangeMetric{}
for _, rangeI := range egressrange {
rangeWithMetric = append(rangeWithMetric, models.EgressRangeMetric{
Network: rangeI,
RouteMetric: 256,
Nat: true,
})
}
hostPeerUpdate.FwUpdate.EgressInfo[fmt.Sprintf("%s-%s", node.ID.String(), "inet")] = models.EgressInfo{
EgressID: fmt.Sprintf("%s-%s", node.ID.String(), "inet"),
Network: node.PrimaryAddressIPNet(),
@ -481,10 +508,11 @@ func GetPeerUpdateForHost(network string, host *models.Host, allNodes []models.N
Mask: getCIDRMaskFromAddr(node.Address6.IP.String()),
},
EgressGWCfg: models.EgressGatewayRequest{
NodeID: fmt.Sprintf("%s-%s", node.ID.String(), "inet"),
NetID: node.Network,
NatEnabled: "yes",
Ranges: egressrange,
NodeID: fmt.Sprintf("%s-%s", node.ID.String(), "inet"),
NetID: node.Network,
NatEnabled: "yes",
Ranges: egressrange,
RangesWithMetric: rangeWithMetric,
},
}
}
@ -583,15 +611,15 @@ func filterConflictingEgressRoutesWithMetric(node, peer models.Node) []models.Eg
func GetAllowedIPs(node, peer *models.Node, metrics *models.Metrics) []net.IPNet {
var allowedips []net.IPNet
allowedips = getNodeAllowedIPs(peer, node)
if peer.EgressDetails.IsInternetGateway && node.EgressDetails.InternetGwID == peer.ID.String() {
if peer.IsInternetGateway && node.InternetGwID == peer.ID.String() {
allowedips = append(allowedips, GetAllowedIpForInetNodeClient(node, peer)...)
return allowedips
}
if node.IsRelayed && node.RelayedBy == peer.ID.String() {
allowedips = append(allowedips, GetAllowedIpsForRelayed(node, peer)...)
// if peer.EgressDetails.InternetGwID != "" {
// return allowedips
// }
if peer.InternetGwID != "" {
return allowedips
}
}
// handle ingress gateway peers

View file

@ -123,10 +123,10 @@ func ValidateRelay(relay models.RelayRequest, update bool) error {
if relayedNode.IsIngressGateway {
return errors.New("cannot relay an ingress gateway (" + relayedNodeID + ")")
}
if relayedNode.EgressDetails.IsInternetGateway {
if relayedNode.IsInternetGateway {
return errors.New("cannot relay an internet gateway (" + relayedNodeID + ")")
}
if relayedNode.EgressDetails.InternetGwID != "" && relayedNode.EgressDetails.InternetGwID != relay.NodeID {
if relayedNode.InternetGwID != "" && relayedNode.InternetGwID != relay.NodeID {
return errors.New("cannot relay an internet client (" + relayedNodeID + ")")
}
if relayedNode.IsFailOver {
@ -217,9 +217,9 @@ func GetAllowedIpsForRelayed(relayed, relay *models.Node) (allowedIPs []net.IPNe
logger.Log(0, "RelayedByRelay called with invalid parameters")
return
}
// if relay.EgressDetails.InternetGwID != "" {
// return GetAllowedIpForInetNodeClient(relayed, relay)
// }
if relay.InternetGwID != "" {
return GetAllowedIpForInetNodeClient(relayed, relay)
}
peers, err := GetNetworkNodes(relay.Network)
if err != nil {
logger.Log(0, "error getting network clients", err.Error())

View file

@ -570,105 +570,6 @@ func migrateToEgressV1() {
logic.UpsertNode(&node)
}
if node.IsInternetGateway {
inetHost, err := logic.GetHost(node.HostID.String())
if err != nil {
continue
}
e := schema.Egress{
ID: uuid.New().String(),
Name: fmt.Sprintf("%s inet gw", inetHost.Name),
Description: "add description",
Network: node.Network,
Nodes: datatypes.JSONMap{
node.ID.String(): 256,
},
Tags: make(datatypes.JSONMap),
Range: "*",
IsInetGw: true,
Nat: true,
Status: true,
CreatedBy: user.UserName,
CreatedAt: time.Now().UTC(),
}
err = e.Create(db.WithContext(context.TODO()))
if err == nil {
node.IsEgressGateway = false
node.EgressGatewayRequest = models.EgressGatewayRequest{}
node.EgressGatewayNatEnabled = false
node.EgressGatewayRanges = []string{}
node.IsInternetGateway = false
src := []models.AclPolicyTag{}
for _, inetClientID := range node.InetNodeReq.InetNodeClientIDs {
_, err := logic.GetNodeByID(inetClientID)
if err == nil {
src = append(src, models.AclPolicyTag{
ID: models.NodeID,
Value: inetClientID,
})
}
}
acl := models.Acl{
ID: uuid.New().String(),
Name: "exit node policy",
MetaData: "all traffic on source nodes will pass through the destination node in the policy",
Default: false,
ServiceType: models.Any,
NetworkID: models.NetworkID(node.Network),
Proto: models.ALL,
RuleType: models.DevicePolicy,
Src: src,
Dst: []models.AclPolicyTag{
{
ID: models.EgressID,
Value: e.ID,
},
},
AllowedDirection: models.TrafficDirectionBi,
Enabled: true,
CreatedBy: "auto",
CreatedAt: time.Now().UTC(),
}
logic.InsertAcl(acl)
acl = models.Acl{
ID: uuid.New().String(),
Name: "exit node policy",
MetaData: "all traffic will pass through the destination node in the policy",
Default: false,
ServiceType: models.Any,
NetworkID: models.NetworkID(node.Network),
Proto: models.ALL,
RuleType: models.UserPolicy,
Src: []models.AclPolicyTag{
{
ID: models.UserAclID,
Value: "*",
},
},
Dst: []models.AclPolicyTag{
{
ID: models.EgressID,
Value: e.ID,
},
},
AllowedDirection: models.TrafficDirectionBi,
Enabled: true,
CreatedBy: "auto",
CreatedAt: time.Now().UTC(),
}
logic.InsertAcl(acl)
node.InetNodeReq = models.InetNodeReq{}
logic.UpsertNode(&node)
}
}
if node.InternetGwID != "" {
node.InternetGwID = ""
logic.UpsertNode(&node)
}
}
}

View file

@ -86,9 +86,9 @@ func (a *ApiNode) ConvertToServerNode(currentNode *Node) *Node {
convertedNode.IngressDNS = a.IngressDns
convertedNode.IngressPersistentKeepalive = a.IngressPersistentKeepalive
convertedNode.IngressMTU = a.IngressMTU
convertedNode.EgressDetails.IsInternetGateway = a.IsInternetGateway
convertedNode.EgressDetails.InternetGwID = currentNode.EgressDetails.InternetGwID
convertedNode.EgressDetails.InetNodeReq = currentNode.EgressDetails.InetNodeReq
convertedNode.IsInternetGateway = a.IsInternetGateway
convertedNode.InternetGwID = currentNode.InternetGwID
convertedNode.InetNodeReq = currentNode.InetNodeReq
convertedNode.RelayedNodes = a.RelayedNodes
convertedNode.DefaultACL = a.DefaultACL
convertedNode.OwnerID = currentNode.OwnerID
@ -196,9 +196,9 @@ func (nm *Node) ConvertToAPINode() *ApiNode {
apiNode.Connected = nm.Connected
apiNode.PendingDelete = nm.PendingDelete
apiNode.DefaultACL = nm.DefaultACL
apiNode.IsInternetGateway = nm.EgressDetails.IsInternetGateway
apiNode.InternetGwID = nm.EgressDetails.InternetGwID
apiNode.InetNodeReq = nm.EgressDetails.InetNodeReq
apiNode.IsInternetGateway = nm.IsInternetGateway
apiNode.InternetGwID = nm.InternetGwID
apiNode.InetNodeReq = nm.InetNodeReq
apiNode.IsFailOver = nm.IsFailOver
apiNode.FailOverPeers = nm.FailOverPeers
apiNode.FailedOverBy = nm.FailedOverBy

View file

@ -127,9 +127,9 @@ type EgressDetails struct {
EgressGatewayRequest EgressGatewayRequest
IsEgressGateway bool
EgressGatewayRanges []string
IsInternetGateway bool `json:"isinternetgateway" yaml:"isinternetgateway"`
InetNodeReq InetNodeReq `json:"inet_node_req" yaml:"inet_node_req"`
InternetGwID string `json:"internetgw_node_id" yaml:"internetgw_node_id"`
// IsInternetGateway bool `json:"isinternetgateway" yaml:"isinternetgateway"`
// InetNodeReq InetNodeReq `json:"inet_node_req" yaml:"inet_node_req"`
// InternetGwID string `json:"internetgw_node_id" yaml:"internetgw_node_id"`
}
// LegacyNode - legacy struct for node model

View file

@ -253,8 +253,8 @@ func failOverME(w http.ResponseWriter, r *http.Request) {
)
return
}
if (node.EgressDetails.InternetGwID != "" && failOverNode.EgressDetails.IsInternetGateway && node.EgressDetails.InternetGwID != failOverNode.ID.String()) ||
(peerNode.EgressDetails.InternetGwID != "" && failOverNode.EgressDetails.IsInternetGateway && peerNode.EgressDetails.InternetGwID != failOverNode.ID.String()) {
if (node.InternetGwID != "" && failOverNode.IsInternetGateway && node.InternetGwID != failOverNode.ID.String()) ||
(peerNode.InternetGwID != "" && failOverNode.IsInternetGateway && peerNode.InternetGwID != failOverNode.ID.String()) {
logic.ReturnErrorResponse(
w,
r,
@ -265,7 +265,7 @@ func failOverME(w http.ResponseWriter, r *http.Request) {
)
return
}
if node.EgressDetails.IsInternetGateway && peerNode.EgressDetails.InternetGwID == node.ID.String() {
if node.IsInternetGateway && peerNode.InternetGwID == node.ID.String() {
logic.ReturnErrorResponse(
w,
r,
@ -276,7 +276,7 @@ func failOverME(w http.ResponseWriter, r *http.Request) {
)
return
}
if node.EgressDetails.InternetGwID != "" && node.EgressDetails.InternetGwID == peerNode.ID.String() {
if node.InternetGwID != "" && node.InternetGwID == peerNode.ID.String() {
logic.ReturnErrorResponse(
w,
r,
@ -414,8 +414,8 @@ func checkfailOverCtx(w http.ResponseWriter, r *http.Request) {
)
return
}
if (node.EgressDetails.InternetGwID != "" && failOverNode.EgressDetails.IsInternetGateway && node.EgressDetails.InternetGwID != failOverNode.ID.String()) ||
(peerNode.EgressDetails.InternetGwID != "" && failOverNode.EgressDetails.IsInternetGateway && peerNode.EgressDetails.InternetGwID != failOverNode.ID.String()) {
if (node.InternetGwID != "" && failOverNode.IsInternetGateway && node.InternetGwID != failOverNode.ID.String()) ||
(peerNode.InternetGwID != "" && failOverNode.IsInternetGateway && peerNode.InternetGwID != failOverNode.ID.String()) {
logic.ReturnErrorResponse(
w,
r,
@ -426,7 +426,7 @@ func checkfailOverCtx(w http.ResponseWriter, r *http.Request) {
)
return
}
if node.EgressDetails.IsInternetGateway && peerNode.EgressDetails.InternetGwID == node.ID.String() {
if node.IsInternetGateway && peerNode.InternetGwID == node.ID.String() {
logic.ReturnErrorResponse(
w,
r,
@ -437,7 +437,7 @@ func checkfailOverCtx(w http.ResponseWriter, r *http.Request) {
)
return
}
if node.EgressDetails.InternetGwID != "" && node.EgressDetails.InternetGwID == peerNode.ID.String() {
if node.InternetGwID != "" && node.InternetGwID == peerNode.ID.String() {
logic.ReturnErrorResponse(
w,
r,

View file

@ -44,7 +44,7 @@ func createInternetGw(w http.ResponseWriter, r *http.Request) {
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
return
}
if node.EgressDetails.IsInternetGateway {
if node.IsInternetGateway {
logic.ReturnSuccessResponse(w, r, "node is already acting as internet gateway")
return
}
@ -70,7 +70,7 @@ func createInternetGw(w http.ResponseWriter, r *http.Request) {
)
return
}
err = logic.ValidateInetGwReq(node, request, false)
err = proLogic.ValidateInetGwReq(node, request, false)
if err != nil {
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
return
@ -132,7 +132,7 @@ func updateInternetGw(w http.ResponseWriter, r *http.Request) {
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
return
}
if !node.EgressDetails.IsInternetGateway {
if !node.IsInternetGateway {
logic.ReturnErrorResponse(
w,
r,
@ -140,7 +140,7 @@ func updateInternetGw(w http.ResponseWriter, r *http.Request) {
)
return
}
err = logic.ValidateInetGwReq(node, request, true)
err = proLogic.ValidateInetGwReq(node, request, true)
if err != nil {
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
return

View file

@ -1092,7 +1092,7 @@ func getUserRemoteAccessNetworkGateways(w http.ResponseWriter, r *http.Request)
GwID: node.ID.String(),
GWName: host.Name,
Network: node.Network,
IsInternetGateway: node.EgressDetails.IsInternetGateway,
IsInternetGateway: node.IsInternetGateway,
Metadata: node.Metadata,
})
@ -1219,7 +1219,7 @@ func getRemoteAccessGatewayConf(w http.ResponseWriter, r *http.Request) {
Network: node.Network,
GwClient: userConf,
Connected: true,
IsInternetGateway: node.EgressDetails.IsInternetGateway,
IsInternetGateway: node.IsInternetGateway,
GwPeerPublicKey: host.PublicKey.String(),
GwListenPort: logic.GetPeerListenPort(host),
Metadata: node.Metadata,
@ -1311,7 +1311,7 @@ func getUserRemoteAccessGwsV1(w http.ResponseWriter, r *http.Request) {
Network: node.Network,
GwClient: extClient,
Connected: true,
IsInternetGateway: node.EgressDetails.IsInternetGateway,
IsInternetGateway: node.IsInternetGateway,
GwPeerPublicKey: host.PublicKey.String(),
GwListenPort: logic.GetPeerListenPort(host),
Metadata: node.Metadata,
@ -1355,7 +1355,7 @@ func getUserRemoteAccessGwsV1(w http.ResponseWriter, r *http.Request) {
GwID: node.ID.String(),
GWName: host.Name,
Network: node.Network,
IsInternetGateway: node.EgressDetails.IsInternetGateway,
IsInternetGateway: node.IsInternetGateway,
GwPeerPublicKey: host.PublicKey.String(),
GwListenPort: logic.GetPeerListenPort(host),
Metadata: node.Metadata,

View file

@ -113,6 +113,11 @@ func InitPro() {
logic.UpdateMetrics = proLogic.UpdateMetrics
logic.DeleteMetrics = proLogic.DeleteMetrics
logic.GetTrialEndDate = getTrialEndDate
logic.SetDefaultGw = proLogic.SetDefaultGw
logic.SetDefaultGwForRelayedUpdate = proLogic.SetDefaultGwForRelayedUpdate
logic.UnsetInternetGw = proLogic.UnsetInternetGw
logic.SetInternetGw = proLogic.SetInternetGw
logic.GetAllowedIpForInetNodeClient = proLogic.GetAllowedIpForInetNodeClient
mq.UpdateMetrics = proLogic.MQUpdateMetrics
mq.UpdateMetricsFallBack = proLogic.MQUpdateMetricsFallBack
logic.GetFilteredNodesByUserAccess = proLogic.GetFilteredNodesByUserAccess
@ -145,7 +150,6 @@ func InitPro() {
logic.IsUserAllowedToCommunicate = proLogic.IsUserAllowedToCommunicate
logic.DeleteAllNetworkTags = proLogic.DeleteAllNetworkTags
logic.CreateDefaultTags = proLogic.CreateDefaultTags
logic.IsNodeUsingInternetGw = proLogic.IsNodeUsingInternetGw
logic.GetInetClientsFromAclPolicies = proLogic.GetInetClientsFromAclPolicies
logic.IsPeerAllowed = proLogic.IsPeerAllowed
logic.IsAclPolicyValid = proLogic.IsAclPolicyValid

View file

@ -6,24 +6,12 @@ import (
"maps"
"net"
"github.com/google/uuid"
"github.com/gravitl/netmaker/db"
"github.com/gravitl/netmaker/logic"
"github.com/gravitl/netmaker/models"
"github.com/gravitl/netmaker/schema"
)
/*
TODO: EGRESS
1. allow only selection of egress ranges in a policy
ranges should be replaced by egress identifier
2. check logic required for MAC exit node
3.
*/
func GetFwRulesForUserNodesOnGw(node models.Node, nodes []models.Node) (rules []models.FwRule) {
defaultUserPolicy, _ := logic.GetDefaultPolicy(models.NetworkID(node.Network), models.UserPolicy)
userNodes := logic.GetStaticUserNodesByNetwork(models.NetworkID(node.Network))
@ -313,43 +301,6 @@ func checkIfAclTagisValid(a models.Acl, t models.AclPolicyTag, isSrc bool) (err
if err != nil {
return errors.New("invalid egress")
}
if e.IsInetGw {
req := models.InetNodeReq{}
for _, srcI := range a.Src {
if srcI.ID == models.NodeTagID {
nodesMap := GetNodesWithTag(models.TagID(srcI.Value))
for _, node := range nodesMap {
if node.ID != uuid.Nil {
req.InetNodeClientIDs = append(req.InetNodeClientIDs, node.ID.String())
}
}
} else if srcI.ID == models.NodeID {
_, nodeErr := logic.GetNodeByID(srcI.Value)
if nodeErr != nil {
_, staticNodeErr := logic.GetExtClient(srcI.Value, a.NetworkID.String())
if staticNodeErr != nil {
return errors.New("invalid node " + srcI.Value)
}
} else {
req.InetNodeClientIDs = append(req.InetNodeClientIDs, srcI.Value)
}
}
}
if len(e.Nodes) > 0 {
for k := range e.Nodes {
inetNode, err := logic.GetNodeByID(k)
if err != nil {
return errors.New("invalid node " + t.Value)
}
if err = logic.ValidateInetGwReq(inetNode, req, false); err != nil {
return err
}
}
}
}
case models.UserAclID:
if a.RuleType == models.DevicePolicy {
@ -966,8 +917,18 @@ func getEgressUserRulesForNode(targetnode *models.Node,
acls := listUserPolicies(models.NetworkID(targetnode.Network))
var targetNodeTags = make(map[models.TagID]struct{})
targetNodeTags["*"] = struct{}{}
for _, rangeI := range targetnode.EgressDetails.EgressGatewayRanges {
targetNodeTags[models.TagID(rangeI)] = struct{}{}
egs, _ := (&schema.Egress{Network: targetnode.Network}).ListByNetwork(db.WithContext(context.TODO()))
if len(egs) == 0 {
return rules
}
for _, egI := range egs {
if !egI.Status {
continue
}
if _, ok := egI.Nodes[targetnode.ID.String()]; ok {
targetNodeTags[models.TagID(egI.Range)] = struct{}{}
targetNodeTags[models.TagID(egI.ID)] = struct{}{}
}
}
for _, acl := range acls {
if !acl.Enabled {
@ -1051,26 +1012,15 @@ func getEgressUserRulesForNode(targetnode *models.Node,
if err != nil {
continue
}
if e.IsInetGw {
r.Dst = append(r.Dst, net.IPNet{
IP: net.IPv4zero,
Mask: net.CIDRMask(0, 32),
})
r.Dst6 = append(r.Dst6, net.IPNet{
IP: net.IPv6zero,
Mask: net.CIDRMask(0, 128),
})
} else {
ip, cidr, err := net.ParseCIDR(e.Range)
if err == nil {
if ip.To4() != nil {
r.Dst = append(r.Dst, *cidr)
} else {
r.Dst6 = append(r.Dst6, *cidr)
}
ip, cidr, err := net.ParseCIDR(e.Range)
if err == nil {
if ip.To4() != nil {
r.Dst = append(r.Dst, *cidr)
} else {
r.Dst6 = append(r.Dst6, *cidr)
}
}
}
@ -1530,12 +1480,7 @@ func GetEgressRulesForNode(targetnode models.Node) (rules map[string]models.AclR
continue
}
if _, ok := egI.Nodes[targetnode.ID.String()]; ok {
if egI.IsInetGw {
targetNodeTags[models.TagID("0.0.0.0/0")] = struct{}{}
targetNodeTags[models.TagID("::/0")] = struct{}{}
} else {
targetNodeTags[models.TagID(egI.Range)] = struct{}{}
}
targetNodeTags[models.TagID(egI.Range)] = struct{}{}
targetNodeTags[models.TagID(egI.ID)] = struct{}{}
}
}
@ -1597,6 +1542,10 @@ func GetEgressRulesForNode(targetnode models.Node) (rules map[string]models.AclR
if err == nil {
nodes = append(nodes, node)
}
extclient, err := logic.GetExtClient(dst, targetnode.Network)
if err == nil {
nodes = append(nodes, extclient.ConvertToStaticNode())
}
}
for _, node := range nodes {
@ -1631,6 +1580,10 @@ func GetEgressRulesForNode(targetnode models.Node) (rules map[string]models.AclR
if err == nil {
nodes = append(nodes, node)
}
extclient, err := logic.GetExtClient(src, targetnode.Network)
if err == nil {
nodes = append(nodes, extclient.ConvertToStaticNode())
}
}
for _, node := range nodes {
if node.ID == targetnode.ID {
@ -1661,6 +1614,10 @@ func GetEgressRulesForNode(targetnode models.Node) (rules map[string]models.AclR
if err == nil {
nodes = append(nodes, node)
}
extclient, err := logic.GetExtClient(srcID, targetnode.Network)
if err == nil {
nodes = append(nodes, extclient.ConvertToStaticNode())
}
}
for dstID := range dstTags {
if dstID == targetnode.ID.String() {
@ -1670,6 +1627,10 @@ func GetEgressRulesForNode(targetnode models.Node) (rules map[string]models.AclR
if err == nil {
nodes = append(nodes, node)
}
extclient, err := logic.GetExtClient(dstID, targetnode.Network)
if err == nil {
nodes = append(nodes, extclient.ConvertToStaticNode())
}
}
for _, node := range nodes {
if node.ID == targetnode.ID {
@ -1768,62 +1729,3 @@ func GetInetClientsFromAclPolicies(eID string) (inetClientIDs []string) {
}
return
}
func IsNodeUsingInternetGw(node *models.Node, acls []models.Acl) {
host, err := logic.GetHost(node.HostID.String())
if err != nil {
return
}
if host.IsDefault || node.IsFailOver {
return
}
nodeTags := maps.Clone(node.Tags)
if nodeTags == nil {
nodeTags = make(map[models.TagID]struct{})
}
nodeTags[models.TagID(node.ID.String())] = struct{}{}
var isUsing bool
for _, acl := range acls {
if !acl.Enabled {
continue
}
srcVal := logic.ConvAclTagToValueMap(acl.Src)
for _, dstI := range acl.Dst {
if dstI.ID == models.EgressID {
e := schema.Egress{ID: dstI.Value}
err := e.Get(db.WithContext(context.TODO()))
if err != nil || !e.Status {
continue
}
if e.IsInetGw {
if _, ok := srcVal[node.ID.String()]; ok {
for nodeID := range e.Nodes {
if nodeID == node.ID.String() {
continue
}
node.EgressDetails.InternetGwID = nodeID
isUsing = true
return
}
}
for tagID := range nodeTags {
if _, ok := srcVal[tagID.String()]; ok {
for nodeID := range e.Nodes {
if nodeID == node.ID.String() {
continue
}
node.EgressDetails.InternetGwID = nodeID
isUsing = true
return
}
}
}
}
}
}
}
if !isUsing {
node.EgressDetails.InternetGwID = ""
}
}

View file

@ -1,8 +1,19 @@
package logic
import (
"errors"
"fmt"
"net"
"github.com/google/uuid"
"github.com/gravitl/netmaker/logic"
"github.com/gravitl/netmaker/models"
"golang.org/x/exp/slog"
)
var (
IPv4Network = "0.0.0.0/0"
IPv6Network = "::/0"
)
// GetNetworkIngresses - gets the gateways of a network
@ -223,3 +234,157 @@ func GetStaticNodeWithTag(tagID models.TagID) map[string]models.Node {
}
return nMap
}
func ValidateInetGwReq(inetNode models.Node, req models.InetNodeReq, update bool) error {
inetHost, err := logic.GetHost(inetNode.HostID.String())
if err != nil {
return err
}
if inetHost.FirewallInUse == models.FIREWALL_NONE {
return errors.New("iptables or nftables needs to be installed")
}
if inetNode.InternetGwID != "" {
return fmt.Errorf("node %s is using a internet gateway already", inetHost.Name)
}
if inetNode.IsRelayed {
return fmt.Errorf("node %s is being relayed", inetHost.Name)
}
for _, clientNodeID := range req.InetNodeClientIDs {
clientNode, err := logic.GetNodeByID(clientNodeID)
if err != nil {
return err
}
if clientNode.IsFailOver {
return errors.New("failover node cannot be set to use internet gateway")
}
clientHost, err := logic.GetHost(clientNode.HostID.String())
if err != nil {
return err
}
if clientHost.IsDefault {
return errors.New("default host cannot be set to use internet gateway")
}
if clientHost.OS != models.OS_Types.Linux && clientHost.OS != models.OS_Types.Windows {
return errors.New("can only attach linux or windows machine to a internet gateway")
}
if clientNode.IsInternetGateway {
return fmt.Errorf("node %s acting as internet gateway cannot use another internet gateway", clientHost.Name)
}
if update {
if clientNode.InternetGwID != "" && clientNode.InternetGwID != inetNode.ID.String() {
return fmt.Errorf("node %s is already using a internet gateway", clientHost.Name)
}
} else {
if clientNode.InternetGwID != "" {
return fmt.Errorf("node %s is already using a internet gateway", clientHost.Name)
}
}
if clientNode.FailedOverBy != uuid.Nil {
ResetFailedOverPeer(&clientNode)
}
if clientNode.IsRelayed && clientNode.RelayedBy != inetNode.ID.String() {
return fmt.Errorf("node %s is being relayed", clientHost.Name)
}
for _, nodeID := range clientHost.Nodes {
node, err := logic.GetNodeByID(nodeID)
if err != nil {
continue
}
if node.InternetGwID != "" && node.InternetGwID != inetNode.ID.String() {
return errors.New("nodes on same host cannot use different internet gateway")
}
}
}
return nil
}
// SetInternetGw - sets the node as internet gw based on flag bool
func SetInternetGw(node *models.Node, req models.InetNodeReq) {
node.IsInternetGateway = true
node.InetNodeReq = req
for _, clientNodeID := range req.InetNodeClientIDs {
clientNode, err := logic.GetNodeByID(clientNodeID)
if err != nil {
continue
}
clientNode.InternetGwID = node.ID.String()
logic.UpsertNode(&clientNode)
}
}
func UnsetInternetGw(node *models.Node) {
nodes, err := logic.GetNetworkNodes(node.Network)
if err != nil {
slog.Error("failed to get network nodes", "network", node.Network, "error", err)
return
}
for _, clientNode := range nodes {
if node.ID.String() == clientNode.InternetGwID {
clientNode.InternetGwID = ""
logic.UpsertNode(&clientNode)
}
}
node.IsInternetGateway = false
node.InetNodeReq = models.InetNodeReq{}
}
func SetDefaultGwForRelayedUpdate(relayed, relay models.Node, peerUpdate models.HostPeerUpdate) models.HostPeerUpdate {
if relay.InternetGwID != "" {
relayedHost, err := logic.GetHost(relayed.HostID.String())
if err != nil {
return peerUpdate
}
peerUpdate.ChangeDefaultGw = true
peerUpdate.DefaultGwIp = relay.Address.IP
if peerUpdate.DefaultGwIp == nil || relayedHost.EndpointIP == nil {
peerUpdate.DefaultGwIp = relay.Address6.IP
}
}
return peerUpdate
}
func SetDefaultGw(node models.Node, peerUpdate models.HostPeerUpdate) models.HostPeerUpdate {
if node.InternetGwID != "" {
inetNode, err := logic.GetNodeByID(node.InternetGwID)
if err != nil {
return peerUpdate
}
host, err := logic.GetHost(node.HostID.String())
if err != nil {
return peerUpdate
}
peerUpdate.ChangeDefaultGw = true
peerUpdate.DefaultGwIp = inetNode.Address.IP
if peerUpdate.DefaultGwIp == nil || host.EndpointIP == nil {
peerUpdate.DefaultGwIp = inetNode.Address6.IP
}
}
return peerUpdate
}
// GetAllowedIpForInetNodeClient - get inet cidr for node using a inet gw
func GetAllowedIpForInetNodeClient(node, peer *models.Node) []net.IPNet {
var allowedips = []net.IPNet{}
if peer.Address.IP != nil {
_, ipnet, _ := net.ParseCIDR(IPv4Network)
allowedips = append(allowedips, *ipnet)
}
if peer.Address6.IP != nil {
_, ipnet, _ := net.ParseCIDR(IPv6Network)
allowedips = append(allowedips, *ipnet)
}
return allowedips
}

View file

@ -19,11 +19,11 @@ type Egress struct {
Tags datatypes.JSONMap `gorm:"tags" json:"tags"`
Range string `gorm:"range" json:"range"`
Nat bool `gorm:"nat" json:"nat"`
IsInetGw bool `gorm:"is_inet_gw" json:"is_internet_gateway"`
Status bool `gorm:"status" json:"status"`
CreatedBy string `gorm:"created_by" json:"created_by"`
CreatedAt time.Time `gorm:"created_at" json:"created_at"`
UpdatedAt time.Time `gorm:"updated_at" json:"updated_at"`
//IsInetGw bool `gorm:"is_inet_gw" json:"is_internet_gateway"`
Status bool `gorm:"status" json:"status"`
CreatedBy string `gorm:"created_by" json:"created_by"`
CreatedAt time.Time `gorm:"created_at" json:"created_at"`
UpdatedAt time.Time `gorm:"updated_at" json:"updated_at"`
}
func (e *Egress) Table() string {
@ -44,12 +44,6 @@ func (e *Egress) UpdateNatStatus(ctx context.Context) error {
}).Error
}
func (e *Egress) UpdateINetGwStatus(ctx context.Context) error {
return db.FromContext(ctx).Table(e.Table()).Where("id = ?", e.ID).Updates(map[string]any{
"is_inet_gw": e.IsInetGw,
}).Error
}
func (e *Egress) UpdateEgressStatus(ctx context.Context) error {
return db.FromContext(ctx).Table(e.Table()).Where("id = ?", e.ID).Updates(map[string]any{
"status": e.Status,