inet gws into gateways

This commit is contained in:
abhishek9686 2025-06-17 16:55:44 +05:30
parent 9760c0945f
commit 8ee37f5fab
9 changed files with 221 additions and 209 deletions

View file

@ -50,6 +50,14 @@ func createGateway(w http.ResponseWriter, r *http.Request) {
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest")) logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
return return
} }
if req.IsInternetGateway && len(req.InetNodeClientIDs) > 0 {
err = logic.ValidateInetGwReq(node, req.InetNodeReq, false)
if err != nil {
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
return
}
}
node, err = logic.CreateIngressGateway(netid, nodeid, req.IngressRequest) node, err = logic.CreateIngressGateway(netid, nodeid, req.IngressRequest)
if err != nil { if err != nil {
logger.Log(0, r.Header.Get("user"), logger.Log(0, r.Header.Get("user"),
@ -84,6 +92,22 @@ func createGateway(w http.ResponseWriter, r *http.Request) {
} }
} }
if len(req.InetNodeClientIDs) > 0 {
logic.SetInternetGw(&node, req.InetNodeReq)
if servercfg.IsPro {
if _, exists := logic.FailOverExists(node.Network); exists {
go func() {
logic.ResetFailedOverPeer(&node)
mq.PublishPeerUpdate(false)
}()
}
}
if node.IsGw && node.IngressDNS == "" {
node.IngressDNS = "1.1.1.1"
}
logic.UpsertNode(&node)
}
logger.Log( logger.Log(
1, 1,
r.Header.Get("user"), r.Header.Get("user"),

View file

@ -1,4 +1,4 @@
package controllers package controller
import ( import (
"encoding/json" "encoding/json"
@ -10,20 +10,9 @@ import (
"github.com/gravitl/netmaker/logic" "github.com/gravitl/netmaker/logic"
"github.com/gravitl/netmaker/models" "github.com/gravitl/netmaker/models"
"github.com/gravitl/netmaker/mq" "github.com/gravitl/netmaker/mq"
proLogic "github.com/gravitl/netmaker/pro/logic"
"github.com/gravitl/netmaker/servercfg" "github.com/gravitl/netmaker/servercfg"
) )
// InetHandlers - handlers for internet gw
func InetHandlers(r *mux.Router) {
r.HandleFunc("/api/nodes/{network}/{nodeid}/inet_gw", logic.SecurityCheck(true, http.HandlerFunc(createInternetGw))).
Methods(http.MethodPost)
r.HandleFunc("/api/nodes/{network}/{nodeid}/inet_gw", logic.SecurityCheck(true, http.HandlerFunc(updateInternetGw))).
Methods(http.MethodPut)
r.HandleFunc("/api/nodes/{network}/{nodeid}/inet_gw", logic.SecurityCheck(true, http.HandlerFunc(deleteInternetGw))).
Methods(http.MethodDelete)
}
// @Summary Create an internet gateway // @Summary Create an internet gateway
// @Router /api/nodes/{network}/{nodeid}/inet_gw [post] // @Router /api/nodes/{network}/{nodeid}/inet_gw [post]
// @Tags PRO // @Tags PRO
@ -70,16 +59,16 @@ func createInternetGw(w http.ResponseWriter, r *http.Request) {
) )
return return
} }
err = proLogic.ValidateInetGwReq(node, request, false) err = logic.ValidateInetGwReq(node, request, false)
if err != nil { if err != nil {
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest")) logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
return return
} }
logic.SetInternetGw(&node, request) logic.SetInternetGw(&node, request)
if servercfg.IsPro { if servercfg.IsPro {
if _, exists := proLogic.FailOverExists(node.Network); exists { if _, exists := logic.FailOverExists(node.Network); exists {
go func() { go func() {
proLogic.ResetFailedOverPeer(&node) logic.ResetFailedOverPeer(&node)
mq.PublishPeerUpdate(false) mq.PublishPeerUpdate(false)
}() }()
} }
@ -140,7 +129,7 @@ func updateInternetGw(w http.ResponseWriter, r *http.Request) {
) )
return return
} }
err = proLogic.ValidateInetGwReq(node, request, true) err = logic.ValidateInetGwReq(node, request, true)
if err != nil { if err != nil {
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest")) logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
return return

View file

@ -11,6 +11,12 @@ import (
func legacyHandlers(r *mux.Router) { func legacyHandlers(r *mux.Router) {
r.HandleFunc("/api/v1/legacy/nodes", logic.SecurityCheck(true, http.HandlerFunc(wipeLegacyNodes))). r.HandleFunc("/api/v1/legacy/nodes", logic.SecurityCheck(true, http.HandlerFunc(wipeLegacyNodes))).
Methods(http.MethodDelete) Methods(http.MethodDelete)
r.HandleFunc("/api/nodes/{network}/{nodeid}/inet_gw", logic.SecurityCheck(true, http.HandlerFunc(createInternetGw))).
Methods(http.MethodPost)
r.HandleFunc("/api/nodes/{network}/{nodeid}/inet_gw", logic.SecurityCheck(true, http.HandlerFunc(updateInternetGw))).
Methods(http.MethodPut)
r.HandleFunc("/api/nodes/{network}/{nodeid}/inet_gw", logic.SecurityCheck(true, http.HandlerFunc(deleteInternetGw))).
Methods(http.MethodDelete)
} }
// @Summary Delete all legacy nodes from DB. // @Summary Delete all legacy nodes from DB.

View file

@ -657,7 +657,6 @@ func updateNode(w http.ResponseWriter, r *http.Request) {
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal")) logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
return return
} }
ifaceDelta := logic.IfaceDelta(&currentNode, newNode)
aclUpdate := currentNode.DefaultACL != newNode.DefaultACL aclUpdate := currentNode.DefaultACL != newNode.DefaultACL
err = logic.UpdateNode(&currentNode, newNode) err = logic.UpdateNode(&currentNode, newNode)
@ -670,7 +669,27 @@ func updateNode(w http.ResponseWriter, r *http.Request) {
if relayUpdate { if relayUpdate {
logic.UpdateRelayed(&currentNode, newNode) logic.UpdateRelayed(&currentNode, newNode)
} }
if !currentNode.IsInternetGateway && newNode.IsInternetGateway {
err = logic.ValidateInetGwReq(*newNode, newNode.InetNodeReq, false)
if err != nil {
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
return
}
logic.SetInternetGw(newNode, newNode.InetNodeReq)
}
if currentNode.IsInternetGateway && newNode.IsInternetGateway {
err = logic.ValidateInetGwReq(*newNode, newNode.InetNodeReq, true)
if err != nil {
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
return
}
logic.UnsetInternetGw(newNode)
logic.SetInternetGw(newNode, newNode.InetNodeReq)
}
if !newNode.IsInternetGateway {
logic.UnsetInternetGw(newNode)
}
logic.UpsertNode(newNode)
logic.GetNodeStatus(newNode, false) logic.GetNodeStatus(newNode, false)
apiNode := newNode.ConvertToAPINode() apiNode := newNode.ConvertToAPINode()
@ -707,11 +726,6 @@ func updateNode(w http.ResponseWriter, r *http.Request) {
if err := mq.NodeUpdate(newNode); err != nil { if err := mq.NodeUpdate(newNode); err != nil {
slog.Error("error publishing node update to node", "node", newNode.ID, "error", err) slog.Error("error publishing node update to node", "node", newNode.ID, "error", err)
} }
if aclUpdate || relayupdate || ifaceDelta {
if err := mq.PublishPeerUpdate(false); err != nil {
logger.Log(0, "error during node ACL update for node", newNode.ID.String())
}
}
mq.PublishPeerUpdate(false) mq.PublishPeerUpdate(false)
if servercfg.IsDNSMode() { if servercfg.IsDNSMode() {
logic.SetDNS() logic.SetDNS()

View file

@ -3,14 +3,22 @@ package logic
import ( import (
"errors" "errors"
"fmt" "fmt"
"net"
"slices" "slices"
"sort" "sort"
"time" "time"
"github.com/google/uuid"
"github.com/gravitl/netmaker/database" "github.com/gravitl/netmaker/database"
"github.com/gravitl/netmaker/logger" "github.com/gravitl/netmaker/logger"
"github.com/gravitl/netmaker/models" "github.com/gravitl/netmaker/models"
"github.com/gravitl/netmaker/servercfg" "github.com/gravitl/netmaker/servercfg"
"golang.org/x/exp/slog"
)
var (
IPv4Network = "0.0.0.0/0"
IPv6Network = "::/0"
) )
// IsInternetGw - checks if node is acting as internet gw // IsInternetGw - checks if node is acting as internet gw
@ -316,3 +324,157 @@ func IsUserAllowedAccessToExtClient(username string, client models.ExtClient) bo
} }
return true return true
} }
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.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.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 := 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 := GetNodeByID(clientNodeID)
if err != nil {
continue
}
clientNode.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.InternetGwID {
clientNode.InternetGwID = ""
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 := 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 := GetNodeByID(node.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,25 +42,6 @@ var (
CreateFailOver = func(node models.Node) error { CreateFailOver = func(node models.Node) error {
return nil 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 // GetHostPeerInfo - fetches required peer info per network

View file

@ -3,6 +3,7 @@ package models
type CreateGwReq struct { type CreateGwReq struct {
IngressRequest IngressRequest
RelayRequest RelayRequest
InetNodeReq
} }
type DeleteGw struct { type DeleteGw struct {

View file

@ -1468,12 +1468,12 @@ func GetAclRuleForInetGw(targetnode models.Node) (rules map[string]models.AclRul
} }
if targetnode.NetworkRange.IP != nil { if targetnode.NetworkRange.IP != nil {
aclRule.IPList = append(aclRule.IPList, targetnode.NetworkRange) aclRule.IPList = append(aclRule.IPList, targetnode.NetworkRange)
_, allIpv4, _ := net.ParseCIDR(IPv4Network) _, allIpv4, _ := net.ParseCIDR(logic.IPv4Network)
aclRule.Dst = append(aclRule.Dst, *allIpv4) aclRule.Dst = append(aclRule.Dst, *allIpv4)
} }
if targetnode.NetworkRange6.IP != nil { if targetnode.NetworkRange6.IP != nil {
aclRule.IP6List = append(aclRule.IP6List, targetnode.NetworkRange6) aclRule.IP6List = append(aclRule.IP6List, targetnode.NetworkRange6)
_, allIpv6, _ := net.ParseCIDR(IPv6Network) _, allIpv6, _ := net.ParseCIDR(logic.IPv6Network)
aclRule.Dst6 = append(aclRule.Dst6, *allIpv6) aclRule.Dst6 = append(aclRule.Dst6, *allIpv6)
} }
rules[aclRule.ID] = aclRule rules[aclRule.ID] = aclRule

View file

@ -1,19 +1,8 @@
package logic package logic
import ( import (
"errors"
"fmt"
"net"
"github.com/google/uuid"
"github.com/gravitl/netmaker/logic" "github.com/gravitl/netmaker/logic"
"github.com/gravitl/netmaker/models" "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 // GetNetworkIngresses - gets the gateways of a network
@ -234,157 +223,3 @@ func GetStaticNodeWithTag(tagID models.TagID) map[string]models.Node {
} }
return nMap 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
}