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"))
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)
if err != nil {
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(
1,
r.Header.Get("user"),

View file

@ -1,4 +1,4 @@
package controllers
package controller
import (
"encoding/json"
@ -10,20 +10,9 @@ import (
"github.com/gravitl/netmaker/logic"
"github.com/gravitl/netmaker/models"
"github.com/gravitl/netmaker/mq"
proLogic "github.com/gravitl/netmaker/pro/logic"
"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
// @Router /api/nodes/{network}/{nodeid}/inet_gw [post]
// @Tags PRO
@ -70,16 +59,16 @@ func createInternetGw(w http.ResponseWriter, r *http.Request) {
)
return
}
err = proLogic.ValidateInetGwReq(node, request, false)
err = logic.ValidateInetGwReq(node, request, false)
if err != nil {
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
return
}
logic.SetInternetGw(&node, request)
if servercfg.IsPro {
if _, exists := proLogic.FailOverExists(node.Network); exists {
if _, exists := logic.FailOverExists(node.Network); exists {
go func() {
proLogic.ResetFailedOverPeer(&node)
logic.ResetFailedOverPeer(&node)
mq.PublishPeerUpdate(false)
}()
}
@ -140,7 +129,7 @@ func updateInternetGw(w http.ResponseWriter, r *http.Request) {
)
return
}
err = proLogic.ValidateInetGwReq(node, request, true)
err = logic.ValidateInetGwReq(node, request, true)
if err != nil {
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
return

View file

@ -11,6 +11,12 @@ import (
func legacyHandlers(r *mux.Router) {
r.HandleFunc("/api/v1/legacy/nodes", logic.SecurityCheck(true, http.HandlerFunc(wipeLegacyNodes))).
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.

View file

@ -657,7 +657,6 @@ func updateNode(w http.ResponseWriter, r *http.Request) {
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
return
}
ifaceDelta := logic.IfaceDelta(&currentNode, newNode)
aclUpdate := currentNode.DefaultACL != newNode.DefaultACL
err = logic.UpdateNode(&currentNode, newNode)
@ -670,7 +669,27 @@ func updateNode(w http.ResponseWriter, r *http.Request) {
if relayUpdate {
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)
apiNode := newNode.ConvertToAPINode()
@ -707,11 +726,6 @@ func updateNode(w http.ResponseWriter, r *http.Request) {
if err := mq.NodeUpdate(newNode); err != nil {
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)
if servercfg.IsDNSMode() {
logic.SetDNS()

View file

@ -3,14 +3,22 @@ package logic
import (
"errors"
"fmt"
"net"
"slices"
"sort"
"time"
"github.com/google/uuid"
"github.com/gravitl/netmaker/database"
"github.com/gravitl/netmaker/logger"
"github.com/gravitl/netmaker/models"
"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
@ -316,3 +324,157 @@ func IsUserAllowedAccessToExtClient(username string, client models.ExtClient) bo
}
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 {
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

View file

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

View file

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

View file

@ -1,19 +1,8 @@
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
@ -234,157 +223,3 @@ 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
}