Browse Source

Merge pull request #1167 from gravitl/v0.14.2

V0.14.2
Alex Feiszli 3 years ago
parent
commit
24f7fbb7b7
71 changed files with 648 additions and 693 deletions
  1. 1 0
      .github/ISSUE_TEMPLATE/bug-report.yml
  2. 3 13
      .github/workflows/publish-netclient-docker-userspace.yml
  3. 13 7
      README.md
  4. 2 1
      auth/azure-ad.go
  5. 2 1
      auth/github.go
  6. 2 1
      auth/google.go
  7. 2 2
      compose/docker-compose.contained.yml
  8. 2 2
      compose/docker-compose.hostnetwork.yml
  9. 2 2
      compose/docker-compose.nocaddy.yml
  10. 2 2
      compose/docker-compose.nodns.yml
  11. 2 2
      compose/docker-compose.reference.yml
  12. 137 0
      compose/docker-compose.traefik.yml
  13. 2 2
      compose/docker-compose.yml
  14. 1 0
      config/config.go
  15. 1 0
      controllers/config/dnsconfig/netmaker.hosts
  16. 2 1
      controllers/network_test.go
  17. 6 4
      controllers/node.go
  18. 1 1
      controllers/node_test.go
  19. 13 19
      controllers/server.go
  20. 0 23
      docker/Dockerfile-builder
  21. 0 36
      docker/Dockerfile-full
  22. 0 22
      docker/Dockerfile-netclient
  23. 1 1
      docker/Dockerfile-netclient-doks
  24. 1 1
      docker/Dockerfile-netclient-doks-uspace
  25. 0 39
      docker/Dockerfile-netclient-full
  26. 0 39
      docker/Dockerfile-netclient-kernel
  27. 1 1
      docker/Dockerfile-netclient-multiarch
  28. 1 1
      docker/Dockerfile-netclient-multiarch-userspace
  29. 0 26
      docker/Dockerfile-netmaker-slim
  30. 0 26
      docker/Dockerfile-userspace
  31. 5 6
      go.mod
  32. 10 12
      go.sum
  33. 14 12
      logger/logger.go
  34. 6 0
      logger/types.go
  35. 2 6
      logic/accesskeys.go
  36. 0 62
      logic/ips/ips.go
  37. 0 50
      logic/ips/ips_test.go
  38. 36 32
      logic/networks.go
  39. 2 6
      logic/nodes.go
  40. 92 51
      logic/peers.go
  41. 6 6
      logic/server.go
  42. 1 1
      logic/telemetry.go
  43. 3 2
      logic/timer.go
  44. 1 0
      logic/util.go
  45. 1 6
      models/accessToken.go
  46. 5 4
      models/mqtt.go
  47. 2 2
      models/node.go
  48. 15 2
      models/structs.go
  49. 1 0
      mq/publishers.go
  50. 31 23
      netclient/config/config.go
  51. 36 0
      netclient/functions/common.go
  52. 17 12
      netclient/functions/daemon.go
  53. 16 27
      netclient/functions/join.go
  54. 1 1
      netclient/functions/localport.go
  55. 1 1
      netclient/functions/localport_freebsd.go
  56. 12 3
      netclient/functions/mqhandlers.go
  57. 16 2
      netclient/functions/mqpublish.go
  58. 7 2
      netclient/functions/pull.go
  59. 18 10
      netclient/functions/register.go
  60. 2 3
      netclient/gui/components/views/join.go
  61. 3 4
      netclient/local/routes_darwin.go
  62. 3 4
      netclient/local/routes_freebsd.go
  63. 3 4
      netclient/local/routes_linux.go
  64. 1 1
      netclient/netclient.exe.manifest.xml
  65. 3 3
      netclient/versioninfo.json
  66. 11 8
      netclient/wireguard/common.go
  67. 16 3
      scripts/netclient.sh
  68. 9 14
      scripts/nm-quick.sh
  69. 34 8
      servercfg/serverconf.go
  70. 1 1
      serverctl/iptables.go
  71. 5 24
      serverctl/serverctl.go

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

@@ -31,6 +31,7 @@ body:
       label: Version
       label: Version
       description: What version are you running?
       description: What version are you running?
       options:
       options:
+        - v0.14.2
         - v0.14.1
         - v0.14.1
         - v0.14.0      
         - v0.14.0      
         - v0.13.1
         - v0.13.1

+ 3 - 13
.github/workflows/publish-netclient-docker-go.yml → .github/workflows/publish-netclient-docker-userspace.yml

@@ -1,4 +1,4 @@
-name: Publish Netclient-go Docker
+name: Publish Netclient-Userspace Docker
 
 
 on:
 on:
   workflow_dispatch:
   workflow_dispatch:
@@ -39,23 +39,13 @@ jobs:
         with:
         with:
           username: ${{ secrets.DOCKERHUB_USERNAME }}
           username: ${{ secrets.DOCKERHUB_USERNAME }}
           password: ${{ secrets.DOCKERHUB_TOKEN }}
           password: ${{ secrets.DOCKERHUB_TOKEN }}
-      - 
-        name: Build x86 and export to Docker
-        uses: docker/build-push-action@v2
-        with:
-          context: .
-          load: true
-          platforms: linux/amd64
-          file: ./docker/Dockerfile-netclient-multiarch-go
-          tags: ${{ env.TAG }}
-          build-args: version=${{ env.TAG }}  
       -
       -
         name: Build and push
         name: Build and push
         uses: docker/build-push-action@v2
         uses: docker/build-push-action@v2
         with:
         with:
           context: .
           context: .
           platforms: linux/amd64
           platforms: linux/amd64
-          file: ./docker/Dockerfile-netclient-multiarch-go
+          file: ./docker/Dockerfile-netclient-multiarch-userspace
           push: true
           push: true
-          tags: gravitl/netclient-go:${{ env.TAG }}, gravitl/netclient-go:latest
+          tags: gravitl/netclient-go:${{ env.TAG }}, gravitl/netclient-userspace:latest
           build-args: version=${{ env.TAG }}  
           build-args: version=${{ env.TAG }}  

+ 13 - 7
README.md

@@ -10,23 +10,26 @@ a platform for modern, blazing fast virtual networks
 
 
 <p align="center">
 <p align="center">
   <a href="https://github.com/gravitl/netmaker/releases">
   <a href="https://github.com/gravitl/netmaker/releases">
-    <img src="https://img.shields.io/badge/Version-0.14.1-informational?style=flat-square" />
+    <img src="https://img.shields.io/badge/Version-0.14.2-informational?style=flat-square" />
   </a>
   </a>
   <a href="https://hub.docker.com/r/gravitl/netmaker/tags">
   <a href="https://hub.docker.com/r/gravitl/netmaker/tags">
-    <img src="https://img.shields.io/docker/pulls/gravitl/netmaker" />
+    <img src="https://img.shields.io/docker/pulls/gravitl/netmaker?label=downloads" />
   </a>  
   </a>  
   <a href="https://goreportcard.com/report/github.com/gravitl/netmaker">
   <a href="https://goreportcard.com/report/github.com/gravitl/netmaker">
     <img src="https://goreportcard.com/badge/github.com/gravitl/netmaker" />
     <img src="https://goreportcard.com/badge/github.com/gravitl/netmaker" />
   </a>
   </a>
-  <a href="https://github.com/gravitl/netmaker/graphs/contributors">
-    <img src="https://img.shields.io/github/commit-activity/m/gravitl/netmaker?color=blue" />
-  </a>
   <a href="https://twitter.com/intent/follow?screen_name=netmaker_io">
   <a href="https://twitter.com/intent/follow?screen_name=netmaker_io">
-    <img src="https://img.shields.io/twitter/follow/netmaker_io?style=social" />
+    <img src="https://img.shields.io/twitter/follow/netmaker_io?label=follow&style=social" />
   </a>
   </a>
   <a href="https://www.youtube.com/channel/UCach3lJY_xBV7rGrbUSvkZQ">
   <a href="https://www.youtube.com/channel/UCach3lJY_xBV7rGrbUSvkZQ">
     <img src="https://img.shields.io/youtube/channel/views/UCach3lJY_xBV7rGrbUSvkZQ?style=social" />
     <img src="https://img.shields.io/youtube/channel/views/UCach3lJY_xBV7rGrbUSvkZQ?style=social" />
   </a>
   </a>
+  <a href="https://reddit.com/r/netmaker">
+    <img src="https://img.shields.io/reddit/subreddit-subscribers/netmaker?label=%2Fr%2Fnetmaker&style=social" />
+  </a>  
+  <a href="https://discord.gg/zRb9Vfhk8A">
+    <img src="https://img.shields.io/discord/825071750290210916?color=%09%237289da&label=chat" />
+  </a> 
 </p>
 </p>
 
 
 # WireGuard® Automation from Homelab to Enterprise
 # WireGuard® Automation from Homelab to Enterprise
@@ -43,7 +46,7 @@ a platform for modern, blazing fast virtual networks
 **For production-grade installations, visit the [Install Docs](https://netmaker.readthedocs.io/en/master/install.html).**  
 **For production-grade installations, visit the [Install Docs](https://netmaker.readthedocs.io/en/master/install.html).**  
 **For an HA install using helm on k8s, visit the [Helm Repo](https://github.com/gravitl/netmaker-helm/).**
 **For an HA install using helm on k8s, visit the [Helm Repo](https://github.com/gravitl/netmaker-helm/).**
 1. Get a cloud VM with Ubuntu 20.04 and a public IP.
 1. Get a cloud VM with Ubuntu 20.04 and a public IP.
-2. Open ports 443, 80, 53, 8883, and 51821-51830/udp on the VM firewall and in cloud security settings.
+2. Open ports 443, 53, and 51821-51830/udp on the VM firewall and in cloud security settings.
 3. Run the script **(see below for optional configurations)**:
 3. Run the script **(see below for optional configurations)**:
 
 
 `wget -qO - https://raw.githubusercontent.com/gravitl/netmaker/master/scripts/nm-quick.sh | sudo bash`
 `wget -qO - https://raw.githubusercontent.com/gravitl/netmaker/master/scripts/nm-quick.sh | sudo bash`
@@ -90,6 +93,9 @@ After installing Netmaker, check out the [Walkthrough](https://itnext.io/getting
 
 
 - [Community (Discord)](https://discord.gg/zRb9Vfhk8A)
 - [Community (Discord)](https://discord.gg/zRb9Vfhk8A)
 
 
+- [Community (Reddit)](https://reddit.com/r/netmaker)
+
+
 - [Business (Subscription)](https://gravitl.com/plans/business)
 - [Business (Subscription)](https://gravitl.com/plans/business)
 
 
 - [Learning Resources](https://gravitl.com/resources)
 - [Learning Resources](https://gravitl.com/resources)

+ 2 - 1
auth/azure-ad.go

@@ -1,6 +1,7 @@
 package auth
 package auth
 
 
 import (
 import (
+	"context"
 	"encoding/json"
 	"encoding/json"
 	"fmt"
 	"fmt"
 	"io"
 	"io"
@@ -90,7 +91,7 @@ func getAzureUserInfo(state string, code string) (*azureOauthUser, error) {
 	if state != oauth_state_string {
 	if state != oauth_state_string {
 		return nil, fmt.Errorf("invalid oauth state")
 		return nil, fmt.Errorf("invalid oauth state")
 	}
 	}
-	var token, err = auth_provider.Exchange(oauth2.NoContext, code)
+	var token, err = auth_provider.Exchange(context.Background(), code)
 	if err != nil {
 	if err != nil {
 		return nil, fmt.Errorf("code exchange failed: %s", err.Error())
 		return nil, fmt.Errorf("code exchange failed: %s", err.Error())
 	}
 	}

+ 2 - 1
auth/github.go

@@ -1,6 +1,7 @@
 package auth
 package auth
 
 
 import (
 import (
+	"context"
 	"encoding/json"
 	"encoding/json"
 	"fmt"
 	"fmt"
 	"io"
 	"io"
@@ -90,7 +91,7 @@ func getGithubUserInfo(state string, code string) (*githubOauthUser, error) {
 	if state != oauth_state_string {
 	if state != oauth_state_string {
 		return nil, fmt.Errorf("invalid OAuth state")
 		return nil, fmt.Errorf("invalid OAuth state")
 	}
 	}
-	var token, err = auth_provider.Exchange(oauth2.NoContext, code)
+	var token, err = auth_provider.Exchange(context.Background(), code)
 	if err != nil {
 	if err != nil {
 		return nil, fmt.Errorf("code exchange failed: %s", err.Error())
 		return nil, fmt.Errorf("code exchange failed: %s", err.Error())
 	}
 	}

+ 2 - 1
auth/google.go

@@ -1,6 +1,7 @@
 package auth
 package auth
 
 
 import (
 import (
+	"context"
 	"encoding/json"
 	"encoding/json"
 	"fmt"
 	"fmt"
 	"io"
 	"io"
@@ -91,7 +92,7 @@ func getGoogleUserInfo(state string, code string) (*googleOauthUser, error) {
 	if state != oauth_state_string {
 	if state != oauth_state_string {
 		return nil, fmt.Errorf("invalid OAuth state")
 		return nil, fmt.Errorf("invalid OAuth state")
 	}
 	}
-	var token, err = auth_provider.Exchange(oauth2.NoContext, code)
+	var token, err = auth_provider.Exchange(context.Background(), code)
 	if err != nil {
 	if err != nil {
 		return nil, fmt.Errorf("code exchange failed: %s", err.Error())
 		return nil, fmt.Errorf("code exchange failed: %s", err.Error())
 	}
 	}

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

@@ -3,7 +3,7 @@ version: "3.4"
 services:
 services:
   netmaker:
   netmaker:
     container_name: netmaker
     container_name: netmaker
-    image: gravitl/netmaker:v0.14.1
+    image: gravitl/netmaker:v0.14.2
     volumes:
     volumes:
       - dnsconfig:/root/config/dnsconfig
       - dnsconfig:/root/config/dnsconfig
       - sqldata:/root/data
       - sqldata:/root/data
@@ -43,7 +43,7 @@ services:
     container_name: netmaker-ui
     container_name: netmaker-ui
     depends_on:
     depends_on:
       - netmaker
       - netmaker
-    image: gravitl/netmaker-ui:v0.14.1
+    image: gravitl/netmaker-ui:v0.14.2
     links:
     links:
       - "netmaker:api"
       - "netmaker:api"
     environment:
     environment:

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

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

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

@@ -3,7 +3,7 @@ version: "3.4"
 services:
 services:
   netmaker:
   netmaker:
     container_name: netmaker
     container_name: netmaker
-    image: gravitl/netmaker:v0.14.1
+    image: gravitl/netmaker:v0.14.2
     volumes:
     volumes:
       - dnsconfig:/root/config/dnsconfig
       - dnsconfig:/root/config/dnsconfig
       - sqldata:/root/data
       - sqldata:/root/data
@@ -44,7 +44,7 @@ services:
     container_name: netmaker-ui
     container_name: netmaker-ui
     depends_on:
     depends_on:
       - netmaker
       - netmaker
-    image: gravitl/netmaker-ui:v0.14.1
+    image: gravitl/netmaker-ui:v0.14.2
     links:
     links:
       - "netmaker:api"
       - "netmaker:api"
     ports:
     ports:

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

@@ -3,7 +3,7 @@ version: "3.4"
 services:
 services:
   netmaker:
   netmaker:
     container_name: netmaker
     container_name: netmaker
-    image: gravitl/netmaker:v0.14.1
+    image: gravitl/netmaker:v0.14.2
     volumes:
     volumes:
       - dnsconfig:/root/config/dnsconfig
       - dnsconfig:/root/config/dnsconfig
       - sqldata:/root/data
       - sqldata:/root/data
@@ -45,7 +45,7 @@ services:
     container_name: netmaker-ui
     container_name: netmaker-ui
     depends_on:
     depends_on:
       - netmaker
       - netmaker
-    image: gravitl/netmaker-ui:v0.14.1
+    image: gravitl/netmaker-ui:v0.14.2
     links:
     links:
       - "netmaker:api"
       - "netmaker:api"
     ports:
     ports:

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

@@ -2,7 +2,7 @@ services:
   netmaker: # The Primary Server for running Netmaker
   netmaker: # The Primary Server for running Netmaker
     privileged: true # Necessary to run sudo/root level commands on host system. Likely using this if running with host networking on.
     privileged: true # Necessary to run sudo/root level commands on host system. Likely using this if running with host networking on.
     container_name: netmaker
     container_name: netmaker
-    image: gravitl/netmaker:v0.14.1
+    image: gravitl/netmaker:v0.14.2
     volumes: # Volume mounts necessary for CLIENT_MODE to control wireguard networking on host (except dnsconfig, which is where dns config files are stored for use by CoreDNS)
     volumes: # Volume mounts necessary for CLIENT_MODE to control wireguard networking on host (except dnsconfig, which is where dns config files are stored for use by CoreDNS)
       - dnsconfig:/root/config/dnsconfig # Netmaker writes Corefile to this location, which gets mounted by CoreDNS for DNS configuration.
       - dnsconfig:/root/config/dnsconfig # Netmaker writes Corefile to this location, which gets mounted by CoreDNS for DNS configuration.
       - sqldata:/root/data
       - sqldata:/root/data
@@ -46,7 +46,7 @@ services:
     container_name: netmaker-ui
     container_name: netmaker-ui
     depends_on:
     depends_on:
       - netmaker
       - netmaker
-    image: gravitl/netmaker-ui:v0.14.1
+    image: gravitl/netmaker-ui:v0.14.2
     links:
     links:
       - "netmaker:api"
       - "netmaker:api"
     ports:
     ports:

+ 137 - 0
compose/docker-compose.traefik.yml

@@ -0,0 +1,137 @@
+version: "3.4"
+
+services:
+  netmaker:
+    container_name: netmaker
+    image: gravitl/netmaker:v0.14.2
+    cap_add: 
+      - NET_ADMIN
+      - NET_RAW
+      - SYS_MODULE
+    sysctls:
+      - net.ipv4.ip_forward=1
+      - net.ipv4.conf.all.src_valid_mark=1
+      - net.ipv6.conf.all.disable_ipv6=0
+      - net.ipv6.conf.all.forwarding=1
+    restart: always
+    volumes:
+      - dnsconfig:/root/config/dnsconfig
+      - sqldata:/root/data
+      - shared_certs:/etc/netmaker
+    environment:
+      SERVER_NAME: "broker.NETMAKER_BASE_DOMAIN"
+      SERVER_HOST: "SERVER_PUBLIC_IP"
+      SERVER_API_CONN_STRING: "api.NETMAKER_BASE_DOMAIN:443"
+      COREDNS_ADDR: "SERVER_PUBLIC_IP"
+      DNS_MODE: "on"
+      SERVER_HTTP_HOST: "api.NETMAKER_BASE_DOMAIN"
+      API_PORT: "8081"
+      CLIENT_MODE: "on"
+      MASTER_KEY: "REPLACE_MASTER_KEY"
+      CORS_ALLOWED_ORIGIN: "*"
+      DISPLAY_KEYS: "on"
+      DATABASE: "sqlite"
+      NODE_ID: "netmaker-server-1"
+      MQ_HOST: "mq"
+      # uncomment once netmaker supports changing MQ port
+      MQ_PORT: "443"
+      HOST_NETWORK: "off"
+      VERBOSITY: "1"
+      MANAGE_IPTABLES: "on"
+      PORT_FORWARD_SERVICES: "dns"
+    ports:
+      - "51821-51830:51821-51830/udp"
+    expose:
+      - "8081"
+    labels:
+      - traefik.enable=true
+      - traefik.http.routers.netmaker-api.entrypoints=websecure
+      - traefik.http.routers.netmaker-api.rule=Host(`api.NETMAKER_BASE_DOMAIN`)
+      - traefik.http.routers.netmaker-api.service=netmaker-api
+      - traefik.http.services.netmaker-api.loadbalancer.server.port=8081
+  netmaker-ui:
+    container_name: netmaker-ui
+    image: gravitl/netmaker-ui:v0.14.2
+    depends_on:
+      - netmaker
+    links:
+      - "netmaker:api"
+    restart: always
+    environment:
+      BACKEND_URL: "https://api.NETMAKER_BASE_DOMAIN"
+    expose:
+      - "80"
+    labels:
+      - traefik.enable=true
+      - traefik.http.middlewares.nmui-security.headers.accessControlAllowOriginList=*.NETMAKER_BASE_DOMAIN
+      - traefik.http.middlewares.nmui-security.headers.stsSeconds=31536000
+      - traefik.http.middlewares.nmui-security.headers.browserXssFilter=true
+      - traefik.http.middlewares.nmui-security.headers.customFrameOptionsValue=SAMEORIGIN
+      - traefik.http.middlewares.nmui-security.headers.customResponseHeaders.X-Robots-Tag=none
+      - traefik.http.middlewares.nmui-security.headers.customResponseHeaders.Server= # Remove the server name
+      - traefik.http.routers.netmaker-ui.entrypoints=websecure
+      - traefik.http.routers.netmaker-ui.middlewares=nmui-security@docker
+      - traefik.http.routers.netmaker-ui.rule=Host(`dashboard.NETMAKER_BASE_DOMAIN`)
+      - traefik.http.routers.netmaker-ui.service=netmaker-ui
+      - traefik.http.services.netmaker-ui.loadbalancer.server.port=80
+  coredns:
+    container_name: coredns
+    image: coredns/coredns
+    command: -conf /root/dnsconfig/Corefile
+    depends_on:
+      - netmaker
+    restart: always
+    volumes:
+      - dnsconfig:/root/dnsconfig
+  traefik:
+    image: traefik:v2.6
+    container_name: traefik
+    command:
+      - "--certificatesresolvers.http.acme.email=YOUR_EMAIL"
+      - "--certificatesresolvers.http.acme.storage=/letsencrypt/acme.json"
+      - "--certificatesresolvers.http.acme.tlschallenge=true"
+      - "--entrypoints.websecure.address=:443"
+      - "--entrypoints.websecure.http.tls=true"
+      - "--entrypoints.websecure.http.tls.certResolver=http"
+      - "--log.level=INFO"
+      - "--providers.docker=true"
+      - "--providers.docker.exposedByDefault=false"
+      - "--serverstransport.insecureskipverify=true"
+    restart: always
+    volumes:
+      - /var/run/docker.sock:/var/run/docker.sock:ro
+      - traefik_certs:/letsencrypt
+    ports:
+      - "443:443"
+  mq:
+    container_name: mq
+    image: eclipse-mosquitto:2.0.11-openssl
+    depends_on:
+      - netmaker
+    restart: unless-stopped
+    volumes:
+      - /root/mosquitto.conf:/mosquitto/config/mosquitto.conf
+      - mosquitto_data:/mosquitto/data
+      - mosquitto_logs:/mosquitto/log
+      - shared_certs:/mosquitto/certs
+    ports:
+      - "127.0.0.1:1883:1883"
+    # comment once netmaker supports changing MQ port
+    #  - "8883:8883"
+    # uncomment once netmaker supports changing MQ port
+    expose:
+      - "8883"
+    labels:
+      - traefik.enable=true
+      - traefik.tcp.routers.mqtts.rule=HostSNI(`broker.NETMAKER_BASE_DOMAIN`)
+      - traefik.tcp.routers.mqtts.tls.passthrough=true
+      - traefik.tcp.services.mqtts-svc.loadbalancer.server.port=8883
+      - traefik.tcp.routers.mqtts.service=mqtts-svc
+      - traefik.tcp.routers.mqtts.entrypoints=websecure
+volumes:
+  traefik_certs: {}
+  shared_certs: {}
+  sqldata: {}
+  dnsconfig: {}
+  mosquitto_data: {}
+  mosquitto_logs: {}

+ 2 - 2
compose/docker-compose.yml

@@ -3,7 +3,7 @@ version: "3.4"
 services:
 services:
   netmaker:
   netmaker:
     container_name: netmaker
     container_name: netmaker
-    image: gravitl/netmaker:v0.14.1
+    image: gravitl/netmaker:v0.14.2
     volumes:
     volumes:
       - dnsconfig:/root/config/dnsconfig
       - dnsconfig:/root/config/dnsconfig
       - sqldata:/root/data
       - sqldata:/root/data
@@ -43,7 +43,7 @@ services:
     container_name: netmaker-ui
     container_name: netmaker-ui
     depends_on:
     depends_on:
       - netmaker
       - netmaker
-    image: gravitl/netmaker-ui:v0.14.1
+    image: gravitl/netmaker-ui:v0.14.2
     links:
     links:
       - "netmaker:api"
       - "netmaker:api"
     environment:
     environment:

+ 1 - 0
config/config.go

@@ -66,6 +66,7 @@ type ServerConfig struct {
 	PortForwardServices   string `yaml:"portforwardservices"`
 	PortForwardServices   string `yaml:"portforwardservices"`
 	HostNetwork           string `yaml:"hostnetwork"`
 	HostNetwork           string `yaml:"hostnetwork"`
 	MQPort                string `yaml:"mqport"`
 	MQPort                string `yaml:"mqport"`
+	MQServerPort          string `yaml:"mqserverport"`
 	Server                string `yaml:"server"`
 	Server                string `yaml:"server"`
 }
 }
 
 

+ 1 - 0
controllers/config/dnsconfig/netmaker.hosts

@@ -1 +1,2 @@
+10.0.0.3         testnode3.skynet
 10.0.0.2         testnode.skynet myhost.skynet
 10.0.0.2         testnode.skynet myhost.skynet

+ 2 - 1
controllers/network_test.go

@@ -289,6 +289,7 @@ func TestIpv6Network(t *testing.T) {
 
 
 	database.InitializeDatabase()
 	database.InitializeDatabase()
 	os.Setenv("MASTER_KEY", "secretkey")
 	os.Setenv("MASTER_KEY", "secretkey")
+	deleteAllNetworks()
 	createNet()
 	createNet()
 	createNetDualStack()
 	createNetDualStack()
 	network, err := logic.GetNetwork("skynet6")
 	network, err := logic.GetNetwork("skynet6")
@@ -300,7 +301,7 @@ func TestIpv6Network(t *testing.T) {
 	nodeErr := logic.CreateNode(&node1)
 	nodeErr := logic.CreateNode(&node1)
 	t.Run("Test node on network IPv6", func(t *testing.T) {
 	t.Run("Test node on network IPv6", func(t *testing.T) {
 		assert.Nil(t, nodeErr)
 		assert.Nil(t, nodeErr)
-		assert.Equal(t, node1.Address6, "fde6:be04:fa5e:d076::1")
+		assert.Equal(t, "fde6:be04:fa5e:d076::", node1.Address6)
 	})
 	})
 }
 }
 
 

+ 6 - 4
controllers/node.go

@@ -373,8 +373,9 @@ func getNode(w http.ResponseWriter, r *http.Request) {
 	}
 	}
 
 
 	response := models.NodeGet{
 	response := models.NodeGet{
-		Node:  node,
-		Peers: peerUpdate.Peers,
+		Node:         node,
+		Peers:        peerUpdate.Peers,
+		ServerConfig: servercfg.GetServerInfo(),
 	}
 	}
 
 
 	logger.Log(2, r.Header.Get("user"), "fetched node", params["nodeid"])
 	logger.Log(2, r.Header.Get("user"), "fetched node", params["nodeid"])
@@ -492,8 +493,9 @@ func createNode(w http.ResponseWriter, r *http.Request) {
 	}
 	}
 
 
 	response := models.NodeGet{
 	response := models.NodeGet{
-		Node:  node,
-		Peers: peerUpdate.Peers,
+		Node:         node,
+		Peers:        peerUpdate.Peers,
+		ServerConfig: servercfg.GetServerInfo(),
 	}
 	}
 
 
 	logger.Log(1, r.Header.Get("user"), "created new node", node.Name, "on network", node.Network)
 	logger.Log(1, r.Header.Get("user"), "created new node", node.Name, "on network", node.Network)

+ 1 - 1
controllers/node_test.go

@@ -188,7 +188,7 @@ func TestNodeACLs(t *testing.T) {
 		currentACL.Save(acls.ContainerID(node1.Network))
 		currentACL.Save(acls.ContainerID(node1.Network))
 	})
 	})
 	t.Run("node acls correct after add new node not allowed", func(t *testing.T) {
 	t.Run("node acls correct after add new node not allowed", func(t *testing.T) {
-		node3 := models.Node{PublicKey: "DM5qhLAE20FG7BbfBCger+Ac9D2NDOwCtY1rbYDXv24=", Name: "testnode3", Endpoint: "10.0.0.100", MacAddress: "01:02:03:04:05:07", Password: "password", Network: "skynet", OS: "linux"}
+		node3 := models.Node{PublicKey: "this-is-not-valid", Name: "testnode3", Endpoint: "10.0.0.100", MacAddress: "01:02:03:04:05:07", Password: "password", Network: "skynet", OS: "linux"}
 		logic.CreateNode(&node3)
 		logic.CreateNode(&node3)
 		var currentACL, err = nodeacls.FetchAllACLs(nodeacls.NetworkID(node3.Network))
 		var currentACL, err = nodeacls.FetchAllACLs(nodeacls.NetworkID(node3.Network))
 		assert.Nil(t, err)
 		assert.Nil(t, err)

+ 13 - 19
controllers/server.go

@@ -23,6 +23,7 @@ func serverHandlers(r *mux.Router) {
 	r.HandleFunc("/api/server/getconfig", securityCheckServer(false, http.HandlerFunc(getConfig))).Methods("GET")
 	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/removenetwork/{network}", securityCheckServer(true, http.HandlerFunc(removeNetwork))).Methods("DELETE")
 	r.HandleFunc("/api/server/register", authorize(true, false, "node", http.HandlerFunc(register))).Methods("POST")
 	r.HandleFunc("/api/server/register", authorize(true, false, "node", http.HandlerFunc(register))).Methods("POST")
+	r.HandleFunc("/api/server/getserverinfo", authorize(true, false, "node", http.HandlerFunc(getServerInfo))).Methods("GET")
 }
 }
 
 
 //Security check is middleware for every function and just checks to make sure that its the master calling
 //Security check is middleware for every function and just checks to make sure that its the master calling
@@ -81,35 +82,26 @@ func removeNetwork(w http.ResponseWriter, r *http.Request) {
 	json.NewEncoder(w).Encode("Server removed from network " + params["network"])
 	json.NewEncoder(w).Encode("Server removed from network " + params["network"])
 }
 }
 
 
-func getConfig(w http.ResponseWriter, r *http.Request) {
+func getServerInfo(w http.ResponseWriter, r *http.Request) {
 	// Set header
 	// Set header
 	w.Header().Set("Content-Type", "application/json")
 	w.Header().Set("Content-Type", "application/json")
 
 
 	// get params
 	// get params
 
 
-	scfg := servercfg.GetServerConfig()
-	json.NewEncoder(w).Encode(scfg)
+	json.NewEncoder(w).Encode(servercfg.GetServerInfo())
 	//w.WriteHeader(http.StatusOK)
 	//w.WriteHeader(http.StatusOK)
 }
 }
 
 
-// func addNetwork(w http.ResponseWriter, r *http.Request) {
-// 	// Set header
-// 	w.Header().Set("Content-Type", "application/json")
-
-// 	// get params
-// 	var params = mux.Vars(r)
-// 	var networkName = params["network"]
-// 	var networkSettings, err := logic.GetNetwork(netwnetworkName)
-
-// 	success, err := serverctl.AddNetwork(params["network"])
+func getConfig(w http.ResponseWriter, r *http.Request) {
+	// Set header
+	w.Header().Set("Content-Type", "application/json")
 
 
-// 	if err != nil || !success {
-// 		json.NewEncoder(w).Encode("Could not add server to network " + params["network"])
-// 		return
-// 	}
+	// get params
 
 
-// 	json.NewEncoder(w).Encode("Server added to network " + params["network"])
-// }
+	scfg := servercfg.GetServerConfig()
+	json.NewEncoder(w).Encode(scfg)
+	//w.WriteHeader(http.StatusOK)
+}
 
 
 // register - registers a client with the server and return the CA and cert
 // register - registers a client with the server and return the CA and cert
 func register(w http.ResponseWriter, r *http.Request) {
 func register(w http.ResponseWriter, r *http.Request) {
@@ -141,6 +133,8 @@ func register(w http.ResponseWriter, r *http.Request) {
 		CAPubKey:   (ca.PublicKey).(ed25519.PublicKey),
 		CAPubKey:   (ca.PublicKey).(ed25519.PublicKey),
 		Cert:       *cert,
 		Cert:       *cert,
 		CertPubKey: (cert.PublicKey).(ed25519.PublicKey),
 		CertPubKey: (cert.PublicKey).(ed25519.PublicKey),
+		Broker:     servercfg.GetServer(),
+		Port:       servercfg.GetMQPort(),
 	}
 	}
 	w.WriteHeader(http.StatusOK)
 	w.WriteHeader(http.StatusOK)
 	json.NewEncoder(w).Encode(response)
 	json.NewEncoder(w).Encode(response)

+ 0 - 23
docker/Dockerfile-builder

@@ -1,23 +0,0 @@
-FROM alpine:3.15.2
-
-RUN apk add --no-cache --virtual .build-deps bash gcc musl-dev openssl go 
-
-RUN wget -O go.tgz https://go.dev/dl/go1.18.linux-amd64.tar.gz
-
-RUN tar -C /usr/local -xzf go.tgz 
-
-WORKDIR /usr/local/go/src
-
-RUN chmod +x make.bash
-
-RUN ./make.bash 
-
-ENV PATH="/usr/local/go/bin:$PATH"
-
-ENV GOPATH=/opt/go/ 
-
-ENV PATH=$PATH:$GOPATH/bin 
-
-RUN apk del .build-deps
-
-RUN apk add build-base

+ 0 - 36
docker/Dockerfile-full

@@ -1,36 +0,0 @@
-#first stage - builder
-
-FROM golang:latest as builder
-
-COPY . /app
-
-WORKDIR /app
-
-ENV GO111MODULE=auto
-
-RUN GOARCH=amd64 CGO_ENABLED=1 GOOS=linux go build -ldflags="-w -s" -o app main.go
-
-WORKDIR /app/netclient
-
-ENV GO111MODULE=auto
-
-RUN GOARCH=amd64 CGO_ENABLED=0 GOOS=linux go build -ldflags="-w -s" -o netclient main.go
-
-#second stage
-
-FROM debian:latest
-
-RUN apt-get update && apt-get -y install systemd procps
-
-WORKDIR /root/
-
-COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
-
-COPY --from=builder /app .
-COPY --from=builder /app/config config
-COPY --from=builder /app/netclient netclient
-
-EXPOSE 8081
-EXPOSE 50051
-
-CMD ["./app"]

+ 0 - 22
docker/Dockerfile-netclient

@@ -1,22 +0,0 @@
-FROM gravitl/builder:latest as builder
-# add glib support daemon manager
-WORKDIR /app
-
-COPY . .
-
-ENV GO111MODULE=auto
-
-RUN GOOS=linux GOARCH=amd64 CGO_ENABLED=0 /usr/local/go/bin/go build -ldflags="-w -s" -o netclient-app netclient/main.go
-
-FROM alpine:3.15.2
-
-RUN apk add gcompat iptables && mkdir -p /etc/netclient
-# set the working directory
-WORKDIR /root/
-
-COPY --from=builder /app/netclient-app /etc/netclient/netclient
-COPY --from=builder /app/scripts/netclient.sh .
-
-RUN chmod 0755 /etc/netclient/netclient && chmod 0755 netclient.sh
-
-ENTRYPOINT ["./netclient.sh"]

+ 1 - 1
docker/Dockerfile-netclient-doks

@@ -36,4 +36,4 @@ COPY --from=builder /app/netclient-app ./netclient
 COPY --from=builder /app/scripts/netclient.sh .
 COPY --from=builder /app/scripts/netclient.sh .
 RUN chmod 0755 netclient && chmod 0755 netclient.sh
 RUN chmod 0755 netclient && chmod 0755 netclient.sh
 
 
-ENTRYPOINT ["/bin/sh", "./netclient.sh"]
+ENTRYPOINT ["/bin/bash", "./netclient.sh"]

+ 1 - 1
docker/Dockerfile-netclient-doks-uspace

@@ -54,4 +54,4 @@ RUN chmod 0755 netclient && chmod 0755 netclient.sh
 
 
 ENV WG_QUICK_USERSPACE_IMPLEMENTATION=wireguard-go
 ENV WG_QUICK_USERSPACE_IMPLEMENTATION=wireguard-go
 
 
-ENTRYPOINT ["/bin/sh", "./netclient.sh"]
+ENTRYPOINT ["/bin/bash", "./netclient.sh"]

+ 0 - 39
docker/Dockerfile-netclient-full

@@ -1,39 +0,0 @@
-FROM gravitl/builder:latest as builder
-# add glib support daemon manager
-WORKDIR /app
-
-COPY . .
-
-ENV GO111MODULE=auto
-
-RUN GOOS=linux GOARCH=amd64 CGO_ENABLED=0 /usr/local/go/bin/go build -ldflags="-w -s" -o netclient-app netclient/main.go
-
-WORKDIR /root/
-
-RUN apk add --update git build-base libmnl-dev iptables
-
-RUN git clone https://git.zx2c4.com/wireguard-go && \
-    cd wireguard-go && \
-    make && \
-    make install
-
-ENV WITH_WGQUICK=yes
-RUN git clone https://git.zx2c4.com/wireguard-tools && \
-    cd wireguard-tools && \
-    cd src && \
-    make && \
-    make install
-
-FROM alpine:3.15.2
-
-WORKDIR /root/
-
-RUN apk add --no-cache --update bash libmnl gcompat iptables openresolv iproute2
-COPY --from=builder /usr/bin/wireguard-go /usr/bin/wg* /usr/bin/
-COPY --from=builder /app/netclient-app ./netclient
-COPY --from=builder /app/scripts/netclient.sh .
-RUN chmod 0755 netclient && chmod 0755 netclient.sh
-
-ENV WG_QUICK_USERSPACE_IMPLEMENTATION=wireguard-go
-
-ENTRYPOINT ["/bin/sh", "./netclient.sh"]

+ 0 - 39
docker/Dockerfile-netclient-kernel

@@ -1,39 +0,0 @@
-FROM debian:buster as builder
-# add glib support daemon manager
-
-RUN apt update -y && apt install -y wget bash gcc musl-dev openssl golang git build-essential libmnl-dev iptables
-
-RUN wget -O go.tgz https://go.dev/dl/go1.18.linux-amd64.tar.gz
-
-RUN tar -C /usr/local -xzf go.tgz
-
-WORKDIR /usr/local/go/src
-
-RUN chmod +x make.bash
-
-RUN ./make.bash
-
-ENV PATH="/usr/local/go/bin:$PATH"
-
-ENV GOPATH=/opt/go/
-
-ENV PATH=$PATH:$GOPATH/bin
-
-WORKDIR /app
-
-COPY . .
-
-ENV GO111MODULE=auto
-
-RUN GOOS=linux GOARCH=amd64 CGO_ENABLED=0 /usr/local/go/bin/go build -ldflags="-w -s" -o netclient-app netclient/main.go
-
-FROM debian:buster
-
-WORKDIR /root/
-
-RUN apt update -y && apt install -y bash curl wget traceroute procps dnsutils iptables openresolv iproute2
-COPY --from=builder /app/netclient-app ./netclient
-COPY --from=builder /app/scripts/netclient.sh .
-RUN chmod 0755 netclient && chmod 0755 netclient.sh
-
-ENTRYPOINT ["/bin/sh", "./netclient.sh"]

+ 1 - 1
docker/Dockerfile-netclient-multiarch

@@ -19,4 +19,4 @@ COPY --from=builder /app/scripts/netclient.sh .
 RUN chmod 0755 netclient && chmod 0755 netclient.sh
 RUN chmod 0755 netclient && chmod 0755 netclient.sh
 
 
 
 
-ENTRYPOINT ["/bin/sh", "./netclient.sh"]
+ENTRYPOINT ["/bin/bash", "./netclient.sh"]

+ 1 - 1
docker/Dockerfile-netclient-multiarch-go → docker/Dockerfile-netclient-multiarch-userspace

@@ -36,4 +36,4 @@ RUN chmod 0755 netclient && chmod 0755 netclient.sh
 
 
 ENV WG_QUICK_USERSPACE_IMPLEMENTATION=wireguard-go
 ENV WG_QUICK_USERSPACE_IMPLEMENTATION=wireguard-go
 
 
-ENTRYPOINT ["/bin/sh", "./netclient.sh"]
+ENTRYPOINT ["/bin/bash", "./netclient.sh"]

+ 0 - 26
docker/Dockerfile-netmaker-slim

@@ -1,26 +0,0 @@
-#first stage - builder
-FROM gravitl/builder as builder
-
-WORKDIR /app
-
-COPY . .
-
-ENV GO111MODULE=auto
-
-RUN GOOS=linux GOARCH=amd64 CGO_ENABLED=1 /usr/local/go/bin/go build -ldflags="-w -s" -o netmaker main.go
-
-FROM alpine:3.15.2
-# add a c lib
-RUN apk add gcompat iptables wireguard-tools
-# set the working directory
-WORKDIR /root/
-
-RUN mkdir -p /etc/netclient/config
-
-COPY --from=builder /app/netmaker .
-COPY --from=builder /app/config config
-
-EXPOSE 8081
-EXPOSE 50051
-
-ENTRYPOINT ["./netmaker"]

+ 0 - 26
docker/Dockerfile-userspace

@@ -1,26 +0,0 @@
-ARG NM_VERSION=
-
-FROM gravitl/builder as builder
-
-RUN apk add --update git build-base libmnl-dev iptables
-
-WORKDIR /root/
-RUN git clone https://git.zx2c4.com/wireguard-go && \
-    cd wireguard-go && \
-    make && \
-    make install
-
-ENV WITH_WGQUICK=yes
-RUN git clone https://git.zx2c4.com/wireguard-tools && \
-    cd wireguard-tools && \
-    cd src && \
-    make && \
-    make install
-
-FROM gravitl/netmaker:${NM_VERSION}
-
-RUN apk add --no-cache --update bash libmnl iptables openresolv iproute2
-COPY --from=builder /usr/bin/wireguard-go /usr/bin/wg* /usr/bin/
-COPY scripts/netclient.sh ./entrypoint.sh
-
-ENTRYPOINT ["/bin/sh", "./entrypoint.sh"]

+ 5 - 6
go.mod

@@ -16,7 +16,7 @@ require (
 	github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e
 	github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e
 	github.com/stretchr/testify v1.7.1
 	github.com/stretchr/testify v1.7.1
 	github.com/txn2/txeh v1.3.0
 	github.com/txn2/txeh v1.3.0
-	github.com/urfave/cli/v2 v2.8.0
+	github.com/urfave/cli/v2 v2.8.1
 	golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd
 	golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd
 	golang.org/x/net v0.0.0-20220225172249-27dd8689420f // indirect
 	golang.org/x/net v0.0.0-20220225172249-27dd8689420f // indirect
 	golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d
 	golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d
@@ -25,24 +25,23 @@ require (
 	golang.zx2c4.com/wireguard v0.0.0-20220318042302-193cf8d6a5d6 // indirect
 	golang.zx2c4.com/wireguard v0.0.0-20220318042302-193cf8d6a5d6 // indirect
 	golang.zx2c4.com/wireguard/wgctrl v0.0.0-20220324164955-056925b7df31
 	golang.zx2c4.com/wireguard/wgctrl v0.0.0-20220324164955-056925b7df31
 	google.golang.org/protobuf v1.28.0 // indirect
 	google.golang.org/protobuf v1.28.0 // indirect
-	gopkg.in/ini.v1 v1.66.4
+	gopkg.in/ini.v1 v1.66.6
 	gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
 	gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
 )
 )
 
 
 require (
 require (
-	filippo.io/edwards25519 v1.0.0-rc.1
+	filippo.io/edwards25519 v1.0.0
 	fyne.io/fyne/v2 v2.1.4
 	fyne.io/fyne/v2 v2.1.4
+	github.com/c-robinson/iplib v1.0.3
 	github.com/cloverstd/tcping v0.1.1
 	github.com/cloverstd/tcping v0.1.1
 	github.com/guumaster/hostctl v1.1.2
 	github.com/guumaster/hostctl v1.1.2
 	github.com/kr/pretty v0.3.0
 	github.com/kr/pretty v0.3.0
 	github.com/posthog/posthog-go v0.0.0-20211028072449-93c17c49e2b0
 	github.com/posthog/posthog-go v0.0.0-20211028072449-93c17c49e2b0
-	github.com/seancfoley/ipaddress-go v1.1.2
 )
 )
 
 
 require (
 require (
 	cloud.google.com/go v0.34.0 // indirect
 	cloud.google.com/go v0.34.0 // indirect
 	github.com/Microsoft/go-winio v0.4.14 // indirect
 	github.com/Microsoft/go-winio v0.4.14 // indirect
-	github.com/antzucaro/matchr v0.0.0-20210222213004-b04723ef80f0 // indirect
 	github.com/cpuguy83/go-md2man/v2 v2.0.1 // indirect
 	github.com/cpuguy83/go-md2man/v2 v2.0.1 // indirect
 	github.com/davecgh/go-spew v1.1.1 // indirect
 	github.com/davecgh/go-spew v1.1.1 // indirect
 	github.com/docker/distribution v2.7.1+incompatible // indirect
 	github.com/docker/distribution v2.7.1+incompatible // indirect
@@ -73,10 +72,10 @@ require (
 	github.com/pmezard/go-difflib v1.0.0 // indirect
 	github.com/pmezard/go-difflib v1.0.0 // indirect
 	github.com/rogpeppe/go-internal v1.8.0 // indirect
 	github.com/rogpeppe/go-internal v1.8.0 // indirect
 	github.com/russross/blackfriday/v2 v2.1.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/spf13/afero v1.3.2 // indirect
 	github.com/srwiley/oksvg v0.0.0-20200311192757-870daf9aa564 // indirect
 	github.com/srwiley/oksvg v0.0.0-20200311192757-870daf9aa564 // indirect
 	github.com/srwiley/rasterx v0.0.0-20200120212402-85cb7272f5e9 // indirect
 	github.com/srwiley/rasterx v0.0.0-20200120212402-85cb7272f5e9 // indirect
+	github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
 	github.com/xtgo/uuid v0.0.0-20140804021211-a0b114877d4c // indirect
 	github.com/xtgo/uuid v0.0.0-20140804021211-a0b114877d4c // indirect
 	github.com/yuin/goldmark v1.3.8 // indirect
 	github.com/yuin/goldmark v1.3.8 // indirect
 	golang.org/x/image v0.0.0-20200430140353-33d19683fad8 // indirect
 	golang.org/x/image v0.0.0-20200430140353-33d19683fad8 // indirect

+ 10 - 12
go.sum

@@ -1,8 +1,8 @@
 cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
 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 h1:eOI3/cP2VTU6uZLDYAoic+eyzzB9YyGmJ7eIjl8rOPg=
 cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
 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=
+filippo.io/edwards25519 v1.0.0 h1:0wAIcmJUqRdI8IJ/3eGi5/HwXZWPujYXXlkrQogz0Ek=
+filippo.io/edwards25519 v1.0.0/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns=
 fyne.io/fyne/v2 v2.1.4 h1:bt1+28++kAzRzPB0GM2EuSV4cnl8rXNX4cjfd8G06Rc=
 fyne.io/fyne/v2 v2.1.4 h1:bt1+28++kAzRzPB0GM2EuSV4cnl8rXNX4cjfd8G06Rc=
 fyne.io/fyne/v2 v2.1.4/go.mod h1:p+E/Dh+wPW8JwR2DVcsZ9iXgR9ZKde80+Y+40Is54AQ=
 fyne.io/fyne/v2 v2.1.4/go.mod h1:p+E/Dh+wPW8JwR2DVcsZ9iXgR9ZKde80+Y+40Is54AQ=
 github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
 github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
@@ -14,11 +14,11 @@ github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAE
 github.com/akavel/rsrc v0.8.0/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkKq+c=
 github.com/akavel/rsrc v0.8.0/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkKq+c=
 github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
 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/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
-github.com/antzucaro/matchr v0.0.0-20210222213004-b04723ef80f0 h1:R/qAiUxFT3mNgQaNqJe0IVznjKRNm23ohAIh9lgtlzc=
-github.com/antzucaro/matchr v0.0.0-20210222213004-b04723ef80f0/go.mod h1:v3ZDlfVAL1OrkKHbGSFFK60k0/7hruHPDq2XMs9Gu6U=
 github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
 github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
 github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
 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/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
+github.com/c-robinson/iplib v1.0.3 h1:NG0UF0GoEsrC1/vyfX1Lx2Ss7CySWl3KqqXh3q4DdPU=
+github.com/c-robinson/iplib v1.0.3/go.mod h1:i3LuuFL1hRT5gFpBRnEydzw8R6yhGkF4szNDIbF8pgo=
 github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
 github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
 github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
 github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
 github.com/cloverstd/tcping v0.1.1 h1:3Yp9nvSDI7Z63zoVQDJzVk1PUczrF9tJoOrKGV30iOk=
 github.com/cloverstd/tcping v0.1.1 h1:3Yp9nvSDI7Z63zoVQDJzVk1PUczrF9tJoOrKGV30iOk=
@@ -200,10 +200,6 @@ 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.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 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
 github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
 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/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.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
 github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
 github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
@@ -242,10 +238,12 @@ github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGr
 github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
 github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
 github.com/urfave/cli v1.22.5/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
 github.com/urfave/cli v1.22.5/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
 github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI=
 github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI=
-github.com/urfave/cli/v2 v2.8.0 h1:EZsAB20oRW4nHcB99TTL6PrXpBGIEujMEKdjwruY9KQ=
-github.com/urfave/cli/v2 v2.8.0/go.mod h1:TYFbtzt/azQoJOrGH5mDfZtS0jIkl/OeFwlRWPR9KRM=
+github.com/urfave/cli/v2 v2.8.1 h1:CGuYNZF9IKZY/rfBe3lJpccSoIY1ytfvmgQT90cNOl4=
+github.com/urfave/cli/v2 v2.8.1/go.mod h1:Z41J9TPoffeoqP0Iza0YbAhGvymRdZAd2uPmZ5JxRdY=
 github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
 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/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
+github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU=
+github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8=
 github.com/xtgo/uuid v0.0.0-20140804021211-a0b114877d4c h1:3lbZUMbMiGUW/LMkfsEABsc5zNT9+b1CvsJx47JzJ8g=
 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=
 github.com/xtgo/uuid v0.0.0-20140804021211-a0b114877d4c/go.mod h1:UrdRz5enIKZ63MEE3IF9l2/ebyx59GyGgPi+tICQdmM=
 github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
 github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
@@ -372,8 +370,8 @@ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntN
 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
 gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
 gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
 gopkg.in/gookit/color.v1 v1.1.6/go.mod h1:IcEkFGaveVShJ+j8ew+jwe9epHyGpJ9IrptHmW3laVY=
 gopkg.in/gookit/color.v1 v1.1.6/go.mod h1:IcEkFGaveVShJ+j8ew+jwe9epHyGpJ9IrptHmW3laVY=
-gopkg.in/ini.v1 v1.66.4 h1:SsAcf+mM7mRZo2nJNGt8mZCjG8ZRaNGMURJw7BsIST4=
-gopkg.in/ini.v1 v1.66.4/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
+gopkg.in/ini.v1 v1.66.6 h1:LATuAqN/shcYAOkv3wl2L4rkaKqkcgTBQjOyYDvcPKI=
+gopkg.in/ini.v1 v1.66.6/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
 gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
 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.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.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

+ 14 - 12
logger/logger.go

@@ -16,7 +16,7 @@ const TimeFormatDay = "2006-01-02"
 const TimeFormat = "2006-01-02 15:04:05"
 const TimeFormat = "2006-01-02 15:04:05"
 
 
 // == fields ==
 // == fields ==
-var currentLogs = make(map[string]string)
+var currentLogs = make(map[string]entry)
 var mu sync.Mutex
 var mu sync.Mutex
 var program string
 var program string
 
 
@@ -38,7 +38,10 @@ func Log(verbosity int, message ...string) {
 		fmt.Printf("[%s] %s %s \n", program, currentTime.Format(TimeFormat), currentMessage)
 		fmt.Printf("[%s] %s %s \n", program, currentTime.Format(TimeFormat), currentMessage)
 	}
 	}
 	if program == "netmaker" {
 	if program == "netmaker" {
-		currentLogs[currentMessage] = currentTime.Format("2006-01-02 15:04:05.999999999")
+		currentLogs[currentMessage] = entry{
+			Time:  currentTime.Format("2006-01-02 15:04:05.999999999"),
+			Count: currentLogs[currentMessage].Count + 1,
+		}
 	}
 	}
 }
 }
 
 
@@ -47,21 +50,23 @@ func Dump() string {
 	if program != "netmaker" {
 	if program != "netmaker" {
 		return ""
 		return ""
 	}
 	}
+	mu.Lock()
+	defer mu.Unlock()
 	var dumpString = ""
 	var dumpString = ""
 	type keyVal struct {
 	type keyVal struct {
 		Key   string
 		Key   string
 		Value time.Time
 		Value time.Time
+		Count int
 	}
 	}
-	var mu sync.Mutex
-	mu.Lock()
-	defer mu.Unlock()
 	var dumpLogs = make([]keyVal, 0, len(currentLogs))
 	var dumpLogs = make([]keyVal, 0, len(currentLogs))
-	for key, value := range currentLogs {
-		parsedTime, err := time.Parse(TimeFormat, value)
+	for key := range currentLogs {
+		currentEntry := currentLogs[key]
+		parsedTime, err := time.Parse(TimeFormat, currentEntry.Time)
 		if err == nil {
 		if err == nil {
 			dumpLogs = append(dumpLogs, keyVal{
 			dumpLogs = append(dumpLogs, keyVal{
 				Key:   key,
 				Key:   key,
 				Value: parsedTime,
 				Value: parsedTime,
+				Count: currentEntry.Count,
 			})
 			})
 		}
 		}
 	}
 	}
@@ -71,7 +76,7 @@ func Dump() string {
 
 
 	for i := range dumpLogs {
 	for i := range dumpLogs {
 		var currLog = dumpLogs[i]
 		var currLog = dumpLogs[i]
-		dumpString += MakeString(" ", "[netmaker]", currLog.Value.Format(TimeFormat), currLog.Key, "\n")
+		dumpString += MakeString(" ", "[netmaker]", currLog.Value.Format(TimeFormat), currLog.Key, fmt.Sprintf("(%d)", currLog.Count), "\n")
 	}
 	}
 
 
 	resetLogs()
 	resetLogs()
@@ -107,9 +112,6 @@ func Retrieve(filePath string) string {
 
 
 // FatalLog - exits os after logging
 // FatalLog - exits os after logging
 func FatalLog(message ...string) {
 func FatalLog(message ...string) {
-	var mu sync.Mutex
-	mu.Lock()
-	defer mu.Unlock()
 	fmt.Printf("[netmaker] Fatal: %s \n", MakeString(" ", message...))
 	fmt.Printf("[netmaker] Fatal: %s \n", MakeString(" ", message...))
 	os.Exit(2)
 	os.Exit(2)
 }
 }
@@ -118,5 +120,5 @@ func FatalLog(message ...string) {
 
 
 // resetLogs - reallocates logs map
 // resetLogs - reallocates logs map
 func resetLogs() {
 func resetLogs() {
-	currentLogs = make(map[string]string)
+	currentLogs = make(map[string]entry)
 }
 }

+ 6 - 0
logger/types.go

@@ -0,0 +1,6 @@
+package logger
+
+type entry struct {
+	Time  string
+	Count int
+}

+ 2 - 6
logic/accesskeys.go

@@ -52,12 +52,8 @@ func CreateAccessKey(accesskey models.AccessKey, network models.Network) (models
 	netID := network.NetID
 	netID := network.NetID
 
 
 	var accessToken models.AccessToken
 	var accessToken models.AccessToken
-	s := servercfg.GetServerConfig()
-	servervals := models.ServerConfig{
-		Server:        s.Server,
-		APIConnString: s.APIConnString,
-	}
-	accessToken.ServerConfig = servervals
+
+	accessToken.APIConnString = servercfg.GetAPIConnString()
 	accessToken.ClientConfig.Network = netID
 	accessToken.ClientConfig.Network = netID
 	accessToken.ClientConfig.Key = accesskey.Value
 	accessToken.ClientConfig.Key = accesskey.Value
 	accessToken.ClientConfig.LocalRange = privAddr
 	accessToken.ClientConfig.LocalRange = privAddr

+ 0 - 62
logic/ips/ips.go

@@ -1,62 +0,0 @@
-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
-}

+ 0 - 50
logic/ips/ips_test.go

@@ -1,50 +0,0 @@
-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")
-	})
-}

+ 36 - 32
logic/networks.go

@@ -8,11 +8,11 @@ import (
 	"os/exec"
 	"os/exec"
 	"strings"
 	"strings"
 
 
+	"github.com/c-robinson/iplib"
 	"github.com/go-playground/validator/v10"
 	"github.com/go-playground/validator/v10"
 	"github.com/gravitl/netmaker/database"
 	"github.com/gravitl/netmaker/database"
 	"github.com/gravitl/netmaker/logger"
 	"github.com/gravitl/netmaker/logger"
 	"github.com/gravitl/netmaker/logic/acls/nodeacls"
 	"github.com/gravitl/netmaker/logic/acls/nodeacls"
-	"github.com/gravitl/netmaker/logic/ips"
 	"github.com/gravitl/netmaker/models"
 	"github.com/gravitl/netmaker/models"
 	"github.com/gravitl/netmaker/netclient/ncutils"
 	"github.com/gravitl/netmaker/netclient/ncutils"
 	"github.com/gravitl/netmaker/validation"
 	"github.com/gravitl/netmaker/validation"
@@ -185,29 +185,30 @@ func UniqueAddress(networkName string, reverse bool) (string, error) {
 	if network.IsIPv4 == "no" {
 	if network.IsIPv4 == "no" {
 		return "", fmt.Errorf("IPv4 not active on network " + networkName)
 		return "", fmt.Errorf("IPv4 not active on network " + networkName)
 	}
 	}
-
-	newAddr, err := ips.GetFirstAddr(network.AddressRange)
-	if err != nil {
+	//ensure AddressRange is valid
+	if _, _, err := net.ParseCIDR(network.AddressRange); err != nil {
 		logger.Log(0, "UniqueAddress encountered  an error")
 		logger.Log(0, "UniqueAddress encountered  an error")
 		return "666", err
 		return "666", err
 	}
 	}
+	net4 := iplib.Net4FromStr(network.AddressRange)
+	newAddrs := net4.FirstAddress()
 
 
-	incVal := 1
 	if reverse {
 	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
-			}
-		}
+		newAddrs = net4.LastAddress()
 	}
 	}
 
 
-	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
+	for {
+		if IsIPUnique(networkName, newAddrs.String(), database.NODES_TABLE_NAME, false) &&
+			IsIPUnique(networkName, newAddrs.String(), database.EXT_CLIENT_TABLE_NAME, false) {
+			return newAddrs.String(), nil
+		}
+		if reverse {
+			newAddrs, err = net4.PreviousIP(newAddrs)
+		} else {
+			newAddrs, err = net4.NextIP(newAddrs)
+		}
+		if err != nil {
+			break
 		}
 		}
 	}
 	}
 
 
@@ -256,27 +257,30 @@ func UniqueAddress6(networkName string, reverse bool) (string, error) {
 		return "", fmt.Errorf("IPv6 not active on network " + networkName)
 		return "", fmt.Errorf("IPv6 not active on network " + networkName)
 	}
 	}
 
 
-	newAddr6, err := ips.GetFirstAddr6(network.AddressRange6)
-	if err != nil {
+	//ensure AddressRange is valid
+	if _, _, err := net.ParseCIDR(network.AddressRange6); err != nil {
 		return "666", err
 		return "666", err
 	}
 	}
+	net6 := iplib.Net6FromStr(network.AddressRange6)
+	newAddrs := net6.FirstAddress()
 
 
-	incVal := 1
 	if reverse {
 	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
-			}
-		}
+		newAddrs = net6.LastAddress()
 	}
 	}
 
 
-	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
+	for {
+
+		if IsIPUnique(networkName, newAddrs.String(), database.NODES_TABLE_NAME, true) &&
+			IsIPUnique(networkName, newAddrs.String(), database.EXT_CLIENT_TABLE_NAME, true) {
+			return newAddrs.String(), nil
+		}
+		if reverse {
+			newAddrs, err = net6.PreviousIP(newAddrs)
+		} else {
+			newAddrs, err = net6.NextIP(newAddrs)
+		}
+		if err != nil {
+			break
 		}
 		}
 	}
 	}
 
 

+ 2 - 6
logic/nodes.go

@@ -220,16 +220,12 @@ func IsNodeIDUnique(node *models.Node) (bool, error) {
 // ValidateNode - validates node values
 // ValidateNode - validates node values
 func ValidateNode(node *models.Node, isUpdate bool) error {
 func ValidateNode(node *models.Node, isUpdate bool) error {
 	v := validator.New()
 	v := validator.New()
-	_ = v.RegisterValidation("macaddress_unique", func(fl validator.FieldLevel) bool {
+	_ = v.RegisterValidation("id_unique", func(fl validator.FieldLevel) bool {
 		if isUpdate {
 		if isUpdate {
 			return true
 			return true
 		}
 		}
-		var unique = true
-		if !(node.MacAddress == "") {
-			unique, _ = isMacAddressUnique(node.MacAddress, node.Network)
-		}
 		isFieldUnique, _ := IsNodeIDUnique(node)
 		isFieldUnique, _ := IsNodeIDUnique(node)
-		return isFieldUnique && unique
+		return isFieldUnique
 	})
 	})
 	_ = v.RegisterValidation("network_exists", func(fl validator.FieldLevel) bool {
 	_ = v.RegisterValidation("network_exists", func(fl validator.FieldLevel) bool {
 		_, err := GetNetworkByNode(node)
 		_, err := GetNetworkByNode(node)

+ 92 - 51
logic/peers.go

@@ -8,83 +8,110 @@ import (
 	"strings"
 	"strings"
 	"time"
 	"time"
 
 
+	"github.com/c-robinson/iplib"
 	"github.com/gravitl/netmaker/database"
 	"github.com/gravitl/netmaker/database"
 	"github.com/gravitl/netmaker/logger"
 	"github.com/gravitl/netmaker/logger"
 	"github.com/gravitl/netmaker/logic/acls"
 	"github.com/gravitl/netmaker/logic/acls"
 	"github.com/gravitl/netmaker/logic/acls/nodeacls"
 	"github.com/gravitl/netmaker/logic/acls/nodeacls"
 	"github.com/gravitl/netmaker/models"
 	"github.com/gravitl/netmaker/models"
-	"github.com/seancfoley/ipaddress-go/ipaddr"
+	"github.com/gravitl/netmaker/servercfg"
 	"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
 	"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
 )
 )
 
 
-// GetHubPeer - in HubAndSpoke networks, if not the hub, return the hub
-/*
-func GetHubPeer(networkName string) []models.Node {
-	var hubpeer = make([]models.Node, 0)
-	servernodes, err := GetNetworkNodes(networkName)
-	if err != nil {
-		return hubpeer
-	}
-	for i := range servernodes {
-		if servernodes[i].IsHub == "yes" {
-			return []models.Node{servernodes[i]}
-		}
-	}
-	return hubpeer
-}
-*/
-
 // GetNodePeers - fetches peers for a given node
 // GetNodePeers - fetches peers for a given node
 func GetNodePeers(network *models.Network, 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 peers []models.Node
+
+	// networkNodes = all nodes in network
+	// egressNetworkNodes = all egress gateways in network
 	var networkNodes, egressNetworkNodes, err = getNetworkEgressAndNodes(network.NetID)
 	var networkNodes, egressNetworkNodes, err = getNetworkEgressAndNodes(network.NetID)
 	if err != nil {
 	if err != nil {
 		return peers, nil
 		return peers, nil
 	}
 	}
 
 
+	// udppeers = the peers parsed from the local interface
+	// gives us correct port to reach
 	udppeers, errN := database.GetPeers(network.NetID)
 	udppeers, errN := database.GetPeers(network.NetID)
 	if errN != nil {
 	if errN != nil {
 		logger.Log(2, errN.Error())
 		logger.Log(2, errN.Error())
 	}
 	}
 
 
+	// gets all the ACL rules
 	currentNetworkACLs, aclErr := nodeacls.FetchAllACLs(nodeacls.NetworkID(network.NetID))
 	currentNetworkACLs, aclErr := nodeacls.FetchAllACLs(nodeacls.NetworkID(network.NetID))
 	if aclErr != nil {
 	if aclErr != nil {
 		return peers, aclErr
 		return peers, aclErr
 	}
 	}
 
 
+	/*
+		at this point we have 4 lists of node information:
+		- networkNodes: all nodes in network (models.Node)
+		- egressNetworkNodes: all egress gateways in network (models.Node)
+		- udppeers: all peers in database (parsed by server off of active WireGuard interface)
+		- currentNetworkACLs: all ACL rules associated with the network
+		- peers: a currently empty list that will be filled and returned
+
+	*/
+
+	// we now parse through all networkNodes and format properly to set as "peers"
 	for _, node := range networkNodes {
 	for _, node := range networkNodes {
+
+		// skip over any node that is disallowed by ACL rules
 		if !currentNetworkACLs.IsAllowed(acls.AclID(nodeid), acls.AclID(node.ID)) {
 		if !currentNetworkACLs.IsAllowed(acls.AclID(nodeid), acls.AclID(node.ID)) {
 			continue
 			continue
 		}
 		}
 
 
+		// create an empty model to fill with peer info
 		var peer = models.Node{}
 		var peer = models.Node{}
+
+		// set egress gateway information if it's an egress gateway
 		if node.IsEgressGateway == "yes" { // handle egress stuff
 		if node.IsEgressGateway == "yes" { // handle egress stuff
 			peer.EgressGatewayRanges = node.EgressGatewayRanges
 			peer.EgressGatewayRanges = node.EgressGatewayRanges
 			peer.IsEgressGateway = node.IsEgressGateway
 			peer.IsEgressGateway = node.IsEgressGateway
 		}
 		}
 
 
+		// set ingress gateway information
 		peer.IsIngressGateway = node.IsIngressGateway
 		peer.IsIngressGateway = node.IsIngressGateway
+
+		/*
+			- similar to ACLs, we must determine if peer is allowed based on Relay information
+			- if the nodes is "not relayed" (not behind a relay), it is ok
+			- if the node IS relayed, but excludeRelay has not been marked, it is ok
+			- excludeRelayed is marked for any node that is NOT a Relay Server
+			- therefore, the peer is allowed as long as it is not "relayed", or the node it is being sent to is its relay server
+		*/
 		allow := node.IsRelayed != "yes" || !excludeRelayed
 		allow := node.IsRelayed != "yes" || !excludeRelayed
 
 
+		// confirm conditions allow node to be added as peer
+		// node should be in same network, not pending, and "allowed" based on above logic
 		if node.Network == network.NetID && node.IsPending != "yes" && allow {
 		if node.Network == network.NetID && node.IsPending != "yes" && allow {
+
+			// node info is cleansed to remove sensitive info using setPeerInfo
 			peer = setPeerInfo(&node)
 			peer = setPeerInfo(&node)
+
+			// Sets ListenPort to UDP Hole Punching Port assuming:
+			// - UDP Hole Punching is enabled
+			// - udppeers retrieval did not return an error
+			// - the endpoint is valid
 			if node.UDPHolePunch == "yes" && errN == nil && CheckEndpoint(udppeers[node.PublicKey]) {
 			if node.UDPHolePunch == "yes" && errN == nil && CheckEndpoint(udppeers[node.PublicKey]) {
 				endpointstring := udppeers[node.PublicKey]
 				endpointstring := udppeers[node.PublicKey]
 				endpointarr := strings.Split(endpointstring, ":")
 				endpointarr := strings.Split(endpointstring, ":")
 				if len(endpointarr) == 2 {
 				if len(endpointarr) == 2 {
 					port, err := strconv.Atoi(endpointarr[1])
 					port, err := strconv.Atoi(endpointarr[1])
 					if err == nil {
 					if err == nil {
-						// peer.Endpoint = endpointarr[0]
 						peer.ListenPort = int32(port)
 						peer.ListenPort = int32(port)
 					}
 					}
 				}
 				}
 			}
 			}
-			// if udp hole punching is on, but port is still set to default (e.g. 51821), use the LocalListenPort
-			// removing IsStatic check. IsStatic will now ONLY refer to endpoint.
-			//if node.UDPHolePunch == "yes" && node.IsStatic != "yes" && peer.ListenPort == node.ListenPort {
-			if node.UDPHolePunch == "yes" && peer.ListenPort == node.ListenPort {
+
+			// if udp hole punching is on, but the node's port is still set to default (e.g. 51821), use the LocalListenPort
+			// or, if port is for some reason zero use the LocalListenPort
+			// but only do this if LocalListenPort is not zero
+			if node.UDPHolePunch == "yes" &&
+				((peer.ListenPort == node.ListenPort || peer.ListenPort == 0) && node.LocalListenPort != 0) {
 				peer.ListenPort = node.LocalListenPort
 				peer.ListenPort = node.LocalListenPort
 			}
 			}
+
+			// if the node is a relay, append the network cidr and any relayed egress ranges
 			if node.IsRelay == "yes" { // TODO, check if addressrange6 needs to be appended
 			if node.IsRelay == "yes" { // TODO, check if addressrange6 needs to be appended
 				peer.AllowedIPs = append(peer.AllowedIPs, network.AddressRange)
 				peer.AllowedIPs = append(peer.AllowedIPs, network.AddressRange)
 				for _, egressNode := range egressNetworkNodes {
 				for _, egressNode := range egressNetworkNodes {
@@ -93,6 +120,8 @@ func GetNodePeers(network *models.Network, nodeid string, excludeRelayed bool, i
 					}
 					}
 				}
 				}
 			}
 			}
+
+			// if the node is an ingress gateway, append all the extclient allowedips
 			if peer.IsIngressGateway == "yes" { // handle ingress stuff
 			if peer.IsIngressGateway == "yes" { // handle ingress stuff
 				if currentExtClients, err := GetExtPeersList(&node); err == nil {
 				if currentExtClients, err := GetExtPeersList(&node); err == nil {
 					for i := range currentExtClients {
 					for i := range currentExtClients {
@@ -106,6 +135,7 @@ func GetNodePeers(network *models.Network, nodeid string, excludeRelayed bool, i
 				}
 				}
 			}
 			}
 
 
+			// dont appent if this isn't a p2p network or if ACLs disallow
 			if (!isP2S || peer.IsHub == "yes") && currentNetworkACLs.IsAllowed(acls.AclID(nodeid), acls.AclID(node.ID)) {
 			if (!isP2S || peer.IsHub == "yes") && currentNetworkACLs.IsAllowed(acls.AclID(nodeid), acls.AclID(node.ID)) {
 				peers = append(peers, peer)
 				peers = append(peers, peer)
 			}
 			}
@@ -133,30 +163,39 @@ func GetPeersList(refnode *models.Node) ([]models.Node, error) {
 	} else if network.IsPointToSite == "yes" && refnode.IsHub != "yes" {
 	} else if network.IsPointToSite == "yes" && refnode.IsHub != "yes" {
 		isP2S = true
 		isP2S = true
 	}
 	}
-	if relayedNodeAddr == "" {
+	if refnode.IsRelayed != "yes" {
+		// if the node is not being relayed, retrieve peers as normal
 		peers, err = GetNodePeers(&network, refnode.ID, excludeRelayed, isP2S)
 		peers, err = GetNodePeers(&network, refnode.ID, excludeRelayed, isP2S)
 	} else {
 	} else {
 		var relayNode models.Node
 		var relayNode models.Node
+		// If this node IS being relayed node, we must first retrieve its relay
 		relayNode, err = GetNodeRelay(networkName, relayedNodeAddr)
 		relayNode, err = GetNodeRelay(networkName, relayedNodeAddr)
-		if relayNode.Address != "" {
+		if relayNode.Address != "" && err == nil {
+			// we must cleanse sensitive info from the relay node
 			var peerNode = setPeerInfo(&relayNode)
 			var peerNode = setPeerInfo(&relayNode)
-			network, err := GetNetwork(networkName)
-			if err == nil { // TODO: check if addressrange6 needs to be appended
-				peerNode.AllowedIPs = append(peerNode.AllowedIPs, network.AddressRange)
-				var _, egressNetworkNodes, err = getNetworkEgressAndNodes(networkName)
-				if err == nil {
-					for _, egress := range egressNetworkNodes {
-						if egress.Address != relayedNodeAddr {
-							peerNode.AllowedIPs = append(peerNode.AllowedIPs, egress.EgressGatewayRanges...)
-						}
+
+			// we must append the CIDR to the relay so the relayed node can reach the network
+			peerNode.AllowedIPs = append(peerNode.AllowedIPs, network.AddressRange)
+
+			// we must append the egress ranges to the relay so the relayed node can reach egress
+			var _, egressNetworkNodes, err = getNetworkEgressAndNodes(networkName)
+			if err == nil {
+				for _, egress := range egressNetworkNodes {
+					if egress.Address != relayedNodeAddr {
+						peerNode.AllowedIPs = append(peerNode.AllowedIPs, egress.EgressGatewayRanges...)
 					}
 					}
 				}
 				}
-			} else {
-				peerNode.AllowedIPs = append(peerNode.AllowedIPs, peerNode.RelayAddrs...)
 			}
 			}
+
+			// get the other peers that are behind the Relay
+			// we dont want to go through the relay to reach them
+			// I'm not sure if this is actually a good call to have this here
+			// may want to test without it, I think it may return bad info
 			nodepeers, err := GetNodePeers(&network, refnode.ID, false, isP2S)
 			nodepeers, err := GetNodePeers(&network, refnode.ID, false, isP2S)
 			if err == nil && peerNode.UDPHolePunch == "yes" {
 			if err == nil && peerNode.UDPHolePunch == "yes" {
 				for _, nodepeer := range nodepeers {
 				for _, nodepeer := range nodepeers {
+
+					// im not sure if this is good either
 					if nodepeer.Address == peerNode.Address {
 					if nodepeer.Address == peerNode.Address {
 						// peerNode.Endpoint = nodepeer.Endpoint
 						// peerNode.Endpoint = nodepeer.Endpoint
 						peerNode.ListenPort = nodepeer.ListenPort
 						peerNode.ListenPort = nodepeer.ListenPort
@@ -239,6 +278,7 @@ func GetPeerUpdate(node *models.Node) (models.PeerUpdate, error) {
 	}
 	}
 
 
 	peerUpdate.Network = node.Network
 	peerUpdate.Network = node.Network
+	peerUpdate.ServerVersion = servercfg.Version
 	peerUpdate.Peers = peers
 	peerUpdate.Peers = peers
 	peerUpdate.ServerAddrs = serverNodeAddresses
 	peerUpdate.ServerAddrs = serverNodeAddresses
 	peerUpdate.DNS = getPeerDNS(node.Network)
 	peerUpdate.DNS = getPeerDNS(node.Network)
@@ -313,29 +353,30 @@ func GetAllowedIPs(node, peer *models.Node) []net.IPNet {
 		}
 		}
 		allowedips = append(allowedips, addr6)
 		allowedips = append(allowedips, addr6)
 	}
 	}
-
 	// handle manually set peers
 	// handle manually set peers
 	for _, allowedIp := range peer.AllowedIPs {
 	for _, allowedIp := range peer.AllowedIPs {
-		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 {
+
+		// parsing as a CIDR first. If valid CIDR, append
+		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 { // parsing as an IP second. If valid IP, check if ipv4 or ipv6, then append
+			if iplib.Version(net.ParseIP(allowedIp)) == 4 && allowedIp != peer.Address {
 				ipnet := net.IPNet{
 				ipnet := net.IPNet{
 					IP:   net.ParseIP(allowedIp),
 					IP:   net.ParseIP(allowedIp),
 					Mask: net.CIDRMask(32, 32),
 					Mask: net.CIDRMask(32, 32),
 				}
 				}
 				allowedips = append(allowedips, ipnet)
 				allowedips = append(allowedips, ipnet)
+			} else if iplib.Version(net.ParseIP(allowedIp)) == 6 && allowedIp != peer.Address6 {
+				ipnet := net.IPNet{
+					IP:   net.ParseIP(allowedIp),
+					Mask: net.CIDRMask(128, 128),
+				}
+				allowedips = append(allowedips, ipnet)
 			}
 			}
-		} else if currentAddr.IsIPv6() {
-			ipnet := net.IPNet{
-				IP:   net.ParseIP(allowedIp),
-				Mask: net.CIDRMask(128, 128),
-			}
-			allowedips = append(allowedips, ipnet)
 		}
 		}
 	}
 	}
 	// handle egress gateway peers
 	// handle egress gateway peers

+ 6 - 6
logic/server.go

@@ -10,13 +10,13 @@ import (
 	"strings"
 	"strings"
 	"time"
 	"time"
 
 
+	"github.com/c-robinson/iplib"
 	"github.com/gravitl/netmaker/logger"
 	"github.com/gravitl/netmaker/logger"
 	"github.com/gravitl/netmaker/logic/acls"
 	"github.com/gravitl/netmaker/logic/acls"
 	"github.com/gravitl/netmaker/logic/acls/nodeacls"
 	"github.com/gravitl/netmaker/logic/acls/nodeacls"
 	"github.com/gravitl/netmaker/models"
 	"github.com/gravitl/netmaker/models"
 	"github.com/gravitl/netmaker/netclient/ncutils"
 	"github.com/gravitl/netmaker/netclient/ncutils"
 	"github.com/gravitl/netmaker/servercfg"
 	"github.com/gravitl/netmaker/servercfg"
-	"github.com/seancfoley/ipaddress-go/ipaddr"
 	"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
 	"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
 )
 )
 
 
@@ -95,7 +95,7 @@ func ServerJoin(networkSettings *models.Network) (models.Node, error) {
 		if node.IsLocal == "yes" && node.LocalAddress != "" {
 		if node.IsLocal == "yes" && node.LocalAddress != "" {
 			node.Endpoint = node.LocalAddress
 			node.Endpoint = node.LocalAddress
 		} else {
 		} else {
-			node.Endpoint, err = ncutils.GetPublicIP()
+			node.Endpoint, err = servercfg.GetPublicIP()
 		}
 		}
 		if err != nil || node.Endpoint == "" {
 		if err != nil || node.Endpoint == "" {
 			logger.Log(0, "Error setting server node Endpoint.")
 			logger.Log(0, "Error setting server node Endpoint.")
@@ -261,8 +261,7 @@ func GetServerPeers(serverNode *models.Node) ([]wgtypes.PeerConfig, bool, []stri
 
 
 		// handle manually set peers
 		// handle manually set peers
 		for _, allowedIp := range node.AllowedIPs {
 		for _, allowedIp := range node.AllowedIPs {
-			currentIP := ipaddr.NewIPAddressString(allowedIp).GetAddress()
-			if currentIP.IsIPv4() {
+			if iplib.Version(net.ParseIP(allowedIp)) == 4 {
 				if _, ipnet, err := net.ParseCIDR(allowedIp); err == nil {
 				if _, ipnet, err := net.ParseCIDR(allowedIp); err == nil {
 					nodeEndpointArr := strings.Split(node.Endpoint, ":")
 					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..
 					if !ipnet.Contains(net.IP(nodeEndpointArr[0])) && ipnet.IP.String() != node.Address { // don't need to add an allowed ip that already exists..
@@ -275,9 +274,10 @@ func GetServerPeers(serverNode *models.Node) ([]wgtypes.PeerConfig, bool, []stri
 					}
 					}
 					allowedips = append(allowedips, ipnet)
 					allowedips = append(allowedips, ipnet)
 				}
 				}
-			} else if currentIP.IsIPv6() {
+			} else if iplib.Version(net.ParseIP(allowedIp)) == 6 {
+				//ipnet : = iplib.Net6FromStr(allowedIp).IP()
 				ipnet := net.IPNet{
 				ipnet := net.IPNet{
-					IP:   currentIP.GetNetIP(),
+					IP:   iplib.Net6FromStr(allowedIp).IP(),
 					Mask: net.CIDRMask(128, 128),
 					Mask: net.CIDRMask(128, 128),
 				}
 				}
 				allowedips = append(allowedips, ipnet)
 				allowedips = append(allowedips, ipnet)

+ 1 - 1
logic/telemetry.go

@@ -95,7 +95,7 @@ func getClientCount(nodes []models.Node) clientCount {
 	var count clientCount
 	var count clientCount
 	for _, node := range nodes {
 	for _, node := range nodes {
 		switch node.OS {
 		switch node.OS {
-		case "macos":
+		case "darwin":
 			count.MacOS += 1
 			count.MacOS += 1
 		case "windows":
 		case "windows":
 			count.Windows += 1
 			count.Windows += 1

+ 3 - 2
logic/timer.go

@@ -29,9 +29,10 @@ func TimerCheckpoint() error {
 	if enoughTimeElapsed {
 	if enoughTimeElapsed {
 		// run any time hooks
 		// run any time hooks
 		runHooks()
 		runHooks()
+		return setTelemetryTimestamp(&telRecord)
+
 	}
 	}
-	// set telemetry timestamp for server, restarts 24 hour cycle
-	return setTelemetryTimestamp(&telRecord)
+	return nil
 }
 }
 
 
 // AddHook - adds a hook function to run every 24hrs
 // AddHook - adds a hook function to run every 24hrs

+ 1 - 0
logic/util.go

@@ -115,6 +115,7 @@ func RandomString(length int) string {
 
 
 // == Private Methods ==
 // == Private Methods ==
 
 
+// getNetworkEgressAndNodes - returns two slices, #1 is all nodes in the network, #2 is the egress nodes in the network
 func getNetworkEgressAndNodes(networkName string) ([]models.Node, []models.Node, error) {
 func getNetworkEgressAndNodes(networkName string) ([]models.Node, []models.Node, error) {
 	var networkNodes, egressNetworkNodes []models.Node
 	var networkNodes, egressNetworkNodes []models.Node
 	collection, err := database.FetchRecords(database.NODES_TABLE_NAME)
 	collection, err := database.FetchRecords(database.NODES_TABLE_NAME)

+ 1 - 6
models/accessToken.go

@@ -1,7 +1,7 @@
 package models
 package models
 
 
 type AccessToken struct {
 type AccessToken struct {
-	ServerConfig
+	APIConnString string `json:"apiconnstring"`
 	ClientConfig
 	ClientConfig
 }
 }
 
 
@@ -10,8 +10,3 @@ type ClientConfig struct {
 	Key        string `json:"key"`
 	Key        string `json:"key"`
 	LocalRange string `json:"localrange"`
 	LocalRange string `json:"localrange"`
 }
 }
-
-type ServerConfig struct {
-	Server        string `json:"server"`
-	APIConnString string `json:"apiconnstring"`
-}

+ 5 - 4
models/mqtt.go

@@ -4,10 +4,11 @@ import "golang.zx2c4.com/wireguard/wgctrl/wgtypes"
 
 
 // PeerUpdate - struct
 // PeerUpdate - struct
 type PeerUpdate struct {
 type PeerUpdate struct {
-	Network     string               `json:"network" bson:"network" yaml:"network"`
-	ServerAddrs []ServerAddr         `json:"serveraddrs" bson:"serveraddrs" yaml:"serveraddrs"`
-	Peers       []wgtypes.PeerConfig `json:"peers" bson:"peers" yaml:"peers"`
-	DNS         string               `json:"dns" bson:"dns" yaml:"dns"`
+	Network       string               `json:"network" bson:"network" yaml:"network"`
+	ServerVersion string               `json:"serverversion" bson:"serverversion" yaml:"serverversion"`
+	ServerAddrs   []ServerAddr         `json:"serveraddrs" bson:"serveraddrs" yaml:"serveraddrs"`
+	Peers         []wgtypes.PeerConfig `json:"peers" bson:"peers" yaml:"peers"`
+	DNS           string               `json:"dns" bson:"dns" yaml:"dns"`
 }
 }
 
 
 // KeyUpdate - key update struct
 // KeyUpdate - key update struct

+ 2 - 2
models/node.go

@@ -35,7 +35,7 @@ var seededRand *rand.Rand = rand.New(
 
 
 // Node - struct for node model
 // Node - struct for node model
 type Node struct {
 type Node struct {
-	ID                  string   `json:"id,omitempty" bson:"id,omitempty" yaml:"id,omitempty" validate:"required,min=5"`
+	ID                  string   `json:"id,omitempty" bson:"id,omitempty" yaml:"id,omitempty" validate:"required,min=5" validate:"id_unique`
 	Address             string   `json:"address" bson:"address" yaml:"address" validate:"omitempty,ipv4"`
 	Address             string   `json:"address" bson:"address" yaml:"address" validate:"omitempty,ipv4"`
 	Address6            string   `json:"address6" bson:"address6" yaml:"address6" validate:"omitempty,ipv6"`
 	Address6            string   `json:"address6" bson:"address6" yaml:"address6" validate:"omitempty,ipv6"`
 	LocalAddress        string   `json:"localaddress" bson:"localaddress" yaml:"localaddress" validate:"omitempty,ip"`
 	LocalAddress        string   `json:"localaddress" bson:"localaddress" yaml:"localaddress" validate:"omitempty,ip"`
@@ -56,7 +56,7 @@ type Node struct {
 	ExpirationDateTime  int64    `json:"expdatetime" bson:"expdatetime" yaml:"expdatetime"`
 	ExpirationDateTime  int64    `json:"expdatetime" bson:"expdatetime" yaml:"expdatetime"`
 	LastPeerUpdate      int64    `json:"lastpeerupdate" bson:"lastpeerupdate" yaml:"lastpeerupdate"`
 	LastPeerUpdate      int64    `json:"lastpeerupdate" bson:"lastpeerupdate" yaml:"lastpeerupdate"`
 	LastCheckIn         int64    `json:"lastcheckin" bson:"lastcheckin" yaml:"lastcheckin"`
 	LastCheckIn         int64    `json:"lastcheckin" bson:"lastcheckin" yaml:"lastcheckin"`
-	MacAddress          string   `json:"macaddress" bson:"macaddress" yaml:"macaddress" validate:"macaddress_unique"`
+	MacAddress          string   `json:"macaddress" bson:"macaddress" yaml:"macaddress"`
 	Password            string   `json:"password" bson:"password" yaml:"password" validate:"required,min=6"`
 	Password            string   `json:"password" bson:"password" yaml:"password" validate:"required,min=6"`
 	Network             string   `json:"network" bson:"network" yaml:"network" validate:"network_exists"`
 	Network             string   `json:"network" bson:"network" yaml:"network" validate:"network_exists"`
 	IsRelayed           string   `json:"isrelayed" bson:"isrelayed" yaml:"isrelayed"`
 	IsRelayed           string   `json:"isrelayed" bson:"isrelayed" yaml:"isrelayed"`

+ 15 - 2
models/structs.go

@@ -190,6 +190,19 @@ type TrafficKeys struct {
 
 
 // NodeGet - struct for a single node get response
 // NodeGet - struct for a single node get response
 type NodeGet struct {
 type NodeGet struct {
-	Node  Node                 `json:"node" bson:"node" yaml:"node"`
-	Peers []wgtypes.PeerConfig `json:"peers" bson:"peers" yaml:"peers"`
+	Node         Node                 `json:"node" bson:"node" yaml:"node"`
+	Peers        []wgtypes.PeerConfig `json:"peers" bson:"peers" yaml:"peers"`
+	ServerConfig ServerConfig         `json:"serverconfig" bson:"serverconfig" yaml:"serverconfig"`
+}
+
+// ServerConfig - struct for dealing with the server information for a netclient
+type ServerConfig struct {
+	CoreDNSAddr string `yaml:"corednsaddr"`
+	API         string `yaml:"apihost"`
+	APIPort     string `yaml:"apiport"`
+	ClientMode  string `yaml:"clientmode"`
+	DNSMode     string `yaml:"dnsmode"`
+	Version     string `yaml:"version"`
+	MQPort      string `yaml:"mqport"`
+	Server      string `yaml:"server"`
 }
 }

+ 1 - 0
mq/publishers.go

@@ -103,6 +103,7 @@ func sendPeers() {
 		if servercfg.ManageIPTables() != "off" {
 		if servercfg.ManageIPTables() != "off" {
 			serverctl.InitIPTables(false)
 			serverctl.InitIPTables(false)
 		}
 		}
+		servercfg.SetHost()
 
 
 		force = true
 		force = true
 		peer_force_send = 0
 		peer_force_send = 0

+ 31 - 23
netclient/config/config.go

@@ -1,8 +1,6 @@
 package config
 package config
 
 
 import (
 import (
-	//"github.com/davecgh/go-spew/spew"
-
 	"crypto/ed25519"
 	"crypto/ed25519"
 	"crypto/x509"
 	"crypto/x509"
 	"crypto/x509/pkix"
 	"crypto/x509/pkix"
@@ -25,20 +23,13 @@ var (
 
 
 // ClientConfig - struct for dealing with client configuration
 // ClientConfig - struct for dealing with client configuration
 type ClientConfig struct {
 type ClientConfig struct {
-	Server          ServerConfig   `yaml:"server"`
-	Node            models.Node    `yaml:"node"`
-	NetworkSettings models.Network `yaml:"networksettings"`
-	Network         string         `yaml:"network"`
-	Daemon          string         `yaml:"daemon"`
-	OperatingSystem string         `yaml:"operatingsystem"`
-}
-
-// ServerConfig - struct for dealing with the server information for a netclient
-type ServerConfig struct {
-	CoreDNSAddr string `yaml:"corednsaddr"`
-	AccessKey   string `yaml:"accesskey"`
-	Server      string `yaml:"server"`
-	API         string `yaml:"api"`
+	Server          models.ServerConfig `yaml:"server"`
+	Node            models.Node         `yaml:"node"`
+	NetworkSettings models.Network      `yaml:"networksettings"`
+	Network         string              `yaml:"network"`
+	Daemon          string              `yaml:"daemon"`
+	OperatingSystem string              `yaml:"operatingsystem"`
+	AccessKey       string              `yaml:"accesskey"`
 }
 }
 
 
 // RegisterRequest - struct for registation with netmaker server
 // RegisterRequest - struct for registation with netmaker server
@@ -53,6 +44,8 @@ type RegisterResponse struct {
 	CAPubKey   ed25519.PublicKey
 	CAPubKey   ed25519.PublicKey
 	Cert       x509.Certificate
 	Cert       x509.Certificate
 	CertPubKey ed25519.PublicKey
 	CertPubKey ed25519.PublicKey
+	Broker     string
+	Port       string
 }
 }
 
 
 // Write - writes the config of a client to disk
 // Write - writes the config of a client to disk
@@ -127,8 +120,8 @@ func (config *ClientConfig) ReadConfig() {
 	}
 	}
 }
 }
 
 
-// ModConfig - overwrites the node inside client config on disk
-func ModConfig(node *models.Node) error {
+// ModNodeConfig - overwrites the node inside client config on disk
+func ModNodeConfig(node *models.Node) error {
 	network := node.Network
 	network := node.Network
 	if network == "" {
 	if network == "" {
 		return errors.New("no network provided")
 		return errors.New("no network provided")
@@ -147,6 +140,21 @@ func ModConfig(node *models.Node) error {
 	return Write(&modconfig, network)
 	return Write(&modconfig, network)
 }
 }
 
 
+// ModNodeConfig - overwrites the server settings inside client config on disk
+func ModServerConfig(scfg *models.ServerConfig, network string) error {
+	var modconfig ClientConfig
+	if FileExists(ncutils.GetNetclientPathSpecific() + "netconfig-" + network) {
+		useconfig, err := ReadConfig(network)
+		if err != nil {
+			return err
+		}
+		modconfig = *useconfig
+	}
+
+	modconfig.Server = (*scfg)
+	return Write(&modconfig, network)
+}
+
 // SaveBackup - saves a backup file of a given network
 // SaveBackup - saves a backup file of a given network
 func SaveBackup(network string) error {
 func SaveBackup(network string) error {
 
 
@@ -195,12 +203,12 @@ func GetCLIConfig(c *cli.Context) (ClientConfig, string, error) {
 		}
 		}
 		cfg.Network = accesstoken.ClientConfig.Network
 		cfg.Network = accesstoken.ClientConfig.Network
 		cfg.Node.Network = accesstoken.ClientConfig.Network
 		cfg.Node.Network = accesstoken.ClientConfig.Network
-		cfg.Server.AccessKey = accesstoken.ClientConfig.Key
+		cfg.AccessKey = accesstoken.ClientConfig.Key
 		cfg.Node.LocalRange = accesstoken.ClientConfig.LocalRange
 		cfg.Node.LocalRange = accesstoken.ClientConfig.LocalRange
-		cfg.Server.Server = accesstoken.ServerConfig.Server
-		cfg.Server.API = accesstoken.ServerConfig.APIConnString
+		//cfg.Server.Server = accesstoken.ServerConfig.Server
+		cfg.Server.API = accesstoken.APIConnString
 		if c.String("key") != "" {
 		if c.String("key") != "" {
-			cfg.Server.AccessKey = c.String("key")
+			cfg.AccessKey = c.String("key")
 		}
 		}
 		if c.String("network") != "all" {
 		if c.String("network") != "all" {
 			cfg.Network = c.String("network")
 			cfg.Network = c.String("network")
@@ -216,7 +224,7 @@ func GetCLIConfig(c *cli.Context) (ClientConfig, string, error) {
 			cfg.Server.API = c.String("apiserver")
 			cfg.Server.API = c.String("apiserver")
 		}
 		}
 	} else {
 	} else {
-		cfg.Server.AccessKey = c.String("key")
+		cfg.AccessKey = c.String("key")
 		cfg.Network = c.String("network")
 		cfg.Network = c.String("network")
 		cfg.Node.Network = c.String("network")
 		cfg.Node.Network = c.String("network")
 		cfg.Node.LocalRange = c.String("localrange")
 		cfg.Node.LocalRange = c.String("localrange")

+ 36 - 0
netclient/functions/common.go

@@ -373,3 +373,39 @@ func Authenticate(cfg *config.ClientConfig) (string, error) {
 	token := tokenData["AuthToken"]
 	token := tokenData["AuthToken"]
 	return token.(string), nil
 	return token.(string), nil
 }
 }
+
+// RegisterWithServer calls the register endpoint with privatekey and commonname - api returns ca and client certificate
+func SetServerInfo(cfg *config.ClientConfig) error {
+	cfg, err := config.ReadConfig(cfg.Network)
+	if err != nil {
+		return err
+	}
+	url := "https://" + cfg.Server.API + "/api/server/getserverinfo"
+	logger.Log(1, "server at "+url)
+
+	token, err := Authenticate(cfg)
+	if err != nil {
+		return err
+	}
+	response, err := API("", http.MethodGet, url, token)
+	if err != nil {
+		return err
+	}
+	if response.StatusCode != http.StatusOK {
+		return errors.New(response.Status)
+	}
+	var resp models.ServerConfig
+	if err := json.NewDecoder(response.Body).Decode(&resp); err != nil {
+		return errors.New("unmarshal cert error " + err.Error())
+	}
+
+	// set broker information on register
+	cfg.Server.Server = resp.Server
+	cfg.Server.MQPort = resp.MQPort
+
+	if err = config.ModServerConfig(&cfg.Server, cfg.Node.Network); err != nil {
+		logger.Log(0, "error overwriting config with broker information: "+err.Error())
+	}
+
+	return nil
+}

+ 17 - 12
netclient/functions/daemon.go

@@ -209,7 +209,8 @@ func NewTLSConfig(server string) *tls.Config {
 func setupMQTT(cfg *config.ClientConfig, publish bool) (mqtt.Client, error) {
 func setupMQTT(cfg *config.ClientConfig, publish bool) (mqtt.Client, error) {
 	opts := mqtt.NewClientOptions()
 	opts := mqtt.NewClientOptions()
 	server := cfg.Server.Server
 	server := cfg.Server.Server
-	opts.AddBroker("ssl://" + server + ":8883") // TODO get the appropriate port of the comms mq server
+	port := cfg.Server.MQPort
+	opts.AddBroker("ssl://" + server + ":" + port)
 	opts.SetTLSConfig(NewTLSConfig(server))
 	opts.SetTLSConfig(NewTLSConfig(server))
 	opts.SetClientID(ncutils.MakeRandomString(23))
 	opts.SetClientID(ncutils.MakeRandomString(23))
 	opts.SetDefaultPublishHandler(All)
 	opts.SetDefaultPublishHandler(All)
@@ -247,26 +248,30 @@ func setupMQTT(cfg *config.ClientConfig, publish bool) (mqtt.Client, error) {
 		} else {
 		} else {
 			err = token.Error()
 			err = token.Error()
 		}
 		}
-		if err := checkBroker(cfg.Server.Server); err != nil {
+		if err := checkBroker(cfg.Server.Server, cfg.Server.MQPort); err != nil {
 			return nil, err
 			return nil, err
 		}
 		}
 		logger.Log(0, "could not connect to broker", cfg.Server.Server, err.Error())
 		logger.Log(0, "could not connect to broker", cfg.Server.Server, err.Error())
 		if strings.Contains(err.Error(), "connectex") || strings.Contains(err.Error(), "connect timeout") {
 		if strings.Contains(err.Error(), "connectex") || strings.Contains(err.Error(), "connect timeout") {
-			logger.Log(0, "connection issue detected.. attempt connection with new certs")
-			key, err := ssl.ReadKey(ncutils.GetNetclientPath() + ncutils.GetSeparator() + "client.key")
-			if err != nil {
-				_, *key, err = ed25519.GenerateKey(rand.Reader)
-				if err != nil {
-					log.Fatal("could not generate new key")
-				}
-			}
-			RegisterWithServer(key, cfg)
-			daemon.Restart()
+			reRegisterWithServer(cfg)
 		}
 		}
 	}
 	}
 	return client, nil
 	return client, nil
 }
 }
 
 
+func reRegisterWithServer(cfg *config.ClientConfig) {
+	logger.Log(0, "connection issue detected.. attempt connection with new certs and broker information")
+	key, err := ssl.ReadKey(ncutils.GetNetclientPath() + ncutils.GetSeparator() + "client.key")
+	if err != nil {
+		_, *key, err = ed25519.GenerateKey(rand.Reader)
+		if err != nil {
+			log.Fatal("could not generate new key")
+		}
+	}
+	RegisterWithServer(key, cfg)
+	daemon.Restart()
+}
+
 // publishes a message to server to update peers on this peer's behalf
 // publishes a message to server to update peers on this peer's behalf
 func publishSignal(nodeCfg *config.ClientConfig, signal byte) error {
 func publishSignal(nodeCfg *config.ClientConfig, signal byte) error {
 	if err := publish(nodeCfg, fmt.Sprintf("signal/%s", nodeCfg.Node.ID), []byte{signal}, 1); err != nil {
 	if err := publish(nodeCfg, fmt.Sprintf("signal/%s", nodeCfg.Node.ID), []byte{signal}, 1); err != nil {

+ 16 - 27
netclient/functions/join.go

@@ -42,10 +42,9 @@ func JoinNetwork(cfg *config.ClientConfig, privateKey string) error {
 	if cfg.Node.Password == "" {
 	if cfg.Node.Password == "" {
 		cfg.Node.Password = logic.GenKey()
 		cfg.Node.Password = logic.GenKey()
 	}
 	}
-	manualPort := false
+	//check if ListenPort was set on command line
 	if cfg.Node.ListenPort != 0 {
 	if cfg.Node.ListenPort != 0 {
 		cfg.Node.UDPHolePunch = "no"
 		cfg.Node.UDPHolePunch = "no"
-		manualPort = true
 	}
 	}
 	var trafficPubKey, trafficPrivKey, errT = box.GenerateKey(rand.Reader) // generate traffic keys
 	var trafficPubKey, trafficPrivKey, errT = box.GenerateKey(rand.Reader) // generate traffic keys
 	if errT != nil {
 	if errT != nil {
@@ -120,12 +119,12 @@ func JoinNetwork(cfg *config.ClientConfig, privateKey string) error {
 	cfg.Node.Name = formatName(cfg.Node)
 	cfg.Node.Name = formatName(cfg.Node)
 	cfg.Node.OS = runtime.GOOS
 	cfg.Node.OS = runtime.GOOS
 	cfg.Node.Version = ncutils.Version
 	cfg.Node.Version = ncutils.Version
-	cfg.Node.AccessKey = cfg.Server.AccessKey
+	cfg.Node.AccessKey = cfg.AccessKey
 	//not sure why this is needed ... setnode defaults should take care of this on server
 	//not sure why this is needed ... setnode defaults should take care of this on server
 	cfg.Node.IPForwarding = "yes"
 	cfg.Node.IPForwarding = "yes"
 	logger.Log(0, "joining "+cfg.Network+" at "+cfg.Server.API)
 	logger.Log(0, "joining "+cfg.Network+" at "+cfg.Server.API)
 	url := "https://" + cfg.Server.API + "/api/nodes/" + cfg.Network
 	url := "https://" + cfg.Server.API + "/api/nodes/" + cfg.Network
-	response, err := API(cfg.Node, http.MethodPost, url, cfg.Server.AccessKey)
+	response, err := API(cfg.Node, http.MethodPost, url, cfg.AccessKey)
 	if err != nil {
 	if err != nil {
 		return fmt.Errorf("error creating node %w", err)
 		return fmt.Errorf("error creating node %w", err)
 	}
 	}
@@ -144,6 +143,7 @@ func JoinNetwork(cfg *config.ClientConfig, privateKey string) error {
 	if nodeGET.Peers == nil {
 	if nodeGET.Peers == nil {
 		nodeGET.Peers = []wgtypes.PeerConfig{}
 		nodeGET.Peers = []wgtypes.PeerConfig{}
 	}
 	}
+
 	// safety check. If returned node from server is local, but not currently configured as local, set to local addr
 	// 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 != "" {
 	if cfg.Node.IsLocal != "yes" && node.IsLocal == "yes" && node.LocalRange != "" {
 		node.LocalAddress, err = ncutils.GetLocalIP(node.LocalRange)
 		node.LocalAddress, err = ncutils.GetLocalIP(node.LocalRange)
@@ -156,6 +156,7 @@ func JoinNetwork(cfg *config.ClientConfig, privateKey string) error {
 		node.UDPHolePunch = "no"
 		node.UDPHolePunch = "no"
 		cfg.Node.IsStatic = "yes"
 		cfg.Node.IsStatic = "yes"
 	}
 	}
+	cfg.Server = nodeGET.ServerConfig
 
 
 	err = wireguard.StorePrivKey(privateKey, cfg.Network)
 	err = wireguard.StorePrivKey(privateKey, cfg.Network)
 	if err != nil {
 	if err != nil {
@@ -170,11 +171,11 @@ func JoinNetwork(cfg *config.ClientConfig, privateKey string) error {
 	}
 	}
 	logger.Log(1, "node created on remote server...updating configs")
 	logger.Log(1, "node created on remote server...updating configs")
 	cfg.Node = node
 	cfg.Node = node
-	logger.Log(1, "turn on UDP hole punching (dynamic port setting)? "+cfg.Node.UDPHolePunch)
-	if !manualPort && (cfg.Node.UDPHolePunch == "no") {
-		setListenPort(cfg)
+	err = config.ModNodeConfig(&cfg.Node)
+	if err != nil {
+		return err
 	}
 	}
-	err = config.ModConfig(&cfg.Node)
+	err = config.ModServerConfig(&cfg.Server, node.Network)
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}
@@ -190,8 +191,13 @@ func JoinNetwork(cfg *config.ClientConfig, privateKey string) error {
 	if err := Register(cfg, privateKey); err != nil {
 	if err := Register(cfg, privateKey); err != nil {
 		return err
 		return err
 	}
 	}
-
-	_ = UpdateLocalListenPort(cfg)
+	if cfg.Server.Server == "" {
+		return errors.New("did not recieve broker address from registration")
+	}
+	// update server with latest data
+	if err := PublishNodeUpdate(cfg); err != nil {
+		logger.Log(0, "failed to publish update for join", err.Error())
+	}
 
 
 	if cfg.Daemon == "install" || ncutils.IsFreeBSD() {
 	if cfg.Daemon == "install" || ncutils.IsFreeBSD() {
 		err = daemon.InstallDaemon(cfg)
 		err = daemon.InstallDaemon(cfg)
@@ -220,20 +226,3 @@ func formatName(node models.Node) string {
 	}
 	}
 	return node.Name
 	return node.Name
 }
 }
-
-func setListenPort(cfg *config.ClientConfig) {
-	// keep track of the returned listenport value
-	newListenPort := cfg.Node.ListenPort
-	var errN error
-	// get free port based on returned default listen port
-	cfg.Node.ListenPort, errN = ncutils.GetFreePort(cfg.Node.ListenPort)
-	if errN != nil {
-		cfg.Node.ListenPort = newListenPort
-		logger.Log(1, "Error retrieving port: ", errN.Error())
-	}
-
-	// if newListenPort has been modified to find an available port, publish to server
-	if cfg.Node.ListenPort != newListenPort {
-		PublishNodeUpdate(cfg)
-	}
-}

+ 1 - 1
netclient/functions/localport.go

@@ -39,7 +39,7 @@ func UpdateLocalListenPort(nodeCfg *config.ClientConfig) error {
 	} else if nodeCfg.Node.LocalListenPort != localPort && localPort != 0 {
 	} else if nodeCfg.Node.LocalListenPort != localPort && localPort != 0 {
 		logger.Log(1, "local port has changed from ", strconv.Itoa(int(nodeCfg.Node.LocalListenPort)), " to ", strconv.Itoa(int(localPort)))
 		logger.Log(1, "local port has changed from ", strconv.Itoa(int(nodeCfg.Node.LocalListenPort)), " to ", strconv.Itoa(int(localPort)))
 		nodeCfg.Node.LocalListenPort = localPort
 		nodeCfg.Node.LocalListenPort = localPort
-		err = config.ModConfig(&nodeCfg.Node)
+		err = config.ModNodeConfig(&nodeCfg.Node)
 		if err != nil {
 		if err != nil {
 			return err
 			return err
 		}
 		}

+ 1 - 1
netclient/functions/localport_freebsd.go

@@ -38,7 +38,7 @@ func UpdateLocalListenPort(nodeCfg *config.ClientConfig) error {
 	} else if nodeCfg.Node.LocalListenPort != localPort && localPort != 0 {
 	} else if nodeCfg.Node.LocalListenPort != localPort && localPort != 0 {
 		logger.Log(1, "local port has changed from ", strconv.Itoa(int(nodeCfg.Node.LocalListenPort)), " to ", strconv.Itoa(int(localPort)))
 		logger.Log(1, "local port has changed from ", strconv.Itoa(int(nodeCfg.Node.LocalListenPort)), " to ", strconv.Itoa(int(localPort)))
 		nodeCfg.Node.LocalListenPort = localPort
 		nodeCfg.Node.LocalListenPort = localPort
-		err = config.ModConfig(&nodeCfg.Node)
+		err = config.ModNodeConfig(&nodeCfg.Node)
 		if err != nil {
 		if err != nil {
 			return err
 			return err
 		}
 		}

+ 12 - 3
netclient/functions/mqhandlers.go

@@ -149,7 +149,7 @@ func NodeUpdate(client mqtt.Client, msg mqtt.Message) {
 	//deal with DNS
 	//deal with DNS
 	if newNode.DNSOn != "yes" && shouldDNSChange && nodeCfg.Node.Interface != "" {
 	if newNode.DNSOn != "yes" && shouldDNSChange && nodeCfg.Node.Interface != "" {
 		logger.Log(0, "settng DNS off")
 		logger.Log(0, "settng DNS off")
-		if err := removeHostDNS(nodeCfg.Network, ncutils.IsWindows()); err != nil {
+		if err := removeHostDNS(nodeCfg.Node.Interface, ncutils.IsWindows()); err != nil {
 			logger.Log(0, "error removing netmaker profile from /etc/hosts "+err.Error())
 			logger.Log(0, "error removing netmaker profile from /etc/hosts "+err.Error())
 		}
 		}
 		//		_, err := ncutils.RunCmd("/usr/bin/resolvectl revert "+nodeCfg.Node.Interface, true)
 		//		_, err := ncutils.RunCmd("/usr/bin/resolvectl revert "+nodeCfg.Node.Interface, true)
@@ -183,6 +183,15 @@ func UpdatePeers(client mqtt.Client, msg mqtt.Message) {
 		return
 		return
 	}
 	}
 	insert(peerUpdate.Network, lastPeerUpdate, string(data))
 	insert(peerUpdate.Network, lastPeerUpdate, string(data))
+	// check version
+	if peerUpdate.ServerVersion != ncutils.Version {
+		logger.Log(0, "server/client version mismatch server: ", peerUpdate.ServerVersion, " client: ", ncutils.Version)
+	}
+	if peerUpdate.ServerVersion != cfg.Server.Version {
+		logger.Log(1, "updating server version")
+		cfg.Server.Version = peerUpdate.ServerVersion
+		config.Write(&cfg, cfg.Network)
+	}
 
 
 	file := ncutils.GetNetclientPathSpecific() + cfg.Node.Interface + ".conf"
 	file := ncutils.GetNetclientPathSpecific() + cfg.Node.Interface + ".conf"
 	err = wireguard.UpdateWgPeers(file, peerUpdate.Peers)
 	err = wireguard.UpdateWgPeers(file, peerUpdate.Peers)
@@ -208,12 +217,12 @@ func UpdatePeers(client mqtt.Client, msg mqtt.Message) {
 	}
 	}
 	logger.Log(0, "received peer update for node "+cfg.Node.Name+" "+cfg.Node.Network)
 	logger.Log(0, "received peer update for node "+cfg.Node.Name+" "+cfg.Node.Network)
 	if cfg.Node.DNSOn == "yes" {
 	if cfg.Node.DNSOn == "yes" {
-		if err := setHostDNS(peerUpdate.DNS, cfg.Node.Network, ncutils.IsWindows()); err != nil {
+		if err := setHostDNS(peerUpdate.DNS, cfg.Node.Interface, ncutils.IsWindows()); err != nil {
 			logger.Log(0, "error updating /etc/hosts "+err.Error())
 			logger.Log(0, "error updating /etc/hosts "+err.Error())
 			return
 			return
 		}
 		}
 	} else {
 	} else {
-		if err := removeHostDNS(cfg.Node.Network, ncutils.IsWindows()); err != nil {
+		if err := removeHostDNS(cfg.Node.Interface, ncutils.IsWindows()); err != nil {
 			logger.Log(0, "error removing profile from /etc/hosts "+err.Error())
 			logger.Log(0, "error removing profile from /etc/hosts "+err.Error())
 			return
 			return
 		}
 		}

+ 16 - 2
netclient/functions/mqpublish.go

@@ -7,6 +7,7 @@ import (
 	"fmt"
 	"fmt"
 	"net"
 	"net"
 	"os"
 	"os"
+	"strconv"
 	"sync"
 	"sync"
 	"time"
 	"time"
 
 
@@ -14,6 +15,7 @@ import (
 	"github.com/gravitl/netmaker/logger"
 	"github.com/gravitl/netmaker/logger"
 	"github.com/gravitl/netmaker/netclient/auth"
 	"github.com/gravitl/netmaker/netclient/auth"
 	"github.com/gravitl/netmaker/netclient/config"
 	"github.com/gravitl/netmaker/netclient/config"
+	"github.com/gravitl/netmaker/netclient/daemon"
 	"github.com/gravitl/netmaker/netclient/ncutils"
 	"github.com/gravitl/netmaker/netclient/ncutils"
 	"github.com/gravitl/netmaker/tls"
 	"github.com/gravitl/netmaker/tls"
 )
 )
@@ -106,6 +108,8 @@ func Hello(nodeCfg *config.ClientConfig) {
 		_, err := Pull(nodeCfg.Node.Network, true)
 		_, err := Pull(nodeCfg.Node.Network, true)
 		if err != nil {
 		if err != nil {
 			logger.Log(0, "could not run pull on "+nodeCfg.Node.Network+", error: "+err.Error())
 			logger.Log(0, "could not run pull on "+nodeCfg.Node.Network+", error: "+err.Error())
+		} else {
+			daemon.Restart()
 		}
 		}
 	}
 	}
 	logger.Log(3, "checkin for", nodeCfg.Network, "complete")
 	logger.Log(3, "checkin for", nodeCfg.Network, "complete")
@@ -164,16 +168,26 @@ func checkCertExpiry(cfg *config.ClientConfig) error {
 	return nil
 	return nil
 }
 }
 
 
-func checkBroker(broker string) error {
+func checkBroker(broker string, port string) error {
+	if broker == "" {
+		return errors.New("error: broker address is blank")
+	}
+	if port == "" {
+		return errors.New("error: broker port is blank")
+	}
 	_, err := net.LookupIP(broker)
 	_, err := net.LookupIP(broker)
 	if err != nil {
 	if err != nil {
 		return errors.New("nslookup failed for broker ... check dns records")
 		return errors.New("nslookup failed for broker ... check dns records")
 	}
 	}
 	pinger := ping.NewTCPing()
 	pinger := ping.NewTCPing()
+	intPort, err := strconv.Atoi(port)
+	if err != nil {
+		logger.Log(1, "error converting port to int: "+err.Error())
+	}
 	pinger.SetTarget(&ping.Target{
 	pinger.SetTarget(&ping.Target{
 		Protocol: ping.TCP,
 		Protocol: ping.TCP,
 		Host:     broker,
 		Host:     broker,
-		Port:     8883,
+		Port:     intPort,
 		Counter:  3,
 		Counter:  3,
 		Interval: 1 * time.Second,
 		Interval: 1 * time.Second,
 		Timeout:  2 * time.Second,
 		Timeout:  2 * time.Second,

+ 7 - 2
netclient/functions/pull.go

@@ -57,9 +57,13 @@ func Pull(network string, iface bool) (*models.Node, error) {
 	if nodeGET.Peers == nil {
 	if nodeGET.Peers == nil {
 		nodeGET.Peers = []wgtypes.PeerConfig{}
 		nodeGET.Peers = []wgtypes.PeerConfig{}
 	}
 	}
-
+	if nodeGET.ServerConfig.API != "" && nodeGET.ServerConfig.MQPort != "" {
+		if err = config.ModServerConfig(&nodeGET.ServerConfig, resNode.Network); err != nil {
+			logger.Log(0, "unable to update server config: "+err.Error())
+		}
+	}
 	if iface {
 	if iface {
-		if err = config.ModConfig(&resNode); err != nil {
+		if err = config.ModNodeConfig(&resNode); err != nil {
 			return nil, err
 			return nil, err
 		}
 		}
 		if err = wireguard.SetWGConfig(network, false, nodeGET.Peers[:]); err != nil {
 		if err = wireguard.SetWGConfig(network, false, nodeGET.Peers[:]); err != nil {
@@ -78,5 +82,6 @@ func Pull(network string, iface bool) (*models.Node, error) {
 	if bkupErr != nil {
 	if bkupErr != nil {
 		logger.Log(0, "unable to update backup file")
 		logger.Log(0, "unable to update backup file")
 	}
 	}
+
 	return &resNode, err
 	return &resNode, err
 }
 }

+ 18 - 10
netclient/functions/register.go

@@ -16,12 +16,7 @@ import (
 
 
 // Register - the function responsible for registering with the server and acquiring certs
 // Register - the function responsible for registering with the server and acquiring certs
 func Register(cfg *config.ClientConfig, key string) error {
 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
 	//generate new key if one doesn' exist
 	var private *ed25519.PrivateKey
 	var private *ed25519.PrivateKey
 	var err error
 	var err error
@@ -50,10 +45,6 @@ func Register(cfg *config.ClientConfig, key string) error {
 
 
 // RegisterWithServer calls the register endpoint with privatekey and commonname - api returns ca and client certificate
 // RegisterWithServer calls the register endpoint with privatekey and commonname - api returns ca and client certificate
 func RegisterWithServer(private *ed25519.PrivateKey, cfg *config.ClientConfig) error {
 func RegisterWithServer(private *ed25519.PrivateKey, cfg *config.ClientConfig) error {
-	cfg, err := config.ReadConfig(cfg.Network)
-	if err != nil {
-		return err
-	}
 	data := config.RegisterRequest{
 	data := config.RegisterRequest{
 		Key:        *private,
 		Key:        *private,
 		CommonName: tls.NewCName(cfg.Node.Name),
 		CommonName: tls.NewCName(cfg.Node.Name),
@@ -76,6 +67,23 @@ func RegisterWithServer(private *ed25519.PrivateKey, cfg *config.ClientConfig) e
 	if err := json.NewDecoder(response.Body).Decode(&resp); err != nil {
 	if err := json.NewDecoder(response.Body).Decode(&resp); err != nil {
 		return errors.New("unmarshal cert error " + err.Error())
 		return errors.New("unmarshal cert error " + err.Error())
 	}
 	}
+
+	// set broker information on register
+	var modServer bool
+	if resp.Broker != "" && resp.Broker != cfg.Server.Server {
+		cfg.Server.Server = resp.Broker
+		modServer = true
+	}
+	if resp.Port != "" && resp.Port != cfg.Server.MQPort {
+		cfg.Server.MQPort = resp.Port
+		modServer = true
+	}
+	if modServer {
+		if err = config.ModServerConfig(&cfg.Server, cfg.Node.Network); err != nil {
+			logger.Log(0, "error overwriting config with broker information: "+err.Error())
+		}
+	}
+
 	//x509.Certificate.PublicKey is an interface so json encoding/decoding results in a string rather that []byte
 	//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
 	//the pubkeys are included in the response so the values in the certificate can be updated appropriately
 	resp.CA.PublicKey = resp.CAPubKey
 	resp.CA.PublicKey = resp.CAPubKey

+ 2 - 3
netclient/gui/components/views/join.go

@@ -29,10 +29,9 @@ func GetJoinView() fyne.CanvasObject {
 		cfg.Network = accesstoken.ClientConfig.Network
 		cfg.Network = accesstoken.ClientConfig.Network
 		cfg.Node.Network = accesstoken.ClientConfig.Network
 		cfg.Node.Network = accesstoken.ClientConfig.Network
 		cfg.Node.Name = ncutils.GetHostname()
 		cfg.Node.Name = ncutils.GetHostname()
-		cfg.Server.AccessKey = accesstoken.ClientConfig.Key
+		cfg.AccessKey = accesstoken.ClientConfig.Key
 		cfg.Node.LocalRange = accesstoken.ClientConfig.LocalRange
 		cfg.Node.LocalRange = accesstoken.ClientConfig.LocalRange
-		cfg.Server.Server = accesstoken.ServerConfig.Server
-		cfg.Server.API = accesstoken.ServerConfig.APIConnString
+		cfg.Server.API = accesstoken.APIConnString
 		err = functions.JoinNetwork(&cfg, "")
 		err = functions.JoinNetwork(&cfg, "")
 		if err != nil {
 		if err != nil {
 			ErrorNotify("Failed to join " + cfg.Network + "!")
 			ErrorNotify("Failed to join " + cfg.Network + "!")

+ 3 - 4
netclient/local/routes_darwin.go

@@ -4,9 +4,9 @@ import (
 	"net"
 	"net"
 	"strings"
 	"strings"
 
 
+	"github.com/c-robinson/iplib"
 	"github.com/gravitl/netmaker/logger"
 	"github.com/gravitl/netmaker/logger"
 	"github.com/gravitl/netmaker/netclient/ncutils"
 	"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
 // route -n add -net 10.0.0.0/8 192.168.0.254
@@ -35,10 +35,9 @@ func deleteRoute(iface string, addr *net.IPNet, address string) error {
 }
 }
 
 
 func setCidr(iface, address string, addr *net.IPNet) {
 func setCidr(iface, address string, addr *net.IPNet) {
-	cidr := ipaddr.NewIPAddressString(addr.String()).GetAddress()
-	if cidr.IsIPv4() {
+	if iplib.Version(addr.IP) == 4 {
 		ncutils.RunCmd("route -q -n add -net "+addr.String()+" "+address, false)
 		ncutils.RunCmd("route -q -n add -net "+addr.String()+" "+address, false)
-	} else if cidr.IsIPv6() {
+	} else if iplib.Version(addr.IP) == 6 {
 		ncutils.RunCmd("route -A inet6 -q -n add -net "+addr.String()+" "+address, false)
 		ncutils.RunCmd("route -A inet6 -q -n add -net "+addr.String()+" "+address, false)
 	} else {
 	} else {
 		logger.Log(1, "could not parse address: "+addr.String())
 		logger.Log(1, "could not parse address: "+addr.String())

+ 3 - 4
netclient/local/routes_freebsd.go

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

+ 3 - 4
netclient/local/routes_linux.go

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

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

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

+ 3 - 3
netclient/versioninfo.json

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

+ 11 - 8
netclient/wireguard/common.go

@@ -135,14 +135,14 @@ func InitWireguard(node *models.Node, privkey string, peers []wgtypes.PeerConfig
 		return err
 		return err
 	}
 	}
 	defer wgclient.Close()
 	defer wgclient.Close()
-	modcfg, err := config.ReadConfig(node.Network)
+	cfg, err := config.ReadConfig(node.Network)
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}
-	nodecfg := modcfg.Node
+	//nodecfg := modcfg.Node
 	var ifacename string
 	var ifacename string
-	if nodecfg.Interface != "" {
-		ifacename = nodecfg.Interface
+	if cfg.Node.Interface != "" {
+		ifacename = cfg.Node.Interface
 	} else if node.Interface != "" {
 	} else if node.Interface != "" {
 		ifacename = node.Interface
 		ifacename = node.Interface
 	} else {
 	} else {
@@ -151,11 +151,14 @@ func InitWireguard(node *models.Node, privkey string, peers []wgtypes.PeerConfig
 	if node.PrimaryAddress() == "" {
 	if node.PrimaryAddress() == "" {
 		return fmt.Errorf("no address to configure")
 		return fmt.Errorf("no address to configure")
 	}
 	}
-
+	logger.Log(1, "turn on UDP hole punching (dynamic port setting)? "+cfg.Node.UDPHolePunch)
 	if node.UDPHolePunch == "yes" {
 	if node.UDPHolePunch == "yes" {
 		node.ListenPort = 0
 		node.ListenPort = 0
+	} else {
+		//get available port based on current default
+		node.ListenPort, err = ncutils.GetFreePort(node.ListenPort)
 	}
 	}
-	if err := WriteWgConfig(&modcfg.Node, key.String(), peers); err != nil {
+	if err := WriteWgConfig(&cfg.Node, key.String(), peers); err != nil {
 		logger.Log(1, "error writing wg conf file: ", err.Error())
 		logger.Log(1, "error writing wg conf file: ", err.Error())
 		return err
 		return err
 	}
 	}
@@ -216,7 +219,7 @@ func InitWireguard(node *models.Node, privkey string, peers []wgtypes.PeerConfig
 
 
 	//ipv4
 	//ipv4
 	if node.Address != "" {
 	if node.Address != "" {
-		_, cidr, cidrErr := net.ParseCIDR(modcfg.NetworkSettings.AddressRange)
+		_, cidr, cidrErr := net.ParseCIDR(cfg.NetworkSettings.AddressRange)
 		if cidrErr == nil {
 		if cidrErr == nil {
 			local.SetCIDRRoute(ifacename, node.Address, cidr)
 			local.SetCIDRRoute(ifacename, node.Address, cidr)
 		} else {
 		} else {
@@ -226,7 +229,7 @@ func InitWireguard(node *models.Node, privkey string, peers []wgtypes.PeerConfig
 	}
 	}
 	if node.Address6 != "" {
 	if node.Address6 != "" {
 		//ipv6
 		//ipv6
-		_, cidr, cidrErr := net.ParseCIDR(modcfg.NetworkSettings.AddressRange6)
+		_, cidr, cidrErr := net.ParseCIDR(cfg.NetworkSettings.AddressRange6)
 		if cidrErr == nil {
 		if cidrErr == nil {
 			local.SetCIDRRoute(ifacename, node.Address6, cidr)
 			local.SetCIDRRoute(ifacename, node.Address6, cidr)
 		} else {
 		} else {

+ 16 - 3
scripts/netclient.sh

@@ -1,4 +1,16 @@
-#!/bin/sh
+#!/bin/bash
+
+#Define cleanup
+cleanup() {
+    nets=($(wg show interfaces))
+    for net in ${nets[@]}; do
+        echo "deleting interface" $net
+        ip link del $net
+    done
+}
+
+#Trap SigTerm
+trap 'cleanup' SIGTERM
 
 
 echo "[netclient] joining network"
 echo "[netclient] joining network"
 
 
@@ -11,11 +23,12 @@ if [ "$TOKEN" != "" ]; then
     TOKEN_CMD="-t $TOKEN"
     TOKEN_CMD="-t $TOKEN"
 fi
 fi
 
 
-/root/netclient join $TOKEN_CMD -daemon off -dnson no -udpholepunch no
+/root/netclient join $TOKEN_CMD -dnson no -udpholepunch no
 if [ $? -ne 0 ]; then { echo "Failed to join, quitting." ; exit 1; } fi
 if [ $? -ne 0 ]; then { echo "Failed to join, quitting." ; exit 1; } fi
 
 
 echo "[netclient] Starting netclient daemon"
 echo "[netclient] Starting netclient daemon"
 
 
-/root/netclient daemon
+/root/netclient daemon &
 
 
+wait $!
 echo "[netclient] exiting"
 echo "[netclient] exiting"

+ 9 - 14
scripts/nm-quick.sh

@@ -125,14 +125,6 @@ echo "   ----------------------------"
 
 
 sleep 5
 sleep 5
 
 
-
-echo "setting caddyfile..."
-
-
-wget -q -O /root/Caddyfile https://raw.githubusercontent.com/gravitl/netmaker/master/docker/Caddyfile
-sed -i "s/NETMAKER_BASE_DOMAIN/$NETMAKER_BASE_DOMAIN/g" /root/Caddyfile
-sed -i "s/YOUR_EMAIL/$EMAIL/g" /root/Caddyfile
-
 echo "setting mosquitto.conf..."
 echo "setting mosquitto.conf..."
 
 
 wget -q -O /root/mosquitto.conf https://raw.githubusercontent.com/gravitl/netmaker/master/docker/mosquitto.conf
 wget -q -O /root/mosquitto.conf https://raw.githubusercontent.com/gravitl/netmaker/master/docker/mosquitto.conf
@@ -141,11 +133,12 @@ echo "setting docker-compose..."
 
 
 mkdir -p /etc/netmaker
 mkdir -p /etc/netmaker
 
 
-wget -q -O /root/docker-compose.yml https://raw.githubusercontent.com/gravitl/netmaker/master/compose/docker-compose.contained.yml
+wget -q -O /root/docker-compose.yml https://raw.githubusercontent.com/gravitl/netmaker/master/compose/docker-compose.traefik.yml
 sed -i "s/NETMAKER_BASE_DOMAIN/$NETMAKER_BASE_DOMAIN/g" /root/docker-compose.yml
 sed -i "s/NETMAKER_BASE_DOMAIN/$NETMAKER_BASE_DOMAIN/g" /root/docker-compose.yml
 sed -i "s/SERVER_PUBLIC_IP/$SERVER_PUBLIC_IP/g" /root/docker-compose.yml
 sed -i "s/SERVER_PUBLIC_IP/$SERVER_PUBLIC_IP/g" /root/docker-compose.yml
 sed -i "s/COREDNS_IP/$COREDNS_IP/g" /root/docker-compose.yml
 sed -i "s/COREDNS_IP/$COREDNS_IP/g" /root/docker-compose.yml
 sed -i "s/REPLACE_MASTER_KEY/$MASTER_KEY/g" /root/docker-compose.yml
 sed -i "s/REPLACE_MASTER_KEY/$MASTER_KEY/g" /root/docker-compose.yml
+sed -i "s/YOUR_EMAIL/$EMAIL/g" /root/docker-compose.yml
 
 
 echo "starting containers..."
 echo "starting containers..."
 
 
@@ -170,22 +163,22 @@ cat << "EOF"
 EOF
 EOF
 
 
 
 
-echo "visit dashboard.$NETMAKER_BASE_DOMAIN to log in"
-sleep 2
+echo "visit https://dashboard.$NETMAKER_BASE_DOMAIN to log in"
+sleep 7
 
 
 setup_mesh() {
 setup_mesh() {
 echo "creating netmaker network (10.101.0.0/16)"
 echo "creating netmaker network (10.101.0.0/16)"
 
 
 curl -s -o /dev/null -d '{"addressrange":"10.101.0.0/16","netid":"netmaker"}' -H "Authorization: Bearer $MASTER_KEY" -H 'Content-Type: application/json' https://api.${NETMAKER_BASE_DOMAIN}/api/networks
 curl -s -o /dev/null -d '{"addressrange":"10.101.0.0/16","netid":"netmaker"}' -H "Authorization: Bearer $MASTER_KEY" -H 'Content-Type: application/json' https://api.${NETMAKER_BASE_DOMAIN}/api/networks
 
 
-sleep 2
+sleep 5
 
 
 echo "creating netmaker access key"
 echo "creating netmaker access key"
 
 
 curlresponse=$(curl -s -d '{"uses":99999,"name":"netmaker-key"}' -H "Authorization: Bearer $MASTER_KEY" -H 'Content-Type: application/json' https://api.${NETMAKER_BASE_DOMAIN}/api/networks/netmaker/keys)
 curlresponse=$(curl -s -d '{"uses":99999,"name":"netmaker-key"}' -H "Authorization: Bearer $MASTER_KEY" -H 'Content-Type: application/json' https://api.${NETMAKER_BASE_DOMAIN}/api/networks/netmaker/keys)
 ACCESS_TOKEN=$(jq -r '.accessstring' <<< ${curlresponse})
 ACCESS_TOKEN=$(jq -r '.accessstring' <<< ${curlresponse})
 
 
-sleep 2
+sleep 5
 
 
 echo "configuring netmaker server as ingress gateway"
 echo "configuring netmaker server as ingress gateway"
 
 
@@ -194,6 +187,8 @@ SERVER_ID=$(jq -r '.[0].id' <<< ${curlresponse})
 
 
 curl -o /dev/null -s -X POST -H "Authorization: Bearer $MASTER_KEY" -H 'Content-Type: application/json' https://api.${NETMAKER_BASE_DOMAIN}/api/nodes/netmaker/$SERVER_ID/createingress
 curl -o /dev/null -s -X POST -H "Authorization: Bearer $MASTER_KEY" -H 'Content-Type: application/json' https://api.${NETMAKER_BASE_DOMAIN}/api/nodes/netmaker/$SERVER_ID/createingress
 
 
+sleep 5
+
 echo "finished configuring server and network. You can now add clients."
 echo "finished configuring server and network. You can now add clients."
 echo ""
 echo ""
 echo "For Linux, Mac, Windows, and FreeBSD:"
 echo "For Linux, Mac, Windows, and FreeBSD:"
@@ -214,7 +209,7 @@ echo "creating vpn network (10.201.0.0/16)"
 
 
 curl -s -o /dev/null -d '{"addressrange":"10.201.0.0/16","netid":"vpn","defaultextclientdns":"8.8.8.8"}' -H "Authorization: Bearer $MASTER_KEY" -H 'Content-Type: application/json' https://api.${NETMAKER_BASE_DOMAIN}/api/networks
 curl -s -o /dev/null -d '{"addressrange":"10.201.0.0/16","netid":"vpn","defaultextclientdns":"8.8.8.8"}' -H "Authorization: Bearer $MASTER_KEY" -H 'Content-Type: application/json' https://api.${NETMAKER_BASE_DOMAIN}/api/networks
 
 
-sleep 2
+sleep 5
 
 
 echo "configuring netmaker server as vpn inlet..."
 echo "configuring netmaker server as vpn inlet..."
 
 

+ 34 - 8
servercfg/serverconf.go

@@ -10,6 +10,7 @@ import (
 	"time"
 	"time"
 
 
 	"github.com/gravitl/netmaker/config"
 	"github.com/gravitl/netmaker/config"
+	"github.com/gravitl/netmaker/models"
 )
 )
 
 
 var (
 var (
@@ -33,14 +34,12 @@ func GetServerConfig() config.ServerConfig {
 	cfg.CoreDNSAddr = GetCoreDNSAddr()
 	cfg.CoreDNSAddr = GetCoreDNSAddr()
 	cfg.APIHost = GetAPIHost()
 	cfg.APIHost = GetAPIHost()
 	cfg.APIPort = GetAPIPort()
 	cfg.APIPort = GetAPIPort()
-	cfg.APIPort = GetAPIPort()
 	cfg.MQPort = GetMQPort()
 	cfg.MQPort = GetMQPort()
 	cfg.MasterKey = "(hidden)"
 	cfg.MasterKey = "(hidden)"
 	cfg.DNSKey = "(hidden)"
 	cfg.DNSKey = "(hidden)"
 	cfg.AllowedOrigin = GetAllowedOrigin()
 	cfg.AllowedOrigin = GetAllowedOrigin()
 	cfg.RestBackend = "off"
 	cfg.RestBackend = "off"
 	cfg.NodeID = GetNodeID()
 	cfg.NodeID = GetNodeID()
-	cfg.MQPort = GetMQPort()
 	if IsRestBackend() {
 	if IsRestBackend() {
 		cfg.RestBackend = "on"
 		cfg.RestBackend = "on"
 	}
 	}
@@ -89,6 +88,23 @@ func GetServerConfig() config.ServerConfig {
 	return cfg
 	return cfg
 }
 }
 
 
+// GetServerConfig - gets the server config into memory from file or env
+func GetServerInfo() models.ServerConfig {
+	var cfg models.ServerConfig
+	cfg.API = GetAPIConnString()
+	cfg.CoreDNSAddr = GetCoreDNSAddr()
+	cfg.APIPort = GetAPIPort()
+	cfg.MQPort = GetMQPort()
+	cfg.DNSMode = "off"
+	if IsDNSMode() {
+		cfg.DNSMode = "on"
+	}
+	cfg.Version = GetVersion()
+	cfg.Server = GetServer()
+
+	return cfg
+}
+
 // GetFrontendURL - gets the frontend url
 // GetFrontendURL - gets the frontend url
 func GetFrontendURL() string {
 func GetFrontendURL() string {
 	var frontend = ""
 	var frontend = ""
@@ -196,13 +212,24 @@ func GetCoreDNSAddr() string {
 
 
 // GetMQPort - gets the mq port
 // GetMQPort - gets the mq port
 func GetMQPort() string {
 func GetMQPort() string {
-	mqport := "1883"
+	port := "8883" //default
 	if os.Getenv("MQ_PORT") != "" {
 	if os.Getenv("MQ_PORT") != "" {
-		mqport = os.Getenv("MQ_PORT")
+		port = os.Getenv("MQ_PORT")
 	} else if config.Config.Server.MQPort != "" {
 	} else if config.Config.Server.MQPort != "" {
-		mqport = config.Config.Server.MQPort
+		port = config.Config.Server.MQPort
+	}
+	return port
+}
+
+// GetMQServerPort - get mq port for server
+func GetMQServerPort() string {
+	port := "1883" //default
+	if os.Getenv("MQ_SERVER_PORT") != "" {
+		port = os.Getenv("MQ_SERVER_PORT")
+	} else if config.Config.Server.MQServerPort != "" {
+		port = config.Config.Server.MQServerPort
 	}
 	}
-	return mqport
+	return port
 }
 }
 
 
 // GetMessageQueueEndpoint - gets the message queue endpoint
 // GetMessageQueueEndpoint - gets the message queue endpoint
@@ -213,8 +240,7 @@ func GetMessageQueueEndpoint() string {
 	} else if config.Config.Server.MQHOST != "" {
 	} else if config.Config.Server.MQHOST != "" {
 		host = config.Config.Server.MQHOST
 		host = config.Config.Server.MQHOST
 	}
 	}
-	//Do we want MQ port configurable???
-	return host + ":1883"
+	return host + ":" + GetMQServerPort()
 }
 }
 
 
 // GetMasterKey - gets the configured master key of server
 // GetMasterKey - gets the configured master key of server

+ 1 - 1
serverctl/iptables.go

@@ -46,7 +46,7 @@ func portForwardServices(force bool) error {
 	for _, service := range services {
 	for _, service := range services {
 		switch service {
 		switch service {
 		case "mq":
 		case "mq":
-			err = iptablesPortForward("mq", "1883", "1883", false, force)
+			err = iptablesPortForward("mq", servercfg.GetMQServerPort(), servercfg.GetMQServerPort(), false, force)
 		case "dns":
 		case "dns":
 			err = iptablesPortForward("coredns", "53", "53", false, force)
 			err = iptablesPortForward("coredns", "53", "53", false, force)
 		case "ssh":
 		case "ssh":

+ 5 - 24
serverctl/serverctl.go

@@ -79,32 +79,13 @@ func SyncServerNetwork(network string) error {
 			if err == nil {
 			if err == nil {
 				err = errors.New("network add failed for " + serverNetworkSettings.NetID)
 				err = errors.New("network add failed for " + serverNetworkSettings.NetID)
 			}
 			}
-			if !strings.Contains(err.Error(), "macaddress_unique") { // ignore macaddress unique error throws
-				logger.Log(1, "error adding network", serverNetworkSettings.NetID, "during sync:", err.Error())
-			}
-		}
-	}
-
-	// remove networks locally that do not exist in database
-	/*
-		for _, localnet := range localnets {
-			if strings.Contains(localnet.Name, "nm-") {
-				var exists = ""
-				if serverNetworkSettings.DefaultInterface == localnet.Name {
-					exists = serverNetworkSettings.NetID
+			/*
+				if !strings.Contains(err.Error(), "macaddress_unique") { // ignore macaddress unique error throws
+					logger.Log(1, "error adding network", serverNetworkSettings.NetID, "during sync:", err.Error())
 				}
 				}
-				if exists == "" {
-					err := logic.DeleteNodeByID(serverNode, true)
-					if err != nil {
-						if err == nil {
-							err = errors.New("network delete failed for " + exists)
-						}
-						logger.Log(1, "error removing network", exists, "during sync", err.Error())
-					}
-				}
-			}
+			*/
 		}
 		}
-	*/
+	}
 	return nil
 	return nil
 }
 }