Browse Source

Merge pull request #1040 from gravitl/v0.13.0

V0.13.0
dcarns 3 years ago
parent
commit
f85ca03535
100 changed files with 1873 additions and 2991 deletions
  1. 31 0
      .github/workflows/buildandrelease.yml
  2. 28 0
      .github/workflows/docker-builder.yml
  3. 1 1
      .github/workflows/test.yml
  4. 1 3
      Dockerfile
  5. 1 1
      README.md
  6. 1 2
      auth/error.go
  7. 12 12
      compose/docker-compose.contained.yml
  8. 9 11
      compose/docker-compose.hostnetwork.yml
  9. 9 12
      compose/docker-compose.nocaddy.yml
  10. 10 10
      compose/docker-compose.nodns.yml
  11. 15 13
      compose/docker-compose.reference.yml
  12. 12 12
      compose/docker-compose.yml
  13. 1 7
      config/config.go
  14. 0 2
      config/environments/dev.yaml
  15. 0 182
      controllers/auth_grpc.go
  16. 0 1
      controllers/config/environments/dev.yaml
  17. 36 36
      controllers/dns_test.go
  18. 19 8
      controllers/ext_client.go
  19. 6 42
      controllers/network.go
  20. 33 2
      controllers/network_test.go
  21. 129 25
      controllers/node.go
  22. 0 326
      controllers/node_grpc.go
  23. 2 2
      controllers/relay.go
  24. 68 0
      controllers/server.go
  25. 0 25
      controllers/user.go
  26. 42 0
      dev.yaml
  27. 0 4
      docker/Caddyfile
  28. 6 0
      docker/Dockerfile-go-builder
  29. 1 1
      docker/Dockerfile-netclient-multiarch
  30. 11 3
      docker/mosquitto.conf
  31. 8 0
      functions/local.go
  32. 9 5
      go.mod
  33. 10 70
      go.sum
  34. 0 200
      grpc/node.pb.go
  35. 0 20
      grpc/node.proto
  36. 0 353
      grpc/node_grpc.pb.go
  37. 0 6
      grpc/types.go
  38. 0 10
      kube/components/netmaker-api.yaml
  39. 0 11
      kube/components/netmaker-backend.yaml
  40. 0 10
      kube/components/netmaker-template.yaml.backup
  41. 0 8
      kube/netmaker-template-udp.yaml
  42. 0 8
      kube/netmaker-template.yaml
  43. 4 10
      logger/util.go
  44. 3 12
      logic/accesskeys.go
  45. 0 1
      logic/dns.go
  46. 18 8
      logic/extpeers.go
  47. 62 0
      logic/ips/ips.go
  48. 50 0
      logic/ips/ips_test.go
  49. 1 1
      logic/jwts.go
  50. 51 81
      logic/networks.go
  51. 18 25
      logic/nodes.go
  52. 64 41
      logic/peers.go
  53. 52 30
      logic/server.go
  54. 0 29
      logic/serverconf.go
  55. 1 0
      logic/util.go
  56. 31 15
      logic/wireguard.go
  57. 83 70
      main.go
  58. 2 3
      models/accessToken.go
  59. 5 3
      models/dnsEntry.go
  60. 0 1
      models/intclient.go
  61. 8 17
      models/network.go
  62. 64 62
      models/node.go
  63. 17 10
      models/structs.go
  64. 1 1
      mq/handlers.go
  65. 17 4
      mq/publishers.go
  66. 58 69
      netclient/auth/auth.go
  67. 0 4
      netclient/cli_options/cmds.go
  68. 0 18
      netclient/cli_options/flags.go
  69. 17 42
      netclient/command/commands.go
  70. 29 22
      netclient/config/config.go
  71. 1 3
      netclient/daemon/freebsd.go
  72. 1 3
      netclient/daemon/macos.go
  73. 1 2
      netclient/daemon/systemd.go
  74. 85 40
      netclient/functions/common.go
  75. 82 88
      netclient/functions/daemon.go
  76. 37 97
      netclient/functions/join.go
  77. 2 59
      netclient/functions/list.go
  78. 63 0
      netclient/functions/localport.go
  79. 50 0
      netclient/functions/localport_freebsd.go
  80. 9 8
      netclient/functions/mqhandlers.go
  81. 75 60
      netclient/functions/mqpublish.go
  82. 31 76
      netclient/functions/pull.go
  83. 92 0
      netclient/functions/register.go
  84. 1 1
      netclient/local/routes.go
  85. 10 1
      netclient/local/routes_darwin.go
  86. 10 0
      netclient/local/routes_freebsd.go
  87. 10 1
      netclient/local/routes_linux.go
  88. 1 7
      netclient/ncutils/iface.go
  89. 20 14
      netclient/ncutils/netclientutils.go
  90. 1 0
      netclient/ncutils/peerhelper.go
  91. 0 346
      netclient/server/grpc.go
  92. 88 53
      netclient/wireguard/common.go
  93. 36 11
      netclient/wireguard/noquick.go
  94. 0 41
      netclient/wireguard/unix.go
  95. 0 27
      netclient/wireguard/windows.go
  96. BIN
      netmaker.exe
  97. 0 17
      nginx/netmaker-nginx-template.conf
  98. 0 11
      scripts/daemon.sh
  99. 0 1
      scripts/install-netmaker.sh
  100. 0 1
      scripts/netmaker-server.sh

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

@@ -394,3 +394,34 @@ jobs:
           overwrite: true
           prerelease: true
           asset_name: netclient-darwin-arm64
+
+  netclient-windows:
+    runs-on: ubuntu-latest
+    needs: version
+    steps:
+      - name: Checkout
+        uses: actions/checkout@v2
+      - name: Set Variables
+        run: |
+          TAG=${{needs.version.outputs.tag}}
+          VERSION=${{needs.version.outputs.version}}
+          echo "NETMAKER_VERSION=${TAG}"  >> $GITHUB_ENV
+          echo "PACKAGE_VERSION=${VERSION}" >> $GITHUB_ENV
+      - name: Setup go
+        uses: actions/setup-go@v2
+        with:
+          go-version: 1.17
+      - name: Build
+        run: |
+          cd netclient
+          env CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -ldflags="-X 'main.version=${NETMAKER_VERSION}'" -o build/netclient.exe main.go
+      - name: Upload netclient windows to Release
+        continue-on-error: true
+        uses: svenstaro/upload-release-action@v2
+        with:
+          repo_token: ${{ secrets.GITHUB_TOKEN }}
+          file: netclient/build/netclient.exe
+          tag: ${{ env.NETMAKER_VERSION }}
+          overwrite: true
+          prerelease: true
+          asset_name: netclient.exe

+ 28 - 0
.github/workflows/docker-builder.yml

@@ -0,0 +1,28 @@
+name: Build go-builder images
+
+on:
+  workflow_dispatch:
+  schedule:
+    - cron: '00 21 * * SUN'
+
+jobs:
+  go-builder:
+    runs-on: ubuntu-latest
+    steps:
+    - name: Checkout
+      uses: actions/checkout@v2
+    - name: SetUp Buildx
+      uses: docker/setup-buildx-action@v1
+    - name: Login to Dockerhub
+      uses: docker/login-action@v1
+      with:
+          username: ${{ secrets.DOCKERHUB_USERNAME }}
+          password: ${{ secrets.DOCKERHUB_TOKEN }}
+      name: Build and push to docker hub
+      uses: docker/build-push-action@v2
+      with:
+        context: .
+        load: true
+        platform: linux/amd64
+        file: ./docker/Dockerfile-go-builder
+        tags: gravitl/go-builder:latest

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

@@ -34,7 +34,7 @@ jobs:
       - name: Setup Go
         uses: actions/setup-go@v2
         with:
-          go-version: 1.17
+          go-version: 1.18
       - name: run tests
         run: |
             go test -p 1 ./... -v

+ 1 - 3
Dockerfile

@@ -1,7 +1,6 @@
 #first stage - builder
-FROM golang:1.18.0-alpine3.15 as builder
+FROM gravitl/go-builder as builder
 ARG version 
-RUN apk add build-base
 WORKDIR /app
 COPY . .
 ENV GO111MODULE=auto
@@ -17,5 +16,4 @@ RUN mkdir -p /etc/netclient/config
 COPY --from=builder /app/netmaker .
 COPY --from=builder /app/config config
 EXPOSE 8081
-EXPOSE 50051
 ENTRYPOINT ["./netmaker"]

+ 1 - 1
README.md

@@ -10,7 +10,7 @@ a platform for modern, blazing fast virtual networks
 
 <p align="center">
   <a href="https://github.com/gravitl/netmaker/releases">
-    <img src="https://img.shields.io/badge/Version-0.12.2-informational?style=flat-square" />
+    <img src="https://img.shields.io/badge/Version-0.13.0-informational?style=flat-square" />
   </a>
   <a href="https://hub.docker.com/r/gravitl/netmaker/tags">
     <img src="https://img.shields.io/docker/pulls/gravitl/netmaker" />

+ 1 - 2
auth/error.go

@@ -6,5 +6,4 @@ const oauthNotConfigured = `<!DOCTYPE html><html>
 <h3>Your Netmaker server does not have OAuth configured.</h3>
 <p>Please visit the docs <a href="https://docs.netmaker.org/oauth.html" target="_blank" rel="noopener">here</a> to learn how to.</p>
 </body>
-</html>
-`
+</html>`

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

@@ -3,10 +3,11 @@ version: "3.4"
 services:
   netmaker:
     container_name: netmaker
-    image: gravitl/netmaker:v0.12.2
+    image: gravitl/netmaker:v0.13.0
     volumes:
       - dnsconfig:/root/config/dnsconfig
       - sqldata:/root/data
+      - /root/certs:/etc/netmaker/
     cap_add: 
       - NET_ADMIN
       - NET_RAW
@@ -14,18 +15,16 @@ services:
     sysctls:
       - net.ipv4.ip_forward=1
       - net.ipv4.conf.all.src_valid_mark=1
+      - net.ipv6.conf.all.disable_ipv6=0
     restart: always
     environment:
+      SERVER_NAME: "broker.NETMAKER_BASE_DOMAIN"
       SERVER_HOST: "SERVER_PUBLIC_IP"
       SERVER_API_CONN_STRING: "api.NETMAKER_BASE_DOMAIN:443"
-      SERVER_GRPC_CONN_STRING: "grpc.NETMAKER_BASE_DOMAIN:443"
       COREDNS_ADDR: "SERVER_PUBLIC_IP"
-      GRPC_SSL: "on"
       DNS_MODE: "on"
       SERVER_HTTP_HOST: "api.NETMAKER_BASE_DOMAIN"
-      SERVER_GRPC_HOST: "grpc.NETMAKER_BASE_DOMAIN"
       API_PORT: "8081"
-      GRPC_PORT: "50051"
       CLIENT_MODE: "on"
       MASTER_KEY: "REPLACE_MASTER_KEY"
       CORS_ALLOWED_ORIGIN: "*"
@@ -34,18 +33,16 @@ services:
       NODE_ID: "netmaker-server-1"
       MQ_HOST: "mq"
       HOST_NETWORK: "off"
-      MANAGE_IPTABLES: "on"
-      PORT_FORWARD_SERVICES: "mq"
       VERBOSITY: "1"
+      MANAGE_IPTABLES: "off"
     ports:
       - "51821-51830:51821-51830/udp"
       - "8081:8081"
-      - "50051:50051"
   netmaker-ui:
     container_name: netmaker-ui
     depends_on:
       - netmaker
-    image: gravitl/netmaker-ui:v0.12.2
+    image: gravitl/netmaker-ui:v0.13.0
     links:
       - "netmaker:api"
     ports:
@@ -73,13 +70,17 @@ services:
       - caddy_data:/data
       - caddy_conf:/config
   mq:
-    image: eclipse-mosquitto:2.0.14
+    image: eclipse-mosquitto:2.0.11-openssl
+    depends_on:
+      - netmaker
     container_name: mq
     restart: unless-stopped
     ports:
-      - "1883:1883"
+      - "127.0.0.1:1883:1883"
+      - "8883:8883"
     volumes:
       - /root/mosquitto.conf:/mosquitto/config/mosquitto.conf
+      - /root/certs/:/mosquitto/certs/
       - mosquitto_data:/mosquitto/data
       - mosquitto_logs:/mosquitto/log
 volumes:
@@ -89,4 +90,3 @@ volumes:
   dnsconfig: {}
   mosquitto_data: {}
   mosquitto_logs: {}
-

+ 9 - 11
compose/docker-compose.hostnetwork.yml

@@ -3,12 +3,13 @@ version: "3.4"
 services:
   netmaker:
     container_name: netmaker
-    image: gravitl/netmaker:v0.12.2
+    image: gravitl/netmaker:v0.13.0
     volumes:
       - dnsconfig:/root/config/dnsconfig
       - /usr/bin/wg:/usr/bin/wg
       - sqldata:/root/data
       - /run/xtables.lock:/run/xtables.lock
+      - /root/certs:/etc/netmaker/
     cap_add:
       - NET_ADMIN
       - NET_RAW
@@ -16,32 +17,27 @@ services:
     network_mode: host
     restart: always
     environment:
+      SERVER_NAME: "broker.NETMAKER_BASE_DOMAIN"
       SERVER_HOST: "SERVER_PUBLIC_IP"
       SERVER_API_CONN_STRING: "api.NETMAKER_BASE_DOMAIN:443"
-      SERVER_GRPC_CONN_STRING: "grpc.NETMAKER_BASE_DOMAIN:443"
       COREDNS_ADDR: "SERVER_PUBLIC_IP"
-      GRPC_SSL: "on"
       DNS_MODE: "on"
       SERVER_HTTP_HOST: "api.NETMAKER_BASE_DOMAIN"
-      SERVER_GRPC_HOST: "grpc.NETMAKER_BASE_DOMAIN"
       API_PORT: "8081"
-      GRPC_PORT: "50051"
       CLIENT_MODE: "on"
       MASTER_KEY: "REPLACE_MASTER_KEY"
-      SERVER_GRPC_WIREGUARD: "off"
       CORS_ALLOWED_ORIGIN: "*"
       DISPLAY_KEYS: "on"
       DATABASE: "sqlite"
       HOST_NETWORK: "on"
       NODE_ID: "netmaker-server-1"
-      MANAGE_IPTABLES: "on"
-      PORT_FORWARD_SERVICES: ""
       VERBOSITY: "1"
+      MANAGE_IPTABLES: "off"
   netmaker-ui:
     container_name: netmaker-ui
     depends_on:
       - netmaker
-    image: gravitl/netmaker-ui:0.12.2
+    image: gravitl/netmaker-ui:v0.13.0
     links:
       - "netmaker:api"
     ports:
@@ -72,13 +68,15 @@ services:
       - caddy_data:/data
       - caddy_conf:/config
   mq:
-    image: eclipse-mosquitto:2.0.14
+    image: eclipse-mosquitto:2.0.11-openssl
     container_name: mq
     restart: unless-stopped
     ports:
-      - "1883:1883"
+      - "127.0.0.1:1883:1883"
+      - "8883:8883"    
     volumes:
       - /root/mosquitto.conf:/mosquitto/config/mosquitto.conf
+      - /root/certs/:/mosquitto/certs/
       - mosquitto_data:/mosquitto/data
       - mosquitto_logs:/mosquitto/log
 volumes:

+ 9 - 12
compose/docker-compose.nocaddy.yml

@@ -3,10 +3,11 @@ version: "3.4"
 services:
   netmaker:
     container_name: netmaker
-    image: gravitl/netmaker:v0.12.2
+    image: gravitl/netmaker:v0.13.0
     volumes:
       - dnsconfig:/root/config/dnsconfig
       - sqldata:/root/data
+      - /root/certs:/etc/netmaker/
     cap_add: 
       - NET_ADMIN
       - NET_RAW
@@ -14,18 +15,16 @@ services:
     sysctls:
       - net.ipv4.ip_forward=1
       - net.ipv4.conf.all.src_valid_mark=1
+      - net.ipv6.conf.all.disable_ipv6=0
     restart: always
     environment:
+      SERVER_NAME: "broker.NETMAKER_BASE_DOMAIN"
       SERVER_HOST: "SERVER_PUBLIC_IP"
       SERVER_API_CONN_STRING: "api.NETMAKER_BASE_DOMAIN:443"
-      SERVER_GRPC_CONN_STRING: "grpc.NETMAKER_BASE_DOMAIN:443"
       COREDNS_ADDR: "SERVER_PUBLIC_IP"
-      GRPC_SSL: "on"
       DNS_MODE: "on"
       SERVER_HTTP_HOST: "api.NETMAKER_BASE_DOMAIN"
-      SERVER_GRPC_HOST: "grpc.NETMAKER_BASE_DOMAIN"
       API_PORT: "8081"
-      GRPC_PORT: "50051"
       CLIENT_MODE: "on"
       MASTER_KEY: "REPLACE_MASTER_KEY"
       CORS_ALLOWED_ORIGIN: "*"
@@ -34,18 +33,16 @@ services:
       NODE_ID: "netmaker-server-1"
       MQ_HOST: "mq"
       HOST_NETWORK: "off"
-      MANAGE_IPTABLES: "on"
-      PORT_FORWARD_SERVICES: "mq"
       VERBOSITY: "1"
+      MANAGE_IPTABLES: "off"
     ports:
       - "51821-51830:51821-51830/udp"
       - "8081:8081"
-      - "50051:50051"
   netmaker-ui:
     container_name: netmaker-ui
     depends_on:
       - netmaker
-    image: gravitl/netmaker-ui:v0.12.2
+    image: gravitl/netmaker-ui:v0.13.0
     links:
       - "netmaker:api"
     ports:
@@ -66,11 +63,12 @@ services:
     volumes:
       - dnsconfig:/root/dnsconfig
   mq:
-    image: eclipse-mosquitto:2.0.14
+    image: eclipse-mosquitto:2.0.11-openssl
     container_name: mq
     restart: unless-stopped
     ports:
-      - "1883:1883"
+      - "127.0.0.1:1883:1883"
+      - "8883:8883"
     volumes:
       - /root/mosquitto.conf:/mosquitto/config/mosquitto.conf
       - mosquitto_data:/mosquitto/data
@@ -80,4 +78,3 @@ volumes:
   dnsconfig: {}
   mosquitto_data: {}
   mosquitto_logs: {}
-

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

@@ -3,10 +3,11 @@ version: "3.4"
 services:
   netmaker:
     container_name: netmaker
-    image: gravitl/netmaker:v0.12.2
+    image: gravitl/netmaker:v0.13.0
     volumes:
       - dnsconfig:/root/config/dnsconfig
       - sqldata:/root/data
+      - /root/certs:/etc/netmaker/
     cap_add: 
       - NET_ADMIN
       - NET_RAW
@@ -14,18 +15,16 @@ services:
     sysctls:
       - net.ipv4.ip_forward=1
       - net.ipv4.conf.all.src_valid_mark=1
+      - net.ipv6.conf.all.disable_ipv6=0
     restart: always
     environment:
+      SERVER_NAME: "broker.NETMAKER_BASE_DOMAIN"
       SERVER_HOST: "SERVER_PUBLIC_IP"
       SERVER_API_CONN_STRING: "api.NETMAKER_BASE_DOMAIN:443"
-      SERVER_GRPC_CONN_STRING: "grpc.NETMAKER_BASE_DOMAIN:443"
       COREDNS_ADDR: "SERVER_PUBLIC_IP"
-      GRPC_SSL: "on"
       DNS_MODE: "off"
       SERVER_HTTP_HOST: "api.NETMAKER_BASE_DOMAIN"
-      SERVER_GRPC_HOST: "grpc.NETMAKER_BASE_DOMAIN"
       API_PORT: "8081"
-      GRPC_PORT: "50051"
       CLIENT_MODE: "on"
       MASTER_KEY: "REPLACE_MASTER_KEY"
       CORS_ALLOWED_ORIGIN: "*"
@@ -34,9 +33,8 @@ services:
       NODE_ID: "netmaker-server-1"
       MQ_HOST: "mq"
       HOST_NETWORK: "off"
-      MANAGE_IPTABLES: "on"
-      PORT_FORWARD_SERVICES: "mq"
       VERBOSITY: "1"
+      MANAGE_IPTABLES: "off"
     ports:
       - "51821-51830:51821-51830/udp"
       - "8081:8081"
@@ -45,7 +43,7 @@ services:
     container_name: netmaker-ui
     depends_on:
       - netmaker
-    image: gravitl/netmaker-ui:v0.12.2
+    image: gravitl/netmaker-ui:v0.13.0
     links:
       - "netmaker:api"
     ports:
@@ -64,15 +62,17 @@ services:
       - caddy_data:/data
       - caddy_conf:/config
   mq:
-    image: eclipse-mosquitto:2.0.14
+    image: eclipse-mosquitto:2.0.11-openssl
     container_name: mq
     restart: unless-stopped
     ports:
-      - "1883:1883"
+      - "127.0.0.1:1883:1883"
+      - "8883:8883" 
     volumes:
       - /root/mosquitto.conf:/mosquitto/config/mosquitto.conf
       - mosquitto_data:/mosquitto/data
       - mosquitto_logs:/mosquitto/log
+      - /root/certs/:/mosquitto/certs/
 volumes:
   caddy_data: {}
   caddy_conf: {}

+ 15 - 13
compose/docker-compose.reference.yml

@@ -2,10 +2,11 @@ services:
   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.
     container_name: netmaker
-    image: gravitl/netmaker:v0.12.2
+    image: gravitl/netmaker:v0.13.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)
       - dnsconfig:/root/config/dnsconfig # Netmaker writes Corefile to this location, which gets mounted by CoreDNS for DNS configuration.
       - sqldata:/root/data
+      - /root/certs:/etc/netmaker/ # cert management location
     cap_add: # Necessary capabilities to set iptables when running in container
       - NET_ADMIN
       - NET_RAW
@@ -13,38 +14,37 @@ services:
     sysctls:
       - net.ipv4.ip_forward=1
       - net.ipv4.conf.all.src_valid_mark=1
+      - net.ipv6.conf.all.disable_ipv6=0
     restart: always
     network_mode: host # Must configure with very particular settngs for host networking to work. Do not just set on!
     environment:
-      SERVER_HOST: "" # All the Docker Compose files pre-populate this with HOST_IP, which you replace as part of the install instructions. This will set both HTTP and GRPC host.
-      SERVER_HTTP_HOST: "127.0.0.1" # Overrides SERVER_HOST if set. Useful for making HTTP and GRPC available via different interfaces/networks.
-      SERVER_GRPC_HOST: "127.0.0.1" # Overrides SERVER_HOST if set. Useful for making HTTP and GRPC available via different interfaces/networks.
+      SERVER_NAME: "" # The domain/host IP indicating the mq broker address
+      SERVER_HOST: "" # All the Docker Compose files pre-populate this with HOST_IP, which you replace as part of the install instructions. This will set the HTTP host.
+      SERVER_HTTP_HOST: "127.0.0.1" # Overrides SERVER_HOST if set. Useful for making HTTP available via different interfaces/networks.
       API_PORT: 8081 # The HTTP API port for Netmaker. Used for API calls / communication from front end. If changed, need to change port of BACKEND_URL for netmaker-ui.
-      GRPC_PORT: 50051 # The GRPC port for Netmaker. Used for communications from nodes.
       CLIENT_MODE: "on" # on if netmaker should run its own client, off if not.
       MASTER_KEY: "secretkey" # The admin master key for accessing the API. Change this in any production installation.
       CORS_ALLOWED_ORIGIN: "*" # The "allowed origin" for API requests. Change to restrict where API requests can come from.
       REST_BACKEND: "on" # Enables the REST backend (API running on API_PORT at SERVER_HTTP_HOST). Change to "off" to turn off.
-      AGENT_BACKEND: "on" # Enables the AGENT backend (GRPC running on GRPC_PORT at SERVER_GRPC_HOST). Change to "off" to turn off.
       DNS_MODE: "on" # Enables DNS Mode, meaning config files will be generated for CoreDNS. Note, turning "off" does not remove CoreDNS. You still need to remove CoreDNS from compose file.
       DISABLE_REMOTE_IP_CHECK: "off" # If turned "on", Server will not set Host based on remote IP check. This is already overridden if SERVER_HOST is set. Turned "off" by default.
-      GRPC_SSL: "off" # Tells clients to use SSL to connect to GRPC. Switch to on to turn on.
       COREDNS_ADDR: "" # Address of the CoreDNS server. Defaults to SERVER_HOST
       DISPLAY_KEYS: "on" # Show keys permanently in UI (until deleted) as opposed to 1-time display.
       SERVER_API_CONN_STRING: "" # Changes the api connection string. IP:PORT format. By default is empty and uses SERVER_HOST:API_PORT
-      SERVER_GRPC_CONN_STRING: "" # Changes the grpc connection string. IP:PORT format. By default is empty and uses SERVER_HOST:GRPC_PORT
       RCE: "off" # Enables setting PostUp and PostDown (arbitrary commands) on nodes from the server. Off by default.
       NODE_ID: "" # Sets the name/id of the nodes that the server creates. Necessary for HA configurations to identify between servers (for instance, netmaker-1, netmaker-2, etc). For non-HA deployments, is not necessary.
       TELEMETRY: "on" # Whether or not to send telemetry data to help improve Netmaker. Switch to "off" to opt out of sending telemetry.
       MQ_HOST: "mq" # the address of the mq server. If running from docker compose it will be "mq". Otherwise, need to input address. If using "host networking", it will find and detect the IP of the mq container.
       HOST_NETWORK: "off" # whether or not host networking is turned on. Only turn on if configured for host networking (see docker-compose.hostnetwork.yml). Will set host-level settings like iptables.
-      MANAGE_IPTABLES: "on" # set iptables on the machine being managed in order to forward properly from wireguard interface to MQ and other services listed in "port forward services"
-      PORT_FORWARD_SERVICES: "mq,dns,ssh" #services for which to configure port forwarding on the machine. 'ssh' forwards port 22 over wireguard, enabling ssh to server over wireguard. dns enables private dns over wireguard. mq enables mq.
+      MANAGE_IPTABLES: "off" # deprecated
+    ports:
+      - "51821-51830:51821-51830/udp"
+      - "8081:8081"
   netmaker-ui: # The Netmaker UI Component
     container_name: netmaker-ui
     depends_on:
       - netmaker
-    image: gravitl/netmaker-ui:v0.12.2
+    image: gravitl/netmaker-ui:v0.13.0
     links:
       - "netmaker:api"
     ports:
@@ -72,15 +72,17 @@ services:
       - caddy_data:/data
       - caddy_conf:/config  
   mq: # the MQTT broker for netmaker
-    image: eclipse-mosquitto:2.0.14
+    image: eclipse-mosquitto:2.0.11-openssl
     container_name: mq
     restart: unless-stopped
     ports:
-      - "1883:1883"
+      - "127.0.0.1:1883:1883"
+      - "8883:8883" 
     volumes:
       - /root/mosquitto.conf:/mosquitto/config/mosquitto.conf # need to pull conf file from github before running (under docker/mosquitto.conf)
       - mosquitto_data:/mosquitto/data
       - mosquitto_logs:/mosquitto/log
+      - /root/certs/:/mosquitto/certs/
 volumes:
   caddy_data: {} # storage for caddy data
   caddy_conf: {} # storage for caddy configuration file

+ 12 - 12
compose/docker-compose.yml

@@ -3,10 +3,11 @@ version: "3.4"
 services:
   netmaker:
     container_name: netmaker
-    image: gravitl/netmaker:v0.12.2
+    image: gravitl/netmaker:v0.13.0
     volumes:
       - dnsconfig:/root/config/dnsconfig
       - sqldata:/root/data
+      - /root/certs:/etc/netmaker/
     cap_add: 
       - NET_ADMIN
       - NET_RAW
@@ -14,18 +15,16 @@ services:
     sysctls:
       - net.ipv4.ip_forward=1
       - net.ipv4.conf.all.src_valid_mark=1
+      - net.ipv6.conf.all.disable_ipv6=0
     restart: always
     environment:
+      SERVER_NAME: "broker.NETMAKER_BASE_DOMAIN"
       SERVER_HOST: "SERVER_PUBLIC_IP"
       SERVER_API_CONN_STRING: "api.NETMAKER_BASE_DOMAIN:443"
-      SERVER_GRPC_CONN_STRING: "grpc.NETMAKER_BASE_DOMAIN:443"
       COREDNS_ADDR: "SERVER_PUBLIC_IP"
-      GRPC_SSL: "on"
       DNS_MODE: "on"
       SERVER_HTTP_HOST: "api.NETMAKER_BASE_DOMAIN"
-      SERVER_GRPC_HOST: "grpc.NETMAKER_BASE_DOMAIN"
       API_PORT: "8081"
-      GRPC_PORT: "50051"
       CLIENT_MODE: "on"
       MASTER_KEY: "REPLACE_MASTER_KEY"
       CORS_ALLOWED_ORIGIN: "*"
@@ -34,18 +33,16 @@ services:
       NODE_ID: "netmaker-server-1"
       MQ_HOST: "mq"
       HOST_NETWORK: "off"
-      MANAGE_IPTABLES: "on"
-      PORT_FORWARD_SERVICES: "mq"
       VERBOSITY: "1"
+      MANAGE_IPTABLES: "off"
     ports:
       - "51821-51830:51821-51830/udp"
       - "8081:8081"
-      - "50051:50051"
   netmaker-ui:
     container_name: netmaker-ui
     depends_on:
       - netmaker
-    image: gravitl/netmaker-ui:v0.12.2
+    image: gravitl/netmaker-ui:v0.13.0
     links:
       - "netmaker:api"
     ports:
@@ -73,13 +70,17 @@ services:
       - caddy_data:/data
       - caddy_conf:/config
   mq:
-    image: eclipse-mosquitto:2.0.14
+    image: eclipse-mosquitto:2.0.11-openssl
+    depends_on:
+      - netmaker
     container_name: mq
     restart: unless-stopped
     ports:
-      - "1883:1883"
+      - "127.0.0.1:1883:1883"
+      - "8883:8883"
     volumes:
       - /root/mosquitto.conf:/mosquitto/config/mosquitto.conf
+      - /root/certs/:/mosquitto/certs/
       - mosquitto_data:/mosquitto/data
       - mosquitto_logs:/mosquitto/log
 volumes:
@@ -89,4 +90,3 @@ volumes:
   dnsconfig: {}
   mosquitto_data: {}
   mosquitto_logs: {}
-

+ 1 - 7
config/config.go

@@ -36,10 +36,6 @@ type ServerConfig struct {
 	APIConnString         string `yaml:"apiconn"`
 	APIHost               string `yaml:"apihost"`
 	APIPort               string `yaml:"apiport"`
-	GRPCConnString        string `yaml:"grpcconn"`
-	GRPCHost              string `yaml:"grpchost"`
-	GRPCPort              string `yaml:"grpcport"`
-	GRPCSecure            string `yaml:"grpcsecure"`
 	MQHOST                string `yaml:"mqhost"`
 	MasterKey             string `yaml:"masterkey"`
 	DNSKey                string `yaml:"dnskey"`
@@ -51,7 +47,6 @@ type ServerConfig struct {
 	ClientMode            string `yaml:"clientmode"`
 	DNSMode               string `yaml:"dnsmode"`
 	DisableRemoteIPCheck  string `yaml:"disableremoteipcheck"`
-	GRPCSSL               string `yaml:"grpcssl"`
 	Version               string `yaml:"version"`
 	SQLConn               string `yaml:"sqlconn"`
 	Platform              string `yaml:"platform"`
@@ -71,9 +66,8 @@ type ServerConfig struct {
 	ManageIPTables        string `yaml:"manageiptables"`
 	PortForwardServices   string `yaml:"portforwardservices"`
 	HostNetwork           string `yaml:"hostnetwork"`
-	CommsCIDR             string `yaml:"commscidr"`
 	MQPort                string `yaml:"mqport"`
-	CommsID               string `yaml:"commsid"`
+	Server                string `yaml:"server"`
 }
 
 // SQLConfig - Generic SQL Config

+ 0 - 2
config/environments/dev.yaml

@@ -1,8 +1,6 @@
 server:
   apihost: "" # defaults to 127.0.0.1 or remote ip (SERVER_HOST) if DisableRemoteIPCheck is not set to true. SERVER_API_HOST if set
   apiport: "" # defaults to 8081 or HTTP_PORT (if set)
-  grpchost: "" # defaults to 127.0.0.1 or remote ip (SERVER_HOST) if DisableRemoteIPCheck is not set to true. SERVER_GRPC_HOST if set.
-  grpcport: "" # defaults to 50051 or GRPC_PORT (if set)
   masterkey: "" # defaults to 'secretkey' or MASTER_KEY (if set)
   allowedorigin: "" # defaults to '*' or CORS_ALLOWED_ORIGIN (if set)
   restbackend: "" # defaults to "on" or REST_BACKEND (if set)

+ 0 - 182
controllers/auth_grpc.go

@@ -1,182 +0,0 @@
-package controller
-
-import (
-	"context"
-	"encoding/json"
-	"errors"
-
-	"github.com/gravitl/netmaker/database"
-	"github.com/gravitl/netmaker/functions"
-	nodepb "github.com/gravitl/netmaker/grpc"
-	"github.com/gravitl/netmaker/logic"
-	"github.com/gravitl/netmaker/models"
-	"golang.org/x/crypto/bcrypt"
-	"google.golang.org/grpc"
-	"google.golang.org/grpc/codes"
-	"google.golang.org/grpc/metadata"
-	"google.golang.org/grpc/status"
-)
-
-// AuthServerUnaryInterceptor - auth unary interceptor logic
-func AuthServerUnaryInterceptor(ctx context.Context,
-	req interface{},
-	info *grpc.UnaryServerInfo,
-	handler grpc.UnaryHandler) (interface{}, error) {
-	// Skip authorize when GetJWT is requested
-
-	if info.FullMethod != "/node.NodeService/Login" {
-		if info.FullMethod != "/node.NodeService/CreateNode" {
-
-			err := grpcAuthorize(ctx)
-			if err != nil {
-				return nil, err
-			}
-		}
-	}
-
-	// Calls the handler
-	h, err := handler(ctx, req)
-
-	return h, err
-}
-
-// AuthServerStreamInterceptor - auth stream interceptor
-func AuthServerStreamInterceptor(
-	srv interface{},
-	stream grpc.ServerStream,
-	info *grpc.StreamServerInfo,
-	handler grpc.StreamHandler,
-) error {
-	if info.FullMethod == "/node.NodeService/GetPeers" {
-		if err := grpcAuthorize(stream.Context()); err != nil {
-			return err
-		}
-	}
-
-	// Calls the handler
-	return handler(srv, stream)
-}
-
-func grpcAuthorize(ctx context.Context) error {
-
-	md, ok := metadata.FromIncomingContext(ctx)
-
-	if !ok {
-		return status.Errorf(codes.InvalidArgument, "Retrieving metadata is failed")
-	}
-
-	authHeader, ok := md["authorization"]
-	if !ok {
-		return status.Errorf(codes.Unauthenticated, "Authorization token is not supplied")
-	}
-
-	authToken := authHeader[0]
-
-	nodeID, _, network, err := logic.VerifyToken(authToken)
-	if err != nil {
-		return err
-	}
-
-	networkexists, err := functions.NetworkExists(network)
-
-	if err != nil {
-		return status.Errorf(codes.Unauthenticated, "Unauthorized. Network does not exist: "+network)
-	}
-	node, err := logic.GetNodeByID(nodeID)
-	if database.IsEmptyRecord(err) {
-		// == DELETE replace logic after 2 major version updates ==
-		if node, err = logic.GetDeletedNodeByID(node.ID); err == nil {
-			if functions.RemoveDeletedNode(node.ID) {
-				return status.Errorf(codes.Unauthenticated, models.NODE_DELETE)
-			}
-			return status.Errorf(codes.Unauthenticated, "Node does not exist.")
-		}
-		return status.Errorf(codes.Unauthenticated, "Empty record")
-	}
-	if err != nil || node.ID == "" {
-		return status.Errorf(codes.Unauthenticated, "Node does not exist.")
-	}
-
-	if !networkexists {
-		return status.Errorf(codes.Unauthenticated, "Network does not exist.")
-	}
-	return nil
-}
-
-// Login - node authenticates using its password and retrieves a JWT for authorization.
-func (s *NodeServiceServer) Login(ctx context.Context, req *nodepb.Object) (*nodepb.Object, error) {
-
-	var reqNode, err = getNodeFromRequestData(req.Data)
-	if err != nil {
-		return nil, err
-	}
-
-	nodeID := reqNode.ID
-	network := reqNode.Network
-	password := reqNode.Password
-	macaddress := reqNode.MacAddress
-
-	var result models.NodeAuth
-
-	if nodeID == "" {
-		//TODO: Set Error  response
-		err = errors.New("missing node ID")
-		return nil, err
-	} else if password == "" {
-		err = errors.New("missing password")
-		return nil, err
-	} else {
-		//Search DB for node with ID. Ignore pending nodes (they should not be able to authenticate with API until approved).
-		collection, err := database.FetchRecords(database.NODES_TABLE_NAME)
-		if err != nil {
-			return nil, err
-		}
-		var found = false
-		for _, value := range collection {
-			if err = json.Unmarshal([]byte(value), &result); err != nil {
-				continue // finish going through nodes
-			}
-			if result.ID == nodeID && result.Network == network {
-				found = true
-				break
-			}
-		}
-
-		if !found {
-			deletedNode, err := database.FetchRecord(database.DELETED_NODES_TABLE_NAME, nodeID)
-			if err != nil {
-				err = errors.New("node not found")
-				return nil, err
-			}
-			if err = json.Unmarshal([]byte(deletedNode), &result); err != nil {
-				err = errors.New("node data corrupted")
-				return nil, err
-			}
-		}
-
-		//compare password from request to stored password in database
-		//might be able to have a common hash (certificates?) and compare those so that a password isn't passed in in plain text...
-		//TODO: Consider a way of hashing the password client side before sending, or using certificates
-		err = bcrypt.CompareHashAndPassword([]byte(result.Password), []byte(password))
-		if err != nil && result.Password != password {
-			return nil, err
-		} else {
-			//Create a new JWT for the node
-			tokenString, err := logic.CreateJWT(result.ID, macaddress, result.Network)
-
-			if err != nil {
-				return nil, err
-			}
-			if tokenString == "" {
-				err = errors.New("something went wrong, could not retrieve token")
-				return nil, err
-			}
-
-			response := &nodepb.Object{
-				Data: tokenString,
-				Type: nodepb.ACCESS_TOKEN,
-			}
-			return response, nil
-		}
-	}
-}

+ 0 - 1
controllers/config/environments/dev.yaml

@@ -1,7 +1,6 @@
 server:
   host: "localhost"
   apiport: "8081"
-  grpcport: "50051"
   masterkey: ""
   allowedorigin: "*"
   restbackend: true            

+ 36 - 36
controllers/dns_test.go

@@ -21,14 +21,14 @@ func TestGetAllDNS(t *testing.T) {
 		assert.Equal(t, []models.DNSEntry(nil), entries)
 	})
 	t.Run("OneEntry", func(t *testing.T) {
-		entry := models.DNSEntry{"10.0.0.3", "newhost", "skynet"}
+		entry := models.DNSEntry{"10.0.0.3", "", "newhost", "skynet"}
 		CreateDNS(entry)
 		entries, err := logic.GetAllDNS()
 		assert.Nil(t, err)
 		assert.Equal(t, 1, len(entries))
 	})
 	t.Run("MultipleEntry", func(t *testing.T) {
-		entry := models.DNSEntry{"10.0.0.7", "anotherhost", "skynet"}
+		entry := models.DNSEntry{"10.0.0.7", "", "anotherhost", "skynet"}
 		CreateDNS(entry)
 		entries, err := logic.GetAllDNS()
 		assert.Nil(t, err)
@@ -83,14 +83,14 @@ func TestGetCustomDNS(t *testing.T) {
 		assert.Equal(t, 0, len(dns))
 	})
 	t.Run("EntryExist", func(t *testing.T) {
-		entry := models.DNSEntry{"10.0.0.3", "newhost", "skynet"}
+		entry := models.DNSEntry{"10.0.0.3", "", "newhost", "skynet"}
 		CreateDNS(entry)
 		dns, err := logic.GetCustomDNS("skynet")
 		assert.Nil(t, err)
 		assert.Equal(t, 1, len(dns))
 	})
 	t.Run("MultipleEntries", func(t *testing.T) {
-		entry := models.DNSEntry{"10.0.0.4", "host4", "skynet"}
+		entry := models.DNSEntry{"10.0.0.4", "", "host4", "skynet"}
 		CreateDNS(entry)
 		dns, err := logic.GetCustomDNS("skynet")
 		assert.Nil(t, err)
@@ -109,7 +109,7 @@ func TestGetDNSEntryNum(t *testing.T) {
 		assert.Equal(t, 0, num)
 	})
 	t.Run("NodeExists", func(t *testing.T) {
-		entry := models.DNSEntry{"10.0.0.2", "newhost", "skynet"}
+		entry := models.DNSEntry{"10.0.0.2", "", "newhost", "skynet"}
 		_, err := CreateDNS(entry)
 		assert.Nil(t, err)
 		num, err := logic.GetDNSEntryNum("newhost", "skynet")
@@ -128,7 +128,7 @@ func TestGetDNS(t *testing.T) {
 		assert.Nil(t, dns)
 	})
 	t.Run("CustomDNSExists", func(t *testing.T) {
-		entry := models.DNSEntry{"10.0.0.2", "newhost", "skynet"}
+		entry := models.DNSEntry{"10.0.0.2", "", "newhost", "skynet"}
 		_, err := CreateDNS(entry)
 		assert.Nil(t, err)
 		dns, err := logic.GetDNS("skynet")
@@ -148,7 +148,7 @@ func TestGetDNS(t *testing.T) {
 		assert.Equal(t, 1, len(dns))
 	})
 	t.Run("NodeAndCustomDNS", func(t *testing.T) {
-		entry := models.DNSEntry{"10.0.0.2", "newhost", "skynet"}
+		entry := models.DNSEntry{"10.0.0.2", "", "newhost", "skynet"}
 		_, err := CreateDNS(entry)
 		dns, err := logic.GetDNS("skynet")
 		t.Log(dns)
@@ -165,7 +165,7 @@ func TestCreateDNS(t *testing.T) {
 	deleteAllDNS(t)
 	deleteAllNetworks()
 	createNet()
-	entry := models.DNSEntry{"10.0.0.2", "newhost", "skynet"}
+	entry := models.DNSEntry{"10.0.0.2", "", "newhost", "skynet"}
 	dns, err := CreateDNS(entry)
 	assert.Nil(t, err)
 	assert.Equal(t, "newhost", dns.Name)
@@ -204,7 +204,7 @@ func TestSetDNS(t *testing.T) {
 		assert.Contains(t, string(content), "testnode.skynet")
 	})
 	t.Run("EntryExists", func(t *testing.T) {
-		entry := models.DNSEntry{"10.0.0.3", "newhost", "skynet"}
+		entry := models.DNSEntry{"10.0.0.3", "", "newhost", "skynet"}
 		CreateDNS(entry)
 		err := logic.SetDNS()
 		assert.Nil(t, err)
@@ -224,7 +224,7 @@ func TestGetDNSEntry(t *testing.T) {
 	deleteAllNetworks()
 	createNet()
 	createTestNode()
-	entry := models.DNSEntry{"10.0.0.2", "newhost", "skynet"}
+	entry := models.DNSEntry{"10.0.0.2", "", "newhost", "skynet"}
 	CreateDNS(entry)
 	t.Run("wrong net", func(t *testing.T) {
 		entry, err := GetDNSEntry("newhost", "w286 Toronto Street South, Uxbridge, ONirecat")
@@ -280,7 +280,7 @@ func TestDeleteDNS(t *testing.T) {
 	deleteAllDNS(t)
 	deleteAllNetworks()
 	createNet()
-	entry := models.DNSEntry{"10.0.0.2", "newhost", "skynet"}
+	entry := models.DNSEntry{"10.0.0.2", "", "newhost", "skynet"}
 	CreateDNS(entry)
 	t.Run("EntryExists", func(t *testing.T) {
 		err := logic.DeleteDNS("newhost", "skynet")
@@ -302,36 +302,36 @@ func TestValidateDNSUpdate(t *testing.T) {
 	deleteAllDNS(t)
 	deleteAllNetworks()
 	createNet()
-	entry := models.DNSEntry{"10.0.0.2", "myhost", "skynet"}
+	entry := models.DNSEntry{"10.0.0.2", "", "myhost", "skynet"}
 	t.Run("BadNetwork", func(t *testing.T) {
-		change := models.DNSEntry{"10.0.0.2", "myhost", "badnet"}
+		change := models.DNSEntry{"10.0.0.2", "", "myhost", "badnet"}
 		err := logic.ValidateDNSUpdate(change, entry)
 		assert.NotNil(t, err)
 		assert.Contains(t, err.Error(), "Field validation for 'Network' failed on the 'network_exists' tag")
 	})
 	t.Run("EmptyNetwork", func(t *testing.T) {
 		//this can't actually happen as change.Network is populated if is blank
-		change := models.DNSEntry{"10.0.0.2", "myhost", ""}
+		change := models.DNSEntry{"10.0.0.2", "", "myhost", ""}
 		err := logic.ValidateDNSUpdate(change, entry)
 		assert.NotNil(t, err)
 		assert.Contains(t, err.Error(), "Field validation for 'Network' failed on the 'network_exists' tag")
 	})
-	t.Run("EmptyAddress", func(t *testing.T) {
-		//this can't actually happen as change.Address is populated if is blank
-		change := models.DNSEntry{"", "myhost", "skynet"}
-		err := logic.ValidateDNSUpdate(change, entry)
-		assert.NotNil(t, err)
-		assert.Contains(t, err.Error(), "Field validation for 'Address' failed on the 'required' tag")
-	})
+	// t.Run("EmptyAddress", func(t *testing.T) {
+	// 	//this can't actually happen as change.Address is populated if is blank
+	// 	change := models.DNSEntry{"", "", "myhost", "skynet"}
+	// 	err := logic.ValidateDNSUpdate(change, entry)
+	// 	assert.NotNil(t, err)
+	// 	assert.Contains(t, err.Error(), "Field validation for 'Address' failed on the 'required' tag")
+	// })
 	t.Run("BadAddress", func(t *testing.T) {
-		change := models.DNSEntry{"10.0.256.1", "myhost", "skynet"}
+		change := models.DNSEntry{"10.0.256.1", "", "myhost", "skynet"}
 		err := logic.ValidateDNSUpdate(change, entry)
 		assert.NotNil(t, err)
 		assert.Contains(t, err.Error(), "Field validation for 'Address' failed on the 'ip' tag")
 	})
 	t.Run("EmptyName", func(t *testing.T) {
 		//this can't actually happen as change.Name is populated if is blank
-		change := models.DNSEntry{"10.0.0.2", "", "skynet"}
+		change := models.DNSEntry{"10.0.0.2", "", "", "skynet"}
 		err := logic.ValidateDNSUpdate(change, entry)
 		assert.NotNil(t, err)
 		assert.Contains(t, err.Error(), "Field validation for 'Name' failed on the 'required' tag")
@@ -341,13 +341,13 @@ func TestValidateDNSUpdate(t *testing.T) {
 		for i := 1; i < 194; i++ {
 			name = name + "a"
 		}
-		change := models.DNSEntry{"10.0.0.2", name, "skynet"}
+		change := models.DNSEntry{"10.0.0.2", "", name, "skynet"}
 		err := logic.ValidateDNSUpdate(change, entry)
 		assert.NotNil(t, err)
 		assert.Contains(t, err.Error(), "Field validation for 'Name' failed on the 'max' tag")
 	})
 	t.Run("NameUnique", func(t *testing.T) {
-		change := models.DNSEntry{"10.0.0.2", "myhost", "wirecat"}
+		change := models.DNSEntry{"10.0.0.2", "", "myhost", "wirecat"}
 		CreateDNS(entry)
 		CreateDNS(change)
 		err := logic.ValidateDNSUpdate(change, entry)
@@ -363,25 +363,25 @@ func TestValidateDNSCreate(t *testing.T) {
 	database.InitializeDatabase()
 	_ = logic.DeleteDNS("mynode", "skynet")
 	t.Run("NoNetwork", func(t *testing.T) {
-		entry := models.DNSEntry{"10.0.0.2", "myhost", "badnet"}
+		entry := models.DNSEntry{"10.0.0.2", "", "myhost", "badnet"}
 		err := logic.ValidateDNSCreate(entry)
 		assert.NotNil(t, err)
 		assert.Contains(t, err.Error(), "Field validation for 'Network' failed on the 'network_exists' tag")
 	})
-	t.Run("EmptyAddress", func(t *testing.T) {
-		entry := models.DNSEntry{"", "myhost", "skynet"}
-		err := logic.ValidateDNSCreate(entry)
-		assert.NotNil(t, err)
-		assert.Contains(t, err.Error(), "Field validation for 'Address' failed on the 'required' tag")
-	})
+	// t.Run("EmptyAddress", func(t *testing.T) {
+	// 	entry := models.DNSEntry{"", "", "myhost", "skynet"}
+	// 	err := logic.ValidateDNSCreate(entry)
+	// 	assert.NotNil(t, err)
+	// 	assert.Contains(t, err.Error(), "Field validation for 'Address' failed on the 'required' tag")
+	// })
 	t.Run("BadAddress", func(t *testing.T) {
-		entry := models.DNSEntry{"10.0.256.1", "myhost", "skynet"}
+		entry := models.DNSEntry{"10.0.256.1", "", "myhost", "skynet"}
 		err := logic.ValidateDNSCreate(entry)
 		assert.NotNil(t, err)
 		assert.Contains(t, err.Error(), "Field validation for 'Address' failed on the 'ip' tag")
 	})
 	t.Run("EmptyName", func(t *testing.T) {
-		entry := models.DNSEntry{"10.0.0.2", "", "skynet"}
+		entry := models.DNSEntry{"10.0.0.2", "", "", "skynet"}
 		err := logic.ValidateDNSCreate(entry)
 		assert.NotNil(t, err)
 		assert.Contains(t, err.Error(), "Field validation for 'Name' failed on the 'required' tag")
@@ -391,13 +391,13 @@ func TestValidateDNSCreate(t *testing.T) {
 		for i := 1; i < 194; i++ {
 			name = name + "a"
 		}
-		entry := models.DNSEntry{"10.0.0.2", name, "skynet"}
+		entry := models.DNSEntry{"10.0.0.2", "", name, "skynet"}
 		err := logic.ValidateDNSCreate(entry)
 		assert.NotNil(t, err)
 		assert.Contains(t, err.Error(), "Field validation for 'Name' failed on the 'max' tag")
 	})
 	t.Run("NameUnique", func(t *testing.T) {
-		entry := models.DNSEntry{"10.0.0.2", "myhost", "skynet"}
+		entry := models.DNSEntry{"10.0.0.2", "", "myhost", "skynet"}
 		_, _ = CreateDNS(entry)
 		err := logic.ValidateDNSCreate(entry)
 		assert.NotNil(t, err)

+ 19 - 8
controllers/ext_client.go

@@ -4,7 +4,6 @@ import (
 	"encoding/json"
 	"errors"
 	"fmt"
-	"io"
 	"net/http"
 	"strconv"
 
@@ -136,12 +135,30 @@ func getExtClientConf(w http.ResponseWriter, r *http.Request) {
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 	}
+
+	addrString := client.Address
+	if addrString != "" {
+		addrString += "/32"
+	}
+	if client.Address6 != "" {
+		if addrString != "" {
+			addrString += ","
+		}
+		addrString += client.Address6 + "/128"
+	}
+
 	keepalive := ""
 	if network.DefaultKeepalive != 0 {
 		keepalive = "PersistentKeepalive = " + strconv.Itoa(int(network.DefaultKeepalive))
 	}
 	gwendpoint := gwnode.Endpoint + ":" + strconv.Itoa(int(gwnode.ListenPort))
 	newAllowedIPs := network.AddressRange
+	if newAllowedIPs != "" {
+		newAllowedIPs += ","
+	}
+	if network.AddressRange6 != "" {
+		newAllowedIPs += network.AddressRange6
+	}
 	if egressGatewayRanges, err := logic.GetEgressRangesOnNetwork(&client); err == nil {
 		for _, egressGatewayRange := range egressGatewayRanges {
 			newAllowedIPs += "," + egressGatewayRange
@@ -168,7 +185,7 @@ AllowedIPs = %s
 Endpoint = %s
 %s
 
-`, client.Address+"/32",
+`, addrString,
 		client.PrivateKey,
 		defaultMTU,
 		defaultDNS,
@@ -241,12 +258,6 @@ func createExtClient(w http.ResponseWriter, r *http.Request) {
 	if err == nil { // check if parent network default ACL is enabled (yes) or not (no)
 		extclient.Enabled = parentNetwork.DefaultACL == "yes"
 	}
-
-	err = json.NewDecoder(r.Body).Decode(&extclient)
-	if err != nil && !errors.Is(err, io.EOF) {
-		returnErrorResponse(w, r, formatError(err, "internal"))
-		return
-	}
 	err = logic.CreateExtClient(&extclient)
 	if err != nil {
 		returnErrorResponse(w, r, formatError(err, "internal"))

+ 6 - 42
controllers/network.go

@@ -15,7 +15,6 @@ import (
 	"github.com/gravitl/netmaker/models"
 	"github.com/gravitl/netmaker/mq"
 	"github.com/gravitl/netmaker/servercfg"
-	"github.com/gravitl/netmaker/serverctl"
 )
 
 // ALL_NETWORK_ACCESS - represents all networks
@@ -84,10 +83,6 @@ func getNetwork(w http.ResponseWriter, r *http.Request) {
 	w.Header().Set("Content-Type", "application/json")
 	var params = mux.Vars(r)
 	netname := params["networkname"]
-	if isCommsEdit(w, r, netname) {
-		return
-	}
-
 	network, err := logic.GetNetwork(netname)
 	if err != nil {
 		returnErrorResponse(w, r, formatError(err, "internal"))
@@ -105,10 +100,6 @@ func keyUpdate(w http.ResponseWriter, r *http.Request) {
 	w.Header().Set("Content-Type", "application/json")
 	var params = mux.Vars(r)
 	netname := params["networkname"]
-	if isCommsEdit(w, r, netname) {
-		return
-	}
-
 	network, err := logic.KeyUpdate(netname)
 	if err != nil {
 		returnErrorResponse(w, r, formatError(err, "internal"))
@@ -162,11 +153,6 @@ func updateNetwork(w http.ResponseWriter, r *http.Request) {
 		return
 	}
 
-	// if newNetwork.IsDualStack != currentNetwork.IsDualStack && newNetwork.IsDualStack == "no" {
-	// 	// Remove IPv6 address from network nodes
-	// 	RemoveNetworkNodeIPv6Addresses(currentNetwork.NetID)
-	// }
-
 	if rangeupdate {
 		err = logic.UpdateNetworkNodeAddresses(network.NetID)
 		if err != nil {
@@ -295,10 +281,6 @@ func deleteNetwork(w http.ResponseWriter, r *http.Request) {
 
 	var params = mux.Vars(r)
 	network := params["networkname"]
-	if isCommsEdit(w, r, network) {
-		return
-	}
-
 	err := logic.DeleteNetwork(network)
 	if err != nil {
 		errtype := "badrequest"
@@ -326,6 +308,11 @@ func createNetwork(w http.ResponseWriter, r *http.Request) {
 		return
 	}
 
+	if network.AddressRange == "" && network.AddressRange6 == "" {
+		returnErrorResponse(w, r, formatError(fmt.Errorf("IPv4 or IPv6 CIDR required"), "badrequest"))
+		return
+	}
+
 	network, err = logic.CreateNetwork(network)
 	if err != nil {
 		returnErrorResponse(w, r, formatError(err, "badrequest"))
@@ -333,8 +320,7 @@ func createNetwork(w http.ResponseWriter, r *http.Request) {
 	}
 
 	if servercfg.IsClientMode() != "off" {
-		var node models.Node
-		node, err = logic.ServerJoin(&network)
+		_, err := logic.ServerJoin(&network)
 		if err != nil {
 			logic.DeleteNetwork(network.NetID)
 			if err == nil {
@@ -343,7 +329,6 @@ func createNetwork(w http.ResponseWriter, r *http.Request) {
 			returnErrorResponse(w, r, formatError(err, "internal"))
 			return
 		}
-		getServerAddrs(&node)
 	}
 
 	logger.Log(1, r.Header.Get("user"), "created network", network.NetID)
@@ -358,9 +343,6 @@ func createAccessKey(w http.ResponseWriter, r *http.Request) {
 	var accesskey models.AccessKey
 	//start here
 	netname := params["networkname"]
-	if isCommsEdit(w, r, netname) {
-		return
-	}
 	network, err := logic.GetParentNetwork(netname)
 	if err != nil {
 		returnErrorResponse(w, r, formatError(err, "internal"))
@@ -413,21 +395,3 @@ func deleteAccessKey(w http.ResponseWriter, r *http.Request) {
 	logger.Log(1, r.Header.Get("user"), "deleted access key", keyname, "on network,", netname)
 	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
-}

+ 33 - 2
controllers/network_test.go

@@ -7,7 +7,6 @@ import (
 	"github.com/gravitl/netmaker/database"
 	"github.com/gravitl/netmaker/logic"
 	"github.com/gravitl/netmaker/models"
-	"github.com/gravitl/netmaker/serverctl"
 	"github.com/stretchr/testify/assert"
 )
 
@@ -285,6 +284,26 @@ func TestValidateNetworkUpdate(t *testing.T) {
 	}
 }
 
+func TestIpv6Network(t *testing.T) {
+	//these seem to work but not sure it the tests are really testing the functionality
+
+	database.InitializeDatabase()
+	os.Setenv("MASTER_KEY", "secretkey")
+	createNet()
+	createNetDualStack()
+	network, err := logic.GetNetwork("skynet6")
+	t.Run("Test Network Create IPv6", func(t *testing.T) {
+		assert.Nil(t, err)
+		assert.Equal(t, network.AddressRange6, "fde6:be04:fa5e:d076::/64")
+	})
+	node1 := models.Node{PublicKey: "DM5qhLAE20PG9BbfBCger+Ac9D2NDOwCtY1rbYDLf34=", Name: "testnode", Endpoint: "10.0.0.50", MacAddress: "01:02:03:04:05:06", Password: "password", Network: "skynet6", OS: "linux"}
+	nodeErr := logic.CreateNode(&node1)
+	t.Run("Test node on network IPv6", func(t *testing.T) {
+		assert.Nil(t, nodeErr)
+		assert.Equal(t, node1.Address6, "fde6:be04:fa5e:d076::1")
+	})
+}
+
 func deleteAllNetworks() {
 	deleteAllNodes()
 	nets, _ := logic.GetNetworks()
@@ -301,5 +320,17 @@ func createNet() {
 	if err != nil {
 		logic.CreateNetwork(network)
 	}
-	serverctl.InitializeCommsNetwork()
+}
+
+func createNetDualStack() {
+	var network models.Network
+	network.NetID = "skynet6"
+	network.AddressRange = "10.1.2.0/24"
+	network.AddressRange6 = "fde6:be04:fa5e:d076::/64"
+	network.IsIPv4 = "yes"
+	network.IsIPv6 = "yes"
+	_, err := logic.GetNetwork("skynet6")
+	if err != nil {
+		logic.CreateNetwork(network)
+	}
 }

+ 129 - 25
controllers/node.go

@@ -19,20 +19,20 @@ import (
 
 func nodeHandlers(r *mux.Router) {
 
-	r.HandleFunc("/api/nodes", authorize(false, "user", http.HandlerFunc(getAllNodes))).Methods("GET")
-	r.HandleFunc("/api/nodes/{network}", authorize(true, "network", http.HandlerFunc(getNetworkNodes))).Methods("GET")
-	r.HandleFunc("/api/nodes/{network}/{nodeid}", authorize(true, "node", http.HandlerFunc(getNode))).Methods("GET")
-	r.HandleFunc("/api/nodes/{network}/{nodeid}", authorize(true, "node", http.HandlerFunc(updateNode))).Methods("PUT")
-	r.HandleFunc("/api/nodes/{network}/{nodeid}", authorize(true, "node", http.HandlerFunc(deleteNode))).Methods("DELETE")
-	r.HandleFunc("/api/nodes/{network}/{nodeid}/createrelay", authorize(true, "user", http.HandlerFunc(createRelay))).Methods("POST")
-	r.HandleFunc("/api/nodes/{network}/{nodeid}/deleterelay", authorize(true, "user", http.HandlerFunc(deleteRelay))).Methods("DELETE")
-	r.HandleFunc("/api/nodes/{network}/{nodeid}/creategateway", authorize(true, "user", http.HandlerFunc(createEgressGateway))).Methods("POST")
-	r.HandleFunc("/api/nodes/{network}/{nodeid}/deletegateway", authorize(true, "user", http.HandlerFunc(deleteEgressGateway))).Methods("DELETE")
+	r.HandleFunc("/api/nodes", authorize(false, false, "user", http.HandlerFunc(getAllNodes))).Methods("GET")
+	r.HandleFunc("/api/nodes/{network}", authorize(false, true, "network", http.HandlerFunc(getNetworkNodes))).Methods("GET")
+	r.HandleFunc("/api/nodes/{network}/{nodeid}", authorize(true, true, "node", http.HandlerFunc(getNode))).Methods("GET")
+	r.HandleFunc("/api/nodes/{network}/{nodeid}", authorize(false, true, "node", http.HandlerFunc(updateNode))).Methods("PUT")
+	r.HandleFunc("/api/nodes/{network}/{nodeid}", authorize(true, true, "node", http.HandlerFunc(deleteNode))).Methods("DELETE")
+	r.HandleFunc("/api/nodes/{network}/{nodeid}/createrelay", authorize(false, true, "user", http.HandlerFunc(createRelay))).Methods("POST")
+	r.HandleFunc("/api/nodes/{network}/{nodeid}/deleterelay", authorize(false, true, "user", http.HandlerFunc(deleteRelay))).Methods("DELETE")
+	r.HandleFunc("/api/nodes/{network}/{nodeid}/creategateway", authorize(false, true, "user", http.HandlerFunc(createEgressGateway))).Methods("POST")
+	r.HandleFunc("/api/nodes/{network}/{nodeid}/deletegateway", authorize(false, true, "user", http.HandlerFunc(deleteEgressGateway))).Methods("DELETE")
 	r.HandleFunc("/api/nodes/{network}/{nodeid}/createingress", securityCheck(false, http.HandlerFunc(createIngressGateway))).Methods("POST")
 	r.HandleFunc("/api/nodes/{network}/{nodeid}/deleteingress", securityCheck(false, http.HandlerFunc(deleteIngressGateway))).Methods("DELETE")
-	r.HandleFunc("/api/nodes/{network}/{nodeid}/approve", authorize(true, "user", http.HandlerFunc(uncordonNode))).Methods("POST")
-	r.HandleFunc("/api/nodes/{network}", createNode).Methods("POST")
-	r.HandleFunc("/api/nodes/adm/{network}/lastmodified", authorize(true, "network", http.HandlerFunc(getLastModified))).Methods("GET")
+	r.HandleFunc("/api/nodes/{network}/{nodeid}/approve", authorize(false, true, "user", http.HandlerFunc(uncordonNode))).Methods("POST")
+	r.HandleFunc("/api/nodes/{network}", nodeauth(http.HandlerFunc(createNode))).Methods("POST")
+	r.HandleFunc("/api/nodes/adm/{network}/lastmodified", authorize(false, true, "network", http.HandlerFunc(getLastModified))).Methods("GET")
 	r.HandleFunc("/api/nodes/adm/{network}/authenticate", authenticate).Methods("POST")
 }
 
@@ -131,6 +131,51 @@ func authenticate(response http.ResponseWriter, request *http.Request) {
 	}
 }
 
+// auth middleware for api calls from nodes where node is has not yet joined the server (register, join)
+func nodeauth(next http.Handler) http.HandlerFunc {
+	return func(w http.ResponseWriter, r *http.Request) {
+		bearerToken := r.Header.Get("Authorization")
+		var tokenSplit = strings.Split(bearerToken, " ")
+		var token = ""
+		if len(tokenSplit) < 2 {
+			errorResponse := models.ErrorResponse{
+				Code: http.StatusUnauthorized, Message: "W1R3: You are unauthorized to access this endpoint.",
+			}
+			returnErrorResponse(w, r, errorResponse)
+			return
+		} else {
+			token = tokenSplit[1]
+		}
+		found := false
+		networks, err := logic.GetNetworks()
+		if err != nil {
+			logger.Log(0, "no networks", err.Error())
+			errorResponse := models.ErrorResponse{
+				Code: http.StatusNotFound, Message: "no networks",
+			}
+			returnErrorResponse(w, r, errorResponse)
+			return
+		}
+		for _, network := range networks {
+			for _, key := range network.AccessKeys {
+				if key.Value == token {
+					found = true
+					break
+				}
+			}
+		}
+		if !found {
+			logger.Log(0, "valid access key not found")
+			errorResponse := models.ErrorResponse{
+				Code: http.StatusUnauthorized, Message: "You are unauthorized to access this endpoint.",
+			}
+			returnErrorResponse(w, r, errorResponse)
+			return
+		}
+		next.ServeHTTP(w, r)
+	}
+}
+
 //The middleware for most requests to the API
 //They all pass  through here first
 //This will validate the JWT (or check for master token)
@@ -138,7 +183,7 @@ func authenticate(response http.ResponseWriter, request *http.Request) {
 //even if it's technically ok
 //This is kind of a poor man's RBAC. There's probably a better/smarter way.
 //TODO: Consider better RBAC implementations
-func authorize(networkCheck bool, authNetwork string, next http.Handler) http.HandlerFunc {
+func authorize(nodesAllowed, networkCheck bool, authNetwork string, next http.Handler) http.HandlerFunc {
 	return func(w http.ResponseWriter, r *http.Request) {
 		var errorResponse = models.ErrorResponse{
 			Code: http.StatusInternalServerError, Message: "W1R3: It's not you it's me.",
@@ -176,6 +221,14 @@ func authorize(networkCheck bool, authNetwork string, next http.Handler) http.Ha
 				returnErrorResponse(w, r, errorResponse)
 				return
 			}
+			//check if node instead of user
+			if nodesAllowed {
+				// TODO --- should ensure that node is only operating on itself
+				if _, _, _, err := logic.VerifyToken(authToken); err == nil {
+					next.ServeHTTP(w, r)
+					return
+				}
+			}
 
 			var isAuthorized = false
 			var nodeID = ""
@@ -329,13 +382,21 @@ func getNode(w http.ResponseWriter, r *http.Request) {
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 	}
-	if logic.IsNodeInComms(&node) {
+
+	peerUpdate, err := logic.GetPeerUpdate(&node)
+	if err != nil && !database.IsEmptyRecord(err) {
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 	}
+
+	response := models.NodeGet{
+		Node:  node,
+		Peers: peerUpdate.Peers,
+	}
+
 	logger.Log(2, r.Header.Get("user"), "fetched node", params["nodeid"])
 	w.WriteHeader(http.StatusOK)
-	json.NewEncoder(w).Encode(node)
+	json.NewEncoder(w).Encode(response)
 }
 
 //Get the time that a network of nodes was last modified.
@@ -395,9 +456,12 @@ func createNode(w http.ResponseWriter, r *http.Request) {
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 	}
-
+	node.NetworkSettings, err = logic.GetNetworkSettings(node.Network)
+	if err != nil {
+		returnErrorResponse(w, r, formatError(err, "internal"))
+		return
+	}
 	validKey := logic.IsKeyValid(networkName, node.AccessKey)
-
 	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.
@@ -411,6 +475,26 @@ func createNode(w http.ResponseWriter, r *http.Request) {
 			return
 		}
 	}
+	key, keyErr := logic.RetrievePublicTrafficKey()
+	if keyErr != nil {
+		logger.Log(0, "error retrieving key: ", keyErr.Error())
+		returnErrorResponse(w, r, formatError(err, "internal"))
+		return
+	}
+	if key == nil {
+		logger.Log(0, "error: server traffic key is nil")
+		returnErrorResponse(w, r, formatError(err, "internal"))
+		return
+	}
+	if node.TrafficKeys.Mine == nil {
+		logger.Log(0, "error: node traffic key is nil")
+		returnErrorResponse(w, r, formatError(err, "internal"))
+		return
+	}
+	node.TrafficKeys = models.TrafficKeys{
+		Mine:   node.TrafficKeys.Mine,
+		Server: key,
+	}
 
 	err = logic.CreateNode(&node)
 	if err != nil {
@@ -418,9 +502,20 @@ func createNode(w http.ResponseWriter, r *http.Request) {
 		return
 	}
 
+	peerUpdate, err := logic.GetPeerUpdate(&node)
+	if err != nil && !database.IsEmptyRecord(err) {
+		returnErrorResponse(w, r, formatError(err, "internal"))
+		return
+	}
+
+	response := models.NodeGet{
+		Node:  node,
+		Peers: peerUpdate.Peers,
+	}
+
 	logger.Log(1, r.Header.Get("user"), "created new node", node.Name, "on network", node.Network)
 	w.WriteHeader(http.StatusOK)
-	json.NewEncoder(w).Encode(node)
+	json.NewEncoder(w).Encode(response)
 	runForceServerUpdate(&node)
 }
 
@@ -660,12 +755,21 @@ func runServerUpdate(node *models.Node, ifaceDelta bool) error {
 	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])
+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)
 		}
-	}
-	return filterdNodes
+
+		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")
+			}
+		}
+	}()
+}
+
+func isServer(node *models.Node) bool {
+	return node.IsServer == "yes"
 }

+ 0 - 326
controllers/node_grpc.go

@@ -1,326 +0,0 @@
-package controller
-
-import (
-	"context"
-	"encoding/json"
-	"errors"
-	"fmt"
-	"strings"
-	"time"
-
-	nodepb "github.com/gravitl/netmaker/grpc"
-	"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"
-	"github.com/gravitl/netmaker/serverctl"
-)
-
-// NodeServiceServer - represents the service server for gRPC
-type NodeServiceServer struct {
-	nodepb.UnimplementedNodeServiceServer
-}
-
-// NodeServiceServer.ReadNode - reads node and responds with gRPC
-func (s *NodeServiceServer) ReadNode(ctx context.Context, req *nodepb.Object) (*nodepb.Object, error) {
-	var node, err = getNodeFromRequestData(req.Data)
-	if err != nil {
-		return nil, err
-	}
-
-	node.NetworkSettings, err = logic.GetNetworkSettings(node.Network)
-	if err != nil {
-		return nil, err
-	}
-	getServerAddrs(&node)
-
-	node.SetLastCheckIn()
-	// Cast to ReadNodeRes type
-	nodeData, errN := json.Marshal(&node)
-	if errN != nil {
-		return nil, err
-	}
-	logic.UpdateNode(&node, &node)
-	response := &nodepb.Object{
-		Data: string(nodeData),
-		Type: nodepb.NODE_TYPE,
-	}
-	return response, nil
-}
-
-// NodeServiceServer.CreateNode - creates a node and responds over gRPC
-func (s *NodeServiceServer) CreateNode(ctx context.Context, req *nodepb.Object) (*nodepb.Object, error) {
-	var node = models.Node{}
-	var err error
-	data := req.GetData()
-	if err := json.Unmarshal([]byte(data), &node); err != nil {
-		return nil, err
-	}
-
-	validKey := logic.IsKeyValid(node.Network, node.AccessKey)
-	node.NetworkSettings, err = logic.GetNetworkSettings(node.Network)
-	if err != nil {
-		return nil, err
-	}
-	if !validKey {
-		if node.NetworkSettings.AllowManualSignUp == "yes" {
-			node.IsPending = "yes"
-		} else {
-			return nil, errors.New("invalid key, and network does not allow no-key signups")
-		}
-	}
-	getServerAddrs(&node)
-
-	key, keyErr := logic.RetrievePublicTrafficKey()
-	if keyErr != nil {
-		logger.Log(0, "error retrieving key: ", keyErr.Error())
-		return nil, keyErr
-	}
-
-	if key == nil {
-		logger.Log(0, "error: server traffic key is nil")
-		return nil, fmt.Errorf("error: server traffic key is nil")
-	}
-	if node.TrafficKeys.Mine == nil {
-		logger.Log(0, "error: node traffic key is nil")
-		return nil, fmt.Errorf("error: node traffic key is nil")
-	}
-
-	node.TrafficKeys = models.TrafficKeys{
-		Mine:   node.TrafficKeys.Mine,
-		Server: key,
-	}
-
-	commID, err := logic.FetchCommsNetID()
-	if err != nil {
-		return nil, err
-	}
-	node.CommID = commID
-
-	err = logic.CreateNode(&node)
-	if err != nil {
-		return nil, err
-	}
-
-	nodeData, errN := json.Marshal(&node)
-	if errN != nil {
-		return nil, err
-	}
-
-	response := &nodepb.Object{
-		Data: string(nodeData),
-		Type: nodepb.NODE_TYPE,
-	}
-
-	runForceServerUpdate(&node)
-
-	go func(node *models.Node) {
-		if node.UDPHolePunch == "yes" {
-			var currentServerNode, getErr = logic.GetNetworkServerLeader(node.Network)
-			if getErr != nil {
-				return
-			}
-			for i := 0; i < 5; i++ {
-				if logic.HasPeerConnected(node) {
-					if logic.ShouldPublishPeerPorts(&currentServerNode) {
-						err = mq.PublishPeerUpdate(&currentServerNode)
-						if err != nil {
-							logger.Log(1, "error publishing port updates when node", node.Name, "joined")
-						}
-						break
-					}
-				}
-				time.Sleep(time.Second << 1) // allow time for client to startup
-			}
-		}
-	}(&node)
-
-	return response, nil
-}
-
-// 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) {
-
-	var newnode models.Node
-	if err := json.Unmarshal([]byte(req.GetData()), &newnode); err != nil {
-		return nil, err
-	}
-
-	node, err := logic.GetNodeByID(newnode.ID)
-	if err != nil {
-		return nil, err
-	}
-
-	if !servercfg.GetRce() {
-		newnode.PostDown = node.PostDown
-		newnode.PostUp = node.PostUp
-	}
-
-	err = logic.UpdateNode(&node, &newnode)
-	if err != nil {
-		return nil, err
-	}
-	newnode.NetworkSettings, err = logic.GetNetworkSettings(node.Network)
-	if err != nil {
-		return nil, err
-	}
-	getServerAddrs(&newnode)
-
-	nodeData, errN := json.Marshal(&newnode)
-	if errN != nil {
-		return nil, err
-	}
-
-	return &nodepb.Object{
-		Data: string(nodeData),
-		Type: nodepb.NODE_TYPE,
-	}, nil
-}
-
-func getServerAddrs(node *models.Node) {
-	serverNodes := logic.GetServerNodes(serverctl.COMMS_NETID)
-	//pubIP, _ := servercfg.GetPublicIP()
-	if len(serverNodes) == 0 {
-		if err := serverctl.SyncServerNetwork(serverctl.COMMS_NETID); err != nil {
-			return
-		}
-	}
-
-	var serverAddrs = make([]models.ServerAddr, 0)
-
-	for _, node := range serverNodes {
-		if node.Address != "" {
-			serverAddrs = append(serverAddrs, models.ServerAddr{
-				IsLeader: logic.IsLeader(&node),
-				Address:  node.Address,
-			})
-		}
-	}
-
-	networkSettings, _ := logic.GetParentNetwork(node.Network)
-	// TODO consolidate functionality around files
-	networkSettings.NodesLastModified = time.Now().Unix()
-	networkSettings.DefaultServerAddrs = serverAddrs
-	if err := logic.SaveNetwork(&networkSettings); err != nil {
-		logger.Log(1, "unable to save network on serverAddr update", err.Error())
-	}
-	node.NetworkSettings.DefaultServerAddrs = networkSettings.DefaultServerAddrs
-}
-
-// NodeServiceServer.DeleteNode - deletes a node and responds over gRPC
-func (s *NodeServiceServer) DeleteNode(ctx context.Context, req *nodepb.Object) (*nodepb.Object, error) {
-
-	var node, err = getNodeFromRequestData(req.Data)
-	if err != nil {
-		return nil, err
-	}
-
-	err = logic.DeleteNodeByID(&node, true)
-	if err != nil {
-		return nil, err
-	}
-
-	runForceServerUpdate(&node)
-
-	return &nodepb.Object{
-		Data: "success",
-		Type: nodepb.STRING_TYPE,
-	}, nil
-}
-
-// NodeServiceServer.GetPeers - fetches peers over gRPC
-func (s *NodeServiceServer) GetPeers(ctx context.Context, req *nodepb.Object) (*nodepb.Object, error) {
-
-	var node, err = getNodeFromRequestData(req.Data)
-	if err != nil {
-		return nil, err
-	}
-
-	peers, err := logic.GetPeersList(&node)
-	if err != nil {
-		if strings.Contains(err.Error(), logic.RELAY_NODE_ERR) {
-			peers, err = logic.PeerListUnRelay(node.ID, node.Network)
-			if err != nil {
-				return nil, err
-			}
-		} else {
-			return nil, err
-		}
-	}
-
-	peersData, err := json.Marshal(&peers)
-	logger.Log(3, node.Address, "checked in successfully")
-	return &nodepb.Object{
-		Data: string(peersData),
-		Type: nodepb.NODE_TYPE,
-	}, err
-}
-
-// NodeServiceServer.GetExtPeers - returns ext peers for a gateway node
-func (s *NodeServiceServer) GetExtPeers(ctx context.Context, req *nodepb.Object) (*nodepb.Object, error) {
-
-	var node, err = getNodeFromRequestData(req.Data)
-	if err != nil {
-		return nil, err
-	}
-
-	peers, err := logic.GetExtPeersList(&node)
-	if err != nil {
-		return nil, err
-	}
-	var extPeers []models.Node
-	for i := 0; i < len(peers); i++ {
-		extPeers = append(extPeers, models.Node{
-			Address:             peers[i].Address,
-			Address6:            peers[i].Address6,
-			Endpoint:            peers[i].Endpoint,
-			PublicKey:           peers[i].PublicKey,
-			PersistentKeepalive: peers[i].KeepAlive,
-			ListenPort:          peers[i].ListenPort,
-			LocalAddress:        peers[i].LocalAddress,
-		})
-	}
-
-	extData, err := json.Marshal(&extPeers)
-	if err != nil {
-		return nil, err
-	}
-
-	return &nodepb.Object{
-		Data: string(extData),
-		Type: nodepb.EXT_PEER,
-	}, nil
-}
-
-// == private methods ==
-
-func getNodeFromRequestData(data string) (models.Node, error) {
-	var reqNode models.Node
-	var err error
-
-	if err = json.Unmarshal([]byte(data), &reqNode); err != nil {
-		return models.Node{}, err
-	}
-	return logic.GetNodeByID(reqNode.ID)
-}
-
-func isServer(node *models.Node) bool {
-	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/relay.go

@@ -31,7 +31,7 @@ func createRelay(w http.ResponseWriter, r *http.Request) {
 	for _, relayedNode := range updatenodes {
 		err = mq.NodeUpdate(&relayedNode)
 		if err != nil {
-			logger.Log(1, "error sending update to relayed node ", relayedNode.Address, "on network", relay.NetID, ": ", err.Error())
+			logger.Log(1, "error sending update to relayed node ", relayedNode.Name, "on network", relay.NetID, ": ", err.Error())
 		}
 	}
 	w.WriteHeader(http.StatusOK)
@@ -53,7 +53,7 @@ func deleteRelay(w http.ResponseWriter, r *http.Request) {
 	for _, relayedNode := range updatenodes {
 		err = mq.NodeUpdate(&relayedNode)
 		if err != nil {
-			logger.Log(1, "error sending update to relayed node ", relayedNode.Address, "on network", netid, ": ", err.Error())
+			logger.Log(1, "error sending update to relayed node ", relayedNode.Name, "on network", netid, ": ", err.Error())
 		}
 	}
 	w.WriteHeader(http.StatusOK)

+ 68 - 0
controllers/server.go

@@ -1,20 +1,28 @@
 package controller
 
 import (
+	"crypto/ed25519"
+	"crypto/x509"
+	"crypto/x509/pkix"
 	"encoding/json"
+	"fmt"
 	"net/http"
 	"strings"
 
 	"github.com/gorilla/mux"
+	"github.com/gravitl/netmaker/logger"
 	"github.com/gravitl/netmaker/logic"
 	"github.com/gravitl/netmaker/models"
+	"github.com/gravitl/netmaker/netclient/config"
 	"github.com/gravitl/netmaker/servercfg"
+	"github.com/gravitl/netmaker/tls"
 )
 
 func serverHandlers(r *mux.Router) {
 	// r.HandleFunc("/api/server/addnetwork/{network}", securityCheckServer(true, http.HandlerFunc(addNetwork))).Methods("POST")
 	r.HandleFunc("/api/server/getconfig", securityCheckServer(false, http.HandlerFunc(getConfig))).Methods("GET")
 	r.HandleFunc("/api/server/removenetwork/{network}", securityCheckServer(true, http.HandlerFunc(removeNetwork))).Methods("DELETE")
+	r.HandleFunc("/api/server/register", authorize(true, false, "node", http.HandlerFunc(register))).Methods("POST")
 }
 
 //Security check is middleware for every function and just checks to make sure that its the master calling
@@ -102,3 +110,63 @@ func getConfig(w http.ResponseWriter, r *http.Request) {
 
 // 	json.NewEncoder(w).Encode("Server added to network " + params["network"])
 // }
+
+// register - registers a client with the server and return the CA and cert
+func register(w http.ResponseWriter, r *http.Request) {
+	logger.Log(2, "processing registration request")
+	w.Header().Set("Content-Type", "application/json")
+	//decode body
+	var request config.RegisterRequest
+	if err := json.NewDecoder(r.Body).Decode(&request); err != nil {
+		logger.Log(0, "error decoding request", err.Error())
+		errorResponse := models.ErrorResponse{
+			Code: http.StatusBadRequest, Message: err.Error(),
+		}
+		returnErrorResponse(w, r, errorResponse)
+		return
+	}
+	cert, ca, err := genCerts(&request.Key, &request.CommonName)
+	if err != nil {
+		logger.Log(0, "failed to generater certs ", err.Error())
+		errorResponse := models.ErrorResponse{
+			Code: http.StatusNotFound, Message: err.Error(),
+		}
+		returnErrorResponse(w, r, errorResponse)
+		return
+	}
+	//x509.Certificate.PublicKey is an interface therefore json encoding/decoding result in a string value rather than a []byte
+	//include the actual public key so the certificate can be properly reassembled on the other end.
+	response := config.RegisterResponse{
+		CA:         *ca,
+		CAPubKey:   (ca.PublicKey).(ed25519.PublicKey),
+		Cert:       *cert,
+		CertPubKey: (cert.PublicKey).(ed25519.PublicKey),
+	}
+	w.WriteHeader(http.StatusOK)
+	json.NewEncoder(w).Encode(response)
+}
+
+// genCerts generates a client certificate and returns the certificate and root CA
+func genCerts(clientKey *ed25519.PrivateKey, name *pkix.Name) (*x509.Certificate, *x509.Certificate, error) {
+	ca, err := tls.ReadCert("/etc/netmaker/root.pem")
+	if err != nil {
+		logger.Log(2, "root ca not found ", err.Error())
+		return nil, nil, fmt.Errorf("root ca not found %w", err)
+	}
+	key, err := tls.ReadKey("/etc/netmaker/root.key")
+	if err != nil {
+		logger.Log(2, "root key not found ", err.Error())
+		return nil, nil, fmt.Errorf("root key not found %w", err)
+	}
+	csr, err := tls.NewCSR(*clientKey, *name)
+	if err != nil {
+		logger.Log(2, "failed to generate client certificate requests", err.Error())
+		return nil, nil, fmt.Errorf("client certification request generation failed %w", err)
+	}
+	cert, err := tls.NewEndEntityCert(*key, csr, ca, tls.CERTIFICATE_VALIDITY)
+	if err != nil {
+		logger.Log(2, "unable to generate client certificate", err.Error())
+		return nil, nil, fmt.Errorf("client certification generation failed %w", err)
+	}
+	return cert, ca, nil
+}

+ 0 - 25
controllers/user.go

@@ -12,7 +12,6 @@ import (
 	"github.com/gravitl/netmaker/logger"
 	"github.com/gravitl/netmaker/logic"
 	"github.com/gravitl/netmaker/models"
-	"github.com/gravitl/netmaker/servercfg"
 )
 
 func userHandlers(r *mux.Router) {
@@ -167,11 +166,6 @@ func createUser(w http.ResponseWriter, r *http.Request) {
 	// get node from body of request
 	_ = 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)
 
 	if err != nil {
@@ -200,11 +194,6 @@ func updateUserNetworks(w http.ResponseWriter, r *http.Request) {
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		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)
 	if err != nil {
 		returnErrorResponse(w, r, formatError(err, "badrequest"))
@@ -229,10 +218,6 @@ 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"))
 		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
 	// we decode our body request params
 	err = json.NewDecoder(r.Body).Decode(&userchange)
@@ -302,13 +287,3 @@ func deleteUser(w http.ResponseWriter, r *http.Request) {
 	logger.Log(1, username, "was 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
-}

+ 42 - 0
dev.yaml

@@ -0,0 +1,42 @@
+server:
+  corednsaddr: ""
+  apiconn: "api.ping.clustercat.com:443"
+  apihost: ""
+  apiport: "8081"
+  grpcconn: "grpc.ping.clustercat.com:443"
+  grpchost: ""
+  grpcport: "50051"
+  grpcsecure: "on"
+  mqhost: "localhost"
+  masterkey: "secretkey"
+  dnskey: ""
+  allowedorigin: "*"
+  nodeid: "netmaker"
+  restbackend: "on"
+  agentbackend: "on"
+  messagequeuebackend: "on"
+  clientmode: "on"
+  dnsmode: "on"
+  disableremoteipcheck: ""
+  grpcssl: "on"
+  version: ""
+  sqlconn: ""
+  platform: ""
+  database: "sqlite"
+  defaultnodelimit: ""
+  verbosity: 3
+  servercheckininterval: ""
+  authprovider: ""
+  clientid: ""
+  clientsecret: ""
+  frontendurl: ""
+  displaykeys: ""
+  azuretenant: ""
+  rce: "off"
+  debug: ""
+  telemetry: ""
+  manageiptables: "off"
+  portforwardservices: ""
+  hostnetwork: "off"
+  mqport: ""
+  server: "broker.ping.clustercat.com"

+ 0 - 4
docker/Caddyfile

@@ -29,7 +29,3 @@ https://api.NETMAKER_BASE_DOMAIN {
         reverse_proxy http://127.0.0.1:8081
 }
 
-# gRPC
-https://grpc.NETMAKER_BASE_DOMAIN {
-        reverse_proxy h2c://127.0.0.1:50051
-}

+ 6 - 0
docker/Dockerfile-go-builder

@@ -0,0 +1,6 @@
+FROM golang:1.18.0-alpine3.15 
+ARG version 
+RUN apk add build-base
+WORKDIR /app
+COPY go.* ./ 
+RUN go mod download

+ 1 - 1
docker/Dockerfile-netclient-multiarch

@@ -1,4 +1,4 @@
-FROM golang:latest as builder
+FROM gravitl/go-builder as builder
 # add glib support daemon manager
 WORKDIR /app
 ARG version

+ 11 - 3
docker/mosquitto.conf

@@ -1,4 +1,12 @@
-persistence true
 per_listener_settings true
-listener 1883
-allow_anonymous true
+
+listener 8883
+allow_anonymous false
+require_certificate true
+use_identity_as_username true
+cafile /mosquitto/certs/root.pem
+certfile /mosquitto/certs/server.pem
+keyfile /mosquitto/certs/server.key
+
+listener 1883 
+allow_anonymous true

+ 8 - 0
functions/local.go

@@ -7,6 +7,9 @@ import (
 	"github.com/gravitl/netmaker/logic"
 )
 
+// LINUX_APP_DATA_PATH - linux path
+const LINUX_APP_DATA_PATH = "/etc/netmaker"
+
 // FileExists - checks if file exists
 func FileExists(f string) bool {
 	info, err := os.Stat(f)
@@ -49,3 +52,8 @@ func SetDNSDir() error {
 	}
 	return nil
 }
+
+// GetNetmakerPath - gets netmaker path locally
+func GetNetmakerPath() string {
+	return LINUX_APP_DATA_PATH
+}

+ 9 - 5
go.mod

@@ -10,13 +10,13 @@ require (
 	github.com/google/uuid v1.3.0
 	github.com/gorilla/handlers v1.5.1
 	github.com/gorilla/mux v1.8.0
-	github.com/lib/pq v1.10.4
+	github.com/lib/pq v1.10.5
 	github.com/mattn/go-sqlite3 v1.14.10
 	github.com/rqlite/gorqlite v0.0.0-20210514125552-08ff1e76b22f
 	github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e
 	github.com/stretchr/testify v1.7.1
 	github.com/txn2/txeh v1.3.0
-	github.com/urfave/cli/v2 v2.4.0
+	github.com/urfave/cli/v2 v2.4.8
 	golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd
 	golang.org/x/net v0.0.0-20220225172249-27dd8689420f // indirect
 	golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d
@@ -24,17 +24,18 @@ require (
 	golang.org/x/text v0.3.7 // indirect
 	golang.zx2c4.com/wireguard v0.0.0-20220318042302-193cf8d6a5d6 // indirect
 	golang.zx2c4.com/wireguard/wgctrl v0.0.0-20220324164955-056925b7df31
-	google.golang.org/genproto v0.0.0-20210201151548-94839c025ad4 // indirect
-	google.golang.org/grpc v1.45.0
-	google.golang.org/protobuf v1.28.0
+	google.golang.org/protobuf v1.28.0 // indirect
 	gopkg.in/ini.v1 v1.66.4
 	gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
 )
 
 require (
+	filippo.io/edwards25519 v1.0.0-rc.1
 	github.com/go-ping/ping v0.0.0-20211130115550-779d1e919534
 	github.com/guumaster/hostctl v1.1.2
+	github.com/kr/pretty v0.3.0
 	github.com/posthog/posthog-go v0.0.0-20211028072449-93c17c49e2b0
+	github.com/seancfoley/ipaddress-go v1.1.2
 )
 
 require (
@@ -53,6 +54,7 @@ require (
 	github.com/google/go-cmp v0.5.7 // indirect
 	github.com/gorilla/websocket v1.4.2 // indirect
 	github.com/josharian/native v1.0.0 // indirect
+	github.com/kr/text v0.2.0 // indirect
 	github.com/leodido/go-urn v1.2.1 // indirect
 	github.com/mdlayher/genetlink v1.2.0 // indirect
 	github.com/mdlayher/netlink v1.6.0 // indirect
@@ -61,7 +63,9 @@ require (
 	github.com/opencontainers/image-spec v1.0.1 // indirect
 	github.com/pkg/errors v0.9.1 // 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.1.0 // indirect
+	github.com/seancfoley/bintree v1.0.1 // indirect
 	github.com/spf13/afero v1.3.2 // indirect
 	github.com/xtgo/uuid v0.0.0-20140804021211-a0b114877d4c // indirect
 	golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect

+ 10 - 70
go.sum

@@ -1,26 +1,19 @@
 cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
 cloud.google.com/go v0.34.0 h1:eOI3/cP2VTU6uZLDYAoic+eyzzB9YyGmJ7eIjl8rOPg=
 cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+filippo.io/edwards25519 v1.0.0-rc.1 h1:m0VOOB23frXZvAOK44usCgLWvtsxIoMCTBGJZlpmGfU=
+filippo.io/edwards25519 v1.0.0-rc.1/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns=
 github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
 github.com/Microsoft/go-winio v0.4.14 h1:+hMXMk01us9KgxGb7ftKQt2Xpf5hH/yky+TDA+qxleU=
 github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA=
 github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
 github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
 github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
-github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
 github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
 github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
 github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
-github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
 github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
-github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
 github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
-github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
-github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
-github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI=
-github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
-github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
-github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
 github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
 github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
 github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
@@ -48,12 +41,6 @@ github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw
 github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
 github.com/eclipse/paho.mqtt.golang v1.3.5 h1:sWtmgNxYM9P2sP+xEItMozsR3w0cqZFlqnNN1bdl41Y=
 github.com/eclipse/paho.mqtt.golang v1.3.5/go.mod h1:eTzb4gxwwyWpqBUHGQZ4ABAV7+Jgm1PklsYT/eo8Hcc=
-github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
-github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
-github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
-github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
-github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=
-github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
 github.com/felixge/httpsnoop v1.0.1 h1:lvB5Jl89CsZtGIWuTcDM1E/vkVs49/Ml7JJe07l8SPQ=
 github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
 github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
@@ -83,30 +70,15 @@ github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4er
 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.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
-github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
-github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
-github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
-github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
-github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
-github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
-github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
-github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
-github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
-github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
 github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
 github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
 github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
 github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
 github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
-github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
-github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
-github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o=
 github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=
-github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
 github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
 github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
 github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
@@ -120,7 +92,6 @@ github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/ad
 github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
 github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
 github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
-github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
 github.com/guumaster/cligger v0.1.1/go.mod h1:7d2cVJR7sExHITuqWUU7S9inAs+Hx1QbMDZwO+21a64=
 github.com/guumaster/hostctl v1.1.2 h1:M+DrRaLLeBt7JTh3YbE607gCgRzyxOKuqyrpBC153LQ=
 github.com/guumaster/hostctl v1.1.2/go.mod h1:n5R/s1/tUbYNN1t3J/F/70ZGUWzExgJnEAS0YZ8VWg8=
@@ -149,8 +120,8 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
 github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
 github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w=
 github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY=
-github.com/lib/pq v1.10.4 h1:SO9z7FRPzA03QhHKJrH5BXA6HU1rS4V2nIVrrNC1iYk=
-github.com/lib/pq v1.10.4/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
+github.com/lib/pq v1.10.5 h1:J+gdV2cUmX7ZqL2B0lFcW0m+egaHC2V3lpO8nWxyYiQ=
+github.com/lib/pq v1.10.5/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
 github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
 github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
 github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
@@ -190,14 +161,12 @@ github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXP
 github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
 github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
 github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
-github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
 github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
 github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
 github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
 github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
 github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
 github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
-github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
 github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
 github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8=
 github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
@@ -207,6 +176,10 @@ github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR
 github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
 github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
 github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
+github.com/seancfoley/bintree v1.0.1 h1:rCb5DEugf2B2DtkrxJ80CP6HT24yohDEcXPOqkQRizo=
+github.com/seancfoley/bintree v1.0.1/go.mod h1:CtE6qO6/n9H3V2CAGEC0lpaYr6/OijhNaMG/dt7P70c=
+github.com/seancfoley/ipaddress-go v1.1.2 h1:zeAUfL7foAPe1pIlT2agp17tgpwzU6YKuEAa2VrRKOw=
+github.com/seancfoley/ipaddress-go v1.1.2/go.mod h1:gR/Gr3Sx+pzusadtM9s98e/tZjvL4YnumYTPcKoHWec=
 github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
 github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
 github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
@@ -240,14 +213,13 @@ github.com/txn2/txeh v1.3.0/go.mod h1:O7M6gUTPeMF+vsa4c4Ipx3JDkOYrruB1Wry8QRsMcw
 github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
 github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
 github.com/urfave/cli v1.22.5/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
-github.com/urfave/cli/v2 v2.4.0 h1:m2pxjjDFgDxSPtO8WSdbndj17Wu2y8vOT86wE/tjr+I=
-github.com/urfave/cli/v2 v2.4.0/go.mod h1:NX9W0zmTvedE5oDoOMs2RTC8RvdK98NTYZE5LbaEYPg=
+github.com/urfave/cli/v2 v2.4.8 h1:9HuvvddU3oEJr1tJlwUVVsk3snVWMuKSpyAO+SzTNuI=
+github.com/urfave/cli/v2 v2.4.8/go.mod h1:oDzoM7pVwz6wHn5ogWgFUU1s4VJayeQS+aEZDqXIEJs=
 github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
 github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
 github.com/xtgo/uuid v0.0.0-20140804021211-a0b114877d4c h1:3lbZUMbMiGUW/LMkfsEABsc5zNT9+b1CvsJx47JzJ8g=
 github.com/xtgo/uuid v0.0.0-20140804021211-a0b114877d4c/go.mod h1:UrdRz5enIKZ63MEE3IF9l2/ebyx59GyGgPi+tICQdmM=
 go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
-go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
 go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
 go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
 go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
@@ -261,22 +233,18 @@ golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0
 golang.org/x/crypto v0.0.0-20220208050332-20e1d8d225ab/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
 golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd h1:XcWmESyNjXJMLahc3mqVQJcgSTDxFxhETVlfk9uGc38=
 golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
-golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
-golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
 golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
 golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
 golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
 golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
 golang.org/x/net v0.0.0-20200425230154-ff2c4b7c35a0/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
 golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
-golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
 golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
 golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
 golang.org/x/net v0.0.0-20210928044308-7d9f5e0b762b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
@@ -291,7 +259,6 @@ golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4Iltr
 golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
 golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -330,9 +297,7 @@ golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGm
 golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
-golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
 golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
-golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
 golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@@ -347,30 +312,8 @@ google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9Ywl
 google.golang.org/appengine v1.4.0 h1:/wp5JvzpHIxhs/dumFmF7BXTf3Z+dd4uXta4kVyO508=
 google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
 google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
-google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
-google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
-google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
-google.golang.org/genproto v0.0.0-20210201151548-94839c025ad4 h1:HPkKL4eEh/nemF/FRzYMrFsAh1ZPm5t8NqKBI/Ejlg0=
-google.golang.org/genproto v0.0.0-20210201151548-94839c025ad4/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
 google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
 google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
-google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
-google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
-google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
-google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
-google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
-google.golang.org/grpc v1.45.0 h1:NEpgUqV3Z+ZjkqMsxMg11IaDrXY4RY6CQukSGK0uI1M=
-google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ=
-google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
-google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
-google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
-google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
-google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
-google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
-google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
-google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
-google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
-google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
 google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
 google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
 google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw=
@@ -388,8 +331,6 @@ gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
 gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
 gopkg.in/yaml.v2 v2.2.1/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.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
 gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
@@ -398,4 +339,3 @@ gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C
 gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
 gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
-honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=

+ 0 - 200
grpc/node.pb.go

@@ -1,200 +0,0 @@
-// Code generated by protoc-gen-go. DO NOT EDIT.
-// versions:
-// 	protoc-gen-go v1.25.0-devel
-// 	protoc        v3.14.0
-// source: grpc/node.proto
-
-package nodepb
-
-import (
-	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
-	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
-	reflect "reflect"
-	sync "sync"
-)
-
-const (
-	// Verify that this generated code is sufficiently up-to-date.
-	_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
-	// Verify that runtime/protoimpl is sufficiently up-to-date.
-	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
-)
-
-type Object struct {
-	state         protoimpl.MessageState
-	sizeCache     protoimpl.SizeCache
-	unknownFields protoimpl.UnknownFields
-
-	Data     string `protobuf:"bytes,1,opt,name=Data,proto3" json:"Data,omitempty"`
-	Type     string `protobuf:"bytes,2,opt,name=Type,proto3" json:"Type,omitempty"`
-	Metadata string `protobuf:"bytes,3,opt,name=Metadata,proto3" json:"Metadata,omitempty"`
-}
-
-func (x *Object) Reset() {
-	*x = Object{}
-	if protoimpl.UnsafeEnabled {
-		mi := &file_grpc_node_proto_msgTypes[0]
-		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
-		ms.StoreMessageInfo(mi)
-	}
-}
-
-func (x *Object) String() string {
-	return protoimpl.X.MessageStringOf(x)
-}
-
-func (*Object) ProtoMessage() {}
-
-func (x *Object) ProtoReflect() protoreflect.Message {
-	mi := &file_grpc_node_proto_msgTypes[0]
-	if protoimpl.UnsafeEnabled && x != nil {
-		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
-		if ms.LoadMessageInfo() == nil {
-			ms.StoreMessageInfo(mi)
-		}
-		return ms
-	}
-	return mi.MessageOf(x)
-}
-
-// Deprecated: Use Object.ProtoReflect.Descriptor instead.
-func (*Object) Descriptor() ([]byte, []int) {
-	return file_grpc_node_proto_rawDescGZIP(), []int{0}
-}
-
-func (x *Object) GetData() string {
-	if x != nil {
-		return x.Data
-	}
-	return ""
-}
-
-func (x *Object) GetType() string {
-	if x != nil {
-		return x.Type
-	}
-	return ""
-}
-
-func (x *Object) GetMetadata() string {
-	if x != nil {
-		return x.Metadata
-	}
-	return ""
-}
-
-var File_grpc_node_proto protoreflect.FileDescriptor
-
-var file_grpc_node_proto_rawDesc = []byte{
-	0x0a, 0x0f, 0x67, 0x72, 0x70, 0x63, 0x2f, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74,
-	0x6f, 0x12, 0x04, 0x6e, 0x6f, 0x64, 0x65, 0x22, 0x4c, 0x0a, 0x06, 0x4f, 0x62, 0x6a, 0x65, 0x63,
-	0x74, 0x12, 0x12, 0x0a, 0x04, 0x44, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
-	0x04, 0x44, 0x61, 0x74, 0x61, 0x12, 0x12, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20,
-	0x01, 0x28, 0x09, 0x52, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x4d, 0x65, 0x74,
-	0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x4d, 0x65, 0x74,
-	0x61, 0x64, 0x61, 0x74, 0x61, 0x32, 0xd2, 0x02, 0x0a, 0x0b, 0x4e, 0x6f, 0x64, 0x65, 0x53, 0x65,
-	0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x23, 0x0a, 0x05, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x12, 0x0c,
-	0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x1a, 0x0c, 0x2e, 0x6e,
-	0x6f, 0x64, 0x65, 0x2e, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x28, 0x0a, 0x0a, 0x43, 0x72,
-	0x65, 0x61, 0x74, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x0c, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e,
-	0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x1a, 0x0c, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x4f, 0x62,
-	0x6a, 0x65, 0x63, 0x74, 0x12, 0x26, 0x0a, 0x08, 0x52, 0x65, 0x61, 0x64, 0x4e, 0x6f, 0x64, 0x65,
-	0x12, 0x0c, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x1a, 0x0c,
-	0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x28, 0x0a, 0x0a,
-	0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x0c, 0x2e, 0x6e, 0x6f, 0x64,
-	0x65, 0x2e, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x1a, 0x0c, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e,
-	0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x28, 0x0a, 0x0a, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65,
-	0x4e, 0x6f, 0x64, 0x65, 0x12, 0x0c, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x4f, 0x62, 0x6a, 0x65,
-	0x63, 0x74, 0x1a, 0x0c, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74,
-	0x12, 0x26, 0x0a, 0x08, 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x73, 0x12, 0x0c, 0x2e, 0x6e,
-	0x6f, 0x64, 0x65, 0x2e, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x1a, 0x0c, 0x2e, 0x6e, 0x6f, 0x64,
-	0x65, 0x2e, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x29, 0x0a, 0x0b, 0x47, 0x65, 0x74, 0x45,
-	0x78, 0x74, 0x50, 0x65, 0x65, 0x72, 0x73, 0x12, 0x0c, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x4f,
-	0x62, 0x6a, 0x65, 0x63, 0x74, 0x1a, 0x0c, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x4f, 0x62, 0x6a,
-	0x65, 0x63, 0x74, 0x12, 0x25, 0x0a, 0x07, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x49, 0x6e, 0x12, 0x0c,
-	0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x1a, 0x0c, 0x2e, 0x6e,
-	0x6f, 0x64, 0x65, 0x2e, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x42, 0x2f, 0x5a, 0x2d, 0x67, 0x6f,
-	0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x67, 0x6f, 0x6c, 0x61, 0x6e, 0x67, 0x2e, 0x6f, 0x72, 0x67, 0x2f,
-	0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2f, 0x6b,
-	0x6e, 0x6f, 0x77, 0x6e, 0x2f, 0x6e, 0x6f, 0x64, 0x65, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f,
-	0x74, 0x6f, 0x33,
-}
-
-var (
-	file_grpc_node_proto_rawDescOnce sync.Once
-	file_grpc_node_proto_rawDescData = file_grpc_node_proto_rawDesc
-)
-
-func file_grpc_node_proto_rawDescGZIP() []byte {
-	file_grpc_node_proto_rawDescOnce.Do(func() {
-		file_grpc_node_proto_rawDescData = protoimpl.X.CompressGZIP(file_grpc_node_proto_rawDescData)
-	})
-	return file_grpc_node_proto_rawDescData
-}
-
-var file_grpc_node_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
-var file_grpc_node_proto_goTypes = []interface{}{
-	(*Object)(nil), // 0: node.Object
-}
-var file_grpc_node_proto_depIdxs = []int32{
-	0, // 0: node.NodeService.Login:input_type -> node.Object
-	0, // 1: node.NodeService.CreateNode:input_type -> node.Object
-	0, // 2: node.NodeService.ReadNode:input_type -> node.Object
-	0, // 3: node.NodeService.UpdateNode:input_type -> node.Object
-	0, // 4: node.NodeService.DeleteNode:input_type -> node.Object
-	0, // 5: node.NodeService.GetPeers:input_type -> node.Object
-	0, // 6: node.NodeService.GetExtPeers:input_type -> node.Object
-	0, // 7: node.NodeService.CheckIn:input_type -> node.Object
-	0, // 8: node.NodeService.Login:output_type -> node.Object
-	0, // 9: node.NodeService.CreateNode:output_type -> node.Object
-	0, // 10: node.NodeService.ReadNode:output_type -> node.Object
-	0, // 11: node.NodeService.UpdateNode:output_type -> node.Object
-	0, // 12: node.NodeService.DeleteNode:output_type -> node.Object
-	0, // 13: node.NodeService.GetPeers:output_type -> node.Object
-	0, // 14: node.NodeService.GetExtPeers:output_type -> node.Object
-	0, // 15: node.NodeService.CheckIn:output_type -> node.Object
-	8, // [8:16] is the sub-list for method output_type
-	0, // [0:8] is the sub-list for method input_type
-	0, // [0:0] is the sub-list for extension type_name
-	0, // [0:0] is the sub-list for extension extendee
-	0, // [0:0] is the sub-list for field type_name
-}
-
-func init() { file_grpc_node_proto_init() }
-func file_grpc_node_proto_init() {
-	if File_grpc_node_proto != nil {
-		return
-	}
-	if !protoimpl.UnsafeEnabled {
-		file_grpc_node_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
-			switch v := v.(*Object); i {
-			case 0:
-				return &v.state
-			case 1:
-				return &v.sizeCache
-			case 2:
-				return &v.unknownFields
-			default:
-				return nil
-			}
-		}
-	}
-	type x struct{}
-	out := protoimpl.TypeBuilder{
-		File: protoimpl.DescBuilder{
-			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
-			RawDescriptor: file_grpc_node_proto_rawDesc,
-			NumEnums:      0,
-			NumMessages:   1,
-			NumExtensions: 0,
-			NumServices:   1,
-		},
-		GoTypes:           file_grpc_node_proto_goTypes,
-		DependencyIndexes: file_grpc_node_proto_depIdxs,
-		MessageInfos:      file_grpc_node_proto_msgTypes,
-	}.Build()
-	File_grpc_node_proto = out.File
-	file_grpc_node_proto_rawDesc = nil
-	file_grpc_node_proto_goTypes = nil
-	file_grpc_node_proto_depIdxs = nil
-}

+ 0 - 20
grpc/node.proto

@@ -1,20 +0,0 @@
-syntax = "proto3";
-package node;
-option go_package = "google.golang.org/protobuf/types/known/nodepb";
-
-service NodeService {
-    rpc Login(Object) returns (Object);
-    rpc CreateNode(Object) returns (Object);
-    rpc ReadNode(Object) returns (Object);
-    rpc UpdateNode(Object) returns (Object);
-    rpc DeleteNode(Object) returns (Object);
-    rpc GetPeers(Object) returns (Object);
-    rpc GetExtPeers(Object) returns (Object);
-    rpc CheckIn(Object) returns (Object);
-}
-
-message Object {  
-    string Data = 1;
-    string Type = 2;
-    string Metadata = 3;
-}

+ 0 - 353
grpc/node_grpc.pb.go

@@ -1,353 +0,0 @@
-// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
-
-package nodepb
-
-import (
-	context "context"
-	grpc "google.golang.org/grpc"
-	codes "google.golang.org/grpc/codes"
-	status "google.golang.org/grpc/status"
-)
-
-// This is a compile-time assertion to ensure that this generated file
-// is compatible with the grpc package it is being compiled against.
-// Requires gRPC-Go v1.32.0 or later.
-const _ = grpc.SupportPackageIsVersion7
-
-// NodeServiceClient is the client API for NodeService service.
-//
-// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
-type NodeServiceClient interface {
-	Login(ctx context.Context, in *Object, opts ...grpc.CallOption) (*Object, error)
-	CreateNode(ctx context.Context, in *Object, opts ...grpc.CallOption) (*Object, error)
-	ReadNode(ctx context.Context, in *Object, opts ...grpc.CallOption) (*Object, error)
-	UpdateNode(ctx context.Context, in *Object, opts ...grpc.CallOption) (*Object, error)
-	DeleteNode(ctx context.Context, in *Object, opts ...grpc.CallOption) (*Object, error)
-	GetPeers(ctx context.Context, in *Object, opts ...grpc.CallOption) (*Object, error)
-	GetExtPeers(ctx context.Context, in *Object, opts ...grpc.CallOption) (*Object, error)
-	CheckIn(ctx context.Context, in *Object, opts ...grpc.CallOption) (*Object, error)
-}
-
-type nodeServiceClient struct {
-	cc grpc.ClientConnInterface
-}
-
-func NewNodeServiceClient(cc grpc.ClientConnInterface) NodeServiceClient {
-	return &nodeServiceClient{cc}
-}
-
-func (c *nodeServiceClient) Login(ctx context.Context, in *Object, opts ...grpc.CallOption) (*Object, error) {
-	out := new(Object)
-	err := c.cc.Invoke(ctx, "/node.NodeService/Login", in, out, opts...)
-	if err != nil {
-		return nil, err
-	}
-	return out, nil
-}
-
-func (c *nodeServiceClient) CreateNode(ctx context.Context, in *Object, opts ...grpc.CallOption) (*Object, error) {
-	out := new(Object)
-	err := c.cc.Invoke(ctx, "/node.NodeService/CreateNode", in, out, opts...)
-	if err != nil {
-		return nil, err
-	}
-	return out, nil
-}
-
-func (c *nodeServiceClient) ReadNode(ctx context.Context, in *Object, opts ...grpc.CallOption) (*Object, error) {
-	out := new(Object)
-	err := c.cc.Invoke(ctx, "/node.NodeService/ReadNode", in, out, opts...)
-	if err != nil {
-		return nil, err
-	}
-	return out, nil
-}
-
-func (c *nodeServiceClient) UpdateNode(ctx context.Context, in *Object, opts ...grpc.CallOption) (*Object, error) {
-	out := new(Object)
-	err := c.cc.Invoke(ctx, "/node.NodeService/UpdateNode", in, out, opts...)
-	if err != nil {
-		return nil, err
-	}
-	return out, nil
-}
-
-func (c *nodeServiceClient) DeleteNode(ctx context.Context, in *Object, opts ...grpc.CallOption) (*Object, error) {
-	out := new(Object)
-	err := c.cc.Invoke(ctx, "/node.NodeService/DeleteNode", in, out, opts...)
-	if err != nil {
-		return nil, err
-	}
-	return out, nil
-}
-
-func (c *nodeServiceClient) GetPeers(ctx context.Context, in *Object, opts ...grpc.CallOption) (*Object, error) {
-	out := new(Object)
-	err := c.cc.Invoke(ctx, "/node.NodeService/GetPeers", in, out, opts...)
-	if err != nil {
-		return nil, err
-	}
-	return out, nil
-}
-
-func (c *nodeServiceClient) GetExtPeers(ctx context.Context, in *Object, opts ...grpc.CallOption) (*Object, error) {
-	out := new(Object)
-	err := c.cc.Invoke(ctx, "/node.NodeService/GetExtPeers", in, out, opts...)
-	if err != nil {
-		return nil, err
-	}
-	return out, nil
-}
-
-func (c *nodeServiceClient) CheckIn(ctx context.Context, in *Object, opts ...grpc.CallOption) (*Object, error) {
-	out := new(Object)
-	err := c.cc.Invoke(ctx, "/node.NodeService/CheckIn", in, out, opts...)
-	if err != nil {
-		return nil, err
-	}
-	return out, nil
-}
-
-// NodeServiceServer is the server API for NodeService service.
-// All implementations must embed UnimplementedNodeServiceServer
-// for forward compatibility
-type NodeServiceServer interface {
-	Login(context.Context, *Object) (*Object, error)
-	CreateNode(context.Context, *Object) (*Object, error)
-	ReadNode(context.Context, *Object) (*Object, error)
-	UpdateNode(context.Context, *Object) (*Object, error)
-	DeleteNode(context.Context, *Object) (*Object, error)
-	GetPeers(context.Context, *Object) (*Object, error)
-	GetExtPeers(context.Context, *Object) (*Object, error)
-	CheckIn(context.Context, *Object) (*Object, error)
-	mustEmbedUnimplementedNodeServiceServer()
-}
-
-// UnimplementedNodeServiceServer must be embedded to have forward compatible implementations.
-type UnimplementedNodeServiceServer struct {
-}
-
-func (UnimplementedNodeServiceServer) Login(context.Context, *Object) (*Object, error) {
-	return nil, status.Errorf(codes.Unimplemented, "method Login not implemented")
-}
-func (UnimplementedNodeServiceServer) CreateNode(context.Context, *Object) (*Object, error) {
-	return nil, status.Errorf(codes.Unimplemented, "method CreateNode not implemented")
-}
-func (UnimplementedNodeServiceServer) ReadNode(context.Context, *Object) (*Object, error) {
-	return nil, status.Errorf(codes.Unimplemented, "method ReadNode not implemented")
-}
-func (UnimplementedNodeServiceServer) UpdateNode(context.Context, *Object) (*Object, error) {
-	return nil, status.Errorf(codes.Unimplemented, "method UpdateNode not implemented")
-}
-func (UnimplementedNodeServiceServer) DeleteNode(context.Context, *Object) (*Object, error) {
-	return nil, status.Errorf(codes.Unimplemented, "method DeleteNode not implemented")
-}
-func (UnimplementedNodeServiceServer) GetPeers(context.Context, *Object) (*Object, error) {
-	return nil, status.Errorf(codes.Unimplemented, "method GetPeers not implemented")
-}
-func (UnimplementedNodeServiceServer) GetExtPeers(context.Context, *Object) (*Object, error) {
-	return nil, status.Errorf(codes.Unimplemented, "method GetExtPeers not implemented")
-}
-func (UnimplementedNodeServiceServer) CheckIn(context.Context, *Object) (*Object, error) {
-	return nil, status.Errorf(codes.Unimplemented, "method CheckIn not implemented")
-}
-func (UnimplementedNodeServiceServer) mustEmbedUnimplementedNodeServiceServer() {}
-
-// UnsafeNodeServiceServer may be embedded to opt out of forward compatibility for this service.
-// Use of this interface is not recommended, as added methods to NodeServiceServer will
-// result in compilation errors.
-type UnsafeNodeServiceServer interface {
-	mustEmbedUnimplementedNodeServiceServer()
-}
-
-func RegisterNodeServiceServer(s grpc.ServiceRegistrar, srv NodeServiceServer) {
-	s.RegisterService(&NodeService_ServiceDesc, srv)
-}
-
-func _NodeService_Login_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
-	in := new(Object)
-	if err := dec(in); err != nil {
-		return nil, err
-	}
-	if interceptor == nil {
-		return srv.(NodeServiceServer).Login(ctx, in)
-	}
-	info := &grpc.UnaryServerInfo{
-		Server:     srv,
-		FullMethod: "/node.NodeService/Login",
-	}
-	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
-		return srv.(NodeServiceServer).Login(ctx, req.(*Object))
-	}
-	return interceptor(ctx, in, info, handler)
-}
-
-func _NodeService_CreateNode_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
-	in := new(Object)
-	if err := dec(in); err != nil {
-		return nil, err
-	}
-	if interceptor == nil {
-		return srv.(NodeServiceServer).CreateNode(ctx, in)
-	}
-	info := &grpc.UnaryServerInfo{
-		Server:     srv,
-		FullMethod: "/node.NodeService/CreateNode",
-	}
-	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
-		return srv.(NodeServiceServer).CreateNode(ctx, req.(*Object))
-	}
-	return interceptor(ctx, in, info, handler)
-}
-
-func _NodeService_ReadNode_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
-	in := new(Object)
-	if err := dec(in); err != nil {
-		return nil, err
-	}
-	if interceptor == nil {
-		return srv.(NodeServiceServer).ReadNode(ctx, in)
-	}
-	info := &grpc.UnaryServerInfo{
-		Server:     srv,
-		FullMethod: "/node.NodeService/ReadNode",
-	}
-	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
-		return srv.(NodeServiceServer).ReadNode(ctx, req.(*Object))
-	}
-	return interceptor(ctx, in, info, handler)
-}
-
-func _NodeService_UpdateNode_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
-	in := new(Object)
-	if err := dec(in); err != nil {
-		return nil, err
-	}
-	if interceptor == nil {
-		return srv.(NodeServiceServer).UpdateNode(ctx, in)
-	}
-	info := &grpc.UnaryServerInfo{
-		Server:     srv,
-		FullMethod: "/node.NodeService/UpdateNode",
-	}
-	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
-		return srv.(NodeServiceServer).UpdateNode(ctx, req.(*Object))
-	}
-	return interceptor(ctx, in, info, handler)
-}
-
-func _NodeService_DeleteNode_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
-	in := new(Object)
-	if err := dec(in); err != nil {
-		return nil, err
-	}
-	if interceptor == nil {
-		return srv.(NodeServiceServer).DeleteNode(ctx, in)
-	}
-	info := &grpc.UnaryServerInfo{
-		Server:     srv,
-		FullMethod: "/node.NodeService/DeleteNode",
-	}
-	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
-		return srv.(NodeServiceServer).DeleteNode(ctx, req.(*Object))
-	}
-	return interceptor(ctx, in, info, handler)
-}
-
-func _NodeService_GetPeers_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
-	in := new(Object)
-	if err := dec(in); err != nil {
-		return nil, err
-	}
-	if interceptor == nil {
-		return srv.(NodeServiceServer).GetPeers(ctx, in)
-	}
-	info := &grpc.UnaryServerInfo{
-		Server:     srv,
-		FullMethod: "/node.NodeService/GetPeers",
-	}
-	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
-		return srv.(NodeServiceServer).GetPeers(ctx, req.(*Object))
-	}
-	return interceptor(ctx, in, info, handler)
-}
-
-func _NodeService_GetExtPeers_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
-	in := new(Object)
-	if err := dec(in); err != nil {
-		return nil, err
-	}
-	if interceptor == nil {
-		return srv.(NodeServiceServer).GetExtPeers(ctx, in)
-	}
-	info := &grpc.UnaryServerInfo{
-		Server:     srv,
-		FullMethod: "/node.NodeService/GetExtPeers",
-	}
-	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
-		return srv.(NodeServiceServer).GetExtPeers(ctx, req.(*Object))
-	}
-	return interceptor(ctx, in, info, handler)
-}
-
-func _NodeService_CheckIn_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
-	in := new(Object)
-	if err := dec(in); err != nil {
-		return nil, err
-	}
-	if interceptor == nil {
-		return srv.(NodeServiceServer).CheckIn(ctx, in)
-	}
-	info := &grpc.UnaryServerInfo{
-		Server:     srv,
-		FullMethod: "/node.NodeService/CheckIn",
-	}
-	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
-		return srv.(NodeServiceServer).CheckIn(ctx, req.(*Object))
-	}
-	return interceptor(ctx, in, info, handler)
-}
-
-// NodeService_ServiceDesc is the grpc.ServiceDesc for NodeService service.
-// It's only intended for direct use with grpc.RegisterService,
-// and not to be introspected or modified (even as a copy)
-var NodeService_ServiceDesc = grpc.ServiceDesc{
-	ServiceName: "node.NodeService",
-	HandlerType: (*NodeServiceServer)(nil),
-	Methods: []grpc.MethodDesc{
-		{
-			MethodName: "Login",
-			Handler:    _NodeService_Login_Handler,
-		},
-		{
-			MethodName: "CreateNode",
-			Handler:    _NodeService_CreateNode_Handler,
-		},
-		{
-			MethodName: "ReadNode",
-			Handler:    _NodeService_ReadNode_Handler,
-		},
-		{
-			MethodName: "UpdateNode",
-			Handler:    _NodeService_UpdateNode_Handler,
-		},
-		{
-			MethodName: "DeleteNode",
-			Handler:    _NodeService_DeleteNode_Handler,
-		},
-		{
-			MethodName: "GetPeers",
-			Handler:    _NodeService_GetPeers_Handler,
-		},
-		{
-			MethodName: "GetExtPeers",
-			Handler:    _NodeService_GetExtPeers_Handler,
-		},
-		{
-			MethodName: "CheckIn",
-			Handler:    _NodeService_CheckIn_Handler,
-		},
-	},
-	Streams:  []grpc.StreamDesc{},
-	Metadata: "grpc/node.proto",
-}

+ 0 - 6
grpc/types.go

@@ -1,6 +0,0 @@
-package nodepb
-
-const STRING_TYPE = "string"
-const NODE_TYPE = "node"
-const EXT_PEER = "extpeer"
-const ACCESS_TOKEN = "accesstoken"

+ 0 - 10
kube/components/netmaker-api.yaml

@@ -25,20 +25,12 @@ spec:
         env:
         - name: SERVER_API_CONN_STRING
           value: "api.nm.k8s.gravitl.com:443"
-        - name: SERVER_GRPC_CONN_STRING
-          value: "grpc.nm.k8s.gravitl.com:443"
         - name: COREDNS_ADDR
           value: "netmaker-dns"
-        - name: GRPC_SSL
-          value: "on"
         - name: SERVER_HTTP_HOST
           value: "api.nm.k8s.gravitl.com"
-        - name: SERVER_GRPC_HOST
-          value: "grpc.nm.k8s.gravitl.com"
         - name: API_PORT
           value: "8081"
-        - name: GRPC_PORT
-          value: "50051"
         - name: AGENT_BACKEND
           value: "off"
         - name: CLIENT_MODE
@@ -47,8 +39,6 @@ spec:
           value: "on"
         - name: MASTER_KEY
           value: "Unkn0wn!"
-        - name: SERVER_GRPC_WIREGUARD
-          value: "off"
         - name: MASTER_KEY
           value: "secretkey"
         - name: CORS_ALLOWED_ORIGIN

+ 0 - 11
kube/components/netmaker-backend.yaml

@@ -25,26 +25,16 @@ spec:
         env:
         - name: SERVER_API_CONN_STRING
           value: "api.nm.k8s.gravitl.com:443"
-        - name: SERVER_GRPC_CONN_STRING
-          value: "grpc.nm.k8s.gravitl.com:443"
         - name: COREDNS_ADDR
           value: "10.152.183.53"
-        - name: GRPC_SSL
-          value: "on"
         - name: SERVER_HTTP_HOST
           value: "api.k8s.gravitl.com"
-        - name: SERVER_GRPC_HOST
-          value: "grpc.k8s.gravitl.com"
         - name: API_PORT
           value: "8081"
-        - name: GRPC_PORT
-          value: "443"
         - name: CLIENT_MODE
           value: "off"
         - name: MASTER_KEY
           value: "Unkn0wn!"
-        - name: SERVER_GRPC_WIREGUARD
-          value: "off"
         - name: MASTER_KEY
           value: "secretkey"
         - name: CORS_ALLOWED_ORIGIN
@@ -97,7 +87,6 @@ kind: Service
 metadata:
   labels:
     app: netmaker-backend
-  name: netmaker-grpc
 spec:
   ports:
   - port: 443

+ 0 - 10
kube/components/netmaker-template.yaml.backup

@@ -84,26 +84,16 @@ spec:
         env:
         - name: SERVER_API_CONN_STRING
           value: "api.NETMAKER_BASE_DOMAIN:443"
-        - name: SERVER_GRPC_CONN_STRING
-          value: "grpc.NETMAKER_BASE_DOMAIN:443"
         - name: COREDNS_ADDR
           value: "10.152.183.53"
-        - name: GRPC_SSL
-          value: "on"
         - name: SERVER_HTTP_HOST
           value: "api.NETMAKER_BASE_DOMAIN"
-        - name: SERVER_GRPC_HOST
-          value: "grpc.NETMAKER_BASE_DOMAIN"
         - name: API_PORT
           value: "8081"
-        - name: GRPC_PORT
-          value: "443"
         - name: CLIENT_MODE
           value: "off"
         - name: MASTER_KEY
           value: "Unkn0wn!"
-        - name: SERVER_GRPC_WIREGUARD
-          value: "off"
         - name: MASTER_KEY
           value: "secretkey"
         - name: CORS_ALLOWED_ORIGIN

+ 0 - 8
kube/netmaker-template-udp.yaml

@@ -56,24 +56,16 @@ spec:
         env:
         - name: SERVER_API_CONN_STRING
           value: "api.NETMAKER_BASE_DOMAIN:443"
-        - name: SERVER_GRPC_CONN_STRING
-          value: "grpc.NETMAKER_BASE_DOMAIN:443"
         - name: COREDNS_ADDR
           value: "10.152.183.53"
         - name: POD_IP
           valueFrom:
             fieldRef:
               fieldPath: status.podIP
-        - name: GRPC_SSL
-          value: "on"
         - name: SERVER_HTTP_HOST
           value: "api.NETMAKER_BASE_DOMAIN:443"
-        - name: SERVER_GRPC_HOST
-          value: "grpc.NETMAKER_BASE_DOMAIN:443"
         - name: API_PORT
           value: "8081"
-        - name: GRPC_PORT
-          value: "443"
         - name: CLIENT_MODE
           value: "off"
         - name: MASTER_KEY

+ 0 - 8
kube/netmaker-template.yaml

@@ -39,24 +39,16 @@ spec:
         env:
         - name: SERVER_API_CONN_STRING
           value: "api.NETMAKER_BASE_DOMAIN:443"
-        - name: SERVER_GRPC_CONN_STRING
-          value: "grpc.NETMAKER_BASE_DOMAIN:443"
         - name: COREDNS_ADDR
           value: "10.152.183.53"
         - name: POD_IP
           valueFrom:
             fieldRef:
               fieldPath: status.podIP
-        - name: GRPC_SSL
-          value: "on"
         - name: SERVER_HTTP_HOST
           value: "api.NETMAKER_BASE_DOMAIN"
-        - name: SERVER_GRPC_HOST
-          value: "grpc.NETMAKER_BASE_DOMAIN"
         - name: API_PORT
           value: "8081"
-        - name: GRPC_PORT
-          value: "80"
         - name: CLIENT_MODE
           value: "off"
         - name: MASTER_KEY

+ 4 - 10
logger/util.go

@@ -1,9 +1,9 @@
 package logger
 
 import (
-	"os"
-	"strconv"
 	"strings"
+
+	"github.com/gravitl/netmaker/servercfg"
 )
 
 // Verbosity - current logging verbosity level (optionally set)
@@ -25,12 +25,6 @@ func getVerbose() int32 {
 	if Verbosity >= 1 && Verbosity <= 3 {
 		return int32(Verbosity)
 	}
-	level, err := strconv.Atoi(os.Getenv("VERBOSITY"))
-	if err != nil || level < 0 {
-		level = 0
-	}
-	if level > 3 {
-		level = 3
-	}
-	return int32(level)
+	Verbosity = int(servercfg.GetVerbosity())
+	return int32(Verbosity)
 }

+ 3 - 12
logic/accesskeys.go

@@ -51,17 +51,11 @@ func CreateAccessKey(accesskey models.AccessKey, network models.Network) (models
 
 	netID := network.NetID
 
-	commsNetID, err := FetchCommsNetID()
-	if err != nil {
-		return models.AccessKey{}, errors.New("could not retrieve comms netid")
-	}
-
 	var accessToken models.AccessToken
 	s := servercfg.GetServerConfig()
 	servervals := models.ServerConfig{
-		GRPCConnString: s.GRPCConnString,
-		GRPCSSL:        s.GRPCSSL,
-		CommsNetwork:   commsNetID,
+		Server:        s.Server,
+		APIConnString: s.APIConnString,
 	}
 	accessToken.ServerConfig = servervals
 	accessToken.ClientConfig.Network = netID
@@ -149,7 +143,7 @@ func DecrimentKey(networkName string, keyvalue string) {
 	var network models.Network
 
 	network, err := GetParentNetwork(networkName)
-	if err != nil || network.IsComms == "yes" {
+	if err != nil {
 		return
 	}
 
@@ -182,9 +176,6 @@ func IsKeyValid(networkname string, keyvalue string) bool {
 		return false
 	}
 	accesskeys := network.AccessKeys
-	if network.IsComms == "yes" {
-		accesskeys = getAllAccessKeys()
-	}
 
 	var key models.AccessKey
 	foundkey := false

+ 0 - 1
logic/dns.go

@@ -50,7 +50,6 @@ func SetDNS() error {
 // GetDNS - gets the DNS of a current network
 func GetDNS(network string) ([]models.DNSEntry, error) {
 
-	var dns []models.DNSEntry
 	dns, err := GetNodeDNS(network)
 	if err != nil && !database.IsEmptyRecord(err) {
 		return dns, err

+ 18 - 8
logic/extpeers.go

@@ -33,6 +33,7 @@ func GetExtPeersList(node *models.Node) ([]models.ExtPeersResponse, error) {
 			logger.Log(2, "failed to unmarshal ext client")
 			continue
 		}
+
 		if extClient.Enabled && extClient.Network == node.Network && extClient.IngressGatewayID == node.ID {
 			peers = append(peers, peer)
 		}
@@ -125,20 +126,29 @@ func CreateExtClient(extclient *models.ExtClient) error {
 		extclient.PublicKey = privateKey.PublicKey().String()
 	}
 
+	parentNetwork, err := GetNetwork(extclient.Network)
+	if err != nil {
+		return err
+	}
+
 	if extclient.Address == "" {
-		newAddress, err := UniqueAddress(extclient.Network)
-		if err != nil {
-			return err
+		if parentNetwork.IsIPv4 == "yes" {
+			newAddress, err := UniqueAddress(extclient.Network, false)
+			if err != nil {
+				return err
+			}
+			extclient.Address = newAddress
 		}
-		extclient.Address = newAddress
 	}
 
 	if extclient.Address6 == "" {
-		addr6, err := UniqueAddress6(extclient.Network)
-		if err != nil {
-			return err
+		if parentNetwork.IsIPv6 == "yes" {
+			addr6, err := UniqueAddress6(extclient.Network, false)
+			if err != nil {
+				return err
+			}
+			extclient.Address6 = addr6
 		}
-		extclient.Address6 = addr6
 	}
 
 	if extclient.ClientID == "" {

+ 62 - 0
logic/ips/ips.go

@@ -0,0 +1,62 @@
+package ips
+
+import (
+	"fmt"
+	"strings"
+
+	"github.com/seancfoley/ipaddress-go/ipaddr"
+)
+
+// GetFirstAddr - gets the first valid address in a given IPv4 CIDR
+func GetFirstAddr(cidr4 string) (*ipaddr.IPAddress, error) {
+	currentCidr := ipaddr.NewIPAddressString(cidr4).GetAddress()
+	if !currentCidr.IsIPv4() {
+		return nil, fmt.Errorf("invalid IPv4 CIDR provided to GetFirstAddr")
+	}
+	lower := currentCidr.GetLower()
+	ipParts := strings.Split(lower.GetNetIPAddr().IP.String(), ".")
+	if ipParts[len(ipParts)-1] == "0" {
+		lower = lower.Increment(1)
+	}
+	return lower, nil
+}
+
+// GetLastAddr - gets the last valid address in a given IPv4 CIDR
+func GetLastAddr(cidr4 string) (*ipaddr.IPAddress, error) {
+	currentCidr := ipaddr.NewIPAddressString(cidr4).GetAddress()
+	if !currentCidr.IsIPv4() {
+		return nil, fmt.Errorf("invalid IPv4 CIDR provided to GetLastAddr")
+	}
+	upper := currentCidr.GetUpper()
+	ipParts := strings.Split(upper.GetNetIPAddr().IP.String(), ".")
+	if ipParts[len(ipParts)-1] == "255" {
+		upper = upper.Increment(-1)
+	}
+	return upper, nil
+}
+
+// GetFirstAddr6 - gets the first valid IPv6 address in a given IPv6 CIDR
+func GetFirstAddr6(cidr6 string) (*ipaddr.IPAddress, error) {
+	currentCidr := ipaddr.NewIPAddressString(cidr6).GetAddress()
+	if !currentCidr.IsIPv6() {
+		return nil, fmt.Errorf("invalid IPv6 CIDR provided to GetFirstAddr6")
+	}
+	lower := currentCidr.GetLower()
+	ipParts := strings.Split(lower.GetNetIPAddr().IP.String(), "::")
+	if len(ipParts) == 2 {
+		if len(ipParts[len(ipParts)-1]) == 0 {
+			lower = lower.Increment(1)
+		}
+	}
+	return lower, nil
+}
+
+// GetLastAddr6 - gets the last valid IPv6 address in a given IPv6 CIDR
+func GetLastAddr6(cidr6 string) (*ipaddr.IPAddress, error) {
+	currentCidr := ipaddr.NewIPAddressString(cidr6).GetAddress()
+	if !currentCidr.IsIPv6() {
+		return nil, fmt.Errorf("invalid IPv6 CIDR provided to GetLastAddr6")
+	}
+	upper := currentCidr.GetUpper()
+	return upper, nil
+}

+ 50 - 0
logic/ips/ips_test.go

@@ -0,0 +1,50 @@
+package ips_test
+
+import (
+	"testing"
+
+	"github.com/gravitl/netmaker/logic/ips"
+	"github.com/stretchr/testify/assert"
+)
+
+func TestIp4(t *testing.T) {
+	const ipv4Cidr = "192.168.0.0/16"
+	const ipv6Cidr = "fde6:be04:fa5e:d076::/64"
+	//delete all current users
+	t.Run("Valid Ipv4", func(t *testing.T) {
+		_, err := ips.GetFirstAddr(ipv4Cidr)
+		assert.Nil(t, err)
+	})
+	t.Run("Invalid Ipv4", func(t *testing.T) {
+		_, err := ips.GetFirstAddr(ipv6Cidr)
+		assert.NotNil(t, err)
+	})
+	t.Run("Valid IPv6", func(t *testing.T) {
+		_, err := ips.GetFirstAddr6(ipv6Cidr)
+		assert.Nil(t, err)
+	})
+	t.Run("Invalid IPv6", func(t *testing.T) {
+		_, err := ips.GetFirstAddr6(ipv4Cidr)
+		assert.NotNil(t, err)
+	})
+	t.Run("Last IPv4", func(t *testing.T) {
+		addr, err := ips.GetLastAddr(ipv4Cidr)
+		assert.Nil(t, err)
+		assert.Equal(t, addr.GetNetIPAddr().IP.String(), "192.168.255.254")
+	})
+	t.Run("First IPv4", func(t *testing.T) {
+		addr, err := ips.GetFirstAddr(ipv4Cidr)
+		assert.Nil(t, err)
+		assert.Equal(t, addr.GetNetIPAddr().IP.String(), "192.168.0.1")
+	})
+	t.Run("Last IPv6", func(t *testing.T) {
+		last, err := ips.GetLastAddr6(ipv6Cidr)
+		assert.Nil(t, err)
+		assert.Equal(t, last.GetNetIPAddr().IP.String(), "fde6:be04:fa5e:d076:ffff:ffff:ffff:ffff")
+	})
+	t.Run("First IPv6", func(t *testing.T) {
+		first, err := ips.GetFirstAddr6(ipv6Cidr)
+		assert.Nil(t, err)
+		assert.Equal(t, first.GetNetIPAddr().IP.String(), "fde6:be04:fa5e:d076::1")
+	})
+}

+ 1 - 1
logic/jwts.go

@@ -98,7 +98,7 @@ func VerifyUserToken(tokenString string) (username string, networks []string, is
 	return "", nil, false, err
 }
 
-// VerifyToken - gRPC [nodes] Only
+// VerifyToken - [nodes] Only
 func VerifyToken(tokenString string) (nodeID string, mac string, network string, err error) {
 	claims := &models.Claims{}
 

+ 51 - 81
logic/networks.go

@@ -1,7 +1,6 @@
 package logic
 
 import (
-	"encoding/binary"
 	"encoding/json"
 	"errors"
 	"fmt"
@@ -13,6 +12,7 @@ import (
 	"github.com/gravitl/netmaker/database"
 	"github.com/gravitl/netmaker/logger"
 	"github.com/gravitl/netmaker/logic/acls/nodeacls"
+	"github.com/gravitl/netmaker/logic/ips"
 	"github.com/gravitl/netmaker/models"
 	"github.com/gravitl/netmaker/netclient/ncutils"
 	"github.com/gravitl/netmaker/validation"
@@ -173,71 +173,45 @@ func GetNetworkSettings(networkname string) (models.Network, error) {
 }
 
 // UniqueAddress - see if address is unique
-func UniqueAddress(networkName string) (string, error) {
+func UniqueAddress(networkName string, reverse bool) (string, error) {
 
 	var network models.Network
 	network, err := GetParentNetwork(networkName)
 	if err != nil {
-		fmt.Println("UniqueAddress encountered  an error")
+		logger.Log(0, "UniqueAddressServer encountered  an error")
 		return "666", err
 	}
 
-	offset := true
-	ip, ipnet, err := net.ParseCIDR(network.AddressRange)
-	if err != nil {
-		fmt.Println("UniqueAddress encountered  an error")
-		return "666", err
+	if network.IsIPv4 == "no" {
+		return "", fmt.Errorf("IPv4 not active on network " + networkName)
 	}
-	for ip := ip.Mask(ipnet.Mask); ipnet.Contains(ip); Inc(ip) {
-		if offset {
-			offset = false
-			continue
-		}
-		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
-	err1 := errors.New("ERROR: No unique addresses available. Check network subnet")
-	return "W1R3: NO UNIQUE ADDRESSES AVAILABLE", err1
-}
 
-// UniqueAddressServer - get unique address starting from last available
-func UniqueAddressServer(networkName string) (string, error) {
-
-	var network models.Network
-	network, err := GetParentNetwork(networkName)
+	newAddr, err := ips.GetFirstAddr(network.AddressRange)
 	if err != nil {
-		logger.Log(0, "UniqueAddressServer encountered  an error")
+		logger.Log(0, "UniqueAddress encountered  an error")
 		return "666", err
 	}
 
-	_, ipv4Net, err := net.ParseCIDR(network.AddressRange)
-	if err != nil {
-		logger.Log(0, "UniqueAddressServer encountered  an error")
-		return "666", err
+	incVal := 1
+	if reverse {
+		incVal = -1
+		newAddr, err = ips.GetLastAddr(network.AddressRange)
+		if err != nil {
+			if err != nil {
+				logger.Log(0, "UniqueAddressServer encountered  an error")
+				return "666", err
+			}
+		}
 	}
 
-	// convert IPNet struct mask and address to uint32
-	// network is BigEndian
-	mask := binary.BigEndian.Uint32(ipv4Net.Mask)
-	start := binary.BigEndian.Uint32(ipv4Net.IP)
-
-	// find the final address
-	finish := (start & mask) | (mask ^ 0xffffffff)
-
-	// loop through addresses as uint32
-	for i := finish - 1; i > start; i-- {
-		// convert back to net.IP
-		ip := make(net.IP, 4)
-		binary.BigEndian.PutUint32(ip, i)
-		if IsIPUnique(networkName, ip.String(), database.NODES_TABLE_NAME, false) && IsIPUnique(networkName, ip.String(), database.EXT_CLIENT_TABLE_NAME, false) {
-			return ip.String(), err
+	for ; newAddr.ToAddressString().IsValid(); newAddr = newAddr.Increment(int64(incVal)) {
+		if IsIPUnique(networkName, newAddr.GetNetIPAddr().IP.String(), database.NODES_TABLE_NAME, false) &&
+			IsIPUnique(networkName, newAddr.GetNetIPAddr().IP.String(), database.EXT_CLIENT_TABLE_NAME, false) {
+			return newAddr.GetNetIPAddr().IP.String(), nil
 		}
 	}
 
-	return "W1R3: NO UNIQUE ADDRESSES AVAILABLE", fmt.Errorf("no unique server addresses found")
+	return "W1R3: NO UNIQUE ADDRESSES AVAILABLE", errors.New("ERROR: No unique addresses available. Check network subnet")
 }
 
 // IsIPUnique - checks if an IP is unique
@@ -270,7 +244,7 @@ func IsIPUnique(network string, ip string, tableName string, isIpv6 bool) bool {
 }
 
 // UniqueAddress6 - see if ipv6 address is unique
-func UniqueAddress6(networkName string) (string, error) {
+func UniqueAddress6(networkName string, reverse bool) (string, error) {
 
 	var network models.Network
 	network, err := GetParentNetwork(networkName)
@@ -278,28 +252,35 @@ func UniqueAddress6(networkName string) (string, error) {
 		fmt.Println("Network Not Found")
 		return "", err
 	}
-	if network.IsDualStack == "no" {
-		return "", nil
+	if network.IsIPv6 == "no" {
+		return "", fmt.Errorf("IPv6 not active on network " + networkName)
 	}
 
-	offset := true
-	ip, ipnet, err := net.ParseCIDR(network.AddressRange6)
+	newAddr6, err := ips.GetFirstAddr6(network.AddressRange6)
 	if err != nil {
-		fmt.Println("UniqueAddress6 encountered  an error")
 		return "666", err
 	}
-	for ip := ip.Mask(ipnet.Mask); ipnet.Contains(ip); Inc(ip) {
-		if offset {
-			offset = false
-			continue
+
+	incVal := 1
+	if reverse {
+		incVal = -1
+		newAddr6, err = ips.GetLastAddr6(network.AddressRange6)
+		if err != nil {
+			if err != nil {
+				logger.Log(0, "UniqueAddress6Server encountered  an error")
+				return "666", err
+			}
 		}
-		if IsIPUnique(networkName, ip.String(), database.NODES_TABLE_NAME, true) {
-			return ip.String(), err
+	}
+
+	for ; newAddr6.ToAddressString().IsValid(); newAddr6 = newAddr6.Increment(int64(incVal)) {
+		if IsIPUnique(networkName, newAddr6.GetNetIPAddr().IP.String(), database.NODES_TABLE_NAME, true) &&
+			IsIPUnique(networkName, newAddr6.GetNetIPAddr().IP.String(), database.EXT_CLIENT_TABLE_NAME, true) {
+			return newAddr6.GetNetIPAddr().IP.String(), nil
 		}
 	}
-	//TODO
-	err1 := errors.New("ERROR: No unique addresses available. Check network subnet")
-	return "W1R3: NO UNIQUE ADDRESSES AVAILABLE", err1
+
+	return "W1R3: NO UNIQUE ADDRESSES AVAILABLE", errors.New("ERROR: No unique IPv6 addresses available. Check network subnet")
 }
 
 // GetLocalIP - gets the local ip
@@ -380,9 +361,9 @@ func UpdateNetworkLocalAddresses(networkName string) error {
 			var ipaddr string
 			var iperr error
 			if node.IsServer == "yes" {
-				ipaddr, iperr = UniqueAddressServer(networkName)
+				ipaddr, iperr = UniqueAddress(networkName, true)
 			} else {
-				ipaddr, iperr = UniqueAddress(networkName)
+				ipaddr, iperr = UniqueAddress(networkName, false)
 			}
 			if iperr != nil {
 				fmt.Println("error in node  address assignment!")
@@ -441,7 +422,6 @@ func RemoveNetworkNodeIPv6Addresses(networkName string) error {
 			return err
 		}
 		if node.Network == networkName {
-			node.IsDualStack = "no"
 			node.Address6 = ""
 			data, err := json.Marshal(&node)
 			if err != nil {
@@ -474,9 +454,9 @@ func UpdateNetworkNodeAddresses(networkName string) error {
 			var ipaddr string
 			var iperr error
 			if node.IsServer == "yes" {
-				ipaddr, iperr = UniqueAddressServer(networkName)
+				ipaddr, iperr = UniqueAddress(networkName, true)
 			} else {
-				ipaddr, iperr = UniqueAddress(networkName)
+				ipaddr, iperr = UniqueAddress(networkName, false)
 			}
 			if iperr != nil {
 				fmt.Println("error in node  address assignment!")
@@ -537,16 +517,6 @@ func UpdateNetwork(currentNetwork *models.Network, newNetwork *models.Network) (
 	return false, false, false, errors.New("failed to update network " + newNetwork.NetID + ", cannot change netid.")
 }
 
-// Inc - increments an IP
-func Inc(ip net.IP) {
-	for j := len(ip) - 1; j >= 0; j-- {
-		ip[j]++
-		if ip[j] > 0 {
-			break
-		}
-	}
-}
-
 // GetNetwork - gets a network from database
 func GetNetwork(networkname string) (models.Network, error) {
 
@@ -561,7 +531,7 @@ func GetNetwork(networkname string) (models.Network, error) {
 	return network, nil
 }
 
-// Network.NetIDInNetworkCharSet - checks if a netid of a network uses valid characters
+// NetIDInNetworkCharSet - checks if a netid of a network uses valid characters
 func NetIDInNetworkCharSet(network *models.Network) bool {
 
 	charset := "abcdefghijklmnopqrstuvwxyz1234567890-_."
@@ -574,7 +544,7 @@ func NetIDInNetworkCharSet(network *models.Network) bool {
 	return true
 }
 
-// Network.Validate - validates fields of an network struct
+// Validate - validates fields of an network struct
 func ValidateNetwork(network *models.Network, isUpdate bool) error {
 	v := validator.New()
 	_ = v.RegisterValidation("netid_valid", func(fl validator.FieldLevel) bool {
@@ -637,7 +607,7 @@ func KeyUpdate(netname string) (models.Network, error) {
 	return models.Network{}, nil
 }
 
-//SaveNetwork - save network struct to database
+// SaveNetwork - save network struct to database
 func SaveNetwork(network *models.Network) error {
 	data, err := json.Marshal(network)
 	if err != nil {

+ 18 - 25
logic/nodes.go

@@ -270,21 +270,30 @@ func CreateNode(node *models.Node) error {
 
 	SetNodeDefaults(node)
 
-	if node.IsServer == "yes" {
-		if node.Address, err = UniqueAddressServer(node.Network); err != nil {
-			return err
+	defaultACLVal := acls.Allowed
+	parentNetwork, err := GetNetwork(node.Network)
+	if err == nil {
+		if parentNetwork.DefaultACL != "yes" {
+			defaultACLVal = acls.NotAllowed
 		}
-	} else if node.Address == "" {
-		if node.Address, err = UniqueAddress(node.Network); err != nil {
-			return err
+	}
+
+	reverse := node.IsServer == "yes"
+	if node.Address == "" {
+		if parentNetwork.IsIPv4 == "yes" {
+			if node.Address, err = UniqueAddress(node.Network, reverse); err != nil {
+				return err
+			}
 		}
 	} else if !IsIPUnique(node.Network, node.Address, database.NODES_TABLE_NAME, false) {
 		return fmt.Errorf("invalid address: ipv4 " + node.Address + " is not unique")
 	}
 
 	if node.Address6 == "" {
-		if node.Address6, err = UniqueAddress6(node.Network); err != nil {
-			return err
+		if parentNetwork.IsIPv6 == "yes" {
+			if node.Address6, err = UniqueAddress6(node.Network, reverse); err != nil {
+				return err
+			}
 		}
 	} else if !IsIPUnique(node.Network, node.Address6, database.NODES_TABLE_NAME, true) {
 		return fmt.Errorf("invalid address: ipv6 " + node.Address6 + " is not unique")
@@ -312,14 +321,6 @@ func CreateNode(node *models.Node) error {
 		return err
 	}
 
-	defaultACLVal := acls.Allowed
-	parentNetwork, err := GetNetwork(node.Network)
-	if err == nil {
-		if parentNetwork.DefaultACL != "yes" {
-			defaultACLVal = acls.NotAllowed
-		}
-	}
-
 	_, err = nodeacls.CreateNodeACL(nodeacls.NetworkID(node.Network), nodeacls.NodeID(node.ID), defaultACLVal)
 	if err != nil {
 		logger.Log(1, "failed to create node ACL for node,", node.ID, "err:", err.Error())
@@ -428,9 +429,7 @@ func SetNodeDefaults(node *models.Node) {
 		}
 	}
 	// == Parent Network settings ==
-	if node.IsDualStack == "" {
-		node.IsDualStack = parentNetwork.IsDualStack
-	}
+
 	if node.MTU == 0 {
 		node.MTU = parentNetwork.DefaultMTU
 	}
@@ -438,7 +437,6 @@ func SetNodeDefaults(node *models.Node) {
 	node.SetIPForwardingDefault()
 	node.SetDNSOnDefault()
 	node.SetIsLocalDefault()
-	node.SetIsDualStackDefault()
 	node.SetLastModified()
 	node.SetDefaultName()
 	node.SetLastCheckIn()
@@ -630,11 +628,6 @@ func IsLocalServer(node *models.Node) bool {
 	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
 func validateServer(currentNode, newNode *models.Node) bool {
 	return (newNode.Address == currentNode.Address &&

+ 64 - 41
logic/peers.go

@@ -13,6 +13,7 @@ import (
 	"github.com/gravitl/netmaker/logic/acls"
 	"github.com/gravitl/netmaker/logic/acls/nodeacls"
 	"github.com/gravitl/netmaker/models"
+	"github.com/seancfoley/ipaddress-go/ipaddr"
 	"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
 )
 
@@ -34,19 +35,19 @@ func GetHubPeer(networkName string) []models.Node {
 */
 
 // GetNodePeers - fetches peers for a given node
-func GetNodePeers(networkName, nodeid string, excludeRelayed bool, isP2S bool) ([]models.Node, error) {
+func GetNodePeers(network *models.Network, nodeid string, excludeRelayed bool, isP2S bool) ([]models.Node, error) {
 	var peers []models.Node
-	var networkNodes, egressNetworkNodes, err = getNetworkEgressAndNodes(networkName)
+	var networkNodes, egressNetworkNodes, err = getNetworkEgressAndNodes(network.NetID)
 	if err != nil {
 		return peers, nil
 	}
 
-	udppeers, errN := database.GetPeers(networkName)
+	udppeers, errN := database.GetPeers(network.NetID)
 	if errN != nil {
 		logger.Log(2, errN.Error())
 	}
 
-	currentNetworkACLs, aclErr := nodeacls.FetchAllACLs(nodeacls.NetworkID(networkName))
+	currentNetworkACLs, aclErr := nodeacls.FetchAllACLs(nodeacls.NetworkID(network.NetID))
 	if aclErr != nil {
 		return peers, aclErr
 	}
@@ -63,10 +64,9 @@ func GetNodePeers(networkName, nodeid string, excludeRelayed bool, isP2S bool) (
 		}
 
 		peer.IsIngressGateway = node.IsIngressGateway
-		isDualStack := node.IsDualStack == "yes"
 		allow := node.IsRelayed != "yes" || !excludeRelayed
 
-		if node.Network == networkName && node.IsPending != "yes" && allow {
+		if node.Network == network.NetID && node.IsPending != "yes" && allow {
 			peer = setPeerInfo(&node)
 			if node.UDPHolePunch == "yes" && errN == nil && CheckEndpoint(udppeers[node.PublicKey]) {
 				endpointstring := udppeers[node.PublicKey]
@@ -79,13 +79,12 @@ func GetNodePeers(networkName, nodeid string, excludeRelayed bool, isP2S bool) (
 					}
 				}
 			}
+			// if udp hole punching is on, but port is still set to default (e.g. 51821), use the LocalListenPort
+			if node.UDPHolePunch == "yes" && node.IsStatic != "yes" && peer.ListenPort == node.ListenPort {
+				peer.ListenPort = node.LocalListenPort
+			}
 			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...)
-				}
+				peer.AllowedIPs = append(peer.AllowedIPs, network.AddressRange)
 				for _, egressNode := range egressNetworkNodes {
 					if egressNode.IsRelayed == "yes" && StringSliceContains(node.RelayAddrs, egressNode.Address) {
 						peer.AllowedIPs = append(peer.AllowedIPs, egressNode.EgressGatewayRanges...)
@@ -95,8 +94,10 @@ func GetNodePeers(networkName, nodeid string, excludeRelayed bool, isP2S bool) (
 			if peer.IsIngressGateway == "yes" { // handle ingress stuff
 				if currentExtClients, err := GetExtPeersList(&node); err == nil {
 					for i := range currentExtClients {
-						peer.AllowedIPs = append(peer.AllowedIPs, currentExtClients[i].Address)
-						if isDualStack {
+						if network.IsIPv4 == "yes" && currentExtClients[i].Address != "" {
+							peer.AllowedIPs = append(peer.AllowedIPs, currentExtClients[i].Address)
+						}
+						if network.IsIPv6 == "yes" && currentExtClients[i].Address6 != "" {
 							peer.AllowedIPs = append(peer.AllowedIPs, currentExtClients[i].Address6)
 						}
 					}
@@ -131,7 +132,7 @@ func GetPeersList(refnode *models.Node) ([]models.Node, error) {
 		isP2S = true
 	}
 	if relayedNodeAddr == "" {
-		peers, err = GetNodePeers(networkName, refnode.ID, excludeRelayed, isP2S)
+		peers, err = GetNodePeers(&network, refnode.ID, excludeRelayed, isP2S)
 	} else {
 		var relayNode models.Node
 		relayNode, err = GetNodeRelay(networkName, relayedNodeAddr)
@@ -151,7 +152,7 @@ func GetPeersList(refnode *models.Node) ([]models.Node, error) {
 			} else {
 				peerNode.AllowedIPs = append(peerNode.AllowedIPs, peerNode.RelayAddrs...)
 			}
-			nodepeers, err := GetNodePeers(networkName, refnode.ID, false, isP2S)
+			nodepeers, err := GetNodePeers(&network, refnode.ID, false, isP2S)
 			if err == nil && peerNode.UDPHolePunch == "yes" {
 				for _, nodepeer := range nodepeers {
 					if nodepeer.Address == peerNode.Address {
@@ -205,6 +206,9 @@ func GetPeerUpdate(node *models.Node) (models.PeerUpdate, error) {
 			// set_local
 			if node.LocalAddress != peer.LocalAddress && peer.LocalAddress != "" {
 				peer.Endpoint = peer.LocalAddress
+				if peer.LocalListenPort != 0 {
+					peer.ListenPort = peer.LocalListenPort
+				}
 			} else {
 				continue
 			}
@@ -278,20 +282,26 @@ func getExtPeers(node *models.Node) ([]wgtypes.PeerConfig, error) {
 			continue
 		}
 
+		var allowedips []net.IPNet
 		var peer wgtypes.PeerConfig
-		var peeraddr = net.IPNet{
-			IP:   net.ParseIP(extPeer.Address),
-			Mask: net.CIDRMask(32, 32),
+		if extPeer.Address != "" {
+			var peeraddr = net.IPNet{
+				IP:   net.ParseIP(extPeer.Address),
+				Mask: net.CIDRMask(32, 32),
+			}
+			if peeraddr.IP != nil && peeraddr.Mask != nil {
+				allowedips = append(allowedips, peeraddr)
+			}
 		}
-		var allowedips []net.IPNet
-		allowedips = append(allowedips, peeraddr)
 
 		if extPeer.Address6 != "" {
 			var addr6 = net.IPNet{
 				IP:   net.ParseIP(extPeer.Address6),
 				Mask: net.CIDRMask(128, 128),
 			}
-			allowedips = append(allowedips, addr6)
+			if addr6.IP != nil && addr6.Mask != nil {
+				allowedips = append(allowedips, addr6)
+			}
 		}
 		peer = wgtypes.PeerConfig{
 			PublicKey:         pubkey,
@@ -307,23 +317,43 @@ func getExtPeers(node *models.Node) ([]wgtypes.PeerConfig, error) {
 // GetAllowedIPs - calculates the wireguard allowedip field for a peer of a node based on the peer and node settings
 func GetAllowedIPs(node, peer *models.Node) []net.IPNet {
 	var allowedips []net.IPNet
-	var peeraddr = net.IPNet{
-		IP:   net.ParseIP(peer.Address),
-		Mask: net.CIDRMask(32, 32),
+
+	if peer.Address != "" {
+		var peeraddr = net.IPNet{
+			IP:   net.ParseIP(peer.Address),
+			Mask: net.CIDRMask(32, 32),
+		}
+		allowedips = append(allowedips, peeraddr)
 	}
-	dualstack := false
-	allowedips = append(allowedips, peeraddr)
+
+	if peer.Address6 != "" {
+		var addr6 = net.IPNet{
+			IP:   net.ParseIP(peer.Address6),
+			Mask: net.CIDRMask(128, 128),
+		}
+		allowedips = append(allowedips, addr6)
+	}
+
 	// handle manually set peers
 	for _, allowedIp := range peer.AllowedIPs {
-		if _, ipnet, err := net.ParseCIDR(allowedIp); err == nil {
-			nodeEndpointArr := strings.Split(node.Endpoint, ":")
-			if !ipnet.Contains(net.IP(nodeEndpointArr[0])) && ipnet.IP.String() != peer.Address { // don't need to add an allowed ip that already exists..
-				allowedips = append(allowedips, *ipnet)
+		currentAddr := ipaddr.NewIPAddressString(allowedIp).GetAddress()
+		if currentAddr.IsIPv4() {
+			if _, ipnet, err := net.ParseCIDR(allowedIp); err == nil {
+				nodeEndpointArr := strings.Split(node.Endpoint, ":")
+				if !ipnet.Contains(net.IP(nodeEndpointArr[0])) && ipnet.IP.String() != peer.Address { // don't need to add an allowed ip that already exists..
+					allowedips = append(allowedips, *ipnet)
+				}
+			} else if appendip := net.ParseIP(allowedIp); appendip != nil && allowedIp != peer.Address {
+				ipnet := net.IPNet{
+					IP:   net.ParseIP(allowedIp),
+					Mask: net.CIDRMask(32, 32),
+				}
+				allowedips = append(allowedips, ipnet)
 			}
-		} else if appendip := net.ParseIP(allowedIp); appendip != nil && allowedIp != peer.Address {
+		} else if currentAddr.IsIPv6() {
 			ipnet := net.IPNet{
 				IP:   net.ParseIP(allowedIp),
-				Mask: net.CIDRMask(32, 32),
+				Mask: net.CIDRMask(128, 128),
 			}
 			allowedips = append(allowedips, ipnet)
 		}
@@ -349,18 +379,11 @@ func GetAllowedIPs(node, peer *models.Node) []net.IPNet {
 				continue // skip adding egress range if overlaps with node's local ip
 			}
 			if err != nil {
-				log.Println("ERROR ENCOUNTERED SETTING GATEWAY")
+				logger.Log(1, "error encountered when setting egress range", err.Error())
 			} else {
 				allowedips = append(allowedips, *ipnet)
 			}
 		}
 	}
-	if peer.Address6 != "" && dualstack {
-		var addr6 = net.IPNet{
-			IP:   net.ParseIP(peer.Address6),
-			Mask: net.CIDRMask(128, 128),
-		}
-		allowedips = append(allowedips, addr6)
-	}
 	return allowedips
 }

+ 52 - 30
logic/server.go

@@ -16,6 +16,7 @@ import (
 	"github.com/gravitl/netmaker/models"
 	"github.com/gravitl/netmaker/netclient/ncutils"
 	"github.com/gravitl/netmaker/servercfg"
+	"github.com/seancfoley/ipaddress-go/ipaddr"
 	"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
 )
 
@@ -43,7 +44,7 @@ func ServerJoin(networkSettings *models.Network) (models.Node, error) {
 	}
 	var ishub = "no"
 
-	if networkSettings.IsPointToSite == "yes" || networkSettings.IsComms == "yes" {
+	if networkSettings.IsPointToSite == "yes" {
 		nodes, err := GetNetworkNodes(networkSettings.NetID)
 		if err != nil || nodes == nil {
 			ishub = "yes"
@@ -237,24 +238,47 @@ func GetServerPeers(serverNode *models.Node) ([]wgtypes.PeerConfig, bool, []stri
 		}
 
 		var peer wgtypes.PeerConfig
-		var peeraddr = net.IPNet{
-			IP:   net.ParseIP(node.Address),
-			Mask: net.CIDRMask(32, 32),
+		var allowedips = []net.IPNet{}
+		if node.Address != "" {
+			var peeraddr = net.IPNet{
+				IP:   net.ParseIP(node.Address),
+				Mask: net.CIDRMask(32, 32),
+			}
+			if peeraddr.IP != nil && peeraddr.Mask != nil {
+				allowedips = append(allowedips, peeraddr)
+			}
 		}
-		var allowedips = []net.IPNet{
-			peeraddr,
+
+		if node.Address6 != "" {
+			var addr6 = net.IPNet{
+				IP:   net.ParseIP(node.Address6),
+				Mask: net.CIDRMask(128, 128),
+			}
+			if addr6.IP != nil && addr6.Mask != nil {
+				allowedips = append(allowedips, addr6)
+			}
 		}
+
 		// handle manually set peers
 		for _, allowedIp := range node.AllowedIPs {
-			if _, ipnet, err := net.ParseCIDR(allowedIp); err == nil {
-				nodeEndpointArr := strings.Split(node.Endpoint, ":")
-				if !ipnet.Contains(net.IP(nodeEndpointArr[0])) && ipnet.IP.String() != node.Address { // don't need to add an allowed ip that already exists..
-					allowedips = append(allowedips, *ipnet)
+			currentIP := ipaddr.NewIPAddressString(allowedIp).GetAddress()
+			if currentIP.IsIPv4() {
+				if _, ipnet, err := net.ParseCIDR(allowedIp); err == nil {
+					nodeEndpointArr := strings.Split(node.Endpoint, ":")
+					if !ipnet.Contains(net.IP(nodeEndpointArr[0])) && ipnet.IP.String() != node.Address { // don't need to add an allowed ip that already exists..
+						allowedips = append(allowedips, *ipnet)
+					}
+				} else if appendip := net.ParseIP(allowedIp); appendip != nil && allowedIp != node.Address {
+					ipnet := net.IPNet{
+						IP:   net.ParseIP(allowedIp),
+						Mask: net.CIDRMask(32, 32),
+					}
+					allowedips = append(allowedips, ipnet)
 				}
-			} else if appendip := net.ParseIP(allowedIp); appendip != nil && allowedIp != node.Address {
+			} else if currentIP.IsIPv6() {
 				ipnet := net.IPNet{
-					IP:   net.ParseIP(allowedIp),
-					Mask: net.CIDRMask(32, 32),
+					IP:   currentIP.GetNetIP(),
+					Mask: net.CIDRMask(128, 128),
 				}
 				allowedips = append(allowedips, ipnet)
 			}
@@ -285,15 +309,8 @@ func GetServerPeers(serverNode *models.Node) ([]wgtypes.PeerConfig, bool, []stri
 					allowedips = append(allowedips, *ipnet)
 				}
 			}
-			ranges = nil
-		}
-		if node.Address6 != "" && serverNode.IsDualStack == "yes" {
-			var addr6 = net.IPNet{
-				IP:   net.ParseIP(node.Address6),
-				Mask: net.CIDRMask(128, 128),
-			}
-			allowedips = append(allowedips, addr6)
 		}
+
 		peer = wgtypes.PeerConfig{
 			PublicKey:                   pubkey,
 			PersistentKeepaliveInterval: &(keepalivedur),
@@ -347,22 +364,27 @@ func GetServerExtPeers(serverNode *models.Node) ([]wgtypes.PeerConfig, error) {
 		if serverNode.PublicKey == extPeer.PublicKey {
 			continue
 		}
+		var allowedips = []net.IPNet{}
 
 		var peer wgtypes.PeerConfig
-		var peeraddr = net.IPNet{
-			IP:   net.ParseIP(extPeer.Address),
-			Mask: net.CIDRMask(32, 32),
-		}
-		var allowedips = []net.IPNet{
-			peeraddr,
+		if extPeer.Address != "" {
+			newAddr := net.IPNet{
+				IP:   net.ParseIP(extPeer.Address),
+				Mask: net.CIDRMask(32, 32),
+			}
+			if &newAddr != nil {
+				allowedips = append(allowedips, newAddr)
+			}
 		}
 
-		if extPeer.Address6 != "" && serverNode.IsDualStack == "yes" {
-			var addr6 = net.IPNet{
+		if extPeer.Address6 != "" {
+			newAddr6 := net.IPNet{
 				IP:   net.ParseIP(extPeer.Address6),
 				Mask: net.CIDRMask(128, 128),
 			}
-			allowedips = append(allowedips, addr6)
+			if &newAddr6 != nil {
+				allowedips = append(allowedips, newAddr6)
+			}
 		}
 		peer = wgtypes.PeerConfig{
 			PublicKey:         pubkey,

+ 0 - 29
logic/serverconf.go

@@ -72,32 +72,3 @@ func StoreJWTSecret(privateKey string) error {
 	}
 	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 - 0
logic/util.go

@@ -154,6 +154,7 @@ func setPeerInfo(node *models.Node) models.Node {
 	peer.Name = node.Name
 	peer.Network = node.Network
 	peer.LocalAddress = node.LocalAddress
+	peer.LocalListenPort = node.LocalListenPort
 	peer.ListenPort = node.ListenPort
 	peer.AllowedIPs = node.AllowedIPs
 	peer.UDPHolePunch = node.UDPHolePunch

+ 31 - 15
logic/wireguard.go

@@ -50,9 +50,9 @@ func HasPeerConnected(node *models.Node) bool {
 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.Address6 != currentNode.Address6 ||
 		newNode.IsEgressGateway != currentNode.IsEgressGateway ||
 		newNode.IsIngressGateway != currentNode.IsIngressGateway ||
 		newNode.IsRelay != currentNode.IsRelay ||
@@ -67,12 +67,6 @@ func IfaceDelta(currentNode *models.Node, newNode *models.Node) bool {
 	}
 
 	// 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
@@ -156,9 +150,22 @@ func initWireguard(node *models.Node, privkey string, peers []wgtypes.PeerConfig
 			logger.Log(0, "failed to get network"+err.Error())
 			return err
 		}
-		net := strings.Split(network.AddressRange, "/")
-		mask := net[len(net)-1]
-		setKernelDevice(ifacename, node.Address, mask)
+		var address4 string
+		var address6 string
+		var mask4 string
+		var mask6 string
+		if network.AddressRange != "" {
+			net := strings.Split(network.AddressRange, "/")
+			mask4 = net[len(net)-1]
+			address4 = node.Address
+		}
+		if network.AddressRange6 != "" {
+			net := strings.Split(network.AddressRange6, "/")
+			mask6 = net[len(net)-1]
+			address6 = node.Address
+		}
+
+		setKernelDevice(ifacename, address4, mask4, address6, mask6)
 	}
 
 	nodeport := int(node.ListenPort)
@@ -239,9 +246,13 @@ func initWireguard(node *models.Node, privkey string, peers []wgtypes.PeerConfig
 				_, _ = ncutils.RunCmd(ipExec+" -4 route add "+gateway+" dev "+ifacename, 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)
+		if node.Address != "" {
+			logger.Log(1, "adding address:", node.Address)
+			_, _ = ncutils.RunCmd(ipExec+" address add dev "+ifacename+" "+node.Address+"/32", true)
+		}
+		if node.Address6 != "" {
+			logger.Log(1, "adding address6:", node.Address6)
+			_, _ = ncutils.RunCmd(ipExec+" address add dev "+ifacename+" "+node.Address6+"/128", true)
 		}
 		wireguard.SetPeers(ifacename, node, peers)
 	}
@@ -249,7 +260,7 @@ func initWireguard(node *models.Node, privkey string, peers []wgtypes.PeerConfig
 	return err
 }
 
-func setKernelDevice(ifacename, address, mask string) error {
+func setKernelDevice(ifacename, address4, mask4, address6, mask6 string) error {
 	ipExec, err := exec.LookPath("ip")
 	if err != nil {
 		return err
@@ -258,7 +269,12 @@ func setKernelDevice(ifacename, address, mask string) error {
 	// == 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
+	if address4 != "" {
+		ncutils.RunCmd(ipExec+" address add dev "+ifacename+" "+address4+"/"+mask4, true)
+	}
+	if address6 != "" {
+		ncutils.RunCmd(ipExec+" address add dev "+ifacename+" "+address6+"/"+mask6, true)
+	}
 
 	return nil
 }

+ 83 - 70
main.go

@@ -2,22 +2,24 @@ package main
 
 import (
 	"context"
+	"crypto/ed25519"
+	"crypto/rand"
+	"errors"
 	"flag"
 	"fmt"
-	"net"
 	"os"
 	"os/signal"
 	"runtime/debug"
 	"strconv"
 	"sync"
 	"syscall"
+	"time"
 
 	"github.com/gravitl/netmaker/auth"
 	"github.com/gravitl/netmaker/config"
 	controller "github.com/gravitl/netmaker/controllers"
 	"github.com/gravitl/netmaker/database"
 	"github.com/gravitl/netmaker/functions"
-	nodepb "github.com/gravitl/netmaker/grpc"
 	"github.com/gravitl/netmaker/logger"
 	"github.com/gravitl/netmaker/logic"
 	"github.com/gravitl/netmaker/models"
@@ -25,7 +27,7 @@ import (
 	"github.com/gravitl/netmaker/netclient/ncutils"
 	"github.com/gravitl/netmaker/servercfg"
 	"github.com/gravitl/netmaker/serverctl"
-	"google.golang.org/grpc"
+	"github.com/gravitl/netmaker/tls"
 )
 
 var version = "dev"
@@ -38,10 +40,10 @@ func main() {
 	setupConfig(*absoluteConfigPath)
 	servercfg.SetVersion(version)
 	fmt.Println(models.RetrieveLogo()) // print the logo
-	initialize()                       // initial db and grpc server
+	initialize()                       // initial db and acls; gen cert if required
 	setGarbageCollection()
 	defer database.CloseDB()
-	startControllers() // start the grpc or rest endpoints
+	startControllers() // start the api endpoint and mq
 }
 
 func setupConfig(absoluteConfigPath string) {
@@ -103,9 +105,6 @@ func initialize() { // Client Mode Prereq Check
 		if err := serverctl.InitServerNetclient(); err != nil {
 			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
 	if servercfg.ManageIPTables() != "off" {
@@ -120,22 +119,18 @@ func initialize() { // Client Mode Prereq Check
 			logger.FatalLog(err.Error())
 		}
 	}
-}
 
-func startControllers() {
-	var waitnetwork sync.WaitGroup
-	//Run Agent Server
-	if servercfg.IsAgentBackend() {
-		if !(servercfg.DisableRemoteIPCheck()) && servercfg.GetGRPCHost() == "127.0.0.1" {
-			err := servercfg.SetHost()
-			if err != nil {
-				logger.FatalLog("Unable to Set host. Exiting...", err.Error())
-			}
+	genCerts()
+
+	if servercfg.IsMessageQueueBackend() {
+		if err = mq.ServerStartNotify(); err != nil {
+			logger.Log(0, "error occurred when notifying nodes of startup", err.Error())
 		}
-		waitnetwork.Add(1)
-		go runGRPC(&waitnetwork)
 	}
+}
 
+func startControllers() {
+	var waitnetwork sync.WaitGroup
 	if servercfg.IsDNSMode() {
 		err := logic.SetDNS()
 		if err != nil {
@@ -167,52 +162,6 @@ func startControllers() {
 	waitnetwork.Wait()
 }
 
-func runGRPC(wg *sync.WaitGroup) {
-
-	defer wg.Done()
-
-	grpcport := servercfg.GetGRPCPort()
-
-	listener, err := net.Listen("tcp", ":"+grpcport)
-	// Handle errors if any
-	if err != nil {
-		logger.FatalLog("[netmaker] Unable to listen on port", grpcport, ": error:", err.Error())
-	}
-
-	s := grpc.NewServer(
-		authServerUnaryInterceptor(),
-	)
-	// Create NodeService type
-	srv := &controller.NodeServiceServer{}
-
-	// Register the service with the server
-	nodepb.RegisterNodeServiceServer(s, srv)
-
-	// Start the server in a child routine
-	go func() {
-		if err := s.Serve(listener); err != nil {
-			logger.FatalLog("Failed to serve:", err.Error())
-		}
-	}()
-	logger.Log(0, "Agent Server successfully started on port ", grpcport, "(gRPC)")
-
-	// Relay os.Interrupt to our channel (os.Interrupt = CTRL+C)
-	// Ignore other incoming signals
-	ctx, stop := signal.NotifyContext(context.TODO(), os.Interrupt)
-	defer stop()
-
-	// Block main routine until a signal is received
-	// As long as user doesn't press CTRL+C a message is not passed and our main routine keeps running
-	<-ctx.Done()
-
-	// After receiving CTRL+C Properly stop the server
-	logger.Log(0, "Stopping the Agent server...")
-	s.GracefulStop()
-	listener.Close()
-	logger.Log(0, "Agent server closed..")
-	logger.Log(0, "Closed DB connection.")
-}
-
 // Should we be using a context vice a waitgroup????????????
 func runMessageQueue(wg *sync.WaitGroup) {
 	defer wg.Done()
@@ -228,13 +177,77 @@ func runMessageQueue(wg *sync.WaitGroup) {
 	client.Disconnect(250)
 }
 
-func authServerUnaryInterceptor() grpc.ServerOption {
-	return grpc.UnaryInterceptor(controller.AuthServerUnaryInterceptor)
-}
-
 func setGarbageCollection() {
 	_, gcset := os.LookupEnv("GOGC")
 	if !gcset {
 		debug.SetGCPercent(ncutils.DEFAULT_GC_PERCENT)
 	}
 }
+
+func genCerts() error {
+	logger.Log(0, "checking keys and certificates")
+	var private *ed25519.PrivateKey
+	var err error
+	private, err = tls.ReadKey(functions.GetNetmakerPath() + "/root.key")
+	if errors.Is(err, os.ErrNotExist) {
+		logger.Log(0, "generating new root key")
+		_, newKey, err := ed25519.GenerateKey(rand.Reader)
+		if err != nil {
+			return err
+		}
+		if err := tls.SaveKey(functions.GetNetmakerPath(), "/root.key", newKey); err != nil {
+			return err
+		}
+		private = &newKey
+	} else if err != nil {
+		return err
+	}
+	ca, err := tls.ReadCert(functions.GetNetmakerPath() + ncutils.GetSeparator() + "root.pem")
+	//if cert doesn't exist or will expire within 10 days --- but can't do this as clients won't be able to connect
+	//if errors.Is(err, os.ErrNotExist) || cert.NotAfter.Before(time.Now().Add(time.Hour*24*10)) {
+	if errors.Is(err, os.ErrNotExist) {
+		logger.Log(0, "generating new root CA")
+		caName := tls.NewName("CA Root", "US", "Gravitl")
+		csr, err := tls.NewCSR(*private, caName)
+		if err != nil {
+			return err
+		}
+		rootCA, err := tls.SelfSignedCA(*private, csr, tls.CERTIFICATE_VALIDITY)
+		if err != nil {
+			return err
+		}
+		if err := tls.SaveCert(functions.GetNetmakerPath(), ncutils.GetSeparator()+"root.pem", rootCA); err != nil {
+			return err
+		}
+		ca = rootCA
+	} else if err != nil {
+		return err
+	}
+	cert, err := tls.ReadCert(functions.GetNetmakerPath() + "/server.pem")
+	if errors.Is(err, os.ErrNotExist) || cert.NotAfter.Before(time.Now().Add(time.Hour*24*10)) {
+		//gen new key
+		logger.Log(0, "generating new server key/certificate")
+		_, key, err := ed25519.GenerateKey(rand.Reader)
+		if err != nil {
+			return err
+		}
+		serverName := tls.NewCName(servercfg.GetServer())
+		csr, err := tls.NewCSR(key, serverName)
+		if err != nil {
+			return err
+		}
+		cert, err := tls.NewEndEntityCert(*private, csr, ca, tls.CERTIFICATE_VALIDITY)
+		if err != nil {
+			return err
+		}
+		if err := tls.SaveKey(functions.GetNetmakerPath(), "/server.key", key); err != nil {
+			return err
+		}
+		if err := tls.SaveCert(functions.GetNetmakerPath(), "/server.pem", cert); err != nil {
+			return err
+		}
+	} else if err != nil {
+		return err
+	}
+	return nil
+}

+ 2 - 3
models/accessToken.go

@@ -12,7 +12,6 @@ type ClientConfig struct {
 }
 
 type ServerConfig struct {
-	GRPCConnString string `json:"grpcconn"`
-	GRPCSSL        string `json:"grpcssl"`
-	CommsNetwork   string `json:"commsnetwork"`
+	Server        string `json:"server"`
+	APIConnString string `json:"apiconnstring"`
 }

+ 5 - 3
models/dnsEntry.go

@@ -1,8 +1,10 @@
 //TODO:  Either add a returnNetwork and returnKey, or delete this
 package models
 
+// DNSEntry - a DNS entry represented as struct
 type DNSEntry struct {
-	Address string `json:"address" bson:"address" validate:"required,ip"`
-	Name    string `json:"name" bson:"name" validate:"required,name_unique,min=1,max=192"`
-	Network string `json:"network" bson:"network" validate:"network_exists"`
+	Address  string `json:"address" bson:"address" validate:"ip"`
+	Address6 string `json:"address6" bson:"address6"`
+	Name     string `json:"name" bson:"name" validate:"required,name_unique,min=1,max=192"`
+	Network  string `json:"network" bson:"network" validate:"network_exists"`
 }

+ 0 - 1
models/intclient.go

@@ -12,7 +12,6 @@ type IntClient struct {
 	ServerAPIPort        string `json:"serverapiport" bson:"serverapiport"`
 	ServerPrivateAddress string `json:"serverprivateaddress" bson:"serverprivateaddress"`
 	ServerWGPort         string `json:"serverwgport" bson:"serverwgport"`
-	ServerGRPCPort       string `json:"servergrpcport" bson:"servergrpcport"`
 	ServerKey            string `json:"serverkey" bson:"serverkey"`
 	IsServer             string `json:"isserver" bson:"isserver"`
 }

+ 8 - 17
models/network.go

@@ -7,8 +7,8 @@ import (
 // Network Struct - contains info for a given unique network
 //At  some point, need to replace all instances of Name with something else like  Identifier
 type Network struct {
-	AddressRange        string      `json:"addressrange" bson:"addressrange" validate:"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]))?$"`
+	AddressRange        string      `json:"addressrange" bson:"addressrange" validate:"omitempty,cidr"`
+	AddressRange6       string      `json:"addressrange6" bson:"addressrange6"`
 	NetID               string      `json:"netid" bson:"netid" validate:"required,min=1,max=12,netid_valid"`
 	NodesLastModified   int64       `json:"nodeslastmodified" bson:"nodeslastmodified"`
 	NetworkLastModified int64       `json:"networklastmodified" bson:"networklastmodified"`
@@ -21,18 +21,14 @@ type Network struct {
 	AccessKeys          []AccessKey `json:"accesskeys" bson:"accesskeys"`
 	AllowManualSignUp   string      `json:"allowmanualsignup" bson:"allowmanualsignup" validate:"checkyesorno"`
 	IsLocal             string      `json:"islocal" bson:"islocal" validate:"checkyesorno"`
-	IsDualStack         string      `json:"isdualstack" bson:"isdualstack" validate:"checkyesorno"`
 	IsIPv4              string      `json:"isipv4" bson:"isipv4" validate:"checkyesorno"`
 	IsIPv6              string      `json:"isipv6" bson:"isipv6" 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"`
 	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"`
-	DefaultACL         string       `json:"defaultacl" bson:"defaultacl" yaml:"defaultacl" validate:"checkyesorno"`
+	DefaultACL          string      `json:"defaultacl" bson:"defaultacl" yaml:"defaultacl" validate:"checkyesorno"`
 }
 
 // SaveData - sensitive fields of a network that should be kept the same
@@ -61,9 +57,6 @@ func (network *Network) SetDefaults() {
 	if network.IsPointToSite == "" {
 		network.IsPointToSite = "no"
 	}
-	if network.IsComms == "" {
-		network.IsComms = "no"
-	}
 	if network.DefaultInterface == "" {
 		if len(network.NetID) < 13 {
 			network.DefaultInterface = "nm-" + network.NetID
@@ -83,15 +76,13 @@ func (network *Network) SetDefaults() {
 	if network.AllowManualSignUp == "" {
 		network.AllowManualSignUp = "no"
 	}
-	if network.IsDualStack == "" {
-		network.IsDualStack = "no"
-	}
-	if network.IsDualStack == "yes" {
-		network.IsIPv6 = "yes"
+
+	if network.IsIPv4 == "" {
 		network.IsIPv4 = "yes"
-	} else {
+	}
+
+	if network.IsIPv6 == "" {
 		network.IsIPv6 = "no"
-		network.IsIPv4 = "yes"
 	}
 
 	if network.DefaultMTU == 0 {

+ 64 - 62
models/node.go

@@ -17,7 +17,7 @@ const (
 	TEN_YEARS_IN_SECONDS = 300000000
 	// MAX_NAME_LENGTH - max name length of node
 	MAX_NAME_LENGTH = 62
-	// == ACTIONS == (can only be set by GRPC)
+	// == ACTIONS == (can only be set by server)
 	// NODE_UPDATE_KEY - action to update key
 	NODE_UPDATE_KEY = "updatekey"
 	// NODE_DELETE - delete node action
@@ -26,6 +26,8 @@ const (
 	NODE_IS_PENDING = "pending"
 	// NODE_NOOP - node no op action
 	NODE_NOOP = "noop"
+	// NODE_FORCE_UPDATE - indicates a node should pull all changes
+	NODE_FORCE_UPDATE = "force"
 )
 
 var seededRand *rand.Rand = rand.New(
@@ -33,54 +35,53 @@ var seededRand *rand.Rand = rand.New(
 
 // Node - struct for node model
 type Node struct {
-	ID                  string   `json:"id,omitempty" bson:"id,omitempty" yaml:"id,omitempty" validate:"required,min=5"`
-	Address             string   `json:"address" bson:"address" yaml:"address" validate:"omitempty,ipv4"`
-	Address6            string   `json:"address6" bson:"address6" yaml:"address6" validate:"omitempty,ipv6"`
-	LocalAddress        string   `json:"localaddress" bson:"localaddress" yaml:"localaddress" validate:"omitempty,ip"`
-	Name                string   `json:"name" bson:"name" yaml:"name" validate:"omitempty,max=62,in_charset"`
-	NetworkSettings     Network  `json:"networksettings" bson:"networksettings" yaml:"networksettings" validate:"-"`
-	ListenPort          int32    `json:"listenport" bson:"listenport" yaml:"listenport" validate:"omitempty,numeric,min=1024,max=65535"`
-	PublicKey           string   `json:"publickey" bson:"publickey" yaml:"publickey" validate:"required,base64"`
-	Endpoint            string   `json:"endpoint" bson:"endpoint" yaml:"endpoint" validate:"required,ip"`
-	PostUp              string   `json:"postup" bson:"postup" yaml:"postup"`
-	PostDown            string   `json:"postdown" bson:"postdown" yaml:"postdown"`
-	AllowedIPs          []string `json:"allowedips" bson:"allowedips" yaml:"allowedips"`
-	PersistentKeepalive int32    `json:"persistentkeepalive" bson:"persistentkeepalive" yaml:"persistentkeepalive" validate:"omitempty,numeric,max=1000"`
-	IsHub               string   `json:"ishub" bson:"ishub" yaml:"ishub" validate:"checkyesorno"`
-	AccessKey           string   `json:"accesskey" bson:"accesskey" yaml:"accesskey"`
-	Interface           string   `json:"interface" bson:"interface" yaml:"interface"`
-	LastModified        int64    `json:"lastmodified" bson:"lastmodified" yaml:"lastmodified"`
-	ExpirationDateTime  int64    `json:"expdatetime" bson:"expdatetime" yaml:"expdatetime"`
-	LastPeerUpdate      int64    `json:"lastpeerupdate" bson:"lastpeerupdate" yaml:"lastpeerupdate"`
-	LastCheckIn         int64    `json:"lastcheckin" bson:"lastcheckin" yaml:"lastcheckin"`
-	MacAddress          string   `json:"macaddress" bson:"macaddress" yaml:"macaddress" validate:"macaddress_unique"`
-	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"`
+	ID                  string      `json:"id,omitempty" bson:"id,omitempty" yaml:"id,omitempty" validate:"required,min=5"`
+	Address             string      `json:"address" bson:"address" yaml:"address" validate:"omitempty,ipv4"`
+	Address6            string      `json:"address6" bson:"address6" yaml:"address6" validate:"omitempty,ipv6"`
+	LocalAddress        string      `json:"localaddress" bson:"localaddress" yaml:"localaddress" validate:"omitempty,ip"`
+	Name                string      `json:"name" bson:"name" yaml:"name" validate:"omitempty,max=62,in_charset"`
+	NetworkSettings     Network     `json:"networksettings" bson:"networksettings" yaml:"networksettings" validate:"-"`
+	ListenPort          int32       `json:"listenport" bson:"listenport" yaml:"listenport" validate:"omitempty,numeric,min=1024,max=65535"`
+	LocalListenPort     int32       `json:"locallistenport" bson:"locallistenport" yaml:"locallistenport" validate:"numeric,min=0,max=65535"`
+	PublicKey           string      `json:"publickey" bson:"publickey" yaml:"publickey" validate:"required,base64"`
+	Endpoint            string      `json:"endpoint" bson:"endpoint" yaml:"endpoint" validate:"required,ip"`
+	PostUp              string      `json:"postup" bson:"postup" yaml:"postup"`
+	PostDown            string      `json:"postdown" bson:"postdown" yaml:"postdown"`
+	AllowedIPs          []string    `json:"allowedips" bson:"allowedips" yaml:"allowedips"`
+	PersistentKeepalive int32       `json:"persistentkeepalive" bson:"persistentkeepalive" yaml:"persistentkeepalive" validate:"omitempty,numeric,max=1000"`
+	IsHub               string      `json:"ishub" bson:"ishub" yaml:"ishub" validate:"checkyesorno"`
+	AccessKey           string      `json:"accesskey" bson:"accesskey" yaml:"accesskey"`
+	Interface           string      `json:"interface" bson:"interface" yaml:"interface"`
+	LastModified        int64       `json:"lastmodified" bson:"lastmodified" yaml:"lastmodified"`
+	ExpirationDateTime  int64       `json:"expdatetime" bson:"expdatetime" yaml:"expdatetime"`
+	LastPeerUpdate      int64       `json:"lastpeerupdate" bson:"lastpeerupdate" yaml:"lastpeerupdate"`
+	LastCheckIn         int64       `json:"lastcheckin" bson:"lastcheckin" yaml:"lastcheckin"`
+	MacAddress          string      `json:"macaddress" bson:"macaddress" yaml:"macaddress" validate:"macaddress_unique"`
+	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"`
+	DNSOn               string      `json:"dnson" bson:"dnson" yaml:"dnson" 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"`
+	Server              string      `json:"server" bson:"server" yaml:"server"`
+	TrafficKeys         TrafficKeys `json:"traffickeys" bson:"traffickeys" yaml:"traffickeys"`
 }
 
 // NodesArray - used for node sorting
@@ -101,6 +102,14 @@ func isLess(ipA string, ipB string) bool {
 	return bytes.Compare(ipNetA, ipNetB) < 0
 }
 
+// Node.PrimaryAddress - return ipv4 address if present, else return ipv6
+func (node *Node) PrimaryAddress() string {
+	if node.Address != "" {
+		return node.Address
+	}
+	return node.Address6
+}
+
 // Node.SetDefaultMTU - sets default MTU of a node
 func (node *Node) SetDefaultMTU() {
 	if node.MTU == 0 {
@@ -199,13 +208,6 @@ func (node *Node) SetDNSOnDefault() {
 	}
 }
 
-// Node.SetIsDualStackDefault - set is dual stack default status
-func (node *Node) SetIsDualStackDefault() {
-	if node.IsDualStack == "" {
-		node.IsDualStack = "no"
-	}
-}
-
 // Node.SetIsServerDefault - sets node isserver default
 func (node *Node) SetIsServerDefault() {
 	if node.IsServer != "yes" {
@@ -268,6 +270,9 @@ func (newNode *Node) Fill(currentNode *Node) {
 	if newNode.ListenPort == 0 && newNode.IsStatic != "yes" {
 		newNode.ListenPort = currentNode.ListenPort
 	}
+	if newNode.LocalListenPort == 0 && newNode.IsStatic != "yes" {
+		newNode.LocalListenPort = currentNode.LocalListenPort
+	}
 	if newNode.PublicKey == "" && newNode.IsStatic != "yes" {
 		newNode.PublicKey = currentNode.PublicKey
 	}
@@ -345,18 +350,12 @@ func (newNode *Node) Fill(currentNode *Node) {
 	if newNode.DNSOn == "" {
 		newNode.DNSOn = currentNode.DNSOn
 	}
-	if newNode.IsDualStack == "" {
-		newNode.IsDualStack = currentNode.IsDualStack
-	}
 	if newNode.IsLocal == "" {
 		newNode.IsLocal = currentNode.IsLocal
 	}
 	if newNode.IPForwarding == "" {
 		newNode.IPForwarding = currentNode.IPForwarding
 	}
-	//if newNode.Roaming == "" {
-	//newNode.Roaming = currentNode.Roaming
-	//}
 	if newNode.Action == "" {
 		newNode.Action = currentNode.Action
 	}
@@ -393,6 +392,9 @@ func (newNode *Node) Fill(currentNode *Node) {
 	if newNode.IsHub == "" {
 		newNode.IsHub = currentNode.IsHub
 	}
+	if newNode.Server == "" {
+		newNode.Server = currentNode.Server
+	}
 }
 
 // StringWithCharset - returns random string inside defined charset

+ 17 - 10
models/structs.go

@@ -2,6 +2,7 @@ package models
 
 import (
 	jwt "github.com/golang-jwt/jwt/v4"
+	"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
 )
 
 const PLACEHOLDER_KEY_TEXT = "ACCESS_KEY"
@@ -101,9 +102,7 @@ type DisplayKey struct {
 
 // GlobalConfig - global config
 type GlobalConfig struct {
-	Name       string `json:"name" bson:"name"`
-	PortGRPC   string `json:"portgrpc" bson:"portgrpc"`
-	ServerGRPC string `json:"servergrpc" bson:"servergrpc"`
+	Name string `json:"name" bson:"name"`
 }
 
 // CheckInResponse - checkin response
@@ -124,6 +123,7 @@ type PeersResponse struct {
 	Address             string `json:"address" bson:"address"`
 	Address6            string `json:"address6" bson:"address6"`
 	LocalAddress        string `json:"localaddress" bson:"localaddress"`
+	LocalListenPort     int32  `json:"locallistenport" bson:"locallistenport"`
 	IsEgressGateway     string `json:"isegressgateway" bson:"isegressgateway"`
 	EgressGatewayRanges string `json:"egressgatewayrange" bson:"egressgatewayrange"`
 	ListenPort          int32  `json:"listenport" bson:"listenport"`
@@ -132,13 +132,14 @@ type PeersResponse struct {
 
 // ExtPeersResponse - ext peers response
 type ExtPeersResponse struct {
-	PublicKey    string `json:"publickey" bson:"publickey"`
-	Endpoint     string `json:"endpoint" bson:"endpoint"`
-	Address      string `json:"address" bson:"address"`
-	Address6     string `json:"address6" bson:"address6"`
-	LocalAddress string `json:"localaddress" bson:"localaddress"`
-	ListenPort   int32  `json:"listenport" bson:"listenport"`
-	KeepAlive    int32  `json:"persistentkeepalive" bson:"persistentkeepalive"`
+	PublicKey       string `json:"publickey" bson:"publickey"`
+	Endpoint        string `json:"endpoint" bson:"endpoint"`
+	Address         string `json:"address" bson:"address"`
+	Address6        string `json:"address6" bson:"address6"`
+	LocalAddress    string `json:"localaddress" bson:"localaddress"`
+	LocalListenPort int32  `json:"locallistenport" bson:"locallistenport"`
+	ListenPort      int32  `json:"listenport" bson:"listenport"`
+	KeepAlive       int32  `json:"persistentkeepalive" bson:"persistentkeepalive"`
 }
 
 // EgressGatewayRequest - egress gateway request
@@ -186,3 +187,9 @@ type TrafficKeys struct {
 	Mine   []byte `json:"mine" bson:"mine" yaml:"mine"`
 	Server []byte `json:"server" bson:"server" yaml:"server"`
 }
+
+// NodeGet - struct for a single node get response
+type NodeGet struct {
+	Node  Node                 `json:"node" bson:"node" yaml:"node"`
+	Peers []wgtypes.PeerConfig `json:"peers" bson:"peers" yaml:"peers"`
+}

+ 1 - 1
mq/handlers.go

@@ -48,7 +48,7 @@ func Ping(client mqtt.Client, msg mqtt.Message) {
 			return
 		}
 
-		logger.Log(3, "ping processed for node", node.ID)
+		logger.Log(3, "ping processed for node", node.Name, node.ID)
 		// --TODO --set client version once feature is implemented.
 		//node.SetClientVersion(msg.Payload())
 	}()

+ 17 - 4
mq/publishers.go

@@ -23,7 +23,7 @@ func PublishPeerUpdate(newNode *models.Node) error {
 	}
 	for _, node := range networkNodes {
 
-		if node.IsServer == "yes" || node.ID == newNode.ID {
+		if node.IsServer == "yes" {
 			continue
 		}
 		peerUpdate, err := logic.GetPeerUpdate(&node)
@@ -39,9 +39,7 @@ func PublishPeerUpdate(newNode *models.Node) error {
 		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)
-			}
+			logger.Log(1, "sent peer update for node", node.Name, "on network:", node.Network)
 		}
 	}
 	return nil
@@ -143,3 +141,18 @@ func sendPeers() {
 		}
 	}
 }
+
+// ServerStartNotify - notifies all non server nodes to pull changes after a restart
+func ServerStartNotify() error {
+	nodes, err := logic.GetAllNodes()
+	if err != nil {
+		return err
+	}
+	for i := range nodes {
+		nodes[i].Action = models.NODE_FORCE_UPDATE
+		if err = NodeUpdate(&nodes[i]); err != nil {
+			logger.Log(1, "error when notifying node", nodes[i].Name, " - ", nodes[i].ID, "of a server startup")
+		}
+	}
+	return nil
+}

+ 58 - 69
netclient/auth/auth.go

@@ -1,84 +1,73 @@
 package auth
 
 import (
-	"encoding/json"
-	"fmt"
 	"os"
 
-	"github.com/gravitl/netmaker/models"
-	"github.com/gravitl/netmaker/netclient/config"
 	"github.com/gravitl/netmaker/netclient/ncutils"
-
 	//    "os"
-	"context"
-
-	nodepb "github.com/gravitl/netmaker/grpc"
-	"google.golang.org/grpc/codes"
-	"google.golang.org/grpc/metadata"
-	"google.golang.org/grpc/status"
 )
 
 // SetJWT func will used to create the JWT while signing in and signing out
-func SetJWT(client nodepb.NodeServiceClient, network string) (context.Context, error) {
-	home := ncutils.GetNetclientPathSpecific()
-	tokentext, err := os.ReadFile(home + "nettoken-" + network)
-	if err != nil {
-		err = AutoLogin(client, network)
-		if err != nil {
-			return nil, status.Errorf(codes.Unauthenticated, fmt.Sprintf("Something went wrong with Auto Login: %v", err))
-		}
-		tokentext, err = ncutils.GetFileWithRetry(home+"nettoken-"+network, 1)
-		if err != nil {
-			return nil, status.Errorf(codes.Unauthenticated, fmt.Sprintf("Something went wrong: %v", err))
-		}
-	}
-	token := string(tokentext)
-
-	// Anything linked to this variable will transmit request headers.
-	md := metadata.New(map[string]string{"authorization": token})
-	ctx := context.Background()
-	ctx = metadata.NewOutgoingContext(ctx, md)
-	return ctx, nil
-}
+//func SetJWT(client nodepb.NodeServiceClient, network string) (context.Context, error) {
+//	home := ncutils.GetNetclientPathSpecific()
+//	tokentext, err := os.ReadFile(home + "nettoken-" + network)
+//	if err != nil {
+//		err = AutoLogin(client, network)
+//		if err != nil {
+//			return nil, status.Errorf(codes.Unauthenticated, fmt.Sprintf("Something went wrong with Auto Login: %v", err))
+//		}
+//		tokentext, err = ncutils.GetFileWithRetry(home+"nettoken-"+network, 1)
+//		if err != nil {
+//			return nil, status.Errorf(codes.Unauthenticated, fmt.Sprintf("Something went wrong: %v", err))
+//		}
+//	}
+//	token := string(tokentext)
+//
+//	// Anything linked to this variable will transmit request headers.
+//	md := metadata.New(map[string]string{"authorization": token})
+//	ctx := context.Background()
+//	ctx = metadata.NewOutgoingContext(ctx, md)
+//	return ctx, nil
+//}
 
 // AutoLogin - auto logins whenever client needs to request from server
-func AutoLogin(client nodepb.NodeServiceClient, network string) error {
-	home := ncutils.GetNetclientPathSpecific()
-	cfg, err := config.ReadConfig(network)
-	if err != nil {
-		return err
-	}
-	pass, err := RetrieveSecret(network)
-	if err != nil {
-		return err
-	}
-	node := models.Node{
-		Password:   pass,
-		MacAddress: cfg.Node.MacAddress,
-		ID:         cfg.Node.ID,
-		Network:    network,
-	}
-	data, err := json.Marshal(&node)
-	if err != nil {
-		return nil
-	}
-
-	login := &nodepb.Object{
-		Data: string(data),
-		Type: nodepb.NODE_TYPE,
-	}
-	// RPC call
-	res, err := client.Login(context.TODO(), login)
-	if err != nil {
-		return err
-	}
-	tokenstring := []byte(res.Data)
-	err = os.WriteFile(home+"nettoken-"+network, tokenstring, 0600)
-	if err != nil {
-		return err
-	}
-	return err
-}
+//func AutoLogin(client nodepb.NodeServiceClient, network string) error {
+//	home := ncutils.GetNetclientPathSpecific()
+//	cfg, err := config.ReadConfig(network)
+//	if err != nil {
+//		return err
+//	}
+//	pass, err := RetrieveSecret(network)
+//	if err != nil {
+//		return err
+//	}
+//	node := models.Node{
+//		Password:   pass,
+//		MacAddress: cfg.Node.MacAddress,
+//		ID:         cfg.Node.ID,
+//		Network:    network,
+//	}
+//	data, err := json.Marshal(&node)
+//	if err != nil {
+//		return nil
+//	}
+//
+//	login := &nodepb.Object{
+//		Data: string(data),
+//		Type: nodepb.NODE_TYPE,
+//	}
+//	// RPC call
+//	res, err := client.Login(context.TODO(), login)
+//	if err != nil {
+//		return err
+//	}
+//	tokenstring := []byte(res.Data)
+//	err = os.WriteFile(home+"nettoken-"+network, tokenstring, 0600)
+//	if err != nil {
+//		return err
+//	}
+//	return err
+//}
 
 // StoreSecret - stores auth secret locally
 func StoreSecret(key string, network string) error {

+ 0 - 4
netclient/cli_options/cmds.go

@@ -26,10 +26,6 @@ func GetCommands(cliFlags []cli.Flag) []*cli.Command {
 					err = errors.New("no network provided")
 					return err
 				}
-				if cfg.Server.GRPCAddress == "" {
-					err = errors.New("no server address provided")
-					return err
-				}
 				err = command.Join(&cfg, pvtKey)
 				return err
 			},

+ 0 - 18
netclient/cli_options/flags.go

@@ -112,18 +112,6 @@ func GetFlags(hostname string) []cli.Flag {
 			Value:   "",
 			Usage:   "Address + API Port (e.g. 1.2.3.4:8081) of Netmaker server.",
 		},
-		&cli.StringFlag{
-			Name:    "grpcserver",
-			EnvVars: []string{"NETCLIENT_GRPC_SERVER"},
-			Value:   "",
-			Usage:   "Address + GRPC Port (e.g. 1.2.3.4:50051) of Netmaker server.",
-		},
-		&cli.StringFlag{
-			Name:    "grpcssl",
-			EnvVars: []string{"NETCLIENT_GRPCSSL"},
-			Value:   "",
-			Usage:   "Tells clients to use SSL to connect to GRPC if 'on'. Disable if 'off'. Off by default.",
-		},
 		&cli.StringFlag{
 			Name:    "key",
 			Aliases: []string{"k"},
@@ -156,12 +144,6 @@ func GetFlags(hostname string) []cli.Flag {
 			Value:   "",
 			Usage:   "Sets endpoint to local address if 'yes'. Ignores if 'no'. Will retrieve from network if unset.",
 		},
-		&cli.StringFlag{
-			Name:    "isdualstack",
-			EnvVars: []string{"NETCLIENT_IS_DUALSTACK"},
-			Value:   "",
-			Usage:   "Sets ipv6 address if 'yes'. Ignores if 'no'. Will retrieve from network if unset.",
-		},
 		&cli.StringFlag{
 			Name:    "udpholepunch",
 			EnvVars: []string{"NETCLIENT_UDP_HOLEPUNCH"},

+ 17 - 42
netclient/command/commands.go

@@ -1,6 +1,8 @@
 package command
 
 import (
+	"crypto/ed25519"
+	"crypto/rand"
 	"strings"
 
 	"github.com/gravitl/netmaker/logger"
@@ -8,47 +10,14 @@ import (
 	"github.com/gravitl/netmaker/netclient/daemon"
 	"github.com/gravitl/netmaker/netclient/functions"
 	"github.com/gravitl/netmaker/netclient/ncutils"
+	"github.com/gravitl/netmaker/tls"
 )
 
-// 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 {
-	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() {
-		return nil
-	}
-	commsCfg.ReadConfig()
-
-	if len(commsCfg.Node.Name) == 0 {
-		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
 func Join(cfg *config.ClientConfig, privateKey string) error {
 	var err error
-	//check if comms network exists
-	if err = JoinComms(cfg); err != nil {
-		return err
-	}
-
 	//join network
-	err = functions.JoinNetwork(cfg, privateKey, false)
+	err = functions.JoinNetwork(cfg, privateKey)
 	if err != nil && !cfg.DebugOn {
 		if !strings.Contains(err.Error(), "ALREADY_INSTALLED") {
 			logger.Log(1, "error installing: ", err.Error())
@@ -98,13 +67,6 @@ func Leave(cfg *config.ClientConfig, force bool) error {
 	} else {
 		logger.Log(0, "success")
 	}
-	nets, err := ncutils.GetSystemNetworks()
-	if err == nil && len(nets) == 1 {
-		if nets[0] == cfg.Node.CommID {
-			logger.Log(1, "detected comms as remaining network, removing...")
-			err = functions.LeaveNetwork(nets[0], true)
-		}
-	}
 	return err
 }
 
@@ -128,7 +90,20 @@ func Pull(cfg *config.ClientConfig) error {
 		}
 		err = nil
 	} else {
+
 		_, err = functions.Pull(cfg.Network, true)
+		_, newKey, kerr := ed25519.GenerateKey(rand.Reader)
+		if kerr == nil && err == nil {
+			if kerr := tls.SaveKey(ncutils.GetNetclientPath(), ncutils.GetSeparator()+"client.key", newKey); kerr != nil {
+				logger.Log(0, "error saving key", kerr.Error())
+			} else {
+				if kerr = functions.RegisterWithServer(&newKey, cfg); err != nil {
+					logger.Log(0, "registration error", kerr.Error())
+				} else {
+					daemon.Restart()
+				}
+			}
+		}
 	}
 	logger.Log(1, "reset network and peer configs")
 	if err == nil {

+ 29 - 22
netclient/config/config.go

@@ -2,6 +2,10 @@ package config
 
 import (
 	//"github.com/davecgh/go-spew/spew"
+
+	"crypto/ed25519"
+	"crypto/x509"
+	"crypto/x509/pkix"
 	"encoding/base64"
 	"encoding/json"
 	"errors"
@@ -29,11 +33,24 @@ type ClientConfig struct {
 
 // ServerConfig - struct for dealing with the server information for a netclient
 type ServerConfig struct {
-	CoreDNSAddr  string `yaml:"corednsaddr"`
-	GRPCAddress  string `yaml:"grpcaddress"`
-	AccessKey    string `yaml:"accesskey"`
-	GRPCSSL      string `yaml:"grpcssl"`
-	CommsNetwork string `yaml:"commsnetwork"`
+	CoreDNSAddr string `yaml:"corednsaddr"`
+	AccessKey   string `yaml:"accesskey"`
+	Server      string `yaml:"server"`
+	API         string `yaml:"api"`
+}
+
+// RegisterRequest - struct for registation with netmaker server
+type RegisterRequest struct {
+	Key        ed25519.PrivateKey
+	CommonName pkix.Name
+}
+
+// RegisterResponse - the response to register function
+type RegisterResponse struct {
+	CA         x509.Certificate
+	CAPubKey   ed25519.PublicKey
+	Cert       x509.Certificate
+	CertPubKey ed25519.PublicKey
 }
 
 // Write - writes the config of a client to disk
@@ -178,20 +195,12 @@ func GetCLIConfig(c *cli.Context) (ClientConfig, string, error) {
 			log.Println("error converting token json to object", tokenbytes)
 			return cfg, "", err
 		}
-
-		if accesstoken.ServerConfig.GRPCConnString != "" {
-			cfg.Server.GRPCAddress = accesstoken.ServerConfig.GRPCConnString
-		}
-
 		cfg.Network = accesstoken.ClientConfig.Network
 		cfg.Node.Network = accesstoken.ClientConfig.Network
 		cfg.Server.AccessKey = accesstoken.ClientConfig.Key
 		cfg.Node.LocalRange = accesstoken.ClientConfig.LocalRange
-		cfg.Server.GRPCSSL = accesstoken.ServerConfig.GRPCSSL
-		cfg.Server.CommsNetwork = accesstoken.ServerConfig.CommsNetwork
-		if c.String("grpcserver") != "" {
-			cfg.Server.GRPCAddress = c.String("grpcserver")
-		}
+		cfg.Server.Server = accesstoken.ServerConfig.Server
+		cfg.Server.API = accesstoken.ServerConfig.APIConnString
 		if c.String("key") != "" {
 			cfg.Server.AccessKey = c.String("key")
 		}
@@ -202,21 +211,20 @@ func GetCLIConfig(c *cli.Context) (ClientConfig, string, error) {
 		if c.String("localrange") != "" {
 			cfg.Node.LocalRange = c.String("localrange")
 		}
-		if c.String("grpcssl") != "" {
-			cfg.Server.GRPCSSL = c.String("grpcssl")
-		}
 		if c.String("corednsaddr") != "" {
 			cfg.Server.CoreDNSAddr = c.String("corednsaddr")
 		}
+		if c.String("apiserver") != "" {
+			cfg.Server.API = c.String("apiserver")
+		}
 
 	} else {
-		cfg.Server.GRPCAddress = c.String("grpcserver")
 		cfg.Server.AccessKey = c.String("key")
 		cfg.Network = c.String("network")
 		cfg.Node.Network = c.String("network")
 		cfg.Node.LocalRange = c.String("localrange")
-		cfg.Server.GRPCSSL = c.String("grpcssl")
 		cfg.Server.CoreDNSAddr = c.String("corednsaddr")
+		cfg.Server.API = c.String("apiserver")
 	}
 	cfg.Node.Name = c.String("name")
 	cfg.Node.Interface = c.String("interface")
@@ -224,12 +232,11 @@ func GetCLIConfig(c *cli.Context) (ClientConfig, string, error) {
 	cfg.Node.MacAddress = c.String("macaddress")
 	cfg.Node.LocalAddress = c.String("localaddress")
 	cfg.Node.Address = c.String("address")
-	cfg.Node.Address6 = c.String("addressIPV6")
+	cfg.Node.Address6 = c.String("address6")
 	//cfg.Node.Roaming = c.String("roaming")
 	cfg.Node.DNSOn = c.String("dnson")
 	cfg.Node.IsLocal = c.String("islocal")
 	cfg.Node.IsStatic = c.String("isstatic")
-	cfg.Node.IsDualStack = c.String("isdualstack")
 	cfg.Node.PostUp = c.String("postup")
 	cfg.Node.PostDown = c.String("postdown")
 	cfg.Node.ListenPort = int32(c.Int("port"))

+ 1 - 3
netclient/daemon/freebsd.go

@@ -3,7 +3,6 @@ package daemon
 import (
 	"log"
 	"os"
-	"path/filepath"
 
 	"github.com/gravitl/netmaker/logger"
 	"github.com/gravitl/netmaker/netclient/ncutils"
@@ -11,11 +10,10 @@ import (
 
 // SetupFreebsdDaemon -- sets up daemon for freebsd
 func SetupFreebsdDaemon() error {
-	dir, err := filepath.Abs(filepath.Dir(os.Args[0]))
+	binarypath, err := os.Executable()
 	if err != nil {
 		return err
 	}
-	binarypath := dir + "/netclient"
 
 	_, err = os.Stat("/etc/netclient/config")
 	if os.IsNotExist(err) {

+ 1 - 3
netclient/daemon/macos.go

@@ -3,7 +3,6 @@ package daemon
 import (
 	"log"
 	"os"
-	"path/filepath"
 	"time"
 
 	"github.com/gravitl/netmaker/logger"
@@ -16,11 +15,10 @@ const MAC_EXEC_DIR = "/usr/local/bin/"
 // SetupMacDaemon - Creates a daemon service from the netclient under LaunchAgents for MacOS
 func SetupMacDaemon() error {
 
-	dir, err := filepath.Abs(filepath.Dir(os.Args[0]))
+	binarypath, err := os.Executable()
 	if err != nil {
 		return err
 	}
-	binarypath := dir + "/netclient"
 
 	if !ncutils.FileExists(MAC_EXEC_DIR + "netclient") {
 		err = ncutils.Copy(binarypath, MAC_EXEC_DIR+"netclient")

+ 1 - 2
netclient/daemon/systemd.go

@@ -20,11 +20,10 @@ func SetupSystemDDaemon() error {
 	if ncutils.IsWindows() {
 		return nil
 	}
-	dir, err := filepath.Abs(filepath.Dir(os.Args[0]))
+	binarypath, err := os.Executable()
 	if err != nil {
 		return err
 	}
-	binarypath := dir + "/netclient"
 
 	_, err = os.Stat("/etc/netclient/config")
 	if os.IsNotExist(err) {

+ 85 - 40
netclient/functions/common.go

@@ -1,28 +1,30 @@
 package functions
 
 import (
+	"bytes"
 	"encoding/json"
 	"errors"
 	"fmt"
+	"io"
 	"log"
 	"net"
+	"net/http"
 	"os"
 	"strings"
 
-	nodepb "github.com/gravitl/netmaker/grpc"
 	"github.com/gravitl/netmaker/logger"
 	"github.com/gravitl/netmaker/models"
-	"github.com/gravitl/netmaker/netclient/auth"
 	"github.com/gravitl/netmaker/netclient/config"
 	"github.com/gravitl/netmaker/netclient/daemon"
 	"github.com/gravitl/netmaker/netclient/local"
 	"github.com/gravitl/netmaker/netclient/ncutils"
 	"github.com/gravitl/netmaker/netclient/wireguard"
 	"golang.zx2c4.com/wireguard/wgctrl"
-	"google.golang.org/grpc"
-	"google.golang.org/grpc/metadata"
 )
 
+// LINUX_APP_DATA_PATH - linux path
+const LINUX_APP_DATA_PATH = "/etc/netmaker"
+
 // ListPorts - lists ports of WireGuard devices
 func ListPorts() error {
 	wgclient, err := wgctrl.New()
@@ -153,52 +155,32 @@ func LeaveNetwork(network string, force bool) error {
 	if err != nil {
 		return err
 	}
-	servercfg := cfg.Server
 	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" {
-		var wcclient nodepb.NodeServiceClient
-		conn, err := grpc.Dial(cfg.Server.GRPCAddress,
-			ncutils.GRPCRequestOpts(cfg.Server.GRPCSSL))
+		token, err := Authenticate(cfg)
 		if err != nil {
-			log.Printf("Unable to establish client connection to "+servercfg.GRPCAddress+": %v", err)
+			return fmt.Errorf("unable to authenticate %w", err)
 		}
-		defer conn.Close()
-		wcclient = nodepb.NewNodeServiceClient(conn)
-
-		ctx, err := auth.SetJWT(wcclient, network)
+		url := "https://" + cfg.Server.API + "/api/nodes/" + cfg.Network + "/" + cfg.Node.ID
+		response, err := API("", http.MethodDelete, url, token)
 		if err != nil {
-			log.Printf("Failed to authenticate: %v", err)
-		} else { // handle client side
-			var header metadata.MD
-			nodeData, err := json.Marshal(&node)
-			if err == nil {
-				_, err = wcclient.DeleteNode(
-					ctx,
-					&nodepb.Object{
-						Data: string(nodeData),
-						Type: nodepb.NODE_TYPE,
-					},
-					grpc.Header(&header),
-				)
-				if err != nil {
-					logger.Log(1, "encountered error deleting node: ", err.Error())
-				} else {
-					logger.Log(1, "removed machine from ", node.Network, " network on remote server")
-				}
-			}
+			return fmt.Errorf("error deleting node on server %w", err)
+		}
+		if response.StatusCode == http.StatusOK {
+			logger.Log(0, "deleted node", cfg.Node.Name, " on network ", cfg.Network)
+		} else {
+			bodybytes, _ := io.ReadAll(response.Body)
+			defer response.Body.Close()
+			return fmt.Errorf("error deleting node on server %s %s", response.Status, string(bodybytes))
 		}
 	}
-
 	wgClient, wgErr := wgctrl.New()
 	if wgErr == nil {
 		removeIface := cfg.Node.Interface
+		queryAddr := cfg.Node.PrimaryAddress()
 		if ncutils.IsMac() {
 			var macIface string
-			macIface, wgErr = local.GetMacIface(cfg.Node.Address)
+			macIface, wgErr = local.GetMacIface(queryAddr)
 			if wgErr == nil && removeIface != "" {
 				removeIface = macIface
 			}
@@ -206,10 +188,10 @@ func LeaveNetwork(network string, force bool) error {
 		}
 		dev, devErr := wgClient.Device(removeIface)
 		if devErr == nil {
-			local.FlushPeerRoutes(removeIface, cfg.Node.Address, dev.Peers[:])
+			local.FlushPeerRoutes(removeIface, queryAddr, dev.Peers[:])
 			_, cidr, cidrErr := net.ParseCIDR(cfg.NetworkSettings.AddressRange)
 			if cidrErr == nil {
-				local.RemoveCIDRRoute(removeIface, cfg.Node.Address, cidr)
+				local.RemoveCIDRRoute(removeIface, queryAddr, cidr)
 			}
 		} else {
 			logger.Log(1, "could not flush peer routes when leaving network, ", cfg.Node.Network)
@@ -321,3 +303,66 @@ func WipeLocal(network string) error {
 	}
 	return err
 }
+
+// GetNetmakerPath - gets netmaker path locally
+func GetNetmakerPath() string {
+	return LINUX_APP_DATA_PATH
+}
+
+//API function to interact with netmaker api endpoints. response from endpoint is returned
+func API(data any, method, url, authorization string) (*http.Response, error) {
+	var request *http.Request
+	var err error
+	if data != "" {
+		payload, err := json.Marshal(data)
+		if err != nil {
+			return nil, fmt.Errorf("error encoding data %w", err)
+		}
+		request, err = http.NewRequest(method, url, bytes.NewBuffer(payload))
+		if err != nil {
+			return nil, fmt.Errorf("error creating http request %w", err)
+		}
+		request.Header.Set("Content-Type", "application/json")
+	} else {
+		request, err = http.NewRequest(method, url, nil)
+		if err != nil {
+			return nil, fmt.Errorf("error creating http request %w", err)
+		}
+	}
+	if authorization != "" {
+		request.Header.Set("authorization", "Bearer "+authorization)
+	}
+	client := http.Client{}
+	return client.Do(request)
+}
+
+// Authenticate authenticates with api to permit subsequent interactions with the api
+func Authenticate(cfg *config.ClientConfig) (string, error) {
+
+	pass, err := os.ReadFile(ncutils.GetNetclientPathSpecific() + "/secret-" + cfg.Network)
+	if err != nil {
+		return "", fmt.Errorf("could not read secrets file %w", err)
+	}
+	data := models.AuthParams{
+		MacAddress: cfg.Node.MacAddress,
+		ID:         cfg.Node.ID,
+		Password:   string(pass),
+	}
+	url := "https://" + cfg.Server.API + "/api/nodes/adm/" + cfg.Network + "/authenticate"
+	response, err := API(data, http.MethodPost, url, "")
+	if err != nil {
+		return "", err
+	}
+	defer response.Body.Close()
+	if response.StatusCode != http.StatusOK {
+		bodybytes, _ := io.ReadAll(response.Body)
+		return "", fmt.Errorf("failed to authenticate %s %s", response.Status, string(bodybytes))
+	}
+	resp := models.SuccessResponse{}
+	if err := json.NewDecoder(response.Body).Decode(&resp); err != nil {
+		return "", fmt.Errorf("error decoding respone %w", err)
+	}
+	tokenData := resp.Response.(map[string]interface{})
+	token := tokenData["AuthToken"]
+	return token.(string), nil
+}

+ 82 - 88
netclient/functions/daemon.go

@@ -2,8 +2,11 @@ package functions
 
 import (
 	"context"
+	"crypto/tls"
+	"crypto/x509"
 	"errors"
 	"fmt"
+	"log"
 	"os"
 	"os/signal"
 	"strings"
@@ -14,7 +17,6 @@ import (
 	mqtt "github.com/eclipse/paho.mqtt.golang"
 	"github.com/go-ping/ping"
 	"github.com/gravitl/netmaker/logger"
-	"github.com/gravitl/netmaker/models"
 	"github.com/gravitl/netmaker/netclient/auth"
 	"github.com/gravitl/netmaker/netclient/config"
 	"github.com/gravitl/netmaker/netclient/daemon"
@@ -36,42 +38,43 @@ type cachedMessage struct {
 
 // Daemon runs netclient daemon from command line
 func Daemon() error {
+	var exists = struct{}{}
+	serverSet := make(map[string]struct{})
 	// == initial pull of all networks ==
 	networks, _ := ncutils.GetSystemNetworks()
+	if len(networks) == 0 {
+		return errors.New("no networks")
+	}
 	for _, network := range networks {
+		logger.Log(3, "initializing network", network)
+		cfg := config.ClientConfig{}
+		cfg.Network = network
+		cfg.ReadConfig()
+		serverSet[cfg.Server.Server] = exists
 		//temporary code --- remove in version v0.13.0
 		removeHostDNS(network, ncutils.IsWindows())
 		// end of code to be removed in version v0.13.0
-		var cfg config.ClientConfig
-		cfg.Network = network
-		cfg.ReadConfig()
 		initialPull(cfg.Network)
 	}
 
-	// == 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 {
-		logger.Log(1, "started comms network daemon, ", currCommsNet)
+	// == subscribe to all nodes for each on machine ==
+	for server := range serverSet {
+		logger.Log(1, "started daemon for server ", server)
 		ctx, cancel := context.WithCancel(context.Background())
-		networkcontext.Store(currCommsNet, cancel)
-		go messageQueue(ctx, currCommsNet)
+		networkcontext.Store(server, cancel)
+		go messageQueue(ctx, server)
 	}
 
 	// == add waitgroup and cancel for checkin routine ==
 	wg := sync.WaitGroup{}
 	ctx, cancel := context.WithCancel(context.Background())
 	wg.Add(1)
-	go Checkin(ctx, &wg, commsNetworks)
+	go Checkin(ctx, &wg)
 	quit := make(chan os.Signal, 1)
-	signal.Notify(quit, syscall.SIGTERM, os.Interrupt, os.Kill)
+	signal.Notify(quit, syscall.SIGTERM, os.Interrupt)
 	<-quit
-	for currCommsNet := range commsNetworks {
-		if cancel, ok := networkcontext.Load(currCommsNet); ok {
+	for server := range serverSet {
+		if cancel, ok := networkcontext.Load(server); ok {
 			cancel.(context.CancelFunc)()
 		}
 	}
@@ -101,16 +104,13 @@ func UpdateKeys(nodeCfg *config.ClientConfig, client mqtt.Client) error {
 	}
 
 	nodeCfg.Node.PublicKey = key.PublicKey().String()
-	var commsCfg = getCommsCfgByNode(&nodeCfg.Node)
-	PublishNodeUpdate(&commsCfg, nodeCfg)
+	PublishNodeUpdate(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)
+func PingServer(cfg *config.ClientConfig) error {
+	pinger, err := ping.NewPinger(cfg.Server.Server)
 	if err != nil {
 		return err
 	}
@@ -120,13 +120,14 @@ func PingServer(commsCfg *config.ClientConfig) error {
 	if stats.PacketLoss == 100 {
 		return errors.New("ping error")
 	}
+	logger.Log(3, "ping of server", cfg.Server.Server, "was successful")
 	return nil
 }
 
 // == Private ==
 
 // sets MQ client subscriptions for a specific node config
-// should be called for each node belonging to a given comms network
+// should be called for each node belonging to a given server
 func setSubscriptions(client mqtt.Client, nodeCfg *config.ClientConfig) {
 	if nodeCfg.DebugOn {
 		if token := client.Subscribe("#", 0, nil); token.Wait() && token.Error() != nil {
@@ -135,21 +136,16 @@ func setSubscriptions(client mqtt.Client, nodeCfg *config.ClientConfig) {
 		}
 		logger.Log(0, "subscribed to all topics for debugging purposes")
 	}
-
 	if token := client.Subscribe(fmt.Sprintf("update/%s/%s", nodeCfg.Node.Network, nodeCfg.Node.ID), 0, mqtt.MessageHandler(NodeUpdate)); token.Wait() && token.Error() != nil {
 		logger.Log(0, token.Error().Error())
 		return
 	}
-	if nodeCfg.DebugOn {
-		logger.Log(0, fmt.Sprintf("subscribed to node updates for node %s update/%s/%s", nodeCfg.Node.Name, nodeCfg.Node.Network, nodeCfg.Node.ID))
-	}
+	logger.Log(3, fmt.Sprintf("subscribed to node updates for node %s update/%s/%s", nodeCfg.Node.Name, nodeCfg.Node.Network, nodeCfg.Node.ID))
 	if token := client.Subscribe(fmt.Sprintf("peers/%s/%s", nodeCfg.Node.Network, nodeCfg.Node.ID), 0, mqtt.MessageHandler(UpdatePeers)); token.Wait() && token.Error() != nil {
 		logger.Log(0, token.Error().Error())
 		return
 	}
-	if nodeCfg.DebugOn {
-		logger.Log(0, fmt.Sprintf("subscribed to peer updates for node %s peers/%s/%s", nodeCfg.Node.Name, nodeCfg.Node.Network, nodeCfg.Node.ID))
-	}
+	logger.Log(3, fmt.Sprintf("subscribed to peer updates for node %s peers/%s/%s", nodeCfg.Node.Name, nodeCfg.Node.Network, nodeCfg.Node.ID))
 }
 
 // on a delete usually, pass in the nodecfg to unsubscribe client broker communications
@@ -171,31 +167,58 @@ func unsubscribeNode(client mqtt.Client, nodeCfg *config.ClientConfig) {
 }
 
 // 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()
-	logger.Log(0, "netclient daemon started for network: ", commsNet)
-	client := setupMQTT(&commsCfg, false)
+// the client should subscribe to ALL nodes that exist on server locally
+func messageQueue(ctx context.Context, server string) {
+	logger.Log(0, "netclient daemon started for server: ", server)
+	client := setupMQTT(nil, server, false)
 	defer client.Disconnect(250)
 	<-ctx.Done()
-	logger.Log(0, "shutting down daemon for comms network ", commsNet)
+	logger.Log(0, "shutting down daemon for server ", server)
+}
+
+// NewTLSConf sets up tls configuration to connect to broker securely
+func NewTLSConfig(server string) *tls.Config {
+	file := ncutils.GetNetclientServerPath(server) + ncutils.GetSeparator() + "root.pem"
+	certpool := x509.NewCertPool()
+	ca, err := os.ReadFile(file)
+	if err != nil {
+		logger.Log(0, "could not read CA file ", err.Error())
+	}
+	ok := certpool.AppendCertsFromPEM(ca)
+	if !ok {
+		logger.Log(0, "failed to append cert")
+	}
+	clientKeyPair, err := tls.LoadX509KeyPair(ncutils.GetNetclientServerPath(server)+ncutils.GetSeparator()+"client.pem", ncutils.GetNetclientPath()+ncutils.GetSeparator()+"client.key")
+	if err != nil {
+		log.Fatalf("could not read client cert/key %v \n", err)
+	}
+	certs := []tls.Certificate{clientKeyPair}
+	return &tls.Config{
+		RootCAs:            certpool,
+		ClientAuth:         tls.NoClientCert,
+		ClientCAs:          nil,
+		Certificates:       certs,
+		InsecureSkipVerify: false,
+	}
 }
 
-// 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 {
+// setupMQTT creates a connection to broker and returns client
+// this function is primarily used to create a connection to publish to the broker
+func setupMQTT(cfg *config.ClientConfig, server string, publish bool) mqtt.Client {
 	opts := mqtt.NewClientOptions()
-	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
+	if cfg != nil {
+		server = cfg.Server.Server
+	}
+	opts.AddBroker("ssl://" + server + ":8883") // TODO get the appropriate port of the comms mq server
+	opts.SetTLSConfig(NewTLSConfig(server))
+	opts.SetClientID(ncutils.MakeRandomString(23))
 	opts.SetDefaultPublishHandler(All)
 	opts.SetAutoReconnect(true)
 	opts.SetConnectRetry(true)
 	opts.SetConnectRetryInterval(time.Second << 2)
 	opts.SetKeepAlive(time.Minute >> 1)
 	opts.SetWriteTimeout(time.Minute)
+
 	opts.SetOnConnectHandler(func(client mqtt.Client) {
 		if !publish {
 			networks, err := ncutils.GetSystemNetworks()
@@ -213,35 +236,36 @@ func setupMQTT(commsCfg *config.ClientConfig, publish bool) mqtt.Client {
 	opts.SetOrderMatters(true)
 	opts.SetResumeSubs(true)
 	opts.SetConnectionLostHandler(func(c mqtt.Client, e error) {
-		logger.Log(0, "detected broker connection lost, running pull for ", commsCfg.Node.Network)
-		_, err := Pull(commsCfg.Node.Network, true)
+		logger.Log(0, "detected broker connection lost, running pull for ", cfg.Node.Network)
+		_, err := Pull(cfg.Node.Network, true)
 		if err != nil {
 			logger.Log(0, "could not run pull, server unreachable: ", err.Error())
 			logger.Log(0, "waiting to retry...")
 		}
 		logger.Log(0, "connection re-established with mqtt server")
 	})
-
 	client := mqtt.NewClient(opts)
+
 	tperiod := time.Now().Add(12 * time.Second)
 	for {
-		//if after 12 seconds, try a gRPC pull on the last try
+		//if after 12 seconds, try a pull on the last try
 		if time.Now().After(tperiod) {
-			logger.Log(0, "running pull for ", commsCfg.Node.Network)
-			_, err := Pull(commsCfg.Node.Network, true)
+			logger.Log(0, "running pull for ", cfg.Node.Network)
+			_, err := Pull(cfg.Node.Network, true)
 			if err != nil {
-				logger.Log(0, "could not run pull, exiting ", commsCfg.Node.Network, " setup: ", err.Error())
+				logger.Log(0, "could not run pull, exiting ", cfg.Node.Network, " setup: ", err.Error())
 				return client
 			}
 			time.Sleep(time.Second)
 		}
 		if token := client.Connect(); token.Wait() && token.Error() != nil {
+
 			logger.Log(0, "unable to connect to broker, retrying ...")
 			if time.Now().After(tperiod) {
-				logger.Log(0, "could not connect to broker, exiting ", commsCfg.Node.Network, " setup: ", token.Error().Error())
+				logger.Log(0, "could not connect to broker, exiting ", cfg.Node.Network, " setup: ", token.Error().Error())
 				if strings.Contains(token.Error().Error(), "connectex") || strings.Contains(token.Error().Error(), "i/o timeout") {
 					logger.Log(0, "connection issue detected.. pulling and restarting daemon")
-					Pull(commsCfg.Node.Network, true)
+					Pull(cfg.Node.Network, true)
 					daemon.Restart()
 				}
 				return client
@@ -255,8 +279,8 @@ func setupMQTT(commsCfg *config.ClientConfig, publish bool) mqtt.Client {
 }
 
 // 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 {
+func publishSignal(nodeCfg *config.ClientConfig, signal byte) error {
+	if err := publish(nodeCfg, fmt.Sprintf("signal/%s", nodeCfg.Node.ID), []byte{signal}, 1); err != nil {
 		return err
 	}
 	return nil
@@ -314,34 +338,6 @@ func decryptMsg(nodeCfg *config.ClientConfig, msg []byte) ([]byte, error) {
 	return ncutils.DeChunk(msg, serverPubKey, diskKey)
 }
 
-func getServerAddress(cfg *config.ClientConfig) string {
-	var server models.ServerAddr
-	for _, server = range cfg.Node.NetworkSettings.DefaultServerAddrs {
-		if server.Address != "" && server.IsLeader {
-			break
-		}
-	}
-	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.CommID
-	commsCfg.ReadConfig()
-	return commsCfg
-}
-
 // == Message Caches ==
 
 func insert(network, which, cache string) {
@@ -367,5 +363,3 @@ func read(network, which string) string {
 	}
 	return ""
 }
-
-// == End Message Caches ==

+ 37 - 97
netclient/functions/join.go

@@ -1,15 +1,15 @@
 package functions
 
 import (
-	"context"
 	"crypto/rand"
 	"encoding/json"
 	"errors"
 	"fmt"
+	"io"
 	"log"
+	"net/http"
 	"runtime"
 
-	nodepb "github.com/gravitl/netmaker/grpc"
 	"github.com/gravitl/netmaker/logger"
 	"github.com/gravitl/netmaker/logic"
 	"github.com/gravitl/netmaker/models"
@@ -18,15 +18,13 @@ import (
 	"github.com/gravitl/netmaker/netclient/daemon"
 	"github.com/gravitl/netmaker/netclient/local"
 	"github.com/gravitl/netmaker/netclient/ncutils"
-	"github.com/gravitl/netmaker/netclient/server"
 	"github.com/gravitl/netmaker/netclient/wireguard"
 	"golang.org/x/crypto/nacl/box"
 	"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
-	"google.golang.org/grpc"
 )
 
 // JoinNetwork - helps a client join a network
-func JoinNetwork(cfg *config.ClientConfig, privateKey string, iscomms bool) error {
+func JoinNetwork(cfg *config.ClientConfig, privateKey string) error {
 	if cfg.Node.Network == "" {
 		return errors.New("no network provided")
 	}
@@ -102,7 +100,7 @@ func JoinNetwork(cfg *config.ClientConfig, privateKey string, iscomms bool) erro
 	// Find and set node MacAddress
 	if cfg.Node.MacAddress == "" {
 		macs, err := ncutils.GetMacAddr()
-		if err != nil || iscomms {
+		if err != nil {
 			//if macaddress can't be found set to random string
 			cfg.Node.MacAddress = ncutils.MakeRandomString(18)
 		} else {
@@ -123,45 +121,32 @@ func JoinNetwork(cfg *config.ClientConfig, privateKey string, iscomms bool) erro
 	}
 	// make sure name is appropriate, if not, give blank name
 	cfg.Node.Name = formatName(cfg.Node)
-	// differentiate between client/server here
-	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,
-		Network:             cfg.Network,
-		ListenPort:          cfg.Node.ListenPort,
-		PostUp:              cfg.Node.PostUp,
-		PostDown:            cfg.Node.PostDown,
-		PersistentKeepalive: cfg.Node.PersistentKeepalive,
-		LocalAddress:        cfg.Node.LocalAddress,
-		Interface:           cfg.Node.Interface,
-		PublicKey:           cfg.Node.PublicKey,
-		DNSOn:               cfg.Node.DNSOn,
-		Name:                cfg.Node.Name,
-		Endpoint:            cfg.Node.Endpoint,
-		UDPHolePunch:        cfg.Node.UDPHolePunch,
-		TrafficKeys:         cfg.Node.TrafficKeys,
-		OS:                  runtime.GOOS,
-		Version:             ncutils.Version,
-	}
-
-	logger.Log(0, "joining "+cfg.Network+" at "+cfg.Server.GRPCAddress)
-	var wcclient nodepb.NodeServiceClient
-
-	conn, err := grpc.Dial(cfg.Server.GRPCAddress,
-		ncutils.GRPCRequestOpts(cfg.Server.GRPCSSL))
-
+	cfg.Node.OS = runtime.GOOS
+	cfg.Node.Version = ncutils.Version
+	cfg.Node.AccessKey = cfg.Server.AccessKey
+	//not sure why this is needed ... setnode defaults should take care of this on server
+	cfg.Node.IPForwarding = "yes"
+	logger.Log(0, "joining "+cfg.Network+" at "+cfg.Server.API)
+	url := "https://" + cfg.Server.API + "/api/nodes/" + cfg.Network
+	response, err := API(cfg.Node, http.MethodPost, url, cfg.Server.AccessKey)
 	if err != nil {
-		log.Fatalf("Unable to establish client connection to "+cfg.Server.GRPCAddress+": %v", err)
+		return fmt.Errorf("error creating node %w", err)
+	}
+	defer response.Body.Close()
+	if response.StatusCode != http.StatusOK {
+		bodybytes, _ := io.ReadAll(response.Body)
+		return fmt.Errorf("error creating node %s %s", response.Status, string(bodybytes))
+	}
+	var nodeGET models.NodeGet
+	if err := json.NewDecoder(response.Body).Decode(&nodeGET); err != nil {
+		//not sure the next line will work as response.Body probably needs to be reset before it can be read again
+		bodybytes, _ := io.ReadAll(response.Body)
+		return fmt.Errorf("error decoding node from server %w %s", err, string(bodybytes))
+	}
+	node := nodeGET.Node
+	if nodeGET.Peers == nil {
+		nodeGET.Peers = []wgtypes.PeerConfig{}
 	}
-	defer conn.Close()
-	wcclient = nodepb.NewNodeServiceClient(conn)
-
 	// safety check. If returned node from server is local, but not currently configured as local, set to local addr
 	if cfg.Node.IsLocal != "yes" && node.IsLocal == "yes" && node.LocalRange != "" {
 		node.LocalAddress, err = ncutils.GetLocalIP(node.LocalRange)
@@ -186,35 +171,11 @@ func JoinNetwork(cfg *config.ClientConfig, privateKey string, iscomms bool) erro
 			return daemon.InstallDaemon(cfg)
 		}
 	}
-	data, err := json.Marshal(&node)
-	if err != nil {
-		return err
-	}
-	// Create node on server
-	res, err := wcclient.CreateNode(
-		context.TODO(),
-		&nodepb.Object{
-			Data: string(data),
-			Type: nodepb.NODE_TYPE,
-		},
-	)
-	if err != nil {
-		return err
-	}
 	logger.Log(1, "node created on remote server...updating configs")
-
 	// keep track of the old listenport value
 	oldListenPort := node.ListenPort
-
-	nodeData := res.Data
-	if err = json.Unmarshal([]byte(nodeData), &node); err != nil {
-		return err
-	}
-
 	cfg.Node = node
-
 	setListenPort(oldListenPort, cfg)
-
 	err = config.ModConfig(&cfg.Node)
 	if err != nil {
 		return err
@@ -223,45 +184,25 @@ func JoinNetwork(cfg *config.ClientConfig, privateKey string, iscomms bool) erro
 	if err = config.SaveBackup(node.Network); err != nil {
 		logger.Log(0, "failed to make backup, node will not auto restore if config is corrupted")
 	}
-
-	logger.Log(0, "retrieving peers")
-	peers, hasGateway, gateways, err := server.GetPeers(node.MacAddress, cfg.Network, cfg.Server.GRPCAddress, node.IsDualStack == "yes", node.IsIngressGateway == "yes", node.IsServer == "yes")
-	if err != nil && !ncutils.IsEmptyRecord(err) {
-		logger.Log(0, "failed to retrieve peers")
-		return err
-	}
-
 	logger.Log(0, "starting wireguard")
-	err = wireguard.InitWireguard(&node, privateKey, peers, hasGateway, gateways, false)
+	err = wireguard.InitWireguard(&node, privateKey, nodeGET.Peers[:], false)
 	if err != nil {
 		return err
 	}
-	//	if node.DNSOn == "yes" {
-	//		for _, server := range node.NetworkSettings.DefaultServerAddrs {
-	//			if server.IsLeader {
-	//				go func() {
-	//					if !local.SetDNSWithRetry(node, server.Address) {
-	//						cfg.Node.DNSOn = "no"
-	//						var currentCommsCfg = getCommsCfgByNode(&cfg.Node)
-	//						PublishNodeUpdate(&currentCommsCfg, &cfg)
-	//					}
-	//				}()
-	//				break
-	//			}
-	//		}
-	//	}
+	if err := Register(cfg, privateKey); err != nil {
+		return err
+	}
 
-	if !iscomms {
-		if cfg.Daemon != "off" {
-			err = daemon.InstallDaemon(cfg)
-		}
+	_ = UpdateLocalListenPort(cfg)
+
+	if cfg.Daemon != "off" {
+		err = daemon.InstallDaemon(cfg)
 		if err != nil {
 			return err
 		} else {
 			daemon.Restart()
 		}
 	}
-
 	return nil
 }
 
@@ -297,8 +238,7 @@ func setListenPort(oldListenPort int32, cfg *config.ClientConfig) {
 
 		// if newListenPort has been modified to find an available port, publish to server
 		if cfg.Node.ListenPort != newListenPort {
-			var currentCommsCfg = getCommsCfgByNode(&cfg.Node)
-			PublishNodeUpdate(&currentCommsCfg, cfg)
+			PublishNodeUpdate(cfg)
 		}
 	}
 }

+ 2 - 59
netclient/functions/list.go

@@ -4,14 +4,9 @@ import (
 	"encoding/json"
 	"fmt"
 
-	nodepb "github.com/gravitl/netmaker/grpc"
 	"github.com/gravitl/netmaker/logger"
-	"github.com/gravitl/netmaker/models"
-	"github.com/gravitl/netmaker/netclient/auth"
 	"github.com/gravitl/netmaker/netclient/config"
 	"github.com/gravitl/netmaker/netclient/ncutils"
-	"google.golang.org/grpc"
-	"google.golang.org/grpc/metadata"
 )
 
 // Peer - the peer struct for list
@@ -67,7 +62,8 @@ func getNetwork(network string) (Network, error) {
 	if err != nil {
 		return Network{}, fmt.Errorf("reading configuration for network %v: %w", network, err)
 	}
-	peers, err := getPeers(network)
+	//peers, err := getPeers(network)
+	peers := []Peer{}
 	if err != nil {
 		return Network{}, fmt.Errorf("listing peers for network %v: %w", network, err)
 	}
@@ -84,56 +80,3 @@ func getNetwork(network string) (Network, error) {
 		},
 	}, nil
 }
-
-func getPeers(network string) ([]Peer, error) {
-	cfg, err := config.ReadConfig(network)
-	if err != nil {
-		return []Peer{}, err
-	}
-	nodecfg := cfg.Node
-	var nodes []models.Node
-
-	var wcclient nodepb.NodeServiceClient
-	conn, err := grpc.Dial(cfg.Server.GRPCAddress,
-		ncutils.GRPCRequestOpts(cfg.Server.GRPCSSL))
-
-	if err != nil {
-		return []Peer{}, fmt.Errorf("connecting to %v: %w", cfg.Server.GRPCAddress, err)
-	}
-	defer conn.Close()
-	// Instantiate the BlogServiceClient with our client connection to the server
-	wcclient = nodepb.NewNodeServiceClient(conn)
-
-	nodeData, err := json.Marshal(&nodecfg)
-	if err != nil {
-		return []Peer{}, fmt.Errorf("could not parse config node on network %s : %w", network, err)
-	}
-
-	req := &nodepb.Object{
-		Data: string(nodeData),
-		Type: nodepb.NODE_TYPE,
-	}
-
-	ctx, err := auth.SetJWT(wcclient, network)
-	if err != nil {
-		return []Peer{}, fmt.Errorf("authenticating: %w", err)
-	}
-	var header metadata.MD
-
-	response, err := wcclient.GetPeers(ctx, req, grpc.Header(&header))
-	if err != nil {
-		return []Peer{}, fmt.Errorf("retrieving peers: %w", err)
-	}
-	if err := json.Unmarshal([]byte(response.GetData()), &nodes); err != nil {
-		return []Peer{}, fmt.Errorf("unmarshaling data for peers: %w", err)
-	}
-
-	peers := []Peer{}
-	for _, node := range nodes {
-		if node.Name != cfg.Node.Name {
-			peers = append(peers, Peer{Name: fmt.Sprintf("%v.%v", node.Name, network), PrivateIPv4: node.Address, PrivateIPv6: node.Address6})
-		}
-	}
-
-	return peers, nil
-}

+ 63 - 0
netclient/functions/localport.go

@@ -0,0 +1,63 @@
+//go:build !freebsd
+// +build !freebsd
+
+package functions
+
+import (
+	"strconv"
+
+	"github.com/gravitl/netmaker/logger"
+	"github.com/gravitl/netmaker/netclient/config"
+	"github.com/gravitl/netmaker/netclient/local"
+	"github.com/gravitl/netmaker/netclient/ncutils"
+	"golang.zx2c4.com/wireguard/wgctrl"
+)
+
+// GetLocalListenPort - Gets the port running on the local interface
+func GetLocalListenPort(ifacename string) (int32, error) {
+	client, err := wgctrl.New()
+	if err != nil {
+		logger.Log(0, "failed to start wgctrl")
+		return 0, err
+	}
+	defer client.Close()
+	device, err := client.Device(ifacename)
+	if err != nil {
+		logger.Log(0, "failed to parse interface")
+		return 0, err
+	}
+	return int32(device.ListenPort), nil
+}
+
+// UpdateLocalListenPort - check local port, if different, mod config and publish
+func UpdateLocalListenPort(nodeCfg *config.ClientConfig) error {
+	var err error
+	ifacename := getRealIface(nodeCfg.Node.Interface, nodeCfg.Node.Address)
+	localPort, err := GetLocalListenPort(ifacename)
+	if err != nil {
+		logger.Log(1, "error encountered checking local listen port: ", err.Error())
+	} else if nodeCfg.Node.LocalListenPort != localPort && localPort != 0 {
+		logger.Log(1, "local port has changed from ", strconv.Itoa(int(nodeCfg.Node.LocalListenPort)), " to ", strconv.Itoa(int(localPort)))
+		nodeCfg.Node.LocalListenPort = localPort
+		err = config.ModConfig(&nodeCfg.Node)
+		if err != nil {
+			return err
+		}
+		if err := PublishNodeUpdate(nodeCfg); err != nil {
+			logger.Log(0, "could not publish local port change")
+		}
+	}
+	return err
+}
+
+func getRealIface(ifacename string, address string) string {
+	var deviceiface = ifacename
+	var err error
+	if ncutils.IsMac() { // if node is Mac (Darwin) get the tunnel name first
+		deviceiface, err = local.GetMacIface(address)
+		if err != nil || deviceiface == "" {
+			deviceiface = ifacename
+		}
+	}
+	return deviceiface
+}

+ 50 - 0
netclient/functions/localport_freebsd.go

@@ -0,0 +1,50 @@
+//go:build freebsd
+// +build freebsd
+
+package functions
+
+import (
+	"errors"
+	"strconv"
+	"strings"
+
+	"github.com/gravitl/netmaker/logger"
+	"github.com/gravitl/netmaker/netclient/config"
+	"github.com/gravitl/netmaker/netclient/ncutils"
+)
+
+// GetLocalListenPort - Gets the port running on the local interface
+func GetLocalListenPort(ifacename string) (int32, error) {
+	portstring, err := ncutils.RunCmd("wg show "+ifacename+" listen-port", false)
+	if err != nil {
+		return 0, err
+	}
+	portstring = strings.TrimSuffix(portstring, "\n")
+	i, err := strconv.ParseInt(portstring, 10, 32)
+	if err != nil {
+		return 0, err
+	} else if i == 0 {
+		return 0, errors.New("parsed port is unset or invalid")
+	}
+	return int32(i), nil
+}
+
+// UpdateLocalListenPort - check local port, if different, mod config and publish
+func UpdateLocalListenPort(nodeCfg *config.ClientConfig) error {
+	var err error
+	localPort, err := GetLocalListenPort(nodeCfg.Node.Interface)
+	if err != nil {
+		logger.Log(1, "error encountered checking local listen port: ", err.Error())
+	} else if nodeCfg.Node.LocalListenPort != localPort && localPort != 0 {
+		logger.Log(1, "local port has changed from ", strconv.Itoa(int(nodeCfg.Node.LocalListenPort)), " to ", strconv.Itoa(int(localPort)))
+		nodeCfg.Node.LocalListenPort = localPort
+		err = config.ModConfig(&nodeCfg.Node)
+		if err != nil {
+			return err
+		}
+		if err := PublishNodeUpdate(nodeCfg); err != nil {
+			logger.Log(0, "could not publish local port change")
+		}
+	}
+	return err
+}

+ 9 - 8
netclient/functions/mqhandlers.go

@@ -33,7 +33,6 @@ func NodeUpdate(client mqtt.Client, msg mqtt.Message) {
 	var network = parseNetworkFromTopic(msg.Topic())
 	nodeCfg.Network = network
 	nodeCfg.ReadConfig()
-	var commsCfg = getCommsCfgByNode(&nodeCfg.Node)
 
 	data, dataErr := decryptMsg(&nodeCfg, msg.Payload())
 	if dataErr != nil {
@@ -88,6 +87,8 @@ func NodeUpdate(client mqtt.Client, msg mqtt.Message) {
 			}
 		}
 		ifaceDelta = true
+	case models.NODE_FORCE_UPDATE:
+		ifaceDelta = true
 	case models.NODE_NOOP:
 	default:
 	}
@@ -131,14 +132,14 @@ func NodeUpdate(client mqtt.Client, msg mqtt.Message) {
 		//			}
 		//		}
 		//	}
-		doneErr := publishSignal(&commsCfg, &nodeCfg, ncutils.DONE)
+		doneErr := publishSignal(&nodeCfg, ncutils.DONE)
 		if doneErr != nil {
 			logger.Log(0, "could not notify server to update peers after interface change")
 		} else {
 			logger.Log(0, "signalled finished interface update to server")
 		}
 	} else if hubChange {
-		doneErr := publishSignal(&commsCfg, &nodeCfg, ncutils.DONE)
+		doneErr := publishSignal(&nodeCfg, ncutils.DONE)
 		if doneErr != nil {
 			logger.Log(0, "could not notify server to update peers after hub change")
 		} else {
@@ -156,6 +157,7 @@ func NodeUpdate(client mqtt.Client, msg mqtt.Message) {
 		//			logger.Log(0, "error applying dns" + err.Error())
 		//		}
 	}
+	_ = UpdateLocalListenPort(&nodeCfg)
 }
 
 // UpdatePeers -- mqtt message handler for peers/<Network>/<NodeID> topic
@@ -188,10 +190,12 @@ func UpdatePeers(client mqtt.Client, msg mqtt.Message) {
 		logger.Log(0, "error updating wireguard peers"+err.Error())
 		return
 	}
+	queryAddr := cfg.Node.PrimaryAddress()
+
 	//err = wireguard.SyncWGQuickConf(cfg.Node.Interface, file)
 	var iface = cfg.Node.Interface
 	if ncutils.IsMac() {
-		iface, err = local.GetMacIface(cfg.Node.Address)
+		iface, err = local.GetMacIface(queryAddr)
 		if err != nil {
 			logger.Log(0, "error retrieving mac iface: "+err.Error())
 			return
@@ -203,10 +207,6 @@ func UpdatePeers(client mqtt.Client, msg mqtt.Message) {
 		return
 	}
 	logger.Log(0, "received peer update for node "+cfg.Node.Name+" "+cfg.Node.Network)
-	//skip dns updates if this is a peer update for comms network
-	if cfg.Node.NetworkSettings.IsComms == "yes" {
-		return
-	}
 	if cfg.Node.DNSOn == "yes" {
 		if err := setHostDNS(peerUpdate.DNS, cfg.Node.Network, ncutils.IsWindows()); err != nil {
 			logger.Log(0, "error updating /etc/hosts "+err.Error())
@@ -218,6 +218,7 @@ func UpdatePeers(client mqtt.Client, msg mqtt.Message) {
 			return
 		}
 	}
+	_ = UpdateLocalListenPort(&cfg)
 }
 
 func setHostDNS(dns, iface string, windows bool) error {

+ 75 - 60
netclient/functions/mqpublish.go

@@ -3,7 +3,9 @@ package functions
 import (
 	"context"
 	"encoding/json"
+	"errors"
 	"fmt"
+	"os"
 	"sync"
 	"time"
 
@@ -11,11 +13,12 @@ import (
 	"github.com/gravitl/netmaker/netclient/auth"
 	"github.com/gravitl/netmaker/netclient/config"
 	"github.com/gravitl/netmaker/netclient/ncutils"
+	"github.com/gravitl/netmaker/tls"
 )
 
 // 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) {
+func Checkin(ctx context.Context, wg *sync.WaitGroup) {
 	defer wg.Done()
 	for {
 		select {
@@ -30,66 +33,61 @@ func Checkin(ctx context.Context, wg *sync.WaitGroup, currentComms map[string]bo
 			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
+			for _, network := range networks {
+				var nodeCfg config.ClientConfig
+				nodeCfg.Network = network
+				nodeCfg.ReadConfig()
+				if nodeCfg.Node.IsStatic != "yes" {
+					extIP, err := ncutils.GetPublicIP()
+					if err != nil {
+						logger.Log(1, "error encountered checking public ip addresses: ", err.Error())
 					}
-					if nodeCfg.Node.IsStatic != "yes" {
-						extIP, err := ncutils.GetPublicIP()
-						if err != nil {
-							logger.Log(1, "error encountered checking public ip addresses: ", err.Error())
+					if nodeCfg.Node.Endpoint != extIP && extIP != "" {
+						logger.Log(1, "endpoint has changed from ", nodeCfg.Node.Endpoint, " to ", extIP)
+						nodeCfg.Node.Endpoint = extIP
+						if err := PublishNodeUpdate(&nodeCfg); err != nil {
+							logger.Log(0, "could not publish endpoint change")
 						}
-						if nodeCfg.Node.Endpoint != extIP && extIP != "" {
-							logger.Log(1, "endpoint has changed from ", nodeCfg.Node.Endpoint, " to ", extIP)
-							nodeCfg.Node.Endpoint = extIP
-							if err := PublishNodeUpdate(&currCommsCfg, &nodeCfg); err != nil {
-								logger.Log(0, "could not publish endpoint change")
-							}
-						}
-						intIP, err := getPrivateAddr()
-						if err != nil {
-							logger.Log(1, "error encountered checking private ip addresses: ", err.Error())
-						}
-						if nodeCfg.Node.LocalAddress != intIP && intIP != "" {
-							logger.Log(1, "local Address has changed from ", nodeCfg.Node.LocalAddress, " to ", intIP)
-							nodeCfg.Node.LocalAddress = intIP
-							if err := PublishNodeUpdate(&currCommsCfg, &nodeCfg); err != nil {
-								logger.Log(0, "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 {
-							logger.Log(1, "error encountered checking local ip addresses: ", err.Error())
-						}
-						if nodeCfg.Node.Endpoint != localIP && localIP != "" {
-							logger.Log(1, "endpoint has changed from "+nodeCfg.Node.Endpoint+" to ", localIP)
-							nodeCfg.Node.Endpoint = localIP
-							if err := PublishNodeUpdate(&currCommsCfg, &nodeCfg); err != nil {
-								logger.Log(0, "could not publish localip change")
-							}
+					}
+					intIP, err := getPrivateAddr()
+					if err != nil {
+						logger.Log(1, "error encountered checking private ip addresses: ", err.Error())
+					}
+					if nodeCfg.Node.LocalAddress != intIP && intIP != "" {
+						logger.Log(1, "local Address has changed from ", nodeCfg.Node.LocalAddress, " to ", intIP)
+						nodeCfg.Node.LocalAddress = intIP
+						if err := PublishNodeUpdate(&nodeCfg); err != nil {
+							logger.Log(0, "could not publish local address change")
 						}
 					}
-					if err := PingServer(&currCommsCfg); err != nil {
-						logger.Log(0, "could not ping server on comms net, ", currCommsCfg.Network, "\n", err.Error())
-					} else {
-						Hello(&currCommsCfg, &nodeCfg)
+					_ = UpdateLocalListenPort(&nodeCfg)
+
+				} else if nodeCfg.Node.IsLocal == "yes" && nodeCfg.Node.LocalRange != "" {
+					localIP, err := ncutils.GetLocalIP(nodeCfg.Node.LocalRange)
+					if err != nil {
+						logger.Log(1, "error encountered checking local ip addresses: ", err.Error())
+					}
+					if nodeCfg.Node.Endpoint != localIP && localIP != "" {
+						logger.Log(1, "endpoint has changed from "+nodeCfg.Node.Endpoint+" to ", localIP)
+						nodeCfg.Node.Endpoint = localIP
+						if err := PublishNodeUpdate(&nodeCfg); err != nil {
+							logger.Log(0, "could not publish localip change")
+						}
 					}
 				}
+				if err := PingServer(&nodeCfg); err != nil {
+					logger.Log(0, "could not ping server for , ", nodeCfg.Network, "\n", err.Error())
+				} else {
+					Hello(&nodeCfg)
+				}
+				checkCertExpiry(&nodeCfg)
 			}
 		}
 	}
 }
 
 // PublishNodeUpdates -- saves node and pushes changes to broker
-func PublishNodeUpdate(commsCfg, nodeCfg *config.ClientConfig) error {
+func PublishNodeUpdate(nodeCfg *config.ClientConfig) error {
 	if err := config.Write(nodeCfg, nodeCfg.Network); err != nil {
 		return err
 	}
@@ -97,40 +95,40 @@ func PublishNodeUpdate(commsCfg, nodeCfg *config.ClientConfig) error {
 	if err != nil {
 		return err
 	}
-	if err = publish(commsCfg, nodeCfg, fmt.Sprintf("update/%s", nodeCfg.Node.ID), data, 1); err != nil {
+	if err = publish(nodeCfg, fmt.Sprintf("update/%s", nodeCfg.Node.ID), data, 1); err != nil {
 		return err
 	}
+
 	logger.Log(0, "sent a node update to server for node", nodeCfg.Node.Name, ", ", nodeCfg.Node.ID)
 	return nil
 }
 
 // Hello -- ping the broker to let server know node it's alive and well
-func Hello(commsCfg, nodeCfg *config.ClientConfig) {
-	if err := publish(commsCfg, nodeCfg, fmt.Sprintf("ping/%s", nodeCfg.Node.ID), []byte(ncutils.Version), 0); err != nil {
+func Hello(nodeCfg *config.ClientConfig) {
+	if err := publish(nodeCfg, fmt.Sprintf("ping/%s", nodeCfg.Node.ID), []byte(ncutils.Version), 0); err != nil {
 		logger.Log(0, fmt.Sprintf("error publishing ping, %v", err))
-		logger.Log(0, "running pull on "+commsCfg.Node.Network+" to reconnect")
-		_, err := Pull(commsCfg.Node.Network, true)
+		logger.Log(0, "running pull on "+nodeCfg.Node.Network+" to reconnect")
+		_, err := Pull(nodeCfg.Node.Network, true)
 		if err != nil {
-			logger.Log(0, "could not run pull on "+commsCfg.Node.Network+", error: "+err.Error())
+			logger.Log(0, "could not run pull on "+nodeCfg.Node.Network+", error: "+err.Error())
 		}
 	}
+	logger.Log(3, "server checkin complete")
 }
 
-// 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 {
+// node cfg is required  in order to fetch the traffic keys of that node for encryption
+func publish(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)
+	client := setupMQTT(nodeCfg, "", true)
 	defer client.Disconnect(250)
 	encrypted, err := ncutils.Chunk(msg, serverPubKey, trafficPrivKey)
 	if err != nil {
@@ -140,5 +138,22 @@ func publish(commsCfg, nodeCfg *config.ClientConfig, dest string, msg []byte, qo
 	if token := client.Publish(dest, qos, false, encrypted); token.Wait() && token.Error() != nil {
 		return token.Error()
 	}
+
+	return nil
+}
+
+func checkCertExpiry(cfg *config.ClientConfig) error {
+	cert, err := tls.ReadCert(ncutils.GetNetclientServerPath(cfg.Server.Server) + ncutils.GetSeparator() + "client.pem")
+	//if cert doesn't exist or will expire within 10 days
+	if errors.Is(err, os.ErrNotExist) || cert.NotAfter.Before(time.Now().Add(time.Hour*24*10)) {
+		key, err := tls.ReadKey(ncutils.GetNetclientPath() + ncutils.GetSeparator() + "client.key")
+		if err != nil {
+			return err
+		}
+		return RegisterWithServer(key, cfg)
+	}
+	if err != nil {
+		return err
+	}
 	return nil
 }

+ 31 - 76
netclient/functions/pull.go

@@ -1,116 +1,72 @@
 package functions
 
 import (
-	"context"
 	"encoding/json"
 	"errors"
+	"fmt"
+	"io"
+	"net/http"
 	"os"
 	"runtime"
 
-	nodepb "github.com/gravitl/netmaker/grpc"
 	"github.com/gravitl/netmaker/logger"
 	"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"
+	"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
 	//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) {
+func Pull(network string, iface 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 {
-			logger.Log(1, "Cant dial GRPC server: ", err.Error())
-			return nil, err
-		}
-		defer conn.Close()
-		wcclient = nodepb.NewNodeServiceClient(conn)
-
-		ctx, err = auth.SetJWT(wcclient, network)
-		if err != nil {
-			logger.Log(1, "Failed to authenticate: ", err.Error())
-			return nil, err
-		}
-		data, err := json.Marshal(&node)
-		if err != nil {
-			logger.Log(1, "Failed to parse node config: ", err.Error())
-			return nil, err
-		}
-
-		req := &nodepb.Object{
-			Data: string(data),
-			Type: nodepb.NODE_TYPE,
-		}
-
-		readres, err := wcclient.ReadNode(ctx, req, grpc.Header(&header))
+	token, err := Authenticate(cfg)
+	if err != nil {
+		return nil, err
+	}
+	url := "https://" + cfg.Server.API + "/api/nodes/" + cfg.Network + "/" + cfg.Node.ID
+	response, err := API("", http.MethodGet, url, token)
+	if err != nil {
+		return nil, err
+	}
+	if response.StatusCode != http.StatusOK {
+		bytes, err := io.ReadAll(response.Body)
 		if err != nil {
-			return nil, err
-		}
-
-		if err = json.Unmarshal([]byte(readres.Data), &resNode); err != nil {
-			return nil, err
+			fmt.Println(err)
 		}
+		return nil, (fmt.Errorf("%s %w", string(bytes), err))
+	}
+	defer response.Body.Close()
+	var nodeGET models.NodeGet
+	if err := json.NewDecoder(response.Body).Decode(&nodeGET); err != nil {
+		return nil, fmt.Errorf("error decoding node %w", err)
 	}
+	resNode := nodeGET.Node
 	// 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 {
-				logger.Log(1, "could not delete old interface ", cfg.Node.Interface)
-			}
-		}
+	if nodeGET.Peers == nil {
+		nodeGET.Peers = []wgtypes.PeerConfig{}
+	}
+
+	if iface {
 		if err = config.ModConfig(&resNode); err != nil {
 			return nil, err
 		}
-		if err = wireguard.SetWGConfig(network, false); err != nil {
+		if err = wireguard.SetWGConfig(network, false, nodeGET.Peers[:]); 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 err = wireguard.SetWGConfig(network, true, nodeGET.Peers[:]); err != nil {
 			if errors.Is(err, os.ErrNotExist) && !ncutils.IsFreeBSD() {
 				return Pull(network, true)
 			} else {
@@ -122,6 +78,5 @@ func Pull(network string, manual bool) (*models.Node, error) {
 	if bkupErr != nil {
 		logger.Log(0, "unable to update backup file")
 	}
-
 	return &resNode, err
 }

+ 92 - 0
netclient/functions/register.go

@@ -0,0 +1,92 @@
+package functions
+
+import (
+	"crypto/ed25519"
+	"crypto/rand"
+	"encoding/json"
+	"errors"
+	"net/http"
+	"os"
+
+	"github.com/gravitl/netmaker/logger"
+	"github.com/gravitl/netmaker/netclient/config"
+	"github.com/gravitl/netmaker/netclient/ncutils"
+	"github.com/gravitl/netmaker/tls"
+)
+
+// Register - the function responsible for registering with the server and acquiring certs
+func Register(cfg *config.ClientConfig, key string) error {
+	if cfg.Server.Server == "" {
+		return errors.New("no server provided")
+	}
+	if cfg.Server.AccessKey == "" {
+		return errors.New("no access key provided")
+	}
+	//generate new key if one doesn' exist
+	var private *ed25519.PrivateKey
+	var err error
+	private, err = tls.ReadKey(ncutils.GetNetclientPath() + ncutils.GetSeparator() + "client.key")
+	if err != nil {
+		_, newKey, err := ed25519.GenerateKey(rand.Reader)
+		if err != nil {
+			return err
+		}
+		if err := tls.SaveKey(ncutils.GetNetclientPath(), ncutils.GetSeparator()+"client.key", newKey); err != nil {
+			return err
+		}
+		private = &newKey
+	}
+	//check if cert exists
+	_, err = tls.ReadCert(ncutils.GetNetclientServerPath(cfg.Server.Server) + ncutils.GetSeparator() + "client.pem")
+	if errors.Is(err, os.ErrNotExist) {
+		if err := RegisterWithServer(private, cfg); err != nil {
+			return err
+		}
+	} else if err != nil {
+		return err
+	}
+	return nil
+}
+
+// RegisterWithServer calls the register endpoint with privatekey and commonname - api returns ca and client certificate
+func RegisterWithServer(private *ed25519.PrivateKey, cfg *config.ClientConfig) error {
+	cfg, err := config.ReadConfig(cfg.Network)
+	if err != nil {
+		return err
+	}
+	data := config.RegisterRequest{
+		Key:        *private,
+		CommonName: tls.NewCName(cfg.Node.Name),
+	}
+	url := "https://" + cfg.Server.API + "/api/server/register"
+	logger.Log(1, "register at "+url)
+
+	token, err := Authenticate(cfg)
+	if err != nil {
+		return err
+	}
+	response, err := API(data, http.MethodPost, url, token)
+	if err != nil {
+		return err
+	}
+	if response.StatusCode != http.StatusOK {
+		return errors.New(response.Status)
+	}
+	var resp config.RegisterResponse
+	if err := json.NewDecoder(response.Body).Decode(&resp); err != nil {
+		return errors.New("unmarshal cert error " + err.Error())
+	}
+	//x509.Certificate.PublicKey is an interface so json encoding/decoding results in a string rather that []byte
+	//the pubkeys are included in the response so the values in the certificate can be updated appropriately
+	resp.CA.PublicKey = resp.CAPubKey
+	resp.Cert.PublicKey = resp.CertPubKey
+	if err := tls.SaveCert(ncutils.GetNetclientServerPath(cfg.Server.Server)+ncutils.GetSeparator(), "root.pem", &resp.CA); err != nil {
+		return err
+	}
+	if err := tls.SaveCert(ncutils.GetNetclientServerPath(cfg.Server.Server)+ncutils.GetSeparator(), "client.pem", &resp.Cert); err != nil {
+		return err
+	}
+	logger.Log(0, "certificates/key saved ")
+	//join the network defined in the token
+	return nil
+}

+ 1 - 1
netclient/local/routes.go

@@ -11,7 +11,7 @@ import (
 // TODO handle ipv6 in future
 
 // SetPeerRoutes - sets/removes ip routes for each peer on a network
-func SetPeerRoutes(iface, currentNodeAddr string, oldPeers map[string][]net.IPNet, newPeers []wgtypes.PeerConfig) {
+func SetPeerRoutes(iface string, oldPeers map[string][]net.IPNet, newPeers []wgtypes.PeerConfig) {
 	// traverse through all recieved peers
 	for _, peer := range newPeers {
 		// if pubkey found in existing peers, check against existing peer

+ 10 - 1
netclient/local/routes_darwin.go

@@ -4,7 +4,9 @@ import (
 	"net"
 	"strings"
 
+	"github.com/gravitl/netmaker/logger"
 	"github.com/gravitl/netmaker/netclient/ncutils"
+	"github.com/seancfoley/ipaddress-go/ipaddr"
 )
 
 // route -n add -net 10.0.0.0/8 192.168.0.254
@@ -33,7 +35,14 @@ func deleteRoute(iface string, addr *net.IPNet, address string) error {
 }
 
 func setCidr(iface, address string, addr *net.IPNet) {
-	ncutils.RunCmd("route -q -n add -net "+addr.String()+" "+address, false)
+	cidr := ipaddr.NewIPAddressString(addr.String()).GetAddress()
+	if cidr.IsIPv4() {
+		ncutils.RunCmd("route -q -n add -net "+addr.String()+" "+address, false)
+	} else if cidr.IsIPv6() {
+		ncutils.RunCmd("route -A inet6 -q -n add -net "+addr.String()+" "+address, false)
+	} else {
+		logger.Log(1, "could not parse address: "+addr.String())
+	}
 }
 
 func removeCidr(iface string, addr *net.IPNet, address string) {

+ 10 - 0
netclient/local/routes_freebsd.go

@@ -3,7 +3,9 @@ package local
 import (
 	"net"
 
+	"github.com/gravitl/netmaker/logger"
 	"github.com/gravitl/netmaker/netclient/ncutils"
+	"github.com/seancfoley/ipaddress-go/ipaddr"
 )
 
 func setRoute(iface string, addr *net.IPNet, address string) error {
@@ -19,6 +21,14 @@ func deleteRoute(iface string, addr *net.IPNet, address string) error {
 }
 
 func setCidr(iface, address string, addr *net.IPNet) {
+	cidr := ipaddr.NewIPAddressString(addr.String()).GetAddress()
+	if cidr.IsIPv4() {
+		ncutils.RunCmd("route add -net "+addr.String()+" -interface "+iface, false)
+	} else if cidr.IsIPv6() {
+		ncutils.RunCmd("route add -net -inet6 "+addr.String()+" -interface "+iface, false)
+	} else {
+		logger.Log(1, "could not parse address: "+addr.String())
+	}
 	ncutils.RunCmd("route add -net "+addr.String()+" -interface "+iface, false)
 }
 

+ 10 - 1
netclient/local/routes_linux.go

@@ -7,7 +7,9 @@ import (
 	"net"
 	"strings"
 
+	"github.com/gravitl/netmaker/logger"
 	"github.com/gravitl/netmaker/netclient/ncutils"
+	"github.com/seancfoley/ipaddress-go/ipaddr"
 )
 
 func setRoute(iface string, addr *net.IPNet, address string) error {
@@ -28,7 +30,14 @@ func deleteRoute(iface string, addr *net.IPNet, address string) error {
 }
 
 func setCidr(iface, address string, addr *net.IPNet) {
-	ncutils.RunCmd("ip -4 route add "+addr.String()+" dev "+iface, false)
+	cidr := ipaddr.NewIPAddressString(addr.String()).GetAddress()
+	if cidr.IsIPv4() {
+		ncutils.RunCmd("ip -4 route add "+addr.String()+" dev "+iface, false)
+	} else if cidr.IsIPv6() {
+		ncutils.RunCmd("ip -6 route add "+addr.String()+" dev "+iface, false)
+	} else {
+		logger.Log(1, "could not parse address: "+addr.String())
+	}
 }
 
 func removeCidr(iface string, addr *net.IPNet, address string) {

+ 1 - 7
netclient/ncutils/iface.go

@@ -10,9 +10,9 @@ import (
 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.Address6 != currentNode.Address6 ||
 		newNode.IsEgressGateway != currentNode.IsEgressGateway ||
 		newNode.IsIngressGateway != currentNode.IsIngressGateway ||
 		newNode.IsRelay != currentNode.IsRelay ||
@@ -27,12 +27,6 @@ func IfaceDelta(currentNode *models.Node, newNode *models.Node) bool {
 	}
 
 	// 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

+ 20 - 14
netclient/ncutils/netclientutils.go

@@ -3,7 +3,6 @@ package ncutils
 import (
 	"bytes"
 	"crypto/rand"
-	"crypto/tls"
 	"encoding/gob"
 	"errors"
 	"fmt"
@@ -23,8 +22,6 @@ import (
 	"github.com/gravitl/netmaker/logger"
 	"github.com/gravitl/netmaker/models"
 	"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
-	"google.golang.org/grpc"
-	"google.golang.org/grpc/credentials"
 )
 
 // Version - version of the netclient
@@ -301,6 +298,15 @@ func GetNetclientPath() string {
 	}
 }
 
+// GetSeparator - gets the separator for OS
+func GetSeparator() string {
+	if IsWindows() {
+		return "\\"
+	} else {
+		return "/"
+	}
+}
+
 // GetFileWithRetry - retry getting file X number of times before failing
 func GetFileWithRetry(path string, retryCount int) ([]byte, error) {
 	var data []byte
@@ -317,6 +323,17 @@ func GetFileWithRetry(path string, retryCount int) ([]byte, error) {
 	return data, err
 }
 
+// GetNetclientServerPath - gets netclient server path
+func GetNetclientServerPath(server string) string {
+	if IsWindows() {
+		return WINDOWS_APP_DATA_PATH + "\\" + server + "\\"
+	} else if IsMac() {
+		return "/etc/netclient/" + server + "/"
+	} else {
+		return LINUX_APP_DATA_PATH + "/" + server
+	}
+}
+
 // GetNetclientPathSpecific - gets specific netclient config path
 func GetNetclientPathSpecific() string {
 	if IsWindows() {
@@ -370,17 +387,6 @@ func GetWGPathSpecific() string {
 	}
 }
 
-// GRPCRequestOpts - gets grps request opts
-func GRPCRequestOpts(isSecure string) grpc.DialOption {
-	var requestOpts grpc.DialOption
-	requestOpts = grpc.WithInsecure()
-	if isSecure == "on" {
-		h2creds := credentials.NewTLS(&tls.Config{NextProtos: []string{"h2"}})
-		requestOpts = grpc.WithTransportCredentials(h2creds)
-	}
-	return requestOpts
-}
-
 // Copy - copies a src file to dest
 func Copy(src, dst string) error {
 	sourceFileStat, err := os.Stat(src)

+ 1 - 0
netclient/ncutils/peerhelper.go

@@ -10,6 +10,7 @@ import (
 	"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
 )
 
+// GetPeers - gets the peers from a given WireGuard interface
 func GetPeers(iface string) ([]wgtypes.Peer, error) {
 
 	var peers []wgtypes.Peer

+ 0 - 346
netclient/server/grpc.go

@@ -1,346 +0,0 @@
-package server
-
-import (
-	"encoding/json"
-	"log"
-	"net"
-	"strconv"
-	"strings"
-	"time"
-
-	nodepb "github.com/gravitl/netmaker/grpc"
-	"github.com/gravitl/netmaker/logger"
-	"github.com/gravitl/netmaker/models"
-	"github.com/gravitl/netmaker/netclient/auth"
-	"github.com/gravitl/netmaker/netclient/config"
-	"github.com/gravitl/netmaker/netclient/ncutils"
-	"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
-	"google.golang.org/grpc"
-	"google.golang.org/grpc/metadata"
-)
-
-// RELAY_KEEPALIVE_MARKER - sets the relay keepalive marker
-const RELAY_KEEPALIVE_MARKER = "20007ms"
-
-func getGrpcClient(cfg *config.ClientConfig) (nodepb.NodeServiceClient, error) {
-	var wcclient nodepb.NodeServiceClient
-	// == GRPC SETUP ==
-	conn, err := grpc.Dial(cfg.Server.GRPCAddress,
-		ncutils.GRPCRequestOpts(cfg.Server.GRPCSSL))
-
-	if err != nil {
-		return nil, err
-	}
-	defer conn.Close()
-	wcclient = nodepb.NewNodeServiceClient(conn)
-	return wcclient, nil
-}
-
-// CheckIn - checkin for node on a network
-func CheckIn(network string) (*models.Node, error) {
-	cfg, err := config.ReadConfig(network)
-	if err != nil {
-		return nil, err
-	}
-	node := cfg.Node
-	if cfg.Node.IsServer != "yes" {
-		wcclient, err := getGrpcClient(cfg)
-		if err != nil {
-			return nil, err
-		}
-		// == run client action ==
-		var header metadata.MD
-		ctx, err := auth.SetJWT(wcclient, network)
-		if err != nil {
-			return nil, err
-		}
-		nodeData, err := json.Marshal(&node)
-		if err != nil {
-			return nil, err
-		}
-		response, err := wcclient.ReadNode(
-			ctx,
-			&nodepb.Object{
-				Data: string(nodeData),
-				Type: nodepb.NODE_TYPE,
-			},
-			grpc.Header(&header),
-		)
-		if err != nil {
-			log.Printf("Encountered error checking in node: %v", err)
-		}
-		if err = json.Unmarshal([]byte(response.GetData()), &node); err != nil {
-			return nil, err
-		}
-	}
-	return &node, err
-}
-
-// GetPeers - gets the peers for a node
-func GetPeers(macaddress string, network string, server string, dualstack bool, isIngressGateway bool, isServer bool) ([]wgtypes.PeerConfig, bool, []string, error) {
-	hasGateway := false
-	var err error
-	var gateways []string
-	var peers []wgtypes.PeerConfig
-	var nodecfg models.Node
-	var nodes []models.Node // fill above fields from server or client
-
-	if !isServer { // set peers client side
-		cfg, err := config.ReadConfig(network)
-		if err != nil {
-			log.Fatalf("Issue retrieving config for network: "+network+". Please investigate: %v", err)
-		}
-		nodecfg = cfg.Node
-		var wcclient nodepb.NodeServiceClient
-		conn, err := grpc.Dial(cfg.Server.GRPCAddress,
-			ncutils.GRPCRequestOpts(cfg.Server.GRPCSSL))
-
-		if err != nil {
-			log.Fatalf("Unable to establish client connection to localhost:50051: %v", err)
-		}
-		defer conn.Close()
-		// Instantiate the BlogServiceClient with our client connection to the server
-		wcclient = nodepb.NewNodeServiceClient(conn)
-
-		nodeData, err := json.Marshal(&nodecfg)
-		if err != nil {
-			logger.Log(1, "could not parse node data from config during peer fetch for network ", network)
-			return peers, hasGateway, gateways, err
-		}
-
-		req := &nodepb.Object{
-			Data: string(nodeData),
-			Type: nodepb.NODE_TYPE,
-		}
-
-		ctx, err := auth.SetJWT(wcclient, network)
-		if err != nil {
-			log.Println("Failed to authenticate.")
-			return peers, hasGateway, gateways, err
-		}
-		var header metadata.MD
-
-		response, err := wcclient.GetPeers(ctx, req, grpc.Header(&header))
-		if err != nil {
-			log.Println("Error retrieving peers")
-			log.Println(err)
-			return nil, hasGateway, gateways, err
-		}
-		if err := json.Unmarshal([]byte(response.GetData()), &nodes); err != nil {
-			log.Println("Error unmarshaling data for peers")
-			return nil, hasGateway, gateways, err
-		}
-	}
-
-	keepalive := nodecfg.PersistentKeepalive
-	keepalivedur, _ := time.ParseDuration(strconv.FormatInt(int64(keepalive), 10) + "s")
-	keepaliveserver, err := time.ParseDuration(strconv.FormatInt(int64(5), 10) + "s")
-	if err != nil {
-		log.Fatalf("Issue with format of keepalive value. Please update netconfig: %v", err)
-	}
-
-	for _, node := range nodes {
-		pubkey, err := wgtypes.ParseKey(node.PublicKey)
-		if err != nil {
-			log.Println("error parsing key")
-			return peers, hasGateway, gateways, err
-		}
-
-		if nodecfg.PublicKey == node.PublicKey {
-			continue
-		}
-		if nodecfg.Endpoint == node.Endpoint {
-			if nodecfg.LocalAddress != node.LocalAddress && node.LocalAddress != "" {
-				node.Endpoint = node.LocalAddress
-			} else {
-				continue
-			}
-		}
-
-		var peer wgtypes.PeerConfig
-		var peeraddr = net.IPNet{
-			IP:   net.ParseIP(node.Address),
-			Mask: net.CIDRMask(32, 32),
-		}
-		var allowedips []net.IPNet
-		allowedips = append(allowedips, peeraddr)
-		// handle manually set peers
-		for _, allowedIp := range node.AllowedIPs {
-			if _, ipnet, err := net.ParseCIDR(allowedIp); err == nil {
-				nodeEndpointArr := strings.Split(node.Endpoint, ":")
-				if !ipnet.Contains(net.IP(nodeEndpointArr[0])) && ipnet.IP.String() != node.Address { // don't need to add an allowed ip that already exists..
-					allowedips = append(allowedips, *ipnet)
-				}
-			} else if appendip := net.ParseIP(allowedIp); appendip != nil && allowedIp != node.Address {
-				ipnet := net.IPNet{
-					IP:   net.ParseIP(allowedIp),
-					Mask: net.CIDRMask(32, 32),
-				}
-				allowedips = append(allowedips, ipnet)
-			}
-		}
-		// handle egress gateway peers
-		if node.IsEgressGateway == "yes" {
-			hasGateway = true
-			ranges := node.EgressGatewayRanges
-			for _, iprange := range ranges { // go through each cidr for egress gateway
-				_, ipnet, err := net.ParseCIDR(iprange) // confirming it's valid cidr
-				if err != nil {
-					logger.Log(1, "could not parse gateway IP range. Not adding ", iprange)
-					continue // if can't parse CIDR
-				}
-				nodeEndpointArr := strings.Split(node.Endpoint, ":") // getting the public ip of node
-				if ipnet.Contains(net.ParseIP(nodeEndpointArr[0])) { // ensuring egress gateway range does not contain public ip of node
-					logger.Log(2, "egress IP range of ", iprange, " overlaps with ", node.Endpoint, ", omitting")
-					continue // skip adding egress range if overlaps with node's ip
-				}
-				if ipnet.Contains(net.ParseIP(nodecfg.LocalAddress)) { // ensuring egress gateway range does not contain public ip of node
-					logger.Log(2, "egress IP range of ", iprange, " overlaps with ", nodecfg.LocalAddress, ", omitting")
-					continue // skip adding egress range if overlaps with node's local ip
-				}
-				gateways = append(gateways, iprange)
-				if err != nil {
-					log.Println("ERROR ENCOUNTERED SETTING GATEWAY")
-				} else {
-					allowedips = append(allowedips, *ipnet)
-				}
-			}
-		}
-		if node.Address6 != "" && dualstack {
-			var addr6 = net.IPNet{
-				IP:   net.ParseIP(node.Address6),
-				Mask: net.CIDRMask(128, 128),
-			}
-			allowedips = append(allowedips, addr6)
-		}
-		if nodecfg.IsServer == "yes" && !(node.IsServer == "yes") {
-			peer = wgtypes.PeerConfig{
-				PublicKey:                   pubkey,
-				PersistentKeepaliveInterval: &keepaliveserver,
-				ReplaceAllowedIPs:           true,
-				AllowedIPs:                  allowedips,
-			}
-		} else if keepalive != 0 {
-			peer = wgtypes.PeerConfig{
-				PublicKey:                   pubkey,
-				PersistentKeepaliveInterval: &keepalivedur,
-				Endpoint: &net.UDPAddr{
-					IP:   net.ParseIP(node.Endpoint),
-					Port: int(node.ListenPort),
-				},
-				ReplaceAllowedIPs: true,
-				AllowedIPs:        allowedips,
-			}
-		} else {
-			peer = wgtypes.PeerConfig{
-				PublicKey: pubkey,
-				Endpoint: &net.UDPAddr{
-					IP:   net.ParseIP(node.Endpoint),
-					Port: int(node.ListenPort),
-				},
-				ReplaceAllowedIPs: true,
-				AllowedIPs:        allowedips,
-			}
-		}
-		peers = append(peers, peer)
-	}
-	if isIngressGateway {
-		extPeers, err := GetExtPeers(macaddress, network, server, dualstack)
-		if err == nil {
-			peers = append(peers, extPeers...)
-		} else {
-			log.Println("ERROR RETRIEVING EXTERNAL PEERS", err)
-		}
-	}
-	return peers, hasGateway, gateways, err
-}
-
-// GetExtPeers - gets the extpeers for a client
-func GetExtPeers(macaddress string, network string, server string, dualstack bool) ([]wgtypes.PeerConfig, error) {
-	var peers []wgtypes.PeerConfig
-	var nodecfg models.Node
-	var extPeers []models.Node
-	var err error
-	// fill above fields from either client or server
-
-	if nodecfg.IsServer != "yes" { // fill extPeers with client side logic
-		var cfg *config.ClientConfig
-		cfg, err = config.ReadConfig(network)
-		if err != nil {
-			log.Fatalf("Issue retrieving config for network: "+network+". Please investigate: %v", err)
-		}
-		nodecfg = cfg.Node
-		var wcclient nodepb.NodeServiceClient
-
-		conn, err := grpc.Dial(cfg.Server.GRPCAddress,
-			ncutils.GRPCRequestOpts(cfg.Server.GRPCSSL))
-		if err != nil {
-			log.Fatalf("Unable to establish client connection to localhost:50051: %v", err)
-		}
-		defer conn.Close()
-		// Instantiate the BlogServiceClient with our client connection to the server
-		wcclient = nodepb.NewNodeServiceClient(conn)
-
-		nodeData, err := json.Marshal(&nodecfg)
-		if err != nil {
-			logger.Log(1, "could not parse node data from config during peer fetch for network ", network)
-			return peers, err
-		}
-
-		req := &nodepb.Object{
-			Data: string(nodeData),
-			Type: nodepb.NODE_TYPE,
-		}
-
-		ctx, err := auth.SetJWT(wcclient, network)
-		if err != nil {
-			log.Println("Failed to authenticate.")
-			return peers, err
-		}
-		var header metadata.MD
-
-		responseObject, err := wcclient.GetExtPeers(ctx, req, grpc.Header(&header))
-		if err != nil {
-			log.Println("Error retrieving peers")
-			log.Println(err)
-			return nil, err
-		}
-		if err = json.Unmarshal([]byte(responseObject.Data), &extPeers); err != nil {
-			return nil, err
-		}
-	}
-	for _, extPeer := range extPeers {
-		pubkey, err := wgtypes.ParseKey(extPeer.PublicKey)
-		if err != nil {
-			log.Println("error parsing key")
-			return peers, err
-		}
-
-		if nodecfg.PublicKey == extPeer.PublicKey {
-			continue
-		}
-
-		var peer wgtypes.PeerConfig
-		var peeraddr = net.IPNet{
-			IP:   net.ParseIP(extPeer.Address),
-			Mask: net.CIDRMask(32, 32),
-		}
-		var allowedips []net.IPNet
-		allowedips = append(allowedips, peeraddr)
-
-		if extPeer.Address6 != "" && dualstack {
-			var addr6 = net.IPNet{
-				IP:   net.ParseIP(extPeer.Address6),
-				Mask: net.CIDRMask(128, 128),
-			}
-			allowedips = append(allowedips, addr6)
-		}
-		peer = wgtypes.PeerConfig{
-			PublicKey:         pubkey,
-			ReplaceAllowedIPs: true,
-			AllowedIPs:        allowedips,
-		}
-		peers = append(peers, peer)
-	}
-	return peers, err
-}

+ 88 - 53
netclient/wireguard/common.go

@@ -14,7 +14,6 @@ import (
 	"github.com/gravitl/netmaker/netclient/config"
 	"github.com/gravitl/netmaker/netclient/local"
 	"github.com/gravitl/netmaker/netclient/ncutils"
-	"github.com/gravitl/netmaker/netclient/server"
 	"golang.zx2c4.com/wireguard/wgctrl"
 	"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
 	"gopkg.in/ini.v1"
@@ -28,28 +27,14 @@ const (
 // SetPeers - sets peers on a given WireGuard interface
 func SetPeers(iface string, node *models.Node, peers []wgtypes.PeerConfig) error {
 	var devicePeers []wgtypes.Peer
-	var currentNodeAddr = node.Address
 	var keepalive = node.PersistentKeepalive
 	var oldPeerAllowedIps = make(map[string][]net.IPNet, len(peers))
 	var err error
-	if ncutils.IsFreeBSD() {
-		if devicePeers, err = ncutils.GetPeers(iface); err != nil {
-			return err
-		}
-	} else {
-		client, err := wgctrl.New()
-		if err != nil {
-			logger.Log(0, "failed to start wgctrl")
-			return err
-		}
-		defer client.Close()
-		device, err := client.Device(iface)
-		if err != nil {
-			logger.Log(0, "failed to parse interface")
-			return err
-		}
-		devicePeers = device.Peers
+	devicePeers, err = GetDevicePeers(iface)
+	if err != nil {
+		return err
 	}
+
 	if len(devicePeers) > 1 && len(peers) == 0 {
 		logger.Log(1, "no peers pulled")
 		return err
@@ -69,7 +54,9 @@ func SetPeers(iface string, node *models.Node, peers []wgtypes.PeerConfig) error
 		var allowedips string
 		var iparr []string
 		for _, ipaddr := range peer.AllowedIPs {
-			iparr = append(iparr, ipaddr.String())
+			if len(peer.AllowedIPs) > 0 && (&ipaddr) != nil {
+				iparr = append(iparr, ipaddr.String())
+			}
 		}
 		allowedips = strings.Join(iparr, ",")
 		keepAliveString := strconv.Itoa(int(keepalive))
@@ -80,7 +67,6 @@ func SetPeers(iface string, node *models.Node, peers []wgtypes.PeerConfig) error
 			_, err = ncutils.RunCmd("wg set "+iface+" peer "+peer.PublicKey.String()+
 				" persistent-keepalive "+keepAliveString+
 				" allowed-ips "+allowedips, true)
-
 		} else {
 			_, err = ncutils.RunCmd("wg set "+iface+" peer "+peer.PublicKey.String()+
 				" endpoint "+udpendpoint+
@@ -115,14 +101,14 @@ func SetPeers(iface string, node *models.Node, peers []wgtypes.PeerConfig) error
 		err = SetMacPeerRoutes(iface)
 		return err
 	} else if ncutils.IsLinux() {
-		local.SetPeerRoutes(iface, currentNodeAddr, oldPeerAllowedIps, peers)
+		local.SetPeerRoutes(iface, oldPeerAllowedIps, peers)
 	}
 
 	return nil
 }
 
 // Initializes a WireGuard interface
-func InitWireguard(node *models.Node, privkey string, peers []wgtypes.PeerConfig, hasGateway bool, gateways []string, syncconf bool) error {
+func InitWireguard(node *models.Node, privkey string, peers []wgtypes.PeerConfig, syncconf bool) error {
 
 	key, err := wgtypes.ParseKey(privkey)
 	if err != nil {
@@ -147,9 +133,10 @@ func InitWireguard(node *models.Node, privkey string, peers []wgtypes.PeerConfig
 	} else {
 		return fmt.Errorf("no interface to configure")
 	}
-	if node.Address == "" {
+	if node.PrimaryAddress() == "" {
 		return fmt.Errorf("no address to configure")
 	}
+
 	if node.UDPHolePunch == "yes" {
 		node.ListenPort = 0
 	}
@@ -160,9 +147,10 @@ func InitWireguard(node *models.Node, privkey string, peers []wgtypes.PeerConfig
 	// spin up userspace / windows interface + apply the conf file
 	confPath := ncutils.GetNetclientPathSpecific() + ifacename + ".conf"
 	var deviceiface = ifacename
+	var mErr error
 	if ncutils.IsMac() { // if node is Mac (Darwin) get the tunnel name first
-		deviceiface, err = local.GetMacIface(node.Address)
-		if err != nil || deviceiface == "" {
+		deviceiface, mErr = local.GetMacIface(node.PrimaryAddress())
+		if mErr != nil || deviceiface == "" {
 			deviceiface = ifacename
 		}
 	}
@@ -175,8 +163,8 @@ func InitWireguard(node *models.Node, privkey string, peers []wgtypes.PeerConfig
 	ifaceReady := strings.Contains(output, deviceiface)
 	for !ifaceReady && !(time.Now().After(starttime.Add(time.Second << 4))) {
 		if ncutils.IsMac() { // if node is Mac (Darwin) get the tunnel name first
-			deviceiface, err = local.GetMacIface(node.Address)
-			if err != nil || deviceiface == "" {
+			deviceiface, mErr = local.GetMacIface(node.PrimaryAddress())
+			if mErr != nil || deviceiface == "" {
 				deviceiface = ifacename
 			}
 		}
@@ -207,21 +195,36 @@ func InitWireguard(node *models.Node, privkey string, peers []wgtypes.PeerConfig
 		if err != nil {
 			logger.Log(1, "error setting peers: ", err.Error())
 		}
+
 		time.Sleep(time.Second)
 	}
-	_, cidr, cidrErr := net.ParseCIDR(modcfg.NetworkSettings.AddressRange)
-	if cidrErr == nil {
-		local.SetCIDRRoute(ifacename, node.Address, cidr)
-	} else {
-		logger.Log(1, "could not set cidr route properly: ", cidrErr.Error())
+
+	//ipv4
+	if node.Address != "" {
+		_, cidr, cidrErr := net.ParseCIDR(modcfg.NetworkSettings.AddressRange)
+		if cidrErr == nil {
+			local.SetCIDRRoute(ifacename, node.Address, cidr)
+		} else {
+			logger.Log(1, "could not set cidr route properly: ", cidrErr.Error())
+		}
+		local.SetCurrentPeerRoutes(ifacename, node.Address, peers)
 	}
-	local.SetCurrentPeerRoutes(ifacename, node.Address, peers)
+	if node.Address6 != "" {
+		//ipv6
+		_, cidr, cidrErr := net.ParseCIDR(modcfg.NetworkSettings.AddressRange6)
+		if cidrErr == nil {
+			local.SetCIDRRoute(ifacename, node.Address6, cidr)
+		} else {
+			logger.Log(1, "could not set cidr route properly: ", cidrErr.Error())
+		}
 
+		local.SetCurrentPeerRoutes(ifacename, node.Address6, peers)
+	}
 	return err
 }
 
 // SetWGConfig - sets the WireGuard Config of a given network and checks if it needs a peer update
-func SetWGConfig(network string, peerupdate bool) error {
+func SetWGConfig(network string, peerupdate bool, peers []wgtypes.PeerConfig) error {
 
 	cfg, err := config.ReadConfig(network)
 	if err != nil {
@@ -230,10 +233,6 @@ func SetWGConfig(network string, peerupdate bool) error {
 	servercfg := cfg.Server
 	nodecfg := cfg.Node
 
-	peers, hasGateway, gateways, err := server.GetPeers(nodecfg.MacAddress, nodecfg.Network, servercfg.GRPCAddress, nodecfg.IsDualStack == "yes", nodecfg.IsIngressGateway == "yes", nodecfg.IsServer == "yes")
-	if err != nil {
-		return err
-	}
 	privkey, err := RetrievePrivKey(network)
 	if err != nil {
 		return err
@@ -242,16 +241,16 @@ func SetWGConfig(network string, peerupdate bool) error {
 		var iface string
 		iface = nodecfg.Interface
 		if ncutils.IsMac() {
-			iface, err = local.GetMacIface(nodecfg.Address)
+			iface, err = local.GetMacIface(nodecfg.PrimaryAddress())
 			if err != nil {
 				return err
 			}
 		}
 		err = SetPeers(iface, &nodecfg, peers)
 	} else if peerupdate {
-		err = InitWireguard(&nodecfg, privkey, peers, hasGateway, gateways, true)
+		err = InitWireguard(&nodecfg, privkey, peers, true)
 	} else {
-		err = InitWireguard(&nodecfg, privkey, peers, hasGateway, gateways, false)
+		err = InitWireguard(&nodecfg, privkey, peers, false)
 	}
 	if nodecfg.DNSOn == "yes" {
 		_ = local.UpdateDNS(nodecfg.Interface, nodecfg.Network, servercfg.CoreDNSAddr)
@@ -301,9 +300,17 @@ func ApplyConf(node *models.Node, ifacename string, confPath string) error {
 	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)
+	if nodeCfg.NetworkSettings.AddressRange != "" {
+		ip, cidr, err := net.ParseCIDR(nodeCfg.NetworkSettings.AddressRange)
+		if err == nil {
+			local.SetCIDRRoute(node.Interface, ip.String(), cidr)
+		}
+	}
+	if nodeCfg.NetworkSettings.AddressRange6 != "" {
+		ip, cidr, err := net.ParseCIDR(nodeCfg.NetworkSettings.AddressRange6)
+		if err == nil {
+			local.SetCIDRRoute(node.Interface, ip.String(), cidr)
+		}
 	}
 
 	return err
@@ -321,12 +328,14 @@ func WriteWgConfig(node *models.Node, privateKey string, peers []wgtypes.PeerCon
 	if node.ListenPort > 0 && node.UDPHolePunch != "yes" {
 		wireguard.Section(section_interface).Key("ListenPort").SetValue(strconv.Itoa(int(node.ListenPort)))
 	}
-	if node.Address != "" {
-		wireguard.Section(section_interface).Key("Address").SetValue(node.Address)
-	}
+	addrString := node.Address
 	if node.Address6 != "" {
-		wireguard.Section(section_interface).Key("Address").SetValue(node.Address6)
+		if addrString != "" {
+			addrString += ","
+		}
+		addrString += node.Address6
 	}
+	wireguard.Section(section_interface).Key("Address").SetValue(addrString)
 	// need to figure out DNS
 	//if node.DNSOn == "yes" {
 	//	wireguard.Section(section_interface).Key("DNS").SetValue(cfg.Server.CoreDNSAddr)
@@ -426,12 +435,14 @@ func UpdateWgInterface(file, privateKey, nameserver string, node models.Node) er
 	}
 	wireguard.Section(section_interface).Key("PrivateKey").SetValue(privateKey)
 	wireguard.Section(section_interface).Key("ListenPort").SetValue(strconv.Itoa(int(node.ListenPort)))
-	if node.Address != "" {
-		wireguard.Section(section_interface).Key("Address").SetValue(node.Address)
-	}
+	addrString := node.Address
 	if node.Address6 != "" {
-		wireguard.Section(section_interface).Key("Address").SetValue(node.Address6)
+		if addrString != "" {
+			addrString += ","
+		}
+		addrString += node.Address6
 	}
+	wireguard.Section(section_interface).Key("Address").SetValue(addrString)
 	//if node.DNSOn == "yes" {
 	//	wireguard.Section(section_interface).Key("DNS").SetValue(nameserver)
 	//}
@@ -517,3 +528,27 @@ func RemoveConfGraceful(ifacename string) {
 	}
 	time.Sleep(time.Second << 1)
 }
+
+// GetDevicePeers - gets the current device's peers
+func GetDevicePeers(iface string) ([]wgtypes.Peer, error) {
+	if ncutils.IsFreeBSD() {
+		if devicePeers, err := ncutils.GetPeers(iface); err != nil {
+			return nil, err
+		} else {
+			return devicePeers, nil
+		}
+	} else {
+		client, err := wgctrl.New()
+		if err != nil {
+			logger.Log(0, "failed to start wgctrl")
+			return nil, err
+		}
+		defer client.Close()
+		device, err := client.Device(iface)
+		if err != nil {
+			logger.Log(0, "failed to parse interface")
+			return nil, err
+		}
+		return device.Peers, nil
+	}
+}

+ 36 - 11
netclient/wireguard/noquick.go

@@ -51,13 +51,29 @@ func ApplyWithoutWGQuick(node *models.Node, ifacename string, confPath string) e
 			ListenPort: &nodeport,
 		}
 	}
-
-	netmaskArr := strings.Split(node.NetworkSettings.AddressRange, "/")
-	var netmask = "32"
-	if len(netmaskArr) == 2 {
-		netmask = netmaskArr[1]
+	var address4 string
+	var address6 string
+	var mask4 string
+	var mask6 string
+	if node.Address != "" {
+		netmaskArr := strings.Split(node.NetworkSettings.AddressRange, "/")
+		var netmask = "32"
+		if len(netmaskArr) == 2 {
+			netmask = netmaskArr[1]
+		}
+		mask4 = netmask
+		address4 = node.Address
+	}
+	if node.Address6 != "" {
+		netmaskArr := strings.Split(node.NetworkSettings.AddressRange6, "/")
+		var netmask = "128"
+		if len(netmaskArr) == 2 {
+			netmask = netmaskArr[1]
+		}
+		mask6 = netmask
+		address6 = node.Address
 	}
-	setKernelDevice(ifacename, node.Address, netmask)
+	setKernelDevice(ifacename, address4, mask4, address6, mask6)
 
 	_, err = wgclient.Device(ifacename)
 	if err != nil {
@@ -88,9 +104,14 @@ func ApplyWithoutWGQuick(node *models.Node, ifacename string, confPath string) e
 		runcmds := strings.Split(node.PostUp, "; ")
 		_ = ncutils.RunCmds(runcmds, true)
 	}
-	if node.Address6 != "" && node.IsDualStack == "yes" {
+	if node.Address6 != "" {
 		logger.Log(1, "adding address: ", node.Address6)
-		_, _ = ncutils.RunCmd(ipExec+" address add dev "+ifacename+" "+node.Address6+"/64", true)
+		netmaskArr := strings.Split(node.NetworkSettings.AddressRange6, "/")
+		var netmask = "64"
+		if len(netmaskArr) == 2 {
+			netmask = netmaskArr[1]
+		}
+		ncutils.RunCmd(ipExec+" address add dev "+ifacename+" "+node.Address6+"/"+netmask, true)
 	}
 	return nil
 }
@@ -120,7 +141,7 @@ func RemoveWithoutWGQuick(ifacename string) error {
 	return err
 }
 
-func setKernelDevice(ifacename, address, mask string) error {
+func setKernelDevice(ifacename, address4, mask4, address6, mask6 string) error {
 	ipExec, err := exec.LookPath("ip")
 	if err != nil {
 		return err
@@ -129,7 +150,11 @@ func setKernelDevice(ifacename, address, mask string) error {
 	// == 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
-
+	if address4 != "" {
+		ncutils.RunCmd(ipExec+" address add dev "+ifacename+" "+address4+"/"+mask4, true)
+	}
+	if address6 != "" {
+		ncutils.RunCmd(ipExec+" address add dev "+ifacename+" "+address6+"/"+mask6, true)
+	}
 	return nil
 }

+ 0 - 41
netclient/wireguard/unix.go

@@ -8,50 +8,9 @@ import (
 
 	"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/wgtypes"
 )
 
-// SetWGKeyConfig - sets the wg conf with a new private key
-func SetWGKeyConfig(network string, serveraddr string) error {
-
-	cfg, err := config.ReadConfig(network)
-	if err != nil {
-		return err
-	}
-
-	node := cfg.Node
-
-	privatekey, err := wgtypes.GeneratePrivateKey()
-	if err != nil {
-		return err
-	}
-	privkeystring := privatekey.String()
-	publickey := privatekey.PublicKey()
-
-	node.PublicKey = publickey.String()
-
-	err = StorePrivKey(privkeystring, network)
-	if err != nil {
-		return err
-	}
-	if node.Action == models.NODE_UPDATE_KEY {
-		node.Action = models.NODE_NOOP
-	}
-	err = config.ModConfig(&node)
-	if err != nil {
-		return err
-	}
-
-	err = SetWGConfig(network, false)
-	if err != nil {
-		return err
-	}
-
-	return err
-}
-
 // ApplyWGQuickConf - applies wg-quick commands if os supports
 func ApplyWGQuickConf(confPath string, ifacename string) error {
 	if ncutils.IsWindows() {

+ 0 - 27
netclient/wireguard/windows.go

@@ -9,16 +9,6 @@ import (
 
 // ApplyWindowsConf - applies the WireGuard configuration file on Windows
 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 {
-				logger.Log(err.Error(), 1)
-			}
-		}
-	*/
 	var commandLine = fmt.Sprintf(`wireguard.exe /installtunnelservice "%s"`, confPath)
 	if _, err := ncutils.RunCmdFormatted(commandLine, false); err != nil {
 		return err
@@ -31,22 +21,5 @@ func RemoveWindowsConf(ifacename string, printlog bool) error {
 	if _, err := ncutils.RunCmd("wireguard.exe /uninstalltunnelservice "+ifacename, printlog); err != nil {
 		logger.Log(1, err.Error())
 	}
-	/*
-		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 {
-				logger.Log(err.Error(), 1)
-			}
-		}
-		time.Sleep(time.Second >> 2)
-		if ncutils.FileExists(dpapipath) {
-			err := os.Remove(dpapipath)
-			if err != nil {
-				logger.Log(err.Error(), 1)
-			}
-		}
-	*/
 	return nil
 }

BIN
netmaker.exe


+ 0 - 17
nginx/netmaker-nginx-template.conf

@@ -31,21 +31,4 @@ server {
         proxy_pass_request_headers      on;
         }
 }
-server {
-    listen 443 ssl http2;
-    server_name grpc.NETMAKER_BASE_DOMAIN;
-    ssl_certificate /etc/letsencrypt/live/NETMAKER_BASE_DOMAIN/fullchain.pem; 
-    ssl_certificate_key /etc/letsencrypt/live/NETMAKER_BASE_DOMAIN/privkey.pem; 
-    #include /etc/letsencrypt/options-ssl-nginx.conf; 
-    #ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; 
 
-        # Forces the header to be the one that is visible from the outside
-        proxy_set_header                Host api.NETMAKER_BASE_DOMAIN; # Please change to your URL
-
-        # Pass all headers through to the backend
-        proxy_pass_request_headers      on;
-
-        location / {
-            grpc_pass grpc://127.0.0.1:50051;
-        }
-}

+ 0 - 11
scripts/daemon.sh

@@ -1,11 +0,0 @@
-# create a logs file
-sudo touch /etc/netclient/netclient.logs
-echo "[netclient] created logs file in /etc/netclient/netclient.logs"
-echo "[netclient] Starting netclient checkins"
-# loop and call checkin -n all
-while [ 1 ]; do
-    # add logs to netclient.logs
-    sudo /etc/netclient/netclient checkin -n all >> /etc/netclient/netclient.logs 2&1>
-    sleep 15
-done &
-echo "[netclient] exiting"

+ 0 - 1
scripts/install-netmaker.sh

@@ -34,7 +34,6 @@ echo "To Override, add a Wildcard (*.netmaker.example.com) DNS record pointing t
 echo "Or, add three DNS records pointing to $SERVER_PUBLIC_IP for the following (Replacing 'netmaker.example.com' with the domain of your choice):"
 echo "   dashboard.netmaker.example.com"
 echo "         api.netmaker.example.com"
-echo "        grpc.netmaker.example.com"
 echo "-----------------------------------------------------"
 read -p "Domain (Hit 'enter' to use $NETMAKER_BASE_DOMAIN): " domain
 read -p "Contact Email: " email

+ 0 - 1
scripts/netmaker-server.sh

@@ -9,7 +9,6 @@ cat >/etc/netmaker/config/environments/dev.yaml<<EOL
 server:
   host:
   apiport: "8081"
-  grpcport: "50051"
   masterkey: "secretkey"
   allowedorigin: "*"
   restbackend: true            

Some files were not shown because too many files changed in this diff