Pārlūkot izejas kodu

Merge pull request #207 from gravitl/feature_0.7.1_refactor

Feature 0.7.1 refactor
Alex 4 gadi atpakaļ
vecāks
revīzija
34ecf46510
46 mainītis faili ar 2546 papildinājumiem un 4593 dzēšanām
  1. 1 0
      .gitignore
  2. 2 2
      Dockerfile
  3. 16 6
      compose/docker-compose.quickstart.yml
  4. 0 4
      config/config.go
  5. 0 8
      config/dnsconfig/Corefile
  6. 0 5
      config/dnsconfig/netmaker.hosts
  7. 13 6
      controllers/authGrpc.go
  8. 69 86
      controllers/common.go
  9. 0 1
      controllers/controller.go
  10. 26 29
      controllers/dnsHttpController.go
  11. 28 66
      controllers/extClientHttpController.go
  12. 19 32
      controllers/networkHttpController.go
  13. 102 274
      controllers/nodeGrpcController.go
  14. 38 68
      controllers/nodeHttpController.go
  15. 1 1
      controllers/serverHttpController.go
  16. 12 6
      controllers/userHttpController.go
  17. 2 2
      controllers/userHttpController_test.go
  18. 27 1
      database/database.go
  19. 54 0
      database/statics.go
  20. 39 42
      docs/quick-start.rst
  21. 99 37
      functions/helpers.go
  22. 2 5
      functions/local.go
  23. 48 1669
      grpc/node.pb.go
  24. 12 153
      grpc/node.proto
  25. 95 150
      grpc/node_grpc.pb.go
  26. 6 0
      grpc/types.go
  27. 17 23
      main.go
  28. 204 0
      models/names.go
  29. 23 23
      models/network.go
  30. 172 71
      models/node.go
  31. 78 51
      netclient/auth/auth.go
  32. 52 61
      netclient/command/commands.go
  33. 28 184
      netclient/config/config.go
  34. 251 346
      netclient/functions/checkin.go
  35. 210 239
      netclient/functions/common.go
  36. 48 39
      netclient/functions/join.go
  37. 49 49
      netclient/functions/register.go
  38. 44 44
      netclient/local/dns.go
  39. 229 227
      netclient/local/local.go
  40. 11 32
      netclient/main.go
  41. 294 319
      netclient/server/grpc.go
  42. 109 219
      netclient/wireguard/kernel.go
  43. 6 6
      nginx/netmaker-nginx-template.conf
  44. 1 2
      scripts/netclient-install.sh
  45. 6 3
      serverctl/serverctl.go
  46. 3 2
      serverctl/wireguard.go

+ 1 - 0
.gitignore

@@ -1,3 +1,4 @@
 netmaker
 netclient/netclient
 netclient/files/netclient
+config/dnsconfig/

+ 2 - 2
Dockerfile

@@ -8,13 +8,13 @@ WORKDIR /app
 
 ENV GO111MODULE=auto
 
-RUN CGO_ENABLED=0 GOOS=linux go build -o app main.go
+RUN GOARCH=amd64 CGO_ENABLED=0 GOOS=linux go build -ldflags="-w -s" -o app main.go
 
 WORKDIR /app/netclient
 
 ENV GO111MODULE=auto
 
-RUN CGO_ENABLED=0 GOOS=linux go build -o netclient main.go
+RUN GOARCH=amd64 CGO_ENABLED=0 GOOS=linux go build -ldflags="-w -s" -o netclient main.go
 
 #second stage
 

+ 16 - 6
compose/docker-compose.quickstart.yml

@@ -4,9 +4,7 @@ services:
   rqlite:
     container_name: rqlite
     image: rqlite/rqlite
-    ports:
-      - "4001:4001"
-      - "4002:4002"
+    network_mode: host
     restart: always
     volumes:
       - sqldata:/rqlite/file/data
@@ -31,12 +29,24 @@ services:
     restart: always
     network_mode: host
     environment:
-      SERVER_HOST: "HOST_IP"
+      SERVER_HOST: "SERVER_PUBLIC_IP"
+      SERVER_API_CONN_STRING: "api.NETMAKER_BASE_DOMAIN:443"
+      SERVER_GRPC_CONN_STRING: "grpc.NETMAKER_BASE_DOMAIN:1443"
+      COREDNS_ADDR: "SERVER_PUBLIC_IP"
+      GRPC_SSL: "on"
+      SERVER_HTTP_HOST: "api.NETMAKER_BASE_DOMAIN"
+      SERVER_GRPC_HOST: "grpc.NETMAKER_BASE_DOMAIN"
+      API_PORT: "8081"
+      GRPC_PORT: "50051"
+      CLIENT_MODE: "on"
+      MASTER_KEY: "REPLACE_MASTER_KEY"
+      SERVER_GRPC_WIREGUARD: "off"
+      CORS_ALLOWED_ORIGIN: "*"
   netmaker-ui:
     container_name: netmaker-ui
     depends_on:
       - netmaker
-    image: gravitl/netmaker-ui:v0.5
+    image: gravitl/netmaker-ui:v0.7
     links:
       - "netmaker:api"
     ports:
@@ -51,7 +61,7 @@ services:
     container_name: coredns
     restart: always
     ports:
-      - "5353:53/udp"
+      - "53:53/udp"
     volumes:
       - dnsconfig:/root/dnsconfig
 volumes:

+ 0 - 4
config/config.go

@@ -73,10 +73,6 @@ func readConfig() *EnvironmentConfig {
 	f, err := os.Open(file)
 	var cfg EnvironmentConfig
 	if err != nil {
-		//log.Fatal(err)
-		//os.Exit(2)
-		//log.Println("Unable to open config file at config/environments/" + getEnv())
-		//log.Println("Will proceed with defaults or enironment variables (no config file).")
 		return &cfg
 	}
 	defer f.Close()

+ 0 - 8
config/dnsconfig/Corefile

@@ -1,8 +0,0 @@
-pissant comms  {
-    reload 15s
-    hosts /root/dnsconfig/netmaker.hosts {
-	fallthrough	
-    }
-    forward . 8.8.8.8 8.8.4.4
-    log
-}

+ 0 - 5
config/dnsconfig/netmaker.hosts

@@ -1,5 +0,0 @@
-11.22.44.1       netmaker.pissant
-11.22.44.3       node-mtxy5.pissant
-11.22.44.5       node-vnqlu.pissant
-11.22.44.4       ubuntu-do.pissant ubuntu.pissant
-11.22.44.2       alex-laptop.pissant porngood.pissant

+ 13 - 6
controllers/authGrpc.go

@@ -4,6 +4,7 @@ import (
 	"context"
 	"encoding/json"
 	"errors"
+
 	"github.com/gravitl/netmaker/database"
 	"github.com/gravitl/netmaker/functions"
 	nodepb "github.com/gravitl/netmaker/grpc"
@@ -97,12 +98,17 @@ func grpcAuthorize(ctx context.Context) error {
 }
 
 //Node authenticates using its password and retrieves a JWT for authorization.
-func (s *NodeServiceServer) Login(ctx context.Context, req *nodepb.LoginRequest) (*nodepb.LoginResponse, error) {
+func (s *NodeServiceServer) Login(ctx context.Context, req *nodepb.Object) (*nodepb.Object, error) {
 
 	//out := new(LoginResponse)
-	macaddress := req.GetMacaddress()
-	network := req.GetNetwork()
-	password := req.GetPassword()
+	var reqNode models.Node
+	if err := json.Unmarshal([]byte(req.Data), &reqNode); err != nil {
+		return nil, err
+	}
+
+	macaddress := reqNode.MacAddress
+	network := reqNode.Network
+	password := reqNode.Password
 
 	var result models.NodeAuth
 
@@ -148,8 +154,9 @@ func (s *NodeServiceServer) Login(ctx context.Context, req *nodepb.LoginRequest)
 				return nil, err
 			}
 
-			response := &nodepb.LoginResponse{
-				Accesstoken: tokenString,
+			response := &nodepb.Object{
+				Data: tokenString,
+				Type: nodepb.ACCESS_TOKEN,
 			}
 			return response, nil
 		}

+ 69 - 86
controllers/common.go

@@ -2,12 +2,9 @@ package controller
 
 import (
 	"encoding/json"
-	"fmt"
-	"log"
 	"strconv"
 	"strings"
 	"time"
-
 	"github.com/gravitl/netmaker/database"
 	"github.com/gravitl/netmaker/functions"
 	"github.com/gravitl/netmaker/models"
@@ -16,36 +13,43 @@ import (
 	"golang.org/x/crypto/bcrypt"
 )
 
-func GetPeersList(networkName string) ([]models.PeersResponse, error) {
+func GetPeersList(networkName string) ([]models.Node, error) {
 
-	var peers []models.PeersResponse
+	var peers []models.Node
 	collection, err := database.FetchRecords(database.NODES_TABLE_NAME)
 	if err != nil {
-		log.Println(err)
+		if database.IsEmptyRecord(err) {
+			return peers, nil
+		}
+		functions.PrintUserLog("",err.Error(),2)
+		return nil, err
 	}
-	udppeers, errN := serverctl.GetPeers(networkName)
+	udppeers, errN := database.GetPeers(networkName)
 	if errN != nil {
-		log.Println(errN)
+		functions.PrintUserLog("",errN.Error(),2)
 	}
 	for _, value := range collection {
 		var node models.Node
-		var peer models.PeersResponse
+		var peer models.Node
 		err := json.Unmarshal([]byte(value), &node)
 		if err != nil {
-			log.Println(err)
-			continue
-		}
-		err = json.Unmarshal([]byte(value), &peer)
-		if err != nil {
-			log.Println(err)
+			functions.PrintUserLog("",err.Error(),2)
 			continue
 		}
-		if node.IsEgressGateway == "yes" {
-			peer.EgressGatewayRanges = strings.Join(node.EgressGatewayRanges, ",")
+		if node.IsEgressGateway == "yes" { // handle egress stuff
+			peer.EgressGatewayRanges = node.EgressGatewayRanges
+			peer.IsEgressGateway = node.IsEgressGateway
 		}
 		if node.Network == networkName && node.IsPending != "yes" {
-			if node.UDPHolePunch == "yes" && errN == nil {
-				endpointstring := udppeers[peer.PublicKey]
+			peer.PublicKey = node.PublicKey
+			peer.Endpoint = node.Endpoint
+			peer.LocalAddress = node.LocalAddress
+			peer.ListenPort = node.ListenPort
+			peer.AllowedIPs = node.AllowedIPs
+			peer.Address = node.Address
+			peer.Address6 = node.Address6
+			if node.UDPHolePunch == "yes" && errN == nil && functions.CheckEndpoint(udppeers[node.PublicKey]) {
+				endpointstring := udppeers[node.PublicKey]
 				endpointarr := strings.Split(endpointstring, ":")
 				if len(endpointarr) == 2 {
 					port, err := strconv.Atoi(endpointarr[1])
@@ -55,6 +59,7 @@ func GetPeersList(networkName string) ([]models.PeersResponse, error) {
 					}
 				}
 			}
+			functions.PrintUserLog(models.NODE_SERVER_NAME, "adding to peer list: "+peer.MacAddress+" "+peer.Endpoint, 3)
 			peers = append(peers, peer)
 		}
 	}
@@ -65,7 +70,7 @@ func GetPeersList(networkName string) ([]models.PeersResponse, error) {
 	return peers, err
 }
 
-func GetExtPeersList(networkName string, macaddress string) ([]models.ExtPeersResponse, error) {
+func GetExtPeersList(macaddress string, networkName string) ([]models.ExtPeersResponse, error) {
 
 	var peers []models.ExtPeersResponse
 	records, err := database.FetchRecords(database.EXT_CLIENT_TABLE_NAME)
@@ -79,12 +84,12 @@ func GetExtPeersList(networkName string, macaddress string) ([]models.ExtPeersRe
 		var extClient models.ExtClient
 		err = json.Unmarshal([]byte(value), &peer)
 		if err != nil {
-			functions.PrintUserLog("netmaker", "failed to unmarshal peer", 2)
+			functions.PrintUserLog(models.NODE_SERVER_NAME, "failed to unmarshal peer", 2)
 			continue
 		}
 		err = json.Unmarshal([]byte(value), &extClient)
 		if err != nil {
-			functions.PrintUserLog("netmaker", "failed to unmarshal ext client", 2)
+			functions.PrintUserLog(models.NODE_SERVER_NAME, "failed to unmarshal ext client", 2)
 			continue
 		}
 		if extClient.Network == networkName && extClient.IngressGatewayID == macaddress {
@@ -94,21 +99,38 @@ func GetExtPeersList(networkName string, macaddress string) ([]models.ExtPeersRe
 	return peers, err
 }
 
-func DeleteNode(macaddress string, network string) error {
-
-	key, err := functions.GetRecordKey(macaddress, network)
-	if err != nil {
-		return err
+/**
+ * If being deleted by server, create a record in the DELETED_NODES_TABLE for the client to find
+ * If being deleted by the client, delete completely
+ */
+func DeleteNode(key string, exterminate bool) error {
+	var err error
+	if !exterminate {
+		args := strings.Split(key, "###")
+		node, err := GetNode(args[0], args[1])
+		if err != nil {
+			return err
+		}
+		node.Action = models.NODE_DELETE
+		nodedata, err := json.Marshal(&node)
+		if err != nil {
+			return err
+		}
+		err = database.Insert(key, string(nodedata), database.DELETED_NODES_TABLE_NAME)
+		if err != nil {
+			return err
+		}
+	} else {
+		if err := database.DeleteRecord(database.DELETED_NODES_TABLE_NAME, key); err != nil {
+			functions.PrintUserLog("",err.Error(),2)
+		}
 	}
-	if err = database.DeleteRecord(database.NODES_TABLE_NAME, key); err != nil {
+	if err := database.DeleteRecord(database.NODES_TABLE_NAME, key); err != nil {
 		return err
 	}
-
-	err = SetNetworkNodesLastModified(network)
 	if servercfg.IsDNSMode() {
 		err = SetDNS()
 	}
-
 	return err
 }
 
@@ -132,6 +154,10 @@ func GetNode(macaddress string, network string) (models.Node, error) {
 	}
 	data, err := database.FetchRecord(database.NODES_TABLE_NAME, key)
 	if err != nil {
+		if data == "" {
+			data, err = database.FetchRecord(database.DELETED_NODES_TABLE_NAME, key)
+			err = json.Unmarshal([]byte(data), &node)
+		}
 		return node, err
 	}
 	if err = json.Unmarshal([]byte(data), &node); err != nil {
@@ -167,6 +193,11 @@ func CreateNode(node models.Node, networkName string) (models.Node, error) {
 	node.Password = string(hash)
 
 	node.Network = networkName
+	if node.Name == models.NODE_SERVER_NAME {
+		if node.CheckIsServer() {
+			node.IsServer = "yes"
+		}
+	}
 
 	node.SetDefaults()
 	node.Address, err = functions.UniqueAddress(networkName)
@@ -187,7 +218,6 @@ func CreateNode(node models.Node, networkName string) (models.Node, error) {
 	if err != nil {
 		return node, err
 	}
-
 	key, err := functions.GetRecordKey(node.MacAddress, node.Network)
 	if err != nil {
 		return node, err
@@ -210,62 +240,15 @@ func CreateNode(node models.Node, networkName string) (models.Node, error) {
 	return node, err
 }
 
-func NodeCheckIn(node models.Node, networkName string) (models.CheckInResponse, error) {
-
-	var response models.CheckInResponse
-
-	parentnetwork, err := functions.GetParentNetwork(networkName)
-	if err != nil {
-		err = fmt.Errorf("%w; Couldnt retrieve Network "+networkName+": ", err)
-		return response, err
-	}
-
-	parentnode, err := GetNode(node.MacAddress, networkName)
-	if err != nil {
-		err = fmt.Errorf("%w; Couldnt Get Node "+node.MacAddress, err)
-		return response, err
-	}
-	if parentnode.IsPending == "yes" {
-		err = fmt.Errorf("%w; Node checking in is still pending: "+node.MacAddress, err)
-		response.IsPending = true
-		return response, err
-	}
-
-	networklm := parentnetwork.NetworkLastModified
-	peerslm := parentnetwork.NodesLastModified
-	gkeyupdate := parentnetwork.KeyUpdateTimeStamp
-	nkeyupdate := parentnode.KeyUpdateTimeStamp
-	peerlistlm := parentnode.LastPeerUpdate
-	parentnodelm := parentnode.LastModified
-	parentnodelastcheckin := parentnode.LastCheckIn
-
-	if parentnodelastcheckin < parentnodelm {
-		response.NeedConfigUpdate = true
-	}
-
-	if parentnodelm < networklm {
-		response.NeedConfigUpdate = true
-	}
-	if peerlistlm < peerslm {
-		response.NeedPeerUpdate = true
-	}
-	if nkeyupdate < gkeyupdate {
-		response.NeedKeyUpdate = true
-	}
-	if time.Now().Unix() > parentnode.ExpirationDateTime {
-		response.NeedDelete = true
-		err = DeleteNode(node.MacAddress, networkName)
-	} else {
-		err = TimestampNode(parentnode, true, false, false)
-
-		if err != nil {
-			err = fmt.Errorf("%w; Couldnt Timestamp Node: ", err)
-			return response, err
+func SetNetworkServerPeers(networkName string) {
+	if currentPeersList, err := serverctl.GetPeers(networkName); err == nil {
+		if database.SetPeers(currentPeersList, networkName) {
+			functions.PrintUserLog(models.NODE_SERVER_NAME,"set new peers on network "+networkName,1)
 		}
+	} else {
+		functions.PrintUserLog(models.NODE_SERVER_NAME,"could not set peers on network "+networkName,1)
+		functions.PrintUserLog(models.NODE_SERVER_NAME,err.Error(),1)
 	}
-	response.Success = true
-
-	return response, err
 }
 
 func SetNetworkNodesLastModified(networkName string) error {

+ 0 - 1
controllers/controller.go

@@ -7,7 +7,6 @@ import (
 	"os"
 	"os/signal"
 	"sync"
-
 	"github.com/gorilla/handlers"
 	"github.com/gorilla/mux"
 	"github.com/gravitl/netmaker/servercfg"

+ 26 - 29
controllers/dnsHttpController.go

@@ -2,9 +2,7 @@ package controller
 
 import (
 	"encoding/json"
-	"fmt"
 	"net/http"
-	"log"
 	"github.com/go-playground/validator/v10"
 	"github.com/gorilla/mux"
 	"github.com/gravitl/netmaker/database"
@@ -148,14 +146,11 @@ func SetDNS() error {
 	for _, net := range networks {
 		corefilestring = corefilestring + net.NetID + " "
 		dns, err := GetDNS(net.NetID)
-		if err != nil {
+		if err != nil && !database.IsEmptyRecord(err) {
 			return err
 		}
 		for _, entry := range dns {
 			hostfile.AddHost(entry.Address, entry.Name+"."+entry.Network)
-			if err != nil {
-				return err
-			}
 		}
 	}
 	if corefilestring == "" {
@@ -211,16 +206,16 @@ func GetDNS(network string) ([]models.DNSEntry, error) {
 
 	var dns []models.DNSEntry
 	dns, err := GetNodeDNS(network)
-	if err != nil {
+	if err != nil && !database.IsEmptyRecord(err) {
 		return dns, err
 	}
 	customdns, err := GetCustomDNS(network)
-	if err != nil {
+	if err != nil && !database.IsEmptyRecord(err) {
 		return dns, err
 	}
 
 	dns = append(dns, customdns...)
-	return dns, err
+	return dns, nil
 }
 
 func createDNS(w http.ResponseWriter, r *http.Request) {
@@ -244,11 +239,11 @@ func createDNS(w http.ResponseWriter, r *http.Request) {
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 	}
-        err = SetDNS()
-        if err != nil {
-                returnErrorResponse(w, r, formatError(err, "internal"))
-                return
-        }
+	err = SetDNS()
+	if err != nil {
+		returnErrorResponse(w, r, formatError(err, "internal"))
+		return
+	}
 	w.WriteHeader(http.StatusOK)
 	json.NewEncoder(w).Encode(entry)
 }
@@ -299,11 +294,11 @@ func updateDNS(w http.ResponseWriter, r *http.Request) {
 		returnErrorResponse(w, r, formatError(err, "badrequest"))
 		return
 	}
-        err = SetDNS()
-        if err != nil {
-                returnErrorResponse(w, r, formatError(err, "internal"))
-                return
-        }
+	err = SetDNS()
+	if err != nil {
+		returnErrorResponse(w, r, formatError(err, "internal"))
+		return
+	}
 	json.NewEncoder(w).Encode(entry)
 }
 
@@ -321,12 +316,12 @@ func deleteDNS(w http.ResponseWriter, r *http.Request) {
 		return
 	}
 	entrytext := params["domain"] + "." + params["network"]
-	functions.PrintUserLog("netmaker", "deleted dns entry: "+entrytext, 1)
-        err = SetDNS()
-        if err != nil {
-                returnErrorResponse(w, r, formatError(err, "internal"))
-                return
-        }
+	functions.PrintUserLog(models.NODE_SERVER_NAME, "deleted dns entry: "+entrytext, 1)
+	err = SetDNS()
+	if err != nil {
+		returnErrorResponse(w, r, formatError(err, "internal"))
+		return
+	}
 	json.NewEncoder(w).Encode(entrytext + " deleted.")
 }
 
@@ -403,7 +398,7 @@ func pushDNS(w http.ResponseWriter, r *http.Request) {
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 	}
-	log.Println("pushed DNS updates to nameserver")
+	functions.PrintUserLog(r.Header.Get("user"),"pushed DNS updates to nameserver",1)
 	json.NewEncoder(w).Encode("DNS Pushed to CoreDNS")
 }
 
@@ -424,7 +419,7 @@ func ValidateDNSCreate(entry models.DNSEntry) error {
 	err := v.Struct(entry)
 	if err != nil {
 		for _, e := range err.(validator.ValidationErrors) {
-			fmt.Println(e)
+			functions.PrintUserLog("", e.Error(),1)
 		}
 	}
 	return err
@@ -444,7 +439,9 @@ func ValidateDNSUpdate(change models.DNSEntry, entry models.DNSEntry) error {
 	})
 	_ = v.RegisterValidation("network_exists", func(fl validator.FieldLevel) bool {
 		_, err := functions.GetParentNetwork(change.Network)
-		fmt.Println(err, entry.Network)
+		if err != nil {
+			functions.PrintUserLog("",err.Error(),0)
+		}
 		return err == nil
 	})
 
@@ -466,7 +463,7 @@ func ValidateDNSUpdate(change models.DNSEntry, entry models.DNSEntry) error {
 
 	if err != nil {
 		for _, e := range err.(validator.ValidationErrors) {
-			fmt.Println(e)
+			functions.PrintUserLog("", e.Error(),1)
 		}
 	}
 	return err

+ 28 - 66
controllers/extClientHttpController.go

@@ -6,12 +6,9 @@ import (
 	"fmt"
 	"io"
 	"math/rand"
-
-	// "fmt"
 	"net/http"
 	"strconv"
 	"time"
-
 	"github.com/gorilla/mux"
 	"github.com/gravitl/netmaker/database"
 	"github.com/gravitl/netmaker/functions"
@@ -31,43 +28,6 @@ func extClientHandlers(r *mux.Router) {
 	r.HandleFunc("/api/extclients/{network}/{macaddress}", securityCheck(false, http.HandlerFunc(createExtClient))).Methods("POST")
 }
 
-// TODO: Implement Validation
-func ValidateExtClientCreate(networkName string, extclient models.ExtClient) error {
-	// 	v := validator.New()
-	// 	_ = v.RegisterValidation("macaddress_unique", func(fl validator.FieldLevel) bool {
-	// 		var isFieldUnique bool = functions.IsFieldUnique(networkName, "macaddress", extclient.MacAddress)
-	// 		return isFieldUnique
-	// 	})
-	// 	_ = v.RegisterValidation("network_exists", func(fl validator.FieldLevel) bool {
-	// 		_, err := extclient.GetNetwork()
-	// 		return err == nil
-	// 	})
-	// 	err := v.Struct(extclient)
-
-	// 	if err != nil {
-	// 		for _, e := range err.(validator.ValidationErrors) {
-	// 			fmt.Println(e)
-	// 		}
-	// 	}
-	return nil
-}
-
-// TODO: Implement Validation
-func ValidateExtClientUpdate(networkName string, extclient models.ExtClient) error {
-	// v := validator.New()
-	// _ = v.RegisterValidation("network_exists", func(fl validator.FieldLevel) bool {
-	// 	_, err := extclient.GetNetwork()
-	// 	return err == nil
-	// })
-	// err := v.Struct(extclient)
-	// if err != nil {
-	// 	for _, e := range err.(validator.ValidationErrors) {
-	// 		fmt.Println(e)
-	// 	}
-	// }
-	return nil
-}
-
 func checkIngressExists(network string, macaddress string) bool {
 	node, err := functions.GetNodeByMacAddress(network, macaddress)
 	if err != nil {
@@ -178,14 +138,14 @@ func getExtClientConf(w http.ResponseWriter, r *http.Request) {
 
 	gwnode, err := functions.GetNodeByMacAddress(client.Network, client.IngressGatewayID)
 	if err != nil {
-		fmt.Println("Could not retrieve Ingress Gateway Node " + client.IngressGatewayID)
+		functions.PrintUserLog(r.Header.Get("user"),"Could not retrieve Ingress Gateway Node " + client.IngressGatewayID,1)
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 	}
 
 	network, err := functions.GetParentNetwork(client.Network)
 	if err != nil {
-		fmt.Println("Could not retrieve Ingress Gateway Network " + client.Network)
+		functions.PrintUserLog(r.Header.Get("user"),"Could not retrieve Ingress Gateway Network " + client.Network,1)
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 	}
@@ -238,7 +198,7 @@ Endpoint = %s
 		}
 		return
 	}
-
+	functions.PrintUserLog(r.Header.Get("user"),"retrieved ext client config",2)
 	w.WriteHeader(http.StatusOK)
 	json.NewEncoder(w).Encode(client)
 }
@@ -263,9 +223,7 @@ func CreateExtClient(extclient models.ExtClient) error {
 	}
 
 	if extclient.ClientID == "" {
-		clientid := StringWithCharset(7, charset)
-		clientname := "client-" + clientid
-		extclient.ClientID = clientname
+		extclient.ClientID = models.GenerateNodeName()
 	}
 
 	extclient.LastModified = time.Now().Unix()
@@ -284,10 +242,10 @@ func CreateExtClient(extclient models.ExtClient) error {
 	err = SetNetworkNodesLastModified(extclient.Network)
 	return err
 }
-
-//This one's a doozy
-//To create a extclient
-//Must have valid key and be unique
+/**
+ * To create a extclient
+ * Must have valid key and be unique
+ */
 func createExtClient(w http.ResponseWriter, r *http.Request) {
 	w.Header().Set("Content-Type", "application/json")
 
@@ -295,9 +253,6 @@ func createExtClient(w http.ResponseWriter, r *http.Request) {
 
 	networkName := params["network"]
 	macaddress := params["macaddress"]
-	//Check if network exists  first
-	//TODO: This is inefficient. Let's find a better way.
-	//Just a few rows down we grab the network anyway
 	ingressExists := checkIngressExists(networkName, macaddress)
 	if !ingressExists {
 		returnErrorResponse(w, r, formatError(errors.New("ingress does not exist"), "internal"))
@@ -319,11 +274,6 @@ func createExtClient(w http.ResponseWriter, r *http.Request) {
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 	}
-	err = ValidateExtClientCreate(params["network"], extclient)
-	if err != nil {
-		returnErrorResponse(w, r, formatError(err, "badrequest"))
-		return
-	}
 	err = CreateExtClient(extclient)
 
 	if err != nil {
@@ -340,14 +290,8 @@ func updateExtClient(w http.ResponseWriter, r *http.Request) {
 
 	var newExtClient models.ExtClient
 	var oldExtClient models.ExtClient
-	// we decode our body request params
 	_ = json.NewDecoder(r.Body).Decode(&newExtClient)
-	// TODO: Validation for update.
-	// err := ValidateExtClientUpdate(params["network"], params["clientid"], newExtClient)
-	// if err != nil {
-	// 	returnErrorResponse(w, r, formatError(err, "badrequest"))
-	// 	return
-	// }
+
 	key, err := functions.GetRecordKey(params["clientid"], params["network"])
 	if err != nil {
 		returnErrorResponse(w, r, formatError(err, "internal"))
@@ -362,7 +306,6 @@ func updateExtClient(w http.ResponseWriter, r *http.Request) {
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 	}
-
 	newclient, err := UpdateExtClient(newExtClient.ClientID, params["network"], oldExtClient)
 	if err != nil {
 		returnErrorResponse(w, r, formatError(err, "internal"))
@@ -393,6 +336,25 @@ func DeleteExtClient(network string, clientid string) error {
 	return err
 }
 
+/**
+ * Deletes ext clients based on gateway (mac) of ingress node and network
+ */
+func DeleteGatewayExtClients(gatewayID string, networkName string) error {
+	currentExtClients, err := GetNetworkExtClients(networkName)
+	if err != nil {
+		return err
+	}
+	for _, extClient := range currentExtClients {
+		if extClient.IngressGatewayID == gatewayID {
+			if err = DeleteExtClient(networkName, extClient.ClientID); err != nil {
+				functions.PrintUserLog(models.NODE_SERVER_NAME, "failed to remove ext client "+extClient.ClientID, 2)
+				continue
+			}
+		}
+	}
+	return nil
+}
+
 //Delete a extclient
 //Pretty straightforward
 func deleteExtClient(w http.ResponseWriter, r *http.Request) {

+ 19 - 32
controllers/networkHttpController.go

@@ -7,7 +7,6 @@ import (
 	"net/http"
 	"strings"
 	"time"
-	"log"
 	"github.com/go-playground/validator/v10"
 	"github.com/gorilla/mux"
 	"github.com/gravitl/netmaker/database"
@@ -68,14 +67,6 @@ func securityCheck(reqAdmin bool, next http.Handler) http.HandlerFunc {
 
 func SecurityCheck(reqAdmin bool, netname, token string) (error, []string, string) {
 
-	networkexists, err := functions.NetworkExists(netname)
-	if err != nil {
-		return err, nil, ""
-	}
-	if netname != "" && !networkexists {
-		return errors.New("This network does not exist"), nil, ""
-	}
-
 	var hasBearer = true
 	var tokenSplit = strings.Split(token, " ")
 	var authToken = ""
@@ -93,14 +84,22 @@ func SecurityCheck(reqAdmin bool, netname, token string) (error, []string, strin
 		userName, networks, isadmin, err := functions.VerifyUserToken(authToken)
 		username = userName
 		if err != nil {
-			return errors.New("Error verifying user token"), nil, username
+			return errors.New("error verifying user token"), nil, username
 		}
 		if !isadmin && reqAdmin {
-			return errors.New("You are unauthorized to access this endpoint"), nil, username
+			return errors.New("you are unauthorized to access this endpoint"), nil, username
 		}
 		userNetworks = networks
 		if isadmin {
 			userNetworks = []string{ALL_NETWORK_ACCESS}
+		} else {
+			networkexists, err := functions.NetworkExists(netname)
+			if err != nil {
+				return err, nil, ""
+			}
+			if netname != "" && !networkexists {
+				return errors.New("this network does not exist"), nil, ""
+			}
 		}
 	} else if isMasterAuthenticated {
 		userNetworks = []string{ALL_NETWORK_ACCESS}
@@ -145,10 +144,9 @@ func getNetworks(w http.ResponseWriter, r *http.Request) {
 			}
 		}
 	}
-	networks := RemoveComms(allnetworks)
 	functions.PrintUserLog(r.Header.Get("user"), "fetched networks.", 2)
 	w.WriteHeader(http.StatusOK)
-	json.NewEncoder(w).Encode(networks)
+	json.NewEncoder(w).Encode(allnetworks)
 }
 
 func RemoveComms(networks []models.Network) []models.Network {
@@ -181,7 +179,7 @@ func ValidateNetworkUpdate(network models.Network) error {
 
 	if err != nil {
 		for _, e := range err.(validator.ValidationErrors) {
-			log.Println(e)
+			functions.PrintUserLog("validator",e.Error(),1)
 		}
 	}
 	return err
@@ -232,17 +230,11 @@ func keyUpdate(w http.ResponseWriter, r *http.Request) {
 }
 
 func KeyUpdate(netname string) (models.Network, error) {
-	network, err := functions.GetParentNetwork(netname)
+	err := functions.NetworkNodesUpdateAction(netname, models.NODE_UPDATE_KEY)
 	if err != nil {
 		return models.Network{}, err
 	}
-	network.KeyUpdateTimeStamp = time.Now().Unix()
-	data, err := json.Marshal(&network)
-	if err != nil {
-		return models.Network{}, err
-	}
-	database.Insert(netname, string(data), database.NETWORKS_TABLE_NAME)
-	return network, nil
+	return models.Network{}, nil
 }
 
 //Update a network
@@ -359,16 +351,11 @@ func deleteNetwork(w http.ResponseWriter, r *http.Request) {
 }
 
 func DeleteNetwork(network string) error {
-
-	nodecount, err := functions.GetNetworkNodeNumber(network)
-	if err != nil {
-		return err
-	} else if nodecount > 0 {
-		return errors.New("node check failed. All nodes must be deleted before deleting network")
+	nodeCount, err := functions.GetNetworkNodeCount(network)
+	if nodeCount == 0 || database.IsEmptyRecord(err) {
+		return database.DeleteRecord(database.NETWORKS_TABLE_NAME, network)
 	}
-
-	database.DeleteRecord(database.NETWORKS_TABLE_NAME, network)
-	return err
+	return errors.New("node check failed. All nodes must be deleted before deleting network")
 }
 
 //Create a network
@@ -528,7 +515,7 @@ func CreateAccessKey(accesskey models.AccessKey, network models.Network) (models
 	err = v.Struct(accesskey)
 	if err != nil {
 		for _, e := range err.(validator.ValidationErrors) {
-			log.Println(e)
+			functions.PrintUserLog("validator",e.Error(),1)
 		}
 		return models.AccessKey{}, err
 	}

+ 102 - 274
controllers/nodeGrpcController.go

@@ -2,83 +2,50 @@ package controller
 
 import (
 	"context"
-	"fmt"
+	"encoding/json"
+	"errors"
+	"strings"
 	"github.com/gravitl/netmaker/functions"
 	nodepb "github.com/gravitl/netmaker/grpc"
 	"github.com/gravitl/netmaker/models"
-	"github.com/gravitl/netmaker/servercfg"
-	"google.golang.org/grpc/codes"
-	"google.golang.org/grpc/status"
 )
 
 type NodeServiceServer struct {
 	nodepb.UnimplementedNodeServiceServer
 }
 
-func (s *NodeServiceServer) ReadNode(ctx context.Context, req *nodepb.ReadNodeReq) (*nodepb.ReadNodeRes, error) {
+func (s *NodeServiceServer) ReadNode(ctx context.Context, req *nodepb.Object) (*nodepb.Object, error) {
 	// convert string id (from proto) to mongoDB ObjectId
-	macaddress := req.GetMacaddress()
-	networkName := req.GetNetwork()
-	network, _ := functions.GetParentNetwork(networkName)
-
-	node, err := GetNode(macaddress, networkName)
+	macAndNetwork := strings.Split(req.Data, "###")
 
+	if len(macAndNetwork) != 2 {
+		return nil, errors.New("could not read node, invalid node id given")
+	}
+	node, err := GetNode(macAndNetwork[0], macAndNetwork[1])
 	if err != nil {
-		return nil, status.Errorf(codes.InvalidArgument, fmt.Sprintf("Something went wrong: %v", err))
+		return nil, err
 	}
+	node.SetLastCheckIn()
 	// Cast to ReadNodeRes type
-
-	response := &nodepb.ReadNodeRes{
-		Node: &nodepb.Node{
-			Macaddress:          node.MacAddress,
-			Name:                node.Name,
-			Address:             node.Address,
-			Address6:            node.Address6,
-			Endpoint:            node.Endpoint,
-			Password:            node.Password,
-			Nodenetwork:         node.Network,
-			Interface:           node.Interface,
-			Localaddress:        node.LocalAddress,
-			Postdown:            node.PostDown,
-			Postup:              node.PostUp,
-			Checkininterval:     node.CheckInInterval,
-			Dnsoff:              !servercfg.IsDNSMode(),
-			Ispending:           node.IsPending == "yes",
-			Isingressgateway:    node.IsIngressGateway == "yes",
-			Ingressgatewayrange: node.IngressGatewayRange,
-			Publickey:           node.PublicKey,
-			Listenport:          node.ListenPort,
-			Keepalive:           node.PersistentKeepalive,
-			Islocal:             network.IsLocal == "yes",
-			Isdualstack:         network.IsDualStack == "yes",
-			Localrange:          network.LocalRange,
-			Udpholepunch:        node.UDPHolePunch,
-		},
+	nodeData, err := json.Marshal(&node)
+	if err != nil {
+		return nil, err
+	}
+	node.Update(&node)
+	response := &nodepb.Object{
+		Data: string(nodeData),
+		Type: nodepb.NODE_TYPE,
 	}
 	return response, nil
 }
 
-func (s *NodeServiceServer) CreateNode(ctx context.Context, req *nodepb.CreateNodeReq) (*nodepb.CreateNodeRes, error) {
+func (s *NodeServiceServer) CreateNode(ctx context.Context, req *nodepb.Object) (*nodepb.Object, error) {
 	// Get the protobuf node type from the protobuf request type
 	// Essentially doing req.Node to access the struct with a nil check
-	data := req.GetNode()
-	// Now we have to convert this into a NodeItem type to convert into BSON
-	node := models.Node{
-		// ID:       primitive.NilObjectID,
-		MacAddress:          data.GetMacaddress(),
-		LocalAddress:        data.GetLocaladdress(),
-		Name:                data.GetName(),
-		Address:             data.GetAddress(),
-		Address6:            data.GetAddress6(),
-		AccessKey:           data.GetAccesskey(),
-		Endpoint:            data.GetEndpoint(),
-		PersistentKeepalive: data.GetKeepalive(),
-		Password:            data.GetPassword(),
-		Interface:           data.GetInterface(),
-		Network:             data.GetNodenetwork(),
-		PublicKey:           data.GetPublickey(),
-		ListenPort:          data.GetListenport(),
-		UDPHolePunch:        data.GetUdpholepunch(),
+	var node models.Node
+	data := req.GetData()
+	if err := json.Unmarshal([]byte(data), &node); err != nil {
+		return nil, err
 	}
 
 	//Check to see if key is valid
@@ -86,7 +53,7 @@ func (s *NodeServiceServer) CreateNode(ctx context.Context, req *nodepb.CreateNo
 	validKey := functions.IsKeyValid(node.Network, node.AccessKey)
 	network, err := functions.GetParentNetwork(node.Network)
 	if err != nil {
-		return nil, status.Errorf(codes.NotFound, fmt.Sprintf("Could not find network: %v", err))
+		return nil, err
 	}
 
 	if !validKey {
@@ -95,274 +62,135 @@ func (s *NodeServiceServer) CreateNode(ctx context.Context, req *nodepb.CreateNo
 		if network.AllowManualSignUp == "yes" {
 			node.IsPending = "yes"
 		} else {
-			return nil, status.Errorf(
-				codes.Internal,
-				fmt.Sprintf("Invalid key, and network does not allow no-key signups"),
-			)
+			return nil, errors.New("invalid key, and network does not allow no-key signups")
 		}
 	}
 
 	node, err = CreateNode(node, node.Network)
-
 	if err != nil {
-		// return internal gRPC error to be handled later
-		return nil, status.Errorf(
-			codes.Internal,
-			fmt.Sprintf("Internal error: %v", err),
-		)
+		return nil, err
 	}
-
+	nodeData, err := json.Marshal(&node)
 	// return the node in a CreateNodeRes type
-	response := &nodepb.CreateNodeRes{
-		Node: &nodepb.Node{
-			Macaddress:   node.MacAddress,
-			Localaddress: node.LocalAddress,
-			Name:         node.Name,
-			Address:      node.Address,
-			Address6:     node.Address6,
-			Endpoint:     node.Endpoint,
-			Password:     node.Password,
-			Interface:    node.Interface,
-			Nodenetwork:  node.Network,
-			Dnsoff:       !servercfg.IsDNSMode(),
-			Ispending:    node.IsPending == "yes",
-			Publickey:    node.PublicKey,
-			Listenport:   node.ListenPort,
-			Keepalive:    node.PersistentKeepalive,
-			Islocal:      network.IsLocal == "yes",
-			Isdualstack:  network.IsDualStack == "yes",
-			Localrange:   network.LocalRange,
-			Udpholepunch: node.UDPHolePunch,
-		},
+	response := &nodepb.Object{
+		Data: string(nodeData),
+		Type: nodepb.NODE_TYPE,
 	}
 	err = SetNetworkNodesLastModified(node.Network)
 	if err != nil {
-		return nil, status.Errorf(codes.NotFound, fmt.Sprintf("Could not update network last modified date: %v", err))
+		return nil, err
 	}
 
 	return response, nil
 }
 
-func (s *NodeServiceServer) CheckIn(ctx context.Context, req *nodepb.CheckInReq) (*nodepb.CheckInRes, error) {
-	// Get the protobuf node type from the protobuf request type
-	// Essentially doing req.Node to access the struct with a nil check
-	data := req.GetNode()
-	//postchanges := req.GetPostchanges()
-	// Now we have to convert this into a NodeItem type to convert into BSON
-	node := models.Node{
-		// ID:       primitive.NilObjectID,
-		MacAddress:          data.GetMacaddress(),
-		Address:             data.GetAddress(),
-		Address6:            data.GetAddress6(),
-		Endpoint:            data.GetEndpoint(),
-		Network:             data.GetNodenetwork(),
-		Password:            data.GetPassword(),
-		LocalAddress:        data.GetLocaladdress(),
-		ListenPort:          data.GetListenport(),
-		PersistentKeepalive: data.GetKeepalive(),
-		PublicKey:           data.GetPublickey(),
-		UDPHolePunch:        data.GetUdpholepunch(),
-		SaveConfig:          data.GetSaveconfig(),
-	}
-
-	checkinresponse, err := NodeCheckIn(node, node.Network)
-
-	if err != nil {
-		// return internal gRPC error to be handled later
-		if checkinresponse == (models.CheckInResponse{}) || !checkinresponse.IsPending {
-			return nil, status.Errorf(
-				codes.Internal,
-				fmt.Sprintf("Internal error: %v", err),
-			)
-		}
-	}
-	// return the node in a CreateNodeRes type
-	response := &nodepb.CheckInRes{
-		Checkinresponse: &nodepb.CheckInResponse{
-			Success:          checkinresponse.Success,
-			Needpeerupdate:   checkinresponse.NeedPeerUpdate,
-			Needdelete:       checkinresponse.NeedDelete,
-			Needconfigupdate: checkinresponse.NeedConfigUpdate,
-			Needkeyupdate:    checkinresponse.NeedKeyUpdate,
-			Nodemessage:      checkinresponse.NodeMessage,
-			Ispending:        checkinresponse.IsPending,
-		},
-	}
-	return response, nil
-}
-
-func (s *NodeServiceServer) UpdateNode(ctx context.Context, req *nodepb.UpdateNodeReq) (*nodepb.UpdateNodeRes, error) {
+func (s *NodeServiceServer) UpdateNode(ctx context.Context, req *nodepb.Object) (*nodepb.Object, error) {
 	// Get the node data from the request
-	data := req.GetNode()
-	// Now we have to convert this into a NodeItem type to convert into BSON
-	newnode := models.Node{
-		// ID:       primitive.NilObjectID,
-		MacAddress:          data.GetMacaddress(),
-		Name:                data.GetName(),
-		Address:             data.GetAddress(),
-		Address6:            data.GetAddress6(),
-		LocalAddress:        data.GetLocaladdress(),
-		Endpoint:            data.GetEndpoint(),
-		Password:            data.GetPassword(),
-		PersistentKeepalive: data.GetKeepalive(),
-		Network:             data.GetNodenetwork(),
-		Interface:           data.GetInterface(),
-		PostDown:            data.GetPostdown(),
-		PostUp:              data.GetPostup(),
-		PublicKey:           data.GetPublickey(),
-		ListenPort:          data.GetListenport(),
-		UDPHolePunch:        data.GetUdpholepunch(),
-		SaveConfig:          data.GetSaveconfig(),
+	var newnode models.Node
+	if err := json.Unmarshal([]byte(req.GetData()), &newnode); err != nil {
+		return nil, err
 	}
-
-	// Convert the Id string to a MongoDB ObjectId
 	macaddress := newnode.MacAddress
 	networkName := newnode.Network
-	network, _ := functions.GetParentNetwork(networkName)
 
 	node, err := functions.GetNodeByMacAddress(networkName, macaddress)
 	if err != nil {
-		return nil, status.Errorf(
-			codes.NotFound,
-			fmt.Sprintf("Could not find node with supplied Mac Address: %v", err),
-		)
+		return nil, err
 	}
 
 	err = node.Update(&newnode)
-
-	if err != nil {
-		return nil, status.Errorf(
-			codes.NotFound,
-			fmt.Sprintf("Could not update node: %v", err),
-		)
-	}
-	return &nodepb.UpdateNodeRes{
-		Node: &nodepb.Node{
-			Macaddress:   newnode.MacAddress,
-			Localaddress: newnode.LocalAddress,
-			Name:         newnode.Name,
-			Address:      newnode.Address,
-			Address6:     newnode.Address6,
-			Endpoint:     newnode.Endpoint,
-			Password:     newnode.Password,
-			Interface:    newnode.Interface,
-			Postdown:     newnode.PostDown,
-			Postup:       newnode.PostUp,
-			Nodenetwork:  newnode.Network,
-			Ispending:    newnode.IsPending == "yes",
-			Publickey:    newnode.PublicKey,
-			Dnsoff:       !servercfg.IsDNSMode(),
-			Listenport:   newnode.ListenPort,
-			Keepalive:    newnode.PersistentKeepalive,
-			Islocal:      network.IsLocal == "yes",
-			Isdualstack:  network.IsDualStack == "yes",
-			Localrange:   network.LocalRange,
-			Udpholepunch: newnode.UDPHolePunch,
-		},
-	}, nil
-}
-
-func (s *NodeServiceServer) DeleteNode(ctx context.Context, req *nodepb.DeleteNodeReq) (*nodepb.DeleteNodeRes, error) {
-	macaddress := req.GetMacaddress()
-	network := req.GetNetworkName()
-
-	err := DeleteNode(macaddress, network)
-
 	if err != nil {
-		fmt.Println("Error deleting node.")
-		fmt.Println(err)
-		return nil, status.Errorf(codes.NotFound, fmt.Sprintf("Could not find/delete node with mac address %s", macaddress))
+		return nil, err
 	}
-
-	fmt.Println("updating network last modified of " + req.GetNetworkName())
-	err = SetNetworkNodesLastModified(req.GetNetworkName())
+	nodeData, err := json.Marshal(&newnode)
 	if err != nil {
-		fmt.Println("Error updating Network")
-		fmt.Println(err)
-		return nil, status.Errorf(codes.NotFound, fmt.Sprintf("Could not update network last modified date: %v", err))
+		return nil, err
 	}
-
-	return &nodepb.DeleteNodeRes{
-		Success: true,
+	return &nodepb.Object{
+		Data: string(nodeData),
+		Type: nodepb.NODE_TYPE,
 	}, nil
 }
 
-func (s *NodeServiceServer) GetPeers(req *nodepb.GetPeersReq, stream nodepb.NodeService_GetPeersServer) error {
-	// Initiate a NodeItem type to write decoded data to
-	//data := &models.PeersResponse{}
-	// collection.Find returns a cursor for our (empty) query
-	peers, err := GetPeersList(req.GetNetwork())
+func (s *NodeServiceServer) DeleteNode(ctx context.Context, req *nodepb.Object) (*nodepb.Object, error) {
+	nodeID := req.GetData()
 
+	err := DeleteNode(nodeID, true)
 	if err != nil {
-		return status.Errorf(codes.Internal, fmt.Sprintf("Unknown internal error: %v", err))
+		return nil, err
 	}
-	// cursor.Next() returns a boolean, if false there are no more items and loop will break
-	for i := 0; i < len(peers); i++ {
 
-		// If no error is found send node over stream
-		stream.Send(&nodepb.GetPeersRes{
-			Peers: &nodepb.PeersResponse{
-				Address:            peers[i].Address,
-				Address6:           peers[i].Address6,
-				Endpoint:           peers[i].Endpoint,
-				Egressgatewayranges: peers[i].EgressGatewayRanges,
-				Isegressgateway:    peers[i].IsEgressGateway == "yes",
-				Publickey:          peers[i].PublicKey,
-				Keepalive:          peers[i].KeepAlive,
-				Listenport:         peers[i].ListenPort,
-				Localaddress:       peers[i].LocalAddress,
-			},
-		})
-	}
+	return &nodepb.Object{
+		Data: "success",
+		Type: nodepb.STRING_TYPE,
+	}, nil
+}
 
-	node, err := functions.GetNodeByMacAddress(req.GetNetwork(), req.GetMacaddress())
-	if err != nil {
-		return status.Errorf(codes.Internal, fmt.Sprintf("Could not get node: %v", err))
-	}
+func (s *NodeServiceServer) GetPeers(ctx context.Context, req *nodepb.Object) (*nodepb.Object, error) {
+	macAndNetwork := strings.Split(req.Data, "###")
+	if len(macAndNetwork) == 2 {
+		// TODO: Make constant and new variable for isServer
+		node, err := GetNode(macAndNetwork[0], macAndNetwork[1])
+		if err != nil {
+			return nil, err
+		}
+		if node.IsServer == "yes" {
+			SetNetworkServerPeers(macAndNetwork[1])
+		}
+		peers, err := GetPeersList(macAndNetwork[1])
+		if err != nil {
+			return nil, err
+		}
 
-	err = TimestampNode(node, false, true, false)
-	if err != nil {
-		return status.Errorf(codes.Internal, fmt.Sprintf("Internal error occurred: %v", err))
+		peersData, err := json.Marshal(&peers)
+		return &nodepb.Object{
+			Data: string(peersData),
+			Type: nodepb.NODE_TYPE,
+		}, err
 	}
-
-	return nil
+	return &nodepb.Object{
+		Data: "",
+		Type: nodepb.NODE_TYPE,
+	}, errors.New("could not fetch peers, invalid node id")
 }
 
-func (s *NodeServiceServer) GetExtPeers(req *nodepb.GetExtPeersReq, stream nodepb.NodeService_GetExtPeersServer) error {
+/**
+ * Return Ext Peers (clients).NodeCheckIn
+ * When a gateway node checks in, it pulls these peers to add to peers list in addition to normal network peers.
+ */
+func (s *NodeServiceServer) GetExtPeers(ctx context.Context, req *nodepb.Object) (*nodepb.Object, error) {
 	// Initiate a NodeItem type to write decoded data to
 	//data := &models.PeersResponse{}
 	// collection.Find returns a cursor for our (empty) query
-	peers, err := GetExtPeersList(req.GetNetwork(), req.GetMacaddress())
-
+	macAndNetwork := strings.Split(req.Data, "###")
+	if len(macAndNetwork) != 2 {
+		return nil, errors.New("did not receive valid node id when fetching ext peers")
+	}
+	peers, err := GetExtPeersList(macAndNetwork[0], macAndNetwork[1])
 	if err != nil {
-		return status.Errorf(codes.Internal, fmt.Sprintf("Unknown internal error: %v", err))
+		return nil, err
 	}
 	// cursor.Next() returns a boolean, if false there are no more items and loop will break
+	var extPeers []models.Node
 	for i := 0; i < len(peers); i++ {
-
-		// If no error is found send node over stream
-		stream.Send(&nodepb.GetExtPeersRes{
-			Extpeers: &nodepb.ExtPeersResponse{
-				Address:      peers[i].Address,
-				Address6:     peers[i].Address6,
-				Endpoint:     peers[i].Endpoint,
-				Publickey:    peers[i].PublicKey,
-				Keepalive:    peers[i].KeepAlive,
-				Listenport:   peers[i].ListenPort,
-				Localaddress: peers[i].LocalAddress,
-			},
+		extPeers = append(extPeers, models.Node{
+			Address:             peers[i].Address,
+			Address6:            peers[i].Address6,
+			Endpoint:            peers[i].Endpoint,
+			PublicKey:           peers[i].PublicKey,
+			PersistentKeepalive: peers[i].KeepAlive,
+			ListenPort:          peers[i].ListenPort,
+			LocalAddress:        peers[i].LocalAddress,
 		})
 	}
 
-	node, err := functions.GetNodeByMacAddress(req.GetNetwork(), req.GetMacaddress())
-	if err != nil {
-		return status.Errorf(codes.Internal, fmt.Sprintf("Could not get node: %v", err))
-	}
-
-	err = TimestampNode(node, false, true, false)
+	extData, err := json.Marshal(&extPeers)
 	if err != nil {
-		return status.Errorf(codes.Internal, fmt.Sprintf("Internal error occurred: %v", err))
+		return nil, err
 	}
 
-	return nil
+	return &nodepb.Object{
+		Data: string(extData),
+		Type: nodepb.EXT_PEER,
+	}, nil
 }

+ 38 - 68
controllers/nodeHttpController.go

@@ -3,11 +3,9 @@ package controller
 import (
 	"encoding/json"
 	"errors"
-	"log"
 	"net/http"
 	"strings"
 	"time"
-
 	"github.com/gorilla/mux"
 	"github.com/gravitl/netmaker/database"
 	"github.com/gravitl/netmaker/functions"
@@ -23,7 +21,6 @@ func nodeHandlers(r *mux.Router) {
 	r.HandleFunc("/api/nodes/{network}/{macaddress}", authorize(true, "node", http.HandlerFunc(getNode))).Methods("GET")
 	r.HandleFunc("/api/nodes/{network}/{macaddress}", authorize(true, "node", http.HandlerFunc(updateNode))).Methods("PUT")
 	r.HandleFunc("/api/nodes/{network}/{macaddress}", authorize(true, "node", http.HandlerFunc(deleteNode))).Methods("DELETE")
-	r.HandleFunc("/api/nodes/{network}/{macaddress}/checkin", authorize(true, "node", http.HandlerFunc(checkIn))).Methods("POST")
 	r.HandleFunc("/api/nodes/{network}/{macaddress}/creategateway", authorize(true, "user", http.HandlerFunc(createEgressGateway))).Methods("POST")
 	r.HandleFunc("/api/nodes/{network}/{macaddress}/deletegateway", authorize(true, "user", http.HandlerFunc(deleteEgressGateway))).Methods("DELETE")
 	r.HandleFunc("/api/nodes/{network}/{macaddress}/createingress", securityCheck(false, http.HandlerFunc(createIngressGateway))).Methods("POST")
@@ -198,7 +195,7 @@ func authorize(networkCheck bool, authNetwork string, next http.Handler) http.Ha
 				isAuthorized = true
 				r.Header.Set("ismasterkey", "yes")
 			} else {
-                                r.Header.Set("ismasterkey", "")
+				r.Header.Set("ismasterkey", "")
 				mac, _, err := functions.VerifyToken(authToken)
 				if err != nil {
 					errorResponse = models.ErrorResponse{
@@ -294,6 +291,9 @@ func GetNetworkNodes(network string) ([]models.Node, error) {
 	var nodes []models.Node
 	collection, err := database.FetchRecords(database.NODES_TABLE_NAME)
 	if err != nil {
+		if database.IsEmptyRecord(err) {
+			return []models.Node{}, nil
+		}
 		return nodes, err
 	}
 	for _, value := range collection {
@@ -320,7 +320,7 @@ func getAllNodes(w http.ResponseWriter, r *http.Request) {
 		return
 	}
 	var nodes []models.Node
-	if user.IsAdmin  || r.Header.Get("ismasterkey") == "yes" {
+	if user.IsAdmin || r.Header.Get("ismasterkey") == "yes" {
 		nodes, err = models.GetAllNodes()
 		if err != nil {
 			returnErrorResponse(w, r, formatError(err, "internal"))
@@ -352,49 +352,6 @@ func getUsersNodes(user models.User) ([]models.Node, error) {
 	return nodes, err
 }
 
-//This function get's called when a node "checks in" at check in interval
-//Honestly I'm not sure what all it should be doing
-//TODO: Implement the necessary stuff, including the below
-//Check the last modified of the network
-//Check the last modified of the nodes
-//Write functions for responding to these two thingies
-func checkIn(w http.ResponseWriter, r *http.Request) {
-
-	//TODO: Current thoughts:
-	//Dont bother with a networklastmodified
-	//Instead, implement a "configupdate" boolean on nodes
-	//when there is a network update  that requrires  a config update,  then the node will pull its new config
-
-	// set header.
-	w.Header().Set("Content-Type", "application/json")
-
-	var params = mux.Vars(r)
-	node, err := CheckIn(params["network"], params["macaddress"])
-	if err != nil {
-		returnErrorResponse(w, r, formatError(err, "internal"))
-		return
-	}
-	w.WriteHeader(http.StatusOK)
-	json.NewEncoder(w).Encode(node)
-}
-func CheckIn(network string, macaddress string) (models.Node, error) {
-	var node models.Node
-
-	node, err := GetNode(macaddress, network)
-	key, err := functions.GetRecordKey(macaddress, network)
-	if err != nil {
-		return node, err
-	}
-	time := time.Now().Unix()
-	node.LastCheckIn = time
-	data, err := json.Marshal(&node)
-	if err != nil {
-		return node, err
-	}
-	err = database.Insert(key, string(data), database.NODES_TABLE_NAME)
-	return node, err
-}
-
 //Get an individual node. Nothin fancy here folks.
 func getNode(w http.ResponseWriter, r *http.Request) {
 	// set header.
@@ -520,6 +477,7 @@ func UncordonNode(network, macaddress string) (models.Node, error) {
 	}
 	node.SetLastModified()
 	node.IsPending = "no"
+	node.PullChanges = "yes"
 	data, err := json.Marshal(&node)
 	if err != nil {
 		return node, err
@@ -590,17 +548,18 @@ func CreateEgressGateway(gateway models.EgressGatewayRequest) (models.Node, erro
 	node.PostUp = postUpCmd
 	node.PostDown = postDownCmd
 	node.SetLastModified()
+	node.PullChanges = "yes"
 	nodeData, err := json.Marshal(&node)
 	if err != nil {
 		return node, err
 	}
-	err = database.Insert(key, string(nodeData), database.NODES_TABLE_NAME)
-	// prepare update model.
-	if err != nil {
+	if err = database.Insert(key, string(nodeData), database.NODES_TABLE_NAME); err != nil {
 		return models.Node{}, err
 	}
-	err = SetNetworkNodesLastModified(gateway.NetID)
-	return node, err
+	if err = functions.NetworkNodesUpdatePullChanges(node.Network); err != nil {
+		return models.Node{}, err
+	}
+	return node, nil
 }
 
 func ValidateEgressGateway(gateway models.EgressGatewayRequest) error {
@@ -627,7 +586,7 @@ func deleteEgressGateway(w http.ResponseWriter, r *http.Request) {
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 	}
-	functions.PrintUserLog(r.Header.Get("user"), "delete egress gateway "+nodeMac+" on network "+netid, 1)
+	functions.PrintUserLog(r.Header.Get("user"), "deleted egress gateway "+nodeMac+" on network "+netid, 1)
 	w.WriteHeader(http.StatusOK)
 	json.NewEncoder(w).Encode(node)
 }
@@ -644,6 +603,7 @@ func DeleteEgressGateway(network, macaddress string) (models.Node, error) {
 	node.PostUp = ""
 	node.PostDown = ""
 	node.SetLastModified()
+	node.PullChanges = "yes"
 	key, err := functions.GetRecordKey(node.MacAddress, node.Network)
 	if err != nil {
 		return models.Node{}, err
@@ -652,12 +612,10 @@ func DeleteEgressGateway(network, macaddress string) (models.Node, error) {
 	if err != nil {
 		return models.Node{}, err
 	}
-	err = database.Insert(key, string(data), database.NODES_TABLE_NAME)
-	if err != nil {
+	if err = database.Insert(key, string(data), database.NODES_TABLE_NAME); err != nil {
 		return models.Node{}, err
 	}
-	err = SetNetworkNodesLastModified(network)
-	if err != nil {
+	if err = functions.NetworkNodesUpdatePullChanges(network); err != nil {
 		return models.Node{}, err
 	}
 	return node, nil
@@ -688,7 +646,6 @@ func CreateIngressGateway(netid string, macaddress string) (models.Node, error)
 
 	network, err := functions.GetParentNetwork(netid)
 	if err != nil {
-		log.Println("Could not find network.")
 		return models.Node{}, err
 	}
 	node.IsIngressGateway = "yes"
@@ -706,8 +663,10 @@ func CreateIngressGateway(netid string, macaddress string) (models.Node, error)
 		}
 	}
 	node.SetLastModified()
-        node.PostUp = postUpCmd
-        node.PostDown = postDownCmd
+	node.PostUp = postUpCmd
+	node.PostDown = postDownCmd
+	node.PullChanges = "yes"
+	node.UDPHolePunch = "no"
 	key, err := functions.GetRecordKey(node.MacAddress, node.Network)
 	if err != nil {
 		return models.Node{}, err
@@ -738,14 +697,27 @@ func deleteIngressGateway(w http.ResponseWriter, r *http.Request) {
 	json.NewEncoder(w).Encode(node)
 }
 
-func DeleteIngressGateway(network, macaddress string) (models.Node, error) {
+func DeleteIngressGateway(networkName string, macaddress string) (models.Node, error) {
 
-	node, err := functions.GetNodeByMacAddress(network, macaddress)
+	node, err := functions.GetNodeByMacAddress(networkName, macaddress)
+	if err != nil {
+		return models.Node{}, err
+	}
+	network, err := functions.GetParentNetwork(networkName)
 	if err != nil {
 		return models.Node{}, err
 	}
+	// delete ext clients belonging to ingress gateway
+	if err = DeleteGatewayExtClients(macaddress, networkName); err != nil {
+		return models.Node{}, err
+	}
+
+	node.UDPHolePunch = network.DefaultUDPHolePunch
 	node.LastModified = time.Now().Unix()
 	node.IsIngressGateway = "no"
+	node.IngressGatewayRange = ""
+	node.PullChanges = "yes"
+
 	key, err := functions.GetRecordKey(node.MacAddress, node.Network)
 	if err != nil {
 		return models.Node{}, err
@@ -758,7 +730,7 @@ func DeleteIngressGateway(network, macaddress string) (models.Node, error) {
 	if err != nil {
 		return models.Node{}, err
 	}
-	err = SetNetworkNodesLastModified(network)
+	err = SetNetworkNodesLastModified(networkName)
 	return node, err
 }
 
@@ -782,15 +754,13 @@ func updateNode(w http.ResponseWriter, r *http.Request) {
 		returnErrorResponse(w, r, formatError(err, "badrequest"))
 		return
 	}
+	newNode.PullChanges = "yes"
 	err = node.Update(&newNode)
 	if err != nil {
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 	}
 
-	if err = SetNetworkNodesLastModified(node.Network); err != nil {
-		log.Println(err)
-	}
 	if servercfg.IsDNSMode() {
 		err = SetDNS()
 	}
@@ -812,7 +782,7 @@ func deleteNode(w http.ResponseWriter, r *http.Request) {
 	// get params
 	var params = mux.Vars(r)
 
-	err := DeleteNode(params["macaddress"], params["network"])
+	err := DeleteNode(params["macaddress"]+"###"+params["network"], false)
 
 	if err != nil {
 		returnErrorResponse(w, r, formatError(err, "internal"))

+ 1 - 1
controllers/serverHttpController.go

@@ -12,7 +12,7 @@ import (
 )
 
 func serverHandlers(r *mux.Router) {
-    //r.HandleFunc("/api/server/addnetwork/{network}", securityCheckServer(http.HandlerFunc(addNetwork))).Methods("POST")
+    r.HandleFunc("/api/server/addnetwork/{network}", securityCheckServer(http.HandlerFunc(addNetwork))).Methods("POST")
     r.HandleFunc("/api/server/getconfig", securityCheckServer(http.HandlerFunc(getConfig))).Methods("GET")
     r.HandleFunc("/api/server/getwgconfig", securityCheckServer(http.HandlerFunc(getWGConfig))).Methods("GET")
     r.HandleFunc("/api/server/removenetwork/{network}", securityCheckServer(http.HandlerFunc(removeNetwork))).Methods("DELETE")

+ 12 - 6
controllers/userHttpController.go

@@ -183,9 +183,13 @@ func HasAdmin() (bool, error) {
 
 	collection, err := database.FetchRecords(database.USERS_TABLE_NAME)
 	if err != nil {
-		return false, err
+		if database.IsEmptyRecord(err) {
+			return false, nil
+		} else {
+			return true, err
+	
+		}
 	}
-
 	for _, value := range collection { // filter for isadmin true
 		var user models.User
 		err = json.Unmarshal([]byte(value), &user)
@@ -204,9 +208,11 @@ func hasAdmin(w http.ResponseWriter, r *http.Request) {
 
 	w.Header().Set("Content-Type", "application/json")
 
-	hasadmin, _ := HasAdmin()
-
-	//Returns all the nodes in JSON format
+	hasadmin, err := HasAdmin()
+	if err != nil {
+		returnErrorResponse(w, r, formatError(err, "internal"))
+		return
+	}	
 
 	json.NewEncoder(w).Encode(hasadmin)
 
@@ -396,7 +402,7 @@ func UpdateUser(userchange models.User, user models.User) (models.User, error) {
 	if err = database.Insert(user.UserName, string(data), database.USERS_TABLE_NAME); err != nil {
 		return models.User{}, err
 	}
-	functions.PrintUserLog("netmaker", "updated user "+queryUser, 1)
+	functions.PrintUserLog(models.NODE_SERVER_NAME, "updated user "+queryUser, 1)
 	return user, nil
 }
 

+ 2 - 2
controllers/userHttpController_test.go

@@ -13,7 +13,7 @@ import (
 	gconf.ServerGRPC = "localhost:8081"
 	gconf.PortGRPC = "50051"
 	//err := SetGlobalConfig(gconf)
-	collection := REMOVE.Client.Database("netmaker").Collection("config")
+	collection := REMOVE.Client.Database(models.NODE_SERVER_NAME).Collection("config")
 	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
 	defer cancel()
 	//create, _, err := functions.GetGlobalConfig()
@@ -24,7 +24,7 @@ import (
 	//drop network, nodes, and user collections
 	var collections = []string{"networks", "nodes", "users", "dns"}
 	for _, table := range collections {
-		collection := REMOVE.Client.Database("netmaker").Collection(table)
+		collection := REMOVE.Client.Database(models.NODE_SERVER_NAME).Collection(table)
 		ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
 		defer cancel()
 		err := collection.Drop(ctx)

+ 27 - 1
database/database.go

@@ -3,17 +3,24 @@ package database
 import (
 	"encoding/json"
 	"errors"
+
 	"github.com/rqlite/gorqlite"
 )
 
 const NETWORKS_TABLE_NAME = "networks"
 const NODES_TABLE_NAME = "nodes"
+const DELETED_NODES_TABLE_NAME = "deletednodes"
 const USERS_TABLE_NAME = "users"
 const DNS_TABLE_NAME = "dns"
 const EXT_CLIENT_TABLE_NAME = "extclients"
 const INT_CLIENTS_TABLE_NAME = "intclients"
+const PEERS_TABLE_NAME = "peers"
 const DATABASE_FILENAME = "netmaker.db"
 
+// == ERROR CONSTS ==
+const NO_RECORD = "no result found"
+const NO_RECORDS = "could not find any records"
+
 var Database gorqlite.Connection
 
 func InitializeDatabase() error {
@@ -33,10 +40,12 @@ func InitializeDatabase() error {
 func createTables() {
 	createTable(NETWORKS_TABLE_NAME)
 	createTable(NODES_TABLE_NAME)
+	createTable(DELETED_NODES_TABLE_NAME)
 	createTable(USERS_TABLE_NAME)
 	createTable(DNS_TABLE_NAME)
 	createTable(EXT_CLIENT_TABLE_NAME)
 	createTable(INT_CLIENTS_TABLE_NAME)
+	createTable(PEERS_TABLE_NAME)
 }
 
 func createTable(tableName string) error {
@@ -64,6 +73,18 @@ func Insert(key string, value string, tableName string) error {
 	}
 }
 
+func InsertPeer(key string, value string) error {
+	if key != "" && value != "" && isJSONString(value) {
+		_, err := Database.WriteOne("INSERT OR REPLACE INTO " + PEERS_TABLE_NAME + " (key, value) VALUES ('" + key + "', '" + value + "')")
+		if err != nil {
+			return err
+		}
+		return nil
+	} else {
+		return errors.New("invalid peer insert " + key + " : " + value)
+	}
+}
+
 func DeleteRecord(tableName string, key string) error {
 	_, err := Database.WriteOne("DELETE FROM " + tableName + " WHERE key = \"" + key + "\"")
 	if err != nil {
@@ -89,6 +110,9 @@ func FetchRecord(tableName string, key string) (string, error) {
 	if err != nil {
 		return "", err
 	}
+	if results[key] == "" {
+		return "", errors.New(NO_RECORD)
+	}
 	return results[key], nil
 }
 
@@ -104,6 +128,8 @@ func FetchRecords(tableName string) (map[string]string, error) {
 		row.Scan(&key, &value)
 		records[key] = value
 	}
-	// log.Println(records)
+	if len(records) == 0 {
+		return nil, errors.New(NO_RECORDS)
+	}
 	return records, nil
 }

+ 54 - 0
database/statics.go

@@ -0,0 +1,54 @@
+package database
+
+import (
+	"encoding/json"
+	"strings"
+)
+
+func SetPeers(newPeers map[string]string, networkName string) bool {
+	areEqual := PeersAreEqual(newPeers, networkName)
+	if !areEqual {
+		jsonData, err := json.Marshal(newPeers)
+		if err != nil {
+			return false
+		}
+		InsertPeer(networkName, string(jsonData))
+		return true
+	}
+	return !areEqual
+}
+func GetPeers(networkName string) (map[string]string, error) {
+	record, err := FetchRecord(PEERS_TABLE_NAME, networkName)
+	if err != nil && !IsEmptyRecord(err) {
+		return nil, err
+	}
+	currentDataMap := make(map[string]string)
+	if IsEmptyRecord(err) {
+		return currentDataMap, nil
+	}
+	err = json.Unmarshal([]byte(record), &currentDataMap)
+	return currentDataMap, err
+}
+
+func PeersAreEqual(toCompare map[string]string, networkName string) bool {
+	currentDataMap, err := GetPeers(networkName)
+	if err != nil {
+		return false
+	}
+	if len(currentDataMap) != len(toCompare) {
+		return false
+	}
+	for k := range currentDataMap {
+		if toCompare[k] != currentDataMap[k] {
+			return false
+		}
+	}
+	return true
+}
+
+func IsEmptyRecord(err error) bool {
+	if err == nil {
+		return false
+	}
+	return strings.Contains(err.Error(), NO_RECORD) || strings.Contains(err.Error(), NO_RECORDS)
+}

+ 39 - 42
docs/quick-start.rst

@@ -9,7 +9,7 @@ This is an **opinionated** guide for getting up and running with Netmaker as qui
 
 We assume for this installation that you want all of the features, want your server to be secure, and want it to be accessible from anywhere. 
 
-We assume you are not deploying for an enterprise-grade scenario. This instance will not be HA, and is not horizontally scalable. However, it should comfortably handle several hundred clients and most average use cases.
+This instance will not be HA, and is not horizontally scalable. However, it should comfortably handle several hundred clients and most average use cases. If you are deploying for an enterprise use case, please contact [email protected] for support.
 
 By the end of this guide, you will have Netmaker installed on a public VM linked to your custom domain, secured behind an Nginx reverse proxy.
 
@@ -21,7 +21,7 @@ By the end of this guide, you will have Netmaker installed on a public VM linked
    - Preferably from a cloud provider (e.x: DigitalOcean, Linode, AWS, GCP, etc.)
    - Public, static IP 
    - Min 2GB RAM, 1 CPU (4GB RAM, 2CPU preferred)
-   - 1GB+ of storage
+   - 5GB+ of storage
    - Ubuntu  20.04 Installed
 
 - **Domain**
@@ -47,18 +47,11 @@ Begin by installing the community version of Docker and docker-compose (there ar
  
 ``sudo apt-get update``
  
-    ``sudo apt-get install \
-    apt-transport-https \
-    ca-certificates \
-    curl \
-    gnupg \
-    lsb-release``
+    ``sudo apt-get install apt-transport-https ca-certificates curl gnupg lsb-release``
 
 ``curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg``
   
-  ``echo \
-  "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \
-  $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null``
+  ``echo "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null``
   
 ``sudo apt-get update``
   
@@ -85,7 +78,10 @@ Install Dependencies
 
 Prepare Domain
 ----------------------------
-1. Choose a base domain or subdomain for Netmaker. If you own **example.com**, this should be something like **netmaker.example.com** 
+1. Choose a base domain or subdomain for Netmaker. If you own **example.com**, this should be something like **netmaker.example.com**
+
+    - You must point your wildcard domain to the public IP of your VM, e.x: *.example.com --> <your public ip>
+
 2. Add an A record pointing to your VM using your DNS service provider for *.netmaker.example.com (inserting your own subdomain of course).
 3. Netmaker will create three subdomains on top of this. For the example above those subdomains would be:
 
@@ -101,77 +97,78 @@ Moving forward we will refer to your base domain using **<your base domain>**. R
 
 5. Generate SSL Certificates using certbot:
 
-  ``certbot certonly --manual \
-  --preferred-challenges=dns \
-  --email [email protected] \
-  --server https://acme-v02.api.letsencrypt.org/directory \
-  --agree-tos \
-  --manual-public-ip-logging-ok \
-  -d “*.<your base domain>”``
+  ``sudo certbot certonly --manual --preferred-challenges=dns --email [email protected] --server https://acme-v02.api.letsencrypt.org/directory --agree-tos --manual-public-ip-logging-ok -d "*.<your base domain>"``
 
-The above command (using your domain instead of <your base domain>), will prompt you to enter a TXT record in your DNS service provider. Do this, and wait a few seconds before clicking enter, or it may fail and you will have to run the command again.
+The above command (using your domain instead of <your base domain>), will prompt you to enter a TXT record in your DNS service provider. Do this, and **wait one  minute** before clicking enter, or it may fail and you will have to run the command again.
 
 Prepare Firewall
 -----------------
 
 Make sure firewall settings are appropriate for Netmaker. You need ports 53 and 443. On the server you can run:
 
-``sudo ufw allow proto tcp from any to any port 443``
-``sudo ufw allow dns``
+``sudo ufw allow proto tcp from any to any port 443 && sudo ufw allow dns && ``
+
+**Based on your cloud provider, you may also need to set inbound security rules for your server. This will be dependent on your cloud provider. Be sure to check before moving on:**
+  - allow 443/tcp from all
+  - allow 1443/tcp from all
+  - allow 53/udp from all
+
+Prepare for DNS
+----------------------------------------------------------------
+
+On Ubuntu 20.04, by default there is a service consuming port 53 related to DNS resolution. We need port 53 open in order to run our own DNS server. The below steps will disable systemd-resolved, and insert a generic DNS nameserver for local resolution.
 
-Based on your cloud provider, you may also need to set inbound security rules for your server. This will be dependent on your cloud provider. Be sure to check before moving on.
+1. ``sudo systemctl stop systemd-resolved``
+2. ``sudo systemctl disable systemd-resolved``
+3. ``sudo vim /etc/systemd/resolved.conf``
+    * uncomment DNS and add 8.8.8.8 or whatever reachable nameserver is your preference
+    * uncomment DNSStubListener and set to "no"
+4. ``sudo ln -sf /run/systemd/resolve/resolv.conf /etc/resolv.conf``
 
 Prepare Nginx
 -----------------
 
 Nginx will serve the SSL certificate with your chosen domain and forward traffic to netmaker.
 
-Add the nginx configuration file:
+Add the nginx configuration files:
 
-``wget https://github.com/gravitl/netmaker/TEMPLATE.conf``
+``wget https://raw.githubusercontent.com/gravitl/netmaker/develop/nginx/netmaker-nginx-template.conf``
+
+``wget https://raw.githubusercontent.com/gravitl/netmaker/develop/nginx/netmaker-nginx-dns.conf``
 
 Insert your domain in the configuration file and add to nginx:
 
-``sed -i ‘s/NETMAKER_BASE_DOMAIN/<your base domain>/g’ netmaker-nginx-template.conf``
+``sed -i 's/NETMAKER_BASE_DOMAIN/<your base domain>/g' netmaker-nginx-template.conf ``
 
-``sudo cp netmaker-nginx-template.conf /etc/nginx/conf.d/<your base domain>.conf``
-``sudo cp netmaker-nginx-dns.conf /etc/nginx/nginx.conf``
+``sudo cp netmaker-nginx-template.conf /etc/nginx/conf.d/<your base domain>.conf && sudo cp netmaker-nginx-dns.conf /etc/nginx/nginx.conf``
 
 ``nginx -t && nginx -s reload``
 
 ``systemctl restart nginx``
 
 
-[NOTE: May not be necessary. Test with 5353] Prepare for DNS
-----------------------------------------------------------------
-
-On Ubuntu 20.04, by default there is a service consuming port 53 related to DNS resolution. We need port 53 open in order to run our own DNS server. The below steps will disable systemd-resolved, and insert a generic DNS nameserver for local resolution. 
-
-1. ``systemctl stop systemd-resolved`` 
-2. ``systemctl disable systemd-resolved`` 
-3. ``vim /etc/systemd/resolved.conf``
-    * uncomment DNS and add 8.8.8.8 or whatever reachable nameserver is your preference
-    * uncomment DNSStubListener and set to "no"
-4. ``ln -sf /run/systemd/resolve/resolv.conf /etc/resolv.conf``
-
 Install Netmaker
 =================
 
 Prepare Templates
 ------------------
 
-wget netmaker template
+``wget https://raw.githubusercontent.com/gravitl/netmaker/develop/compose/docker-compose.quickstart.yml``
 
 ``sed -i 's/NETMAKER_BASE_DOMAIN/<your base domain>/g' docker-compose.quickstart.yml``
+
 ``sed -i 's/SERVER_PUBLIC_IP/<your server ip>/g' docker-compose.quickstart.yml``
 
 Generate a unique master key and insert it:
+
 ``tr -dc A-Za-z0-9 </dev/urandom | head -c 30 ; echo ''``
+
 ``sed -i 's/REPLACE_MASTER_KEY/<your generated key>/g' docker-compose.quickstart.yml``
 
 Start Netmaker
 ----------------
- docker-compose -f docker-compose.quickstart.yml up -d
+
+``sudo docker-compose -f docker-compose.quickstart.yml up -d``
 
 ===========
 Quick Start

+ 99 - 37
functions/helpers.go

@@ -20,6 +20,11 @@ import (
 	"github.com/gravitl/netmaker/servercfg"
 )
 
+func CheckEndpoint(endpoint string) bool {
+	endpointarr := strings.Split(endpoint, ":")
+	return len(endpointarr) == 2
+}
+
 func PrintUserLog(username string, message string, loglevel int) {
 	log.SetFlags(log.Flags() &^ (log.Llongfile | log.Lshortfile))
 	if int32(loglevel) <= servercfg.GetVerbose() && servercfg.GetVerbose() != 0 {
@@ -195,9 +200,6 @@ func GetRecordKey(id string, network string) (string, error) {
 	return id + "###" + network, nil
 }
 
-//TODO: This is  very inefficient (N-squared). Need to find a better way.
-//Takes a list of  nodes in a network and iterates through
-//for each node, it gets a unique address. That requires checking against all other nodes once more
 func UpdateNetworkNodeAddresses(networkName string) error {
 
 	collections, err := database.FetchRecords(database.NODES_TABLE_NAME)
@@ -213,18 +215,85 @@ func UpdateNetworkNodeAddresses(networkName string) error {
 			fmt.Println("error in node address assignment!")
 			return err
 		}
-		ipaddr, iperr := UniqueAddress(networkName)
-		if iperr != nil {
-			fmt.Println("error in node  address assignment!")
-			return iperr
+		if node.Network == networkName {
+			ipaddr, iperr := UniqueAddress(networkName)
+			if iperr != nil {
+				fmt.Println("error in node  address assignment!")
+				return iperr
+			}
+
+			node.Address = ipaddr
+			data, err := json.Marshal(&node)
+			if err != nil {
+				return err
+			}
+			node.SetID()
+			database.Insert(node.ID, string(data), database.NODES_TABLE_NAME)
 		}
+	}
+
+	return nil
+}
+
+func NetworkNodesUpdateAction(networkName string, action string) error {
+
+	collections, err := database.FetchRecords(database.NODES_TABLE_NAME)
+	if err != nil {
+		if database.IsEmptyRecord(err) {
+			return nil
+		}
+		return err
+	}
 
-		node.Address = ipaddr
-		data, err := json.Marshal(&node)
+	for _, value := range collections {
+		var node models.Node
+		err := json.Unmarshal([]byte(value), &node)
 		if err != nil {
+			fmt.Println("error in node address assignment!")
 			return err
 		}
-		database.Insert(node.MacAddress, string(data), database.NODES_TABLE_NAME)
+		if action == models.NODE_UPDATE_KEY && node.IsStatic == "yes" {
+			continue
+		}
+		if node.Network == networkName {
+			node.Action = action
+			data, err := json.Marshal(&node)
+			if err != nil {
+				return err
+			}
+			node.SetID()
+			database.Insert(node.ID, string(data), database.NODES_TABLE_NAME)
+		}
+ 	}
+	return nil
+}
+
+func NetworkNodesUpdatePullChanges(networkName string) error {
+
+	collections, err := database.FetchRecords(database.NODES_TABLE_NAME)
+	if err != nil {
+		if database.IsEmptyRecord(err) {
+			return nil
+		}
+		return err
+	}
+
+	for _, value := range collections {
+		var node models.Node
+		err := json.Unmarshal([]byte(value), &node)
+		if err != nil {
+			fmt.Println("error in node address assignment!")
+			return err
+		}
+		if node.Network == networkName {
+			node.PullChanges = "yes"
+			data, err := json.Marshal(&node)
+			if err != nil {
+				return err
+			}
+			node.SetID()
+			database.Insert(node.ID, string(data), database.NODES_TABLE_NAME)
+		}
 	}
 
 	return nil
@@ -247,19 +316,22 @@ func UpdateNetworkLocalAddresses(networkName string) error {
 			fmt.Println("error in node address assignment!")
 			return err
 		}
-		ipaddr, iperr := UniqueAddress(networkName)
-		if iperr != nil {
-			fmt.Println("error in node  address assignment!")
-			return iperr
-		}
+		if node.Network == networkName {
+			ipaddr, iperr := UniqueAddress(networkName)
+			if iperr != nil {
+				fmt.Println("error in node  address assignment!")
+				return iperr
+			}
 
-		node.Address = ipaddr
-		newNodeData, err := json.Marshal(&node)
-		if err != nil {
-			fmt.Println("error in node  address assignment!")
-			return err
+			node.Address = ipaddr
+			newNodeData, err := json.Marshal(&node)
+			if err != nil {
+				fmt.Println("error in node  address assignment!")
+				return err
+			}
+			node.SetID()
+			database.Insert(node.ID, string(newNodeData), database.NODES_TABLE_NAME)
 		}
-		database.Insert(node.MacAddress, string(newNodeData), database.NODES_TABLE_NAME)
 	}
 
 	return nil
@@ -271,7 +343,7 @@ func IsNetworkDisplayNameUnique(name string) (bool, error) {
 
 	dbs, err := models.GetNetworks()
 	if err != nil {
-		return false, err
+		return database.IsEmptyRecord(err), err
 	}
 
 	for i := 0; i < len(dbs); i++ {
@@ -286,29 +358,19 @@ func IsNetworkDisplayNameUnique(name string) (bool, error) {
 
 func IsMacAddressUnique(macaddress string, networkName string) (bool, error) {
 
-	collection, err := database.FetchRecords(database.NODES_TABLE_NAME)
+	_, err := database.FetchRecord(database.NODES_TABLE_NAME, macaddress+"###"+networkName)
 	if err != nil {
-		return false, err
-	}
-	for _, value := range collection {
-		var node models.Node
-		if err = json.Unmarshal([]byte(value), &node); err != nil {
-			return false, err
-		} else {
-			if node.MacAddress == macaddress && node.Network == networkName {
-				return false, nil
-			}
-		}
+		return database.IsEmptyRecord(err), err
 	}
 
 	return true, nil
 }
 
-func GetNetworkNodeNumber(networkName string) (int, error) {
+func GetNetworkNodeCount(networkName string) (int, error) {
 
 	collection, err := database.FetchRecords(database.NODES_TABLE_NAME)
 	count := 0
-	if err != nil {
+	if err != nil && !database.IsEmptyRecord(err) {
 		return count, err
 	}
 	for _, value := range collection {
@@ -703,7 +765,7 @@ func DecrimentKey(networkName string, keyvalue string) {
 	}
 
 	if newNetworkData, err := json.Marshal(&network); err != nil {
-		PrintUserLog("netmaker", "failed to decrement key", 2)
+		PrintUserLog(models.NODE_SERVER_NAME, "failed to decrement key", 2)
 		return
 	} else {
 		database.Insert(network.NetID, string(newNetworkData), database.NETWORKS_TABLE_NAME)

+ 2 - 5
functions/local.go

@@ -2,7 +2,6 @@ package functions
 
 import (
 	"io/ioutil"
-	"log"
 	"os"
 )
 
@@ -23,7 +22,7 @@ func SetDNSDir() error {
         if os.IsNotExist(err) {
                 os.Mkdir(dir+"/config/dnsconfig", 744)
         } else if err != nil {
-                log.Println("couldnt find or create /config/dnsconfig")
+                PrintUserLog("","couldnt find or create /config/dnsconfig",0)
                 return err
         }
 	return nil
@@ -38,7 +37,7 @@ func SetCorefile(domains string) error {
 	if os.IsNotExist(err) {
 		os.Mkdir(dir+"/config/dnsconfig", 744)
 	} else if err != nil {
-		log.Println("couldnt find or create /config/dnsconfig")
+		PrintUserLog("","couldnt find or create /config/dnsconfig",0)
 		return err
 	}
 
@@ -55,8 +54,6 @@ func SetCorefile(domains string) error {
 
 	err = ioutil.WriteFile(dir+"/config/dnsconfig/Corefile", corebytes, 0644)
 	if err != nil {
-		log.Println(err)
-		log.Println("")
 		return err
 	}
 	return err

Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 48 - 1669
grpc/node.pb.go


+ 12 - 153
grpc/node.proto

@@ -3,159 +3,18 @@ package node;
 option go_package = "google.golang.org/protobuf/types/known/nodepb";
 
 service NodeService {
-    rpc Login(LoginRequest) returns (LoginResponse);
-    rpc CreateNode(CreateNodeReq) returns (CreateNodeRes);
-    rpc ReadNode(ReadNodeReq) returns (ReadNodeRes);
-    rpc UpdateNode(UpdateNodeReq) returns (UpdateNodeRes);
-    rpc DeleteNode(DeleteNodeReq) returns (DeleteNodeRes);
-    rpc GetPeers(GetPeersReq) returns (stream GetPeersRes);
-    rpc GetExtPeers(GetExtPeersReq) returns (stream GetExtPeersRes);
-    rpc CheckIn(CheckInReq) returns (CheckInRes);
+    rpc Login(Object) returns (Object);
+    rpc CreateNode(Object) returns (Object);
+    rpc ReadNode(Object) returns (Object);
+    rpc UpdateNode(Object) returns (Object);
+    rpc DeleteNode(Object) returns (Object);
+    rpc GetPeers(Object) returns (Object);
+    rpc GetExtPeers(Object) returns (Object);
+    rpc CheckIn(Object) returns (Object);
 }
 
-message LoginRequest {
-  string macaddress = 1;
-  string password = 2;
-  string network = 3;
+message Object {  
+    string Data = 1;
+    string Type = 2;
+    string Metadata = 3;
 }
-
-message LoginResponse { string accesstoken = 1; }
-
-message Node {
-    string id = 1;
-    string name = 2;
-    string address = 3;
-    string address6 = 26;
-    int32 listenport = 4;
-    string publickey = 5;
-    string endpoint = 6;
-    string macaddress = 7;
-    string password = 8;
-    string nodenetwork = 9;
-    bool ispending = 10;
-    string postup = 11;
-    string postdown = 12;
-    int32 keepalive = 13;
-    string saveconfig = 14;
-    string accesskey = 15;
-    string interface = 16;
-    string lastcheckin = 17;
-    string lastmodified = 18;
-    int32 checkininterval = 19;
-    string localaddress = 20;
-    string postchanges = 21;
-    string allowedips = 22;
-    bool islocal = 23;
-    bool isingressgateway = 28;
-    string ingressgatewayrange = 29;
-    bool isdualstack = 27;
-    bool dnsoff = 24;
-    string localrange = 25;
-    string udpholepunch = 30;
-}
-
-message CheckInResponse {
-    bool success = 1;
-    bool needpeerupdate = 2;
-    bool needconfigupdate = 3;
-    string nodemessage = 4;
-    bool ispending = 5;
-    bool needkeyupdate = 6;
-    bool needdelete = 7;
-}
-
-message PeersResponse {
-    bool isegressgateway = 1;
-    string egressgatewayranges = 2;
-    string ingressgatewayrange = 9;
-    string publickey = 5;
-    string endpoint = 6;
-    string address = 3;
-    string address6 = 8;
-    int32 listenport = 4;
-    string localaddress = 7;
-    int32 keepalive = 13;
-}
-
-message ExtPeersResponse {
-    string publickey = 5;
-    string endpoint = 6;
-    string address = 3;
-    string address6 = 8;
-    int32 listenport = 4;
-    string localaddress = 7;
-    int32 keepalive = 13;
-}
-
-message Client {
-    string privatekey = 1;
-    string publickey = 2;
-    string accesskey = 3;
-    string address = 4;
-    string address6 = 5;
-    string serverwgendpoint = 6;
-    string serverport = 7;
-    string serverkey = 8;
-}
-
-message CreateNodeReq {
-    Node node = 1; // Node id blank
-}
-
-message CreateNodeRes {
-    Node node = 1; // Node id filled in
-}
-
-message UpdateNodeReq {
-    Node node = 1;
-}
-
-message UpdateNodeRes {
-    Node node = 1;
-}
-
-message ReadNodeReq {
-    string macaddress = 1;
-    string network = 2;
-}
-
-message ReadNodeRes {
-    Node node = 1;
-}
-
-message DeleteNodeReq {
-    string macaddress = 1;
-    string networkName = 2;
-}
-
-message DeleteNodeRes {
-    bool success = 1;
-}
-
-message GetPeersReq {
-    string macaddress = 1;
-    string network = 2;
-}
-
-message GetExtPeersReq {
-    string macaddress = 1;
-    string network = 2;
-}
-
-message GetPeersRes {
-    PeersResponse peers = 1;
-}
-
-message GetExtPeersRes {
-    ExtPeersResponse extpeers = 1;
-}
-
-message CheckInReq {
-    Node node = 1;
- //   bool postchanges = 2;
-}
-
-message CheckInRes {
-    CheckInResponse checkinresponse = 1;
-}
-

+ 95 - 150
grpc/node_grpc.pb.go

@@ -18,14 +18,14 @@ const _ = grpc.SupportPackageIsVersion7
 //
 // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
 type NodeServiceClient interface {
-	Login(ctx context.Context, in *LoginRequest, opts ...grpc.CallOption) (*LoginResponse, error)
-	CreateNode(ctx context.Context, in *CreateNodeReq, opts ...grpc.CallOption) (*CreateNodeRes, error)
-	ReadNode(ctx context.Context, in *ReadNodeReq, opts ...grpc.CallOption) (*ReadNodeRes, error)
-	UpdateNode(ctx context.Context, in *UpdateNodeReq, opts ...grpc.CallOption) (*UpdateNodeRes, error)
-	DeleteNode(ctx context.Context, in *DeleteNodeReq, opts ...grpc.CallOption) (*DeleteNodeRes, error)
-	GetPeers(ctx context.Context, in *GetPeersReq, opts ...grpc.CallOption) (NodeService_GetPeersClient, error)
-	GetExtPeers(ctx context.Context, in *GetExtPeersReq, opts ...grpc.CallOption) (NodeService_GetExtPeersClient, error)
-	CheckIn(ctx context.Context, in *CheckInReq, opts ...grpc.CallOption) (*CheckInRes, error)
+	Login(ctx context.Context, in *Object, opts ...grpc.CallOption) (*Object, error)
+	CreateNode(ctx context.Context, in *Object, opts ...grpc.CallOption) (*Object, error)
+	ReadNode(ctx context.Context, in *Object, opts ...grpc.CallOption) (*Object, error)
+	UpdateNode(ctx context.Context, in *Object, opts ...grpc.CallOption) (*Object, error)
+	DeleteNode(ctx context.Context, in *Object, opts ...grpc.CallOption) (*Object, error)
+	GetPeers(ctx context.Context, in *Object, opts ...grpc.CallOption) (*Object, error)
+	GetExtPeers(ctx context.Context, in *Object, opts ...grpc.CallOption) (*Object, error)
+	CheckIn(ctx context.Context, in *Object, opts ...grpc.CallOption) (*Object, error)
 }
 
 type nodeServiceClient struct {
@@ -36,8 +36,8 @@ func NewNodeServiceClient(cc grpc.ClientConnInterface) NodeServiceClient {
 	return &nodeServiceClient{cc}
 }
 
-func (c *nodeServiceClient) Login(ctx context.Context, in *LoginRequest, opts ...grpc.CallOption) (*LoginResponse, error) {
-	out := new(LoginResponse)
+func (c *nodeServiceClient) Login(ctx context.Context, in *Object, opts ...grpc.CallOption) (*Object, error) {
+	out := new(Object)
 	err := c.cc.Invoke(ctx, "/node.NodeService/Login", in, out, opts...)
 	if err != nil {
 		return nil, err
@@ -45,8 +45,8 @@ func (c *nodeServiceClient) Login(ctx context.Context, in *LoginRequest, opts ..
 	return out, nil
 }
 
-func (c *nodeServiceClient) CreateNode(ctx context.Context, in *CreateNodeReq, opts ...grpc.CallOption) (*CreateNodeRes, error) {
-	out := new(CreateNodeRes)
+func (c *nodeServiceClient) CreateNode(ctx context.Context, in *Object, opts ...grpc.CallOption) (*Object, error) {
+	out := new(Object)
 	err := c.cc.Invoke(ctx, "/node.NodeService/CreateNode", in, out, opts...)
 	if err != nil {
 		return nil, err
@@ -54,8 +54,8 @@ func (c *nodeServiceClient) CreateNode(ctx context.Context, in *CreateNodeReq, o
 	return out, nil
 }
 
-func (c *nodeServiceClient) ReadNode(ctx context.Context, in *ReadNodeReq, opts ...grpc.CallOption) (*ReadNodeRes, error) {
-	out := new(ReadNodeRes)
+func (c *nodeServiceClient) ReadNode(ctx context.Context, in *Object, opts ...grpc.CallOption) (*Object, error) {
+	out := new(Object)
 	err := c.cc.Invoke(ctx, "/node.NodeService/ReadNode", in, out, opts...)
 	if err != nil {
 		return nil, err
@@ -63,8 +63,8 @@ func (c *nodeServiceClient) ReadNode(ctx context.Context, in *ReadNodeReq, opts
 	return out, nil
 }
 
-func (c *nodeServiceClient) UpdateNode(ctx context.Context, in *UpdateNodeReq, opts ...grpc.CallOption) (*UpdateNodeRes, error) {
-	out := new(UpdateNodeRes)
+func (c *nodeServiceClient) UpdateNode(ctx context.Context, in *Object, opts ...grpc.CallOption) (*Object, error) {
+	out := new(Object)
 	err := c.cc.Invoke(ctx, "/node.NodeService/UpdateNode", in, out, opts...)
 	if err != nil {
 		return nil, err
@@ -72,8 +72,8 @@ func (c *nodeServiceClient) UpdateNode(ctx context.Context, in *UpdateNodeReq, o
 	return out, nil
 }
 
-func (c *nodeServiceClient) DeleteNode(ctx context.Context, in *DeleteNodeReq, opts ...grpc.CallOption) (*DeleteNodeRes, error) {
-	out := new(DeleteNodeRes)
+func (c *nodeServiceClient) DeleteNode(ctx context.Context, in *Object, opts ...grpc.CallOption) (*Object, error) {
+	out := new(Object)
 	err := c.cc.Invoke(ctx, "/node.NodeService/DeleteNode", in, out, opts...)
 	if err != nil {
 		return nil, err
@@ -81,72 +81,26 @@ func (c *nodeServiceClient) DeleteNode(ctx context.Context, in *DeleteNodeReq, o
 	return out, nil
 }
 
-func (c *nodeServiceClient) GetPeers(ctx context.Context, in *GetPeersReq, opts ...grpc.CallOption) (NodeService_GetPeersClient, error) {
-	stream, err := c.cc.NewStream(ctx, &NodeService_ServiceDesc.Streams[0], "/node.NodeService/GetPeers", opts...)
+func (c *nodeServiceClient) GetPeers(ctx context.Context, in *Object, opts ...grpc.CallOption) (*Object, error) {
+	out := new(Object)
+	err := c.cc.Invoke(ctx, "/node.NodeService/GetPeers", in, out, opts...)
 	if err != nil {
 		return nil, err
 	}
-	x := &nodeServiceGetPeersClient{stream}
-	if err := x.ClientStream.SendMsg(in); err != nil {
-		return nil, err
-	}
-	if err := x.ClientStream.CloseSend(); err != nil {
-		return nil, err
-	}
-	return x, nil
-}
-
-type NodeService_GetPeersClient interface {
-	Recv() (*GetPeersRes, error)
-	grpc.ClientStream
-}
-
-type nodeServiceGetPeersClient struct {
-	grpc.ClientStream
-}
-
-func (x *nodeServiceGetPeersClient) Recv() (*GetPeersRes, error) {
-	m := new(GetPeersRes)
-	if err := x.ClientStream.RecvMsg(m); err != nil {
-		return nil, err
-	}
-	return m, nil
+	return out, nil
 }
 
-func (c *nodeServiceClient) GetExtPeers(ctx context.Context, in *GetExtPeersReq, opts ...grpc.CallOption) (NodeService_GetExtPeersClient, error) {
-	stream, err := c.cc.NewStream(ctx, &NodeService_ServiceDesc.Streams[1], "/node.NodeService/GetExtPeers", opts...)
+func (c *nodeServiceClient) GetExtPeers(ctx context.Context, in *Object, opts ...grpc.CallOption) (*Object, error) {
+	out := new(Object)
+	err := c.cc.Invoke(ctx, "/node.NodeService/GetExtPeers", in, out, opts...)
 	if err != nil {
 		return nil, err
 	}
-	x := &nodeServiceGetExtPeersClient{stream}
-	if err := x.ClientStream.SendMsg(in); err != nil {
-		return nil, err
-	}
-	if err := x.ClientStream.CloseSend(); err != nil {
-		return nil, err
-	}
-	return x, nil
-}
-
-type NodeService_GetExtPeersClient interface {
-	Recv() (*GetExtPeersRes, error)
-	grpc.ClientStream
-}
-
-type nodeServiceGetExtPeersClient struct {
-	grpc.ClientStream
-}
-
-func (x *nodeServiceGetExtPeersClient) Recv() (*GetExtPeersRes, error) {
-	m := new(GetExtPeersRes)
-	if err := x.ClientStream.RecvMsg(m); err != nil {
-		return nil, err
-	}
-	return m, nil
+	return out, nil
 }
 
-func (c *nodeServiceClient) CheckIn(ctx context.Context, in *CheckInReq, opts ...grpc.CallOption) (*CheckInRes, error) {
-	out := new(CheckInRes)
+func (c *nodeServiceClient) CheckIn(ctx context.Context, in *Object, opts ...grpc.CallOption) (*Object, error) {
+	out := new(Object)
 	err := c.cc.Invoke(ctx, "/node.NodeService/CheckIn", in, out, opts...)
 	if err != nil {
 		return nil, err
@@ -158,14 +112,14 @@ func (c *nodeServiceClient) CheckIn(ctx context.Context, in *CheckInReq, opts ..
 // All implementations must embed UnimplementedNodeServiceServer
 // for forward compatibility
 type NodeServiceServer interface {
-	Login(context.Context, *LoginRequest) (*LoginResponse, error)
-	CreateNode(context.Context, *CreateNodeReq) (*CreateNodeRes, error)
-	ReadNode(context.Context, *ReadNodeReq) (*ReadNodeRes, error)
-	UpdateNode(context.Context, *UpdateNodeReq) (*UpdateNodeRes, error)
-	DeleteNode(context.Context, *DeleteNodeReq) (*DeleteNodeRes, error)
-	GetPeers(*GetPeersReq, NodeService_GetPeersServer) error
-	GetExtPeers(*GetExtPeersReq, NodeService_GetExtPeersServer) error
-	CheckIn(context.Context, *CheckInReq) (*CheckInRes, error)
+	Login(context.Context, *Object) (*Object, error)
+	CreateNode(context.Context, *Object) (*Object, error)
+	ReadNode(context.Context, *Object) (*Object, error)
+	UpdateNode(context.Context, *Object) (*Object, error)
+	DeleteNode(context.Context, *Object) (*Object, error)
+	GetPeers(context.Context, *Object) (*Object, error)
+	GetExtPeers(context.Context, *Object) (*Object, error)
+	CheckIn(context.Context, *Object) (*Object, error)
 	mustEmbedUnimplementedNodeServiceServer()
 }
 
@@ -173,28 +127,28 @@ type NodeServiceServer interface {
 type UnimplementedNodeServiceServer struct {
 }
 
-func (UnimplementedNodeServiceServer) Login(context.Context, *LoginRequest) (*LoginResponse, error) {
+func (UnimplementedNodeServiceServer) Login(context.Context, *Object) (*Object, error) {
 	return nil, status.Errorf(codes.Unimplemented, "method Login not implemented")
 }
-func (UnimplementedNodeServiceServer) CreateNode(context.Context, *CreateNodeReq) (*CreateNodeRes, error) {
+func (UnimplementedNodeServiceServer) CreateNode(context.Context, *Object) (*Object, error) {
 	return nil, status.Errorf(codes.Unimplemented, "method CreateNode not implemented")
 }
-func (UnimplementedNodeServiceServer) ReadNode(context.Context, *ReadNodeReq) (*ReadNodeRes, error) {
+func (UnimplementedNodeServiceServer) ReadNode(context.Context, *Object) (*Object, error) {
 	return nil, status.Errorf(codes.Unimplemented, "method ReadNode not implemented")
 }
-func (UnimplementedNodeServiceServer) UpdateNode(context.Context, *UpdateNodeReq) (*UpdateNodeRes, error) {
+func (UnimplementedNodeServiceServer) UpdateNode(context.Context, *Object) (*Object, error) {
 	return nil, status.Errorf(codes.Unimplemented, "method UpdateNode not implemented")
 }
-func (UnimplementedNodeServiceServer) DeleteNode(context.Context, *DeleteNodeReq) (*DeleteNodeRes, error) {
+func (UnimplementedNodeServiceServer) DeleteNode(context.Context, *Object) (*Object, error) {
 	return nil, status.Errorf(codes.Unimplemented, "method DeleteNode not implemented")
 }
-func (UnimplementedNodeServiceServer) GetPeers(*GetPeersReq, NodeService_GetPeersServer) error {
-	return status.Errorf(codes.Unimplemented, "method GetPeers not implemented")
+func (UnimplementedNodeServiceServer) GetPeers(context.Context, *Object) (*Object, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method GetPeers not implemented")
 }
-func (UnimplementedNodeServiceServer) GetExtPeers(*GetExtPeersReq, NodeService_GetExtPeersServer) error {
-	return status.Errorf(codes.Unimplemented, "method GetExtPeers not implemented")
+func (UnimplementedNodeServiceServer) GetExtPeers(context.Context, *Object) (*Object, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method GetExtPeers not implemented")
 }
-func (UnimplementedNodeServiceServer) CheckIn(context.Context, *CheckInReq) (*CheckInRes, error) {
+func (UnimplementedNodeServiceServer) CheckIn(context.Context, *Object) (*Object, error) {
 	return nil, status.Errorf(codes.Unimplemented, "method CheckIn not implemented")
 }
 func (UnimplementedNodeServiceServer) mustEmbedUnimplementedNodeServiceServer() {}
@@ -211,7 +165,7 @@ func RegisterNodeServiceServer(s grpc.ServiceRegistrar, srv NodeServiceServer) {
 }
 
 func _NodeService_Login_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
-	in := new(LoginRequest)
+	in := new(Object)
 	if err := dec(in); err != nil {
 		return nil, err
 	}
@@ -223,13 +177,13 @@ func _NodeService_Login_Handler(srv interface{}, ctx context.Context, dec func(i
 		FullMethod: "/node.NodeService/Login",
 	}
 	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
-		return srv.(NodeServiceServer).Login(ctx, req.(*LoginRequest))
+		return srv.(NodeServiceServer).Login(ctx, req.(*Object))
 	}
 	return interceptor(ctx, in, info, handler)
 }
 
 func _NodeService_CreateNode_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
-	in := new(CreateNodeReq)
+	in := new(Object)
 	if err := dec(in); err != nil {
 		return nil, err
 	}
@@ -241,13 +195,13 @@ func _NodeService_CreateNode_Handler(srv interface{}, ctx context.Context, dec f
 		FullMethod: "/node.NodeService/CreateNode",
 	}
 	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
-		return srv.(NodeServiceServer).CreateNode(ctx, req.(*CreateNodeReq))
+		return srv.(NodeServiceServer).CreateNode(ctx, req.(*Object))
 	}
 	return interceptor(ctx, in, info, handler)
 }
 
 func _NodeService_ReadNode_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
-	in := new(ReadNodeReq)
+	in := new(Object)
 	if err := dec(in); err != nil {
 		return nil, err
 	}
@@ -259,13 +213,13 @@ func _NodeService_ReadNode_Handler(srv interface{}, ctx context.Context, dec fun
 		FullMethod: "/node.NodeService/ReadNode",
 	}
 	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
-		return srv.(NodeServiceServer).ReadNode(ctx, req.(*ReadNodeReq))
+		return srv.(NodeServiceServer).ReadNode(ctx, req.(*Object))
 	}
 	return interceptor(ctx, in, info, handler)
 }
 
 func _NodeService_UpdateNode_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
-	in := new(UpdateNodeReq)
+	in := new(Object)
 	if err := dec(in); err != nil {
 		return nil, err
 	}
@@ -277,13 +231,13 @@ func _NodeService_UpdateNode_Handler(srv interface{}, ctx context.Context, dec f
 		FullMethod: "/node.NodeService/UpdateNode",
 	}
 	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
-		return srv.(NodeServiceServer).UpdateNode(ctx, req.(*UpdateNodeReq))
+		return srv.(NodeServiceServer).UpdateNode(ctx, req.(*Object))
 	}
 	return interceptor(ctx, in, info, handler)
 }
 
 func _NodeService_DeleteNode_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
-	in := new(DeleteNodeReq)
+	in := new(Object)
 	if err := dec(in); err != nil {
 		return nil, err
 	}
@@ -295,55 +249,49 @@ func _NodeService_DeleteNode_Handler(srv interface{}, ctx context.Context, dec f
 		FullMethod: "/node.NodeService/DeleteNode",
 	}
 	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
-		return srv.(NodeServiceServer).DeleteNode(ctx, req.(*DeleteNodeReq))
+		return srv.(NodeServiceServer).DeleteNode(ctx, req.(*Object))
 	}
 	return interceptor(ctx, in, info, handler)
 }
 
-func _NodeService_GetPeers_Handler(srv interface{}, stream grpc.ServerStream) error {
-	m := new(GetPeersReq)
-	if err := stream.RecvMsg(m); err != nil {
-		return err
+func _NodeService_GetPeers_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(Object)
+	if err := dec(in); err != nil {
+		return nil, err
 	}
-	return srv.(NodeServiceServer).GetPeers(m, &nodeServiceGetPeersServer{stream})
-}
-
-type NodeService_GetPeersServer interface {
-	Send(*GetPeersRes) error
-	grpc.ServerStream
-}
-
-type nodeServiceGetPeersServer struct {
-	grpc.ServerStream
-}
-
-func (x *nodeServiceGetPeersServer) Send(m *GetPeersRes) error {
-	return x.ServerStream.SendMsg(m)
-}
-
-func _NodeService_GetExtPeers_Handler(srv interface{}, stream grpc.ServerStream) error {
-	m := new(GetExtPeersReq)
-	if err := stream.RecvMsg(m); err != nil {
-		return err
+	if interceptor == nil {
+		return srv.(NodeServiceServer).GetPeers(ctx, in)
 	}
-	return srv.(NodeServiceServer).GetExtPeers(m, &nodeServiceGetExtPeersServer{stream})
-}
-
-type NodeService_GetExtPeersServer interface {
-	Send(*GetExtPeersRes) error
-	grpc.ServerStream
-}
-
-type nodeServiceGetExtPeersServer struct {
-	grpc.ServerStream
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: "/node.NodeService/GetPeers",
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(NodeServiceServer).GetPeers(ctx, req.(*Object))
+	}
+	return interceptor(ctx, in, info, handler)
 }
 
-func (x *nodeServiceGetExtPeersServer) Send(m *GetExtPeersRes) error {
-	return x.ServerStream.SendMsg(m)
+func _NodeService_GetExtPeers_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(Object)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(NodeServiceServer).GetExtPeers(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: "/node.NodeService/GetExtPeers",
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(NodeServiceServer).GetExtPeers(ctx, req.(*Object))
+	}
+	return interceptor(ctx, in, info, handler)
 }
 
 func _NodeService_CheckIn_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
-	in := new(CheckInReq)
+	in := new(Object)
 	if err := dec(in); err != nil {
 		return nil, err
 	}
@@ -355,7 +303,7 @@ func _NodeService_CheckIn_Handler(srv interface{}, ctx context.Context, dec func
 		FullMethod: "/node.NodeService/CheckIn",
 	}
 	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
-		return srv.(NodeServiceServer).CheckIn(ctx, req.(*CheckInReq))
+		return srv.(NodeServiceServer).CheckIn(ctx, req.(*Object))
 	}
 	return interceptor(ctx, in, info, handler)
 }
@@ -388,21 +336,18 @@ var NodeService_ServiceDesc = grpc.ServiceDesc{
 			Handler:    _NodeService_DeleteNode_Handler,
 		},
 		{
-			MethodName: "CheckIn",
-			Handler:    _NodeService_CheckIn_Handler,
+			MethodName: "GetPeers",
+			Handler:    _NodeService_GetPeers_Handler,
 		},
-	},
-	Streams: []grpc.StreamDesc{
 		{
-			StreamName:    "GetPeers",
-			Handler:       _NodeService_GetPeers_Handler,
-			ServerStreams: true,
+			MethodName: "GetExtPeers",
+			Handler:    _NodeService_GetExtPeers_Handler,
 		},
 		{
-			StreamName:    "GetExtPeers",
-			Handler:       _NodeService_GetExtPeers_Handler,
-			ServerStreams: true,
+			MethodName: "CheckIn",
+			Handler:    _NodeService_CheckIn_Handler,
 		},
 	},
+	Streams:  []grpc.StreamDesc{},
 	Metadata: "grpc/node.proto",
 }

+ 6 - 0
grpc/types.go

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

+ 17 - 23
main.go

@@ -4,10 +4,10 @@
 package main
 
 import (
+	"fmt"
 	"log"
 	"net"
 	"os"
-	"os/exec"
 	"os/signal"
 	"strconv"
 	"sync"
@@ -16,23 +16,28 @@ import (
 	"github.com/gravitl/netmaker/database"
 	"github.com/gravitl/netmaker/functions"
 	nodepb "github.com/gravitl/netmaker/grpc"
+	"github.com/gravitl/netmaker/models"
+	"github.com/gravitl/netmaker/netclient/local"
 	"github.com/gravitl/netmaker/servercfg"
-	"github.com/gravitl/netmaker/serverctl"
 	"google.golang.org/grpc"
 )
 
 //Start MongoDB Connection and start API Request Handler
 func main() {
-	checkModes() // check which flags are set and if root or not
-	initialize() // initial db and grpc server
+	fmt.Println(models.RetrieveLogo()) // print the logo
+	initialize()                       // initial db and grpc server
 	defer database.Database.Close()
 	startControllers() // start the grpc or rest endpoints
 }
 
-func checkModes() { // Client Mode Prereq Check
+func initialize() { // Client Mode Prereq Check
 	var err error
-	cmd := exec.Command("id", "-u")
-	output, err := cmd.Output()
+	if err = database.InitializeDatabase(); err != nil {
+		log.Println("Error connecting to database.")
+		log.Fatal(err)
+	}
+	log.Println("database successfully connected.")
+	output, err := local.RunCmd("id -u")
 
 	if err != nil {
 		log.Println("Error running 'id -u' for prereq check. Please investigate or disable client mode.")
@@ -53,17 +58,6 @@ func checkModes() { // Client Mode Prereq Check
 			log.Fatal(err)
 		}
 	}
-
-}
-
-func initialize() {
-	database.InitializeDatabase()
-	if servercfg.IsGRPCWireGuard() {
-		if err := serverctl.InitServerWireGuard(); err != nil {
-			log.Fatal(err)
-		}
-	}
-	functions.PrintUserLog("netmaker", "successfully created db tables if not present", 1)
 }
 
 func startControllers() {
@@ -83,7 +77,7 @@ func startControllers() {
 	if servercfg.IsDNSMode() {
 		err := controller.SetDNS()
 		if err != nil {
-			log.Fatal(err)
+			log.Println("error occurred initializing DNS:", err)
 		}
 	}
 	//Run Rest Server
@@ -123,7 +117,6 @@ func runGRPC(wg *sync.WaitGroup) {
 
 	s := grpc.NewServer(
 		authServerUnaryInterceptor(),
-		authServerStreamInterceptor(),
 	)
 	// Create NodeService type
 	srv := &controller.NodeServiceServer{}
@@ -162,6 +155,7 @@ func runGRPC(wg *sync.WaitGroup) {
 func authServerUnaryInterceptor() grpc.ServerOption {
 	return grpc.UnaryInterceptor(controller.AuthServerUnaryInterceptor)
 }
-func authServerStreamInterceptor() grpc.ServerOption {
-	return grpc.StreamInterceptor(controller.AuthServerStreamInterceptor)
-}
+
+// func authServerStreamInterceptor() grpc.ServerOption {
+// 	return grpc.StreamInterceptor(controller.AuthServerStreamInterceptor)
+// }

+ 204 - 0
models/names.go

@@ -0,0 +1,204 @@
+package models
+
+import (
+	"math/rand"
+	"time"
+)
+
+// 5-7 chars only
+var NAMES = []string{
+	"logic",
+	"warrant",
+	"iconic",
+	"threat",
+	"strike",
+	"vital",
+	"unity",
+	"audio",
+	"schemer",
+	"depth",
+	"gravitl",
+	"mystic",
+	"donkey",
+	"atomic",
+	"turtle",
+	"monkey",
+	"rabbit",
+	"static",
+	"mosaic",
+	"elite",
+	"stonks",
+	"doggy",
+	"python",
+	"mohawk",
+	"arctic",
+	"linear",
+	"rival",
+	"vibes",
+	"delay",
+	"bridge",
+	"weeble",
+	"combat",
+	"animal",
+	"wobble",
+	"rubble",
+	"bucket",
+	"proof",
+	"worker",
+	"beetle",
+	"racket",
+	"equal",
+	"panda",
+	"antics",
+	"strong",
+	"forum",
+	"koala",
+	"anchor",
+	"ornery",
+	"indigo",
+	"schism",
+	"dragon",
+	"knight",
+	"bishop",
+	"laser",
+	"rhino",
+	"clutch",
+	"shark",
+	"leader",
+	"smelly",
+	"young",
+	"robot",
+	"squish",
+	"chimp",
+	"rocket",
+	"space",
+	"queen",
+	"royal",
+	"flush",
+	"earth",
+	"planet",
+	"heart",
+	"droplet",
+	"dillon",
+	"saturn",
+	"pluto",
+	"school",
+	"alien",
+	"matte",
+	"dingo",
+	"meercat",
+	"cookie",
+	"snack",
+	"goose",
+	"pepper",
+	"melissa",
+}
+
+// must be 4 chars or less
+var SMALL_NAMES = []string{
+	"ace",
+	"tank",
+	"alex",
+	"dude",
+	"root",
+	"sudo",
+	"mars",
+	"meow",
+	"elon",
+	"musk",
+	"moon",
+	"beef",
+	"tack",
+	"matt",
+	"soon",
+	"man",
+	"sup",
+	"yo",
+	"bro",
+	"john",
+	"drop",
+	"dank",
+	"red",
+	"gold",
+	"big",
+	"old",
+	"og",
+	"best",
+	"blue",
+	"lil",
+	"mom",
+	"bot",
+	"farm",
+	"evil",
+	"good",
+	"holy",
+	"rad",
+	"bad",
+	"sad",
+	"mad",
+	"chad",
+	"hat",
+	"pre",
+	"post",
+	"foot",
+	"soft",
+	"hard",
+	"bob",
+	"tree",
+	"lite",
+	"fish",
+	"dark",
+	"true",
+	"cat",
+	"dog",
+	"wow",
+	"yay",
+	"yeet",
+	"zoo",
+	"toy",
+	"boy",
+	"soy",
+	"rude",
+	"nice",
+	"cow",
+	"meh",
+	"shoe",
+	"sock",
+	"toe",
+	"nail",
+	"hair",
+	"nose",
+	"ear",
+	"tear",
+	"lad",
+	"taco",
+	"star",
+	"sun",
+	"ship",
+	"pack",
+	"mule",
+	"drag",
+	"king",
+}
+
+func GenerateNodeName() string {
+	rand.Seed(time.Now().UnixNano())
+	return NAMES[rand.Intn(len(SMALL_NAMES))] + "-" + NAMES[seededRand.Intn(len(NAMES))]
+}
+
+func RetrieveLogo() string {
+	return `
+    ______     ______     ______     __   __   __     ______   __                        
+   /\  ___\   /\  == \   /\  __ \   /\ \ / /  /\ \   /\__  _\ /\ \                       
+   \ \ \__ \  \ \  __<   \ \  __ \  \ \ \'/   \ \ \  \/_/\ \/ \ \ \____                  
+    \ \_____\  \ \_\ \_\  \ \_\ \_\  \ \__|    \ \_\    \ \_\  \ \_____\                 
+     \/_____/   \/_/ /_/   \/_/\/_/   \/_/      \/_/     \/_/   \/_____/                 
+                                                                                         
+ __   __     ______     ______   __    __     ______     __  __     ______     ______    
+/\ "-.\ \   /\  ___\   /\__  _\ /\ "-./  \   /\  __ \   /\ \/ /    /\  ___\   /\  == \   
+\ \ \-.  \  \ \  __\   \/_/\ \/ \ \ \-./\ \  \ \  __ \  \ \  _"-.  \ \  __\   \ \  __<   
+ \ \_\\"\_\  \ \_____\    \ \_\  \ \_\ \ \_\  \ \_\ \_\  \ \_\ \_\  \ \_____\  \ \_\ \_\ 
+  \/_/ \/_/   \/_____/     \/_/   \/_/  \/_/   \/_/\/_/   \/_/\/_/   \/_____/   \/_/ /_/ 
+                                                                                         																							 
+`
+}

+ 23 - 23
models/network.go

@@ -136,7 +136,7 @@ func (network *Network) IsNetworkDisplayNameUnique() (bool, error) {
 
 	records, err := GetNetworks()
 
-	if err != nil {
+	if err != nil && !database.IsEmptyRecord(err) {
 		return false, err
 	}
 
@@ -157,7 +157,7 @@ func (network *Network) IsNetworkNameUnique() (bool, error) {
 
 	dbs, err := GetNetworks()
 
-	if err != nil {
+	if err != nil && !database.IsEmptyRecord(err) {
 		return false, err
 	}
 
@@ -299,29 +299,29 @@ func (currentNetwork *Network) Update(newNetwork *Network) (bool, bool, error) {
 
 func (network *Network) SetNetworkNodesLastModified() error {
 
-        timestamp := time.Now().Unix()
-
-        network.NodesLastModified = timestamp
-        data, err := json.Marshal(&network)
-        if err != nil {
-                return err
-        }
-        err = database.Insert(network.NetID, string(data), database.NETWORKS_TABLE_NAME)
-        if err != nil {
-                return err
-        }
-        return nil
+	timestamp := time.Now().Unix()
+
+	network.NodesLastModified = timestamp
+	data, err := json.Marshal(&network)
+	if err != nil {
+		return err
+	}
+	err = database.Insert(network.NetID, string(data), database.NETWORKS_TABLE_NAME)
+	if err != nil {
+		return err
+	}
+	return nil
 }
 
 func GetNetwork(networkname string) (Network, error) {
 
-        var network Network
-        networkData, err := database.FetchRecord(database.NETWORKS_TABLE_NAME, networkname)
-        if err != nil {
-                return network, err
-        }
-        if err = json.Unmarshal([]byte(networkData), &network); err != nil {
-                return Network{}, err
-        }
-        return network, nil
+	var network Network
+	networkData, err := database.FetchRecord(database.NETWORKS_TABLE_NAME, networkname)
+	if err != nil {
+		return network, err
+	}
+	if err = json.Unmarshal([]byte(networkData), &network); err != nil {
+		return Network{}, err
+	}
+	return network, nil
 }

+ 172 - 71
models/node.go

@@ -15,48 +15,117 @@ import (
 
 const charset = "abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
 const TEN_YEARS_IN_SECONDS = 300000000
+
+// == ACTIONS == (can only be set by GRPC)
+const NODE_UPDATE_KEY = "updatekey"
+const NODE_SERVER_NAME = "netmaker"
+const NODE_DELETE = "delete"
+const NODE_IS_PENDING = "pending"
+const NODE_NOOP = "noop"
+
 var seededRand *rand.Rand = rand.New(
 	rand.NewSource(time.Now().UnixNano()))
 
 //node struct
 type Node struct {
 	ID                  string   `json:"id,omitempty" bson:"id,omitempty"`
-	Address             string   `json:"address" bson:"address" validate:"omitempty,ipv4"`
-	Address6            string   `json:"address6" bson:"address6" validate:"omitempty,ipv6"`
-	LocalAddress        string   `json:"localaddress" bson:"localaddress" validate:"omitempty,ip"`
-	Name                string   `json:"name" bson:"name" validate:"omitempty,max=12,in_charset"`
-	ListenPort          int32    `json:"listenport" bson:"listenport" validate:"omitempty,numeric,min=1024,max=65535"`
-	PublicKey           string   `json:"publickey" bson:"publickey" validate:"required,base64"`
-	Endpoint            string   `json:"endpoint" bson:"endpoint" validate:"required,ip"`
-	PostUp              string   `json:"postup" bson:"postup"`
-	PostDown            string   `json:"postdown" bson:"postdown"`
-	AllowedIPs          []string `json:"allowedips" bson:"allowedips"`
-	PersistentKeepalive int32    `json:"persistentkeepalive" bson:"persistentkeepalive" validate:"omitempty,numeric,max=1000"`
-	SaveConfig          string   `json:"saveconfig" bson:"saveconfig" validate:"checkyesorno"`
-	AccessKey           string   `json:"accesskey" bson:"accesskey"`
-	Interface           string   `json:"interface" bson:"interface"`
-	LastModified        int64    `json:"lastmodified" bson:"lastmodified"`
-	KeyUpdateTimeStamp  int64    `json:"keyupdatetimestamp" bson:"keyupdatetimestamp"`
-	ExpirationDateTime  int64    `json:"expdatetime" bson:"expdatetime"`
-	LastPeerUpdate      int64    `json:"lastpeerupdate" bson:"lastpeerupdate"`
-	LastCheckIn         int64    `json:"lastcheckin" bson:"lastcheckin"`
-	MacAddress          string   `json:"macaddress" bson:"macaddress" validate:"required,mac,macaddress_unique"`
-	CheckInInterval     int32    `json:"checkininterval" bson:"checkininterval"`
-	Password            string   `json:"password" bson:"password" validate:"required,min=6"`
-	Network             string   `json:"network" bson:"network" validate:"network_exists"`
-	IsPending           string   `json:"ispending" bson:"ispending"`
-	IsEgressGateway     string   `json:"isegressgateway" bson:"isegressgateway"`
-	IsIngressGateway    string   `json:"isingressgateway" bson:"isingressgateway"`
-	EgressGatewayRanges []string `json:"egressgatewayranges" bson:"egressgatewayranges"`
-	IngressGatewayRange string   `json:"ingressgatewayrange" bson:"ingressgatewayrange"`
-	PostChanges         string   `json:"postchanges" bson:"postchanges"`
-	StaticIP            string   `json:"staticip" bson:"staticip"`
-	StaticPubKey        string   `json:"staticpubkey" bson:"staticpubkey"`
-	UDPHolePunch        string   `json:"udpholepunch" bson:"udpholepunch" validate:"checkyesorno"`
+	Address             string   `json:"address" bson:"address" yaml:"address" validate:"omitempty,ipv4"`
+	Address6            string   `json:"address6" bson:"address6" yaml:"address6" validate:"omitempty,ipv6"`
+	LocalAddress        string   `json:"localaddress" bson:"localaddress" yaml:"localaddress" validate:"omitempty,ip"`
+	Name                string   `json:"name" bson:"name" yaml:"name" validate:"omitempty,max=12,in_charset"`
+	ListenPort          int32    `json:"listenport" bson:"listenport" yaml:"listenport" validate:"omitempty,numeric,min=1024,max=65535"`
+	PublicKey           string   `json:"publickey" bson:"publickey" yaml:"publickey" validate:"required,base64"`
+	Endpoint            string   `json:"endpoint" bson:"endpoint" yaml:"endpoint" validate:"required,ip"`
+	PostUp              string   `json:"postup" bson:"postup" yaml:"postup"`
+	PostDown            string   `json:"postdown" bson:"postdown" yaml:"postdown"`
+	AllowedIPs          []string `json:"allowedips" bson:"allowedips" yaml:"allowedips"`
+	PersistentKeepalive int32    `json:"persistentkeepalive" bson:"persistentkeepalive" yaml:"persistentkeepalive" validate:"omitempty,numeric,max=1000"`
+	SaveConfig          string   `json:"saveconfig" bson:"saveconfig" yaml:"saveconfig" validate:"checkyesorno"`
+	AccessKey           string   `json:"accesskey" bson:"accesskey" yaml:"accesskey"`
+	Interface           string   `json:"interface" bson:"interface" yaml:"interface"`
+	LastModified        int64    `json:"lastmodified" bson:"lastmodified" yaml:"lastmodified"`
+	KeyUpdateTimeStamp  int64    `json:"keyupdatetimestamp" bson:"keyupdatetimestamp" yaml:"keyupdatetimestamp"`
+	ExpirationDateTime  int64    `json:"expdatetime" bson:"expdatetime" yaml:"expdatetime"`
+	LastPeerUpdate      int64    `json:"lastpeerupdate" bson:"lastpeerupdate" yaml:"lastpeerupdate"`
+	LastCheckIn         int64    `json:"lastcheckin" bson:"lastcheckin" yaml:"lastcheckin"`
+	MacAddress          string   `json:"macaddress" bson:"macaddress" yaml:"macaddress" validate:"required,mac,macaddress_unique"`
+	CheckInInterval     int32    `json:"checkininterval" bson:"checkininterval" yaml:"checkininterval"`
+	Password            string   `json:"password" bson:"password" yaml:"password" validate:"required,min=6"`
+	Network             string   `json:"network" bson:"network" yaml:"network" validate:"network_exists"`
+	IsPending           string   `json:"ispending" bson:"ispending" yaml:"ispending"`
+	IsEgressGateway     string   `json:"isegressgateway" bson:"isegressgateway" yaml:"isegressgateway"`
+	IsIngressGateway    string   `json:"isingressgateway" bson:"isingressgateway" yaml:"isingressgateway"`
+	EgressGatewayRanges []string `json:"egressgatewayranges" bson:"egressgatewayranges" yaml:"egressgatewayranges"`
+	IngressGatewayRange string   `json:"ingressgatewayrange" bson:"ingressgatewayrange" yaml:"ingressgatewayrange"`
+	IsStatic	        string   `json:"isstatic" bson:"isstatic" yaml:"isstatic" validate:"checkyesorno"`
+	UDPHolePunch        string   `json:"udpholepunch" bson:"udpholepunch" yaml:"udpholepunch" validate:"checkyesorno"`
+	PullChanges         string   `json:"pullchanges" bson:"pullchanges" yaml:"pullchanges" validate:"checkyesorno"`
+	DNSOn               string   `json:"dnson" bson:"dnson" yaml:"dnson" validate:"checkyesorno"`
+	IsDualStack         string   `json:"isdualstack" bson:"isdualstack" yaml:"isdualstack" validate:"checkyesorno"`
+	IsServer            string   `json:"isserver" bson:"isserver" yaml:"isserver" validate:"checkyesorno"`
+	Action              string   `json:"action" bson:"action" yaml:"action"`
+	IsLocal             string   `json:"islocal" bson:"islocal" yaml:"islocal" validate:"checkyesorno"`
+	LocalRange          string   `json:"localrange" bson:"localrange" yaml:"localrange"`
+	Roaming             string   `json:"roaming" bson:"roaming" yaml:"roaming" validate:"checkyesorno"`
+	IPForwarding        string   `json:"ipforwarding" bson:"ipforwarding" yaml:"ipforwarding" validate:"checkyesorno"`
+}
+
+func (node *Node) SetDefaultAction() {
+	if node.Action == "" {
+		node.Action = NODE_NOOP
+	}
+}
+
+func (node *Node) SetRoamingDefault() {
+	if node.Roaming == "" {
+		node.Roaming = "yes"
+	}
+}
+
+func (node *Node) SetPullChangesDefault() {
+	if node.PullChanges == "" {
+		node.PullChanges = "no"
+	}
+}
+
+func (node *Node) SetIPForwardingDefault() {
+	if node.IPForwarding == "" {
+		node.IPForwarding = "yes"
+	}
+}
+
+func (node *Node) SetIsLocalDefault() {
+	if node.IsLocal == "" {
+		node.IsLocal = "no"
+	}
+}
+
+func (node *Node) SetDNSOnDefault() {
+	if node.DNSOn == "" {
+		node.DNSOn = "no"
+	}
+}
+
+func (node *Node) SetIsDualStackDefault() {
+	if node.IsDualStack == "" {
+		node.IsDualStack = "no"
+	}
+}
+
+func (node *Node) SetIsServerDefault() {
+	if node.IsServer != "yes" {
+		node.IsServer = "no"
+	}
+}
+
+func (node *Node) SetIsStaticDefault() {
+	if node.IsServer == "yes" {
+		node.IsStatic = "yes"
+	} else if node.IsStatic != "yes" {
+		node.IsStatic = "no"
+	}
 }
 
-//TODO:
-//Not sure if below two methods are necessary. May want to revisit
 func (node *Node) SetLastModified() {
 	node.LastModified = time.Now().Unix()
 }
@@ -79,10 +148,25 @@ func (node *Node) SetExpirationDateTime() {
 
 func (node *Node) SetDefaultName() {
 	if node.Name == "" {
-		nodeid := StringWithCharset(5, charset)
-		nodename := "node-" + nodeid
-		node.Name = nodename
+		node.Name = GenerateNodeName()
+	}
+}
+
+func (node *Node) CheckIsServer() bool {
+	nodeData, err := database.FetchRecords(database.NODES_TABLE_NAME)
+	if err != nil && !database.IsEmptyRecord(err) {
+		return false
+	}
+	for _, value := range nodeData {
+		var tmpNode Node
+		if err := json.Unmarshal([]byte(value), &tmpNode); err != nil {
+			continue
+		}
+		if tmpNode.Network == node.Network && tmpNode.MacAddress != node.MacAddress {
+			return false
+		}
 	}
+	return true
 }
 
 func (node *Node) GetNetwork() (Network, error) {
@@ -127,11 +211,8 @@ func (node *Node) SetDefaults() {
 		postup := parentNetwork.DefaultPostUp
 		node.PostUp = postup
 	}
-	if node.StaticIP == "" {
-		node.StaticIP = "no"
-	}
-	if node.StaticPubKey == "" {
-		node.StaticPubKey = "no"
+	if node.IsStatic == "" {
+		node.IsStatic = "no"
 	}
 	if node.UDPHolePunch == "" {
 		node.UDPHolePunch = parentNetwork.DefaultUDPHolePunch
@@ -140,12 +221,20 @@ func (node *Node) SetDefaults() {
 		}
 	}
 	node.CheckInInterval = parentNetwork.DefaultCheckInInterval
-
+	node.SetIPForwardingDefault()
+	node.SetDNSOnDefault()
+	node.SetIsLocalDefault()
+	node.SetIsDualStackDefault()
 	node.SetLastModified()
 	node.SetDefaultName()
 	node.SetLastCheckIn()
 	node.SetLastPeerUpdate()
+	node.SetRoamingDefault()
+	node.SetPullChangesDefault()
+	node.SetDefaultAction()
 	node.SetID()
+	node.SetIsServerDefault()
+	node.SetIsStaticDefault()
 	node.KeyUpdateTimeStamp = time.Now().Unix()
 }
 
@@ -153,10 +242,10 @@ func (newNode *Node) Fill(currentNode *Node) {
 	if newNode.ID == "" {
 		newNode.ID = currentNode.ID
 	}
-	if newNode.Address == "" {
+	if newNode.Address == ""  && newNode.IsStatic != "yes"{
 		newNode.Address = currentNode.Address
 	}
-	if newNode.Address6 == "" {
+	if newNode.Address6 == ""  && newNode.IsStatic != "yes"{
 		newNode.Address6 = currentNode.Address6
 	}
 	if newNode.LocalAddress == "" {
@@ -165,15 +254,15 @@ func (newNode *Node) Fill(currentNode *Node) {
 	if newNode.Name == "" {
 		newNode.Name = currentNode.Name
 	}
-	if newNode.ListenPort == 0 {
+	if newNode.ListenPort == 0  && newNode.IsStatic != "yes"{
 		newNode.ListenPort = currentNode.ListenPort
 	}
-	if newNode.PublicKey == "" {
+	if newNode.PublicKey == "" && newNode.IsStatic != "yes" {
 		newNode.PublicKey = currentNode.PublicKey
 	} else {
 		newNode.KeyUpdateTimeStamp = time.Now().Unix()
 	}
-	if newNode.Endpoint == "" {
+	if newNode.Endpoint == ""  && newNode.IsStatic != "yes"{
 		newNode.Endpoint = currentNode.Endpoint
 	}
 	if newNode.PostUp == "" {
@@ -247,39 +336,51 @@ func (newNode *Node) Fill(currentNode *Node) {
 	if newNode.IngressGatewayRange == "" {
 		newNode.IngressGatewayRange = currentNode.IngressGatewayRange
 	}
-	if newNode.StaticIP == "" {
-		newNode.StaticIP = currentNode.StaticIP
-	}
-	if newNode.StaticIP == "" {
-		newNode.StaticIP = currentNode.StaticIP
-	}
-	if newNode.StaticPubKey == "" {
-		newNode.StaticPubKey = currentNode.StaticPubKey
+	if newNode.IsStatic == "" {
+		newNode.IsStatic = currentNode.IsStatic
 	}
 	if newNode.UDPHolePunch == "" {
 		newNode.UDPHolePunch = currentNode.SaveConfig
 	}
-
-	newNode.PostChanges = "no"
+	if newNode.DNSOn == "" {
+		newNode.DNSOn = currentNode.DNSOn
+	}
+	if newNode.IsDualStack == "" {
+		newNode.IsDualStack = currentNode.IsDualStack
+	}
+	if newNode.IsLocal == "" {
+		newNode.IsLocal = currentNode.IsLocal
+	}
+	if newNode.IPForwarding == "" {
+		newNode.IPForwarding = currentNode.IPForwarding
+	}
+	if newNode.PullChanges == "" {
+		newNode.PullChanges = currentNode.PullChanges
+	}
+	if newNode.Roaming == "" {
+		newNode.Roaming = currentNode.Roaming
+	}
+	if newNode.Action == "" {
+		newNode.Action = currentNode.Action
+	}
+	newNode.IsServer = currentNode.IsServer
+	if newNode.IsServer == "yes" {
+		newNode.IsStatic = "yes"
+	}
 }
 
 func (currentNode *Node) Update(newNode *Node) error {
-        newNode.Fill(currentNode)
+	newNode.Fill(currentNode)
 	if err := newNode.Validate(true); err != nil {
 		return err
 	}
 	newNode.SetID()
 	if newNode.ID == currentNode.ID {
+		newNode.SetLastModified()
 		if data, err := json.Marshal(newNode); err != nil {
 			return err
 		} else {
-			newNode.SetLastModified()
-			if err = database.Insert(newNode.ID, string(data), database.NODES_TABLE_NAME); err == nil {
-				if network, err := GetNetwork(newNode.Network); err == nil {
-					err = network.SetNetworkNodesLastModified()
-				}
-			}
-			return err
+			return database.Insert(newNode.ID, string(data), database.NODES_TABLE_NAME)
 		}
 	}
 	return errors.New("failed to update node " + newNode.MacAddress + ", cannot change macaddress.")
@@ -326,11 +427,8 @@ func (node *Node) Validate(isUpdate bool) error {
 }
 
 func (node *Node) IsIDUnique() (bool, error) {
-	record, err := database.FetchRecord(database.NODES_TABLE_NAME, node.ID)
-	if err != nil {
-		return false, err
-	}
-	return record == "", err
+	_, err := database.FetchRecord(database.NODES_TABLE_NAME, node.ID)
+	return database.IsEmptyRecord(err), err
 }
 
 func (node *Node) NameInNodeCharSet() bool {
@@ -350,6 +448,9 @@ func GetAllNodes() ([]Node, error) {
 
 	collection, err := database.FetchRecords(database.NODES_TABLE_NAME)
 	if err != nil {
+		if database.IsEmptyRecord(err) {
+			return []Node{}, nil
+		}
 		return []Node{}, err
 	}
 

+ 78 - 51
netclient/auth/auth.go

@@ -1,69 +1,96 @@
 package auth
 
 import (
-    "github.com/gravitl/netmaker/netclient/config"
-    "fmt"
-//    "os"
-    "context"
-    "io/ioutil"
-    "google.golang.org/grpc/metadata"
-    "google.golang.org/grpc/status"
-    "google.golang.org/grpc/codes"
-    nodepb "github.com/gravitl/netmaker/grpc"
+	"encoding/json"
+	"fmt"
 
+	"github.com/gravitl/netmaker/models"
+	"github.com/gravitl/netmaker/netclient/config"
+
+	//    "os"
+	"context"
+	"io/ioutil"
+
+	nodepb "github.com/gravitl/netmaker/grpc"
+	"google.golang.org/grpc/codes"
+	"google.golang.org/grpc/metadata"
+	"google.golang.org/grpc/status"
 )
 
 // CreateJWT func will used to create the JWT while signing in and signing out
 func SetJWT(client nodepb.NodeServiceClient, network string) (context.Context, error) {
-		//home, err := os.UserHomeDir()
-		home := "/etc/netclient"
-		tokentext, err := ioutil.ReadFile(home + "/nettoken-"+network)
-                if err != nil {
-			err = AutoLogin(client, network)
-			if err != nil {
-                                return nil, status.Errorf(codes.Unauthenticated, fmt.Sprintf("Something went wrong with Auto Login: %v", err))
-                        }
-			tokentext, err = ioutil.ReadFile(home + "/nettoken-"+network)
-			if err != nil {
-				return nil, status.Errorf(codes.Unauthenticated, fmt.Sprintf("Something went wrong: %v", err))
-			}
+	//home, err := os.UserHomeDir()
+	home := "/etc/netclient"
+	tokentext, err := ioutil.ReadFile(home + "/nettoken-" + network)
+	if err != nil {
+		err = AutoLogin(client, network)
+		if err != nil {
+			return nil, status.Errorf(codes.Unauthenticated, fmt.Sprintf("Something went wrong with Auto Login: %v", err))
 		}
-                token := string(tokentext)
+		tokentext, err = ioutil.ReadFile(home + "/nettoken-" + network)
+		if err != nil {
+			return nil, status.Errorf(codes.Unauthenticated, fmt.Sprintf("Something went wrong: %v", err))
+		}
+	}
+	token := string(tokentext)
 
-                // Anything linked to this variable will transmit request headers.
-                md := metadata.New(map[string]string{"authorization": token})
-                ctx := context.Background()
-                ctx = metadata.NewOutgoingContext(ctx, md)
-		return ctx, nil
+	// Anything linked to this variable will transmit request headers.
+	md := metadata.New(map[string]string{"authorization": token})
+	ctx := context.Background()
+	ctx = metadata.NewOutgoingContext(ctx, md)
+	return ctx, nil
 }
 
 func AutoLogin(client nodepb.NodeServiceClient, network string) error {
-	        //home, err := os.UserHomeDir()
-		home := "/etc/netclient"
-		//nodecfg := config.Config.Node
-                cfg, err := config.ReadConfig(network) 
-		if err != nil {
-			return err
-		}
-		login := &nodepb.LoginRequest{
-                        Password: cfg.Node.Password,
-                        Macaddress: cfg.Node.MacAddress,
-                        Network: network,
-                }
-    // RPC call
-                res, err := client.Login(context.TODO(), login)
-                if err != nil {
-                        return err
-                }
-                tokenstring := []byte(res.Accesstoken)
-                err = ioutil.WriteFile(home + "/nettoken-"+network, tokenstring, 0644)
-                if err != nil {
-                        return err
-                }
-                return err
+	//home, err := os.UserHomeDir()
+	home := "/etc/netclient"
+	//nodecfg := config.Config.Node
+	cfg, err := config.ReadConfig(network)
+	if err != nil {
+		return err
+	}
+	pass, err := RetrieveSecret(network)
+	if err != nil {
+		return err
+	}
+	node := models.Node{
+		Password:   pass,
+		MacAddress: cfg.Node.MacAddress,
+		Network:    network,
+	}
+	data, err := json.Marshal(&node)
+	if err != nil {
+		return nil
+	}
+
+	login := &nodepb.Object{
+		Data: string(data),
+	}
+	// RPC call
+	res, err := client.Login(context.TODO(), login)
+	if err != nil {
+		return err
+	}
+	tokenstring := []byte(res.Data)
+	err = ioutil.WriteFile(home+"/nettoken-"+network, tokenstring, 0644)
+	if err != nil {
+		return err
+	}
+	return err
+}
+
+func StoreSecret(key string, network string) error {
+	d1 := []byte(key)
+	err := ioutil.WriteFile("/etc/netclient/secret-"+network, d1, 0644)
+	return err
+}
+
+func RetrieveSecret(network string) (string, error) {
+	dat, err := ioutil.ReadFile("/etc/netclient/secret-" + network)
+	return string(dat), err
 }
 
 type Configuration struct {
 	MacAddress string
-	Password string
+	Password   string
 }

+ 52 - 61
netclient/command/commands.go

@@ -1,32 +1,28 @@
 package command
 
 import (
-        "github.com/gravitl/netmaker/netclient/functions"
-        "github.com/gravitl/netmaker/netclient/config"
-        "github.com/gravitl/netmaker/netclient/local"
-        "golang.zx2c4.com/wireguard/wgctrl"
-        nodepb "github.com/gravitl/netmaker/grpc"
+	"log"
 	"os"
 	"strings"
-	"log"
+
+	nodepb "github.com/gravitl/netmaker/grpc"
+	"github.com/gravitl/netmaker/netclient/config"
+	"github.com/gravitl/netmaker/netclient/functions"
+	"github.com/gravitl/netmaker/netclient/local"
+	"golang.zx2c4.com/wireguard/wgctrl"
 )
 
 var (
-        wgclient *wgctrl.Client
+	wgclient *wgctrl.Client
 )
 
 var (
-        wcclient nodepb.NodeServiceClient
+	wcclient nodepb.NodeServiceClient
 )
 
-func Register(cfg config.GlobalConfig) error {
-        err := functions.Register(cfg)
-        return err
-}
-
-func Join(cfg config.ClientConfig) error {
+func Join(cfg config.ClientConfig, privateKey string) error {
 
-	err := functions.JoinNetwork(cfg)
+	err := functions.JoinNetwork(cfg, privateKey)
 	if err != nil {
 		if !strings.Contains(err.Error(), "ALREADY_INSTALLED") {
 			log.Println("Error installing: ", err)
@@ -38,15 +34,15 @@ func Join(cfg config.ClientConfig) error {
 				}
 			}
 			if cfg.Daemon != "off" {
-	                        err = local.RemoveSystemDServices(cfg.Network)
-	                        if err != nil {
-	                                log.Println("Error removing services: ", err)
-	                        }
+				err = local.RemoveSystemDServices(cfg.Network)
+				if err != nil {
+					log.Println("Error removing services: ", err)
+				}
 			}
 		}
 		return err
 	}
-        log.Println("joined " + cfg.Network)
+	log.Println("joined " + cfg.Network)
 	if cfg.Daemon != "off" {
 		err = functions.InstallDaemon(cfg)
 	}
@@ -54,74 +50,70 @@ func Join(cfg config.ClientConfig) error {
 }
 
 func CheckIn(cfg config.ClientConfig) error {
-        if cfg.Network == "all" || cfg.Network == "" {
+	if cfg.Network == "all" || cfg.Network == "" {
 		log.Println("Required, '-n'. No network provided. Exiting.")
-                os.Exit(1)
-        }
-	err := functions.CheckIn(cfg)
-	if err != nil {
-		log.Println("Error checking in: ", err)
 		os.Exit(1)
 	}
-	return nil
+	err := functions.CheckConfig(cfg)
+	return err
 }
 
 func Leave(cfg config.ClientConfig) error {
 	err := functions.LeaveNetwork(cfg.Network)
-        if err != nil {
+	if err != nil {
 		log.Println("Error attempting to leave network " + cfg.Network)
-        }
+	}
 	return err
 }
 
 func Push(cfg config.ClientConfig) error {
-        var err error
-        if cfg.Network == "all" {
-                log.Println("No network selected. Running Push for all networks.")
-                networks, err := functions.GetNetworks()
-                if err != nil {
-                        log.Println("Error retrieving networks. Exiting.")
-                        return err
-                }
-                for _, network := range networks {
-                        err = functions.Push(network)
-                        if err != nil {
-                                log.Printf("Error pushing network configs for " + network + " network: ", err)
-                        } else {
-                                log.Println("pushed network config for " + network)
-                        }
-                }
-                err = nil
-        } else {
-                err = functions.Push(cfg.Network)
-        }
-        log.Println("Completed pushing network configs to remote server.")
-        return err
+	var err error
+	if cfg.Network == "all" {
+		log.Println("No network selected. Running Push for all networks.")
+		networks, err := functions.GetNetworks()
+		if err != nil {
+			log.Println("Error retrieving networks. Exiting.")
+			return err
+		}
+		for _, network := range networks {
+			err = functions.Push(network)
+			if err != nil {
+				log.Printf("Error pushing network configs for "+network+" network: ", err)
+			} else {
+				log.Println("pushed network config for " + network)
+			}
+		}
+		err = nil
+	} else {
+		err = functions.Push(cfg.Network)
+	}
+	log.Println("Completed pushing network configs to remote server.")
+	return err
 }
 
 func Pull(cfg config.ClientConfig) error {
-        var err error
+	var err error
 	if cfg.Network == "all" {
-                log.Println("No network selected. Running Pull for all networks.")
+		log.Println("No network selected. Running Pull for all networks.")
 		networks, err := functions.GetNetworks()
 		if err != nil {
 			log.Println("Error retrieving networks. Exiting.")
 			return err
 		}
 		for _, network := range networks {
-			err = functions.Pull(network)
+			_, err = functions.Pull(network, true)
 			if err != nil {
-				log.Printf("Error pulling network config for " + network + " network: ", err)
+				log.Printf("Error pulling network config for "+network+" network: ", err)
 			} else {
 				log.Println("pulled network config for " + network)
 			}
 		}
 		err = nil
 	} else {
-	        err = functions.Pull(cfg.Network)
+		_, err = functions.Pull(cfg.Network, true)
 	}
 	log.Println("Completed pulling network and peer configs.")
-        return err
+	return err
 }
 
 func List(cfg config.ClientConfig) error {
@@ -133,10 +125,9 @@ func Uninstall(cfg config.GlobalConfig) error {
 	log.Println("Uninstalling netclient")
 	err := functions.Uninstall()
 	err = functions.Unregister(cfg)
-        return err
+	return err
 }
 func Unregister(cfg config.GlobalConfig) error {
-        err := functions.Unregister(cfg)
-        return err
+	err := functions.Unregister(cfg)
+	return err
 }
-

+ 28 - 184
netclient/config/config.go

@@ -9,7 +9,6 @@ import (
 	"log"
 	"os"
 
-	nodepb "github.com/gravitl/netmaker/grpc"
 	"github.com/gravitl/netmaker/models"
 	"github.com/urfave/cli/v2"
 	"gopkg.in/yaml.v3"
@@ -22,7 +21,7 @@ type GlobalConfig struct {
 
 type ClientConfig struct {
 	Server          ServerConfig `yaml:"server"`
-	Node            NodeConfig   `yaml:"node"`
+	Node            models.Node  `yaml:"node"`
 	Network         string       `yaml:"network"`
 	Daemon          string       `yaml:"daemon"`
 	OperatingSystem string       `yaml:"operatingsystem"`
@@ -36,45 +35,6 @@ type ServerConfig struct {
 	GRPCWireGuard string `yaml:"grpcwg"`
 }
 
-type ListConfig struct {
-	Name           string `yaml:"name"`
-	Interface      string `yaml:"interface"`
-	PrivateIPv4    string `yaml:"wgaddress"`
-	PrivateIPv6    string `yaml:"wgaddress6"`
-	PublicEndpoint string `yaml:"endpoint"`
-}
-
-type NodeConfig struct {
-	Name             string `yaml:"name"`
-	Interface        string `yaml:"interface"`
-	Network          string `yaml:"network"`
-	Password         string `yaml:"password"`
-	MacAddress       string `yaml:"macaddress"`
-	LocalAddress     string `yaml:"localaddress"`
-	WGAddress        string `yaml:"wgaddress"`
-	WGAddress6       string `yaml:"wgaddress6"`
-	Roaming          string `yaml:"roaming"`
-	DNS              string `yaml:"dns"`
-	IsLocal          string `yaml:"islocal"`
-	IsDualStack      string `yaml:"isdualstack"`
-	IsIngressGateway string `yaml:"isingressgateway"`
-	LocalRange       string `yaml:"localrange"`
-	PostUp           string `yaml:"postup"`
-	PostDown         string `yaml:"postdown"`
-	Port             int32  `yaml:"port"`
-	KeepAlive        int32  `yaml:"keepalive"`
-	PublicKey        string `yaml:"publickey"`
-	ServerPubKey     string `yaml:"serverpubkey"`
-	PrivateKey       string `yaml:"privatekey"`
-	Endpoint         string `yaml:"endpoint"`
-	PostChanges      string `yaml:"postchanges"`
-	StaticIP         string `yaml:"staticip"`
-	StaticPubKey     string `yaml:"staticpubkey"`
-	IPForwarding     string `yaml:"ipforwarding"`
-	UDPHolePunch     string `yaml:"udpholepunch"`
-	SaveConfig     string `yaml:"saveconfig"`
-}
-
 //reading in the env file
 func Write(config *ClientConfig, network string) error {
 	if network == "" {
@@ -232,6 +192,7 @@ func (config *ClientConfig) ReadConfig() {
 			fmt.Println(err)
 			log.Fatal(err)
 		} else {
+			config.Node.SetID()
 			//config = cfg
 		}
 	}
@@ -289,10 +250,10 @@ func ModGlobalConfig(cfg models.IntClient) error {
 	return err
 }
 
-func ModConfig(node *nodepb.Node) error {
-	network := node.Nodenetwork
+func ModConfig(node *models.Node) error {
+	network := node.Network
 	if network == "" {
-		return errors.New("No Network Provided")
+		return errors.New("no network provided")
 	}
 	var modconfig ClientConfig
 	var err error
@@ -303,90 +264,23 @@ func ModConfig(node *nodepb.Node) error {
 		}
 		modconfig = *useconfig
 	}
-	nodecfg := modconfig.Node
-	if node.Name != "" {
-		nodecfg.Name = node.Name
-	}
-	if node.Interface != "" {
-		nodecfg.Interface = node.Interface
-	}
-	if node.Nodenetwork != "" {
-		nodecfg.Network = node.Nodenetwork
-	}
-	if node.Macaddress != "" {
-		nodecfg.MacAddress = node.Macaddress
-	}
-	if node.Localaddress != "" {
-		nodecfg.LocalAddress = node.Localaddress
-	}
-	if node.Postup != "" {
-		nodecfg.PostUp = node.Postup
-	}
-	if node.Postdown != "" {
-		nodecfg.PostDown = node.Postdown
-	}
-	if node.Listenport != 0 {
-		nodecfg.Port = node.Listenport
-	}
-	if node.Keepalive != 0 {
-		nodecfg.KeepAlive = node.Keepalive
-	}
-	if node.Publickey != "" {
-		nodecfg.PublicKey = node.Publickey
-	}
-	if node.Endpoint != "" {
-		nodecfg.Endpoint = node.Endpoint
-	}
-	if node.Password != "" {
-		nodecfg.Password = node.Password
-	}
-	if node.Address != "" {
-		nodecfg.WGAddress = node.Address
-	}
-	if node.Address6 != "" {
-		nodecfg.WGAddress6 = node.Address6
-	}
-	if node.Postchanges != "" {
-		nodecfg.PostChanges = node.Postchanges
-	}
-	if node.Dnsoff == true {
-		nodecfg.DNS = "off"
-	}
-	if node.Isdualstack == true {
-		nodecfg.IsDualStack = "yes"
-	}
-	if node.Udpholepunch != "" {
-		nodecfg.UDPHolePunch = node.Udpholepunch
-	}
-        if node.Saveconfig != "" {
-                nodecfg.SaveConfig = node.Saveconfig
-        }
-	if node.Isingressgateway {
-		nodecfg.IsIngressGateway = "yes"
-	} else {
-		nodecfg.IsIngressGateway = "no"
-	}
-	if node.Localrange != "" && node.Islocal {
-		nodecfg.IsLocal = "yes"
-		nodecfg.LocalRange = node.Localrange
-	}
-	modconfig.Node = nodecfg
+	modconfig.Node = (*node)
 	err = Write(&modconfig, network)
 	return err
 }
 
-func GetCLIConfig(c *cli.Context) (ClientConfig, error) {
+func GetCLIConfig(c *cli.Context) (ClientConfig, string, error) {
 	var cfg ClientConfig
 	if c.String("token") != "" {
 		tokenbytes, err := base64.StdEncoding.DecodeString(c.String("token"))
 		if err != nil {
 			log.Println("error decoding token")
-			return cfg, err
+			return cfg, "", err
 		}
 		var accesstoken models.AccessToken
 		if err := json.Unmarshal(tokenbytes, &accesstoken); err != nil {
 			log.Println("error converting token json to object", tokenbytes)
-			return cfg, err
+			return cfg, "", err
 		}
 
 		if accesstoken.ServerConfig.APIConnString != "" {
@@ -454,87 +348,25 @@ func GetCLIConfig(c *cli.Context) (ClientConfig, error) {
 	cfg.Node.Password = c.String("password")
 	cfg.Node.MacAddress = c.String("macaddress")
 	cfg.Node.LocalAddress = c.String("localaddress")
-	cfg.Node.WGAddress = c.String("address")
-	cfg.Node.WGAddress6 = c.String("addressIPV6")
+	cfg.Node.Address = c.String("address")
+	cfg.Node.Address6 = c.String("addressIPV6")
 	cfg.Node.Roaming = c.String("roaming")
-	cfg.Node.DNS = c.String("dns")
+	cfg.Node.DNSOn = c.String("dns")
 	cfg.Node.IsLocal = c.String("islocal")
 	cfg.Node.IsDualStack = c.String("isdualstack")
 	cfg.Node.PostUp = c.String("postup")
 	cfg.Node.PostDown = c.String("postdown")
-	cfg.Node.Port = int32(c.Int("port"))
-	cfg.Node.KeepAlive = int32(c.Int("keepalive"))
+	cfg.Node.ListenPort = int32(c.Int("port"))
+	cfg.Node.PersistentKeepalive = int32(c.Int("keepalive"))
 	cfg.Node.PublicKey = c.String("publickey")
-	cfg.Node.PrivateKey = c.String("privatekey")
+	privateKey := c.String("privatekey")
 	cfg.Node.Endpoint = c.String("endpoint")
 	cfg.Node.IPForwarding = c.String("ipforwarding")
 	cfg.OperatingSystem = c.String("operatingsystem")
 	cfg.Daemon = c.String("daemon")
 	cfg.Node.UDPHolePunch = c.String("udpholepunch")
 
-	return cfg, nil
-}
-
-func GetCLIConfigRegister(c *cli.Context) (GlobalConfig, error) {
-	var cfg GlobalConfig
-	if c.String("token") != "" {
-		tokenbytes, err := base64.StdEncoding.DecodeString(c.String("token"))
-		if err != nil {
-			log.Println("error decoding token")
-			return cfg, err
-		}
-		var accesstoken models.AccessToken
-		if err := json.Unmarshal(tokenbytes, &accesstoken); err != nil {
-			log.Println("error converting token json to object", tokenbytes)
-			return cfg, err
-		}
-		cfg.GRPCWireGuard = accesstoken.WG.GRPCWireGuard
-		cfg.Client.ServerPrivateAddress = accesstoken.WG.GRPCWGAddress
-		cfg.Client.ServerGRPCPort = accesstoken.WG.GRPCWGPort
-		if err != nil {
-			log.Println("error decoding token grpcserver")
-			return cfg, err
-		}
-		if err != nil {
-			log.Println("error decoding token apiserver")
-			return cfg, err
-		}
-		if accesstoken.ServerConfig.APIConnString != "" {
-			cfg.Client.ServerPublicEndpoint = accesstoken.ServerConfig.APIConnString
-		} else {
-			cfg.Client.ServerPublicEndpoint = accesstoken.ServerConfig.APIHost
-			if accesstoken.ServerConfig.APIPort != "" {
-				cfg.Client.ServerAPIPort = accesstoken.ServerConfig.APIPort
-			}
-		}
-		cfg.Client.ServerWGPort = accesstoken.WG.GRPCWGPort
-		cfg.Client.ServerKey = accesstoken.ClientConfig.Key
-		cfg.Client.ServerKey = accesstoken.WG.GRPCWGPubKey
-
-		if c.String("grpcserver") != "" {
-			cfg.Client.ServerPrivateAddress = c.String("grpcserver")
-		}
-		if c.String("apiserver") != "" {
-			cfg.Client.ServerPublicEndpoint = c.String("apiserver")
-		}
-		if c.String("pubkey") != "" {
-			cfg.Client.ServerKey = c.String("pubkey")
-		}
-		if c.String("network") != "all" {
-			cfg.Client.Network = c.String("network")
-		}
-	} else {
-		cfg.Client.ServerPrivateAddress = c.String("grpcserver")
-		cfg.Client.ServerPublicEndpoint = c.String("apiserver")
-		cfg.Client.ServerKey = c.String("key")
-		cfg.Client.Network = c.String("network")
-	}
-	cfg.Client.Address = c.String("address")
-	cfg.Client.Address6 = c.String("addressIPV6")
-	cfg.Client.PublicKey = c.String("pubkey")
-	cfg.Client.PrivateKey = c.String("privkey")
-
-	return cfg, nil
+	return cfg, privateKey, nil
 }
 
 func ReadConfig(network string) (*ClientConfig, error) {
@@ -596,3 +428,15 @@ func FileExists(f string) bool {
 	}
 	return !info.IsDir()
 }
+
+func GetNode(network string) models.Node {
+
+	modcfg, err := ReadConfig(network)
+	if err != nil {
+		log.Fatalf("Error: %v", err)
+	}
+	var node models.Node
+	node.Fill(&modcfg.Node)
+
+	return node
+}

+ 251 - 346
netclient/functions/checkin.go

@@ -1,390 +1,295 @@
 package functions
 
 import (
-        "google.golang.org/grpc/credentials"
-        "crypto/tls"
-	"fmt"
-	"context"
-	"strings"
+	"crypto/tls"
+	"encoding/json"
+	"errors"
 	"log"
-	"net"
-	"os/exec"
-        "github.com/gravitl/netmaker/netclient/config"
-        "github.com/gravitl/netmaker/netclient/local"
-        "github.com/gravitl/netmaker/netclient/wireguard"
-        "github.com/gravitl/netmaker/netclient/server"
-        "github.com/gravitl/netmaker/netclient/auth"
-        nodepb "github.com/gravitl/netmaker/grpc"
-        "google.golang.org/grpc"
+
+	nodepb "github.com/gravitl/netmaker/grpc"
+	"github.com/gravitl/netmaker/models"
+	"github.com/gravitl/netmaker/netclient/auth"
+	"github.com/gravitl/netmaker/netclient/config"
+	"github.com/gravitl/netmaker/netclient/local"
+	"github.com/gravitl/netmaker/netclient/wireguard"
+	"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
+	"google.golang.org/grpc"
+	"google.golang.org/grpc/credentials"
 	"google.golang.org/grpc/metadata"
 	//homedir "github.com/mitchellh/go-homedir"
 )
 
-func CheckIn(cliconf config.ClientConfig) error {
-	network := cliconf.Network
-	node := server.GetNode(network)
-        cfg, err := config.ReadConfig(network)
-        if err != nil {
-                return err
-        }
-	nodecfg := cfg.Node
-	servercfg := cfg.Server
-	fmt.Println("Checking into server at " + servercfg.GRPCAddress)
-
-	setupcheck := true
+func checkIP(node *models.Node, servercfg config.ServerConfig, cliconf config.ClientConfig, network string) bool {
 	ipchange := false
-
-        if nodecfg.DNS == "on" || cliconf.Node.DNS == "on" {
-		fmt.Println("setting dns")
-		ifacename := node.Interface
-		nameserver := servercfg.CoreDNSAddr
-		network := node.Nodenetwork
-                _ = local.UpdateDNS(ifacename, network, nameserver)
-        }
-
-	if !(nodecfg.IPForwarding == "off") {
-		out, err := exec.Command("sysctl", "net.ipv4.ip_forward").Output()
-                 if err != nil {
-	                 fmt.Println(err)
-			 fmt.Println("WARNING: Error encountered setting ip forwarding. This can break functionality.")
-                 } else {
-                         s := strings.Fields(string(out))
-                         if s[2] != "1" {
-				_, err = exec.Command("sysctl", "-w", "net.ipv4.ip_forward=1").Output()
-				if err != nil {
-					fmt.Println(err)
-					fmt.Println("WARNING: Error encountered setting ip forwarding. You may want to investigate this.")
-				}
+	var err error
+	if node.Roaming == "yes" && node.IsStatic != "yes" {
+		if node.IsLocal == "no" {
+			log.Println("Checking to see if public addresses have changed")
+			extIP, err := getPublicIP()
+			if err != nil {
+				log.Println("error encountered checking ip addresses:", err)
+			}
+			if node.Endpoint != extIP && extIP != "" {
+				log.Println("Endpoint has changed from " +
+					node.Endpoint + " to " + extIP)
+				log.Println("Updating address")
+				node.Endpoint = extIP
+				ipchange = true
+			}
+			intIP, err := getPrivateAddr()
+			if err != nil {
+				log.Println("error encountered checking ip addresses:", err)
+			}
+			if node.LocalAddress != intIP && intIP != "" {
+				log.Println("Local Address has changed from " +
+					node.LocalAddress + " to " + intIP)
+				log.Println("Updating address")
+				node.LocalAddress = intIP
+				ipchange = true
+			}
+		} else {
+			log.Println("Checking to see if local addresses have changed")
+			localIP, err := getLocalIP(node.LocalRange)
+			if err != nil {
+				log.Println("error encountered checking ip addresses:", err)
+			}
+			if node.Endpoint != localIP && localIP != "" {
+				log.Println("Endpoint has changed from " +
+					node.Endpoint + " to " + localIP)
+				log.Println("Updating address")
+				node.Endpoint = localIP
+				node.LocalAddress = localIP
+				ipchange = true
 			}
 		}
 	}
-
-	if nodecfg.Roaming != "off" {
-		if nodecfg.IsLocal != "yes" {
-		fmt.Println("Checking to see if public addresses have changed")
-		extIP, err := getPublicIP()
+	if ipchange {
+		err = config.ModConfig(node)
 		if err != nil {
-			fmt.Printf("Error encountered checking ip addresses: %v", err)
-		}
-		if nodecfg.Endpoint != extIP  && extIP != "" {
-	                fmt.Println("Endpoint has changed from " +
-			nodecfg.Endpoint + " to " + extIP)
-			fmt.Println("Updating address")
-			nodecfg.Endpoint = extIP
-			nodecfg.PostChanges = "true"
-			node.Endpoint = extIP
-			node.Postchanges = "true"
-			ipchange = true
+			log.Println("Error:", err)
+			return false
 		}
-		intIP, err := getPrivateAddr()
-                if err != nil {
-                        fmt.Printf("Error encountered checking ip addresses: %v", err)
-                }
-                if nodecfg.LocalAddress != intIP  && intIP != "" {
-                        fmt.Println("Local Address has changed from " +
-			nodecfg.LocalAddress + " to " + intIP)
-			fmt.Println("Updating address")
-			nodecfg.LocalAddress = intIP
-			nodecfg.PostChanges = "true"
-			node.Localaddress = intIP
-			node.Postchanges = "true"
-			ipchange = true
-                }
-		} else {
-                fmt.Println("Checking to see if local addresses have changed")
-                localIP, err := getLocalIP(nodecfg.LocalRange)
-                if err != nil {
-                        fmt.Printf("Error encountered checking ip addresses: %v", err)
-                }
-                if nodecfg.Endpoint != localIP  && localIP != "" {
-                        fmt.Println("Endpoint has changed from " +
-                        nodecfg.Endpoint + " to " + localIP)
-                        fmt.Println("Updating address")
-                        nodecfg.Endpoint = localIP
-                        nodecfg.LocalAddress = localIP
-                        nodecfg.PostChanges = "true"
-                        node.Endpoint = localIP
-                        node.Localaddress = localIP
-                        node.Postchanges = "true"
-                        ipchange = true
-                }
+		err = wireguard.SetWGConfig(network, false)
+		if err != nil {
+			log.Println("Error:", err)
+			return false
 		}
-		if node.Postchanges != "true" {
-			fmt.Println("Addresses have not changed.")
+	}
+	return ipchange && err == nil
+}
+
+func setDNS(node *models.Node, servercfg config.ServerConfig, nodecfg *models.Node) {
+	if nodecfg.DNSOn == "yes" {
+		log.Println("setting dns")
+		ifacename := node.Interface
+		nameserver := servercfg.CoreDNSAddr
+		network := node.Network
+		_ = local.UpdateDNS(ifacename, network, nameserver)
+	}
+}
+
+func checkNodeActions(node *models.Node, network string, servercfg config.ServerConfig, localNode *models.Node) string {
+	if (node.Action == models.NODE_UPDATE_KEY || localNode.Action == models.NODE_UPDATE_KEY) && 
+		node.IsStatic != "yes" {
+		err := wireguard.SetWGKeyConfig(network, servercfg.GRPCAddress)
+		if err != nil {
+			log.Println("Unable to process reset keys request:", err)
+			return ""
 		}
 	}
-	if ipchange {
-		err := config.ModConfig(&node)
-                if err != nil {
-                        return err
-                        log.Fatalf("Error: %v", err)
-                }
-                err = wireguard.SetWGConfig(network)
-                if err != nil {
-                        return err
-                        log.Fatalf("Error: %v", err)
-                }
-	        node = server.GetNode(network)
-		cfg, err := config.ReadConfig(network)
+	if node.Action == models.NODE_DELETE || localNode.Action == models.NODE_DELETE {
+		err := LeaveNetwork(network)
 		if err != nil {
-			return err
+			log.Println("Error:", err)
+			return ""
 		}
-		nodecfg = cfg.Node
+		return models.NODE_DELETE
 	}
+	return ""
+}
 
-        var wcclient nodepb.NodeServiceClient
-        var requestOpts grpc.DialOption
-        requestOpts = grpc.WithInsecure()
-        if servercfg.GRPCSSL == "on" {
-		log.Println("using SSL")
-                h2creds := credentials.NewTLS(&tls.Config{NextProtos: []string{"h2"}})
-                requestOpts = grpc.WithTransportCredentials(h2creds)
-        } else {
-                log.Println("using insecure GRPC connection")
-	}
-        conn, err := grpc.Dial(servercfg.GRPCAddress, requestOpts)
-        if err != nil {
-		fmt.Printf("Cant dial GRPC server: %v", err)
-		return err
-        }
-        wcclient = nodepb.NewNodeServiceClient(conn)
+/**
+ * Pull changes if any (interface refresh)
+ * - Save it
+ * Check local changes for (ipAddress, publickey, configfile changes) (interface refresh)
+ * - Save it
+ * - Push it
+ * Pull Peers (sync)
+ */
+func CheckConfig(cliconf config.ClientConfig) error {
 
-        ctx := context.Background()
-        fmt.Println("Authenticating with GRPC Server")
-        ctx, err = auth.SetJWT(wcclient, network)
-        if err != nil {
-                fmt.Printf("Failed to authenticate: %v", err)
+	network := cliconf.Network
+	cfg, err := config.ReadConfig(network)
+	if err != nil {
 		return err
 	}
-        fmt.Println("Authenticated")
-        fmt.Println("Checking In.")
+	servercfg := cfg.Server
+	currentNode := cfg.Node
 
-        var header metadata.MD
-	node.Nodenetwork = network
-        checkinres, err := wcclient.CheckIn(
-                ctx,
-                &nodepb.CheckInReq{
-                        Node: &node,
-                },
-		grpc.Header(&header),
-        )
-        if err != nil {
-        if  checkinres != nil && checkinres.Checkinresponse.Ispending {
-                fmt.Println("Node is in pending status. Waiting for Admin approval of  node before making further updates.")
-                return nil
-        }
-                fmt.Printf("Unable to process Check In request: %v", err)
-		return err
-        }
-	fmt.Println("Checked in.")
-	if  checkinres.Checkinresponse.Ispending {
-		fmt.Println("Node is in pending status. Waiting for Admin approval of  node before making further updates.")
+	newNode, err := Pull(network, false)
+	if err != nil {
 		return err
 	}
+	if newNode.IsPending == "yes" {
+		return errors.New("node is pending")
+	}
 
-                newinterface := server.GetNode(network).Interface
-                readreq := &nodepb.ReadNodeReq{
-                        Macaddress: node.Macaddress,
-                        Network: node.Nodenetwork,
-                }
-                readres, err := wcclient.ReadNode(ctx, readreq, grpc.Header(&header))
-                if err != nil {
-                        fmt.Printf("Error: %v", err)
-                } else {
-                currentiface := readres.Node.Interface
-                ifaceupdate := newinterface != currentiface
-                if err != nil {
-                        log.Printf("Error retrieving interface: %v", err)
-                }
-                if ifaceupdate {
-			fmt.Println("Interface update: " + currentiface +
-			" >>>> " + newinterface)
-                        err := DeleteInterface(currentiface, nodecfg.PostDown)
-                        if err != nil {
-                                fmt.Println("ERROR DELETING INTERFACE: " + currentiface)
-                        }
-                err = wireguard.SetWGConfig(network)
-                if err != nil {
-                        log.Printf("Error updating interface: %v", err)
-                }
-		}
+	actionCompleted := checkNodeActions(newNode, network, servercfg, &currentNode)
+	if actionCompleted == models.NODE_DELETE {
+		return errors.New("node has been removed")
+	}
+	// Check if ip changed and push if so
+	checkIP(newNode, servercfg, cliconf, network)
+	return Push(network)
+}
+
+/**
+ * Pull the latest node from server
+ * Perform action if necessary
+ */
+func Pull(network string, manual bool) (*models.Node, error) {
+	cfg, err := config.ReadConfig(network)
+	node := cfg.Node
+	if err != nil {
+		return nil, err
+	}
+	servercfg := cfg.Server
+	var header metadata.MD
+
+	if cfg.Node.IPForwarding == "yes" {
+		if err = local.SetIPForwarding(); err != nil {
+			return nil, err
 		}
+	}
+
+	var requestOpts grpc.DialOption
+	requestOpts = grpc.WithInsecure()
+	if cfg.Server.GRPCSSL == "on" {
+		h2creds := credentials.NewTLS(&tls.Config{NextProtos: []string{"h2"}})
+		requestOpts = grpc.WithTransportCredentials(h2creds)
+	}
+	conn, err := grpc.Dial(servercfg.GRPCAddress, requestOpts)
+	if err != nil {
+		log.Println("Cant dial GRPC server:", err)
+		return nil, err
+	}
+	wcclient := nodepb.NewNodeServiceClient(conn)
 
-	if checkinres.Checkinresponse.Needconfigupdate {
-		fmt.Println("Server has requested that node update config.")
-		fmt.Println("Updating config from remote server.")
-                req := &nodepb.ReadNodeReq{
-                        Macaddress: node.Macaddress,
-                        Network: node.Nodenetwork,
-                }
-                readres, err := wcclient.ReadNode(ctx, req, grpc.Header(&header))
-                if err != nil {
-			return err
-                        log.Fatalf("Error: %v", err)
-                }
-                err = config.ModConfig(readres.Node)
-                if err != nil {
-			return err
-                        log.Fatalf("Error: %v", err)
-                }
-                err = wireguard.SetWGConfig(network)
-                if err != nil {
-			return err
-                        log.Fatalf("Error: %v", err)
-                }
-		setupcheck = false
-	} else if nodecfg.PostChanges == "true" {
-                fmt.Println("Node has requested to update remote config.")
-                fmt.Println("Posting local config to remote server.")
-		postnode := server.GetNode(network)
-		fmt.Println("POSTING NODE: ",postnode.Macaddress,postnode.Saveconfig)
-		req := &nodepb.UpdateNodeReq{
-                               Node: &postnode,
-                        }
-		res, err := wcclient.UpdateNode(ctx, req, grpc.Header(&header))
-                if err != nil {
-			return err
-			log.Fatalf("Error: %v", err)
-                }
-		res.Node.Postchanges = "false"
-		err = config.ModConfig(res.Node)
-                if err != nil {
-			return err
-                        log.Fatalf("Error: %v", err)
-                }
-		//err = wireguard.SetWGConfig(network)
-                if err != nil {
-			return err
-                        log.Fatalf("Error: %v", err)
-                }
-		setupcheck = false
+	ctx, err := auth.SetJWT(wcclient, network)
+	if err != nil {
+		log.Println("Failed to authenticate:", err)
+		return nil, err
 	}
-        if checkinres.Checkinresponse.Needkeyupdate {
-                fmt.Println("Server has requested that node update key pairs.")
-                fmt.Println("Proceeding to re-generate key pairs for Wiregard.")
-                err = wireguard.SetWGKeyConfig(network, servercfg.GRPCAddress)
-                if err != nil {
-                        return err
-                        log.Fatalf("Unable to process reset keys request: %v", err)
-                }
-                setupcheck = false
-        }
-        if checkinres.Checkinresponse.Needpeerupdate {
-                fmt.Println("Server has requested that node update peer list.")
-                fmt.Println("Updating peer list from remote server.")
-                err = wireguard.SetWGConfig(network)
-                if err != nil {
-			return err
-                        log.Fatalf("Unable to process Set Peers request: %v", err)
-                }
-		setupcheck = false
-        }
-	if checkinres.Checkinresponse.Needdelete {
-		fmt.Println("This machine got the delete signal. Deleting.")
-                err := LeaveNetwork(network)
-                if err != nil {
-                        return err
-                        log.Fatalf("Error: %v", err)
-                }
+
+	req := &nodepb.Object{
+		Data: node.MacAddress + "###" + node.Network,
+		Type: nodepb.STRING_TYPE,
 	}
-	if setupcheck {
-	iface := nodecfg.Interface
-	_, err := net.InterfaceByName(iface)
-        if err != nil {
-		fmt.Println("interface " + iface + " does not currently exist. Setting up WireGuard.")
-                err = wireguard.SetWGKeyConfig(network, servercfg.GRPCAddress)
-                if err != nil {
-                        return err
-                        log.Fatalf("Error: %v", err)
-                }
+	readres, err := wcclient.ReadNode(ctx, req, grpc.Header(&header))
+	if err != nil {
+		return nil, err
 	}
+	var resNode models.Node
+	if err = json.Unmarshal([]byte(readres.Data), &resNode); err != nil {
+		return nil, err
+	}
+	if resNode.PullChanges == "yes" || manual {
+		// check for interface change
+		if cfg.Node.Interface != resNode.Interface {
+			if err = DeleteInterface(cfg.Node.Interface, cfg.Node.PostDown); err != nil {
+				log.Println("could not delete old interface", cfg.Node.Interface)
+			}
+		}
+		resNode.PullChanges = "no"
+		if err = config.ModConfig(&resNode); err != nil {
+			return nil, err
+		}
+		if err = wireguard.SetWGConfig(network, false); err != nil {
+			return nil, err
+		}
+		nodeData, err := json.Marshal(&resNode)
+		if err != nil {
+			return &resNode, err
+		}
+		req := &nodepb.Object{
+			Data:     string(nodeData),
+			Type:     nodepb.NODE_TYPE,
+			Metadata: "",
+		}
+		_, err = wcclient.UpdateNode(ctx, req, grpc.Header(&header))
+		if err != nil {
+			return &resNode, err
+		}
+	} else {
+		if err = wireguard.SetWGConfig(network, true); err != nil {
+			return nil, err
+		}
 	}
-	return nil
+	setDNS(&resNode, servercfg, &cfg.Node)
+
+	return &resNode, err
 }
 
-func Pull (network string) error{
-        node := server.GetNode(network)
+func Push(network string) error {
 	cfg, err := config.ReadConfig(network)
-        if err != nil {
-                return err
-        }
-        servercfg := cfg.Server
-        var header metadata.MD
+	postnode := cfg.Node
+	if err != nil {
+		return err
+	}
+	servercfg := cfg.Server
+	var header metadata.MD
 
 	var wcclient nodepb.NodeServiceClient
-        var requestOpts grpc.DialOption
-        requestOpts = grpc.WithInsecure()
-        if cfg.Server.GRPCSSL == "on" {
-                h2creds := credentials.NewTLS(&tls.Config{NextProtos: []string{"h2"}})
-                requestOpts = grpc.WithTransportCredentials(h2creds)
-        }
-        conn, err := grpc.Dial(servercfg.GRPCAddress, requestOpts)
-        if err != nil {
-                fmt.Printf("Cant dial GRPC server: %v", err)
-                return err
-        }
-        wcclient = nodepb.NewNodeServiceClient(conn)
-
-        ctx := context.Background()
-        ctx, err = auth.SetJWT(wcclient, network)
-        if err != nil {
-                fmt.Printf("Failed to authenticate: %v", err)
-                return err
-        }
-
-        req := &nodepb.ReadNodeReq{
-                Macaddress: node.Macaddress,
-                Network: node.Nodenetwork,
-        }
-         readres, err := wcclient.ReadNode(ctx, req, grpc.Header(&header))
-         if err != nil {
-               return err
-         }
-         err = config.ModConfig(readres.Node)
-         if err != nil {
-                return err
-         }
-         err = wireguard.SetWGConfig(network)
-        if err != nil {
-                return err
-        }
-
-	return err
-}
+	var requestOpts grpc.DialOption
+	requestOpts = grpc.WithInsecure()
+	if cfg.Server.GRPCSSL == "on" {
+		h2creds := credentials.NewTLS(&tls.Config{NextProtos: []string{"h2"}})
+		requestOpts = grpc.WithTransportCredentials(h2creds)
+	}
+	conn, err := grpc.Dial(servercfg.GRPCAddress, requestOpts)
+	if err != nil {
+		log.Println("Cant dial GRPC server:", err)
+		return err
+	}
+	wcclient = nodepb.NewNodeServiceClient(conn)
 
-func Push (network string) error{
-        postnode := server.GetNode(network)
-        cfg, err := config.ReadConfig(network)
-        if err != nil {
-                return err
-        }
-        servercfg := cfg.Server
-        var header metadata.MD
+	ctx, err := auth.SetJWT(wcclient, network)
+	if err != nil {
+		log.Println("Failed to authenticate:", err)
+		return err
+	}
 
-        var wcclient nodepb.NodeServiceClient
-        var requestOpts grpc.DialOption
-        requestOpts = grpc.WithInsecure()
-        if cfg.Server.GRPCSSL == "on" {
-                h2creds := credentials.NewTLS(&tls.Config{NextProtos: []string{"h2"}})
-                requestOpts = grpc.WithTransportCredentials(h2creds)
-        }
-        conn, err := grpc.Dial(servercfg.GRPCAddress, requestOpts)
-        if err != nil {
-                fmt.Printf("Cant dial GRPC server: %v", err)
-                return err
-        }
-        wcclient = nodepb.NewNodeServiceClient(conn)
+	privateKey, err := wireguard.RetrievePrivKey(network)
+	if err != nil {
+		return err
+	}
+	privateKeyWG, err := wgtypes.ParseKey(privateKey)
+	if err != nil {
+		return err
+	}
+	if postnode.PublicKey != privateKeyWG.PublicKey().String() {
+		postnode.PublicKey = privateKeyWG.PublicKey().String()
+	}
 
-        ctx := context.Background()
-        ctx, err = auth.SetJWT(wcclient, network)
-        if err != nil {
-                fmt.Printf("Failed to authenticate: %v", err)
-                return err
-        }
+	postnode.SetLastCheckIn()
+	nodeData, err := json.Marshal(&postnode)
+	if err != nil {
+		return err
+	}
 
-        req := &nodepb.UpdateNodeReq{
-                       Node: &postnode,
-                }
-        _, err = wcclient.UpdateNode(ctx, req, grpc.Header(&header))
-        return err
+	req := &nodepb.Object{
+		Data:     string(nodeData),
+		Type:     nodepb.NODE_TYPE,
+		Metadata: "",
+	}
+	data, err := wcclient.UpdateNode(ctx, req, grpc.Header(&header))
+	if err != nil {
+		return err
+	}
+	err = json.Unmarshal([]byte(data.Data), &postnode)
+	if err != nil {
+		return err
+	}
+	err = config.ModConfig(&postnode)
+	return err
 }

+ 210 - 239
netclient/functions/common.go

@@ -1,66 +1,68 @@
 package functions
 
 import (
-        "google.golang.org/grpc/credentials"
-        "crypto/tls"
-	"fmt"
+	"context"
+	"crypto/tls"
 	"encoding/json"
 	"errors"
-	"context"
-        "net/http"
-        "io/ioutil"
-	"strings"
+	"fmt"
+	"io/ioutil"
 	"log"
 	"net"
+	"net/http"
 	"os"
 	"os/exec"
-        "github.com/gravitl/netmaker/netclient/config"
-        "github.com/gravitl/netmaker/netclient/local"
-        "github.com/gravitl/netmaker/netclient/auth"
-        nodepb "github.com/gravitl/netmaker/grpc"
+	"strings"
+
+	nodepb "github.com/gravitl/netmaker/grpc"
+	"github.com/gravitl/netmaker/models"
+	"github.com/gravitl/netmaker/netclient/auth"
+	"github.com/gravitl/netmaker/netclient/config"
+	"github.com/gravitl/netmaker/netclient/local"
 	"golang.zx2c4.com/wireguard/wgctrl"
-        "google.golang.org/grpc"
+	"google.golang.org/grpc"
+	"google.golang.org/grpc/credentials"
 	"google.golang.org/grpc/metadata"
 	//homedir "github.com/mitchellh/go-homedir"
 )
 
 var (
-        wcclient nodepb.NodeServiceClient
+	wcclient nodepb.NodeServiceClient
 )
 
-func ListPorts() error{
+func ListPorts() error {
 	wgclient, err := wgctrl.New()
-	if err  != nil {
+	if err != nil {
 		return err
 	}
 	devices, err := wgclient.Devices()
-        if err  != nil {
-                return err
-        }
+	if err != nil {
+		return err
+	}
 	fmt.Println("Here are your ports:")
-	 for _, i := range devices {
+	for _, i := range devices {
 		fmt.Println(i.ListenPort)
 	}
 	return err
 }
 
-func GetFreePort(rangestart int32) (int32, error){
-        wgclient, err := wgctrl.New()
-        if err  != nil {
-                return 0, err
-        }
-        devices, err := wgclient.Devices()
-        if err  != nil {
-                return 0, err
-        }
+func GetFreePort(rangestart int32) (int32, error) {
+	wgclient, err := wgctrl.New()
+	if err != nil {
+		return 0, err
+	}
+	devices, err := wgclient.Devices()
+	if err != nil {
+		return 0, err
+	}
 	var portno int32
 	portno = 0
-	for  x := rangestart; x <= 60000; x++ {
+	for x := rangestart; x <= 60000; x++ {
 		conflict := false
 		for _, i := range devices {
 			if int32(i.ListenPort) == x {
 				conflict = true
-				break;
+				break
 			}
 		}
 		if conflict {
@@ -69,49 +71,49 @@ func GetFreePort(rangestart int32) (int32, error){
 		portno = x
 		break
 	}
-        return portno, err
+	return portno, err
 }
 
 func getLocalIP(localrange string) (string, error) {
 	_, localRange, err := net.ParseCIDR(localrange)
-        if err != nil {
-                return "", err
-        }
+	if err != nil {
+		return "", err
+	}
 	ifaces, err := net.Interfaces()
-        if err != nil {
+	if err != nil {
 		return "", err
-        }
-        var local string
-        found := false
-        for _, i := range ifaces {
-        if i.Flags&net.FlagUp == 0 {
-		continue // interface down
-        }
-        if i.Flags&net.FlagLoopback != 0 {
-		continue // loopback interface
-        }
-	addrs, err := i.Addrs()
-        if err != nil {
-                return "", err
-        }
-        for _, addr := range addrs {
-                var ip net.IP
-                switch v := addr.(type) {
-                case *net.IPNet:
-			if !found {
-				 ip = v.IP
-                                 local = ip.String()
-                                 found = localRange.Contains(ip)
-                        }
-		case *net.IPAddr:
-			if !found {
-				ip = v.IP
-                                local = ip.String()
-                                found = localRange.Contains(ip)
-                        }
-                }
-        }
-        }
+	}
+	var local string
+	found := false
+	for _, i := range ifaces {
+		if i.Flags&net.FlagUp == 0 {
+			continue // interface down
+		}
+		if i.Flags&net.FlagLoopback != 0 {
+			continue // loopback interface
+		}
+		addrs, err := i.Addrs()
+		if err != nil {
+			return "", err
+		}
+		for _, addr := range addrs {
+			var ip net.IP
+			switch v := addr.(type) {
+			case *net.IPNet:
+				if !found {
+					ip = v.IP
+					local = ip.String()
+					found = localRange.Contains(ip)
+				}
+			case *net.IPAddr:
+				if !found {
+					ip = v.IP
+					local = ip.String()
+					found = localRange.Contains(ip)
+				}
+			}
+		}
+	}
 	if !found || local == "" {
 		return "", errors.New("Failed to find local IP in range " + localrange)
 	}
@@ -120,10 +122,10 @@ func getLocalIP(localrange string) (string, error) {
 
 func getPublicIP() (string, error) {
 
-	iplist := []string{"http://ip.client.gravitl.com","https://ifconfig.me", "http://api.ipify.org", "http://ipinfo.io/ip"}
+	iplist := []string{"http://ip.client.gravitl.com", "https://ifconfig.me", "http://api.ipify.org", "http://ipinfo.io/ip"}
 	endpoint := ""
 	var err error
-	    for _, ipserver := range iplist {
+	for _, ipserver := range iplist {
 		resp, err := http.Get(ipserver)
 		if err != nil {
 			continue
@@ -140,125 +142,97 @@ func getPublicIP() (string, error) {
 
 	}
 	if err == nil && endpoint == "" {
-		err =  errors.New("Public Address Not Found.")
+		err = errors.New("Public Address Not Found.")
 	}
 	return endpoint, err
 }
 
 func getMacAddr() ([]string, error) {
-    ifas, err := net.Interfaces()
-    if err != nil {
-        return nil, err
-    }
-    var as []string
-    for _, ifa := range ifas {
-        a := ifa.HardwareAddr.String()
-        if a != "" {
-            as = append(as, a)
-        }
-    }
-    return as, nil
+	ifas, err := net.Interfaces()
+	if err != nil {
+		return nil, err
+	}
+	var as []string
+	for _, ifa := range ifas {
+		a := ifa.HardwareAddr.String()
+		if a != "" {
+			as = append(as, a)
+		}
+	}
+	return as, nil
 }
 
 func getPrivateAddr() (string, error) {
-                ifaces, err := net.Interfaces()
-                if err != nil {
-                        return "", err
-                }
-                var local string
-                found := false
-                for _, i := range ifaces {
-                        if i.Flags&net.FlagUp == 0 {
-                                continue // interface down
-                        }
-                        if i.Flags&net.FlagLoopback != 0 {
-                                continue // loopback interface
-                        }
-                        addrs, err := i.Addrs()
-                        if err != nil {
-                                return "", err
-                        }
-                        for _, addr := range addrs {
-                                var ip net.IP
-                                switch v := addr.(type) {
-                                case *net.IPNet:
-                                        if !found {
-                                                ip = v.IP
-                                                local = ip.String()
-                                                found = true
-                                        }
-                                case *net.IPAddr:
-                                        if  !found {
-                                                ip = v.IP
-                                                local = ip.String()
-                                                found = true
-                                        }
-                                }
-                        }
-                }
-		if !found {
-			err := errors.New("Local Address Not Found.")
+	ifaces, err := net.Interfaces()
+	if err != nil {
+		return "", err
+	}
+	var local string
+	found := false
+	for _, i := range ifaces {
+		if i.Flags&net.FlagUp == 0 {
+			continue // interface down
+		}
+		if i.Flags&net.FlagLoopback != 0 {
+			continue // loopback interface
+		}
+		addrs, err := i.Addrs()
+		if err != nil {
 			return "", err
 		}
-		return local, err
+		for _, addr := range addrs {
+			var ip net.IP
+			switch v := addr.(type) {
+			case *net.IPNet:
+				if !found {
+					ip = v.IP
+					local = ip.String()
+					found = true
+				}
+			case *net.IPAddr:
+				if !found {
+					ip = v.IP
+					local = ip.String()
+					found = true
+				}
+			}
+		}
+	}
+	if !found {
+		err := errors.New("Local Address Not Found.")
+		return "", err
+	}
+	return local, err
 }
 
 func needInterfaceUpdate(ctx context.Context, mac string, network string, iface string) (bool, string, error) {
-                var header metadata.MD
-		req := &nodepb.ReadNodeReq{
-                        Macaddress: mac,
-                        Network: network,
-                }
-                readres, err := wcclient.ReadNode(ctx, req, grpc.Header(&header))
-                if err != nil {
-                        return false, "", err
-                        log.Fatalf("Error: %v", err)
-                }
-		oldiface := readres.Node.Interface
+	var header metadata.MD
+	req := &nodepb.Object{
+		Data: mac + "###" + network,
+		Type: nodepb.STRING_TYPE,
+	}
+	readres, err := wcclient.ReadNode(ctx, req, grpc.Header(&header))
+	if err != nil {
+		return false, "", err
+		log.Fatalf("Error: %v", err)
+	}
+	var resNode models.Node
+	if err := json.Unmarshal([]byte(readres.Data), &resNode); err != nil {
+		return false, iface, err
+	}
+	oldiface := resNode.Interface
 
-		return iface != oldiface, oldiface, err
+	return iface != oldiface, oldiface, err
 }
 
-func GetNode(network string) nodepb.Node {
+func GetNode(network string) models.Node {
 
-        modcfg, err := config.ReadConfig(network)
-        if err != nil {
-                log.Fatalf("Error: %v", err)
-        }
-
-	nodecfg := modcfg.Node
-	var node nodepb.Node
+	modcfg, err := config.ReadConfig(network)
+	if err != nil {
+		log.Fatalf("Error: %v", err)
+	}
 
-	node.Name = nodecfg.Name
-	node.Interface = nodecfg.Interface
-	node.Nodenetwork = nodecfg.Network
-	node.Localaddress = nodecfg.LocalAddress
-	node.Address = nodecfg.WGAddress
-	node.Address6 = nodecfg.WGAddress6
-	node.Listenport = nodecfg.Port
-	node.Keepalive = nodecfg.KeepAlive
-	node.Postup = nodecfg.PostUp
-	node.Postdown = nodecfg.PostDown
-	node.Publickey = nodecfg.PublicKey
-	node.Macaddress = nodecfg.MacAddress
-	node.Endpoint = nodecfg.Endpoint
-	node.Password = nodecfg.Password
-        if nodecfg.DNS == "on" {
-                node.Dnsoff = true
-        } else {
-                node.Dnsoff = false
-        }
-	if nodecfg.IsDualStack == "yes" {
-		node.Isdualstack = true
-	} else {
-		node.Isdualstack = false
-	}
-        if nodecfg.IsIngressGateway == "yes" {
-                node.Isingressgateway = true
-        } else {
-                node.Isingressgateway = false
-        }
-        return node
+	return modcfg.Node
 }
 
 func Uninstall() error {
@@ -270,7 +244,7 @@ func Uninstall() error {
 		for _, network := range networks {
 			err = LeaveNetwork(network)
 			if err != nil {
-				log.Println("Encounter issue leaving network " + network + ": ", err)
+				log.Println("Encounter issue leaving network "+network+": ", err)
 			}
 		}
 	}
@@ -278,40 +252,40 @@ func Uninstall() error {
 }
 
 func LeaveNetwork(network string) error {
-        //need to  implement checkin on server side
-        cfg, err := config.ReadConfig(network)
-        if err != nil {
-                return err
-        }
+	//need to  implement checkin on server side
+	cfg, err := config.ReadConfig(network)
+	if err != nil {
+		return err
+	}
 	servercfg := cfg.Server
-        node := cfg.Node
+	node := cfg.Node
 
-        var wcclient nodepb.NodeServiceClient
-        var requestOpts grpc.DialOption
-        requestOpts = grpc.WithInsecure()
-        if cfg.Server.GRPCSSL == "on" {
-                h2creds := credentials.NewTLS(&tls.Config{NextProtos: []string{"h2"}})
-                requestOpts = grpc.WithTransportCredentials(h2creds)
-        }
-        conn, err := grpc.Dial(servercfg.GRPCAddress, requestOpts)
+	var wcclient nodepb.NodeServiceClient
+	var requestOpts grpc.DialOption
+	requestOpts = grpc.WithInsecure()
+	if cfg.Server.GRPCSSL == "on" {
+		h2creds := credentials.NewTLS(&tls.Config{NextProtos: []string{"h2"}})
+		requestOpts = grpc.WithTransportCredentials(h2creds)
+	}
+	conn, err := grpc.Dial(servercfg.GRPCAddress, requestOpts)
 	if err != nil {
-                log.Printf("Unable to establish client connection to " + servercfg.GRPCAddress + ": %v", err)
-        }else {
+		log.Printf("Unable to establish client connection to "+servercfg.GRPCAddress+": %v", err)
+	} else {
 		wcclient = nodepb.NewNodeServiceClient(conn)
 
 		ctx := context.Background()
 		ctx, err = auth.SetJWT(wcclient, network)
 		if err != nil {
-                log.Printf("Failed to authenticate: %v", err)
+			log.Printf("Failed to authenticate: %v", err)
 		} else {
 			var header metadata.MD
 			_, err = wcclient.DeleteNode(
-			ctx,
-			&nodepb.DeleteNodeReq{
-				Macaddress: node.MacAddress,
-				NetworkName: node.Network,
-			},
-			grpc.Header(&header),
+				ctx,
+				&nodepb.Object{
+					Data: node.ID,
+					Type: nodepb.STRING_TYPE,
+				},
+				grpc.Header(&header),
 			)
 			if err != nil {
 				log.Printf("Encountered error deleting node: %v", err)
@@ -323,41 +297,40 @@ func LeaveNetwork(network string) error {
 	}
 	err = local.WipeLocal(network)
 	if err != nil {
-                log.Printf("Unable to wipe local config: %v", err)
+		log.Printf("Unable to wipe local config: %v", err)
 	} else {
 		log.Println("Removed " + node.Network + " network locally")
 	}
 	if cfg.Daemon != "off" {
-		err =  local.RemoveSystemDServices(network)
+		err = local.RemoveSystemDServices(network)
 	}
 	return err
 }
 
-func DeleteInterface(ifacename string, postdown string) error{
-        ipExec, err := exec.LookPath("ip")
+func DeleteInterface(ifacename string, postdown string) error {
+	ipExec, err := exec.LookPath("ip")
 
-        cmdIPLinkDel := &exec.Cmd {
-                Path: ipExec,
-                Args: []string{ ipExec, "link", "del", ifacename },
-                Stdout: os.Stdout,
-                Stderr: os.Stdout,
-        }
-        err = cmdIPLinkDel.Run()
-        if  err  !=  nil {
-                log.Println(err)
-        }
-        if postdown != "" {
-                runcmds := strings.Split(postdown, "; ")
-                err = local.RunCmds(runcmds)
-                if err != nil {
-                        log.Println("Error encountered running PostDown: " + err.Error())
-                }
-        }
-        return err
+	cmdIPLinkDel := &exec.Cmd{
+		Path:   ipExec,
+		Args:   []string{ipExec, "link", "del", ifacename},
+		Stdout: os.Stdout,
+		Stderr: os.Stdout,
+	}
+	err = cmdIPLinkDel.Run()
+	if err != nil {
+		log.Println(err)
+	}
+	if postdown != "" {
+		runcmds := strings.Split(postdown, "; ")
+		err = local.RunCmds(runcmds)
+		if err != nil {
+			log.Println("Error encountered running PostDown: " + err.Error())
+		}
+	}
+	return err
 }
 
-
-func List() error{
+func List() error {
 
 	networks, err := GetNetworks()
 	if err != nil {
@@ -366,36 +339,34 @@ func List() error{
 	for _, network := range networks {
 		cfg, err := config.ReadConfig(network)
 		if err == nil {
-			//cfg2 := *cfg
-			listconfig := &config.ListConfig{
-					Name: cfg.Node.Name,
-					Interface: cfg.Node.Interface,
-					PrivateIPv4: cfg.Node.WGAddress,
-					PrivateIPv6: cfg.Node.WGAddress6,
-					PublicEndpoint: cfg.Node.Endpoint,
-				}
-			jsoncfg, _ := json.Marshal(listconfig)
+			jsoncfg, _ := json.Marshal(
+				map[string]string{
+					"Name":           cfg.Node.Name,
+					"Interface":      cfg.Node.Interface,
+					"PrivateIPv4":    cfg.Node.Address,
+					"PrivateIPv6":    cfg.Node.Address6,
+					"PublicEndpoint": cfg.Node.Endpoint,
+				})
 			log.Println(network + ": " + string(jsoncfg))
 		} else {
 			log.Println(network + ": Could not retrieve network configuration.")
 		}
 	}
 	return nil
-
 }
 
 func GetNetworks() ([]string, error) {
-        var networks []string
-        files, err := ioutil.ReadDir("/etc/netclient")
-        if err != nil {
-                return networks, err
-        }
-        for _, f := range files {
-                if strings.Contains(f.Name(), "netconfig-") && !strings.Contains(f.Name(), "global-001"){
-                        networkname := stringAfter(f.Name(), "netconfig-")
-                        networks = append(networks, networkname)
-                }
-        }
+	var networks []string
+	files, err := ioutil.ReadDir("/etc/netclient")
+	if err != nil {
+		return networks, err
+	}
+	for _, f := range files {
+		if strings.Contains(f.Name(), "netconfig-") && !strings.Contains(f.Name(), "global-001") {
+			networkname := stringAfter(f.Name(), "netconfig-")
+			networks = append(networks, networkname)
+		}
+	}
 	return networks, err
 }
 

+ 48 - 39
netclient/functions/join.go

@@ -3,6 +3,7 @@ package functions
 import (
 	"context"
 	"crypto/tls"
+	"encoding/json"
 	"errors"
 	"fmt"
 	"log"
@@ -11,6 +12,8 @@ import (
 	"time"
 
 	nodepb "github.com/gravitl/netmaker/grpc"
+	"github.com/gravitl/netmaker/models"
+	"github.com/gravitl/netmaker/netclient/auth"
 	"github.com/gravitl/netmaker/netclient/config"
 	"github.com/gravitl/netmaker/netclient/local"
 	"github.com/gravitl/netmaker/netclient/server"
@@ -22,7 +25,7 @@ import (
 	//homedir "github.com/mitchellh/go-homedir"
 )
 
-func JoinNetwork(cfg config.ClientConfig) error {
+func JoinNetwork(cfg config.ClientConfig, privateKey string) error {
 
 	hasnet := local.HasNetwork(cfg.Network)
 	if hasnet {
@@ -101,11 +104,11 @@ func JoinNetwork(cfg config.ClientConfig) error {
 	if cfg.Node.Password == "" {
 		cfg.Node.Password = GenPass()
 	}
+	auth.StoreSecret(cfg.Node.Password, cfg.Node.Network)
 	if cfg.Node.Endpoint == "" {
 		if cfg.Node.IsLocal == "yes" && cfg.Node.LocalAddress != "" {
 			cfg.Node.Endpoint = cfg.Node.LocalAddress
 		} else {
-
 			cfg.Node.Endpoint, err = getPublicIP()
 			if err != nil {
 				fmt.Println("Error setting cfg.Node.Endpoint.")
@@ -115,13 +118,13 @@ func JoinNetwork(cfg config.ClientConfig) error {
 	} else {
 		cfg.Node.Endpoint = cfg.Node.Endpoint
 	}
-	if cfg.Node.PrivateKey == "" {
-		privatekey, err := wgtypes.GeneratePrivateKey()
+	if privateKey == "" {
+		wgPrivatekey, err := wgtypes.GeneratePrivateKey()
 		if err != nil {
 			log.Fatal(err)
 		}
-		cfg.Node.PrivateKey = privatekey.String()
-		cfg.Node.PublicKey = privatekey.PublicKey().String()
+		privateKey = wgPrivatekey.String()
+		cfg.Node.PublicKey = wgPrivatekey.PublicKey().String()
 	}
 
 	if cfg.Node.MacAddress == "" {
@@ -134,8 +137,8 @@ func JoinNetwork(cfg config.ClientConfig) error {
 			cfg.Node.MacAddress = macs[0]
 		}
 	}
-	if cfg.Node.Port == 0 {
-		cfg.Node.Port, err = GetFreePort(51821)
+	if cfg.Node.ListenPort == 0 {
+		cfg.Node.ListenPort, err = GetFreePort(51821)
 		if err != nil {
 			fmt.Printf("Error retrieving port: %v", err)
 		}
@@ -155,59 +158,65 @@ func JoinNetwork(cfg config.ClientConfig) error {
 
 	wcclient = nodepb.NewNodeServiceClient(conn)
 
-	postnode := &nodepb.Node{
-		Password:     cfg.Node.Password,
-		Macaddress:   cfg.Node.MacAddress,
-		Accesskey:    cfg.Server.AccessKey,
-		Nodenetwork:  cfg.Network,
-		Listenport:   cfg.Node.Port,
-		Postup:       cfg.Node.PostUp,
-		Postdown:     cfg.Node.PostDown,
-		Keepalive:    cfg.Node.KeepAlive,
-		Localaddress: cfg.Node.LocalAddress,
-		Interface:    cfg.Node.Interface,
-		Publickey:    cfg.Node.PublicKey,
-		Name:         cfg.Node.Name,
-		Endpoint:     cfg.Node.Endpoint,
-		Saveconfig:     cfg.Node.SaveConfig,
-		Udpholepunch:     cfg.Node.UDPHolePunch,
+	postnode := &models.Node{
+		Password:            cfg.Node.Password,
+		MacAddress:          cfg.Node.MacAddress,
+		AccessKey:           cfg.Server.AccessKey,
+		Network:             cfg.Network,
+		ListenPort:          cfg.Node.ListenPort,
+		PostUp:              cfg.Node.PostUp,
+		PostDown:            cfg.Node.PostDown,
+		PersistentKeepalive: cfg.Node.PersistentKeepalive,
+		LocalAddress:        cfg.Node.LocalAddress,
+		Interface:           cfg.Node.Interface,
+		PublicKey:           cfg.Node.PublicKey,
+		Name:                cfg.Node.Name,
+		Endpoint:            cfg.Node.Endpoint,
+		SaveConfig:          cfg.Node.SaveConfig,
+		UDPHolePunch:        cfg.Node.UDPHolePunch,
+	}
+	if err = config.ModConfig(postnode); err != nil {
+		return err
 	}
-	err = config.ModConfig(postnode)
+	data, err := json.Marshal(&postnode)
 	if err != nil {
 		return err
 	}
 
 	res, err := wcclient.CreateNode(
 		context.TODO(),
-		&nodepb.CreateNodeReq{
-			Node: postnode,
+		&nodepb.Object{
+			Data: string(data),
+			Type: nodepb.NODE_TYPE,
 		},
 	)
 	if err != nil {
 		return err
 	}
 	log.Println("node created on remote server...updating configs")
-	node := res.Node
-	if err != nil {
+
+	nodeData := res.Data
+	var node models.Node
+	if err = json.Unmarshal([]byte(nodeData), &node); err != nil {
 		return err
 	}
 
-	if node.Dnsoff == true {
-		cfg.Node.DNS = "yes"
+	if node.DNSOn == "yes" {
+		cfg.Node.DNSOn = "yes"
 	}
-	if !(cfg.Node.IsLocal == "yes") && node.Islocal && node.Localrange != "" {
-		node.Localaddress, err = getLocalIP(node.Localrange)
+	if !(cfg.Node.IsLocal == "yes") && node.IsLocal == "yes" && node.LocalRange != "" {
+		node.LocalAddress, err = getLocalIP(node.LocalRange)
 		if err != nil {
 			return err
 		}
-		node.Endpoint = node.Localaddress
+		node.Endpoint = node.LocalAddress
 	}
-	err = config.ModConfig(node)
+	err = config.ModConfig(&node)
 	if err != nil {
 		return err
 	}
 
-	if node.Ispending {
+	if node.IsPending == "yes" {
 		fmt.Println("Node is marked as PENDING.")
 		fmt.Println("Awaiting approval from Admin before configuring WireGuard.")
 		if cfg.Daemon != "off" {
@@ -216,18 +225,18 @@ func JoinNetwork(cfg config.ClientConfig) error {
 		}
 	}
 	log.Println("retrieving remote peers")
-	peers, hasGateway, gateways, err := server.GetPeers(node.Macaddress, cfg.Network, cfg.Server.GRPCAddress, node.Isdualstack, node.Isingressgateway)
+	peers, hasGateway, gateways, err := server.GetPeers(node.MacAddress, cfg.Network, cfg.Server.GRPCAddress, node.IsDualStack == "yes", node.IsIngressGateway == "yes")
 
 	if err != nil {
 		log.Println("failed to retrieve peers")
 		return err
 	}
-	err = wireguard.StorePrivKey(cfg.Node.PrivateKey, cfg.Network)
+	err = wireguard.StorePrivKey(privateKey, cfg.Network)
 	if err != nil {
 		return err
 	}
 	log.Println("starting wireguard")
-	err = wireguard.InitWireguard(node, cfg.Node.PrivateKey, peers, hasGateway, gateways)
+	err = wireguard.InitWireguard(&node, privateKey, peers, hasGateway, gateways)
 	if err != nil {
 		return err
 	}

+ 49 - 49
netclient/functions/register.go

@@ -1,95 +1,95 @@
 package functions
 
 import (
-	"time"
-	"os"
-	"net"
-	"log"
-	"io/ioutil"
 	"bytes"
-        "github.com/gravitl/netmaker/netclient/config"
-        "github.com/gravitl/netmaker/netclient/local"
-        "github.com/gravitl/netmaker/netclient/wireguard"
-        "github.com/gravitl/netmaker/models"
 	"encoding/json"
-	"net/http"
 	"errors"
-//	"github.com/davecgh/go-spew/spew"
+	"io/ioutil"
+	"log"
+	"net"
+	"net/http"
+	"os"
+	"time"
+
+	"github.com/gravitl/netmaker/models"
+	"github.com/gravitl/netmaker/netclient/config"
+	"github.com/gravitl/netmaker/netclient/local"
+	//	"github.com/davecgh/go-spew/spew"
 )
 
 func Register(cfg config.GlobalConfig) error {
 
 	_, err := os.Stat("/etc/netclient")
-        if os.IsNotExist(err) {
-                os.Mkdir("/etc/netclient", 744)
-        } else if err != nil {
-                log.Println("couldnt find or create /etc/netclient")
-                return err
-        }
+	if os.IsNotExist(err) {
+		os.Mkdir("/etc/netclient", 744)
+	} else if err != nil {
+		log.Println("couldnt find or create /etc/netclient")
+		return err
+	}
 
-        postclient := &models.IntClient{
-                AccessKey: cfg.Client.AccessKey,
-                PublicKey: cfg.Client.PublicKey,
-                PrivateKey: cfg.Client.PublicKey,
-		Address: cfg.Client.Address,
-		Address6: cfg.Client.Address6,
-		Network: "comms",
+	postclient := &models.IntClient{
+		AccessKey:  cfg.Client.AccessKey,
+		PublicKey:  cfg.Client.PublicKey,
+		PrivateKey: cfg.Client.PublicKey,
+		Address:    cfg.Client.Address,
+		Address6:   cfg.Client.Address6,
+		Network:    "comms",
 	}
 
 	jsonstring, err := json.Marshal(postclient)
-        if err != nil {
-                return err
-        }
+	if err != nil {
+		return err
+	}
 	jsonbytes := []byte(jsonstring)
 	body := bytes.NewBuffer(jsonbytes)
 	publicaddress := net.JoinHostPort(cfg.Client.ServerPublicEndpoint, cfg.Client.ServerAPIPort)
 
-	res, err := http.Post("http://"+publicaddress+"/api/intclient/register","application/json",body)
-        if err != nil {
-		log.Println("Failed to register to http://"+publicaddress+"/api/client/register")
-                return err
-        }
+	res, err := http.Post("http://"+publicaddress+"/api/intclient/register", "application/json", body)
+	if err != nil {
+		log.Println("Failed to register to http://" + publicaddress + "/api/client/register")
+		return err
+	}
 	if res.StatusCode != http.StatusOK {
-		log.Println("Failed to register to http://"+publicaddress+"/api/client/register")
+		log.Println("Failed to register to http://" + publicaddress + "/api/client/register")
 		return errors.New("request to server failed: " + res.Status)
 	}
 	bodyBytes, err := ioutil.ReadAll(res.Body)
-        //bodyString := string(bodyBytes)
+	//bodyString := string(bodyBytes)
 	//spew.Dump(bodyString)
 	if err != nil {
 		return err
 	}
 	var wgclient models.IntClient
 	json.Unmarshal(bodyBytes, &wgclient)
-        //spew.Dump(wgclient)
+	//spew.Dump(wgclient)
 	err = config.ModGlobalConfig(wgclient)
-        if err != nil {
-                return err
-        }
-        //spew.Dump(wgclient)
-	err = wireguard.InitGRPCWireguard(wgclient)
-        if err != nil {
-                return err
-        }
+	if err != nil {
+		return err
+	}
+	//spew.Dump(wgclient)
+	// err = wireguard.InitGRPCWireguard(wgclient)
+	//     if err != nil {
+	//             return err
+	//     }
 	log.Println("registered netclient to " + cfg.Client.ServerPrivateAddress)
 	return err
 }
 
 func Unregister(cfg config.GlobalConfig) error {
-	client := &http.Client{ Timeout: 7 * time.Second,}
+	client := &http.Client{Timeout: 7 * time.Second}
 	publicaddress := net.JoinHostPort(cfg.Client.ServerPublicEndpoint, cfg.Client.ServerAPIPort)
-	log.Println("sending delete request to: " + "http://"+publicaddress+"/api/intclient/"+cfg.Client.ClientID)
+	log.Println("sending delete request to: " + "http://" + publicaddress + "/api/intclient/" + cfg.Client.ClientID)
 	req, err := http.NewRequest("DELETE", "http://"+publicaddress+"/api/intclient/"+cfg.Client.ClientID, nil)
 	if err != nil {
-                log.Println(err)
-        } else {
+		log.Println(err)
+	} else {
 		res, err := client.Do(req)
 		if res == nil {
-	                err = errors.New("server not reachable at " + "http://"+publicaddress+"/api/intclient/"+cfg.Client.ClientID)
+			err = errors.New("server not reachable at " + "http://" + publicaddress + "/api/intclient/" + cfg.Client.ClientID)
 			log.Println(err)
 		} else if res.StatusCode != http.StatusOK {
 			err = errors.New("request to server failed: " + res.Status)
-	                log.Println(err)
+			log.Println(err)
 			defer res.Body.Close()
 		}
 	}

+ 44 - 44
netclient/local/dns.go

@@ -4,56 +4,56 @@ import (
 	"io/ioutil"
 	"os"
 	"strings"
+
 	//"github.com/davecgh/go-spew/spew"
-        "log"
-        "os/exec"
+	"log"
+	"os/exec"
 )
 
 func SetDNS(nameserver string) error {
-        bytes, err := ioutil.ReadFile("/etc/resolv.conf")
-        if err != nil {
-                return err
-        }
-        resolvstring := string(bytes)
-        // //check whether s contains substring text
-        hasdns := strings.Contains(resolvstring, nameserver)
-        if hasdns {
-                return nil
-        }
-        resolv, err := os.OpenFile("/etc/resolv.conf",os.O_APPEND|os.O_WRONLY, 0644)
-        if err != nil {
-                return err
-        }
-        defer resolv.Close()
-        _, err = resolv.WriteString("nameserver " + nameserver + "\n")
+	bytes, err := ioutil.ReadFile("/etc/resolv.conf")
+	if err != nil {
+		return err
+	}
+	resolvstring := string(bytes)
+	// //check whether s contains substring text
+	hasdns := strings.Contains(resolvstring, nameserver)
+	if hasdns {
+		return nil
+	}
+	resolv, err := os.OpenFile("/etc/resolv.conf", os.O_APPEND|os.O_WRONLY, 0644)
+	if err != nil {
+		return err
+	}
+	defer resolv.Close()
+	_, err = resolv.WriteString("nameserver " + nameserver + "\n")
 
-        return err
+	return err
 }
 
-
 func UpdateDNS(ifacename string, network string, nameserver string) error {
-                _, err := exec.LookPath("resolvectl")
-                if err != nil {
-                        log.Println(err)
-                        log.Println("WARNING: resolvectl not present. Unable to set dns. Install resolvectl or run manually.")
-                } else {
-                        _, err = exec.Command("resolvectl", "domain", ifacename, "~"+network).Output()
-                        if err != nil {
-                                log.Println(err)
-                                log.Println("WARNING: Error encountered setting domain on dns. Aborted setting dns.")
-                        } else {
-                                _, err = exec.Command("resolvectl", "default-route", ifacename, "false").Output()
-                                if err != nil {
-                                        log.Println(err)
-                                        log.Println("WARNING: Error encountered setting default-route on dns. Aborted setting dns.")
-                                } else {
-                                        _, err = exec.Command("resolvectl", "dns", ifacename, nameserver).Output()
-                                        if err!= nil {
-						log.Println("WARNING: Error encountered running resolvectl dns " + ifacename + " " + nameserver)
-						log.Println(err)
-					}
-                                }
-                        }
-                }
-		return err
+	_, err := exec.LookPath("resolvectl")
+	if err != nil {
+		log.Println(err)
+		log.Println("WARNING: resolvectl not present. Unable to set dns. Install resolvectl or run manually.")
+	} else {
+		_, err = RunCmd("resolvectl domain " + ifacename + " ~" + network)
+		if err != nil {
+			log.Println(err)
+			log.Println("WARNING: Error encountered setting domain on dns. Aborted setting dns.")
+		} else {
+			_, err = RunCmd("resolvectl default-route " + ifacename + " false")
+			if err != nil {
+				log.Println(err)
+				log.Println("WARNING: Error encountered setting default-route on dns. Aborted setting dns.")
+			} else {
+				_, err = RunCmd("resolvectl dns " + ifacename + " " + nameserver)
+				if err != nil {
+					log.Println("WARNING: Error encountered running resolvectl dns " + ifacename + " " + nameserver)
+					log.Println(err)
+				}
+			}
+		}
+	}
+	return err
 }

+ 229 - 227
netclient/local/local.go

@@ -1,83 +1,122 @@
 package local
 
 import (
-        //"github.com/davecgh/go-spew/spew"
+	//"github.com/davecgh/go-spew/spew"
 	"errors"
-	"github.com/gravitl/netmaker/netclient/config"
+	"io"
+	"io/ioutil"
 	"log"
-        "io/ioutil"
+	"os"
+	"os/exec"
 	"path/filepath"
-        "io"
+	"runtime"
 	"strings"
-        "os"
-        "os/exec"
+
+	"github.com/gravitl/netmaker/netclient/config"
 )
 
+func SetIPForwarding() error {
+	os := runtime.GOOS
+	var err error
+	switch os {
+	case "linux":
+		err = SetIPForwardingLinux()
+	default:
+		err = errors.New("This OS is not supported")
+	}
+	return err
+}
+
+func SetIPForwardingLinux() error {
+	out, err := RunCmd("sysctl net.ipv4.ip_forward")
+	if err != nil {
+		log.Println(err)
+		log.Println("WARNING: Error encountered setting ip forwarding. This can break functionality.")
+		return err
+	} else {
+		s := strings.Fields(string(out))
+		if s[2] != "1" {
+			_, err = RunCmd("sysctl -w net.ipv4.ip_forward=1")
+			if err != nil {
+				log.Println(err)
+				log.Println("WARNING: Error encountered setting ip forwarding. You may want to investigate this.")
+				return err
+			}
+		}
+	}
+	return nil
+}
+
+func RunCmd(command string) (string, error) {
+	args := strings.Fields(command)
+	out, err := exec.Command(args[0], args[1:]...).Output()
+	return string(out), err
+}
+
 func RunCmds(commands []string) error {
-        var err error
-        for _, command := range commands {
-                args := strings.Fields(command)
-                out, err := exec.Command(args[0], args[1:]...).Output()
-                if string(out) != "" {
+	var err error
+	for _, command := range commands {
+		args := strings.Fields(command)
+		out, err := exec.Command(args[0], args[1:]...).Output()
+		if string(out) != "" {
 			log.Println(string(out))
 		}
-                if err != nil {
-                        return err
-                }
-        }
-        return err
+		if err != nil {
+			return err
+		}
+	}
+	return err
 }
 
 func FileExists(f string) bool {
-    info, err := os.Stat(f)
-    if os.IsNotExist(err) {
-        return false
-    }
-    return !info.IsDir()
+	info, err := os.Stat(f)
+	if os.IsNotExist(err) {
+		return false
+	}
+	return !info.IsDir()
 }
 
 func ConfigureSystemD(network string) error {
 	/*
-	path, err := os.Getwd()
-	if err != nil {
-		log.Println(err)
-		return err
-	}
+		path, err := os.Getwd()
+		if err != nil {
+			log.Println(err)
+			return err
+		}
 	*/
 	//binarypath := path  + "/netclient"
 	dir, err := filepath.Abs(filepath.Dir(os.Args[0]))
 	if err != nil {
-            return err
+		return err
 	}
-	binarypath := dir  + "/netclient"
+	binarypath := dir + "/netclient"
 
 	_, err = os.Stat("/etc/netclient")
-        if os.IsNotExist(err) {
-                os.Mkdir("/etc/netclient", 744)
-        } else if err != nil {
-                log.Println("couldnt find or create /etc/netclient")
-                return err
-        }
-
-	if !FileExists("/usr/local/bin/netclient") {
-		os.Symlink("/etc/netclient/netclient","/usr/local/bin/netclient")
-	/*
-	_, err = copy(binarypath, "/usr/local/bin/netclient")
-	if err != nil {
-		log.Println(err)
+	if os.IsNotExist(err) {
+		os.Mkdir("/etc/netclient", 744)
+	} else if err != nil {
+		log.Println("couldnt find or create /etc/netclient")
 		return err
 	}
-	*/
+
+	if !FileExists("/usr/local/bin/netclient") {
+		os.Symlink("/etc/netclient/netclient", "/usr/local/bin/netclient")
+		/*
+			_, err = copy(binarypath, "/usr/local/bin/netclient")
+			if err != nil {
+				log.Println(err)
+				return err
+			}
+		*/
 	}
 	if !FileExists("/etc/netclient/netclient") {
-        _, err = copy(binarypath, "/etc/netclient/netclient")
-        if err != nil {
-                log.Println(err)
-                return err
-        }
+		_, err = copy(binarypath, "/etc/netclient/netclient")
+		if err != nil {
+			log.Println(err)
+			return err
+		}
 	}
 
-
 	systemservice := `[Unit]
 Description=network check for remote peers and local config
 Wants=netclient.timer
@@ -94,18 +133,18 @@ WantedBy=multi-user.target
 Description=Calls the Netmaker Mesh Client Service
 
 `
-systemtimer = systemtimer + "Requires=netclient@"+network+".service"
+	systemtimer = systemtimer + "Requires=netclient@" + network + ".service"
 
-systemtimer = systemtimer +
-`
+	systemtimer = systemtimer +
+		`
 
 [Timer]
 
 `
-systemtimer = systemtimer + "Unit=netclient@"+network+".service"
+	systemtimer = systemtimer + "Unit=netclient@" + network + ".service"
 
-systemtimer = systemtimer +
-`
+	systemtimer = systemtimer +
+		`
 
 OnCalendar=*:*:0/30
 
@@ -117,67 +156,41 @@ WantedBy=timers.target
 	timerbytes := []byte(systemtimer)
 
 	if !FileExists("/etc/systemd/system/[email protected]") {
-	err = ioutil.WriteFile("/etc/systemd/system/[email protected]", servicebytes, 0644)
-        if err != nil {
-                log.Println(err)
-                return err
-        }
-	}
-
-        if !FileExists("/etc/systemd/system/netclient-"+network+".timer") {
-        err = ioutil.WriteFile("/etc/systemd/system/netclient-"+network+".timer", timerbytes, 0644)
-        if err != nil {
-                log.Println(err)
-                return err
-        }
-	}
-        //sysExec, err := exec.LookPath("systemctl")
-
-        cmdSysEnableService := exec.Command("systemctl", "enable", "[email protected]")/*&exec.Cmd {
-                Path: sysExec,
-                Args: []string{ sysExec, "enable", "[email protected]" },
-                Stdout: os.Stdout,
-                Stderr: os.Stdout,
-        }*/
-        cmdSysDaemonReload := exec.Command("systemctl", "daemon-reload")/*&exec.Cmd {
-                Path: sysExec,
-                Args: []string{ sysExec, "daemon-reload"},
-                Stdout: os.Stdout,
-                Stderr: os.Stdout,
-        }*/
-        cmdSysEnableTimer := exec.Command("systemctl", "enable", "netclient-"+network+".timer")/*&exec.Cmd {
-                Path: sysExec,
-                Args: []string{ sysExec, "enable", "netclient-"+network+".timer" },
-                Stdout: os.Stdout,
-                Stderr: os.Stdout,
-        }*/
-        cmdSysStartTimer := exec.Command("systemctl", "start", "netclient-"+network+".timer")/*&exec.Cmd {
-                Path: sysExec,
-		Args: []string{ sysExec, "start", "netclient-"+network+".timer"},
-                Stdout: os.Stdout,
-                Stderr: os.Stdout,
-        }*/
-
-        err = cmdSysEnableService.Run()
-        if  err  !=  nil {
-                log.Println("Error enabling [email protected]. Please investigate.")
-                log.Println(err)
-        }
-        err = cmdSysDaemonReload.Run()
-        if  err  !=  nil {
-                log.Println("Error reloading system daemons. Please investigate.")
-                log.Println(err)
-        }
-        err = cmdSysEnableTimer.Run()
-        if  err  !=  nil {
-                log.Println("Error enabling netclient.timer. Please investigate.")
-                log.Println(err)
-        }
-        err = cmdSysStartTimer.Run()
-        if  err  !=  nil {
-                log.Println("Error starting netclient-"+network+".timer. Please investigate.")
-                log.Println(err)
-        }
+		err = ioutil.WriteFile("/etc/systemd/system/[email protected]", servicebytes, 0644)
+		if err != nil {
+			log.Println(err)
+			return err
+		}
+	}
+
+	if !FileExists("/etc/systemd/system/netclient-" + network + ".timer") {
+		err = ioutil.WriteFile("/etc/systemd/system/netclient-"+network+".timer", timerbytes, 0644)
+		if err != nil {
+			log.Println(err)
+			return err
+		}
+	}
+
+	_, err = RunCmd("systemctl enable [email protected]")
+	if err != nil {
+		log.Println("Error enabling [email protected]. Please investigate.")
+		log.Println(err)
+	}
+	_, err = RunCmd("systemctl daemon-reload")
+	if err != nil {
+		log.Println("Error reloading system daemons. Please investigate.")
+		log.Println(err)
+	}
+	_, err = RunCmd("systemctl enable netclient-" + network + ".timer")
+	if err != nil {
+		log.Println("Error enabling netclient.timer. Please investigate.")
+		log.Println(err)
+	}
+	_, err = RunCmd("systemctl start netclient-" + network + ".timer")
+	if err != nil {
+		log.Println("Error starting netclient-" + network + ".timer. Please investigate.")
+		log.Println(err)
+	}
 	return nil
 }
 
@@ -188,7 +201,7 @@ func isOnlyService(network string) (bool, error) {
 		return isonly, err
 	}
 	count := len(files)
-	if count  == 0 {
+	if count == 0 {
 		isonly = true
 	}
 	return isonly, err
@@ -196,78 +209,67 @@ func isOnlyService(network string) (bool, error) {
 }
 
 func RemoveSystemDServices(network string) error {
-        //sysExec, err := exec.LookPath("systemctl")
-
+	//sysExec, err := exec.LookPath("systemctl")
 
 	fullremove, err := isOnlyService(network)
 	if err != nil {
 		log.Println(err)
 	}
 
-	cmdSysDisableService := exec.Command("systemctl","disable","[email protected]")
-        cmdSysDaemonReload := exec.Command("systemctl","daemon-reload")
-        cmdSysResetFailed := exec.Command("systemctl","reset-failed")
-        cmdSysStopTimer := exec.Command("systemctl", "stop", "netclient-"+network+".timer")
-        cmdSysDisableTimer :=  exec.Command("systemctl", "disable", "netclient-"+network+".timer")
-        if  err  !=  nil {
-                log.Println("Error stopping [email protected]. Please investigate.")
-                log.Println(err)
-        }
 	if fullremove {
-        err = cmdSysDisableService.Run()
-        if  err  !=  nil {
-                log.Println("Error disabling [email protected]. Please investigate.")
-                log.Println(err)
-        }
-	}
-        err = cmdSysStopTimer.Run()
-        if  err  !=  nil {
-                log.Println("Error stopping netclient-"+network+".timer. Please investigate.")
-                log.Println(err)
-        }
-        err = cmdSysDisableTimer.Run()
-        if  err  !=  nil {
-                log.Println("Error disabling netclient-"+network+".timer. Please investigate.")
-                log.Println(err)
-        }
+		_, err = RunCmd("systemctl disable [email protected]")
+		if err != nil {
+			log.Println("Error disabling [email protected]. Please investigate.")
+			log.Println(err)
+		}
+	}
+	_, err = RunCmd("systemctl daemon-reload")
+	if err != nil {
+		log.Println("Error stopping netclient-" + network + ".timer. Please investigate.")
+		log.Println(err)
+	}
+	_, err = RunCmd("systemctl disable netclient-" + network + ".timer")
+	if err != nil {
+		log.Println("Error disabling netclient-" + network + ".timer. Please investigate.")
+		log.Println(err)
+	}
 	if fullremove {
 		if FileExists("/etc/systemd/system/[email protected]") {
 			err = os.Remove("/etc/systemd/system/[email protected]")
 		}
 	}
-	if FileExists("/etc/systemd/system/netclient-"+network+".timer") {
-		err = os.Remove("/etc/systemd/system/netclient-"+network+".timer")
+	if FileExists("/etc/systemd/system/netclient-" + network + ".timer") {
+		err = os.Remove("/etc/systemd/system/netclient-" + network + ".timer")
+	}
+	if err != nil {
+		log.Println("Error removing file. Please investigate.")
+		log.Println(err)
+	}
+	_, err = RunCmd("systemctl daemon-reload")
+	if err != nil {
+		log.Println("Error reloading system daemons. Please investigate.")
+		log.Println(err)
 	}
+	_, err = RunCmd("systemctl reset-failed")
 	if err != nil {
-                log.Println("Error removing file. Please investigate.")
-                log.Println(err)
-	}
-        err = cmdSysDaemonReload.Run()
-        if  err  !=  nil {
-                log.Println("Error reloading system daemons. Please investigate.")
-                log.Println(err)
-        }
-        err = cmdSysResetFailed.Run()
-        if  err  !=  nil {
-                log.Println("Error reseting failed system services. Please investigate.")
-                log.Println(err)
-        }
+		log.Println("Error reseting failed system services. Please investigate.")
+		log.Println(err)
+	}
 	return err
-
 }
 
-func WipeLocal(network string) error{
-        cfg, err := config.ReadConfig(network)
-        if err != nil {
-                return err
-        }
-        nodecfg := cfg.Node
-        ifacename := nodecfg.Interface
+func WipeLocal(network string) error {
+	cfg, err := config.ReadConfig(network)
+	if err != nil {
+		return err
+	}
+	nodecfg := cfg.Node
+	ifacename := nodecfg.Interface
 
-        //home, err := homedir.Dir()
-        home := "/etc/netclient"
+	//home, err := homedir.Dir()
+	home := "/etc/netclient"
 	if FileExists(home + "/netconfig-" + network) {
-	        _ = os.Remove(home + "/netconfig-" + network)
+		_ = os.Remove(home + "/netconfig-" + network)
 	}
 	if FileExists(home + "/nettoken-" + network) {
 		_ = os.Remove(home + "/nettoken-" + network)
@@ -276,79 +278,79 @@ func WipeLocal(network string) error{
 		_ = os.Remove(home + "/wgkey-" + network)
 	}
 
-        ipExec, err := exec.LookPath("ip")
-
-        if ifacename != "" {
-        cmdIPLinkDel := &exec.Cmd {
-                Path: ipExec,
-                Args: []string{ ipExec, "link", "del", ifacename },
-                Stdout: os.Stdout,
-                Stderr: os.Stdout,
-        }
-        err = cmdIPLinkDel.Run()
-        if  err  !=  nil {
-                log.Println(err)
-        }
-        if nodecfg.PostDown != "" {
-                runcmds := strings.Split(nodecfg.PostDown, "; ")
-                err = RunCmds(runcmds)
-                if err != nil {
-                        log.Println("Error encountered running PostDown: " + err.Error())
-                }
-        }
-        }
-        return err
+	ipExec, err := exec.LookPath("ip")
+
+	if ifacename != "" {
+		cmdIPLinkDel := &exec.Cmd{
+			Path:   ipExec,
+			Args:   []string{ipExec, "link", "del", ifacename},
+			Stdout: os.Stdout,
+			Stderr: os.Stdout,
+		}
+		err = cmdIPLinkDel.Run()
+		if err != nil {
+			log.Println(err)
+		}
+		if nodecfg.PostDown != "" {
+			runcmds := strings.Split(nodecfg.PostDown, "; ")
+			err = RunCmds(runcmds)
+			if err != nil {
+				log.Println("Error encountered running PostDown: " + err.Error())
+			}
+		}
+	}
+	return err
 
 }
 
-func WipeGRPCClient() error{
-        home := "/etc/netclient"
-        _ = os.Remove(home + "/netconfig-global-001")
+func WipeGRPCClient() error {
+	home := "/etc/netclient"
+	_ = os.Remove(home + "/netconfig-global-001")
 
 	ipExec, err := exec.LookPath("ip")
 
-        cmdIPLinkDel := &exec.Cmd {
-                Path: ipExec,
-                Args: []string{ ipExec, "link", "del", "grpc-wg-001" },
-                Stdout: os.Stdout,
-                Stderr: os.Stdout,
-        }
-        err = cmdIPLinkDel.Run()
-        return err
+	cmdIPLinkDel := &exec.Cmd{
+		Path:   ipExec,
+		Args:   []string{ipExec, "link", "del", "grpc-wg-001"},
+		Stdout: os.Stdout,
+		Stderr: os.Stdout,
+	}
+	err = cmdIPLinkDel.Run()
+	return err
 }
 
-func HasNetwork(network string) bool{
+func HasNetwork(network string) bool {
 
-return  FileExists("/etc/systemd/system/netclient-"+network+".timer") ||
-	FileExists("/etc/netclient/netconfig-"+network)
+	return FileExists("/etc/systemd/system/netclient-"+network+".timer") ||
+		FileExists("/etc/netclient/netconfig-"+network)
 
 }
 
 func copy(src, dst string) (int64, error) {
-        sourceFileStat, err := os.Stat(src)
-        if err != nil {
-                return 0, err
-        }
-
-        if !sourceFileStat.Mode().IsRegular() {
-                return 0, errors.New(src + " is not a regular file")
-        }
-
-        source, err := os.Open(src)
-        if err != nil {
-                return 0, err
-        }
-        defer source.Close()
-
-        destination, err := os.Create(dst)
-        if err != nil {
-                return 0, err
-        }
-        defer destination.Close()
-        nBytes, err := io.Copy(destination, source)
+	sourceFileStat, err := os.Stat(src)
+	if err != nil {
+		return 0, err
+	}
+
+	if !sourceFileStat.Mode().IsRegular() {
+		return 0, errors.New(src + " is not a regular file")
+	}
+
+	source, err := os.Open(src)
+	if err != nil {
+		return 0, err
+	}
+	defer source.Close()
+
+	destination, err := os.Create(dst)
+	if err != nil {
+		return 0, err
+	}
+	defer destination.Close()
+	nBytes, err := io.Copy(destination, source)
 	err = os.Chmod(dst, 0755)
 	if err != nil {
 		log.Println(err)
 	}
-        return nBytes, err
+	return nBytes, err
 }

+ 11 - 32
netclient/main.go

@@ -9,6 +9,7 @@ import (
 
 	"github.com/gravitl/netmaker/netclient/command"
 	"github.com/gravitl/netmaker/netclient/config"
+	"github.com/gravitl/netmaker/netclient/local"
 	"github.com/urfave/cli/v2"
 )
 
@@ -16,7 +17,7 @@ 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.Version = "v0.5.11"
+	app.Version = "v0.7.1"
 
 	cliFlags := []cli.Flag{
 		&cli.StringFlag{
@@ -30,7 +31,7 @@ func main() {
 			Name:    "password",
 			Aliases: []string{"p"},
 			EnvVars: []string{"NETCLIENT_PASSWORD"},
-			Value:   "badpassword",
+			Value:   "",
 			Usage:   "Password for authenticating with netmaker.",
 		},
 		&cli.StringFlag{
@@ -202,33 +203,12 @@ func main() {
 	}
 
 	app.Commands = []*cli.Command{
-		{
-			Name:  "register",
-			Usage: "Register with Netmaker Server for secure GRPC communications.",
-			Flags: cliFlags,
-			Action: func(c *cli.Context) error {
-				cfg, err := config.GetCLIConfigRegister(c)
-				if err != nil {
-					return err
-				}
-				if cfg.GRPCWireGuard == "off" {
-					log.Println("Server is not using WireGuard to secure GRPC. Skipping.")
-					return err
-				}
-				if cfg.Client.ServerPrivateAddress == "" {
-					err = errors.New("No server address provided.")
-					return err
-				}
-				err = command.Register(cfg)
-				return err
-			},
-		},
 		{
 			Name:  "join",
 			Usage: "Join a Netmaker network.",
 			Flags: cliFlags,
 			Action: func(c *cli.Context) error {
-				cfg, err := config.GetCLIConfig(c)
+				cfg, pvtKey, err := config.GetCLIConfig(c)
 				if err != nil {
 					return err
 				}
@@ -240,7 +220,7 @@ func main() {
 					err = errors.New("No server address provided.")
 					return err
 				}
-				err = command.Join(cfg)
+				err = command.Join(cfg, pvtKey)
 				return err
 			},
 		},
@@ -251,7 +231,7 @@ func main() {
 			// the action, or code that will be executed when
 			// we execute our `ns` command
 			Action: func(c *cli.Context) error {
-				cfg, err := config.GetCLIConfig(c)
+				cfg, _, err := config.GetCLIConfig(c)
 				if err != nil {
 					return err
 				}
@@ -266,7 +246,7 @@ func main() {
 			// the action, or code that will be executed when
 			// we execute our `ns` command
 			Action: func(c *cli.Context) error {
-				cfg, err := config.GetCLIConfig(c)
+				cfg, _, err := config.GetCLIConfig(c)
 				if err != nil {
 					return err
 				}
@@ -281,7 +261,7 @@ func main() {
 			// the action, or code that will be executed when
 			// we execute our `ns` command
 			Action: func(c *cli.Context) error {
-				cfg, err := config.GetCLIConfig(c)
+				cfg, _, err := config.GetCLIConfig(c)
 				if err != nil {
 					return err
 				}
@@ -296,7 +276,7 @@ func main() {
 			// the action, or code that will be executed when
 			// we execute our `ns` command
 			Action: func(c *cli.Context) error {
-				cfg, err := config.GetCLIConfig(c)
+				cfg, _, err := config.GetCLIConfig(c)
 				if err != nil {
 					return err
 				}
@@ -311,7 +291,7 @@ func main() {
 			// the action, or code that will be executed when
 			// we execute our `ns` command
 			Action: func(c *cli.Context) error {
-				cfg, err := config.GetCLIConfig(c)
+				cfg, _, err := config.GetCLIConfig(c)
 				if err != nil {
 					return err
 				}
@@ -356,8 +336,7 @@ func main() {
 	}
 
 	// start our application
-	getID := exec.Command("id", "-u")
-	out, err := getID.Output()
+	out, err := local.RunCmd("id -u")
 
 	if err != nil {
 		log.Fatal(err)

+ 294 - 319
netclient/server/grpc.go

@@ -1,376 +1,351 @@
 package server
 
 import (
-"github.com/davecgh/go-spew/spew"
-	"google.golang.org/grpc/credentials"
-        "crypto/tls"
-	"fmt"
-	"context"
+	"crypto/tls"
+	"encoding/json"
 	"log"
-	"strings"
-	"strconv"
 	"net"
+	"strconv"
+	"strings"
 	"time"
-	"io"
-        "golang.zx2c4.com/wireguard/wgctrl/wgtypes"
+
+	nodepb "github.com/gravitl/netmaker/grpc"
+	"github.com/gravitl/netmaker/models"
+	"github.com/gravitl/netmaker/netclient/auth"
 	"github.com/gravitl/netmaker/netclient/config"
-        "github.com/gravitl/netmaker/netclient/auth"
-        "github.com/gravitl/netmaker/netclient/local"
-        nodepb "github.com/gravitl/netmaker/grpc"
-        "google.golang.org/grpc"
+	"github.com/gravitl/netmaker/netclient/local"
+	"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
+	"google.golang.org/grpc"
+	"google.golang.org/grpc/credentials"
 	"google.golang.org/grpc/metadata"
-	//homedir "github.com/mitchellh/go-homedir"
 )
 
-func GetNode(network string) nodepb.Node {
-
-        modcfg, err := config.ReadConfig(network)
-        if err != nil {
-                log.Fatalf("Error: %v", err)
-        }
-
-	nodecfg := modcfg.Node
-	var node nodepb.Node
-
-	node.Name = nodecfg.Name
-	node.Interface = nodecfg.Interface
-	node.Nodenetwork = nodecfg.Network
-	node.Localaddress = nodecfg.LocalAddress
-	node.Address = nodecfg.WGAddress
-	node.Address6 = nodecfg.WGAddress6
-	node.Listenport = nodecfg.Port
-	node.Keepalive = nodecfg.KeepAlive
-	node.Postup = nodecfg.PostUp
-	node.Postdown = nodecfg.PostDown
-	node.Publickey = nodecfg.PublicKey
-	node.Macaddress = nodecfg.MacAddress
-	node.Endpoint = nodecfg.Endpoint
-	node.Password = nodecfg.Password
-	node.Saveconfig = nodecfg.SaveConfig
-	node.Udpholepunch = nodecfg.UDPHolePunch
-	if nodecfg.DNS == "on" {
-		node.Dnsoff = false
-	} else {
-		node.Dnsoff = true
+func getGrpcClient(cfg *config.ClientConfig) (nodepb.NodeServiceClient, error) {
+	servercfg := cfg.Server
+	var wcclient nodepb.NodeServiceClient
+	// == GRPC SETUP ==
+	var requestOpts grpc.DialOption
+	requestOpts = grpc.WithInsecure()
+	if cfg.Server.GRPCSSL == "on" {
+		h2creds := credentials.NewTLS(&tls.Config{NextProtos: []string{"h2"}})
+		requestOpts = grpc.WithTransportCredentials(h2creds)
+	}
+	conn, err := grpc.Dial(servercfg.GRPCAddress, requestOpts)
+	if err != nil {
+		return nil, err
 	}
-        if nodecfg.IsDualStack == "yes" {
-                node.Isdualstack = true
-        } else {
-                node.Isdualstack = false
-        }
-        if nodecfg.IsIngressGateway == "yes" {
-                node.Isingressgateway= true
-        } else {
-                node.Isingressgateway = false
-        }
-        return node
+	wcclient = nodepb.NewNodeServiceClient(conn)
+	return wcclient, nil
 }
 
-
+func CheckIn(network string) (*models.Node, error) {
+	cfg, err := config.ReadConfig(network)
+	if err != nil {
+		return nil, err
+	}
+	node := cfg.Node
+	wcclient, err := getGrpcClient(cfg)
+	if err != nil {
+		return nil, err
+	}
+	// == run client action ==
+	var header metadata.MD
+	ctx, err := auth.SetJWT(wcclient, network)
+	nodeData, err := json.Marshal(&node)
+	if err != nil {
+		return nil, err
+	}
+	response, err := wcclient.ReadNode(
+		ctx,
+		&nodepb.Object{
+			Data: string(nodeData),
+			Type: nodepb.NODE_TYPE,
+		},
+		grpc.Header(&header),
+	)
+	if err != nil {
+		log.Printf("Encountered error checking in node: %v", err)
+	}
+	if err = json.Unmarshal([]byte(response.GetData()), &node); err != nil {
+		return nil, err
+	}
+	return &node, err
+}
 
 func RemoveNetwork(network string) error {
-        //need to  implement checkin on server side
-        cfg, err := config.ReadConfig(network)
-        if err != nil {
-                return err
-        }
+	//need to  implement checkin on server side
+	cfg, err := config.ReadConfig(network)
+	if err != nil {
+		return err
+	}
 	servercfg := cfg.Server
-        node := cfg.Node
-	fmt.Println("Deleting remote node with MAC: " + node.MacAddress)
+	node := cfg.Node
+	log.Println("Deleting remote node with MAC: " + node.MacAddress)
 
-        var wcclient nodepb.NodeServiceClient
-        var requestOpts grpc.DialOption
-        requestOpts = grpc.WithInsecure()
-        if cfg.Server.GRPCSSL == "on" {
-                h2creds := credentials.NewTLS(&tls.Config{NextProtos: []string{"h2"}})
-                requestOpts = grpc.WithTransportCredentials(h2creds)
-        }
-        conn, err := grpc.Dial(servercfg.GRPCAddress, requestOpts)
+	var wcclient nodepb.NodeServiceClient
+	var requestOpts grpc.DialOption
+	requestOpts = grpc.WithInsecure()
+	if cfg.Server.GRPCSSL == "on" {
+		h2creds := credentials.NewTLS(&tls.Config{NextProtos: []string{"h2"}})
+		requestOpts = grpc.WithTransportCredentials(h2creds)
+	}
+	conn, err := grpc.Dial(servercfg.GRPCAddress, requestOpts)
 	if err != nil {
-                log.Printf("Unable to establish client connection to " + servercfg.GRPCAddress + ": %v", err)
+		log.Printf("Unable to establish client connection to "+servercfg.GRPCAddress+": %v", err)
 		//return err
-        }else {
-        wcclient = nodepb.NewNodeServiceClient(conn)
-
-        ctx := context.Background()
-        ctx, err = auth.SetJWT(wcclient, network)
-        if err != nil {
-                //return err
-                log.Printf("Failed to authenticate: %v", err)
-        } else {
+	} else {
+		wcclient = nodepb.NewNodeServiceClient(conn)
+		ctx, err := auth.SetJWT(wcclient, network)
+		if err != nil {
+			//return err
+			log.Printf("Failed to authenticate: %v", err)
+		} else {
 
-        var header metadata.MD
+			var header metadata.MD
 
-        _, err = wcclient.DeleteNode(
-                ctx,
-                &nodepb.DeleteNodeReq{
-                        Macaddress: node.MacAddress,
-                        NetworkName: node.Network,
-                },
-                grpc.Header(&header),
-        )
-        if err != nil {
-		log.Printf("Encountered error deleting node: %v", err)
-		fmt.Println(err)
-        } else {
-		fmt.Println("Deleted node " + node.MacAddress)
-	}
-	}
+			_, err = wcclient.DeleteNode(
+				ctx,
+				&nodepb.Object{
+					Data: node.MacAddress + "###" + node.Network,
+					Type: nodepb.STRING_TYPE,
+				},
+				grpc.Header(&header),
+			)
+			if err != nil {
+				log.Printf("Encountered error deleting node: %v", err)
+				log.Println(err)
+			} else {
+				log.Println("Deleted node " + node.MacAddress)
+			}
+		}
 	}
 	err = local.WipeLocal(network)
 	if err != nil {
-                log.Printf("Unable to wipe local config: %v", err)
+		log.Printf("Unable to wipe local config: %v", err)
 	}
 	if cfg.Daemon != "off" {
-		err =  local.RemoveSystemDServices(network)
+		err = local.RemoveSystemDServices(network)
 	}
 	return err
 }
 
 func GetPeers(macaddress string, network string, server string, dualstack bool, isIngressGateway bool) ([]wgtypes.PeerConfig, bool, []string, error) {
-        //need to  implement checkin on server side
-        hasGateway := false
-        var gateways []string
-        var peers []wgtypes.PeerConfig
-        var wcclient nodepb.NodeServiceClient
-        cfg, err := config.ReadConfig(network)
-        if err != nil {
-                log.Fatalf("Issue retrieving config for network: " + network +  ". Please investigate: %v", err)
-        }
-        nodecfg := cfg.Node
-        keepalive := nodecfg.KeepAlive
-        keepalivedur, err := time.ParseDuration(strconv.FormatInt(int64(keepalive), 10) + "s")
-        keepaliveserver, err := time.ParseDuration(strconv.FormatInt(int64(5), 10) + "s")
-        if err != nil {
-                log.Fatalf("Issue with format of keepalive value. Please update netconfig: %v", err)
-        }
-
+	//need to  implement checkin on server side
+	hasGateway := false
+	var gateways []string
+	var peers []wgtypes.PeerConfig
+	var wcclient nodepb.NodeServiceClient
+	cfg, err := config.ReadConfig(network)
+	if err != nil {
+		log.Fatalf("Issue retrieving config for network: "+network+". Please investigate: %v", err)
+	}
+	nodecfg := cfg.Node
+	keepalive := nodecfg.PersistentKeepalive
+	keepalivedur, err := time.ParseDuration(strconv.FormatInt(int64(keepalive), 10) + "s")
+	keepaliveserver, err := time.ParseDuration(strconv.FormatInt(int64(5), 10) + "s")
+	if err != nil {
+		log.Fatalf("Issue with format of keepalive value. Please update netconfig: %v", err)
+	}
 
-        requestOpts := grpc.WithInsecure()
-        if cfg.Server.GRPCSSL == "on" {
-                h2creds := credentials.NewTLS(&tls.Config{NextProtos: []string{"h2"}})
-                requestOpts = grpc.WithTransportCredentials(h2creds)
-        }
+	requestOpts := grpc.WithInsecure()
+	if cfg.Server.GRPCSSL == "on" {
+		h2creds := credentials.NewTLS(&tls.Config{NextProtos: []string{"h2"}})
+		requestOpts = grpc.WithTransportCredentials(h2creds)
+	}
 
 	conn, err := grpc.Dial(server, requestOpts)
-        if err != nil {
-                log.Fatalf("Unable to establish client connection to localhost:50051: %v", err)
-        }
-        // Instantiate the BlogServiceClient with our client connection to the server
-        wcclient = nodepb.NewNodeServiceClient(conn)
+	if err != nil {
+		log.Fatalf("Unable to establish client connection to localhost:50051: %v", err)
+	}
+	// Instantiate the BlogServiceClient with our client connection to the server
+	wcclient = nodepb.NewNodeServiceClient(conn)
 
-        req := &nodepb.GetPeersReq{
-                Macaddress: macaddress,
-                Network: network,
-        }
-        ctx := context.Background()
-        ctx, err = auth.SetJWT(wcclient, network)
-        if err != nil {
-                log.Println("Failed to authenticate.")
-                return peers, hasGateway, gateways, err
-        }
-        var header metadata.MD
+	req := &nodepb.Object{
+		Data: macaddress + "###" + network,
+		Type: nodepb.STRING_TYPE,
+	}
 
-        stream, err := wcclient.GetPeers(ctx, req, grpc.Header(&header))
-        if err != nil {
-                log.Println("Error retrieving peers")
-                log.Println(err)
-                return nil, hasGateway, gateways, err
-        }
-        for {
-                res, err := stream.Recv()
-                // If end of stream, break the loop
+	ctx, err := auth.SetJWT(wcclient, network)
+	if err != nil {
+		log.Println("Failed to authenticate.")
+		return peers, hasGateway, gateways, err
+	}
+	var header metadata.MD
 
-                if err == io.EOF {
-                        break
-                }
-                // if err, return an error
-                if err != nil {
-                        if strings.Contains(err.Error(), "mongo: no documents in result") {
-                                continue
-                        } else {
-                        fmt.Println("ERROR ENCOUNTERED WITH RESPONSE")
-                        fmt.Println(res)
-                        return peers, hasGateway, gateways, err
-                        }
-                }
-	        spew.Dump(res.Peers)
-                pubkey, err := wgtypes.ParseKey(res.Peers.Publickey)
-                if err != nil {
-                        fmt.Println("error parsing key")
-                        return peers, hasGateway, gateways, err
-                }
+	response, err := wcclient.GetPeers(ctx, req, grpc.Header(&header))
+	if err != nil {
+		log.Println("Error retrieving peers")
+		log.Println(err)
+		return nil, hasGateway, gateways, err
+	}
+	var nodes []models.Node
+	if err := json.Unmarshal([]byte(response.GetData()), &nodes); err != nil {
+		log.Println("Error unmarshaling data for peers")
+		return nil, hasGateway, gateways, err
+	}
+	for _, node := range nodes {
+		pubkey, err := wgtypes.ParseKey(node.PublicKey)
+		if err != nil {
+			log.Println("error parsing key")
+			return peers, hasGateway, gateways, err
+		}
 
-                if nodecfg.PublicKey == res.Peers.Publickey {
-                        continue
-                }
-                if nodecfg.Endpoint == res.Peers.Endpoint {
-                        if nodecfg.LocalAddress != res.Peers.Localaddress && res.Peers.Localaddress != "" {
-				res.Peers.Endpoint = res.Peers.Localaddress
+		if nodecfg.PublicKey == node.PublicKey {
+			continue
+		}
+		if nodecfg.Endpoint == node.Endpoint {
+			if nodecfg.LocalAddress != node.LocalAddress && node.LocalAddress != "" {
+				node.Endpoint = node.LocalAddress
 			} else {
 				continue
 			}
-                }
+		}
 
-                var peer wgtypes.PeerConfig
-                var peeraddr = net.IPNet{
-                        IP: net.ParseIP(res.Peers.Address),
-                        Mask: net.CIDRMask(32, 32),
-                }
-                var allowedips []net.IPNet
-                allowedips = append(allowedips, peeraddr)
-                if res.Peers.Isegressgateway {
-                        hasGateway = true
-			log.Println(peeraddr.String(),"HAS GATEWAY",res.Peers.Egressgatewayranges)
-			ranges := strings.Split(res.Peers.Egressgatewayranges, ",")
+		var peer wgtypes.PeerConfig
+		var peeraddr = net.IPNet{
+			IP:   net.ParseIP(node.Address),
+			Mask: net.CIDRMask(32, 32),
+		}
+		var allowedips []net.IPNet
+		allowedips = append(allowedips, peeraddr)
+		if node.IsEgressGateway == "yes" {
+			hasGateway = true
+			ranges := node.EgressGatewayRanges
 			for _, iprange := range ranges {
-			gateways = append(gateways,iprange)
-                        _, ipnet, err := net.ParseCIDR(iprange)
-                        if err != nil {
-                                fmt.Println("ERROR ENCOUNTERED SETTING GATEWAY")
-                                fmt.Println("NOT SETTING GATEWAY")
-                                fmt.Println(err)
-                        } else {
-                                fmt.Println("    Gateway Range: "  + iprange)
-                                allowedips = append(allowedips, *ipnet)
-                        }
+				_, ipnet, err := net.ParseCIDR(iprange)
+				nodeEndpointArr := strings.Split(node.Endpoint, ":")
+				if len(nodeEndpointArr) != 2 || ipnet.Contains(net.IP(nodeEndpointArr[0])) {
+					continue
+				}
+				gateways = append(gateways, iprange)
+				if err != nil {
+					log.Println("ERROR ENCOUNTERED SETTING GATEWAY")
+				} else {
+					allowedips = append(allowedips, *ipnet)
+				}
+			}
+		}
+		if node.Address6 != "" && dualstack {
+			var addr6 = net.IPNet{
+				IP:   net.ParseIP(node.Address6),
+				Mask: net.CIDRMask(128, 128),
+			}
+			allowedips = append(allowedips, addr6)
+		}
+		if nodecfg.IsServer == "yes" {
+			peer = wgtypes.PeerConfig{
+				PublicKey:                   pubkey,
+				PersistentKeepaliveInterval: &keepaliveserver,
+				ReplaceAllowedIPs:           true,
+				AllowedIPs:                  allowedips,
 			}
-                }
-                if res.Peers.Address6 != "" && dualstack {
-                        var addr6 = net.IPNet{
-                                IP: net.ParseIP(res.Peers.Address6),
-                                Mask: net.CIDRMask(128, 128),
-                        }
-                        allowedips = append(allowedips, addr6)
-                }
-                if nodecfg.Name == "netmaker" {
-                peer = wgtypes.PeerConfig{
-                        PublicKey: pubkey,
-                        PersistentKeepaliveInterval: &keepaliveserver,
-                        ReplaceAllowedIPs: true,
-                        AllowedIPs: allowedips,
-                        }
 		} else if keepalive != 0 {
-                peer = wgtypes.PeerConfig{
-                        PublicKey: pubkey,
-                        PersistentKeepaliveInterval: &keepalivedur,
-                        Endpoint: &net.UDPAddr{
-                                IP:   net.ParseIP(res.Peers.Endpoint),
-                                Port: int(res.Peers.Listenport),
-                        },
-                        ReplaceAllowedIPs: true,
-                        AllowedIPs: allowedips,
-                        }
-                } else {
-                peer = wgtypes.PeerConfig{
-                        PublicKey: pubkey,
-                        Endpoint: &net.UDPAddr{
-                                IP:   net.ParseIP(res.Peers.Endpoint),
-                                Port: int(res.Peers.Listenport),
-                        },
-                        ReplaceAllowedIPs: true,
-                        AllowedIPs: allowedips,
-                        }
-                }
-                peers = append(peers, peer)
+			peer = wgtypes.PeerConfig{
+				PublicKey:                   pubkey,
+				PersistentKeepaliveInterval: &keepalivedur,
+				Endpoint: &net.UDPAddr{
+					IP:   net.ParseIP(node.Endpoint),
+					Port: int(node.ListenPort),
+				},
+				ReplaceAllowedIPs: true,
+				AllowedIPs:        allowedips,
+			}
+		} else {
+			peer = wgtypes.PeerConfig{
+				PublicKey: pubkey,
+				Endpoint: &net.UDPAddr{
+					IP:   net.ParseIP(node.Endpoint),
+					Port: int(node.ListenPort),
+				},
+				ReplaceAllowedIPs: true,
+				AllowedIPs:        allowedips,
+			}
+		}
+		peers = append(peers, peer)
 
-        }
-        if isIngressGateway {
-                extPeers, err := GetExtPeers(macaddress, network, server, dualstack)
-                if err == nil {
-                        peers = append(peers, extPeers...)
-                } else {
-                        fmt.Println("ERROR RETRIEVING EXTERNAL PEERS")
-                        fmt.Println(err)
-                }
-        }
-        return peers, hasGateway, gateways, err
+	}
+	if isIngressGateway {
+		extPeers, err := GetExtPeers(macaddress, network, server, dualstack)
+		if err == nil {
+			peers = append(peers, extPeers...)
+		} else {
+			log.Println("ERROR RETRIEVING EXTERNAL PEERS")
+		}
+	}
+	return peers, hasGateway, gateways, err
 }
 
 func GetExtPeers(macaddress string, network string, server string, dualstack bool) ([]wgtypes.PeerConfig, error) {
-        var peers []wgtypes.PeerConfig
-        var wcclient nodepb.NodeServiceClient
-        cfg, err := config.ReadConfig(network)
-        if err != nil {
-                log.Fatalf("Issue retrieving config for network: " + network +  ". Please investigate: %v", err)
-        }
-        nodecfg := cfg.Node
-
-        requestOpts := grpc.WithInsecure()
-        conn, err := grpc.Dial(server, requestOpts)
-        if err != nil {
-                log.Fatalf("Unable to establish client connection to localhost:50051: %v", err)
-        }
-        // Instantiate the BlogServiceClient with our client connection to the server
-        wcclient = nodepb.NewNodeServiceClient(conn)
+	var peers []wgtypes.PeerConfig
+	var wcclient nodepb.NodeServiceClient
+	cfg, err := config.ReadConfig(network)
+	if err != nil {
+		log.Fatalf("Issue retrieving config for network: "+network+". Please investigate: %v", err)
+	}
+	nodecfg := cfg.Node
 
-        req := &nodepb.GetExtPeersReq{
-                Macaddress: macaddress,
-                Network: network,
-        }
-        ctx := context.Background()
-        ctx, err = auth.SetJWT(wcclient, network)
-        if err != nil {
-                fmt.Println("Failed to authenticate.")
-                return peers, err
-        }
-        var header metadata.MD
+	requestOpts := grpc.WithInsecure()
+	conn, err := grpc.Dial(server, requestOpts)
+	if err != nil {
+		log.Fatalf("Unable to establish client connection to localhost:50051: %v", err)
+	}
+	// Instantiate the BlogServiceClient with our client connection to the server
+	wcclient = nodepb.NewNodeServiceClient(conn)
 
-        stream, err := wcclient.GetExtPeers(ctx, req, grpc.Header(&header))
-        if err != nil {
-                fmt.Println("Error retrieving peers")
-                fmt.Println(err)
-                return nil, err
-        }
-        for {
-                res, err := stream.Recv()
-                // If end of stream, break the loop
+	req := &nodepb.Object{
+		Data: macaddress + "###" + network,
+		Type: nodepb.STRING_TYPE,
+	}
 
-                if err == io.EOF {
-                        break
-                }
-                // if err, return an error
-                if err != nil {
-                        if strings.Contains(err.Error(), "mongo: no documents in result") {
-                                continue
-                        } else {
-                        fmt.Println("ERROR ENCOUNTERED WITH RESPONSE")
-                        fmt.Println(res)
-                        return peers, err
-                        }
-                }
-                pubkey, err := wgtypes.ParseKey(res.Extpeers.Publickey)
-                if err != nil {
-                        fmt.Println("error parsing key")
-                        return peers, err
-                }
+	ctx, err := auth.SetJWT(wcclient, network)
+	if err != nil {
+		log.Println("Failed to authenticate.")
+		return peers, err
+	}
+	var header metadata.MD
 
-                if nodecfg.PublicKey == res.Extpeers.Publickey {
-                        continue
-                }
+	responseObject, err := wcclient.GetExtPeers(ctx, req, grpc.Header(&header))
+	if err != nil {
+		log.Println("Error retrieving peers")
+		log.Println(err)
+		return nil, err
+	}
+	var extPeers []models.Node
+	if err = json.Unmarshal([]byte(responseObject.Data), &extPeers); err != nil {
+		return nil, err
+	}
+	for _, extPeer := range extPeers {
+		pubkey, err := wgtypes.ParseKey(extPeer.PublicKey)
+		if err != nil {
+			log.Println("error parsing key")
+			return peers, err
+		}
 
-                var peer wgtypes.PeerConfig
-                var peeraddr = net.IPNet{
-                        IP: net.ParseIP(res.Extpeers.Address),
-                        Mask: net.CIDRMask(32, 32),
-                }
-                var allowedips []net.IPNet
-                allowedips = append(allowedips, peeraddr)
+		if nodecfg.PublicKey == extPeer.PublicKey {
+			continue
+		}
 
-		if res.Extpeers.Address6 != "" && dualstack {
-                        var addr6 = net.IPNet{
-                                IP: net.ParseIP(res.Extpeers.Address6),
-                                Mask: net.CIDRMask(128, 128),
-                        }
-                        allowedips = append(allowedips, addr6)
-                }
-                peer = wgtypes.PeerConfig{
-                        PublicKey: pubkey,
-                        ReplaceAllowedIPs: true,
-                        AllowedIPs: allowedips,
-                        }
-                peers = append(peers, peer)
+		var peer wgtypes.PeerConfig
+		var peeraddr = net.IPNet{
+			IP:   net.ParseIP(extPeer.Address),
+			Mask: net.CIDRMask(32, 32),
+		}
+		var allowedips []net.IPNet
+		allowedips = append(allowedips, peeraddr)
 
-        }
-        return peers, err
+		if extPeer.Address6 != "" && dualstack {
+			var addr6 = net.IPNet{
+				IP:   net.ParseIP(extPeer.Address6),
+				Mask: net.CIDRMask(128, 128),
+			}
+			allowedips = append(allowedips, addr6)
+		}
+		peer = wgtypes.PeerConfig{
+			PublicKey:         pubkey,
+			ReplaceAllowedIPs: true,
+			AllowedIPs:        allowedips,
+		}
+		peers = append(peers, peer)
+	}
+	return peers, err
 }

+ 109 - 219
netclient/wireguard/kernel.go

@@ -1,152 +1,24 @@
 package wireguard
 
 import (
-	"github.com/davecgh/go-spew/spew"
-	"context"
-	"crypto/tls"
-	"errors"
 	"fmt"
 	"io/ioutil"
 	"log"
-	"net"
 	"os"
 	"os/exec"
 	"strconv"
 	"strings"
 
-	nodepb "github.com/gravitl/netmaker/grpc"
 	"github.com/gravitl/netmaker/models"
-	"github.com/gravitl/netmaker/netclient/auth"
 	"github.com/gravitl/netmaker/netclient/config"
 	"github.com/gravitl/netmaker/netclient/local"
 	"github.com/gravitl/netmaker/netclient/server"
 	"golang.zx2c4.com/wireguard/wgctrl"
 	"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
-	"google.golang.org/grpc"
-	"google.golang.org/grpc/credentials"
-	"google.golang.org/grpc/metadata"
 	//homedir "github.com/mitchellh/go-homedir"
 )
 
-func InitGRPCWireguard(client models.IntClient) error {
-	//spew.Dump(client)
-
-	key, err := wgtypes.ParseKey(client.PrivateKey)
-	if err != nil {
-		return err
-	}
-	serverkey, err := wgtypes.ParseKey(client.ServerKey)
-	if err != nil {
-		return err
-	}
-	serverport, err := strconv.Atoi(client.ServerWGPort)
-	if err != nil {
-		return err
-	}
-
-	wgclient, err := wgctrl.New()
-	if err != nil {
-		log.Fatalf("failed to open client: %v", err)
-	}
-	defer wgclient.Close()
-
-	ifacename := "grpc-wg-001"
-	if client.Address6 == "" && client.Address == "" {
-		return errors.New("no address to configure")
-	}
-	cmdIPDevLinkAdd := exec.Command("ip", "link", "add", "dev", ifacename, "type", "wireguard")
-	cmdIPAddrAdd := exec.Command("ip", "address", "add", "dev", ifacename, client.Address+"/24")
-	cmdIPAddr6Add := exec.Command("ip", "address", "add", "dev", ifacename, client.Address6+"/64")
-	currentiface, err := net.InterfaceByName(ifacename)
-	if err != nil {
-		err = cmdIPDevLinkAdd.Run()
-		if err != nil && !strings.Contains(err.Error(), "exists") {
-			log.Println("Error creating interface")
-		}
-	}
-	match := false
-	match6 := false
-	addrs, _ := currentiface.Addrs()
-
-	//Add IPv4Address (make into separate function)
-	for _, a := range addrs {
-		if strings.Contains(a.String(), client.Address) {
-			match = true
-		}
-		if strings.Contains(a.String(), client.Address6) {
-			match6 = true
-		}
-	}
-	if !match && client.Address != "" {
-		err = cmdIPAddrAdd.Run()
-		if err != nil {
-			log.Println("Error adding ipv4 address")
-			fmt.Println(err)
-		}
-	}
-	if !match6 && client.Address6 != "" {
-		err = cmdIPAddr6Add.Run()
-		if err != nil {
-			log.Println("Error adding ipv6 address")
-			fmt.Println(err)
-		}
-	}
-	var peers []wgtypes.PeerConfig
-	var peeraddr = net.IPNet{
-		IP:   net.ParseIP(client.ServerPrivateAddress),
-		Mask: net.CIDRMask(32, 32),
-	}
-	var allowedips []net.IPNet
-	allowedips = append(allowedips, peeraddr)
-	net.ParseIP(client.ServerPublicEndpoint)
-	peer := wgtypes.PeerConfig{
-		PublicKey: serverkey,
-		Endpoint: &net.UDPAddr{
-			IP:   net.ParseIP(client.ServerPublicEndpoint),
-			Port: serverport,
-		},
-		ReplaceAllowedIPs: true,
-		AllowedIPs:        allowedips,
-	}
-	peers = append(peers, peer)
-	conf := wgtypes.Config{
-		PrivateKey:   &key,
-		ReplacePeers: true,
-		Peers:        peers,
-	}
-	_, err = wgclient.Device(ifacename)
-	if err != nil {
-		if os.IsNotExist(err) {
-			log.Println("Device does not exist: ")
-			log.Println(err)
-		} else {
-			return err
-		}
-	}
-	//spew.Dump(conf)
-	err = wgclient.ConfigureDevice(ifacename, conf)
-
-	if err != nil {
-		if os.IsNotExist(err) {
-			log.Println("Device does not exist: ")
-			log.Println(err)
-		} else {
-			log.Printf("This is inconvenient: %v", err)
-		}
-	}
-
-	cmdIPLinkUp := exec.Command("ip", "link", "set", "up", "dev", ifacename)
-	cmdIPLinkDown := exec.Command("ip", "link", "set", "down", "dev", ifacename)
-	err = cmdIPLinkDown.Run()
-	err = cmdIPLinkUp.Run()
-	if err != nil {
-		return err
-	}
-
-	return err
-}
-
-func InitWireguard(node *nodepb.Node, privkey string, peers []wgtypes.PeerConfig, hasGateway bool, gateways []string) error {
+func InitWireguard(node *models.Node, privkey string, peers []wgtypes.PeerConfig, hasGateway bool, gateways []string) error {
 
 	ipExec, err := exec.LookPath("ip")
 	if err != nil {
@@ -161,7 +33,7 @@ func InitWireguard(node *nodepb.Node, privkey string, peers []wgtypes.PeerConfig
 	if err != nil {
 		return err
 	}
-	modcfg, err := config.ReadConfig(node.Nodenetwork)
+	modcfg, err := config.ReadConfig(node.Network)
 	if err != nil {
 		return err
 	}
@@ -185,54 +57,33 @@ func InitWireguard(node *nodepb.Node, privkey string, peers []wgtypes.PeerConfig
 		log.Fatal("no address to configure")
 	}
 	nameserver := servercfg.CoreDNSAddr
-	network := node.Nodenetwork
+	network := node.Network
 	if nodecfg.Network != "" {
 		network = nodecfg.Network
-	} else if node.Nodenetwork != "" {
-		network = node.Nodenetwork
-	}
-	cmdIPDevLinkAdd := &exec.Cmd{
-		Path:   ipExec,
-		Args:   []string{ipExec, "link", "add", "dev", ifacename, "type", "wireguard"},
-		Stdout: os.Stdout,
-		Stderr: os.Stdout,
-	}
-	cmdIPAddrAdd := &exec.Cmd{
-		Path:   ipExec,
-		Args:   []string{ipExec, "address", "add", "dev", ifacename, node.Address + "/24"},
-		Stdout: os.Stdout,
-		Stderr: os.Stdout,
+	} else if node.Network != "" {
+		network = node.Network
 	}
 
-	currentiface, err := net.InterfaceByName(ifacename)
-
-	if err != nil {
-		err = cmdIPDevLinkAdd.Run()
-		if err != nil && !strings.Contains(err.Error(), "exists") {
-			fmt.Println("Error creating interface")
-			//fmt.Println(err.Error())
-			//return err
-		}
+	_, delErr := local.RunCmd("ip link delete dev " + ifacename)
+	_, addLinkErr := local.RunCmd(ipExec + " link add dev " + ifacename + " type wireguard")
+	_, addErr := local.RunCmd(ipExec + " address add dev " + ifacename + " " + node.Address + "/24")
+	if delErr != nil {
+		log.Println(delErr)
 	}
-	match := false
-	addrs, _ := currentiface.Addrs()
-	for _, a := range addrs {
-		if strings.Contains(a.String(), node.Address) {
-			match = true
-		}
+	if addLinkErr != nil {
+		log.Println(addLinkErr)
 	}
-	if !match {
-		err = cmdIPAddrAdd.Run()
-		if err != nil {
-			fmt.Println("Error adding address")
-			//return err
-		}
+	if addErr != nil {
+		log.Println(addErr)
 	}
 	var nodeport int
-	nodeport = int(node.Listenport)
+	nodeport = int(node.ListenPort)
 
 	conf := wgtypes.Config{}
-	if nodecfg.UDPHolePunch == "yes" && nodecfg.Name != "netmaker" {
+	if nodecfg.UDPHolePunch == "yes" &&  
+	nodecfg.IsServer == "no"  &&    
+	nodecfg.IsIngressGateway == "no" && 
+	nodecfg.IsStatic != "yes" {
 		conf = wgtypes.Config{
 			PrivateKey:   &key,
 			ReplacePeers: true,
@@ -267,8 +118,7 @@ func InitWireguard(node *nodepb.Node, privkey string, peers []wgtypes.PeerConfig
 		}
 	}
 	//=========DNS Setup==========\\
-	log.Println("NODECFG.DNS:",nodecfg.DNS)
-	if nodecfg.DNS == "on" {
+	if nodecfg.DNSOn == "yes" {
 		_ = local.UpdateDNS(ifacename, network, nameserver)
 	}
 	//=========End DNS Setup=======\\
@@ -308,20 +158,17 @@ func InitWireguard(node *nodepb.Node, privkey string, peers []wgtypes.PeerConfig
 		}
 	}
 	if hasGateway {
-		spew.Dump(gateways)
 		for _, gateway := range gateways {
-			log.Println("Gateway:")
-			spew.Dump(gateway)
-			out, err := exec.Command(ipExec, "-4", "route", "add", gateway, "dev", ifacename).Output()
+			out, err := local.RunCmd(ipExec + " -4 route add " + gateway + " dev " + ifacename)
 			fmt.Println(string(out))
 			if err != nil {
 				fmt.Println("Error encountered adding gateway: " + err.Error())
 			}
 		}
 	}
-	if node.Address6 != "" && node.Isdualstack {
+	if node.Address6 != "" && node.IsDualStack == "yes" {
 		fmt.Println("Adding address: " + node.Address6)
-		out, err := exec.Command(ipExec, "address", "add", "dev", ifacename, node.Address6+"/64").Output()
+		out, err := local.RunCmd(ipExec + " address add dev " + ifacename + " " + node.Address6 + "/64")
 		if err != nil {
 			fmt.Println(out)
 			fmt.Println("Error encountered adding ipv6: " + err.Error())
@@ -333,36 +180,12 @@ func InitWireguard(node *nodepb.Node, privkey string, peers []wgtypes.PeerConfig
 
 func SetWGKeyConfig(network string, serveraddr string) error {
 
-	ctx := context.Background()
-	var header metadata.MD
-
 	cfg, err := config.ReadConfig(network)
 	if err != nil {
 		return err
 	}
 
-	var wcclient nodepb.NodeServiceClient
-	var requestOpts grpc.DialOption
-	requestOpts = grpc.WithInsecure()
-	if cfg.Server.GRPCSSL == "on" {
-		h2creds := credentials.NewTLS(&tls.Config{NextProtos: []string{"h2"}})
-		requestOpts = grpc.WithTransportCredentials(h2creds)
-	}
-
-	conn, err := grpc.Dial(serveraddr, requestOpts)
-	if err != nil {
-		fmt.Printf("Cant dial GRPC server: %v", err)
-		return err
-	}
-	wcclient = nodepb.NewNodeServiceClient(conn)
-
-	ctx, err = auth.SetJWT(wcclient, network)
-	if err != nil {
-		fmt.Printf("Failed to authenticate: %v", err)
-		return err
-	}
-
-	node := server.GetNode(network)
+	node := cfg.Node
 
 	privatekey, err := wgtypes.GeneratePrivateKey()
 	if err != nil {
@@ -371,37 +194,29 @@ func SetWGKeyConfig(network string, serveraddr string) error {
 	privkeystring := privatekey.String()
 	publickey := privatekey.PublicKey()
 
-	node.Publickey = publickey.String()
+	node.PublicKey = publickey.String()
 
 	err = StorePrivKey(privkeystring, network)
 	if err != nil {
 		return err
 	}
+	if node.Action == models.NODE_UPDATE_KEY {
+		node.Action = models.NODE_NOOP
+	}
 	err = config.ModConfig(&node)
 	if err != nil {
 		return err
 	}
 
-	postnode := server.GetNode(network)
-
-	req := &nodepb.UpdateNodeReq{
-		Node: &postnode,
-	}
-
-	_, err = wcclient.UpdateNode(ctx, req, grpc.Header(&header))
-	if err != nil {
-		return err
-	}
-	err = SetWGConfig(network)
+	err = SetWGConfig(network, false)
 	if err != nil {
 		return err
-		log.Fatalf("Error: %v", err)
 	}
 
 	return err
 }
 
-func SetWGConfig(network string) error {
+func SetWGConfig(network string, peerupdate bool) error {
 
 	cfg, err := config.ReadConfig(network)
 	if err != nil {
@@ -409,9 +224,8 @@ func SetWGConfig(network string) error {
 	}
 	servercfg := cfg.Server
 	nodecfg := cfg.Node
-	node := server.GetNode(network)
 
-	peers, hasGateway, gateways, err := server.GetPeers(node.Macaddress, nodecfg.Network, servercfg.GRPCAddress, node.Isdualstack, node.Isingressgateway)
+	peers, hasGateway, gateways, err := server.GetPeers(nodecfg.MacAddress, nodecfg.Network, servercfg.GRPCAddress, nodecfg.IsDualStack == "yes", nodecfg.IsIngressGateway == "yes")
 	if err != nil {
 		return err
 	}
@@ -419,8 +233,11 @@ func SetWGConfig(network string) error {
 	if err != nil {
 		return err
 	}
-
-	err = InitWireguard(&node, privkey, peers, hasGateway, gateways)
+	if peerupdate {
+		SetPeers(nodecfg.Interface, nodecfg.PersistentKeepalive, peers)
+	} else {
+		err = InitWireguard(&nodecfg, privkey, peers, hasGateway, gateways)
+	}
 	if err != nil {
 		return err
 	}
@@ -428,6 +245,79 @@ func SetWGConfig(network string) error {
 	return err
 }
 
+func SetPeers(iface string, keepalive int32, peers []wgtypes.PeerConfig) {
+
+	client, err := wgctrl.New()
+	if err != nil {
+		log.Println("failed to start wgctrl")
+		return
+	}
+	device, err := client.Device(iface)
+	if err != nil {
+		log.Println("failed to parse interface")
+		return
+	}
+	devicePeers := device.Peers
+	if len(devicePeers) > 1 && len(peers) == 0 {
+		log.Println("no peers pulled")
+		return
+	}
+
+	for _, peer := range peers {
+
+		for _, currentPeer := range devicePeers {
+			if currentPeer.AllowedIPs[0].String() == peer.AllowedIPs[0].String() &&
+				currentPeer.PublicKey.String() != peer.PublicKey.String() {
+				_, err := local.RunCmd("wg set " + iface + " peer " + currentPeer.PublicKey.String() + " remove")
+				if err != nil {
+					log.Println("error removing peer", peer.Endpoint.String())
+				}
+			}
+		}
+		udpendpoint := peer.Endpoint.String()
+		var allowedips string
+		var iparr []string
+		for _, ipaddr := range peer.AllowedIPs {
+			iparr = append(iparr, ipaddr.String())
+		}
+		allowedips = strings.Join(iparr, ",")
+		keepAliveString := strconv.Itoa(int(keepalive))
+		if keepAliveString == "0" {
+			keepAliveString = "5"
+		}
+		if peer.Endpoint != nil {
+			_, err = local.RunCmd("wg set " + iface + " peer " + peer.PublicKey.String() +
+				" endpoint " + udpendpoint +
+				" persistent-keepalive " + keepAliveString +
+				" allowed-ips " + allowedips)
+		} else {
+			_, err = local.RunCmd("wg set " + iface + " peer " + peer.PublicKey.String() +
+				" persistent-keepalive " + keepAliveString +
+				" allowed-ips " + allowedips)
+		}
+		if err != nil {
+			log.Println("error setting peer", peer.PublicKey.String(), err)
+		}
+	}
+
+	for _, currentPeer := range devicePeers {
+		shouldDelete := true
+		for _, peer := range peers {
+			if peer.AllowedIPs[0].String() == currentPeer.AllowedIPs[0].String() {
+				shouldDelete = false
+			}
+		}
+		if shouldDelete {
+			_, err := local.RunCmd("wg set " + iface + " peer " + currentPeer.PublicKey.String() + " remove")
+			if err != nil {
+				log.Println("error removing peer", currentPeer.PublicKey.String())
+			} else {
+				log.Println("removed peer " + currentPeer.PublicKey.String())
+			}
+		}
+	}
+}
+
 func StorePrivKey(key string, network string) error {
 	d1 := []byte(key)
 	err := ioutil.WriteFile("/etc/netclient/wgkey-"+network, d1, 0644)

+ 6 - 6
nginx/netmaker-nginx-template.conf

@@ -4,8 +4,8 @@ server {
     server_name dashboard.NETMAKER_BASE_DOMAIN;
     ssl_certificate /etc/letsencrypt/live/NETMAKER_BASE_DOMAIN/fullchain.pem; 
     ssl_certificate_key /etc/letsencrypt/live/NETMAKER_BASE_DOMAIN/privkey.pem; 
-    include /etc/letsencrypt/options-ssl-nginx.conf; 
-    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; 
+    #include /etc/letsencrypt/options-ssl-nginx.conf; 
+    #ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; 
     location / {
         proxy_pass http://127.0.0.1:8082;
      }
@@ -16,8 +16,8 @@ server {
     server_name api.NETMAKER_BASE_DOMAIN;
     ssl_certificate /etc/letsencrypt/live/NETMAKER_BASE_DOMAIN/fullchain.pem;
     ssl_certificate_key /etc/letsencrypt/live/NETMAKER_BASE_DOMAIN/privkey.pem;
-    include /etc/letsencrypt/options-ssl-nginx.conf;
-    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
+    #include /etc/letsencrypt/options-ssl-nginx.conf;
+    #ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
 
     location / {
         proxy_pass http://127.0.0.1:8081;
@@ -30,8 +30,8 @@ server {
     server_name grpc.NETMAKER_BASE_DOMAIN
     ssl_certificate /etc/letsencrypt/live/NETMAKER_BASE_DOMAIN/fullchain.pem; 
     ssl_certificate_key /etc/letsencrypt/live/NETMAKER_BASE_DOMAIN/privkey.pem; 
-    include /etc/letsencrypt/options-ssl-nginx.conf; 
-    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; 
+    #include /etc/letsencrypt/options-ssl-nginx.conf; 
+    #ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; 
 
         # Forces the header to be the one that is visible from the outside
         proxy_set_header                Host api.NETMAKER_BASE_DOMAIN; # Please change to your URL

+ 1 - 2
scripts/netclient-install.sh

@@ -8,8 +8,7 @@ fi
 
 [ -z "$KEY" ] && KEY=nokey;
 
-wget -O netclient https://github.com/gravitl/netmaker/releases/download/v0.5.11/netclient
+wget -O netclient https://github.com/gravitl/netmaker/releases/download/v0.7/netclient
 chmod +x netclient
-sudo ./netclient register -t $KEY
 sudo ./netclient join -t $KEY
 rm -f netclient

+ 6 - 3
serverctl/serverctl.go

@@ -12,6 +12,7 @@ import (
 	"github.com/gravitl/netmaker/database"
 	"github.com/gravitl/netmaker/functions"
 	"github.com/gravitl/netmaker/models"
+	"github.com/gravitl/netmaker/netclient/local"
 	"github.com/gravitl/netmaker/servercfg"
 )
 
@@ -121,7 +122,7 @@ func RemoveNetwork(network string) (bool, error) {
 		log.Println("could not find /etc/netclient")
 		return false, err
 	}
-	cmdoutput, err := exec.Command("/etc/netclient/netclient", "leave", "-n", network).Output()
+	cmdoutput, err := local.RunCmd("/etc/netclient/netclient leave -n " + network)
 	if err != nil {
 		log.Println(string(cmdoutput))
 		return false, err
@@ -162,10 +163,12 @@ func AddNetwork(network string) (bool, error) {
 		log.Println("could not change netclient directory permissions")
 		return false, err
 	}
-	log.Println("executing network join: " + "/etc/netclient/netclient " + "join " + "-t " + token + " -name " + "netmaker" + " -endpoint " + pubip)
+	functions.PrintUserLog(models.NODE_SERVER_NAME,"executing network join: " + "/etc/netclient/netclient " + "join " + "-t " + token + " -name " + models.NODE_SERVER_NAME + " -endpoint " + pubip,0)
 
-	joinCMD := exec.Command("/etc/netclient/netclient", "join", "-t", token, "-name", "netmaker", "-endpoint", pubip)
+	joinCMD := exec.Command("/etc/netclient/netclient", "join", "-t", token, "-name", models.NODE_SERVER_NAME, "-endpoint", pubip)
 	err = joinCMD.Start()
+	
+	
 	if err != nil {
 		log.Println(err)
 	}

+ 3 - 2
serverctl/wireguard.go

@@ -201,8 +201,9 @@ func GetPeers(networkName string) (map[string]string, error) {
 		return nil, err
 	}
 	for _, peer := range device.Peers {
-		peers[peer.PublicKey.String()] = peer.Endpoint.String()
+		if functions.IsBase64(peer.PublicKey.String()) && peer.Endpoint != nil && functions.CheckEndpoint(peer.Endpoint.String()) {
+			peers[peer.PublicKey.String()] = peer.Endpoint.String()
+		}
 	}
-
 	return peers, nil
 }

Daži faili netika attēloti, jo izmaiņu fails ir pārāk liels