2
0
Эх сурвалжийг харах

setup user access middlerware controller

abhishek9686 1 жил өмнө
parent
commit
6eaedc5fb0

+ 1 - 1
Dockerfile

@@ -6,7 +6,7 @@ COPY . .
 
 RUN GOOS=linux CGO_ENABLED=1 go build -ldflags="-s -w " -tags ${tags} .
 # RUN go build -tags=ee . -o netmaker main.go
-FROM alpine:3.19.1
+FROM alpine:3.20.0
 
 # add a c lib
 # set the working directory

+ 1 - 1
Dockerfile-quick

@@ -1,5 +1,5 @@
 #first stage - builder
-FROM alpine:3.19.1
+FROM alpine:3.20.0
 ARG version 
 WORKDIR /app
 COPY ./netmaker /root/netmaker

+ 4 - 1
cli/cmd/host/update.go

@@ -18,6 +18,7 @@ var (
 	name            string
 	listenPort      int
 	mtu             int
+	isStaticPort    bool
 	isStatic        bool
 	isDefault       bool
 	keepAlive       int
@@ -45,6 +46,7 @@ var hostUpdateCmd = &cobra.Command{
 			apiHost.Name = name
 			apiHost.ListenPort = listenPort
 			apiHost.MTU = mtu
+			apiHost.IsStaticPort = isStaticPort
 			apiHost.IsStatic = isStatic
 			apiHost.IsDefault = isDefault
 			apiHost.PersistentKeepalive = keepAlive
@@ -61,7 +63,8 @@ func init() {
 	hostUpdateCmd.Flags().IntVar(&listenPort, "listen_port", 0, "Listen port of the host")
 	hostUpdateCmd.Flags().IntVar(&mtu, "mtu", 0, "Host MTU size")
 	hostUpdateCmd.Flags().IntVar(&keepAlive, "keep_alive", 0, "Interval (seconds) in which packets are sent to keep connections open with peers")
-	hostUpdateCmd.Flags().BoolVar(&isStatic, "static", false, "Make Host Static ?")
+	hostUpdateCmd.Flags().BoolVar(&isStaticPort, "static_port", false, "Make Host Static Port?")
+	hostUpdateCmd.Flags().BoolVar(&isStatic, "static_endpoint", false, "Make Host Static Endpoint?")
 	hostUpdateCmd.Flags().BoolVar(&isDefault, "default", false, "Make Host Default ?")
 	rootCmd.AddCommand(hostUpdateCmd)
 }

+ 3 - 1
controllers/controller.go

@@ -17,7 +17,9 @@ import (
 )
 
 // HttpMiddlewares - middleware functions for REST interactions
-var HttpMiddlewares []mux.MiddlewareFunc
+var HttpMiddlewares = []mux.MiddlewareFunc{
+	userMiddleWare,
+}
 
 // HttpHandlers - handler functions for REST interactions
 var HttpHandlers = []interface{}{

+ 5 - 5
controllers/hosts.go

@@ -304,17 +304,17 @@ func deleteHost(w http.ResponseWriter, r *http.Request) {
 			slog.Error("failed to remove host credentials from EMQX", "id", currHost.ID, "error", err)
 		}
 	}
-	if err = logic.RemoveHost(currHost, forceDelete); err != nil {
-		logger.Log(0, r.Header.Get("user"), "failed to delete a host:", err.Error())
-		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
-		return
-	}
 	if err = mq.HostUpdate(&models.HostUpdate{
 		Action: models.DeleteHost,
 		Host:   *currHost,
 	}); err != nil {
 		logger.Log(0, r.Header.Get("user"), "failed to send delete host update: ", currHost.ID.String(), err.Error())
 	}
+	if err = logic.RemoveHost(currHost, forceDelete); err != nil {
+		logger.Log(0, r.Header.Get("user"), "failed to delete a host:", err.Error())
+		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
+		return
+	}
 
 	apiHostData := currHost.ConvertNMHostToAPI()
 	logger.Log(2, r.Header.Get("user"), "removed host", currHost.Name)

+ 63 - 0
controllers/middleware.go

@@ -0,0 +1,63 @@
+package controller
+
+import (
+	"net/http"
+	"strings"
+
+	"github.com/gorilla/mux"
+	"github.com/gravitl/netmaker/models"
+)
+
+func userMiddleWare(handler http.Handler) http.Handler {
+	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		var params = mux.Vars(r)
+		r.Header.Set("NET_ID", params["network"])
+		if strings.Contains(r.URL.Path, "host") || strings.Contains(r.URL.Path, "node") {
+			r.Header.Set("TARGET_RSRC", models.HostRsrc.String())
+			r.Header.Set("RSRC_TYPE", models.HostRsrc.String())
+		}
+		if strings.Contains(r.URL.Path, "dns") {
+			r.Header.Set("RSRC_TYPE", models.DnsRsrc.String())
+			r.Header.Set("TARGET_RSRC", models.DnsRsrc.String())
+		}
+		if strings.Contains(r.URL.Path, "users") {
+			r.Header.Set("RSRC_TYPE", models.UserRsrc.String())
+			r.Header.Set("TARGET_RSRC", models.UserRsrc.String())
+		}
+		if strings.Contains(r.URL.Path, "ingress") {
+			r.Header.Set("TARGET_RSRC", models.RemoteAccessGwRsrc.String())
+		}
+		if strings.Contains(r.URL.Path, "gateway") {
+			r.Header.Set("TARGET_RSRC", models.EgressGwRsrc.String())
+		}
+		if strings.Contains(r.URL.Path, "networks") {
+			r.Header.Set("TARGET_RSRC", models.NetworkRsrc.String())
+			r.Header.Set("RSRC_TYPE", models.NetworkRsrc.String())
+		}
+		if strings.Contains(r.URL.Path, "extclients") {
+			r.Header.Set("TARGET_RSRC", models.ExtClientsRsrc.String())
+			r.Header.Set("RSRC_TYPE", models.ExtClientsRsrc.String())
+		}
+		if nodeID, ok := params["nodeid"]; ok {
+			r.Header.Set("TARGET_RSRC_ID", nodeID)
+		}
+		if hostID, ok := params["hostid"]; ok {
+			r.Header.Set("TARGET_RSRC_ID", hostID)
+		}
+		if clientID, ok := params["clientid"]; ok {
+			r.Header.Set("TARGET_RSRC_ID", clientID)
+		}
+		if netID, ok := params["networkname"]; ok {
+			r.Header.Set("TARGET_RSRC_ID", netID)
+		}
+		if userID, ok := params["username"]; ok {
+			r.Header.Set("TARGET_RSRC_ID", userID)
+		}
+		if r.Header.Get("TARGET_RSRC_ID") == "" {
+			r.Header.Set("IS_GLOBAL_ACCESS", "yes")
+		}
+		// pro
+
+		handler.ServeHTTP(w, r)
+	})
+}

+ 1 - 0
controllers/migrate.go

@@ -150,6 +150,7 @@ func convertLegacyHostNode(legacy models.LegacyNode) (models.Host, models.Node)
 	host.EndpointIP = net.ParseIP(legacy.Endpoint)
 	host.IsDocker = models.ParseBool(legacy.IsDocker)
 	host.IsK8S = models.ParseBool(legacy.IsK8S)
+	host.IsStaticPort = models.ParseBool(legacy.IsStatic)
 	host.IsStatic = models.ParseBool(legacy.IsStatic)
 	host.PersistentKeepalive = time.Duration(legacy.PersistentKeepalive) * time.Second
 	if host.PersistentKeepalive == 0 {

+ 1 - 1
go.mod

@@ -57,7 +57,7 @@ require (
 	github.com/felixge/httpsnoop v1.0.3 // indirect
 	github.com/go-playground/locales v0.14.1 // indirect
 	github.com/go-playground/universal-translator v0.18.1 // indirect
-	github.com/hashicorp/go-version v1.6.0
+	github.com/hashicorp/go-version v1.7.0
 	github.com/leodido/go-urn v1.4.0 // indirect
 	github.com/mattn/go-runewidth v0.0.13 // indirect
 	github.com/pmezard/go-difflib v1.0.0 // indirect

+ 2 - 2
go.sum

@@ -41,8 +41,8 @@ github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/
 github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY=
 github.com/guumaster/tablewriter v0.0.10 h1:A0HD94yMdt4usgxBjoEceNeE0XMJ027euoHAzsPqBQs=
 github.com/guumaster/tablewriter v0.0.10/go.mod h1:p4FRFhyfo0UD9ZLmMRbbJooTUsxo6b80qZTERVDWrH8=
-github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek=
-github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
+github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY=
+github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
 github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
 github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
 github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=

+ 5 - 0
k8s/client/netclient-daemonset.yaml

@@ -23,6 +23,8 @@ spec:
         volumeMounts:
         - mountPath: /etc/netclient
           name: etc-netclient
+        - mountPath: /var/log
+          name: log-netclient
         securityContext:
           privileged: true
       volumes:
@@ -32,3 +34,6 @@ spec:
           path: /etc/netclient
           type: DirectoryOrCreate
         name: etc-netclient
+      - emptyDir:
+          medium: Memory
+        name: log-netclient

+ 5 - 0
k8s/client/netclient.yaml

@@ -35,6 +35,8 @@ spec:
         volumeMounts:
         - mountPath: /etc/netclient
           name: etc-netclient
+        - mountPath: /var/log
+          name: log-netclient
         securityContext:
           privileged: true
       volumes:
@@ -42,3 +44,6 @@ spec:
           path: /etc/netclient
           type: DirectoryOrCreate
         name: etc-netclient
+      - emptyDir:
+          medium: Memory
+        name: log-netclient

+ 12 - 17
logic/extpeers.go

@@ -376,7 +376,7 @@ func ToggleExtClientConnectivity(client *models.ExtClient, enable bool) (models.
 	return newClient, nil
 }
 
-func getExtPeers(node, peer *models.Node) ([]wgtypes.PeerConfig, []models.IDandAddr, []models.EgressNetworkRoutes, error) {
+func GetExtPeers(node, peer *models.Node) ([]wgtypes.PeerConfig, []models.IDandAddr, []models.EgressNetworkRoutes, error) {
 	var peers []wgtypes.PeerConfig
 	var idsAndAddr []models.IDandAddr
 	var egressRoutes []models.EgressNetworkRoutes
@@ -431,7 +431,7 @@ func getExtPeers(node, peer *models.Node) ([]wgtypes.PeerConfig, []models.IDandA
 				allowedips = append(allowedips, *cidr)
 			}
 		}
-		egressRoutes = append(egressRoutes, getExtPeerEgressRoute(extPeer)...)
+		egressRoutes = append(egressRoutes, getExtPeerEgressRoute(*node, extPeer)...)
 		primaryAddr := extPeer.Address
 		if primaryAddr == "" {
 			primaryAddr = extPeer.Address6
@@ -453,23 +453,18 @@ func getExtPeers(node, peer *models.Node) ([]wgtypes.PeerConfig, []models.IDandA
 
 }
 
-func getExtPeerEgressRoute(extPeer models.ExtClient) (egressRoutes []models.EgressNetworkRoutes) {
-	if extPeer.Address != "" {
-		egressRoutes = append(egressRoutes, models.EgressNetworkRoutes{
-			NodeAddr:     extPeer.AddressIPNet4(),
-			EgressRanges: extPeer.ExtraAllowedIPs,
-		})
-	}
-	if extPeer.Address6 != "" {
-		egressRoutes = append(egressRoutes, models.EgressNetworkRoutes{
-			NodeAddr:     extPeer.AddressIPNet6(),
-			EgressRanges: extPeer.ExtraAllowedIPs,
-		})
-	}
+func getExtPeerEgressRoute(node models.Node, extPeer models.ExtClient) (egressRoutes []models.EgressNetworkRoutes) {
+	egressRoutes = append(egressRoutes, models.EgressNetworkRoutes{
+		EgressGwAddr:  extPeer.AddressIPNet4(),
+		EgressGwAddr6: extPeer.AddressIPNet6(),
+		NodeAddr:      node.Address,
+		NodeAddr6:     node.Address6,
+		EgressRanges:  extPeer.ExtraAllowedIPs,
+	})
 	return
 }
 
-func getExtpeersExtraRoutes(network string) (egressRoutes []models.EgressNetworkRoutes) {
+func getExtpeersExtraRoutes(node models.Node, network string) (egressRoutes []models.EgressNetworkRoutes) {
 	extPeers, err := GetNetworkExtClients(network)
 	if err != nil {
 		return
@@ -478,7 +473,7 @@ func getExtpeersExtraRoutes(network string) (egressRoutes []models.EgressNetwork
 		if len(extPeer.ExtraAllowedIPs) == 0 {
 			continue
 		}
-		egressRoutes = append(egressRoutes, getExtPeerEgressRoute(extPeer)...)
+		egressRoutes = append(egressRoutes, getExtPeerEgressRoute(node, extPeer)...)
 	}
 	return
 }

+ 1 - 0
logic/gateway.go

@@ -170,6 +170,7 @@ func CreateIngressGateway(netid string, nodeid string, ingress models.IngressReq
 		}
 	}
 	node.SetLastModified()
+	node.Metadata = ingress.Metadata
 	if node.Metadata == "" {
 		node.Metadata = "This host can be used for remote access"
 	}

+ 6 - 12
logic/hosts.go

@@ -266,6 +266,7 @@ func UpdateHostFromClient(newHost, currHost *models.Host) (sendPeerUpdate bool)
 	currHost.Debug = newHost.Debug
 	currHost.Verbosity = newHost.Verbosity
 	currHost.Version = newHost.Version
+	currHost.IsStaticPort = newHost.IsStaticPort
 	currHost.IsStatic = newHost.IsStatic
 	currHost.MTU = newHost.MTU
 	currHost.Name = newHost.Name
@@ -396,20 +397,13 @@ func DissasociateNodeFromHost(n *models.Node, h *models.Host) error {
 	if len(h.Nodes) == 0 {
 		return fmt.Errorf("no nodes present in given host")
 	}
-	index := -1
+	nList := []string{}
 	for i := range h.Nodes {
-		if h.Nodes[i] == n.ID.String() {
-			index = i
-			break
+		if h.Nodes[i] != n.ID.String() {
+			nList = append(nList, h.Nodes[i])
 		}
 	}
-	if index < 0 {
-		if len(h.Nodes) == 0 {
-			return fmt.Errorf("node %s, not found in host, %s", n.ID.String(), h.ID.String())
-		}
-	} else {
-		h.Nodes = RemoveStringSlice(h.Nodes, index)
-	}
+	h.Nodes = nList
 	go func() {
 		if servercfg.IsPro {
 			if clients, err := GetNetworkExtClients(n.Network); err != nil {
@@ -434,7 +428,7 @@ func DisassociateAllNodesFromHost(hostID string) error {
 	for _, nodeID := range host.Nodes {
 		node, err := GetNodeByID(nodeID)
 		if err != nil {
-			logger.Log(0, "failed to get host node", err.Error())
+			logger.Log(0, "failed to get host node, node id:", nodeID, err.Error())
 			continue
 		}
 		if err := DeleteNode(&node, true); err != nil {

+ 11 - 9
logic/peers.go

@@ -181,7 +181,7 @@ func GetPeerUpdateForHost(network string, host *models.Host, allNodes []models.N
 				})
 			}
 			if peer.IsIngressGateway {
-				hostPeerUpdate.EgressRoutes = append(hostPeerUpdate.EgressRoutes, getExtpeersExtraRoutes(peer.Network)...)
+				hostPeerUpdate.EgressRoutes = append(hostPeerUpdate.EgressRoutes, getExtpeersExtraRoutes(node, peer.Network)...)
 			}
 			_, isFailOverPeer := node.FailOverPeers[peer.ID.String()]
 			if servercfg.IsPro {
@@ -249,9 +249,10 @@ func GetPeerUpdateForHost(network string, host *models.Host, allNodes []models.N
 				hostPeerUpdate.Peers = append(hostPeerUpdate.Peers, peerConfig)
 				peerIndexMap[peerHost.PublicKey.String()] = len(hostPeerUpdate.Peers) - 1
 				hostPeerUpdate.HostNetworkInfo[peerHost.PublicKey.String()] = models.HostNetworkInfo{
-					Interfaces: peerHost.Interfaces,
-					ListenPort: peerHost.ListenPort,
-					IsStatic:   peerHost.IsStatic,
+					Interfaces:   peerHost.Interfaces,
+					ListenPort:   peerHost.ListenPort,
+					IsStaticPort: peerHost.IsStaticPort,
+					IsStatic:     peerHost.IsStatic,
 				}
 				nodePeer = peerConfig
 			} else {
@@ -260,9 +261,10 @@ func GetPeerUpdateForHost(network string, host *models.Host, allNodes []models.N
 				hostPeerUpdate.Peers[peerIndexMap[peerHost.PublicKey.String()]].AllowedIPs = peerAllowedIPs
 				hostPeerUpdate.Peers[peerIndexMap[peerHost.PublicKey.String()]].Remove = false
 				hostPeerUpdate.HostNetworkInfo[peerHost.PublicKey.String()] = models.HostNetworkInfo{
-					Interfaces: peerHost.Interfaces,
-					ListenPort: peerHost.ListenPort,
-					IsStatic:   peerHost.IsStatic,
+					Interfaces:   peerHost.Interfaces,
+					ListenPort:   peerHost.ListenPort,
+					IsStaticPort: peerHost.IsStaticPort,
+					IsStatic:     peerHost.IsStatic,
 				}
 				nodePeer = hostPeerUpdate.Peers[peerIndexMap[peerHost.PublicKey.String()]]
 			}
@@ -283,7 +285,7 @@ func GetPeerUpdateForHost(network string, host *models.Host, allNodes []models.N
 		var extPeerIDAndAddrs []models.IDandAddr
 		var egressRoutes []models.EgressNetworkRoutes
 		if node.IsIngressGateway {
-			extPeers, extPeerIDAndAddrs, egressRoutes, err = getExtPeers(&node, &node)
+			extPeers, extPeerIDAndAddrs, egressRoutes, err = GetExtPeers(&node, &node)
 			if err == nil {
 				hostPeerUpdate.EgressRoutes = append(hostPeerUpdate.EgressRoutes, egressRoutes...)
 				hostPeerUpdate.Peers = append(hostPeerUpdate.Peers, extPeers...)
@@ -415,7 +417,7 @@ func GetAllowedIPs(node, peer *models.Node, metrics *models.Metrics) []net.IPNet
 
 	// handle ingress gateway peers
 	if peer.IsIngressGateway {
-		extPeers, _, _, err := getExtPeers(peer, node)
+		extPeers, _, _, err := GetExtPeers(peer, node)
 		if err != nil {
 			logger.Log(2, "could not retrieve ext peers for ", peer.ID.String(), err.Error())
 		}

+ 3 - 0
models/api_host.go

@@ -15,6 +15,7 @@ type ApiHost struct {
 	Name                string     `json:"name"`
 	OS                  string     `json:"os"`
 	Debug               bool       `json:"debug"`
+	IsStaticPort        bool       `json:"isstaticport"`
 	IsStatic            bool       `json:"isstatic"`
 	ListenPort          int        `json:"listenport"`
 	WgPublicListenPort  int        `json:"wg_public_listen_port" yaml:"wg_public_listen_port"`
@@ -61,6 +62,7 @@ func (h *Host) ConvertNMHostToAPI() *ApiHost {
 		}
 	}
 	a.DefaultInterface = h.DefaultInterface
+	a.IsStaticPort = h.IsStaticPort
 	a.IsStatic = h.IsStatic
 	a.ListenPort = h.ListenPort
 	a.MTU = h.MTU
@@ -104,6 +106,7 @@ func (a *ApiHost) ConvertAPIHostToNMHost(currentHost *Host) *Host {
 	h.DefaultInterface = currentHost.DefaultInterface
 	h.IsDocker = currentHost.IsDocker
 	h.IsK8S = currentHost.IsK8S
+	h.IsStaticPort = a.IsStaticPort
 	h.IsStatic = a.IsStatic
 	h.ListenPort = a.ListenPort
 	h.MTU = a.MTU

+ 2 - 1
models/host.go

@@ -66,7 +66,8 @@ type Host struct {
 	EndpointIPv6        net.IP           `json:"endpointipv6"            yaml:"endpointipv6"`
 	IsDocker            bool             `json:"isdocker"                yaml:"isdocker"`
 	IsK8S               bool             `json:"isk8s"                   yaml:"isk8s"`
-	IsStatic            bool             `json:"isstatic"                yaml:"isstatic"`
+	IsStaticPort        bool             `json:"isstaticport"            yaml:"isstaticport"`
+	IsStatic            bool             `json:"isstatic"        yaml:"isstatic"`
 	IsDefault           bool             `json:"isdefault"               yaml:"isdefault"`
 	NatType             string           `json:"nat_type,omitempty"      yaml:"nat_type,omitempty"`
 	TurnEndpoint        *netip.AddrPort  `json:"turn_endpoint,omitempty" yaml:"turn_endpoint,omitempty"`

+ 4 - 3
models/metrics.go

@@ -42,9 +42,10 @@ type HostInfoMap map[string]HostNetworkInfo
 
 // HostNetworkInfo - holds info related to host networking (used for client side peer calculations)
 type HostNetworkInfo struct {
-	Interfaces []Iface `json:"interfaces" yaml:"interfaces"`
-	ListenPort int     `json:"listen_port" yaml:"listen_port"`
-	IsStatic   bool    `json:"is_static"`
+	Interfaces   []Iface `json:"interfaces" yaml:"interfaces"`
+	ListenPort   int     `json:"listen_port" yaml:"listen_port"`
+	IsStaticPort bool    `json:"is_static_port"`
+	IsStatic     bool    `json:"is_static"`
 }
 
 // PeerMap - peer map for ids and addresses in metrics

+ 2 - 0
models/structs.go

@@ -42,6 +42,7 @@ type UserRemoteGws struct {
 	GwListenPort      int       `json:"gw_listen_port"`
 	Metadata          string    `json:"metadata"`
 	AllowedEndpoints  []string  `json:"allowed_endpoints"`
+	NetworkAddresses  []string  `json:"network_addresses"`
 }
 
 // UserRemoteGwsReq - struct to hold user remote acccess gws req
@@ -164,6 +165,7 @@ type HostRelayRequest struct {
 type IngressRequest struct {
 	ExtclientDNS      string `json:"extclientdns"`
 	IsInternetGateway bool   `json:"is_internet_gw"`
+	Metadata          string `json:"metadata"`
 }
 
 // InetNodeReq - exit node request struct

+ 10 - 0
models/user_mgmt.go

@@ -12,27 +12,37 @@ type RsrcID string
 type UserRole string
 type UserGroupID string
 
+func (r RsrcType) String() string {
+	return string(r)
+}
+
 const (
 	HostRsrc           RsrcType = "hosts"
 	RelayRsrc          RsrcType = "relays"
 	RemoteAccessGwRsrc RsrcType = "remote_access_gw"
+	ExtClientsRsrc     RsrcType = "extclients"
 	InetGwRsrc         RsrcType = "inet_gw"
 	EgressGwRsrc       RsrcType = "egress"
 	NetworkRsrc        RsrcType = "networks"
 	EnrollmentKeysRsrc RsrcType = "enrollment_key"
 	UserRsrc           RsrcType = "users"
 	AclRsrc            RsrcType = "acl"
+	DnsRsrc            RsrcType = "dns"
+	FailOverRsrc       RsrcType = "fail_over"
 )
 
 const (
 	AllHostRsrcID           RsrcID = "all_host"
 	AllRelayRsrcID          RsrcID = "all_relay"
 	AllRemoteAccessGwRsrcID RsrcID = "all_remote_access_gw"
+	AllExtClientsRsrc       RsrcID = "all_extclients"
 	AllInetGwRsrcID         RsrcID = "all_inet_gw"
 	AllEgressGwRsrcID       RsrcID = "all_egress"
 	AllNetworkRsrcID        RsrcID = "all_network"
 	AllEnrollmentKeysRsrcID RsrcID = "all_enrollment_key"
 	AllUserRsrcID           RsrcID = "all_user"
+	AllDnsRsrcID            RsrcID = "all_dns"
+	AllFailOverRsrc         RsrcID = "all_fail_over"
 )
 
 // Pre-Defined User Roles

+ 1 - 14
mq/handlers.go

@@ -201,20 +201,7 @@ func signalPeer(signal models.Signal) {
 		slog.Error("failed to signal, peer host not found", "error", err)
 		return
 	}
-	peerNode, err := logic.GetNodeByID(signal.ToNodeID)
-	if err != nil {
-		slog.Error("failed to signal, node not found", "error", err)
-		return
-	}
-	node, err := logic.GetNodeByID(signal.FromNodeID)
-	if err != nil {
-		slog.Error("failed to signal, peer node not found", "error", err)
-		return
-	}
-	if peerNode.IsIngressGateway || node.IsIngressGateway || peerNode.IsInternetGateway || node.IsInternetGateway {
-		signal.Action = ""
-		return
-	}
+
 	err = HostUpdate(&models.HostUpdate{
 		Action: models.SignalHost,
 		Host:   *peerHost,

+ 15 - 4
pro/auth/headless_callback.go

@@ -6,6 +6,7 @@ import (
 	"net/http"
 
 	"github.com/gravitl/netmaker/auth"
+	"github.com/gravitl/netmaker/database"
 	"github.com/gravitl/netmaker/logger"
 	"github.com/gravitl/netmaker/logic"
 	"github.com/gravitl/netmaker/logic/pro/netcache"
@@ -58,10 +59,20 @@ func HandleHeadlessSSOCallback(w http.ResponseWriter, r *http.Request) {
 	}
 	user, err := logic.GetUser(userClaims.getUserName())
 	if err != nil {
-		response := returnErrTemplate("", "user not found", state, reqKeyIf)
-		w.WriteHeader(http.StatusForbidden)
-		w.Write(response)
-		return
+		if database.IsEmptyRecord(err) { // user must not exist, so try to make one
+			err = logic.InsertPendingUser(&models.User{
+				UserName: userClaims.getUserName(),
+			})
+			if err != nil {
+				handleSomethingWentWrong(w)
+				return
+			}
+			handleFirstTimeOauthUserSignUp(w)
+			return
+		} else {
+			handleSomethingWentWrong(w)
+			return
+		}
 	}
 	newPass, fetchErr := auth.FetchPassValue("")
 	if fetchErr != nil {

+ 16 - 4
pro/controllers/failover.go

@@ -159,12 +159,24 @@ func failOverME(w http.ResponseWriter, r *http.Request) {
 		logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("peer not found"), "badrequest"))
 		return
 	}
-	if node.IsRelayed || node.IsFailOver {
-		logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("node is relayed or acting as failover"), "badrequest"))
+	if node.IsFailOver {
+		logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("node is acting as failover"), "badrequest"))
 		return
 	}
-	if peerNode.IsRelayed || peerNode.IsFailOver {
-		logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("peer node is relayed or acting as failover"), "badrequest"))
+	if node.IsRelayed && node.RelayedBy == peerNode.ID.String() {
+		logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("node is relayed by peer node"), "badrequest"))
+		return
+	}
+	if node.IsRelay && peerNode.RelayedBy == node.ID.String() {
+		logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("node acting as relay for the peer node"), "badrequest"))
+		return
+	}
+	if node.IsInternetGateway && peerNode.InternetGwID == node.ID.String() {
+		logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("node acting as internet gw for the peer node"), "badrequest"))
+		return
+	}
+	if node.InternetGwID != "" && node.InternetGwID == peerNode.ID.String() {
+		logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("node using a internet gw by the peer node"), "badrequest"))
 		return
 	}
 

+ 16 - 0
pro/controllers/users.go

@@ -214,6 +214,10 @@ func getUserRemoteAccessGws(w http.ResponseWriter, r *http.Request) {
 			if err != nil {
 				continue
 			}
+			network, err := logic.GetNetwork(node.Network)
+			if err != nil {
+				slog.Error("failed to get node network", "error", err)
+			}
 
 			if _, ok := user.RemoteGwIDs[node.ID.String()]; (!user.IsAdmin && !user.IsSuperAdmin) && ok {
 				gws := userGws[node.Network]
@@ -229,6 +233,7 @@ func getUserRemoteAccessGws(w http.ResponseWriter, r *http.Request) {
 					GwListenPort:      logic.GetPeerListenPort(host),
 					Metadata:          node.Metadata,
 					AllowedEndpoints:  getAllowedRagEndpoints(&node, host),
+					NetworkAddresses:  []string{network.AddressRange, network.AddressRange6},
 				})
 				userGws[node.Network] = gws
 				delete(user.RemoteGwIDs, node.ID.String())
@@ -246,6 +251,7 @@ func getUserRemoteAccessGws(w http.ResponseWriter, r *http.Request) {
 					GwListenPort:      logic.GetPeerListenPort(host),
 					Metadata:          node.Metadata,
 					AllowedEndpoints:  getAllowedRagEndpoints(&node, host),
+					NetworkAddresses:  []string{network.AddressRange, network.AddressRange6},
 				})
 				userGws[node.Network] = gws
 				processedAdminNodeIds[node.ID.String()] = struct{}{}
@@ -270,6 +276,10 @@ func getUserRemoteAccessGws(w http.ResponseWriter, r *http.Request) {
 			if err != nil {
 				continue
 			}
+			network, err := logic.GetNetwork(node.Network)
+			if err != nil {
+				slog.Error("failed to get node network", "error", err)
+			}
 			gws := userGws[node.Network]
 
 			gws = append(gws, models.UserRemoteGws{
@@ -281,6 +291,7 @@ func getUserRemoteAccessGws(w http.ResponseWriter, r *http.Request) {
 				GwListenPort:      logic.GetPeerListenPort(host),
 				Metadata:          node.Metadata,
 				AllowedEndpoints:  getAllowedRagEndpoints(&node, host),
+				NetworkAddresses:  []string{network.AddressRange, network.AddressRange6},
 			})
 			userGws[node.Network] = gws
 		}
@@ -299,6 +310,10 @@ func getUserRemoteAccessGws(w http.ResponseWriter, r *http.Request) {
 					slog.Error("failed to fetch host", "error", err)
 					continue
 				}
+				network, err := logic.GetNetwork(node.Network)
+				if err != nil {
+					slog.Error("failed to get node network", "error", err)
+				}
 				gws := userGws[node.Network]
 
 				gws = append(gws, models.UserRemoteGws{
@@ -310,6 +325,7 @@ func getUserRemoteAccessGws(w http.ResponseWriter, r *http.Request) {
 					GwListenPort:      logic.GetPeerListenPort(host),
 					Metadata:          node.Metadata,
 					AllowedEndpoints:  getAllowedRagEndpoints(&node, host),
+					NetworkAddresses:  []string{network.AddressRange, network.AddressRange6},
 				})
 				userGws[node.Network] = gws
 			}

+ 36 - 6
pro/logic/failover.go

@@ -5,15 +5,14 @@ import (
 	"net"
 
 	"github.com/google/uuid"
+	"github.com/gravitl/netmaker/logger"
 	"github.com/gravitl/netmaker/logic"
 	"github.com/gravitl/netmaker/models"
 	"golang.org/x/exp/slog"
 )
 
 func SetFailOverCtx(failOverNode, victimNode, peerNode models.Node) error {
-	if victimNode.IsIngressGateway || peerNode.IsIngressGateway || victimNode.IsInternetGateway || peerNode.IsInternetGateway {
-		return nil
-	}
+
 	if peerNode.FailOverPeers == nil {
 		peerNode.FailOverPeers = make(map[string]struct{})
 	}
@@ -125,7 +124,38 @@ func GetFailOverPeerIps(peer, node *models.Node) []net.IPNet {
 			if failOverpeer.IsEgressGateway {
 				allowedips = append(allowedips, logic.GetEgressIPs(&failOverpeer)...)
 			}
-
+			if failOverpeer.IsRelay {
+				for _, id := range failOverpeer.RelayedNodes {
+					rNode, _ := logic.GetNodeByID(id)
+					if rNode.Address.IP != nil {
+						allowed := net.IPNet{
+							IP:   rNode.Address.IP,
+							Mask: net.CIDRMask(32, 32),
+						}
+						allowedips = append(allowedips, allowed)
+					}
+					if rNode.Address6.IP != nil {
+						allowed := net.IPNet{
+							IP:   rNode.Address6.IP,
+							Mask: net.CIDRMask(128, 128),
+						}
+						allowedips = append(allowedips, allowed)
+					}
+					if rNode.IsEgressGateway {
+						allowedips = append(allowedips, logic.GetEgressIPs(&rNode)...)
+					}
+				}
+			}
+			// handle ingress gateway peers
+			if failOverpeer.IsIngressGateway {
+				extPeers, _, _, err := logic.GetExtPeers(&failOverpeer, node)
+				if err != nil {
+					logger.Log(2, "could not retrieve ext peers for ", peer.ID.String(), err.Error())
+				}
+				for _, extPeer := range extPeers {
+					allowedips = append(allowedips, extPeer.AllowedIPs...)
+				}
+			}
 		}
 	}
 	return allowedips
@@ -140,10 +170,10 @@ func CreateFailOver(node models.Node) error {
 		return err
 	}
 	if host.OS != models.OS_Types.Linux {
-		return err
+		return errors.New("only linux nodes are allowed to be set as failover")
 	}
 	if node.IsRelayed {
-		return err
+		return errors.New("relayed node cannot be set as failover")
 	}
 	node.IsFailOver = true
 	err = logic.UpsertNode(&node)

+ 16 - 3
pro/logic/nodes.go

@@ -5,6 +5,7 @@ import (
 	"fmt"
 	"net"
 
+	"github.com/google/uuid"
 	"github.com/gravitl/netmaker/logic"
 	"github.com/gravitl/netmaker/models"
 	"golang.org/x/exp/slog"
@@ -29,6 +30,7 @@ func ValidateInetGwReq(inetNode models.Node, req models.InetNodeReq, update bool
 	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 {
@@ -53,6 +55,9 @@ func ValidateInetGwReq(inetNode models.Node, req models.InetNodeReq, update bool
 				return fmt.Errorf("node %s is already using a internet gateway", clientHost.Name)
 			}
 		}
+		if clientNode.FailedOverBy != uuid.Nil {
+			ResetFailedOverPeer(&clientNode)
+		}
 
 		if clientNode.IsRelayed {
 			return fmt.Errorf("node %s is being relayed", clientHost.Name)
@@ -107,9 +112,13 @@ func UnsetInternetGw(node *models.Node) {
 
 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 {
+		if peerUpdate.DefaultGwIp == nil || relayedHost.EndpointIP == nil {
 			peerUpdate.DefaultGwIp = relay.Address6.IP
 		}
 
@@ -124,9 +133,14 @@ func SetDefaultGw(node models.Node, peerUpdate models.HostPeerUpdate) models.Hos
 		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 {
+		if peerUpdate.DefaultGwIp == nil || host.EndpointIP == nil {
 			peerUpdate.DefaultGwIp = inetNode.Address6.IP
 		}
 	}
@@ -155,7 +169,6 @@ func GetAllowedIpForInetNodeClient(node, peer *models.Node) []net.IPNet {
 	if peer.Address.IP != nil {
 		_, ipnet, _ := net.ParseCIDR(IPv4Network)
 		allowedips = append(allowedips, *ipnet)
-		return allowedips
 	}
 
 	if peer.Address6.IP != nil {

+ 7 - 0
pro/logic/relays.go

@@ -5,6 +5,7 @@ import (
 	"fmt"
 	"net"
 
+	"github.com/google/uuid"
 	"github.com/gravitl/netmaker/logger"
 	"github.com/gravitl/netmaker/logic"
 	"github.com/gravitl/netmaker/logic/acls/nodeacls"
@@ -122,6 +123,12 @@ func ValidateRelay(relay models.RelayRequest, update bool) error {
 		if relayedNode.IsInternetGateway {
 			return errors.New("cannot relay an internet gateway (" + relayedNodeID + ")")
 		}
+		if relayedNode.IsFailOver {
+			return errors.New("cannot relay a failOver (" + relayedNodeID + ")")
+		}
+		if relayedNode.FailedOverBy != uuid.Nil {
+			ResetFailedOverPeer(&relayedNode)
+		}
 	}
 	return err
 }