Browse Source

Merge pull request #1415 from gravitl/release_v0.14.6

Release v0.14.6
Alex Feiszli 3 years ago
parent
commit
edc8f63ea2
49 changed files with 819 additions and 642 deletions
  1. 1 0
      .github/ISSUE_TEMPLATE/bug-report.yml
  2. 2 1
      .github/workflows/test.yml
  3. 2 2
      compose/docker-compose.reference.yml
  4. 2 2
      compose/docker-compose.yml
  5. 32 18
      controllers/dns.go
  6. 54 9
      controllers/ext_client.go
  7. 79 8
      controllers/network.go
  8. 10 10
      controllers/network_test.go
  9. 80 10
      controllers/node.go
  10. 34 0
      controllers/node_test.go
  11. 7 2
      controllers/relay.go
  12. 10 5
      controllers/server.go
  13. 69 19
      controllers/user.go
  14. 8 7
      go.mod
  15. 4 4
      go.sum
  16. 1 1
      k8s/client/netclient-daemonset.yaml
  17. 1 1
      k8s/server/netmaker-server.yaml
  18. 22 0
      logger/logger.go
  19. 1 1
      logger/util.go
  20. 13 6
      logic/gateway.go
  21. 2 2
      models/network.go
  22. 35 34
      models/node.go
  23. 1 0
      models/structs.go
  24. 4 3
      mq/publishers.go
  25. 3 1
      netclient/cli_options/cmds.go
  26. 6 0
      netclient/cli_options/flags.go
  27. 3 3
      netclient/command/commands.go
  28. 25 3
      netclient/daemon/common.go
  29. 1 0
      netclient/daemon/freebsd.go
  30. 1 0
      netclient/daemon/systemd.go
  31. 12 33
      netclient/functions/common.go
  32. 82 61
      netclient/functions/daemon.go
  33. 3 0
      netclient/functions/install.go
  34. 15 10
      netclient/functions/join.go
  35. 2 2
      netclient/functions/localport.go
  36. 3 3
      netclient/functions/localport_freebsd.go
  37. 42 15
      netclient/functions/mqhandlers.go
  38. 51 47
      netclient/functions/mqpublish.go
  39. 1 1
      netclient/functions/pull.go
  40. 2 2
      netclient/functions/register.go
  41. 25 0
      netclient/functions/upgrades/v0-14-6.go
  42. 46 0
      netclient/ncutils/pid.go
  43. 3 3
      netclient/versioninfo.json
  44. 1 1
      netclient/wireguard/noquick.go
  45. 0 289
      scripts/install-netmaker.sh
  46. 14 12
      scripts/netclient-install.sh
  47. 2 9
      scripts/nm-quick.sh
  48. 1 1
      scripts/token-convert.sh
  49. 1 1
      servercfg/serverconf.go

+ 1 - 0
.github/ISSUE_TEMPLATE/bug-report.yml

@@ -31,6 +31,7 @@ body:
       label: Version
       description: What version are you running?
       options:
+        - v0.14.6
         - v0.14.5
         - v0.14.4
         - v0.14.3      

+ 2 - 1
.github/workflows/test.yml

@@ -1,7 +1,8 @@
 name: Integration Test
 
 on:
-  push:
+  pull_request:
+    types: [opened, reopened]
 
 jobs:
   build:

+ 2 - 2
compose/docker-compose.reference.yml

@@ -3,7 +3,7 @@ version: "3.4"
 services:
   netmaker: # The Primary Server for running Netmaker
     container_name: netmaker
-    image: gravitl/netmaker:v0.14.5
+    image: gravitl/netmaker:v0.14.6
     cap_add: 
       - NET_ADMIN
       - NET_RAW
@@ -62,7 +62,7 @@ services:
       - traefik.http.services.netmaker-api.loadbalancer.server.port=8081
   netmaker-ui:  # The Netmaker UI Component
     container_name: netmaker-ui
-    image: gravitl/netmaker-ui:v0.14.5
+    image: gravitl/netmaker-ui:v0.14.6
     depends_on:
       - netmaker
     links:

+ 2 - 2
compose/docker-compose.yml

@@ -3,7 +3,7 @@ version: "3.4"
 services:
   netmaker:
     container_name: netmaker
-    image: gravitl/netmaker:v0.14.5
+    image: gravitl/netmaker:v0.14.6
     cap_add: 
       - NET_ADMIN
       - NET_RAW
@@ -51,7 +51,7 @@ services:
       - traefik.http.services.netmaker-api.loadbalancer.server.port=8081
   netmaker-ui:
     container_name: netmaker-ui
-    image: gravitl/netmaker-ui:v0.14.5
+    image: gravitl/netmaker-ui:v0.14.6
     depends_on:
       - netmaker
     links:

+ 32 - 18
controllers/dns.go

@@ -2,6 +2,7 @@ package controller
 
 import (
 	"encoding/json"
+	"fmt"
 	"net/http"
 
 	"github.com/gorilla/mux"
@@ -24,67 +25,69 @@ func dnsHandlers(r *mux.Router) {
 	r.HandleFunc("/api/dns/{network}/{domain}", securityCheck(false, http.HandlerFunc(deleteDNS))).Methods("DELETE")
 }
 
-//Gets all nodes associated with network, including pending nodes
+//Gets node DNS entries associated with a network
 func getNodeDNS(w http.ResponseWriter, r *http.Request) {
 
 	w.Header().Set("Content-Type", "application/json")
 
 	var dns []models.DNSEntry
 	var params = mux.Vars(r)
-
-	dns, err := logic.GetNodeDNS(params["network"])
+	network := params["network"]
+	dns, err := logic.GetNodeDNS(network)
 	if err != nil {
+		logger.Log(0, r.Header.Get("user"),
+			fmt.Sprintf("failed to get node DNS entries for network [%s]: %v", network, err))
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 	}
-
-	//Returns all the nodes in JSON format
 	w.WriteHeader(http.StatusOK)
 	json.NewEncoder(w).Encode(dns)
 }
 
-//Gets all nodes associated with network, including pending nodes
+//Gets all DNS entries.
 func getAllDNS(w http.ResponseWriter, r *http.Request) {
 	w.Header().Set("Content-Type", "application/json")
 	dns, err := logic.GetAllDNS()
 	if err != nil {
+		logger.Log(0, r.Header.Get("user"), "failed to get all DNS entries: ", err.Error())
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 	}
-	//Returns all the nodes in JSON format
 	w.WriteHeader(http.StatusOK)
 	json.NewEncoder(w).Encode(dns)
 }
 
-//Gets all nodes associated with network, including pending nodes
+//Gets custom DNS entries associated with a network
 func getCustomDNS(w http.ResponseWriter, r *http.Request) {
 
 	w.Header().Set("Content-Type", "application/json")
 
 	var dns []models.DNSEntry
 	var params = mux.Vars(r)
-
-	dns, err := logic.GetCustomDNS(params["network"])
+	network := params["network"]
+	dns, err := logic.GetCustomDNS(network)
 	if err != nil {
+		logger.Log(0, r.Header.Get("user"),
+			fmt.Sprintf("failed to get custom DNS entries for network [%s]: %v", network, err.Error()))
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 	}
-
-	//Returns all the nodes in JSON format
 	w.WriteHeader(http.StatusOK)
 	json.NewEncoder(w).Encode(dns)
 }
 
-// Gets all nodes associated with network, including pending nodes
+// Gets all DNS entries associated with the network
 func getDNS(w http.ResponseWriter, r *http.Request) {
 
 	w.Header().Set("Content-Type", "application/json")
 
 	var dns []models.DNSEntry
 	var params = mux.Vars(r)
-
-	dns, err := logic.GetDNS(params["network"])
+	network := params["network"]
+	dns, err := logic.GetDNS(network)
 	if err != nil {
+		logger.Log(0, r.Header.Get("user"),
+			fmt.Sprintf("failed to get all DNS entries for network [%s]: %v", network, err.Error()))
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 	}
@@ -98,23 +101,28 @@ func createDNS(w http.ResponseWriter, r *http.Request) {
 	var entry models.DNSEntry
 	var params = mux.Vars(r)
 
-	//get node from body of request
 	_ = json.NewDecoder(r.Body).Decode(&entry)
 	entry.Network = params["network"]
 
 	err := logic.ValidateDNSCreate(entry)
 	if err != nil {
+		logger.Log(0, r.Header.Get("user"),
+			fmt.Sprintf("invalid DNS entry %+v: %v", entry, err))
 		returnErrorResponse(w, r, formatError(err, "badrequest"))
 		return
 	}
 
 	entry, err = CreateDNS(entry)
 	if err != nil {
+		logger.Log(0, r.Header.Get("user"),
+			fmt.Sprintf("Failed to create DNS entry %+v: %v", entry, err))
 		returnErrorResponse(w, r, 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))
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 	}
@@ -132,6 +140,8 @@ func createDNS(w http.ResponseWriter, r *http.Request) {
 			}
 		}
 	}
+	logger.Log(2, r.Header.Get("user"),
+		fmt.Sprintf("DNS entry is set: %+v", entry))
 	w.WriteHeader(http.StatusOK)
 	json.NewEncoder(w).Encode(entry)
 }
@@ -142,17 +152,19 @@ func deleteDNS(w http.ResponseWriter, r *http.Request) {
 
 	// get params
 	var params = mux.Vars(r)
-
+	entrytext := params["domain"] + "." + params["network"]
 	err := logic.DeleteDNS(params["domain"], params["network"])
 
 	if err != nil {
+		logger.Log(0, "failed to delete dns entry: ", entrytext)
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 	}
-	entrytext := params["domain"] + "." + params["network"]
 	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))
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 	}
@@ -197,6 +209,8 @@ func pushDNS(w http.ResponseWriter, r *http.Request) {
 	err := logic.SetDNS()
 
 	if err != nil {
+		logger.Log(0, r.Header.Get("user"),
+			fmt.Sprintf("Failed to set DNS entries on file: %v", err))
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 	}

+ 54 - 9
controllers/ext_client.go

@@ -43,8 +43,11 @@ func getNetworkExtClients(w http.ResponseWriter, r *http.Request) {
 
 	var extclients []models.ExtClient
 	var params = mux.Vars(r)
-	extclients, err := logic.GetNetworkExtClients(params["network"])
+	network := params["network"]
+	extclients, err := logic.GetNetworkExtClients(network)
 	if err != nil {
+		logger.Log(0, r.Header.Get("user"),
+			fmt.Sprintf("failed to get ext clients for network [%s]: %v", network, err))
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 	}
@@ -64,6 +67,8 @@ func getAllExtClients(w http.ResponseWriter, r *http.Request) {
 	networksSlice := []string{}
 	marshalErr := json.Unmarshal([]byte(headerNetworks), &networksSlice)
 	if marshalErr != nil {
+		logger.Log(0, "error unmarshalling networks: ",
+			marshalErr.Error())
 		returnErrorResponse(w, r, formatError(marshalErr, "internal"))
 		return
 	}
@@ -72,6 +77,7 @@ func getAllExtClients(w http.ResponseWriter, r *http.Request) {
 	if networksSlice[0] == ALL_NETWORK_ACCESS {
 		clients, err = functions.GetAllExtClients()
 		if err != nil && !database.IsEmptyRecord(err) {
+			logger.Log(0, "failed to get all extclients: ", err.Error())
 			returnErrorResponse(w, r, formatError(err, "internal"))
 			return
 		}
@@ -100,6 +106,8 @@ func getExtClient(w http.ResponseWriter, r *http.Request) {
 	network := params["network"]
 	client, err := logic.GetExtClient(clientid, network)
 	if err != nil {
+		logger.Log(0, r.Header.Get("user"), fmt.Sprintf("failed to get extclient for [%s] on network [%s]: %v",
+			clientid, network, err))
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 	}
@@ -118,13 +126,16 @@ func getExtClientConf(w http.ResponseWriter, r *http.Request) {
 	networkid := params["network"]
 	client, err := logic.GetExtClient(clientid, networkid)
 	if err != nil {
+		logger.Log(0, r.Header.Get("user"), fmt.Sprintf("failed to get extclient for [%s] on network [%s]: %v",
+			clientid, networkid, err))
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 	}
 
 	gwnode, err := logic.GetNodeByID(client.IngressGatewayID)
 	if err != nil {
-		logger.Log(1, r.Header.Get("user"), "Could not retrieve Ingress Gateway Node", client.IngressGatewayID)
+		logger.Log(0, r.Header.Get("user"),
+			fmt.Sprintf("failed to get ingress gateway node [%s] info: %v", client.IngressGatewayID, err))
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 	}
@@ -197,6 +208,7 @@ Endpoint = %s
 	if params["type"] == "qr" {
 		bytes, err := qrcode.Encode(config, qrcode.Medium, 220)
 		if err != nil {
+			logger.Log(1, r.Header.Get("user"), "failed to encode qr code: ", err.Error())
 			returnErrorResponse(w, r, formatError(err, "internal"))
 			return
 		}
@@ -204,6 +216,7 @@ Endpoint = %s
 		w.WriteHeader(http.StatusOK)
 		_, err = w.Write(bytes)
 		if err != nil {
+			logger.Log(1, r.Header.Get("user"), "response writer error (qr) ", err.Error())
 			returnErrorResponse(w, r, formatError(err, "internal"))
 			return
 		}
@@ -217,6 +230,7 @@ Endpoint = %s
 		w.WriteHeader(http.StatusOK)
 		_, err := fmt.Fprint(w, config)
 		if err != nil {
+			logger.Log(1, r.Header.Get("user"), "response writer error (file) ", err.Error())
 			returnErrorResponse(w, r, formatError(err, "internal"))
 		}
 		return
@@ -239,7 +253,10 @@ func createExtClient(w http.ResponseWriter, r *http.Request) {
 	nodeid := params["nodeid"]
 	ingressExists := checkIngressExists(nodeid)
 	if !ingressExists {
-		returnErrorResponse(w, r, formatError(errors.New("ingress does not exist"), "internal"))
+		err := errors.New("ingress does not exist")
+		logger.Log(0, r.Header.Get("user"),
+			fmt.Sprintf("failed to create extclient on network [%s]: %v", networkName, err))
+		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 	}
 
@@ -248,6 +265,8 @@ func createExtClient(w http.ResponseWriter, r *http.Request) {
 	extclient.IngressGatewayID = nodeid
 	node, err := logic.GetNodeByID(nodeid)
 	if err != nil {
+		logger.Log(0, r.Header.Get("user"),
+			fmt.Sprintf("failed to get ingress gateway node [%s] info: %v", nodeid, err))
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 	}
@@ -260,6 +279,8 @@ func createExtClient(w http.ResponseWriter, r *http.Request) {
 	}
 	err = logic.CreateExtClient(&extclient)
 	if err != nil {
+		logger.Log(0, r.Header.Get("user"),
+			fmt.Sprintf("failed to create new ext client on network [%s]: %v", networkName, err))
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 	}
@@ -278,25 +299,43 @@ func updateExtClient(w http.ResponseWriter, r *http.Request) {
 
 	var newExtClient models.ExtClient
 	var oldExtClient models.ExtClient
-	_ = json.NewDecoder(r.Body).Decode(&newExtClient)
-
-	key, err := logic.GetRecordKey(params["clientid"], params["network"])
+	err := json.NewDecoder(r.Body).Decode(&newExtClient)
+	if err != nil {
+		logger.Log(0, r.Header.Get("user"), "error decoding request body: ",
+			err.Error())
+		returnErrorResponse(w, r, formatError(err, "badrequest"))
+		return
+	}
+	clientid := params["clientid"]
+	network := params["network"]
+	key, err := logic.GetRecordKey(clientid, network)
 	if err != nil {
+		logger.Log(0, r.Header.Get("user"),
+			fmt.Sprintf("failed to get record key for client [%s], network [%s]: %v",
+				clientid, network, err))
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 	}
 	data, err := database.FetchRecord(database.EXT_CLIENT_TABLE_NAME, key)
 	if err != nil {
+		logger.Log(0, r.Header.Get("user"),
+			fmt.Sprintf("failed to fetch  ext client record key [%s] from db for client [%s], network [%s]: %v",
+				key, clientid, network, err))
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 	}
 	if err = json.Unmarshal([]byte(data), &oldExtClient); err != nil {
+		logger.Log(0, "error unmarshalling extclient: ",
+			err.Error())
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 	}
 	var changedEnabled = newExtClient.Enabled != oldExtClient.Enabled // indicates there was a change in enablement
 	newclient, err := logic.UpdateExtClient(newExtClient.ClientID, params["network"], newExtClient.Enabled, &oldExtClient)
 	if err != nil {
+		logger.Log(0, r.Header.Get("user"),
+			fmt.Sprintf("failed to update ext client [%s], network [%s]: %v",
+				clientid, network, err))
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 	}
@@ -320,22 +359,28 @@ func deleteExtClient(w http.ResponseWriter, r *http.Request) {
 
 	// get params
 	var params = mux.Vars(r)
-
-	extclient, err := logic.GetExtClient(params["clientid"], params["network"])
+	clientid := params["clientid"]
+	network := params["network"]
+	extclient, err := logic.GetExtClient(clientid, network)
 	if err != nil {
 		err = errors.New("Could not delete extclient " + params["clientid"])
+		logger.Log(0, r.Header.Get("user"),
+			fmt.Sprintf("failed to delete extclient [%s],network [%s]: %v", clientid, network, err))
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 	}
 	ingressnode, err := logic.GetNodeByID(extclient.IngressGatewayID)
 	if err != nil {
+		logger.Log(0, r.Header.Get("user"),
+			fmt.Sprintf("failed to get ingress gateway node [%s] info: %v", extclient.IngressGatewayID, err))
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 	}
 
 	err = logic.DeleteExtClient(params["network"], params["clientid"])
-
 	if err != nil {
+		logger.Log(0, r.Header.Get("user"),
+			fmt.Sprintf("failed to delete extclient [%s],network [%s]: %v", clientid, network, err))
 		err = errors.New("Could not delete extclient " + params["clientid"])
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return

+ 79 - 8
controllers/network.go

@@ -46,7 +46,9 @@ func getNetworks(w http.ResponseWriter, r *http.Request) {
 	networksSlice := []string{}
 	marshalErr := json.Unmarshal([]byte(headerNetworks), &networksSlice)
 	if marshalErr != nil {
-		returnErrorResponse(w, r, formatError(marshalErr, "internal"))
+		logger.Log(0, r.Header.Get("user"), "error unmarshalling networks: ",
+			marshalErr.Error())
+		returnErrorResponse(w, r, formatError(marshalErr, "badrequest"))
 		return
 	}
 	allnetworks := []models.Network{}
@@ -54,6 +56,7 @@ func getNetworks(w http.ResponseWriter, r *http.Request) {
 	if networksSlice[0] == ALL_NETWORK_ACCESS {
 		allnetworks, err = logic.GetNetworks()
 		if err != nil && !database.IsEmptyRecord(err) {
+			logger.Log(0, r.Header.Get("user"), "failed to fetch networks: ", err.Error())
 			returnErrorResponse(w, r, formatError(err, "internal"))
 			return
 		}
@@ -85,6 +88,8 @@ func getNetwork(w http.ResponseWriter, r *http.Request) {
 	netname := params["networkname"]
 	network, err := logic.GetNetwork(netname)
 	if err != nil {
+		logger.Log(0, r.Header.Get("user"), fmt.Sprintf("failed to fetch network [%s] info: %v",
+			netname, err))
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 	}
@@ -102,6 +107,8 @@ func keyUpdate(w http.ResponseWriter, r *http.Request) {
 	netname := params["networkname"]
 	network, err := logic.KeyUpdate(netname)
 	if err != nil {
+		logger.Log(0, r.Header.Get("user"), fmt.Sprintf("failed to update keys for network [%s]: %v",
+			netname, err))
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 	}
@@ -110,7 +117,7 @@ func keyUpdate(w http.ResponseWriter, r *http.Request) {
 	json.NewEncoder(w).Encode(network)
 	nodes, err := logic.GetNetworkNodes(netname)
 	if err != nil {
-		logger.Log(2, "failed to retrieve network nodes for network", netname, err.Error())
+		logger.Log(0, "failed to retrieve network nodes for network", netname, err.Error())
 		return
 	}
 	for _, node := range nodes {
@@ -132,12 +139,16 @@ func updateNetwork(w http.ResponseWriter, r *http.Request) {
 
 	network, err := logic.GetParentNetwork(netname)
 	if err != nil {
+		logger.Log(0, r.Header.Get("user"), "failed to get network info: ",
+			err.Error())
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 	}
 	var newNetwork models.Network
 	err = json.NewDecoder(r.Body).Decode(&newNetwork)
 	if err != nil {
+		logger.Log(0, r.Header.Get("user"), "error decoding request body: ",
+			err.Error())
 		returnErrorResponse(w, r, formatError(err, "badrequest"))
 		return
 	}
@@ -149,6 +160,8 @@ func updateNetwork(w http.ResponseWriter, r *http.Request) {
 
 	rangeupdate4, rangeupdate6, localrangeupdate, holepunchupdate, err := logic.UpdateNetwork(&network, &newNetwork)
 	if err != nil {
+		logger.Log(0, r.Header.Get("user"), "failed to update network: ",
+			err.Error())
 		returnErrorResponse(w, r, formatError(err, "badrequest"))
 		return
 	}
@@ -156,6 +169,9 @@ func updateNetwork(w http.ResponseWriter, r *http.Request) {
 	if rangeupdate4 {
 		err = logic.UpdateNetworkNodeAddresses(network.NetID)
 		if err != nil {
+			logger.Log(0, r.Header.Get("user"),
+				fmt.Sprintf("failed to update network [%s] ipv4 addresses: %v",
+					network.NetID, err.Error()))
 			returnErrorResponse(w, r, formatError(err, "internal"))
 			return
 		}
@@ -163,6 +179,9 @@ func updateNetwork(w http.ResponseWriter, r *http.Request) {
 	if rangeupdate6 {
 		err = logic.UpdateNetworkNodeAddresses6(network.NetID)
 		if err != nil {
+			logger.Log(0, r.Header.Get("user"),
+				fmt.Sprintf("failed to update network [%s] ipv6 addresses: %v",
+					network.NetID, err.Error()))
 			returnErrorResponse(w, r, formatError(err, "internal"))
 			return
 		}
@@ -170,6 +189,9 @@ func updateNetwork(w http.ResponseWriter, r *http.Request) {
 	if localrangeupdate {
 		err = logic.UpdateNetworkLocalAddresses(network.NetID)
 		if err != nil {
+			logger.Log(0, r.Header.Get("user"),
+				fmt.Sprintf("failed to update network [%s] local addresses: %v",
+					network.NetID, err.Error()))
 			returnErrorResponse(w, r, formatError(err, "internal"))
 			return
 		}
@@ -177,6 +199,9 @@ func updateNetwork(w http.ResponseWriter, r *http.Request) {
 	if holepunchupdate {
 		err = logic.UpdateNetworkHolePunching(network.NetID, newNetwork.DefaultUDPHolePunch)
 		if err != nil {
+			logger.Log(0, r.Header.Get("user"),
+				fmt.Sprintf("failed to update network [%s] hole punching: %v",
+					network.NetID, err.Error()))
 			returnErrorResponse(w, r, formatError(err, "internal"))
 			return
 		}
@@ -184,6 +209,9 @@ func updateNetwork(w http.ResponseWriter, r *http.Request) {
 	if rangeupdate4 || rangeupdate6 || localrangeupdate || holepunchupdate {
 		nodes, err := logic.GetNetworkNodes(network.NetID)
 		if err != nil {
+			logger.Log(0, r.Header.Get("user"),
+				fmt.Sprintf("failed to get network [%s] nodes: %v",
+					network.NetID, err.Error()))
 			returnErrorResponse(w, r, formatError(err, "internal"))
 			return
 		}
@@ -206,18 +234,28 @@ func updateNetworkNodeLimit(w http.ResponseWriter, r *http.Request) {
 	netname := params["networkname"]
 	network, err := logic.GetParentNetwork(netname)
 	if err != nil {
+		logger.Log(0, r.Header.Get("user"),
+			fmt.Sprintf("failed to get network [%s] nodes: %v",
+				network.NetID, err.Error()))
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 	}
 
 	var networkChange models.Network
 
-	_ = json.NewDecoder(r.Body).Decode(&networkChange)
-
+	err = json.NewDecoder(r.Body).Decode(&networkChange)
+	if err != nil {
+		logger.Log(0, r.Header.Get("user"), "error decoding request body: ",
+			err.Error())
+		returnErrorResponse(w, r, formatError(err, "badrequest"))
+		return
+	}
 	if networkChange.NodeLimit != 0 {
 		network.NodeLimit = networkChange.NodeLimit
 		data, err := json.Marshal(&network)
 		if err != nil {
+			logger.Log(0, r.Header.Get("user"),
+				"error marshalling resp: ", err.Error())
 			returnErrorResponse(w, r, formatError(err, "badrequest"))
 			return
 		}
@@ -235,12 +273,22 @@ func updateNetworkACL(w http.ResponseWriter, r *http.Request) {
 	var networkACLChange acls.ACLContainer
 	networkACLChange, err := networkACLChange.Get(acls.ContainerID(netname))
 	if err != nil {
+		logger.Log(0, r.Header.Get("user"),
+			fmt.Sprintf("failed to fetch ACLs for network [%s]: %v", netname, err))
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 	}
-	_ = json.NewDecoder(r.Body).Decode(&networkACLChange)
+	err = json.NewDecoder(r.Body).Decode(&networkACLChange)
+	if err != nil {
+		logger.Log(0, r.Header.Get("user"), "error decoding request body: ",
+			err.Error())
+		returnErrorResponse(w, r, formatError(err, "badrequest"))
+		return
+	}
 	newNetACL, err := networkACLChange.Save(acls.ContainerID(netname))
 	if err != nil {
+		logger.Log(0, r.Header.Get("user"),
+			fmt.Sprintf("failed to update ACLs for network [%s]: %v", netname, err))
 		returnErrorResponse(w, r, formatError(err, "badrequest"))
 		return
 	}
@@ -272,6 +320,8 @@ func getNetworkACL(w http.ResponseWriter, r *http.Request) {
 	var networkACL acls.ACLContainer
 	networkACL, err := networkACL.Get(acls.ContainerID(netname))
 	if err != nil {
+		logger.Log(0, r.Header.Get("user"),
+			fmt.Sprintf("failed to fetch ACLs for network [%s]: %v", netname, err))
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 	}
@@ -294,6 +344,8 @@ func deleteNetwork(w http.ResponseWriter, r *http.Request) {
 		if strings.Contains(err.Error(), "Node check failed") {
 			errtype = "forbidden"
 		}
+		logger.Log(0, r.Header.Get("user"),
+			fmt.Sprintf("failed to delete network [%s]: %v", network, err))
 		returnErrorResponse(w, r, formatError(err, errtype))
 		return
 	}
@@ -311,17 +363,24 @@ func createNetwork(w http.ResponseWriter, r *http.Request) {
 	// we decode our body request params
 	err := json.NewDecoder(r.Body).Decode(&network)
 	if err != nil {
-		returnErrorResponse(w, r, formatError(err, "internal"))
+		logger.Log(0, r.Header.Get("user"), "error decoding request body: ",
+			err.Error())
+		returnErrorResponse(w, r, formatError(err, "badrequest"))
 		return
 	}
 
 	if network.AddressRange == "" && network.AddressRange6 == "" {
-		returnErrorResponse(w, r, formatError(fmt.Errorf("IPv4 or IPv6 CIDR required"), "badrequest"))
+		err := errors.New("IPv4 or IPv6 CIDR required")
+		logger.Log(0, r.Header.Get("user"), "failed to create network: ",
+			err.Error())
+		returnErrorResponse(w, r, formatError(err, "badrequest"))
 		return
 	}
 
 	network, err = logic.CreateNetwork(network)
 	if err != nil {
+		logger.Log(0, r.Header.Get("user"), "failed to create network: ",
+			err.Error())
 		returnErrorResponse(w, r, formatError(err, "badrequest"))
 		return
 	}
@@ -333,6 +392,8 @@ func createNetwork(w http.ResponseWriter, r *http.Request) {
 			if err == nil {
 				err = errors.New("Failed to add server to network " + network.NetID)
 			}
+			logger.Log(0, r.Header.Get("user"), "failed to create network: ",
+				err.Error())
 			returnErrorResponse(w, r, formatError(err, "internal"))
 			return
 		}
@@ -352,16 +413,22 @@ func createAccessKey(w http.ResponseWriter, r *http.Request) {
 	netname := params["networkname"]
 	network, err := logic.GetParentNetwork(netname)
 	if err != nil {
+		logger.Log(0, r.Header.Get("user"), "failed to get network info: ",
+			err.Error())
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 	}
 	err = json.NewDecoder(r.Body).Decode(&accesskey)
 	if err != nil {
-		returnErrorResponse(w, r, formatError(err, "internal"))
+		logger.Log(0, r.Header.Get("user"), "error decoding request body: ",
+			err.Error())
+		returnErrorResponse(w, r, formatError(err, "badrequest"))
 		return
 	}
 	key, err := logic.CreateAccessKey(accesskey, network)
 	if err != nil {
+		logger.Log(0, r.Header.Get("user"), "failed to create access key: ",
+			err.Error())
 		returnErrorResponse(w, r, formatError(err, "badrequest"))
 		return
 	}
@@ -377,6 +444,8 @@ func getAccessKeys(w http.ResponseWriter, r *http.Request) {
 	network := params["networkname"]
 	keys, err := logic.GetKeys(network)
 	if err != nil {
+		logger.Log(0, r.Header.Get("user"), fmt.Sprintf("failed to get keys for network [%s]: %v",
+			network, err))
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 	}
@@ -396,6 +465,8 @@ func deleteAccessKey(w http.ResponseWriter, r *http.Request) {
 	netname := params["networkname"]
 	err := logic.DeleteKey(keyname, netname)
 	if err != nil {
+		logger.Log(0, r.Header.Get("user"), fmt.Sprintf("failed to delete key [%s] for network [%s]: %v",
+			keyname, netname, err))
 		returnErrorResponse(w, r, formatError(err, "badrequest"))
 		return
 	}

+ 10 - 10
controllers/network_test.go

@@ -223,16 +223,16 @@ func TestValidateNetwork(t *testing.T) {
 				NetID:        "skynet",
 				AddressRange: "10.0.0.256",
 			},
-			errMessage: "Field validation for 'AddressRange' failed on the 'cidr' tag",
+			errMessage: "Field validation for 'AddressRange' failed on the 'cidrv4' tag",
+		},
+		{
+			testname: "InvalidAddress6",
+			network: models.Network{
+				NetID:         "skynet1",
+				AddressRange6: "2607::ffff/130",
+			},
+			errMessage: "Field validation for 'AddressRange6' failed on the 'cidrv6' tag",
 		},
-		//{
-		//	testname: "InvalidAddress6",
-		//	network: models.Network{
-		//		NetID:         "skynet1",
-		//		AddressRange6: "2607::ffff/130",
-		//	},
-		//	errMessage: "Field validation for 'AddressRange6' failed on the 'cidr' tag",
-		//},
 		{
 			testname: "InvalidNetID",
 			network: models.Network{
@@ -287,7 +287,7 @@ func TestValidateNetwork(t *testing.T) {
 			network.SetDefaults()
 			err := logic.ValidateNetwork(&network, false)
 			assert.NotNil(t, err)
-			assert.Contains(t, err.Error(), tc.errMessage)
+			assert.Contains(t, err.Error(), tc.errMessage) // test passes if err.Error() contains the expected errMessage.
 		})
 	}
 }

+ 80 - 10
controllers/node.go

@@ -51,16 +51,20 @@ func authenticate(response http.ResponseWriter, request *http.Request) {
 	if decoderErr != nil {
 		errorResponse.Code = http.StatusBadRequest
 		errorResponse.Message = decoderErr.Error()
+		logger.Log(0, request.Header.Get("user"), "error decoding request body: ",
+			decoderErr.Error())
 		returnErrorResponse(response, request, errorResponse)
 		return
 	} else {
 		errorResponse.Code = http.StatusBadRequest
 		if authRequest.ID == "" {
 			errorResponse.Message = "W1R3: ID can't be empty"
+			logger.Log(0, request.Header.Get("user"), errorResponse.Message)
 			returnErrorResponse(response, request, errorResponse)
 			return
 		} else if authRequest.Password == "" {
 			errorResponse.Message = "W1R3: Password can't be empty"
+			logger.Log(0, request.Header.Get("user"), errorResponse.Message)
 			returnErrorResponse(response, request, errorResponse)
 			return
 		} else {
@@ -70,6 +74,8 @@ func authenticate(response http.ResponseWriter, request *http.Request) {
 			if err != nil {
 				errorResponse.Code = http.StatusBadRequest
 				errorResponse.Message = err.Error()
+				logger.Log(0, request.Header.Get("user"),
+					fmt.Sprintf("failed to get node info [%s]: %v", authRequest.ID, err))
 				returnErrorResponse(response, request, errorResponse)
 				return
 			}
@@ -78,14 +84,18 @@ func authenticate(response http.ResponseWriter, request *http.Request) {
 			if err != nil {
 				errorResponse.Code = http.StatusBadRequest
 				errorResponse.Message = err.Error()
+				logger.Log(0, request.Header.Get("user"),
+					"error validating user password: ", err.Error())
 				returnErrorResponse(response, request, errorResponse)
 				return
 			} else {
-				tokenString, _ := logic.CreateJWT(authRequest.ID, authRequest.MacAddress, result.Network)
+				tokenString, err := logic.CreateJWT(authRequest.ID, authRequest.MacAddress, result.Network)
 
 				if tokenString == "" {
 					errorResponse.Code = http.StatusBadRequest
 					errorResponse.Message = "Could not create Token"
+					logger.Log(0, request.Header.Get("user"),
+						fmt.Sprintf("%s: %v", errorResponse.Message, err))
 					returnErrorResponse(response, request, errorResponse)
 					return
 				}
@@ -103,6 +113,8 @@ func authenticate(response http.ResponseWriter, request *http.Request) {
 				if jsonError != nil {
 					errorResponse.Code = http.StatusBadRequest
 					errorResponse.Message = err.Error()
+					logger.Log(0, request.Header.Get("user"),
+						"error marshalling resp: ", err.Error())
 					returnErrorResponse(response, request, errorResponse)
 					return
 				}
@@ -301,6 +313,8 @@ func getNetworkNodes(w http.ResponseWriter, r *http.Request) {
 
 	nodes, err := logic.GetNetworkNodes(networkName)
 	if err != nil {
+		logger.Log(0, r.Header.Get("user"),
+			fmt.Sprintf("error fetching nodes on network %s: %v", networkName, err))
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 	}
@@ -317,6 +331,8 @@ func getAllNodes(w http.ResponseWriter, r *http.Request) {
 	w.Header().Set("Content-Type", "application/json")
 	user, err := logic.GetUser(r.Header.Get("user"))
 	if err != nil && r.Header.Get("ismasterkey") != "yes" {
+		logger.Log(0, r.Header.Get("user"),
+			"error fetching user info: ", err.Error())
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 	}
@@ -324,12 +340,15 @@ func getAllNodes(w http.ResponseWriter, r *http.Request) {
 	if user.IsAdmin || r.Header.Get("ismasterkey") == "yes" {
 		nodes, err = logic.GetAllNodes()
 		if err != nil {
+			logger.Log(0, "error fetching all nodes info: ", err.Error())
 			returnErrorResponse(w, r, formatError(err, "internal"))
 			return
 		}
 	} else {
 		nodes, err = getUsersNodes(user)
 		if err != nil {
+			logger.Log(0, r.Header.Get("user"),
+				"error fetching nodes: ", err.Error())
 			returnErrorResponse(w, r, formatError(err, "internal"))
 			return
 		}
@@ -359,15 +378,19 @@ func getNode(w http.ResponseWriter, r *http.Request) {
 	w.Header().Set("Content-Type", "application/json")
 
 	var params = mux.Vars(r)
-
-	node, err := logic.GetNodeByID(params["nodeid"])
+	nodeid := params["nodeid"]
+	node, err := logic.GetNodeByID(nodeid)
 	if err != nil {
+		logger.Log(0, r.Header.Get("user"),
+			fmt.Sprintf("error fetching node [ %s ] info: %v", nodeid, err))
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 	}
 
 	peerUpdate, err := logic.GetPeerUpdate(&node)
 	if err != nil && !database.IsEmptyRecord(err) {
+		logger.Log(0, r.Header.Get("user"),
+			fmt.Sprintf("error fetching wg peers config for node [ %s ]: %v", nodeid, err))
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 	}
@@ -392,8 +415,11 @@ func getLastModified(w http.ResponseWriter, r *http.Request) {
 	w.Header().Set("Content-Type", "application/json")
 
 	var params = mux.Vars(r)
-	network, err := logic.GetNetwork(params["network"])
+	networkName := params["network"]
+	network, err := logic.GetNetwork(networkName)
 	if err != nil {
+		logger.Log(0, r.Header.Get("user"),
+			fmt.Sprintf("error fetching network [%s] info: %v", networkName, err))
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 	}
@@ -414,12 +440,16 @@ func createNode(w http.ResponseWriter, r *http.Request) {
 	networkexists, err := functions.NetworkExists(networkName)
 
 	if err != nil {
+		logger.Log(0, r.Header.Get("user"),
+			fmt.Sprintf("failed to fetch network [%s] info: %v", networkName, err))
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 	} else if !networkexists {
 		errorResponse = models.ErrorResponse{
 			Code: http.StatusNotFound, Message: "W1R3: Network does not exist! ",
 		}
+		logger.Log(0, r.Header.Get("user"),
+			fmt.Sprintf("network [%s] does not exist", networkName))
 		returnErrorResponse(w, r, errorResponse)
 		return
 	}
@@ -429,7 +459,8 @@ func createNode(w http.ResponseWriter, r *http.Request) {
 	//get node from body of request
 	err = json.NewDecoder(r.Body).Decode(&node)
 	if err != nil {
-		returnErrorResponse(w, r, formatError(err, "internal"))
+		logger.Log(0, r.Header.Get("user"), "error decoding request body: ", err.Error())
+		returnErrorResponse(w, r, formatError(err, "badrequest"))
 		return
 	}
 
@@ -437,11 +468,15 @@ func createNode(w http.ResponseWriter, r *http.Request) {
 
 	network, err := logic.GetNetworkByNode(&node)
 	if err != nil {
+		logger.Log(0, r.Header.Get("user"),
+			fmt.Sprintf("failed to get network [%s] info: %v", node.Network, err))
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 	}
 	node.NetworkSettings, err = logic.GetNetworkSettings(node.Network)
 	if err != nil {
+		logger.Log(0, r.Header.Get("user"),
+			fmt.Sprintf("failed to get network [%s] settings: %v", node.Network, err))
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 	}
@@ -455,6 +490,9 @@ func createNode(w http.ResponseWriter, r *http.Request) {
 			errorResponse = models.ErrorResponse{
 				Code: http.StatusUnauthorized, Message: "W1R3: Key invalid, or none provided.",
 			}
+			logger.Log(0, r.Header.Get("user"),
+				fmt.Sprintf("failed to create node on network [%s]: %s",
+					node.Network, errorResponse.Message))
 			returnErrorResponse(w, r, errorResponse)
 			return
 		}
@@ -482,12 +520,17 @@ func createNode(w http.ResponseWriter, r *http.Request) {
 
 	err = logic.CreateNode(&node)
 	if err != nil {
+		logger.Log(0, r.Header.Get("user"),
+			fmt.Sprintf("failed to create node on network [%s]: %s",
+				node.Network, err))
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 	}
 
 	peerUpdate, err := logic.GetPeerUpdate(&node)
 	if err != nil && !database.IsEmptyRecord(err) {
+		logger.Log(0, r.Header.Get("user"),
+			fmt.Sprintf("error fetching wg peers config for node [ %s ]: %v", node.ID, err))
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 	}
@@ -512,6 +555,8 @@ func uncordonNode(w http.ResponseWriter, r *http.Request) {
 	var nodeid = params["nodeid"]
 	node, err := logic.UncordonNode(nodeid)
 	if err != nil {
+		logger.Log(0, r.Header.Get("user"),
+			fmt.Sprintf("failed to uncordon node [%s]: %v", node.Name, err))
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 	}
@@ -530,13 +575,17 @@ func createEgressGateway(w http.ResponseWriter, r *http.Request) {
 	w.Header().Set("Content-Type", "application/json")
 	err := json.NewDecoder(r.Body).Decode(&gateway)
 	if err != nil {
-		returnErrorResponse(w, r, formatError(err, "internal"))
+		logger.Log(0, r.Header.Get("user"), "error decoding request body: ", err.Error())
+		returnErrorResponse(w, r, formatError(err, "badrequest"))
 		return
 	}
 	gateway.NetID = params["network"]
 	gateway.NodeID = params["nodeid"]
 	node, err := logic.CreateEgressGateway(gateway)
 	if err != nil {
+		logger.Log(0, r.Header.Get("user"),
+			fmt.Sprintf("failed to create egress gateway on node [%s] on network [%s]: %v",
+				gateway.NodeID, gateway.NetID, err))
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 	}
@@ -555,11 +604,14 @@ func deleteEgressGateway(w http.ResponseWriter, r *http.Request) {
 	netid := params["network"]
 	node, err := logic.DeleteEgressGateway(netid, nodeid)
 	if err != nil {
+		logger.Log(0, r.Header.Get("user"),
+			fmt.Sprintf("failed to delete egress gateway on node [%s] on network [%s]: %v",
+				nodeid, netid, err))
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 	}
 
-	logger.Log(1, r.Header.Get("user"), "deleted egress gateway", nodeid, "on network", netid)
+	logger.Log(1, r.Header.Get("user"), "deleted egress gateway on node", nodeid, "on network", netid)
 	w.WriteHeader(http.StatusOK)
 	json.NewEncoder(w).Encode(node)
 
@@ -575,6 +627,9 @@ func createIngressGateway(w http.ResponseWriter, r *http.Request) {
 	netid := params["network"]
 	node, err := logic.CreateIngressGateway(netid, nodeid)
 	if err != nil {
+		logger.Log(0, r.Header.Get("user"),
+			fmt.Sprintf("failed to create ingress gateway on node [%s] on network [%s]: %v",
+				nodeid, netid, err))
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 	}
@@ -590,8 +645,12 @@ func deleteIngressGateway(w http.ResponseWriter, r *http.Request) {
 	w.Header().Set("Content-Type", "application/json")
 	var params = mux.Vars(r)
 	nodeid := params["nodeid"]
-	node, err := logic.DeleteIngressGateway(params["network"], nodeid)
+	netid := params["network"]
+	node, err := logic.DeleteIngressGateway(netid, nodeid)
 	if err != nil {
+		logger.Log(0, r.Header.Get("user"),
+			fmt.Sprintf("failed to delete ingress gateway on node [%s] on network [%s]: %v",
+				nodeid, netid, err))
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 	}
@@ -610,8 +669,11 @@ func updateNode(w http.ResponseWriter, r *http.Request) {
 
 	var node models.Node
 	//start here
-	node, err := logic.GetNodeByID(params["nodeid"])
+	nodeid := params["nodeid"]
+	node, err := logic.GetNodeByID(nodeid)
 	if err != nil {
+		logger.Log(0, r.Header.Get("user"),
+			fmt.Sprintf("error fetching node [ %s ] info: %v", nodeid, err))
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 	}
@@ -620,6 +682,7 @@ func updateNode(w http.ResponseWriter, r *http.Request) {
 	// we decode our body request params
 	err = json.NewDecoder(r.Body).Decode(&newNode)
 	if err != nil {
+		logger.Log(0, r.Header.Get("user"), "error decoding request body: ", err.Error())
 		returnErrorResponse(w, r, formatError(err, "badrequest"))
 		return
 	}
@@ -666,6 +729,8 @@ func updateNode(w http.ResponseWriter, r *http.Request) {
 
 	err = logic.UpdateNode(&node, &newNode)
 	if err != nil {
+		logger.Log(0, r.Header.Get("user"),
+			fmt.Sprintf("failed to update node info [ %s ] info: %v", nodeid, err))
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 	}
@@ -703,11 +768,16 @@ func deleteNode(w http.ResponseWriter, r *http.Request) {
 	var nodeid = params["nodeid"]
 	var node, err = logic.GetNodeByID(nodeid)
 	if err != nil {
+		logger.Log(0, r.Header.Get("user"),
+			fmt.Sprintf("error fetching node [ %s ] info: %v", nodeid, err))
 		returnErrorResponse(w, r, formatError(err, "badrequest"))
 		return
 	}
 	if isServer(&node) {
-		returnErrorResponse(w, r, formatError(fmt.Errorf("cannot delete server node"), "badrequest"))
+		err := fmt.Errorf("cannot delete server node")
+		logger.Log(0, r.Header.Get("user"),
+			fmt.Sprintf("failed to delete node [ %s ]: %v", nodeid, err))
+		returnErrorResponse(w, r, formatError(err, "badrequest"))
 		return
 	}
 	//send update to node to be deleted before deleting on server otherwise message cannot be sent

+ 34 - 0
controllers/node_test.go

@@ -33,7 +33,39 @@ func TestCreateEgressGateway(t *testing.T) {
 		assert.Equal(t, models.Node{}, node)
 		assert.EqualError(t, err, "windows is unsupported for egress gateways")
 	})
+	t.Run("Success-Nat-Enabled", func(t *testing.T) {
+		deleteAllNodes()
+		testnode := createTestNode()
+		gateway.NodeID = testnode.ID
+		gateway.NatEnabled = "yes"
+
+		node, err := logic.CreateEgressGateway(gateway)
+		t.Log(node.EgressGatewayNatEnabled)
+		t.Log(node.PostUp)
+		t.Log(node.PostDown)
+		assert.Nil(t, err)
+		assert.Contains(t, node.PostUp, "-j MASQUERADE")
+		assert.Contains(t, node.PostDown, "-j MASQUERADE")
+	})
+	t.Run("Success-Nat-Disabled", func(t *testing.T) {
+		deleteAllNodes()
+		testnode := createTestNode()
+		gateway.NodeID = testnode.ID
+		gateway.NatEnabled = "no"
+
+		node, err := logic.CreateEgressGateway(gateway)
+		t.Log(node.EgressGatewayNatEnabled)
+		t.Log(node.PostUp)
+		t.Log(node.PostDown)
+		assert.Nil(t, err)
+		assert.NotContains(t, node.PostUp, "-j MASUERADE")
+		assert.NotContains(t, node.PostDown, "-j MASUERADE")
+	})
 	t.Run("Success", func(t *testing.T) {
+		var gateway models.EgressGatewayRequest
+		gateway.Interface = "eth0"
+		gateway.Ranges = []string{"10.100.100.0/24"}
+		gateway.NetID = "skynet"
 		deleteAllNodes()
 		testnode := createTestNode()
 		gateway.NodeID = testnode.ID
@@ -41,6 +73,8 @@ func TestCreateEgressGateway(t *testing.T) {
 		node, err := logic.CreateEgressGateway(gateway)
 		t.Log(node)
 		assert.Nil(t, err)
+		assert.Contains(t, node.PostUp, "-j MASQUERADE")
+		assert.Contains(t, node.PostDown, "-j MASQUERADE")
 		assert.Equal(t, "yes", node.IsEgressGateway)
 		assert.Equal(t, gateway.Ranges, node.EgressGatewayRanges)
 	})

+ 7 - 2
controllers/relay.go

@@ -2,6 +2,7 @@ package controller
 
 import (
 	"encoding/json"
+	"fmt"
 	"net/http"
 
 	"github.com/gorilla/mux"
@@ -17,13 +18,16 @@ func createRelay(w http.ResponseWriter, r *http.Request) {
 	w.Header().Set("Content-Type", "application/json")
 	err := json.NewDecoder(r.Body).Decode(&relay)
 	if err != nil {
-		returnErrorResponse(w, r, formatError(err, "internal"))
+		logger.Log(0, r.Header.Get("user"), "error decoding request body: ", err.Error())
+		returnErrorResponse(w, r, formatError(err, "badrequest"))
 		return
 	}
 	relay.NetID = params["network"]
 	relay.NodeID = params["nodeid"]
 	updatenodes, node, err := logic.CreateRelay(relay)
 	if err != nil {
+		logger.Log(0, r.Header.Get("user"),
+			fmt.Sprintf("failed to create relay on node [%s] on network [%s]: %v", relay.NodeID, relay.NetID, err))
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 	}
@@ -46,7 +50,8 @@ func deleteRelay(w http.ResponseWriter, r *http.Request) {
 	netid := params["network"]
 	updatenodes, node, err := logic.DeleteRelay(netid, nodeid)
 	if err != nil {
-		returnErrorResponse(w, r, formatError(err, "internal"))
+		logger.Log(0, r.Header.Get("user"), "error decoding request body: ", err.Error())
+		returnErrorResponse(w, r, formatError(err, "badrequest"))
 		return
 	}
 	logger.Log(1, r.Header.Get("user"), "deleted relay server", nodeid, "on network", netid)

+ 10 - 5
controllers/server.go

@@ -73,14 +73,17 @@ func removeNetwork(w http.ResponseWriter, r *http.Request) {
 
 	// get params
 	var params = mux.Vars(r)
-
-	err := logic.DeleteNetwork(params["network"])
+	network := params["network"]
+	err := logic.DeleteNetwork(network)
 	if err != nil {
-		json.NewEncoder(w).Encode("Could not remove server from network " + params["network"])
+		logger.Log(0, r.Header.Get("user"),
+			fmt.Sprintf("failed to delete network [%s]: %v", network, err))
+		json.NewEncoder(w).Encode(fmt.Sprintf("could not remove network %s from server", network))
 		return
 	}
-
-	json.NewEncoder(w).Encode("Server removed from network " + params["network"])
+	logger.Log(1, r.Header.Get("user"),
+		fmt.Sprintf("deleted network [%s]: %v", network, err))
+	json.NewEncoder(w).Encode(fmt.Sprintf("network %s removed from server", network))
 }
 
 func getServerInfo(w http.ResponseWriter, r *http.Request) {
@@ -137,6 +140,8 @@ func register(w http.ResponseWriter, r *http.Request) {
 		Broker:     servercfg.GetServer(),
 		Port:       servercfg.GetMQPort(),
 	}
+	logger.Log(2, r.Header.Get("user"),
+		fmt.Sprintf("registered client [%+v] with server", request))
 	w.WriteHeader(http.StatusOK)
 	json.NewEncoder(w).Encode(response)
 }

+ 69 - 19
controllers/user.go

@@ -44,23 +44,27 @@ func authenticateUser(response http.ResponseWriter, request *http.Request) {
 	decoderErr := decoder.Decode(&authRequest)
 	defer request.Body.Close()
 	if decoderErr != nil {
+		logger.Log(0, "error decoding request body: ",
+			decoderErr.Error())
 		returnErrorResponse(response, request, errorResponse)
 		return
 	}
-
+	username := authRequest.UserName
 	jwt, err := logic.VerifyAuthRequest(authRequest)
 	if err != nil {
+		logger.Log(0, username, "user validation failed: ",
+			err.Error())
 		returnErrorResponse(response, request, formatError(err, "badrequest"))
 		return
 	}
 
 	if jwt == "" {
 		// very unlikely that err is !nil and no jwt returned, but handle it anyways.
+		logger.Log(0, username, "jwt token is empty")
 		returnErrorResponse(response, request, formatError(errors.New("no token returned"), "internal"))
 		return
 	}
 
-	username := authRequest.UserName
 	var successResponse = models.SuccessResponse{
 		Code:    http.StatusOK,
 		Message: "W1R3: Device " + username + " Authorized",
@@ -73,6 +77,8 @@ func authenticateUser(response http.ResponseWriter, request *http.Request) {
 	successJSONResponse, jsonError := json.Marshal(successResponse)
 
 	if jsonError != nil {
+		logger.Log(0, username,
+			"error marshalling resp: ", err.Error())
 		returnErrorResponse(response, request, errorResponse)
 		return
 	}
@@ -87,6 +93,7 @@ func hasAdmin(w http.ResponseWriter, r *http.Request) {
 
 	hasadmin, err := logic.HasAdmin()
 	if err != nil {
+		logger.Log(0, "failed to check for admin: ", err.Error())
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 	}
@@ -109,7 +116,7 @@ func GetUserInternal(username string) (models.User, error) {
 	return user, err
 }
 
-// Get an individual node. Nothin fancy here folks.
+// Get an individual user. Nothin fancy here folks.
 func getUser(w http.ResponseWriter, r *http.Request) {
 	// set header.
 	w.Header().Set("Content-Type", "application/json")
@@ -119,6 +126,7 @@ func getUser(w http.ResponseWriter, r *http.Request) {
 	user, err := logic.GetUser(usernameFetched)
 
 	if err != nil {
+		logger.Log(0, usernameFetched, "failed to fetch user: ", err.Error())
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 	}
@@ -126,7 +134,7 @@ func getUser(w http.ResponseWriter, r *http.Request) {
 	json.NewEncoder(w).Encode(user)
 }
 
-// Get an individual node. Nothin fancy here folks.
+// Get all users. Nothin fancy here folks.
 func getUsers(w http.ResponseWriter, r *http.Request) {
 	// set header.
 	w.Header().Set("Content-Type", "application/json")
@@ -134,6 +142,7 @@ func getUsers(w http.ResponseWriter, r *http.Request) {
 	users, err := logic.GetUsers()
 
 	if err != nil {
+		logger.Log(0, "failed to fetch users: ", err.Error())
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 	}
@@ -146,12 +155,20 @@ func createAdmin(w http.ResponseWriter, r *http.Request) {
 	w.Header().Set("Content-Type", "application/json")
 
 	var admin models.User
-	// get node from body of request
-	_ = json.NewDecoder(r.Body).Decode(&admin)
 
-	admin, err := logic.CreateAdmin(admin)
+	err := json.NewDecoder(r.Body).Decode(&admin)
+	if err != nil {
+
+		logger.Log(0, admin.UserName, "error decoding request body: ",
+			err.Error())
+		returnErrorResponse(w, r, formatError(err, "badrequest"))
+		return
+	}
+	admin, err = logic.CreateAdmin(admin)
 
 	if err != nil {
+		logger.Log(0, admin.UserName, "failed to create admin: ",
+			err.Error())
 		returnErrorResponse(w, r, formatError(err, "badrequest"))
 		return
 	}
@@ -163,12 +180,17 @@ func createUser(w http.ResponseWriter, r *http.Request) {
 	w.Header().Set("Content-Type", "application/json")
 
 	var user models.User
-	// get node from body of request
-	_ = json.NewDecoder(r.Body).Decode(&user)
-
-	user, err := logic.CreateUser(user)
-
+	err := json.NewDecoder(r.Body).Decode(&user)
+	if err != nil {
+		logger.Log(0, user.UserName, "error decoding request body: ",
+			err.Error())
+		returnErrorResponse(w, r, formatError(err, "badrequest"))
+		return
+	}
+	user, err = logic.CreateUser(user)
 	if err != nil {
+		logger.Log(0, user.UserName, "error creating new user: ",
+			err.Error())
 		returnErrorResponse(w, r, formatError(err, "badrequest"))
 		return
 	}
@@ -184,6 +206,8 @@ func updateUserNetworks(w http.ResponseWriter, r *http.Request) {
 	username := params["username"]
 	user, err := GetUserInternal(username)
 	if err != nil {
+		logger.Log(0, username,
+			"failed to update user networks: ", err.Error())
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 	}
@@ -191,11 +215,15 @@ func updateUserNetworks(w http.ResponseWriter, r *http.Request) {
 	// we decode our body request params
 	err = json.NewDecoder(r.Body).Decode(&userchange)
 	if err != nil {
-		returnErrorResponse(w, r, formatError(err, "internal"))
+		logger.Log(0, username, "error decoding request body: ",
+			err.Error())
+		returnErrorResponse(w, r, formatError(err, "badrequest"))
 		return
 	}
 	err = logic.UpdateUserNetworks(userchange.Networks, userchange.IsAdmin, &user)
 	if err != nil {
+		logger.Log(0, username,
+			"failed to update user networks: ", err.Error())
 		returnErrorResponse(w, r, formatError(err, "badrequest"))
 		return
 	}
@@ -211,23 +239,31 @@ func updateUser(w http.ResponseWriter, r *http.Request) {
 	username := params["username"]
 	user, err := GetUserInternal(username)
 	if err != nil {
+		logger.Log(0, username,
+			"failed to update user info: ", err.Error())
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 	}
 	if auth.IsOauthUser(&user) == nil {
-		returnErrorResponse(w, r, formatError(fmt.Errorf("can not update user info for oauth user %s", username), "forbidden"))
+		err := fmt.Errorf("cannot update user info for oauth user %s", username)
+		logger.Log(0, err.Error())
+		returnErrorResponse(w, r, formatError(err, "forbidden"))
 		return
 	}
 	var userchange models.User
 	// we decode our body request params
 	err = json.NewDecoder(r.Body).Decode(&userchange)
 	if err != nil {
-		returnErrorResponse(w, r, formatError(err, "internal"))
+		logger.Log(0, username, "error decoding request body: ",
+			err.Error())
+		returnErrorResponse(w, r, formatError(err, "badrequest"))
 		return
 	}
 	userchange.Networks = nil
 	user, err = logic.UpdateUser(userchange, user)
 	if err != nil {
+		logger.Log(0, username,
+			"failed to update user info: ", err.Error())
 		returnErrorResponse(w, r, formatError(err, "badrequest"))
 		return
 	}
@@ -247,18 +283,28 @@ func updateUserAdm(w http.ResponseWriter, r *http.Request) {
 		return
 	}
 	if auth.IsOauthUser(&user) != nil {
-		returnErrorResponse(w, r, formatError(fmt.Errorf("can not update user info for oauth user"), "forbidden"))
+		err := fmt.Errorf("cannot update user info for oauth user %s", username)
+		logger.Log(0, err.Error())
+		returnErrorResponse(w, r, formatError(err, "forbidden"))
 		return
 	}
 	var userchange models.User
 	// we decode our body request params
 	err = json.NewDecoder(r.Body).Decode(&userchange)
 	if err != nil {
-		returnErrorResponse(w, r, formatError(err, "internal"))
+		logger.Log(0, username, "error decoding request body: ",
+			err.Error())
+		returnErrorResponse(w, r, formatError(err, "badrequest"))
 		return
 	}
+	if !user.IsAdmin {
+		logger.Log(0, username, "not an admin user")
+		returnErrorResponse(w, r, formatError(errors.New("not a admin user"), "badrequest"))
+	}
 	user, err = logic.UpdateUser(userchange, user)
 	if err != nil {
+		logger.Log(0, username,
+			"failed to update user (admin) info: ", err.Error())
 		returnErrorResponse(w, r, formatError(err, "badrequest"))
 		return
 	}
@@ -274,13 +320,17 @@ func deleteUser(w http.ResponseWriter, r *http.Request) {
 	var params = mux.Vars(r)
 
 	username := params["username"]
-	success, err := logic.DeleteUser(username)
 
+	success, err := logic.DeleteUser(username)
 	if err != nil {
+		logger.Log(0, username,
+			"failed to delete user: ", err.Error())
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 	} else if !success {
-		returnErrorResponse(w, r, formatError(errors.New("delete unsuccessful"), "badrequest"))
+		err := errors.New("delete unsuccessful")
+		logger.Log(0, username, err.Error())
+		returnErrorResponse(w, r, formatError(err, "badrequest"))
 		return
 	}
 

+ 8 - 7
go.mod

@@ -6,7 +6,6 @@ require (
 	github.com/eclipse/paho.mqtt.golang v1.4.1
 	github.com/go-playground/validator/v10 v10.11.0
 	github.com/golang-jwt/jwt/v4 v4.4.2
-	github.com/golang/protobuf v1.5.2 // indirect
 	github.com/google/uuid v1.3.0
 	github.com/gorilla/handlers v1.5.1
 	github.com/gorilla/mux v1.8.0
@@ -16,12 +15,9 @@ require (
 	github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e
 	github.com/stretchr/testify v1.8.0
 	github.com/txn2/txeh v1.3.0
-	github.com/urfave/cli/v2 v2.10.3
+	github.com/urfave/cli/v2 v2.11.1
 	golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd
-	golang.org/x/net v0.0.0-20220225172249-27dd8689420f // indirect
 	golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602
-	golang.org/x/sys v0.0.0-20220412211240-33da011f77ad // indirect
-	golang.org/x/text v0.3.7 // indirect
 	golang.zx2c4.com/wireguard v0.0.0-20220318042302-193cf8d6a5d6 // indirect
 	golang.zx2c4.com/wireguard/wgctrl v0.0.0-20220324164955-056925b7df31
 	google.golang.org/protobuf v1.28.0 // indirect
@@ -31,7 +27,7 @@ require (
 
 require (
 	filippo.io/edwards25519 v1.0.0
-	fyne.io/fyne/v2 v2.2.2
+	fyne.io/fyne/v2 v2.2.3
 	github.com/c-robinson/iplib v1.0.3
 	github.com/cloverstd/tcping v0.1.1
 	github.com/guumaster/hostctl v1.1.2
@@ -39,11 +35,12 @@ require (
 	github.com/posthog/posthog-go v0.0.0-20211028072449-93c17c49e2b0
 )
 
+require github.com/coreos/go-oidc/v3 v3.2.0
+
 require (
 	cloud.google.com/go v0.81.0 // indirect
 	fyne.io/systray v1.10.1-0.20220621085403-9a2652634e93 // indirect
 	github.com/Microsoft/go-winio v0.4.14 // indirect
-	github.com/coreos/go-oidc/v3 v3.2.0
 	github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
 	github.com/davecgh/go-spew v1.1.1 // indirect
 	github.com/docker/distribution v2.7.1+incompatible // indirect
@@ -63,6 +60,7 @@ require (
 	github.com/godbus/dbus/v5 v5.1.0 // indirect
 	github.com/gogo/protobuf v1.3.2 // indirect
 	github.com/goki/freetype v0.0.0-20181231101311-fa8a33aabaff // indirect
+	github.com/golang/protobuf v1.5.2 // indirect
 	github.com/google/go-cmp v0.5.7 // indirect
 	github.com/gopherjs/gopherjs v1.17.2 // indirect
 	github.com/gorilla/websocket v1.4.2 // indirect
@@ -88,7 +86,10 @@ require (
 	github.com/yuin/goldmark v1.4.0 // indirect
 	golang.org/x/image v0.0.0-20220601225756-64ec528b34cd // indirect
 	golang.org/x/mobile v0.0.0-20211207041440-4e6c2922fdee // indirect
+	golang.org/x/net v0.0.0-20220225172249-27dd8689420f // indirect
 	golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect
+	golang.org/x/sys v0.0.0-20220412211240-33da011f77ad // indirect
+	golang.org/x/text v0.3.7 // indirect
 	google.golang.org/appengine v1.6.7 // indirect
 	gopkg.in/square/go-jose.v2 v2.5.1 // indirect
 	gopkg.in/yaml.v2 v2.4.0 // indirect

+ 4 - 4
go.sum

@@ -40,8 +40,8 @@ cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9
 dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
 filippo.io/edwards25519 v1.0.0 h1:0wAIcmJUqRdI8IJ/3eGi5/HwXZWPujYXXlkrQogz0Ek=
 filippo.io/edwards25519 v1.0.0/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns=
-fyne.io/fyne/v2 v2.2.2 h1:/ox4o1JeDYb7LmcQS1LiJBmAnnsgKUEn25wZlAR8Ph0=
-fyne.io/fyne/v2 v2.2.2/go.mod h1:MBoGuHzLLSXdQOWFAwWhIhYTEMp33zqtGCReSWhaQTA=
+fyne.io/fyne/v2 v2.2.3 h1:Umi3vVVW8XnWWPJmMkhIWQOMU/jxB1OqpWVUmjhODD0=
+fyne.io/fyne/v2 v2.2.3/go.mod h1:MBoGuHzLLSXdQOWFAwWhIhYTEMp33zqtGCReSWhaQTA=
 fyne.io/systray v1.10.1-0.20220621085403-9a2652634e93 h1:V2IC9t0Zj9Ur6qDbfhUuzVmIvXKFyxZXRJyigUvovs4=
 fyne.io/systray v1.10.1-0.20220621085403-9a2652634e93/go.mod h1:oM2AQqGJ1AMo4nNqZFYU8xYygSBZkW2hmdJ7n4yjedE=
 github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
@@ -445,8 +445,8 @@ github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGr
 github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
 github.com/urfave/cli v1.22.5/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
 github.com/urfave/cli/v2 v2.4.0/go.mod h1:NX9W0zmTvedE5oDoOMs2RTC8RvdK98NTYZE5LbaEYPg=
-github.com/urfave/cli/v2 v2.10.3 h1:oi571Fxz5aHugfBAJd5nkwSk3fzATXtMlpxdLylSCMo=
-github.com/urfave/cli/v2 v2.10.3/go.mod h1:f8iq5LtQ/bLxafbdBSLPPNsgaW0l/2fYYEHhAyPlwvo=
+github.com/urfave/cli/v2 v2.11.1 h1:UKK6SP7fV3eKOefbS87iT9YHefv7iB/53ih6e+GNAsE=
+github.com/urfave/cli/v2 v2.11.1/go.mod h1:f8iq5LtQ/bLxafbdBSLPPNsgaW0l/2fYYEHhAyPlwvo=
 github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
 github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
 github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU=

+ 1 - 1
k8s/client/netclient-daemonset.yaml

@@ -16,7 +16,7 @@ spec:
       hostNetwork: true
       containers:
       - name: netclient
-        image: gravitl/netclient-go:v0.14.5
+        image: gravitl/netclient-go:v0.14.6
         env:
         - name: TOKEN
           value: "TOKEN_VALUE"

+ 1 - 1
k8s/server/netmaker-server.yaml

@@ -83,7 +83,7 @@ spec:
           value: "Kubernetes"
         - name: VERBOSITY
           value: "3"
-        image: gravitl/netmaker:v0.14.5
+        image: gravitl/netmaker:v0.14.6
         imagePullPolicy: Always
         name: netmaker
         ports:

+ 22 - 0
logger/logger.go

@@ -4,7 +4,9 @@ import (
 	"fmt"
 	"os"
 	"path/filepath"
+	"runtime"
 	"sort"
+	"strings"
 	"sync"
 	"time"
 )
@@ -34,9 +36,29 @@ func Log(verbosity int, message ...string) {
 	defer mu.Unlock()
 	var currentTime = time.Now()
 	var currentMessage = MakeString(" ", message...)
+
+	if getVerbose() >= 4 {
+		pc, file, line, ok := runtime.Caller(1)
+		if !ok {
+			file = "?"
+			line = 0
+		}
+
+		fn := runtime.FuncForPC(pc)
+		var fnName string
+		if fn == nil {
+			fnName = "?()"
+		} else {
+			fnName = strings.TrimLeft(filepath.Ext(fn.Name()), ".") + "()"
+		}
+		currentMessage = fmt.Sprintf("[%s-%d] %s: %s",
+			filepath.Base(file), line, fnName, currentMessage)
+	}
+
 	if int32(verbosity) <= getVerbose() && getVerbose() >= 0 {
 		fmt.Printf("[%s] %s %s \n", program, currentTime.Format(TimeFormat), currentMessage)
 	}
+
 	if program == "netmaker" {
 		currentLogs[currentMessage] = entry{
 			Time:  currentTime.Format("2006-01-02 15:04:05.999999999"),

+ 1 - 1
logger/util.go

@@ -22,7 +22,7 @@ func MakeString(delimeter string, message ...string) string {
 }
 
 func getVerbose() int32 {
-	if Verbosity >= 1 && Verbosity <= 3 {
+	if Verbosity >= 1 && Verbosity <= 4 {
 		return int32(Verbosity)
 	}
 	Verbosity = int(servercfg.GetVerbosity())

+ 13 - 6
logic/gateway.go

@@ -20,21 +20,28 @@ func CreateEgressGateway(gateway models.EgressGatewayRequest) (models.Node, erro
 	if node.OS != "linux" && node.OS != "freebsd" { // add in darwin later
 		return models.Node{}, errors.New(node.OS + " is unsupported for egress gateways")
 	}
+	if gateway.NatEnabled == "" {
+		gateway.NatEnabled = "yes"
+	}
 	err = ValidateEgressGateway(gateway)
 	if err != nil {
 		return models.Node{}, err
 	}
 	node.IsEgressGateway = "yes"
 	node.EgressGatewayRanges = gateway.Ranges
+	node.EgressGatewayNatEnabled = gateway.NatEnabled
 	postUpCmd := ""
 	postDownCmd := ""
 	if node.OS == "linux" {
-		postUpCmd = "iptables -A FORWARD -i " + node.Interface + " -j ACCEPT ; "
-		postUpCmd += "iptables -A FORWARD -o " + node.Interface + " -j ACCEPT ; "
-		postUpCmd += "iptables -t nat -A POSTROUTING -o " + gateway.Interface + " -j MASQUERADE"
-		postDownCmd = "iptables -D FORWARD -i " + node.Interface + " -j ACCEPT ; "
-		postDownCmd += "iptables -D FORWARD -o " + node.Interface + " -j ACCEPT ; "
-		postDownCmd += "iptables -t nat -D POSTROUTING -o " + gateway.Interface + " -j MASQUERADE"
+		postUpCmd = "iptables -A FORWARD -i " + node.Interface + " -j ACCEPT; "
+		postUpCmd += "iptables -A FORWARD -o " + node.Interface + " -j ACCEPT"
+		postDownCmd = "iptables -D FORWARD -i " + node.Interface + " -j ACCEPT; "
+		postDownCmd += "iptables -D FORWARD -o " + node.Interface + " -j ACCEPT"
+
+		if node.EgressGatewayNatEnabled == "yes" {
+			postUpCmd += "; iptables -t nat -A POSTROUTING -o " + gateway.Interface + " -j MASQUERADE"
+			postDownCmd += "; iptables -t nat -D POSTROUTING -o " + gateway.Interface + " -j MASQUERADE"
+		}
 	}
 	if node.OS == "freebsd" {
 		postUpCmd = "kldload ipfw ipfw_nat ; "

+ 2 - 2
models/network.go

@@ -7,8 +7,8 @@ import (
 // Network Struct - contains info for a given unique network
 //At  some point, need to replace all instances of Name with something else like  Identifier
 type Network struct {
-	AddressRange        string      `json:"addressrange" bson:"addressrange" validate:"omitempty,cidr"`
-	AddressRange6       string      `json:"addressrange6" bson:"addressrange6"`
+	AddressRange        string      `json:"addressrange" bson:"addressrange" validate:"omitempty,cidrv4"`
+	AddressRange6       string      `json:"addressrange6" bson:"addressrange6" validate:"omitempty,cidrv6"`
 	NetID               string      `json:"netid" bson:"netid" validate:"required,min=1,max=12,netid_valid"`
 	NodesLastModified   int64       `json:"nodeslastmodified" bson:"nodeslastmodified"`
 	NetworkLastModified int64       `json:"networklastmodified" bson:"networklastmodified"`

+ 35 - 34
models/node.go

@@ -35,40 +35,41 @@ var seededRand *rand.Rand = rand.New(
 
 // Node - struct for node model
 type Node struct {
-	ID                  string   `json:"id,omitempty" bson:"id,omitempty" yaml:"id,omitempty" validate:"required,min=5" validate:"id_unique`
-	Address             string   `json:"address" bson:"address" yaml:"address" validate:"omitempty,ipv4"`
-	Address6            string   `json:"address6" bson:"address6" yaml:"address6" validate:"omitempty,ipv6"`
-	LocalAddress        string   `json:"localaddress" bson:"localaddress" yaml:"localaddress" validate:"omitempty,ip"`
-	Name                string   `json:"name" bson:"name" yaml:"name" validate:"omitempty,max=62,in_charset"`
-	NetworkSettings     Network  `json:"networksettings" bson:"networksettings" yaml:"networksettings" validate:"-"`
-	ListenPort          int32    `json:"listenport" bson:"listenport" yaml:"listenport" validate:"omitempty,numeric,min=1024,max=65535"`
-	LocalListenPort     int32    `json:"locallistenport" bson:"locallistenport" yaml:"locallistenport" validate:"numeric,min=0,max=65535"`
-	PublicKey           string   `json:"publickey" bson:"publickey" yaml:"publickey" validate:"required,base64"`
-	Endpoint            string   `json:"endpoint" bson:"endpoint" yaml:"endpoint" validate:"required,ip"`
-	PostUp              string   `json:"postup" bson:"postup" yaml:"postup"`
-	PostDown            string   `json:"postdown" bson:"postdown" yaml:"postdown"`
-	AllowedIPs          []string `json:"allowedips" bson:"allowedips" yaml:"allowedips"`
-	PersistentKeepalive int32    `json:"persistentkeepalive" bson:"persistentkeepalive" yaml:"persistentkeepalive" validate:"omitempty,numeric,max=1000"`
-	IsHub               string   `json:"ishub" bson:"ishub" yaml:"ishub" validate:"checkyesorno"`
-	AccessKey           string   `json:"accesskey" bson:"accesskey" yaml:"accesskey"`
-	Interface           string   `json:"interface" bson:"interface" yaml:"interface"`
-	LastModified        int64    `json:"lastmodified" bson:"lastmodified" yaml:"lastmodified"`
-	ExpirationDateTime  int64    `json:"expdatetime" bson:"expdatetime" yaml:"expdatetime"`
-	LastPeerUpdate      int64    `json:"lastpeerupdate" bson:"lastpeerupdate" yaml:"lastpeerupdate"`
-	LastCheckIn         int64    `json:"lastcheckin" bson:"lastcheckin" yaml:"lastcheckin"`
-	MacAddress          string   `json:"macaddress" bson:"macaddress" yaml:"macaddress"`
-	Password            string   `json:"password" bson:"password" yaml:"password" validate:"required,min=6"`
-	Network             string   `json:"network" bson:"network" yaml:"network" validate:"network_exists"`
-	IsRelayed           string   `json:"isrelayed" bson:"isrelayed" yaml:"isrelayed"`
-	IsPending           string   `json:"ispending" bson:"ispending" yaml:"ispending"`
-	IsRelay             string   `json:"isrelay" bson:"isrelay" yaml:"isrelay" validate:"checkyesorno"`
-	IsDocker            string   `json:"isdocker" bson:"isdocker" yaml:"isdocker" validate:"checkyesorno"`
-	IsK8S               string   `json:"isk8s" bson:"isk8s" yaml:"isk8s" validate:"checkyesorno"`
-	IsEgressGateway     string   `json:"isegressgateway" bson:"isegressgateway" yaml:"isegressgateway"`
-	IsIngressGateway    string   `json:"isingressgateway" bson:"isingressgateway" yaml:"isingressgateway"`
-	EgressGatewayRanges []string `json:"egressgatewayranges" bson:"egressgatewayranges" yaml:"egressgatewayranges"`
-	RelayAddrs          []string `json:"relayaddrs" bson:"relayaddrs" yaml:"relayaddrs"`
-	IngressGatewayRange string   `json:"ingressgatewayrange" bson:"ingressgatewayrange" yaml:"ingressgatewayrange"`
+	ID                      string   `json:"id,omitempty" bson:"id,omitempty" yaml:"id,omitempty" validate:"required,min=5" validate:"id_unique`
+	Address                 string   `json:"address" bson:"address" yaml:"address" validate:"omitempty,ipv4"`
+	Address6                string   `json:"address6" bson:"address6" yaml:"address6" validate:"omitempty,ipv6"`
+	LocalAddress            string   `json:"localaddress" bson:"localaddress" yaml:"localaddress" validate:"omitempty,ip"`
+	Name                    string   `json:"name" bson:"name" yaml:"name" validate:"omitempty,max=62,in_charset"`
+	NetworkSettings         Network  `json:"networksettings" bson:"networksettings" yaml:"networksettings" validate:"-"`
+	ListenPort              int32    `json:"listenport" bson:"listenport" yaml:"listenport" validate:"omitempty,numeric,min=1024,max=65535"`
+	LocalListenPort         int32    `json:"locallistenport" bson:"locallistenport" yaml:"locallistenport" validate:"numeric,min=0,max=65535"`
+	PublicKey               string   `json:"publickey" bson:"publickey" yaml:"publickey" validate:"required,base64"`
+	Endpoint                string   `json:"endpoint" bson:"endpoint" yaml:"endpoint" validate:"required,ip"`
+	PostUp                  string   `json:"postup" bson:"postup" yaml:"postup"`
+	PostDown                string   `json:"postdown" bson:"postdown" yaml:"postdown"`
+	AllowedIPs              []string `json:"allowedips" bson:"allowedips" yaml:"allowedips"`
+	PersistentKeepalive     int32    `json:"persistentkeepalive" bson:"persistentkeepalive" yaml:"persistentkeepalive" validate:"omitempty,numeric,max=1000"`
+	IsHub                   string   `json:"ishub" bson:"ishub" yaml:"ishub" validate:"checkyesorno"`
+	AccessKey               string   `json:"accesskey" bson:"accesskey" yaml:"accesskey"`
+	Interface               string   `json:"interface" bson:"interface" yaml:"interface"`
+	LastModified            int64    `json:"lastmodified" bson:"lastmodified" yaml:"lastmodified"`
+	ExpirationDateTime      int64    `json:"expdatetime" bson:"expdatetime" yaml:"expdatetime"`
+	LastPeerUpdate          int64    `json:"lastpeerupdate" bson:"lastpeerupdate" yaml:"lastpeerupdate"`
+	LastCheckIn             int64    `json:"lastcheckin" bson:"lastcheckin" yaml:"lastcheckin"`
+	MacAddress              string   `json:"macaddress" bson:"macaddress" yaml:"macaddress"`
+	Password                string   `json:"password" bson:"password" yaml:"password" validate:"required,min=6"`
+	Network                 string   `json:"network" bson:"network" yaml:"network" validate:"network_exists"`
+	IsRelayed               string   `json:"isrelayed" bson:"isrelayed" yaml:"isrelayed"`
+	IsPending               string   `json:"ispending" bson:"ispending" yaml:"ispending"`
+	IsRelay                 string   `json:"isrelay" bson:"isrelay" yaml:"isrelay" validate:"checkyesorno"`
+	IsDocker                string   `json:"isdocker" bson:"isdocker" yaml:"isdocker" validate:"checkyesorno"`
+	IsK8S                   string   `json:"isk8s" bson:"isk8s" yaml:"isk8s" validate:"checkyesorno"`
+	IsEgressGateway         string   `json:"isegressgateway" bson:"isegressgateway" yaml:"isegressgateway"`
+	IsIngressGateway        string   `json:"isingressgateway" bson:"isingressgateway" yaml:"isingressgateway"`
+	EgressGatewayRanges     []string `json:"egressgatewayranges" bson:"egressgatewayranges" yaml:"egressgatewayranges"`
+	EgressGatewayNatEnabled string   `json:"egressgatewaynatenabled" bson:"egressgatewaynatenabled" yaml:"egressgatewaynatenabled"`
+	RelayAddrs              []string `json:"relayaddrs" bson:"relayaddrs" yaml:"relayaddrs"`
+	IngressGatewayRange     string   `json:"ingressgatewayrange" bson:"ingressgatewayrange" yaml:"ingressgatewayrange"`
 	// IsStatic - refers to if the Endpoint is set manually or dynamically
 	IsStatic     string      `json:"isstatic" bson:"isstatic" yaml:"isstatic" validate:"checkyesorno"`
 	UDPHolePunch string      `json:"udpholepunch" bson:"udpholepunch" yaml:"udpholepunch" validate:"checkyesorno"`

+ 1 - 0
models/structs.go

@@ -149,6 +149,7 @@ type EgressGatewayRequest struct {
 	NodeID      string   `json:"nodeid" bson:"nodeid"`
 	NetID       string   `json:"netid" bson:"netid"`
 	RangeString string   `json:"rangestring" bson:"rangestring"`
+	NatEnabled  string   `json:"natenabled" bson:"natenabled"`
 	Ranges      []string `json:"ranges" bson:"ranges"`
 	Interface   string   `json:"interface" bson:"interface"`
 	PostUp      string   `json:"postup" bson:"postup"`

+ 4 - 3
mq/publishers.go

@@ -4,6 +4,7 @@ import (
 	"encoding/json"
 	"fmt"
 
+	"github.com/gravitl/netmaker/database"
 	"github.com/gravitl/netmaker/logger"
 	"github.com/gravitl/netmaker/logic"
 	"github.com/gravitl/netmaker/models"
@@ -117,19 +118,19 @@ func sendPeers() {
 		}
 	}
 	networks, err := logic.GetNetworks()
-	if err != nil {
+	if err != nil && !database.IsEmptyRecord(err) {
 		logger.Log(1, "error retrieving networks for keepalive", err.Error())
 	}
 
 	for _, network := range networks {
-		serverNode, errN := logic.GetNetworkServerLeader(network.NetID)
+		serverNode, errN := logic.GetNetworkServerLocal(network.NetID)
 		if errN == nil {
 			serverNode.SetLastCheckIn()
 			if err := logic.UpdateNode(&serverNode, &serverNode); err != nil {
 				logger.Log(0, "failed checkin for server node", serverNode.Name, "on network", network.NetID, err.Error())
 			}
 		}
-		isLeader := logic.IsLocalServer(&serverNode)
+		isLeader := logic.IsLeader(&serverNode)
 		if errN == nil && isLeader {
 			if network.DefaultUDPHolePunch == "yes" {
 				if logic.ShouldPublishPeerPorts(&serverNode) || force {

+ 3 - 1
netclient/cli_options/cmds.go

@@ -90,7 +90,7 @@ func GetCommands(cliFlags []cli.Flag) []*cli.Command {
 			Flags: cliFlags,
 			Action: func(c *cli.Context) error {
 				// set max verbosity for daemon regardless
-				logger.Verbosity = 3
+				logger.Verbosity = 4
 				err := command.Daemon()
 				return err
 			},
@@ -116,5 +116,7 @@ func parseVerbosity(c *cli.Context) {
 		logger.Verbosity = 2
 	} else if c.Bool("vvv") {
 		logger.Verbosity = 3
+	} else if c.Bool("vvvv") {
+		logger.Verbosity = 4
 	}
 }

+ 6 - 0
netclient/cli_options/flags.go

@@ -198,5 +198,11 @@ func GetFlags(hostname string) []cli.Flag {
 			Value:   false,
 			Usage:   "Netclient Verbosity level 3.",
 		},
+		&cli.BoolFlag{
+			Name:    "verbosity-level-4",
+			Aliases: []string{"vvvv"},
+			Value:   false,
+			Usage:   "Netclient Verbosity level 4.",
+		},
 	}
 }

+ 3 - 3
netclient/command/commands.go

@@ -43,7 +43,7 @@ func Join(cfg *config.ClientConfig, privateKey string) error {
 		}
 		return err
 	}
-	logger.Log(1, "joined ", cfg.Network)
+	logger.Log(1, "joined", cfg.Network)
 
 	return err
 }
@@ -85,7 +85,7 @@ func Pull(cfg *config.ClientConfig) error {
 
 		_, err = functions.Pull(network, true)
 		if err != nil {
-			logger.Log(1, "Error pulling network config for network: ", network, "\n", err.Error())
+			logger.Log(1, "error pulling network config for network: ", network, "\n", err.Error())
 		} else {
 			logger.Log(1, "pulled network config for "+network)
 		}
@@ -113,7 +113,7 @@ func Pull(cfg *config.ClientConfig) error {
 			daemon.Restart()
 		}
 	}
-	logger.Log(1, "reset network and peer configs")
+	logger.Log(1, "reset network", cfg.Network, "and peer configs")
 
 	return err
 }

+ 25 - 3
netclient/daemon/common.go

@@ -2,8 +2,13 @@ package daemon
 
 import (
 	"errors"
+	"fmt"
+	"os"
 	"runtime"
+	"syscall"
 	"time"
+
+	"github.com/gravitl/netmaker/netclient/ncutils"
 )
 
 // InstallDaemon - Calls the correct function to install the netclient as a daemon service on the given operating system.
@@ -28,11 +33,28 @@ func InstallDaemon() error {
 
 // Restart - restarts a system daemon
 func Restart() error {
+	if ncutils.IsWindows() {
+		RestartWindowsDaemon()
+		return nil
+	}
+	pid, err := ncutils.ReadPID()
+	if err != nil {
+		return fmt.Errorf("failed to find pid %w", err)
+	}
+	p, err := os.FindProcess(pid)
+	if err != nil {
+		return fmt.Errorf("failed to find running process for pid %d -- %w", pid, err)
+	}
+	if err := p.Signal(syscall.SIGHUP); err != nil {
+		return fmt.Errorf("SIGHUP failed -- %w", err)
+	}
+	return nil
+}
+
+// Start - starts system daemon
+func Start() error {
 	os := runtime.GOOS
 	var err error
-
-	time.Sleep(time.Second)
-
 	switch os {
 	case "windows":
 		RestartWindowsDaemon()

+ 1 - 0
netclient/daemon/freebsd.go

@@ -108,6 +108,7 @@ func FreebsdDaemon(command string) {
 
 // CleanupFreebsd - removes config files and netclient binary
 func CleanupFreebsd() {
+	RemoveFreebsdDaemon()
 	if err := os.RemoveAll(ncutils.GetNetclientPath()); err != nil {
 		logger.Log(1, "Removing netclient configs: ", err.Error())
 	}

+ 1 - 0
netclient/daemon/systemd.go

@@ -83,6 +83,7 @@ func RestartSystemD() {
 
 // CleanupLinux - cleans up neclient configs
 func CleanupLinux() {
+	RemoveSystemDServices()
 	if err := os.RemoveAll(ncutils.GetNetclientPath()); err != nil {
 		logger.Log(1, "Removing netclient configs: ", err.Error())
 	}

+ 12 - 33
netclient/functions/common.go

@@ -134,11 +134,12 @@ func Uninstall() error {
 		for _, network := range networks {
 			err = LeaveNetwork(network)
 			if err != nil {
-				logger.Log(1, "Encounter issue leaving network ", network, ": ", err.Error())
+				logger.Log(1, "encounter issue leaving network", network, ":", err.Error())
 			}
 		}
 	}
 	err = nil
+
 	// clean up OS specific stuff
 	if ncutils.IsWindows() {
 		daemon.CleanupWindows()
@@ -165,19 +166,19 @@ func LeaveNetwork(network string) error {
 	if node.IsServer != "yes" {
 		token, err := Authenticate(cfg)
 		if err != nil {
-			logger.Log(0, "unable to authenticate: "+err.Error())
+			logger.Log(0, "network:", cfg.Network, "unable to authenticate: "+err.Error())
 		} else {
 			url := "https://" + cfg.Server.API + "/api/nodes/" + cfg.Network + "/" + cfg.Node.ID
 			response, err := API("", http.MethodDelete, url, token)
 			if err != nil {
-				logger.Log(0, "error deleting node on server: "+err.Error())
+				logger.Log(0, "network:", cfg.Network, "error deleting node on server: "+err.Error())
 			} else {
 				if response.StatusCode == http.StatusOK {
-					logger.Log(0, "deleted node", cfg.Node.Name, " on network ", cfg.Network)
+					logger.Log(0, "network:", cfg.Network, "deleted node", cfg.Node.Name, ".")
 				} else {
 					bodybytes, _ := io.ReadAll(response.Body)
 					defer response.Body.Close()
-					logger.Log(0, fmt.Sprintf("error deleting node on server %s %s", response.Status, string(bodybytes)))
+					logger.Log(0, fmt.Sprintf("network: %s error deleting node on server %s %s", cfg.Network, response.Status, string(bodybytes)))
 				}
 			}
 		}
@@ -202,42 +203,20 @@ func LeaveNetwork(network string) error {
 				local.RemoveCIDRRoute(removeIface, queryAddr, cidr)
 			}
 		} else {
-			logger.Log(1, "could not flush peer routes when leaving network, ", cfg.Node.Network)
+			logger.Log(1, "could not flush peer routes when leaving network,", cfg.Node.Network)
 		}
 	}
 
 	err = WipeLocal(node.Network)
 	if err != nil {
-		logger.Log(1, "unable to wipe local config")
+		logger.Log(1, "network:", node.Network, "unable to wipe local config")
 	} else {
-		logger.Log(1, "removed ", node.Network, " network locally")
+		logger.Log(1, "removed", node.Network, "network locally")
 	}
 
-	currentNets, err := ncutils.GetSystemNetworks()
-	if err != nil || len(currentNets) <= 1 {
-		daemon.Stop() // stop system daemon if last network
-		return RemoveLocalInstance(cfg, network)
-	}
 	return daemon.Restart()
 }
 
-// RemoveLocalInstance - remove all netclient files locally for a network
-func RemoveLocalInstance(cfg *config.ClientConfig, networkName string) error {
-
-	if cfg.Daemon != "off" {
-		if ncutils.IsWindows() {
-			// TODO: Remove job?
-		} else if ncutils.IsMac() {
-			//TODO: Delete mac daemon
-		} else if ncutils.IsFreeBSD() {
-			daemon.RemoveFreebsdDaemon()
-		} else {
-			daemon.RemoveSystemDServices()
-		}
-	}
-	return nil
-}
-
 // DeleteInterface - delete an interface of a network
 func DeleteInterface(ifacename string, postdown string) error {
 	return wireguard.RemoveConf(ifacename, true)
@@ -253,7 +232,7 @@ func WipeLocal(network string) error {
 	ifacename := nodecfg.Interface
 	if ifacename != "" {
 		if err = wireguard.RemoveConf(ifacename, true); err == nil {
-			logger.Log(1, "removed WireGuard interface: ", ifacename)
+			logger.Log(1, "network:", nodecfg.Network, "removed WireGuard interface: ", ifacename)
 		} else if strings.Contains(err.Error(), "does not exist") {
 			err = nil
 		}
@@ -419,8 +398,8 @@ func SetServerInfo(cfg *config.ClientConfig) error {
 
 func informPortChange(node *models.Node) {
 	if node.ListenPort == 0 {
-		logger.Log(0, "UDP hole punching enabled for node", node.Name)
+		logger.Log(0, "network:", node.Network, "UDP hole punching enabled for node", node.Name)
 	} else {
-		logger.Log(0, "node", node.Name, "is using port", strconv.Itoa(int(node.ListenPort)))
+		logger.Log(0, "network:", node.Network, "node", node.Name, "is using port", strconv.Itoa(int(node.ListenPort)))
 	}
 }

+ 82 - 61
netclient/functions/daemon.go

@@ -30,7 +30,8 @@ import (
 )
 
 var messageCache = new(sync.Map)
-var networkcontext = new(sync.Map)
+
+var serverSet map[string]bool
 
 const lastNodeUpdate = "lnu"
 const lastPeerUpdate = "lpu"
@@ -42,20 +43,51 @@ type cachedMessage struct {
 
 // Daemon runs netclient daemon from command line
 func Daemon() error {
+	logger.Log(0, "netclient daemon started -- version:", ncutils.Version)
 	UpdateClientConfig()
-	serverSet := make(map[string]bool)
-	// == initial pull of all networks ==
-	networks, _ := ncutils.GetSystemNetworks()
-	if len(networks) == 0 {
-		return errors.New("no networks")
+	if err := ncutils.SavePID(); err != nil {
+		return err
 	}
-	pubNetworks = append(pubNetworks, networks...)
+	// reference required to eliminate unused statticcheck
+	serverSet = make(map[string]bool)
+	serverSet["dummy"] = false
 	// set ipforwarding on startup
 	err := local.SetIPForwarding()
 	if err != nil {
 		logger.Log(0, err.Error())
 	}
 
+	// == add waitgroup and cancel for checkin routine ==
+	wg := sync.WaitGroup{}
+	quit := make(chan os.Signal, 1)
+	reset := make(chan os.Signal, 1)
+	signal.Notify(quit, syscall.SIGTERM, os.Interrupt)
+	signal.Notify(reset, syscall.SIGHUP)
+	cancel := startGoRoutines(&wg)
+	for {
+		select {
+		case <-quit:
+			cancel()
+			logger.Log(0, "shutting down netclient daemon")
+			wg.Wait()
+			logger.Log(0, "shutdown complete")
+			return nil
+		case <-reset:
+			logger.Log(0, "received reset")
+			cancel()
+			wg.Wait()
+			logger.Log(0, "restarting daemon")
+			cancel = startGoRoutines(&wg)
+		}
+	}
+}
+
+func startGoRoutines(wg *sync.WaitGroup) context.CancelFunc {
+	ctx, cancel := context.WithCancel(context.Background())
+	wg.Add(1)
+	go Checkin(ctx, wg)
+	serverSet := make(map[string]bool)
+	networks, _ := ncutils.GetSystemNetworks()
 	for _, network := range networks {
 		logger.Log(3, "initializing network", network)
 		cfg := config.ClientConfig{}
@@ -69,47 +101,28 @@ func Daemon() error {
 			// == subscribe to all nodes for each on machine ==
 			serverSet[server] = true
 			logger.Log(1, "started daemon for server ", server)
-			ctx, cancel := context.WithCancel(context.Background())
-			networkcontext.Store(server, cancel)
-			go messageQueue(ctx, &cfg)
+			wg.Add(1)
+			go messageQueue(ctx, wg, &cfg)
 		}
 	}
-
-	// == add waitgroup and cancel for checkin routine ==
-	wg := sync.WaitGroup{}
-	ctx, cancel := context.WithCancel(context.Background())
-	wg.Add(1)
-	go Checkin(ctx, &wg)
-	quit := make(chan os.Signal, 1)
-	signal.Notify(quit, syscall.SIGTERM, os.Interrupt)
-	<-quit
-	for server := range serverSet {
-		if cancel, ok := networkcontext.Load(server); ok {
-			cancel.(context.CancelFunc)()
-		}
-	}
-	cancel()
-	logger.Log(0, "shutting down netclient daemon")
-	wg.Wait()
-	logger.Log(0, "shutdown complete")
-	return nil
+	return cancel
 }
 
 // UpdateKeys -- updates private key and returns new publickey
 func UpdateKeys(nodeCfg *config.ClientConfig, client mqtt.Client) error {
-	logger.Log(0, "received message to update wireguard keys for network ", nodeCfg.Network)
+	logger.Log(0, "interface:", nodeCfg.Node.Interface, "received message to update wireguard keys for network ", nodeCfg.Network)
 	key, err := wgtypes.GeneratePrivateKey()
 	if err != nil {
-		logger.Log(0, "error generating privatekey ", err.Error())
+		logger.Log(0, "network:", nodeCfg.Node.Network, "error generating privatekey ", err.Error())
 		return err
 	}
 	file := ncutils.GetNetclientPathSpecific() + nodeCfg.Node.Interface + ".conf"
 	if err := wireguard.UpdatePrivateKey(file, key.String()); err != nil {
-		logger.Log(0, "error updating wireguard key ", err.Error())
+		logger.Log(0, "network:", nodeCfg.Node.Network, "error updating wireguard key ", err.Error())
 		return err
 	}
 	if storeErr := wireguard.StorePrivKey(key.String(), nodeCfg.Network); storeErr != nil {
-		logger.Log(0, "failed to save private key", storeErr.Error())
+		logger.Log(0, "network:", nodeCfg.Network, "failed to save private key", storeErr.Error())
 		return storeErr
 	}
 
@@ -125,15 +138,15 @@ func UpdateKeys(nodeCfg *config.ClientConfig, client mqtt.Client) error {
 func setSubscriptions(client mqtt.Client, nodeCfg *config.ClientConfig) {
 	if token := client.Subscribe(fmt.Sprintf("update/%s/%s", nodeCfg.Node.Network, nodeCfg.Node.ID), 0, mqtt.MessageHandler(NodeUpdate)); token.WaitTimeout(mq.MQ_TIMEOUT*time.Second) && token.Error() != nil {
 		if token.Error() == nil {
-			logger.Log(0, "connection timeout")
+			logger.Log(0, "network:", nodeCfg.Node.Network, "connection timeout")
 		} else {
-			logger.Log(0, token.Error().Error())
+			logger.Log(0, "network:", nodeCfg.Node.Network, token.Error().Error())
 		}
 		return
 	}
 	logger.Log(3, fmt.Sprintf("subscribed to node updates for node %s update/%s/%s", nodeCfg.Node.Name, nodeCfg.Node.Network, nodeCfg.Node.ID))
 	if token := client.Subscribe(fmt.Sprintf("peers/%s/%s", nodeCfg.Node.Network, nodeCfg.Node.ID), 0, mqtt.MessageHandler(UpdatePeers)); token.Wait() && token.Error() != nil {
-		logger.Log(0, token.Error().Error())
+		logger.Log(0, "network", nodeCfg.Node.Network, token.Error().Error())
 		return
 	}
 	logger.Log(3, fmt.Sprintf("subscribed to peer updates for node %s peers/%s/%s", nodeCfg.Node.Name, nodeCfg.Node.Network, nodeCfg.Node.ID))
@@ -146,29 +159,30 @@ func unsubscribeNode(client mqtt.Client, nodeCfg *config.ClientConfig) {
 	var ok = true
 	if token := client.Unsubscribe(fmt.Sprintf("update/%s/%s", nodeCfg.Node.Network, nodeCfg.Node.ID)); token.WaitTimeout(mq.MQ_TIMEOUT*time.Second) && token.Error() != nil {
 		if token.Error() == nil {
-			logger.Log(1, "unable to unsubscribe from updates for node ", nodeCfg.Node.Name, "\n", "connection timeout")
+			logger.Log(1, "network:", nodeCfg.Node.Network, "unable to unsubscribe from updates for node ", nodeCfg.Node.Name, "\n", "connection timeout")
 		} else {
-			logger.Log(1, "unable to unsubscribe from updates for node ", nodeCfg.Node.Name, "\n", token.Error().Error())
+			logger.Log(1, "network:", nodeCfg.Node.Network, "unable to unsubscribe from updates for node ", nodeCfg.Node.Name, "\n", token.Error().Error())
 		}
 		ok = false
 	}
 	if token := client.Unsubscribe(fmt.Sprintf("peers/%s/%s", nodeCfg.Node.Network, nodeCfg.Node.ID)); token.WaitTimeout(mq.MQ_TIMEOUT*time.Second) && token.Error() != nil {
 		if token.Error() == nil {
-			logger.Log(1, "unable to unsubscribe from peer updates for node ", nodeCfg.Node.Name, "\n", "connection timeout")
+			logger.Log(1, "network:", nodeCfg.Node.Network, "unable to unsubscribe from peer updates for node", nodeCfg.Node.Name, "\n", "connection timeout")
 		} else {
-			logger.Log(1, "unable to unsubscribe from peer updates for node ", nodeCfg.Node.Name, "\n", token.Error().Error())
+			logger.Log(1, "network:", nodeCfg.Node.Network, "unable to unsubscribe from peer updates for node", nodeCfg.Node.Name, "\n", token.Error().Error())
 		}
 		ok = false
 	}
 	if ok {
-		logger.Log(1, "successfully unsubscribed node ", nodeCfg.Node.ID, " : ", nodeCfg.Node.Name)
+		logger.Log(1, "network:", nodeCfg.Node.Network, "successfully unsubscribed node ", nodeCfg.Node.ID, " : ", nodeCfg.Node.Name)
 	}
 }
 
 // sets up Message Queue and subsribes/publishes updates to/from server
 // the client should subscribe to ALL nodes that exist on server locally
-func messageQueue(ctx context.Context, cfg *config.ClientConfig) {
-	logger.Log(0, "netclient daemon started for server: ", cfg.Server.Server)
+func messageQueue(ctx context.Context, wg *sync.WaitGroup, cfg *config.ClientConfig) {
+	defer wg.Done()
+	logger.Log(0, "network:", cfg.Node.Network, "netclient message queue started for server:", cfg.Server.Server)
 	client, err := setupMQTT(cfg, false)
 	if err != nil {
 		logger.Log(0, "unable to connect to broker", cfg.Server.Server, err.Error())
@@ -176,7 +190,7 @@ func messageQueue(ctx context.Context, cfg *config.ClientConfig) {
 	}
 	defer client.Disconnect(250)
 	<-ctx.Done()
-	logger.Log(0, "shutting down daemon for server ", cfg.Server.Server)
+	logger.Log(0, "shutting down message queue for server", cfg.Server.Server)
 }
 
 // NewTLSConf sets up tls configuration to connect to broker securely
@@ -185,7 +199,7 @@ func NewTLSConfig(server string) (*tls.Config, error) {
 	certpool := x509.NewCertPool()
 	ca, err := os.ReadFile(file)
 	if err != nil {
-		logger.Log(0, "could not read CA file ", err.Error())
+		logger.Log(0, "could not read CA file", err.Error())
 	}
 	ok := certpool.AppendCertsFromPEM(ca)
 	if !ok {
@@ -193,7 +207,7 @@ func NewTLSConfig(server string) (*tls.Config, error) {
 	}
 	clientKeyPair, err := tls.LoadX509KeyPair(ncutils.GetNetclientServerPath(server)+ncutils.GetSeparator()+"client.pem", ncutils.GetNetclientPath()+ncutils.GetSeparator()+"client.key")
 	if err != nil {
-		logger.Log(0, "could not read client cert/key ", err.Error())
+		logger.Log(0, "could not read client cert/key", err.Error())
 		return nil, err
 	}
 	certs := []tls.Certificate{clientKeyPair}
@@ -232,7 +246,7 @@ func setupMQTT(cfg *config.ClientConfig, publish bool) (mqtt.Client, error) {
 		if !publish {
 			networks, err := ncutils.GetSystemNetworks()
 			if err != nil {
-				logger.Log(0, "error retriving networks ", err.Error())
+				logger.Log(0, "error retriving networks", err.Error())
 			}
 			for _, network := range networks {
 				var currNodeCfg config.ClientConfig
@@ -245,25 +259,32 @@ func setupMQTT(cfg *config.ClientConfig, publish bool) (mqtt.Client, error) {
 	opts.SetOrderMatters(true)
 	opts.SetResumeSubs(true)
 	opts.SetConnectionLostHandler(func(c mqtt.Client, e error) {
-		logger.Log(0, "detected broker connection lost for", cfg.Server.Server)
+		logger.Log(0, "network:", cfg.Node.Network, "detected broker connection lost for", cfg.Server.Server)
 	})
 	client := mqtt.NewClient(opts)
-	for token := client.Connect(); !token.WaitTimeout(30*time.Second) || token.Error() != nil; token = client.Connect() {
-		logger.Log(0, "unable to connect to broker, retrying ...")
-		var err error
-		if token.Error() == nil {
-			err = errors.New("connect timeout")
-		} else {
-			err = token.Error()
-		}
-		if err := checkBroker(cfg.Server.Server, cfg.Server.MQPort); err != nil {
-			return nil, err
+	var connecterr error
+	for count := 0; count < 3; count++ {
+		connecterr = nil
+		if token := client.Connect(); !token.WaitTimeout(30*time.Second) || token.Error() != nil {
+			logger.Log(0, "unable to connect to broker, retrying ...")
+			if token.Error() == nil {
+				connecterr = errors.New("connect timeout")
+			} else {
+				connecterr = token.Error()
+			}
+			if err := checkBroker(cfg.Server.Server, cfg.Server.MQPort); err != nil {
+				logger.Log(0, "could not connect to broker", cfg.Server.Server, err.Error())
+			}
 		}
-		logger.Log(0, "could not connect to broker", cfg.Server.Server, err.Error())
-		if strings.Contains(err.Error(), "connectex") || strings.Contains(err.Error(), "connect timeout") {
-			reRegisterWithServer(cfg)
+	}
+	if connecterr != nil {
+		reRegisterWithServer(cfg)
+		//try after re-registering
+		if token := client.Connect(); !token.WaitTimeout(30*time.Second) || token.Error() != nil {
+			return client, errors.New("unable to connect to broker")
 		}
 	}
+
 	return client, nil
 }
 

+ 3 - 0
netclient/functions/install.go

@@ -1,6 +1,8 @@
 package functions
 
 import (
+	"time"
+
 	"github.com/gravitl/netmaker/logger"
 	"github.com/gravitl/netmaker/netclient/daemon"
 )
@@ -12,5 +14,6 @@ func Install() error {
 		logger.Log(0, "error installing daemon", err.Error())
 		return err
 	}
+	time.Sleep(time.Second * 5)
 	return daemon.Restart()
 }

+ 15 - 10
netclient/functions/join.go

@@ -76,7 +76,7 @@ func JoinNetwork(cfg *config.ClientConfig, privateKey string) error {
 		if err == nil {
 			cfg.Node.LocalAddress = intIP
 		} else {
-			logger.Log(1, "error retrieving private address: ", err.Error())
+			logger.Log(1, "network:", cfg.Network, "error retrieving private address: ", err.Error())
 		}
 	}
 
@@ -88,7 +88,7 @@ func JoinNetwork(cfg *config.ClientConfig, privateKey string) error {
 			cfg.Node.Endpoint, err = ncutils.GetPublicIP()
 		}
 		if err != nil || cfg.Node.Endpoint == "" {
-			logger.Log(0, "Error setting cfg.Node.Endpoint.")
+			logger.Log(0, "network:", cfg.Network, "error setting cfg.Node.Endpoint.")
 			return err
 		}
 	}
@@ -163,13 +163,13 @@ func JoinNetwork(cfg *config.ClientConfig, privateKey string) error {
 		return err
 	}
 	if node.IsPending == "yes" {
-		logger.Log(0, "Node is marked as PENDING.")
-		logger.Log(0, "Awaiting approval from Admin before configuring WireGuard.")
+		logger.Log(0, "network:", cfg.Network, "node is marked as PENDING.")
+		logger.Log(0, "network:", cfg.Network, "awaiting approval from Admin before configuring WireGuard.")
 		if cfg.Daemon != "off" {
 			return daemon.InstallDaemon()
 		}
 	}
-	logger.Log(1, "node created on remote server...updating configs")
+	logger.Log(1, "network:", cfg.Node.Network, "node created on remote server...updating configs")
 	err = ncutils.ModPort(&node)
 	if err != nil {
 		return err
@@ -186,7 +186,7 @@ func JoinNetwork(cfg *config.ClientConfig, privateKey string) error {
 	}
 	// attempt to make backup
 	if err = config.SaveBackup(node.Network); err != nil {
-		logger.Log(0, "failed to make backup, node will not auto restore if config is corrupted")
+		logger.Log(0, "network:", node.Network, "failed to make backup, node will not auto restore if config is corrupted")
 	}
 	logger.Log(0, "starting wireguard")
 	err = wireguard.InitWireguard(&node, privateKey, nodeGET.Peers[:], false)
@@ -202,7 +202,7 @@ func JoinNetwork(cfg *config.ClientConfig, privateKey string) error {
 	}
 	// update server with latest data
 	if err := PublishNodeUpdate(cfg); err != nil {
-		logger.Log(0, "failed to publish update for join", err.Error())
+		logger.Log(0, "network:", cfg.Network, "failed to publish update for join", err.Error())
 	}
 
 	if cfg.Daemon == "install" || ncutils.IsFreeBSD() {
@@ -212,7 +212,12 @@ func JoinNetwork(cfg *config.ClientConfig, privateKey string) error {
 		}
 	}
 
-	daemon.Restart()
+	if err := daemon.Restart(); err != nil {
+		log.Println("daemon restart failed ", err)
+		if err := daemon.Start(); err != nil {
+			return err
+		}
+	}
 	return nil
 }
 
@@ -226,8 +231,8 @@ func formatName(node models.Node) string {
 		node.Name = ncutils.ShortenString(node.Name, models.MAX_NAME_LENGTH)
 	}
 	if !node.NameInNodeCharSet() || len(node.Name) > models.MAX_NAME_LENGTH {
-		logger.Log(1, "could not properly format name: "+node.Name)
-		logger.Log(1, "setting name to blank")
+		logger.Log(1, "network:", node.Network, "could not properly format name: "+node.Name)
+		logger.Log(1, "network:", node.Network, "setting name to blank")
 		node.Name = ""
 	}
 	return node.Name

+ 2 - 2
netclient/functions/localport.go

@@ -35,9 +35,9 @@ func UpdateLocalListenPort(nodeCfg *config.ClientConfig) error {
 	ifacename := getRealIface(nodeCfg.Node.Interface, nodeCfg.Node.Address)
 	localPort, err := GetLocalListenPort(ifacename)
 	if err != nil {
-		logger.Log(1, "error encountered checking local listen port: ", ifacename, err.Error())
+		logger.Log(1, "network:", nodeCfg.Node.Network, "error encountered checking local listen port: ", ifacename, err.Error())
 	} else if nodeCfg.Node.LocalListenPort != localPort && localPort != 0 {
-		logger.Log(1, "local port has changed from ", strconv.Itoa(int(nodeCfg.Node.LocalListenPort)), " to ", strconv.Itoa(int(localPort)))
+		logger.Log(1, "network:", nodeCfg.Node.Network, "local port has changed from ", strconv.Itoa(int(nodeCfg.Node.LocalListenPort)), " to ", strconv.Itoa(int(localPort)))
 		nodeCfg.Node.LocalListenPort = localPort
 		err = config.ModNodeConfig(&nodeCfg.Node)
 		if err != nil {

+ 3 - 3
netclient/functions/localport_freebsd.go

@@ -34,16 +34,16 @@ func UpdateLocalListenPort(nodeCfg *config.ClientConfig) error {
 	var err error
 	localPort, err := GetLocalListenPort(nodeCfg.Node.Interface)
 	if err != nil {
-		logger.Log(1, "error encountered checking local listen port for interface : ", nodeCfg.Node.Interface, err.Error())
+		logger.Log(1, "network:", nodeCfg.Node.Network, "error encountered checking local listen port for interface : ", nodeCfg.Node.Interface, err.Error())
 	} else if nodeCfg.Node.LocalListenPort != localPort && localPort != 0 {
-		logger.Log(1, "local port has changed from ", strconv.Itoa(int(nodeCfg.Node.LocalListenPort)), " to ", strconv.Itoa(int(localPort)))
+		logger.Log(1, "network:", nodeCfg.Node.Network, "local port has changed from ", strconv.Itoa(int(nodeCfg.Node.LocalListenPort)), " to ", strconv.Itoa(int(localPort)))
 		nodeCfg.Node.LocalListenPort = localPort
 		err = config.ModNodeConfig(&nodeCfg.Node)
 		if err != nil {
 			return err
 		}
 		if err := PublishNodeUpdate(nodeCfg); err != nil {
-			logger.Log(0, "could not publish local port change")
+			logger.Log(0, "network:", nodeCfg.Node.Network, "could not publish local port change")
 		}
 	}
 	return err

+ 42 - 15
netclient/functions/mqhandlers.go

@@ -2,6 +2,9 @@ package functions
 
 import (
 	"encoding/json"
+	"errors"
+	"fmt"
+	"os"
 	"runtime"
 	"strings"
 	"time"
@@ -22,7 +25,7 @@ import (
 // All -- mqtt message hander for all ('#') topics
 var All mqtt.MessageHandler = func(client mqtt.Client, msg mqtt.Message) {
 	logger.Log(0, "default message handler -- received message but not handling")
-	logger.Log(0, "Topic: "+string(msg.Topic()))
+	logger.Log(0, "topic: "+string(msg.Topic()))
 	//logger.Log(0, "Message: " + string(msg.Payload()))
 }
 
@@ -50,7 +53,7 @@ func NodeUpdate(client mqtt.Client, msg mqtt.Message) {
 		return
 	}
 	insert(newNode.Network, lastNodeUpdate, string(data)) // store new message in cache
-	logger.Log(0, "received message to update node "+newNode.Name)
+	logger.Log(0, "network:", newNode.Network, "received message to update node "+newNode.Name)
 
 	// ensure that OS never changes
 	newNode.OS = runtime.GOOS
@@ -63,7 +66,7 @@ func NodeUpdate(client mqtt.Client, msg mqtt.Message) {
 	nodeCfg.Node = newNode
 	switch newNode.Action {
 	case models.NODE_DELETE:
-		logger.Log(0, "received delete request for %s", nodeCfg.Node.Name)
+		logger.Log(0, "network:", nodeCfg.Node.Network, " received delete request for %s", nodeCfg.Node.Name)
 		unsubscribeNode(client, &nodeCfg)
 		if err = LeaveNetwork(nodeCfg.Node.Network); err != nil {
 			if !strings.Contains("rpc error", err.Error()) {
@@ -71,7 +74,7 @@ func NodeUpdate(client mqtt.Client, msg mqtt.Message) {
 				return
 			}
 		}
-		logger.Log(0, nodeCfg.Node.Name, " was removed")
+		logger.Log(0, nodeCfg.Node.Name, "was removed from network", nodeCfg.Node.Network)
 		return
 	case models.NODE_UPDATE_KEY:
 		// == get the current key for node ==
@@ -95,7 +98,7 @@ func NodeUpdate(client mqtt.Client, msg mqtt.Message) {
 	// Save new config
 	nodeCfg.Node.Action = models.NODE_NOOP
 	if err := config.Write(&nodeCfg, nodeCfg.Network); err != nil {
-		logger.Log(0, "error updating node configuration: ", err.Error())
+		logger.Log(0, nodeCfg.Node.Network, "error updating node configuration: ", err.Error())
 	}
 	nameserver := nodeCfg.Server.CoreDNSAddr
 	privateKey, err := wireguard.RetrievePrivKey(newNode.Network)
@@ -112,7 +115,7 @@ func NodeUpdate(client mqtt.Client, msg mqtt.Message) {
 			}
 			err = ncutils.ModPort(&newNode)
 			if err != nil {
-				logger.Log(0, "error modifying node port on", newNode.Name, "-", err.Error())
+				logger.Log(0, "network:", nodeCfg.Node.Network, "error modifying node port on", newNode.Name, "-", err.Error())
 				return
 			}
 			informPortChange(&newNode)
@@ -145,23 +148,23 @@ func NodeUpdate(client mqtt.Client, msg mqtt.Message) {
 		//	}
 		doneErr := publishSignal(&nodeCfg, ncutils.DONE)
 		if doneErr != nil {
-			logger.Log(0, "could not notify server to update peers after interface change")
+			logger.Log(0, "network:", nodeCfg.Node.Network, "could not notify server to update peers after interface change")
 		} else {
-			logger.Log(0, "signalled finished interface update to server")
+			logger.Log(0, "network:", nodeCfg.Node.Network, "signalled finished interface update to server")
 		}
 	} else if hubChange {
 		doneErr := publishSignal(&nodeCfg, ncutils.DONE)
 		if doneErr != nil {
-			logger.Log(0, "could not notify server to update peers after hub change")
+			logger.Log(0, "network:", nodeCfg.Node.Network, "could not notify server to update peers after hub change")
 		} else {
-			logger.Log(0, "signalled finished hub update to server")
+			logger.Log(0, "network:", nodeCfg.Node.Network, "signalled finished hub update to server")
 		}
 	}
 	//deal with DNS
 	if newNode.DNSOn != "yes" && shouldDNSChange && nodeCfg.Node.Interface != "" {
-		logger.Log(0, "settng DNS off")
+		logger.Log(0, "network:", nodeCfg.Node.Network, "settng DNS off")
 		if err := removeHostDNS(nodeCfg.Node.Interface, ncutils.IsWindows()); err != nil {
-			logger.Log(0, "error removing netmaker profile from /etc/hosts "+err.Error())
+			logger.Log(0, "network:", nodeCfg.Node.Network, "error removing netmaker profile from /etc/hosts "+err.Error())
 		}
 		//		_, err := ncutils.RunCmd("/usr/bin/resolvectl revert "+nodeCfg.Node.Interface, true)
 		//		if err != nil {
@@ -226,15 +229,15 @@ func UpdatePeers(client mqtt.Client, msg mqtt.Message) {
 		logger.Log(0, "error syncing wg after peer update: "+err.Error())
 		return
 	}
-	logger.Log(0, "received peer update for node "+cfg.Node.Name+" "+cfg.Node.Network)
+	logger.Log(0, "network:", cfg.Node.Network, "received peer update for node "+cfg.Node.Name+" "+cfg.Node.Network)
 	if cfg.Node.DNSOn == "yes" {
 		if err := setHostDNS(peerUpdate.DNS, cfg.Node.Interface, ncutils.IsWindows()); err != nil {
-			logger.Log(0, "error updating /etc/hosts "+err.Error())
+			logger.Log(0, "network:", cfg.Node.Network, "error updating /etc/hosts "+err.Error())
 			return
 		}
 	} else {
 		if err := removeHostDNS(cfg.Node.Interface, ncutils.IsWindows()); err != nil {
-			logger.Log(0, "error removing profile from /etc/hosts "+err.Error())
+			logger.Log(0, "network:", cfg.Node.Network, "error removing profile from /etc/hosts "+err.Error())
 			return
 		}
 	}
@@ -243,9 +246,21 @@ func UpdatePeers(client mqtt.Client, msg mqtt.Message) {
 
 func setHostDNS(dns, iface string, windows bool) error {
 	etchosts := "/etc/hosts"
+	temp := os.TempDir()
+	lockfile := temp + "/netclient-lock"
 	if windows {
 		etchosts = "c:\\windows\\system32\\drivers\\etc\\hosts"
+		lockfile = temp + "\\netclient-lock"
 	}
+	if _, err := os.Stat(lockfile); !errors.Is(err, os.ErrNotExist) {
+		return errors.New("/etc/hosts file is locked .... aborting")
+	}
+	lock, err := os.Create(lockfile)
+	if err != nil {
+		return fmt.Errorf("could not create lock file %w", err)
+	}
+	lock.Close()
+	defer os.Remove(lockfile)
 	dnsdata := strings.NewReader(dns)
 	profile, err := parser.ParseProfile(dnsdata)
 	if err != nil {
@@ -268,9 +283,21 @@ func setHostDNS(dns, iface string, windows bool) error {
 
 func removeHostDNS(iface string, windows bool) error {
 	etchosts := "/etc/hosts"
+	temp := os.TempDir()
+	lockfile := temp + "/netclient-lock"
 	if windows {
 		etchosts = "c:\\windows\\system32\\drivers\\etc\\hosts"
+		lockfile = temp + "\\netclient-lock"
+	}
+	if _, err := os.Stat(lockfile); !errors.Is(err, os.ErrNotExist) {
+		return errors.New("/etc/hosts file is locked .... aborting")
+	}
+	lock, err := os.Create(lockfile)
+	if err != nil {
+		return fmt.Errorf("could not create lock file %w", err)
 	}
+	lock.Close()
+	defer os.Remove(lockfile)
 	hosts, err := file.NewFile(etchosts)
 	if err != nil {
 		return err

+ 51 - 47
netclient/functions/mqpublish.go

@@ -19,12 +19,10 @@ import (
 	"github.com/gravitl/netmaker/tls"
 )
 
-// pubNetworks hold the currently publishable networks
-var pubNetworks []string
-
 // Checkin  -- go routine that checks for public or local ip changes, publishes changes
 //   if there are no updates, simply "pings" the server as a checkin
 func Checkin(ctx context.Context, wg *sync.WaitGroup) {
+	logger.Log(2, "starting checkin goroutine")
 	defer wg.Done()
 	for {
 		select {
@@ -33,52 +31,58 @@ func Checkin(ctx context.Context, wg *sync.WaitGroup) {
 			return
 			//delay should be configuraable -> use cfg.Node.NetworkSettings.DefaultCheckInInterval ??
 		case <-time.After(time.Second * 60):
-			for _, network := range pubNetworks {
-				var nodeCfg config.ClientConfig
-				nodeCfg.Network = network
-				nodeCfg.ReadConfig()
-				if nodeCfg.Node.IsStatic != "yes" {
-					extIP, err := ncutils.GetPublicIP()
-					if err != nil {
-						logger.Log(1, "error encountered checking public ip addresses: ", err.Error())
-					}
-					if nodeCfg.Node.Endpoint != extIP && extIP != "" {
-						logger.Log(1, "endpoint has changed from ", nodeCfg.Node.Endpoint, " to ", extIP)
-						nodeCfg.Node.Endpoint = extIP
-						if err := PublishNodeUpdate(&nodeCfg); err != nil {
-							logger.Log(0, "could not publish endpoint change")
-						}
-					}
-					intIP, err := getPrivateAddr()
-					if err != nil {
-						logger.Log(1, "error encountered checking private ip addresses: ", err.Error())
-					}
-					if nodeCfg.Node.LocalAddress != intIP && intIP != "" {
-						logger.Log(1, "local Address has changed from ", nodeCfg.Node.LocalAddress, " to ", intIP)
-						nodeCfg.Node.LocalAddress = intIP
-						if err := PublishNodeUpdate(&nodeCfg); err != nil {
-							logger.Log(0, "could not publish local address change")
-						}
-					}
-					_ = UpdateLocalListenPort(&nodeCfg)
+			checkin()
+		}
+	}
+}
+
+func checkin() {
+	networks, _ := ncutils.GetSystemNetworks()
+	logger.Log(3, "checkin with server(s) for all networks")
+	for _, network := range networks {
+		var nodeCfg config.ClientConfig
+		nodeCfg.Network = network
+		nodeCfg.ReadConfig()
+		if nodeCfg.Node.IsStatic != "yes" {
+			extIP, err := ncutils.GetPublicIP()
+			if err != nil {
+				logger.Log(1, "error encountered checking public ip addresses: ", err.Error())
+			}
+			if nodeCfg.Node.Endpoint != extIP && extIP != "" {
+				logger.Log(1, "network:", nodeCfg.Node.Network, "endpoint has changed from ", nodeCfg.Node.Endpoint, " to ", extIP)
+				nodeCfg.Node.Endpoint = extIP
+				if err := PublishNodeUpdate(&nodeCfg); err != nil {
+					logger.Log(0, "network:", nodeCfg.Node.Network, "could not publish endpoint change")
+				}
+			}
+			intIP, err := getPrivateAddr()
+			if err != nil {
+				logger.Log(1, "network:", nodeCfg.Node.Network, "error encountered checking private ip addresses: ", err.Error())
+			}
+			if nodeCfg.Node.LocalAddress != intIP && intIP != "" {
+				logger.Log(1, "network:", nodeCfg.Node.Network, "local Address has changed from ", nodeCfg.Node.LocalAddress, " to ", intIP)
+				nodeCfg.Node.LocalAddress = intIP
+				if err := PublishNodeUpdate(&nodeCfg); err != nil {
+					logger.Log(0, "Network: ", nodeCfg.Node.Network, " could not publish local address change")
+				}
+			}
+			_ = UpdateLocalListenPort(&nodeCfg)
 
-				} else if nodeCfg.Node.IsLocal == "yes" && nodeCfg.Node.LocalRange != "" {
-					localIP, err := ncutils.GetLocalIP(nodeCfg.Node.LocalRange)
-					if err != nil {
-						logger.Log(1, "error encountered checking local ip addresses: ", err.Error())
-					}
-					if nodeCfg.Node.Endpoint != localIP && localIP != "" {
-						logger.Log(1, "endpoint has changed from "+nodeCfg.Node.Endpoint+" to ", localIP)
-						nodeCfg.Node.Endpoint = localIP
-						if err := PublishNodeUpdate(&nodeCfg); err != nil {
-							logger.Log(0, "could not publish localip change")
-						}
-					}
+		} else if nodeCfg.Node.IsLocal == "yes" && nodeCfg.Node.LocalRange != "" {
+			localIP, err := ncutils.GetLocalIP(nodeCfg.Node.LocalRange)
+			if err != nil {
+				logger.Log(1, "network:", nodeCfg.Node.Network, "error encountered checking local ip addresses: ", err.Error())
+			}
+			if nodeCfg.Node.Endpoint != localIP && localIP != "" {
+				logger.Log(1, "network:", nodeCfg.Node.Network, "endpoint has changed from "+nodeCfg.Node.Endpoint+" to ", localIP)
+				nodeCfg.Node.Endpoint = localIP
+				if err := PublishNodeUpdate(&nodeCfg); err != nil {
+					logger.Log(0, "network:", nodeCfg.Node.Network, "could not publish localip change")
 				}
-				Hello(&nodeCfg)
-				checkCertExpiry(&nodeCfg)
 			}
 		}
+		Hello(&nodeCfg)
+		checkCertExpiry(&nodeCfg)
 	}
 }
 
@@ -95,14 +99,14 @@ func PublishNodeUpdate(nodeCfg *config.ClientConfig) error {
 		return err
 	}
 
-	logger.Log(0, "sent a node update to server for node", nodeCfg.Node.Name, ", ", nodeCfg.Node.ID)
+	logger.Log(0, "network:", nodeCfg.Node.Network, "sent a node update to server for node", nodeCfg.Node.Name, ", ", nodeCfg.Node.ID)
 	return nil
 }
 
 // Hello -- ping the broker to let server know node it's alive and well
 func Hello(nodeCfg *config.ClientConfig) {
 	if err := publish(nodeCfg, fmt.Sprintf("ping/%s", nodeCfg.Node.ID), []byte(ncutils.Version), 0); err != nil {
-		logger.Log(0, fmt.Sprintf("error publishing ping, %v", err))
+		logger.Log(0, fmt.Sprintf("Network: %s error publishing ping, %v", nodeCfg.Node.Network, err))
 		logger.Log(0, "running pull on "+nodeCfg.Node.Network+" to reconnect")
 		_, err := Pull(nodeCfg.Node.Network, true)
 		if err != nil {

+ 1 - 1
netclient/functions/pull.go

@@ -90,7 +90,7 @@ func Pull(network string, iface bool) (*models.Node, error) {
 	}
 	var bkupErr = config.SaveBackup(network)
 	if bkupErr != nil {
-		logger.Log(0, "unable to update backup file")
+		logger.Log(0, "unable to update backup file for", network)
 	}
 
 	return &resNode, err

+ 2 - 2
netclient/functions/register.go

@@ -80,7 +80,7 @@ func RegisterWithServer(private *ed25519.PrivateKey, cfg *config.ClientConfig) e
 	}
 	if modServer {
 		if err = config.ModServerConfig(&cfg.Server, cfg.Node.Network); err != nil {
-			logger.Log(0, "error overwriting config with broker information: "+err.Error())
+			logger.Log(0, "network:", cfg.Node.Network, "error overwriting config with broker information: "+err.Error())
 		}
 	}
 
@@ -94,7 +94,7 @@ func RegisterWithServer(private *ed25519.PrivateKey, cfg *config.ClientConfig) e
 	if err := tls.SaveCertToFile(ncutils.GetNetclientServerPath(cfg.Server.Server)+ncutils.GetSeparator(), "client.pem", &resp.Cert); err != nil {
 		return err
 	}
-	logger.Log(0, "certificates/key saved ")
+	logger.Log(0, "network:", cfg.Network, "certificates/key saved ")
 	//join the network defined in the token
 	return nil
 }

+ 25 - 0
netclient/functions/upgrades/v0-14-6.go

@@ -0,0 +1,25 @@
+package upgrades
+
+import (
+	"github.com/gravitl/netmaker/logger"
+	"github.com/gravitl/netmaker/netclient/config"
+)
+
+var upgrade0146 = UpgradeInfo{
+	RequiredVersions: []string{
+		"v0.14.0",
+		"v0.14.1",
+		"v0.14.2",
+		"v0.14.3",
+		"v0.14.4",
+		"v0.14.5",
+	},
+	NewVersion: "v0.14.6",
+	OP:         update0146,
+}
+
+func update0146(cfg *config.ClientConfig) {
+	// do stuff for 14.X -> 14.5
+	// No-op
+	logger.Log(0, "updating schema for 0.14.6")
+}

+ 46 - 0
netclient/ncutils/pid.go

@@ -0,0 +1,46 @@
+package ncutils
+
+import (
+	"fmt"
+	"os"
+	"strconv"
+)
+
+// PIDFILE - path/name of pid file
+const PIDFILE = "/var/run/netclient.pid"
+
+// WindowsPIDError - error returned from pid function on windows
+type WindowsPIDError struct{}
+
+// Error generates error for windows os
+func (*WindowsPIDError) Error() string {
+	return "pid tracking not supported on windows"
+}
+
+// SavePID - saves the pid of running program to disk
+func SavePID() error {
+	if IsWindows() {
+		return &WindowsPIDError{}
+	}
+	pid := os.Getpid()
+	if err := os.WriteFile(PIDFILE, []byte(fmt.Sprintf("%d", pid)), 0644); err != nil {
+		return fmt.Errorf("could not write to pid file %w", err)
+	}
+	return nil
+}
+
+// ReadPID - reads a previously saved pid from disk
+func ReadPID() (int, error) {
+	if IsWindows() {
+		return 0, &WindowsPIDError{}
+	}
+	bytes, err := os.ReadFile(PIDFILE)
+	if err != nil {
+		return 0, fmt.Errorf("could not read pid file %w", err)
+	}
+	pid, err := strconv.Atoi(string(bytes))
+	if err != nil {
+		return 0, fmt.Errorf("pid file contents invalid %w", err)
+	}
+	return pid, nil
+}

+ 3 - 3
netclient/versioninfo.json

@@ -3,13 +3,13 @@
         "FileVersion": {
             "Major": 0,
             "Minor": 14,
-            "Patch": 3,
+            "Patch": 6,
             "Build": 0
         },
         "ProductVersion": {
             "Major": 0,
             "Minor": 14,
-            "Patch": 3,
+            "Patch": 6,
             "Build": 0
         },
         "FileFlagsMask": "3f",
@@ -29,7 +29,7 @@
         "OriginalFilename": "",
         "PrivateBuild": "",
         "ProductName": "Netclient",
-        "ProductVersion": "v0.14.5.0",
+        "ProductVersion": "v0.14.6.0",
         "SpecialBuild": ""
     },
     "VarFileInfo": {

+ 1 - 1
netclient/wireguard/noquick.go

@@ -70,7 +70,7 @@ func ApplyWithoutWGQuick(node *models.Node, ifacename string, confPath string) e
 			netmask = netmaskArr[1]
 		}
 		mask6 = netmask
-		address6 = node.Address
+		address6 = node.Address6
 	}
 	setKernelDevice(ifacename, address4, mask4, address6, mask6)
 

+ 0 - 289
scripts/install-netmaker.sh

@@ -1,289 +0,0 @@
-#!/bin/bash
-
-set -e
-
-cat << "EOF"
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-    ______     ______     ______     __   __   __     ______   __                        
-   /\  ___\   /\  == \   /\  __ \   /\ \ / /  /\ \   /\__  _\ /\ \                       
-   \ \ \__ \  \ \  __<   \ \  __ \  \ \ \'/   \ \ \  \/_/\ \/ \ \ \____                  
-    \ \_____\  \ \_\ \_\  \ \_\ \_\  \ \__|    \ \_\    \ \_\  \ \_____\                 
-     \/_____/   \/_/ /_/   \/_/\/_/   \/_/      \/_/     \/_/   \/_____/                 
-                                                                                         
- __   __     ______     ______   __    __     ______     __  __     ______     ______    
-/\ "-.\ \   /\  ___\   /\__  _\ /\ "-./  \   /\  __ \   /\ \/ /    /\  ___\   /\  == \   
-\ \ \-.  \  \ \  __\   \/_/\ \/ \ \ \-./\ \  \ \  __ \  \ \  _"-.  \ \  __\   \ \  __<   
- \ \_\\"\_\  \ \_____\    \ \_\  \ \_\ \ \_\  \ \_\ \_\  \ \_\ \_\  \ \_____\  \ \_\ \_\ 
-  \/_/ \/_/   \/_____/     \/_/   \/_/  \/_/   \/_/\/_/   \/_/\/_/   \/_____/   \/_/ /_/ 
-                                                                                                                                                                                                 
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-EOF
-
-NETMAKER_BASE_DOMAIN=nm.$(curl -s ifconfig.me | tr . -).nip.io
-COREDNS_IP=$(ip route get 1 | sed -n 's/^.*src \([0-9.]*\) .*$/\1/p')
-SERVER_PUBLIC_IP=$(curl -s ifconfig.me)
-MASTER_KEY=$(tr -dc A-Za-z0-9 </dev/urandom | head -c 30 ; echo '')
-EMAIL="[email protected]"
-
-echo "Default Base Domain: $NETMAKER_BASE_DOMAIN"
-echo "To Override, add a Wildcard (*.netmaker.example.com) DNS record pointing to $SERVER_PUBLIC_IP"
-echo "Or, add three DNS records pointing to $SERVER_PUBLIC_IP for the following (Replacing 'netmaker.example.com' with the domain of your choice):"
-echo "   dashboard.netmaker.example.com"
-echo "         api.netmaker.example.com"
-echo "-----------------------------------------------------"
-read -p "Domain (Hit 'enter' to use $NETMAKER_BASE_DOMAIN): " domain
-read -p "Contact Email: " email
-
-if [ -n "$domain" ]; then
-  NETMAKER_BASE_DOMAIN=$domain
-fi
-if [ -n "$email" ]; then
-  EMAIL=$email
-fi
-
-while true; do
-    read -p "Configure a default network automatically (y/n)? " yn
-    case $yn in
-        [Yy]* ) MESH_SETUP="true"; break;;
-        [Nn]* ) MESH_SETUP="false"; break;;
-        * ) echo "Please answer yes or no.";;
-    esac
-done
-
-while true; do
-    read -p "Configure a VPN gateway automatically (y/n)? " yn
-    case $yn in
-        [Yy]* ) VPN_SETUP="true"; break;;
-        [Nn]* ) VPN_SETUP="false"; break;;
-        * ) echo "Please answer yes or no.";;
-    esac
-done
-
-if [ "${VPN_SETUP}" == "true" ]; then
-while :; do
-    read -ep '# of VPN clients to configure by default: ' num_clients
-    [[ $num_clients =~ ^[[:digit:]]+$ ]] || continue
-    (( ( (num_clients=(10#$num_clients)) <= 200 ) && num_clients >= 0 )) || continue
-    break
-done
-fi
-
-if [ -n "$num_clients" ]; then
-  NUM_CLIENTS=$num_clients
-fi
-
-while true; do
-    read -p "Override master key ($MASTER_KEY) (y/n)? " yn
-    case $yn in
-        [Yy]* ) override="true"; break;;
-        [Nn]* ) override="false"; break;;
-        * ) echo "Please answer yes or no.";;
-    esac
-done
-
-if [ "${override}" == "true" ]; then
-while :; do
-    read -ep 'New Master Key: ' key
-    result="$(cracklib-check <<<"$key")"
-    okay="$(awk -F': ' '{ print $2}' <<<"$result")"
-    if [[ "$okay" == "OK" ]]
-    then
-	MASTER_KEY=$key
-	break
-    else
-	echo "Your password was rejected - $result"
-        echo "Try again."
-    fi
-done
-fi
-
-echo "-----------------------------------------------------------------"
-echo "                SETUP ARGUMENTS"
-echo "-----------------------------------------------------------------"
-echo "        domain: $NETMAKER_BASE_DOMAIN"
-echo "         email: $EMAIL"
-echo "    coredns ip: $COREDNS_IP"
-echo "     public ip: $SERVER_PUBLIC_IP"
-echo "    master key: $MASTER_KEY"
-echo "   setup mesh?: $MESH_SETUP"
-echo "    setup vpn?: $VPN_SETUP"
-if [ "${VPN_SETUP}" == "true" ]; then
-echo "     # clients: $NUM_CLIENTS"
-fi
-
-while true; do
-    read -p "Does everything look right (y/n)? " yn
-    case $yn in
-        [Yy]* ) override="true"; break;;
-        [Nn]* ) echo "exiting..."; exit;;
-        * ) echo "Please answer yes or no.";;
-    esac
-done
-
-
-echo "Beginning installation in 5 seconds..."
-
-sleep 5
-
-
-echo "Setting Caddyfile..."
-
-sed -i "s/NETMAKER_BASE_DOMAIN/$NETMAKER_BASE_DOMAIN/g" /root/Caddyfile
-sed -i "s/YOUR_EMAIL/$EMAIL/g" /root/Caddyfile
-
-echo "Setting docker-compose..."
-
-sed -i "s/NETMAKER_BASE_DOMAIN/$NETMAKER_BASE_DOMAIN/g" /root/docker-compose.yml
-sed -i "s/SERVER_PUBLIC_IP/$SERVER_PUBLIC_IP/g" /root/docker-compose.yml
-sed -i "s/COREDNS_IP/$COREDNS_IP/g" /root/docker-compose.yml
-sed -i "s/REPLACE_MASTER_KEY/$MASTER_KEY/g" /root/docker-compose.yml
-
-echo "Starting containers..."
-
-docker-compose -f /root/docker-compose.yml up -d
-
-sleep 2
-
-setup_mesh() {
-echo "Creating default network (10.101.0.0/16)..."
-
-curl -s -o /dev/null -d '{"addressrange":"10.101.0.0/16","netid":"default"}' -H "Authorization: Bearer $MASTER_KEY" -H 'Content-Type: application/json' localhost:8081/api/networks
-
-sleep 2
-
-echo "Creating default key..."
-
-curlresponse=$(curl -s -d '{"uses":99999,"name":"defaultkey"}' -H "Authorization: Bearer $MASTER_KEY" -H 'Content-Type: application/json' localhost:8081/api/networks/default/keys)
-ACCESS_TOKEN=$(jq -r '.accessstring' <<< ${curlresponse})
-
-sleep 2
-
-echo "Configuring Netmaker server as ingress gateway..."
-
-curlresponse=$(curl -s -H "Authorization: Bearer $MASTER_KEY" -H 'Content-Type: application/json' localhost:8081/api/nodes/default)
-SERVER_ID=$(jq -r '.[0].macaddress' <<< ${curlresponse})
-
-curl -o /dev/null -s -X POST -H "Authorization: Bearer $MASTER_KEY" -H 'Content-Type: application/json' localhost:8081/api/nodes/default/$SERVER_ID/createingress
-
-VPN_ACCESS_TOKEN=$ACCESS_TOKEN
-
-}
-
-mesh_connect_logs() {
-sleep 5
-echo "-----------------------------------------------------------------"
-echo "-----------------------------------------------------------------"
-echo "DEFAULT NETWORK CLIENT INSTALL INSTRUCTIONS:"
-echo "-----------------------------------------------------------------"
-echo "-----------------------------------------------------------------"
-sleep 5
-echo "For Linux and Mac clients, install with the following command:"
-echo "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -"
-echo "curl -sfL https://raw.githubusercontent.com/gravitl/netmaker/develop/scripts/netclient-install.sh | sudo KEY=$VPN_ACCESS_TOKEN sh -"
-sleep 5
-echo "-----------------------------------------------------------------"
-echo "-----------------------------------------------------------------"
-echo "For Windows clients, perform the following from powershell, as administrator:"
-echo "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -"
-echo "1. Make sure WireGuardNT is installed - https://download.wireguard.com/windows-client/wireguard-installer.exe"
-echo "2. Download netclient.exe - wget https://github.com/gravitl/netmaker/releases/download/latest/netclient.exe"
-echo "3. Install Netclient - powershell.exe .\\netclient.exe join -t $VPN_ACCESS_TOKEN"
-echo "4. Whitelist C:\ProgramData\Netclient in Windows Defender"
-sleep 5
-echo "-----------------------------------------------------------------"
-echo "-----------------------------------------------------------------"
-echo "For Android and iOS clients, perform the following steps:"
-echo "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -"
-echo "1. Log into UI at dashboard.$NETMAKER_BASE_DOMAIN"
-echo "2. Navigate to \"EXTERNAL CLIENTS\" tab"
-echo "3. Select the gateway and create clients"
-echo "4. Scan the QR Code from WireGuard app in iOS or Android"
-echo "-----------------------------------------------------------------"
-echo "-----------------------------------------------------------------"
-sleep 5
-}
-
-setup_vpn() {
-echo "Creating vpn network (10.201.0.0/16)..."
-
-curl -s -o /dev/null -d '{"addressrange":"10.201.0.0/16","netid":"vpn","defaultextclientdns":"8.8.8.8"}' -H "Authorization: Bearer $MASTER_KEY" -H 'Content-Type: application/json' localhost:8081/api/networks
-
-sleep 2
-
-echo "Configuring Netmaker server as vpn inlet..."
-
-curlresponse=$(curl -s -H "Authorization: Bearer $MASTER_KEY" -H 'Content-Type: application/json' localhost:8081/api/nodes/vpn)
-SERVER_ID=$(jq -r '.[0].macaddress' <<< ${curlresponse})
-
-curl -s -o /dev/null -X POST -H "Authorization: Bearer $MASTER_KEY" -H 'Content-Type: application/json' localhost:8081/api/nodes/vpn/$SERVER_ID/createingress
-
-echo "Waiting 10 seconds for server to apply configuration..."
-
-sleep 10
-
-echo "Configuring Netmaker server VPN gateway..."
-
-[ -z "$GATEWAY_IFACE" ] && GATEWAY_IFACE=$(ip -4 route ls | grep default | grep -Po '(?<=dev )(\S+)' | grep -v default)
-
-curlresponse=$(curl -s -H "Authorization: Bearer $MASTER_KEY" -H 'Content-Type: application/json' localhost:8081/api/nodes/vpn)
-SERVER_ID=$(jq -r '.[0].macaddress' <<< ${curlresponse})
-
-EGRESS_JSON=$( jq -n \
-                  --arg gw "$GATEWAY_IFACE" \
-                  '{ranges: ["0.0.0.0/0"], interface: $gw}' )
-
-curl -s -o /dev/null -X POST -d "$EGRESS_JSON" -H "Authorization: Bearer $MASTER_KEY" -H 'Content-Type: application/json' localhost:8081/api/nodes/vpn/$SERVER_ID/creategateway
-
-echo "Creating client configs..."
-
-for ((a=1; a <= $NUM_CLIENTS; a++))
-do
-        CLIENT_JSON=$( jq -n \
-                  --arg clientid "vpnclient-$a" \
-                  '{clientid: $clientid}' )
-
-        curl -s -o /dev/null -d "$CLIENT_JSON" -H "Authorization: Bearer $MASTER_KEY" -H 'Content-Type: application/json' localhost:8081/api/extclients/vpn/$SERVER_ID
-done
-
-}
-
-vpn_connect_logs() {
-sleep 5
-echo "-----------------------------------------------------------------"
-echo "-----------------------------------------------------------------"
-echo "VPN GATEWAY CLIENT INSTALL INSTRUCTIONS:"
-echo "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -"
-echo "1. log into dashboard.$NETMAKER_BASE_DOMAIN"
-echo "2. Navigate to \"EXTERNAL CLIENTS\" tab"
-echo "3. Download or scan a client config (vpnclient-x) to the appropriate device"
-echo "4. Follow the steps for your system to configure WireGuard on the appropriate device"
-echo "5. Create and delete clients as necessary. Changes to netmaker server settings require regenerating ext clients."
-echo "-----------------------------------------------------------------"
-echo "-----------------------------------------------------------------"
-sleep 5
-}
-
-if [ "${MESH_SETUP}" != "false" ]; then
-        setup_mesh
-fi
-
-if [ "${VPN_SETUP}" == "true" ]; then
-        setup_vpn
-fi
-
-if [ "${MESH_SETUP}" != "false" ]; then
-        mesh_connect_logs
-fi
-
-if [ "${VPN_SETUP}" == "true" ]; then
-        vpn_connect_logs
-fi
-
-echo "Netmaker setup is now complete. You are ready to begin using Netmaker."
-echo "Visit dashboard.$NETMAKER_BASE_DOMAIN to log in"
-
-cp -f /etc/skel/.bashrc /root/.bashrc

+ 14 - 12
scripts/netclient-install.sh

@@ -38,7 +38,7 @@ elif [ "${OS}" = "FreeBSD" ]; then
 	update_cmd='pkg update'
 	install_cmd='pkg install -y'
 elif [ -f /etc/openwrt_release ]; then
-	dependencies="wireguard-tools"
+	dependencies="wireguard-tools bash"
 	OS="OpenWRT"
 	update_cmd='opkg update'	
 	install_cmd='opkg install'
@@ -51,6 +51,8 @@ if [ -z "${install_cmd}" ]; then
 	exit 1
 fi
 
+${update_cmd}
+
 set -- $dependencies
 while [ -n "$1" ]; do
     echo $1
@@ -114,7 +116,7 @@ dist=netclient
 echo "OS Version = $(uname)"
 echo "Netclient Version = $VERSION"
 
-case $(uname | tr '[:upper:]' '[:lower:]') in
+case $(uname | tr A-Z a-z) in
 	linux*)
 		if [ -z "$CPU_ARCH" ]; then
 			CPU_ARCH=$(uname -m)
@@ -130,29 +132,29 @@ case $(uname | tr '[:upper:]' '[:lower:]') in
 				dist=netclient-arm64
 			;;
 			aarch64)
-                                dist=netclient-arm64
+                dist=netclient-arm64
 			;;
 			armv6l)
-                                dist=netclient-arm6
+                dist=netclient-arm6
 			;;
 			armv7l)
-                                dist=netclient-arm7
+                dist=netclient-arm7
 			;;
 			arm*)
 				dist=netclient-$CPU_ARCH
 			;;
-                        mipsle)
-                                dist=netclient-mipsle
+            mipsle)
+                dist=netclient-mipsle
 			;;
 			*)
 				fatal "$CPU_ARCH : cpu architecture not supported"
     		esac
 	;;
 	darwin)
-        	dist=netclient-darwin
+        dist=netclient-darwin
 	;;
 	Darwin)
-        	dist=netclient-darwin
+        dist=netclient-darwin
 	;;
 	freebsd*)
 		if [ -z "$CPU_ARCH" ]; then
@@ -169,14 +171,14 @@ case $(uname | tr '[:upper:]' '[:lower:]') in
 				dist=netclient-freebsd-arm64
 			;;
 			aarch64)
-                                dist=netclient-freebsd-arm64
+                dist=netclient-freebsd-arm64
 			;;
 			armv7l)
-                                dist=netclient-freebsd-arm7
+                dist=netclient-freebsd-arm7
 			;;
 			arm*)
 				dist=netclient-freebsd-$CPU_ARCH
-            		;;
+            ;;
 			*)
 				fatal "$CPU_ARCH : cpu architecture not supported"
     		esac

+ 2 - 9
scripts/nm-quick.sh

@@ -79,7 +79,7 @@ NETMAKER_BASE_DOMAIN=nm.$(curl -s ifconfig.me | tr . -).nip.io
 COREDNS_IP=$(ip route get 1 | sed -n 's/^.*src \([0-9.]*\) .*$/\1/p')
 SERVER_PUBLIC_IP=$(curl -s ifconfig.me)
 MASTER_KEY=$(tr -dc A-Za-z0-9 </dev/urandom | head -c 30 ; echo '')
-EMAIL="fake@email.com"
+EMAIL="$(echo $RANDOM | md5sum  | head -c 32)@email.com"
 
 if [ -n "$domain" ]; then
   NETMAKER_BASE_DOMAIN=$domain
@@ -146,12 +146,6 @@ docker-compose -f /root/docker-compose.yml up -d
 
 cat << "EOF"
 
-
-    ______     ______     ______     __   __   __     ______   __                        
-   /\  ___\   /\  == \   /\  __ \   /\ \ / /  /\ \   /\__  _\ /\ \                       
-   \ \ \__ \  \ \  __<   \ \  __ \  \ \ \'/   \ \ \  \/_/\ \/ \ \ \____                  
-    \ \_____\  \ \_\ \_\  \ \_\ \_\  \ \__|    \ \_\    \ \_\  \ \_____\                 
-     \/_____/   \/_/ /_/   \/_/\/_/   \/_/      \/_/     \/_/   \/_____/                 
                                                                                          
  __   __     ______     ______   __    __     ______     __  __     ______     ______    
 /\ "-.\ \   /\  ___\   /\__  _\ /\ "-./  \   /\  __ \   /\ \/ /    /\  ___\   /\  == \   
@@ -234,8 +228,7 @@ SERVER_ID=$(jq -r '.[0].id' <<< ${curlresponse})
 
 EGRESS_JSON=$( jq -n \
                   --arg gw "$GATEWAY_IFACE" \
-                  '{ranges: ["0.0.0.0/0"], interface: $gw}' )
-
+                  '{ranges: ["0.0.0.0/5","8.0.0.0/7","11.0.0.0/8","12.0.0.0/6","16.0.0.0/4","32.0.0.0/3","64.0.0.0/2","128.0.0.0/3","160.0.0.0/5","168.0.0.0/6","172.0.0.0/12","172.32.0.0/11","172.64.0.0/10","172.128.0.0/9","173.0.0.0/8","174.0.0.0/7","176.0.0.0/4","192.0.0.0/9","192.128.0.0/11","192.160.0.0/13","192.169.0.0/16","192.170.0.0/15","192.172.0.0/14","192.176.0.0/12","192.192.0.0/10","193.0.0.0/8","194.0.0.0/7","196.0.0.0/6","200.0.0.0/5","208.0.0.0/4"], interface: $gw}' )
 
 echo "egress json: $EGRESS_JSON"
 curl -s -o /dev/null -X POST -d "$EGRESS_JSON" -H "Authorization: Bearer $MASTER_KEY" -H 'Content-Type: application/json' https://api.${NETMAKER_BASE_DOMAIN}/api/nodes/vpn/$SERVER_ID/creategateway

+ 1 - 1
scripts/token-convert.sh

@@ -6,7 +6,7 @@ token=$1
 
 token_json=$(echo $token | base64 -d)
 
-api_addr=$(echo $token_json | jq -r '.apiconn')
+api_addr=$(echo $token_json | jq -r '.apiconnstring')
 network=$(echo $token_json | jq -r '.network')
 key=$(echo $token_json | jq -r '.key')
 

+ 1 - 1
servercfg/serverconf.go

@@ -369,7 +369,7 @@ func GetVerbosity() int32 {
 	} else if config.Config.Server.Verbosity != 0 {
 		verbosity = int(config.Config.Server.Verbosity)
 	}
-	if verbosity < 0 || verbosity > 3 {
+	if verbosity < 0 || verbosity > 4 {
 		verbosity = 0
 	}
 	return int32(verbosity)