Browse Source

Merge pull request #1743 from gravitl/release_v0.16.3

Release v0.16.3
Matthew R Kasun 3 years ago
parent
commit
c77b59677e
48 changed files with 735 additions and 530 deletions
  1. 2 0
      .github/ISSUE_TEMPLATE/bug-report.yml
  2. 42 0
      .github/workflows/buildandrelease.yml
  3. 1 1
      .github/workflows/docker-builder.yml
  4. 2 2
      .github/workflows/publish-docker.yml
  5. 17 1
      .github/workflows/publish-netclient-docker.yml
  6. 1 1
      README.md
  7. 1 1
      SECURITY.md
  8. 2 2
      compose/docker-compose.ee.yml
  9. 2 2
      compose/docker-compose.reference.yml
  10. 2 2
      compose/docker-compose.yml
  11. 1 1
      controllers/docs.go
  12. 1 1
      controllers/ext_client.go
  13. 1 1
      controllers/network.go
  14. 53 0
      ee/ee_controllers/metrics.go
  15. 6 5
      go.mod
  16. 17 8
      go.sum
  17. 1 1
      k8s/client/netclient-daemonset.yaml
  18. 1 1
      k8s/client/netclient.yaml
  19. 1 1
      k8s/server/netmaker-server.yaml
  20. 1 1
      k8s/server/netmaker-ui.yaml
  21. 3 0
      logic/auth.go
  22. 4 2
      logic/gateway.go
  23. 41 0
      logic/metrics.go
  24. 16 1
      logic/nodes.go
  25. 0 2
      logic/peers.go
  26. 1 1
      logic/security.go
  27. 9 1
      logic/zombie.go
  28. 0 1
      main.go
  29. 27 8
      mq/dynsec.go
  30. 3 1
      mq/dynsec_helper.go
  31. 15 4
      mq/handlers.go
  32. 6 1
      netclient/bin-maker.sh
  33. 0 6
      netclient/functions/mqhandlers.go
  34. 1 0
      netclient/functions/upgrades/upgrades.go
  35. 22 0
      netclient/functions/upgrades/v0-16-2.go
  36. 71 1
      netclient/gui/components/views/networks.go
  37. 37 1
      netclient/gui/gui.go
  38. BIN
      netclient/main.exe
  39. 1 1
      netclient/netclient.exe.manifest.xml
  40. 3 3
      netclient/versioninfo.json
  41. 23 22
      netclient/wireguard/common.go
  42. 0 238
      netclient/wireguard/mac.go
  43. 1 13
      netclient/wireguard/unix.go
  44. 3 1
      netclient/wireguard/windows.go
  45. 28 9
      scripts/netclient-install.sh
  46. 263 179
      scripts/nm-quick-interactive.sh
  47. 1 1
      servercfg/sqlconf.go
  48. 1 1
      swagger.yaml

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

@@ -31,6 +31,8 @@ body:
       label: Version
       label: Version
       description: What version are you running?
       description: What version are you running?
       options:
       options:
+        - v0.16.3
+        - v0.16.2
         - v0.16.1
         - v0.16.1
         - v0.16.0      
         - v0.16.0      
         - v0.15.2
         - v0.15.2

+ 42 - 0
.github/workflows/buildandrelease.yml

@@ -306,6 +306,48 @@ jobs:
           prerelease: true
           prerelease: true
           asset_name: netclient-mipsle
           asset_name: netclient-mipsle
 
 
+  netclient-mips:
+    runs-on: ubuntu-latest
+    needs: version
+    steps:
+      - name: Checkout
+        uses: actions/checkout@v2
+      - name: Set Variables
+        run: |
+          TAG=${{needs.version.outputs.tag}}
+          VERSION=${{needs.version.outputs.version}}
+          echo "NETMAKER_VERSION=${TAG}"  >> $GITHUB_ENV
+          echo "PACKAGE_VERSION=${VERSION}" >> $GITHUB_ENV
+      - name: Setup go
+        uses: actions/setup-go@v2
+        with:
+          go-version: 1.18
+      - name: Build
+        run: |
+          cd netclient
+          env CGO_ENABLED=0 GOOS=linux GOARCH=mipsle GOMIPS=softfloat go build -ldflags "-s -w -X 'main.version=$NETMAKER_VERSION'" -o build/netclient-mips/netclient main.go
+          env CGO_ENABLED=0 GOOS=linux GOARCH=mipsle GOMIPS=softfloat go build -ldflags "-s -w -X 'main.version=$NETMAKER_VERSION'" -o build/netclient-mips-upx/netclient main.go && upx build/netclient-mips-upx/netclient
+
+      - name: Upload mips to Release
+        uses: svenstaro/upload-release-action@v2
+        with:
+          repo_token: ${{ secrets.GITHUB_TOKEN }}
+          file: netclient/build/netclient-mips/netclient
+          tag: ${{ env.NETMAKER_VERSION }}
+          overwrite: true
+          prerelease: true
+          asset_name: netclient-mips
+
+      - name: Upload upx compressed version of mips to Release
+        uses: svenstaro/upload-release-action@v2
+        with:
+          repo_token: ${{ secrets.GITHUB_TOKEN }}
+          file: netclient/build/netclient-mips-upx/netclient
+          tag: ${{ env.NETMAKER_VERSION }}
+          overwrite: true
+          prerelease: true
+          asset_name: netclient-mips-upx
+
   netclient-freebsd:
   netclient-freebsd:
     runs-on: ubuntu-latest
     runs-on: ubuntu-latest
     needs: version
     needs: version

+ 1 - 1
.github/workflows/docker-builder.yml

@@ -23,6 +23,6 @@ jobs:
       with:
       with:
         context: .
         context: .
         push: true
         push: true
-        platforms: linux/amd64, linux/arm64, linux/armv7l
+        platforms: linux/amd64, linux/arm64, linux/arm/v7
         file: ./docker/Dockerfile-go-builder
         file: ./docker/Dockerfile-go-builder
         tags: gravitl/go-builder:latest
         tags: gravitl/go-builder:latest

+ 2 - 2
.github/workflows/publish-docker.yml

@@ -75,7 +75,7 @@ jobs:
         with:
         with:
           context: .
           context: .
           load: true
           load: true
-          platforms: linux/armv7l
+          platforms: linux/arm/v7
           tags: ${{ env.TAG }}
           tags: ${{ env.TAG }}
           build-args: version=${{ env.TAG }}
           build-args: version=${{ env.TAG }}
       -
       -
@@ -89,7 +89,7 @@ jobs:
         uses: docker/build-push-action@v2
         uses: docker/build-push-action@v2
         with:
         with:
           context: .
           context: .
-          platforms: linux/amd64, linux/arm64, linux/armv7l
+          platforms: linux/amd64, linux/arm64, linux/arm/v7
           push: true
           push: true
           tags: ${{ github.repository }}:${{ env.TAG }}, ${{ github.repository }}:latest
           tags: ${{ github.repository }}:${{ env.TAG }}, ${{ github.repository }}:latest
           build-args: version=${{ env.TAG }}
           build-args: version=${{ env.TAG }}

+ 17 - 1
.github/workflows/publish-netclient-docker.yml

@@ -71,12 +71,28 @@ jobs:
             docker run --rm ${{ env.TAG }}&
             docker run --rm ${{ env.TAG }}&
             sleep 10
             sleep 10
             kill %1
             kill %1
+      -
+        name: Build armv7l and export to Docker
+        uses: docker/build-push-action@v2
+        with:
+          context: .
+          load: true
+          platforms: linux/arm/v7
+          file: ./docker/Dockerfile-netclient-multiarch
+          tags: ${{ env.TAG }}
+          build-args: version=${{ env.TAG }}  
+      -
+        name: Test armv7l
+        run: |
+            docker run --rm ${{ env.TAG }}&
+            sleep 10
+            kill %1
       -
       -
         name: Build and push
         name: Build and push
         uses: docker/build-push-action@v2
         uses: docker/build-push-action@v2
         with:
         with:
           context: .
           context: .
-          platforms: linux/amd64, linux/arm64
+          platforms: linux/amd64, linux/arm64, linux/arm/v7
           file: ./docker/Dockerfile-netclient-multiarch
           file: ./docker/Dockerfile-netclient-multiarch
           push: true
           push: true
           tags: gravitl/netclient:${{ env.TAG }}, gravitl/netclient:latest
           tags: gravitl/netclient:${{ env.TAG }}, gravitl/netclient:latest

+ 1 - 1
README.md

@@ -17,7 +17,7 @@
 
 
 <p align="center">
 <p align="center">
   <a href="https://github.com/gravitl/netmaker/releases">
   <a href="https://github.com/gravitl/netmaker/releases">
-    <img src="https://img.shields.io/badge/Version-0.16.1-informational?style=flat-square" />
+    <img src="https://img.shields.io/badge/Version-0.16.3-informational?style=flat-square" />
   </a>
   </a>
   <a href="https://hub.docker.com/r/gravitl/netmaker/tags">
   <a href="https://hub.docker.com/r/gravitl/netmaker/tags">
     <img src="https://img.shields.io/docker/pulls/gravitl/netmaker?label=downloads" />
     <img src="https://img.shields.io/docker/pulls/gravitl/netmaker?label=downloads" />

+ 1 - 1
SECURITY.md

@@ -9,4 +9,4 @@ However, there is no official bug bounty program up yet for the Netmaker project
 
 
 ## Reporting a Vulnerability
 ## Reporting a Vulnerability
 
 
-Please report security issues to `info@gravitl.com`
+Please report security issues to `info@netmaker.io`

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

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

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

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

+ 2 - 2
compose/docker-compose.yml

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

+ 1 - 1
controllers/docs.go

@@ -10,7 +10,7 @@
 //
 //
 //	Schemes: https
 //	Schemes: https
 //	BasePath: /
 //	BasePath: /
-//	Version: 0.16.1
+//	Version: 0.16.3
 //	Host: netmaker.io
 //	Host: netmaker.io
 //
 //
 //	Consumes:
 //	Consumes:

+ 1 - 1
controllers/ext_client.go

@@ -101,7 +101,7 @@ func getAllExtClients(w http.ResponseWriter, r *http.Request) {
 	}
 	}
 	clients := []models.ExtClient{}
 	clients := []models.ExtClient{}
 	var err error
 	var err error
-	if networksSlice[0] == logic.ALL_NETWORK_ACCESS {
+	if len(networksSlice) > 0 && networksSlice[0] == logic.ALL_NETWORK_ACCESS {
 		clients, err = functions.GetAllExtClients()
 		clients, err = functions.GetAllExtClients()
 		if err != nil && !database.IsEmptyRecord(err) {
 		if err != nil && !database.IsEmptyRecord(err) {
 			logger.Log(0, "failed to get all extclients: ", err.Error())
 			logger.Log(0, "failed to get all extclients: ", err.Error())

+ 1 - 1
controllers/network.go

@@ -57,7 +57,7 @@ func getNetworks(w http.ResponseWriter, r *http.Request) {
 	}
 	}
 	allnetworks := []models.Network{}
 	allnetworks := []models.Network{}
 	var err error
 	var err error
-	if networksSlice[0] == logic.ALL_NETWORK_ACCESS {
+	if len(networksSlice) > 0 && networksSlice[0] == logic.ALL_NETWORK_ACCESS {
 		allnetworks, err = logic.GetNetworks()
 		allnetworks, err = logic.GetNetworks()
 		if err != nil && !database.IsEmptyRecord(err) {
 		if err != nil && !database.IsEmptyRecord(err) {
 			logger.Log(0, r.Header.Get("user"), "failed to fetch networks: ", err.Error())
 			logger.Log(0, r.Header.Get("user"), "failed to fetch networks: ", err.Error())

+ 53 - 0
ee/ee_controllers/metrics.go

@@ -15,6 +15,7 @@ func MetricHandlers(r *mux.Router) {
 	r.HandleFunc("/api/metrics/{network}/{nodeid}", logic.SecurityCheck(true, http.HandlerFunc(getNodeMetrics))).Methods("GET")
 	r.HandleFunc("/api/metrics/{network}/{nodeid}", logic.SecurityCheck(true, http.HandlerFunc(getNodeMetrics))).Methods("GET")
 	r.HandleFunc("/api/metrics/{network}", logic.SecurityCheck(true, http.HandlerFunc(getNetworkNodesMetrics))).Methods("GET")
 	r.HandleFunc("/api/metrics/{network}", logic.SecurityCheck(true, http.HandlerFunc(getNetworkNodesMetrics))).Methods("GET")
 	r.HandleFunc("/api/metrics", logic.SecurityCheck(true, http.HandlerFunc(getAllMetrics))).Methods("GET")
 	r.HandleFunc("/api/metrics", logic.SecurityCheck(true, http.HandlerFunc(getAllMetrics))).Methods("GET")
+	r.HandleFunc("/api/metrics-ext/{network}", logic.SecurityCheck(true, http.HandlerFunc(getNetworkExtMetrics))).Methods("GET")
 }
 }
 
 
 // get the metrics of a given node
 // get the metrics of a given node
@@ -72,6 +73,58 @@ func getNetworkNodesMetrics(w http.ResponseWriter, r *http.Request) {
 	json.NewEncoder(w).Encode(networkMetrics)
 	json.NewEncoder(w).Encode(networkMetrics)
 }
 }
 
 
+// get the metrics for ext clients on a given network
+func getNetworkExtMetrics(w http.ResponseWriter, r *http.Request) {
+	// set header.
+	w.Header().Set("Content-Type", "application/json")
+
+	var params = mux.Vars(r)
+	network := params["network"]
+
+	logger.Log(1, r.Header.Get("user"), "requested fetching external client metrics on network", network)
+	ingresses, err := logic.GetNetworkIngresses(network) // grab all the ingress gateways
+	if err != nil {
+		logger.Log(1, r.Header.Get("user"), "failed to fetch metrics of ext clients in network", network, err.Error())
+		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
+		return
+	}
+
+	clients, err := logic.GetNetworkExtClients(network) // grab all the network ext clients
+	if err != nil {
+		logger.Log(1, r.Header.Get("user"), "failed to fetch metrics of ext clients in network", network, err.Error())
+		logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
+		return
+	}
+
+	networkMetrics := models.Metrics{}
+	networkMetrics.Connectivity = make(map[string]models.Metric)
+
+	for i := range ingresses {
+		id := ingresses[i].ID
+		ingressMetrics, err := logic.GetMetrics(id)
+		if err != nil {
+			logger.Log(1, r.Header.Get("user"), "failed to append external client metrics from ingress node", id, err.Error())
+			continue
+		}
+		if ingressMetrics.Connectivity == nil {
+			continue
+		}
+		for j := range clients {
+			if clients[j].Network != network {
+				continue
+			}
+			// if metrics for that client have been reported, append them
+			if len(ingressMetrics.Connectivity[clients[j].ClientID].NodeName) > 0 {
+				networkMetrics.Connectivity[clients[j].ClientID] = ingressMetrics.Connectivity[clients[j].ClientID]
+			}
+		}
+	}
+
+	logger.Log(1, r.Header.Get("user"), "fetched ext client metrics for network", network)
+	w.WriteHeader(http.StatusOK)
+	json.NewEncoder(w).Encode(networkMetrics.Connectivity)
+}
+
 // get Metrics of all nodes on server, lots of data
 // get Metrics of all nodes on server, lots of data
 func getAllMetrics(w http.ResponseWriter, r *http.Request) {
 func getAllMetrics(w http.ResponseWriter, r *http.Request) {
 	w.Header().Set("Content-Type", "application/json")
 	w.Header().Set("Content-Type", "application/json")

+ 6 - 5
go.mod

@@ -3,19 +3,19 @@ module github.com/gravitl/netmaker
 go 1.18
 go 1.18
 
 
 require (
 require (
-	github.com/eclipse/paho.mqtt.golang v1.4.1
+	github.com/eclipse/paho.mqtt.golang v1.4.2
 	github.com/go-playground/validator/v10 v10.11.1
 	github.com/go-playground/validator/v10 v10.11.1
 	github.com/golang-jwt/jwt/v4 v4.4.2
 	github.com/golang-jwt/jwt/v4 v4.4.2
 	github.com/google/uuid v1.3.0
 	github.com/google/uuid v1.3.0
 	github.com/gorilla/handlers v1.5.1
 	github.com/gorilla/handlers v1.5.1
 	github.com/gorilla/mux v1.8.0
 	github.com/gorilla/mux v1.8.0
 	github.com/lib/pq v1.10.7
 	github.com/lib/pq v1.10.7
-	github.com/mattn/go-sqlite3 v1.14.15
+	github.com/mattn/go-sqlite3 v1.14.16
 	github.com/rqlite/gorqlite v0.0.0-20210514125552-08ff1e76b22f
 	github.com/rqlite/gorqlite v0.0.0-20210514125552-08ff1e76b22f
 	github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e
 	github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e
-	github.com/stretchr/testify v1.8.0
+	github.com/stretchr/testify v1.8.1
 	github.com/txn2/txeh v1.3.0
 	github.com/txn2/txeh v1.3.0
-	github.com/urfave/cli/v2 v2.16.3
+	github.com/urfave/cli/v2 v2.23.4
 	golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd
 	golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd
 	golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b // indirect
 	golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b // indirect
 	golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094
 	golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094
@@ -35,11 +35,12 @@ require (
 	github.com/cloverstd/tcping v0.1.1
 	github.com/cloverstd/tcping v0.1.1
 	github.com/go-ping/ping v1.1.0
 	github.com/go-ping/ping v1.1.0
 	github.com/guumaster/hostctl v1.1.3
 	github.com/guumaster/hostctl v1.1.3
-	github.com/kr/pretty v0.3.0
+	github.com/kr/pretty v0.3.1
 	github.com/posthog/posthog-go v0.0.0-20211028072449-93c17c49e2b0
 	github.com/posthog/posthog-go v0.0.0-20211028072449-93c17c49e2b0
 )
 )
 
 
 require (
 require (
+	github.com/agnivade/levenshtein v1.1.1
 	github.com/coreos/go-oidc/v3 v3.4.0
 	github.com/coreos/go-oidc/v3 v3.4.0
 	github.com/gorilla/websocket v1.5.0
 	github.com/gorilla/websocket v1.5.0
 	golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e
 	golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e

+ 17 - 8
go.sum

@@ -73,8 +73,12 @@ github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym
 github.com/Microsoft/go-winio v0.5.2 h1:a9IhgEQBCUEk6QCdml9CiJGhAws+YwffDHEMp1VMrpA=
 github.com/Microsoft/go-winio v0.5.2 h1:a9IhgEQBCUEk6QCdml9CiJGhAws+YwffDHEMp1VMrpA=
 github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY=
 github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY=
 github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
 github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
+github.com/agnivade/levenshtein v1.1.1 h1:QY8M92nrzkmr798gCo3kmMyqXFzdQVpxLlGPRBij0P8=
+github.com/agnivade/levenshtein v1.1.1/go.mod h1:veldBMzWxcCG2ZvUTKD2kJNRdCk5hVbJomOvKkmgYbo=
 github.com/akavel/rsrc v0.10.2/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkKq+c=
 github.com/akavel/rsrc v0.10.2/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkKq+c=
 github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
 github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
+github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0 h1:jfIu9sQUG6Ig+0+Ap1h4unLjW6YQJpKZVmUzxsD4E/Q=
+github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0/go.mod h1:t2tdKJDJF9BV14lnkjHmOQgcvEKgtqs5a1N3LNdJhGE=
 github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
 github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
 github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
 github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
 github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
 github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
@@ -118,6 +122,8 @@ github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ3
 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
 github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/dgryski/trifles v0.0.0-20200323201526-dd97f9abfb48 h1:fRzb/w+pyskVMQ+UbP35JkH8yB7MYb4q/qhBarqZE6g=
+github.com/dgryski/trifles v0.0.0-20200323201526-dd97f9abfb48/go.mod h1:if7Fbed8SFyPtHLHbg49SI7NAdJiC5WIA09pe59rfAA=
 github.com/docker/distribution v2.8.1+incompatible h1:Q50tZOPR6T/hjNsyc9g8/syEs6bk8XXApsHjKukMl68=
 github.com/docker/distribution v2.8.1+incompatible h1:Q50tZOPR6T/hjNsyc9g8/syEs6bk8XXApsHjKukMl68=
 github.com/docker/distribution v2.8.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
 github.com/docker/distribution v2.8.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
 github.com/docker/docker v20.10.17+incompatible h1:JYCuMrWaVNophQTOrMMoSwudOVEfcegoZZrleKc1xwE=
 github.com/docker/docker v20.10.17+incompatible h1:JYCuMrWaVNophQTOrMMoSwudOVEfcegoZZrleKc1xwE=
@@ -126,8 +132,8 @@ github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKoh
 github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
 github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
 github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw=
 github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw=
 github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
 github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
-github.com/eclipse/paho.mqtt.golang v1.4.1 h1:tUSpviiL5G3P9SZZJPC4ZULZJsxQKXxfENpMvdbAXAI=
-github.com/eclipse/paho.mqtt.golang v1.4.1/go.mod h1:JGt0RsEwEX+Xa/agj90YJ9d9DH2b7upDZMK9HRbFvCA=
+github.com/eclipse/paho.mqtt.golang v1.4.2 h1:66wOzfUHSSI1zamx7jR6yMEI5EuHnT1G6rNA5PM12m4=
+github.com/eclipse/paho.mqtt.golang v1.4.2/go.mod h1:JGt0RsEwEX+Xa/agj90YJ9d9DH2b7upDZMK9HRbFvCA=
 github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
 github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
 github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
 github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
 github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
 github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
@@ -321,8 +327,9 @@ github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+o
 github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
 github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
 github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
 github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
 github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
 github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
-github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
 github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
 github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
+github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
+github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
 github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
 github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
 github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
 github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
 github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
 github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
@@ -337,8 +344,8 @@ github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPK
 github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
 github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
 github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
 github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
 github.com/mattn/go-runewidth v0.0.10 h1:CoZ3S2P7pvtP45xOtBw+/mDL2z0RKI576gSkzRRpdGg=
 github.com/mattn/go-runewidth v0.0.10 h1:CoZ3S2P7pvtP45xOtBw+/mDL2z0RKI576gSkzRRpdGg=
-github.com/mattn/go-sqlite3 v1.14.15 h1:vfoHhTN1af61xCRSWzFIWzx2YskyMTwHLrExkBOjvxI=
-github.com/mattn/go-sqlite3 v1.14.15/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
+github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y=
+github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
 github.com/mcuadros/go-version v0.0.0-20190830083331-035f6764e8d2/go.mod h1:76rfSfYPWj01Z85hUf/ituArm797mNKcvINh1OlsZKo=
 github.com/mcuadros/go-version v0.0.0-20190830083331-035f6764e8d2/go.mod h1:76rfSfYPWj01Z85hUf/ituArm797mNKcvINh1OlsZKo=
 github.com/mdlayher/genetlink v1.2.0 h1:4yrIkRV5Wfk1WfpWTcoOlGmsWgQj3OtQN9ZsbrE+XtU=
 github.com/mdlayher/genetlink v1.2.0 h1:4yrIkRV5Wfk1WfpWTcoOlGmsWgQj3OtQN9ZsbrE+XtU=
 github.com/mdlayher/genetlink v1.2.0/go.mod h1:ra5LDov2KrUCZJiAtEvXXZBxGMInICMXIwshlJ+qRxQ=
 github.com/mdlayher/genetlink v1.2.0/go.mod h1:ra5LDov2KrUCZJiAtEvXXZBxGMInICMXIwshlJ+qRxQ=
@@ -434,6 +441,7 @@ github.com/srwiley/rasterx v0.0.0-20200120212402-85cb7272f5e9 h1:m59mIOBO4kfcNCE
 github.com/srwiley/rasterx v0.0.0-20200120212402-85cb7272f5e9/go.mod h1:mvWM0+15UqyrFKqdRjY6LuAVJR0HOVhJlEgZ5JWtSWU=
 github.com/srwiley/rasterx v0.0.0-20200120212402-85cb7272f5e9/go.mod h1:mvWM0+15UqyrFKqdRjY6LuAVJR0HOVhJlEgZ5JWtSWU=
 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
 github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
+github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
 github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
 github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
 github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
 github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
 github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
 github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
@@ -442,8 +450,9 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
 github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
 github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
 github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
 github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
 github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
 github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
-github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
 github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
 github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
+github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
+github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
 github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
 github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
 github.com/tevino/abool v1.2.0 h1:heAkClL8H6w+mK5md9dzsuohKeXHUpY7Vw0ZCKW+huA=
 github.com/tevino/abool v1.2.0 h1:heAkClL8H6w+mK5md9dzsuohKeXHUpY7Vw0ZCKW+huA=
 github.com/tevino/abool v1.2.0/go.mod h1:qc66Pna1RiIsPa7O4Egxxs9OqkuxDX55zznh9K07Tzg=
 github.com/tevino/abool v1.2.0/go.mod h1:qc66Pna1RiIsPa7O4Egxxs9OqkuxDX55zznh9K07Tzg=
@@ -452,8 +461,8 @@ github.com/txn2/txeh v1.3.0/go.mod h1:O7M6gUTPeMF+vsa4c4Ipx3JDkOYrruB1Wry8QRsMcw
 github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
 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 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.4.0/go.mod h1:NX9W0zmTvedE5oDoOMs2RTC8RvdK98NTYZE5LbaEYPg=
-github.com/urfave/cli/v2 v2.16.3 h1:gHoFIwpPjoyIMbJp/VFd+/vuD0dAgFK4B6DpEMFJfQk=
-github.com/urfave/cli/v2 v2.16.3/go.mod h1:1CNUng3PtjQMtRzJO4FMXBQvkGtuYRxxiR9xMa7jMwI=
+github.com/urfave/cli/v2 v2.23.4 h1:gcaHwki8kGX6lfp2zz7irxu7eZkcIl1Xapt6XW0Ynqc=
+github.com/urfave/cli/v2 v2.23.4/go.mod h1:1CNUng3PtjQMtRzJO4FMXBQvkGtuYRxxiR9xMa7jMwI=
 github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
 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=
 github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU=
 github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8=
 github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8=

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

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

+ 1 - 1
k8s/client/netclient.yaml

@@ -28,7 +28,7 @@ spec:
       #           - "<node label value>"
       #           - "<node label value>"
       containers:
       containers:
       - name: netclient
       - name: netclient
-        image: gravitl/netclient:v0.16.1
+        image: gravitl/netclient:v0.16.3
         env:
         env:
         - name: TOKEN
         - name: TOKEN
           value: "TOKEN_VALUE"
           value: "TOKEN_VALUE"

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

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

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

@@ -15,7 +15,7 @@ spec:
     spec:
     spec:
       containers:
       containers:
       - name: netmaker-ui
       - name: netmaker-ui
-        image: gravitl/netmaker-ui:v0.16.1
+        image: gravitl/netmaker-ui:v0.16.3
         ports:
         ports:
         - containerPort: 443
         - containerPort: 443
         env:
         env:

+ 3 - 0
logic/auth.go

@@ -282,6 +282,9 @@ func UpdateUser(userchange models.User, user models.User) (models.User, error) {
 
 
 		user.Password = userchange.Password
 		user.Password = userchange.Password
 	}
 	}
+	if userchange.IsAdmin != user.IsAdmin {
+		user.IsAdmin = userchange.IsAdmin
+	}
 
 
 	err := ValidateUser(user)
 	err := ValidateUser(user)
 	if err != nil {
 	if err != nil {

+ 4 - 2
logic/gateway.go

@@ -265,7 +265,9 @@ func DeleteIngressGateway(networkName string, nodeid string) (models.Node, bool,
 	}
 	}
 	logger.Log(3, "deleting ingress gateway")
 	logger.Log(3, "deleting ingress gateway")
 	wasFailover := node.Failover == "yes"
 	wasFailover := node.Failover == "yes"
-	node.UDPHolePunch = network.DefaultUDPHolePunch
+	if node.IsServer != "yes" {
+		node.UDPHolePunch = network.DefaultUDPHolePunch
+	}
 	node.LastModified = time.Now().Unix()
 	node.LastModified = time.Now().Unix()
 	node.IsIngressGateway = "no"
 	node.IsIngressGateway = "no"
 	node.IngressGatewayRange = ""
 	node.IngressGatewayRange = ""
@@ -322,7 +324,7 @@ func firewallNFTCommandsCreateIngress(networkInterface string) (string, string)
 	postUp += "nft add rule ip filter FORWARD oifname " + networkInterface + " counter accept ; "
 	postUp += "nft add rule ip filter FORWARD oifname " + networkInterface + " counter accept ; "
 	postUp += "nft add table nat ; "
 	postUp += "nft add table nat ; "
 	postUp += "nft add chain nat postrouting ; "
 	postUp += "nft add chain nat postrouting ; "
-	postUp += "nft add rule ip nat postrouting oifname " + networkInterface + " counter masquerade"
+	postUp += "nft add rule ip nat postrouting oifname " + networkInterface + " counter masquerade ; "
 
 
 	// doesn't remove potentially empty tables or chains
 	// doesn't remove potentially empty tables or chains
 	postDown := "nft flush table filter ; "
 	postDown := "nft flush table filter ; "

+ 41 - 0
logic/metrics.go

@@ -5,6 +5,7 @@ import (
 
 
 	"github.com/gravitl/netmaker/database"
 	"github.com/gravitl/netmaker/database"
 	"github.com/gravitl/netmaker/models"
 	"github.com/gravitl/netmaker/models"
+	"github.com/gravitl/netmaker/netclient/wireguard"
 )
 )
 
 
 // GetMetrics - gets the metrics
 // GetMetrics - gets the metrics
@@ -42,9 +43,11 @@ func DeleteMetrics(nodeid string) error {
 func CollectServerMetrics(serverID string, networkNodes []models.Node) *models.Metrics {
 func CollectServerMetrics(serverID string, networkNodes []models.Node) *models.Metrics {
 	newServerMetrics := models.Metrics{}
 	newServerMetrics := models.Metrics{}
 	newServerMetrics.Connectivity = make(map[string]models.Metric)
 	newServerMetrics.Connectivity = make(map[string]models.Metric)
+	var serverNode models.Node
 	for i := range networkNodes {
 	for i := range networkNodes {
 		currNodeID := networkNodes[i].ID
 		currNodeID := networkNodes[i].ID
 		if currNodeID == serverID {
 		if currNodeID == serverID {
+			serverNode = networkNodes[i]
 			continue
 			continue
 		}
 		}
 		if currMetrics, err := GetMetrics(currNodeID); err == nil {
 		if currMetrics, err := GetMetrics(currNodeID); err == nil {
@@ -61,5 +64,43 @@ func CollectServerMetrics(serverID string, networkNodes []models.Node) *models.M
 			}
 			}
 		}
 		}
 	}
 	}
+
+	if serverNode.IsIngressGateway == "yes" {
+		clients, err := GetExtClientsByID(serverID, serverNode.Network)
+		if err == nil {
+			peers, err := wireguard.GetDevicePeers(serverNode.Interface)
+			if err == nil {
+				for i := range clients {
+					for j := range peers {
+						if clients[i].PublicKey == peers[j].PublicKey.String() {
+							if peers[j].ReceiveBytes > 0 &&
+								peers[j].TransmitBytes > 0 {
+								newServerMetrics.Connectivity[clients[i].ClientID] = models.Metric{
+									NodeName:      clients[i].ClientID,
+									TotalTime:     5,
+									Uptime:        5,
+									IsServer:      "no",
+									TotalReceived: peers[j].ReceiveBytes,
+									TotalSent:     peers[j].TransmitBytes,
+									Connected:     true,
+									Latency:       -1, // can not determine latency on server currently
+								}
+							} else {
+								newServerMetrics.Connectivity[clients[i].ClientID] = models.Metric{
+									NodeName:  clients[i].ClientID,
+									TotalTime: 5,
+									Uptime:    0,
+									IsServer:  "no",
+									Connected: false,
+									Latency:   999,
+								}
+							}
+						}
+					}
+				}
+			}
+		}
+	}
+
 	return &newServerMetrics
 	return &newServerMetrics
 }
 }

+ 16 - 1
logic/nodes.go

@@ -335,7 +335,7 @@ func CreateNode(node *models.Node) error {
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}
-	// CheckZombies(node)
+	CheckZombies(node)
 
 
 	nodebytes, err := json.Marshal(&node)
 	nodebytes, err := json.Marshal(&node)
 	if err != nil {
 	if err != nil {
@@ -741,6 +741,21 @@ func findNode(ip string) (*models.Node, error) {
 	return nil, errors.New("node not found")
 	return nil, errors.New("node not found")
 }
 }
 
 
+// GetNetworkIngresses - gets the gateways of a network
+func GetNetworkIngresses(network string) ([]models.Node, error) {
+	var ingresses []models.Node
+	netNodes, err := GetNetworkNodes(network)
+	if err != nil {
+		return []models.Node{}, err
+	}
+	for i := range netNodes {
+		if netNodes[i].IsIngressGateway == "yes" {
+			ingresses = append(ingresses, netNodes[i])
+		}
+	}
+	return ingresses, nil
+}
+
 // == PRO ==
 // == PRO ==
 
 
 func updateProNodeACLS(node *models.Node) error {
 func updateProNodeACLS(node *models.Node) error {

+ 0 - 2
logic/peers.go

@@ -111,8 +111,6 @@ func GetPeerUpdate(node *models.Node) (models.PeerUpdate, error) {
 				if peer.LocalListenPort != 0 {
 				if peer.LocalListenPort != 0 {
 					peer.ListenPort = peer.LocalListenPort
 					peer.ListenPort = peer.LocalListenPort
 				}
 				}
-			} else {
-				continue
 			}
 			}
 		}
 		}
 
 

+ 1 - 1
logic/security.go

@@ -162,7 +162,7 @@ func UserPermissions(reqAdmin bool, netname string, token string) ([]string, str
 	if len(netname) > 0 && (!authenticateNetworkUser(netname, userNetworks) || len(userNetworks) == 0) {
 	if len(netname) > 0 && (!authenticateNetworkUser(netname, userNetworks) || len(userNetworks) == 0) {
 		return nil, username, Unauthorized_Err
 		return nil, username, Unauthorized_Err
 	}
 	}
-	if !pro.IsUserNetAdmin(netname, username) {
+	if isEE && !pro.IsUserNetAdmin(netname, username) {
 		return nil, "", Unauthorized_Err
 		return nil, "", Unauthorized_Err
 	}
 	}
 	return userNetworks, username, nil
 	return userNetworks, username, nil

+ 9 - 1
logic/zombie.go

@@ -31,6 +31,7 @@ func CheckZombies(newnode *models.Node) {
 	}
 	}
 	for _, node := range nodes {
 	for _, node := range nodes {
 		if node.MacAddress == newnode.MacAddress {
 		if node.MacAddress == newnode.MacAddress {
+			logger.Log(0, "adding ", node.ID, " to zombie list")
 			newZombie <- node.ID
 			newZombie <- node.ID
 		}
 		}
 	}
 	}
@@ -38,6 +39,8 @@ func CheckZombies(newnode *models.Node) {
 
 
 // ManageZombies - goroutine which adds/removes/deletes nodes from the zombie node quarantine list
 // ManageZombies - goroutine which adds/removes/deletes nodes from the zombie node quarantine list
 func ManageZombies(ctx context.Context) {
 func ManageZombies(ctx context.Context) {
+	logger.Log(2, "Zombie management started")
+	InitializeZombies()
 	for {
 	for {
 		select {
 		select {
 		case <-ctx.Done():
 		case <-ctx.Done():
@@ -60,11 +63,14 @@ func ManageZombies(ctx context.Context) {
 				logger.Log(3, "no zombies found")
 				logger.Log(3, "no zombies found")
 			}
 			}
 		case <-time.After(time.Second * ZOMBIE_TIMEOUT):
 		case <-time.After(time.Second * ZOMBIE_TIMEOUT):
+			logger.Log(0, "checking for zombie nodes")
 			if len(zombies) > 0 {
 			if len(zombies) > 0 {
 				for i := len(zombies) - 1; i >= 0; i-- {
 				for i := len(zombies) - 1; i >= 0; i-- {
 					node, err := GetNodeByID(zombies[i])
 					node, err := GetNodeByID(zombies[i])
 					if err != nil {
 					if err != nil {
 						logger.Log(1, "error retrieving zombie node", zombies[i], err.Error())
 						logger.Log(1, "error retrieving zombie node", zombies[i], err.Error())
+						logger.Log(1, "deleting ", node.Name, " from zombie list")
+						zombies = append(zombies[:i], zombies[i+1:]...)
 						continue
 						continue
 					}
 					}
 					if time.Since(time.Unix(node.LastCheckIn, 0)) > time.Minute*ZOMBIE_DELETE_TIME {
 					if time.Since(time.Unix(node.LastCheckIn, 0)) > time.Minute*ZOMBIE_DELETE_TIME {
@@ -82,7 +88,7 @@ func ManageZombies(ctx context.Context) {
 }
 }
 
 
 // InitializeZombies - populates the zombie quarantine list (should be called from initialization)
 // InitializeZombies - populates the zombie quarantine list (should be called from initialization)
-func InitalizeZombies() {
+func InitializeZombies() {
 	nodes, err := GetAllNodes()
 	nodes, err := GetAllNodes()
 	if err != nil {
 	if err != nil {
 		logger.Log(1, "failed to retrieve nodes", err.Error())
 		logger.Log(1, "failed to retrieve nodes", err.Error())
@@ -101,8 +107,10 @@ func InitalizeZombies() {
 			if node.MacAddress == othernode.MacAddress {
 			if node.MacAddress == othernode.MacAddress {
 				if node.LastCheckIn > othernode.LastCheckIn {
 				if node.LastCheckIn > othernode.LastCheckIn {
 					zombies = append(zombies, othernode.ID)
 					zombies = append(zombies, othernode.ID)
+					logger.Log(1, "adding ", othernode.Name, " with ID ", othernode.ID, " to zombie list")
 				} else {
 				} else {
 					zombies = append(zombies, node.ID)
 					zombies = append(zombies, node.ID)
+					logger.Log(1, "adding ", node.Name, " with ID ", node.ID, " to zombie list")
 				}
 				}
 			}
 			}
 		}
 		}

+ 0 - 1
main.go

@@ -134,7 +134,6 @@ func initialize() { // Client Mode Prereq Check
 			logger.Log(0, "error occurred when notifying nodes of startup", err.Error())
 			logger.Log(0, "error occurred when notifying nodes of startup", err.Error())
 		}
 		}
 	}
 	}
-	logic.InitalizeZombies()
 }
 }
 
 
 func startControllers() {
 func startControllers() {

+ 27 - 8
mq/dynsec.go

@@ -132,19 +132,27 @@ func encodePasswordToPBKDF2(password string, salt string, iterations int, keyLen
 
 
 // Configure - configures the dynamic initial configuration for MQ
 // Configure - configures the dynamic initial configuration for MQ
 func Configure() error {
 func Configure() error {
+
+	logger.Log(0, "Configuring MQ...")
+	dynConfig := dynConfigInI
 	path := functions.GetNetmakerPath() + ncutils.GetSeparator() + dynamicSecurityFile
 	path := functions.GetNetmakerPath() + ncutils.GetSeparator() + dynamicSecurityFile
-	if logic.CheckIfFileExists(path) {
-		logger.Log(0, "MQ Is Already Configured, Skipping...")
-		return nil
-	}
-	if servercfg.Is_EE {
-		dynConfig.Clients = append(dynConfig.Clients, exporterMQClient)
-		dynConfig.Roles = append(dynConfig.Roles, exporterMQRole)
-	}
+
 	password := servercfg.GetMqAdminPassword()
 	password := servercfg.GetMqAdminPassword()
 	if password == "" {
 	if password == "" {
 		return errors.New("MQ admin password not provided")
 		return errors.New("MQ admin password not provided")
 	}
 	}
+	if logic.CheckIfFileExists(path) {
+		data, err := os.ReadFile(path)
+		if err == nil {
+			var cfg dynJSON
+			err = json.Unmarshal(data, &cfg)
+			if err == nil {
+				logger.Log(0, "MQ config exists already, So Updating Existing Config...")
+				dynConfig = cfg
+			}
+		}
+	}
+	exporter := false
 	for i, cI := range dynConfig.Clients {
 	for i, cI := range dynConfig.Clients {
 		if cI.Username == mqAdminUserName || cI.Username == mqNetmakerServerUserName {
 		if cI.Username == mqAdminUserName || cI.Username == mqNetmakerServerUserName {
 			salt := logic.RandomString(12)
 			salt := logic.RandomString(12)
@@ -154,6 +162,7 @@ func Configure() error {
 			cI.Salt = base64.StdEncoding.EncodeToString([]byte(salt))
 			cI.Salt = base64.StdEncoding.EncodeToString([]byte(salt))
 			dynConfig.Clients[i] = cI
 			dynConfig.Clients[i] = cI
 		} else if servercfg.Is_EE && cI.Username == mqExporterUserName {
 		} else if servercfg.Is_EE && cI.Username == mqExporterUserName {
+			exporter = true
 			exporterPassword := servercfg.GetLicenseKey()
 			exporterPassword := servercfg.GetLicenseKey()
 			salt := logic.RandomString(12)
 			salt := logic.RandomString(12)
 			hashed := encodePasswordToPBKDF2(exporterPassword, salt, 101, 64)
 			hashed := encodePasswordToPBKDF2(exporterPassword, salt, 101, 64)
@@ -163,6 +172,16 @@ func Configure() error {
 			dynConfig.Clients[i] = cI
 			dynConfig.Clients[i] = cI
 		}
 		}
 	}
 	}
+	if servercfg.Is_EE && !exporter {
+		exporterPassword := servercfg.GetLicenseKey()
+		salt := logic.RandomString(12)
+		hashed := encodePasswordToPBKDF2(exporterPassword, salt, 101, 64)
+		exporterMQClient.Password = hashed
+		exporterMQClient.Iterations = 101
+		exporterMQClient.Salt = base64.StdEncoding.EncodeToString([]byte(salt))
+		dynConfig.Clients = append(dynConfig.Clients, exporterMQClient)
+		dynConfig.Roles = append(dynConfig.Roles, exporterMQRole)
+	}
 	data, err := json.MarshalIndent(dynConfig, "", " ")
 	data, err := json.MarshalIndent(dynConfig, "", " ")
 	if err != nil {
 	if err != nil {
 		return err
 		return err

+ 3 - 1
mq/dynsec_helper.go

@@ -26,7 +26,7 @@ const (
 
 
 var (
 var (
 	// default configuration of dynamic security
 	// default configuration of dynamic security
-	dynConfig = dynJSON{
+	dynConfigInI = dynJSON{
 		Clients: []client{
 		Clients: []client{
 			{
 			{
 				Username:   mqAdminUserName,
 				Username:   mqAdminUserName,
@@ -52,6 +52,7 @@ var (
 					},
 					},
 				},
 				},
 			},
 			},
+			exporterMQClient,
 		},
 		},
 		Roles: []role{
 		Roles: []role{
 			{
 			{
@@ -66,6 +67,7 @@ var (
 				Rolename: NodeRole,
 				Rolename: NodeRole,
 				Acls:     fetchNodeAcls(),
 				Acls:     fetchNodeAcls(),
 			},
 			},
+			exporterMQRole,
 		},
 		},
 		DefaultAcl: defaultAccessAcl{
 		DefaultAcl: defaultAccessAcl{
 			PublishClientSend:    false,
 			PublishClientSend:    false,

+ 15 - 4
mq/handlers.go

@@ -97,7 +97,11 @@ func UpdateNode(client mqtt.Client, msg mqtt.Message) {
 			logger.Log(1, "error saving node", err.Error())
 			logger.Log(1, "error saving node", err.Error())
 			return
 			return
 		}
 		}
-		updateNodePeers(&currentNode)
+		if ifaceDelta { // reduce number of unneeded updates, by only sending on iface changes
+			if err = PublishPeerUpdate(&currentNode, true); err != nil {
+				logger.Log(0, "error updating peers when node", currentNode.Name, currentNode.ID, "informed the server of an interface change", err.Error())
+			}
+		}
 		logger.Log(1, "updated node", id, newNode.Name)
 		logger.Log(1, "updated node", id, newNode.Name)
 	}()
 	}()
 }
 }
@@ -238,10 +242,17 @@ func updateNodeMetrics(currentNode *models.Node, newMetrics *models.Metrics) boo
 		// associate ext clients with IDs
 		// associate ext clients with IDs
 		for i := range attachedClients {
 		for i := range attachedClients {
 			extMetric := newMetrics.Connectivity[attachedClients[i].PublicKey]
 			extMetric := newMetrics.Connectivity[attachedClients[i].PublicKey]
-			delete(newMetrics.Connectivity, attachedClients[i].PublicKey)
-			if extMetric.Connected { // add ext client metrics
-				newMetrics.Connectivity[attachedClients[i].ClientID] = extMetric
+			if len(extMetric.NodeName) == 0 &&
+				len(newMetrics.Connectivity[attachedClients[i].ClientID].NodeName) > 0 { // cover server clients
+				extMetric = newMetrics.Connectivity[attachedClients[i].ClientID]
+				if extMetric.TotalReceived > 0 && extMetric.TotalSent > 0 {
+					extMetric.Connected = true
+				}
 			}
 			}
+			extMetric.NodeName = attachedClients[i].ClientID
+			extMetric.IsServer = "no"
+			delete(newMetrics.Connectivity, attachedClients[i].PublicKey)
+			newMetrics.Connectivity[attachedClients[i].ClientID] = extMetric
 		}
 		}
 	}
 	}
 
 

+ 6 - 1
netclient/bin-maker.sh

@@ -20,7 +20,12 @@ function build
 	    build $_goarch $_goose 5 && build $_goarch $_goose 6 && build $_goarch $_goose 7
 	    build $_goarch $_goose 5 && build $_goarch $_goose 6 && build $_goarch $_goose 7
     else
     else
         echo $_out
         echo $_out
-        GOARM=$_goarm GOARCH=$_goarch GOOS=$_goose GOHOSTARCH=$__HOST_ARCH CGO_ENABLED=0 go build -ldflags="-X 'main.version=$VERSION'" -o $_out
+        if [ "$_goarch" == "mips" ]; then
+            # If the binary created through `GOMIPS=softfloat GOARCH=mipsle` is not compatible with your hardware, try changing these variables and creating a binary file compatible with your hardware.
+            GOARM=$_goarm GOMIPS=softfloat GOARCH=mipsle GOOS=$_goose GOHOSTARCH=$__HOST_ARCH CGO_ENABLED=0 go build -ldflags="-X 'main.version=$VERSION'" -o $_out
+        else
+            GOARM=$_goarm GOARCH=$_goarch GOOS=$_goose GOHOSTARCH=$__HOST_ARCH CGO_ENABLED=0 go build -ldflags="-X 'main.version=$VERSION'" -o $_out
+        fi
     fi
     fi
 }
 }
 
 

+ 0 - 6
netclient/functions/mqhandlers.go

@@ -129,9 +129,6 @@ func NodeUpdate(client mqtt.Client, msg mqtt.Message) {
 		wireguard.UpdateKeepAlive(file, newNode.PersistentKeepalive)
 		wireguard.UpdateKeepAlive(file, newNode.PersistentKeepalive)
 	}
 	}
 	logger.Log(0, "applying WG conf to "+file)
 	logger.Log(0, "applying WG conf to "+file)
-	if ncutils.IsWindows() {
-		wireguard.RemoveConfGraceful(nodeCfg.Node.Interface)
-	}
 	err = wireguard.ApplyConf(&nodeCfg.Node, nodeCfg.Node.Interface, file)
 	err = wireguard.ApplyConf(&nodeCfg.Node, nodeCfg.Node.Interface, file)
 	if err != nil {
 	if err != nil {
 		logger.Log(0, "error restarting wg after node update -", err.Error())
 		logger.Log(0, "error restarting wg after node update -", err.Error())
@@ -227,9 +224,6 @@ func UpdatePeers(client mqtt.Client, msg mqtt.Message) {
 		if err := config.ModNodeConfig(&cfg.Node); err != nil {
 		if err := config.ModNodeConfig(&cfg.Node); err != nil {
 			logger.Log(0, "failed to save internet gateway", err.Error())
 			logger.Log(0, "failed to save internet gateway", err.Error())
 		}
 		}
-		if ncutils.IsWindows() {
-			wireguard.RemoveConfGraceful(cfg.Node.Interface)
-		}
 		if err := wireguard.ApplyConf(&cfg.Node, cfg.Node.Interface, file); err != nil {
 		if err := wireguard.ApplyConf(&cfg.Node, cfg.Node.Interface, file); err != nil {
 			logger.Log(0, "error applying internet gateway", err.Error())
 			logger.Log(0, "error applying internet gateway", err.Error())
 		}
 		}

+ 1 - 0
netclient/functions/upgrades/upgrades.go

@@ -7,6 +7,7 @@ func InitializeUpgrades() {
 		upgrade0146,
 		upgrade0146,
 		upgrade0160,
 		upgrade0160,
 		upgrade0161,
 		upgrade0161,
+		upgrade0162,
 	})
 	})
 }
 }
 
 

+ 22 - 0
netclient/functions/upgrades/v0-16-2.go

@@ -0,0 +1,22 @@
+package upgrades
+
+import (
+	"github.com/gravitl/netmaker/netclient/config"
+)
+
+var upgrade0162 = UpgradeInfo{
+	RequiredVersions: []string{
+		"v0.14.6",
+		"v0.15.0",
+		"v0.15.1",
+		"v0.15.2",
+		"v0.16.1",
+	},
+	NewVersion: "v0.16.2",
+	OP:         update0162,
+}
+
+func update0162(cfg *config.ClientConfig) {
+	// set connect default if not present 15.X -> 16.0
+	update0161(cfg)
+}

+ 71 - 1
netclient/gui/components/views/networks.go

@@ -21,11 +21,12 @@ func GetNetworksView(networks []string) fyne.CanvasObject {
 	if len(networks) == 0 {
 	if len(networks) == 0 {
 		return container.NewCenter(widget.NewLabel("No networks present"))
 		return container.NewCenter(widget.NewLabel("No networks present"))
 	}
 	}
-	grid := container.New(layout.NewGridLayout(4),
+	grid := container.New(layout.NewGridLayout(5),
 		container.NewCenter(widget.NewLabel("Network Name")),
 		container.NewCenter(widget.NewLabel("Network Name")),
 		container.NewCenter(widget.NewLabel("Node Info")),
 		container.NewCenter(widget.NewLabel("Node Info")),
 		container.NewCenter(widget.NewLabel("Pull Latest")),
 		container.NewCenter(widget.NewLabel("Pull Latest")),
 		container.NewCenter(widget.NewLabel("Leave network")),
 		container.NewCenter(widget.NewLabel("Leave network")),
+		container.NewCenter(widget.NewLabel("Connection status")),
 	)
 	)
 	for i := range networks {
 	for i := range networks {
 		network := &networks[i]
 		network := &networks[i]
@@ -49,6 +50,24 @@ func GetNetworksView(networks []string) fyne.CanvasObject {
 				leave(*network)
 				leave(*network)
 			}, components.Danger_color),
 			}, components.Danger_color),
 		)
 		)
+		cfg, err := config.ReadConfig(*network)
+		if err != nil {
+			fmt.Println(err)
+		}
+		if cfg.Node.Connected == "yes" {
+			grid.Add(
+				components.ColoredIconButton("disconnect", theme.CheckButtonCheckedIcon(), func() {
+					disconnect(*network)
+				}, components.Gravitl_color),
+			)
+		} else {
+			grid.Add(
+				components.ColoredIconButton("connect", theme.CheckButtonIcon(), func() {
+					connect(*network)
+				}, components.Danger_color),
+			)
+		}
+
 		// renders = append(renders, container.NewCenter(netToolbar))
 		// renders = append(renders, container.NewCenter(netToolbar))
 	}
 	}
 
 
@@ -164,3 +183,54 @@ func leave(network string) {
 	RefreshComponent(Confirm, confirmView)
 	RefreshComponent(Confirm, confirmView)
 	ShowView(Confirm)
 	ShowView(Confirm)
 }
 }
+func connect(network string) {
+
+	confirmView := GetConfirmation("Confirm connecting "+network+"?", func() {
+		ShowView(Networks)
+	}, func() {
+		LoadingNotify()
+		err := functions.Connect(network)
+		if err != nil {
+
+			ErrorNotify("Failed to connect " + network + " : " + err.Error())
+
+		} else {
+			SuccessNotify("connected to " + network)
+		}
+		networks, err := ncutils.GetSystemNetworks()
+		if err != nil {
+			networks = []string{}
+			ErrorNotify("Failed to read local networks!")
+		}
+		RefreshComponent(Networks, GetNetworksView(networks))
+		ShowView(Networks)
+	})
+	RefreshComponent(Confirm, confirmView)
+	ShowView(Confirm)
+}
+func disconnect(network string) {
+
+	confirmView := GetConfirmation("Confirm disconnecting  "+network+"?", func() {
+		ShowView(Networks)
+	}, func() {
+		LoadingNotify()
+		fmt.Println(network)
+		err := functions.Disconnect(network)
+		if err != nil {
+
+			ErrorNotify("Failed to disconnect " + network + " : " + err.Error())
+
+		} else {
+			SuccessNotify("disconnected from " + network)
+		}
+		networks, err := ncutils.GetSystemNetworks()
+		if err != nil {
+			networks = []string{}
+			ErrorNotify("Failed to read local networks!")
+		}
+		RefreshComponent(Networks, GetNetworksView(networks))
+		ShowView(Networks)
+	})
+	RefreshComponent(Confirm, confirmView)
+	ShowView(Confirm)
+}

+ 37 - 1
netclient/gui/gui.go

@@ -10,6 +10,8 @@ import (
 	"fyne.io/fyne/v2/container"
 	"fyne.io/fyne/v2/container"
 	"fyne.io/fyne/v2/theme"
 	"fyne.io/fyne/v2/theme"
 	"fyne.io/fyne/v2/widget"
 	"fyne.io/fyne/v2/widget"
+	"github.com/agnivade/levenshtein"
+
 	"github.com/gravitl/netmaker/logger"
 	"github.com/gravitl/netmaker/logger"
 	"github.com/gravitl/netmaker/netclient/functions"
 	"github.com/gravitl/netmaker/netclient/functions"
 	"github.com/gravitl/netmaker/netclient/gui/components"
 	"github.com/gravitl/netmaker/netclient/gui/components"
@@ -48,15 +50,48 @@ func Run(networks []string) error {
 	views.SetView(views.NetDetails, netDetailsViews)
 	views.SetView(views.NetDetails, netDetailsViews)
 	window.SetFixedSize(false)
 	window.SetFixedSize(false)
 
 
+	searchBar := widget.NewEntry()
+	searchBar.PlaceHolder = "Search a Network ..."
+	searchBar.TextStyle = fyne.TextStyle{
+		Italic: true,
+	}
+	searchBar.OnChanged = func(text string) {
+		if text == "" {
+			networkView = container.NewVScroll(views.GetNetworksView(networks))
+			networkView.SetMinSize(fyne.NewSize(400, 300))
+			views.RefreshComponent(views.Networks, networkView)
+			views.ShowView(views.Networks)
+			return
+		}
+
+		opts := []string{}
+		for _, n := range networks {
+			r := levenshtein.ComputeDistance(text, n)
+			if r <= 2 {
+				opts = append(opts, n)
+			}
+		}
+
+		// fmt.Println(opts)
+		networkView = container.NewVScroll(views.GetNetworksView(opts))
+		networkView.SetMinSize(fyne.NewSize(400, 300))
+		views.RefreshComponent(views.Networks, networkView)
+		views.ShowView(views.Networks)
+		opts = nil
+	}
+
 	toolbar := container.NewCenter(widget.NewToolbar(
 	toolbar := container.NewCenter(widget.NewToolbar(
 		components.NewToolbarLabelButton("Networks", theme.HomeIcon(), func() {
 		components.NewToolbarLabelButton("Networks", theme.HomeIcon(), func() {
+			searchBar.Show()
 			views.ShowView(views.Networks)
 			views.ShowView(views.Networks)
 			views.ClearNotification()
 			views.ClearNotification()
 		}, components.Blue_color),
 		}, components.Blue_color),
 		components.NewToolbarLabelButton("Join new", theme.ContentAddIcon(), func() {
 		components.NewToolbarLabelButton("Join new", theme.ContentAddIcon(), func() {
+			searchBar.Hide()
 			views.ShowView(views.Join)
 			views.ShowView(views.Join)
 		}, components.Gravitl_color),
 		}, components.Gravitl_color),
 		components.NewToolbarLabelButton("Uninstall", theme.ErrorIcon(), func() {
 		components.NewToolbarLabelButton("Uninstall", theme.ErrorIcon(), func() {
+			searchBar.Hide()
 			confirmView := views.GetConfirmation("Confirm Netclient uninstall?", func() {
 			confirmView := views.GetConfirmation("Confirm Netclient uninstall?", func() {
 				views.ShowView(views.Networks)
 				views.ShowView(views.Networks)
 			}, func() {
 			}, func() {
@@ -96,8 +131,9 @@ func Run(networks []string) error {
 	views.CurrentContent = container.NewVBox()
 	views.CurrentContent = container.NewVBox()
 
 
 	views.CurrentContent.Add(container.NewGridWithRows(
 	views.CurrentContent.Add(container.NewGridWithRows(
-		1,
+		2,
 		toolbar,
 		toolbar,
+		searchBar,
 	))
 	))
 	views.CurrentContent.Add(views.GetView(views.Networks))
 	views.CurrentContent.Add(views.GetView(views.Networks))
 	views.CurrentContent.Add(views.GetView(views.NetDetails))
 	views.CurrentContent.Add(views.GetView(views.NetDetails))

BIN
netclient/main.exe


+ 1 - 1
netclient/netclient.exe.manifest.xml

@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
 <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
 <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
 <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
     <assemblyIdentity
     <assemblyIdentity
-            version="0.16.1.0"
+            version="0.16.3.0"
             processorArchitecture="*"
             processorArchitecture="*"
             name="netclient.exe"
             name="netclient.exe"
             type="win32"
             type="win32"

+ 3 - 3
netclient/versioninfo.json

@@ -3,13 +3,13 @@
         "FileVersion": {
         "FileVersion": {
             "Major": 0,
             "Major": 0,
             "Minor": 16,
             "Minor": 16,
-            "Patch": 1,
+            "Patch": 3,
             "Build": 0
             "Build": 0
         },
         },
         "ProductVersion": {
         "ProductVersion": {
             "Major": 0,
             "Major": 0,
             "Minor": 16,
             "Minor": 16,
-            "Patch": 1,
+            "Patch": 3,
             "Build": 0
             "Build": 0
         },
         },
         "FileFlagsMask": "3f",
         "FileFlagsMask": "3f",
@@ -29,7 +29,7 @@
         "OriginalFilename": "",
         "OriginalFilename": "",
         "PrivateBuild": "",
         "PrivateBuild": "",
         "ProductName": "Netclient",
         "ProductName": "Netclient",
-        "ProductVersion": "v0.16.1.0",
+        "ProductVersion": "v0.16.3.0",
         "SpecialBuild": ""
         "SpecialBuild": ""
     },
     },
     "VarFileInfo": {
     "VarFileInfo": {

+ 23 - 22
netclient/wireguard/common.go

@@ -110,13 +110,10 @@ func SetPeers(iface string, node *models.Node, peers []wgtypes.PeerConfig) error
 			}
 			}
 		}
 		}
 	}
 	}
-	if ncutils.IsMac() {
-		err = SetMacPeerRoutes(iface)
-		return err
-	} else if ncutils.IsLinux() {
-		if len(peers) > 0 {
-			local.SetPeerRoutes(iface, oldPeerAllowedIps, peers)
-		}
+
+	// if routes are wrong, come back to this, but should work...I would think. Or we should get it working.
+	if len(peers) > 0 {
+		local.SetPeerRoutes(iface, oldPeerAllowedIps, peers)
 	}
 	}
 
 
 	return nil
 	return nil
@@ -263,8 +260,6 @@ func RemoveConf(iface string, printlog bool) error {
 		err = RemoveWithoutWGQuick(iface)
 		err = RemoveWithoutWGQuick(iface)
 	case "windows":
 	case "windows":
 		err = RemoveWindowsConf(iface, printlog)
 		err = RemoveWindowsConf(iface, printlog)
-	case "darwin":
-		err = RemoveConfMac(iface)
 	default:
 	default:
 		confPath := ncutils.GetNetclientPathSpecific() + iface + ".conf"
 		confPath := ncutils.GetNetclientPathSpecific() + iface + ".conf"
 		err = RemoveWGQuickConf(confPath, printlog)
 		err = RemoveWGQuickConf(confPath, printlog)
@@ -282,9 +277,7 @@ func ApplyConf(node *models.Node, ifacename string, confPath string) error {
 	var err error
 	var err error
 	switch os {
 	switch os {
 	case "windows":
 	case "windows":
-		ApplyWindowsConf(confPath, isConnected)
-	case "darwin":
-		ApplyMacOSConf(node, ifacename, confPath, isConnected)
+		ApplyWindowsConf(confPath, ifacename, isConnected)
 	case "nowgquick":
 	case "nowgquick":
 		ApplyWithoutWGQuick(node, ifacename, confPath, isConnected)
 		ApplyWithoutWGQuick(node, ifacename, confPath, isConnected)
 	default:
 	default:
@@ -469,21 +462,29 @@ func UpdateWgInterface(file, privateKey, nameserver string, node models.Node) er
 	//}
 	//}
 	//need to split postup/postdown because ini lib adds a quotes which breaks freebsd
 	//need to split postup/postdown because ini lib adds a quotes which breaks freebsd
 	if node.PostUp != "" {
 	if node.PostUp != "" {
-		parts := strings.Split(node.PostUp, " ; ")
-		for i, part := range parts {
-			if i == 0 {
-				wireguard.Section(section_interface).Key("PostUp").SetValue(part)
+		if node.OS == "freebsd" {
+			parts := strings.Split(node.PostUp, " ; ")
+			for i, part := range parts {
+				if i == 0 {
+					wireguard.Section(section_interface).Key("PostUp").SetValue(part)
+				}
+				wireguard.Section(section_interface).Key("PostUp").AddShadow(part)
 			}
 			}
-			wireguard.Section(section_interface).Key("PostUp").AddShadow(part)
+		} else {
+			wireguard.Section(section_interface).Key("PostUp").SetValue(node.PostUp)
 		}
 		}
 	}
 	}
 	if node.PostDown != "" {
 	if node.PostDown != "" {
-		parts := strings.Split(node.PostDown, " ; ")
-		for i, part := range parts {
-			if i == 0 {
-				wireguard.Section(section_interface).Key("PostDown").SetValue(part)
+		if node.OS == "freebsd" {
+			parts := strings.Split(node.PostDown, " ; ")
+			for i, part := range parts {
+				if i == 0 {
+					wireguard.Section(section_interface).Key("PostDown").SetValue(part)
+				}
+				wireguard.Section(section_interface).Key("PostDown").AddShadow(part)
 			}
 			}
-			wireguard.Section(section_interface).Key("PostDown").AddShadow(part)
+		} else {
+			wireguard.Section(section_interface).Key("PostDown").SetValue(node.PostDown)
 		}
 		}
 	}
 	}
 	if node.MTU != 0 {
 	if node.MTU != 0 {

+ 0 - 238
netclient/wireguard/mac.go

@@ -1,106 +1,11 @@
 package wireguard
 package wireguard
 
 
 import (
 import (
-	"bufio"
 	"errors"
 	"errors"
-	"os"
-	"strconv"
-	"strings"
-	"time"
 
 
-	"github.com/gravitl/netmaker/logger"
-	"github.com/gravitl/netmaker/models"
 	"github.com/gravitl/netmaker/netclient/ncutils"
 	"github.com/gravitl/netmaker/netclient/ncutils"
 )
 )
 
 
-// WgQuickDownMac - bring down mac interface, remove routes, and run post-down commands
-func WgQuickDownMac(node *models.Node, iface string) error {
-	if err := RemoveConfMac(iface); err != nil {
-		return err
-	}
-	if node.PostDown != "" {
-		ncutils.RunCmd(node.PostDown, true)
-	}
-	return nil
-}
-
-// RemoveConfMac - bring down mac interface and remove routes
-func RemoveConfMac(iface string) error {
-	realIface, err := GetRealIface(iface)
-	if realIface != "" {
-		err = deleteInterface(iface, realIface)
-	}
-	return err
-}
-
-// WgQuickUpMac - bring up mac interface and set routes
-func WgQuickUpMac(node *models.Node, iface string, confPath string) error {
-	var err error
-	var realIface string
-	realIface, err = GetRealIface(iface)
-	if realIface != "" && err == nil {
-		deleteInterface(iface, realIface)
-		deleteRoutes(realIface)
-	}
-	realIface, err = addInterface(iface)
-	if err != nil {
-		logger.Log(1, "error creating wg interface")
-		return err
-	}
-	time.Sleep(time.Second / 2)
-
-	err = setConfig(realIface, confPath)
-	if err != nil {
-		logger.Log(1, "error setting config for ", realIface)
-		return err
-	}
-	var ips = append(node.AllowedIPs, node.Address, node.Address6)
-	for _, i := range ips {
-		if i != "" {
-			err = addAddress(realIface, i)
-			if err != nil {
-				logger.Log(1, "error adding address ", i, " on interface ", realIface)
-				return err
-			}
-		}
-	}
-	setMTU(realIface, int(node.MTU))
-	err = upInterface(realIface)
-	if err != nil {
-		logger.Log(1, "error turning on interface ", iface)
-		return err
-	}
-	peerIPs := getPeerIPs(realIface)
-	for _, i := range peerIPs {
-		if i != "" {
-			err = addRoute(i, realIface)
-			if err != nil {
-				logger.Log(1, "error adding route to ", realIface, " for ", i)
-				return err
-			}
-		}
-	}
-	//next, wg-quick runs set_endpoint_direct_route
-	//next, wg-quick runs monitor_daemon
-	time.Sleep(time.Second / 2)
-	if node.PostUp != "" {
-		ncutils.RunCmd(node.PostUp, true)
-	}
-	return err
-}
-
-// addInterface - adds mac interface and creates reference file to match iface name with tun iface
-func addInterface(iface string) (string, error) {
-	ncutils.RunCmd("mkdir -p /var/run/wireguard/", true)
-	ncutils.RunCmd("wireguard-go utun", true)
-	realIface, err := ncutils.GetNewIface("/var/run/wireguard/")
-	if iface != "" && err == nil {
-		ifacePath := "/var/run/wireguard/" + iface + ".name"
-		err = os.WriteFile(ifacePath, []byte(realIface), 0600)
-	}
-	return realIface, err
-}
-
 // GetRealIface - retrieves tun iface based on reference iface name from config file
 // GetRealIface - retrieves tun iface based on reference iface name from config file
 func GetRealIface(iface string) (string, error) {
 func GetRealIface(iface string) (string, error) {
 	ncutils.RunCmd("wg show interfaces", false)
 	ncutils.RunCmd("wg show interfaces", false)
@@ -117,146 +22,3 @@ func GetRealIface(iface string) (string, error) {
 	}
 	}
 	return realIfaceName, nil
 	return realIfaceName, nil
 }
 }
-
-// deleteRoutes - deletes network routes associated with interface
-func deleteRoutes(iface string) error {
-	realIface, err := GetRealIface(iface)
-	if err != nil {
-		return err
-	}
-	var inets = [2]string{"inet", "inet6"}
-	for _, inet := range inets {
-		ifaceList, err := ncutils.RunCmd("netstat -nr -f "+inet+" | grep -e "+realIface+" | awk '{print $1}'", true)
-		if err != nil {
-			return err
-		}
-		destinations := strings.Split(ifaceList, "\n")
-
-		for _, i := range destinations {
-			ncutils.RunCmd("route -q -n delete -"+inet+" "+i, true)
-		}
-	}
-	// wg-quick deletes ENDPOINTS here (runs 'route -q delete' for each peer endpoint on the interface.)
-	// We don't believe this is necessary.
-	return nil
-}
-
-// deleteInterface - deletes the real interface and the referance file
-func deleteInterface(iface string, realIface string) error {
-	var err error
-	var out string
-	if iface != "" {
-		os.Remove("/var/run/wireguard/" + realIface + ".sock")
-		os.Remove("/var/run/wireguard/" + iface + ".name")
-	}
-	out, err = ncutils.RunCmd("ifconfig "+realIface+" down", false)
-	if err != nil && strings.Contains(err.Error(), "does not exist") {
-		err = nil
-	} else if err != nil && out != "" {
-		err = errors.New(out)
-	}
-	return err
-}
-
-// upInterface - bring up the interface with ifconfig
-func upInterface(iface string) error {
-	var err error
-	_, err = ncutils.RunCmd("ifconfig "+iface+" up", true)
-	return err
-}
-
-// addAddress - adds private address to the interface
-func addAddress(iface string, addr string) error {
-	var err error
-	if strings.Contains(addr, ":") {
-		_, err = ncutils.RunCmd("ifconfig "+iface+" inet6 "+addr+" alias", true)
-	} else {
-		_, err = ncutils.RunCmd("ifconfig "+iface+" inet "+addr+" 255.255.255.0 alias", true)
-	}
-	return err
-}
-
-// setMTU - sets MTU for the interface
-func setMTU(iface string, mtu int) error {
-	var err error
-	if mtu == 0 {
-		mtu = 1280
-	}
-	_, err = ncutils.RunCmd("ifconfig "+iface+" mtu "+strconv.Itoa(mtu), true)
-	return err
-}
-
-// addRoute - adds network route to the interface if it does not already exist
-func addRoute(addr string, iface string) error {
-	var err error
-	var out string
-	var inetx = "inet"
-	if strings.Contains(addr, ":") {
-		inetx = "inet6"
-	}
-	out, err = ncutils.RunCmd("route -n get -"+inetx+" "+addr, true)
-	if err != nil {
-		return err
-	}
-	if !(strings.Contains(out, iface)) {
-		_, err = ncutils.RunCmd("route -q -n add -"+inetx+" "+addr+" -interface "+iface, true)
-	}
-	return err
-}
-
-// setConfig - sets configuration of the wireguard interface from the config file
-func setConfig(realIface string, confPath string) error {
-	confString := getConfig(confPath)
-	// pathFormatted := strings.Replace(confPath, " ", "\\ ", -1)
-	err := os.WriteFile(confPath+".tmp", []byte(confString), 0600)
-	if err != nil {
-		return err
-	}
-	_, err = ncutils.RunCmd("wg setconf "+realIface+" "+confPath+".tmp", true)
-	os.Remove(confPath + ".tmp")
-	return err
-}
-
-// getConfig - gets config from config file and strips out incompatible fields
-func getConfig(path string) string {
-	// pathFormatted := strings.Replace(path, " ", "\\ ", -1)
-	var confCmd = "grep -v -e Address -e MTU -e PostUp -e PostDown "
-	confRaw, _ := ncutils.RunCmd(confCmd+path, false)
-	return confRaw
-}
-
-// SetMacPeerRoutes - sets routes for interface from the peer list for all AllowedIps
-func SetMacPeerRoutes(realIface string) error {
-	var err error
-	peerIPs := getPeerIPs(realIface)
-	if len(peerIPs) == 0 {
-		return err
-	}
-	for _, i := range peerIPs {
-		if i != "" {
-			err = addRoute(i, realIface)
-			if err != nil {
-				logger.Log(1, "error adding route to ", realIface, " for ", i)
-				return err
-			}
-		}
-	}
-	return err
-}
-
-// getPeerIPs - retrieves peer AllowedIPs from WireGuard interface
-func getPeerIPs(realIface string) []string {
-	allowedIps := []string{}
-	out, err := ncutils.RunCmd("wg show "+realIface+" allowed-ips", false)
-	if err != nil {
-		return allowedIps
-	}
-	scanner := bufio.NewScanner(strings.NewReader(out))
-	for scanner.Scan() {
-		fields := strings.Fields(scanner.Text())
-		if len(fields) > 1 {
-			allowedIps = append(allowedIps, fields[1:]...)
-		}
-	}
-	return allowedIps
-}

+ 1 - 13
netclient/wireguard/unix.go

@@ -5,14 +5,13 @@ import (
 	"os"
 	"os"
 
 
 	"github.com/gravitl/netmaker/logger"
 	"github.com/gravitl/netmaker/logger"
-	"github.com/gravitl/netmaker/models"
 	"github.com/gravitl/netmaker/netclient/ncutils"
 	"github.com/gravitl/netmaker/netclient/ncutils"
 )
 )
 
 
 // ApplyWGQuickConf - applies wg-quick commands if os supports
 // ApplyWGQuickConf - applies wg-quick commands if os supports
 func ApplyWGQuickConf(confPath, ifacename string, isConnected bool) error {
 func ApplyWGQuickConf(confPath, ifacename string, isConnected bool) error {
 	if ncutils.IsWindows() {
 	if ncutils.IsWindows() {
-		return ApplyWindowsConf(confPath, isConnected)
+		return ApplyWindowsConf(confPath, ifacename, isConnected)
 	} else {
 	} else {
 		_, err := os.Stat(confPath)
 		_, err := os.Stat(confPath)
 		if err != nil {
 		if err != nil {
@@ -31,17 +30,6 @@ func ApplyWGQuickConf(confPath, ifacename string, isConnected bool) error {
 	}
 	}
 }
 }
 
 
-// ApplyMacOSConf - applies system commands similar to wg-quick using golang for MacOS
-func ApplyMacOSConf(node *models.Node, ifacename, confPath string, isConnected bool) error {
-	var err error
-	_ = WgQuickDownMac(node, ifacename)
-	if !isConnected {
-		return nil
-	}
-	err = WgQuickUpMac(node, ifacename, confPath)
-	return err
-}
-
 // RemoveWGQuickConf - calls wg-quick down
 // RemoveWGQuickConf - calls wg-quick down
 func RemoveWGQuickConf(confPath string, printlog bool) error {
 func RemoveWGQuickConf(confPath string, printlog bool) error {
 	_, err := ncutils.RunCmd(fmt.Sprintf("wg-quick down %s", confPath), printlog)
 	_, err := ncutils.RunCmd(fmt.Sprintf("wg-quick down %s", confPath), printlog)

+ 3 - 1
netclient/wireguard/windows.go

@@ -8,7 +8,9 @@ import (
 )
 )
 
 
 // ApplyWindowsConf - applies the WireGuard configuration file on Windows
 // ApplyWindowsConf - applies the WireGuard configuration file on Windows
-func ApplyWindowsConf(confPath string, isConnected bool) error {
+func ApplyWindowsConf(confPath, iface string, isConnected bool) error {
+	RemoveConfGraceful(iface) // have to remove gracefully before applying windows conf
+
 	if !isConnected {
 	if !isConnected {
 		return nil
 		return nil
 	}
 	}

+ 28 - 9
scripts/netclient-install.sh

@@ -37,6 +37,11 @@ elif [ "${OS}" = "FreeBSD" ]; then
 	dependencies="wireguard wget"
 	dependencies="wireguard wget"
 	update_cmd='pkg update'
 	update_cmd='pkg update'
 	install_cmd='pkg install -y'
 	install_cmd='pkg install -y'
+elif [ -f /etc/turris-version ]; then
+	dependencies="wireguard-tools bash"
+	OS="TurrisOS"
+	update_cmd='opkg update'	
+	install_cmd='opkg install'
 elif [ -f /etc/openwrt_release ]; then
 elif [ -f /etc/openwrt_release ]; then
 	dependencies="wireguard-tools bash"
 	dependencies="wireguard-tools bash"
 	OS="OpenWRT"
 	OS="OpenWRT"
@@ -75,7 +80,7 @@ while [ -n "$1" ]; do
 			fi
 			fi
 		fi	
 		fi	
 	else
 	else
-		if [ "${OS}" = "OpenWRT" ]; then
+		if [ "${OS}" = "OpenWRT" ] || [ "${OS}" = "TurrisOS" ]; then
 			is_installed=$(opkg list-installed $1 | grep $1)
 			is_installed=$(opkg list-installed $1 | grep $1)
 		else
 		else
 			is_installed=$(dpkg-query -W --showformat='${Status}\n' $1 | grep "install ok installed")
 			is_installed=$(dpkg-query -W --showformat='${Status}\n' $1 | grep "install ok installed")
@@ -86,7 +91,7 @@ while [ -n "$1" ]; do
 			echo "    " $1 is not installed. Attempting install.
 			echo "    " $1 is not installed. Attempting install.
 			${install_cmd} $1
 			${install_cmd} $1
 			sleep 5
 			sleep 5
-			if [ "${OS}" = "OpenWRT" ]; then
+			if [ "${OS}" = "OpenWRT" ] || [ "${OS}" = "TurrisOS" ]; then
 				is_installed=$(opkg list-installed $1 | grep $1)
 				is_installed=$(opkg list-installed $1 | grep $1)
 			else
 			else
 				is_installed=$(dpkg-query -W --showformat='${Status}\n' $1 | grep "install ok installed")
 				is_installed=$(dpkg-query -W --showformat='${Status}\n' $1 | grep "install ok installed")
@@ -143,8 +148,11 @@ case $(uname | tr A-Z a-z) in
 			arm*)
 			arm*)
 				dist=netclient-$CPU_ARCH
 				dist=netclient-$CPU_ARCH
 			;;
 			;;
-            mipsle)
+			mipsle)
                 dist=netclient-mipsle
                 dist=netclient-mipsle
+			;;
+			mips*)
+                dist=netclient-$CPU_ARCH
 			;;
 			;;
 			*)
 			*)
 				fatal "$CPU_ARCH : cpu architecture not supported"
 				fatal "$CPU_ARCH : cpu architecture not supported"
@@ -189,7 +197,7 @@ echo "Binary = $dist"
 
 
 url="https://github.com/gravitl/netmaker/releases/download/$VERSION/$dist"
 url="https://github.com/gravitl/netmaker/releases/download/$VERSION/$dist"
 curl_opts='-nv'
 curl_opts='-nv'
-if [ "${OS}" = "OpenWRT" ]; then
+if [ "${OS}" = "OpenWRT" ] || [ "${OS}" = "TurrisOS" ]; then
 	curl_opts='-q'
 	curl_opts='-q'
 fi
 fi
 
 
@@ -204,7 +212,7 @@ fi
 chmod +x netclient
 chmod +x netclient
 
 
 EXTRA_ARGS=""
 EXTRA_ARGS=""
-if [  "${OS}" = "OpenWRT" ]; then
+if [ "${OS}" = "OpenWRT" ] || [ "${OS}" = "TurrisOS" ]; then
 	EXTRA_ARGS="--daemon=off"
 	EXTRA_ARGS="--daemon=off"
 fi
 fi
 
 
@@ -225,9 +233,20 @@ if [ "${OS}" = "FreeBSD" ]; then
   fi
   fi
 fi
 fi
 
 
-if [ "${OS}" = "OpenWRT" ]; then
+if [ "${OS}" = "OpenWRT" ] || [ "${OS}" = "TurrisOS" ]; then
 	mv ./netclient /sbin/netclient
 	mv ./netclient /sbin/netclient
-	cat << 'END_OF_FILE' > ./netclient.service.tmp
+
+	if [ "${OS}" = "TurrisOS" ]; then
+		url="https://raw.githubusercontent.com/gravitl/netmaker/$VERSION/scripts/openwrt-daemon.sh"
+		if curl --output /dev/null --silent --head --fail $url; then
+			wget $curl_opts -O netclient.service.tmp $url
+		else
+			wget $curl_opts -O netclient.service.tmp https://raw.githubusercontent.com/gravitl/netmaker/master/scripts/openwrt-daemon.sh
+		fi
+	elif [ "${OS}" = "OpenWRT" ] && [ "$CPU_ARCH" = "mips" ]; then
+		wget $curl_opts -O netclient.service.tmp https://raw.githubusercontent.com/gravitl/netmaker/master/scripts/openwrt-daemon.sh
+	else
+		cat << 'END_OF_FILE' > ./netclient.service.tmp
 #!/bin/sh /etc/rc.common
 #!/bin/sh /etc/rc.common
 
 
 EXTRA_COMMANDS="status"
 EXTRA_COMMANDS="status"
@@ -271,11 +290,11 @@ status() {
 }
 }
 
 
 END_OF_FILE
 END_OF_FILE
+	fi
 	mv ./netclient.service.tmp /etc/init.d/netclient
 	mv ./netclient.service.tmp /etc/init.d/netclient
 	chmod +x /etc/init.d/netclient
 	chmod +x /etc/init.d/netclient
 	/etc/init.d/netclient enable
 	/etc/init.d/netclient enable
 	/etc/init.d/netclient start
 	/etc/init.d/netclient start
 else 
 else 
 	rm -f netclient
 	rm -f netclient
-fi
-
+fi

+ 263 - 179
scripts/nm-quick-interactive.sh

@@ -1,7 +1,5 @@
 #!/bin/bash
 #!/bin/bash
 
 
-set -e
-
 cat << "EOF"
 cat << "EOF"
 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -19,59 +17,249 @@ cat << "EOF"
 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 EOF
 EOF
 
 
+if [ -z "$1" ]; then
+	echo "-----------------------------------------------------"
+	echo "Would you like to install Netmaker Community Edition (CE), or Netmaker Enterprise Edition (EE)?"
+	echo "EE will require you to create an account at https://dashboard.license.netmaker.io"
+	echo "-----------------------------------------------------"
+	select install_option in "Community Edition" "Enterprise Edition"; do
+	case $REPLY in
+		1)
+		echo "installing Netmaker CE"
+		INSTALL_TYPE="ce"
+		break
+		;;      
+		2)
+		echo "installing Netmaker EE"
+		INSTALL_TYPE="ee"
+		break
+		;;
+		*) echo "invalid option $REPLY";;
+	esac
+	done
+elif [ "$1" = "ce" ]; then
+	echo "installing Netmaker CE"
+	INSTALL_TYPE="ce"
+elif [ "$1" = "ee" ]; then
+	echo "installing Netmaker EE"
+	INSTALL_TYPE="ee"
+else
+	echo "install type invalid (options: 'ce, ee')"
+	exit 1
+fi
+
+wait_seconds() {(
+  for ((a=1; a <= $1; a++))
+  do
+    echo ". . ."
+    sleep 1
+  done
+)}
+
+confirm() {(
+  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
+)}
+
+if [ $(id -u) -ne 0 ]; then
+   echo "This script must be run as root"
+   exit 1
+fi
+
+echo "checking dependencies..."
+
+OS=$(uname)
+
+if [ -f /etc/debian_version ]; then
+	dependencies="wireguard wireguard-tools jq docker.io docker-compose"
+	update_cmd='apt update'
+	install_cmd='apt-get install -y'
+elif [ -f /etc/alpine-release ]; then
+	dependencies="wireguard jq docker.io docker-compose"
+	update_cmd='apk update'
+	install_cmd='apk --update add'
+elif [ -f /etc/centos-release ]; then
+	dependencies="wireguard jq docker.io docker-compose"
+	update_cmd='yum update'
+	install_cmd='yum install -y'
+elif [ -f /etc/fedora-release ]; then
+	dependencies="wireguard jq docker.io docker-compose"
+	update_cmd='dnf update'
+	install_cmd='dnf install -y'
+elif [ -f /etc/redhat-release ]; then
+	dependencies="wireguard jq docker.io docker-compose"
+	update_cmd='yum update'
+	install_cmd='yum install -y'
+elif [ -f /etc/arch-release ]; then
+    	dependecies="wireguard-tools jq docker.io docker-compose"
+	update_cmd='pacman -Sy'
+	install_cmd='pacman -S --noconfirm'
+elif [ "${OS}" = "FreeBSD" ]; then
+	dependencies="wireguard wget jq docker.io docker-compose"
+	update_cmd='pkg update'
+	install_cmd='pkg install -y'
+elif [ -f /etc/turris-version ]; then
+	dependencies="wireguard-tools bash jq docker.io docker-compose"
+	OS="TurrisOS"
+	update_cmd='opkg update'	
+	install_cmd='opkg install'
+elif [ -f /etc/openwrt_release ]; then
+	dependencies="wireguard-tools bash jq docker.io docker-compose"
+	OS="OpenWRT"
+	update_cmd='opkg update'	
+	install_cmd='opkg install'
+else
+	install_cmd=''
+fi
+
+if [ -z "${install_cmd}" ]; then
+        echo "OS unsupported for automatic dependency install"
+	exit 1
+fi
+
+set -- $dependencies
+while [ -n "$1" ]; do
+	if [ "${OS}" = "FreeBSD" ]; then
+		is_installed=$(pkg check -d $1 | grep "Checking" | grep "done")
+		if [ "$is_installed" != "" ]; then
+			echo "  " $1 is installed
+		else
+			echo "  " $1 is not installed. Attempting install.
+			${install_cmd} $1
+			sleep 5
+			is_installed=$(pkg check -d $1 | grep "Checking" | grep "done")
+			if [ "$is_installed" != "" ]; then
+				echo "  " $1 is installed
+			elif [ -x "$(command -v $1)" ]; then
+				echo "  " $1 is installed
+			else
+				echo "  " FAILED TO INSTALL $1
+				echo "  " This may break functionality.
+			fi
+		fi	
+	else
+		if [ "${OS}" = "OpenWRT" ] || [ "${OS}" = "TurrisOS" ]; then
+			is_installed=$(opkg list-installed $1 | grep $1)
+		else
+			is_installed=$(dpkg-query -W --showformat='${Status}\n' $1 | grep "install ok installed")
+		fi
+		if [ "${is_installed}" != "" ]; then
+			echo "    " $1 is installed
+		else
+			echo "    " $1 is not installed. Attempting install.
+			${install_cmd} $1
+			sleep 5
+			if [ "${OS}" = "OpenWRT" ] || [ "${OS}" = "TurrisOS" ]; then
+				is_installed=$(opkg list-installed $1 | grep $1)
+			else
+				is_installed=$(dpkg-query -W --showformat='${Status}\n' $1 | grep "install ok installed")
+			fi
+			if [ "${is_installed}" != "" ]; then
+				echo "    " $1 is installed
+			elif [ -x "$(command -v $1)" ]; then
+				echo "  " $1 is installed
+			else
+				echo "  " FAILED TO INSTALL $1
+				echo "  " This may break functionality.
+			fi
+		fi
+	fi
+	shift
+done
+
+echo "-----------------------------------------------------"
+echo "dependency check complete"
+echo "-----------------------------------------------------"
+
+wait_seconds 3
+
+set -e
+
 NETMAKER_BASE_DOMAIN=nm.$(curl -s ifconfig.me | tr . -).nip.io
 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')
 COREDNS_IP=$(ip route get 1 | sed -n 's/^.*src \([0-9.]*\) .*$/\1/p')
 SERVER_PUBLIC_IP=$(curl -s ifconfig.me)
 SERVER_PUBLIC_IP=$(curl -s ifconfig.me)
 MASTER_KEY=$(tr -dc A-Za-z0-9 </dev/urandom | head -c 30 ; echo '')
 MASTER_KEY=$(tr -dc A-Za-z0-9 </dev/urandom | head -c 30 ; echo '')
+MQ_PASSWORD=$(tr -dc A-Za-z0-9 </dev/urandom | head -c 30 ; echo '')
 EMAIL="$(echo $RANDOM | md5sum  | head -c 16)@email.com"
 EMAIL="$(echo $RANDOM | md5sum  | head -c 16)@email.com"
+DOMAIN_TYPE=""
 
 
-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 "        grpc.netmaker.example.com"
 echo "-----------------------------------------------------"
 echo "-----------------------------------------------------"
-read -p "Domain (Hit 'enter' to use $NETMAKER_BASE_DOMAIN): " domain
-read -p "Email for LetsEncrypt (Hit 'enter' to use $EMAIL): " email
+echo "Would you like to use your own domain for netmaker, or an auto-generated domain?"
+echo "To use your own domain, add a Wildcard DNS record (e.x: *.netmaker.example.com) pointing to $SERVER_PUBLIC_IP"
+echo "-----------------------------------------------------"
+select domain_option in "Auto Generated ($NETMAKER_BASE_DOMAIN)" "Custom Domain (e.x: netmaker.example.com)"; do
+  case $REPLY in
+    1)
+      echo "using $NETMAKER_BASE_DOMAIN for base domain"
+      DOMAIN_TYPE="auto"
+	  break
+      ;;      
+    2)
+      read -p "Enter Custom Domain (make sure  *.domain points to $SERVER_PUBLIC_IP first): " domain
+      NETMAKER_BASE_DOMAIN=$domain
+      echo "using $NETMAKER_BASE_DOMAIN"
+      DOMAIN_TYPE="custom"
+      break
+      ;;
+    *) echo "invalid option $REPLY";;
+  esac
+done
+
+wait_seconds 2
 
 
-if [ -n "$domain" ]; then
-  NETMAKER_BASE_DOMAIN=$domain
+echo "-----------------------------------------------------"
+echo "The following subdomains will be used:"
+echo "          dashboard.$NETMAKER_BASE_DOMAIN"
+echo "                api.$NETMAKER_BASE_DOMAIN"
+echo "             broker.$NETMAKER_BASE_DOMAIN"
+
+if [ "$INSTALL_TYPE" = "ee" ]; then
+	echo "         prometheus.$NETMAKER_BASE_DOMAIN"
+	echo "  netmaker-exporter.$NETMAKER_BASE_DOMAIN"
+	echo "            grafana.$NETMAKER_BASE_DOMAIN"
 fi
 fi
-if [ -n "$email" ]; then
-  EMAIL=$email
+
+echo "-----------------------------------------------------"
+
+if [[ "$DOMAIN_TYPE" == "custom" ]]; then
+	echo "before continuing, confirm DNS is configured correctly, with records pointing to $SERVER_PUBLIC_IP"
+	confirm
 fi
 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
+wait_seconds 1
+
+if [ "$INSTALL_TYPE" = "ee" ]; then
+
+	echo "-----------------------------------------------------"
+	echo "Provide Details for EE installation:"
+	echo "    1. Log into https://dashboard.license.netmaker.io"
+	echo "    2. Copy License Key Value: https://dashboard.license.netmaker.io/license-keys"
+	echo "    3. Retrieve Account ID: https://dashboard.license.netmaker.io/user"
+	echo "    4. note email address"
+	echo "-----------------------------------------------------"
+	unset LICENSE_KEY
+	while [ -z "$LICENSE_KEY" ]; do
+		read -p "License Key: " LICENSE_KEY
+	done
+	unset ACCOUNT_ID
+	while [ -z ${ACCOUNT_ID} ]; do
+		read -p "Account ID: " ACCOUNT_ID
+	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
+fi
 
 
-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
+unset EMAIL
+while [ -z ${EMAIL} ]; do
+     read -p "Email Address (for LetsEncrypt): " EMAIL
 done
 done
-fi
 
 
-if [ -n "$num_clients" ]; then
-  NUM_CLIENTS=$num_clients
-fi
+wait_seconds 2
 
 
 echo "-----------------------------------------------------------------"
 echo "-----------------------------------------------------------------"
 echo "                SETUP ARGUMENTS"
 echo "                SETUP ARGUMENTS"
@@ -79,41 +267,31 @@ echo "-----------------------------------------------------------------"
 echo "        domain: $NETMAKER_BASE_DOMAIN"
 echo "        domain: $NETMAKER_BASE_DOMAIN"
 echo "         email: $EMAIL"
 echo "         email: $EMAIL"
 echo "     public ip: $SERVER_PUBLIC_IP"
 echo "     public ip: $SERVER_PUBLIC_IP"
-echo "   setup mesh?: $MESH_SETUP"
-echo "    setup vpn?: $VPN_SETUP"
-if [ "${VPN_SETUP}" == "true" ]; then
-echo "     # clients: $NUM_CLIENTS"
+if [ "$INSTALL_TYPE" = "ee" ]; then
+	echo "       license: $LICENSE_KEY"
+	echo "    account id: $ACCOUNT_ID"
 fi
 fi
+echo "-----------------------------------------------------------------"
+echo "Confirm Settings for Installation"
+echo "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -"
 
 
-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
-
+confirm
 
 
-echo "Beginning installation in 5 seconds..."
 
 
-sleep 5
+echo "-----------------------------------------------------------------"
+echo "Beginning installation..."
+echo "-----------------------------------------------------------------"
 
 
-if [ -f "/root/docker-compose.yml" ]; then
-    echo "Using existing docker compose"
-else 
-    echo "Pulling docker compose"
-    wget -q -O /root/docker-compose.yml https://raw.githubusercontent.com/gravitl/netmaker/master/compose/docker-compose.yml
-fi
+wait_seconds 3
 
 
+echo "Pulling config files..."
 
 
-if [ -f "/root/mosquitto.conf" ]; then
-    echo "Using existing mosquitto config"
-else
-    echo "Pulling mosquitto config"
-    wget -q -O /root/mosquitto.conf https://raw.githubusercontent.com/gravitl/netmaker/master/docker/mosquitto.conf
+COMPOSE_URL="https://raw.githubusercontent.com/gravitl/netmaker/master/compose/docker-compose.yml" 
+if [ "$INSTALL_TYPE" = "ee" ]; then
+	COMPOSE_URL="https://raw.githubusercontent.com/gravitl/netmaker/master/compose/docker-compose.ee.yml" 
 fi
 fi
 
 
+wget -O docker-compose.yml $COMPOSE_URL && wget -O /root/mosquitto.conf https://raw.githubusercontent.com/gravitl/netmaker/master/docker/mosquitto.conf && wget -q -O /root/wait.sh https://raw.githubusercontent.com/gravitl/netmaker/develop/docker/wait.sh && chmod +x wait.sh
 
 
 mkdir -p /etc/netmaker
 mkdir -p /etc/netmaker
 
 
@@ -123,7 +301,11 @@ 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/SERVER_PUBLIC_IP/$SERVER_PUBLIC_IP/g" /root/docker-compose.yml
 sed -i "s/REPLACE_MASTER_KEY/$MASTER_KEY/g" /root/docker-compose.yml
 sed -i "s/REPLACE_MASTER_KEY/$MASTER_KEY/g" /root/docker-compose.yml
 sed -i "s/YOUR_EMAIL/$EMAIL/g" /root/docker-compose.yml
 sed -i "s/YOUR_EMAIL/$EMAIL/g" /root/docker-compose.yml
-
+sed -i "s/REPLACE_MQ_ADMIN_PASSWORD/$MQ_PASSWORD/g" /root/docker-compose.yml 
+if [ "$INSTALL_TYPE" = "ee" ]; then
+	sed -i "s~YOUR_LICENSE_KEY~$LICENSE_KEY~g" /root/docker-compose.yml 
+	sed -i "s/YOUR_ACCOUNT_ID/$ACCOUNT_ID/g" /root/docker-compose.yml 
+fi
 echo "Starting containers..."
 echo "Starting containers..."
 
 
 docker-compose -f /root/docker-compose.yml up -d
 docker-compose -f /root/docker-compose.yml up -d
@@ -157,140 +339,42 @@ done
 
 
 
 
 setup_mesh() {( set -e
 setup_mesh() {( set -e
-sleep 5
+
+wait_seconds 5
+
 echo "Creating netmaker network (10.101.0.0/16)"
 echo "Creating netmaker network (10.101.0.0/16)"
 
 
 curl -s -o /dev/null -d '{"addressrange":"10.101.0.0/16","netid":"netmaker"}' -H "Authorization: Bearer $MASTER_KEY" -H 'Content-Type: application/json' https://api.${NETMAKER_BASE_DOMAIN}/api/networks
 curl -s -o /dev/null -d '{"addressrange":"10.101.0.0/16","netid":"netmaker"}' -H "Authorization: Bearer $MASTER_KEY" -H 'Content-Type: application/json' https://api.${NETMAKER_BASE_DOMAIN}/api/networks
 
 
-sleep 5
+wait_seconds 5
 
 
 echo "Creating netmaker access key"
 echo "Creating netmaker access key"
 
 
 curlresponse=$(curl -s -d '{"uses":99999,"name":"netmaker-key"}' -H "Authorization: Bearer $MASTER_KEY" -H 'Content-Type: application/json' https://api.${NETMAKER_BASE_DOMAIN}/api/networks/netmaker/keys)
 curlresponse=$(curl -s -d '{"uses":99999,"name":"netmaker-key"}' -H "Authorization: Bearer $MASTER_KEY" -H 'Content-Type: application/json' https://api.${NETMAKER_BASE_DOMAIN}/api/networks/netmaker/keys)
 ACCESS_TOKEN=$(jq -r '.accessstring' <<< ${curlresponse})
 ACCESS_TOKEN=$(jq -r '.accessstring' <<< ${curlresponse})
 
 
-sleep 5
+wait_seconds 3
 
 
 echo "Configuring netmaker server as ingress gateway"
 echo "Configuring netmaker server as ingress gateway"
 
 
-curlresponse=$(curl -s -H "Authorization: Bearer $MASTER_KEY" -H 'Content-Type: application/json' https://api.${NETMAKER_BASE_DOMAIN}/api/nodes/netmaker)
-SERVER_ID=$(jq -r '.[0].id' <<< ${curlresponse})
 
 
-curl -o /dev/null -s -X POST -H "Authorization: Bearer $MASTER_KEY" -H 'Content-Type: application/json' https://api.${NETMAKER_BASE_DOMAIN}/api/nodes/netmaker/$SERVER_ID/createingress
-
-sleep 5
-)}
-
-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() {( set -e
-
-echo "Creating vpn network (10.201.0.0/16)"
-
-sleep 5
-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' https://api.${NETMAKER_BASE_DOMAIN}/api/networks
-
-sleep 5
-
-echo "Configuring netmaker server as vpn inlet..."
-
-curlresponse=$(curl -s -H "Authorization: Bearer $MASTER_KEY" -H 'Content-Type: application/json' https://api.${NETMAKER_BASE_DOMAIN}/api/nodes/vpn)
-SERVER_ID=$(jq -r '.[0].id' <<< ${curlresponse})
-
-curl -s -o /dev/null -X POST -H "Authorization: Bearer $MASTER_KEY" -H 'Content-Type: application/json' https://api.${NETMAKER_BASE_DOMAIN}/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+)')
-
-echo "Gateway iface: $GATEWAY_IFACE"
-
-curlresponse=$(curl -s -H "Authorization: Bearer $MASTER_KEY" -H 'Content-Type: application/json' https://api.${NETMAKER_BASE_DOMAIN}/api/nodes/vpn)
-SERVER_ID=$(jq -r '.[0].id' <<< ${curlresponse})
-
-EGRESS_JSON=$( jq -n \
-                  --arg gw "$GATEWAY_IFACE" \
-                  '{ranges: ["0.0.0.0/0","::/0"], 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
-
-echo "Creating client configs..."
+while [ -z "$SERVER_ID" ]; do
+	echo "waiting for server node to become available"
+	wait_seconds 2
+	curlresponse=$(curl -s -H "Authorization: Bearer $MASTER_KEY" -H 'Content-Type: application/json' https://api.${NETMAKER_BASE_DOMAIN}/api/nodes/netmaker)
+	SERVER_ID=$(jq -r '.[0].id' <<< ${curlresponse})
+done
 
 
-for ((a=1; a <= $NUM_CLIENTS; a++))
-do
-        CLIENT_JSON=$( jq -n \
-                  --arg clientid "vpnclient-$a" \
-                  '{clientid: $clientid}' )
+curl -o /dev/null -s -X POST -H "Authorization: Bearer $MASTER_KEY" -H 'Content-Type: application/json' https://api.${NETMAKER_BASE_DOMAIN}/api/nodes/netmaker/$SERVER_ID/createingress
 
 
-        curl -s -o /dev/null -d "$CLIENT_JSON" -H "Authorization: Bearer $MASTER_KEY" -H 'Content-Type: application/json' https://api.${NETMAKER_BASE_DOMAIN}/api/extclients/vpn/$SERVER_ID
-done
-sleep 5
 )}
 )}
 
 
-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
-}
-
 set +e
 set +e
 test_connection
 test_connection
 
 
-if [ "${MESH_SETUP}" != "false" ]; then
-        setup_mesh
-fi
+wait_seconds 3
 
 
-if [ "${VPN_SETUP}" == "true" ]; then
-        setup_vpn
-fi
+setup_mesh
 
 
 echo "-----------------------------------------------------------------"
 echo "-----------------------------------------------------------------"
 echo "-----------------------------------------------------------------"
 echo "-----------------------------------------------------------------"

+ 1 - 1
servercfg/sqlconf.go

@@ -36,7 +36,7 @@ func GetSQLPort() int32 {
 	return port
 	return port
 }
 }
 func GetSQLUser() string {
 func GetSQLUser() string {
-	user := "posgres"
+	user := "postgres"
 	if os.Getenv("SQL_USER") != "" {
 	if os.Getenv("SQL_USER") != "" {
 		user = os.Getenv("SQL_USER")
 		user = os.Getenv("SQL_USER")
 	} else if config.Config.SQL.Username != "" {
 	} else if config.Config.SQL.Username != "" {

+ 1 - 1
swagger.yaml

@@ -746,7 +746,7 @@ info:
 
 
         API calls must be authenticated via a header of the format -H “Authorization: Bearer <YOUR_SECRET_KEY>” There are two methods to obtain YOUR_SECRET_KEY: 1. Using the masterkey. By default, this value is “secret key,” but you should change this on your instance and keep it secure. This value can be set via env var at startup or in a config file (config/environments/< env >.yaml). See the [Netmaker](https://docs.netmaker.org/index.html) documentation for more details. 2. Using a JWT received for a node. This can be retrieved by calling the /api/nodes/<network>/authenticate endpoint, as documented below.
         API calls must be authenticated via a header of the format -H “Authorization: Bearer <YOUR_SECRET_KEY>” There are two methods to obtain YOUR_SECRET_KEY: 1. Using the masterkey. By default, this value is “secret key,” but you should change this on your instance and keep it secure. This value can be set via env var at startup or in a config file (config/environments/< env >.yaml). See the [Netmaker](https://docs.netmaker.org/index.html) documentation for more details. 2. Using a JWT received for a node. This can be retrieved by calling the /api/nodes/<network>/authenticate endpoint, as documented below.
     title: Netmaker
     title: Netmaker
-    version: 0.16.1
+    version: 0.16.3
 paths:
 paths:
     /api/dns:
     /api/dns:
         get:
         get: