Browse Source

Merge pull request #984 from gravitl/v0.12.2

V0.12.2
dcarns 3 years ago
parent
commit
0df0899059
43 changed files with 385 additions and 336 deletions
  1. 3 3
      .github/workflows/buildandrelease.yml
  2. 0 117
      .github/workflows/test-artifacts.yml
  3. 1 1
      .github/workflows/test.yml
  4. 2 2
      Dockerfile
  5. 2 2
      compose/docker-compose.contained.yml
  6. 2 2
      compose/docker-compose.hostnetwork.yml
  7. 2 2
      compose/docker-compose.nocaddy.yml
  8. 2 2
      compose/docker-compose.nodns.yml
  9. 2 2
      compose/docker-compose.reference.yml
  10. 2 2
      compose/docker-compose.yml
  11. 6 14
      config/config.go
  12. 1 1
      config/config_test.go
  13. 2 2
      docker/Dockerfile-builder
  14. 1 1
      docker/Dockerfile-netclient
  15. 1 1
      docker/Dockerfile-netclient-doks
  16. 1 1
      docker/Dockerfile-netclient-doks-uspace
  17. 1 1
      docker/Dockerfile-netclient-full
  18. 1 1
      docker/Dockerfile-netclient-kernel
  19. 1 1
      docker/Dockerfile-netclient-multiarch
  20. 1 1
      docker/Dockerfile-netmaker-slim
  21. 0 13
      functions/helpers.go
  22. 93 0
      functions/helpers_test.go
  23. 13 12
      go.mod
  24. 39 72
      go.sum
  25. 6 0
      logger/util.go
  26. 2 2
      logic/accesskeys.go
  27. 1 1
      logic/accesskeys_test.go
  28. 20 0
      logic/peers.go
  29. 18 2
      main.go
  30. 3 1
      mq/handlers.go
  31. 6 2
      mq/publishers.go
  32. 34 0
      netclient/bin-maker.sh
  33. 20 0
      netclient/cli_options/cmds.go
  34. 18 0
      netclient/cli_options/flags.go
  35. 0 1
      netclient/config/config.go
  36. 2 1
      netclient/functions/join.go
  37. 5 0
      netclient/functions/list.go
  38. 4 3
      netclient/main.go
  39. 9 36
      netclient/ncutils/netclientutils.go
  40. 32 0
      netclient/ncutils/netclientutils_test.go
  41. 1 14
      scripts/build-binaries.sh
  42. 21 17
      serverctl/iptables.go
  43. 4 0
      serverctl/serverctl.go

+ 3 - 3
.github/workflows/buildandrelease.yml

@@ -264,7 +264,7 @@ jobs:
       - name: Setup go
         uses: actions/setup-go@v2
         with:
-          go-version: 1.17
+          go-version: 1.18
       - name: Build
         run: |
           cd netclient
@@ -294,7 +294,7 @@ jobs:
       - name: Setup go
         uses: actions/setup-go@v2
         with:
-          go-version: 1.17
+          go-version: 1.18
       - name: Build
         run: |
           cd netclient
@@ -369,7 +369,7 @@ jobs:
       - name: Setup go                                    
         uses: actions/setup-go@v2                        
         with:                                           
-          go-version: 1.17                             
+          go-version: 1.18
       - name: Build                                   
         run: |                                       
           cd netclient                              

+ 0 - 117
.github/workflows/test-artifacts.yml

@@ -1,117 +0,0 @@
-name: Build artifacts for deployment testing 
-
-on:
-    push:
-        branches:
-            - 'testing'
-    workflow_dispatch:
-
-jobs:
-    docker:
-        runs-on: ubuntu-latest
-        steps:
-            - name: Checkout
-              uses: actions/checkout@v2
-            - name: Setup Go
-              uses: actions/setup-go@v2
-              with:
-                  go-version: 1.17
-            - name: Set up QEMU
-              uses: docker/setup-qemu-action@v1
-            - name: Set up Docker Buildx
-              uses: docker/setup-buildx-action@v1
-            - name: Login to DockerHub
-              uses: docker/login-action@v1
-              with:
-                  registry: ghcr.io
-                  username: ${{ github.actor }}
-                  password: ${{ secrets.GITHUB_TOKEN }}
-            - name: Build and Push test
-              uses: docker/build-push-action@v2
-              with:
-                  context: .
-                  platforms: linux/amd64
-                  push: true
-                  tags: ghcr.io/${{ github.repository }}:testing
-                  build-args: version=testing
-    docker-netclient:
-        runs-on: ubuntu-latest
-        steps:
-            - name: Checkout                 
-              uses: actions/checkout@v2
-            - name: Setup Go
-              uses: actions/setup-go@v2
-              with:
-                  go-version: 1.17
-            - name: Set up QEMU
-              uses: docker/setup-qemu-action@v1
-            - name: Set up Docker Buildx
-              uses: docker/setup-buildx-action@v1
-            - name: Login to DockerHub
-              uses: docker/login-action@v1
-              with:
-                  registry: ghcr.io
-                  username: ${{ github.actor }}
-                  password: ${{ secrets.GITHUB_TOKEN }}
-            - name: Build and Push test
-              uses: docker/build-push-action@v2
-              with:
-                  context: .
-                  platforms: linux/amd64, linux/arm64
-                  file: ./docker/Dockerfile-netclient-multiarch
-                  push: true
-                  tags: ghcr.io/gravitl/netclient:testing
-                  build-args: version=testing                
-    netclient:
-        runs-on: ubuntu-latest
-        steps:
-            - name: Checkout
-              uses: actions/checkout@v2
-            - name: Setup Go
-              uses: actions/setup-go@v2
-              with:
-                go-version: 1.17
-            - name: build client
-              run: |
-                cd netclient
-                env CGO_ENABLED=0 go build -ldflags="-X 'main.version=testing'" -o build/netclient
-            - name: deploy
-              uses: mdallasanta/[email protected]
-              with:
-                local: ./netclient/build/netclient                            # Local file path - REQUIRED false - DEFAULT ./
-                remote: /var/www/files/testing/                               # Remote file path - REQUIRED false - DEFAULT ~/
-                host: fileserver.clustercat.com                               # Remote server address - REQUIRED true
-                #port: ${{secrets.PORT}}                                      # Remote server port - REQUIRED false - DEFAULT 22
-                user: root                                                    # Remote server user - REQUIRED true
-                #password: ${{secrets.PASSWORD}}                              # User password - REQUIRED at least one of "password" or "key" 
-                key: ${{secrets.TESTING_SSH_KEY}}                             # Remote server private key - REQUIRED at least one of "password" or "key" 
-                #pre_upload: echo "This will be executed before the upload!"  # Command to run via ssh before scp upload - REQUIRED false
-                #post_upload: echo "This will be executed after the upload!"  # Command to run via ssh after scp upload - REQUIRED false
-                #ssh_options: -o StrictHostKeyChecking=no                     # A set of ssh_option separated by -o - REQUIRED false - DEFAULT -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null
-                #scp_options: -v                                              # Flags to use during scp - REQUIRED false - DEFAULT ''
-    netmaker:
-        runs-on: ubuntu-latest
-        steps:
-            - name: Checkout
-              uses: actions/checkout@v2
-            - name: Setup Go
-              uses: actions/setup-go@v2
-              with:
-                go-version: 1.17
-            - name: build server
-              run:
-                env CGO_ENABLED=1 go build -ldflags="-X 'main.version=testing'" -o build/netmaker
-            - name: deploy
-              uses: mdallasanta/[email protected]
-              with:
-                local: ./build/netmaker                                       # Local file path - REQUIRED false - DEFAULT ./
-                remote: /var/www/files/testing/                               # Remote file path - REQUIRED false - DEFAULT ~/
-                host: fileserver.clustercat.com                               # Remote server address - REQUIRED true
-                #port: ${{secrets.PORT}}                                      # Remote server port - REQUIRED false - DEFAULT 22
-                user: root                                                    # Remote server user - REQUIRED true
-                #password: ${{secrets.PASSWORD}}                              # User password - REQUIRED at least one of "password" or "key" 
-                key: ${{secrets.TESTING_SSH_KEY}}                             # Remote server private key - REQUIRED at least one of "password" or "key" 
-                #pre_upload: echo "This will be executed before the upload!"  # Command to run via ssh before scp upload - REQUIRED false
-                #post_upload: echo "This will be executed after the upload!"  # Command to run via ssh after scp upload - REQUIRED false
-                #ssh_options: -o StrictHostKeyChecking=no                     # A set of ssh_option separated by -o - REQUIRED false - DEFAULT -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null
-                #scp_options: -v                                              # Flags to use during scp - REQUIRED false - DEFAULT ''

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

@@ -12,7 +12,7 @@ jobs:
       - name: Setup Go
         uses: actions/setup-go@v2
         with:
-            go-version: 1.17
+            go-version: 1.18
       - name: Build
         run: |
          env CGO_ENABLED=1 GOOS=linux GOARCH=amd64 go build main.go

+ 2 - 2
Dockerfile

@@ -1,5 +1,5 @@
 #first stage - builder
-FROM golang:1.17-alpine as builder
+FROM golang:1.18.0-alpine3.15 as builder
 ARG version 
 RUN apk add build-base
 WORKDIR /app
@@ -7,7 +7,7 @@ COPY . .
 ENV GO111MODULE=auto
 
 RUN GOOS=linux CGO_ENABLED=1 go build -ldflags="-s -X 'main.version=${version}'" -o netmaker main.go
-FROM alpine:3.14.3
+FROM alpine:3.15.2
 
 # add a c lib
 RUN apk add gcompat iptables wireguard-tools

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

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

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

@@ -3,7 +3,7 @@ version: "3.4"
 services:
   netmaker:
     container_name: netmaker
-    image: gravitl/netmaker:v0.12.1
+    image: gravitl/netmaker:v0.12.2
     volumes:
       - dnsconfig:/root/config/dnsconfig
       - /usr/bin/wg:/usr/bin/wg
@@ -41,7 +41,7 @@ services:
     container_name: netmaker-ui
     depends_on:
       - netmaker
-    image: gravitl/netmaker-ui:0.12.1
+    image: gravitl/netmaker-ui:0.12.2
     links:
       - "netmaker:api"
     ports:

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

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

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

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

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

@@ -2,7 +2,7 @@ services:
   netmaker: # The Primary Server for running Netmaker
     privileged: true # Necessary to run sudo/root level commands on host system. Likely using this if running with host networking on.
     container_name: netmaker
-    image: gravitl/netmaker:v0.12.1
+    image: gravitl/netmaker:v0.12.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)
       - dnsconfig:/root/config/dnsconfig # Netmaker writes Corefile to this location, which gets mounted by CoreDNS for DNS configuration.
       - sqldata:/root/data
@@ -44,7 +44,7 @@ services:
     container_name: netmaker-ui
     depends_on:
       - netmaker
-    image: gravitl/netmaker-ui:v0.12.1
+    image: gravitl/netmaker-ui:v0.12.2
     links:
       - "netmaker:api"
     ports:

+ 2 - 2
compose/docker-compose.yml

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

+ 6 - 14
config/config.go

@@ -13,18 +13,15 @@ import (
 
 // setting dev by default
 func getEnv() string {
-
 	env := os.Getenv("NETMAKER_ENV")
-
 	if len(env) == 0 {
 		return "dev"
 	}
-
 	return env
 }
 
 // Config : application config stored as global variable
-var Config *EnvironmentConfig
+var Config *EnvironmentConfig = &EnvironmentConfig{}
 var SetupErr error
 
 // EnvironmentConfig - environment conf struct
@@ -90,9 +87,11 @@ type SQLConfig struct {
 }
 
 // reading in the env file
-func readConfig() (*EnvironmentConfig, error) {
-	file := fmt.Sprintf("environments/%s.yaml", getEnv())
-	f, err := os.Open(file)
+func ReadConfig(absolutePath string) (*EnvironmentConfig, error) {
+	if len(absolutePath) == 0 {
+		absolutePath = fmt.Sprintf("environments/%s.yaml", getEnv())
+	}
+	f, err := os.Open(absolutePath)
 	var cfg EnvironmentConfig
 	if err != nil {
 		return &cfg, err
@@ -104,11 +103,4 @@ func readConfig() (*EnvironmentConfig, error) {
 		return &cfg, err
 	}
 	return &cfg, err
-
-}
-
-func init() {
-	if Config, SetupErr = readConfig(); SetupErr != nil {
-		Config = &EnvironmentConfig{}
-	}
 }

+ 1 - 1
config/config_test.go

@@ -23,7 +23,7 @@ func Test_readConfig(t *testing.T) {
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
-			got, err := readConfig()
+			got, err := ReadConfig("")
 			if (err != nil) != tt.wantErr {
 				t.Errorf("readConfig() error = %v, wantErr %v", err, tt.wantErr)
 				return

+ 2 - 2
docker/Dockerfile-builder

@@ -1,8 +1,8 @@
-FROM alpine:3.13.6
+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://dl.google.com/go/go1.17.1.linux-amd64.tar.gz 
+RUN wget -O go.tgz https://go.dev/dl/go1.18.linux-amd64.tar.gz
 
 RUN tar -C /usr/local -xzf go.tgz 
 

+ 1 - 1
docker/Dockerfile-netclient

@@ -8,7 +8,7 @@ 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.13.6
+FROM alpine:3.15.2
 
 RUN apk add gcompat iptables && mkdir -p /etc/netclient
 # set the working directory

+ 1 - 1
docker/Dockerfile-netclient-doks

@@ -3,7 +3,7 @@ FROM debian:buster as builder
 
 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://dl.google.com/go/go1.17.1.linux-amd64.tar.gz
+RUN wget -O go.tgz https://go.dev/dl/go1.18.linux-amd64.tar.gz
 
 RUN tar -C /usr/local -xzf go.tgz
 

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

@@ -3,7 +3,7 @@ FROM debian:buster as builder
 
 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://dl.google.com/go/go1.17.1.linux-amd64.tar.gz
+RUN wget -O go.tgz https://go.dev/dl/go1.18.linux-amd64.tar.gz
 
 RUN tar -C /usr/local -xzf go.tgz
 

+ 1 - 1
docker/Dockerfile-netclient-full

@@ -24,7 +24,7 @@ RUN git clone https://git.zx2c4.com/wireguard-tools && \
     make && \
     make install
 
-FROM alpine:3.13.6
+FROM alpine:3.15.2
 
 WORKDIR /root/
 

+ 1 - 1
docker/Dockerfile-netclient-kernel

@@ -3,7 +3,7 @@ FROM debian:buster as builder
 
 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://dl.google.com/go/go1.17.1.linux-amd64.tar.gz
+RUN wget -O go.tgz https://go.dev/dl/go1.18.linux-amd64.tar.gz
 
 RUN tar -C /usr/local -xzf go.tgz
 

+ 1 - 1
docker/Dockerfile-netclient-multiarch

@@ -9,7 +9,7 @@ ENV GO111MODULE=auto
 
 RUN GOOS=linux CGO_ENABLED=0 /usr/local/go/bin/go build -ldflags="-w -s -X 'main.version=${TAG}'" -o netclient-app netclient/main.go
 
-FROM alpine:3.13.6
+FROM alpine:3.15.2
 
 WORKDIR /root/
 

+ 1 - 1
docker/Dockerfile-netmaker-slim

@@ -9,7 +9,7 @@ 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.13.6
+FROM alpine:3.15.2
 # add a c lib
 RUN apk add gcompat iptables wireguard-tools
 # set the working directory

+ 0 - 13
functions/helpers.go

@@ -71,16 +71,3 @@ func GetAllExtClients() ([]models.ExtClient, error) {
 
 	return extclients, nil
 }
-
-// DeleteKey - deletes a key
-func DeleteKey(network models.Network, i int) {
-
-	network.AccessKeys = append(network.AccessKeys[:i],
-		network.AccessKeys[i+1:]...)
-
-	if networkData, err := json.Marshal(&network); err != nil {
-		return
-	} else {
-		database.Insert(network.NetID, string(networkData), database.NETWORKS_TABLE_NAME)
-	}
-}

+ 93 - 0
functions/helpers_test.go

@@ -0,0 +1,93 @@
+package functions
+
+import (
+	"encoding/json"
+	"testing"
+
+	"github.com/gravitl/netmaker/database"
+	"github.com/gravitl/netmaker/logic"
+	"github.com/gravitl/netmaker/models"
+)
+
+var (
+	testNetwork = &models.Network{
+		NetID: "not-a-network",
+	}
+	testExternalClient = &models.ExtClient{
+		ClientID:    "testExtClient",
+		Description: "ext client for testing",
+	}
+)
+
+func TestNetworkExists(t *testing.T) {
+	err := database.InitializeDatabase()
+	if err != nil {
+		t.Fatalf("error initilizing database: %s", err)
+	}
+	database.DeleteRecord(database.NETWORKS_TABLE_NAME, testNetwork.NetID)
+	defer database.CloseDB()
+	exists, err := NetworkExists(testNetwork.NetID)
+	if err == nil {
+		t.Fatalf("expected error, received nil")
+	}
+	if exists {
+		t.Fatalf("expected false")
+	}
+
+	err = logic.SaveNetwork(testNetwork)
+	if err != nil {
+		t.Fatalf("failed to save test network in databse: %s", err)
+	}
+	exists, err = NetworkExists(testNetwork.NetID)
+	if err != nil {
+		t.Fatalf("expected nil, received err: %s", err)
+	}
+	if !exists {
+		t.Fatalf("expected network to exist in database")
+	}
+
+	err = database.DeleteRecord(database.NETWORKS_TABLE_NAME, testNetwork.NetID)
+	if err != nil {
+		t.Fatalf("expected nil, failed to delete test network: %s", err)
+	}
+}
+
+func TestGetAllExtClients(t *testing.T) {
+	err := database.InitializeDatabase()
+	if err != nil {
+		t.Fatalf("error initilizing database: %s", err)
+	}
+	defer database.CloseDB()
+	database.DeleteRecord(database.EXT_CLIENT_TABLE_NAME, testExternalClient.ClientID)
+
+	extClients, err := GetAllExtClients()
+	if err == nil {
+		t.Fatalf("expected error, received nil")
+	}
+	if len(extClients) >= 1 {
+		t.Fatalf("expected no external clients, received %d", len(extClients))
+	}
+
+	extClient, err := json.Marshal(testExternalClient)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	err = database.Insert(testExternalClient.ClientID, string(extClient), database.EXT_CLIENT_TABLE_NAME)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	extClients, err = GetAllExtClients()
+	if err != nil {
+		t.Fatalf("expected nil, received: %s", err)
+	}
+	if len(extClients) < 1 {
+		t.Fatalf("expected 1 external client, received %d", len(extClients))
+	}
+
+	err = database.DeleteRecord(database.EXT_CLIENT_TABLE_NAME, testExternalClient.ClientID)
+	if err != nil {
+		t.Fatalf("failed removing extclient: %s", err)
+	}
+}

+ 13 - 12
go.mod

@@ -1,11 +1,11 @@
 module github.com/gravitl/netmaker
 
-go 1.17
+go 1.18
 
 require (
 	github.com/eclipse/paho.mqtt.golang v1.3.5
 	github.com/go-playground/validator/v10 v10.10.1
-	github.com/golang-jwt/jwt/v4 v4.4.0
+	github.com/golang-jwt/jwt/v4 v4.4.1
 	github.com/golang/protobuf v1.5.2 // indirect
 	github.com/google/uuid v1.3.0
 	github.com/gorilla/handlers v1.5.1
@@ -17,16 +17,16 @@ require (
 	github.com/stretchr/testify v1.7.1
 	github.com/txn2/txeh v1.3.0
 	github.com/urfave/cli/v2 v2.4.0
-	golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3
-	golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 // indirect
+	golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd
+	golang.org/x/net v0.0.0-20220225172249-27dd8689420f // indirect
 	golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d
-	golang.org/x/sys v0.0.0-20210903071746-97244b99971b // indirect
+	golang.org/x/sys v0.0.0-20220315194320-039c03cc5b86 // indirect
 	golang.org/x/text v0.3.7 // indirect
-	golang.zx2c4.com/wireguard v0.0.0-20210805125648-3957e9b9dd19 // indirect
-	golang.zx2c4.com/wireguard/wgctrl v0.0.0-20210913210325-91d1988e44de
+	golang.zx2c4.com/wireguard v0.0.0-20220318042302-193cf8d6a5d6 // indirect
+	golang.zx2c4.com/wireguard/wgctrl v0.0.0-20220324164955-056925b7df31
 	google.golang.org/genproto v0.0.0-20210201151548-94839c025ad4 // indirect
 	google.golang.org/grpc v1.45.0
-	google.golang.org/protobuf v1.27.1
+	google.golang.org/protobuf v1.28.0
 	gopkg.in/ini.v1 v1.66.4
 	gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
 )
@@ -50,12 +50,13 @@ require (
 	github.com/go-playground/locales v0.14.0 // indirect
 	github.com/go-playground/universal-translator v0.18.0 // indirect
 	github.com/gogo/protobuf v1.3.1 // indirect
-	github.com/google/go-cmp v0.5.6 // indirect
+	github.com/google/go-cmp v0.5.7 // indirect
 	github.com/gorilla/websocket v1.4.2 // indirect
-	github.com/josharian/native v0.0.0-20200817173448-b6b71def0850 // indirect
+	github.com/josharian/native v1.0.0 // indirect
 	github.com/leodido/go-urn v1.2.1 // indirect
-	github.com/mdlayher/genetlink v1.0.0 // indirect
-	github.com/mdlayher/netlink v1.4.0 // indirect
+	github.com/mdlayher/genetlink v1.2.0 // indirect
+	github.com/mdlayher/netlink v1.6.0 // indirect
+	github.com/mdlayher/socket v0.1.1 // indirect
 	github.com/opencontainers/go-digest v1.0.0 // indirect
 	github.com/opencontainers/image-spec v1.0.1 // indirect
 	github.com/pkg/errors v0.9.1 // indirect

+ 39 - 72
go.sum

@@ -27,7 +27,6 @@ github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8Nz
 github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
 github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
 github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
-github.com/cpuguy83/go-md2man v1.0.10 h1:BSKMNlYxDvnunlTymqtgONjNnaRV1sTpcovwwjF22jk=
 github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
 github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
 github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
@@ -77,8 +76,8 @@ github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7a
 github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
 github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls=
 github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
-github.com/golang-jwt/jwt/v4 v4.4.0 h1:EmVIxB5jzbllGIjiCV5JG4VylbK3KE400tLGLI1cdfU=
-github.com/golang-jwt/jwt/v4 v4.4.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
+github.com/golang-jwt/jwt/v4 v4.4.1 h1:pC5DB52sCeK48Wlb9oPcdhnjkz1TKt1D/P7WKJ0kUcQ=
+github.com/golang-jwt/jwt/v4 v4.4.1/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
 github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
 github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
 github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
@@ -103,11 +102,10 @@ github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw
 github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
 github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
 github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o=
+github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=
 github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
 github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
 github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
@@ -132,16 +130,8 @@ github.com/guumaster/tablewriter v0.0.9/go.mod h1:9B1xy1BLPtcVAeYjC1EXPxcklqnzk7
 github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
 github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
 github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
-github.com/josharian/native v0.0.0-20200817173448-b6b71def0850 h1:uhL5Gw7BINiiPAo24A2sxkcDI0Jt/sqp1v5xQCniEFA=
-github.com/josharian/native v0.0.0-20200817173448-b6b71def0850/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w=
-github.com/jsimonetti/rtnetlink v0.0.0-20190606172950-9527aa82566a/go.mod h1:Oz+70psSo5OFh8DBl0Zv2ACw7Esh6pPUphlvZG9x7uw=
-github.com/jsimonetti/rtnetlink v0.0.0-20200117123717-f846d4f6c1f4/go.mod h1:WGuG/smIU4J/54PblvSbh+xvCZmpJnFgr3ds6Z55XMQ=
-github.com/jsimonetti/rtnetlink v0.0.0-20201009170750-9c6f07d100c1/go.mod h1:hqoO/u39cqLeBLebZ8fWdE96O7FxrAsRYhnVOdgHxok=
-github.com/jsimonetti/rtnetlink v0.0.0-20201216134343-bde56ed16391/go.mod h1:cR77jAZG3Y3bsb8hF6fHJbFoyFukLFOkQ98S0pQz3xw=
-github.com/jsimonetti/rtnetlink v0.0.0-20201220180245-69540ac93943/go.mod h1:z4c53zj6Eex712ROyh8WI0ihysb5j2ROyV42iNogmAs=
-github.com/jsimonetti/rtnetlink v0.0.0-20210122163228-8d122574c736/go.mod h1:ZXpIyOK59ZnN7J0BV99cZUPmsqDRZ3eq5X+st7u/oSA=
-github.com/jsimonetti/rtnetlink v0.0.0-20210212075122-66c871082f2b h1:c3NTyLNozICy8B4mlMXemD3z/gXgQzVXZS/HqT+i3do=
-github.com/jsimonetti/rtnetlink v0.0.0-20210212075122-66c871082f2b/go.mod h1:8w9Rh8m+aHZIG69YPGGem1i5VzoyRC8nw2kA8B+ik5U=
+github.com/josharian/native v1.0.0 h1:Ts/E8zCSEsG17dUqv7joXJFybuMLjQfWE04tsBODTxk=
+github.com/josharian/native v1.0.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w=
 github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
 github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
 github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
@@ -169,20 +159,12 @@ github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m
 github.com/mattn/go-sqlite3 v1.14.10 h1:MLn+5bFRlWMGoSRmJour3CL1w/qL96mvipqpwQW/Sfk=
 github.com/mattn/go-sqlite3 v1.14.10/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
 github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
-github.com/mdlayher/ethtool v0.0.0-20210210192532-2b88debcdd43 h1:WgyLFv10Ov49JAQI/ZLUkCZ7VJS3r74hwFIGXJsgZlY=
-github.com/mdlayher/ethtool v0.0.0-20210210192532-2b88debcdd43/go.mod h1:+t7E0lkKfbBsebllff1xdTmyJt8lH37niI6kwFk9OTo=
-github.com/mdlayher/genetlink v1.0.0 h1:OoHN1OdyEIkScEmRgxLEe2M9U8ClMytqA5niynLtfj0=
-github.com/mdlayher/genetlink v1.0.0/go.mod h1:0rJ0h4itni50A86M2kHcgS85ttZazNt7a8H2a2cw0Gc=
-github.com/mdlayher/netlink v0.0.0-20190409211403-11939a169225/go.mod h1:eQB3mZE4aiYnlUsyGGCOpPETfdQq4Jhsgf1fk3cwQaA=
-github.com/mdlayher/netlink v1.0.0/go.mod h1:KxeJAFOFLG6AjpyDkQ/iIhxygIUKD+vcwqcnu43w/+M=
-github.com/mdlayher/netlink v1.1.0/go.mod h1:H4WCitaheIsdF9yOYu8CFmCgQthAPIWZmcKp9uZHgmY=
-github.com/mdlayher/netlink v1.1.1/go.mod h1:WTYpFb/WTvlRJAyKhZL5/uy69TDDpHHu2VZmb2XgV7o=
-github.com/mdlayher/netlink v1.2.0/go.mod h1:kwVW1io0AZy9A1E2YYgaD4Cj+C+GPkU6klXCMzIJ9p8=
-github.com/mdlayher/netlink v1.2.1/go.mod h1:bacnNlfhqHqqLo4WsYeXSqfyXkInQ9JneWI68v1KwSU=
-github.com/mdlayher/netlink v1.2.2-0.20210123213345-5cc92139ae3e/go.mod h1:bacnNlfhqHqqLo4WsYeXSqfyXkInQ9JneWI68v1KwSU=
-github.com/mdlayher/netlink v1.3.0/go.mod h1:xK/BssKuwcRXHrtN04UBkwQ6dY9VviGGuriDdoPSWys=
-github.com/mdlayher/netlink v1.4.0 h1:n3ARR+Fm0dDv37dj5wSWZXDKcy+U0zwcXS3zKMnSiT0=
-github.com/mdlayher/netlink v1.4.0/go.mod h1:dRJi5IABcZpBD2A3D0Mv/AiX8I9uDEu5oGkAVrekmf8=
+github.com/mdlayher/genetlink v1.2.0 h1:4yrIkRV5Wfk1WfpWTcoOlGmsWgQj3OtQN9ZsbrE+XtU=
+github.com/mdlayher/genetlink v1.2.0/go.mod h1:ra5LDov2KrUCZJiAtEvXXZBxGMInICMXIwshlJ+qRxQ=
+github.com/mdlayher/netlink v1.6.0 h1:rOHX5yl7qnlpiVkFWoqccueppMtXzeziFjWAjLg6sz0=
+github.com/mdlayher/netlink v1.6.0/go.mod h1:0o3PlBmGst1xve7wQ7j/hwpNaFaH4qCRyWCdcZk8/vA=
+github.com/mdlayher/socket v0.1.1 h1:q3uOGirUPfAV2MUoaC7BavjQ154J7+JOkTWyiV+intI=
+github.com/mdlayher/socket v0.1.1/go.mod h1:mYV5YIZAfHh4dzDVzI8x8tWLWCliuX8Mon5Awbj+qDs=
 github.com/mikioh/ipaddr v0.0.0-20190404000644-d465c8ab6721 h1:RlZweED6sbSArvlE924+mUcZuXKLBHA35U7LN621Bws=
 github.com/mikioh/ipaddr v0.0.0-20190404000644-d465c8ab6721/go.mod h1:Ickgr2WtCLZ2MDGd4Gr0geeCH5HybhRJbonOgQpvSxc=
 github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
@@ -221,7 +203,6 @@ github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUA
 github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
 github.com/rqlite/gorqlite v0.0.0-20210514125552-08ff1e76b22f h1:BSnJgAfHzEp7o8PYJ7YfwAVHhqu7BYUTggcn/LGlUWY=
 github.com/rqlite/gorqlite v0.0.0-20210514125552-08ff1e76b22f/go.mod h1:UW/gxgQwSePTvL1KA8QEHsXeYHP4xkoXgbDdN781p34=
-github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo=
 github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
 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=
@@ -258,7 +239,6 @@ github.com/txn2/txeh v1.3.0 h1:vnbv63htVMZCaQgLqVBxKvj2+HHHFUzNW7I183zjg3E=
 github.com/txn2/txeh v1.3.0/go.mod h1:O7M6gUTPeMF+vsa4c4Ipx3JDkOYrruB1Wry8QRsMcw8=
 github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
 github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
-github.com/urfave/cli v1.22.5 h1:lNq9sAHXK2qfdI8W+GRItjCEkI+2oR4d+MEHy1CKXoU=
 github.com/urfave/cli v1.22.5/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
 github.com/urfave/cli/v2 v2.4.0 h1:m2pxjjDFgDxSPtO8WSdbndj17Wu2y8vOT86wE/tjr+I=
 github.com/urfave/cli/v2 v2.4.0/go.mod h1:NX9W0zmTvedE5oDoOMs2RTC8RvdK98NTYZE5LbaEYPg=
@@ -276,10 +256,11 @@ golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnf
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
 golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
-golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
-golang.org/x/crypto v0.0.0-20210503195802-e9a32991a82e/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
-golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3 h1:0es+/5331RGQPcXlMfP+WrnIIS6dNnNRe0WB02W0F4M=
+golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
 golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
+golang.org/x/crypto v0.0.0-20220208050332-20e1d8d225ab/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
+golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd h1:XcWmESyNjXJMLahc3mqVQJcgSTDxFxhETVlfk9uGc38=
+golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
 golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
 golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
@@ -293,22 +274,17 @@ golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73r
 golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
 golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
 golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
-golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20191007182048-72f939374954/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20200425230154-ff2c4b7c35a0/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
 golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
 golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
-golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
-golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
-golang.org/x/net v0.0.0-20201216054612-986b41b23924/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
-golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
-golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
 golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
 golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
-golang.org/x/net v0.0.0-20210504132125-bbd867fde50d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
-golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 h1:CIJ76btIcR3eFI5EgSo6k1qKw9KJexJuRLI9G7Hp5wE=
+golang.org/x/net v0.0.0-20210928044308-7d9f5e0b762b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.0.0-20211111083644-e5c967477495/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
 golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
+golang.org/x/net v0.0.0-20220225172249-27dd8689420f h1:oA4XRj0qtSt8Yo1Zms0CUlsT3KG69V2UGQWPBxujDmc=
+golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
 golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
 golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d h1:TzXSXBo42m9gQenoE3b9BGiEpg5IG2JkU5FkPIawgtw=
 golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -324,37 +300,26 @@ golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5h
 golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190411185658-b44545bcd369/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200720211630-cb9d2d5c5666/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20201009025420-dfb3f7c4e634/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20201118182958-a01c418693c7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20201218084310-7d0127a74742/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210110051926-789bb1bd4061/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210123111255-9b0068b26619/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210216163648-f7da38b97c65/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210309040221-94ec62e08169/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210503173754-0981d6026fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20210903071746-97244b99971b h1:3Dq0eVHn0uaQJmPO+/aYPI/fRMqdrVDbu7MQcku54gg=
-golang.org/x/sys v0.0.0-20210903071746-97244b99971b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
+golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20211110154304-99a53858aa08/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220207234003-57398862261d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220315194320-039c03cc5b86 h1:A9i04dxx7Cribqbs8jf3FQLogkL/CV2YN7hj9KWJCkc=
+golang.org/x/sys v0.0.0-20220315194320-039c03cc5b86/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
+golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
@@ -371,11 +336,13 @@ golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBn
 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
 golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-golang.zx2c4.com/wireguard v0.0.0-20210427022245-097af6e1351b/go.mod h1:a057zjmoc00UN7gVkaJt2sXVK523kMJcogDTEvPIasg=
-golang.zx2c4.com/wireguard v0.0.0-20210805125648-3957e9b9dd19 h1:ab2jcw2W91Rz07eHAb8Lic7sFQKO0NhBftjv6m/gL/0=
-golang.zx2c4.com/wireguard v0.0.0-20210805125648-3957e9b9dd19/go.mod h1:laHzsbfMhGSobUmruXWAyMKKHSqvIcrqZJMyHD+/3O8=
-golang.zx2c4.com/wireguard/wgctrl v0.0.0-20210913210325-91d1988e44de h1:M9Jc92kgqmVmidpnOeegP2VgO2DfHEcsUWtWMmBwNFQ=
-golang.zx2c4.com/wireguard/wgctrl v0.0.0-20210913210325-91d1988e44de/go.mod h1:+1XihzyZUBJcSc5WO9SwNA7v26puQwOEDwanaxfNXPQ=
+golang.zx2c4.com/go118/netip v0.0.0-20211111135330-a4a02eeacf9d/go.mod h1:5yyfuiqVIJ7t+3MqrpTQ+QqRkMWiESiyDvPNvKYCecg=
+golang.zx2c4.com/wintun v0.0.0-20211104114900-415007cec224/go.mod h1:deeaetjYA+DHMHg+sMSMI58GrEteJUUzzw7en6TJQcI=
+golang.zx2c4.com/wireguard v0.0.0-20220202223031-3b95c81cc178/go.mod h1:TjUWrnD5ATh7bFvmm/ALEJZQ4ivKbETb6pmyj1vUoNI=
+golang.zx2c4.com/wireguard v0.0.0-20220318042302-193cf8d6a5d6 h1:kgBK1EGuTIYbwoKROmsoV0FQp08gnCcVa110A4Unqhk=
+golang.zx2c4.com/wireguard v0.0.0-20220318042302-193cf8d6a5d6/go.mod h1:bVQfyl2sCM/QIIGHpWbFGfHPuDvqnCNkT6MQLTCjO/U=
+golang.zx2c4.com/wireguard/wgctrl v0.0.0-20220324164955-056925b7df31 h1:AgW3hljgTzuRbCB0j+q9tXT0uy6ij7vMjEzSCeMlQY0=
+golang.zx2c4.com/wireguard/wgctrl v0.0.0-20220324164955-056925b7df31/go.mod h1:8P32Ilp1kCpwB4ItaHyvSk4xAtnpQ+8gQVfg5WaO1TU=
 google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
 google.golang.org/appengine v1.4.0 h1:/wp5JvzpHIxhs/dumFmF7BXTf3Z+dd4uXta4kVyO508=
 google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
@@ -406,8 +373,8 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj
 google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
 google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
 google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
-google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ=
-google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
+google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw=
+google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
 gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=

+ 6 - 0
logger/util.go

@@ -6,6 +6,9 @@ import (
 	"strings"
 )
 
+// Verbosity - current logging verbosity level (optionally set)
+var Verbosity = 0
+
 // MakeString - makes a string using golang string builder
 func MakeString(delimeter string, message ...string) string {
 	var builder strings.Builder
@@ -19,6 +22,9 @@ func MakeString(delimeter string, message ...string) string {
 }
 
 func getVerbose() int32 {
+	if Verbosity >= 1 && Verbosity <= 3 {
+		return int32(Verbosity)
+	}
 	level, err := strconv.Atoi(os.Getenv("VERBOSITY"))
 	if err != nil || level < 0 {
 		level = 0

+ 2 - 2
logic/accesskeys.go

@@ -28,7 +28,7 @@ func CreateAccessKey(accesskey models.AccessKey, network models.Network) (models
 	}
 
 	if accesskey.Value == "" {
-		accesskey.Value = genKey()
+		accesskey.Value = GenKey()
 	}
 	if accesskey.Uses == 0 {
 		accesskey.Uses = 1
@@ -238,7 +238,7 @@ func genKeyName() string {
 	return strings.Join([]string{"key", entropy.Text(16)[:16]}, "-")
 }
 
-func genKey() string {
+func GenKey() string {
 	entropy, _ := rand.Int(rand.Reader, maxentropy)
 	return entropy.Text(16)[:16]
 }

+ 1 - 1
logic/accesskeys_test.go

@@ -14,7 +14,7 @@ func Test_genKeyName(t *testing.T) {
 
 func Test_genKey(t *testing.T) {
 	for i := 0; i < 100; i++ {
-		kname := genKey()
+		kname := GenKey()
 		t.Log(kname)
 		if len(kname) != 16 {
 			t.Fatalf("improper length of key name, expected 16 got :%d", len(kname))

+ 20 - 0
logic/peers.go

@@ -61,6 +61,9 @@ func GetNodePeers(networkName, nodeid string, excludeRelayed bool, isP2S bool) (
 			peer.EgressGatewayRanges = node.EgressGatewayRanges
 			peer.IsEgressGateway = node.IsEgressGateway
 		}
+
+		peer.IsIngressGateway = node.IsIngressGateway
+		isDualStack := node.IsDualStack == "yes"
 		allow := node.IsRelayed != "yes" || !excludeRelayed
 
 		if node.Network == networkName && node.IsPending != "yes" && allow {
@@ -89,6 +92,17 @@ func GetNodePeers(networkName, nodeid string, excludeRelayed bool, isP2S bool) (
 					}
 				}
 			}
+			if peer.IsIngressGateway == "yes" { // handle ingress stuff
+				if currentExtClients, err := GetExtPeersList(&node); err == nil {
+					for i := range currentExtClients {
+						peer.AllowedIPs = append(peer.AllowedIPs, currentExtClients[i].Address)
+						if isDualStack {
+							peer.AllowedIPs = append(peer.AllowedIPs, currentExtClients[i].Address6)
+						}
+					}
+				}
+			}
+
 			if (!isP2S || peer.IsHub == "yes") && currentNetworkACLs.IsAllowed(acls.AclID(nodeid), acls.AclID(node.ID)) {
 				peers = append(peers, peer)
 			}
@@ -237,6 +251,12 @@ func GetPeerUpdate(node *models.Node) (models.PeerUpdate, error) {
 
 
 	*/
+	if customDNSEntries, err := GetCustomDNS(peerUpdate.Network); err == nil {
+		for _, entry := range customDNSEntries {
+			// TODO - filter entries based on ACLs / given peers vs nodes in network
+			dns = dns + fmt.Sprintf("%s %s.%s\n", entry.Address, entry.Name, entry.Network)
+		}
+	}
 	peerUpdate.DNS = dns
 	return peerUpdate, nil
 }

+ 18 - 2
main.go

@@ -2,6 +2,7 @@ package main
 
 import (
 	"context"
+	"flag"
 	"fmt"
 	"net"
 	"os"
@@ -12,6 +13,7 @@ import (
 	"syscall"
 
 	"github.com/gravitl/netmaker/auth"
+	"github.com/gravitl/netmaker/config"
 	controller "github.com/gravitl/netmaker/controllers"
 	"github.com/gravitl/netmaker/database"
 	"github.com/gravitl/netmaker/functions"
@@ -30,6 +32,10 @@ var version = "dev"
 
 // Start DB Connection and start API Request Handler
 func main() {
+	absoluteConfigPath := flag.String("c", "", "absolute path to configuration file")
+	flag.Parse()
+
+	setupConfig(*absoluteConfigPath)
 	servercfg.SetVersion(version)
 	fmt.Println(models.RetrieveLogo()) // print the logo
 	initialize()                       // initial db and grpc server
@@ -38,6 +44,17 @@ func main() {
 	startControllers() // start the grpc or rest endpoints
 }
 
+func setupConfig(absoluteConfigPath string) {
+	if len(absoluteConfigPath) > 0 {
+		cfg, err := config.ReadConfig(absoluteConfigPath)
+		if err != nil {
+			logger.Log(0, fmt.Sprintf("failed parsing config at: %s", absoluteConfigPath))
+			return
+		}
+		config.Config = cfg
+	}
+}
+
 func initialize() { // Client Mode Prereq Check
 	var err error
 
@@ -92,9 +109,8 @@ func initialize() { // Client Mode Prereq Check
 	}
 	// initialize iptables to ensure gateways work correctly and mq is forwarded if containerized
 	if servercfg.ManageIPTables() != "off" {
-		if err = serverctl.InitIPTables(); err != nil {
+		if err = serverctl.InitIPTables(true); err != nil {
 			logger.FatalLog("Unable to initialize iptables on host:", err.Error())
-
 		}
 	}
 

+ 3 - 1
mq/handlers.go

@@ -36,16 +36,18 @@ func Ping(client mqtt.Client, msg mqtt.Message) {
 			logger.Log(0, record)
 			return
 		}
-		_, decryptErr := decryptMsg(&node, msg.Payload())
+		version, decryptErr := decryptMsg(&node, msg.Payload())
 		if decryptErr != nil {
 			logger.Log(0, "error decrypting when updating node ", node.ID, decryptErr.Error())
 			return
 		}
 		node.SetLastCheckIn()
+		node.Version = string(version)
 		if err := logic.UpdateNode(&node, &node); err != nil {
 			logger.Log(0, "error updating node", node.Name, node.ID, " on checkin", err.Error())
 			return
 		}
+
 		logger.Log(3, "ping processed for node", node.ID)
 		// --TODO --set client version once feature is implemented.
 		//node.SetClientVersion(msg.Payload())

+ 6 - 2
mq/publishers.go

@@ -69,7 +69,11 @@ func PublishExtPeerUpdate(node *models.Node) error {
 	if err != nil {
 		return err
 	}
-	return publish(node, fmt.Sprintf("peers/%s/%s", node.Network, node.ID), data)
+	if err = publish(node, fmt.Sprintf("peers/%s/%s", node.Network, node.ID), data); err != nil {
+		return err
+	}
+	go PublishPeerUpdate(node)
+	return nil
 }
 
 // NodeUpdate -- publishes a node update
@@ -99,7 +103,7 @@ func sendPeers() {
 
 		// run iptables update to ensure gateways work correctly and mq is forwarded if containerized
 		if servercfg.ManageIPTables() != "off" {
-			serverctl.InitIPTables()
+			serverctl.InitIPTables(false)
 		}
 
 		force = true

+ 34 - 0
netclient/bin-maker.sh

@@ -0,0 +1,34 @@
+#!/bin/bash
+VERSION=${VERSION:-"develop"}
+echo "build with version tag: $VERSION"
+readonly __HOST_ARCH=${1:-"amd64"}  # change this for your machine.
+readonly __HOST_GOOSE=${2:-"linux"} # change this for your machine.
+readonly __EXEC_DIR=$(dirname "$(realpath $0)") && cd $__EXEC_DIR   
+
+__darwin=( arm64 amd64 )
+__linux=( amd64 arm arm64 mips mips64 mips64le mipsle ppc64 ppc64le riscv64 s390x 386 )
+__freebsd=( amd64 arm arm64 386 )
+__windows=( amd64 arm arm64 386 ) 
+
+function build
+{   
+    local _goarch=${1:-"None"} && if [[ $_goarch == "None" ]]; then exit 1; fi
+    local _goose="${2:-"None"}" && if [[ $_goose == "None" ]]; then exit 1; fi
+    local _goarm=${3:-""}
+    local _out=build/netclient-$_goose-$_goarch$_goarm && mkdir -p build
+    if [ "$_goarch" == "arm" ] && [ "$_goarm" == "" ]; then
+	    build $_goarch $_goose 5 && build $_goarch $_goose 6 && build $_goarch $_goose 7
+    else
+        echo $_out
+        GOARM=$_goarm GOARCH=$_goarch GOOS=$_goose GOHOSTARCH=$__HOST_ARCH CGO_ENABLED=0 go build -ldflags="-X 'main.version=$VERSION'" -o $_out
+    fi
+}
+
+for arch in ${__linux[*]}; do build "$arch" "linux"; done
+
+for arch in ${__freebsd[*]}; do build "$arch" "freebsd"; done
+
+for arch in ${__darwin[*]}; do build "$arch" "darwin"; done
+
+for arch in ${__windows[*]}; do build "$arch" "windows"; done
+

+ 20 - 0
netclient/cli_options/cmds.go

@@ -3,6 +3,7 @@ package cli_options
 import (
 	"errors"
 
+	"github.com/gravitl/netmaker/logger"
 	"github.com/gravitl/netmaker/netclient/command"
 	"github.com/gravitl/netmaker/netclient/config"
 	"github.com/urfave/cli/v2"
@@ -16,6 +17,7 @@ func GetCommands(cliFlags []cli.Flag) []*cli.Command {
 			Usage: "Join a Netmaker network.",
 			Flags: cliFlags,
 			Action: func(c *cli.Context) error {
+				parseVerbosity(c)
 				cfg, pvtKey, err := config.GetCLIConfig(c)
 				if err != nil {
 					return err
@@ -39,6 +41,7 @@ func GetCommands(cliFlags []cli.Flag) []*cli.Command {
 			// the action, or code that will be executed when
 			// we execute our `ns` command
 			Action: func(c *cli.Context) error {
+				parseVerbosity(c)
 				cfg, _, err := config.GetCLIConfig(c)
 				if err != nil {
 					return err
@@ -54,6 +57,7 @@ func GetCommands(cliFlags []cli.Flag) []*cli.Command {
 			// the action, or code that will be executed when
 			// we execute our `ns` command
 			Action: func(c *cli.Context) error {
+				parseVerbosity(c)
 				cfg, _, err := config.GetCLIConfig(c)
 				if err != nil {
 					return err
@@ -69,6 +73,7 @@ func GetCommands(cliFlags []cli.Flag) []*cli.Command {
 			// the action, or code that will be executed when
 			// we execute our `ns` command
 			Action: func(c *cli.Context) error {
+				parseVerbosity(c)
 				cfg, _, err := config.GetCLIConfig(c)
 				if err != nil {
 					return err
@@ -84,6 +89,7 @@ func GetCommands(cliFlags []cli.Flag) []*cli.Command {
 			// the action, or code that will be executed when
 			// we execute our `ns` command
 			Action: func(c *cli.Context) error {
+				parseVerbosity(c)
 				err := command.Uninstall()
 				return err
 			},
@@ -93,9 +99,23 @@ func GetCommands(cliFlags []cli.Flag) []*cli.Command {
 			Usage: "run netclient as daemon",
 			Flags: cliFlags,
 			Action: func(c *cli.Context) error {
+				// set max verbosity for daemon regardless
+				logger.Verbosity = 3
 				err := command.Daemon()
 				return err
 			},
 		},
 	}
 }
+
+// == Private funcs ==
+
+func parseVerbosity(c *cli.Context) {
+	if c.Bool("v") {
+		logger.Verbosity = 1
+	} else if c.Bool("vv") {
+		logger.Verbosity = 2
+	} else if c.Bool("vvv") {
+		logger.Verbosity = 3
+	}
+}

+ 18 - 0
netclient/cli_options/flags.go

@@ -204,5 +204,23 @@ func GetFlags(hostname string) []cli.Flag {
 			Value:   "no",
 			Usage:   "Allows to run the command with force, if otherwise prevented.",
 		},
+		&cli.BoolFlag{
+			Name:    "verbosity-level-1",
+			Aliases: []string{"v"},
+			Value:   false,
+			Usage:   "Netclient Verbosity level 1.",
+		},
+		&cli.BoolFlag{
+			Name:    "verbosity-level-2",
+			Aliases: []string{"vv"},
+			Value:   false,
+			Usage:   "Netclient Verbosity level 2.",
+		},
+		&cli.BoolFlag{
+			Name:    "verbosity-level-3",
+			Aliases: []string{"vvv"},
+			Value:   false,
+			Usage:   "Netclient Verbosity level 3.",
+		},
 	}
 }

+ 0 - 1
netclient/config/config.go

@@ -25,7 +25,6 @@ type ClientConfig struct {
 	Daemon          string         `yaml:"daemon"`
 	OperatingSystem string         `yaml:"operatingsystem"`
 	DebugOn         bool           `yaml:"debugon"`
-	
 }
 
 // ServerConfig - struct for dealing with the server information for a netclient

+ 2 - 1
netclient/functions/join.go

@@ -11,6 +11,7 @@ import (
 
 	nodepb "github.com/gravitl/netmaker/grpc"
 	"github.com/gravitl/netmaker/logger"
+	"github.com/gravitl/netmaker/logic"
 	"github.com/gravitl/netmaker/models"
 	"github.com/gravitl/netmaker/netclient/auth"
 	"github.com/gravitl/netmaker/netclient/config"
@@ -41,7 +42,7 @@ func JoinNetwork(cfg *config.ClientConfig, privateKey string, iscomms bool) erro
 		return err
 	}
 	if cfg.Node.Password == "" {
-		cfg.Node.Password = ncutils.GenPass()
+		cfg.Node.Password = logic.GenKey()
 	}
 	var trafficPubKey, trafficPrivKey, errT = box.GenerateKey(rand.Reader) // generate traffic keys
 	if errT != nil {

+ 5 - 0
netclient/functions/list.go

@@ -14,6 +14,7 @@ import (
 	"google.golang.org/grpc/metadata"
 )
 
+// Peer - the peer struct for list
 type Peer struct {
 	Name           string `json:"name"`
 	Interface      string `json:"interface,omitempty"`
@@ -22,12 +23,15 @@ type Peer struct {
 	PublicEndpoint string `json:"public_endpoint,omitempty"`
 }
 
+// Network - the local node network representation for list command
 type Network struct {
 	Name        string `json:"name"`
+	ID          string `json:"node_id"`
 	CurrentNode Peer   `json:"current_node"`
 	Peers       []Peer `json:"peers"`
 }
 
+// List - lists the current peers for the local node with name and node ID
 func List(network string) error {
 	nets := []Network{}
 	var err error
@@ -69,6 +73,7 @@ func getNetwork(network string) (Network, error) {
 	}
 	return Network{
 		Name:  network,
+		ID:    cfg.Node.ID,
 		Peers: peers,
 		CurrentNode: Peer{
 			Name:           cfg.Node.Name,

+ 4 - 3
netclient/main.go

@@ -17,13 +17,14 @@ var version = "dev"
 
 func main() {
 	app := cli.NewApp()
-	app.Name = "Netclient CLI"
-	app.Usage = "Netmaker's netclient agent and CLI. Used to perform interactions with Netmaker server and set local WireGuard config."
+	app.Name = "Netclient"
 	app.Version = version
 	ncutils.SetVersion(version)
-
 	cliFlags := cli_options.GetFlags(ncutils.GetHostname())
 	app.Commands = cli_options.GetCommands(cliFlags[:])
+	app.Description = "Used to perform interactions with Netmaker server and set local WireGuard config."
+	app.Usage = "Netmaker's netclient agent and CLI."
+	app.UsageText = "netclient [global options] command [command options] [arguments...]. Adjust verbosity of given command with -v, -vv or -vvv (max)."
 
 	setGarbageCollection()
 

+ 9 - 36
netclient/ncutils/netclientutils.go

@@ -2,13 +2,13 @@ package ncutils
 
 import (
 	"bytes"
+	"crypto/rand"
 	"crypto/tls"
 	"encoding/gob"
 	"errors"
 	"fmt"
 	"io"
 	"log"
-	"math/rand"
 	"net"
 	"net/http"
 	"os"
@@ -30,9 +30,6 @@ import (
 // Version - version of the netclient
 var Version = "dev"
 
-// src - for random strings
-var src = rand.NewSource(time.Now().UnixNano())
-
 // MAX_NAME_LENGTH - maximum node name length
 const MAX_NAME_LENGTH = 62
 
@@ -127,23 +124,6 @@ func IsEmptyRecord(err error) bool {
 	return strings.Contains(err.Error(), NO_DB_RECORD) || strings.Contains(err.Error(), NO_DB_RECORDS)
 }
 
-//generate an access key value
-// GenPass - generates a pass
-func GenPass() string {
-
-	var seededRand *rand.Rand = rand.New(
-		rand.NewSource(time.Now().UnixNano()))
-
-	length := 16
-	charset := "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
-
-	b := make([]byte, length)
-	for i := range b {
-		b[i] = charset[seededRand.Intn(len(charset))]
-	}
-	return string(b)
-}
-
 // GetPublicIP - gets public ip
 func GetPublicIP() (string, error) {
 
@@ -592,20 +572,13 @@ func ServerAddrSliceContains(slice []models.ServerAddr, item models.ServerAddr)
 
 // MakeRandomString - generates a random string of len n
 func MakeRandomString(n int) string {
-	sb := strings.Builder{}
-	sb.Grow(n)
-	// A src.Int63() generates 63 random bits, enough for letterIdxMax characters!
-	for i, cache, remain := n-1, src.Int63(), letterIdxMax; i >= 0; {
-		if remain == 0 {
-			cache, remain = src.Int63(), letterIdxMax
-		}
-		if idx := int(cache & letterIdxMask); idx < len(letterBytes) {
-			sb.WriteByte(letterBytes[idx])
-			i--
-		}
-		cache >>= letterIdxBits
-		remain--
+	const validChars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
+	result := make([]byte, n)
+	if _, err := rand.Reader.Read(result); err != nil {
+		return ""
 	}
-
-	return sb.String()
+	for i, b := range result {
+		result[i] = validChars[b%byte(len(validChars))]
+	}
+	return string(result)
 }

+ 32 - 0
netclient/ncutils/netclientutils_test.go

@@ -0,0 +1,32 @@
+package ncutils
+
+import (
+	"strings"
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+)
+
+func TestMakeRandomString(t *testing.T) {
+	for testCase := 0; testCase < 100; testCase++ {
+		for size := 2; size < 2058; size++ {
+			if length := len(MakeRandomString(size)); length != size {
+				t.Fatalf("expected random string of size %d, got %d instead", size, length)
+			}
+		}
+	}
+}
+
+func TestMakeRandomStringValid(t *testing.T) {
+	lengthStr := MakeRandomString(10)
+	assert.Equal(t, len(lengthStr), 10)
+	validMqID := MakeRandomString(23)
+	assert.False(t, strings.Contains(validMqID, "#"))
+	assert.False(t, strings.Contains(validMqID, "!"))
+	assert.False(t, strings.Contains(validMqID, "\""))
+	assert.False(t, strings.Contains(validMqID, "\\"))
+	assert.False(t, strings.Contains(validMqID, "+"))
+	assert.False(t, strings.Contains(validMqID, "-"))
+	assert.False(t, strings.Contains(validMqID, "{"))
+	assert.False(t, strings.Contains(validMqID, "}"))
+}

+ 1 - 14
scripts/build-binaries.sh

@@ -4,18 +4,5 @@
 env CGO_ENABLED=1 GOOS=linux GOARCH=amd64 go build -ldflags="-X 'main.version=$VERSION'" -o netclient/build/netmaker main.go
 
 cd netclient
+./bin-maker.sh
 
-#client build
-env CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags="-X 'main.version=$VERSION'" -o build/netclient main.go
-env CGO_ENABLED=0 GOOS=linux GOARCH=arm GOARM=5 go build -ldflags="-X 'main.version=$VERSION'" -o build/netclient-arm5 main.go
-env CGO_ENABLED=0 GOOS=linux GOARCH=arm GOARM=6 go build -ldflags="-X 'main.version=$VERSION'" -o build/netclient-arm6 main.go
-env CGO_ENABLED=0 GOOS=linux GOARCH=arm GOARM=7 go build -ldflags="-X 'main.version=$VERSION'" -o build/netclient-arm7 main.go
-env CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -ldflags="-X 'main.version=$VERSION'" -o build/netclient-arm64 main.go
-env CGO_ENABLED=0 GOOS=linux GOARCH=mipsle go build -ldflags "-s -w -X 'main.version=$VERSION'" -o build/netclient-mipsle main.go && upx build/netclient-mipsle
-env CGO_ENABLED=0 GOOS=freebsd GOARCH=amd64 go build  -ldflags="-X 'main.version=$VERSION'" -o build/netclient-freebsd main.go
-env CGO_ENABLED=0 GOOS=freebsd GOARCH=arm GOARM=5 go build -ldflags="-X 'main.version=$VERSION'" -o build/netclient-freebsd-arm5 main.go
-env CGO_ENABLED=0 GOOS=freebsd GOARCH=arm GOARM=6 go build -ldflags="-X 'main.version=$VERSION'" -o build/netclient-freebsd-arm6 main.go
-env CGO_ENABLED=0 GOOS=freebsd GOARCH=arm GOARM=7 go build -ldflags="-X 'main.version=$VERSION'" -o build/netclient-freebsd-arm7 main.go
-env CGO_ENABLED=0 GOOS=freebsd GOARCH=arm64 go build -ldflags="-X 'main.version=$VERSION'" -o build/netclient-freebsd-arm64 main.go
-env CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -ldflags="-X 'main.version=$VERSION'" -o build/netclient-darwin main.go
-env CGO_ENABLED=0 GOOS=darwin GOARCH=arm64 go build -ldflags="-X 'main.version=${VERSION}'" -o build/netclient-darwin-arm64 main.go

+ 21 - 17
serverctl/iptables.go

@@ -16,7 +16,7 @@ import (
 const netmakerProcessName = "netmaker"
 
 // InitIPTables - intializes the server iptables
-func InitIPTables() error {
+func InitIPTables(force bool) error {
 	_, err := exec.LookPath("iptables")
 	if err != nil {
 		return err
@@ -26,7 +26,7 @@ func InitIPTables() error {
 		logger.Log(0, "error setting iptables forward policy: "+err.Error())
 	}
 
-	err = portForwardServices()
+	err = portForwardServices(force)
 	if err != nil {
 		return err
 	}
@@ -37,7 +37,7 @@ func InitIPTables() error {
 }
 
 // set up port forwarding for services listed in config
-func portForwardServices() error {
+func portForwardServices(force bool) error {
 	var err error
 	services := servercfg.GetPortForwardServiceList()
 	if len(services) == 0 || services[0] == "" {
@@ -46,15 +46,15 @@ func portForwardServices() error {
 	for _, service := range services {
 		switch service {
 		case "mq":
-			err = iptablesPortForward("mq", "1883", "1883", false)
+			err = iptablesPortForward("mq", "1883", "1883", false, force)
 		case "dns":
-			err = iptablesPortForward("coredns", "53", "53", false)
+			err = iptablesPortForward("coredns", "53", "53", false, force)
 		case "ssh":
-			err = iptablesPortForward("netmaker", "22", "22", false)
+			err = iptablesPortForward("netmaker", "22", "22", false, force)
 		default:
 			params := strings.Split(service, ":")
 			if len(params) == 3 {
-				err = iptablesPortForward(params[0], params[1], params[2], true)
+				err = iptablesPortForward(params[0], params[1], params[2], true, force)
 			}
 		}
 		if err != nil {
@@ -83,8 +83,7 @@ func setForwardPolicy() error {
 }
 
 // port forward from an entry, can contain a dns name for lookup
-func iptablesPortForward(entry string, inport string, outport string, isIP bool) error {
-	logger.Log(1, "forwarding "+entry+" traffic from host port "+inport+" to container port "+outport)
+func iptablesPortForward(entry string, inport string, outport string, isIP, force bool) error {
 
 	var address string
 	if !isIP {
@@ -111,16 +110,21 @@ func iptablesPortForward(entry string, inport string, outport string, isIP bool)
 		return errors.New("could not locate ip for " + entry)
 	}
 
-	_, err := ncutils.RunCmd("iptables -t nat -A PREROUTING -p tcp --dport "+inport+" -j DNAT --to-destination "+address+":"+outport, false)
-	if err != nil {
-		return err
-	}
-	_, err = ncutils.RunCmd("iptables -t nat -A PREROUTING -p udp --dport "+inport+" -j DNAT --to-destination "+address+":"+outport, false)
-	if err != nil {
+	if output, err := ncutils.RunCmd("iptables -t nat -C PREROUTING -p tcp --dport "+inport+" -j DNAT --to-destination "+address+":"+outport, false); output != "" || err != nil || force {
+		_, err := ncutils.RunCmd("iptables -t nat -A PREROUTING -p tcp --dport "+inport+" -j DNAT --to-destination "+address+":"+outport, false)
+		if err != nil {
+			return err
+		}
+		_, err = ncutils.RunCmd("iptables -t nat -A PREROUTING -p udp --dport "+inport+" -j DNAT --to-destination "+address+":"+outport, false)
+		if err != nil {
+			return err
+		}
+		_, err = ncutils.RunCmd("iptables -t nat -A POSTROUTING -j MASQUERADE", false)
 		return err
+	} else {
+		logger.Log(3, "mq forwarding is already set... skipping")
 	}
-	_, err = ncutils.RunCmd("iptables -t nat -A POSTROUTING -j MASQUERADE", false)
-	return err
+	return nil
 }
 
 // if running in host networking mode, run iptables to map to CoreDNS container

+ 4 - 0
serverctl/serverctl.go

@@ -100,6 +100,10 @@ func InitServerNetclient() error {
 		for _, network := range networks {
 			var currentServerNode, nodeErr = logic.GetNetworkServerLocal(network.NetID)
 			if nodeErr == nil {
+				if currentServerNode.Version != servercfg.Version {
+					currentServerNode.Version = servercfg.Version
+					logic.UpdateNode(&currentServerNode, &currentServerNode)
+				}
 				if err = logic.ServerPull(&currentServerNode, true); err != nil {
 					logger.Log(1, "failed pull for network", network.NetID, ", on server node", currentServerNode.ID)
 				}