Ver código fonte

rebase with develop

abhishek9686 1 ano atrás
pai
commit
b20ad3d551

+ 9 - 0
auth/azure-ad.go

@@ -66,6 +66,15 @@ func handleAzureCallback(w http.ResponseWriter, r *http.Request) {
 			return
 		}
 	}
+	user, err := logic.GetUser(content.Email)
+	if err != nil {
+		handleOauthUserNotFound(w)
+		return
+	}
+	if !(user.IsSuperAdmin || user.IsAdmin) {
+		handleOauthUserNotAllowed(w)
+		return
+	}
 	var newPass, fetchErr = fetchPassValue("")
 	if fetchErr != nil {
 		return

+ 25 - 0
auth/error.go

@@ -10,6 +10,31 @@ const oauthNotConfigured = `<!DOCTYPE html><html>
 </body>
 </html>`
 
+const userNotAllowed = `<!DOCTYPE html><html>
+<body>
+<h3>Only Admins are allowed to access Dashboard.</h3>
+<p>Non-Admins can access the netmaker networks using <a href="https://docs.netmaker.io/pro/rac.html" target="_blank" rel="noopener">RemoteAccessClient.</a></p>
+</body>
+</html>
+`
+const userNotFound = `<!DOCTYPE html><html>
+<body>
+<h3>User Not Found.</h3>
+</body>
+</html>`
+
+func handleOauthUserNotFound(response http.ResponseWriter) {
+	response.Header().Set("Content-Type", "text/html; charset=utf-8")
+	response.WriteHeader(http.StatusNotFound)
+	response.Write([]byte(userNotFound))
+}
+
+func handleOauthUserNotAllowed(response http.ResponseWriter) {
+	response.Header().Set("Content-Type", "text/html; charset=utf-8")
+	response.WriteHeader(http.StatusForbidden)
+	response.Write([]byte(userNotAllowed))
+}
+
 // handleOauthNotConfigured - returns an appropriate html page when oauth is not configured on netmaker server but an oauth login was attempted
 func handleOauthNotConfigured(response http.ResponseWriter) {
 	response.Header().Set("Content-Type", "text/html; charset=utf-8")

+ 9 - 0
auth/github.go

@@ -66,6 +66,15 @@ func handleGithubCallback(w http.ResponseWriter, r *http.Request) {
 			return
 		}
 	}
+	user, err := logic.GetUser(content.Email)
+	if err != nil {
+		handleOauthUserNotFound(w)
+		return
+	}
+	if !(user.IsSuperAdmin || user.IsAdmin) {
+		handleOauthUserNotAllowed(w)
+		return
+	}
 	var newPass, fetchErr = fetchPassValue("")
 	if fetchErr != nil {
 		return

+ 9 - 0
auth/google.go

@@ -68,6 +68,15 @@ func handleGoogleCallback(w http.ResponseWriter, r *http.Request) {
 			return
 		}
 	}
+	user, err := logic.GetUser(content.Email)
+	if err != nil {
+		handleOauthUserNotFound(w)
+		return
+	}
+	if !(user.IsSuperAdmin || user.IsAdmin) {
+		handleOauthUserNotAllowed(w)
+		return
+	}
 	var newPass, fetchErr = fetchPassValue("")
 	if fetchErr != nil {
 		return

+ 9 - 0
auth/oidc.go

@@ -79,6 +79,15 @@ func handleOIDCCallback(w http.ResponseWriter, r *http.Request) {
 			return
 		}
 	}
+	user, err := logic.GetUser(content.Email)
+	if err != nil {
+		handleOauthUserNotFound(w)
+		return
+	}
+	if !(user.IsSuperAdmin || user.IsAdmin) {
+		handleOauthUserNotAllowed(w)
+		return
+	}
 	var newPass, fetchErr = fetchPassValue("")
 	if fetchErr != nil {
 		return

+ 1 - 0
compose/docker-compose.yml

@@ -56,6 +56,7 @@ services:
       - "443:443"
 
   coredns:
+    #network_mode: host
     container_name: coredns
     image: coredns/coredns:1.10.1
     command: -conf /root/dnsconfig/Corefile

+ 1 - 1
controllers/controller.go

@@ -41,7 +41,7 @@ func HandleRESTRequests(wg *sync.WaitGroup, ctx context.Context) {
 
 	// Currently allowed dev origin is all. Should change in prod
 	// should consider analyzing the allowed methods further
-	headersOk := handlers.AllowedHeaders([]string{"Access-Control-Allow-Origin", "X-Requested-With", "Content-Type", "authorization"})
+	headersOk := handlers.AllowedHeaders([]string{"Access-Control-Allow-Origin", "X-Requested-With", "Content-Type", "authorization", "From-Ui"})
 	originsOk := handlers.AllowedOrigins(strings.Split(servercfg.GetAllowedOrigin(), ","))
 	methodsOk := handlers.AllowedMethods([]string{http.MethodGet, http.MethodPut, http.MethodPost, http.MethodDelete})
 

+ 23 - 33
controllers/dns.go

@@ -2,6 +2,7 @@ package controller
 
 import (
 	"encoding/json"
+	"errors"
 	"fmt"
 	"net/http"
 
@@ -10,7 +11,6 @@ import (
 	"github.com/gravitl/netmaker/logger"
 	"github.com/gravitl/netmaker/logic"
 	"github.com/gravitl/netmaker/models"
-	"github.com/gravitl/netmaker/mq"
 	"github.com/gravitl/netmaker/servercfg"
 )
 
@@ -170,24 +170,17 @@ func createDNS(w http.ResponseWriter, r *http.Request) {
 		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
 		return
 	}
-	err = logic.SetDNS()
-	if err != nil {
-		logger.Log(0, r.Header.Get("user"),
-			fmt.Sprintf("Failed to set DNS entries on file: %v", err))
-		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
-		return
+	if servercfg.IsDNSMode() {
+		err = logic.SetDNS()
+		if err != nil {
+			logger.Log(0, r.Header.Get("user"),
+				fmt.Sprintf("Failed to set DNS entries on file: %v", err))
+			logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
+			return
+		}
 	}
+
 	logger.Log(1, "new DNS record added:", entry.Name)
-	if servercfg.IsMessageQueueBackend() {
-		go func() {
-			if err = mq.PublishPeerUpdate(); err != nil {
-				logger.Log(0, "failed to publish peer update after ACL update on", entry.Network)
-			}
-			if err := mq.PublishCustomDNS(&entry); err != nil {
-				logger.Log(0, "error publishing custom dns", err.Error())
-			}
-		}()
-	}
 	logger.Log(2, r.Header.Get("user"),
 		fmt.Sprintf("DNS entry is set: %+v", entry))
 	w.WriteHeader(http.StatusOK)
@@ -221,23 +214,17 @@ func deleteDNS(w http.ResponseWriter, r *http.Request) {
 		return
 	}
 	logger.Log(1, "deleted dns entry: ", entrytext)
-	err = logic.SetDNS()
-	if err != nil {
-		logger.Log(0, r.Header.Get("user"),
-			fmt.Sprintf("Failed to set DNS entries on file: %v", err))
-		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
-		return
+	if servercfg.IsDNSMode() {
+		err = logic.SetDNS()
+		if err != nil {
+			logger.Log(0, r.Header.Get("user"),
+				fmt.Sprintf("Failed to set DNS entries on file: %v", err))
+			logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
+			return
+		}
 	}
+
 	json.NewEncoder(w).Encode(entrytext + " deleted.")
-	go func() {
-		dns := models.DNSUpdate{
-			Action: models.DNSDeleteByName,
-			Name:   entrytext,
-		}
-		if err := mq.PublishDNSUpdate(params["network"], dns); err != nil {
-			logger.Log(0, "failed to publish dns update", err.Error())
-		}
-	}()
 
 }
 
@@ -271,7 +258,10 @@ func GetDNSEntry(domain string, network string) (models.DNSEntry, error) {
 func pushDNS(w http.ResponseWriter, r *http.Request) {
 	// Set header
 	w.Header().Set("Content-Type", "application/json")
-
+	if !servercfg.IsDNSMode() {
+		logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("DNS Mode is set to off"), "badrequest"))
+		return
+	}
 	err := logic.SetDNS()
 
 	if err != nil {

+ 27 - 28
controllers/ext_client.go

@@ -12,6 +12,7 @@ import (
 	"github.com/gravitl/netmaker/database"
 	"github.com/gravitl/netmaker/logger"
 	"github.com/gravitl/netmaker/logic"
+	"github.com/gravitl/netmaker/servercfg"
 
 	"github.com/gravitl/netmaker/models"
 
@@ -355,30 +356,28 @@ func createExtClient(w http.ResponseWriter, r *http.Request) {
 			return
 		}
 		userName = caller.UserName
-		if !caller.IsAdmin && !caller.IsSuperAdmin {
-			if _, ok := caller.RemoteGwIDs[nodeid]; !ok {
-				err = errors.New("permission denied")
-				slog.Error("failed to create extclient", "error", err)
-				logic.ReturnErrorResponse(w, r, logic.FormatError(err, "forbidden"))
-				return
-			}
-			// check if user has a config already for remote access client
-			extclients, err := logic.GetNetworkExtClients(node.Network)
-			if err != nil {
-				slog.Error("failed to get extclients", "error", err)
-				logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
+		if _, ok := caller.RemoteGwIDs[nodeid]; (!caller.IsAdmin && !caller.IsSuperAdmin) && !ok {
+			err = errors.New("permission denied")
+			slog.Error("failed to create extclient", "error", err)
+			logic.ReturnErrorResponse(w, r, logic.FormatError(err, "forbidden"))
+			return
+		}
+		// check if user has a config already for remote access client
+		extclients, err := logic.GetNetworkExtClients(node.Network)
+		if err != nil {
+			slog.Error("failed to get extclients", "error", err)
+			logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
+			return
+		}
+		for _, extclient := range extclients {
+			if extclient.RemoteAccessClientID != "" &&
+				extclient.RemoteAccessClientID == customExtClient.RemoteAccessClientID && nodeid == extclient.IngressGatewayID {
+				// extclient on the gw already exists for the remote access client
+				err = errors.New("remote client config already exists on the gateway. it may have been created by another user with this same remote client machine")
+				slog.Error("failed to create extclient", "user", userName, "error", err)
+				logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
 				return
 			}
-			for _, extclient := range extclients {
-				if extclient.RemoteAccessClientID != "" &&
-					extclient.RemoteAccessClientID == customExtClient.RemoteAccessClientID && nodeid == extclient.IngressGatewayID {
-					// extclient on the gw already exists for the remote access client
-					err = errors.New("remote client config already exists on the gateway")
-					slog.Error("failed to create extclient", "user", userName, "error", err)
-					logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
-					return
-				}
-			}
 		}
 	}
 
@@ -426,8 +425,8 @@ func createExtClient(w http.ResponseWriter, r *http.Request) {
 		if err := mq.PublishPeerUpdate(); err != nil {
 			logger.Log(1, "error setting ext peers on "+nodeid+": "+err.Error())
 		}
-		if err := mq.PublishExtClientDNS(&extclient); err != nil {
-			logger.Log(1, "error publishing extclient dns", err.Error())
+		if servercfg.IsDNSMode() {
+			logic.SetDNS()
 		}
 	}()
 }
@@ -522,8 +521,8 @@ func updateExtClient(w http.ResponseWriter, r *http.Request) {
 	json.NewEncoder(w).Encode(newclient)
 	if changedID {
 		go func() {
-			if err := mq.PublishExtClientDNSUpdate(oldExtClient, newclient, oldExtClient.Network); err != nil {
-				logger.Log(1, "error pubishing dns update for extcient update", err.Error())
+			if servercfg.IsDNSMode() {
+				logic.SetDNS()
 			}
 		}()
 	}
@@ -583,8 +582,8 @@ func deleteExtClient(w http.ResponseWriter, r *http.Request) {
 		if err := mq.PublishDeletedClientPeerUpdate(&extclient); err != nil {
 			logger.Log(1, "error setting ext peers on "+ingressnode.ID.String()+": "+err.Error())
 		}
-		if err = mq.PublishDeleteExtClientDNS(&extclient); err != nil {
-			logger.Log(1, "error publishing dns update for extclient deletion", err.Error())
+		if servercfg.IsDNSMode() {
+			logic.SetDNS()
 		}
 	}()
 

+ 17 - 12
controllers/hosts.go

@@ -199,16 +199,8 @@ func updateHost(w http.ResponseWriter, r *http.Request) {
 			logger.Log(0, "fail to publish peer update: ", err.Error())
 		}
 		if newHost.Name != currHost.Name {
-			networks := logic.GetHostNetworks(currHost.ID.String())
-			if err := mq.PublishHostDNSUpdate(currHost, newHost, networks); err != nil {
-				var dnsError *models.DNSError
-				if errors.Is(err, dnsError) {
-					for _, message := range err.(models.DNSError).ErrorStrings {
-						logger.Log(0, message)
-					}
-				} else {
-					logger.Log(0, err.Error())
-				}
+			if servercfg.IsDNSMode() {
+				logic.SetDNS()
 			}
 		}
 	}()
@@ -300,6 +292,12 @@ func deleteHost(w http.ResponseWriter, r *http.Request) {
 		go mq.PublishMqUpdatesForDeletedNode(node, false, gwClients)
 
 	}
+	if servercfg.GetBrokerType() == servercfg.EmqxBrokerType {
+		// delete EMQX credentials for host
+		if err := mq.DeleteEmqxUser(currHost.ID.String()); err != nil {
+			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"))
@@ -359,7 +357,9 @@ func addHostToNetwork(w http.ResponseWriter, r *http.Request) {
 			Node:   *newNode,
 		})
 		mq.PublishPeerUpdate()
-		mq.HandleNewNodeDNS(currHost, newNode)
+		if servercfg.IsDNSMode() {
+			logic.SetDNS()
+		}
 	}()
 	logger.Log(2, r.Header.Get("user"), fmt.Sprintf("added host %s to network %s", currHost.Name, network))
 	w.WriteHeader(http.StatusOK)
@@ -444,7 +444,12 @@ func deleteHostFromNetwork(w http.ResponseWriter, r *http.Request) {
 		logic.ReturnErrorResponse(w, r, logic.FormatError(fmt.Errorf("failed to delete node"), "internal"))
 		return
 	}
-	go mq.PublishMqUpdatesForDeletedNode(*node, true, gwClients)
+	go func() {
+		mq.PublishMqUpdatesForDeletedNode(*node, true, gwClients)
+		if servercfg.IsDNSMode() {
+			logic.SetDNS()
+		}
+	}()
 	logger.Log(2, r.Header.Get("user"), fmt.Sprintf("removed host %s from network %s", currHost.Name, network))
 	w.WriteHeader(http.StatusOK)
 }

+ 6 - 7
controllers/node.go

@@ -596,7 +596,9 @@ func deleteIngressGateway(w http.ResponseWriter, r *http.Request) {
 				if err := mq.NodeUpdate(&node); err != nil {
 					slog.Error("error publishing node update to node", "node", node.ID, "error", err)
 				}
-				mq.PublishDeleteAllExtclientsDNS(node.Network, removedClients)
+				if servercfg.IsDNSMode() {
+					logic.SetDNS()
+				}
 			}()
 		}
 	}
@@ -635,7 +637,7 @@ func updateNode(w http.ResponseWriter, r *http.Request) {
 	}
 	newNode := newData.ConvertToServerNode(&currentNode)
 	relayUpdate := logic.RelayUpdates(&currentNode, newNode)
-	host, err := logic.GetHost(newNode.HostID.String())
+	_, err = logic.GetHost(newNode.HostID.String())
 	if err != nil {
 		logger.Log(0, r.Header.Get("user"),
 			fmt.Sprintf("failed to get host for node  [ %s ] info: %v", nodeid, err))
@@ -655,9 +657,6 @@ func updateNode(w http.ResponseWriter, r *http.Request) {
 	if relayUpdate {
 		logic.UpdateRelayed(&currentNode, newNode)
 	}
-	if servercfg.IsDNSMode() {
-		logic.SetDNS()
-	}
 
 	apiNode := newNode.ConvertToAPINode()
 	logger.Log(1, r.Header.Get("user"), "updated node", currentNode.ID.String(), "on network", currentNode.Network)
@@ -672,8 +671,8 @@ func updateNode(w http.ResponseWriter, r *http.Request) {
 				logger.Log(0, "error during node ACL update for node", newNode.ID.String())
 			}
 		}
-		if err := mq.PublishReplaceDNS(&currentNode, newNode, host); err != nil {
-			logger.Log(1, "failed to publish dns update", err.Error())
+		if servercfg.IsDNSMode() {
+			logic.SetDNS()
 		}
 	}(aclUpdate, relayUpdate, newNode)
 }

+ 18 - 1
controllers/user.go

@@ -71,6 +71,20 @@ func authenticateUser(response http.ResponseWriter, request *http.Request) {
 		logic.ReturnErrorResponse(response, request, errorResponse)
 		return
 	}
+	if val := request.Header.Get("From-Ui"); val == "true" {
+		// request came from UI, if normal user block Login
+		user, err := logic.GetUser(authRequest.UserName)
+		if err != nil {
+			logger.Log(0, authRequest.UserName, "user validation failed: ",
+				err.Error())
+			logic.ReturnErrorResponse(response, request, logic.FormatError(err, "unauthorized"))
+			return
+		}
+		if !(user.IsAdmin || user.IsSuperAdmin) {
+			logic.ReturnErrorResponse(response, request, logic.FormatError(errors.New("only admins can access dashboard"), "unauthorized"))
+			return
+		}
+	}
 	username := authRequest.UserName
 	jwt, err := logic.VerifyAuthRequest(authRequest)
 	if err != nil {
@@ -119,7 +133,7 @@ func authenticateUser(response http.ResponseWriter, request *http.Request) {
 				if client.OwnerID == username && !client.Enabled {
 					slog.Info(fmt.Sprintf("enabling ext client %s for user %s due to RAC autodisabling feature", client.ClientID, client.OwnerID))
 					if newClient, err := logic.ToggleExtClientConnectivity(&client, true); err != nil {
-						slog.Error("error disabling ext client in RAC autodisable hook", "error", err)
+						slog.Error("error enabling ext client in RAC autodisable hook", "error", err)
 						continue // dont return but try for other clients
 					} else {
 						// publish peer update to ingress gateway
@@ -545,6 +559,9 @@ func deleteUser(w http.ResponseWriter, r *http.Request) {
 				}
 			}
 		}
+		if servercfg.IsDNSMode() {
+			logic.SetDNS()
+		}
 	}()
 	logger.Log(1, username, "was deleted")
 	json.NewEncoder(w).Encode(params["username"] + " deleted.")

+ 29 - 2
logic/dns.go

@@ -11,6 +11,7 @@ import (
 	"github.com/gravitl/netmaker/database"
 	"github.com/gravitl/netmaker/logger"
 	"github.com/gravitl/netmaker/models"
+	"github.com/gravitl/netmaker/servercfg"
 	"github.com/txn2/txeh"
 )
 
@@ -36,6 +37,10 @@ func SetDNS() error {
 			hostfile.AddHost(entry.Address, entry.Name)
 		}
 	}
+	dns := GetExtclientDNS()
+	for _, entry := range dns {
+		hostfile.AddHost(entry.Address, entry.Name)
+	}
 	if corefilestring == "" {
 		corefilestring = "example.com"
 	}
@@ -69,6 +74,28 @@ func GetDNS(network string) ([]models.DNSEntry, error) {
 	return dns, nil
 }
 
+// GetExtclientDNS - gets all extclients dns entries
+func GetExtclientDNS() []models.DNSEntry {
+	extclients, err := GetAllExtClients()
+	if err != nil {
+		return []models.DNSEntry{}
+	}
+	var dns []models.DNSEntry
+	for _, extclient := range extclients {
+		var entry = models.DNSEntry{}
+		entry.Name = fmt.Sprintf("%s.%s", extclient.ClientID, extclient.Network)
+		entry.Network = extclient.Network
+		if extclient.Address != "" {
+			entry.Address = extclient.Address
+		}
+		if extclient.Address6 != "" {
+			entry.Address6 = extclient.Address6
+		}
+		dns = append(dns, entry)
+	}
+	return dns
+}
+
 // GetNodeDNS - gets the DNS of a network node
 func GetNodeDNS(network string) ([]models.DNSEntry, error) {
 
@@ -142,6 +169,7 @@ func SetCorefile(domains string) error {
 	}
 
 	corefile := domains + ` {
+	bind %s
     reload 15s
     hosts /root/dnsconfig/netmaker.hosts {
 	fallthrough	
@@ -150,8 +178,7 @@ func SetCorefile(domains string) error {
     log
 }
 `
-	corebytes := []byte(corefile)
-
+	corebytes := []byte(fmt.Sprintf(corefile, servercfg.GetCoreDNSAddr()))
 	err = os.WriteFile(dir+"/config/dnsconfig/Corefile", corebytes, 0644)
 	if err != nil {
 		return err

+ 5 - 0
logic/hosts.go

@@ -309,6 +309,11 @@ func RemoveHost(h *models.Host, forceDelete bool) error {
 	if servercfg.CacheEnabled() {
 		deleteHostFromCache(h.ID.String())
 	}
+	go func() {
+		if servercfg.IsDNSMode() {
+			SetDNS()
+		}
+	}()
 
 	return nil
 }

+ 2 - 2
models/extclient.go

@@ -17,7 +17,7 @@ type ExtClient struct {
 	Enabled                bool                `json:"enabled" bson:"enabled"`
 	OwnerID                string              `json:"ownerid" bson:"ownerid"`
 	DeniedACLs             map[string]struct{} `json:"deniednodeacls" bson:"acls,omitempty"`
-	RemoteAccessClientID   string              `json:"remote_access_client_id"`
+	RemoteAccessClientID   string              `json:"remote_access_client_id"` // unique ID (MAC address) of RAC machine
 }
 
 // CustomExtClient - struct for CustomExtClient params
@@ -28,5 +28,5 @@ type CustomExtClient struct {
 	ExtraAllowedIPs      []string            `json:"extraallowedips,omitempty"`
 	Enabled              bool                `json:"enabled,omitempty"`
 	DeniedACLs           map[string]struct{} `json:"deniednodeacls" bson:"acls,omitempty"`
-	RemoteAccessClientID string              `json:"remote_access_client_id"`
+	RemoteAccessClientID string              `json:"remote_access_client_id"` // unique ID (MAC address) of RAC machine
 }

+ 0 - 10
mq/emqx.go

@@ -286,16 +286,6 @@ func CreateHostACL(hostID, serverName string) error {
 				Permission: "allow",
 				Action:     "all",
 			},
-			{
-				Topic:      fmt.Sprintf("dns/all/%s/%s", hostID, serverName),
-				Permission: "allow",
-				Action:     "all",
-			},
-			{
-				Topic:      fmt.Sprintf("dns/update/%s/%s", hostID, serverName),
-				Permission: "allow",
-				Action:     "all",
-			},
 			{
 				Topic:      fmt.Sprintf("host/serverupdate/%s/%s", serverName, hostID),
 				Permission: "allow",

+ 3 - 27
mq/handlers.go

@@ -126,10 +126,6 @@ func UpdateHost(client mqtt.Client, msg mqtt.Message) {
 					slog.Error("failed peers publish after join acknowledged", "name", hostUpdate.Host.Name, "id", currentHost.ID, "error", err)
 					return
 				}
-				if err = HandleNewNodeDNS(&hu.Host, &hu.Node); err != nil {
-					slog.Error("failed to send dns update after node added to host", "name", hostUpdate.Host.Name, "id", currentHost.ID, "error", err)
-					return
-				}
 			}
 		}
 	case models.UpdateHost:
@@ -166,7 +162,6 @@ func UpdateHost(client mqtt.Client, msg mqtt.Message) {
 			// delete EMQX credentials for host
 			if err := DeleteEmqxUser(currentHost.ID.String()); err != nil {
 				slog.Error("failed to remove host credentials from EMQX", "id", currentHost.ID, "error", err)
-				return
 			}
 		}
 
@@ -193,6 +188,9 @@ func UpdateHost(client mqtt.Client, msg mqtt.Message) {
 			slog.Error("failed to delete host", "id", currentHost.ID, "error", err)
 			return
 		}
+		if servercfg.IsDNSMode() {
+			logic.SetDNS()
+		}
 		sendPeerUpdate = true
 	case models.SignalHost:
 		signalPeer(hostUpdate.Signal)
@@ -260,28 +258,6 @@ func ClientPeerUpdate(client mqtt.Client, msg mqtt.Message) {
 	slog.Info("sent peer updates after signal received from", "id", id)
 }
 
-func HandleNewNodeDNS(host *models.Host, node *models.Node) error {
-	dns := models.DNSUpdate{
-		Action: models.DNSInsert,
-		Name:   host.Name + "." + node.Network,
-	}
-	if node.Address.IP != nil {
-		dns.Address = node.Address.IP.String()
-		if err := PublishDNSUpdate(node.Network, dns); err != nil {
-			return err
-		}
-	} else if node.Address6.IP != nil {
-		dns.Address = node.Address6.IP.String()
-		if err := PublishDNSUpdate(node.Network, dns); err != nil {
-			return err
-		}
-	}
-	if err := PublishAllDNS(node); err != nil {
-		return err
-	}
-	return nil
-}
-
 func HandleHostCheckin(h, currentHost *models.Host) bool {
 	if h == nil {
 		return false

+ 2 - 286
mq/publishers.go

@@ -166,73 +166,6 @@ func ServerStartNotify() error {
 	return nil
 }
 
-// PublishDNSUpdatev1 - published dns updates to all nodes passed
-func PublishDNSUpdatev1(network string, dns models.DNSUpdate, nodes []models.Node) error {
-	for _, node := range nodes {
-		host, err := logic.GetHost(node.HostID.String())
-		if err != nil {
-			logger.Log(0, "error retrieving host for dns update", node.HostID.String(), err.Error())
-			continue
-		}
-		data, err := json.Marshal(dns)
-		if err != nil {
-			logger.Log(0, "failed to encode dns data for node", node.ID.String(), err.Error())
-		}
-		if err := publish(host, "dns/update/"+host.ID.String()+"/"+servercfg.GetServer(), data); err != nil {
-			logger.Log(0, "error publishing dns update to host", host.ID.String(), err.Error())
-			continue
-		}
-		logger.Log(3, "published dns update to host", host.ID.String())
-	}
-	return nil
-}
-
-// PublishDNSUpdate publishes a dns update to all nodes on a network
-func PublishDNSUpdate(network string, dns models.DNSUpdate) error {
-	nodes, err := logic.GetNetworkNodes(network)
-	if err != nil {
-		return err
-	}
-	for _, node := range nodes {
-		host, err := logic.GetHost(node.HostID.String())
-		if err != nil {
-			logger.Log(0, "error retrieving host for dns update", node.HostID.String(), err.Error())
-			continue
-		}
-		data, err := json.Marshal(dns)
-		if err != nil {
-			logger.Log(0, "failed to encode dns data for node", node.ID.String(), err.Error())
-		}
-		if err := publish(host, "dns/update/"+host.ID.String()+"/"+servercfg.GetServer(), data); err != nil {
-			logger.Log(0, "error publishing dns update to host", host.ID.String(), err.Error())
-			continue
-		}
-		logger.Log(3, "published dns update to host", host.ID.String())
-	}
-	return nil
-}
-
-// PublishAllDNS publishes an array of dns updates (ip / host.network) for each peer to a node joining a network
-func PublishAllDNS(newnode *models.Node) error {
-	alldns := []models.DNSUpdate{}
-	newnodeHost, err := logic.GetHost(newnode.HostID.String())
-	if err != nil {
-		return fmt.Errorf("error retrieving host for dns update %w", err)
-	}
-	alldns = append(alldns, getNodeDNS(newnode.Network)...)
-	alldns = append(alldns, getExtClientDNS(newnode.Network)...)
-	alldns = append(alldns, getCustomDNS(newnode.Network)...)
-	data, err := json.Marshal(alldns)
-	if err != nil {
-		return fmt.Errorf("error encoding dns data %w", err)
-	}
-	if err := publish(newnodeHost, "dns/all/"+newnodeHost.ID.String()+"/"+servercfg.GetServer(), data); err != nil {
-		return fmt.Errorf("error publishing full dns update to %s, %w", newnodeHost.ID.String(), err)
-	}
-	logger.Log(3, "published full dns update to %s", newnodeHost.ID.String())
-	return nil
-}
-
 // PublishMqUpdatesForDeletedNode - published all the required updates for deleted node
 func PublishMqUpdatesForDeletedNode(node models.Node, sendNodeUpdate bool, gwClients []models.ExtClient) {
 	// notify of peer change
@@ -246,162 +179,10 @@ func PublishMqUpdatesForDeletedNode(node models.Node, sendNodeUpdate bool, gwCli
 	if err := PublishDeletedNodePeerUpdate(&node); err != nil {
 		logger.Log(1, "error publishing peer update ", err.Error())
 	}
-	host, err := logic.GetHost(node.HostID.String())
-	if err != nil {
-		logger.Log(1, "failed to retrieve host for node", node.ID.String(), err.Error())
+	if servercfg.IsDNSMode() {
+		logic.SetDNS()
 	}
-	if err := PublishDNSDelete(&node, host); err != nil {
-		logger.Log(1, "error publishing dns update", err.Error())
-	}
-	if err := PublishDeleteAllExtclientsDNS(node.Network, gwClients); err != nil {
-		logger.Log(1, "error publishing ext dns update", err.Error())
-	}
-
-}
 
-// PublishDNSDelete publish a dns update deleting a node to all hosts on a network
-func PublishDNSDelete(node *models.Node, host *models.Host) error {
-	dns := models.DNSUpdate{
-		Action: models.DNSDeleteByIP,
-		Name:   host.Name + "." + node.Network,
-	}
-	if node.Address.IP != nil {
-		dns.Address = node.Address.IP.String()
-		if err := PublishDNSUpdate(node.Network, dns); err != nil {
-			return fmt.Errorf("dns update node deletion %w", err)
-		}
-	}
-	if node.Address6.IP != nil {
-		dns.Address = node.Address6.IP.String()
-		if err := PublishDNSUpdate(node.Network, dns); err != nil {
-			return fmt.Errorf("dns update node deletion %w", err)
-		}
-	}
-	return nil
-}
-
-// PublishReplaceDNS publish a dns update to replace a dns entry on all hosts in network
-func PublishReplaceDNS(oldNode, newNode *models.Node, host *models.Host) error {
-	dns := models.DNSUpdate{
-		Action: models.DNSReplaceIP,
-		Name:   host.Name + "." + oldNode.Network,
-	}
-	if !oldNode.Address.IP.Equal(newNode.Address.IP) {
-		dns.Address = oldNode.Address.IP.String()
-		dns.NewAddress = newNode.Address.IP.String()
-		if err := PublishDNSUpdate(oldNode.Network, dns); err != nil {
-			return err
-		}
-	}
-	if !oldNode.Address6.IP.Equal(newNode.Address6.IP) {
-		dns.Address = oldNode.Address6.IP.String()
-		dns.NewAddress = newNode.Address6.IP.String()
-		if err := PublishDNSUpdate(oldNode.Network, dns); err != nil {
-			return err
-		}
-	}
-	return nil
-}
-
-// PublishExtClientDNS publish dns update for new extclient
-func PublishExtClientDNS(client *models.ExtClient) error {
-	errMsgs := models.DNSError{}
-	dns := models.DNSUpdate{
-		Action:  models.DNSInsert,
-		Name:    client.ClientID + "." + client.Network,
-		Address: client.Address,
-	}
-	if client.Address != "" {
-		dns.Address = client.Address
-		if err := PublishDNSUpdate(client.Network, dns); err != nil {
-			errMsgs.ErrorStrings = append(errMsgs.ErrorStrings, err.Error())
-		}
-
-	}
-	if client.Address6 != "" {
-		dns.Address = client.Address6
-		if err := PublishDNSUpdate(client.Network, dns); err != nil {
-			errMsgs.ErrorStrings = append(errMsgs.ErrorStrings, err.Error())
-		}
-	}
-	if len(errMsgs.ErrorStrings) > 0 {
-		return errMsgs
-	}
-	return nil
-}
-
-// PublishExtClientDNSUpdate update for extclient name change
-func PublishExtClientDNSUpdate(old, new models.ExtClient, network string) error {
-	dns := models.DNSUpdate{
-		Action:  models.DNSReplaceName,
-		Name:    old.ClientID + "." + network,
-		NewName: new.ClientID + "." + network,
-	}
-	if err := PublishDNSUpdate(network, dns); err != nil {
-		return err
-	}
-	return nil
-}
-
-// PublishDeleteAllExtclientsDNS - publish to delete all passed ext clients dns entries
-func PublishDeleteAllExtclientsDNS(network string, clients []models.ExtClient) error {
-	nodes, err := logic.GetNetworkNodes(network)
-	if err != nil {
-		return err
-	}
-	for _, client := range clients {
-		dns := models.DNSUpdate{
-			Action: models.DNSDeleteByName,
-			Name:   client.ClientID + "." + client.Network,
-		}
-		go PublishDNSUpdatev1(client.Network, dns, nodes)
-	}
-	return nil
-}
-
-// PublishDeleteExtClientDNS publish dns update to delete extclient entry
-func PublishDeleteExtClientDNS(client *models.ExtClient) error {
-	dns := models.DNSUpdate{
-		Action: models.DNSDeleteByName,
-		Name:   client.ClientID + "." + client.Network,
-	}
-	if err := PublishDNSUpdate(client.Network, dns); err != nil {
-		return err
-	}
-	return nil
-}
-
-// PublishCustomDNS publish dns update for new custom dns entry
-func PublishCustomDNS(entry *models.DNSEntry) error {
-	dns := models.DNSUpdate{
-		Action: models.DNSInsert,
-		Name:   entry.Name,
-		//entry.Address6 is never used
-		Address: entry.Address,
-	}
-	if err := PublishDNSUpdate(entry.Network, dns); err != nil {
-		return err
-	}
-	return nil
-}
-
-// PublishHostDNSUpdate publishes dns update on host name change
-func PublishHostDNSUpdate(old, new *models.Host, networks []string) error {
-	errMsgs := models.DNSError{}
-	for _, network := range networks {
-		dns := models.DNSUpdate{
-			Action:  models.DNSReplaceName,
-			Name:    old.Name + "." + network,
-			NewName: new.Name + "." + network,
-		}
-		if err := PublishDNSUpdate(network, dns); err != nil {
-			errMsgs.ErrorStrings = append(errMsgs.ErrorStrings, err.Error())
-		}
-	}
-	if len(errMsgs.ErrorStrings) > 0 {
-		return errMsgs
-	}
-	return nil
 }
 
 func PushMetricsToExporter(metrics models.Metrics) error {
@@ -422,71 +203,6 @@ func PushMetricsToExporter(metrics models.Metrics) error {
 	return nil
 }
 
-func getNodeDNS(network string) []models.DNSUpdate {
-	alldns := []models.DNSUpdate{}
-	dns := models.DNSUpdate{}
-	nodes, err := logic.GetNetworkNodes(network)
-	if err != nil {
-		logger.Log(0, "error retreiving network nodes for network", network, err.Error())
-	}
-	for _, node := range nodes {
-		host, err := logic.GetHost(node.HostID.String())
-		if err != nil {
-			logger.Log(0, "error retrieving host for dns update", node.HostID.String(), err.Error())
-			continue
-		}
-		dns.Action = models.DNSInsert
-		dns.Name = host.Name + "." + node.Network
-		if node.Address.IP != nil {
-			dns.Address = node.Address.IP.String()
-			alldns = append(alldns, dns)
-		}
-		if node.Address6.IP != nil {
-			dns.Address = node.Address6.IP.String()
-			alldns = append(alldns, dns)
-		}
-	}
-	return alldns
-}
-
-func getExtClientDNS(network string) []models.DNSUpdate {
-	alldns := []models.DNSUpdate{}
-	dns := models.DNSUpdate{}
-	clients, err := logic.GetNetworkExtClients(network)
-	if err != nil {
-		logger.Log(0, "error retrieving extclients", err.Error())
-	}
-	for _, client := range clients {
-		dns.Action = models.DNSInsert
-		dns.Name = client.ClientID + "." + client.Network
-		if client.Address != "" {
-			dns.Address = client.Address
-			alldns = append(alldns, dns)
-		}
-		if client.Address6 != "" {
-			dns.Address = client.Address
-			alldns = append(alldns, dns)
-		}
-	}
-	return alldns
-}
-
-func getCustomDNS(network string) []models.DNSUpdate {
-	alldns := []models.DNSUpdate{}
-	dns := models.DNSUpdate{}
-	customdns, err := logic.GetCustomDNS(network)
-	if err != nil {
-		logger.Log(0, "error retrieving custom dns entries", err.Error())
-	}
-	for _, custom := range customdns {
-		dns.Action = models.DNSInsert
-		dns.Address = custom.Address
-		dns.Name = custom.Name + "." + custom.Network
-		alldns = append(alldns, dns)
-	}
-	return alldns
-}
-
 // sendPeers - retrieve networks, send peer ports to all peers
 func sendPeers() {
 

+ 71 - 29
pro/controllers/users.go

@@ -10,6 +10,7 @@ import (
 	"github.com/gravitl/netmaker/logger"
 	"github.com/gravitl/netmaker/logic"
 	"github.com/gravitl/netmaker/models"
+	"github.com/gravitl/netmaker/servercfg"
 	"golang.org/x/exp/slog"
 )
 
@@ -116,6 +117,9 @@ func removeUserFromRemoteAccessGW(w http.ResponseWriter, r *http.Request) {
 				logic.DeleteExtClient(extclient.Network, extclient.ClientID)
 			}
 		}
+		if servercfg.IsDNSMode() {
+			logic.SetDNS()
+		}
 	}(*user, remoteGwID)
 
 	err = logic.UpsertUser(*user)
@@ -166,16 +170,13 @@ func getUserRemoteAccessGws(w http.ResponseWriter, r *http.Request) {
 		logic.ReturnErrorResponse(w, r, logic.FormatError(fmt.Errorf("failed to fetch user %s, error: %v", username, err), "badrequest"))
 		return
 	}
-	if user.IsAdmin || user.IsSuperAdmin {
-		logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("admins can visit dashboard to create remote clients"), "badrequest"))
-		return
-	}
 	allextClients, err := logic.GetAllExtClients()
 	if err != nil {
 		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
 		return
 	}
 
+	processedAdminNodeIds := make(map[string]struct{})
 	for _, extClient := range allextClients {
 		if extClient.RemoteAccessClientID == req.RemoteAccessClientID && extClient.OwnerID == username {
 			node, err := logic.GetNodeByID(extClient.IngressGatewayID)
@@ -193,7 +194,7 @@ func getUserRemoteAccessGws(w http.ResponseWriter, r *http.Request) {
 				continue
 			}
 
-			if _, ok := user.RemoteGwIDs[node.ID.String()]; ok {
+			if _, ok := user.RemoteGwIDs[node.ID.String()]; (!user.IsAdmin && !user.IsSuperAdmin) && ok {
 				gws := userGws[node.Network]
 				extClient.AllowedIPs = logic.GetExtclientAllowedIPs(extClient)
 				gws = append(gws, models.UserRemoteGws{
@@ -207,40 +208,81 @@ func getUserRemoteAccessGws(w http.ResponseWriter, r *http.Request) {
 				})
 				userGws[node.Network] = gws
 				delete(user.RemoteGwIDs, node.ID.String())
-
+			} else {
+				gws := userGws[node.Network]
+				extClient.AllowedIPs = logic.GetExtclientAllowedIPs(extClient)
+				gws = append(gws, models.UserRemoteGws{
+					GwID:              node.ID.String(),
+					GWName:            host.Name,
+					Network:           node.Network,
+					GwClient:          extClient,
+					Connected:         true,
+					IsInternetGateway: node.IsInternetGateway,
+					GwPeerPublicKey:   host.PublicKey.String(),
+				})
+				userGws[node.Network] = gws
+				processedAdminNodeIds[node.ID.String()] = struct{}{}
 			}
 		}
-
 	}
 
 	// add remaining gw nodes to resp
-	for gwID := range user.RemoteGwIDs {
-		node, err := logic.GetNodeByID(gwID)
-		if err != nil {
-			continue
-		}
-		if !node.IsIngressGateway {
-			continue
-		}
-		if node.PendingDelete {
-			continue
+	if !user.IsAdmin && !user.IsSuperAdmin {
+		for gwID := range user.RemoteGwIDs {
+			node, err := logic.GetNodeByID(gwID)
+			if err != nil {
+				continue
+			}
+			if !node.IsIngressGateway {
+				continue
+			}
+			if node.PendingDelete {
+				continue
+			}
+			host, err := logic.GetHost(node.HostID.String())
+			if err != nil {
+				continue
+			}
+			gws := userGws[node.Network]
+
+			gws = append(gws, models.UserRemoteGws{
+				GwID:              node.ID.String(),
+				GWName:            host.Name,
+				Network:           node.Network,
+				IsInternetGateway: node.IsInternetGateway,
+				GwPeerPublicKey:   host.PublicKey.String(),
+			})
+			userGws[node.Network] = gws
 		}
-		host, err := logic.GetHost(node.HostID.String())
+	} else {
+		allNodes, err := logic.GetAllNodes()
 		if err != nil {
-			continue
+			slog.Error("failed to fetch all nodes", "error", err)
+			logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
+			return
 		}
-		gws := userGws[node.Network]
+		for _, node := range allNodes {
+			_, ok := processedAdminNodeIds[node.ID.String()]
+			if node.IsIngressGateway && !node.PendingDelete && !ok {
+				host, err := logic.GetHost(node.HostID.String())
+				if err != nil {
+					slog.Error("failed to fetch host", "error", err)
+					continue
+				}
+				gws := userGws[node.Network]
 
-		gws = append(gws, models.UserRemoteGws{
-			GwID:              node.ID.String(),
-			GWName:            host.Name,
-			Network:           node.Network,
-			IsInternetGateway: node.IsInternetGateway,
-			GwPeerPublicKey:   host.PublicKey.String(),
-		})
-		userGws[node.Network] = gws
+				gws = append(gws, models.UserRemoteGws{
+					GwID:              node.ID.String(),
+					GWName:            host.Name,
+					Network:           node.Network,
+					IsInternetGateway: node.IsInternetGateway,
+					GwPeerPublicKey:   host.PublicKey.String(),
+				})
+				userGws[node.Network] = gws
+			}
+		}
 	}
-
+	slog.Debug("returned user gws", "user", username, "gws", userGws)
 	w.WriteHeader(http.StatusOK)
 	json.NewEncoder(w).Encode(userGws)
 }