Browse Source

Merge pull request #823 from gravitl/v0.11.0

V0.11.0
Alex Feiszli 3 years ago
parent
commit
db4dcf4f54
76 changed files with 2247 additions and 2180 deletions
  1. 11 0
      .github/workflows/buildandrelease.yml
  2. 45 12
      .github/workflows/test-artifacts.yml
  3. 1 1
      README.md
  4. 2 2
      compose/docker-compose.contained.yml
  5. 3 3
      compose/docker-compose.hostnetwork.yml
  6. 2 2
      compose/docker-compose.nocaddy.yml
  7. 3 3
      compose/docker-compose.nodns.yml
  8. 3 3
      compose/docker-compose.reference.yml
  9. 2 2
      compose/docker-compose.yml
  10. 3 3
      config/config.go
  11. 1 1
      controllers/ext_client.go
  12. 53 14
      controllers/network.go
  13. 6 53
      controllers/network_test.go
  14. 69 30
      controllers/node.go
  15. 27 12
      controllers/node_grpc.go
  16. 2 2
      controllers/security.go
  17. 1 6
      controllers/server.go
  18. 0 34
      controllers/server_util.go
  19. 24 0
      controllers/user.go
  20. 0 4
      database/database.go
  21. 0 167
      functions/helpers.go
  22. 5 2
      go.mod
  23. 4 4
      go.sum
  24. 19 28
      logger/logger.go
  25. 30 0
      logger/util.go
  26. 32 13
      logic/accesskeys.go
  27. 3 1
      logic/dns.go
  28. 0 4
      logic/gateway.go
  29. 2 2
      logic/jwts.go
  30. 18 46
      logic/networks.go
  31. 37 43
      logic/nodes.go
  32. 130 0
      logic/peers.go
  33. 7 9
      logic/relay.go
  34. 19 2
      logic/server.go
  35. 29 0
      logic/serverconf.go
  36. 1 96
      logic/util.go
  37. 57 0
      logic/wireguard.go
  38. BIN
      main
  39. 9 1
      main.go
  40. 3 18
      models/accessToken.go
  41. 12 43
      models/network.go
  42. 61 81
      models/node.go
  43. 131 0
      mq/handlers.go
  44. 4 222
      mq/mq.go
  45. 127 0
      mq/publishers.go
  46. 23 3
      mq/util.go
  47. 1 31
      netclient/cli_options/cmds.go
  48. 6 0
      netclient/cli_options/flags.go
  49. 49 123
      netclient/command/commands.go
  50. 20 48
      netclient/config/config.go
  51. 2 7
      netclient/daemon/common.go
  52. 11 10
      netclient/daemon/macos.go
  53. 1 1
      netclient/daemon/systemd.go
  54. 0 320
      netclient/functions/checkin.go
  55. 5 57
      netclient/functions/common.go
  56. 208 454
      netclient/functions/daemon.go
  57. 23 20
      netclient/functions/join.go
  58. 192 0
      netclient/functions/mqhandlers.go
  59. 143 0
      netclient/functions/mqpublish.go
  60. 126 0
      netclient/functions/pull.go
  61. 8 0
      netclient/ncutils/constants.go
  62. 105 0
      netclient/ncutils/encryption.go
  63. 3 1
      netclient/ncutils/iface.go
  64. 7 25
      netclient/ncutils/netclientutils.go
  65. 0 2
      netclient/ncutils/netclientutils_darwin.go
  66. 1 1
      netclient/netclient.exe.manifest.xml
  67. BIN
      netclient/netclient.syso
  68. 1 1
      netclient/versioninfo.json
  69. 40 12
      netclient/wireguard/common.go
  70. 135 0
      netclient/wireguard/noquick.go
  71. 1 0
      netclient/wireguard/unix.go
  72. 24 23
      netclient/wireguard/windows.go
  73. 1 0
      scripts/build-binaries.sh
  74. 62 65
      servercfg/serverconf.go
  75. 4 2
      serverctl/iptables.go
  76. 47 5
      serverctl/serverctl.go

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

@@ -47,6 +47,7 @@ jobs:
           env CGO_ENABLED=0 GOOS=freebsd GOARCH=arm GOARM=7 go build -ldflags="-X 'main.version=${NETMAKER_VERSION}'" -o build/netclient-freebsd-arm7/netclient main.go
           env CGO_ENABLED=0 GOOS=freebsd GOARCH=arm GOARM=7 go build -ldflags="-X 'main.version=${NETMAKER_VERSION}'" -o build/netclient-freebsd-arm7/netclient main.go
           env CGO_ENABLED=0 GOOS=freebsd GOARCH=arm64 go build -ldflags="-X 'main.version=${NETMAKER_VERSION}'" -o build/netclient-freebsd-arm64/netclient main.go
           env CGO_ENABLED=0 GOOS=freebsd GOARCH=arm64 go build -ldflags="-X 'main.version=${NETMAKER_VERSION}'" -o build/netclient-freebsd-arm64/netclient main.go
           env CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -ldflags="-X 'main.version=${NETMAKER_VERSION}'" -o build/netclient-darwin/netclient main.go
           env CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -ldflags="-X 'main.version=${NETMAKER_VERSION}'" -o build/netclient-darwin/netclient main.go
+          env CGO_ENABLED=0 GOOS=darwin GOARCH=arm64 go build -ldflags="-X 'main.version=${NETMAKER_VERSION}'" -o build/netclient-darwin-arm64/netclient main.go
           
           
       - name: Upload netmaker x86 to Release
       - name: Upload netmaker x86 to Release
         uses: svenstaro/upload-release-action@v2
         uses: svenstaro/upload-release-action@v2
@@ -177,3 +178,13 @@ jobs:
           overwrite: true
           overwrite: true
           prerelease: true
           prerelease: true
           asset_name: netclient-darwin
           asset_name: netclient-darwin
+
+      - name: Upload darwin-arm64 to Release
+        uses: svenstaro/upload-release-action@v2
+        with:
+          repo_token: ${{ secrets.GITHUB_TOKEN }}
+          file: netclient/build/netclient-darwin-arm64/netclient
+          tag: ${{ env.NETMAKER_VERSION }}
+          overwrite: true
+          prerelease: true
+          asset_name: netclient-darwin-arm64

+ 45 - 12
.github/workflows/test-artifacts.yml

@@ -38,18 +38,51 @@ jobs:
         steps:
         steps:
             - name: Checkout
             - name: Checkout
               uses: actions/checkout@v2
               uses: actions/checkout@v2
+            - name: Setup Go
+              uses: actions/setup-go@v2
+              with:
+                go-version: 1.17
             - name: build client
             - name: build client
               run: |
               run: |
                 cd netclient
                 cd netclient
-                go build -ldflags="-X 'main.version=testing'" .
-                curl -H 'Authorization: Bearer ${{ secrets.NUSAK_MASTERKEY }}' \
-                -H 'Content-Type: multipart/form-data' --form upload='./netclient' \
-                -X POST https://dashboard.nusak.ca/api/file/netclient
-    #deploy:
-         #runs-on: ubuntu-latest
-         #steps:
-            #- name: Deploy Testing Server and Client(s)
-            #  run: |
-            #      curl -X POST https://api.github.com/mattkasun/terraform-test/dispatches \
-            #      -H 'Accept: application/vnd.github.everest-preview+json' \
-            #      -u ${{ secrets.ACCESS_TOKEN }} 
+                go build -ldflags="-X 'main.version=testing'" -o build/netclient
+            - name: deploy
+              uses: mdallasanta/[email protected]
+              with:
+                local: ./netclient/build/netclient                            # Local file path - REQUIRED false - DEFAULT ./
+                remote: /var/www/files/testing/                               # Remote file path - REQUIRED false - DEFAULT ~/
+                host: fileserver.clustercat.com                               # Remote server address - REQUIRED true
+                #port: ${{secrets.PORT}}                                      # Remote server port - REQUIRED false - DEFAULT 22
+                user: root                                                    # Remote server user - REQUIRED true
+                #password: ${{secrets.PASSWORD}}                              # User password - REQUIRED at least one of "password" or "key" 
+                key: ${{secrets.TESTING_SSH_KEY}}                             # Remote server private key - REQUIRED at least one of "password" or "key" 
+                #pre_upload: echo "This will be executed before the upload!"  # Command to run via ssh before scp upload - REQUIRED false
+                #post_upload: echo "This will be executed after the upload!"  # Command to run via ssh after scp upload - REQUIRED false
+                #ssh_options: -o StrictHostKeyChecking=no                     # A set of ssh_option separated by -o - REQUIRED false - DEFAULT -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null
+                #scp_options: -v                                              # Flags to use during scp - REQUIRED false - DEFAULT ''
+    netmaker:
+        runs-on: ubuntu-latest
+        steps:
+            - name: Checkout
+              uses: actions/checkout@v2
+            - name: Setup Go
+              uses: actions/setup-go@v2
+              with:
+                go-version: 1.17
+            - name: build server
+              run:
+                go build -ldflags="-X 'main.version=testing'" -o build/netmaker
+            - name: deploy
+              uses: mdallasanta/[email protected]
+              with:
+                local: ./build/netmaker                                       # Local file path - REQUIRED false - DEFAULT ./
+                remote: /var/www/files/testing/                               # Remote file path - REQUIRED false - DEFAULT ~/
+                host: fileserver.clustercat.com                               # Remote server address - REQUIRED true
+                #port: ${{secrets.PORT}}                                      # Remote server port - REQUIRED false - DEFAULT 22
+                user: root                                                    # Remote server user - REQUIRED true
+                #password: ${{secrets.PASSWORD}}                              # User password - REQUIRED at least one of "password" or "key" 
+                key: ${{secrets.TESTING_SSH_KEY}}                             # Remote server private key - REQUIRED at least one of "password" or "key" 
+                #pre_upload: echo "This will be executed before the upload!"  # Command to run via ssh before scp upload - REQUIRED false
+                #post_upload: echo "This will be executed after the upload!"  # Command to run via ssh after scp upload - REQUIRED false
+                #ssh_options: -o StrictHostKeyChecking=no                     # A set of ssh_option separated by -o - REQUIRED false - DEFAULT -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null
+                #scp_options: -v                                              # Flags to use during scp - REQUIRED false - DEFAULT ''

+ 1 - 1
README.md

@@ -8,7 +8,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.10.0-informational?style=flat-square" />
+    <img src="https://img.shields.io/badge/Version-0.11.0-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" />
     <img src="https://img.shields.io/docker/pulls/gravitl/netmaker" />

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

@@ -3,7 +3,7 @@ version: "3.4"
 services:
 services:
   netmaker:
   netmaker:
     container_name: netmaker
     container_name: netmaker
-    image: gravitl/netmaker:v0.10.0
+    image: gravitl/netmaker:v0.11.0
     volumes:
     volumes:
       - dnsconfig:/root/config/dnsconfig
       - dnsconfig:/root/config/dnsconfig
       - /usr/bin/wg:/usr/bin/wg
       - /usr/bin/wg:/usr/bin/wg
@@ -46,7 +46,7 @@ services:
     container_name: netmaker-ui
     container_name: netmaker-ui
     depends_on:
     depends_on:
       - netmaker
       - netmaker
-    image: gravitl/netmaker-ui:v0.10.0
+    image: gravitl/netmaker-ui:v0.11.0
     links:
     links:
       - "netmaker:api"
       - "netmaker:api"
     ports:
     ports:

+ 3 - 3
compose/docker-compose.hostnetwork.yml

@@ -3,7 +3,7 @@ version: "3.4"
 services:
 services:
   netmaker:
   netmaker:
     container_name: netmaker
     container_name: netmaker
-    image: gravitl/netmaker:v0.10.0
+    image: gravitl/netmaker:v0.11.0
     volumes:
     volumes:
       - dnsconfig:/root/config/dnsconfig
       - dnsconfig:/root/config/dnsconfig
       - /usr/bin/wg:/usr/bin/wg
       - /usr/bin/wg:/usr/bin/wg
@@ -41,7 +41,7 @@ services:
     container_name: netmaker-ui
     container_name: netmaker-ui
     depends_on:
     depends_on:
       - netmaker
       - netmaker
-    image: gravitl/netmaker-ui:0.10.0
+    image: gravitl/netmaker-ui:0.11.0
     links:
     links:
       - "netmaker:api"
       - "netmaker:api"
     ports:
     ports:
@@ -87,4 +87,4 @@ volumes:
   sqldata: {}
   sqldata: {}
   dnsconfig: {}
   dnsconfig: {}
   mosquitto_data: {}
   mosquitto_data: {}
-  mosquitto_logs: {}
+  mosquitto_logs: {}

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

@@ -3,7 +3,7 @@ version: "3.4"
 services:
 services:
   netmaker:
   netmaker:
     container_name: netmaker
     container_name: netmaker
-    image: gravitl/netmaker:v0.10.0
+    image: gravitl/netmaker:v0.11.0
     volumes:
     volumes:
       - dnsconfig:/root/config/dnsconfig
       - dnsconfig:/root/config/dnsconfig
       - /usr/bin/wg:/usr/bin/wg
       - /usr/bin/wg:/usr/bin/wg
@@ -46,7 +46,7 @@ services:
     container_name: netmaker-ui
     container_name: netmaker-ui
     depends_on:
     depends_on:
       - netmaker
       - netmaker
-    image: gravitl/netmaker-ui:v0.10.0
+    image: gravitl/netmaker-ui:v0.11.0
     links:
     links:
       - "netmaker:api"
       - "netmaker:api"
     ports:
     ports:

+ 3 - 3
compose/docker-compose.nodns.yml

@@ -3,7 +3,7 @@ version: "3.4"
 services:
 services:
   netmaker:
   netmaker:
     container_name: netmaker
     container_name: netmaker
-    image: gravitl/netmaker:v0.10.0
+    image: gravitl/netmaker:v0.11.0
     volumes:
     volumes:
       - dnsconfig:/root/config/dnsconfig
       - dnsconfig:/root/config/dnsconfig
       - /usr/bin/wg:/usr/bin/wg
       - /usr/bin/wg:/usr/bin/wg
@@ -46,7 +46,7 @@ services:
     container_name: netmaker-ui
     container_name: netmaker-ui
     depends_on:
     depends_on:
       - netmaker
       - netmaker
-    image: gravitl/netmaker-ui:v0.10.0
+    image: gravitl/netmaker-ui:v0.11.0
     links:
     links:
       - "netmaker:api"
       - "netmaker:api"
     ports:
     ports:
@@ -79,4 +79,4 @@ volumes:
   caddy_conf: {}
   caddy_conf: {}
   sqldata: {}
   sqldata: {}
   mosquitto_data: {}
   mosquitto_data: {}
-  mosquitto_logs: {}
+  mosquitto_logs: {}

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

@@ -2,7 +2,7 @@ services:
   netmaker: # The Primary Server for running Netmaker
   netmaker: # The Primary Server for running Netmaker
     privileged: true # Necessary to run sudo/root level commands on host system. Likely using this if running with host networking on.
     privileged: true # Necessary to run sudo/root level commands on host system. Likely using this if running with host networking on.
     container_name: netmaker
     container_name: netmaker
-    image: gravitl/netmaker:v0.10.0
+    image: gravitl/netmaker:v0.11.0
     volumes: # Volume mounts necessary for CLIENT_MODE to control wireguard networking on host (except dnsconfig, which is where dns config files are stored for use by CoreDNS)
     volumes: # Volume mounts necessary for CLIENT_MODE to control wireguard networking on host (except dnsconfig, which is where dns config files are stored for use by CoreDNS)
       - dnsconfig:/root/config/dnsconfig # Netmaker writes Corefile to this location, which gets mounted by CoreDNS for DNS configuration.
       - dnsconfig:/root/config/dnsconfig # Netmaker writes Corefile to this location, which gets mounted by CoreDNS for DNS configuration.
       - /usr/bin/wg:/usr/bin/wg
       - /usr/bin/wg:/usr/bin/wg
@@ -45,7 +45,7 @@ services:
     container_name: netmaker-ui
     container_name: netmaker-ui
     depends_on:
     depends_on:
       - netmaker
       - netmaker
-    image: gravitl/netmaker-ui:v0.10.0
+    image: gravitl/netmaker-ui:v0.11.0
     links:
     links:
       - "netmaker:api"
       - "netmaker:api"
     ports:
     ports:
@@ -88,4 +88,4 @@ volumes:
   sqldata: {} # storage for embedded sqlite
   sqldata: {} # storage for embedded sqlite
   dnsconfig: {} # storage for coredns
   dnsconfig: {} # storage for coredns
   mosquitto_data: {} # storage for mqtt data
   mosquitto_data: {} # storage for mqtt data
-  mosquitto_logs: {} # storage for mqtt logs
+  mosquitto_logs: {} # storage for mqtt logs

+ 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.10.0
+    image: gravitl/netmaker:v0.11.0
     volumes:
     volumes:
       - dnsconfig:/root/config/dnsconfig
       - dnsconfig:/root/config/dnsconfig
       - /usr/bin/wg:/usr/bin/wg
       - /usr/bin/wg:/usr/bin/wg
@@ -46,7 +46,7 @@ services:
     container_name: netmaker-ui
     container_name: netmaker-ui
     depends_on:
     depends_on:
       - netmaker
       - netmaker
-    image: gravitl/netmaker-ui:v0.10.0
+    image: gravitl/netmaker-ui:v0.11.0
     links:
     links:
       - "netmaker:api"
       - "netmaker:api"
     ports:
     ports:

+ 3 - 3
config/config.go

@@ -53,15 +53,12 @@ type ServerConfig struct {
 	MessageQueueBackend   string `yaml:"messagequeuebackend"`
 	MessageQueueBackend   string `yaml:"messagequeuebackend"`
 	ClientMode            string `yaml:"clientmode"`
 	ClientMode            string `yaml:"clientmode"`
 	DNSMode               string `yaml:"dnsmode"`
 	DNSMode               string `yaml:"dnsmode"`
-	SplitDNS              string `yaml:"splitdns"`
 	DisableRemoteIPCheck  string `yaml:"disableremoteipcheck"`
 	DisableRemoteIPCheck  string `yaml:"disableremoteipcheck"`
-	DisableDefaultNet     string `yaml:"disabledefaultnet"`
 	GRPCSSL               string `yaml:"grpcssl"`
 	GRPCSSL               string `yaml:"grpcssl"`
 	Version               string `yaml:"version"`
 	Version               string `yaml:"version"`
 	SQLConn               string `yaml:"sqlconn"`
 	SQLConn               string `yaml:"sqlconn"`
 	Platform              string `yaml:"platform"`
 	Platform              string `yaml:"platform"`
 	Database              string `yaml:"database"`
 	Database              string `yaml:"database"`
-	CheckinInterval       string `yaml:"checkininterval"`
 	DefaultNodeLimit      int32  `yaml:"defaultnodelimit"`
 	DefaultNodeLimit      int32  `yaml:"defaultnodelimit"`
 	Verbosity             int32  `yaml:"verbosity"`
 	Verbosity             int32  `yaml:"verbosity"`
 	ServerCheckinInterval int64  `yaml:"servercheckininterval"`
 	ServerCheckinInterval int64  `yaml:"servercheckininterval"`
@@ -77,6 +74,9 @@ type ServerConfig struct {
 	ManageIPTables        string `yaml:"manageiptables"`
 	ManageIPTables        string `yaml:"manageiptables"`
 	PortForwardServices   string `yaml:"portforwardservices"`
 	PortForwardServices   string `yaml:"portforwardservices"`
 	HostNetwork           string `yaml:"hostnetwork"`
 	HostNetwork           string `yaml:"hostnetwork"`
+	CommsCIDR             string `yaml:"commscidr"`
+	MQPort                string `yaml:"mqport"`
+	CommsID               string `yaml:"commsid"`
 }
 }
 
 
 // SQLConfig - Generic SQL Config
 // SQLConfig - Generic SQL Config

+ 1 - 1
controllers/ext_client.go

@@ -125,7 +125,7 @@ func getExtClientConf(w http.ResponseWriter, r *http.Request) {
 
 
 	gwnode, err := logic.GetNodeByID(client.IngressGatewayID)
 	gwnode, err := logic.GetNodeByID(client.IngressGatewayID)
 	if err != nil {
 	if err != nil {
-		logger.Log(1, fmt.Sprintf("%s %s %s", r.Header.Get("user"), "Could not retrieve Ingress Gateway Node", client.IngressGatewayID))
+		logger.Log(1, r.Header.Get("user"), "Could not retrieve Ingress Gateway Node", client.IngressGatewayID)
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 		return
 	}
 	}

+ 53 - 14
controllers/network.go

@@ -14,9 +14,13 @@ import (
 	"github.com/gravitl/netmaker/models"
 	"github.com/gravitl/netmaker/models"
 	"github.com/gravitl/netmaker/mq"
 	"github.com/gravitl/netmaker/mq"
 	"github.com/gravitl/netmaker/servercfg"
 	"github.com/gravitl/netmaker/servercfg"
+	"github.com/gravitl/netmaker/serverctl"
 )
 )
 
 
+// ALL_NETWORK_ACCESS - represents all networks
 const ALL_NETWORK_ACCESS = "THIS_USER_HAS_ALL"
 const ALL_NETWORK_ACCESS = "THIS_USER_HAS_ALL"
+
+// NO_NETWORKS_PRESENT - represents no networks
 const NO_NETWORKS_PRESENT = "THIS_USER_HAS_NONE"
 const NO_NETWORKS_PRESENT = "THIS_USER_HAS_NONE"
 
 
 func networkHandlers(r *mux.Router) {
 func networkHandlers(r *mux.Router) {
@@ -26,7 +30,7 @@ func networkHandlers(r *mux.Router) {
 	r.HandleFunc("/api/networks/{networkname}", securityCheck(false, http.HandlerFunc(updateNetwork))).Methods("PUT")
 	r.HandleFunc("/api/networks/{networkname}", securityCheck(false, http.HandlerFunc(updateNetwork))).Methods("PUT")
 	r.HandleFunc("/api/networks/{networkname}/nodelimit", securityCheck(true, http.HandlerFunc(updateNetworkNodeLimit))).Methods("PUT")
 	r.HandleFunc("/api/networks/{networkname}/nodelimit", securityCheck(true, http.HandlerFunc(updateNetworkNodeLimit))).Methods("PUT")
 	r.HandleFunc("/api/networks/{networkname}", securityCheck(true, http.HandlerFunc(deleteNetwork))).Methods("DELETE")
 	r.HandleFunc("/api/networks/{networkname}", securityCheck(true, http.HandlerFunc(deleteNetwork))).Methods("DELETE")
-	r.HandleFunc("/api/networks/{networkname}/keyupdate", securityCheck(false, http.HandlerFunc(keyUpdate))).Methods("POST")
+	r.HandleFunc("/api/networks/{networkname}/keyupdate", securityCheck(true, http.HandlerFunc(keyUpdate))).Methods("POST")
 	r.HandleFunc("/api/networks/{networkname}/keys", securityCheck(false, http.HandlerFunc(createAccessKey))).Methods("POST")
 	r.HandleFunc("/api/networks/{networkname}/keys", securityCheck(false, http.HandlerFunc(createAccessKey))).Methods("POST")
 	r.HandleFunc("/api/networks/{networkname}/keys", securityCheck(false, http.HandlerFunc(getAccessKeys))).Methods("GET")
 	r.HandleFunc("/api/networks/{networkname}/keys", securityCheck(false, http.HandlerFunc(getAccessKeys))).Methods("GET")
 	r.HandleFunc("/api/networks/{networkname}/keys/{name}", securityCheck(false, http.HandlerFunc(deleteAccessKey))).Methods("DELETE")
 	r.HandleFunc("/api/networks/{networkname}/keys/{name}", securityCheck(false, http.HandlerFunc(deleteAccessKey))).Methods("DELETE")
@@ -43,7 +47,7 @@ func getNetworks(w http.ResponseWriter, r *http.Request) {
 		return
 		return
 	}
 	}
 	allnetworks := []models.Network{}
 	allnetworks := []models.Network{}
-	err := errors.New("Networks Error")
+	var err error
 	if networksSlice[0] == ALL_NETWORK_ACCESS {
 	if networksSlice[0] == ALL_NETWORK_ACCESS {
 		allnetworks, err = logic.GetNetworks()
 		allnetworks, err = logic.GetNetworks()
 		if err != nil && !database.IsEmptyRecord(err) {
 		if err != nil && !database.IsEmptyRecord(err) {
@@ -64,6 +68,7 @@ func getNetworks(w http.ResponseWriter, r *http.Request) {
 			allnetworks[i] = net
 			allnetworks[i] = net
 		}
 		}
 	}
 	}
+
 	logger.Log(2, r.Header.Get("user"), "fetched networks.")
 	logger.Log(2, r.Header.Get("user"), "fetched networks.")
 	w.WriteHeader(http.StatusOK)
 	w.WriteHeader(http.StatusOK)
 	json.NewEncoder(w).Encode(allnetworks)
 	json.NewEncoder(w).Encode(allnetworks)
@@ -75,6 +80,10 @@ func getNetwork(w http.ResponseWriter, r *http.Request) {
 	w.Header().Set("Content-Type", "application/json")
 	w.Header().Set("Content-Type", "application/json")
 	var params = mux.Vars(r)
 	var params = mux.Vars(r)
 	netname := params["networkname"]
 	netname := params["networkname"]
+	if isCommsEdit(w, r, netname) {
+		return
+	}
+
 	network, err := logic.GetNetwork(netname)
 	network, err := logic.GetNetwork(netname)
 	if err != nil {
 	if err != nil {
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		returnErrorResponse(w, r, formatError(err, "internal"))
@@ -92,6 +101,10 @@ func keyUpdate(w http.ResponseWriter, r *http.Request) {
 	w.Header().Set("Content-Type", "application/json")
 	w.Header().Set("Content-Type", "application/json")
 	var params = mux.Vars(r)
 	var params = mux.Vars(r)
 	netname := params["networkname"]
 	netname := params["networkname"]
+	if isCommsEdit(w, r, netname) {
+		return
+	}
+
 	network, err := logic.KeyUpdate(netname)
 	network, err := logic.KeyUpdate(netname)
 	if err != nil {
 	if err != nil {
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		returnErrorResponse(w, r, formatError(err, "internal"))
@@ -106,17 +119,13 @@ func keyUpdate(w http.ResponseWriter, r *http.Request) {
 		return
 		return
 	}
 	}
 	for _, node := range nodes {
 	for _, node := range nodes {
-		fmt.Println("updating node ", node.Name, " for a key update")
-		if err := mq.NodeUpdate(&node); err != nil {
-			logger.Log(2, "failed key update ", node.Name)
+		logger.Log(2, "updating node ", node.Name, " for a key update")
+		if node.IsServer != "yes" {
+			if err = mq.NodeUpdate(&node); err != nil {
+				logger.Log(1, "failed to send update to node during a network wide key update", node.Name, node.ID, err.Error())
+			}
 		}
 		}
 	}
 	}
-	node, err := logic.GetNetworkServerLeader(netname)
-	if err != nil {
-		logger.Log(2, "failed to get server node")
-		return
-	}
-	runUpdates(&node, false)
 }
 }
 
 
 // Update a network
 // Update a network
@@ -125,6 +134,10 @@ func updateNetwork(w http.ResponseWriter, r *http.Request) {
 	var params = mux.Vars(r)
 	var params = mux.Vars(r)
 	var network models.Network
 	var network models.Network
 	netname := params["networkname"]
 	netname := params["networkname"]
+	if isCommsEdit(w, r, netname) {
+		return
+	}
+
 	network, err := logic.GetParentNetwork(netname)
 	network, err := logic.GetParentNetwork(netname)
 	if err != nil {
 	if err != nil {
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		returnErrorResponse(w, r, formatError(err, "internal"))
@@ -181,7 +194,9 @@ func updateNetwork(w http.ResponseWriter, r *http.Request) {
 			return
 			return
 		}
 		}
 		for _, node := range nodes {
 		for _, node := range nodes {
-			runUpdates(&node, true)
+			if err = mq.NodeUpdate(&node); err != nil {
+				logger.Log(1, "failed to send update to node during a network wide update", node.Name, node.ID, err.Error())
+			}
 		}
 		}
 	}
 	}
 
 
@@ -227,8 +242,11 @@ func deleteNetwork(w http.ResponseWriter, r *http.Request) {
 
 
 	var params = mux.Vars(r)
 	var params = mux.Vars(r)
 	network := params["networkname"]
 	network := params["networkname"]
-	err := logic.DeleteNetwork(network)
+	if isCommsEdit(w, r, network) {
+		return
+	}
 
 
+	err := logic.DeleteNetwork(network)
 	if err != nil {
 	if err != nil {
 		errtype := "badrequest"
 		errtype := "badrequest"
 		if strings.Contains(err.Error(), "Node check failed") {
 		if strings.Contains(err.Error(), "Node check failed") {
@@ -267,7 +285,7 @@ func createNetwork(w http.ResponseWriter, r *http.Request) {
 		if err != nil {
 		if err != nil {
 			logic.DeleteNetwork(network.NetID)
 			logic.DeleteNetwork(network.NetID)
 			if err == nil {
 			if err == nil {
-				err = errors.New("Failed to add server to network " + network.DisplayName)
+				err = errors.New("Failed to add server to network " + network.NetID)
 			}
 			}
 			returnErrorResponse(w, r, formatError(err, "internal"))
 			returnErrorResponse(w, r, formatError(err, "internal"))
 			return
 			return
@@ -286,6 +304,9 @@ func createAccessKey(w http.ResponseWriter, r *http.Request) {
 	var accesskey models.AccessKey
 	var accesskey models.AccessKey
 	//start here
 	//start here
 	netname := params["networkname"]
 	netname := params["networkname"]
+	if isCommsEdit(w, r, netname) {
+		return
+	}
 	network, err := logic.GetParentNetwork(netname)
 	network, err := logic.GetParentNetwork(netname)
 	if err != nil {
 	if err != nil {
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		returnErrorResponse(w, r, formatError(err, "internal"))
@@ -338,3 +359,21 @@ func deleteAccessKey(w http.ResponseWriter, r *http.Request) {
 	logger.Log(1, r.Header.Get("user"), "deleted access key", keyname, "on network,", netname)
 	logger.Log(1, r.Header.Get("user"), "deleted access key", keyname, "on network,", netname)
 	w.WriteHeader(http.StatusOK)
 	w.WriteHeader(http.StatusOK)
 }
 }
+
+func isCommsEdit(w http.ResponseWriter, r *http.Request, netname string) bool {
+	if netname == serverctl.COMMS_NETID {
+		returnErrorResponse(w, r, formatError(fmt.Errorf("cannot access comms network"), "internal"))
+		return true
+	}
+	return false
+}
+
+func filterCommsNetwork(networks []models.Network) []models.Network {
+	var filterdNets []models.Network
+	for i := range networks {
+		if networks[i].IsComms != "yes" && networks[i].NetID != servercfg.GetCommsID() {
+			filterdNets = append(filterdNets, networks[i])
+		}
+	}
+	return filterdNets
+}

+ 6 - 53
controllers/network_test.go

@@ -1,12 +1,13 @@
 package controller
 package controller
 
 
 import (
 import (
+	"os"
 	"testing"
 	"testing"
-	"time"
 
 
 	"github.com/gravitl/netmaker/database"
 	"github.com/gravitl/netmaker/database"
 	"github.com/gravitl/netmaker/logic"
 	"github.com/gravitl/netmaker/logic"
 	"github.com/gravitl/netmaker/models"
 	"github.com/gravitl/netmaker/models"
+	"github.com/gravitl/netmaker/serverctl"
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/assert"
 )
 )
 
 
@@ -23,7 +24,8 @@ func TestCreateNetwork(t *testing.T) {
 	var network models.Network
 	var network models.Network
 	network.NetID = "skynet"
 	network.NetID = "skynet"
 	network.AddressRange = "10.0.0.1/24"
 	network.AddressRange = "10.0.0.1/24"
-	network.DisplayName = "mynetwork"
+	// if tests break - check here (removed displayname)
+	//network.DisplayName = "mynetwork"
 
 
 	err := logic.CreateNetwork(network)
 	err := logic.CreateNetwork(network)
 	assert.Nil(t, err)
 	assert.Nil(t, err)
@@ -60,20 +62,6 @@ func TestDeleteNetwork(t *testing.T) {
 	})
 	})
 }
 }
 
 
-func TestKeyUpdate(t *testing.T) {
-	t.Skip() //test is failing on last assert  --- not sure why
-	database.InitializeDatabase()
-	createNet()
-	existing, err := logic.GetNetwork("skynet")
-	assert.Nil(t, err)
-	time.Sleep(time.Second * 1)
-	network, err := logic.KeyUpdate("skynet")
-	assert.Nil(t, err)
-	network, err = logic.GetNetwork("skynet")
-	assert.Nil(t, err)
-	assert.Greater(t, network.KeyUpdateTimeStamp, existing.KeyUpdateTimeStamp)
-}
-
 func TestCreateKey(t *testing.T) {
 func TestCreateKey(t *testing.T) {
 	database.InitializeDatabase()
 	database.InitializeDatabase()
 	createNet()
 	createNet()
@@ -193,6 +181,7 @@ func TestSecurityCheck(t *testing.T) {
 	//these seem to work but not sure it the tests are really testing the functionality
 	//these seem to work but not sure it the tests are really testing the functionality
 
 
 	database.InitializeDatabase()
 	database.InitializeDatabase()
+	os.Setenv("MASTER_KEY", "secretkey")
 	t.Run("NoNetwork", func(t *testing.T) {
 	t.Run("NoNetwork", func(t *testing.T) {
 		err, networks, username := SecurityCheck(false, "", "Bearer secretkey")
 		err, networks, username := SecurityCheck(false, "", "Bearer secretkey")
 		assert.Nil(t, err)
 		assert.Nil(t, err)
@@ -243,28 +232,6 @@ func TestValidateNetworkUpdate(t *testing.T) {
 			},
 			},
 			errMessage: "Field validation for 'AddressRange6' failed on the 'cidr' tag",
 			errMessage: "Field validation for 'AddressRange6' failed on the 'cidr' tag",
 		},
 		},
-
-		{
-			testname: "BadDisplayName",
-			network: models.Network{
-				DisplayName: "skynet*",
-			},
-			errMessage: "Field validation for 'DisplayName' failed on the 'alphanum' tag",
-		},
-		{
-			testname: "DisplayNameTooLong",
-			network: models.Network{
-				DisplayName: "Thisisareallylongdisplaynamethatistoolong",
-			},
-			errMessage: "Field validation for 'DisplayName' failed on the 'max' tag",
-		},
-		{
-			testname: "DisplayNameTooShort",
-			network: models.Network{
-				DisplayName: "1",
-			},
-			errMessage: "Field validation for 'DisplayName' failed on the 'min' tag",
-		},
 		{
 		{
 			testname: "InvalidNetID",
 			testname: "InvalidNetID",
 			network: models.Network{
 			network: models.Network{
@@ -307,20 +274,6 @@ func TestValidateNetworkUpdate(t *testing.T) {
 			},
 			},
 			errMessage: "Field validation for 'LocalRange' failed on the 'cidr' tag",
 			errMessage: "Field validation for 'LocalRange' failed on the 'cidr' tag",
 		},
 		},
-		{
-			testname: "CheckInIntervalTooBig",
-			network: models.Network{
-				DefaultCheckInInterval: 100001,
-			},
-			errMessage: "Field validation for 'DefaultCheckInInterval' failed on the 'max' tag",
-		},
-		{
-			testname: "CheckInIntervalTooSmall",
-			network: models.Network{
-				DefaultCheckInInterval: 1,
-			},
-			errMessage: "Field validation for 'DefaultCheckInInterval' failed on the 'min' tag",
-		},
 	}
 	}
 	for _, tc := range cases {
 	for _, tc := range cases {
 		t.Run(tc.testname, func(t *testing.T) {
 		t.Run(tc.testname, func(t *testing.T) {
@@ -344,9 +297,9 @@ func createNet() {
 	var network models.Network
 	var network models.Network
 	network.NetID = "skynet"
 	network.NetID = "skynet"
 	network.AddressRange = "10.0.0.1/24"
 	network.AddressRange = "10.0.0.1/24"
-	network.DisplayName = "mynetwork"
 	_, err := logic.GetNetwork("skynet")
 	_, err := logic.GetNetwork("skynet")
 	if err != nil {
 	if err != nil {
 		logic.CreateNetwork(network)
 		logic.CreateNetwork(network)
 	}
 	}
+	serverctl.InitializeCommsNetwork()
 }
 }

+ 69 - 30
controllers/node.go

@@ -5,7 +5,6 @@ import (
 	"fmt"
 	"fmt"
 	"net/http"
 	"net/http"
 	"strings"
 	"strings"
-	"time"
 
 
 	"github.com/gorilla/mux"
 	"github.com/gorilla/mux"
 	"github.com/gravitl/netmaker/database"
 	"github.com/gravitl/netmaker/database"
@@ -182,6 +181,13 @@ func authorize(networkCheck bool, authNetwork string, next http.Handler) http.Ha
 			var isAuthorized = false
 			var isAuthorized = false
 			var nodeID = ""
 			var nodeID = ""
 			username, networks, isadmin, errN := logic.VerifyUserToken(authToken)
 			username, networks, isadmin, errN := logic.VerifyUserToken(authToken)
+			if errN != nil {
+				errorResponse = models.ErrorResponse{
+					Code: http.StatusUnauthorized, Message: "W1R3: Unauthorized, Invalid Token Processed.",
+				}
+				returnErrorResponse(w, r, errorResponse)
+				return
+			}
 			isnetadmin := isadmin
 			isnetadmin := isadmin
 			if errN == nil && isadmin {
 			if errN == nil && isadmin {
 				nodeID = "mastermac"
 				nodeID = "mastermac"
@@ -257,6 +263,7 @@ func getNetworkNodes(w http.ResponseWriter, r *http.Request) {
 	var nodes []models.Node
 	var nodes []models.Node
 	var params = mux.Vars(r)
 	var params = mux.Vars(r)
 	networkName := params["network"]
 	networkName := params["network"]
+
 	nodes, err := logic.GetNetworkNodes(networkName)
 	nodes, err := logic.GetNetworkNodes(networkName)
 	if err != nil {
 	if err != nil {
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		returnErrorResponse(w, r, formatError(err, "internal"))
@@ -293,9 +300,9 @@ func getAllNodes(w http.ResponseWriter, r *http.Request) {
 		}
 		}
 	}
 	}
 	//Return all the nodes in JSON format
 	//Return all the nodes in JSON format
-	logger.Log(2, r.Header.Get("user"), "fetched nodes")
+	logger.Log(3, r.Header.Get("user"), "fetched all nodes they have access to")
 	w.WriteHeader(http.StatusOK)
 	w.WriteHeader(http.StatusOK)
-	json.NewEncoder(w).Encode(nodes)
+	json.NewEncoder(w).Encode(filterCommsNodes(nodes))
 }
 }
 
 
 func getUsersNodes(user models.User) ([]models.Node, error) {
 func getUsersNodes(user models.User) ([]models.Node, error) {
@@ -323,6 +330,10 @@ func getNode(w http.ResponseWriter, r *http.Request) {
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 		return
 	}
 	}
+	if logic.IsNodeInComms(&node) {
+		returnErrorResponse(w, r, formatError(err, "internal"))
+		return
+	}
 	logger.Log(2, r.Header.Get("user"), "fetched node", params["nodeid"])
 	logger.Log(2, r.Header.Get("user"), "fetched node", params["nodeid"])
 	w.WriteHeader(http.StatusOK)
 	w.WriteHeader(http.StatusOK)
 	json.NewEncoder(w).Encode(node)
 	json.NewEncoder(w).Encode(node)
@@ -389,8 +400,8 @@ func createNode(w http.ResponseWriter, r *http.Request) {
 	validKey := logic.IsKeyValid(networkName, node.AccessKey)
 	validKey := logic.IsKeyValid(networkName, node.AccessKey)
 
 
 	if !validKey {
 	if !validKey {
-		//Check to see if network will allow manual sign up
-		//may want to switch this up with the valid key check and avoid a DB call that way.
+		// Check to see if network will allow manual sign up
+		// may want to switch this up with the valid key check and avoid a DB call that way.
 		if network.AllowManualSignUp == "yes" {
 		if network.AllowManualSignUp == "yes" {
 			node.IsPending = "yes"
 			node.IsPending = "yes"
 		} else {
 		} else {
@@ -411,12 +422,11 @@ func createNode(w http.ResponseWriter, r *http.Request) {
 	logger.Log(1, r.Header.Get("user"), "created new node", node.Name, "on network", node.Network)
 	logger.Log(1, r.Header.Get("user"), "created new node", node.Name, "on network", node.Network)
 	w.WriteHeader(http.StatusOK)
 	w.WriteHeader(http.StatusOK)
 	json.NewEncoder(w).Encode(node)
 	json.NewEncoder(w).Encode(node)
-
-	runUpdates(&node, false)
+	runForceServerUpdate(&node)
 }
 }
 
 
-//Takes node out of pending state
-//TODO: May want to use cordon/uncordon terminology instead of "ispending".
+// Takes node out of pending state
+// TODO: May want to use cordon/uncordon terminology instead of "ispending".
 func uncordonNode(w http.ResponseWriter, r *http.Request) {
 func uncordonNode(w http.ResponseWriter, r *http.Request) {
 	var params = mux.Vars(r)
 	var params = mux.Vars(r)
 	w.Header().Set("Content-Type", "application/json")
 	w.Header().Set("Content-Type", "application/json")
@@ -430,9 +440,11 @@ func uncordonNode(w http.ResponseWriter, r *http.Request) {
 	w.WriteHeader(http.StatusOK)
 	w.WriteHeader(http.StatusOK)
 	json.NewEncoder(w).Encode("SUCCESS")
 	json.NewEncoder(w).Encode("SUCCESS")
 
 
-	runUpdates(&node, true)
+	runUpdates(&node, false)
 }
 }
 
 
+// == EGRESS ==
+
 func createEgressGateway(w http.ResponseWriter, r *http.Request) {
 func createEgressGateway(w http.ResponseWriter, r *http.Request) {
 	var gateway models.EgressGatewayRequest
 	var gateway models.EgressGatewayRequest
 	var params = mux.Vars(r)
 	var params = mux.Vars(r)
@@ -532,7 +544,6 @@ func updateNode(w http.ResponseWriter, r *http.Request) {
 		returnErrorResponse(w, r, formatError(err, "badrequest"))
 		returnErrorResponse(w, r, formatError(err, "badrequest"))
 		return
 		return
 	}
 	}
-	newNode.PullChanges = "yes"
 	relayupdate := false
 	relayupdate := false
 	if node.IsRelay == "yes" && len(newNode.RelayAddrs) > 0 {
 	if node.IsRelay == "yes" && len(newNode.RelayAddrs) > 0 {
 		if len(newNode.RelayAddrs) != len(node.RelayAddrs) {
 		if len(newNode.RelayAddrs) != len(node.RelayAddrs) {
@@ -551,6 +562,8 @@ func updateNode(w http.ResponseWriter, r *http.Request) {
 		newNode.PostUp = node.PostUp
 		newNode.PostUp = node.PostUp
 	}
 	}
 
 
+	ifaceDelta := logic.IfaceDelta(&node, &newNode)
+
 	err = logic.UpdateNode(&node, &newNode)
 	err = logic.UpdateNode(&node, &newNode)
 	if err != nil {
 	if err != nil {
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		returnErrorResponse(w, r, formatError(err, "internal"))
@@ -563,10 +576,7 @@ func updateNode(w http.ResponseWriter, r *http.Request) {
 		}
 		}
 		if len(updatenodes) > 0 {
 		if len(updatenodes) > 0 {
 			for _, relayedNode := range updatenodes {
 			for _, relayedNode := range updatenodes {
-				err = mq.NodeUpdate(&relayedNode)
-				if err != nil {
-					logger.Log(1, "error sending update to relayed node ", relayedNode.Address, "on network", node.Network, ": ", err.Error())
-				}
+				runUpdates(&relayedNode, false)
 			}
 			}
 		}
 		}
 	}
 	}
@@ -579,7 +589,7 @@ func updateNode(w http.ResponseWriter, r *http.Request) {
 	w.WriteHeader(http.StatusOK)
 	w.WriteHeader(http.StatusOK)
 	json.NewEncoder(w).Encode(newNode)
 	json.NewEncoder(w).Encode(newNode)
 
 
-	runUpdates(&newNode, true)
+	runUpdates(&newNode, ifaceDelta)
 }
 }
 
 
 func deleteNode(w http.ResponseWriter, r *http.Request) {
 func deleteNode(w http.ResponseWriter, r *http.Request) {
@@ -600,11 +610,6 @@ func deleteNode(w http.ResponseWriter, r *http.Request) {
 	}
 	}
 	//send update to node to be deleted before deleting on server otherwise message cannot be sent
 	//send update to node to be deleted before deleting on server otherwise message cannot be sent
 	node.Action = models.NODE_DELETE
 	node.Action = models.NODE_DELETE
-	if err := mq.NodeUpdate(&node); err != nil {
-		logger.Log(1, "error publishing node update", err.Error())
-		returnErrorResponse(w, r, formatError(err, "internal"))
-		return
-	}
 
 
 	err = logic.DeleteNodeByID(&node, false)
 	err = logic.DeleteNodeByID(&node, false)
 	if err != nil {
 	if err != nil {
@@ -613,25 +618,59 @@ func deleteNode(w http.ResponseWriter, r *http.Request) {
 	}
 	}
 	returnSuccessResponse(w, r, nodeid+" deleted.")
 	returnSuccessResponse(w, r, nodeid+" deleted.")
 
 
-	time.Sleep(time.Second << 1)
 	logger.Log(1, r.Header.Get("user"), "Deleted node", nodeid, "from network", params["network"])
 	logger.Log(1, r.Header.Get("user"), "Deleted node", nodeid, "from network", params["network"])
 	runUpdates(&node, false)
 	runUpdates(&node, false)
+	runForceServerUpdate(&node)
 }
 }
 
 
-func runUpdates(node *models.Node, nodeUpdate bool) error {
-	//don't publish to server node
-
-	if nodeUpdate && !isServer(node) {
+func runUpdates(node *models.Node, ifaceDelta bool) {
+	go func() { // don't block http response
+		err := logic.TimerCheckpoint()
+		if err != nil {
+			logger.Log(3, "error occurred on timer,", err.Error())
+		}
+		// publish node update if not server
 		if err := mq.NodeUpdate(node); err != nil {
 		if err := mq.NodeUpdate(node); err != nil {
-			logger.Log(1, "error publishing node update", err.Error())
-			return err
+			logger.Log(1, "error publishing node update to node", node.Name, node.ID, err.Error())
+		}
+
+		if err := runServerUpdate(node, ifaceDelta); err != nil {
+			logger.Log(1, "error running server update", err.Error())
 		}
 		}
+	}()
+}
+
+// updates local peers for a server on a given node's network
+func runServerUpdate(node *models.Node, ifaceDelta bool) error {
+
+	if servercfg.IsClientMode() != "on" || !isServer(node) {
+		return nil
 	}
 	}
 
 
-	if err := runServerPeerUpdate(node, isServer(node)); err != nil {
-		logger.Log(1, "internal error when running peer node:", err.Error())
+	currentServerNode, err := logic.GetNetworkServerLocal(node.Network)
+	if err != nil {
 		return err
 		return err
 	}
 	}
 
 
+	if ifaceDelta && logic.IsLeader(&currentServerNode) {
+		if err := mq.PublishPeerUpdate(&currentServerNode); err != nil {
+			logger.Log(1, "failed to publish peer update "+err.Error())
+		}
+	}
+
+	if err := logic.ServerUpdate(&currentServerNode, ifaceDelta); err != nil {
+		logger.Log(1, "server node:", currentServerNode.ID, "failed update")
+		return err
+	}
 	return nil
 	return nil
 }
 }
+
+func filterCommsNodes(nodes []models.Node) []models.Node {
+	var filterdNodes []models.Node
+	for i := range nodes {
+		if !logic.IsNodeInComms(&nodes[i]) {
+			filterdNodes = append(filterdNodes, nodes[i])
+		}
+	}
+	return filterdNodes
+}

+ 27 - 12
controllers/node_grpc.go

@@ -92,6 +92,12 @@ func (s *NodeServiceServer) CreateNode(ctx context.Context, req *nodepb.Object)
 		Server: key,
 		Server: key,
 	}
 	}
 
 
+	commID, err := logic.FetchCommsNetID()
+	if err != nil {
+		return nil, err
+	}
+	node.CommID = commID
+
 	err = logic.CreateNode(&node)
 	err = logic.CreateNode(&node)
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
@@ -107,7 +113,7 @@ func (s *NodeServiceServer) CreateNode(ctx context.Context, req *nodepb.Object)
 		Type: nodepb.NODE_TYPE,
 		Type: nodepb.NODE_TYPE,
 	}
 	}
 
 
-	runUpdates(&node, false)
+	runForceServerUpdate(&node)
 
 
 	go func(node *models.Node) {
 	go func(node *models.Node) {
 		if node.UDPHolePunch == "yes" {
 		if node.UDPHolePunch == "yes" {
@@ -134,6 +140,7 @@ func (s *NodeServiceServer) CreateNode(ctx context.Context, req *nodepb.Object)
 }
 }
 
 
 // NodeServiceServer.UpdateNode updates a node and responds over gRPC
 // NodeServiceServer.UpdateNode updates a node and responds over gRPC
+// DELETE ONE DAY - DEPRECATED
 func (s *NodeServiceServer) UpdateNode(ctx context.Context, req *nodepb.Object) (*nodepb.Object, error) {
 func (s *NodeServiceServer) UpdateNode(ctx context.Context, req *nodepb.Object) (*nodepb.Object, error) {
 
 
 	var newnode models.Node
 	var newnode models.Node
@@ -166,8 +173,6 @@ func (s *NodeServiceServer) UpdateNode(ctx context.Context, req *nodepb.Object)
 		return nil, err
 		return nil, err
 	}
 	}
 
 
-	runUpdates(&newnode, false)
-
 	return &nodepb.Object{
 	return &nodepb.Object{
 		Data: string(nodeData),
 		Data: string(nodeData),
 		Type: nodepb.NODE_TYPE,
 		Type: nodepb.NODE_TYPE,
@@ -175,10 +180,10 @@ func (s *NodeServiceServer) UpdateNode(ctx context.Context, req *nodepb.Object)
 }
 }
 
 
 func getServerAddrs(node *models.Node) {
 func getServerAddrs(node *models.Node) {
-	serverNodes := logic.GetServerNodes(node.Network)
+	serverNodes := logic.GetServerNodes(serverctl.COMMS_NETID)
 	//pubIP, _ := servercfg.GetPublicIP()
 	//pubIP, _ := servercfg.GetPublicIP()
 	if len(serverNodes) == 0 {
 	if len(serverNodes) == 0 {
-		if err := serverctl.SyncServerNetwork(node.Network); err != nil {
+		if err := serverctl.SyncServerNetwork(serverctl.COMMS_NETID); err != nil {
 			return
 			return
 		}
 		}
 	}
 	}
@@ -217,7 +222,7 @@ func (s *NodeServiceServer) DeleteNode(ctx context.Context, req *nodepb.Object)
 		return nil, err
 		return nil, err
 	}
 	}
 
 
-	runServerPeerUpdate(&node, false)
+	runForceServerUpdate(&node)
 
 
 	return &nodepb.Object{
 	return &nodepb.Object{
 		Data: "success",
 		Data: "success",
@@ -233,12 +238,7 @@ func (s *NodeServiceServer) GetPeers(ctx context.Context, req *nodepb.Object) (*
 		return nil, err
 		return nil, err
 	}
 	}
 
 
-	excludeIsRelayed := node.IsRelay != "yes"
-	var relayedNode string
-	if node.IsRelayed == "yes" {
-		relayedNode = node.Address
-	}
-	peers, err := logic.GetPeersList(node.Network, excludeIsRelayed, relayedNode)
+	peers, err := logic.GetPeersList(&node)
 	if err != nil {
 	if err != nil {
 		if strings.Contains(err.Error(), logic.RELAY_NODE_ERR) {
 		if strings.Contains(err.Error(), logic.RELAY_NODE_ERR) {
 			peers, err = logic.PeerListUnRelay(node.ID, node.Network)
 			peers, err = logic.PeerListUnRelay(node.ID, node.Network)
@@ -309,3 +309,18 @@ func getNodeFromRequestData(data string) (models.Node, error) {
 func isServer(node *models.Node) bool {
 func isServer(node *models.Node) bool {
 	return node.IsServer == "yes"
 	return node.IsServer == "yes"
 }
 }
+
+func runForceServerUpdate(node *models.Node) {
+	go func() {
+		if err := mq.PublishPeerUpdate(node); err != nil {
+			logger.Log(1, "failed a peer update after creation of node", node.Name)
+		}
+
+		var currentServerNode, getErr = logic.GetNetworkServerLeader(node.Network)
+		if getErr == nil {
+			if err := logic.ServerUpdate(&currentServerNode, false); err != nil {
+				logger.Log(1, "server node:", currentServerNode.ID, "failed update")
+			}
+		}
+	}()
+}

+ 2 - 2
controllers/security.go

@@ -98,9 +98,9 @@ func SecurityCheck(reqAdmin bool, netname string, token string) (error, []string
 	return nil, userNetworks, username
 	return nil, userNetworks, username
 }
 }
 
 
-//Consider a more secure way of setting master key
+// Consider a more secure way of setting master key
 func authenticateMaster(tokenString string) bool {
 func authenticateMaster(tokenString string) bool {
-	return tokenString == servercfg.GetMasterKey()
+	return tokenString == servercfg.GetMasterKey() && servercfg.GetMasterKey() != ""
 }
 }
 
 
 //Consider a more secure way of setting master key
 //Consider a more secure way of setting master key

+ 1 - 6
controllers/server.go

@@ -49,7 +49,7 @@ func securityCheckServer(adminonly bool, next http.Handler) http.HandlerFunc {
 			returnErrorResponse(w, r, errorResponse)
 			returnErrorResponse(w, r, errorResponse)
 			return
 			return
 		}
 		}
-		if adminonly && !isadmin && !authenticateMasterServer(authToken) {
+		if adminonly && !isadmin && !authenticateMaster(authToken) {
 			returnErrorResponse(w, r, errorResponse)
 			returnErrorResponse(w, r, errorResponse)
 			return
 			return
 		}
 		}
@@ -57,11 +57,6 @@ func securityCheckServer(adminonly bool, next http.Handler) http.HandlerFunc {
 	}
 	}
 }
 }
 
 
-//Consider a more secure way of setting master key
-func authenticateMasterServer(tokenString string) bool {
-	return tokenString == servercfg.GetMasterKey()
-}
-
 func removeNetwork(w http.ResponseWriter, r *http.Request) {
 func removeNetwork(w http.ResponseWriter, r *http.Request) {
 	// Set header
 	// Set header
 	w.Header().Set("Content-Type", "application/json")
 	w.Header().Set("Content-Type", "application/json")

+ 0 - 34
controllers/server_util.go

@@ -1,34 +0,0 @@
-package controller
-
-import (
-	"github.com/gravitl/netmaker/logger"
-	"github.com/gravitl/netmaker/logic"
-	"github.com/gravitl/netmaker/models"
-	"github.com/gravitl/netmaker/mq"
-	"github.com/gravitl/netmaker/servercfg"
-)
-
-func runServerPeerUpdate(node *models.Node, ifaceDelta bool) error {
-
-	err := logic.TimerCheckpoint()
-	if err != nil {
-		logger.Log(3, "error occurred on timer,", err.Error())
-	}
-
-	if err := mq.PublishPeerUpdate(node); err != nil {
-		logger.Log(0, "failed to inform peers of new node ", err.Error())
-	}
-
-	if servercfg.IsClientMode() != "on" {
-		return nil
-	}
-	var currentServerNode, getErr = logic.GetNetworkServerLeader(node.Network)
-	if err != nil {
-		return getErr
-	}
-	if err = logic.ServerUpdate(&currentServerNode, ifaceDelta); err != nil {
-		logger.Log(1, "server node:", currentServerNode.ID, "failed update")
-		return err
-	}
-	return nil
-}

+ 24 - 0
controllers/user.go

@@ -12,6 +12,7 @@ import (
 	"github.com/gravitl/netmaker/logger"
 	"github.com/gravitl/netmaker/logger"
 	"github.com/gravitl/netmaker/logic"
 	"github.com/gravitl/netmaker/logic"
 	"github.com/gravitl/netmaker/models"
 	"github.com/gravitl/netmaker/models"
+	"github.com/gravitl/netmaker/servercfg"
 )
 )
 
 
 func userHandlers(r *mux.Router) {
 func userHandlers(r *mux.Router) {
@@ -166,6 +167,11 @@ func createUser(w http.ResponseWriter, r *http.Request) {
 	// get node from body of request
 	// get node from body of request
 	_ = json.NewDecoder(r.Body).Decode(&user)
 	_ = json.NewDecoder(r.Body).Decode(&user)
 
 
+	if !user.IsAdmin && isAddingComms(user.Networks) {
+		returnErrorResponse(w, r, formatError(fmt.Errorf("can not add comms network to non admin"), "badrequest"))
+		return
+	}
+
 	user, err := logic.CreateUser(user)
 	user, err := logic.CreateUser(user)
 
 
 	if err != nil {
 	if err != nil {
@@ -194,6 +200,10 @@ func updateUserNetworks(w http.ResponseWriter, r *http.Request) {
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 		return
 	}
 	}
+	if !userchange.IsAdmin && isAddingComms(userchange.Networks) {
+		returnErrorResponse(w, r, formatError(fmt.Errorf("can not add comms network to non admin"), "badrequest"))
+		return
+	}
 
 
 	err = logic.UpdateUserNetworks(userchange.Networks, userchange.IsAdmin, &user)
 	err = logic.UpdateUserNetworks(userchange.Networks, userchange.IsAdmin, &user)
 	if err != nil {
 	if err != nil {
@@ -219,6 +229,10 @@ func updateUser(w http.ResponseWriter, r *http.Request) {
 		returnErrorResponse(w, r, formatError(fmt.Errorf("can not update user info for oauth user %s", username), "forbidden"))
 		returnErrorResponse(w, r, formatError(fmt.Errorf("can not update user info for oauth user %s", username), "forbidden"))
 		return
 		return
 	}
 	}
+	if !user.IsAdmin && isAddingComms(user.Networks) {
+		returnErrorResponse(w, r, formatError(fmt.Errorf("can not add comms network to non admin"), "badrequest"))
+		return
+	}
 	var userchange models.User
 	var userchange models.User
 	// we decode our body request params
 	// we decode our body request params
 	err = json.NewDecoder(r.Body).Decode(&userchange)
 	err = json.NewDecoder(r.Body).Decode(&userchange)
@@ -288,3 +302,13 @@ func deleteUser(w http.ResponseWriter, r *http.Request) {
 	logger.Log(1, username, "was deleted")
 	logger.Log(1, username, "was deleted")
 	json.NewEncoder(w).Encode(params["username"] + " deleted.")
 	json.NewEncoder(w).Encode(params["username"] + " deleted.")
 }
 }
+
+func isAddingComms(networks []string) bool {
+	commsID := servercfg.GetCommsID()
+	for i := range networks {
+		if networks[i] == commsID {
+			return true
+		}
+	}
+	return false
+}

+ 0 - 4
database/database.go

@@ -32,9 +32,6 @@ const DNS_TABLE_NAME = "dns"
 // EXT_CLIENT_TABLE_NAME - ext client table
 // EXT_CLIENT_TABLE_NAME - ext client table
 const EXT_CLIENT_TABLE_NAME = "extclients"
 const EXT_CLIENT_TABLE_NAME = "extclients"
 
 
-// INT_CLIENTS_TABLE_NAME - int client table
-const INT_CLIENTS_TABLE_NAME = "intclients"
-
 // PEERS_TABLE_NAME - peers table
 // PEERS_TABLE_NAME - peers table
 const PEERS_TABLE_NAME = "peers"
 const PEERS_TABLE_NAME = "peers"
 
 
@@ -126,7 +123,6 @@ func createTables() {
 	createTable(USERS_TABLE_NAME)
 	createTable(USERS_TABLE_NAME)
 	createTable(DNS_TABLE_NAME)
 	createTable(DNS_TABLE_NAME)
 	createTable(EXT_CLIENT_TABLE_NAME)
 	createTable(EXT_CLIENT_TABLE_NAME)
-	createTable(INT_CLIENTS_TABLE_NAME)
 	createTable(PEERS_TABLE_NAME)
 	createTable(PEERS_TABLE_NAME)
 	createTable(SERVERCONF_TABLE_NAME)
 	createTable(SERVERCONF_TABLE_NAME)
 	createTable(SERVER_UUID_TABLE_NAME)
 	createTable(SERVER_UUID_TABLE_NAME)

+ 0 - 167
functions/helpers.go

@@ -2,100 +2,12 @@ package functions
 
 
 import (
 import (
 	"encoding/json"
 	"encoding/json"
-	"log"
 	"strings"
 	"strings"
 
 
 	"github.com/gravitl/netmaker/database"
 	"github.com/gravitl/netmaker/database"
-	"github.com/gravitl/netmaker/logic"
 	"github.com/gravitl/netmaker/models"
 	"github.com/gravitl/netmaker/models"
 )
 )
 
 
-// ParseNode - parses a node into a model
-func ParseNode(value string) (models.Node, error) {
-	var node models.Node
-	err := json.Unmarshal([]byte(value), &node)
-	return node, err
-}
-
-// ParseExtClient - parses an extclient into a model
-func ParseExtClient(value string) (models.ExtClient, error) {
-	var extClient models.ExtClient
-	err := json.Unmarshal([]byte(value), &extClient)
-	return extClient, err
-}
-
-// ParseIntClient - parses int client
-func ParseIntClient(value string) (models.IntClient, error) {
-	var intClient models.IntClient
-	err := json.Unmarshal([]byte(value), &intClient)
-	return intClient, err
-}
-
-// GetPeersList - gets peers for given network
-func GetPeersList(networkName string) ([]models.PeersResponse, error) {
-
-	var peers []models.PeersResponse
-	collection, err := database.FetchRecords(database.NODES_TABLE_NAME)
-	if err != nil {
-		return peers, err
-	}
-
-	for _, value := range collection {
-
-		var peer models.PeersResponse
-		err := json.Unmarshal([]byte(value), &peer)
-		if err != nil {
-			continue // try the rest
-		}
-		peers = append(peers, peer)
-	}
-
-	return peers, err
-}
-
-// GetIntPeersList - get int peers list
-func GetIntPeersList() ([]models.PeersResponse, error) {
-
-	var peers []models.PeersResponse
-	records, err := database.FetchRecords(database.INT_CLIENTS_TABLE_NAME)
-
-	if err != nil {
-		return peers, err
-	}
-	// parse the peers
-
-	for _, value := range records {
-
-		var peer models.PeersResponse
-		err := json.Unmarshal([]byte(value), &peer)
-		if err != nil {
-			log.Fatal(err)
-		}
-		// add the node to our node array
-		//maybe better to just return this? But then that's just GetNodes...
-		peers = append(peers, peer)
-	}
-
-	return peers, err
-}
-
-// GetServerIntClient - get server int client
-func GetServerIntClient() (*models.IntClient, error) {
-
-	intClients, err := database.FetchRecords(database.INT_CLIENTS_TABLE_NAME)
-	for _, value := range intClients {
-		var intClient models.IntClient
-		err = json.Unmarshal([]byte(value), &intClient)
-		if err != nil {
-			return nil, err
-		}
-		if intClient.IsServer == "yes" && intClient.Network == "comms" {
-			return &intClient, nil
-		}
-	}
-	return nil, err
-}
-
 // NetworkExists - check if network exists
 // NetworkExists - check if network exists
 func NetworkExists(name string) (bool, error) {
 func NetworkExists(name string) (bool, error) {
 
 
@@ -107,54 +19,6 @@ func NetworkExists(name string) (bool, error) {
 	return len(network) > 0, nil
 	return len(network) > 0, nil
 }
 }
 
 
-// IsNetworkDisplayNameUnique - checks if network display name unique
-func IsNetworkDisplayNameUnique(name string) (bool, error) {
-
-	isunique := true
-
-	dbs, err := logic.GetNetworks()
-	if err != nil {
-		return database.IsEmptyRecord(err), err
-	}
-
-	for i := 0; i < len(dbs); i++ {
-
-		if name == dbs[i].DisplayName {
-			isunique = false
-		}
-	}
-
-	return isunique, nil
-}
-
-// IsKeyValidGlobal - checks if a key is valid globally
-func IsKeyValidGlobal(keyvalue string) bool {
-
-	networks, _ := logic.GetNetworks()
-	var key models.AccessKey
-	foundkey := false
-	isvalid := false
-	for _, network := range networks {
-		for i := len(network.AccessKeys) - 1; i >= 0; i-- {
-			currentkey := network.AccessKeys[i]
-			if currentkey.Value == keyvalue {
-				key = currentkey
-				foundkey = true
-				break
-			}
-		}
-		if foundkey {
-			break
-		}
-	}
-	if foundkey {
-		if key.Uses > 0 {
-			isvalid = true
-		}
-	}
-	return isvalid
-}
-
 // NameInDNSCharSet - name in dns char set
 // NameInDNSCharSet - name in dns char set
 func NameInDNSCharSet(name string) bool {
 func NameInDNSCharSet(name string) bool {
 
 
@@ -186,37 +50,6 @@ func RemoveDeletedNode(nodeid string) bool {
 	return database.DeleteRecord(database.DELETED_NODES_TABLE_NAME, nodeid) == nil
 	return database.DeleteRecord(database.DELETED_NODES_TABLE_NAME, nodeid) == nil
 }
 }
 
 
-// DeleteAllIntClients - delete all int clients
-func DeleteAllIntClients() error {
-	err := database.DeleteAllRecords(database.INT_CLIENTS_TABLE_NAME)
-	if err != nil {
-		return err
-	}
-	return nil
-}
-
-// GetAllIntClients - get all int clients
-func GetAllIntClients() ([]models.IntClient, error) {
-	var clients []models.IntClient
-	collection, err := database.FetchRecords(database.INT_CLIENTS_TABLE_NAME)
-
-	if err != nil {
-		return clients, err
-	}
-
-	for _, value := range collection {
-		var client models.IntClient
-		err := json.Unmarshal([]byte(value), &client)
-		if err != nil {
-			return []models.IntClient{}, err
-		}
-		// add node to our array
-		clients = append(clients, client)
-	}
-
-	return clients, nil
-}
-
 // GetAllExtClients - get all ext clients
 // GetAllExtClients - get all ext clients
 func GetAllExtClients() ([]models.ExtClient, error) {
 func GetAllExtClients() ([]models.ExtClient, error) {
 	var extclients []models.ExtClient
 	var extclients []models.ExtClient

+ 5 - 2
go.mod

@@ -5,7 +5,7 @@ go 1.17
 require (
 require (
 	github.com/eclipse/paho.mqtt.golang v1.3.5
 	github.com/eclipse/paho.mqtt.golang v1.3.5
 	github.com/go-playground/validator/v10 v10.10.0
 	github.com/go-playground/validator/v10 v10.10.0
-	github.com/golang-jwt/jwt/v4 v4.2.0
+	github.com/golang-jwt/jwt/v4 v4.3.0
 	github.com/golang/protobuf v1.5.2 // indirect
 	github.com/golang/protobuf v1.5.2 // indirect
 	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
@@ -27,7 +27,7 @@ require (
 	google.golang.org/genproto v0.0.0-20210201151548-94839c025ad4 // indirect
 	google.golang.org/genproto v0.0.0-20210201151548-94839c025ad4 // indirect
 	google.golang.org/grpc v1.44.0
 	google.golang.org/grpc v1.44.0
 	google.golang.org/protobuf v1.27.1
 	google.golang.org/protobuf v1.27.1
-	gopkg.in/ini.v1 v1.66.3
+	gopkg.in/ini.v1 v1.66.4
 	gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
 	gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
 )
 )
 
 
@@ -46,10 +46,13 @@ require (
 	github.com/google/go-cmp v0.5.5 // indirect
 	github.com/google/go-cmp v0.5.5 // indirect
 	github.com/gorilla/websocket v1.4.2 // indirect
 	github.com/gorilla/websocket v1.4.2 // indirect
 	github.com/josharian/native v0.0.0-20200817173448-b6b71def0850 // indirect
 	github.com/josharian/native v0.0.0-20200817173448-b6b71def0850 // indirect
+	github.com/kr/pretty v0.3.0 // indirect
+	github.com/kr/text v0.2.0 // indirect
 	github.com/leodido/go-urn v1.2.1 // indirect
 	github.com/leodido/go-urn v1.2.1 // indirect
 	github.com/mdlayher/genetlink v1.0.0 // indirect
 	github.com/mdlayher/genetlink v1.0.0 // indirect
 	github.com/mdlayher/netlink v1.4.0 // indirect
 	github.com/mdlayher/netlink v1.4.0 // indirect
 	github.com/pmezard/go-difflib v1.0.0 // indirect
 	github.com/pmezard/go-difflib v1.0.0 // indirect
+	github.com/rogpeppe/go-internal v1.8.0 // indirect
 	github.com/russross/blackfriday/v2 v2.0.1 // indirect
 	github.com/russross/blackfriday/v2 v2.0.1 // indirect
 	github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect
 	github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect
 	github.com/xtgo/uuid v0.0.0-20140804021211-a0b114877d4c // indirect
 	github.com/xtgo/uuid v0.0.0-20140804021211-a0b114877d4c // indirect

+ 4 - 4
go.sum

@@ -46,8 +46,8 @@ github.com/go-playground/universal-translator v0.18.0 h1:82dyy6p4OuJq4/CByFNOn/j
 github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA=
 github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA=
 github.com/go-playground/validator/v10 v10.10.0 h1:I7mrTYv78z8k8VXa/qJlOlEXn/nBh+BF8dHX5nt/dr0=
 github.com/go-playground/validator/v10 v10.10.0 h1:I7mrTYv78z8k8VXa/qJlOlEXn/nBh+BF8dHX5nt/dr0=
 github.com/go-playground/validator/v10 v10.10.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos=
 github.com/go-playground/validator/v10 v10.10.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos=
-github.com/golang-jwt/jwt/v4 v4.2.0 h1:besgBTC8w8HjP6NzQdxwKH9Z5oQMZ24ThTrHp3cZ8eU=
-github.com/golang-jwt/jwt/v4 v4.2.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
+github.com/golang-jwt/jwt/v4 v4.3.0 h1:kHL1vqdqWNfATmA0FNMdmZNMyZI1U6O31X4rlIPoBog=
+github.com/golang-jwt/jwt/v4 v4.3.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
 github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
 github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
 github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
 github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
 github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
 github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
@@ -299,8 +299,8 @@ gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8
 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
 gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
 gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
-gopkg.in/ini.v1 v1.66.3 h1:jRskFVxYaMGAMUbN0UZ7niA9gzL9B49DOqE78vg0k3w=
-gopkg.in/ini.v1 v1.66.3/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
+gopkg.in/ini.v1 v1.66.4 h1:SsAcf+mM7mRZo2nJNGt8mZCjG8ZRaNGMURJw7BsIST4=
+gopkg.in/ini.v1 v1.66.4/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
 gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

+ 19 - 28
logger/logger.go

@@ -4,44 +4,26 @@ import (
 	"fmt"
 	"fmt"
 	"os"
 	"os"
 	"sort"
 	"sort"
-	"strconv"
-	"strings"
 	"sync"
 	"sync"
 	"time"
 	"time"
 )
 )
 
 
+// TimeFormatDay - format of the day for timestamps
 const TimeFormatDay = "2006-01-02"
 const TimeFormatDay = "2006-01-02"
+
+// TimeFormat - total time format
 const TimeFormat = "2006-01-02 15:04:05"
 const TimeFormat = "2006-01-02 15:04:05"
 
 
+// == fields ==
 var currentLogs = make(map[string]string)
 var currentLogs = make(map[string]string)
-
-func makeString(message ...string) string {
-	return strings.Join(message, " ")
-}
-
-func getVerbose() int32 {
-	level, err := strconv.Atoi(os.Getenv("VERBOSITY"))
-	if err != nil || level < 0 {
-		level = 0
-	}
-	if level > 3 {
-		level = 3
-	}
-	return int32(level)
-}
-
-// ResetLogs - reallocates logs map
-func ResetLogs() {
-	currentLogs = make(map[string]string)
-}
+var mu sync.Mutex
 
 
 // Log - handles adding logs
 // Log - handles adding logs
 func Log(verbosity int, message ...string) {
 func Log(verbosity int, message ...string) {
-	var mu sync.Mutex
 	mu.Lock()
 	mu.Lock()
 	defer mu.Unlock()
 	defer mu.Unlock()
 	var currentTime = time.Now()
 	var currentTime = time.Now()
-	var currentMessage = makeString(message...)
+	var currentMessage = MakeString(" ", message...)
 	if int32(verbosity) <= getVerbose() && getVerbose() >= 0 {
 	if int32(verbosity) <= getVerbose() && getVerbose() >= 0 {
 		fmt.Printf("[netmaker] %s %s \n", currentTime.Format(TimeFormat), currentMessage)
 		fmt.Printf("[netmaker] %s %s \n", currentTime.Format(TimeFormat), currentMessage)
 	}
 	}
@@ -74,9 +56,10 @@ func Dump() string {
 
 
 	for i := range dumpLogs {
 	for i := range dumpLogs {
 		var currLog = dumpLogs[i]
 		var currLog = dumpLogs[i]
-		dumpString += fmt.Sprintf("[netmaker] %s %s \n", currLog.Value.Format(TimeFormat), currLog.Key)
+		dumpString += MakeString(" ", "[netmaker]", currLog.Value.Format(TimeFormat), currLog.Key, "\n")
 	}
 	}
 
 
+	resetLogs()
 	return dumpString
 	return dumpString
 }
 }
 
 
@@ -84,13 +67,14 @@ func Dump() string {
 func DumpFile(filePath string) {
 func DumpFile(filePath string) {
 	f, err := os.OpenFile(filePath, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0600)
 	f, err := os.OpenFile(filePath, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0600)
 	if err != nil {
 	if err != nil {
-		panic(err)
+		fmt.Println(MakeString(" ", "could not open log file", filePath))
+		return
 	}
 	}
 
 
 	defer f.Close()
 	defer f.Close()
 
 
 	if _, err = f.WriteString(Dump()); err != nil {
 	if _, err = f.WriteString(Dump()); err != nil {
-		panic(err)
+		fmt.Println("could not dump logs")
 	}
 	}
 }
 }
 
 
@@ -108,6 +92,13 @@ func FatalLog(message ...string) {
 	var mu sync.Mutex
 	var mu sync.Mutex
 	mu.Lock()
 	mu.Lock()
 	defer mu.Unlock()
 	defer mu.Unlock()
-	fmt.Printf("[netmaker] Fatal: %s \n", makeString(message...))
+	fmt.Printf("[netmaker] Fatal: %s \n", MakeString(" ", message...))
 	os.Exit(2)
 	os.Exit(2)
 }
 }
+
+// == private ==
+
+// resetLogs - reallocates logs map
+func resetLogs() {
+	currentLogs = make(map[string]string)
+}

+ 30 - 0
logger/util.go

@@ -0,0 +1,30 @@
+package logger
+
+import (
+	"os"
+	"strconv"
+	"strings"
+)
+
+// MakeString - makes a string using golang string builder
+func MakeString(delimeter string, message ...string) string {
+	var builder strings.Builder
+	for i := range message {
+		builder.WriteString(message[i])
+		if delimeter != "" && i != len(message)-1 {
+			builder.WriteString(delimeter)
+		}
+	}
+	return builder.String()
+}
+
+func getVerbose() int32 {
+	level, err := strconv.Atoi(os.Getenv("VERBOSITY"))
+	if err != nil || level < 0 {
+		level = 0
+	}
+	if level > 3 {
+		level = 3
+	}
+	return int32(level)
+}

+ 32 - 13
logic/accesskeys.go

@@ -49,18 +49,17 @@ func CreateAccessKey(accesskey models.AccessKey, network models.Network) (models
 
 
 	netID := network.NetID
 	netID := network.NetID
 
 
+	commsNetID, err := FetchCommsNetID()
+	if err != nil {
+		return models.AccessKey{}, errors.New("could not retrieve comms netid")
+	}
+
 	var accessToken models.AccessToken
 	var accessToken models.AccessToken
 	s := servercfg.GetServerConfig()
 	s := servercfg.GetServerConfig()
 	servervals := models.ServerConfig{
 	servervals := models.ServerConfig{
-		CoreDNSAddr:     s.CoreDNSAddr,
-		APIConnString:   s.APIConnString,
-		APIHost:         s.APIHost,
-		APIPort:         s.APIPort,
-		GRPCConnString:  s.GRPCConnString,
-		GRPCHost:        s.GRPCHost,
-		GRPCPort:        s.GRPCPort,
-		GRPCSSL:         s.GRPCSSL,
-		CheckinInterval: s.CheckinInterval,
+		GRPCConnString: s.GRPCConnString,
+		GRPCSSL:        s.GRPCSSL,
+		CommsNetwork:   commsNetID,
 	}
 	}
 	accessToken.ServerConfig = servervals
 	accessToken.ServerConfig = servervals
 	accessToken.ClientConfig.Network = netID
 	accessToken.ClientConfig.Network = netID
@@ -148,7 +147,7 @@ func DecrimentKey(networkName string, keyvalue string) {
 	var network models.Network
 	var network models.Network
 
 
 	network, err := GetParentNetwork(networkName)
 	network, err := GetParentNetwork(networkName)
-	if err != nil {
+	if err != nil || network.IsComms == "yes" {
 		return
 		return
 	}
 	}
 
 
@@ -176,13 +175,21 @@ func DecrimentKey(networkName string, keyvalue string) {
 // IsKeyValid - check if key is valid
 // IsKeyValid - check if key is valid
 func IsKeyValid(networkname string, keyvalue string) bool {
 func IsKeyValid(networkname string, keyvalue string) bool {
 
 
-	network, _ := GetParentNetwork(networkname)
+	network, err := GetParentNetwork(networkname)
+	if err != nil {
+		return false
+	}
+	accesskeys := network.AccessKeys
+	if network.IsComms == "yes" {
+		accesskeys = getAllAccessKeys()
+	}
+
 	var key models.AccessKey
 	var key models.AccessKey
 	foundkey := false
 	foundkey := false
 	isvalid := false
 	isvalid := false
 
 
-	for i := len(network.AccessKeys) - 1; i >= 0; i-- {
-		currentkey := network.AccessKeys[i]
+	for i := len(accesskeys) - 1; i >= 0; i-- {
+		currentkey := accesskeys[i]
 		if currentkey.Value == keyvalue {
 		if currentkey.Value == keyvalue {
 			key = currentkey
 			key = currentkey
 			foundkey = true
 			foundkey = true
@@ -236,3 +243,15 @@ func genKey() string {
 	}
 	}
 	return string(b)
 	return string(b)
 }
 }
+
+func getAllAccessKeys() []models.AccessKey {
+	var accesskeys = make([]models.AccessKey, 0)
+	networks, err := GetNetworks()
+	if err != nil {
+		return accesskeys
+	}
+	for i := range networks {
+		accesskeys = append(accesskeys, networks[i].AccessKeys...)
+	}
+	return accesskeys
+}

+ 3 - 1
logic/dns.go

@@ -8,7 +8,6 @@ import (
 	"github.com/gravitl/netmaker/database"
 	"github.com/gravitl/netmaker/database"
 	"github.com/gravitl/netmaker/logger"
 	"github.com/gravitl/netmaker/logger"
 	"github.com/gravitl/netmaker/models"
 	"github.com/gravitl/netmaker/models"
-	"github.com/gravitl/netmaker/servercfg"
 	"github.com/txn2/txeh"
 	"github.com/txn2/txeh"
 )
 )
 
 
@@ -39,9 +38,12 @@ func SetDNS() error {
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}
+	/* if something goes wrong with server DNS, check here
+	// commented out bc we were not using IsSplitDNS
 	if servercfg.IsSplitDNS() {
 	if servercfg.IsSplitDNS() {
 		err = SetCorefile(corefilestring)
 		err = SetCorefile(corefilestring)
 	}
 	}
+	*/
 	return err
 	return err
 }
 }
 
 

+ 0 - 4
logic/gateway.go

@@ -48,7 +48,6 @@ func CreateEgressGateway(gateway models.EgressGatewayRequest) (models.Node, erro
 	node.PostUp = postUpCmd
 	node.PostUp = postUpCmd
 	node.PostDown = postDownCmd
 	node.PostDown = postDownCmd
 	node.SetLastModified()
 	node.SetLastModified()
-	node.PullChanges = "yes"
 	nodeData, err := json.Marshal(&node)
 	nodeData, err := json.Marshal(&node)
 	if err != nil {
 	if err != nil {
 		return node, err
 		return node, err
@@ -94,7 +93,6 @@ func DeleteEgressGateway(network, nodeid string) (models.Node, error) {
 		node.PostDown = "iptables -D FORWARD -i " + node.Interface + " -j ACCEPT; iptables -t nat -D POSTROUTING -o " + node.Interface + " -j MASQUERADE"
 		node.PostDown = "iptables -D FORWARD -i " + node.Interface + " -j ACCEPT; iptables -t nat -D POSTROUTING -o " + node.Interface + " -j MASQUERADE"
 	}
 	}
 	node.SetLastModified()
 	node.SetLastModified()
-	node.PullChanges = "yes"
 
 
 	data, err := json.Marshal(&node)
 	data, err := json.Marshal(&node)
 	if err != nil {
 	if err != nil {
@@ -142,7 +140,6 @@ func CreateIngressGateway(netid string, nodeid string) (models.Node, error) {
 	node.SetLastModified()
 	node.SetLastModified()
 	node.PostUp = postUpCmd
 	node.PostUp = postUpCmd
 	node.PostDown = postDownCmd
 	node.PostDown = postDownCmd
-	node.PullChanges = "yes"
 	node.UDPHolePunch = "no"
 	node.UDPHolePunch = "no"
 
 
 	data, err := json.Marshal(&node)
 	data, err := json.Marshal(&node)
@@ -177,7 +174,6 @@ func DeleteIngressGateway(networkName string, nodeid string) (models.Node, error
 	node.LastModified = time.Now().Unix()
 	node.LastModified = time.Now().Unix()
 	node.IsIngressGateway = "no"
 	node.IsIngressGateway = "no"
 	node.IngressGatewayRange = ""
 	node.IngressGatewayRange = ""
-	node.PullChanges = "yes"
 
 
 	data, err := json.Marshal(&node)
 	data, err := json.Marshal(&node)
 	if err != nil {
 	if err != nil {

+ 2 - 2
logic/jwts.go

@@ -80,7 +80,7 @@ func CreateUserJWT(username string, networks []string, isadmin bool) (response s
 func VerifyUserToken(tokenString string) (username string, networks []string, isadmin bool, err error) {
 func VerifyUserToken(tokenString string) (username string, networks []string, isadmin bool, err error) {
 	claims := &models.UserClaims{}
 	claims := &models.UserClaims{}
 
 
-	if tokenString == servercfg.GetMasterKey() {
+	if tokenString == servercfg.GetMasterKey() && servercfg.GetMasterKey() != "" {
 		return "masteradministrator", nil, true, nil
 		return "masteradministrator", nil, true, nil
 	}
 	}
 
 
@@ -104,7 +104,7 @@ func VerifyToken(tokenString string) (nodeID string, mac string, network string,
 
 
 	//this may be a stupid way of serving up a master key
 	//this may be a stupid way of serving up a master key
 	//TODO: look into a different method. Encryption?
 	//TODO: look into a different method. Encryption?
-	if tokenString == servercfg.GetMasterKey() {
+	if tokenString == servercfg.GetMasterKey() && servercfg.GetMasterKey() != "" {
 		return "mastermac", "", "", nil
 		return "mastermac", "", "", nil
 	}
 	}
 
 

+ 18 - 46
logic/networks.go

@@ -8,7 +8,6 @@ import (
 	"net"
 	"net"
 	"os/exec"
 	"os/exec"
 	"strings"
 	"strings"
-	"time"
 
 
 	"github.com/go-playground/validator/v10"
 	"github.com/go-playground/validator/v10"
 	"github.com/gravitl/netmaker/database"
 	"github.com/gravitl/netmaker/database"
@@ -68,7 +67,6 @@ func CreateNetwork(network models.Network) error {
 	network.SetDefaults()
 	network.SetDefaults()
 	network.SetNodesLastModified()
 	network.SetNodesLastModified()
 	network.SetNetworkLastModified()
 	network.SetNetworkLastModified()
-	network.KeyUpdateTimeStamp = time.Now().Unix()
 
 
 	err := ValidateNetwork(&network, false)
 	err := ValidateNetwork(&network, false)
 	if err != nil {
 	if err != nil {
@@ -106,7 +104,6 @@ func NetworkNodesUpdatePullChanges(networkName string) error {
 			return err
 			return err
 		}
 		}
 		if node.Network == networkName {
 		if node.Network == networkName {
-			node.PullChanges = "yes"
 			data, err := json.Marshal(&node)
 			data, err := json.Marshal(&node)
 			if err != nil {
 			if err != nil {
 				return err
 				return err
@@ -190,19 +187,13 @@ func UniqueAddress(networkName string) (string, error) {
 			offset = false
 			offset = false
 			continue
 			continue
 		}
 		}
-		if networkName == "comms" {
-			if IsIPUnique(networkName, ip.String(), database.INT_CLIENTS_TABLE_NAME, false) {
-				return ip.String(), err
-			}
-		} else {
-			if IsIPUnique(networkName, ip.String(), database.NODES_TABLE_NAME, false) && IsIPUnique(networkName, ip.String(), database.EXT_CLIENT_TABLE_NAME, false) {
-				return ip.String(), err
-			}
+		if IsIPUnique(networkName, ip.String(), database.NODES_TABLE_NAME, false) && IsIPUnique(networkName, ip.String(), database.EXT_CLIENT_TABLE_NAME, false) {
+			return ip.String(), err
 		}
 		}
 	}
 	}
 
 
 	//TODO
 	//TODO
-	err1 := errors.New("ERROR: No unique addresses available. Check network subnet.")
+	err1 := errors.New("ERROR: No unique addresses available. Check network subnet")
 	return "W1R3: NO UNIQUE ADDRESSES AVAILABLE", err1
 	return "W1R3: NO UNIQUE ADDRESSES AVAILABLE", err1
 }
 }
 
 
@@ -301,7 +292,7 @@ func UniqueAddress6(networkName string) (string, error) {
 		}
 		}
 	}
 	}
 	//TODO
 	//TODO
-	err1 := errors.New("ERROR: No unique addresses available. Check network subnet.")
+	err1 := errors.New("ERROR: No unique addresses available. Check network subnet")
 	return "W1R3: NO UNIQUE ADDRESSES AVAILABLE", err1
 	return "W1R3: NO UNIQUE ADDRESSES AVAILABLE", err1
 }
 }
 
 
@@ -380,7 +371,13 @@ func UpdateNetworkLocalAddresses(networkName string) error {
 			return err
 			return err
 		}
 		}
 		if node.Network == networkName {
 		if node.Network == networkName {
-			ipaddr, iperr := UniqueAddress(networkName)
+			var ipaddr string
+			var iperr error
+			if node.IsServer == "yes" {
+				ipaddr, iperr = UniqueAddressServer(networkName)
+			} else {
+				ipaddr, iperr = UniqueAddress(networkName)
+			}
 			if iperr != nil {
 			if iperr != nil {
 				fmt.Println("error in node  address assignment!")
 				fmt.Println("error in node  address assignment!")
 				return iperr
 				return iperr
@@ -440,7 +437,6 @@ func RemoveNetworkNodeIPv6Addresses(networkName string) error {
 		if node.Network == networkName {
 		if node.Network == networkName {
 			node.IsDualStack = "no"
 			node.IsDualStack = "no"
 			node.Address6 = ""
 			node.Address6 = ""
-			node.PullChanges = "yes"
 			data, err := json.Marshal(&node)
 			data, err := json.Marshal(&node)
 			if err != nil {
 			if err != nil {
 				return err
 				return err
@@ -469,14 +465,19 @@ func UpdateNetworkNodeAddresses(networkName string) error {
 			return err
 			return err
 		}
 		}
 		if node.Network == networkName {
 		if node.Network == networkName {
-			ipaddr, iperr := UniqueAddress(networkName)
+			var ipaddr string
+			var iperr error
+			if node.IsServer == "yes" {
+				ipaddr, iperr = UniqueAddressServer(networkName)
+			} else {
+				ipaddr, iperr = UniqueAddress(networkName)
+			}
 			if iperr != nil {
 			if iperr != nil {
 				fmt.Println("error in node  address assignment!")
 				fmt.Println("error in node  address assignment!")
 				return iperr
 				return iperr
 			}
 			}
 
 
 			node.Address = ipaddr
 			node.Address = ipaddr
-			node.PullChanges = "yes"
 			data, err := json.Marshal(&node)
 			data, err := json.Marshal(&node)
 			if err != nil {
 			if err != nil {
 				return err
 				return err
@@ -488,27 +489,6 @@ func UpdateNetworkNodeAddresses(networkName string) error {
 	return nil
 	return nil
 }
 }
 
 
-// IsNetworkDisplayNameUnique - checks if displayname is unique from other networks
-func IsNetworkDisplayNameUnique(network *models.Network) (bool, error) {
-
-	isunique := true
-
-	records, err := GetNetworks()
-
-	if err != nil && !database.IsEmptyRecord(err) {
-		return false, err
-	}
-
-	for i := 0; i < len(records); i++ {
-
-		if network.NetID == records[i].DisplayName {
-			isunique = false
-		}
-	}
-
-	return isunique, nil
-}
-
 // IsNetworkNameUnique - checks to see if any other networks have the same name (id)
 // IsNetworkNameUnique - checks to see if any other networks have the same name (id)
 func IsNetworkNameUnique(network *models.Network) (bool, error) {
 func IsNetworkNameUnique(network *models.Network) (bool, error) {
 
 
@@ -600,14 +580,6 @@ func ValidateNetwork(network *models.Network, isUpdate bool) error {
 		return isFieldUnique && inCharSet
 		return isFieldUnique && inCharSet
 	})
 	})
 	//
 	//
-	_ = v.RegisterValidation("displayname_valid", func(fl validator.FieldLevel) bool {
-		isFieldUnique, _ := IsNetworkDisplayNameUnique(network)
-		inCharSet := network.DisplayNameInNetworkCharSet()
-		if isUpdate {
-			return inCharSet
-		}
-		return isFieldUnique && inCharSet
-	})
 	_ = v.RegisterValidation("checkyesorno", func(fl validator.FieldLevel) bool {
 	_ = v.RegisterValidation("checkyesorno", func(fl validator.FieldLevel) bool {
 		return validation.CheckYesOrNo(fl)
 		return validation.CheckYesOrNo(fl)
 	})
 	})

+ 37 - 43
logic/nodes.go

@@ -85,7 +85,6 @@ func UncordonNode(nodeid string) (models.Node, error) {
 	}
 	}
 	node.SetLastModified()
 	node.SetLastModified()
 	node.IsPending = "no"
 	node.IsPending = "no"
-	node.PullChanges = "yes"
 	data, err := json.Marshal(&node)
 	data, err := json.Marshal(&node)
 	if err != nil {
 	if err != nil {
 		return node, err
 		return node, err
@@ -100,12 +99,7 @@ func GetPeers(node *models.Node) ([]models.Node, error) {
 	if IsLeader(node) {
 	if IsLeader(node) {
 		setNetworkServerPeers(node)
 		setNetworkServerPeers(node)
 	}
 	}
-	excludeIsRelayed := node.IsRelay != "yes"
-	var relayedNode string
-	if node.IsRelayed == "yes" {
-		relayedNode = node.Address
-	}
-	peers, err := GetPeersList(node.Network, excludeIsRelayed, relayedNode)
+	peers, err := GetPeersList(node)
 	if err != nil {
 	if err != nil {
 		if strings.Contains(err.Error(), RELAY_NODE_ERR) {
 		if strings.Contains(err.Error(), RELAY_NODE_ERR) {
 			peers, err = PeerListUnRelay(node.ID, node.Network)
 			peers, err = PeerListUnRelay(node.ID, node.Network)
@@ -145,6 +139,13 @@ func IsLeader(node *models.Node) bool {
 
 
 // UpdateNode - takes a node and updates another node with it's values
 // UpdateNode - takes a node and updates another node with it's values
 func UpdateNode(currentNode *models.Node, newNode *models.Node) error {
 func UpdateNode(currentNode *models.Node, newNode *models.Node) error {
+	var err error
+	if newNode.IsHub == "yes" && currentNode.IsHub != "yes" {
+		if err = unsetHub(newNode.Network); err != nil {
+			return err
+		}
+	}
+
 	if newNode.Address != currentNode.Address {
 	if newNode.Address != currentNode.Address {
 		if network, err := GetParentNetwork(newNode.Network); err == nil {
 		if network, err := GetParentNetwork(newNode.Network); err == nil {
 			if !IsAddressInCIDR(newNode.Address, network.AddressRange) {
 			if !IsAddressInCIDR(newNode.Address, network.AddressRange) {
@@ -350,13 +351,7 @@ func SetNodeDefaults(node *models.Node) {
 	if node.ListenPort == 0 {
 	if node.ListenPort == 0 {
 		node.ListenPort = parentNetwork.DefaultListenPort
 		node.ListenPort = parentNetwork.DefaultListenPort
 	}
 	}
-	if node.SaveConfig == "" {
-		if parentNetwork.DefaultSaveConfig != "" {
-			node.SaveConfig = parentNetwork.DefaultSaveConfig
-		} else {
-			node.SaveConfig = "yes"
-		}
-	}
+
 	if node.Interface == "" {
 	if node.Interface == "" {
 		node.Interface = parentNetwork.DefaultInterface
 		node.Interface = parentNetwork.DefaultInterface
 	}
 	}
@@ -396,8 +391,6 @@ func SetNodeDefaults(node *models.Node) {
 	node.SetDefaultName()
 	node.SetDefaultName()
 	node.SetLastCheckIn()
 	node.SetLastCheckIn()
 	node.SetLastPeerUpdate()
 	node.SetLastPeerUpdate()
-	node.SetRoamingDefault()
-	node.SetPullChangesDefault()
 	node.SetDefaultAction()
 	node.SetDefaultAction()
 	node.SetIsServerDefault()
 	node.SetIsServerDefault()
 	node.SetIsStaticDefault()
 	node.SetIsStaticDefault()
@@ -409,7 +402,7 @@ func SetNodeDefaults(node *models.Node) {
 	node.SetDefaultIsRelay()
 	node.SetDefaultIsRelay()
 	node.SetDefaultIsDocker()
 	node.SetDefaultIsDocker()
 	node.SetDefaultIsK8S()
 	node.SetDefaultIsK8S()
-	node.KeyUpdateTimeStamp = time.Now().Unix()
+	node.SetDefaultIsHub()
 }
 }
 
 
 // GetRecordKey - get record key
 // GetRecordKey - get record key
@@ -512,32 +505,6 @@ func GetNodeRelay(network string, relayedNodeAddr string) (models.Node, error) {
 	return relay, errors.New(RELAY_NODE_ERR + " " + relayedNodeAddr)
 	return relay, errors.New(RELAY_NODE_ERR + " " + relayedNodeAddr)
 }
 }
 
 
-// GetNodeByIDorMacAddress - gets the node, if a mac address exists, but not id, then it should delete it and recreate in DB with new ID
-/*
-func GetNodeByIDorMacAddress(uuid string, macaddress string, network string) (models.Node, error) {
-	var node models.Node
-	var err error
-	node, err = GetNodeByID(uuid)
-	if err != nil && macaddress != "" && network != "" {
-		node, err = GetNodeByMacAddress(network, macaddress)
-		if err != nil {
-			return models.Node{}, err
-		}
-		err = DeleteNodeByMacAddress(&node, true) // remove node
-		if err != nil {
-			return models.Node{}, err
-		}
-		err = CreateNode(&node)
-		if err != nil {
-			return models.Node{}, err
-		}
-		logger.Log(2, "rewriting legacy node data; node now has id,", node.ID)
-		node.PullChanges = "yes"
-	}
-	return node, err
-}
-*/
-// GetNodeByID - get node by uuid, should have been set by create
 func GetNodeByID(uuid string) (models.Node, error) {
 func GetNodeByID(uuid string) (models.Node, error) {
 	var record, err = database.FetchRecord(database.NODES_TABLE_NAME, uuid)
 	var record, err = database.FetchRecord(database.NODES_TABLE_NAME, uuid)
 	if err != nil {
 	if err != nil {
@@ -611,6 +578,11 @@ func IsLocalServer(node *models.Node) bool {
 	return node.ID != "" && local.ID == node.ID
 	return node.ID != "" && local.ID == node.ID
 }
 }
 
 
+// IsNodeInComms returns if node is in comms network or not
+func IsNodeInComms(node *models.Node) bool {
+	return node.Network == servercfg.GetCommsID() && node.IsServer != "yes"
+}
+
 // validateServer - make sure servers dont change port or address
 // validateServer - make sure servers dont change port or address
 func validateServer(currentNode, newNode *models.Node) bool {
 func validateServer(currentNode, newNode *models.Node) bool {
 	return (newNode.Address == currentNode.Address &&
 	return (newNode.Address == currentNode.Address &&
@@ -640,3 +612,25 @@ func isMacAddressUnique(macaddress string, networkName string) (bool, error) {
 
 
 	return isunique, nil
 	return isunique, nil
 }
 }
+
+// unsetHub - unset hub on network nodes
+func unsetHub(networkName string) error {
+
+	nodes, err := GetNetworkNodes(networkName)
+	if err != nil {
+		return err
+	}
+
+	for i := range nodes {
+		if nodes[i].IsHub == "yes" {
+			nodes[i].IsHub = "no"
+			newNodeData, err := json.Marshal(&nodes[i])
+			if err != nil {
+				logger.Log(1, "error on node during hub update")
+				return err
+			}
+			database.Insert(nodes[i].ID, string(newNodeData), database.NODES_TABLE_NAME)
+		}
+	}
+	return nil
+}

+ 130 - 0
logic/peers.go

@@ -7,12 +7,142 @@ import (
 	"strings"
 	"strings"
 	"time"
 	"time"
 
 
+	"github.com/gravitl/netmaker/database"
 	"github.com/gravitl/netmaker/logger"
 	"github.com/gravitl/netmaker/logger"
 	"github.com/gravitl/netmaker/models"
 	"github.com/gravitl/netmaker/models"
 	"github.com/gravitl/netmaker/netclient/ncutils"
 	"github.com/gravitl/netmaker/netclient/ncutils"
 	"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
 	"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
 )
 )
 
 
+// GetHubPeer - in HubAndSpoke networks, if not the hub, return the hub
+/*
+func GetHubPeer(networkName string) []models.Node {
+	var hubpeer = make([]models.Node, 0)
+	servernodes, err := GetNetworkNodes(networkName)
+	if err != nil {
+		return hubpeer
+	}
+	for i := range servernodes {
+		if servernodes[i].IsHub == "yes" {
+			return []models.Node{servernodes[i]}
+		}
+	}
+	return hubpeer
+}
+*/
+
+// GetNodePeers - fetches peers for a given node
+func GetNodePeers(networkName string, excludeRelayed bool, isP2S bool) ([]models.Node, error) {
+	var peers []models.Node
+	var networkNodes, egressNetworkNodes, err = getNetworkEgressAndNodes(networkName)
+	if err != nil {
+		return peers, nil
+	}
+
+	udppeers, errN := database.GetPeers(networkName)
+	if errN != nil {
+		logger.Log(2, errN.Error())
+	}
+
+	for _, node := range networkNodes {
+		var peer = models.Node{}
+		if node.IsEgressGateway == "yes" { // handle egress stuff
+			peer.EgressGatewayRanges = node.EgressGatewayRanges
+			peer.IsEgressGateway = node.IsEgressGateway
+		}
+		allow := node.IsRelayed != "yes" || !excludeRelayed
+
+		if node.Network == networkName && node.IsPending != "yes" && allow {
+			peer = setPeerInfo(&node)
+			if node.UDPHolePunch == "yes" && errN == nil && CheckEndpoint(udppeers[node.PublicKey]) {
+				endpointstring := udppeers[node.PublicKey]
+				endpointarr := strings.Split(endpointstring, ":")
+				if len(endpointarr) == 2 {
+					port, err := strconv.Atoi(endpointarr[1])
+					if err == nil {
+						// peer.Endpoint = endpointarr[0]
+						peer.ListenPort = int32(port)
+					}
+				}
+			}
+			if node.IsRelay == "yes" {
+				network, err := GetNetwork(networkName)
+				if err == nil {
+					peer.AllowedIPs = append(peer.AllowedIPs, network.AddressRange)
+				} else {
+					peer.AllowedIPs = append(peer.AllowedIPs, node.RelayAddrs...)
+				}
+				for _, egressNode := range egressNetworkNodes {
+					if egressNode.IsRelayed == "yes" && StringSliceContains(node.RelayAddrs, egressNode.Address) {
+						peer.AllowedIPs = append(peer.AllowedIPs, egressNode.EgressGatewayRanges...)
+					}
+				}
+			}
+			if !isP2S || peer.IsHub == "yes" {
+				peers = append(peers, peer)
+			}
+		}
+	}
+
+	return peers, err
+}
+
+// GetPeersList - gets the peers of a given network
+func GetPeersList(refnode *models.Node) ([]models.Node, error) {
+	var peers []models.Node
+	var err error
+	var isP2S bool
+	var networkName = refnode.Network
+	var excludeRelayed = refnode.IsRelay != "yes"
+	var relayedNodeAddr string
+	if refnode.IsRelayed == "yes" {
+		relayedNodeAddr = refnode.Address
+	}
+
+	network, err := GetNetwork(networkName)
+	if err != nil {
+		return peers, err
+	} else if network.IsPointToSite == "yes" && refnode.IsHub != "yes" {
+		isP2S = true
+	}
+	if relayedNodeAddr == "" {
+		peers, err = GetNodePeers(networkName, excludeRelayed, isP2S)
+	} else {
+		var relayNode models.Node
+		relayNode, err = GetNodeRelay(networkName, relayedNodeAddr)
+		if relayNode.Address != "" {
+			var peerNode = setPeerInfo(&relayNode)
+			network, err := GetNetwork(networkName)
+			if err == nil {
+				peerNode.AllowedIPs = append(peerNode.AllowedIPs, network.AddressRange)
+				var _, egressNetworkNodes, err = getNetworkEgressAndNodes(networkName)
+				if err == nil {
+					for _, egress := range egressNetworkNodes {
+						if egress.Address != relayedNodeAddr {
+							peerNode.AllowedIPs = append(peerNode.AllowedIPs, egress.EgressGatewayRanges...)
+						}
+					}
+				}
+			} else {
+				peerNode.AllowedIPs = append(peerNode.AllowedIPs, peerNode.RelayAddrs...)
+			}
+			nodepeers, err := GetNodePeers(networkName, false, isP2S)
+			if err == nil && peerNode.UDPHolePunch == "yes" {
+				for _, nodepeer := range nodepeers {
+					if nodepeer.Address == peerNode.Address {
+						// peerNode.Endpoint = nodepeer.Endpoint
+						peerNode.ListenPort = nodepeer.ListenPort
+					}
+				}
+			}
+			if !isP2S || peerNode.IsHub == "yes" {
+				peers = append(peers, peerNode)
+			}
+		}
+	}
+	return peers, err
+}
+
 // GetPeerUpdate - gets a wireguard peer config for each peer of a node
 // GetPeerUpdate - gets a wireguard peer config for each peer of a node
 func GetPeerUpdate(node *models.Node) (models.PeerUpdate, error) {
 func GetPeerUpdate(node *models.Node) (models.PeerUpdate, error) {
 	var peerUpdate models.PeerUpdate
 	var peerUpdate models.PeerUpdate

+ 7 - 9
logic/relay.go

@@ -30,7 +30,6 @@ func CreateRelay(relay models.RelayRequest) ([]models.Node, models.Node, error)
 	node.RelayAddrs = relay.RelayAddrs
 	node.RelayAddrs = relay.RelayAddrs
 
 
 	node.SetLastModified()
 	node.SetLastModified()
-	node.PullChanges = "yes"
 	nodeData, err := json.Marshal(&node)
 	nodeData, err := json.Marshal(&node)
 	if err != nil {
 	if err != nil {
 		return returnnodes, node, err
 		return returnnodes, node, err
@@ -90,14 +89,14 @@ func SetRelayedNodes(yesOrno string, networkName string, addrs []string) ([]mode
 }
 }
 
 
 // SetNodeIsRelayed - Sets IsRelayed to on or off for relay
 // SetNodeIsRelayed - Sets IsRelayed to on or off for relay
-func SetNodeIsRelayed(yesOrno string, id string) error {
+func SetNodeIsRelayed(yesOrno string, id string) (models.Node, error) {
 	node, err := GetNodeByID(id)
 	node, err := GetNodeByID(id)
 	if err != nil {
 	if err != nil {
-		return err
+		return node, err
 	}
 	}
 	network, err := GetNetworkByNode(&node)
 	network, err := GetNetworkByNode(&node)
 	if err != nil {
 	if err != nil {
-		return err
+		return node, err
 	}
 	}
 	node.IsRelayed = yesOrno
 	node.IsRelayed = yesOrno
 	if yesOrno == "yes" {
 	if yesOrno == "yes" {
@@ -107,18 +106,18 @@ func SetNodeIsRelayed(yesOrno string, id string) error {
 	}
 	}
 	data, err := json.Marshal(&node)
 	data, err := json.Marshal(&node)
 	if err != nil {
 	if err != nil {
-		return err
+		return node, err
 	}
 	}
-	return database.Insert(node.ID, string(data), database.NODES_TABLE_NAME)
+	return node, database.Insert(node.ID, string(data), database.NODES_TABLE_NAME)
 }
 }
 
 
 // PeerListUnRelay - call this function if a relayed node fails to get its relay: unrelays node and gets new peer list
 // PeerListUnRelay - call this function if a relayed node fails to get its relay: unrelays node and gets new peer list
 func PeerListUnRelay(id string, network string) ([]models.Node, error) {
 func PeerListUnRelay(id string, network string) ([]models.Node, error) {
-	err := SetNodeIsRelayed("no", id)
+	node, err := SetNodeIsRelayed("no", id)
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
-	return GetPeersList(network, true, "")
+	return GetPeersList(&node)
 }
 }
 
 
 // ValidateRelay - checks if relay is valid
 // ValidateRelay - checks if relay is valid
@@ -162,7 +161,6 @@ func DeleteRelay(network, nodeid string) ([]models.Node, models.Node, error) {
 	node.IsRelay = "no"
 	node.IsRelay = "no"
 	node.RelayAddrs = []string{}
 	node.RelayAddrs = []string{}
 	node.SetLastModified()
 	node.SetLastModified()
-	node.PullChanges = "yes"
 
 
 	data, err := json.Marshal(&node)
 	data, err := json.Marshal(&node)
 	if err != nil {
 	if err != nil {

+ 19 - 2
logic/server.go

@@ -39,7 +39,24 @@ func ServerJoin(networkSettings *models.Network) (models.Node, error) {
 	if currentServers != nil {
 	if currentServers != nil {
 		serverCount = len(currentServers) + 1
 		serverCount = len(currentServers) + 1
 	}
 	}
+	var ishub = "no"
 
 
+	if networkSettings.IsPointToSite == "yes" || networkSettings.IsComms == "yes" {
+		nodes, err := GetNetworkNodes(networkSettings.NetID)
+		if err != nil || nodes == nil {
+			ishub = "yes"
+		} else {
+			sethub := true
+			for i := range nodes {
+				if nodes[i].IsHub == "yes" {
+					sethub = false
+				}
+			}
+			if sethub {
+				ishub = "yes"
+			}
+		}
+	}
 	var node = &models.Node{
 	var node = &models.Node{
 		IsServer:     "yes",
 		IsServer:     "yes",
 		DNSOn:        "no",
 		DNSOn:        "no",
@@ -52,6 +69,7 @@ func ServerJoin(networkSettings *models.Network) (models.Node, error) {
 		LocalRange:   networkSettings.LocalRange,
 		LocalRange:   networkSettings.LocalRange,
 		OS:           runtime.GOOS,
 		OS:           runtime.GOOS,
 		Version:      servercfg.Version,
 		Version:      servercfg.Version,
+		IsHub:        ishub,
 	}
 	}
 
 
 	SetNodeDefaults(node)
 	SetNodeDefaults(node)
@@ -389,7 +407,7 @@ func ServerPull(serverNode *models.Node, ifaceDelta bool) error {
 	}
 	}
 	serverNode.OS = runtime.GOOS
 	serverNode.OS = runtime.GOOS
 
 
-	if serverNode.PullChanges == "yes" || ifaceDelta {
+	if ifaceDelta {
 		// check for interface change
 		// check for interface change
 		// checks if address is in use by another interface
 		// checks if address is in use by another interface
 		var oldIfaceName, isIfacePresent = isInterfacePresent(serverNode.Interface, serverNode.Address)
 		var oldIfaceName, isIfacePresent = isInterfacePresent(serverNode.Interface, serverNode.Address)
@@ -399,7 +417,6 @@ func ServerPull(serverNode *models.Node, ifaceDelta bool) error {
 			}
 			}
 			logger.Log(1, "removed old interface", oldIfaceName)
 			logger.Log(1, "removed old interface", oldIfaceName)
 		}
 		}
-		serverNode.PullChanges = "no"
 		if err = setWGConfig(serverNode, false); err != nil {
 		if err = setWGConfig(serverNode, false); err != nil {
 			return err
 			return err
 		}
 		}

+ 29 - 0
logic/serverconf.go

@@ -72,3 +72,32 @@ func StoreJWTSecret(privateKey string) error {
 	}
 	}
 	return database.Insert("nm-jwt-secret", string(data), database.SERVERCONF_TABLE_NAME)
 	return database.Insert("nm-jwt-secret", string(data), database.SERVERCONF_TABLE_NAME)
 }
 }
+
+// FetchCommsNetID - fetches comms netid from db
+func FetchCommsNetID() (string, error) {
+	var dbData string
+	var err error
+	var fetchedData = serverData{}
+	dbData, err = database.FetchRecord(database.SERVERCONF_TABLE_NAME, "nm-comms-id")
+	if err != nil {
+		return "", err
+	}
+	err = json.Unmarshal([]byte(dbData), &fetchedData)
+	if err != nil {
+		return "", err
+	}
+	return fetchedData.PrivateKey, nil
+}
+
+// StoreCommsNetID - stores server comms network netid if needed
+func StoreCommsNetID(netid string) error {
+	var newData = serverData{}
+	var err error
+	var data []byte
+	newData.PrivateKey = netid
+	data, err = json.Marshal(&newData)
+	if err != nil {
+		return err
+	}
+	return database.Insert("nm-comms-id", string(data), database.SERVERCONF_TABLE_NAME)
+}

+ 1 - 96
logic/util.go

@@ -10,7 +10,6 @@ import (
 	"math/rand"
 	"math/rand"
 	"net"
 	"net"
 	"os"
 	"os"
-	"strconv"
 	"strings"
 	"strings"
 	"time"
 	"time"
 
 
@@ -130,101 +129,6 @@ func DeleteNodeByID(node *models.Node, exterminate bool) error {
 	return removeLocalServer(node)
 	return removeLocalServer(node)
 }
 }
 
 
-// GetNodePeers - fetches peers for a given node
-func GetNodePeers(networkName string, excludeRelayed bool) ([]models.Node, error) {
-	var peers []models.Node
-	var networkNodes, egressNetworkNodes, err = getNetworkEgressAndNodes(networkName)
-	if err != nil {
-		return peers, nil
-	}
-
-	udppeers, errN := database.GetPeers(networkName)
-	if errN != nil {
-		logger.Log(2, errN.Error())
-	}
-
-	for _, node := range networkNodes {
-		var peer = models.Node{}
-		if node.IsEgressGateway == "yes" { // handle egress stuff
-			peer.EgressGatewayRanges = node.EgressGatewayRanges
-			peer.IsEgressGateway = node.IsEgressGateway
-		}
-		allow := node.IsRelayed != "yes" || !excludeRelayed
-
-		if node.Network == networkName && node.IsPending != "yes" && allow {
-			peer = setPeerInfo(&node)
-			if node.UDPHolePunch == "yes" && errN == nil && CheckEndpoint(udppeers[node.PublicKey]) {
-				endpointstring := udppeers[node.PublicKey]
-				endpointarr := strings.Split(endpointstring, ":")
-				if len(endpointarr) == 2 {
-					port, err := strconv.Atoi(endpointarr[1])
-					if err == nil {
-						// peer.Endpoint = endpointarr[0]
-						peer.ListenPort = int32(port)
-					}
-				}
-			}
-			if node.IsRelay == "yes" {
-				network, err := GetNetwork(networkName)
-				if err == nil {
-					peer.AllowedIPs = append(peer.AllowedIPs, network.AddressRange)
-				} else {
-					peer.AllowedIPs = append(peer.AllowedIPs, node.RelayAddrs...)
-				}
-				for _, egressNode := range egressNetworkNodes {
-					if egressNode.IsRelayed == "yes" && StringSliceContains(node.RelayAddrs, egressNode.Address) {
-						peer.AllowedIPs = append(peer.AllowedIPs, egressNode.EgressGatewayRanges...)
-					}
-				}
-			}
-			peers = append(peers, peer)
-		}
-	}
-
-	return peers, err
-}
-
-// GetPeersList - gets the peers of a given network
-func GetPeersList(networkName string, excludeRelayed bool, relayedNodeAddr string) ([]models.Node, error) {
-	var peers []models.Node
-	var err error
-	if relayedNodeAddr == "" {
-		peers, err = GetNodePeers(networkName, excludeRelayed)
-	} else {
-		var relayNode models.Node
-		relayNode, err = GetNodeRelay(networkName, relayedNodeAddr)
-		if relayNode.Address != "" {
-			var peerNode = setPeerInfo(&relayNode)
-			network, err := GetNetwork(networkName)
-			if err == nil {
-				peerNode.AllowedIPs = append(peerNode.AllowedIPs, network.AddressRange)
-				var _, egressNetworkNodes, err = getNetworkEgressAndNodes(networkName)
-				if err == nil {
-					for _, egress := range egressNetworkNodes {
-						if egress.Address != relayedNodeAddr {
-							peerNode.AllowedIPs = append(peerNode.AllowedIPs, egress.EgressGatewayRanges...)
-						}
-					}
-				}
-			} else {
-				peerNode.AllowedIPs = append(peerNode.AllowedIPs, peerNode.RelayAddrs...)
-			}
-			nodepeers, err := GetNodePeers(networkName, false)
-			if err == nil && peerNode.UDPHolePunch == "yes" {
-				for _, nodepeer := range nodepeers {
-					if nodepeer.Address == peerNode.Address {
-						// peerNode.Endpoint = nodepeer.Endpoint
-						peerNode.ListenPort = nodepeer.ListenPort
-					}
-				}
-			}
-
-			peers = append(peers, peerNode)
-		}
-	}
-	return peers, err
-}
-
 // RandomString - returns a random string in a charset
 // RandomString - returns a random string in a charset
 func RandomString(length int) string {
 func RandomString(length int) string {
 	const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
 	const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
@@ -283,6 +187,7 @@ func setPeerInfo(node *models.Node) models.Node {
 	peer.UDPHolePunch = node.UDPHolePunch
 	peer.UDPHolePunch = node.UDPHolePunch
 	peer.Address = node.Address
 	peer.Address = node.Address
 	peer.Address6 = node.Address6
 	peer.Address6 = node.Address6
+	peer.IsHub = node.IsHub
 	peer.EgressGatewayRanges = node.EgressGatewayRanges
 	peer.EgressGatewayRanges = node.EgressGatewayRanges
 	peer.IsEgressGateway = node.IsEgressGateway
 	peer.IsEgressGateway = node.IsEgressGateway
 	peer.IngressGatewayRange = node.IngressGatewayRange
 	peer.IngressGatewayRange = node.IngressGatewayRange

+ 57 - 0
logic/wireguard.go

@@ -46,6 +46,63 @@ func HasPeerConnected(node *models.Node) bool {
 	return false
 	return false
 }
 }
 
 
+// IfaceDelta - checks if the new node causes an interface change
+func IfaceDelta(currentNode *models.Node, newNode *models.Node) bool {
+	// single comparison statements
+	if newNode.Endpoint != currentNode.Endpoint ||
+		newNode.LocalAddress != currentNode.LocalAddress ||
+		newNode.PublicKey != currentNode.PublicKey ||
+		newNode.Address != currentNode.Address ||
+		newNode.IsEgressGateway != currentNode.IsEgressGateway ||
+		newNode.IsIngressGateway != currentNode.IsIngressGateway ||
+		newNode.IsRelay != currentNode.IsRelay ||
+		newNode.UDPHolePunch != currentNode.UDPHolePunch ||
+		newNode.IsPending != currentNode.IsPending ||
+		newNode.ListenPort != currentNode.ListenPort ||
+		newNode.MTU != currentNode.MTU ||
+		newNode.PersistentKeepalive != currentNode.PersistentKeepalive ||
+		newNode.DNSOn != currentNode.DNSOn ||
+		len(newNode.AllowedIPs) != len(currentNode.AllowedIPs) {
+		return true
+	}
+
+	// multi-comparison statements
+	if newNode.IsDualStack == "yes" {
+		if newNode.Address6 != currentNode.Address6 {
+			return true
+		}
+	}
+
+	if newNode.IsEgressGateway == "yes" {
+		if len(currentNode.EgressGatewayRanges) != len(newNode.EgressGatewayRanges) {
+			return true
+		}
+		for _, address := range newNode.EgressGatewayRanges {
+			if !StringSliceContains(currentNode.EgressGatewayRanges, address) {
+				return true
+			}
+		}
+	}
+
+	if newNode.IsRelay == "yes" {
+		if len(currentNode.RelayAddrs) != len(newNode.RelayAddrs) {
+			return true
+		}
+		for _, address := range newNode.RelayAddrs {
+			if !StringSliceContains(currentNode.RelayAddrs, address) {
+				return true
+			}
+		}
+	}
+
+	for _, address := range newNode.AllowedIPs {
+		if !StringSliceContains(currentNode.AllowedIPs, address) {
+			return true
+		}
+	}
+	return false
+}
+
 // == Private Functions ==
 // == Private Functions ==
 
 
 // gets the server peers locally
 // gets the server peers locally

BIN
main


+ 9 - 1
main.go

@@ -40,6 +40,11 @@ func main() {
 
 
 func initialize() { // Client Mode Prereq Check
 func initialize() { // Client Mode Prereq Check
 	var err error
 	var err error
+
+	if servercfg.GetMasterKey() == "" {
+		logger.Log(0, "warning: MASTER_KEY not set, this could make account recovery difficult")
+	}
+
 	if servercfg.GetNodeID() == "" {
 	if servercfg.GetNodeID() == "" {
 		logger.FatalLog("error: must set NODE_ID, currently blank")
 		logger.FatalLog("error: must set NODE_ID, currently blank")
 	}
 	}
@@ -76,6 +81,9 @@ func initialize() { // Client Mode Prereq Check
 		if err := serverctl.InitServerNetclient(); err != nil {
 		if err := serverctl.InitServerNetclient(); err != nil {
 			logger.FatalLog("Did not find netclient to use CLIENT_MODE")
 			logger.FatalLog("Did not find netclient to use CLIENT_MODE")
 		}
 		}
+		if err := serverctl.InitializeCommsNetwork(); err != nil {
+			logger.FatalLog("could not inintialize comms network")
+		}
 	}
 	}
 	// initialize iptables to ensure gateways work correctly and mq is forwarded if containerized
 	// initialize iptables to ensure gateways work correctly and mq is forwarded if containerized
 	if servercfg.ManageIPTables() != "off" {
 	if servercfg.ManageIPTables() != "off" {
@@ -187,7 +195,7 @@ func runGRPC(wg *sync.WaitGroup) {
 // Should we be using a context vice a waitgroup????????????
 // Should we be using a context vice a waitgroup????????????
 func runMessageQueue(wg *sync.WaitGroup) {
 func runMessageQueue(wg *sync.WaitGroup) {
 	defer wg.Done()
 	defer wg.Done()
-	logger.Log(0, fmt.Sprintf("connecting to mq broker at %s", servercfg.GetMessageQueueEndpoint()))
+	logger.Log(0, "connecting to mq broker at", servercfg.GetMessageQueueEndpoint())
 	var client = mq.SetupMQTT(false) // Set up the subscription listener
 	var client = mq.SetupMQTT(false) // Set up the subscription listener
 	ctx, cancel := context.WithCancel(context.Background())
 	ctx, cancel := context.WithCancel(context.Background())
 	go mq.Keepalive(ctx)
 	go mq.Keepalive(ctx)

+ 3 - 18
models/accessToken.go

@@ -3,7 +3,6 @@ package models
 type AccessToken struct {
 type AccessToken struct {
 	ServerConfig
 	ServerConfig
 	ClientConfig
 	ClientConfig
-	WG
 }
 }
 
 
 type ClientConfig struct {
 type ClientConfig struct {
@@ -13,21 +12,7 @@ type ClientConfig struct {
 }
 }
 
 
 type ServerConfig struct {
 type ServerConfig struct {
-	CoreDNSAddr     string `json:"corednsaddr"`
-	APIConnString   string `json:"apiconn"`
-	APIHost         string `json:"apihost"`
-	APIPort         string `json:"apiport"`
-	GRPCConnString  string `json:"grpcconn"`
-	GRPCHost        string `json:"grpchost"`
-	GRPCPort        string `json:"grpcport"`
-	GRPCSSL         string `json:"grpcssl"`
-	CheckinInterval string `json:"checkininterval"`
-}
-
-type WG struct {
-	GRPCWireGuard  string `json:"grpcwg"`
-	GRPCWGAddress  string `json:"grpcwgaddr"`
-	GRPCWGPort     string `json:"grpcwgport"`
-	GRPCWGPubKey   string `json:"grpcwgpubkey"`
-	GRPCWGEndpoint string `json:"grpcwgendpoint"`
+	GRPCConnString string `json:"grpcconn"`
+	GRPCSSL        string `json:"grpcssl"`
+	CommsNetwork   string `json:"commsnetwork"`
 }
 }

+ 12 - 43
models/network.go

@@ -1,10 +1,7 @@
 package models
 package models
 
 
 import (
 import (
-	"strings"
 	"time"
 	"time"
-
-	"github.com/gravitl/netmaker/servercfg"
 )
 )
 
 
 // Network Struct - contains info for a given unique network
 // Network Struct - contains info for a given unique network
@@ -12,7 +9,6 @@ import (
 type Network struct {
 type Network struct {
 	AddressRange        string      `json:"addressrange" bson:"addressrange" validate:"required,cidr"`
 	AddressRange        string      `json:"addressrange" bson:"addressrange" validate:"required,cidr"`
 	AddressRange6       string      `json:"addressrange6" bson:"addressrange6" validate:"regexp=^s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:)))(%.+)?s*(\/([0-9]|[1-9][0-9]|1[0-1][0-9]|12[0-8]))?$"`
 	AddressRange6       string      `json:"addressrange6" bson:"addressrange6" validate:"regexp=^s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:)))(%.+)?s*(\/([0-9]|[1-9][0-9]|1[0-1][0-9]|12[0-8]))?$"`
-	DisplayName         string      `json:"displayname,omitempty" bson:"displayname,omitempty" validate:"omitempty,min=1,max=20,displayname_valid"`
 	NetID               string      `json:"netid" bson:"netid" validate:"required,min=1,max=12,netid_valid"`
 	NetID               string      `json:"netid" bson:"netid" validate:"required,min=1,max=12,netid_valid"`
 	NodesLastModified   int64       `json:"nodeslastmodified" bson:"nodeslastmodified"`
 	NodesLastModified   int64       `json:"nodeslastmodified" bson:"nodeslastmodified"`
 	NetworkLastModified int64       `json:"networklastmodified" bson:"networklastmodified"`
 	NetworkLastModified int64       `json:"networklastmodified" bson:"networklastmodified"`
@@ -21,24 +17,21 @@ type Network struct {
 	NodeLimit           int32       `json:"nodelimit" bson:"nodelimit"`
 	NodeLimit           int32       `json:"nodelimit" bson:"nodelimit"`
 	DefaultPostUp       string      `json:"defaultpostup" bson:"defaultpostup"`
 	DefaultPostUp       string      `json:"defaultpostup" bson:"defaultpostup"`
 	DefaultPostDown     string      `json:"defaultpostdown" bson:"defaultpostdown"`
 	DefaultPostDown     string      `json:"defaultpostdown" bson:"defaultpostdown"`
-	KeyUpdateTimeStamp  int64       `json:"keyupdatetimestamp" bson:"keyupdatetimestamp"`
 	DefaultKeepalive    int32       `json:"defaultkeepalive" bson:"defaultkeepalive" validate:"omitempty,max=1000"`
 	DefaultKeepalive    int32       `json:"defaultkeepalive" bson:"defaultkeepalive" validate:"omitempty,max=1000"`
-	DefaultSaveConfig   string      `json:"defaultsaveconfig" bson:"defaultsaveconfig" validate:"checkyesorno"`
 	AccessKeys          []AccessKey `json:"accesskeys" bson:"accesskeys"`
 	AccessKeys          []AccessKey `json:"accesskeys" bson:"accesskeys"`
 	AllowManualSignUp   string      `json:"allowmanualsignup" bson:"allowmanualsignup" validate:"checkyesorno"`
 	AllowManualSignUp   string      `json:"allowmanualsignup" bson:"allowmanualsignup" validate:"checkyesorno"`
 	IsLocal             string      `json:"islocal" bson:"islocal" validate:"checkyesorno"`
 	IsLocal             string      `json:"islocal" bson:"islocal" validate:"checkyesorno"`
 	IsDualStack         string      `json:"isdualstack" bson:"isdualstack" validate:"checkyesorno"`
 	IsDualStack         string      `json:"isdualstack" bson:"isdualstack" validate:"checkyesorno"`
 	IsIPv4              string      `json:"isipv4" bson:"isipv4" validate:"checkyesorno"`
 	IsIPv4              string      `json:"isipv4" bson:"isipv4" validate:"checkyesorno"`
 	IsIPv6              string      `json:"isipv6" bson:"isipv6" validate:"checkyesorno"`
 	IsIPv6              string      `json:"isipv6" bson:"isipv6" validate:"checkyesorno"`
-	IsGRPCHub           string      `json:"isgrpchub" bson:"isgrpchub" validate:"checkyesorno"`
+	IsPointToSite       string      `json:"ispointtosite" bson:"ispointtosite" validate:"checkyesorno"`
+	IsComms             string      `json:"iscomms" bson:"iscomms" validate:"checkyesorno"`
 	LocalRange          string      `json:"localrange" bson:"localrange" validate:"omitempty,cidr"`
 	LocalRange          string      `json:"localrange" bson:"localrange" validate:"omitempty,cidr"`
-
-	// checkin interval is depreciated at the network level. Set on server with CHECKIN_INTERVAL
-	DefaultCheckInInterval int32        `json:"checkininterval,omitempty" bson:"checkininterval,omitempty" validate:"omitempty,numeric,min=2,max=100000"`
-	DefaultUDPHolePunch    string       `json:"defaultudpholepunch" bson:"defaultudpholepunch" validate:"checkyesorno"`
-	DefaultExtClientDNS    string       `json:"defaultextclientdns" bson:"defaultextclientdns"`
-	DefaultMTU             int32        `json:"defaultmtu" bson:"defaultmtu"`
-	DefaultServerAddrs     []ServerAddr `json:"defaultserveraddrs" bson:"defaultserveraddrs" yaml:"defaultserveraddrs"`
+	DefaultUDPHolePunch string      `json:"defaultudpholepunch" bson:"defaultudpholepunch" validate:"checkyesorno"`
+	DefaultExtClientDNS string      `json:"defaultextclientdns" bson:"defaultextclientdns"`
+	DefaultMTU          int32       `json:"defaultmtu" bson:"defaultmtu"`
+	// consider removing - may be depreciated
+	DefaultServerAddrs []ServerAddr `json:"defaultserveraddrs" bson:"defaultserveraddrs" yaml:"defaultserveraddrs"`
 }
 }
 
 
 // SaveData - sensitive fields of a network that should be kept the same
 // SaveData - sensitive fields of a network that should be kept the same
@@ -46,19 +39,6 @@ type SaveData struct { // put sensitive fields here
 	NetID string `json:"netid" bson:"netid" validate:"required,min=1,max=12,netid_valid"`
 	NetID string `json:"netid" bson:"netid" validate:"required,min=1,max=12,netid_valid"`
 }
 }
 
 
-// Network.DisplayNameInNetworkCharSet - checks if displayname uses valid characters
-func (network *Network) DisplayNameInNetworkCharSet() bool {
-
-	charset := "abcdefghijklmnopqrstuvwxyz1234567890-_./;% ^#()!@$*"
-
-	for _, char := range network.DisplayName {
-		if !strings.Contains(charset, strings.ToLower(string(char))) {
-			return false
-		}
-	}
-	return true
-}
-
 // Network.SetNodesLastModified - sets nodes last modified on network, depricated
 // Network.SetNodesLastModified - sets nodes last modified on network, depricated
 func (network *Network) SetNodesLastModified() {
 func (network *Network) SetNodesLastModified() {
 	network.NodesLastModified = time.Now().Unix()
 	network.NodesLastModified = time.Now().Unix()
@@ -72,20 +52,16 @@ func (network *Network) SetNetworkLastModified() {
 // Network.SetDefaults - sets default values for a network struct
 // Network.SetDefaults - sets default values for a network struct
 func (network *Network) SetDefaults() {
 func (network *Network) SetDefaults() {
 	if network.DefaultUDPHolePunch == "" {
 	if network.DefaultUDPHolePunch == "" {
-		if servercfg.IsClientMode() != "off" {
-			network.DefaultUDPHolePunch = "yes"
-		} else {
-			network.DefaultUDPHolePunch = "no"
-		}
+		network.DefaultUDPHolePunch = "no"
 	}
 	}
 	if network.IsLocal == "" {
 	if network.IsLocal == "" {
 		network.IsLocal = "no"
 		network.IsLocal = "no"
 	}
 	}
-	if network.IsGRPCHub == "" {
-		network.IsGRPCHub = "no"
+	if network.IsPointToSite == "" {
+		network.IsPointToSite = "no"
 	}
 	}
-	if network.DisplayName == "" {
-		network.DisplayName = network.NetID
+	if network.IsComms == "" {
+		network.IsComms = "no"
 	}
 	}
 	if network.DefaultInterface == "" {
 	if network.DefaultInterface == "" {
 		if len(network.NetID) < 13 {
 		if len(network.NetID) < 13 {
@@ -100,16 +76,9 @@ func (network *Network) SetDefaults() {
 	if network.NodeLimit == 0 {
 	if network.NodeLimit == 0 {
 		network.NodeLimit = 999999999
 		network.NodeLimit = 999999999
 	}
 	}
-	if network.DefaultSaveConfig == "" {
-		network.DefaultSaveConfig = "no"
-	}
 	if network.DefaultKeepalive == 0 {
 	if network.DefaultKeepalive == 0 {
 		network.DefaultKeepalive = 20
 		network.DefaultKeepalive = 20
 	}
 	}
-	//Check-In Interval for Nodes, In Seconds
-	if network.DefaultCheckInInterval == 0 {
-		network.DefaultCheckInInterval = 30
-	}
 	if network.AllowManualSignUp == "" {
 	if network.AllowManualSignUp == "" {
 		network.AllowManualSignUp = "no"
 		network.AllowManualSignUp = "no"
 	}
 	}

+ 61 - 81
models/node.go

@@ -10,15 +10,23 @@ import (
 	"golang.org/x/crypto/bcrypt"
 	"golang.org/x/crypto/bcrypt"
 )
 )
 
 
-const TEN_YEARS_IN_SECONDS = 300000000
-const MAX_NAME_LENGTH = 62
-
-// == ACTIONS == (can only be set by GRPC)
-const NODE_UPDATE_KEY = "updatekey"
-const NODE_SERVER_NAME = "netmaker"
-const NODE_DELETE = "delete"
-const NODE_IS_PENDING = "pending"
-const NODE_NOOP = "noop"
+const (
+	// NODE_SERVER_NAME - the default server name
+	NODE_SERVER_NAME = "netmaker"
+	// TEN_YEARS_IN_SECONDS - ten years in seconds
+	TEN_YEARS_IN_SECONDS = 300000000
+	// MAX_NAME_LENGTH - max name length of node
+	MAX_NAME_LENGTH = 62
+	// == ACTIONS == (can only be set by GRPC)
+	// NODE_UPDATE_KEY - action to update key
+	NODE_UPDATE_KEY = "updatekey"
+	// NODE_DELETE - delete node action
+	NODE_DELETE = "delete"
+	// NODE_IS_PENDING - node pending status
+	NODE_IS_PENDING = "pending"
+	// NODE_NOOP - node no op action
+	NODE_NOOP = "noop"
+)
 
 
 var seededRand *rand.Rand = rand.New(
 var seededRand *rand.Rand = rand.New(
 	rand.NewSource(time.Now().UnixNano()))
 	rand.NewSource(time.Now().UnixNano()))
@@ -38,45 +46,41 @@ type Node struct {
 	PostDown            string   `json:"postdown" bson:"postdown" yaml:"postdown"`
 	PostDown            string   `json:"postdown" bson:"postdown" yaml:"postdown"`
 	AllowedIPs          []string `json:"allowedips" bson:"allowedips" yaml:"allowedips"`
 	AllowedIPs          []string `json:"allowedips" bson:"allowedips" yaml:"allowedips"`
 	PersistentKeepalive int32    `json:"persistentkeepalive" bson:"persistentkeepalive" yaml:"persistentkeepalive" validate:"omitempty,numeric,max=1000"`
 	PersistentKeepalive int32    `json:"persistentkeepalive" bson:"persistentkeepalive" yaml:"persistentkeepalive" validate:"omitempty,numeric,max=1000"`
-	SaveConfig          string   `json:"saveconfig" bson:"saveconfig" yaml:"saveconfig" validate:"checkyesorno"`
+	IsHub               string   `json:"ishub" bson:"ishub" yaml:"ishub" validate:"checkyesorno"`
 	AccessKey           string   `json:"accesskey" bson:"accesskey" yaml:"accesskey"`
 	AccessKey           string   `json:"accesskey" bson:"accesskey" yaml:"accesskey"`
 	Interface           string   `json:"interface" bson:"interface" yaml:"interface"`
 	Interface           string   `json:"interface" bson:"interface" yaml:"interface"`
 	LastModified        int64    `json:"lastmodified" bson:"lastmodified" yaml:"lastmodified"`
 	LastModified        int64    `json:"lastmodified" bson:"lastmodified" yaml:"lastmodified"`
-	KeyUpdateTimeStamp  int64    `json:"keyupdatetimestamp" bson:"keyupdatetimestamp" yaml:"keyupdatetimestamp"`
 	ExpirationDateTime  int64    `json:"expdatetime" bson:"expdatetime" yaml:"expdatetime"`
 	ExpirationDateTime  int64    `json:"expdatetime" bson:"expdatetime" yaml:"expdatetime"`
 	LastPeerUpdate      int64    `json:"lastpeerupdate" bson:"lastpeerupdate" yaml:"lastpeerupdate"`
 	LastPeerUpdate      int64    `json:"lastpeerupdate" bson:"lastpeerupdate" yaml:"lastpeerupdate"`
 	LastCheckIn         int64    `json:"lastcheckin" bson:"lastcheckin" yaml:"lastcheckin"`
 	LastCheckIn         int64    `json:"lastcheckin" bson:"lastcheckin" yaml:"lastcheckin"`
 	MacAddress          string   `json:"macaddress" bson:"macaddress" yaml:"macaddress" validate:"macaddress_unique"`
 	MacAddress          string   `json:"macaddress" bson:"macaddress" yaml:"macaddress" validate:"macaddress_unique"`
-	// checkin interval is depreciated at the network level. Set on server with CHECKIN_INTERVAL
-	CheckInInterval     int32       `json:"checkininterval" bson:"checkininterval" yaml:"checkininterval"`
-	Password            string      `json:"password" bson:"password" yaml:"password" validate:"required,min=6"`
-	Network             string      `json:"network" bson:"network" yaml:"network" validate:"network_exists"`
-	IsRelayed           string      `json:"isrelayed" bson:"isrelayed" yaml:"isrelayed"`
-	IsPending           string      `json:"ispending" bson:"ispending" yaml:"ispending"`
-	IsRelay             string      `json:"isrelay" bson:"isrelay" yaml:"isrelay" validate:"checkyesorno"`
-	IsDocker            string      `json:"isdocker" bson:"isdocker" yaml:"isdocker" validate:"checkyesorno"`
-	IsK8S               string      `json:"isk8s" bson:"isk8s" yaml:"isk8s" validate:"checkyesorno"`
-	IsEgressGateway     string      `json:"isegressgateway" bson:"isegressgateway" yaml:"isegressgateway"`
-	IsIngressGateway    string      `json:"isingressgateway" bson:"isingressgateway" yaml:"isingressgateway"`
-	EgressGatewayRanges []string    `json:"egressgatewayranges" bson:"egressgatewayranges" yaml:"egressgatewayranges"`
-	RelayAddrs          []string    `json:"relayaddrs" bson:"relayaddrs" yaml:"relayaddrs"`
-	IngressGatewayRange string      `json:"ingressgatewayrange" bson:"ingressgatewayrange" yaml:"ingressgatewayrange"`
-	IsStatic            string      `json:"isstatic" bson:"isstatic" yaml:"isstatic" validate:"checkyesorno"`
-	UDPHolePunch        string      `json:"udpholepunch" bson:"udpholepunch" yaml:"udpholepunch" validate:"checkyesorno"`
-	PullChanges         string      `json:"pullchanges" bson:"pullchanges" yaml:"pullchanges" validate:"checkyesorno"`
-	DNSOn               string      `json:"dnson" bson:"dnson" yaml:"dnson" validate:"checkyesorno"`
-	IsDualStack         string      `json:"isdualstack" bson:"isdualstack" yaml:"isdualstack" validate:"checkyesorno"`
-	IsServer            string      `json:"isserver" bson:"isserver" yaml:"isserver" validate:"checkyesorno"`
-	Action              string      `json:"action" bson:"action" yaml:"action"`
-	IsLocal             string      `json:"islocal" bson:"islocal" yaml:"islocal" validate:"checkyesorno"`
-	LocalRange          string      `json:"localrange" bson:"localrange" yaml:"localrange"`
-	Roaming             string      `json:"roaming" bson:"roaming" yaml:"roaming" validate:"checkyesorno"`
-	IPForwarding        string      `json:"ipforwarding" bson:"ipforwarding" yaml:"ipforwarding" validate:"checkyesorno"`
-	OS                  string      `json:"os" bson:"os" yaml:"os"`
-	MTU                 int32       `json:"mtu" bson:"mtu" yaml:"mtu"`
-	Version             string      `json:"version" bson:"version" yaml:"version"`
-	ExcludedAddrs       []string    `json:"excludedaddrs" bson:"excludedaddrs" yaml:"excludedaddrs"`
-	TrafficKeys         TrafficKeys `json:"traffickeys" bson:"traffickeys" yaml:"traffickeys"`
+	Password            string   `json:"password" bson:"password" yaml:"password" validate:"required,min=6"`
+	Network             string   `json:"network" bson:"network" yaml:"network" validate:"network_exists"`
+	IsRelayed           string   `json:"isrelayed" bson:"isrelayed" yaml:"isrelayed"`
+	IsPending           string   `json:"ispending" bson:"ispending" yaml:"ispending"`
+	IsRelay             string   `json:"isrelay" bson:"isrelay" yaml:"isrelay" validate:"checkyesorno"`
+	IsDocker            string   `json:"isdocker" bson:"isdocker" yaml:"isdocker" validate:"checkyesorno"`
+	IsK8S               string   `json:"isk8s" bson:"isk8s" yaml:"isk8s" validate:"checkyesorno"`
+	IsEgressGateway     string   `json:"isegressgateway" bson:"isegressgateway" yaml:"isegressgateway"`
+	IsIngressGateway    string   `json:"isingressgateway" bson:"isingressgateway" yaml:"isingressgateway"`
+	EgressGatewayRanges []string `json:"egressgatewayranges" bson:"egressgatewayranges" yaml:"egressgatewayranges"`
+	RelayAddrs          []string `json:"relayaddrs" bson:"relayaddrs" yaml:"relayaddrs"`
+	IngressGatewayRange string   `json:"ingressgatewayrange" bson:"ingressgatewayrange" yaml:"ingressgatewayrange"`
+	IsStatic            string   `json:"isstatic" bson:"isstatic" yaml:"isstatic" validate:"checkyesorno"`
+	UDPHolePunch        string   `json:"udpholepunch" bson:"udpholepunch" yaml:"udpholepunch" validate:"checkyesorno"`
+	//PullChanges         string      `json:"pullchanges" bson:"pullchanges" yaml:"pullchanges" validate:"checkyesorno"`
+	DNSOn        string      `json:"dnson" bson:"dnson" yaml:"dnson" validate:"checkyesorno"`
+	IsDualStack  string      `json:"isdualstack" bson:"isdualstack" yaml:"isdualstack" validate:"checkyesorno"`
+	IsServer     string      `json:"isserver" bson:"isserver" yaml:"isserver" validate:"checkyesorno"`
+	Action       string      `json:"action" bson:"action" yaml:"action"`
+	IsLocal      string      `json:"islocal" bson:"islocal" yaml:"islocal" validate:"checkyesorno"`
+	LocalRange   string      `json:"localrange" bson:"localrange" yaml:"localrange"`
+	IPForwarding string      `json:"ipforwarding" bson:"ipforwarding" yaml:"ipforwarding" validate:"checkyesorno"`
+	OS           string      `json:"os" bson:"os" yaml:"os"`
+	MTU          int32       `json:"mtu" bson:"mtu" yaml:"mtu"`
+	Version      string      `json:"version" bson:"version" yaml:"version"`
+	CommID       string      `json:"commid" bson:"commid" yaml:"comid"`
+	TrafficKeys  TrafficKeys `json:"traffickeys" bson:"traffickeys" yaml:"traffickeys"`
 }
 }
 
 
 // NodesArray - used for node sorting
 // NodesArray - used for node sorting
@@ -118,6 +122,13 @@ func (node *Node) SetDefaultIsRelayed() {
 	}
 	}
 }
 }
 
 
+// Node.SetDefaultIsRelayed - set default is relayed
+func (node *Node) SetDefaultIsHub() {
+	if node.IsHub == "" {
+		node.IsHub = "no"
+	}
+}
+
 // Node.SetDefaultIsRelay - set default isrelay
 // Node.SetDefaultIsRelay - set default isrelay
 func (node *Node) SetDefaultIsRelay() {
 func (node *Node) SetDefaultIsRelay() {
 	if node.IsRelay == "" {
 	if node.IsRelay == "" {
@@ -161,18 +172,11 @@ func (node *Node) SetDefaultAction() {
 }
 }
 
 
 // Node.SetRoamingDefault - sets default roaming status
 // Node.SetRoamingDefault - sets default roaming status
-func (node *Node) SetRoamingDefault() {
-	if node.Roaming == "" {
-		node.Roaming = "yes"
-	}
-}
-
-// Node.SetPullChangesDefault - sets default pull changes status
-func (node *Node) SetPullChangesDefault() {
-	if node.PullChanges == "" {
-		node.PullChanges = "no"
-	}
-}
+//func (node *Node) SetRoamingDefault() {
+//	if node.Roaming == "" {
+//		node.Roaming = "yes"
+//	}
+//}
 
 
 // Node.SetIPForwardingDefault - set ip forwarding default
 // Node.SetIPForwardingDefault - set ip forwarding default
 func (node *Node) SetIPForwardingDefault() {
 func (node *Node) SetIPForwardingDefault() {
@@ -245,13 +249,6 @@ func (node *Node) SetDefaultName() {
 	}
 	}
 }
 }
 
 
-// Node.SetDefaultExcludedAddrs - sets ExcludedAddrs to empty array if nil
-func (node *Node) SetDefaultExcludedAddrs() {
-	if node.ExcludedAddrs == nil {
-		node.ExcludedAddrs = make([]string, 0)
-	}
-}
-
 // Node.Fill - fills other node data into calling node data if not set on calling node
 // Node.Fill - fills other node data into calling node data if not set on calling node
 func (newNode *Node) Fill(currentNode *Node) {
 func (newNode *Node) Fill(currentNode *Node) {
 	newNode.ID = currentNode.ID
 	newNode.ID = currentNode.ID
@@ -273,8 +270,6 @@ func (newNode *Node) Fill(currentNode *Node) {
 	}
 	}
 	if newNode.PublicKey == "" && newNode.IsStatic != "yes" {
 	if newNode.PublicKey == "" && newNode.IsStatic != "yes" {
 		newNode.PublicKey = currentNode.PublicKey
 		newNode.PublicKey = currentNode.PublicKey
-	} else {
-		newNode.KeyUpdateTimeStamp = time.Now().Unix()
 	}
 	}
 	if newNode.Endpoint == "" && newNode.IsStatic != "yes" {
 	if newNode.Endpoint == "" && newNode.IsStatic != "yes" {
 		newNode.Endpoint = currentNode.Endpoint
 		newNode.Endpoint = currentNode.Endpoint
@@ -291,9 +286,6 @@ func (newNode *Node) Fill(currentNode *Node) {
 	if newNode.PersistentKeepalive == 0 {
 	if newNode.PersistentKeepalive == 0 {
 		newNode.PersistentKeepalive = currentNode.PersistentKeepalive
 		newNode.PersistentKeepalive = currentNode.PersistentKeepalive
 	}
 	}
-	if newNode.SaveConfig == "" {
-		newNode.SaveConfig = currentNode.SaveConfig
-	}
 	if newNode.AccessKey == "" {
 	if newNode.AccessKey == "" {
 		newNode.AccessKey = currentNode.AccessKey
 		newNode.AccessKey = currentNode.AccessKey
 	}
 	}
@@ -303,9 +295,6 @@ func (newNode *Node) Fill(currentNode *Node) {
 	if newNode.LastModified == 0 {
 	if newNode.LastModified == 0 {
 		newNode.LastModified = currentNode.LastModified
 		newNode.LastModified = currentNode.LastModified
 	}
 	}
-	if newNode.KeyUpdateTimeStamp == 0 {
-		newNode.LastModified = currentNode.LastModified
-	}
 	if newNode.ExpirationDateTime == 0 {
 	if newNode.ExpirationDateTime == 0 {
 		newNode.ExpirationDateTime = currentNode.ExpirationDateTime
 		newNode.ExpirationDateTime = currentNode.ExpirationDateTime
 	}
 	}
@@ -318,9 +307,6 @@ func (newNode *Node) Fill(currentNode *Node) {
 	if newNode.MacAddress == "" {
 	if newNode.MacAddress == "" {
 		newNode.MacAddress = currentNode.MacAddress
 		newNode.MacAddress = currentNode.MacAddress
 	}
 	}
-	if newNode.CheckInInterval == 0 {
-		newNode.CheckInInterval = currentNode.CheckInInterval
-	}
 	if newNode.Password != "" {
 	if newNode.Password != "" {
 		err := bcrypt.CompareHashAndPassword([]byte(newNode.Password), []byte(currentNode.Password))
 		err := bcrypt.CompareHashAndPassword([]byte(newNode.Password), []byte(currentNode.Password))
 		if err != nil && currentNode.Password != newNode.Password {
 		if err != nil && currentNode.Password != newNode.Password {
@@ -354,7 +340,7 @@ func (newNode *Node) Fill(currentNode *Node) {
 		newNode.IsStatic = currentNode.IsStatic
 		newNode.IsStatic = currentNode.IsStatic
 	}
 	}
 	if newNode.UDPHolePunch == "" {
 	if newNode.UDPHolePunch == "" {
-		newNode.UDPHolePunch = currentNode.SaveConfig
+		newNode.UDPHolePunch = currentNode.UDPHolePunch
 	}
 	}
 	if newNode.DNSOn == "" {
 	if newNode.DNSOn == "" {
 		newNode.DNSOn = currentNode.DNSOn
 		newNode.DNSOn = currentNode.DNSOn
@@ -368,12 +354,9 @@ func (newNode *Node) Fill(currentNode *Node) {
 	if newNode.IPForwarding == "" {
 	if newNode.IPForwarding == "" {
 		newNode.IPForwarding = currentNode.IPForwarding
 		newNode.IPForwarding = currentNode.IPForwarding
 	}
 	}
-	if newNode.PullChanges == "" {
-		newNode.PullChanges = currentNode.PullChanges
-	}
-	if newNode.Roaming == "" {
-		newNode.Roaming = currentNode.Roaming
-	}
+	//if newNode.Roaming == "" {
+	//newNode.Roaming = currentNode.Roaming
+	//}
 	if newNode.Action == "" {
 	if newNode.Action == "" {
 		newNode.Action = currentNode.Action
 		newNode.Action = currentNode.Action
 	}
 	}
@@ -407,9 +390,6 @@ func (newNode *Node) Fill(currentNode *Node) {
 	if newNode.Version == "" {
 	if newNode.Version == "" {
 		newNode.Version = currentNode.Version
 		newNode.Version = currentNode.Version
 	}
 	}
-	if newNode.ExcludedAddrs == nil || len(newNode.ExcludedAddrs) != len(currentNode.ExcludedAddrs) {
-		newNode.ExcludedAddrs = currentNode.ExcludedAddrs
-	}
 }
 }
 
 
 // StringWithCharset - returns random string inside defined charset
 // StringWithCharset - returns random string inside defined charset

+ 131 - 0
mq/handlers.go

@@ -0,0 +1,131 @@
+package mq
+
+import (
+	"encoding/json"
+
+	mqtt "github.com/eclipse/paho.mqtt.golang"
+	"github.com/gravitl/netmaker/database"
+	"github.com/gravitl/netmaker/logger"
+	"github.com/gravitl/netmaker/logic"
+	"github.com/gravitl/netmaker/models"
+	"github.com/gravitl/netmaker/netclient/ncutils"
+)
+
+// DefaultHandler default message queue handler - only called when GetDebug == true
+func DefaultHandler(client mqtt.Client, msg mqtt.Message) {
+	logger.Log(0, "MQTT Message: Topic: ", string(msg.Topic()), " Message: ", string(msg.Payload()))
+}
+
+// Ping message Handler -- handles ping topic from client nodes
+func Ping(client mqtt.Client, msg mqtt.Message) {
+	go func() {
+		id, err := getID(msg.Topic())
+		if err != nil {
+			logger.Log(0, "error getting node.ID sent on ping topic ")
+			return
+		}
+		node, err := logic.GetNodeByID(id)
+		if err != nil {
+			logger.Log(0, "mq-ping error getting node: ", err.Error())
+			record, err := database.FetchRecord(database.NODES_TABLE_NAME, id)
+			if err != nil {
+				logger.Log(0, "error reading database ", err.Error())
+				return
+			}
+			logger.Log(0, "record from database")
+			logger.Log(0, record)
+			return
+		}
+		_, decryptErr := decryptMsg(&node, msg.Payload())
+		if decryptErr != nil {
+			logger.Log(0, "error decrypting when updating node ", node.ID, decryptErr.Error())
+			return
+		}
+		node.SetLastCheckIn()
+		if err := logic.UpdateNode(&node, &node); err != nil {
+			logger.Log(0, "error updating node", node.Name, node.ID, " on checkin", err.Error())
+			return
+		}
+		logger.Log(3, "ping processed for node", node.ID)
+		// --TODO --set client version once feature is implemented.
+		//node.SetClientVersion(msg.Payload())
+	}()
+}
+
+// UpdateNode  message Handler -- handles updates from client nodes
+func UpdateNode(client mqtt.Client, msg mqtt.Message) {
+	go func() {
+		id, err := getID(msg.Topic())
+		if err != nil {
+			logger.Log(1, "error getting node.ID sent on ", msg.Topic(), err.Error())
+			return
+		}
+		currentNode, err := logic.GetNodeByID(id)
+		if err != nil {
+			logger.Log(1, "error getting node ", id, err.Error())
+			return
+		}
+		decrypted, decryptErr := decryptMsg(&currentNode, msg.Payload())
+		if decryptErr != nil {
+			logger.Log(1, "failed to decrypt message for node ", id, decryptErr.Error())
+			return
+		}
+		var newNode models.Node
+		if err := json.Unmarshal(decrypted, &newNode); err != nil {
+			logger.Log(1, "error unmarshaling payload ", err.Error())
+			return
+		}
+		if err := logic.UpdateNode(&currentNode, &newNode); err != nil {
+			logger.Log(1, "error saving node", err.Error())
+			return
+		}
+		logger.Log(1, "updated node", id, newNode.Name)
+	}()
+}
+
+// ClientPeerUpdate  message handler -- handles updating peers after signal from client nodes
+func ClientPeerUpdate(client mqtt.Client, msg mqtt.Message) {
+	go func() {
+		id, err := getID(msg.Topic())
+		if err != nil {
+			logger.Log(1, "error getting node.ID sent on ", msg.Topic(), err.Error())
+			return
+		}
+		currentNode, err := logic.GetNodeByID(id)
+		if err != nil {
+			logger.Log(1, "error getting node ", id, err.Error())
+			return
+		}
+		decrypted, decryptErr := decryptMsg(&currentNode, msg.Payload())
+		if decryptErr != nil {
+			logger.Log(1, "failed to decrypt message during client peer update for node ", id, decryptErr.Error())
+			return
+		}
+		switch decrypted[0] {
+		case ncutils.ACK:
+			currentServerNode, err := logic.GetNetworkServerLocal(currentNode.Network)
+			if err != nil {
+				return
+			}
+			if err := logic.ServerUpdate(&currentServerNode, false); err != nil {
+				logger.Log(1, "server node:", currentServerNode.ID, "failed update")
+				return
+			}
+		case ncutils.DONE:
+			currentServerNode, err := logic.GetNetworkServerLocal(currentNode.Network)
+			if err != nil {
+				return
+			}
+			if err := logic.ServerUpdate(&currentServerNode, false); err != nil {
+				logger.Log(1, "server node:", currentServerNode.ID, "failed update")
+				return
+			}
+			if err := PublishPeerUpdate(&currentNode); err != nil {
+				logger.Log(1, "error publishing peer update ", err.Error())
+				return
+			}
+		}
+
+		logger.Log(1, "sent peer updates after signal received from", id, currentNode.Name)
+	}()
+}

+ 4 - 222
mq/mq.go

@@ -2,18 +2,11 @@ package mq
 
 
 import (
 import (
 	"context"
 	"context"
-	"encoding/json"
-	"errors"
-	"fmt"
 	"log"
 	"log"
-	"strings"
 	"time"
 	"time"
 
 
 	mqtt "github.com/eclipse/paho.mqtt.golang"
 	mqtt "github.com/eclipse/paho.mqtt.golang"
-	"github.com/gravitl/netmaker/database"
 	"github.com/gravitl/netmaker/logger"
 	"github.com/gravitl/netmaker/logger"
-	"github.com/gravitl/netmaker/logic"
-	"github.com/gravitl/netmaker/models"
 	"github.com/gravitl/netmaker/netclient/ncutils"
 	"github.com/gravitl/netmaker/netclient/ncutils"
 	"github.com/gravitl/netmaker/servercfg"
 	"github.com/gravitl/netmaker/servercfg"
 )
 )
@@ -25,170 +18,6 @@ const MQ_DISCONNECT = 250
 
 
 var peer_force_send = 0
 var peer_force_send = 0
 
 
-// DefaultHandler default message queue handler - only called when GetDebug == true
-func DefaultHandler(client mqtt.Client, msg mqtt.Message) {
-	logger.Log(0, "MQTT Message: Topic: ", string(msg.Topic()), " Message: ", string(msg.Payload()))
-}
-
-// Ping message Handler -- handles ping topic from client nodes
-func Ping(client mqtt.Client, msg mqtt.Message) {
-	logger.Log(0, "Ping Handler: ", msg.Topic())
-	go func() {
-		id, err := GetID(msg.Topic())
-		if err != nil {
-			logger.Log(0, "error getting node.ID sent on ping topic ")
-			return
-		}
-		node, err := logic.GetNodeByID(id)
-		if err != nil {
-			logger.Log(0, "mq-ping error getting node: ", err.Error())
-			record, err := database.FetchRecord(database.NODES_TABLE_NAME, id)
-			if err != nil {
-				logger.Log(0, "error reading database ", err.Error())
-				return
-			}
-			logger.Log(0, "record from database")
-			logger.Log(0, record)
-			return
-		}
-		_, decryptErr := decryptMsg(&node, msg.Payload())
-		if decryptErr != nil {
-			logger.Log(0, "error updating node ", node.ID, err.Error())
-			return
-		}
-		node.SetLastCheckIn()
-		if err := logic.UpdateNode(&node, &node); err != nil {
-			logger.Log(0, "error updating node ", err.Error())
-		}
-		logger.Log(3, "ping processed for node", node.ID)
-		// --TODO --set client version once feature is implemented.
-		//node.SetClientVersion(msg.Payload())
-	}()
-}
-
-// UpdateNode  message Handler -- handles updates from client nodes
-func UpdateNode(client mqtt.Client, msg mqtt.Message) {
-	go func() {
-		id, err := GetID(msg.Topic())
-		if err != nil {
-			logger.Log(1, "error getting node.ID sent on ", msg.Topic(), err.Error())
-			return
-		}
-		currentNode, err := logic.GetNodeByID(id)
-		if err != nil {
-			logger.Log(1, "error getting node ", id, err.Error())
-			return
-		}
-		decrypted, decryptErr := decryptMsg(&currentNode, msg.Payload())
-		if decryptErr != nil {
-			logger.Log(1, "failed to decrypt message for node ", id, decryptErr.Error())
-			return
-		}
-		logger.Log(1, "Update Node Handler", id)
-		var newNode models.Node
-		if err := json.Unmarshal(decrypted, &newNode); err != nil {
-			logger.Log(1, "error unmarshaling payload ", err.Error())
-			return
-		}
-		if err := logic.UpdateNode(&currentNode, &newNode); err != nil {
-			logger.Log(1, "error saving node", err.Error())
-		}
-		if err := PublishPeerUpdate(&newNode); err != nil {
-			logger.Log(1, "error publishing peer update ", err.Error())
-			return
-		}
-		logger.Log(1, "no need to update peers")
-	}()
-}
-
-// PublishPeerUpdate --- deterines and publishes a peer update to all the peers of a node
-func PublishPeerUpdate(newNode *models.Node) error {
-	if !servercfg.IsMessageQueueBackend() {
-		return nil
-	}
-	networkNodes, err := logic.GetNetworkNodes(newNode.Network)
-	if err != nil {
-		logger.Log(1, "err getting Network Nodes", err.Error())
-		return err
-	}
-	for _, node := range networkNodes {
-
-		if node.IsServer == "yes" || node.ID == newNode.ID {
-			continue
-		}
-		peerUpdate, err := logic.GetPeerUpdate(&node)
-		if err != nil {
-			logger.Log(1, "error getting peer update for node", node.ID, err.Error())
-			continue
-		}
-		data, err := json.Marshal(&peerUpdate)
-		if err != nil {
-			logger.Log(2, "error marshaling peer update for node", node.ID, err.Error())
-			continue
-		}
-		if err = publish(&node, fmt.Sprintf("peers/%s/%s", node.Network, node.ID), data); err != nil {
-			logger.Log(1, "failed to publish peer update for node", node.ID)
-		} else {
-			logger.Log(1, fmt.Sprintf("sent peer update for node %s on network: %s ", node.Name, node.Network))
-		}
-	}
-	return nil
-}
-
-// PublishPeerUpdate --- deterines and publishes a peer update to all the peers of a node
-func PublishExtPeerUpdate(node *models.Node) error {
-	var err error
-	if logic.IsLocalServer(node) {
-		if err = logic.ServerUpdate(node, false); err != nil {
-			logger.Log(1, "server node:", node.ID, "failed to update peers with ext clients")
-			return err
-		} else {
-			return nil
-		}
-	}
-	if !servercfg.IsMessageQueueBackend() {
-		return nil
-	}
-	peerUpdate, err := logic.GetPeerUpdate(node)
-	if err != nil {
-		return err
-	}
-	data, err := json.Marshal(&peerUpdate)
-	if err != nil {
-		return err
-	}
-	return publish(node, fmt.Sprintf("peers/%s/%s", node.Network, node.ID), data)
-}
-
-// GetID -- decodes a message queue topic and returns the embedded node.ID
-func GetID(topic string) (string, error) {
-	parts := strings.Split(topic, "/")
-	count := len(parts)
-	if count == 1 {
-		return "", errors.New("invalid topic")
-	}
-	//the last part of the topic will be the node.ID
-	return parts[count-1], nil
-}
-
-// NodeUpdate -- publishes a node update
-func NodeUpdate(node *models.Node) error {
-	if !servercfg.IsMessageQueueBackend() {
-		return nil
-	}
-	logger.Log(3, "publishing node update to "+node.Name)
-	data, err := json.Marshal(node)
-	if err != nil {
-		logger.Log(2, "error marshalling node update ", err.Error())
-		return err
-	}
-	if err = publish(node, fmt.Sprintf("update/%s/%s", node.Network, node.ID), data); err != nil {
-		logger.Log(2, "error publishing node update to peer ", node.ID, err.Error())
-		return err
-	}
-	return nil
-}
-
 // SetupMQTT creates a connection to broker and return client
 // SetupMQTT creates a connection to broker and return client
 func SetupMQTT(publish bool) mqtt.Client {
 func SetupMQTT(publish bool) mqtt.Client {
 	opts := mqtt.NewClientOptions()
 	opts := mqtt.NewClientOptions()
@@ -216,6 +45,10 @@ func SetupMQTT(publish bool) mqtt.Client {
 				client.Disconnect(240)
 				client.Disconnect(240)
 				logger.Log(0, "node update subscription failed")
 				logger.Log(0, "node update subscription failed")
 			}
 			}
+			if token := client.Subscribe("signal/#", 0, mqtt.MessageHandler(ClientPeerUpdate)); token.Wait() && token.Error() != nil {
+				client.Disconnect(240)
+				logger.Log(0, "node client subscription failed")
+			}
 
 
 			opts.SetOrderMatters(true)
 			opts.SetOrderMatters(true)
 			opts.SetResumeSubs(true)
 			opts.SetResumeSubs(true)
@@ -248,54 +81,3 @@ func Keepalive(ctx context.Context) {
 		}
 		}
 	}
 	}
 }
 }
-
-// sendPeers - retrieve networks, send peer ports to all peers
-func sendPeers() {
-	var force bool
-	peer_force_send++
-	if peer_force_send == 5 {
-		force = true
-		peer_force_send = 0
-	}
-	networks, err := logic.GetNetworks()
-	if err != nil {
-		logger.Log(1, "error retrieving networks for keepalive", err.Error())
-	}
-	for _, network := range networks {
-		serverNode, errN := logic.GetNetworkServerLeader(network.NetID)
-		if errN == nil {
-			serverNode.SetLastCheckIn()
-			logic.UpdateNode(&serverNode, &serverNode)
-			if network.DefaultUDPHolePunch == "yes" {
-				if logic.ShouldPublishPeerPorts(&serverNode) || force {
-					if force {
-						logger.Log(2, "sending scheduled peer update (5 min)")
-					}
-					err = PublishPeerUpdate(&serverNode)
-					if err != nil {
-						logger.Log(1, "error publishing udp port updates for network", network.NetID)
-						logger.Log(1, errN.Error())
-					}
-				}
-			}
-		} else {
-			logger.Log(1, "unable to retrieve leader for network ", network.NetID)
-			logger.Log(1, errN.Error())
-			continue
-		}
-	}
-}
-
-// func publishServerKeepalive(client mqtt.Client, network *models.Network) {
-// 	nodes, err := logic.GetNetworkNodes(network.NetID)
-// 	if err != nil {
-// 		return
-// 	}
-// 	for _, node := range nodes {
-// 		if token := client.Publish(fmt.Sprintf("serverkeepalive/%s/%s", network.NetID, node.ID), 0, false, servercfg.GetVersion()); token.Wait() && token.Error() != nil {
-// 			logger.Log(1, "error publishing server keepalive for network", network.NetID, token.Error().Error())
-// 		} else {
-// 			logger.Log(2, "keepalive sent for network/node", network.NetID, node.ID)
-// 		}
-// 	}
-// }

+ 127 - 0
mq/publishers.go

@@ -0,0 +1,127 @@
+package mq
+
+import (
+	"encoding/json"
+	"fmt"
+
+	"github.com/gravitl/netmaker/logger"
+	"github.com/gravitl/netmaker/logic"
+	"github.com/gravitl/netmaker/models"
+	"github.com/gravitl/netmaker/servercfg"
+)
+
+// PublishPeerUpdate --- deterines and publishes a peer update to all the peers of a node
+func PublishPeerUpdate(newNode *models.Node) error {
+	if !servercfg.IsMessageQueueBackend() {
+		return nil
+	}
+	networkNodes, err := logic.GetNetworkNodes(newNode.Network)
+	if err != nil {
+		logger.Log(1, "err getting Network Nodes", err.Error())
+		return err
+	}
+	for _, node := range networkNodes {
+
+		if node.IsServer == "yes" || node.ID == newNode.ID {
+			continue
+		}
+		peerUpdate, err := logic.GetPeerUpdate(&node)
+		if err != nil {
+			logger.Log(1, "error getting peer update for node", node.ID, err.Error())
+			continue
+		}
+		data, err := json.Marshal(&peerUpdate)
+		if err != nil {
+			logger.Log(2, "error marshaling peer update for node", node.ID, err.Error())
+			continue
+		}
+		if err = publish(&node, fmt.Sprintf("peers/%s/%s", node.Network, node.ID), data); err != nil {
+			logger.Log(1, "failed to publish peer update for node", node.ID)
+		} else {
+			if node.Network != servercfg.GetCommsID() {
+				logger.Log(1, "sent peer update for node", node.Name, "on network:", node.Network)
+			}
+		}
+	}
+	return nil
+}
+
+// PublishPeerUpdate --- publishes a peer update to all the peers of a node
+func PublishExtPeerUpdate(node *models.Node) error {
+	var err error
+	if logic.IsLocalServer(node) {
+		if err = logic.ServerUpdate(node, false); err != nil {
+			logger.Log(1, "server node:", node.ID, "failed to update peers with ext clients")
+			return err
+		} else {
+			return nil
+		}
+	}
+	if !servercfg.IsMessageQueueBackend() {
+		return nil
+	}
+	peerUpdate, err := logic.GetPeerUpdate(node)
+	if err != nil {
+		return err
+	}
+	data, err := json.Marshal(&peerUpdate)
+	if err != nil {
+		return err
+	}
+	return publish(node, fmt.Sprintf("peers/%s/%s", node.Network, node.ID), data)
+}
+
+// NodeUpdate -- publishes a node update
+func NodeUpdate(node *models.Node) error {
+	if !servercfg.IsMessageQueueBackend() || node.IsServer == "yes" {
+		return nil
+	}
+	logger.Log(3, "publishing node update to "+node.Name)
+	data, err := json.Marshal(node)
+	if err != nil {
+		logger.Log(2, "error marshalling node update ", err.Error())
+		return err
+	}
+	if err = publish(node, fmt.Sprintf("update/%s/%s", node.Network, node.ID), data); err != nil {
+		logger.Log(2, "error publishing node update to peer ", node.ID, err.Error())
+		return err
+	}
+	return nil
+}
+
+// sendPeers - retrieve networks, send peer ports to all peers
+func sendPeers() {
+	var force bool
+	peer_force_send++
+	if peer_force_send == 5 {
+		force = true
+		peer_force_send = 0
+	}
+	networks, err := logic.GetNetworks()
+	if err != nil {
+		logger.Log(1, "error retrieving networks for keepalive", err.Error())
+	}
+	for _, network := range networks {
+		serverNode, errN := logic.GetNetworkServerLeader(network.NetID)
+		if errN == nil {
+			serverNode.SetLastCheckIn()
+			logic.UpdateNode(&serverNode, &serverNode)
+			if network.DefaultUDPHolePunch == "yes" {
+				if logic.ShouldPublishPeerPorts(&serverNode) || force {
+					if force {
+						logger.Log(2, "sending scheduled peer update (5 min)")
+					}
+					err = PublishPeerUpdate(&serverNode)
+					if err != nil {
+						logger.Log(1, "error publishing udp port updates for network", network.NetID)
+						logger.Log(1, errN.Error())
+					}
+				}
+			}
+		} else {
+			logger.Log(1, "unable to retrieve leader for network ", network.NetID)
+			logger.Log(1, errN.Error())
+			continue
+		}
+	}
+}

+ 23 - 3
mq/util.go

@@ -2,6 +2,7 @@ package mq
 
 
 import (
 import (
 	"fmt"
 	"fmt"
+	"strings"
 
 
 	"github.com/gravitl/netmaker/logic"
 	"github.com/gravitl/netmaker/logic"
 	"github.com/gravitl/netmaker/models"
 	"github.com/gravitl/netmaker/models"
@@ -10,7 +11,7 @@ import (
 
 
 func decryptMsg(node *models.Node, msg []byte) ([]byte, error) {
 func decryptMsg(node *models.Node, msg []byte) ([]byte, error) {
 	if len(msg) <= 24 { // make sure message is of appropriate length
 	if len(msg) <= 24 { // make sure message is of appropriate length
-		return nil, fmt.Errorf("recieved invalid message from broker %s", string(msg))
+		return nil, fmt.Errorf("recieved invalid message from broker %v", msg)
 	}
 	}
 
 
 	trafficKey, trafficErr := logic.RetrievePrivateTrafficKey() // get server private key
 	trafficKey, trafficErr := logic.RetrievePrivateTrafficKey() // get server private key
@@ -26,7 +27,11 @@ func decryptMsg(node *models.Node, msg []byte) ([]byte, error) {
 		return nil, err
 		return nil, err
 	}
 	}
 
 
-	return ncutils.BoxDecrypt(msg, nodePubTKey, serverPrivTKey)
+	if strings.Contains(node.Version, "0.10.0") {
+		return ncutils.BoxDecrypt(msg, nodePubTKey, serverPrivTKey)
+	}
+
+	return ncutils.DeChunk(msg, nodePubTKey, serverPrivTKey)
 }
 }
 
 
 func encryptMsg(node *models.Node, msg []byte) ([]byte, error) {
 func encryptMsg(node *models.Node, msg []byte) ([]byte, error) {
@@ -46,7 +51,11 @@ func encryptMsg(node *models.Node, msg []byte) ([]byte, error) {
 		return nil, err
 		return nil, err
 	}
 	}
 
 
-	return ncutils.BoxEncrypt(msg, nodePubKey, serverPrivKey)
+	if strings.Contains(node.Version, "0.10.0") {
+		return ncutils.BoxEncrypt(msg, nodePubKey, serverPrivKey)
+	}
+
+	return ncutils.Chunk(msg, nodePubKey, serverPrivKey)
 }
 }
 
 
 func publish(node *models.Node, dest string, msg []byte) error {
 func publish(node *models.Node, dest string, msg []byte) error {
@@ -61,3 +70,14 @@ func publish(node *models.Node, dest string, msg []byte) error {
 	}
 	}
 	return nil
 	return nil
 }
 }
+
+//  decodes a message queue topic and returns the embedded node.ID
+func getID(topic string) (string, error) {
+	parts := strings.Split(topic, "/")
+	count := len(parts)
+	if count == 1 {
+		return "", fmt.Errorf("invalid topic")
+	}
+	//the last part of the topic will be the node.ID
+	return parts[count-1], nil
+}

+ 1 - 31
netclient/cli_options/cmds.go

@@ -43,40 +43,10 @@ func GetCommands(cliFlags []cli.Flag) []*cli.Command {
 				if err != nil {
 				if err != nil {
 					return err
 					return err
 				}
 				}
-				err = command.Leave(cfg)
+				err = command.Leave(cfg, c.String("force") == "yes")
 				return err
 				return err
 			},
 			},
 		},
 		},
-		{
-			Name:  "checkin",
-			Usage: "Checks for local changes and then checks into the specified Netmaker network to ask about remote changes.",
-			Flags: cliFlags,
-			// the action, or code that will be executed when
-			// we execute our `ns` command
-			Action: func(c *cli.Context) error {
-				cfg, _, err := config.GetCLIConfig(c)
-				if err != nil {
-					return err
-				}
-				err = command.CheckIn(cfg)
-				return err
-			},
-		},
-		// {
-		// 	Name:  "push",
-		// 	Usage: "Push configuration changes to server.",
-		// 	Flags: cliFlags,
-		// 	// the action, or code that will be executed when
-		// 	// we execute our `ns` command
-		// 	Action: func(c *cli.Context) error {
-		// 		cfg, _, err := config.GetCLIConfig(c)
-		// 		if err != nil {
-		// 			return err
-		// 		}
-		// 		err = command.Push(cfg)
-		// 		return err
-		// 	},
-		// },
 		{
 		{
 			Name:  "pull",
 			Name:  "pull",
 			Usage: "Pull latest configuration and peers from server.",
 			Usage: "Pull latest configuration and peers from server.",

+ 6 - 0
netclient/cli_options/flags.go

@@ -198,5 +198,11 @@ func GetFlags(hostname string) []cli.Flag {
 			Value:   "yes",
 			Value:   "yes",
 			Usage:   "Checks for IP changes if 'yes'. Ignores if 'no'. Yes by default.",
 			Usage:   "Checks for IP changes if 'yes'. Ignores if 'no'. Yes by default.",
 		},
 		},
+		&cli.StringFlag{
+			Name:    "force",
+			EnvVars: []string{"NETCLIENT_FORCE"},
+			Value:   "no",
+			Usage:   "Allows to run the command with force, if otherwise prevented.",
+		},
 	}
 	}
 }
 }

+ 49 - 123
netclient/command/commands.go

@@ -1,10 +1,7 @@
 package command
 package command
 
 
 import (
 import (
-	"os"
-	"strconv"
 	"strings"
 	"strings"
-	"time"
 
 
 	"github.com/gravitl/netmaker/netclient/config"
 	"github.com/gravitl/netmaker/netclient/config"
 	"github.com/gravitl/netmaker/netclient/daemon"
 	"github.com/gravitl/netmaker/netclient/daemon"
@@ -12,15 +9,47 @@ import (
 	"github.com/gravitl/netmaker/netclient/ncutils"
 	"github.com/gravitl/netmaker/netclient/ncutils"
 )
 )
 
 
+// JoinComms -- Join the message queue comms network if it doesn't have it
+// tries to ping if already found locally, if fail ping pull for best effort for communication
+func JoinComms(cfg *config.ClientConfig) error {
+	var commsCfg config.ClientConfig
+	commsCfg.Network = cfg.Server.CommsNetwork
+	commsCfg.Node.Network = cfg.Server.CommsNetwork
+	commsCfg.Server.AccessKey = cfg.Server.AccessKey
+	commsCfg.Server.GRPCAddress = cfg.Server.GRPCAddress
+	commsCfg.Server.GRPCSSL = cfg.Server.GRPCSSL
+	commsCfg.Server.CoreDNSAddr = cfg.Server.CoreDNSAddr
+	if commsCfg.ConfigFileExists() {
+		commsCfg.ReadConfig()
+	}
+	if commsCfg.Node.Name == "" {
+		if err := functions.JoinNetwork(commsCfg, "", true); err != nil {
+			return err
+		}
+	} else { // check if comms is currently reachable
+		if err := functions.PingServer(&commsCfg); err != nil {
+			if err = Pull(commsCfg); err != nil {
+				return err
+			}
+		}
+	}
+	return nil
+}
+
 // Join - join command to run from cli
 // Join - join command to run from cli
 func Join(cfg config.ClientConfig, privateKey string) error {
 func Join(cfg config.ClientConfig, privateKey string) error {
-
 	var err error
 	var err error
-	err = functions.JoinNetwork(cfg, privateKey)
+	//check if comms network exists
+	if err = JoinComms(&cfg); err != nil {
+		return err
+	}
+
+	//join network
+	err = functions.JoinNetwork(cfg, privateKey, false)
 	if err != nil && !cfg.DebugOn {
 	if err != nil && !cfg.DebugOn {
 		if !strings.Contains(err.Error(), "ALREADY_INSTALLED") {
 		if !strings.Contains(err.Error(), "ALREADY_INSTALLED") {
 			ncutils.PrintLog("error installing: "+err.Error(), 1)
 			ncutils.PrintLog("error installing: "+err.Error(), 1)
-			err = functions.LeaveNetwork(cfg.Network)
+			err = functions.LeaveNetwork(cfg.Network, true)
 			if err != nil {
 			if err != nil {
 				err = functions.WipeLocal(cfg.Network)
 				err = functions.WipeLocal(cfg.Network)
 				if err != nil {
 				if err != nil {
@@ -48,134 +77,30 @@ func Join(cfg config.ClientConfig, privateKey string) error {
 		return err
 		return err
 	}
 	}
 	ncutils.PrintLog("joined "+cfg.Network, 1)
 	ncutils.PrintLog("joined "+cfg.Network, 1)
-	if ncutils.IsWindows() {
-		ncutils.PrintLog("setting up WireGuard app", 0)
-		time.Sleep(time.Second >> 1)
-		functions.Pull(cfg.Network, true)
-	}
-	return err
-}
-
-func getWindowsInterval() int {
-	interval := 15
-	networks, err := ncutils.GetSystemNetworks()
-	if err != nil {
-		return interval
-	}
-	cfg, err := config.ReadConfig(networks[0])
-	if err != nil {
-		return interval
-	}
-	netint, err := strconv.Atoi(cfg.Server.CheckinInterval)
-	if err == nil && netint != 0 {
-		interval = netint
-	}
-	return interval
-}
-
-// RunUserspaceDaemon - runs continual checkins
-func RunUserspaceDaemon() {
-
-	cfg := config.ClientConfig{
-		Network: "all",
-	}
-	interval := getWindowsInterval()
-	dur := time.Duration(interval) * time.Second
-	for {
-		CheckIn(cfg)
-		time.Sleep(dur)
-	}
-}
-
-// CheckIn - runs checkin command from cli
-func CheckIn(cfg config.ClientConfig) error {
-	//log.Println("checkin --- diabled for now")
-	//return nil
-	var err error
-	var errN error
-	if cfg.Network == "" {
-		ncutils.PrintLog("required, '-n', exiting", 0)
-		os.Exit(1)
-	} else if cfg.Network == "all" {
-		ncutils.PrintLog("running checkin for all networks", 1)
-		networks, err := ncutils.GetSystemNetworks()
-		if err != nil {
-			ncutils.PrintLog("error retrieving networks, exiting", 1)
-			return err
+	/*
+		if ncutils.IsWindows() {
+			ncutils.PrintLog("setting up WireGuard app", 0)
+			time.Sleep(time.Second >> 1)
+			functions.Pull(cfg.Network, true)
 		}
 		}
-		for _, network := range networks {
-			currConf, err := config.ReadConfig(network)
-			if err != nil {
-				continue
-			}
-			err = functions.CheckConfig(*currConf)
-			if err != nil {
-				if strings.Contains(err.Error(), "could not find iface") {
-					err = Pull(cfg)
-					if err != nil {
-						ncutils.PrintLog(err.Error(), 1)
-					}
-				} else {
-					ncutils.PrintLog("error checking in for "+network+" network: "+err.Error(), 1)
-				}
-			} else {
-				ncutils.PrintLog("checked in successfully for "+network, 1)
-			}
-		}
-		if len(networks) == 0 {
-			if ncutils.IsWindows() { // Windows specific - there are no netclients, so stop daemon process
-				daemon.StopWindowsDaemon()
-			}
-		}
-		errN = err
-		err = nil
-	} else {
-		err = functions.CheckConfig(cfg)
-	}
-	if err == nil && errN != nil {
-		err = errN
-	}
+	*/
 	return err
 	return err
 }
 }
 
 
 // Leave - runs the leave command from cli
 // Leave - runs the leave command from cli
-func Leave(cfg config.ClientConfig) error {
-	err := functions.LeaveNetwork(cfg.Network)
+func Leave(cfg config.ClientConfig, force bool) error {
+	err := functions.LeaveNetwork(cfg.Network, force)
 	if err != nil {
 	if err != nil {
 		ncutils.PrintLog("error attempting to leave network "+cfg.Network, 1)
 		ncutils.PrintLog("error attempting to leave network "+cfg.Network, 1)
 	} else {
 	} else {
 		ncutils.PrintLog("success", 0)
 		ncutils.PrintLog("success", 0)
 	}
 	}
-	return err
-}
-
-// Push - runs push command
-func Push(cfg config.ClientConfig) error {
-	var err error
-	if cfg.Network == "all" || ncutils.IsWindows() {
-		ncutils.PrintLog("pushing config to server for all networks.", 0)
-		networks, err := ncutils.GetSystemNetworks()
-		if err != nil {
-			ncutils.PrintLog("error retrieving networks, exiting.", 0)
-			return err
-		}
-		for _, network := range networks {
-			err = functions.Push(network)
-			if err != nil {
-				ncutils.PrintLog("error pushing network configs for network: "+network+"\n"+err.Error(), 1)
-			} else {
-				ncutils.PrintLog("pushed network config for "+network, 1)
-			}
+	nets, err := ncutils.GetSystemNetworks()
+	if err == nil && len(nets) == 1 {
+		if nets[0] == cfg.Node.CommID {
+			ncutils.PrintLog("detected comms as remaining network, removing...", 1)
+			err = functions.LeaveNetwork(nets[0], true)
 		}
 		}
-		err = nil
-	} else {
-		err = functions.Push(cfg.Network)
-	}
-	if err == nil {
-		ncutils.PrintLog("completed pushing network configs to remote server", 1)
-		ncutils.PrintLog("success", 1)
-	} else {
-		ncutils.PrintLog("error occurred pushing configs", 1)
 	}
 	}
 	return err
 	return err
 }
 }
@@ -226,6 +151,7 @@ func Uninstall() error {
 	return err
 	return err
 }
 }
 
 
+// Daemon - runs the daemon
 func Daemon() error {
 func Daemon() error {
 	err := functions.Daemon()
 	err := functions.Daemon()
 	return err
 	return err

+ 20 - 48
netclient/config/config.go

@@ -15,12 +15,6 @@ import (
 	"gopkg.in/yaml.v3"
 	"gopkg.in/yaml.v3"
 )
 )
 
 
-// GlobalConfig - struct for handling IntClients currently
-type GlobalConfig struct {
-	GRPCWireGuard string `yaml:"grpcwg"`
-	Client        models.IntClient
-}
-
 // ClientConfig - struct for dealing with client configuration
 // ClientConfig - struct for dealing with client configuration
 type ClientConfig struct {
 type ClientConfig struct {
 	Server          ServerConfig   `yaml:"server"`
 	Server          ServerConfig   `yaml:"server"`
@@ -34,13 +28,11 @@ type ClientConfig struct {
 
 
 // ServerConfig - struct for dealing with the server information for a netclient
 // ServerConfig - struct for dealing with the server information for a netclient
 type ServerConfig struct {
 type ServerConfig struct {
-	CoreDNSAddr     string `yaml:"corednsaddr"`
-	GRPCAddress     string `yaml:"grpcaddress"`
-	APIAddress      string `yaml:"apiaddress"`
-	AccessKey       string `yaml:"accesskey"`
-	GRPCSSL         string `yaml:"grpcssl"`
-	GRPCWireGuard   string `yaml:"grpcwg"`
-	CheckinInterval string `yaml:"checkininterval"`
+	CoreDNSAddr  string `yaml:"corednsaddr"`
+	GRPCAddress  string `yaml:"grpcaddress"`
+	AccessKey    string `yaml:"accesskey"`
+	GRPCSSL      string `yaml:"grpcssl"`
+	CommsNetwork string `yaml:"commsnetwork"`
 }
 }
 
 
 // Write - writes the config of a client to disk
 // Write - writes the config of a client to disk
@@ -71,6 +63,18 @@ func Write(config *ClientConfig, network string) error {
 	return f.Sync()
 	return f.Sync()
 }
 }
 
 
+// ConfigFileExists - return true if config file exists
+func (config *ClientConfig) ConfigFileExists() bool {
+	home := ncutils.GetNetclientPathSpecific()
+
+	file := fmt.Sprintf(home + "netconfig-" + config.Network)
+	info, err := os.Stat(file)
+	if os.IsNotExist(err) {
+		return false
+	}
+	return !info.IsDir()
+}
+
 // ClientConfig.ReadConfig - used to read config from client disk into memory
 // ClientConfig.ReadConfig - used to read config from client disk into memory
 func (config *ClientConfig) ReadConfig() {
 func (config *ClientConfig) ReadConfig() {
 
 
@@ -82,8 +86,7 @@ func (config *ClientConfig) ReadConfig() {
 	//f, err := os.Open(file)
 	//f, err := os.Open(file)
 	f, err := os.OpenFile(file, os.O_RDONLY, 0600)
 	f, err := os.OpenFile(file, os.O_RDONLY, 0600)
 	if err != nil {
 	if err != nil {
-		fmt.Println("trouble opening file")
-		fmt.Println(err)
+		ncutils.PrintLog("trouble opening file: "+err.Error(), 1)
 		nofile = true
 		nofile = true
 		//fmt.Println("Could not access " + home + "/.netconfig,  proceeding...")
 		//fmt.Println("Could not access " + home + "/.netconfig,  proceeding...")
 	}
 	}
@@ -175,21 +178,8 @@ func GetCLIConfig(c *cli.Context) (ClientConfig, string, error) {
 			return cfg, "", err
 			return cfg, "", err
 		}
 		}
 
 
-		if accesstoken.ServerConfig.APIConnString != "" {
-			cfg.Server.APIAddress = accesstoken.ServerConfig.APIConnString
-		} else {
-			cfg.Server.APIAddress = accesstoken.ServerConfig.APIHost
-			if accesstoken.ServerConfig.APIPort != "" {
-				cfg.Server.APIAddress = cfg.Server.APIAddress + ":" + accesstoken.ServerConfig.APIPort
-			}
-		}
 		if accesstoken.ServerConfig.GRPCConnString != "" {
 		if accesstoken.ServerConfig.GRPCConnString != "" {
 			cfg.Server.GRPCAddress = accesstoken.ServerConfig.GRPCConnString
 			cfg.Server.GRPCAddress = accesstoken.ServerConfig.GRPCConnString
-		} else {
-			cfg.Server.GRPCAddress = accesstoken.ServerConfig.GRPCHost
-			if accesstoken.ServerConfig.GRPCPort != "" {
-				cfg.Server.GRPCAddress = cfg.Server.GRPCAddress + ":" + accesstoken.ServerConfig.GRPCPort
-			}
 		}
 		}
 
 
 		cfg.Network = accesstoken.ClientConfig.Network
 		cfg.Network = accesstoken.ClientConfig.Network
@@ -197,15 +187,10 @@ func GetCLIConfig(c *cli.Context) (ClientConfig, string, error) {
 		cfg.Server.AccessKey = accesstoken.ClientConfig.Key
 		cfg.Server.AccessKey = accesstoken.ClientConfig.Key
 		cfg.Node.LocalRange = accesstoken.ClientConfig.LocalRange
 		cfg.Node.LocalRange = accesstoken.ClientConfig.LocalRange
 		cfg.Server.GRPCSSL = accesstoken.ServerConfig.GRPCSSL
 		cfg.Server.GRPCSSL = accesstoken.ServerConfig.GRPCSSL
-		cfg.Server.CheckinInterval = accesstoken.ServerConfig.CheckinInterval
-		cfg.Server.GRPCWireGuard = accesstoken.WG.GRPCWireGuard
-		cfg.Server.CoreDNSAddr = accesstoken.ServerConfig.CoreDNSAddr
+		cfg.Server.CommsNetwork = accesstoken.ServerConfig.CommsNetwork
 		if c.String("grpcserver") != "" {
 		if c.String("grpcserver") != "" {
 			cfg.Server.GRPCAddress = c.String("grpcserver")
 			cfg.Server.GRPCAddress = c.String("grpcserver")
 		}
 		}
-		if c.String("apiserver") != "" {
-			cfg.Server.APIAddress = c.String("apiserver")
-		}
 		if c.String("key") != "" {
 		if c.String("key") != "" {
 			cfg.Server.AccessKey = c.String("key")
 			cfg.Server.AccessKey = c.String("key")
 		}
 		}
@@ -222,24 +207,15 @@ func GetCLIConfig(c *cli.Context) (ClientConfig, string, error) {
 		if c.String("corednsaddr") != "" {
 		if c.String("corednsaddr") != "" {
 			cfg.Server.CoreDNSAddr = c.String("corednsaddr")
 			cfg.Server.CoreDNSAddr = c.String("corednsaddr")
 		}
 		}
-		if c.String("grpcwg") != "" {
-			cfg.Server.GRPCWireGuard = c.String("grpcwg")
-		}
-		if c.String("checkininterval") != "" {
-			cfg.Server.CheckinInterval = c.String("checkininterval")
-		}
 
 
 	} else {
 	} else {
 		cfg.Server.GRPCAddress = c.String("grpcserver")
 		cfg.Server.GRPCAddress = c.String("grpcserver")
-		cfg.Server.APIAddress = c.String("apiserver")
 		cfg.Server.AccessKey = c.String("key")
 		cfg.Server.AccessKey = c.String("key")
 		cfg.Network = c.String("network")
 		cfg.Network = c.String("network")
 		cfg.Node.Network = c.String("network")
 		cfg.Node.Network = c.String("network")
 		cfg.Node.LocalRange = c.String("localrange")
 		cfg.Node.LocalRange = c.String("localrange")
-		cfg.Server.GRPCWireGuard = c.String("grpcwg")
 		cfg.Server.GRPCSSL = c.String("grpcssl")
 		cfg.Server.GRPCSSL = c.String("grpcssl")
 		cfg.Server.CoreDNSAddr = c.String("corednsaddr")
 		cfg.Server.CoreDNSAddr = c.String("corednsaddr")
-		cfg.Server.CheckinInterval = c.String("checkininterval")
 	}
 	}
 	cfg.Node.Name = c.String("name")
 	cfg.Node.Name = c.String("name")
 	cfg.Node.Interface = c.String("interface")
 	cfg.Node.Interface = c.String("interface")
@@ -248,7 +224,7 @@ func GetCLIConfig(c *cli.Context) (ClientConfig, string, error) {
 	cfg.Node.LocalAddress = c.String("localaddress")
 	cfg.Node.LocalAddress = c.String("localaddress")
 	cfg.Node.Address = c.String("address")
 	cfg.Node.Address = c.String("address")
 	cfg.Node.Address6 = c.String("addressIPV6")
 	cfg.Node.Address6 = c.String("addressIPV6")
-	cfg.Node.Roaming = c.String("roaming")
+	//cfg.Node.Roaming = c.String("roaming")
 	cfg.Node.DNSOn = c.String("dnson")
 	cfg.Node.DNSOn = c.String("dnson")
 	cfg.Node.IsLocal = c.String("islocal")
 	cfg.Node.IsLocal = c.String("islocal")
 	cfg.Node.IsStatic = c.String("isstatic")
 	cfg.Node.IsStatic = c.String("isstatic")
@@ -266,10 +242,6 @@ func GetCLIConfig(c *cli.Context) (ClientConfig, string, error) {
 	cfg.Node.UDPHolePunch = c.String("udpholepunch")
 	cfg.Node.UDPHolePunch = c.String("udpholepunch")
 	cfg.Node.MTU = int32(c.Int("mtu"))
 	cfg.Node.MTU = int32(c.Int("mtu"))
 
 
-	if cfg.Server.CheckinInterval == "" {
-		cfg.Server.CheckinInterval = "15"
-	}
-
 	return cfg, privateKey, nil
 	return cfg, privateKey, nil
 }
 }
 
 

+ 2 - 7
netclient/daemon/common.go

@@ -13,18 +13,13 @@ func InstallDaemon(cfg config.ClientConfig) error {
 	os := runtime.GOOS
 	os := runtime.GOOS
 	var err error
 	var err error
 
 
-	interval := "15"
-	if cfg.Server.CheckinInterval != "" {
-		interval = cfg.Server.CheckinInterval
-	}
-
 	switch os {
 	switch os {
 	case "windows":
 	case "windows":
 		err = SetupWindowsDaemon()
 		err = SetupWindowsDaemon()
 	case "darwin":
 	case "darwin":
-		err = SetupMacDaemon(interval)
+		err = SetupMacDaemon()
 	case "linux":
 	case "linux":
-		err = SetupSystemDDaemon(interval)
+		err = SetupSystemDDaemon()
 	case "freebsd":
 	case "freebsd":
 		err = SetupFreebsdDaemon()
 		err = SetupFreebsdDaemon()
 	default:
 	default:

+ 11 - 10
netclient/daemon/macos.go

@@ -1,7 +1,6 @@
 package daemon
 package daemon
 
 
 import (
 import (
-	"fmt"
 	"log"
 	"log"
 	"os"
 	"os"
 	"path/filepath"
 	"path/filepath"
@@ -14,7 +13,7 @@ const MAC_SERVICE_NAME = "com.gravitl.netclient"
 const MAC_EXEC_DIR = "/usr/local/bin/"
 const MAC_EXEC_DIR = "/usr/local/bin/"
 
 
 // SetupMacDaemon - Creates a daemon service from the netclient under LaunchAgents for MacOS
 // SetupMacDaemon - Creates a daemon service from the netclient under LaunchAgents for MacOS
-func SetupMacDaemon(interval string) error {
+func SetupMacDaemon() error {
 
 
 	dir, err := filepath.Abs(filepath.Dir(os.Args[0]))
 	dir, err := filepath.Abs(filepath.Dir(os.Args[0]))
 	if err != nil {
 	if err != nil {
@@ -34,7 +33,7 @@ func SetupMacDaemon(interval string) error {
 	if os.IsNotExist(errN) {
 	if os.IsNotExist(errN) {
 		os.Mkdir("~/Library/LaunchAgents", 0755)
 		os.Mkdir("~/Library/LaunchAgents", 0755)
 	}
 	}
-	err = CreateMacService(MAC_SERVICE_NAME, interval)
+	err = CreateMacService(MAC_SERVICE_NAME)
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}
@@ -69,7 +68,7 @@ func StopLaunchD() {
 }
 }
 
 
 // CreateMacService - Creates the mac service file for LaunchDaemons
 // CreateMacService - Creates the mac service file for LaunchDaemons
-func CreateMacService(servicename string, interval string) error {
+func CreateMacService(servicename string) error {
 	_, err := os.Stat("/Library/LaunchDaemons")
 	_, err := os.Stat("/Library/LaunchDaemons")
 	if os.IsNotExist(err) {
 	if os.IsNotExist(err) {
 		os.Mkdir("/Library/LaunchDaemons", 0755)
 		os.Mkdir("/Library/LaunchDaemons", 0755)
@@ -77,7 +76,7 @@ func CreateMacService(servicename string, interval string) error {
 		log.Println("couldnt find or create /Library/LaunchDaemons")
 		log.Println("couldnt find or create /Library/LaunchDaemons")
 		return err
 		return err
 	}
 	}
-	daemonstring := MacDaemonString(interval)
+	daemonstring := MacDaemonString()
 	daemonbytes := []byte(daemonstring)
 	daemonbytes := []byte(daemonstring)
 
 
 	if !ncutils.FileExists("/Library/LaunchDaemons/com.gravitl.netclient.plist") {
 	if !ncutils.FileExists("/Library/LaunchDaemons/com.gravitl.netclient.plist") {
@@ -87,8 +86,8 @@ func CreateMacService(servicename string, interval string) error {
 }
 }
 
 
 // MacDaemonString - the file contents for the mac netclient daemon service (launchdaemon)
 // MacDaemonString - the file contents for the mac netclient daemon service (launchdaemon)
-func MacDaemonString(interval string) string {
-	return fmt.Sprintf(`<?xml version='1.0' encoding='UTF-8'?>
+func MacDaemonString() string {
+	return `<?xml version='1.0' encoding='UTF-8'?>
 <!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\" >
 <!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\" >
 <plist version='1.0'>
 <plist version='1.0'>
 <dict>
 <dict>
@@ -100,9 +99,11 @@ func MacDaemonString(interval string) string {
 		</array>
 		</array>
 	<key>StandardOutPath</key><string>/etc/netclient/com.gravitl.netclient.log</string>
 	<key>StandardOutPath</key><string>/etc/netclient/com.gravitl.netclient.log</string>
 	<key>StandardErrorPath</key><string>/etc/netclient/com.gravitl.netclient.log</string>
 	<key>StandardErrorPath</key><string>/etc/netclient/com.gravitl.netclient.log</string>
+	<key>RunAtLoad</key>
+	<true/>
+	<key>KeepAlive</key>
+	<true/>
 	<key>AbandonProcessGroup</key><true/>
 	<key>AbandonProcessGroup</key><true/>
-	<key>StartInterval</key>
-	    <integer>%s</integer>
 	<key>EnvironmentVariables</key>
 	<key>EnvironmentVariables</key>
 		<dict>
 		<dict>
 			<key>PATH</key>
 			<key>PATH</key>
@@ -110,7 +111,7 @@ func MacDaemonString(interval string) string {
 		</dict>
 		</dict>
 </dict>
 </dict>
 </plist>
 </plist>
-`, interval)
+`
 }
 }
 
 
 // MacTemplateData - struct to represent the mac service
 // MacTemplateData - struct to represent the mac service

+ 1 - 1
netclient/daemon/systemd.go

@@ -14,7 +14,7 @@ import (
 const EXEC_DIR = "/sbin/"
 const EXEC_DIR = "/sbin/"
 
 
 // SetupSystemDDaemon - sets system daemon for supported machines
 // SetupSystemDDaemon - sets system daemon for supported machines
-func SetupSystemDDaemon(interval string) error {
+func SetupSystemDDaemon() error {
 
 
 	if ncutils.IsWindows() {
 	if ncutils.IsWindows() {
 		return nil
 		return nil

+ 0 - 320
netclient/functions/checkin.go

@@ -1,320 +0,0 @@
-package functions
-
-import (
-	"context"
-	"encoding/json"
-	"errors"
-	"os"
-	"runtime"
-	"strings"
-
-	nodepb "github.com/gravitl/netmaker/grpc"
-	"github.com/gravitl/netmaker/models"
-	"github.com/gravitl/netmaker/netclient/auth"
-	"github.com/gravitl/netmaker/netclient/config"
-	"github.com/gravitl/netmaker/netclient/local"
-	"github.com/gravitl/netmaker/netclient/ncutils"
-	"github.com/gravitl/netmaker/netclient/wireguard"
-	"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
-	"google.golang.org/grpc"
-	"google.golang.org/grpc/metadata"
-	//homedir "github.com/mitchellh/go-homedir"
-)
-
-func isDeleteError(err error) bool {
-	return err != nil && strings.Contains(err.Error(), models.NODE_DELETE)
-}
-
-func checkIP(node *models.Node, servercfg config.ServerConfig, cliconf config.ClientConfig, network string) bool {
-	ipchange := false
-	var err error
-	if node.Roaming == "yes" && node.IsStatic != "yes" {
-		if node.IsLocal == "no" {
-			extIP, err := ncutils.GetPublicIP()
-			if err != nil {
-				ncutils.PrintLog("error encountered checking ip addresses: "+err.Error(), 1)
-			}
-			if node.Endpoint != extIP && extIP != "" {
-				ncutils.PrintLog("endpoint has changed from "+
-					node.Endpoint+" to "+extIP, 1)
-				ncutils.PrintLog("updating address", 1)
-				node.Endpoint = extIP
-				ipchange = true
-			}
-			intIP, err := getPrivateAddr()
-			if err != nil {
-				ncutils.PrintLog("error encountered checking ip addresses: "+err.Error(), 1)
-			}
-			if node.LocalAddress != intIP && intIP != "" {
-				ncutils.PrintLog("local Address has changed from "+
-					node.LocalAddress+" to "+intIP, 1)
-				ncutils.PrintLog("updating address", 1)
-				node.LocalAddress = intIP
-				ipchange = true
-			}
-		} else {
-			localIP, err := ncutils.GetLocalIP(node.LocalRange)
-			if err != nil {
-				ncutils.PrintLog("error encountered checking ip addresses: "+err.Error(), 1)
-			}
-			if node.Endpoint != localIP && localIP != "" {
-				ncutils.PrintLog("endpoint has changed from "+
-					node.Endpoint+" to "+localIP, 1)
-				ncutils.PrintLog("updating address", 1)
-				node.Endpoint = localIP
-				node.LocalAddress = localIP
-				ipchange = true
-			}
-		}
-	}
-	if ipchange {
-		err = config.ModConfig(node)
-		if err != nil {
-			ncutils.PrintLog("error modifying config file: "+err.Error(), 1)
-			return false
-		}
-		err = wireguard.SetWGConfig(network, false)
-		if err != nil {
-			ncutils.PrintLog("error setting wireguard config: "+err.Error(), 1)
-			return false
-		}
-	}
-	return ipchange && err == nil
-}
-
-// DEPRECATED
-// func setDNS(node *models.Node, servercfg config.ServerConfig, nodecfg *models.Node) {
-// 	if nodecfg.DNSOn == "yes" {
-// 		ifacename := node.Interface
-// 		nameserver := servercfg.CoreDNSAddr
-// 		network := node.Network
-// 		local.UpdateDNS(ifacename, network, nameserver)
-// 	}
-// }
-
-func checkNodeActions(node *models.Node, networkName string, servercfg config.ServerConfig, localNode *models.Node, cfg *config.ClientConfig) string {
-	if (node.Action == models.NODE_UPDATE_KEY || localNode.Action == models.NODE_UPDATE_KEY) &&
-		node.IsStatic != "yes" {
-		err := wireguard.SetWGKeyConfig(networkName, servercfg.GRPCAddress)
-		if err != nil {
-			ncutils.PrintLog("unable to process reset keys request: "+err.Error(), 1)
-			return ""
-		}
-	}
-	if node.Action == models.NODE_DELETE || localNode.Action == models.NODE_DELETE {
-		err := RemoveLocalInstance(cfg, networkName)
-		if err != nil {
-			ncutils.PrintLog("error deleting locally: "+err.Error(), 1)
-		}
-		return models.NODE_DELETE
-	}
-	return ""
-}
-
-// CheckConfig - checks if current config of client needs update, see flow below
-/**
- * Pull changes if any (interface refresh)
- * - Save it
- * Check local changes for (ipAddress, publickey, configfile changes) (interface refresh)
- * - Save it
- * - Push it
- * Pull Peers (sync)
- */
-func CheckConfig(cliconf config.ClientConfig) error {
-
-	network := cliconf.Network
-	cfg, err := config.ReadConfig(network)
-	if err != nil {
-		return err
-	}
-	servercfg := cfg.Server
-	currentNode := cfg.Node
-
-	newNode, err := Pull(network, false)
-	if isDeleteError(err) {
-		return RemoveLocalInstance(cfg, network)
-	}
-	if err != nil {
-		return err
-	}
-	if newNode.IsPending == "yes" {
-		return errors.New("node is pending")
-	}
-	actionCompleted := checkNodeActions(newNode, network, servercfg, &currentNode, cfg)
-	if actionCompleted == models.NODE_DELETE {
-		return errors.New("node has been removed")
-	}
-	// Check if ip changed and push if so
-	checkIP(newNode, servercfg, cliconf, network)
-	return Push(network)
-}
-
-// Pull - pulls the latest config from the server, if manual it will overwrite
-func Pull(network string, manual bool) (*models.Node, error) {
-	cfg, err := config.ReadConfig(network)
-	if err != nil {
-		return nil, err
-	}
-	node := cfg.Node
-	//servercfg := cfg.Server
-
-	if cfg.Node.IPForwarding == "yes" && !ncutils.IsWindows() {
-		if err = local.SetIPForwarding(); err != nil {
-			return nil, err
-		}
-	}
-	var resNode models.Node // just need to fill this with either server calls or client calls
-
-	var header metadata.MD
-	var wcclient nodepb.NodeServiceClient
-	var ctx context.Context
-
-	if cfg.Node.IsServer != "yes" {
-		conn, err := grpc.Dial(cfg.Server.GRPCAddress,
-			ncutils.GRPCRequestOpts(cfg.Server.GRPCSSL))
-		if err != nil {
-			ncutils.PrintLog("Cant dial GRPC server: "+err.Error(), 1)
-			return nil, err
-		}
-		defer conn.Close()
-		wcclient = nodepb.NewNodeServiceClient(conn)
-
-		ctx, err = auth.SetJWT(wcclient, network)
-		if err != nil {
-			ncutils.PrintLog("Failed to authenticate: "+err.Error(), 1)
-			return nil, err
-		}
-		data, err := json.Marshal(&node)
-		if err != nil {
-			ncutils.PrintLog("Failed to parse node config: "+err.Error(), 1)
-			return nil, err
-		}
-
-		req := &nodepb.Object{
-			Data: string(data),
-			Type: nodepb.NODE_TYPE,
-		}
-
-		readres, err := wcclient.ReadNode(ctx, req, grpc.Header(&header))
-		if err != nil {
-			return nil, err
-		}
-
-		if err = json.Unmarshal([]byte(readres.Data), &resNode); err != nil {
-			return nil, err
-		}
-	}
-	// ensure that the OS never changes
-	resNode.OS = runtime.GOOS
-	if resNode.PullChanges == "yes" || manual {
-		// check for interface change
-		if cfg.Node.Interface != resNode.Interface {
-			if err = DeleteInterface(cfg.Node.Interface, cfg.Node.PostDown); err != nil {
-				ncutils.PrintLog("could not delete old interface "+cfg.Node.Interface, 1)
-			}
-		}
-		resNode.PullChanges = "no"
-		if err = config.ModConfig(&resNode); err != nil {
-			return nil, err
-		}
-		if err = wireguard.SetWGConfig(network, false); err != nil {
-			return nil, err
-		}
-		nodeData, err := json.Marshal(&resNode)
-		if err != nil {
-			return &resNode, err
-		}
-
-		if resNode.IsServer != "yes" {
-			if wcclient == nil || ctx == nil {
-				return &cfg.Node, errors.New("issue initializing gRPC client")
-			}
-			req := &nodepb.Object{
-				Data:     string(nodeData),
-				Type:     nodepb.NODE_TYPE,
-				Metadata: "",
-			}
-			_, err = wcclient.UpdateNode(ctx, req, grpc.Header(&header))
-			if err != nil {
-				return &resNode, err
-			}
-		}
-	} else {
-		if err = wireguard.SetWGConfig(network, true); err != nil {
-			if errors.Is(err, os.ErrNotExist) && !ncutils.IsFreeBSD() {
-				return Pull(network, true)
-			} else {
-				return nil, err
-			}
-		}
-	}
-	var bkupErr = config.SaveBackup(network)
-	if bkupErr != nil {
-		ncutils.Log("unable to update backup file")
-	}
-
-	return &resNode, err
-}
-
-// Push - pushes current client configuration to server
-func Push(network string) error {
-
-	cfg, err := config.ReadConfig(network)
-	if err != nil {
-		return err
-	}
-	postnode := cfg.Node
-	// always set the OS on client
-	postnode.OS = runtime.GOOS
-	postnode.SetLastCheckIn()
-
-	var header metadata.MD
-	var wcclient nodepb.NodeServiceClient
-	conn, err := grpc.Dial(cfg.Server.GRPCAddress,
-		ncutils.GRPCRequestOpts(cfg.Server.GRPCSSL))
-	if err != nil {
-		ncutils.PrintLog("Cant dial GRPC server: "+err.Error(), 1)
-		return err
-	}
-	defer conn.Close()
-	wcclient = nodepb.NewNodeServiceClient(conn)
-
-	ctx, err := auth.SetJWT(wcclient, network)
-	if err != nil {
-		ncutils.PrintLog("Failed to authenticate with server: "+err.Error(), 1)
-		return err
-	}
-	if postnode.IsPending != "yes" {
-		privateKey, err := wireguard.RetrievePrivKey(network)
-		if err != nil {
-			return err
-		}
-		privateKeyWG, err := wgtypes.ParseKey(privateKey)
-		if err != nil {
-			return err
-		}
-		if postnode.PublicKey != privateKeyWG.PublicKey().String() {
-			postnode.PublicKey = privateKeyWG.PublicKey().String()
-		}
-	}
-	nodeData, err := json.Marshal(&postnode)
-	if err != nil {
-		return err
-	}
-
-	req := &nodepb.Object{
-		Data:     string(nodeData),
-		Type:     nodepb.NODE_TYPE,
-		Metadata: "",
-	}
-	data, err := wcclient.UpdateNode(ctx, req, grpc.Header(&header))
-	if err != nil {
-		return err
-	}
-	err = json.Unmarshal([]byte(data.Data), &postnode)
-	if err != nil {
-		return err
-	}
-	err = config.ModConfig(&postnode)
-	return err
-}

+ 5 - 57
netclient/functions/common.go

@@ -124,7 +124,7 @@ func Uninstall() error {
 		ncutils.PrintLog("continuing uninstall without leaving networks", 1)
 		ncutils.PrintLog("continuing uninstall without leaving networks", 1)
 	} else {
 	} else {
 		for _, network := range networks {
 		for _, network := range networks {
-			err = LeaveNetwork(network)
+			err = LeaveNetwork(network, true)
 			if err != nil {
 			if err != nil {
 				ncutils.PrintLog("Encounter issue leaving network "+network+": "+err.Error(), 1)
 				ncutils.PrintLog("Encounter issue leaving network "+network+": "+err.Error(), 1)
 			}
 			}
@@ -147,13 +147,16 @@ func Uninstall() error {
 }
 }
 
 
 // LeaveNetwork - client exits a network
 // LeaveNetwork - client exits a network
-func LeaveNetwork(network string) error {
+func LeaveNetwork(network string, force bool) error {
 	cfg, err := config.ReadConfig(network)
 	cfg, err := config.ReadConfig(network)
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}
 	servercfg := cfg.Server
 	servercfg := cfg.Server
 	node := cfg.Node
 	node := cfg.Node
+	if node.NetworkSettings.IsComms == "yes" && !force {
+		return errors.New("COMMS_NET - You are trying to leave the comms network. This will break network updates. Unless you re-join. If you really want to leave, run with --force=yes.")
+	}
 
 
 	if node.IsServer != "yes" {
 	if node.IsServer != "yes" {
 		var wcclient nodepb.NodeServiceClient
 		var wcclient nodepb.NodeServiceClient
@@ -317,58 +320,3 @@ func WipeLocal(network string) error {
 	}
 	}
 	return err
 	return err
 }
 }
-
-func getLocalIP(node models.Node) string {
-
-	var local string
-
-	ifaces, err := net.Interfaces()
-	if err != nil {
-		return local
-	}
-	_, localrange, err := net.ParseCIDR(node.LocalRange)
-	if err != nil {
-		return local
-	}
-
-	found := false
-	for _, i := range ifaces {
-		if i.Flags&net.FlagUp == 0 {
-			continue // interface down
-		}
-		if i.Flags&net.FlagLoopback != 0 {
-			continue // loopback interface
-		}
-		addrs, err := i.Addrs()
-		if err != nil {
-			return local
-		}
-		for _, addr := range addrs {
-			var ip net.IP
-			switch v := addr.(type) {
-			case *net.IPNet:
-				if !found {
-					ip = v.IP
-					local = ip.String()
-					if node.IsLocal == "yes" {
-						found = localrange.Contains(ip)
-					} else {
-						found = true
-					}
-				}
-			case *net.IPAddr:
-				if !found {
-					ip = v.IP
-					local = ip.String()
-					if node.IsLocal == "yes" {
-						found = localrange.Contains(ip)
-
-					} else {
-						found = true
-					}
-				}
-			}
-		}
-	}
-	return local
-}

+ 208 - 454
netclient/functions/daemon.go

@@ -2,12 +2,10 @@ package functions
 
 
 import (
 import (
 	"context"
 	"context"
-	"encoding/json"
 	"errors"
 	"errors"
 	"fmt"
 	"fmt"
 	"os"
 	"os"
 	"os/signal"
 	"os/signal"
-	"runtime"
 	"strings"
 	"strings"
 	"sync"
 	"sync"
 	"syscall"
 	"syscall"
@@ -19,14 +17,11 @@ import (
 	"github.com/gravitl/netmaker/netclient/auth"
 	"github.com/gravitl/netmaker/netclient/auth"
 	"github.com/gravitl/netmaker/netclient/config"
 	"github.com/gravitl/netmaker/netclient/config"
 	"github.com/gravitl/netmaker/netclient/daemon"
 	"github.com/gravitl/netmaker/netclient/daemon"
-	"github.com/gravitl/netmaker/netclient/local"
 	"github.com/gravitl/netmaker/netclient/ncutils"
 	"github.com/gravitl/netmaker/netclient/ncutils"
 	"github.com/gravitl/netmaker/netclient/wireguard"
 	"github.com/gravitl/netmaker/netclient/wireguard"
 	"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
 	"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
 )
 )
 
 
-// == Message Caches ==
-// var keepalive = new(sync.Map)
 var messageCache = new(sync.Map)
 var messageCache = new(sync.Map)
 var networkcontext = new(sync.Map)
 var networkcontext = new(sync.Map)
 
 
@@ -38,63 +33,159 @@ type cachedMessage struct {
 	LastSeen time.Time
 	LastSeen time.Time
 }
 }
 
 
-func insert(network, which, cache string) {
-	var newMessage = cachedMessage{
-		Message:  cache,
-		LastSeen: time.Now(),
+// Daemon runs netclient daemon from command line
+func Daemon() error {
+	// == initial pull of all networks ==
+	networks, _ := ncutils.GetSystemNetworks()
+	for _, network := range networks {
+		var cfg config.ClientConfig
+		cfg.Network = network
+		cfg.ReadConfig()
+		initialPull(cfg.Network)
 	}
 	}
-	messageCache.Store(fmt.Sprintf("%s%s", network, which), newMessage)
-}
 
 
-func read(network, which string) string {
-	val, isok := messageCache.Load(fmt.Sprintf("%s%s", network, which))
-	if isok {
-		var readMessage = val.(cachedMessage) // fetch current cached message
-		if readMessage.LastSeen.IsZero() {
-			return ""
-		}
-		if time.Now().After(readMessage.LastSeen.Add(time.Minute * 10)) { // check if message has been there over a minute
-			messageCache.Delete(fmt.Sprintf("%s%s", network, which)) // remove old message if expired
-			return ""
+	// == get all the comms networks on machine ==
+	commsNetworks, err := getCommsNetworks(networks[:])
+	if err != nil {
+		return errors.New("no comm networks exist")
+	}
+
+	// == subscribe to all nodes on each comms network on machine ==
+	for currCommsNet := range commsNetworks {
+		ncutils.PrintLog("started comms network daemon, "+currCommsNet, 1)
+		ctx, cancel := context.WithCancel(context.Background())
+		networkcontext.Store(currCommsNet, cancel)
+		go messageQueue(ctx, currCommsNet)
+	}
+
+	// == add waitgroup and cancel for checkin routine ==
+	wg := sync.WaitGroup{}
+	ctx, cancel := context.WithCancel(context.Background())
+	wg.Add(1)
+	go Checkin(ctx, &wg, commsNetworks)
+	quit := make(chan os.Signal, 1)
+	signal.Notify(quit, syscall.SIGTERM, os.Interrupt, os.Kill)
+	<-quit
+	for currCommsNet := range commsNetworks {
+		if cancel, ok := networkcontext.Load(currCommsNet); ok {
+			cancel.(context.CancelFunc)()
 		}
 		}
-		return readMessage.Message // return current message if not expired
 	}
 	}
-	return ""
+	cancel()
+	ncutils.Log("shutting down netclient daemon")
+	wg.Wait()
+	ncutils.Log("shutdown complete")
+	return nil
 }
 }
 
 
-// == End Message Caches ==
+// UpdateKeys -- updates private key and returns new publickey
+func UpdateKeys(nodeCfg *config.ClientConfig, client mqtt.Client) error {
+	ncutils.Log("received message to update wireguard keys for network " + nodeCfg.Network)
+	key, err := wgtypes.GeneratePrivateKey()
+	if err != nil {
+		ncutils.Log("error generating privatekey " + err.Error())
+		return err
+	}
+	file := ncutils.GetNetclientPathSpecific() + nodeCfg.Node.Interface + ".conf"
+	if err := wireguard.UpdatePrivateKey(file, key.String()); err != nil {
+		ncutils.Log("error updating wireguard key " + err.Error())
+		return err
+	}
+	if storeErr := wireguard.StorePrivKey(key.String(), nodeCfg.Network); storeErr != nil {
+		ncutils.Log("failed to save private key" + storeErr.Error())
+		return storeErr
+	}
 
 
-// Daemon runs netclient daemon from command line
-func Daemon() error {
-	networks, err := ncutils.GetSystemNetworks()
+	nodeCfg.Node.PublicKey = key.PublicKey().String()
+	var commsCfg = getCommsCfgByNode(&nodeCfg.Node)
+	PublishNodeUpdate(&commsCfg, nodeCfg)
+	return nil
+}
+
+// PingServer -- checks if server is reachable
+// use commsCfg only*
+func PingServer(commsCfg *config.ClientConfig) error {
+	node := getServerAddress(commsCfg)
+	pinger, err := ping.NewPinger(node)
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}
-	for _, network := range networks {
-		ctx, cancel := context.WithCancel(context.Background())
-		networkcontext.Store(network, cancel)
-		go MessageQueue(ctx, network)
+	pinger.Timeout = 2 * time.Second
+	pinger.Run()
+	stats := pinger.Statistics()
+	if stats.PacketLoss == 100 {
+		return errors.New("ping error")
 	}
 	}
-	quit := make(chan os.Signal, 1)
-	signal.Notify(quit, syscall.SIGTERM, os.Interrupt)
-	<-quit
-	for _, network := range networks {
-		if cancel, ok := networkcontext.Load(network); ok {
-			cancel.(context.CancelFunc)()
+	return nil
+}
+
+// == Private ==
+
+// sets MQ client subscriptions for a specific node config
+// should be called for each node belonging to a given comms network
+func setSubscriptions(client mqtt.Client, nodeCfg *config.ClientConfig) {
+	if nodeCfg.DebugOn {
+		if token := client.Subscribe("#", 0, nil); token.Wait() && token.Error() != nil {
+			ncutils.Log(token.Error().Error())
+			return
 		}
 		}
+		ncutils.Log("subscribed to all topics for debugging purposes")
 	}
 	}
-	ncutils.Log("all done")
-	return nil
 
 
+	if token := client.Subscribe(fmt.Sprintf("update/%s/%s", nodeCfg.Node.Network, nodeCfg.Node.ID), 0, mqtt.MessageHandler(NodeUpdate)); token.Wait() && token.Error() != nil {
+		ncutils.Log(token.Error().Error())
+		return
+	}
+	if nodeCfg.DebugOn {
+		ncutils.Log(fmt.Sprintf("subscribed to node updates for node %s update/%s/%s", nodeCfg.Node.Name, nodeCfg.Node.Network, nodeCfg.Node.ID))
+	}
+	if token := client.Subscribe(fmt.Sprintf("peers/%s/%s", nodeCfg.Node.Network, nodeCfg.Node.ID), 0, mqtt.MessageHandler(UpdatePeers)); token.Wait() && token.Error() != nil {
+		ncutils.Log(token.Error().Error())
+		return
+	}
+	if nodeCfg.DebugOn {
+		ncutils.Log(fmt.Sprintf("subscribed to peer updates for node %s peers/%s/%s", nodeCfg.Node.Name, nodeCfg.Node.Network, nodeCfg.Node.ID))
+	}
 }
 }
 
 
-// SetupMQTT creates a connection to broker and return client
-func SetupMQTT(cfg *config.ClientConfig, publish bool) mqtt.Client {
+// on a delete usually, pass in the nodecfg to unsubscribe client broker communications
+// for the node in nodeCfg
+func unsubscribeNode(client mqtt.Client, nodeCfg *config.ClientConfig) {
+	client.Unsubscribe(fmt.Sprintf("update/%s/%s", nodeCfg.Node.Network, nodeCfg.Node.ID))
+	var ok = true
+	if token := client.Unsubscribe(fmt.Sprintf("update/%s/%s", nodeCfg.Node.Network, nodeCfg.Node.ID)); token.Wait() && token.Error() != nil {
+		ncutils.PrintLog("unable to unsubscribe from updates for node "+nodeCfg.Node.Name+"\n"+token.Error().Error(), 1)
+		ok = false
+	}
+	if token := client.Unsubscribe(fmt.Sprintf("peers/%s/%s", nodeCfg.Node.Network, nodeCfg.Node.ID)); token.Wait() && token.Error() != nil {
+		ncutils.PrintLog("unable to unsubscribe from peer updates for node "+nodeCfg.Node.Name+"\n"+token.Error().Error(), 1)
+		ok = false
+	}
+	if ok {
+		ncutils.PrintLog("successfully unsubscribed node "+nodeCfg.Node.ID+" : "+nodeCfg.Node.Name, 0)
+	}
+}
+
+// sets up Message Queue and subsribes/publishes updates to/from server
+// the client should subscribe to ALL nodes that exist on unique comms network locally
+func messageQueue(ctx context.Context, commsNet string) {
+	var commsCfg config.ClientConfig
+	commsCfg.Network = commsNet
+	commsCfg.ReadConfig()
+	ncutils.Log("netclient daemon started for network: " + commsNet)
+	client := setupMQTT(&commsCfg, false)
+	defer client.Disconnect(250)
+	<-ctx.Done()
+	ncutils.Log("shutting down daemon for comms network " + commsNet)
+}
+
+// setupMQTT creates a connection to broker and return client
+// utilizes comms client configs to setup connections
+func setupMQTT(commsCfg *config.ClientConfig, publish bool) mqtt.Client {
 	opts := mqtt.NewClientOptions()
 	opts := mqtt.NewClientOptions()
-	server := getServerAddress(cfg)
-	opts.AddBroker(server + ":1883")
-	id := ncutils.MakeRandomString(23)
-	opts.ClientID = id
+	server := getServerAddress(commsCfg)
+	opts.AddBroker(server + ":1883")             // TODO get the appropriate port of the comms mq server
+	opts.ClientID = ncutils.MakeRandomString(23) // helps avoid id duplication on broker
 	opts.SetDefaultPublishHandler(All)
 	opts.SetDefaultPublishHandler(All)
 	opts.SetAutoReconnect(true)
 	opts.SetAutoReconnect(true)
 	opts.SetConnectRetry(true)
 	opts.SetConnectRetry(true)
@@ -103,43 +194,26 @@ func SetupMQTT(cfg *config.ClientConfig, publish bool) mqtt.Client {
 	opts.SetWriteTimeout(time.Minute)
 	opts.SetWriteTimeout(time.Minute)
 	opts.SetOnConnectHandler(func(client mqtt.Client) {
 	opts.SetOnConnectHandler(func(client mqtt.Client) {
 		if !publish {
 		if !publish {
-			if cfg.DebugOn {
-				if token := client.Subscribe("#", 0, nil); token.Wait() && token.Error() != nil {
-					ncutils.Log(token.Error().Error())
-					return
-				}
-				ncutils.Log("subscribed to all topics for debugging purposes")
-			}
-			if token := client.Subscribe(fmt.Sprintf("update/%s/%s", cfg.Node.Network, cfg.Node.ID), 0, mqtt.MessageHandler(NodeUpdate)); token.Wait() && token.Error() != nil {
-				ncutils.Log(token.Error().Error())
-				return
-			}
-			if cfg.DebugOn {
-				ncutils.Log(fmt.Sprintf("subscribed to node updates for node %s update/%s/%s", cfg.Node.Name, cfg.Node.Network, cfg.Node.ID))
-			}
-			if token := client.Subscribe(fmt.Sprintf("peers/%s/%s", cfg.Node.Network, cfg.Node.ID), 0, mqtt.MessageHandler(UpdatePeers)); token.Wait() && token.Error() != nil {
-				ncutils.Log(token.Error().Error())
-				return
+			networks, err := ncutils.GetSystemNetworks()
+			if err != nil {
+				ncutils.Log("error retriving networks " + err.Error())
 			}
 			}
-			if cfg.DebugOn {
-				ncutils.Log(fmt.Sprintf("subscribed to peer updates for node %s peers/%s/%s", cfg.Node.Name, cfg.Node.Network, cfg.Node.ID))
+			for _, network := range networks {
+				var currNodeCfg config.ClientConfig
+				currNodeCfg.Network = network
+				currNodeCfg.ReadConfig()
+				setSubscriptions(client, &currNodeCfg)
 			}
 			}
-			opts.SetOrderMatters(true)
-			opts.SetResumeSubs(true)
 		}
 		}
 	})
 	})
+	opts.SetOrderMatters(true)
+	opts.SetResumeSubs(true)
 	opts.SetConnectionLostHandler(func(c mqtt.Client, e error) {
 	opts.SetConnectionLostHandler(func(c mqtt.Client, e error) {
-		ncutils.Log("detected broker connection lost, running pull for " + cfg.Node.Network)
-		_, err := Pull(cfg.Node.Network, true)
+		ncutils.Log("detected broker connection lost, running pull for " + commsCfg.Node.Network)
+		_, err := Pull(commsCfg.Node.Network, true)
 		if err != nil {
 		if err != nil {
 			ncutils.Log("could not run pull, server unreachable: " + err.Error())
 			ncutils.Log("could not run pull, server unreachable: " + err.Error())
 			ncutils.Log("waiting to retry...")
 			ncutils.Log("waiting to retry...")
-			/*
-				//Consider putting in logic to restart - daemon may take long time to refresh
-				time.Sleep(time.Minute * 5)
-					ncutils.Log("restarting netclient")
-					daemon.Restart()
-			*/
 		}
 		}
 		ncutils.Log("connection re-established with mqtt server")
 		ncutils.Log("connection re-established with mqtt server")
 	})
 	})
@@ -149,10 +223,10 @@ func SetupMQTT(cfg *config.ClientConfig, publish bool) mqtt.Client {
 	for {
 	for {
 		//if after 12 seconds, try a gRPC pull on the last try
 		//if after 12 seconds, try a gRPC pull on the last try
 		if time.Now().After(tperiod) {
 		if time.Now().After(tperiod) {
-			ncutils.Log("running pull for " + cfg.Node.Network)
-			_, err := Pull(cfg.Node.Network, true)
+			ncutils.Log("running pull for " + commsCfg.Node.Network)
+			_, err := Pull(commsCfg.Node.Network, true)
 			if err != nil {
 			if err != nil {
-				ncutils.Log("could not run pull, exiting " + cfg.Node.Network + " setup: " + err.Error())
+				ncutils.Log("could not run pull, exiting " + commsCfg.Node.Network + " setup: " + err.Error())
 				return client
 				return client
 			}
 			}
 			time.Sleep(time.Second)
 			time.Sleep(time.Second)
@@ -160,10 +234,10 @@ func SetupMQTT(cfg *config.ClientConfig, publish bool) mqtt.Client {
 		if token := client.Connect(); token.Wait() && token.Error() != nil {
 		if token := client.Connect(); token.Wait() && token.Error() != nil {
 			ncutils.Log("unable to connect to broker, retrying ...")
 			ncutils.Log("unable to connect to broker, retrying ...")
 			if time.Now().After(tperiod) {
 			if time.Now().After(tperiod) {
-				ncutils.Log("could not connect to broker, exiting " + cfg.Node.Network + " setup: " + token.Error().Error())
+				ncutils.Log("could not connect to broker, exiting " + commsCfg.Node.Network + " setup: " + token.Error().Error())
 				if strings.Contains(token.Error().Error(), "connectex") || strings.Contains(token.Error().Error(), "i/o timeout") {
 				if strings.Contains(token.Error().Error(), "connectex") || strings.Contains(token.Error().Error(), "i/o timeout") {
 					ncutils.PrintLog("connection issue detected.. pulling and restarting daemon", 0)
 					ncutils.PrintLog("connection issue detected.. pulling and restarting daemon", 0)
-					Pull(cfg.Node.Network, true)
+					Pull(commsCfg.Node.Network, true)
 					daemon.Restart()
 					daemon.Restart()
 				}
 				}
 				return client
 				return client
@@ -176,341 +250,14 @@ func SetupMQTT(cfg *config.ClientConfig, publish bool) mqtt.Client {
 	return client
 	return client
 }
 }
 
 
-// MessageQueue sets up Message Queue and subsribes/publishes updates to/from server
-func MessageQueue(ctx context.Context, network string) {
-	ncutils.Log("netclient go routine started for " + network)
-	var cfg config.ClientConfig
-	cfg.Network = network
-	initialPull(cfg.Network)
-
-	cfg.ReadConfig()
-	ncutils.Log("daemon started for network: " + network)
-	client := SetupMQTT(&cfg, false)
-
-	defer client.Disconnect(250)
-	wg := &sync.WaitGroup{}
-	wg.Add(2)
-	checkinctx, checkincancel := context.WithCancel(context.Background())
-	go Checkin(checkinctx, wg, &cfg, network)
-	<-ctx.Done()
-	checkincancel()
-	ncutils.Log("shutting down message queue for network " + network)
-	wg.Wait()
-	ncutils.Log("shutdown complete")
-}
-
-// All -- mqtt message hander for all ('#') topics
-var All mqtt.MessageHandler = func(client mqtt.Client, msg mqtt.Message) {
-	ncutils.Log("default message handler -- received message but not handling")
-	ncutils.Log("Topic: " + string(msg.Topic()))
-	//ncutils.Log("Message: " + string(msg.Payload()))
-}
-
-// NodeUpdate -- mqtt message handler for /update/<NodeID> topic
-func NodeUpdate(client mqtt.Client, msg mqtt.Message) {
-	var newNode models.Node
-	var cfg config.ClientConfig
-	var network = parseNetworkFromTopic(msg.Topic())
-	cfg.Network = network
-	cfg.ReadConfig()
-
-	data, dataErr := decryptMsg(&cfg, msg.Payload())
-	if dataErr != nil {
-		return
-	}
-	err := json.Unmarshal([]byte(data), &newNode)
-	if err != nil {
-		ncutils.Log("error unmarshalling node update data" + err.Error())
-		return
-	}
-
-	ncutils.Log("received message to update node " + newNode.Name)
-	// see if cache hit, if so skip
-	var currentMessage = read(newNode.Network, lastNodeUpdate)
-	if currentMessage == string(data) {
-		return
-	}
-	insert(newNode.Network, lastNodeUpdate, string(data)) // store new message in cache
-
-	//check if interface name has changed if so delete.
-	if cfg.Node.Interface != newNode.Interface {
-		if err = wireguard.RemoveConf(cfg.Node.Interface, true); err != nil {
-			ncutils.PrintLog("could not delete old interface "+cfg.Node.Interface+": "+err.Error(), 1)
-		}
-	}
-	newNode.PullChanges = "no"
-	//ensure that OS never changes
-	newNode.OS = runtime.GOOS
-	// check if interface needs to delta
-	ifaceDelta := ncutils.IfaceDelta(&cfg.Node, &newNode)
-	shouldDNSChange := cfg.Node.DNSOn != newNode.DNSOn
-
-	cfg.Node = newNode
-	switch newNode.Action {
-	case models.NODE_DELETE:
-		if cancel, ok := networkcontext.Load(newNode.Network); ok {
-			ncutils.Log("cancelling message queue context for " + newNode.Network)
-			cancel.(context.CancelFunc)()
-		} else {
-			ncutils.Log("failed to kill go routines for network " + newNode.Network)
-		}
-		ncutils.PrintLog(fmt.Sprintf("received delete request for %s", cfg.Node.Name), 1)
-		if err = LeaveNetwork(cfg.Node.Network); err != nil {
-			if !strings.Contains("rpc error", err.Error()) {
-				ncutils.PrintLog(fmt.Sprintf("failed to leave, please check that local files for network %s were removed", cfg.Node.Network), 1)
-			}
-			ncutils.PrintLog(fmt.Sprintf("%s was removed", cfg.Node.Name), 1)
-			return
-		}
-		ncutils.PrintLog(fmt.Sprintf("%s was removed", cfg.Node.Name), 1)
-		return
-	case models.NODE_UPDATE_KEY:
-		if err := UpdateKeys(&cfg, client); err != nil {
-			ncutils.PrintLog("err updating wireguard keys: "+err.Error(), 1)
-		}
-	case models.NODE_NOOP:
-	default:
-	}
-	// Save new config
-	cfg.Node.Action = models.NODE_NOOP
-	if err := config.Write(&cfg, cfg.Network); err != nil {
-		ncutils.PrintLog("error updating node configuration: "+err.Error(), 1)
-	}
-	nameserver := cfg.Server.CoreDNSAddr
-	privateKey, err := wireguard.RetrievePrivKey(newNode.Network)
-	if err != nil {
-		ncutils.Log("error reading PrivateKey " + err.Error())
-		return
-	}
-	file := ncutils.GetNetclientPathSpecific() + cfg.Node.Interface + ".conf"
-	if err := wireguard.UpdateWgInterface(file, privateKey, nameserver, newNode); err != nil {
-		ncutils.Log("error updating wireguard config " + err.Error())
-		return
-	}
-	if ifaceDelta {
-		ncutils.Log("applying WG conf to " + file)
-		err = wireguard.ApplyConf(&cfg.Node, cfg.Node.Interface, file)
-		if err != nil {
-			ncutils.Log("error restarting wg after node update " + err.Error())
-			return
-		}
-		time.Sleep(time.Second >> 1)
-		// if err = Resubscribe(client, &cfg); err != nil {
-		// 	ncutils.Log("error resubscribing after interface change " + err.Error())
-		// 	return
-		// }
-		if newNode.DNSOn == "yes" {
-			for _, server := range newNode.NetworkSettings.DefaultServerAddrs {
-				if server.IsLeader {
-					go local.SetDNSWithRetry(newNode, server.Address)
-					break
-				}
-			}
-		}
-	}
-	//deal with DNS
-	if newNode.DNSOn != "yes" && shouldDNSChange && cfg.Node.Interface != "" {
-		ncutils.Log("settng DNS off")
-		_, err := ncutils.RunCmd("/usr/bin/resolvectl revert "+cfg.Node.Interface, true)
-		if err != nil {
-			ncutils.Log("error applying dns" + err.Error())
-		}
-	}
-}
-
-// UpdatePeers -- mqtt message handler for peers/<Network>/<NodeID> topic
-func UpdatePeers(client mqtt.Client, msg mqtt.Message) {
-	var peerUpdate models.PeerUpdate
-	var network = parseNetworkFromTopic(msg.Topic())
-	var cfg = config.ClientConfig{}
-	cfg.Network = network
-	cfg.ReadConfig()
-
-	data, dataErr := decryptMsg(&cfg, msg.Payload())
-	if dataErr != nil {
-		return
-	}
-	err := json.Unmarshal([]byte(data), &peerUpdate)
-	if err != nil {
-		ncutils.Log("error unmarshalling peer data")
-		return
-	}
-	// see if cached hit, if so skip
-	var currentMessage = read(peerUpdate.Network, lastPeerUpdate)
-	if currentMessage == string(data) {
-		return
-	}
-	insert(peerUpdate.Network, lastPeerUpdate, string(data))
-
-	file := ncutils.GetNetclientPathSpecific() + cfg.Node.Interface + ".conf"
-	err = wireguard.UpdateWgPeers(file, peerUpdate.Peers)
-	if err != nil {
-		ncutils.Log("error updating wireguard peers" + err.Error())
-		return
-	}
-	//err = wireguard.SyncWGQuickConf(cfg.Node.Interface, file)
-	var iface = cfg.Node.Interface
-	if ncutils.IsMac() {
-		iface, err = local.GetMacIface(cfg.Node.Address)
-		if err != nil {
-			ncutils.Log("error retrieving mac iface: " + err.Error())
-			return
-		}
-	}
-	err = wireguard.SetPeers(iface, cfg.Node.Address, cfg.Node.PersistentKeepalive, peerUpdate.Peers)
-	if err != nil {
-		ncutils.Log("error syncing wg after peer update: " + err.Error())
-		return
-	}
-}
-
-// MonitorKeepalive - checks time last server keepalive received.  If more than 3+ minutes, notify and resubscribe
-// func MonitorKeepalive(ctx context.Context, wg *sync.WaitGroup, client mqtt.Client, cfg *config.ClientConfig) {
-// 	defer wg.Done()
-// 	for {
-// 		select {
-// 		case <-ctx.Done():
-// 			ncutils.Log("cancel recieved, monitor keepalive exiting")
-// 			return
-// 		case <-time.After(time.Second * 150):
-// 			var keepalivetime time.Time
-// 			keepaliveval, ok := keepalive.Load(cfg.Node.Network)
-// 			if ok {
-// 				keepalivetime = keepaliveval.(time.Time)
-// 				if !keepalivetime.IsZero() && time.Since(keepalivetime) > time.Second*120 { // more than 2+ minutes
-// 					// ncutils.Log("server keepalive not recieved recently, resubscribe to message queue")
-// 					// err := Resubscribe(client, cfg)
-// 					// if err != nil {
-// 					// 	ncutils.Log("closing " + err.Error())
-// 					// }
-// 					ncutils.Log("maybe wanna call something")
-// 				}
-// 			}
-// 		}
-// 	}
-// }
-
-// ServerKeepAlive -- handler to react to keepalive messages published by server
-// func ServerKeepAlive(client mqtt.Client, msg mqtt.Message) {
-// 	var currentTime = time.Now()
-// 	keepalive.Store(parseNetworkFromTopic(msg.Topic()), currentTime)
-// 	ncutils.PrintLog("received server keepalive at "+currentTime.String(), 2)
-// }
-
-// UpdateKeys -- updates private key and returns new publickey
-func UpdateKeys(cfg *config.ClientConfig, client mqtt.Client) error {
-	ncutils.Log("received message to update keys")
-	key, err := wgtypes.GeneratePrivateKey()
-	if err != nil {
-		ncutils.Log("error generating privatekey " + err.Error())
-		return err
-	}
-	file := ncutils.GetNetclientPathSpecific() + cfg.Node.Interface + ".conf"
-	if err := wireguard.UpdatePrivateKey(file, key.String()); err != nil {
-		ncutils.Log("error updating wireguard key " + err.Error())
-		return err
-	}
-	cfg.Node.PublicKey = key.PublicKey().String()
-	if err := config.ModConfig(&cfg.Node); err != nil {
-		ncutils.Log("error updating local config " + err.Error())
-	}
-	PublishNodeUpdate(cfg)
-	if err = wireguard.ApplyConf(&cfg.Node, cfg.Node.Interface, file); err != nil {
-		ncutils.Log("error applying new config " + err.Error())
-		return err
-	}
-	return nil
-}
-
-// Checkin  -- go routine that checks for public or local ip changes, publishes changes
-//   if there are no updates, simply "pings" the server as a checkin
-func Checkin(ctx context.Context, wg *sync.WaitGroup, cfg *config.ClientConfig, network string) {
-	defer wg.Done()
-	for {
-		select {
-		case <-ctx.Done():
-			ncutils.Log("Checkin cancelled")
-			return
-			//delay should be configuraable -> use cfg.Node.NetworkSettings.DefaultCheckInInterval ??
-		case <-time.After(time.Second * 60):
-			// ncutils.Log("Checkin running")
-			//read latest config
-			cfg.ReadConfig()
-			if cfg.Node.Roaming == "yes" && cfg.Node.IsStatic != "yes" {
-				extIP, err := ncutils.GetPublicIP()
-				if err != nil {
-					ncutils.PrintLog("error encountered checking ip addresses: "+err.Error(), 1)
-				}
-				if cfg.Node.Endpoint != extIP && extIP != "" {
-					ncutils.PrintLog("endpoint has changed from "+cfg.Node.Endpoint+" to "+extIP, 1)
-					cfg.Node.Endpoint = extIP
-					if err := PublishNodeUpdate(cfg); err != nil {
-						ncutils.Log("could not publish endpoint change")
-					}
-				}
-				intIP, err := getPrivateAddr()
-				if err != nil {
-					ncutils.PrintLog("error encountered checking ip addresses: "+err.Error(), 1)
-				}
-				if cfg.Node.LocalAddress != intIP && intIP != "" {
-					ncutils.PrintLog("local Address has changed from "+cfg.Node.LocalAddress+" to "+intIP, 1)
-					cfg.Node.LocalAddress = intIP
-					if err := PublishNodeUpdate(cfg); err != nil {
-						ncutils.Log("could not publish local address change")
-					}
-				}
-			} else {
-				localIP, err := ncutils.GetLocalIP(cfg.Node.LocalRange)
-				if err != nil {
-					ncutils.PrintLog("error encountered checking ip addresses: "+err.Error(), 1)
-				}
-				if cfg.Node.Endpoint != localIP && localIP != "" {
-					ncutils.PrintLog("endpoint has changed from "+cfg.Node.Endpoint+" to "+localIP, 1)
-					cfg.Node.Endpoint = localIP
-					if err := PublishNodeUpdate(cfg); err != nil {
-						ncutils.Log("could not publish localip change")
-					}
-				}
-			}
-			if err := pingServer(cfg); err != nil {
-				ncutils.PrintLog("could not ping server "+err.Error(), 0)
-			}
-			Hello(cfg, network)
-			// ncutils.Log("Checkin complete")
-		}
-	}
-}
-
-// PublishNodeUpdates -- saves node and pushes changes to broker
-func PublishNodeUpdate(cfg *config.ClientConfig) error {
-	if err := config.Write(cfg, cfg.Network); err != nil {
-		return err
-	}
-	data, err := json.Marshal(cfg.Node)
-	if err != nil {
-		return err
-	}
-	if err = publish(cfg, fmt.Sprintf("update/%s", cfg.Node.ID), data); err != nil {
+// publishes a message to server to update peers on this peer's behalf
+func publishSignal(commsCfg, nodeCfg *config.ClientConfig, signal byte) error {
+	if err := publish(commsCfg, nodeCfg, fmt.Sprintf("signal/%s", nodeCfg.Node.ID), []byte{signal}, 1); err != nil {
 		return err
 		return err
 	}
 	}
 	return nil
 	return nil
 }
 }
 
 
-// Hello -- ping the broker to let server know node is alive and doing fine
-func Hello(cfg *config.ClientConfig, network string) {
-	if err := publish(cfg, fmt.Sprintf("ping/%s", cfg.Node.ID), []byte(ncutils.Version)); err != nil {
-		ncutils.Log(fmt.Sprintf("error publishing ping, %v", err))
-		ncutils.Log("running pull on " + cfg.Node.Network + " to reconnect")
-		_, err := Pull(cfg.Node.Network, true)
-		if err != nil {
-			ncutils.Log("could not run pull on " + cfg.Node.Network + ", error: " + err.Error())
-		}
-
-	}
-}
-
-// == Private ==
-
 func initialPull(network string) {
 func initialPull(network string) {
 	ncutils.Log("pulling latest config for " + network)
 	ncutils.Log("pulling latest config for " + network)
 	var configPath = fmt.Sprintf("%snetconfig-%s", ncutils.GetNetclientPathSpecific(), network)
 	var configPath = fmt.Sprintf("%snetconfig-%s", ncutils.GetNetclientPathSpecific(), network)
@@ -539,67 +286,28 @@ func initialPull(network string) {
 	}
 	}
 }
 }
 
 
-func publish(cfg *config.ClientConfig, dest string, msg []byte) error {
-	// setup the keys
-	trafficPrivKey, err := auth.RetrieveTrafficKey(cfg.Node.Network)
-	if err != nil {
-		return err
-	}
-
-	serverPubKey, err := ncutils.ConvertBytesToKey(cfg.Node.TrafficKeys.Server)
-	if err != nil {
-		return err
-	}
-
-	client := SetupMQTT(cfg, true)
-	defer client.Disconnect(250)
-	encrypted, err := ncutils.BoxEncrypt(msg, serverPubKey, trafficPrivKey)
-	if err != nil {
-		return err
-	}
-
-	if token := client.Publish(dest, 0, false, encrypted); token.Wait() && token.Error() != nil {
-		return token.Error()
-	}
-	return nil
-}
-
 func parseNetworkFromTopic(topic string) string {
 func parseNetworkFromTopic(topic string) string {
 	return strings.Split(topic, "/")[1]
 	return strings.Split(topic, "/")[1]
 }
 }
 
 
-func decryptMsg(cfg *config.ClientConfig, msg []byte) ([]byte, error) {
+// should only ever use node client configs
+func decryptMsg(nodeCfg *config.ClientConfig, msg []byte) ([]byte, error) {
 	if len(msg) <= 24 { // make sure message is of appropriate length
 	if len(msg) <= 24 { // make sure message is of appropriate length
-		return nil, fmt.Errorf("recieved invalid message from broker %s", string(msg))
+		return nil, fmt.Errorf("recieved invalid message from broker %v", msg)
 	}
 	}
 
 
 	// setup the keys
 	// setup the keys
-	diskKey, keyErr := auth.RetrieveTrafficKey(cfg.Node.Network)
+	diskKey, keyErr := auth.RetrieveTrafficKey(nodeCfg.Node.Network)
 	if keyErr != nil {
 	if keyErr != nil {
 		return nil, keyErr
 		return nil, keyErr
 	}
 	}
 
 
-	serverPubKey, err := ncutils.ConvertBytesToKey(cfg.Node.TrafficKeys.Server)
+	serverPubKey, err := ncutils.ConvertBytesToKey(nodeCfg.Node.TrafficKeys.Server)
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
 
 
-	return ncutils.BoxDecrypt(msg, serverPubKey, diskKey)
-}
-
-func pingServer(cfg *config.ClientConfig) error {
-	node := getServerAddress(cfg)
-	pinger, err := ping.NewPinger(node)
-	if err != nil {
-		return err
-	}
-	pinger.Timeout = 2 * time.Second
-	pinger.Run()
-	stats := pinger.Statistics()
-	if stats.PacketLoss == 100 {
-		return errors.New("ping error")
-	}
-	return nil
+	return ncutils.DeChunk(msg, serverPubKey, diskKey)
 }
 }
 
 
 func getServerAddress(cfg *config.ClientConfig) string {
 func getServerAddress(cfg *config.ClientConfig) string {
@@ -611,3 +319,49 @@ func getServerAddress(cfg *config.ClientConfig) string {
 	}
 	}
 	return server.Address
 	return server.Address
 }
 }
+
+func getCommsNetworks(networks []string) (map[string]bool, error) {
+	var cfg config.ClientConfig
+	var response = make(map[string]bool, 1)
+	for _, network := range networks {
+		cfg.Network = network
+		cfg.ReadConfig()
+		response[cfg.Node.CommID] = true
+	}
+	return response, nil
+}
+
+func getCommsCfgByNode(node *models.Node) config.ClientConfig {
+	var commsCfg config.ClientConfig
+	commsCfg.Network = node.Network
+	commsCfg.ReadConfig()
+	return commsCfg
+}
+
+// == Message Caches ==
+
+func insert(network, which, cache string) {
+	var newMessage = cachedMessage{
+		Message:  cache,
+		LastSeen: time.Now(),
+	}
+	messageCache.Store(fmt.Sprintf("%s%s", network, which), newMessage)
+}
+
+func read(network, which string) string {
+	val, isok := messageCache.Load(fmt.Sprintf("%s%s", network, which))
+	if isok {
+		var readMessage = val.(cachedMessage) // fetch current cached message
+		if readMessage.LastSeen.IsZero() {
+			return ""
+		}
+		if time.Now().After(readMessage.LastSeen.Add(time.Minute * 10)) { // check if message has been there over a minute
+			messageCache.Delete(fmt.Sprintf("%s%s", network, which)) // remove old message if expired
+			return ""
+		}
+		return readMessage.Message // return current message if not expired
+	}
+	return ""
+}
+
+// == End Message Caches ==

+ 23 - 20
netclient/functions/join.go

@@ -25,7 +25,7 @@ import (
 )
 )
 
 
 // JoinNetwork - helps a client join a network
 // JoinNetwork - helps a client join a network
-func JoinNetwork(cfg config.ClientConfig, privateKey string) error {
+func JoinNetwork(cfg config.ClientConfig, privateKey string, iscomms bool) error {
 	if cfg.Node.Network == "" {
 	if cfg.Node.Network == "" {
 		return errors.New("no network provided")
 		return errors.New("no network provided")
 	}
 	}
@@ -103,7 +103,8 @@ func JoinNetwork(cfg config.ClientConfig, privateKey string) error {
 	if cfg.Node.MacAddress == "" {
 	if cfg.Node.MacAddress == "" {
 		macs, err := ncutils.GetMacAddr()
 		macs, err := ncutils.GetMacAddr()
 		if err != nil {
 		if err != nil {
-			return err
+			//if macaddress can't be found set to random string
+			cfg.Node.MacAddress = ncutils.MakeRandomString(18)
 		} else {
 		} else {
 			cfg.Node.MacAddress = macs[0]
 			cfg.Node.MacAddress = macs[0]
 		}
 		}
@@ -124,14 +125,14 @@ func JoinNetwork(cfg config.ClientConfig, privateKey string) error {
 	cfg.Node.Name = formatName(cfg.Node)
 	cfg.Node.Name = formatName(cfg.Node)
 	// differentiate between client/server here
 	// differentiate between client/server here
 	var node = models.Node{
 	var node = models.Node{
-		Password:            cfg.Node.Password,
-		Address:             cfg.Node.Address,
-		Address6:            cfg.Node.Address6,
-		ID:                  cfg.Node.ID,
-		MacAddress:          cfg.Node.MacAddress,
-		AccessKey:           cfg.Server.AccessKey,
-		IsStatic:            cfg.Node.IsStatic,
-		Roaming:             cfg.Node.Roaming,
+		Password:   cfg.Node.Password,
+		Address:    cfg.Node.Address,
+		Address6:   cfg.Node.Address6,
+		ID:         cfg.Node.ID,
+		MacAddress: cfg.Node.MacAddress,
+		AccessKey:  cfg.Server.AccessKey,
+		IsStatic:   cfg.Node.IsStatic,
+		//Roaming:             cfg.Node.Roaming,
 		Network:             cfg.Network,
 		Network:             cfg.Network,
 		ListenPort:          cfg.Node.ListenPort,
 		ListenPort:          cfg.Node.ListenPort,
 		PostUp:              cfg.Node.PostUp,
 		PostUp:              cfg.Node.PostUp,
@@ -143,7 +144,6 @@ func JoinNetwork(cfg config.ClientConfig, privateKey string) error {
 		DNSOn:               cfg.Node.DNSOn,
 		DNSOn:               cfg.Node.DNSOn,
 		Name:                cfg.Node.Name,
 		Name:                cfg.Node.Name,
 		Endpoint:            cfg.Node.Endpoint,
 		Endpoint:            cfg.Node.Endpoint,
-		SaveConfig:          cfg.Node.SaveConfig,
 		UDPHolePunch:        cfg.Node.UDPHolePunch,
 		UDPHolePunch:        cfg.Node.UDPHolePunch,
 		TrafficKeys:         cfg.Node.TrafficKeys,
 		TrafficKeys:         cfg.Node.TrafficKeys,
 		OS:                  runtime.GOOS,
 		OS:                  runtime.GOOS,
@@ -242,7 +242,8 @@ func JoinNetwork(cfg config.ClientConfig, privateKey string) error {
 				go func() {
 				go func() {
 					if !local.SetDNSWithRetry(node, server.Address) {
 					if !local.SetDNSWithRetry(node, server.Address) {
 						cfg.Node.DNSOn = "no"
 						cfg.Node.DNSOn = "no"
-						PublishNodeUpdate(&cfg)
+						var currentCommsCfg = getCommsCfgByNode(&cfg.Node)
+						PublishNodeUpdate(&currentCommsCfg, &cfg)
 					}
 					}
 				}()
 				}()
 				break
 				break
@@ -250,16 +251,18 @@ func JoinNetwork(cfg config.ClientConfig, privateKey string) error {
 		}
 		}
 	}
 	}
 
 
-	if cfg.Daemon != "off" {
-		err = daemon.InstallDaemon(cfg)
-	}
-	if err != nil {
-		return err
-	} else {
-		daemon.Restart()
+	if !iscomms {
+		if cfg.Daemon != "off" {
+			err = daemon.InstallDaemon(cfg)
+		}
+		if err != nil {
+			return err
+		} else {
+			daemon.Restart()
+		}
 	}
 	}
 
 
-	return err
+	return nil
 }
 }
 
 
 // format name appropriately. Set to blank on failure
 // format name appropriately. Set to blank on failure

+ 192 - 0
netclient/functions/mqhandlers.go

@@ -0,0 +1,192 @@
+package functions
+
+import (
+	"encoding/json"
+	"fmt"
+	"runtime"
+	"strings"
+	"time"
+
+	mqtt "github.com/eclipse/paho.mqtt.golang"
+	"github.com/gravitl/netmaker/models"
+	"github.com/gravitl/netmaker/netclient/config"
+	"github.com/gravitl/netmaker/netclient/local"
+	"github.com/gravitl/netmaker/netclient/ncutils"
+	"github.com/gravitl/netmaker/netclient/wireguard"
+	"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
+)
+
+// All -- mqtt message hander for all ('#') topics
+var All mqtt.MessageHandler = func(client mqtt.Client, msg mqtt.Message) {
+	ncutils.Log("default message handler -- received message but not handling")
+	ncutils.Log("Topic: " + string(msg.Topic()))
+	//ncutils.Log("Message: " + string(msg.Payload()))
+}
+
+// NodeUpdate -- mqtt message handler for /update/<NodeID> topic
+func NodeUpdate(client mqtt.Client, msg mqtt.Message) {
+	var newNode models.Node
+	var nodeCfg config.ClientConfig
+	var network = parseNetworkFromTopic(msg.Topic())
+	nodeCfg.Network = network
+	nodeCfg.ReadConfig()
+	var commsCfg = getCommsCfgByNode(&nodeCfg.Node)
+
+	data, dataErr := decryptMsg(&nodeCfg, msg.Payload())
+	if dataErr != nil {
+		return
+	}
+	err := json.Unmarshal([]byte(data), &newNode)
+	if err != nil {
+		ncutils.Log("error unmarshalling node update data" + err.Error())
+		return
+	}
+
+	ncutils.Log("received message to update node " + newNode.Name)
+	// see if cache hit, if so skip
+	var currentMessage = read(newNode.Network, lastNodeUpdate)
+	if currentMessage == string(data) {
+		return
+	}
+	insert(newNode.Network, lastNodeUpdate, string(data)) // store new message in cache
+
+	// ensure that OS never changes
+	newNode.OS = runtime.GOOS
+	// check if interface needs to delta
+	ifaceDelta := ncutils.IfaceDelta(&nodeCfg.Node, &newNode)
+	shouldDNSChange := nodeCfg.Node.DNSOn != newNode.DNSOn
+	hubChange := nodeCfg.Node.IsHub != newNode.IsHub
+
+	nodeCfg.Node = newNode
+	switch newNode.Action {
+	case models.NODE_DELETE:
+		ncutils.PrintLog(fmt.Sprintf("received delete request for %s", nodeCfg.Node.Name), 0)
+		unsubscribeNode(client, &nodeCfg)
+		if err = LeaveNetwork(nodeCfg.Node.Network, true); err != nil {
+			if !strings.Contains("rpc error", err.Error()) {
+				ncutils.PrintLog(fmt.Sprintf("failed to leave, please check that local files for network %s were removed", nodeCfg.Node.Network), 0)
+				return
+			}
+		}
+		ncutils.PrintLog(fmt.Sprintf("%s was removed", nodeCfg.Node.Name), 0)
+		return
+	case models.NODE_UPDATE_KEY:
+		// == get the current key for node ==
+		oldPrivateKey, retErr := wireguard.RetrievePrivKey(nodeCfg.Network)
+		if retErr != nil {
+			break
+		}
+		if err := UpdateKeys(&nodeCfg, client); err != nil {
+			ncutils.PrintLog("err updating wireguard keys, reusing last key\n"+err.Error(), 0)
+			if key, parseErr := wgtypes.ParseKey(oldPrivateKey); parseErr == nil {
+				wireguard.StorePrivKey(key.String(), nodeCfg.Network)
+				nodeCfg.Node.PublicKey = key.PublicKey().String()
+			}
+		}
+		ifaceDelta = true
+	case models.NODE_NOOP:
+	default:
+	}
+	// Save new config
+	nodeCfg.Node.Action = models.NODE_NOOP
+	if err := config.Write(&nodeCfg, nodeCfg.Network); err != nil {
+		ncutils.PrintLog("error updating node configuration: "+err.Error(), 0)
+	}
+	nameserver := nodeCfg.Server.CoreDNSAddr
+	privateKey, err := wireguard.RetrievePrivKey(newNode.Network)
+	if err != nil {
+		ncutils.Log("error reading PrivateKey " + err.Error())
+		return
+	}
+	file := ncutils.GetNetclientPathSpecific() + nodeCfg.Node.Interface + ".conf"
+
+	if err := wireguard.UpdateWgInterface(file, privateKey, nameserver, newNode); err != nil {
+		ncutils.Log("error updating wireguard config " + err.Error())
+		return
+	}
+	if ifaceDelta { // if a change caused an ifacedelta we need to notify the server to update the peers
+		ncutils.Log("applying WG conf to " + file)
+		err = wireguard.ApplyConf(&nodeCfg.Node, nodeCfg.Node.Interface, file)
+		if err != nil {
+			ncutils.Log("error restarting wg after node update " + err.Error())
+			return
+		}
+
+		time.Sleep(time.Second >> 0)
+		if newNode.DNSOn == "yes" {
+			for _, server := range newNode.NetworkSettings.DefaultServerAddrs {
+				if server.IsLeader {
+					go local.SetDNSWithRetry(newNode, server.Address)
+					break
+				}
+			}
+		}
+		doneErr := publishSignal(&commsCfg, &nodeCfg, ncutils.DONE)
+		if doneErr != nil {
+			ncutils.Log("could not notify server to update peers after interface change")
+		} else {
+			ncutils.Log("signalled finished interface update to server")
+		}
+	} else if hubChange {
+		doneErr := publishSignal(&commsCfg, &nodeCfg, ncutils.DONE)
+		if doneErr != nil {
+			ncutils.Log("could not notify server to update peers after hub change")
+		} else {
+			ncutils.Log("signalled finished hub update to server")
+		}
+	}
+	//deal with DNS
+	if newNode.DNSOn != "yes" && shouldDNSChange && nodeCfg.Node.Interface != "" {
+		ncutils.Log("settng DNS off")
+		_, err := ncutils.RunCmd("/usr/bin/resolvectl revert "+nodeCfg.Node.Interface, true)
+		if err != nil {
+			ncutils.Log("error applying dns" + err.Error())
+		}
+	}
+}
+
+// UpdatePeers -- mqtt message handler for peers/<Network>/<NodeID> topic
+func UpdatePeers(client mqtt.Client, msg mqtt.Message) {
+	var peerUpdate models.PeerUpdate
+	var network = parseNetworkFromTopic(msg.Topic())
+	var cfg = config.ClientConfig{}
+	cfg.Network = network
+	cfg.ReadConfig()
+
+	data, dataErr := decryptMsg(&cfg, msg.Payload())
+	if dataErr != nil {
+		return
+	}
+	err := json.Unmarshal([]byte(data), &peerUpdate)
+	if err != nil {
+		ncutils.Log("error unmarshalling peer data")
+		return
+	}
+	// see if cached hit, if so skip
+	var currentMessage = read(peerUpdate.Network, lastPeerUpdate)
+	if currentMessage == string(data) {
+		return
+	}
+	insert(peerUpdate.Network, lastPeerUpdate, string(data))
+
+	file := ncutils.GetNetclientPathSpecific() + cfg.Node.Interface + ".conf"
+	err = wireguard.UpdateWgPeers(file, peerUpdate.Peers)
+	if err != nil {
+		ncutils.Log("error updating wireguard peers" + err.Error())
+		return
+	}
+	//err = wireguard.SyncWGQuickConf(cfg.Node.Interface, file)
+	var iface = cfg.Node.Interface
+	if ncutils.IsMac() {
+		iface, err = local.GetMacIface(cfg.Node.Address)
+		if err != nil {
+			ncutils.Log("error retrieving mac iface: " + err.Error())
+			return
+		}
+	}
+	err = wireguard.SetPeers(iface, &cfg.Node, peerUpdate.Peers)
+	if err != nil {
+		ncutils.Log("error syncing wg after peer update: " + err.Error())
+		return
+	}
+}

+ 143 - 0
netclient/functions/mqpublish.go

@@ -0,0 +1,143 @@
+package functions
+
+import (
+	"context"
+	"encoding/json"
+	"fmt"
+	"sync"
+	"time"
+
+	"github.com/gravitl/netmaker/netclient/auth"
+	"github.com/gravitl/netmaker/netclient/config"
+	"github.com/gravitl/netmaker/netclient/ncutils"
+)
+
+// Checkin  -- go routine that checks for public or local ip changes, publishes changes
+//   if there are no updates, simply "pings" the server as a checkin
+func Checkin(ctx context.Context, wg *sync.WaitGroup, currentComms map[string]bool) {
+	defer wg.Done()
+	for {
+		select {
+		case <-ctx.Done():
+			ncutils.Log("checkin routine closed")
+			return
+			//delay should be configuraable -> use cfg.Node.NetworkSettings.DefaultCheckInInterval ??
+		case <-time.After(time.Second * 60):
+			// ncutils.Log("Checkin running")
+			//read latest config
+			networks, err := ncutils.GetSystemNetworks()
+			if err != nil {
+				return
+			}
+			for commsNet := range currentComms {
+				var currCommsCfg config.ClientConfig
+				currCommsCfg.Network = commsNet
+				currCommsCfg.ReadConfig()
+				for _, network := range networks {
+					var nodeCfg config.ClientConfig
+					nodeCfg.Network = network
+					nodeCfg.ReadConfig()
+					if nodeCfg.Node.CommID != commsNet {
+						continue // skip if not on current comms network
+					}
+					if nodeCfg.Node.IsStatic != "yes" {
+						extIP, err := ncutils.GetPublicIP()
+						if err != nil {
+							ncutils.PrintLog("error encountered checking public ip addresses: "+err.Error(), 1)
+						}
+						if nodeCfg.Node.Endpoint != extIP && extIP != "" {
+							ncutils.PrintLog("endpoint has changed from "+nodeCfg.Node.Endpoint+" to "+extIP, 1)
+							nodeCfg.Node.Endpoint = extIP
+							if err := PublishNodeUpdate(&currCommsCfg, &nodeCfg); err != nil {
+								ncutils.Log("could not publish endpoint change")
+							}
+						}
+						intIP, err := getPrivateAddr()
+						if err != nil {
+							ncutils.PrintLog("error encountered checking private ip addresses: "+err.Error(), 1)
+						}
+						if nodeCfg.Node.LocalAddress != intIP && intIP != "" {
+							ncutils.PrintLog("local Address has changed from "+nodeCfg.Node.LocalAddress+" to "+intIP, 1)
+							nodeCfg.Node.LocalAddress = intIP
+							if err := PublishNodeUpdate(&currCommsCfg, &nodeCfg); err != nil {
+								ncutils.Log("could not publish local address change")
+							}
+						}
+					} else if nodeCfg.Node.IsLocal == "yes" && nodeCfg.Node.LocalRange != "" {
+						localIP, err := ncutils.GetLocalIP(nodeCfg.Node.LocalRange)
+						if err != nil {
+							ncutils.PrintLog("error encountered checking local ip addresses: "+err.Error(), 1)
+						}
+						if nodeCfg.Node.Endpoint != localIP && localIP != "" {
+							ncutils.PrintLog("endpoint has changed from "+nodeCfg.Node.Endpoint+" to "+localIP, 1)
+							nodeCfg.Node.Endpoint = localIP
+							if err := PublishNodeUpdate(&currCommsCfg, &nodeCfg); err != nil {
+								ncutils.Log("could not publish localip change")
+							}
+						}
+					}
+					if err := PingServer(&currCommsCfg); err != nil {
+						ncutils.PrintLog("could not ping server on comms net, "+currCommsCfg.Network+"\n"+err.Error(), 0)
+					} else {
+						Hello(&currCommsCfg, &nodeCfg)
+					}
+				}
+			}
+		}
+	}
+}
+
+// PublishNodeUpdates -- saves node and pushes changes to broker
+func PublishNodeUpdate(commsCfg, nodeCfg *config.ClientConfig) error {
+	if err := config.Write(nodeCfg, nodeCfg.Network); err != nil {
+		return err
+	}
+	data, err := json.Marshal(nodeCfg.Node)
+	if err != nil {
+		return err
+	}
+	if err = publish(commsCfg, nodeCfg, fmt.Sprintf("update/%s", nodeCfg.Node.ID), data, 1); err != nil {
+		return err
+	}
+	ncutils.PrintLog("sent a node update to server for node"+nodeCfg.Node.Name+", "+nodeCfg.Node.ID, 1)
+	return nil
+}
+
+// Hello -- ping the broker to let server know node it's alive and well
+func Hello(commsCfg, nodeCfg *config.ClientConfig) {
+	if err := publish(commsCfg, nodeCfg, fmt.Sprintf("ping/%s", nodeCfg.Node.ID), []byte(ncutils.Version), 0); err != nil {
+		ncutils.Log(fmt.Sprintf("error publishing ping, %v", err))
+		ncutils.Log("running pull on " + commsCfg.Node.Network + " to reconnect")
+		_, err := Pull(commsCfg.Node.Network, true)
+		if err != nil {
+			ncutils.Log("could not run pull on " + commsCfg.Node.Network + ", error: " + err.Error())
+		}
+	}
+}
+
+// requires the commscfg in which to send traffic over and nodecfg of node that is publish the message
+// node cfg is so that the traffic keys of that node may be fetched for encryption
+func publish(commsCfg, nodeCfg *config.ClientConfig, dest string, msg []byte, qos byte) error {
+	// setup the keys
+	trafficPrivKey, err := auth.RetrieveTrafficKey(nodeCfg.Node.Network)
+	if err != nil {
+		return err
+	}
+
+	serverPubKey, err := ncutils.ConvertBytesToKey(nodeCfg.Node.TrafficKeys.Server)
+	if err != nil {
+		return err
+	}
+
+	client := setupMQTT(commsCfg, true)
+	defer client.Disconnect(250)
+	encrypted, err := ncutils.Chunk(msg, serverPubKey, trafficPrivKey)
+	if err != nil {
+		return err
+	}
+
+	if token := client.Publish(dest, qos, false, encrypted); token.Wait() && token.Error() != nil {
+		return token.Error()
+	}
+	return nil
+}

+ 126 - 0
netclient/functions/pull.go

@@ -0,0 +1,126 @@
+package functions
+
+import (
+	"context"
+	"encoding/json"
+	"errors"
+	"os"
+	"runtime"
+
+	nodepb "github.com/gravitl/netmaker/grpc"
+	"github.com/gravitl/netmaker/models"
+	"github.com/gravitl/netmaker/netclient/auth"
+	"github.com/gravitl/netmaker/netclient/config"
+	"github.com/gravitl/netmaker/netclient/local"
+	"github.com/gravitl/netmaker/netclient/ncutils"
+	"github.com/gravitl/netmaker/netclient/wireguard"
+	"google.golang.org/grpc"
+	"google.golang.org/grpc/metadata"
+	//homedir "github.com/mitchellh/go-homedir"
+)
+
+// Pull - pulls the latest config from the server, if manual it will overwrite
+func Pull(network string, manual bool) (*models.Node, error) {
+	cfg, err := config.ReadConfig(network)
+	if err != nil {
+		return nil, err
+	}
+	node := cfg.Node
+	//servercfg := cfg.Server
+
+	if cfg.Node.IPForwarding == "yes" && !ncutils.IsWindows() {
+		if err = local.SetIPForwarding(); err != nil {
+			return nil, err
+		}
+	}
+	var resNode models.Node // just need to fill this with either server calls or client calls
+
+	var header metadata.MD
+	var wcclient nodepb.NodeServiceClient
+	var ctx context.Context
+
+	if cfg.Node.IsServer != "yes" {
+		conn, err := grpc.Dial(cfg.Server.GRPCAddress,
+			ncutils.GRPCRequestOpts(cfg.Server.GRPCSSL))
+		if err != nil {
+			ncutils.PrintLog("Cant dial GRPC server: "+err.Error(), 1)
+			return nil, err
+		}
+		defer conn.Close()
+		wcclient = nodepb.NewNodeServiceClient(conn)
+
+		ctx, err = auth.SetJWT(wcclient, network)
+		if err != nil {
+			ncutils.PrintLog("Failed to authenticate: "+err.Error(), 1)
+			return nil, err
+		}
+		data, err := json.Marshal(&node)
+		if err != nil {
+			ncutils.PrintLog("Failed to parse node config: "+err.Error(), 1)
+			return nil, err
+		}
+
+		req := &nodepb.Object{
+			Data: string(data),
+			Type: nodepb.NODE_TYPE,
+		}
+
+		readres, err := wcclient.ReadNode(ctx, req, grpc.Header(&header))
+		if err != nil {
+			return nil, err
+		}
+
+		if err = json.Unmarshal([]byte(readres.Data), &resNode); err != nil {
+			return nil, err
+		}
+	}
+	// ensure that the OS never changes
+	resNode.OS = runtime.GOOS
+	if manual {
+		// check for interface change
+		if cfg.Node.Interface != resNode.Interface {
+			if err = DeleteInterface(cfg.Node.Interface, cfg.Node.PostDown); err != nil {
+				ncutils.PrintLog("could not delete old interface "+cfg.Node.Interface, 1)
+			}
+		}
+		if err = config.ModConfig(&resNode); err != nil {
+			return nil, err
+		}
+		if err = wireguard.SetWGConfig(network, false); err != nil {
+			return nil, err
+		}
+		nodeData, err := json.Marshal(&resNode)
+		if err != nil {
+			return &resNode, err
+		}
+
+		if resNode.IsServer != "yes" {
+			if wcclient == nil || ctx == nil {
+				return &cfg.Node, errors.New("issue initializing gRPC client")
+			}
+			req := &nodepb.Object{
+				Data:     string(nodeData),
+				Type:     nodepb.NODE_TYPE,
+				Metadata: "",
+			}
+			_, err = wcclient.UpdateNode(ctx, req, grpc.Header(&header))
+			if err != nil {
+				return &resNode, err
+			}
+		}
+	} else {
+		if err = wireguard.SetWGConfig(network, true); err != nil {
+			if errors.Is(err, os.ErrNotExist) && !ncutils.IsFreeBSD() {
+				return Pull(network, true)
+			} else {
+				return nil, err
+			}
+		}
+	}
+	var bkupErr = config.SaveBackup(network)
+	if bkupErr != nil {
+		ncutils.Log("unable to update backup file")
+	}
+
+	return &resNode, err
+}

+ 8 - 0
netclient/ncutils/constants.go

@@ -0,0 +1,8 @@
+package ncutils
+
+const (
+	// ACK - acknowledgement signal for MQ
+	ACK = 1
+	// DONE - done signal for MQ
+	DONE = 2
+)

+ 105 - 0
netclient/ncutils/encryption.go

@@ -0,0 +1,105 @@
+package ncutils
+
+import (
+	"bytes"
+	"crypto/rand"
+	"fmt"
+	"io"
+
+	"golang.org/x/crypto/nacl/box"
+)
+
+const (
+	chunkSize = 16000 // 16000 bytes max message size
+)
+
+// BoxEncrypt - encrypts traffic box
+func BoxEncrypt(message []byte, recipientPubKey *[32]byte, senderPrivateKey *[32]byte) ([]byte, error) {
+	var nonce [24]byte // 192 bits of randomization
+	if _, err := io.ReadFull(rand.Reader, nonce[:]); err != nil {
+		return nil, err
+	}
+
+	encrypted := box.Seal(nonce[:], message, &nonce, recipientPubKey, senderPrivateKey)
+	return encrypted, nil
+}
+
+// BoxDecrypt - decrypts traffic box
+func BoxDecrypt(encrypted []byte, senderPublicKey *[32]byte, recipientPrivateKey *[32]byte) ([]byte, error) {
+	var decryptNonce [24]byte
+	copy(decryptNonce[:], encrypted[:24])
+	decrypted, ok := box.Open(nil, encrypted[24:], &decryptNonce, senderPublicKey, recipientPrivateKey)
+	if !ok {
+		return nil, fmt.Errorf("could not decrypt message, %v", encrypted)
+	}
+	return decrypted, nil
+}
+
+// Chunk - chunks a message and encrypts each chunk
+func Chunk(message []byte, recipientPubKey *[32]byte, senderPrivateKey *[32]byte) ([]byte, error) {
+	var chunks [][]byte
+	for i := 0; i < len(message); i += chunkSize {
+		end := i + chunkSize
+
+		if end > len(message) {
+			end = len(message)
+		}
+
+		encryptedMsgSlice, err := BoxEncrypt(message[i:end], recipientPubKey, senderPrivateKey)
+		if err != nil {
+			return nil, err
+		}
+
+		chunks = append(chunks, encryptedMsgSlice)
+	}
+
+	chunkedMsg, err := convertBytesToMsg(chunks) // encode the array into some bytes to decode on receiving end
+	if err != nil {
+		return nil, err
+	}
+
+	return chunkedMsg, nil
+}
+
+// DeChunk - "de" chunks and decrypts a message
+func DeChunk(chunkedMsg []byte, senderPublicKey *[32]byte, recipientPrivateKey *[32]byte) ([]byte, error) {
+	chunks, err := convertMsgToBytes(chunkedMsg) // convert the message to it's original chunks form
+	if err != nil {
+		return nil, err
+	}
+
+	var totalMsg []byte
+	for i := range chunks {
+		decodedMsg, err := BoxDecrypt(chunks[i], senderPublicKey, recipientPrivateKey)
+		if err != nil {
+			return nil, err
+		}
+		totalMsg = append(totalMsg, decodedMsg...)
+	}
+	return totalMsg, nil
+}
+
+// == private ==
+
+var splitKey = []byte("|(,)(,)|")
+
+// ConvertMsgToBytes - converts a message (MQ) to it's chunked version
+// decode action
+func convertMsgToBytes(msg []byte) ([][]byte, error) {
+	splitMsg := bytes.Split(msg, splitKey)
+	return splitMsg, nil
+}
+
+// ConvertBytesToMsg - converts the chunked message into a MQ message
+// encode action
+func convertBytesToMsg(b [][]byte) ([]byte, error) {
+
+	var buffer []byte  // allocate a buffer with adequate sizing
+	for i := range b { // append bytes to it with key
+		buffer = append(buffer, b[i]...)
+		if i != len(b)-1 {
+			buffer = append(buffer, splitKey...)
+		}
+	}
+	return buffer, nil
+}

+ 3 - 1
netclient/ncutils/iface.go

@@ -6,6 +6,7 @@ import (
 	"github.com/gravitl/netmaker/models"
 	"github.com/gravitl/netmaker/models"
 )
 )
 
 
+// IfaceDelta - checks if the new node causes an interface change
 func IfaceDelta(currentNode *models.Node, newNode *models.Node) bool {
 func IfaceDelta(currentNode *models.Node, newNode *models.Node) bool {
 	// single comparison statements
 	// single comparison statements
 	if newNode.Endpoint != currentNode.Endpoint ||
 	if newNode.Endpoint != currentNode.Endpoint ||
@@ -15,11 +16,12 @@ func IfaceDelta(currentNode *models.Node, newNode *models.Node) bool {
 		newNode.IsEgressGateway != currentNode.IsEgressGateway ||
 		newNode.IsEgressGateway != currentNode.IsEgressGateway ||
 		newNode.IsIngressGateway != currentNode.IsIngressGateway ||
 		newNode.IsIngressGateway != currentNode.IsIngressGateway ||
 		newNode.IsRelay != currentNode.IsRelay ||
 		newNode.IsRelay != currentNode.IsRelay ||
+		newNode.ListenPort != currentNode.ListenPort ||
 		newNode.UDPHolePunch != currentNode.UDPHolePunch ||
 		newNode.UDPHolePunch != currentNode.UDPHolePunch ||
+		newNode.MTU != currentNode.MTU ||
 		newNode.IsPending != currentNode.IsPending ||
 		newNode.IsPending != currentNode.IsPending ||
 		newNode.PersistentKeepalive != currentNode.PersistentKeepalive ||
 		newNode.PersistentKeepalive != currentNode.PersistentKeepalive ||
 		newNode.DNSOn != currentNode.DNSOn ||
 		newNode.DNSOn != currentNode.DNSOn ||
-		len(newNode.ExcludedAddrs) != len(currentNode.ExcludedAddrs) ||
 		len(newNode.AllowedIPs) != len(currentNode.AllowedIPs) {
 		len(newNode.AllowedIPs) != len(currentNode.AllowedIPs) {
 		return true
 		return true
 	}
 	}

+ 7 - 25
netclient/ncutils/netclientutils.go

@@ -2,7 +2,6 @@ package ncutils
 
 
 import (
 import (
 	"bytes"
 	"bytes"
-	crand "crypto/rand"
 	"crypto/tls"
 	"crypto/tls"
 	"encoding/gob"
 	"encoding/gob"
 	"errors"
 	"errors"
@@ -22,7 +21,6 @@ import (
 	"time"
 	"time"
 
 
 	"github.com/gravitl/netmaker/models"
 	"github.com/gravitl/netmaker/models"
-	"golang.org/x/crypto/nacl/box"
 	"golang.zx2c4.com/wireguard/wgctrl"
 	"golang.zx2c4.com/wireguard/wgctrl"
 	"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
 	"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
 	"google.golang.org/grpc"
 	"google.golang.org/grpc"
@@ -51,7 +49,7 @@ const LINUX_APP_DATA_PATH = "/etc/netclient"
 const WINDOWS_APP_DATA_PATH = "C:\\ProgramData\\Netclient"
 const WINDOWS_APP_DATA_PATH = "C:\\ProgramData\\Netclient"
 
 
 // WINDOWS_APP_DATA_PATH - windows path
 // WINDOWS_APP_DATA_PATH - windows path
-const WINDOWS_WG_DPAPI_PATH = "C:\\Program Files\\WireGuard\\Data\\Configurations"
+//const WINDOWS_WG_DPAPI_PATH = "C:\\Program Files\\WireGuard\\Data\\Configurations"
 
 
 // WINDOWS_SVC_NAME - service name
 // WINDOWS_SVC_NAME - service name
 const WINDOWS_SVC_NAME = "netclient"
 const WINDOWS_SVC_NAME = "netclient"
@@ -104,6 +102,12 @@ func IsFreeBSD() bool {
 	return runtime.GOOS == "freebsd"
 	return runtime.GOOS == "freebsd"
 }
 }
 
 
+// HasWGQuick - checks if WGQuick command is present
+func HasWgQuick() bool {
+	cmd, err := exec.LookPath("wg-quick")
+	return err == nil && cmd != ""
+}
+
 // GetWireGuard - checks if wg is installed
 // GetWireGuard - checks if wg is installed
 func GetWireGuard() string {
 func GetWireGuard() string {
 	userspace := os.Getenv("WG_QUICK_USERSPACE_IMPLEMENTATION")
 	userspace := os.Getenv("WG_QUICK_USERSPACE_IMPLEMENTATION")
@@ -613,28 +617,6 @@ func ServerAddrSliceContains(slice []models.ServerAddr, item models.ServerAddr)
 	return false
 	return false
 }
 }
 
 
-// BoxEncrypt - encrypts traffic box
-func BoxEncrypt(message []byte, recipientPubKey *[32]byte, senderPrivateKey *[32]byte) ([]byte, error) {
-	var nonce [24]byte // 192 bits of randomization
-	if _, err := io.ReadFull(crand.Reader, nonce[:]); err != nil {
-		return nil, err
-	}
-
-	encrypted := box.Seal(nonce[:], message, &nonce, recipientPubKey, senderPrivateKey)
-	return encrypted, nil
-}
-
-// BoxDecrypt - decrypts traffic box
-func BoxDecrypt(encrypted []byte, senderPublicKey *[32]byte, recipientPrivateKey *[32]byte) ([]byte, error) {
-	var decryptNonce [24]byte
-	copy(decryptNonce[:], encrypted[:24])
-	decrypted, ok := box.Open(nil, encrypted[24:], &decryptNonce, senderPublicKey, recipientPrivateKey)
-	if !ok {
-		return nil, fmt.Errorf("could not decrypt message")
-	}
-	return decrypted, nil
-}
-
 // MakeRandomString - generates a random string of len n
 // MakeRandomString - generates a random string of len n
 func MakeRandomString(n int) string {
 func MakeRandomString(n int) string {
 	sb := strings.Builder{}
 	sb := strings.Builder{}

+ 0 - 2
netclient/ncutils/netclientutils_darwin.go

@@ -28,5 +28,3 @@ func RunCmdFormatted(command string, printerr bool) (string, error) {
 func GetEmbedded() error {
 func GetEmbedded() error {
 	return nil
 	return nil
 }
 }
-
-

+ 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.10.0.0"
+            version="0.11.0.0"
             processorArchitecture="*"
             processorArchitecture="*"
             name="netclient.exe"
             name="netclient.exe"
             type="win32"
             type="win32"

BIN
netclient/netclient.syso


+ 1 - 1
netclient/versioninfo.json

@@ -29,7 +29,7 @@
         "OriginalFilename": "",
         "OriginalFilename": "",
         "PrivateBuild": "",
         "PrivateBuild": "",
         "ProductName": "Netclient",
         "ProductName": "Netclient",
-        "ProductVersion": "v0.10.0.0",
+        "ProductVersion": "v0.11.0.0",
         "SpecialBuild": ""
         "SpecialBuild": ""
     },
     },
     "VarFileInfo": {
     "VarFileInfo": {

+ 40 - 12
netclient/wireguard/common.go

@@ -25,8 +25,10 @@ const (
 )
 )
 
 
 // SetPeers - sets peers on a given WireGuard interface
 // SetPeers - sets peers on a given WireGuard interface
-func SetPeers(iface, currentNodeAddr string, keepalive int32, peers []wgtypes.PeerConfig) error {
+func SetPeers(iface string, node *models.Node, peers []wgtypes.PeerConfig) error {
 	var devicePeers []wgtypes.Peer
 	var devicePeers []wgtypes.Peer
+	var currentNodeAddr = node.Address
+	var keepalive = node.PersistentKeepalive
 	var oldPeerAllowedIps = make(map[string][]net.IPNet, len(peers))
 	var oldPeerAllowedIps = make(map[string][]net.IPNet, len(peers))
 	var err error
 	var err error
 	if ncutils.IsFreeBSD() {
 	if ncutils.IsFreeBSD() {
@@ -73,13 +75,14 @@ func SetPeers(iface, currentNodeAddr string, keepalive int32, peers []wgtypes.Pe
 		if keepAliveString == "0" {
 		if keepAliveString == "0" {
 			keepAliveString = "15"
 			keepAliveString = "15"
 		}
 		}
-		if peer.Endpoint != nil {
+		if node.IsHub == "yes" || peer.Endpoint == nil {
 			_, err = ncutils.RunCmd("wg set "+iface+" peer "+peer.PublicKey.String()+
 			_, err = ncutils.RunCmd("wg set "+iface+" peer "+peer.PublicKey.String()+
-				" endpoint "+udpendpoint+
 				" persistent-keepalive "+keepAliveString+
 				" persistent-keepalive "+keepAliveString+
 				" allowed-ips "+allowedips, true)
 				" allowed-ips "+allowedips, true)
+
 		} else {
 		} else {
 			_, err = ncutils.RunCmd("wg set "+iface+" peer "+peer.PublicKey.String()+
 			_, err = ncutils.RunCmd("wg set "+iface+" peer "+peer.PublicKey.String()+
+				" endpoint "+udpendpoint+
 				" persistent-keepalive "+keepAliveString+
 				" persistent-keepalive "+keepAliveString+
 				" allowed-ips "+allowedips, true)
 				" allowed-ips "+allowedips, true)
 		}
 		}
@@ -94,6 +97,10 @@ func SetPeers(iface, currentNodeAddr string, keepalive int32, peers []wgtypes.Pe
 			if peer.AllowedIPs[0].String() == currentPeer.AllowedIPs[0].String() {
 			if peer.AllowedIPs[0].String() == currentPeer.AllowedIPs[0].String() {
 				shouldDelete = false
 				shouldDelete = false
 			}
 			}
+			// re-check this if logic is not working, added in case of allowedips not working
+			if peer.PublicKey.String() == currentPeer.PublicKey.String() {
+				shouldDelete = false
+			}
 		}
 		}
 		if shouldDelete {
 		if shouldDelete {
 			output, err := ncutils.RunCmd("wg set "+iface+" peer "+currentPeer.PublicKey.String()+" remove", true)
 			output, err := ncutils.RunCmd("wg set "+iface+" peer "+currentPeer.PublicKey.String()+" remove", true)
@@ -131,10 +138,6 @@ func InitWireguard(node *models.Node, privkey string, peers []wgtypes.PeerConfig
 		return err
 		return err
 	}
 	}
 	nodecfg := modcfg.Node
 	nodecfg := modcfg.Node
-
-	if err != nil {
-		log.Fatalf("failed to open client: %v", err)
-	}
 	var ifacename string
 	var ifacename string
 	if nodecfg.Interface != "" {
 	if nodecfg.Interface != "" {
 		ifacename = nodecfg.Interface
 		ifacename = nodecfg.Interface
@@ -206,7 +209,13 @@ func InitWireguard(node *models.Node, privkey string, peers []wgtypes.PeerConfig
 	if syncconf { // should never be called really.
 	if syncconf { // should never be called really.
 		err = SyncWGQuickConf(ifacename, confPath)
 		err = SyncWGQuickConf(ifacename, confPath)
 	}
 	}
-
+	if !ncutils.HasWgQuick() && ncutils.IsLinux() {
+		err = SetPeers(ifacename, node, peers)
+		if err != nil {
+			ncutils.PrintLog("error setting peers: "+err.Error(), 1)
+		}
+		time.Sleep(time.Second)
+	}
 	_, cidr, cidrErr := net.ParseCIDR(modcfg.NetworkSettings.AddressRange)
 	_, cidr, cidrErr := net.ParseCIDR(modcfg.NetworkSettings.AddressRange)
 	if cidrErr == nil {
 	if cidrErr == nil {
 		local.SetCIDRRoute(ifacename, node.Address, cidr)
 		local.SetCIDRRoute(ifacename, node.Address, cidr)
@@ -245,7 +254,7 @@ func SetWGConfig(network string, peerupdate bool) error {
 				return err
 				return err
 			}
 			}
 		}
 		}
-		err = SetPeers(iface, nodecfg.Address, nodecfg.PersistentKeepalive, peers)
+		err = SetPeers(iface, &nodecfg, peers)
 	} else if peerupdate {
 	} else if peerupdate {
 		err = InitWireguard(&nodecfg, privkey, peers, hasGateway, gateways, true)
 		err = InitWireguard(&nodecfg, privkey, peers, hasGateway, gateways, true)
 	} else {
 	} else {
@@ -260,8 +269,13 @@ func SetWGConfig(network string, peerupdate bool) error {
 // RemoveConf - removes a configuration for a given WireGuard interface
 // RemoveConf - removes a configuration for a given WireGuard interface
 func RemoveConf(iface string, printlog bool) error {
 func RemoveConf(iface string, printlog bool) error {
 	os := runtime.GOOS
 	os := runtime.GOOS
+	if !ncutils.HasWgQuick() {
+		os = "nowgquick"
+	}
 	var err error
 	var err error
 	switch os {
 	switch os {
+	case "nowgquick":
+		err = RemoveWithoutWGQuick(iface)
 	case "windows":
 	case "windows":
 		err = RemoveWindowsConf(iface, printlog)
 		err = RemoveWindowsConf(iface, printlog)
 	case "darwin":
 	case "darwin":
@@ -276,15 +290,29 @@ func RemoveConf(iface string, printlog bool) error {
 // ApplyConf - applys a conf on disk to WireGuard interface
 // ApplyConf - applys a conf on disk to WireGuard interface
 func ApplyConf(node *models.Node, ifacename string, confPath string) error {
 func ApplyConf(node *models.Node, ifacename string, confPath string) error {
 	os := runtime.GOOS
 	os := runtime.GOOS
+	if ncutils.IsLinux() && !ncutils.HasWgQuick() {
+		os = "nowgquick"
+	}
 	var err error
 	var err error
 	switch os {
 	switch os {
+	case "nowgquick":
+		ApplyWithoutWGQuick(node, ifacename, confPath)
 	case "windows":
 	case "windows":
-		_ = ApplyWindowsConf(confPath)
+		ApplyWindowsConf(confPath)
 	case "darwin":
 	case "darwin":
-		_ = ApplyMacOSConf(node, ifacename, confPath)
+		ApplyMacOSConf(node, ifacename, confPath)
 	default:
 	default:
-		err = ApplyWGQuickConf(confPath, ifacename)
+		ApplyWGQuickConf(confPath, ifacename)
+	}
+
+	var nodeCfg config.ClientConfig
+	nodeCfg.Network = node.Network
+	nodeCfg.ReadConfig()
+	ip, cidr, err := net.ParseCIDR(nodeCfg.NetworkSettings.AddressRange)
+	if err == nil {
+		local.SetCIDRRoute(node.Interface, ip.String(), cidr)
 	}
 	}
+
 	return err
 	return err
 }
 }
 
 

+ 135 - 0
netclient/wireguard/noquick.go

@@ -0,0 +1,135 @@
+package wireguard
+
+import (
+	"errors"
+	"os"
+	"os/exec"
+	"strconv"
+	"strings"
+
+	"github.com/gravitl/netmaker/logger"
+	"github.com/gravitl/netmaker/models"
+	"github.com/gravitl/netmaker/netclient/config"
+	"github.com/gravitl/netmaker/netclient/ncutils"
+	"golang.zx2c4.com/wireguard/wgctrl"
+	"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
+)
+
+// ApplyWithoutWGQuick - Function for running the equivalent of "wg-quick up" for linux if wg-quick is missing
+func ApplyWithoutWGQuick(node *models.Node, ifacename string, confPath string) error {
+
+	ipExec, err := exec.LookPath("ip")
+	if err != nil {
+		return err
+	}
+	wgclient, err := wgctrl.New()
+	if err != nil {
+		return err
+	}
+	defer wgclient.Close()
+
+	privkey, err := RetrievePrivKey(node.Network)
+	if err != nil {
+		return err
+	}
+	key, err := wgtypes.ParseKey(privkey)
+	if err != nil {
+		return err
+	}
+	conf := wgtypes.Config{}
+	nodeport := int(node.ListenPort)
+	if node.UDPHolePunch == "yes" &&
+		node.IsServer == "no" &&
+		node.IsIngressGateway != "yes" &&
+		node.IsStatic != "yes" {
+		conf = wgtypes.Config{
+			PrivateKey: &key,
+		}
+	} else {
+		conf = wgtypes.Config{
+			PrivateKey: &key,
+			ListenPort: &nodeport,
+		}
+	}
+
+	netmaskArr := strings.Split(node.NetworkSettings.AddressRange, "/")
+	var netmask = "32"
+	if len(netmaskArr) == 2 {
+		netmask = netmaskArr[1]
+	}
+	setKernelDevice(ifacename, node.Address, netmask)
+
+	_, err = wgclient.Device(ifacename)
+	if err != nil {
+		if !os.IsNotExist(err) {
+			return errors.New("Unknown config error: " + err.Error())
+		}
+	}
+	err = wgclient.ConfigureDevice(ifacename, conf)
+	if err != nil {
+		if os.IsNotExist(err) {
+			ncutils.PrintLog("Could not configure device: "+err.Error(), 0)
+		}
+	}
+	if _, err := ncutils.RunCmd(ipExec+" link set down dev "+ifacename, false); err != nil {
+		logger.Log(2, "attempted to remove interface before editing")
+		return err
+	}
+	if node.PostDown != "" {
+		runcmds := strings.Split(node.PostDown, "; ")
+		_ = ncutils.RunCmds(runcmds, false)
+	}
+	// set MTU of node interface
+	if _, err := ncutils.RunCmd(ipExec+" link set mtu "+strconv.Itoa(int(node.MTU))+" up dev "+ifacename, true); err != nil {
+		logger.Log(2, "failed to create interface with mtu", strconv.Itoa(int(node.MTU)), "-", ifacename)
+		return err
+	}
+	if node.PostUp != "" {
+		runcmds := strings.Split(node.PostUp, "; ")
+		_ = ncutils.RunCmds(runcmds, true)
+	}
+	if node.Address6 != "" && node.IsDualStack == "yes" {
+		logger.Log(1, "adding address:", node.Address6)
+		_, _ = ncutils.RunCmd(ipExec+" address add dev "+ifacename+" "+node.Address6+"/64", true)
+	}
+	return nil
+}
+
+// RemoveWithoutWGQuick - Function for running the equivalent of "wg-quick down" for linux if wg-quick is missing
+func RemoveWithoutWGQuick(ifacename string) error {
+	ipExec, err := exec.LookPath("ip")
+	if err != nil {
+		return err
+	}
+	out, err := ncutils.RunCmd(ipExec+" link del "+ifacename, false)
+	dontprint := strings.Contains(out, "does not exist") || strings.Contains(out, "Cannot find device")
+	if err != nil && !dontprint {
+		logger.Log(1, "error running command:", ipExec, "link del", ifacename)
+		logger.Log(1, out)
+	}
+	network := strings.ReplaceAll(ifacename, "nm-", "")
+	nodeconf, err := config.ReadConfig(network)
+	if nodeconf != nil && err == nil {
+		if nodeconf.Node.PostDown != "" {
+			runcmds := strings.Split(nodeconf.Node.PostDown, "; ")
+			_ = ncutils.RunCmds(runcmds, false)
+		}
+	} else if err != nil {
+		ncutils.PrintLog("error retrieving config: "+err.Error(), 1)
+	}
+	return err
+}
+
+func setKernelDevice(ifacename, address, mask string) error {
+	ipExec, err := exec.LookPath("ip")
+	if err != nil {
+		return err
+	}
+
+	// == best effort ==
+	ncutils.RunCmd("ip link delete dev "+ifacename, false)
+	ncutils.RunCmd(ipExec+" link add dev "+ifacename+" type wireguard", true)
+	ncutils.RunCmd(ipExec+" address add dev "+ifacename+" "+address+"/"+mask, true) // this was a bug waiting to happen
+
+	return nil
+}

+ 1 - 0
netclient/wireguard/unix.go

@@ -65,6 +65,7 @@ func ApplyWGQuickConf(confPath string, ifacename string) error {
 			ncutils.RunCmd("wg-quick down "+confPath, true)
 			ncutils.RunCmd("wg-quick down "+confPath, true)
 		}
 		}
 		_, err = ncutils.RunCmd("wg-quick up "+confPath, true)
 		_, err = ncutils.RunCmd("wg-quick up "+confPath, true)
+
 		return err
 		return err
 	}
 	}
 }
 }

+ 24 - 23
netclient/wireguard/windows.go

@@ -2,23 +2,22 @@ package wireguard
 
 
 import (
 import (
 	"fmt"
 	"fmt"
-	"os"
-	"strings"
-	"time"
 
 
 	"github.com/gravitl/netmaker/netclient/ncutils"
 	"github.com/gravitl/netmaker/netclient/ncutils"
 )
 )
 
 
 // ApplyWindowsConf - applies the WireGuard configuration file on Windows
 // ApplyWindowsConf - applies the WireGuard configuration file on Windows
 func ApplyWindowsConf(confPath string) error {
 func ApplyWindowsConf(confPath string) error {
-	pathStrings := strings.Split(confPath, ncutils.GetWGPathSpecific())
-	if len(pathStrings) == 2 {
-		copyConfPath := fmt.Sprintf("%s\\%s", ncutils.WINDOWS_WG_DPAPI_PATH, pathStrings[1])
-		err := ncutils.Copy(confPath, copyConfPath)
-		if err != nil {
-			ncutils.PrintLog(err.Error(), 1)
+	/*
+		pathStrings := strings.Split(confPath, ncutils.GetWGPathSpecific())
+		if len(pathStrings) == 2 {
+			copyConfPath := fmt.Sprintf("%s\\%s", ncutils.WINDOWS_WG_DPAPI_PATH, pathStrings[1])
+			err := ncutils.Copy(confPath, copyConfPath)
+			if err != nil {
+				ncutils.PrintLog(err.Error(), 1)
+			}
 		}
 		}
-	}
+	*/
 	var commandLine = fmt.Sprintf(`wireguard.exe /installtunnelservice "%s"`, confPath)
 	var commandLine = fmt.Sprintf(`wireguard.exe /installtunnelservice "%s"`, confPath)
 	if _, err := ncutils.RunCmdFormatted(commandLine, false); err != nil {
 	if _, err := ncutils.RunCmdFormatted(commandLine, false); err != nil {
 		return err
 		return err
@@ -31,20 +30,22 @@ func RemoveWindowsConf(ifacename string, printlog bool) error {
 	if _, err := ncutils.RunCmd("wireguard.exe /uninstalltunnelservice "+ifacename, printlog); err != nil {
 	if _, err := ncutils.RunCmd("wireguard.exe /uninstalltunnelservice "+ifacename, printlog); err != nil {
 		ncutils.PrintLog(err.Error(), 1)
 		ncutils.PrintLog(err.Error(), 1)
 	}
 	}
-	dpapipath := fmt.Sprintf("%s\\%s.conf.dpapi", ncutils.WINDOWS_WG_DPAPI_PATH, ifacename)
-	confpath := fmt.Sprintf("%s\\%s.conf", ncutils.WINDOWS_WG_DPAPI_PATH, ifacename)
-	if ncutils.FileExists(confpath) {
-		err := os.Remove(confpath)
-		if err != nil {
-			ncutils.PrintLog(err.Error(), 1)
+	/*
+		dpapipath := fmt.Sprintf("%s\\%s.conf.dpapi", ncutils.WINDOWS_WG_DPAPI_PATH, ifacename)
+		confpath := fmt.Sprintf("%s\\%s.conf", ncutils.WINDOWS_WG_DPAPI_PATH, ifacename)
+		if ncutils.FileExists(confpath) {
+			err := os.Remove(confpath)
+			if err != nil {
+				ncutils.PrintLog(err.Error(), 1)
+			}
 		}
 		}
-	}
-	time.Sleep(time.Second >> 2)
-	if ncutils.FileExists(dpapipath) {
-		err := os.Remove(dpapipath)
-		if err != nil {
-			ncutils.PrintLog(err.Error(), 1)
+		time.Sleep(time.Second >> 2)
+		if ncutils.FileExists(dpapipath) {
+			err := os.Remove(dpapipath)
+			if err != nil {
+				ncutils.PrintLog(err.Error(), 1)
+			}
 		}
 		}
-	}
+	*/
 	return nil
 	return nil
 }
 }

+ 1 - 0
scripts/build-binaries.sh

@@ -18,3 +18,4 @@ env CGO_ENABLED=0 GOOS=freebsd GOARCH=arm GOARM=6 go build -ldflags="-X 'main.ve
 env CGO_ENABLED=0 GOOS=freebsd GOARCH=arm GOARM=7 go build -ldflags="-X 'main.version=$VERSION'" -o build/netclient-freebsd-arm7 main.go
 env CGO_ENABLED=0 GOOS=freebsd GOARCH=arm GOARM=7 go build -ldflags="-X 'main.version=$VERSION'" -o build/netclient-freebsd-arm7 main.go
 env CGO_ENABLED=0 GOOS=freebsd GOARCH=arm64 go build -ldflags="-X 'main.version=$VERSION'" -o build/netclient-freebsd-arm64 main.go
 env CGO_ENABLED=0 GOOS=freebsd GOARCH=arm64 go build -ldflags="-X 'main.version=$VERSION'" -o build/netclient-freebsd-arm64 main.go
 env CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -ldflags="-X 'main.version=$VERSION'" -o build/netclient-darwin main.go
 env CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -ldflags="-X 'main.version=$VERSION'" -o build/netclient-darwin main.go
+env CGO_ENABLED=0 GOOS=darwin GOARCH=arm64 go build -ldflags="-X 'main.version=${VERSION}'" -o build/netclient-darwin-arm64 main.go

+ 62 - 65
servercfg/serverconf.go

@@ -12,7 +12,10 @@ import (
 	"github.com/gravitl/netmaker/config"
 	"github.com/gravitl/netmaker/config"
 )
 )
 
 
-var Version = "dev"
+var (
+	Version = "dev"
+	commsID = ""
+)
 
 
 // SetHost - sets the host ip
 // SetHost - sets the host ip
 func SetHost() error {
 func SetHost() error {
@@ -31,16 +34,17 @@ func GetServerConfig() config.ServerConfig {
 	cfg.CoreDNSAddr = GetCoreDNSAddr()
 	cfg.CoreDNSAddr = GetCoreDNSAddr()
 	cfg.APIHost = GetAPIHost()
 	cfg.APIHost = GetAPIHost()
 	cfg.APIPort = GetAPIPort()
 	cfg.APIPort = GetAPIPort()
-	cfg.GRPCConnString = GetGRPCConnString()
+	cfg.APIPort = GetAPIPort()
+	cfg.MQPort = GetMQPort()
 	cfg.GRPCHost = GetGRPCHost()
 	cfg.GRPCHost = GetGRPCHost()
 	cfg.GRPCPort = GetGRPCPort()
 	cfg.GRPCPort = GetGRPCPort()
+	cfg.GRPCConnString = GetGRPCConnString()
 	cfg.MasterKey = "(hidden)"
 	cfg.MasterKey = "(hidden)"
 	cfg.DNSKey = "(hidden)"
 	cfg.DNSKey = "(hidden)"
 	cfg.AllowedOrigin = GetAllowedOrigin()
 	cfg.AllowedOrigin = GetAllowedOrigin()
 	cfg.RestBackend = "off"
 	cfg.RestBackend = "off"
 	cfg.NodeID = GetNodeID()
 	cfg.NodeID = GetNodeID()
-	cfg.CheckinInterval = GetCheckinInterval()
-	cfg.ServerCheckinInterval = GetServerCheckinInterval()
+	cfg.MQPort = GetMQPort()
 	if IsRestBackend() {
 	if IsRestBackend() {
 		cfg.RestBackend = "on"
 		cfg.RestBackend = "on"
 	}
 	}
@@ -68,10 +72,6 @@ func GetServerConfig() config.ServerConfig {
 	if DisableRemoteIPCheck() {
 	if DisableRemoteIPCheck() {
 		cfg.DisableRemoteIPCheck = "on"
 		cfg.DisableRemoteIPCheck = "on"
 	}
 	}
-	cfg.DisableDefaultNet = "off"
-	if DisableDefaultNet() {
-		cfg.DisableRemoteIPCheck = "on"
-	}
 	cfg.Database = GetDB()
 	cfg.Database = GetDB()
 	cfg.Platform = GetPlatform()
 	cfg.Platform = GetPlatform()
 	cfg.Version = GetVersion()
 	cfg.Version = GetVersion()
@@ -90,8 +90,10 @@ func GetServerConfig() config.ServerConfig {
 	cfg.Debug = GetDebug()
 	cfg.Debug = GetDebug()
 	cfg.Telemetry = Telemetry()
 	cfg.Telemetry = Telemetry()
 	cfg.ManageIPTables = ManageIPTables()
 	cfg.ManageIPTables = ManageIPTables()
+	cfg.CommsCIDR = GetCommsCIDR()
 	services := strings.Join(GetPortForwardServiceList(), ",")
 	services := strings.Join(GetPortForwardServiceList(), ",")
 	cfg.PortForwardServices = services
 	cfg.PortForwardServices = services
+	cfg.CommsID = GetCommsCIDR()
 
 
 	return cfg
 	return cfg
 }
 }
@@ -177,17 +179,6 @@ func GetAPIPort() string {
 	return apiport
 	return apiport
 }
 }
 
 
-// GetCheckinInterval - get check in interval for nodes
-func GetCheckinInterval() string {
-	seconds := "15"
-	if os.Getenv("CHECKIN_INTERVAL") != "" {
-		seconds = os.Getenv("CHECKIN_INTERVAL")
-	} else if config.Config.Server.CheckinInterval != "" {
-		seconds = config.Config.Server.CheckinInterval
-	}
-	return seconds
-}
-
 // GetDefaultNodeLimit - get node limit if one is set
 // GetDefaultNodeLimit - get node limit if one is set
 func GetDefaultNodeLimit() int32 {
 func GetDefaultNodeLimit() int32 {
 	var limit int32
 	var limit int32
@@ -208,6 +199,8 @@ func GetGRPCConnString() string {
 		conn = os.Getenv("SERVER_GRPC_CONN_STRING")
 		conn = os.Getenv("SERVER_GRPC_CONN_STRING")
 	} else if config.Config.Server.GRPCConnString != "" {
 	} else if config.Config.Server.GRPCConnString != "" {
 		conn = config.Config.Server.GRPCConnString
 		conn = config.Config.Server.GRPCConnString
+	} else {
+		conn = GetGRPCHost() + ":" + GetGRPCPort()
 	}
 	}
 	return conn
 	return conn
 }
 }
@@ -252,6 +245,42 @@ func GetGRPCPort() string {
 	return grpcport
 	return grpcport
 }
 }
 
 
+// GetMQPort - gets the mq port
+func GetMQPort() string {
+	mqport := "1883"
+	if os.Getenv("MQ_PORT") != "" {
+		mqport = os.Getenv("MQ_PORT")
+	} else if config.Config.Server.MQPort != "" {
+		mqport = config.Config.Server.MQPort
+	}
+	return mqport
+}
+
+// GetGRPCPort - gets the grpc port
+func GetCommsCIDR() string {
+	netrange := "172.242.0.0/16"
+	if os.Getenv("COMMS_CIDR") != "" {
+		netrange = os.Getenv("COMMS_CIDR")
+	} else if config.Config.Server.CommsCIDR != "" {
+		netrange = config.Config.Server.CommsCIDR
+	}
+	_, _, err := net.ParseCIDR(netrange)
+	if err == nil {
+		return netrange
+	}
+	return "172.242.0.0/16"
+}
+
+// GetCommsID - gets the grpc port
+func GetCommsID() string {
+	return commsID
+}
+
+// SetCommsID - sets the commsID
+func SetCommsID(newCommsID string) {
+	commsID = newCommsID
+}
+
 // GetMessageQueueEndpoint - gets the message queue endpoint
 // GetMessageQueueEndpoint - gets the message queue endpoint
 func GetMessageQueueEndpoint() string {
 func GetMessageQueueEndpoint() string {
 	host, _ := GetPublicIP()
 	host, _ := GetPublicIP()
@@ -266,7 +295,7 @@ func GetMessageQueueEndpoint() string {
 
 
 // GetMasterKey - gets the configured master key of server
 // GetMasterKey - gets the configured master key of server
 func GetMasterKey() string {
 func GetMasterKey() string {
-	key := "secretkey"
+	key := ""
 	if os.Getenv("MASTER_KEY") != "" {
 	if os.Getenv("MASTER_KEY") != "" {
 		key = os.Getenv("MASTER_KEY")
 		key = os.Getenv("MASTER_KEY")
 	} else if config.Config.Server.MasterKey != "" {
 	} else if config.Config.Server.MasterKey != "" {
@@ -415,8 +444,8 @@ func IsGRPCSSL() bool {
 		if os.Getenv("GRPC_SSL") == "on" {
 		if os.Getenv("GRPC_SSL") == "on" {
 			isssl = true
 			isssl = true
 		}
 		}
-	} else if config.Config.Server.DNSMode != "" {
-		if config.Config.Server.DNSMode == "on" {
+	} else if config.Config.Server.GRPCSSL != "" {
+		if config.Config.Server.GRPCSSL == "on" {
 			isssl = true
 			isssl = true
 		}
 		}
 	}
 	}
@@ -438,21 +467,6 @@ func DisableRemoteIPCheck() bool {
 	return disabled
 	return disabled
 }
 }
 
 
-// DisableDefaultNet - disable default net
-func DisableDefaultNet() bool {
-	disabled := false
-	if os.Getenv("DISABLE_DEFAULT_NET") != "" {
-		if os.Getenv("DISABLE_DEFAULT_NET") == "on" {
-			disabled = true
-		}
-	} else if config.Config.Server.DisableDefaultNet != "" {
-		if config.Config.Server.DisableDefaultNet == "on" {
-			disabled = true
-		}
-	}
-	return disabled
-}
-
 // GetPublicIP - gets public ip
 // GetPublicIP - gets public ip
 func GetPublicIP() (string, error) {
 func GetPublicIP() (string, error) {
 
 
@@ -516,18 +530,7 @@ func GetSQLConn() string {
 	return sqlconn
 	return sqlconn
 }
 }
 
 
-// IsSplitDNS - checks if split dns is on
-func IsSplitDNS() bool {
-	issplit := false
-	if os.Getenv("IS_SPLIT_DNS") == "yes" {
-		issplit = true
-	} else if config.Config.Server.SplitDNS == "yes" {
-		issplit = true
-	}
-	return issplit
-}
-
-// IsSplitDNS - checks if split dns is on
+// IsHostNetwork - checks if running on host network
 func IsHostNetwork() bool {
 func IsHostNetwork() bool {
 	ishost := false
 	ishost := false
 	if os.Getenv("HOST_NETWORK") == "on" {
 	if os.Getenv("HOST_NETWORK") == "on" {
@@ -541,15 +544,25 @@ func IsHostNetwork() bool {
 // GetNodeID - gets the node id
 // GetNodeID - gets the node id
 func GetNodeID() string {
 func GetNodeID() string {
 	var id string
 	var id string
+	var err error
 	// id = getMacAddr()
 	// id = getMacAddr()
 	if os.Getenv("NODE_ID") != "" {
 	if os.Getenv("NODE_ID") != "" {
 		id = os.Getenv("NODE_ID")
 		id = os.Getenv("NODE_ID")
 	} else if config.Config.Server.NodeID != "" {
 	} else if config.Config.Server.NodeID != "" {
 		id = config.Config.Server.NodeID
 		id = config.Config.Server.NodeID
+	} else {
+		id, err = os.Hostname()
+		if err != nil {
+			return ""
+		}
 	}
 	}
 	return id
 	return id
 }
 }
 
 
+func SetNodeID(id string) {
+	config.Config.Server.NodeID = id
+}
+
 // GetServerCheckinInterval - gets the server check-in time
 // GetServerCheckinInterval - gets the server check-in time
 func GetServerCheckinInterval() int64 {
 func GetServerCheckinInterval() int64 {
 	var t = int64(5)
 	var t = int64(5)
@@ -592,22 +605,6 @@ func GetAzureTenant() string {
 	return azureTenant
 	return azureTenant
 }
 }
 
 
-// GetMacAddr - get's mac address
-func getMacAddr() string {
-	ifas, err := net.Interfaces()
-	if err != nil {
-		return ""
-	}
-	var as []string
-	for _, ifa := range ifas {
-		a := ifa.HardwareAddr.String()
-		if a != "" {
-			as = append(as, a)
-		}
-	}
-	return as[0]
-}
-
 // GetRce - sees if Rce is enabled, off by default
 // GetRce - sees if Rce is enabled, off by default
 func GetRce() bool {
 func GetRce() bool {
 	return os.Getenv("RCE") == "on" || config.Config.Server.RCE == "on"
 	return os.Getenv("RCE") == "on" || config.Config.Server.RCE == "on"

+ 4 - 2
serverctl/iptables.go

@@ -50,10 +50,12 @@ func portForwardServices() error {
 		case "dns":
 		case "dns":
 			err = iptablesPortForward("coredns", "53", "53", false)
 			err = iptablesPortForward("coredns", "53", "53", false)
 		case "ssh":
 		case "ssh":
-			err = iptablesPortForward("127.0.0.1", "22", "22", true)
+			err = iptablesPortForward("netmaker", "22", "22", false)
 		default:
 		default:
 			params := strings.Split(service, ":")
 			params := strings.Split(service, ":")
-			err = iptablesPortForward(params[0], params[1], params[2], true)
+			if len(params) == 3 {
+				err = iptablesPortForward(params[0], params[1], params[2], true)
+			}
 		}
 		}
 		if err != nil {
 		if err != nil {
 			return err
 			return err

+ 47 - 5
serverctl/serverctl.go

@@ -2,7 +2,6 @@ package serverctl
 
 
 import (
 import (
 	"errors"
 	"errors"
-	"fmt"
 	"net"
 	"net"
 	"os"
 	"os"
 	"strings"
 	"strings"
@@ -10,10 +9,55 @@ import (
 	"github.com/gravitl/netmaker/database"
 	"github.com/gravitl/netmaker/database"
 	"github.com/gravitl/netmaker/logger"
 	"github.com/gravitl/netmaker/logger"
 	"github.com/gravitl/netmaker/logic"
 	"github.com/gravitl/netmaker/logic"
+	"github.com/gravitl/netmaker/models"
 	"github.com/gravitl/netmaker/netclient/ncutils"
 	"github.com/gravitl/netmaker/netclient/ncutils"
+	"github.com/gravitl/netmaker/servercfg"
 )
 )
 
 
-const NETMAKER_BINARY_NAME = "netmaker"
+// COMMS_NETID - name of the comms network
+var COMMS_NETID string
+
+const (
+	// NETMAKER_BINARY_NAME - name of netmaker binary
+	NETMAKER_BINARY_NAME = "netmaker"
+)
+
+// InitializeCommsNetwork - Check if comms network exists (for MQ, DNS, SSH traffic), if not, create
+func InitializeCommsNetwork() error {
+
+	setCommsID()
+
+	_, err := logic.GetNetwork(COMMS_NETID)
+	if err != nil {
+		logger.Log(1, "comms net does not exist, creating")
+		var network models.Network
+		network.NetID = COMMS_NETID
+		network.AddressRange = servercfg.GetCommsCIDR()
+		network.IsPointToSite = "yes"
+		network.DefaultUDPHolePunch = "yes"
+		network.IsComms = "yes"
+		return logic.CreateNetwork(network)
+	}
+	SyncServerNetwork(COMMS_NETID)
+
+	return nil
+}
+
+// SetJWTSecret - sets the jwt secret on server startup
+func setCommsID() {
+	currentid, idErr := logic.FetchCommsNetID()
+	if idErr != nil {
+		commsid := logic.RandomString(8)
+		if err := logic.StoreCommsNetID(commsid); err != nil {
+			logger.FatalLog("something went wrong when configuring comms id")
+		}
+		COMMS_NETID = commsid
+		servercfg.SetCommsID(COMMS_NETID)
+		return
+	}
+	COMMS_NETID = currentid
+	servercfg.SetCommsID(COMMS_NETID)
+}
 
 
 // InitServerNetclient - intializes the server netclient
 // InitServerNetclient - intializes the server netclient
 // 1. Check if config directory exists, if not attempt to make
 // 1. Check if config directory exists, if not attempt to make
@@ -34,9 +78,7 @@ func InitServerNetclient() error {
 			var currentServerNode, nodeErr = logic.GetNetworkServerLocal(network.NetID)
 			var currentServerNode, nodeErr = logic.GetNetworkServerLocal(network.NetID)
 			if nodeErr == nil {
 			if nodeErr == nil {
 				if err = logic.ServerPull(&currentServerNode, true); err != nil {
 				if err = logic.ServerPull(&currentServerNode, true); err != nil {
-					logger.Log(1, fmt.Sprintf("failed pull for network %s, on server node %s",
-						network.NetID,
-						currentServerNode.ID))
+					logger.Log(1, "failed pull for network", network.NetID, ", on server node", currentServerNode.ID)
 				}
 				}
 			}
 			}
 		}
 		}