Ver código fonte

Merge pull request #205 from gravitl/feature_0.7_cleanup

Feature 0.7 cleanup
Alex 4 anos atrás
pai
commit
866891a4e0
52 arquivos alterados com 5434 adições e 5252 exclusões
  1. 12 0
      compose/docker-compose.coredns.yml
  2. 59 0
      compose/docker-compose.quickstart.yml
  3. 3 13
      config/config.go
  4. 1 1
      config/dnsconfig/Corefile
  5. 5 0
      config/dnsconfig/netmaker.hosts
  6. 0 6
      config/environments/dev.yaml
  7. 90 92
      controllers/authGrpc.go
  8. 127 368
      controllers/common.go
  9. 11 19
      controllers/common_test.go
  10. 41 43
      controllers/controller.go
  11. 75 132
      controllers/dnsHttpController.go
  12. 4 6
      controllers/dnsHttpController_test.go
  13. 120 156
      controllers/extClientHttpController.go
  14. 132 134
      controllers/intClientHttpController.go
  15. 100 357
      controllers/networkHttpController.go
  16. 9 15
      controllers/networkHttpController_test.go
  17. 87 179
      controllers/nodeGrpcController.go
  18. 165 260
      controllers/nodeHttpController.go
  19. 1 1
      controllers/serverHttpController.go
  20. 76 125
      controllers/userHttpController.go
  21. 8 12
      controllers/userHttpController_test.go
  22. 109 0
      database/database.go
  23. 166 18
      docs/quick-start.rst
  24. 183 508
      functions/helpers.go
  25. 5 1
      go.mod
  26. 6 0
      go.sum
  27. 1569 915
      grpc/node.pb.go
  28. 3 2
      grpc/node.proto
  29. 0 2
      kube/netmaker-template.yaml
  30. 105 137
      main.go
  31. 1 1
      models/dnsEntry.go
  32. 277 78
      models/network.go
  33. 306 136
      models/node.go
  34. 21 15
      models/structs.go
  35. 16 0
      models/validation.go
  36. 0 67
      mongoconn/mongoconn.go
  37. 353 347
      netclient/config/config.go
  38. 2 2
      netclient/functions/checkin.go
  39. 126 124
      netclient/functions/join.go
  40. 2 2
      netclient/local/dns.go
  41. 370 364
      netclient/main.go
  42. 21 5
      netclient/server/grpc.go
  43. 290 285
      netclient/wireguard/kernel.go
  44. 96 0
      nginx/netmaker-nginx-dns.conf
  45. 45 0
      nginx/netmaker-nginx-template.conf
  46. 0 53
      servercfg/mongoconf.go
  47. 2 2
      servercfg/serverconf.go
  48. 129 187
      serverctl/serverctl.go
  49. 100 77
      serverctl/wireguard.go
  50. 1 1
      test/api_test.go
  51. 1 1
      test/groupcreate.sh
  52. 3 3
      test/nodecreate.sh

+ 12 - 0
compose/docker-compose.coredns.yml

@@ -0,0 +1,12 @@
+version: "3.4"
+
+services:
+  coredns:
+    image: coredns/coredns
+    command: -conf /root/dnsconfig/Corefile
+    container_name: coredns
+    restart: always
+    ports:
+      - "53:53/udp"
+    volumes:
+      - /root/netmaker/config/dnsconfig:/root/dnsconfig

+ 59 - 0
compose/docker-compose.quickstart.yml

@@ -0,0 +1,59 @@
+version: "3.4"
+
+services:
+  rqlite:
+    container_name: rqlite
+    image: rqlite/rqlite
+    ports:
+      - "4001:4001"
+      - "4002:4002"
+    restart: always
+    volumes:
+      - sqldata:/rqlite/file/data
+  netmaker:
+    depends_on:
+      - rqlite
+    privileged: true
+    container_name: netmaker
+    image: gravitl/netmaker:v0.7
+    volumes:
+      - ./:/local
+      - /etc/netclient:/etc/netclient
+      - dnsconfig:/root/config/dnsconfig
+      - /usr/bin/wg:/usr/bin/wg
+      - /var/run/dbus/system_bus_socket:/var/run/dbus/system_bus_socket
+      - /run/systemd/system:/run/systemd/system
+      - /etc/systemd/system:/etc/systemd/system
+      - /sys/fs/cgroup:/sys/fs/cgroup
+    cap_add: 
+      - NET_ADMIN
+      - SYS_MODULE
+    restart: always
+    network_mode: host
+    environment:
+      SERVER_HOST: "HOST_IP"
+  netmaker-ui:
+    container_name: netmaker-ui
+    depends_on:
+      - netmaker
+    image: gravitl/netmaker-ui:v0.5
+    links:
+      - "netmaker:api"
+    ports:
+      - "8082:80"
+    environment:
+      BACKEND_URL: "https://api.NETMAKER_BASE_DOMAIN"
+  coredns:
+    depends_on:
+      - netmaker 
+    image: coredns/coredns
+    command: -conf /root/dnsconfig/Corefile
+    container_name: coredns
+    restart: always
+    ports:
+      - "5353:53/udp"
+    volumes:
+      - dnsconfig:/root/dnsconfig
+volumes:
+  sqldata: {}
+  dnsconfig: {}

+ 3 - 13
config/config.go

@@ -2,7 +2,6 @@
 //Currently the only thing it does is set the master password
 //Should probably have it take over functions from OS such as port and mongodb connection details
 //Reads from the config/environments/dev.yaml file by default
-//TODO:  Add vars for mongo and remove from  OS vars in mongoconn
 package config
 
 import (
@@ -30,14 +29,13 @@ var Config *EnvironmentConfig
 
 // EnvironmentConfig :
 type EnvironmentConfig struct {
-	Server    ServerConfig    `yaml:"server"`
-	MongoConn MongoConnConfig `yaml:"mongoconn"`
-	WG        WG              `yaml:"wg"`
+	Server ServerConfig `yaml:"server"`
+	WG     WG           `yaml:"wg"`
 }
 
 // ServerConfig :
 type ServerConfig struct {
-	CoreDNSAddr string `yaml:"corednsaddr"`
+	CoreDNSAddr          string `yaml:"corednsaddr"`
 	APIConnString        string `yaml:"apiconn"`
 	APIHost              string `yaml:"apihost"`
 	APIPort              string `yaml:"apiport"`
@@ -69,14 +67,6 @@ type WG struct {
 	GRPCWGPrivKey       string `yaml:"privkey"`
 }
 
-type MongoConnConfig struct {
-	User string `yaml:"user"`
-	Pass string `yaml:"pass"`
-	Host string `yaml:"host"`
-	Port string `yaml:"port"`
-	Opts string `yaml:"opts"`
-}
-
 //reading in the env file
 func readConfig() *EnvironmentConfig {
 	file := fmt.Sprintf("config/environments/%s.yaml", getEnv())

+ 1 - 1
config/dnsconfig/Corefile

@@ -1,4 +1,4 @@
-default k8scom tester textx comms  {
+pissant comms  {
     reload 15s
     hosts /root/dnsconfig/netmaker.hosts {
 	fallthrough	

+ 5 - 0
config/dnsconfig/netmaker.hosts

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

+ 0 - 6
config/environments/dev.yaml

@@ -10,12 +10,6 @@ server:
   clientmode: "" # defaults to "on" or CLIENT_MODE (if set)
   dnsmode: "" # defaults to "on" or DNS_MODE (if set)
   disableremoteipcheck: "" # defaults to "false" or DISABLE_REMOTE_IP_CHECK (if set)
-mongoconn:
-  user: "" # defaults to "mongoadmin" or MONGO_ADMIN (if set)
-  pass: "" # defaults to "mongopass" or MONGO_PASS (if set)
-  host: "" # defaults to 127.0.0.1 or MONGO_HOST (if set)
-  port: "" # defaults to 27017 or MONGO_PORT (if set)
-  opts: '' # defaults to '/?authSource=admin' or MONGO_OPTS (if set)
 wg:
   keyrequired: "" # defaults to "". If set to "yes", a key is required for signing up for the comms network 
   grpcwg: "" # defaults to "on" or SERVER_GRPC_WIREGUARD if set

+ 90 - 92
controllers/authGrpc.go

@@ -1,20 +1,18 @@
 package controller
 
 import (
-	"errors"
 	"context"
-        "golang.org/x/crypto/bcrypt"
-        "time"
-        nodepb "github.com/gravitl/netmaker/grpc"
-        "github.com/gravitl/netmaker/models"
-        "github.com/gravitl/netmaker/functions"
-        "github.com/gravitl/netmaker/mongoconn"
-        "go.mongodb.org/mongo-driver/bson"
+	"encoding/json"
+	"errors"
+	"github.com/gravitl/netmaker/database"
+	"github.com/gravitl/netmaker/functions"
+	nodepb "github.com/gravitl/netmaker/grpc"
+	"github.com/gravitl/netmaker/models"
+	"golang.org/x/crypto/bcrypt"
 	"google.golang.org/grpc"
+	"google.golang.org/grpc/codes"
 	"google.golang.org/grpc/metadata"
 	"google.golang.org/grpc/status"
-	"google.golang.org/grpc/codes"
-
 )
 
 func AuthServerUnaryInterceptor(ctx context.Context,
@@ -24,15 +22,14 @@ func AuthServerUnaryInterceptor(ctx context.Context,
 	// Skip authorize when GetJWT is requested
 
 	if info.FullMethod != "/node.NodeService/Login" {
-	if info.FullMethod != "/node.NodeService/CreateNode" {
+		if info.FullMethod != "/node.NodeService/CreateNode" {
 
-		err := grpcAuthorize(ctx)
-		if err != nil {
-			return nil, err
+			err := grpcAuthorize(ctx)
+			if err != nil {
+				return nil, err
+			}
 		}
 	}
-	}
-
 
 	// Calls the handler
 	h, err := handler(ctx, req)
@@ -40,66 +37,65 @@ func AuthServerUnaryInterceptor(ctx context.Context,
 	return h, err
 }
 func AuthServerStreamInterceptor(
-		srv interface{},
-		stream grpc.ServerStream,
-		info *grpc.StreamServerInfo,
-		handler grpc.StreamHandler,
-	) error {
-		if info.FullMethod == "/node.NodeService/GetPeers" {
-			if err := grpcAuthorize(stream.Context()); err != nil {
-				return err
-			}
+	srv interface{},
+	stream grpc.ServerStream,
+	info *grpc.StreamServerInfo,
+	handler grpc.StreamHandler,
+) error {
+	if info.FullMethod == "/node.NodeService/GetPeers" {
+		if err := grpcAuthorize(stream.Context()); err != nil {
+			return err
 		}
+	}
 
-
-		// Calls the handler
-		return handler(srv, stream)
+	// Calls the handler
+	return handler(srv, stream)
 }
 
 func grpcAuthorize(ctx context.Context) error {
 
+	md, ok := metadata.FromIncomingContext(ctx)
 
-		md, ok := metadata.FromIncomingContext(ctx)
-
-		if !ok {
-			return status.Errorf(codes.InvalidArgument, "Retrieving metadata is failed")
-		}
+	if !ok {
+		return status.Errorf(codes.InvalidArgument, "Retrieving metadata is failed")
+	}
 
-		authHeader, ok := md["authorization"]
-		if !ok {
-			return status.Errorf(codes.Unauthenticated, "Authorization token is not supplied")
-		}
+	authHeader, ok := md["authorization"]
+	if !ok {
+		return status.Errorf(codes.Unauthenticated, "Authorization token is not supplied")
+	}
 
-		authToken := authHeader[0]
+	authToken := authHeader[0]
 
-		mac, network, err := functions.VerifyToken(authToken)
+	mac, network, err := functions.VerifyToken(authToken)
 
-		if err  != nil { return err }
+	if err != nil {
+		return err
+	}
 
-                networkexists, err := functions.NetworkExists(network)
+	networkexists, err := functions.NetworkExists(network)
 
-		if err != nil {
-			return status.Errorf(codes.Unauthenticated, "Unauthorized. Network does not exist: " + network)
+	if err != nil {
+		return status.Errorf(codes.Unauthenticated, "Unauthorized. Network does not exist: "+network)
 
-		}
-		emptynode := models.Node{}
-		node, err := functions.GetNodeByMacAddress(network, mac)
-		if err != nil || node.MacAddress == emptynode.MacAddress {
-                        return status.Errorf(codes.Unauthenticated, "Node does not exist.")
-		}
+	}
+	emptynode := models.Node{}
+	node, err := functions.GetNodeByMacAddress(network, mac)
+	if err != nil || node.MacAddress == emptynode.MacAddress {
+		return status.Errorf(codes.Unauthenticated, "Node does not exist.")
+	}
 
-                //check that the request is for a valid network
-                //if (networkCheck && !networkexists) || err != nil {
-                if (!networkexists) {
+	//check that the request is for a valid network
+	//if (networkCheck && !networkexists) || err != nil {
+	if !networkexists {
 
-			return status.Errorf(codes.Unauthenticated, "Network does not exist.")
+		return status.Errorf(codes.Unauthenticated, "Network does not exist.")
 
-                } else {
-                        return nil
-                }
+	} else {
+		return nil
+	}
 }
 
-
 //Node authenticates using its password and retrieves a JWT for authorization.
 func (s *NodeServiceServer) Login(ctx context.Context, req *nodepb.LoginRequest) (*nodepb.LoginResponse, error) {
 
@@ -112,48 +108,50 @@ func (s *NodeServiceServer) Login(ctx context.Context, req *nodepb.LoginRequest)
 
 	err := errors.New("Generic server error.")
 
-
-        if macaddress == "" {
+	if macaddress == "" {
 		//TODO: Set Error  response
 		err = errors.New("Missing Mac Address.")
 		return nil, err
-        } else if password == "" {
-                err = errors.New("Missing Password.")
-                return nil, err
-        } else {
-            //Search DB for node with Mac Address. Ignore pending nodes (they should not be able to authenticate with API untill approved).
-            collection := mongoconn.Client.Database("netmaker").Collection("nodes")
-            ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-	    var err = collection.FindOne(ctx, bson.M{ "macaddress": macaddress, "network": network}).Decode(&result)
-
-            defer cancel()
-
-            if err != nil {
-                return nil, err
-            }
-
-           //compare password from request to stored password in database
-           //might be able to have a common hash (certificates?) and compare those so that a password isn't passed in in plain text...
-           //TODO: Consider a way of hashing the password client side before sending, or using certificates
-           err = bcrypt.CompareHashAndPassword([]byte(result.Password), []byte(password))
-	   if err != nil && result.Password != password {
-			return nil, err
-           } else {
-                //Create a new JWT for the node
-                tokenString, err := functions.CreateJWT(macaddress, result.Network)
-
+	} else if password == "" {
+		err = errors.New("Missing Password.")
+		return nil, err
+	} else {
+		//Search DB for node with Mac Address. Ignore pending nodes (they should not be able to authenticate with API untill approved).
+		collection, err := database.FetchRecords(database.NODES_TABLE_NAME)
 		if err != nil {
 			return nil, err
 		}
-                if tokenString == "" {
-		    err = errors.New("Something went wrong. Could not retrieve token.")
-                    return nil, err
-                }
+		for _, value := range collection {
+			if err = json.Unmarshal([]byte(value), &result); err != nil {
+				continue // finish going through nodes
+			}
+			if result.MacAddress == macaddress && result.Network == network {
+				break
+			}
+		}
+
+		//compare password from request to stored password in database
+		//might be able to have a common hash (certificates?) and compare those so that a password isn't passed in in plain text...
+		//TODO: Consider a way of hashing the password client side before sending, or using certificates
+		err = bcrypt.CompareHashAndPassword([]byte(result.Password), []byte(password))
+		if err != nil && result.Password != password {
+			return nil, err
+		} else {
+			//Create a new JWT for the node
+			tokenString, err := functions.CreateJWT(macaddress, result.Network)
 
-		response := &nodepb.LoginResponse{
+			if err != nil {
+				return nil, err
+			}
+			if tokenString == "" {
+				err = errors.New("Something went wrong. Could not retrieve token.")
+				return nil, err
+			}
+
+			response := &nodepb.LoginResponse{
 				Accesstoken: tokenString,
 			}
-		return response, nil
-        }
-    }
+			return response, nil
+		}
+	}
 }

+ 127 - 368
controllers/common.go

@@ -1,365 +1,163 @@
 package controller
 
 import (
-	"context"
+	"encoding/json"
 	"fmt"
 	"log"
+	"strconv"
+	"strings"
 	"time"
 
-	"github.com/go-playground/validator/v10"
+	"github.com/gravitl/netmaker/database"
 	"github.com/gravitl/netmaker/functions"
 	"github.com/gravitl/netmaker/models"
-	"github.com/gravitl/netmaker/mongoconn"
 	"github.com/gravitl/netmaker/servercfg"
 	"github.com/gravitl/netmaker/serverctl"
-	"go.mongodb.org/mongo-driver/bson"
-	"go.mongodb.org/mongo-driver/mongo/options"
 	"golang.org/x/crypto/bcrypt"
 )
 
 func GetPeersList(networkName string) ([]models.PeersResponse, error) {
 
 	var peers []models.PeersResponse
-
-	//Connection mongoDB with mongoconn class
-	collection := mongoconn.Client.Database("netmaker").Collection("nodes")
-
-	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-
-	//Get all nodes in the relevant network which are NOT in pending state
-	filter := bson.M{"network": networkName, "ispending": false}
-	cur, err := collection.Find(ctx, filter)
-
+	collection, err := database.FetchRecords(database.NODES_TABLE_NAME)
 	if err != nil {
-		return peers, err
+		log.Println(err)
 	}
-
-	// Close the cursor once finished and cancel if it takes too long
-	defer cancel()
-
-	for cur.Next(context.TODO()) {
-
+	udppeers, errN := serverctl.GetPeers(networkName)
+	if errN != nil {
+		log.Println(errN)
+	}
+	for _, value := range collection {
+		var node models.Node
 		var peer models.PeersResponse
-		err := cur.Decode(&peer)
+		err := json.Unmarshal([]byte(value), &node)
 		if err != nil {
-			log.Fatal(err)
+			log.Println(err)
+			continue
+		}
+		err = json.Unmarshal([]byte(value), &peer)
+		if err != nil {
+			log.Println(err)
+			continue
+		}
+		if node.IsEgressGateway == "yes" {
+			peer.EgressGatewayRanges = strings.Join(node.EgressGatewayRanges, ",")
+		}
+		if node.Network == networkName && node.IsPending != "yes" {
+			if node.UDPHolePunch == "yes" && errN == nil {
+				endpointstring := udppeers[peer.PublicKey]
+				endpointarr := strings.Split(endpointstring, ":")
+				if len(endpointarr) == 2 {
+					port, err := strconv.Atoi(endpointarr[1])
+					if err == nil {
+						peer.Endpoint = endpointarr[0]
+						peer.ListenPort = int32(port)
+					}
+				}
+			}
+			peers = append(peers, peer)
 		}
-
-		// add the node to our node array
-		//maybe better to just return this? But then that's just GetNodes...
-		peers = append(peers, peer)
 	}
-
-	//Uh oh, fatal error! This needs some better error handling
-	//TODO: needs appropriate error handling so the server doesnt shut down.
-	if err := cur.Err(); err != nil {
-		log.Fatal(err)
+	if err != nil {
+		return peers, err
 	}
 
 	return peers, err
 }
 
-
 func GetExtPeersList(networkName string, macaddress string) ([]models.ExtPeersResponse, error) {
 
-        var peers []models.ExtPeersResponse
-
-        //Connection mongoDB with mongoconn class
-        collection := mongoconn.Client.Database("netmaker").Collection("extclients")
-
-        ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-
-        //Get all nodes in the relevant network which are NOT in pending state
-	filter := bson.M{"network": networkName, "ingressgatewayid": macaddress}
-        cur, err := collection.Find(ctx, filter)
-
-        if err != nil {
-                return peers, err
-        }
-
-        // Close the cursor once finished and cancel if it takes too long
-        defer cancel()
-
-        for cur.Next(context.TODO()) {
-
-                var peer models.ExtPeersResponse
-                err := cur.Decode(&peer)
-                if err != nil {
-                        log.Fatal(err)
-                }
-
-                // add the node to our node array
-                //maybe better to just return this? But then that's just GetNodes...
-                peers = append(peers, peer)
-        }
-
-        //Uh oh, fatal error! This needs some better error handling
-        //TODO: needs appropriate error handling so the server doesnt shut down.
-        if err := cur.Err(); err != nil {
-                log.Fatal(err)
-        }
-
-        return peers, err
-}
-
-
-func ValidateNodeCreate(networkName string, node models.Node) error {
-	v := validator.New()
-	_ = v.RegisterValidation("macaddress_unique", func(fl validator.FieldLevel) bool {
-		var isFieldUnique bool = functions.IsFieldUnique(networkName, "macaddress", node.MacAddress)
-		return isFieldUnique
-	})
-	_ = v.RegisterValidation("network_exists", func(fl validator.FieldLevel) bool {
-		_, err := node.GetNetwork()
-		return err == nil
-	})
-        _ = v.RegisterValidation("in_charset", func(fl validator.FieldLevel) bool {
-                isgood := functions.NameInNodeCharSet(node.Name)
-                return isgood
-        })
-	err := v.Struct(node)
+	var peers []models.ExtPeersResponse
+	records, err := database.FetchRecords(database.EXT_CLIENT_TABLE_NAME)
 
 	if err != nil {
-		for _, e := range err.(validator.ValidationErrors) {
-			fmt.Println(e)
-		}
+		return peers, err
 	}
-	return err
-}
 
-func ValidateNodeUpdate(networkName string, node models.NodeUpdate) error {
-	v := validator.New()
-	_ = v.RegisterValidation("network_exists", func(fl validator.FieldLevel) bool {
-		_, err := node.GetNetwork()
-		return err == nil
-	})
-        _ = v.RegisterValidation("in_charset", func(fl validator.FieldLevel) bool {
-                isgood := functions.NameInNodeCharSet(node.Name)
-                return isgood
-        })
-	err := v.Struct(node)
-	if err != nil {
-		for _, e := range err.(validator.ValidationErrors) {
-			fmt.Println(e)
+	for _, value := range records {
+		var peer models.ExtPeersResponse
+		var extClient models.ExtClient
+		err = json.Unmarshal([]byte(value), &peer)
+		if err != nil {
+			functions.PrintUserLog("netmaker", "failed to unmarshal peer", 2)
+			continue
 		}
-	}
-	return err
-}
-
-func UpdateNode(nodechange models.NodeUpdate, node models.Node) (models.Node, error) {
-	//Question: Is there a better way  of doing  this than a bunch of "if" statements? probably...
-	//Eventually, lets have a better way to check if any of the fields are filled out...
-	queryMac := node.MacAddress
-	queryNetwork := node.Network
-	notifynetwork := false
-
-	if nodechange.Address != "" {
-		node.Address = nodechange.Address
-		notifynetwork = true
-	}
-	if nodechange.Address6 != "" {
-		node.Address6 = nodechange.Address6
-		notifynetwork = true
-	}
-	if nodechange.Name != "" {
-		node.Name = nodechange.Name
-	}
-	if nodechange.LocalAddress != "" {
-		node.LocalAddress = nodechange.LocalAddress
-	}
-	if nodechange.ListenPort != 0 {
-		node.ListenPort = nodechange.ListenPort
-	}
-	if nodechange.ExpirationDateTime != 0 {
-		node.ExpirationDateTime = nodechange.ExpirationDateTime
-	}
-	if nodechange.PostDown != "" {
-		node.PostDown = nodechange.PostDown
-	}
-	if nodechange.Interface != "" {
-		node.Interface = nodechange.Interface
-	}
-	if nodechange.PostUp != "" {
-		node.PostUp = nodechange.PostUp
-	}
-	if nodechange.AccessKey != "" {
-		node.AccessKey = nodechange.AccessKey
-	}
-	if nodechange.Endpoint != "" {
-		node.Endpoint = nodechange.Endpoint
-		notifynetwork = true
-	}
-	if nodechange.SaveConfig != nil {
-		node.SaveConfig = nodechange.SaveConfig
-	}
-	if nodechange.PersistentKeepalive != 0 {
-		node.PersistentKeepalive = nodechange.PersistentKeepalive
-	}
-	if nodechange.Password != "" {
-		err := bcrypt.CompareHashAndPassword([]byte(nodechange.Password), []byte(node.Password))
-		if err != nil && nodechange.Password != node.Password {
-			hash, err := bcrypt.GenerateFromPassword([]byte(nodechange.Password), 5)
-			if err != nil {
-				return node, err
-			}
-			nodechange.Password = string(hash)
-			node.Password = nodechange.Password
+		err = json.Unmarshal([]byte(value), &extClient)
+		if err != nil {
+			functions.PrintUserLog("netmaker", "failed to unmarshal ext client", 2)
+			continue
+		}
+		if extClient.Network == networkName && extClient.IngressGatewayID == macaddress {
+			peers = append(peers, peer)
 		}
 	}
-	if nodechange.MacAddress != "" {
-		node.MacAddress = nodechange.MacAddress
-	}
-	if nodechange.PublicKey != "" {
-		node.PublicKey = nodechange.PublicKey
-		node.KeyUpdateTimeStamp = time.Now().Unix()
-		notifynetwork = true
-	}
-
-	//collection := mongoconn.ConnectDB()
-	collection := mongoconn.Client.Database("netmaker").Collection("nodes")
-
-	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-
-	// Create filter
-	filter := bson.M{"macaddress": queryMac, "network": queryNetwork}
-
-	node.SetLastModified()
-
-	// prepare update model.
-	update := bson.D{
-		{"$set", bson.D{
-			{"address", node.Address},
-			{"address6", node.Address6},
-			{"name", node.Name},
-			{"password", node.Password},
-			{"listenport", node.ListenPort},
-			{"publickey", node.PublicKey},
-			{"keyupdatetimestamp", node.KeyUpdateTimeStamp},
-			{"expdatetime", node.ExpirationDateTime},
-			{"endpoint", node.Endpoint},
-			{"postup", node.PostUp},
-			{"postdown", node.PostDown},
-			{"macaddress", node.MacAddress},
-			{"localaddress", node.LocalAddress},
-			{"persistentkeepalive", node.PersistentKeepalive},
-			{"saveconfig", node.SaveConfig},
-			{"accesskey", node.AccessKey},
-			{"interface", node.Interface},
-			{"lastmodified", node.LastModified},
-		}},
-	}
-	var nodeupdate models.Node
-	errN := collection.FindOneAndUpdate(ctx, filter, update).Decode(&nodeupdate)
-	if errN != nil {
-		return nodeupdate, errN
-	}
-
-	if nodechange.MacAddress != "" {
-		queryMac = nodechange.MacAddress
-	}
-	returnnode, errN := GetNode(queryMac, queryNetwork)
-
-	defer cancel()
-
-	if notifynetwork {
-		errN = SetNetworkNodesLastModified(queryNetwork)
-	}
-	if servercfg.IsDNSMode() {
-		errN = SetDNS()
-	}
-
-	return returnnode, errN
+	return peers, err
 }
 
-func DeleteNode(macaddress string, network string) (bool, error) {
-
-	deleted := false
-
-	collection := mongoconn.Client.Database("netmaker").Collection("nodes")
-
-	filter := bson.M{"macaddress": macaddress, "network": network}
+func DeleteNode(macaddress string, network string) error {
 
-	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-
-	result, err := collection.DeleteOne(ctx, filter)
-
-	deletecount := result.DeletedCount
-
-	if deletecount > 0 {
-		deleted = true
+	key, err := functions.GetRecordKey(macaddress, network)
+	if err != nil {
+		return err
+	}
+	if err = database.DeleteRecord(database.NODES_TABLE_NAME, key); err != nil {
+		return err
 	}
-
-	defer cancel()
 
 	err = SetNetworkNodesLastModified(network)
-	fmt.Println("Deleted node " + macaddress + " from network " + network)
 	if servercfg.IsDNSMode() {
 		err = SetDNS()
 	}
 
-	return deleted, err
+	return err
 }
 
 func DeleteIntClient(clientid string) (bool, error) {
 
-        deleted := false
-
-        collection := mongoconn.Client.Database("netmaker").Collection("intclients")
-
-        filter := bson.M{"clientid": clientid}
-
-        ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-
-        result, err := collection.DeleteOne(ctx, filter)
-
-        deletecount := result.DeletedCount
-
-        if deletecount > 0 {
-                deleted = true
-        }
-
-        defer cancel()
-
-	err = serverctl.ReconfigureServerWireGuard()
+	err := database.DeleteRecord(database.INT_CLIENTS_TABLE_NAME, clientid)
+	if err != nil {
+		return false, err
+	}
 
-        return deleted, err
+	return true, nil
 }
 
 func GetNode(macaddress string, network string) (models.Node, error) {
 
 	var node models.Node
 
-	collection := mongoconn.Client.Database("netmaker").Collection("nodes")
-
-	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-
-	filter := bson.M{"macaddress": macaddress, "network": network}
-	err := collection.FindOne(ctx, filter, options.FindOne().SetProjection(bson.M{"_id": 0})).Decode(&node)
-
-	defer cancel()
+	key, err := functions.GetRecordKey(macaddress, network)
+	if err != nil {
+		return node, err
+	}
+	data, err := database.FetchRecord(database.NODES_TABLE_NAME, key)
+	if err != nil {
+		return node, err
+	}
+	if err = json.Unmarshal([]byte(data), &node); err != nil {
+		return node, err
+	}
 
 	return node, err
 }
 
 func GetIntClient(clientid string) (models.IntClient, error) {
 
-        var client models.IntClient
+	var client models.IntClient
 
-        collection := mongoconn.Client.Database("netmaker").Collection("intclients")
-
-        ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-
-        filter := bson.M{"clientid": clientid}
-        err := collection.FindOne(ctx, filter, options.FindOne().SetProjection(bson.M{"_id": 0})).Decode(&clientid)
-
-        defer cancel()
-
-        return client, err
+	value, err := database.FetchRecord(database.INT_CLIENTS_TABLE_NAME, clientid)
+	if err != nil {
+		return client, err
+	}
+	if err = json.Unmarshal([]byte(value), &client); err != nil {
+		return models.IntClient{}, err
+	}
+	return client, nil
 }
 
 func CreateNode(node models.Node, networkName string) (models.Node, error) {
 
-	//encrypt that password so we never see it again
+	//encrypt that password so we never see it
 	hash, err := bcrypt.GenerateFromPassword([]byte(node.Password), 5)
 
 	if err != nil {
@@ -370,62 +168,41 @@ func CreateNode(node models.Node, networkName string) (models.Node, error) {
 
 	node.Network = networkName
 
-	//node.SetDefaults()
-	//Umm, why am I doing this again?
-	//TODO: Why am I using a local function instead of the struct function? I really dont know.
-	//I think I thought it didn't work but uhhh...idk
 	node.SetDefaults()
-
-	//Another DB call here...Inefficient
-	//Anyways, this scrolls through all the IP Addresses in the network range and checks against nodes
-	//until one is open and then returns it
 	node.Address, err = functions.UniqueAddress(networkName)
 	if err != nil {
 		return node, err
 	}
-
 	node.Address6, err = functions.UniqueAddress6(networkName)
-
 	if err != nil {
 		return node, err
 	}
-
-	//IDK why these aren't a part of "set defaults. Pretty dumb.
-	//TODO: This is dumb. Consolidate and fix.
-	node.SetLastModified()
-	node.SetDefaultName()
-	node.SetLastCheckIn()
-	node.SetLastPeerUpdate()
-	node.KeyUpdateTimeStamp = time.Now().Unix()
-
 	//Create a JWT for the node
 	tokenString, _ := functions.CreateJWT(node.MacAddress, networkName)
-
 	if tokenString == "" {
 		//returnErrorResponse(w, r, errorResponse)
 		return node, err
 	}
-
-	// connect db
-	collection := mongoconn.Client.Database("netmaker").Collection("nodes")
-	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-
-	// insert our node to the node db.
-	result, err := collection.InsertOne(ctx, node)
-	_ = result
-
-	defer cancel()
-
+	err = node.Validate(false)
 	if err != nil {
 		return node, err
 	}
-	//return response for if node  is pending
-	if !node.IsPending {
 
+	key, err := functions.GetRecordKey(node.MacAddress, node.Network)
+	if err != nil {
+		return node, err
+	}
+	nodebytes, err := json.Marshal(&node)
+	if err != nil {
+		return node, err
+	}
+	err = database.Insert(key, string(nodebytes), database.NODES_TABLE_NAME)
+	if err != nil {
+		return node, err
+	}
+	if node.IsPending != "yes" {
 		functions.DecrimentKey(node.Network, node.AccessKey)
-
 	}
-
 	SetNetworkNodesLastModified(node.Network)
 	if servercfg.IsDNSMode() {
 		err = SetDNS()
@@ -443,12 +220,12 @@ func NodeCheckIn(node models.Node, networkName string) (models.CheckInResponse,
 		return response, err
 	}
 
-	parentnode, err := functions.GetNodeByMacAddress(networkName, node.MacAddress)
+	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 {
+	if parentnode.IsPending == "yes" {
 		err = fmt.Errorf("%w; Node checking in is still pending: "+node.MacAddress, err)
 		response.IsPending = true
 		return response, err
@@ -477,7 +254,7 @@ func NodeCheckIn(node models.Node, networkName string) (models.CheckInResponse,
 	}
 	if time.Now().Unix() > parentnode.ExpirationDateTime {
 		response.NeedDelete = true
-		_, err = DeleteNode(node.MacAddress, networkName)
+		err = DeleteNode(node.MacAddress, networkName)
 	} else {
 		err = TimestampNode(parentnode, true, false, false)
 
@@ -495,28 +272,19 @@ func SetNetworkNodesLastModified(networkName string) error {
 
 	timestamp := time.Now().Unix()
 
-	collection := mongoconn.Client.Database("netmaker").Collection("networks")
-
-	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-
-	// Create filter
-	filter := bson.M{"netid": networkName}
-
-	// prepare update model.
-	update := bson.D{
-		{"$set", bson.D{
-			{"nodeslastmodified", timestamp},
-		}},
+	network, err := functions.GetParentNetwork(networkName)
+	if err != nil {
+		return err
 	}
-
-	result := collection.FindOneAndUpdate(ctx, filter, update)
-
-	defer cancel()
-
-	if result.Err() != nil {
-		return result.Err()
+	network.NodesLastModified = timestamp
+	data, err := json.Marshal(&network)
+	if err != nil {
+		return err
+	}
+	err = database.Insert(networkName, string(data), database.NETWORKS_TABLE_NAME)
+	if err != nil {
+		return err
 	}
-
 	return nil
 }
 
@@ -531,25 +299,16 @@ func TimestampNode(node models.Node, updatecheckin bool, updatepeers bool, updat
 		node.SetLastPeerUpdate()
 	}
 
-	collection := mongoconn.Client.Database("netmaker").Collection("nodes")
-
-	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-
-	// Create filter
-	filter := bson.M{"macaddress": node.MacAddress, "network": node.Network}
-
-	// prepare update model.
-	update := bson.D{
-		{"$set", bson.D{
-			{"lastmodified", node.LastModified},
-			{"lastpeerupdate", node.LastPeerUpdate},
-			{"lastcheckin", node.LastCheckIn},
-		}},
+	key, err := functions.GetRecordKey(node.MacAddress, node.Network)
+	if err != nil {
+		return err
+	}
+	value, err := json.Marshal(&node)
+	if err != nil {
+		return err
 	}
 
-	var nodeupdate models.Node
-	err := collection.FindOneAndUpdate(ctx, filter, update).Decode(&nodeupdate)
-	defer cancel()
+	err = database.Insert(key, string(value), database.NODES_TABLE_NAME)
 
 	return err
 }

+ 11 - 19
controllers/common_test.go

@@ -1,14 +1,13 @@
 package controller
 
 import (
-	"context"
+	"encoding/json"
 	"testing"
 	"time"
 
+	"github.com/gravitl/netmaker/database"
 	"github.com/gravitl/netmaker/models"
-	"github.com/gravitl/netmaker/mongoconn"
 	"github.com/stretchr/testify/assert"
-	"go.mongodb.org/mongo-driver/bson"
 )
 
 type NodeValidationTC struct {
@@ -51,14 +50,12 @@ func TestDeleteNode(t *testing.T) {
 	createNet()
 	node := createTestNode(t)
 	t.Run("NodeExists", func(t *testing.T) {
-		deleted, err := DeleteNode(node.MacAddress, node.Network)
+		err := DeleteNode(node.MacAddress, node.Network)
 		assert.Nil(t, err)
-		assert.True(t, deleted)
 	})
 	t.Run("NonExistantNode", func(t *testing.T) {
-		deleted, err := DeleteNode(node.MacAddress, node.Network)
+		err := DeleteNode(node.MacAddress, node.Network)
 		assert.Nil(t, err)
-		assert.False(t, deleted)
 	})
 }
 func TestGetNode(t *testing.T) {
@@ -89,7 +86,7 @@ func TestGetNode(t *testing.T) {
 		assert.Equal(t, "mongo: no documents in result", err.Error())
 	})
 	t.Run("NoNode", func(t *testing.T) {
-		_, _ = DeleteNode("01:02:03:04:05:06", "skynet")
+		_ = DeleteNode("01:02:03:04:05:06", "skynet")
 		response, err := GetNode(node.MacAddress, node.Network)
 		assert.NotNil(t, err)
 		assert.Equal(t, models.Node{}, response)
@@ -110,7 +107,7 @@ func TestGetPeerList(t *testing.T) {
 		t.Log(peers)
 	})
 	t.Run("NoNodes", func(t *testing.T) {
-		_, _ = DeleteNode("01:02:03:04:05:06", "skynet")
+		_ = DeleteNode("01:02:03:04:05:06", "skynet")
 		peers, err := GetPeersList("skynet")
 		assert.Nil(t, err)
 		assert.Equal(t, []models.PeersResponse(nil), peers)
@@ -178,17 +175,12 @@ func TestNodeCheckIn(t *testing.T) {
 		newtime := time.Now().Add(time.Hour * 24).Unix()
 		t.Log(newtime, time.Now().Unix())
 		//this is cheating; but can't find away to update timestamp through existing api
-		collection := mongoconn.Client.Database("netmaker").Collection("networks")
-		ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-		filter := bson.M{"netid": "skynet"}
-		update := bson.D{
-			{"$set", bson.D{
-				{"keyupdatetimestamp", newtime},
-			}},
-		}
-		defer cancel()
-		err := collection.FindOneAndUpdate(ctx, filter, update).Decode(&network)
+
+		record, err := database.FetchRecord(database.NETWORKS_TABLE_NAME, "skynet")
+		assert.Nil(t, err)
+		err = json.Unmarshal([]byte(record), &network)
 		assert.Nil(t, err)
+		network.KeyUpdateTimeStamp = newtime
 		response, err := NodeCheckIn(node, "skynet")
 		assert.Nil(t, err)
 		assert.Equal(t, true, response.Success)

+ 41 - 43
controllers/controller.go

@@ -1,63 +1,61 @@
 package controller
 
 import (
-    "github.com/gravitl/netmaker/mongoconn"
-    "github.com/gravitl/netmaker/servercfg"
-    "os/signal"
-    "os"
-    "log"
-    "context"
-    "net/http"
-    "github.com/gorilla/mux"
-    "github.com/gorilla/handlers"
-    "sync"
+	"context"
+	"log"
+	"net/http"
+	"os"
+	"os/signal"
+	"sync"
+
+	"github.com/gorilla/handlers"
+	"github.com/gorilla/mux"
+	"github.com/gravitl/netmaker/servercfg"
 )
 
-
 func HandleRESTRequests(wg *sync.WaitGroup) {
-    defer wg.Done()
+	defer wg.Done()
 
-    r := mux.NewRouter()
+	r := mux.NewRouter()
 
-    // Currently allowed dev origin is all. Should change in prod
-    // should consider analyzing the allowed methods further
-    headersOk := handlers.AllowedHeaders([]string{"Access-Control-Allow-Origin", "X-Requested-With", "Content-Type", "authorization"})
-    originsOk := handlers.AllowedOrigins([]string{servercfg.GetAllowedOrigin()})
-    methodsOk := handlers.AllowedMethods([]string{"GET", "PUT", "POST", "DELETE"})
+	// Currently allowed dev origin is all. Should change in prod
+	// should consider analyzing the allowed methods further
+	headersOk := handlers.AllowedHeaders([]string{"Access-Control-Allow-Origin", "X-Requested-With", "Content-Type", "authorization"})
+	originsOk := handlers.AllowedOrigins([]string{servercfg.GetAllowedOrigin()})
+	methodsOk := handlers.AllowedMethods([]string{"GET", "PUT", "POST", "DELETE"})
 
-    nodeHandlers(r)
-    userHandlers(r)
-    networkHandlers(r)
-    dnsHandlers(r)
-    fileHandlers(r)
-    serverHandlers(r)
-    extClientHandlers(r)
-    intClientHandlers(r)
+	nodeHandlers(r)
+	userHandlers(r)
+	networkHandlers(r)
+	dnsHandlers(r)
+	fileHandlers(r)
+	serverHandlers(r)
+	extClientHandlers(r)
+	intClientHandlers(r)
 
-		port := servercfg.GetAPIPort()
+	port := servercfg.GetAPIPort()
 
-		srv := &http.Server{Addr: ":" + port, Handler: handlers.CORS(originsOk, headersOk, methodsOk)(r)}
-		go func(){
+	srv := &http.Server{Addr: ":" + port, Handler: handlers.CORS(originsOk, headersOk, methodsOk)(r)}
+	go func() {
 		err := srv.ListenAndServe()
 		if err != nil {
 			log.Println(err)
 		}
-		}()
+	}()
 
-		log.Println("REST Server succesfully started on port " + port + " (REST)")
-		c := make(chan os.Signal)
+	log.Println("REST Server succesfully started on port " + port + " (REST)")
+	c := make(chan os.Signal)
 
-		// Relay os.Interrupt to our channel (os.Interrupt = CTRL+C)
-		// Ignore other incoming signals
-		signal.Notify(c, os.Interrupt)
+	// Relay os.Interrupt to our channel (os.Interrupt = CTRL+C)
+	// Ignore other incoming signals
+	signal.Notify(c, os.Interrupt)
 
-		// Block main routine until a signal is received
-		// As long as user doesn't press CTRL+C a message is not passed and our main routine keeps running
-		<-c
+	// Block main routine until a signal is received
+	// As long as user doesn't press CTRL+C a message is not passed and our main routine keeps running
+	<-c
 
-		// After receiving CTRL+C Properly stop the server
-		log.Println("Stopping the REST server...")
-		srv.Shutdown(context.TODO())
-                log.Println("REST Server closed.")
-		mongoconn.Client.Disconnect(context.TODO())
+	// After receiving CTRL+C Properly stop the server
+	log.Println("Stopping the REST server...")
+	srv.Shutdown(context.TODO())
+	log.Println("REST Server closed.")
 }

+ 75 - 132
controllers/dnsHttpController.go

@@ -1,21 +1,16 @@
 package controller
 
 import (
-	"context"
 	"encoding/json"
-	"errors"
 	"fmt"
 	"net/http"
-	"time"
-
+	"log"
 	"github.com/go-playground/validator/v10"
 	"github.com/gorilla/mux"
+	"github.com/gravitl/netmaker/database"
 	"github.com/gravitl/netmaker/functions"
 	"github.com/gravitl/netmaker/models"
-	"github.com/gravitl/netmaker/mongoconn"
 	"github.com/txn2/txeh"
-	"go.mongodb.org/mongo-driver/bson"
-	"go.mongodb.org/mongo-driver/mongo/options"
 )
 
 func dnsHandlers(r *mux.Router) {
@@ -64,7 +59,7 @@ func getAllDNS(w http.ResponseWriter, r *http.Request) {
 
 func GetAllDNS() ([]models.DNSEntry, error) {
 	var dns []models.DNSEntry
-	networks, err := functions.ListNetworks()
+	networks, err := models.GetNetworks()
 	if err != nil {
 		return []models.DNSEntry{}, err
 	}
@@ -82,39 +77,23 @@ func GetNodeDNS(network string) ([]models.DNSEntry, error) {
 
 	var dns []models.DNSEntry
 
-	collection := mongoconn.Client.Database("netmaker").Collection("nodes")
-
-	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-
-	filter := bson.M{"network": network}
-
-	cur, err := collection.Find(ctx, filter, options.Find().SetProjection(bson.M{"_id": 0}))
-
+	collection, err := database.FetchRecords(database.NODES_TABLE_NAME)
 	if err != nil {
 		return dns, err
 	}
 
-	defer cancel()
-
-	for cur.Next(context.TODO()) {
-
+	for _, value := range collection {
 		var entry models.DNSEntry
-
-		err := cur.Decode(&entry)
-		if err != nil {
-			return dns, err
+		var node models.Node
+		if err = json.Unmarshal([]byte(value), &node); err != nil {
+			continue
+		}
+		if err = json.Unmarshal([]byte(value), &entry); node.Network == network && err == nil {
+			dns = append(dns, entry)
 		}
-
-		// add item our array of nodes
-		dns = append(dns, entry)
-	}
-
-	//TODO: Another fatal error we should take care of.
-	if err := cur.Err(); err != nil {
-		return dns, err
 	}
 
-	return dns, err
+	return dns, nil
 }
 
 //Gets all nodes associated with network, including pending nodes
@@ -140,36 +119,19 @@ func GetCustomDNS(network string) ([]models.DNSEntry, error) {
 
 	var dns []models.DNSEntry
 
-	collection := mongoconn.Client.Database("netmaker").Collection("dns")
-
-	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-
-	filter := bson.M{"network": network}
-
-	cur, err := collection.Find(ctx, filter, options.Find().SetProjection(bson.M{"_id": 0}))
-
+	collection, err := database.FetchRecords(database.DNS_TABLE_NAME)
 	if err != nil {
 		return dns, err
 	}
-
-	defer cancel()
-
-	for cur.Next(context.TODO()) {
-
+	for _, value := range collection { // filter for entries based on network
 		var entry models.DNSEntry
-
-		err := cur.Decode(&entry)
-		if err != nil {
-			return dns, err
+		if err := json.Unmarshal([]byte(value), &entry); err != nil {
+			continue
 		}
 
-		// add item our array of nodes
-		dns = append(dns, entry)
-	}
-
-	//TODO: Another fatal error we should take care of.
-	if err := cur.Err(); err != nil {
-		return dns, err
+		if entry.Network == network {
+			dns = append(dns, entry)
+		}
 	}
 
 	return dns, err
@@ -178,7 +140,7 @@ func GetCustomDNS(network string) ([]models.DNSEntry, error) {
 func SetDNS() error {
 	hostfile := txeh.Hosts{}
 	var corefilestring string
-	networks, err := functions.ListNetworks()
+	networks, err := models.GetNetworks()
 	if err != nil {
 		return err
 	}
@@ -282,6 +244,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
+        }
 	w.WriteHeader(http.StatusOK)
 	json.NewEncoder(w).Encode(entry)
 }
@@ -332,7 +299,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
+        }
 	json.NewEncoder(w).Encode(entry)
 }
 
@@ -343,109 +314,83 @@ func deleteDNS(w http.ResponseWriter, r *http.Request) {
 	// get params
 	var params = mux.Vars(r)
 
-	success, err := DeleteDNS(params["domain"], params["network"])
+	err := DeleteDNS(params["domain"], params["network"])
 
 	if err != nil {
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
-	} else if !success {
-		returnErrorResponse(w, r, formatError(errors.New("Delete unsuccessful."), "badrequest"))
-		return
 	}
-
-	json.NewEncoder(w).Encode(params["domain"] + " deleted.")
+	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
+        }
+	json.NewEncoder(w).Encode(entrytext + " deleted.")
 }
 
 func CreateDNS(entry models.DNSEntry) (models.DNSEntry, error) {
 
-	// connect db
-	collection := mongoconn.Client.Database("netmaker").Collection("dns")
-	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-
-	// insert our node to the node db.
-	_, err := collection.InsertOne(ctx, entry)
-
-	defer cancel()
+	data, err := json.Marshal(&entry)
+	if err != nil {
+		return models.DNSEntry{}, err
+	}
+	key, err := functions.GetRecordKey(entry.Name, entry.Network)
+	if err != nil {
+		return models.DNSEntry{}, err
+	}
+	err = database.Insert(key, string(data), database.DNS_TABLE_NAME)
 
 	return entry, err
 }
 
 func GetDNSEntry(domain string, network string) (models.DNSEntry, error) {
 	var entry models.DNSEntry
-
-	collection := mongoconn.Client.Database("netmaker").Collection("dns")
-
-	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-
-	filter := bson.M{"name": domain, "network": network}
-	err := collection.FindOne(ctx, filter, options.FindOne().SetProjection(bson.M{"_id": 0})).Decode(&entry)
-
-	defer cancel()
-
+	key, err := functions.GetRecordKey(domain, network)
+	if err != nil {
+		return entry, err
+	}
+	record, err := database.FetchRecord(database.DNS_TABLE_NAME, key)
+	if err != nil {
+		return entry, err
+	}
+	err = json.Unmarshal([]byte(record), &entry)
 	return entry, err
 }
 
 func UpdateDNS(dnschange models.DNSEntry, entry models.DNSEntry) (models.DNSEntry, error) {
 
-	queryDNS := entry.Name
-
+	key, err := functions.GetRecordKey(entry.Name, entry.Network)
+	if err != nil {
+		return entry, err
+	}
 	if dnschange.Name != "" {
 		entry.Name = dnschange.Name
 	}
 	if dnschange.Address != "" {
 		entry.Address = dnschange.Address
 	}
-	//collection := mongoconn.ConnectDB()
-	collection := mongoconn.Client.Database("netmaker").Collection("dns")
-
-	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
+	newkey, err := functions.GetRecordKey(entry.Name, entry.Network)
 
-	// Create filter
-	filter := bson.M{"name": queryDNS}
-
-	// prepare update model.
-	update := bson.D{
-		{"$set", bson.D{
-			{"name", entry.Name},
-			{"address", entry.Address},
-		}},
-	}
-	var dnsupdate models.DNSEntry
-
-	errN := collection.FindOneAndUpdate(ctx, filter, update).Decode(&dnsupdate)
-	if errN != nil {
-		fmt.Println("Could not update: ")
-		fmt.Println(errN)
-	} else {
-		fmt.Println("DNS Entry updated successfully.")
+	err = database.DeleteRecord(database.DNS_TABLE_NAME, key)
+	if err != nil {
+		return entry, err
 	}
 
-	defer cancel()
+	data, err := json.Marshal(&entry)
+	err = database.Insert(newkey, string(data), database.DNS_TABLE_NAME)
+	return entry, err
 
-	return dnsupdate, errN
 }
 
-func DeleteDNS(domain string, network string) (bool, error) {
-	fmt.Println("delete dns entry ", domain, network)
-	deleted := false
-
-	collection := mongoconn.Client.Database("netmaker").Collection("dns")
-
-	filter := bson.M{"name": domain, "network": network}
-
-	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-
-	result, err := collection.DeleteOne(ctx, filter)
-
-	deletecount := result.DeletedCount
-
-	if deletecount > 0 {
-		deleted = true
+func DeleteDNS(domain string, network string) error {
+	key, err := functions.GetRecordKey(domain, network)
+	if err != nil {
+		return err
 	}
-
-	defer cancel()
-
-	return deleted, err
+	err = database.DeleteRecord(database.DNS_TABLE_NAME, key)
+	return err
 }
 
 func pushDNS(w http.ResponseWriter, r *http.Request) {
@@ -458,15 +403,13 @@ func pushDNS(w http.ResponseWriter, r *http.Request) {
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 	}
+	log.Println("pushed DNS updates to nameserver")
 	json.NewEncoder(w).Encode("DNS Pushed to CoreDNS")
 }
 
 func ValidateDNSCreate(entry models.DNSEntry) error {
 
 	v := validator.New()
-	fmt.Println("Validating DNS: " + entry.Name)
-	fmt.Println("       Address: " + entry.Address)
-	fmt.Println("       Network: " + entry.Network)
 
 	_ = v.RegisterValidation("name_unique", func(fl validator.FieldLevel) bool {
 		num, err := GetDNSEntryNum(entry.Name, entry.Network)

+ 4 - 6
controllers/dnsHttpController_test.go

@@ -54,21 +54,19 @@ func TestUpdateDNS(t *testing.T) {
 }
 func TestDeleteDNS(t *testing.T) {
 	t.Run("EntryExists", func(t *testing.T) {
-		success, err := DeleteDNS("myhost", "skynet")
+		err := DeleteDNS("myhost", "skynet")
 		assert.Nil(t, err)
-		assert.True(t, success)
 	})
 	t.Run("NoEntry", func(t *testing.T) {
-		success, err := DeleteDNS("myhost", "skynet")
+		err := DeleteDNS("myhost", "skynet")
 		assert.Nil(t, err)
-		assert.False(t, success)
 	})
 
 }
 
 func TestValidateDNSUpdate(t *testing.T) {
 	entry := models.DNSEntry{"10.0.0.2", "myhost", "skynet"}
-	_, _ = DeleteDNS("mynode", "skynet")
+	_ = DeleteDNS("mynode", "skynet")
 	t.Run("BadNetwork", func(t *testing.T) {
 		change := models.DNSEntry{"10.0.0.2", "myhost", "badnet"}
 		err := ValidateDNSUpdate(change, entry)
@@ -129,7 +127,7 @@ func TestValidateDNSUpdate(t *testing.T) {
 
 }
 func TestValidateDNSCreate(t *testing.T) {
-	_, _ = DeleteDNS("mynode", "skynet")
+	_ = DeleteDNS("mynode", "skynet")
 	t.Run("NoNetwork", func(t *testing.T) {
 		entry := models.DNSEntry{"10.0.0.2", "myhost", "badnet"}
 		err := ValidateDNSCreate(entry)

+ 120 - 156
controllers/extClientHttpController.go

@@ -1,25 +1,23 @@
 package controller
 
 import (
-	"context"
 	"encoding/json"
-	"io"
 	"errors"
 	"fmt"
-        "math/rand"
+	"io"
+	"math/rand"
 
 	// "fmt"
 	"net/http"
-	"time"
 	"strconv"
+	"time"
+
 	"github.com/gorilla/mux"
+	"github.com/gravitl/netmaker/database"
 	"github.com/gravitl/netmaker/functions"
 	"github.com/gravitl/netmaker/models"
-	"github.com/gravitl/netmaker/mongoconn"
-	"go.mongodb.org/mongo-driver/bson"
-	"go.mongodb.org/mongo-driver/mongo/options"
-	"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
 	"github.com/skip2/go-qrcode"
+	"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
 )
 
 func extClientHandlers(r *mux.Router) {
@@ -75,7 +73,7 @@ func checkIngressExists(network string, macaddress string) bool {
 	if err != nil {
 		return false
 	}
-	return node.IsIngressGateway
+	return node.IsIngressGateway == "yes"
 }
 
 //Gets all extclients associated with network, including pending extclients
@@ -98,34 +96,22 @@ func getNetworkExtClients(w http.ResponseWriter, r *http.Request) {
 
 func GetNetworkExtClients(network string) ([]models.ExtClient, error) {
 	var extclients []models.ExtClient
-	collection := mongoconn.Client.Database("netmaker").Collection("extclients")
-	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-	filter := bson.M{"network": network}
-	//Filtering out the ID field cuz Dillon doesn't like it. May want to filter out other fields in the future
-	cur, err := collection.Find(ctx, filter, options.Find().SetProjection(bson.M{"_id": 0}))
+
+	records, err := database.FetchRecords(database.EXT_CLIENT_TABLE_NAME)
 	if err != nil {
-		return []models.ExtClient{}, err
-	}
-	defer cancel()
-	for cur.Next(context.TODO()) {
-		//Using a different model for the ReturnExtClient (other than regular extclient).
-		//Either we should do this for ALL structs (so Networks and Keys)
-		//OR we should just use the original struct
-		//My preference is to make some new return structs
-		//TODO: Think about this. Not an immediate concern. Just need to get some consistency eventually
+		return extclients, err
+	}
+	for _, value := range records {
 		var extclient models.ExtClient
-		err := cur.Decode(&extclient)
+		err = json.Unmarshal([]byte(value), &extclient)
 		if err != nil {
-			return []models.ExtClient{}, err
+			continue
+		}
+		if extclient.Network == network {
+			extclients = append(extclients, extclient)
 		}
-		// add item our array of extclients
-		extclients = append(extclients, extclient)
-	}
-	//TODO: Another fatal error we should take care of.
-	if err := cur.Err(); err != nil {
-		return []models.ExtClient{}, err
 	}
-	return extclients, nil
+	return extclients, err
 }
 
 //A separate function to get all extclients, not just extclients for a particular network.
@@ -149,58 +135,60 @@ func getExtClient(w http.ResponseWriter, r *http.Request) {
 
 	var params = mux.Vars(r)
 
-	var extclient models.ExtClient
-
-	collection := mongoconn.Client.Database("netmaker").Collection("extclients")
-
-	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-
-	filter := bson.M{"network": params["network"], "clientid": params["clientid"]}
-	err := collection.FindOne(ctx, filter, options.FindOne().SetProjection(bson.M{"_id": 0})).Decode(&extclient)
+	clientid := params["clientid"]
+	network := params["network"]
+	client, err := GetExtClient(clientid, network)
 	if err != nil {
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 	}
 
-	defer cancel()
-
 	w.WriteHeader(http.StatusOK)
-	json.NewEncoder(w).Encode(extclient)
+	json.NewEncoder(w).Encode(client)
 }
 
-//Get an individual extclient. Nothin fancy here folks.
-func getExtClientConf(w http.ResponseWriter, r *http.Request) {
-        // set header.
-        w.Header().Set("Content-Type", "application/json")
-
-        var params = mux.Vars(r)
+func GetExtClient(clientid string, network string) (models.ExtClient, error) {
+	var extclient models.ExtClient
+	key, err := functions.GetRecordKey(clientid, network)
+	if err != nil {
+		return extclient, err
+	}
+	data, err := database.FetchRecord(database.EXT_CLIENT_TABLE_NAME, key)
+	if err != nil {
+		return extclient, err
+	}
+	err = json.Unmarshal([]byte(data), &extclient)
 
-        var extclient models.ExtClient
+	return extclient, err
+}
 
-        collection := mongoconn.Client.Database("netmaker").Collection("extclients")
+//Get an individual extclient. Nothin fancy here folks.
+func getExtClientConf(w http.ResponseWriter, r *http.Request) {
+	// set header.
+	w.Header().Set("Content-Type", "application/json")
 
-        ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
+	var params = mux.Vars(r)
+	clientid := params["clientid"]
+	networkid := params["network"]
+	client, err := GetExtClient(clientid, networkid)
+	if err != nil {
+		returnErrorResponse(w, r, formatError(err, "internal"))
+		return
+	}
 
-        filter := bson.M{"network": params["network"], "clientid": params["clientid"]}
-        err := collection.FindOne(ctx, filter, options.FindOne().SetProjection(bson.M{"_id": 0})).Decode(&extclient)
-        if err != nil {
-                returnErrorResponse(w, r, formatError(err, "internal"))
-                return
-        }
+	gwnode, err := functions.GetNodeByMacAddress(client.Network, client.IngressGatewayID)
+	if err != nil {
+		fmt.Println("Could not retrieve Ingress Gateway Node " + client.IngressGatewayID)
+		returnErrorResponse(w, r, formatError(err, "internal"))
+		return
+	}
 
-        gwnode, err := functions.GetNodeByMacAddress(extclient.Network, extclient.IngressGatewayID)
-        if err != nil {
-		fmt.Println("Could not retrieve Ingress Gateway Node " + extclient.IngressGatewayID)
+	network, err := functions.GetParentNetwork(client.Network)
+	if err != nil {
+		fmt.Println("Could not retrieve Ingress Gateway Network " + client.Network)
 		returnErrorResponse(w, r, formatError(err, "internal"))
-                return
-        }
-
-	network, err := functions.GetParentNetwork(extclient.Network)
-        if err != nil {
-                fmt.Println("Could not retrieve Ingress Gateway Network " + extclient.Network)
-                returnErrorResponse(w, r, formatError(err, "internal"))
-                return
-        }
+		return
+	}
 	keepalive := ""
 	if network.DefaultKeepalive != 0 {
 		keepalive = "PersistentKeepalive = " + strconv.Itoa(int(network.DefaultKeepalive))
@@ -216,12 +204,12 @@ AllowedIPs = %s
 Endpoint = %s
 %s
 
-`, extclient.Address + "/32",
-   extclient.PrivateKey,
-   gwnode.PublicKey,
-   network.AddressRange,
-   gwendpoint,
-   keepalive)
+`, client.Address+"/32",
+		client.PrivateKey,
+		gwnode.PublicKey,
+		network.AddressRange,
+		gwendpoint,
+		keepalive)
 
 	if params["type"] == "qr" {
 		bytes, err := qrcode.Encode(config, qrcode.Medium, 220)
@@ -240,21 +228,19 @@ Endpoint = %s
 	}
 
 	if params["type"] == "file" {
-		name := extclient.ClientID + ".conf"
-                w.Header().Set("Content-Type", "application/config")
-		w.Header().Set("Content-Disposition", "attachment; filename=\"" + name + "\"")
+		name := client.ClientID + ".conf"
+		w.Header().Set("Content-Type", "application/config")
+		w.Header().Set("Content-Disposition", "attachment; filename=\""+name+"\"")
 		w.WriteHeader(http.StatusOK)
 		_, err := fmt.Fprint(w, config)
 		if err != nil {
-                        returnErrorResponse(w, r, formatError(err, "internal"))
+			returnErrorResponse(w, r, formatError(err, "internal"))
 		}
 		return
 	}
 
-        defer cancel()
-
-        w.WriteHeader(http.StatusOK)
-        json.NewEncoder(w).Encode(extclient)
+	w.WriteHeader(http.StatusOK)
+	json.NewEncoder(w).Encode(client)
 }
 
 func CreateExtClient(extclient models.ExtClient) error {
@@ -276,25 +262,26 @@ func CreateExtClient(extclient models.ExtClient) error {
 		extclient.Address = newAddress
 	}
 
-        if extclient.ClientID == "" {
-                clientid := StringWithCharset(7, charset)
-                clientname := "client-" + clientid
-                extclient.ClientID = clientname
-        }
+	if extclient.ClientID == "" {
+		clientid := StringWithCharset(7, charset)
+		clientname := "client-" + clientid
+		extclient.ClientID = clientname
+	}
 
 	extclient.LastModified = time.Now().Unix()
 
-	collection := mongoconn.Client.Database("netmaker").Collection("extclients")
-	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-	// insert our network into the network table
-	_, err := collection.InsertOne(ctx, extclient)
-	defer cancel()
+	key, err := functions.GetRecordKey(extclient.ClientID, extclient.Network)
 	if err != nil {
 		return err
 	}
-
+	data, err := json.Marshal(&extclient)
+	if err != nil {
+		return err
+	}
+	if err = database.Insert(key, string(data), database.EXT_CLIENT_TABLE_NAME); err != nil {
+		return err
+	}
 	err = SetNetworkNodesLastModified(extclient.Network)
-
 	return err
 }
 
@@ -322,9 +309,9 @@ func createExtClient(w http.ResponseWriter, r *http.Request) {
 	extclient.IngressGatewayID = macaddress
 	node, err := functions.GetNodeByMacAddress(networkName, macaddress)
 	if err != nil {
-                returnErrorResponse(w, r, formatError(err, "internal"))
-                return
-        }
+		returnErrorResponse(w, r, formatError(err, "internal"))
+		return
+	}
 	extclient.IngressGatewayEndpoint = node.Endpoint + ":" + strconv.FormatInt(int64(node.ListenPort), 10)
 
 	err = json.NewDecoder(r.Body).Decode(&extclient)
@@ -361,71 +348,49 @@ func updateExtClient(w http.ResponseWriter, r *http.Request) {
 	// 	returnErrorResponse(w, r, formatError(err, "badrequest"))
 	// 	return
 	// }
-	collection := mongoconn.Client.Database("netmaker").Collection("extclients")
-	ctx, _ := context.WithTimeout(context.Background(), 10*time.Second)
-	filter := bson.M{"network": params["network"], "clientid": params["clientid"]}
-	err := collection.FindOne(ctx, filter, options.FindOne().SetProjection(bson.M{"_id": 0})).Decode(&oldExtClient)
+	key, err := functions.GetRecordKey(params["clientid"], params["network"])
 	if err != nil {
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 	}
-	newclient, err := UpdateExtClient(newExtClient.ClientID, params["network"], oldExtClient)
+	data, err := database.FetchRecord(database.EXT_CLIENT_TABLE_NAME, key)
 	if err != nil {
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 	}
+	if err = json.Unmarshal([]byte(data), &oldExtClient); err != nil {
+		returnErrorResponse(w, r, formatError(err, "internal"))
+		return
+	}
 
+	newclient, err := UpdateExtClient(newExtClient.ClientID, params["network"], oldExtClient)
+	if err != nil {
+		returnErrorResponse(w, r, formatError(err, "internal"))
+		return
+	}
+	functions.PrintUserLog(r.Header.Get("user"), "updated client "+newExtClient.ClientID, 1)
 	w.WriteHeader(http.StatusOK)
 	json.NewEncoder(w).Encode(newclient)
 }
 
 func UpdateExtClient(newclientid string, network string, client models.ExtClient) (models.ExtClient, error) {
 
-        //collection := mongoconn.ConnectDB()
-        collection := mongoconn.Client.Database("netmaker").Collection("extclients")
-
-        ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-
-        // Create filter
-	filter := bson.M{"clientid": client.ClientID, "network": network}
-
-        // prepare update model.
-        update := bson.D{
-                {"$set", bson.D{
-                        {"clientid", newclientid},
-                }},
-        }
-        var clientupdate models.ExtClient
-
-        err := collection.FindOneAndUpdate(ctx, filter, update).Decode(&clientupdate)
-
-        defer cancel()
-
-        return clientupdate, err
+	err := DeleteExtClient(network, client.ClientID)
+	if err != nil {
+		return client, err
+	}
+	client.ClientID = newclientid
+	CreateExtClient(client)
+	return client, err
 }
 
-func DeleteExtClient(network string, clientid string) (bool, error) {
-
-	deleted := false
-
-	collection := mongoconn.Client.Database("netmaker").Collection("extclients")
-
-	filter := bson.M{"network": network, "clientid": clientid}
-
-	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-
-	result, err := collection.DeleteOne(ctx, filter)
-
-	deletecount := result.DeletedCount
-
-	if deletecount > 0 {
-		deleted = true
+func DeleteExtClient(network string, clientid string) error {
+	key, err := functions.GetRecordKey(clientid, network)
+	if err != nil {
+		return err
 	}
-
-	defer cancel()
-
-	fmt.Println("Deleted extclient client " + clientid + " from network " + network)
-	return deleted, err
+	err = database.DeleteRecord(database.EXT_CLIENT_TABLE_NAME, key)
+	return err
 }
 
 //Delete a extclient
@@ -437,28 +402,27 @@ func deleteExtClient(w http.ResponseWriter, r *http.Request) {
 	// get params
 	var params = mux.Vars(r)
 
-	success, err := DeleteExtClient(params["network"], params["clientid"])
+	err := DeleteExtClient(params["network"], params["clientid"])
 
 	if err != nil {
-		returnErrorResponse(w, r, formatError(err, "internal"))
-		return
-	} else if !success {
 		err = errors.New("Could not delete extclient " + params["clientid"])
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 	}
+	functions.PrintUserLog(r.Header.Get("user"),
+		"Deleted extclient client "+params["clientid"]+" from network "+params["network"], 1)
 	returnSuccessResponse(w, r, params["clientid"]+" deleted.")
 }
 
 func StringWithCharset(length int, charset string) string {
-        b := make([]byte, length)
-        for i := range b {
-                b[i] = charset[seededRand.Intn(len(charset))]
-        }
-        return string(b)
+	b := make([]byte, length)
+	for i := range b {
+		b[i] = charset[seededRand.Intn(len(charset))]
+	}
+	return string(b)
 }
 
 const charset = "abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
 
 var seededRand *rand.Rand = rand.New(
-        rand.NewSource(time.Now().UnixNano()))
+	rand.NewSource(time.Now().UnixNano()))

+ 132 - 134
controllers/intClientHttpController.go

@@ -3,17 +3,17 @@ package controller
 import (
 	//	"fmt"
 	// "github.com/davecgh/go-spew/spew"
-	"errors"
-	"context"
+
 	"encoding/json"
+	"errors"
 	"net/http"
-	"time"
+
 	"github.com/gorilla/mux"
+	"github.com/gravitl/netmaker/database"
 	"github.com/gravitl/netmaker/functions"
-	"github.com/gravitl/netmaker/serverctl"
-	"github.com/gravitl/netmaker/servercfg"
 	"github.com/gravitl/netmaker/models"
-	"github.com/gravitl/netmaker/mongoconn"
+	"github.com/gravitl/netmaker/servercfg"
+	"github.com/gravitl/netmaker/serverctl"
 	"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
 )
 
@@ -21,99 +21,98 @@ func intClientHandlers(r *mux.Router) {
 
 	r.HandleFunc("/api/intclient/{clientid}", securityCheck(false, http.HandlerFunc(getIntClient))).Methods("GET")
 	r.HandleFunc("/api/intclients", securityCheck(false, http.HandlerFunc(getAllIntClients))).Methods("GET")
-        r.HandleFunc("/api/intclients/deleteall", securityCheck(false, http.HandlerFunc(deleteAllIntClients))).Methods("DELETE")
-        r.HandleFunc("/api/intclient/{clientid}", securityCheck(false, http.HandlerFunc(updateIntClient))).Methods("PUT")
+	r.HandleFunc("/api/intclients/deleteall", securityCheck(false, http.HandlerFunc(deleteAllIntClients))).Methods("DELETE")
+	r.HandleFunc("/api/intclient/{clientid}", securityCheck(false, http.HandlerFunc(updateIntClient))).Methods("PUT")
 	r.HandleFunc("/api/intclient/register", http.HandlerFunc(registerIntClient)).Methods("POST")
 	r.HandleFunc("/api/intclient/{clientid}", http.HandlerFunc(deleteIntClient)).Methods("DELETE")
 }
 
 func getAllIntClients(w http.ResponseWriter, r *http.Request) {
-        w.Header().Set("Content-Type", "application/json")
-        clients, err := functions.GetAllIntClients()
-        if err != nil {
-                returnErrorResponse(w, r, formatError(err, "internal"))
-                return
-        }
-        //Return all the extclients in JSON format
-        w.WriteHeader(http.StatusOK)
-        json.NewEncoder(w).Encode(clients)
+	w.Header().Set("Content-Type", "application/json")
+	clients, err := functions.GetAllIntClients()
+	if err != nil {
+		returnErrorResponse(w, r, formatError(err, "internal"))
+		return
+	}
+	//Return all the extclients in JSON format
+	w.WriteHeader(http.StatusOK)
+	json.NewEncoder(w).Encode(clients)
 }
 
 func deleteAllIntClients(w http.ResponseWriter, r *http.Request) {
-        w.Header().Set("Content-Type", "application/json")
-        err := functions.DeleteAllIntClients()
-        if err != nil {
-                returnErrorResponse(w, r, formatError(err, "internal"))
-                return
-        }
-        w.WriteHeader(http.StatusOK)
+	w.Header().Set("Content-Type", "application/json")
+	err := functions.DeleteAllIntClients()
+	if err != nil {
+		returnErrorResponse(w, r, formatError(err, "internal"))
+		return
+	}
+	w.WriteHeader(http.StatusOK)
 }
 
 func deleteIntClient(w http.ResponseWriter, r *http.Request) {
-        w.Header().Set("Content-Type", "application/json")
-        // get params
-        var params = mux.Vars(r)
-
-        success, err := DeleteIntClient(params["clientid"])
-
-        if err != nil {
-                returnErrorResponse(w, r, formatError(err, "internal"))
-                return
-        } else if !success {
-                err = errors.New("Could not delete intclient " + params["clientid"])
-                returnErrorResponse(w, r, formatError(err, "internal"))
-                return
-        }
-        returnSuccessResponse(w, r, params["clientid"]+" deleted.")
-}
+	w.Header().Set("Content-Type", "application/json")
+	// get params
+	var params = mux.Vars(r)
+
+	success, err := DeleteIntClient(params["clientid"])
 
+	if err != nil {
+		returnErrorResponse(w, r, formatError(err, "internal"))
+		return
+	} else if !success {
+		err = errors.New("Could not delete intclient " + params["clientid"])
+		returnErrorResponse(w, r, formatError(err, "internal"))
+		return
+	}
+	returnSuccessResponse(w, r, params["clientid"]+" deleted.")
+}
 
 func getIntClient(w http.ResponseWriter, r *http.Request) {
-        w.Header().Set("Content-Type", "application/json")
-        var params = mux.Vars(r)
+	w.Header().Set("Content-Type", "application/json")
+	var params = mux.Vars(r)
 
 	client, err := GetIntClient(params["clientid"])
-        if err != nil {
-                returnErrorResponse(w, r, formatError(err, "internal"))
-                return
-        }
-        w.WriteHeader(http.StatusOK)
-        json.NewEncoder(w).Encode(client)
+	if err != nil {
+		returnErrorResponse(w, r, formatError(err, "internal"))
+		return
+	}
+	w.WriteHeader(http.StatusOK)
+	json.NewEncoder(w).Encode(client)
 }
 
 func updateIntClient(w http.ResponseWriter, r *http.Request) {
-        w.Header().Set("Content-Type", "application/json")
-
-        var errorResponse = models.ErrorResponse{
-                Code: http.StatusInternalServerError, Message: "W1R3: It's not you it's me.",
-        }
-
-        var clientreq models.IntClient
-
-        //get node from body of request
-        err := json.NewDecoder(r.Body).Decode(&clientreq)
-        if err != nil {
-                returnErrorResponse(w, r, formatError(err, "internal"))
-                return
-        }
-        if servercfg.IsRegisterKeyRequired() {
-                validKey := functions.IsKeyValidGlobal(clientreq.AccessKey)
-                if !validKey {
-                                errorResponse = models.ErrorResponse{
-                                        Code: http.StatusUnauthorized, Message: "W1R3: Key invalid, or none provided.",
-                                }
-                                returnErrorResponse(w, r, errorResponse)
-                                return
-                }
-        }
-        client, err := RegisterIntClient(clientreq)
-
-        if err != nil {
-                returnErrorResponse(w, r, formatError(err, "internal"))
-                return
-        }
-        w.WriteHeader(http.StatusOK)
-        json.NewEncoder(w).Encode(client)
+	w.Header().Set("Content-Type", "application/json")
+
+	var errorResponse = models.ErrorResponse{
+		Code: http.StatusInternalServerError, Message: "W1R3: It's not you it's me.",
+	}
+
+	var clientreq models.IntClient
+
+	//get node from body of request
+	err := json.NewDecoder(r.Body).Decode(&clientreq)
+	if err != nil {
+		returnErrorResponse(w, r, formatError(err, "internal"))
+		return
+	}
+	if servercfg.IsRegisterKeyRequired() {
+		validKey := functions.IsKeyValidGlobal(clientreq.AccessKey)
+		if !validKey {
+			errorResponse = models.ErrorResponse{
+				Code: http.StatusUnauthorized, Message: "W1R3: Key invalid, or none provided.",
+			}
+			returnErrorResponse(w, r, errorResponse)
+			return
+		}
+	}
+	client, err := RegisterIntClient(clientreq)
+
+	if err != nil {
+		returnErrorResponse(w, r, formatError(err, "internal"))
+		return
+	}
+	w.WriteHeader(http.StatusOK)
+	json.NewEncoder(w).Encode(client)
 }
 
 func RegisterIntClient(client models.IntClient) (models.IntClient, error) {
@@ -137,71 +136,70 @@ func RegisterIntClient(client models.IntClient) (models.IntClient, error) {
 		}
 		client.Address = newAddress
 	}
-        if client.Network == "" { client.Network = "comms" }
+	if client.Network == "" {
+		client.Network = "comms"
+	}
 	server, err := serverctl.GetServerWGConf()
-        //spew.Dump(server)
+	//spew.Dump(server)
 	if err != nil {
-                return client, err
-        }
+		return client, err
+	}
 	client.ServerPublicEndpoint = server.ServerPublicEndpoint
-        client.ServerAPIPort = server.ServerAPIPort
-        client.ServerPrivateAddress = server.ServerPrivateAddress
-        client.ServerWGPort = server.ServerWGPort
-        client.ServerGRPCPort = server.ServerGRPCPort
-        client.ServerKey = server.ServerKey
-
-        if client.ClientID == "" {
-                clientid := StringWithCharset(7, charset)
-                clientname := "client-" + clientid
-                client.ClientID = clientname
-        }
-
-	//spew.Dump(client)
-	collection := mongoconn.Client.Database("netmaker").Collection("intclients")
-	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-	// insert our network into the network table
-	_, err = collection.InsertOne(ctx, client)
-	defer cancel()
+	client.ServerAPIPort = server.ServerAPIPort
+	client.ServerPrivateAddress = server.ServerPrivateAddress
+	client.ServerWGPort = server.ServerWGPort
+	client.ServerGRPCPort = server.ServerGRPCPort
+	client.ServerKey = server.ServerKey
+
+	if client.ClientID == "" {
+		clientid := StringWithCharset(7, charset)
+		clientname := "client-" + clientid
+		client.ClientID = clientname
+	}
 
+	data, err := json.Marshal(&client)
 	if err != nil {
 		return client, err
 	}
+	if err = database.Insert(client.ClientID, string(data), database.INT_CLIENTS_TABLE_NAME); err != nil {
+		return client, err
+	}
 
 	err = serverctl.ReconfigureServerWireGuard()
 
 	return client, err
 }
 func registerIntClient(w http.ResponseWriter, r *http.Request) {
-        w.Header().Set("Content-Type", "application/json")
-
-        var errorResponse = models.ErrorResponse{
-                Code: http.StatusInternalServerError, Message: "W1R3: It's not you it's me.",
-        }
-
-        var clientreq models.IntClient
-
-        //get node from body of request
-        err := json.NewDecoder(r.Body).Decode(&clientreq)
-        if err != nil {
-                returnErrorResponse(w, r, formatError(err, "internal"))
-                return
-        }
-        if servercfg.IsRegisterKeyRequired() {
-                validKey := functions.IsKeyValidGlobal(clientreq.AccessKey)
-                if !validKey {
-                                errorResponse = models.ErrorResponse{
-                                        Code: http.StatusUnauthorized, Message: "W1R3: Key invalid, or none provided.",
-                                }
-                                returnErrorResponse(w, r, errorResponse)
-                                return
-                }
-        }
-        client, err := RegisterIntClient(clientreq)
-
-        if err != nil {
-                returnErrorResponse(w, r, formatError(err, "internal"))
-                return
-        }
-        w.WriteHeader(http.StatusOK)
-        json.NewEncoder(w).Encode(client)
+	w.Header().Set("Content-Type", "application/json")
+
+	var errorResponse = models.ErrorResponse{
+		Code: http.StatusInternalServerError, Message: "W1R3: It's not you it's me.",
+	}
+
+	var clientreq models.IntClient
+
+	//get node from body of request
+	err := json.NewDecoder(r.Body).Decode(&clientreq)
+	if err != nil {
+		returnErrorResponse(w, r, formatError(err, "internal"))
+		return
+	}
+	if servercfg.IsRegisterKeyRequired() {
+		validKey := functions.IsKeyValidGlobal(clientreq.AccessKey)
+		if !validKey {
+			errorResponse = models.ErrorResponse{
+				Code: http.StatusUnauthorized, Message: "W1R3: Key invalid, or none provided.",
+			}
+			returnErrorResponse(w, r, errorResponse)
+			return
+		}
+	}
+	client, err := RegisterIntClient(clientreq)
+
+	if err != nil {
+		returnErrorResponse(w, r, formatError(err, "internal"))
+		return
+	}
+	w.WriteHeader(http.StatusOK)
+	json.NewEncoder(w).Encode(client)
 }

+ 100 - 357
controllers/networkHttpController.go

@@ -1,24 +1,20 @@
 package controller
 
 import (
-	"context"
 	"encoding/base64"
 	"encoding/json"
 	"errors"
-	"fmt"
 	"net/http"
 	"strings"
 	"time"
-
+	"log"
 	"github.com/go-playground/validator/v10"
 	"github.com/gorilla/mux"
+	"github.com/gravitl/netmaker/database"
 	"github.com/gravitl/netmaker/functions"
 	"github.com/gravitl/netmaker/models"
-	"github.com/gravitl/netmaker/mongoconn"
 	"github.com/gravitl/netmaker/servercfg"
-	"go.mongodb.org/mongo-driver/bson"
-	"go.mongodb.org/mongo-driver/mongo"
-	"go.mongodb.org/mongo-driver/mongo/options"
+	"github.com/gravitl/netmaker/serverctl"
 )
 
 const ALL_NETWORK_ACCESS = "THIS_USER_HAS_ALL"
@@ -136,7 +132,7 @@ func getNetworks(w http.ResponseWriter, r *http.Request) {
 	allnetworks := []models.Network{}
 	err := errors.New("Networks Error")
 	if networksSlice[0] == ALL_NETWORK_ACCESS {
-		allnetworks, err = functions.ListNetworks()
+		allnetworks, err = models.GetNetworks()
 		if err != nil {
 			returnErrorResponse(w, r, formatError(err, "internal"))
 			return
@@ -170,7 +166,7 @@ func RemoveComms(networks []models.Network) []models.Network {
 	return append(returnable, networks[index+1:]...)
 }
 
-func ValidateNetworkUpdate(network models.NetworkUpdate) error {
+func ValidateNetworkUpdate(network models.Network) error {
 	v := validator.New()
 
 	_ = v.RegisterValidation("netid_valid", func(fl validator.FieldLevel) bool {
@@ -181,76 +177,11 @@ func ValidateNetworkUpdate(network models.NetworkUpdate) error {
 		return inCharSet
 	})
 
-	//	_ = v.RegisterValidation("addressrange_valid", func(fl validator.FieldLevel) bool {
-	//		isvalid := fl.Field().String() == "" || functions.IsIpCIDR(fl.Field().String())
-	//		return isvalid
-	//	})
-	//_ = v.RegisterValidation("addressrange6_valid", func(fl validator.FieldLevel) bool {
-	//		isvalid := fl.Field().String() == "" || functions.IsIpCIDR(fl.Field().String())
-	//		return isvalid
-	//	})
-
-	//	_ = v.RegisterValidation("localrange_valid", func(fl validator.FieldLevel) bool {
-	//		isvalid := fl.Field().String() == "" || functions.IsIpCIDR(fl.Field().String())
-	//		return isvalid
-	//	})
-
-	//	_ = v.RegisterValidation("netid_valid", func(fl validator.FieldLevel) bool {
-	//		return true
-	//	})
-
-	//	_ = v.RegisterValidation("displayname_unique", func(fl validator.FieldLevel) bool {
-	//		return true
-	//	})
-
 	err := v.Struct(network)
 
 	if err != nil {
 		for _, e := range err.(validator.ValidationErrors) {
-			fmt.Println(e)
-		}
-	}
-	return err
-}
-
-func ValidateNetworkCreate(network models.Network) error {
-
-	v := validator.New()
-
-	//	_ = v.RegisterValidation("addressrange_valid", func(fl validator.FieldLevel) bool {
-	//		isvalid := functions.IsIpCIDR(fl.Field().String())
-	//		return isvalid
-	//	})
-	_ = v.RegisterValidation("addressrange6_valid", func(fl validator.FieldLevel) bool {
-		isvalid := true
-		if *network.IsDualStack {
-			isvalid = functions.IsIpCIDR(fl.Field().String())
-		}
-		return isvalid
-	})
-	//
-	//	_ = v.RegisterValidation("localrange_valid", func(fl validator.FieldLevel) bool {
-	//		isvalid := fl.Field().String() == "" || functions.IsIpCIDR(fl.Field().String())
-	//		return isvalid
-	//	})
-	//
-	_ = v.RegisterValidation("netid_valid", func(fl validator.FieldLevel) bool {
-		isFieldUnique, _ := functions.IsNetworkNameUnique(fl.Field().String())
-		inCharSet := functions.NameInNetworkCharSet(fl.Field().String())
-		return isFieldUnique && inCharSet
-	})
-	//
-	_ = v.RegisterValidation("displayname_valid", func(fl validator.FieldLevel) bool {
-		isFieldUnique, _ := functions.IsNetworkDisplayNameUnique(fl.Field().String())
-		inCharSet := functions.NameInNetworkCharSet(fl.Field().String())
-		return isFieldUnique && inCharSet
-	})
-
-	err := v.Struct(network)
-
-	if err != nil {
-		for _, e := range err.(validator.ValidationErrors) {
-			fmt.Println(e)
+			log.Println(e)
 		}
 	}
 	return err
@@ -274,14 +205,15 @@ func getNetwork(w http.ResponseWriter, r *http.Request) {
 
 func GetNetwork(name string) (models.Network, error) {
 	var network models.Network
-	collection := mongoconn.Client.Database("netmaker").Collection("networks")
-	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-	filter := bson.M{"netid": name}
-	err := collection.FindOne(ctx, filter, options.FindOne().SetProjection(bson.M{"_id": 0})).Decode(&network)
-	defer cancel()
+	record, err := database.FetchRecord(database.NETWORKS_TABLE_NAME, name)
 	if err != nil {
+		return network, err
+	}
+
+	if err = json.Unmarshal([]byte(record), &network); err != nil {
 		return models.Network{}, err
 	}
+
 	return network, nil
 }
 
@@ -305,61 +237,31 @@ func KeyUpdate(netname string) (models.Network, error) {
 		return models.Network{}, err
 	}
 	network.KeyUpdateTimeStamp = time.Now().Unix()
-	collection := mongoconn.Client.Database("netmaker").Collection("networks")
-	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-	filter := bson.M{"netid": netname}
-	// prepare update model.
-	update := bson.D{
-		{"$set", bson.D{
-			{"addressrange", network.AddressRange},
-			{"addressrange6", network.AddressRange6},
-			{"displayname", network.DisplayName},
-			{"defaultlistenport", network.DefaultListenPort},
-			{"defaultpostup", network.DefaultPostUp},
-			{"defaultpostdown", network.DefaultPostDown},
-			{"defaultkeepalive", network.DefaultKeepalive},
-			{"keyupdatetimestamp", network.KeyUpdateTimeStamp},
-			{"defaultsaveconfig", network.DefaultSaveConfig},
-			{"defaultinterface", network.DefaultInterface},
-			{"nodeslastmodified", network.NodesLastModified},
-			{"networklastmodified", network.NetworkLastModified},
-			{"allowmanualsignup", network.AllowManualSignUp},
-			{"checkininterval", network.DefaultCheckInInterval},
-		}},
-	}
-	err = collection.FindOneAndUpdate(ctx, filter, update).Decode(&network)
-	defer cancel()
+	data, err := json.Marshal(&network)
 	if err != nil {
 		return models.Network{}, err
 	}
+	database.Insert(netname, string(data), database.NETWORKS_TABLE_NAME)
 	return network, nil
 }
 
 //Update a network
 func AlertNetwork(netid string) error {
 
-	collection := mongoconn.Client.Database("netmaker").Collection("networks")
-	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-	filter := bson.M{"netid": netid}
-
 	var network models.Network
-
 	network, err := functions.GetParentNetwork(netid)
 	if err != nil {
 		return err
 	}
 	updatetime := time.Now().Unix()
-	update := bson.D{
-		{"$set", bson.D{
-			{"nodeslastmodified", updatetime},
-			{"networklastmodified", updatetime},
-		}},
+	network.NodesLastModified = updatetime
+	network.NetworkLastModified = updatetime
+	data, err := json.Marshal(&network)
+	if err != nil {
+		return err
 	}
-
-	err = collection.FindOneAndUpdate(ctx, filter, update).Decode(&network)
-	defer cancel()
-
-	return err
+	database.Insert(netid, string(data), database.NETWORKS_TABLE_NAME)
+	return nil
 }
 
 //Update a network
@@ -373,34 +275,35 @@ func updateNetwork(w http.ResponseWriter, r *http.Request) {
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 	}
-
-	var networkChange models.NetworkUpdate
-
-	_ = json.NewDecoder(r.Body).Decode(&networkChange)
-	if networkChange.AddressRange == "" {
-		networkChange.AddressRange = network.AddressRange
-	}
-	if networkChange.AddressRange6 == "" {
-		networkChange.AddressRange6 = network.AddressRange6
-	}
-	if networkChange.NetID == "" {
-		networkChange.NetID = network.NetID
-	}
-
-	err = ValidateNetworkUpdate(networkChange)
+	var newNetwork models.Network
+	err = json.NewDecoder(r.Body).Decode(&newNetwork)
 	if err != nil {
 		returnErrorResponse(w, r, formatError(err, "badrequest"))
 		return
 	}
-	returnednetwork, err := UpdateNetwork(networkChange, network)
+	rangeupdate, localrangeupdate, err := network.Update(&newNetwork)
 	if err != nil {
 		returnErrorResponse(w, r, formatError(err, "badrequest"))
 		return
 	}
 
+	if rangeupdate {
+		err = functions.UpdateNetworkNodeAddresses(network.NetID)
+		if err != nil {
+			returnErrorResponse(w, r, formatError(err, "internal"))
+			return
+		}
+	}
+	if localrangeupdate {
+		err = functions.UpdateNetworkLocalAddresses(network.NetID)
+		if err != nil {
+			returnErrorResponse(w, r, formatError(err, "internal"))
+			return
+		}
+	}
 	functions.PrintUserLog(r.Header.Get("user"), "updated network "+netname, 1)
 	w.WriteHeader(http.StatusOK)
-	json.NewEncoder(w).Encode(returnednetwork)
+	json.NewEncoder(w).Encode(newNetwork)
 }
 
 func updateNetworkNodeLimit(w http.ResponseWriter, r *http.Request) {
@@ -414,149 +317,24 @@ func updateNetworkNodeLimit(w http.ResponseWriter, r *http.Request) {
 		return
 	}
 
-	var networkChange models.NetworkUpdate
+	var networkChange models.Network
 
 	_ = json.NewDecoder(r.Body).Decode(&networkChange)
 
-	collection := mongoconn.Client.Database("netmaker").Collection("networks")
-	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-	filter := bson.M{"netid": network.NetID}
-
 	if networkChange.NodeLimit != 0 {
-		update := bson.D{
-			{"$set", bson.D{
-				{"nodelimit", networkChange.NodeLimit},
-			}},
-		}
-		err := collection.FindOneAndUpdate(ctx, filter, update).Decode(&network)
-		defer cancel()
+		network.NodeLimit = networkChange.NodeLimit
+		data, err := json.Marshal(&network)
 		if err != nil {
 			returnErrorResponse(w, r, formatError(err, "badrequest"))
 			return
 		}
+		database.Insert(network.NetID, string(data), database.NETWORKS_TABLE_NAME)
+		functions.PrintUserLog(r.Header.Get("user"), "updated network node limit on, "+netname, 1)
 	}
-	functions.PrintUserLog(r.Header.Get("user"), "updated network node limit on, "+netname, 1)
 	w.WriteHeader(http.StatusOK)
 	json.NewEncoder(w).Encode(network)
 }
 
-func UpdateNetwork(networkChange models.NetworkUpdate, network models.Network) (models.Network, error) {
-	//NOTE: Network.NetID is intentionally NOT editable. It acts as a static ID for the network.
-	//DisplayName can be changed instead, which is what shows on the front end
-	if networkChange.NetID != network.NetID {
-		return models.Network{}, errors.New("NetID is not editable")
-	}
-
-	haschange := false
-	hasrangeupdate := false
-	haslocalrangeupdate := false
-
-	if networkChange.AddressRange != "" {
-		haschange = true
-		hasrangeupdate = true
-		network.AddressRange = networkChange.AddressRange
-	}
-	if networkChange.LocalRange != "" {
-		haschange = true
-		haslocalrangeupdate = true
-		network.LocalRange = networkChange.LocalRange
-	}
-	if networkChange.IsLocal != nil {
-		network.IsLocal = networkChange.IsLocal
-	}
-	if networkChange.IsDualStack != nil {
-		network.IsDualStack = networkChange.IsDualStack
-	}
-	if networkChange.DefaultListenPort != 0 {
-		network.DefaultListenPort = networkChange.DefaultListenPort
-		haschange = true
-	}
-	if networkChange.DefaultPostDown != "" {
-		network.DefaultPostDown = networkChange.DefaultPostDown
-		haschange = true
-	}
-	if networkChange.DefaultInterface != "" {
-		network.DefaultInterface = networkChange.DefaultInterface
-		haschange = true
-	}
-	if networkChange.DefaultPostUp != "" {
-		network.DefaultPostUp = networkChange.DefaultPostUp
-		haschange = true
-	}
-	if networkChange.DefaultKeepalive != 0 {
-		network.DefaultKeepalive = networkChange.DefaultKeepalive
-		haschange = true
-	}
-	if networkChange.DisplayName != "" {
-		network.DisplayName = networkChange.DisplayName
-		haschange = true
-	}
-	if networkChange.DefaultCheckInInterval != 0 {
-		network.DefaultCheckInInterval = networkChange.DefaultCheckInInterval
-		haschange = true
-	}
-	if networkChange.AllowManualSignUp != nil {
-		network.AllowManualSignUp = networkChange.AllowManualSignUp
-		haschange = true
-	}
-
-	collection := mongoconn.Client.Database("netmaker").Collection("networks")
-	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-	filter := bson.M{"netid": network.NetID}
-
-	if haschange {
-		network.SetNetworkLastModified()
-	}
-	// prepare update model.
-	update := bson.D{
-		{"$set", bson.D{
-			{"addressrange", network.AddressRange},
-			{"addressrange6", network.AddressRange6},
-			{"displayname", network.DisplayName},
-			{"defaultlistenport", network.DefaultListenPort},
-			{"defaultpostup", network.DefaultPostUp},
-			{"defaultpostdown", network.DefaultPostDown},
-			{"defaultkeepalive", network.DefaultKeepalive},
-			{"defaultsaveconfig", network.DefaultSaveConfig},
-			{"defaultinterface", network.DefaultInterface},
-			{"nodeslastmodified", network.NodesLastModified},
-			{"networklastmodified", network.NetworkLastModified},
-			{"allowmanualsignup", network.AllowManualSignUp},
-			{"localrange", network.LocalRange},
-			{"islocal", network.IsLocal},
-			{"isdualstack", network.IsDualStack},
-			{"checkininterval", network.DefaultCheckInInterval},
-		}},
-	}
-
-	err := collection.FindOneAndUpdate(ctx, filter, update).Decode(&network)
-	defer cancel()
-
-	if err != nil {
-		return models.Network{}, err
-	}
-
-	//Cycles through nodes and gives them new IP's based on the new range
-	//Pretty cool, but also pretty inefficient currently
-	if hasrangeupdate {
-		err = functions.UpdateNetworkNodeAddresses(network.NetID)
-		if err != nil {
-			return models.Network{}, err
-		}
-	}
-	if haslocalrangeupdate {
-		err = functions.UpdateNetworkPrivateAddresses(network.NetID)
-		if err != nil {
-			return models.Network{}, err
-		}
-	}
-	returnnetwork, err := functions.GetParentNetwork(network.NetID)
-	if err != nil {
-		return models.Network{}, err
-	}
-	return returnnetwork, nil
-}
-
 //Delete a network
 //Will stop you if  there's any nodes associated
 func deleteNetwork(w http.ResponseWriter, r *http.Request) {
@@ -565,7 +343,7 @@ func deleteNetwork(w http.ResponseWriter, r *http.Request) {
 
 	var params = mux.Vars(r)
 	network := params["networkname"]
-	count, err := DeleteNetwork(network)
+	err := DeleteNetwork(network)
 
 	if err != nil {
 		errtype := "badrequest"
@@ -577,34 +355,20 @@ func deleteNetwork(w http.ResponseWriter, r *http.Request) {
 	}
 	functions.PrintUserLog(r.Header.Get("user"), "deleted network "+network, 1)
 	w.WriteHeader(http.StatusOK)
-	json.NewEncoder(w).Encode(count)
+	json.NewEncoder(w).Encode("success")
 }
 
-func DeleteNetwork(network string) (*mongo.DeleteResult, error) {
-	none := &mongo.DeleteResult{}
+func DeleteNetwork(network string) error {
 
 	nodecount, err := functions.GetNetworkNodeNumber(network)
 	if err != nil {
-		//returnErrorResponse(w, r, formatError(err, "internal"))
-		return none, err
+		return err
 	} else if nodecount > 0 {
-		//errorResponse := models.ErrorResponse{
-		//	Code: http.StatusForbidden, Message: "W1R3: Node check failed. All nodes must be deleted before deleting network.",
-		//}
-		//returnErrorResponse(w, r, errorResponse)
-		return none, errors.New("Node check failed. All nodes must be deleted before deleting network")
+		return errors.New("node check failed. All nodes must be deleted before deleting network")
 	}
 
-	collection := mongoconn.Client.Database("netmaker").Collection("networks")
-	filter := bson.M{"netid": network}
-	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-	deleteResult, err := collection.DeleteOne(ctx, filter)
-	defer cancel()
-	if err != nil {
-		//returnErrorResponse(w, r, formatError(err, "internal"))
-		return none, err
-	}
-	return deleteResult, nil
+	database.DeleteRecord(database.NETWORKS_TABLE_NAME, network)
+	return err
 }
 
 //Create a network
@@ -627,43 +391,40 @@ func createNetwork(w http.ResponseWriter, r *http.Request) {
 		returnErrorResponse(w, r, formatError(err, "badrequest"))
 		return
 	}
+	success, err := serverctl.AddNetwork(network.NetID)
+	if err != nil || !success {
+		if err == nil {
+			err = errors.New("Failed to add server to network " + network.DisplayName)
+		}
+		returnErrorResponse(w, r, formatError(err, "internal"))
+		return
+	}
 	functions.PrintUserLog(r.Header.Get("user"), "created network "+network.NetID, 1)
 	w.WriteHeader(http.StatusOK)
 	//json.NewEncoder(w).Encode(result)
 }
 
 func CreateNetwork(network models.Network) error {
-	//TODO: Not really doing good validation here. Same as createNode, updateNode, and updateNetwork
-	//Need to implement some better validation across the board
-
-	if network.IsLocal == nil {
-		falsevar := false
-		network.IsLocal = &falsevar
-	}
-	if network.IsDualStack == nil {
-		falsevar := false
-		network.IsDualStack = &falsevar
-	}
 
-	err := ValidateNetworkCreate(network)
-	if err != nil {
-		//returnErrorResponse(w, r, formatError(err, "badrequest"))
-		return err
-	}
 	network.SetDefaults()
 	network.SetNodesLastModified()
 	network.SetNetworkLastModified()
 	network.KeyUpdateTimeStamp = time.Now().Unix()
 
-	collection := mongoconn.Client.Database("netmaker").Collection("networks")
-	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
+	err := network.Validate(false)
+	if err != nil {
+		//returnErrorResponse(w, r, formatError(err, "badrequest"))
+		return err
+	}
 
-	// insert our network into the network table
-	_, err = collection.InsertOne(ctx, network)
-	defer cancel()
+	data, err := json.Marshal(&network)
 	if err != nil {
 		return err
 	}
+	if err = database.Insert(network.NetID, string(data), database.NETWORKS_TABLE_NAME); err != nil {
+		return err
+	}
+
 	return nil
 }
 
@@ -692,7 +453,7 @@ func createAccessKey(w http.ResponseWriter, r *http.Request) {
 		returnErrorResponse(w, r, formatError(err, "badrequest"))
 		return
 	}
-	functions.PrintUserLog(r.Header.Get("user"), "created access key "+netname, 1)
+	functions.PrintUserLog(r.Header.Get("user"), "created access key "+accesskey.Name+" on "+netname, 1)
 	w.WriteHeader(http.StatusOK)
 	json.NewEncoder(w).Encode(key)
 	//w.Write([]byte(accesskey.AccessString))
@@ -718,14 +479,12 @@ func CreateAccessKey(accesskey models.AccessKey, network models.Network) (models
 
 	for _, key := range checkkeys {
 		if key.Name == accesskey.Name {
-			return models.AccessKey{}, errors.New("Duplicate AccessKey Name")
+			return models.AccessKey{}, errors.New("duplicate AccessKey Name")
 		}
 	}
 	privAddr := ""
-	if network.IsLocal != nil {
-		if *network.IsLocal {
-			privAddr = network.LocalRange
-		}
+	if network.IsLocal != "" {
+		privAddr = network.LocalRange
 	}
 
 	netID := network.NetID
@@ -734,14 +493,14 @@ func CreateAccessKey(accesskey models.AccessKey, network models.Network) (models
 	s := servercfg.GetServerConfig()
 	w := servercfg.GetWGConfig()
 	servervals := models.ServerConfig{
-			CoreDNSAddr: s.CoreDNSAddr,
-			APIConnString: s.APIConnString,
-			APIHost: s.APIHost,
-			APIPort: s.APIPort,
-			GRPCConnString: s.GRPCConnString,
-			GRPCHost: s.GRPCHost,
-			GRPCPort: s.GRPCPort,
-			GRPCSSL: s.GRPCSSL,
+		CoreDNSAddr:    s.CoreDNSAddr,
+		APIConnString:  s.APIConnString,
+		APIHost:        s.APIHost,
+		APIPort:        s.APIPort,
+		GRPCConnString: s.GRPCConnString,
+		GRPCHost:       s.GRPCHost,
+		GRPCPort:       s.GRPCPort,
+		GRPCSSL:        s.GRPCSSL,
 	}
 	wgvals := models.WG{
 		GRPCWireGuard:  w.GRPCWireGuard,
@@ -769,28 +528,20 @@ func CreateAccessKey(accesskey models.AccessKey, network models.Network) (models
 	err = v.Struct(accesskey)
 	if err != nil {
 		for _, e := range err.(validator.ValidationErrors) {
-			fmt.Println(e)
+			log.Println(e)
 		}
 		return models.AccessKey{}, err
 	}
+
 	network.AccessKeys = append(network.AccessKeys, accesskey)
-	collection := mongoconn.Client.Database("netmaker").Collection("networks")
-	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-	// Create filter
-	filter := bson.M{"netid": network.NetID}
-	// Read update model from body request
-	// prepare update model.
-	update := bson.D{
-		{"$set", bson.D{
-			{"accesskeys", network.AccessKeys},
-		}},
-	}
-	err = collection.FindOneAndUpdate(ctx, filter, update).Decode(&network)
-	defer cancel()
-	if err != nil {
-		//returnErrorResponse(w, r, formatError(err, "internal"))
+	data, err := json.Marshal(&network)
+	if err != nil {
 		return models.AccessKey{}, err
 	}
+	if err = database.Insert(network.NetID, string(data), database.NETWORKS_TABLE_NAME); err != nil {
+		return models.AccessKey{}, err
+	}
+
 	return accesskey, nil
 }
 
@@ -859,12 +610,11 @@ func getAccessKeys(w http.ResponseWriter, r *http.Request) {
 }
 func GetKeys(net string) ([]models.AccessKey, error) {
 
-	var network models.Network
-	collection := mongoconn.Client.Database("netmaker").Collection("networks")
-	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-	filter := bson.M{"netid": net}
-	err := collection.FindOne(ctx, filter, options.FindOne().SetProjection(bson.M{"_id": 0})).Decode(&network)
-	defer cancel()
+	record, err := database.FetchRecord(database.NETWORKS_TABLE_NAME, net)
+	if err != nil {
+		return []models.AccessKey{}, err
+	}
+	network, err := functions.ParseNetwork(record)
 	if err != nil {
 		return []models.AccessKey{}, err
 	}
@@ -904,21 +654,14 @@ func DeleteKey(keyname, netname string) error {
 	if !found {
 		return errors.New("key " + keyname + " does not exist")
 	}
-
-	collection := mongoconn.Client.Database("netmaker").Collection("networks")
-	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-	// Create filter
-	filter := bson.M{"netid": netname}
-	// prepare update model.
-	update := bson.D{
-		{"$set", bson.D{
-			{"accesskeys", updatedKeys},
-		}},
-	}
-	err = collection.FindOneAndUpdate(ctx, filter, update).Decode(&network)
-	defer cancel()
+	network.AccessKeys = updatedKeys
+	data, err := json.Marshal(&network)
 	if err != nil {
 		return err
 	}
+	if err := database.Insert(network.NetID, string(data), database.NETWORKS_TABLE_NAME); err != nil {
+		return err
+	}
+
 	return nil
 }

+ 9 - 15
controllers/networkHttpController_test.go

@@ -20,19 +20,17 @@ func deleteNet(t *testing.T) {
 	assert.Nil(t, err)
 	for _, node := range nodes {
 		t.Log("deleting node", node.Name)
-		result, err := DeleteNode(node.MacAddress, node.Network)
+		err := DeleteNode(node.MacAddress, node.Network)
 		assert.Nil(t, err)
-		assert.True(t, result)
 	}
 	dns, err := GetAllDNS()
 	assert.Nil(t, err)
 	for _, entry := range dns {
 		t.Log("deleting dns enty", entry.Name, entry.Network)
-		success, err := DeleteDNS(entry.Name, entry.Network)
+		err := DeleteDNS(entry.Name, entry.Network)
 		assert.Nil(t, err)
-		assert.True(t, success)
 	}
-	networks, _ := functions.ListNetworks()
+	networks, _ := models.GetNetworks()
 	for _, network := range networks {
 		t.Log("deleting network", network.NetID)
 		success, err := DeleteNetwork(network.NetID)
@@ -56,7 +54,7 @@ func getNet() models.Network {
 }
 
 func TestGetNetworks(t *testing.T) {
-	//calls functions.ListNetworks --- nothing to be done
+	//calls models.GetNetworks --- nothing to be done
 }
 func TestCreateNetwork(t *testing.T) {
 	deleteNet(t)
@@ -78,10 +76,8 @@ func TestGetDeleteNetwork(t *testing.T) {
 		assert.Equal(t, "skynet", network.NetID)
 	})
 	t.Run("DeleteExistingNetwork", func(t *testing.T) {
-		result, err := DeleteNetwork("skynet")
+		err := DeleteNetwork("skynet")
 		assert.Nil(t, err)
-		assert.Equal(t, int64(1), result.DeletedCount)
-		t.Log(result.DeletedCount)
 	})
 	t.Run("GetNonExistantNetwork", func(t *testing.T) {
 		network, err := GetNetwork("skynet")
@@ -90,10 +86,8 @@ func TestGetDeleteNetwork(t *testing.T) {
 		assert.Equal(t, "", network.NetID)
 	})
 	t.Run("NonExistantNetwork", func(t *testing.T) {
-		result, err := DeleteNetwork("skynet")
+		err := DeleteNetwork("skynet")
 		assert.Nil(t, err)
-		assert.Equal(t, int64(0), result.DeletedCount)
-		t.Log(result.DeletedCount)
 	})
 }
 func TestGetNetwork(t *testing.T) {
@@ -114,14 +108,14 @@ func TestUpdateNetwork(t *testing.T) {
 	createNet()
 	network := getNet()
 	t.Run("NetID", func(t *testing.T) {
-		var networkupdate models.NetworkUpdate
+		var networkupdate models.Network
 		networkupdate.NetID = "wirecat"
 		_, err := UpdateNetwork(networkupdate, network)
 		assert.NotNil(t, err)
 		assert.Equal(t, "NetID is not editable", err.Error())
 	})
 	t.Run("LocalRange", func(t *testing.T) {
-		var networkupdate models.NetworkUpdate
+		var networkupdate models.Network
 		//NetID needs to be set as it will be in updateNetwork
 		networkupdate.NetID = "skynet"
 		networkupdate.LocalRange = "192.168.0.1/24"
@@ -378,7 +372,7 @@ func TestValidateNetworkUpdate(t *testing.T) {
 	}
 	for _, tc := range cases {
 		t.Run(tc.testname, func(t *testing.T) {
-			network := models.NetworkUpdate(tc.network)
+			network := models.Network(tc.network)
 			err := ValidateNetworkUpdate(network)
 			assert.NotNil(t, err)
 			assert.Contains(t, err.Error(), tc.errMessage)

+ 87 - 179
controllers/nodeGrpcController.go

@@ -7,13 +7,11 @@ import (
 	nodepb "github.com/gravitl/netmaker/grpc"
 	"github.com/gravitl/netmaker/models"
 	"github.com/gravitl/netmaker/servercfg"
-	"go.mongodb.org/mongo-driver/mongo"
 	"google.golang.org/grpc/codes"
 	"google.golang.org/grpc/status"
 )
 
 type NodeServiceServer struct {
-	NodeDB *mongo.Collection
 	nodepb.UnimplementedNodeServiceServer
 }
 
@@ -28,102 +26,38 @@ func (s *NodeServiceServer) ReadNode(ctx context.Context, req *nodepb.ReadNodeRe
 	if err != nil {
 		return nil, status.Errorf(codes.InvalidArgument, fmt.Sprintf("Something went wrong: %v", err))
 	}
-
-	/*
-		if node == nil {
-			return nil, status.Errorf(codes.NotFound, fmt.Sprintf("Could not find node with Mac Address %s: %v", req.GetMacaddress(), err))
-		}
-	*/
 	// Cast to ReadNodeRes type
-	dualvar := false
-	if network.IsDualStack != nil {
-		dualvar = *network.IsDualStack
-	}
-	localvar := false
-	if network.IsLocal != nil {
-		localvar = *network.IsLocal
-	}
 
 	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,
-			Isingressgateway:       node.IsIngressGateway,
-			Ingressgatewayrange:       node.IngressGatewayRange,
-			Publickey:       node.PublicKey,
-			Listenport:      node.ListenPort,
-			Keepalive:       node.PersistentKeepalive,
-			Islocal:         localvar,
-			Isdualstack:     dualvar,
-			Localrange:      network.LocalRange,
+			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,
 		},
 	}
 	return response, nil
 }
-/*
-func (s *NodeServiceServer) GetConn(ctx context.Context, data *nodepb.Client) (*nodepb.Client, error) {
-        // Get the protobuf node type from the protobuf request type
-        // Essentially doing req.Node to access the struct with a nil check
-        // Now we have to convert this into a NodeItem type to convert into BSON
-        clientreq := models.IntClient{
-                // ID:       primitive.NilObjectID,
-                Address:             data.GetAddress(),
-                Address6:            data.GetAddress6(),
-                AccessKey:           data.GetAccesskey(),
-                PublicKey:           data.GetPublickey(),
-                PrivateKey:           data.GetPrivatekey(),
-                ServerPort:          data.GetServerport(),
-                ServerKey:          data.GetServerkey(),
-                ServerWGEndpoint:          data.GetServerwgendpoint(),
-        }
-
-        //Check to see if key is valid
-        //TODO: Triple inefficient!!! This is the third call to the DB we make for networks
-        if servercfg.IsRegisterKeyRequired() {
-		validKey := functions.IsKeyValidGlobal(clientreq.AccessKey)
-		if !validKey {
-			return nil, status.Errorf(
-                                codes.Internal,
-                                fmt.Sprintf("Invalid key, and server does not allow no-key signups"),
-                        )
-		}
-	}
-	client, err := RegisterIntClient(clientreq)
-
-        if err != nil {
-                // return internal gRPC error to be handled later
-                return nil, status.Errorf(
-                        codes.Internal,
-                        fmt.Sprintf("Internal error: %v", err),
-                )
-        }
-        // return the node in a CreateNodeRes type
-        response := &nodepb.Client{
-                        Privatekey:   client.PrivateKey,
-                        Publickey: client.PublicKey,
-                        Accesskey:         client.AccessKey,
-                        Address:      client.Address,
-                        Address6:     client.Address6,
-                        Serverwgendpoint:     client.ServerWGEndpoint,
-                        Serverport:     client.ServerPort,
-                        Serverkey:    client.ServerKey,
-        }
-
-        return response, nil
-}
-*/
+
 func (s *NodeServiceServer) CreateNode(ctx context.Context, req *nodepb.CreateNodeReq) (*nodepb.CreateNodeRes, error) {
 	// Get the protobuf node type from the protobuf request type
 	// Essentially doing req.Node to access the struct with a nil check
@@ -142,16 +76,9 @@ func (s *NodeServiceServer) CreateNode(ctx context.Context, req *nodepb.CreateNo
 		Password:            data.GetPassword(),
 		Interface:           data.GetInterface(),
 		Network:             data.GetNodenetwork(),
-		IsPending:           data.GetIspending(),
 		PublicKey:           data.GetPublickey(),
 		ListenPort:          data.GetListenport(),
-	}
-
-	err := ValidateNodeCreate(node.Network, node)
-
-	if err != nil {
-		// return internal gRPC error to be handled later
-		return nil, err
+		UDPHolePunch:        data.GetUdpholepunch(),
 	}
 
 	//Check to see if key is valid
@@ -165,8 +92,8 @@ func (s *NodeServiceServer) CreateNode(ctx context.Context, req *nodepb.CreateNo
 	if !validKey {
 		//Check to see if network will allow manual sign up
 		//may want to switch this up with the valid key check and avoid a DB call that way.
-		if *network.AllowManualSignUp {
-			node.IsPending = true
+		if network.AllowManualSignUp == "yes" {
+			node.IsPending = "yes"
 		} else {
 			return nil, status.Errorf(
 				codes.Internal,
@@ -184,14 +111,6 @@ func (s *NodeServiceServer) CreateNode(ctx context.Context, req *nodepb.CreateNo
 			fmt.Sprintf("Internal error: %v", err),
 		)
 	}
-	dualvar := false
-	if network.IsDualStack != nil {
-		dualvar = *network.IsDualStack
-	}
-	localvar := false
-	if network.IsLocal != nil {
-		localvar = *network.IsLocal
-	}
 
 	// return the node in a CreateNodeRes type
 	response := &nodepb.CreateNodeRes{
@@ -206,13 +125,14 @@ func (s *NodeServiceServer) CreateNode(ctx context.Context, req *nodepb.CreateNo
 			Interface:    node.Interface,
 			Nodenetwork:  node.Network,
 			Dnsoff:       !servercfg.IsDNSMode(),
-			Ispending:    node.IsPending,
+			Ispending:    node.IsPending == "yes",
 			Publickey:    node.PublicKey,
 			Listenport:   node.ListenPort,
 			Keepalive:    node.PersistentKeepalive,
-			Islocal:      localvar,
-			Isdualstack:  dualvar,
+			Islocal:      network.IsLocal == "yes",
+			Isdualstack:  network.IsDualStack == "yes",
 			Localrange:   network.LocalRange,
+			Udpholepunch: node.UDPHolePunch,
 		},
 	}
 	err = SetNetworkNodesLastModified(node.Network)
@@ -241,6 +161,8 @@ func (s *NodeServiceServer) CheckIn(ctx context.Context, req *nodepb.CheckInReq)
 		ListenPort:          data.GetListenport(),
 		PersistentKeepalive: data.GetKeepalive(),
 		PublicKey:           data.GetPublickey(),
+		UDPHolePunch:        data.GetUdpholepunch(),
+		SaveConfig:          data.GetSaveconfig(),
 	}
 
 	checkinresponse, err := NodeCheckIn(node, node.Network)
@@ -273,7 +195,7 @@ func (s *NodeServiceServer) UpdateNode(ctx context.Context, req *nodepb.UpdateNo
 	// Get the node data from the request
 	data := req.GetNode()
 	// Now we have to convert this into a NodeItem type to convert into BSON
-	nodechange := models.NodeUpdate{
+	newnode := models.Node{
 		// ID:       primitive.NilObjectID,
 		MacAddress:          data.GetMacaddress(),
 		Name:                data.GetName(),
@@ -287,21 +209,17 @@ func (s *NodeServiceServer) UpdateNode(ctx context.Context, req *nodepb.UpdateNo
 		Interface:           data.GetInterface(),
 		PostDown:            data.GetPostdown(),
 		PostUp:              data.GetPostup(),
-		IsPending:           data.GetIspending(),
 		PublicKey:           data.GetPublickey(),
 		ListenPort:          data.GetListenport(),
+		UDPHolePunch:        data.GetUdpholepunch(),
+		SaveConfig:          data.GetSaveconfig(),
 	}
 
 	// Convert the Id string to a MongoDB ObjectId
-	macaddress := nodechange.MacAddress
-	networkName := nodechange.Network
+	macaddress := newnode.MacAddress
+	networkName := newnode.Network
 	network, _ := functions.GetParentNetwork(networkName)
 
-	err := ValidateNodeUpdate(networkName, nodechange)
-	if err != nil {
-		return nil, err
-	}
-
 	node, err := functions.GetNodeByMacAddress(networkName, macaddress)
 	if err != nil {
 		return nil, status.Errorf(
@@ -310,23 +228,14 @@ func (s *NodeServiceServer) UpdateNode(ctx context.Context, req *nodepb.UpdateNo
 		)
 	}
 
-	newnode, err := UpdateNode(nodechange, node)
+	err = node.Update(&newnode)
 
 	if err != nil {
 		return nil, status.Errorf(
 			codes.NotFound,
-			fmt.Sprintf("Could not find node with supplied Mac Address: %v", err),
+			fmt.Sprintf("Could not update node: %v", err),
 		)
 	}
-	dualvar := false
-	if network.IsDualStack != nil {
-		dualvar = *network.IsDualStack
-	}
-	localvar := false
-	if network.IsLocal != nil {
-		localvar = *network.IsLocal
-	}
-
 	return &nodepb.UpdateNodeRes{
 		Node: &nodepb.Node{
 			Macaddress:   newnode.MacAddress,
@@ -340,14 +249,15 @@ func (s *NodeServiceServer) UpdateNode(ctx context.Context, req *nodepb.UpdateNo
 			Postdown:     newnode.PostDown,
 			Postup:       newnode.PostUp,
 			Nodenetwork:  newnode.Network,
-			Ispending:    newnode.IsPending,
+			Ispending:    newnode.IsPending == "yes",
 			Publickey:    newnode.PublicKey,
 			Dnsoff:       !servercfg.IsDNSMode(),
 			Listenport:   newnode.ListenPort,
 			Keepalive:    newnode.PersistentKeepalive,
-			Islocal:      localvar,
-			Isdualstack:  dualvar,
+			Islocal:      network.IsLocal == "yes",
+			Isdualstack:  network.IsDualStack == "yes",
 			Localrange:   network.LocalRange,
+			Udpholepunch: newnode.UDPHolePunch,
 		},
 	}, nil
 }
@@ -356,9 +266,9 @@ func (s *NodeServiceServer) DeleteNode(ctx context.Context, req *nodepb.DeleteNo
 	macaddress := req.GetMacaddress()
 	network := req.GetNetworkName()
 
-	success, err := DeleteNode(macaddress, network)
+	err := DeleteNode(macaddress, network)
 
-	if err != nil || !success {
+	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))
@@ -381,7 +291,6 @@ func (s *NodeServiceServer) GetPeers(req *nodepb.GetPeersReq, stream nodepb.Node
 	// Initiate a NodeItem type to write decoded data to
 	//data := &models.PeersResponse{}
 	// collection.Find returns a cursor for our (empty) query
-	//cursor, err := s.NodeDB.Find(context.Background(), bson.M{})
 	peers, err := GetPeersList(req.GetNetwork())
 
 	if err != nil {
@@ -393,11 +302,50 @@ func (s *NodeServiceServer) GetPeers(req *nodepb.GetPeersReq, stream nodepb.Node
 		// 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,
+			},
+		})
+	}
+
+	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)
+	if err != nil {
+		return status.Errorf(codes.Internal, fmt.Sprintf("Internal error occurred: %v", err))
+	}
+
+	return nil
+}
+
+func (s *NodeServiceServer) GetExtPeers(req *nodepb.GetExtPeersReq, stream nodepb.NodeService_GetExtPeersServer) 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())
+
+	if err != nil {
+		return status.Errorf(codes.Internal, fmt.Sprintf("Unknown internal error: %v", 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.GetExtPeersRes{
+			Extpeers: &nodepb.ExtPeersResponse{
 				Address:      peers[i].Address,
 				Address6:     peers[i].Address6,
 				Endpoint:     peers[i].Endpoint,
-				Egressgatewayrange: peers[i].EgressGatewayRange,
-				Isegressgateway:    peers[i].IsEgressGateway,
 				Publickey:    peers[i].PublicKey,
 				Keepalive:    peers[i].KeepAlive,
 				Listenport:   peers[i].ListenPort,
@@ -418,43 +366,3 @@ func (s *NodeServiceServer) GetPeers(req *nodepb.GetPeersReq, stream nodepb.Node
 
 	return nil
 }
-
-func (s *NodeServiceServer) GetExtPeers(req *nodepb.GetExtPeersReq, stream nodepb.NodeService_GetExtPeersServer) error {
-        // Initiate a NodeItem type to write decoded data to
-        //data := &models.PeersResponse{}
-        // collection.Find returns a cursor for our (empty) query
-        //cursor, err := s.NodeDB.Find(context.Background(), bson.M{})
-        peers, err := GetExtPeersList(req.GetNetwork(), req.GetMacaddress())
-
-        if err != nil {
-                return status.Errorf(codes.Internal, fmt.Sprintf("Unknown internal error: %v", 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.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,
-                        },
-                })
-        }
-
-        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)
-        if err != nil {
-                return status.Errorf(codes.Internal, fmt.Sprintf("Internal error occurred: %v", err))
-        }
-
-        return nil
-}

+ 165 - 260
controllers/nodeHttpController.go

@@ -1,37 +1,34 @@
 package controller
 
 import (
-	"context"
 	"encoding/json"
 	"errors"
-	"fmt"
 	"log"
 	"net/http"
 	"strings"
 	"time"
 
 	"github.com/gorilla/mux"
+	"github.com/gravitl/netmaker/database"
 	"github.com/gravitl/netmaker/functions"
 	"github.com/gravitl/netmaker/models"
-	"github.com/gravitl/netmaker/mongoconn"
-	"go.mongodb.org/mongo-driver/bson"
-	"go.mongodb.org/mongo-driver/mongo/options"
+	"github.com/gravitl/netmaker/servercfg"
 	"golang.org/x/crypto/bcrypt"
 )
 
 func nodeHandlers(r *mux.Router) {
 
-	r.HandleFunc("/api/nodes", authorize(false, "master", http.HandlerFunc(getAllNodes))).Methods("GET")
+	r.HandleFunc("/api/nodes", authorize(false, "user", http.HandlerFunc(getAllNodes))).Methods("GET")
 	r.HandleFunc("/api/nodes/{network}", authorize(true, "network", http.HandlerFunc(getNetworkNodes))).Methods("GET")
 	r.HandleFunc("/api/nodes/{network}/{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, "master", http.HandlerFunc(createEgressGateway))).Methods("POST")
-	r.HandleFunc("/api/nodes/{network}/{macaddress}/deletegateway", authorize(true, "master", http.HandlerFunc(deleteEgressGateway))).Methods("DELETE")
+	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")
 	r.HandleFunc("/api/nodes/{network}/{macaddress}/deleteingress", securityCheck(false, http.HandlerFunc(deleteIngressGateway))).Methods("DELETE")
-	r.HandleFunc("/api/nodes/{network}/{macaddress}/approve", authorize(true, "master", http.HandlerFunc(uncordonNode))).Methods("POST")
+	r.HandleFunc("/api/nodes/{network}/{macaddress}/approve", authorize(true, "user", http.HandlerFunc(uncordonNode))).Methods("POST")
 	r.HandleFunc("/api/nodes/{network}", createNode).Methods("POST")
 	r.HandleFunc("/api/nodes/adm/{network}/lastmodified", authorize(true, "network", http.HandlerFunc(getLastModified))).Methods("GET")
 	r.HandleFunc("/api/nodes/adm/{network}/authenticate", authenticate).Methods("POST")
@@ -41,6 +38,8 @@ func nodeHandlers(r *mux.Router) {
 //Node authenticates using its password and retrieves a JWT for authorization.
 func authenticate(response http.ResponseWriter, request *http.Request) {
 
+	var params = mux.Vars(request)
+	networkname := params["network"]
 	//Auth request consists of Mac Address and Password (from node that is authorizing
 	//in case of Master, auth is ignored and mac is set to "mastermac"
 	var authRequest models.AuthParams
@@ -72,11 +71,21 @@ func authenticate(response http.ResponseWriter, request *http.Request) {
 		} else {
 
 			//Search DB for node with Mac Address. Ignore pending nodes (they should not be able to authenticate with API untill approved).
-			collection := mongoconn.Client.Database("netmaker").Collection("nodes")
-			ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-			var err = collection.FindOne(ctx, bson.M{"macaddress": authRequest.MacAddress, "ispending": false}).Decode(&result)
-
-			defer cancel()
+			collection, err := database.FetchRecords(database.NODES_TABLE_NAME)
+			if err != nil {
+				errorResponse.Code = http.StatusBadRequest
+				errorResponse.Message = err.Error()
+				returnErrorResponse(response, request, errorResponse)
+				return
+			}
+			for _, value := range collection {
+				if err := json.Unmarshal([]byte(value), &result); err != nil {
+					continue
+				}
+				if result.MacAddress == authRequest.MacAddress && result.IsPending != "yes" && result.Network == networkname {
+					break
+				}
+			}
 
 			if err != nil {
 				errorResponse.Code = http.StatusBadRequest
@@ -139,7 +148,6 @@ func authenticate(response http.ResponseWriter, request *http.Request) {
 //TODO: Consider better RBAC implementations
 func authorize(networkCheck bool, authNetwork string, next http.Handler) http.HandlerFunc {
 	return func(w http.ResponseWriter, r *http.Request) {
-
 		var errorResponse = models.ErrorResponse{
 			Code: http.StatusInternalServerError, Message: "W1R3: It's not you it's me.",
 		}
@@ -147,7 +155,6 @@ func authorize(networkCheck bool, authNetwork string, next http.Handler) http.Ha
 		var params = mux.Vars(r)
 
 		networkexists, _ := functions.NetworkExists(params["network"])
-
 		//check that the request is for a valid network
 		//if (networkCheck && !networkexists) || err != nil {
 		if networkCheck && !networkexists {
@@ -156,9 +163,7 @@ func authorize(networkCheck bool, authNetwork string, next http.Handler) http.Ha
 			}
 			returnErrorResponse(w, r, errorResponse)
 			return
-
 		} else {
-
 			w.Header().Set("Content-Type", "application/json")
 
 			//get the auth token
@@ -184,7 +189,6 @@ func authorize(networkCheck bool, authNetwork string, next http.Handler) http.Ha
 			//A: the token is the master password
 			//B: the token corresponds to a mac address, and if so, which one
 			//TODO: There's probably a better way of dealing with the "master token"/master password. Plz Halp.
-
 			var isAuthorized = false
 			var macaddress = ""
 			username, networks, isadmin, errN := functions.VerifyUserToken(authToken)
@@ -192,7 +196,9 @@ func authorize(networkCheck bool, authNetwork string, next http.Handler) http.Ha
 			if errN == nil && isadmin {
 				macaddress = "mastermac"
 				isAuthorized = true
+				r.Header.Set("ismasterkey", "yes")
 			} else {
+                                r.Header.Set("ismasterkey", "")
 				mac, _, err := functions.VerifyToken(authToken)
 				if err != nil {
 					errorResponse = models.ErrorResponse{
@@ -211,7 +217,7 @@ func authorize(networkCheck bool, authNetwork string, next http.Handler) http.Ha
 			//The mastermac (login with masterkey from config) can do everything!! May be dangerous.
 			if macaddress == "mastermac" {
 				isAuthorized = true
-
+				r.Header.Set("ismasterkey", "yes")
 				//for everyone else, there's poor man's RBAC. The "cases" are defined in the routes in the handlers
 				//So each route defines which access network should be allowed to access it
 			} else {
@@ -240,8 +246,8 @@ func authorize(networkCheck bool, authNetwork string, next http.Handler) http.Ha
 					} else {
 						isAuthorized = (macaddress == params["macaddress"])
 					}
-				case "master":
-					isAuthorized = (macaddress == "mastermac")
+				case "user":
+					isAuthorized = true
 				default:
 					isAuthorized = false
 				}
@@ -286,32 +292,20 @@ func getNetworkNodes(w http.ResponseWriter, r *http.Request) {
 
 func GetNetworkNodes(network string) ([]models.Node, error) {
 	var nodes []models.Node
-	collection := mongoconn.Client.Database("netmaker").Collection("nodes")
-	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-	filter := bson.M{"network": network}
-	//Filtering out the ID field cuz Dillon doesn't like it. May want to filter out other fields in the future
-	cur, err := collection.Find(ctx, filter, options.Find().SetProjection(bson.M{"_id": 0}))
-	if err != nil {
-		return []models.Node{}, err
-	}
-	defer cancel()
-	for cur.Next(context.TODO()) {
-		//Using a different model for the Node (other than regular node).
-		//Either we should do this for ALL structs (so Networks and Keys)
-		//OR we should just use the original struct
-		//My preference is to make some new return structs
-		//TODO: Think about this. Not an immediate concern. Just need to get some consistency eventually
+	collection, err := database.FetchRecords(database.NODES_TABLE_NAME)
+	if err != nil {
+		return nodes, err
+	}
+	for _, value := range collection {
+
 		var node models.Node
-		err := cur.Decode(&node)
+		err := json.Unmarshal([]byte(value), &node)
 		if err != nil {
-			return []models.Node{}, err
+			continue
+		}
+		if node.Network == network {
+			nodes = append(nodes, node)
 		}
-		// add item our array of nodes
-		nodes = append(nodes, node)
-	}
-	//TODO: Another fatal error we should take care of.
-	if err := cur.Err(); err != nil {
-		return []models.Node{}, err
 	}
 	return nodes, nil
 }
@@ -320,17 +314,44 @@ func GetNetworkNodes(network string) ([]models.Node, error) {
 //Not quite sure if this is necessary. Probably necessary based on front end but may want to review after iteration 1 if it's being used or not
 func getAllNodes(w http.ResponseWriter, r *http.Request) {
 	w.Header().Set("Content-Type", "application/json")
-	nodes, err := functions.GetAllNodes()
-	if err != nil {
+	user, err := functions.GetUser(r.Header.Get("user"))
+	if err != nil && r.Header.Get("ismasterkey") != "yes" {
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 	}
+	var nodes []models.Node
+	if user.IsAdmin  || r.Header.Get("ismasterkey") == "yes" {
+		nodes, err = models.GetAllNodes()
+		if err != nil {
+			returnErrorResponse(w, r, formatError(err, "internal"))
+			return
+		}
+	} else {
+		nodes, err = getUsersNodes(user)
+		if err != nil {
+			returnErrorResponse(w, r, formatError(err, "internal"))
+			return
+		}
+	}
 	//Return all the nodes in JSON format
 	functions.PrintUserLog(r.Header.Get("user"), "fetched nodes", 2)
 	w.WriteHeader(http.StatusOK)
 	json.NewEncoder(w).Encode(nodes)
 }
 
+func getUsersNodes(user models.User) ([]models.Node, error) {
+	var nodes []models.Node
+	var err error
+	for _, networkName := range user.Networks {
+		tmpNodes, err := GetNetworkNodes(networkName)
+		if err != nil {
+			continue
+		}
+		nodes = append(nodes, tmpNodes...)
+	}
+	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
@@ -356,35 +377,22 @@ func checkIn(w http.ResponseWriter, r *http.Request) {
 	w.WriteHeader(http.StatusOK)
 	json.NewEncoder(w).Encode(node)
 }
-func CheckIn(network, macaddress string) (models.Node, error) {
+func CheckIn(network string, macaddress string) (models.Node, error) {
 	var node models.Node
 
-	//Retrieves node with DB Call which is inefficient. Let's just get the time and set it.
-	//node = functions.GetNodeByMacAddress(params["network"], params["macaddress"])
-	collection := mongoconn.Client.Database("netmaker").Collection("nodes")
-	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-	filter := bson.M{"macaddress": macaddress, "network": network}
-	//old code was inefficient, this is all we need.
-	time := time.Now().Unix()
-	//node.SetLastCheckIn()
-	// prepare update model with new time
-	update := bson.D{
-		{"$set", bson.D{
-			{"lastcheckin", time},
-		}},
-	}
-	err := collection.FindOneAndUpdate(ctx, filter, update).Decode(&node)
-	defer cancel()
+	node, err := GetNode(macaddress, network)
+	key, err := functions.GetRecordKey(macaddress, network)
 	if err != nil {
-		return models.Node{}, err
+		return node, err
 	}
-	//TODO: check node last modified vs network last modified
-	//Get Updated node to return
-	node, err = GetNode(macaddress, network)
+	time := time.Now().Unix()
+	node.LastCheckIn = time
+	data, err := json.Marshal(&node)
 	if err != nil {
-		return models.Node{}, err
+		return node, err
 	}
-	return node, nil
+	err = database.Insert(key, string(data), database.NODES_TABLE_NAME)
+	return node, err
 }
 
 //Get an individual node. Nothin fancy here folks.
@@ -413,7 +421,7 @@ func getLastModified(w http.ResponseWriter, r *http.Request) {
 	w.Header().Set("Content-Type", "application/json")
 
 	var params = mux.Vars(r)
-	network, err := GetLastModified(params["network"])
+	network, err := GetNetwork(params["network"])
 	if err != nil {
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
@@ -423,23 +431,6 @@ func getLastModified(w http.ResponseWriter, r *http.Request) {
 	json.NewEncoder(w).Encode(network.NodesLastModified)
 }
 
-func GetLastModified(network string) (models.Network, error) {
-	var net models.Network
-	collection := mongoconn.Client.Database("netmaker").Collection("networks")
-	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-	filter := bson.M{"netid": network}
-	err := collection.FindOne(ctx, filter).Decode(&net)
-	defer cancel()
-	if err != nil {
-		fmt.Println(err)
-		return models.Network{}, err
-	}
-	return net, nil
-}
-
-//This one's a doozy
-//To create a node
-//Must have valid key and be unique
 func createNode(w http.ResponseWriter, r *http.Request) {
 	w.Header().Set("Content-Type", "application/json")
 
@@ -448,12 +439,7 @@ func createNode(w http.ResponseWriter, r *http.Request) {
 	var errorResponse = models.ErrorResponse{
 		Code: http.StatusInternalServerError, Message: "W1R3: It's not you it's me.",
 	}
-
 	networkName := params["network"]
-
-	//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
 	networkexists, err := functions.NetworkExists(networkName)
 
 	if err != nil {
@@ -491,8 +477,8 @@ func createNode(w http.ResponseWriter, r *http.Request) {
 	if !validKey {
 		//Check to see if network will allow manual sign up
 		//may want to switch this up with the valid key check and avoid a DB call that way.
-		if *network.AllowManualSignUp {
-			node.IsPending = true
+		if network.AllowManualSignUp == "yes" {
+			node.IsPending = "yes"
 		} else {
 			errorResponse = models.ErrorResponse{
 				Code: http.StatusUnauthorized, Message: "W1R3: Key invalid, or none provided.",
@@ -502,12 +488,6 @@ func createNode(w http.ResponseWriter, r *http.Request) {
 		}
 	}
 
-	err = ValidateNodeCreate(networkName, node)
-	if err != nil {
-		returnErrorResponse(w, r, formatError(err, "badrequest"))
-		return
-	}
-
 	node, err = CreateNode(node, networkName)
 	if err != nil {
 		returnErrorResponse(w, r, formatError(err, "internal"))
@@ -538,24 +518,19 @@ func UncordonNode(network, macaddress string) (models.Node, error) {
 	if err != nil {
 		return models.Node{}, err
 	}
-	collection := mongoconn.Client.Database("netmaker").Collection("nodes")
-	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-	// Create filter
-	filter := bson.M{"macaddress": macaddress, "network": network}
 	node.SetLastModified()
-	fmt.Println("Uncordoning node " + node.Name)
-	// prepare update model.
-	update := bson.D{
-		{"$set", bson.D{
-			{"ispending", false},
-		}},
+	node.IsPending = "no"
+	data, err := json.Marshal(&node)
+	if err != nil {
+		return node, err
 	}
-	err = collection.FindOneAndUpdate(ctx, filter, update).Decode(&node)
-	defer cancel()
+	key, err := functions.GetRecordKey(node.MacAddress, node.Network)
 	if err != nil {
-		return models.Node{}, err
+		return node, err
 	}
-	return node, nil
+
+	err = database.Insert(key, string(data), database.NODES_TABLE_NAME)
+	return node, err
 }
 
 func createEgressGateway(w http.ResponseWriter, r *http.Request) {
@@ -588,62 +563,44 @@ func CreateEgressGateway(gateway models.EgressGatewayRequest) (models.Node, erro
 	if err != nil {
 		return models.Node{}, err
 	}
-	var nodechange models.Node
-	nodechange.IsEgressGateway = true
-	nodechange.EgressGatewayRanges = gateway.Ranges
-	nodechange.PostUp = "iptables -A FORWARD -i " + node.Interface + " -j ACCEPT; iptables -t nat -A POSTROUTING -o " + gateway.Interface + " -j MASQUERADE"
-	nodechange.PostDown = "iptables -D FORWARD -i " + node.Interface + " -j ACCEPT; iptables -t nat -D POSTROUTING -o " + gateway.Interface + " -j MASQUERADE"
+	node.IsEgressGateway = "yes"
+	node.EgressGatewayRanges = gateway.Ranges
+	postUpCmd := "iptables -A FORWARD -i " + node.Interface + " -j ACCEPT; iptables -t nat -A POSTROUTING -o " + gateway.Interface + " -j MASQUERADE"
+	postDownCmd := "iptables -D FORWARD -i " + node.Interface + " -j ACCEPT; iptables -t nat -D POSTROUTING -o " + gateway.Interface + " -j MASQUERADE"
 	if gateway.PostUp != "" {
-		nodechange.PostUp = gateway.PostUp
+		postUpCmd = gateway.PostUp
 	}
 	if gateway.PostDown != "" {
-		nodechange.PostDown = gateway.PostDown
+		postDownCmd = gateway.PostDown
 	}
 	if node.PostUp != "" {
-		if !strings.Contains(node.PostUp, nodechange.PostUp) {
-			nodechange.PostUp = node.PostUp + "; " + nodechange.PostUp
-		} else {
-			nodechange.PostUp = node.PostUp
+		if !strings.Contains(node.PostUp, postUpCmd) {
+			postUpCmd = node.PostUp + "; " + postUpCmd
 		}
 	}
 	if node.PostDown != "" {
-		if !strings.Contains(node.PostDown, nodechange.PostDown) {
-			nodechange.PostDown = node.PostDown + "; " + nodechange.PostDown
-		} else {
-			nodechange.PostDown = node.PostDown
+		if !strings.Contains(node.PostDown, postDownCmd) {
+			postDownCmd = node.PostDown + "; " + postDownCmd
 		}
 	}
-	collection := mongoconn.Client.Database("netmaker").Collection("nodes")
-	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-	// Create filter
-	filter := bson.M{"macaddress": gateway.NodeID, "network": gateway.NetID}
-	nodechange.SetLastModified()
-	// prepare update model.
-	update := bson.D{
-		{"$set", bson.D{
-			{"postup", nodechange.PostUp},
-			{"postdown", nodechange.PostDown},
-			{"isegressgateway", nodechange.IsEgressGateway},
-			{"egressgatewayranges", nodechange.EgressGatewayRanges},
-			{"lastmodified", nodechange.LastModified},
-		}},
-	}
-	var nodeupdate models.Node
-	err = collection.FindOneAndUpdate(ctx, filter, update).Decode(&nodeupdate)
-	defer cancel()
+	key, err := functions.GetRecordKey(gateway.NodeID, gateway.NetID)
 	if err != nil {
-		return models.Node{}, err
+		return node, err
 	}
-	err = SetNetworkNodesLastModified(gateway.NetID)
+	node.PostUp = postUpCmd
+	node.PostDown = postDownCmd
+	node.SetLastModified()
+	nodeData, err := json.Marshal(&node)
 	if err != nil {
-		return models.Node{}, err
+		return node, err
 	}
-	//Get updated values to return
-	node, err = functions.GetNodeByMacAddress(gateway.NetID, gateway.NodeID)
+	err = database.Insert(key, string(nodeData), database.NODES_TABLE_NAME)
+	// prepare update model.
 	if err != nil {
 		return models.Node{}, err
 	}
-	return node, nil
+	err = SetNetworkNodesLastModified(gateway.NetID)
+	return node, err
 }
 
 func ValidateEgressGateway(gateway models.EgressGatewayRequest) error {
@@ -677,44 +634,29 @@ func deleteEgressGateway(w http.ResponseWriter, r *http.Request) {
 
 func DeleteEgressGateway(network, macaddress string) (models.Node, error) {
 
-	var nodeupdate models.Node
-	var nodechange models.Node
 	node, err := functions.GetNodeByMacAddress(network, macaddress)
 	if err != nil {
 		return models.Node{}, err
 	}
 
-	nodechange.IsEgressGateway = false
-	nodechange.EgressGatewayRanges = []string{}
-	nodechange.PostUp = ""
-	nodechange.PostDown = ""
-
-	collection := mongoconn.Client.Database("netmaker").Collection("nodes")
-	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-	// Create filter
-	filter := bson.M{"macaddress": macaddress, "network": network}
-	nodechange.SetLastModified()
-	// prepare update model.
-	update := bson.D{
-		{"$set", bson.D{
-			{"postup", nodechange.PostUp},
-			{"postdown", nodechange.PostDown},
-			{"isegressgateway", nodechange.IsEgressGateway},
-			{"egressgatewayranges", nodechange.EgressGatewayRanges},
-			{"lastmodified", nodechange.LastModified},
-		}},
-	}
-	err = collection.FindOneAndUpdate(ctx, filter, update).Decode(&nodeupdate)
-	defer cancel()
+	node.IsEgressGateway = "no"
+	node.EgressGatewayRanges = []string{}
+	node.PostUp = ""
+	node.PostDown = ""
+	node.SetLastModified()
+	key, err := functions.GetRecordKey(node.MacAddress, node.Network)
 	if err != nil {
 		return models.Node{}, err
 	}
-	err = SetNetworkNodesLastModified(network)
+	data, err := json.Marshal(&node)
 	if err != nil {
 		return models.Node{}, err
 	}
-	//Get updated values to return
-	node, err = functions.GetNodeByMacAddress(network, macaddress)
+	err = database.Insert(key, string(data), database.NODES_TABLE_NAME)
+	if err != nil {
+		return models.Node{}, err
+	}
+	err = SetNetworkNodesLastModified(network)
 	if err != nil {
 		return models.Node{}, err
 	}
@@ -749,58 +691,37 @@ func CreateIngressGateway(netid string, macaddress string) (models.Node, error)
 		log.Println("Could not find network.")
 		return models.Node{}, err
 	}
-	var nodechange models.Node
-	nodechange.IngressGatewayRange = network.AddressRange
-	nodechange.PostUp = "iptables -A FORWARD -i " + node.Interface + " -j ACCEPT; iptables -t nat -A POSTROUTING -o " + node.Interface + " -j MASQUERADE"
-	nodechange.PostDown = "iptables -D FORWARD -i " + node.Interface + " -j ACCEPT; iptables -t nat -D POSTROUTING -o " + node.Interface + " -j MASQUERADE"
+	node.IsIngressGateway = "yes"
+	node.IngressGatewayRange = network.AddressRange
+	postUpCmd := "iptables -A FORWARD -i " + node.Interface + " -j ACCEPT; iptables -t nat -A POSTROUTING -o " + node.Interface + " -j MASQUERADE"
+	postDownCmd := "iptables -D FORWARD -i " + node.Interface + " -j ACCEPT; iptables -t nat -D POSTROUTING -o " + node.Interface + " -j MASQUERADE"
 	if node.PostUp != "" {
-		if !strings.Contains(node.PostUp, nodechange.PostUp) {
-			nodechange.PostUp = node.PostUp + "; " + nodechange.PostUp
-		} else {
-			nodechange.PostUp = node.PostUp
+		if !strings.Contains(node.PostUp, postUpCmd) {
+			postUpCmd = node.PostUp + "; " + postUpCmd
 		}
 	}
 	if node.PostDown != "" {
-		if !strings.Contains(node.PostDown, nodechange.PostDown) {
-			nodechange.PostDown = node.PostDown + "; " + nodechange.PostDown
-		} else {
-			nodechange.PostDown = node.PostDown
+		if !strings.Contains(node.PostDown, postDownCmd) {
+			postDownCmd = node.PostDown + "; " + postDownCmd
 		}
 	}
-
-	collection := mongoconn.Client.Database("netmaker").Collection("nodes")
-	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-	// Create filter
-	filter := bson.M{"macaddress": macaddress, "network": netid}
 	node.SetLastModified()
-	// prepare update model.
-	update := bson.D{
-		{"$set", bson.D{
-			{"postup", nodechange.PostUp},
-			{"postdown", nodechange.PostDown},
-			{"isingressgateway", true},
-			{"ingressgatewayrange", nodechange.IngressGatewayRange},
-			{"lastmodified", node.LastModified},
-		}},
-	}
-	var nodeupdate models.Node
-	err = collection.FindOneAndUpdate(ctx, filter, update).Decode(&nodeupdate)
-	defer cancel()
-	if err != nil {
-		log.Println("error updating node to gateway")
+        node.PostUp = postUpCmd
+        node.PostDown = postDownCmd
+	key, err := functions.GetRecordKey(node.MacAddress, node.Network)
+	if err != nil {
 		return models.Node{}, err
 	}
-	err = SetNetworkNodesLastModified(netid)
+	data, err := json.Marshal(&node)
 	if err != nil {
-		return node, err
+		return models.Node{}, err
 	}
-	//Get updated values to return
-	node, err = functions.GetNodeByMacAddress(netid, macaddress)
+	err = database.Insert(key, string(data), database.NODES_TABLE_NAME)
 	if err != nil {
-		log.Println("error finding node after update")
-		return node, err
+		return models.Node{}, err
 	}
-	return node, nil
+	err = SetNetworkNodesLastModified(netid)
+	return node, err
 }
 
 func deleteIngressGateway(w http.ResponseWriter, r *http.Request) {
@@ -819,38 +740,26 @@ func deleteIngressGateway(w http.ResponseWriter, r *http.Request) {
 
 func DeleteIngressGateway(network, macaddress string) (models.Node, error) {
 
-	var nodeupdate models.Node
 	node, err := functions.GetNodeByMacAddress(network, macaddress)
 	if err != nil {
 		return models.Node{}, err
 	}
-
-	collection := mongoconn.Client.Database("netmaker").Collection("nodes")
-	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-	// Create filter
-	filter := bson.M{"macaddress": macaddress, "network": network}
-	// prepare update model.
-	update := bson.D{
-		{"$set", bson.D{
-			{"lastmodified", time.Now().Unix()},
-			{"isingressgateway", false},
-		}},
-	}
-	err = collection.FindOneAndUpdate(ctx, filter, update).Decode(&nodeupdate)
-	defer cancel()
+	node.LastModified = time.Now().Unix()
+	node.IsIngressGateway = "no"
+	key, err := functions.GetRecordKey(node.MacAddress, node.Network)
 	if err != nil {
 		return models.Node{}, err
 	}
-	err = SetNetworkNodesLastModified(network)
+	data, err := json.Marshal(&node)
 	if err != nil {
 		return models.Node{}, err
 	}
-	//Get updated values to return
-	node, err = functions.GetNodeByMacAddress(network, macaddress)
+	err = database.Insert(key, string(data), database.NODES_TABLE_NAME)
 	if err != nil {
 		return models.Node{}, err
 	}
-	return node, nil
+	err = SetNetworkNodesLastModified(network)
+	return node, err
 }
 
 func updateNode(w http.ResponseWriter, r *http.Request) {
@@ -858,11 +767,7 @@ func updateNode(w http.ResponseWriter, r *http.Request) {
 
 	var params = mux.Vars(r)
 
-	//Get id from parameters
-	//id, _ := primitive.ObjectIDFromHex(params["id"])
-
 	var node models.Node
-
 	//start here
 	node, err := functions.GetNodeByMacAddress(params["network"], params["macaddress"])
 	if err != nil {
@@ -870,29 +775,32 @@ func updateNode(w http.ResponseWriter, r *http.Request) {
 		return
 	}
 
-	var nodechange models.NodeUpdate
-
+	var newNode models.Node
 	// we decode our body request params
-	_ = json.NewDecoder(r.Body).Decode(&nodechange)
-	if nodechange.Network == "" {
-		nodechange.Network = node.Network
-	}
-	if nodechange.MacAddress == "" {
-		nodechange.MacAddress = node.MacAddress
-	}
-	err = ValidateNodeUpdate(params["network"], nodechange)
+	err = json.NewDecoder(r.Body).Decode(&newNode)
 	if err != nil {
 		returnErrorResponse(w, r, formatError(err, "badrequest"))
 		return
 	}
+	err = node.Update(&newNode)
+	if err != nil {
+		returnErrorResponse(w, r, formatError(err, "internal"))
+		return
+	}
 
-	node, err = UpdateNode(nodechange, node)
+	if err = SetNetworkNodesLastModified(node.Network); err != nil {
+		log.Println(err)
+	}
+	if servercfg.IsDNSMode() {
+		err = SetDNS()
+	}
 	if err != nil {
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 	}
+	functions.PrintUserLog(r.Header.Get("user"), "updated node "+node.MacAddress+" on network "+node.Network, 1)
 	w.WriteHeader(http.StatusOK)
-	json.NewEncoder(w).Encode(node)
+	json.NewEncoder(w).Encode(newNode)
 }
 
 //Delete a node
@@ -904,15 +812,12 @@ func deleteNode(w http.ResponseWriter, r *http.Request) {
 	// get params
 	var params = mux.Vars(r)
 
-	success, err := DeleteNode(params["macaddress"], params["network"])
+	err := DeleteNode(params["macaddress"], params["network"])
 
 	if err != nil {
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
-	} else if !success {
-		err = errors.New("Could not delete node " + params["macaddress"])
-		returnErrorResponse(w, r, formatError(err, "internal"))
-		return
 	}
+	functions.PrintUserLog(r.Header.Get("user"), "Deleted node "+params["macaddress"]+" from network "+params["network"], 1)
 	returnSuccessResponse(w, r, params["macaddress"]+" deleted.")
 }

+ 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")

+ 76 - 125
controllers/userHttpController.go

@@ -1,22 +1,17 @@
 package controller
 
 import (
-	"context"
 	"encoding/json"
 	"errors"
 	"fmt"
 	"net/http"
 	"strings"
-	"time"
 
 	"github.com/go-playground/validator/v10"
 	"github.com/gorilla/mux"
+	"github.com/gravitl/netmaker/database"
 	"github.com/gravitl/netmaker/functions"
 	"github.com/gravitl/netmaker/models"
-	"github.com/gravitl/netmaker/mongoconn"
-	"go.mongodb.org/mongo-driver/bson"
-	"go.mongodb.org/mongo-driver/mongo"
-	"go.mongodb.org/mongo-driver/mongo/options"
 	"golang.org/x/crypto/bcrypt"
 )
 
@@ -87,30 +82,24 @@ func authenticateUser(response http.ResponseWriter, request *http.Request) {
 func VerifyAuthRequest(authRequest models.UserAuthParams) (string, error) {
 	var result models.User
 	if authRequest.UserName == "" {
-		return "", errors.New("Username can't be empty")
+		return "", errors.New("username can't be empty")
 	} else if authRequest.Password == "" {
-		return "", errors.New("Password can't be empty")
+		return "", errors.New("password can't be empty")
 	}
 	//Search DB for node with Mac Address. Ignore pending nodes (they should not be able to authenticate with API untill approved).
-	collection := mongoconn.Client.Database("netmaker").Collection("users")
-	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-	var err = collection.FindOne(ctx, bson.M{"username": authRequest.UserName}).Decode(&result)
-
-	defer cancel()
+	record, err := database.FetchRecord(database.USERS_TABLE_NAME, authRequest.UserName)
 	if err != nil {
-		return "", errors.New("User " + authRequest.UserName + " not found")
+		return "", errors.New("user " + authRequest.UserName + " not found")
+	}
+	if err = json.Unmarshal([]byte(record), &result); err != nil {
+		return "", errors.New("user " + authRequest.UserName + " not found")
 	}
-	// This is a a useless test as cannot create user that is not an an admin
-	//if !result.IsAdmin {
-	//	return "", errors.New("User is not an admin")
-	//}
 
 	//compare password from request to stored password in database
 	//might be able to have a common hash (certificates?) and compare those so that a password isn't passed in in plain text...
 	//TODO: Consider a way of hashing the password client side before sending, or using certificates
-	err = bcrypt.CompareHashAndPassword([]byte(result.Password), []byte(authRequest.Password))
-	if err != nil {
-		return "", errors.New("Wrong Password")
+	if err = bcrypt.CompareHashAndPassword([]byte(result.Password), []byte(authRequest.Password)); err != nil {
+		return "", errors.New("wrong password")
 	}
 
 	//Create a new JWT for the node
@@ -163,7 +152,6 @@ func authorizeUserAdm(next http.Handler) http.HandlerFunc {
 
 func ValidateUserToken(token string, user string, adminonly bool) error {
 	var tokenSplit = strings.Split(token, " ")
-
 	//I put this in in case the user doesn't put in a token at all (in which case it's empty)
 	//There's probably a smarter way of handling this.
 	var authToken = "928rt238tghgwe@TY@$Y@#WQAEGB2FC#@HG#@$Hddd"
@@ -193,27 +181,23 @@ func ValidateUserToken(token string, user string, adminonly bool) error {
 
 func HasAdmin() (bool, error) {
 
-	collection := mongoconn.Client.Database("netmaker").Collection("users")
-
-	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-
-	filter := bson.M{"isadmin": true}
-
-	//Filtering out the ID field cuz Dillon doesn't like it. May want to filter out other fields in the future
-	var result bson.M
-
-	err := collection.FindOne(ctx, filter).Decode(&result)
-
-	defer cancel()
-
+	collection, err := database.FetchRecords(database.USERS_TABLE_NAME)
 	if err != nil {
-		if err == mongo.ErrNoDocuments {
-			return false, nil
-		}
 		return false, err
-		fmt.Println(err)
 	}
-	return true, err
+
+	for _, value := range collection { // filter for isadmin true
+		var user models.User
+		err = json.Unmarshal([]byte(value), &user)
+		if err != nil {
+			continue
+		}
+		if user.IsAdmin {
+			return true, nil
+		}
+	}
+
+	return false, err
 }
 
 func hasAdmin(w http.ResponseWriter, r *http.Request) {
@@ -228,54 +212,52 @@ func hasAdmin(w http.ResponseWriter, r *http.Request) {
 
 }
 
-func GetUser(username string) (models.User, error) {
-
-	var user models.User
-
-	collection := mongoconn.Client.Database("netmaker").Collection("users")
-
-	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-
-	filter := bson.M{"username": username}
-	err := collection.FindOne(ctx, filter, options.FindOne().SetProjection(bson.M{"_id": 0})).Decode(&user)
-
-	defer cancel()
+func GetUser(username string) (models.ReturnUser, error) {
 
+	var user models.ReturnUser
+	record, err := database.FetchRecord(database.USERS_TABLE_NAME, username)
+	if err != nil {
+		return user, err
+	}
+	if err = json.Unmarshal([]byte(record), &user); err != nil {
+		return models.ReturnUser{}, err
+	}
 	return user, err
 }
 
-func GetUsers() ([]models.User, error) {
+func GetUserInternal(username string) (models.User, error) {
 
-	var users []models.User
+	var user models.User
+	record, err := database.FetchRecord(database.USERS_TABLE_NAME, username)
+	if err != nil {
+		return user, err
+	}
+	if err = json.Unmarshal([]byte(record), &user); err != nil {
+		return models.User{}, err
+	}
+	return user, err
+}
 
-	collection := mongoconn.Client.Database("netmaker").Collection("users")
+func GetUsers() ([]models.ReturnUser, error) {
 
-	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
+	var users []models.ReturnUser
 
-	cur, err := collection.Find(ctx, bson.M{}, options.Find().SetProjection(bson.M{"_id": 0}))
+	collection, err := database.FetchRecords(database.USERS_TABLE_NAME)
 
 	if err != nil {
 		return users, err
 	}
 
-	defer cancel()
-
-	for cur.Next(context.TODO()) {
+	for _, value := range collection {
 
-		var user models.User
-		err := cur.Decode(&user)
+		var user models.ReturnUser
+		err = json.Unmarshal([]byte(value), &user)
 		if err != nil {
-			return users, err
+			continue // get users
 		}
-
-		// add network our array
 		users = append(users, user)
 	}
 
-	if err := cur.Err(); err != nil {
-		return users, err
-	}
-
 	return users, err
 }
 
@@ -334,12 +316,11 @@ func CreateUser(user models.User) (models.User, error) {
 	}
 
 	// connect db
-	collection := mongoconn.Client.Database("netmaker").Collection("users")
-	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-
-	// insert our node to the node db.
-	_, err = collection.InsertOne(ctx, user)
-	defer cancel()
+	data, err := json.Marshal(&user)
+	if err != nil {
+		return user, err
+	}
+	err = database.Insert(user.UserName, string(data), database.USERS_TABLE_NAME)
 
 	return user, err
 }
@@ -405,38 +386,18 @@ func UpdateUser(userchange models.User, user models.User) (models.User, error) {
 
 		user.Password = userchange.Password
 	}
-	//collection := mongoconn.ConnectDB()
-	collection := mongoconn.Client.Database("netmaker").Collection("users")
-
-	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-
-	// Create filter
-	filter := bson.M{"username": queryUser}
-
-	fmt.Println("Updating User " + user.UserName)
-
-	// prepare update model.
-	update := bson.D{
-		{"$set", bson.D{
-			{"username", user.UserName},
-			{"password", user.Password},
-			{"networks", user.Networks},
-			{"isadmin", user.IsAdmin},
-		}},
+	if err = database.DeleteRecord(database.USERS_TABLE_NAME, queryUser); err != nil {
+		return models.User{}, err
 	}
-	var userupdate models.User
-
-	errN := collection.FindOneAndUpdate(ctx, filter, update).Decode(&userupdate)
-	if errN != nil {
-		fmt.Println("Could not update: ")
-		fmt.Println(errN)
-	} else {
-		fmt.Println("User updated  successfully.")
+	data, err := json.Marshal(&user)
+	if err != nil {
+		return models.User{}, err
 	}
-
-	defer cancel()
-
-	return user, errN
+	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)
+	return user, nil
 }
 
 func updateUser(w http.ResponseWriter, r *http.Request) {
@@ -445,7 +406,7 @@ func updateUser(w http.ResponseWriter, r *http.Request) {
 	var user models.User
 	//start here
 	username := params["username"]
-	user, err := GetUser(username)
+	user, err := GetUserInternal(username)
 	if err != nil {
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
@@ -473,7 +434,7 @@ func updateUserAdm(w http.ResponseWriter, r *http.Request) {
 	var user models.User
 	//start here
 	username := params["username"]
-	user, err := GetUser(username)
+	user, err := GetUserInternal(username)
 	if err != nil {
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
@@ -496,25 +457,15 @@ func updateUserAdm(w http.ResponseWriter, r *http.Request) {
 
 func DeleteUser(user string) (bool, error) {
 
-	deleted := false
-
-	collection := mongoconn.Client.Database("netmaker").Collection("users")
-
-	filter := bson.M{"username": user}
-
-	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-
-	result, err := collection.DeleteOne(ctx, filter)
-
-	deletecount := result.DeletedCount
-
-	if deletecount > 0 {
-		deleted = true
+	if userRecord, err := database.FetchRecord(database.USERS_TABLE_NAME, user); err != nil || len(userRecord) == 0 {
+		return false, errors.New("user does not exist")
 	}
 
-	defer cancel()
-
-	return deleted, err
+	err := database.DeleteRecord(database.USERS_TABLE_NAME, user)
+	if err != nil {
+		return false, err
+	}
+	return true, nil
 }
 
 func deleteUser(w http.ResponseWriter, r *http.Request) {
@@ -531,7 +482,7 @@ func deleteUser(w http.ResponseWriter, r *http.Request) {
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 	} else if !success {
-		returnErrorResponse(w, r, formatError(errors.New("Delete unsuccessful."), "badrequest"))
+		returnErrorResponse(w, r, formatError(errors.New("delete unsuccessful."), "badrequest"))
 		return
 	}
 

+ 8 - 12
controllers/userHttpController_test.go

@@ -1,23 +1,19 @@
 package controller
 
 import (
-	"context"
-	"os"
 	"testing"
-	"time"
 
 	"github.com/gravitl/netmaker/models"
-	"github.com/gravitl/netmaker/mongoconn"
 	"github.com/stretchr/testify/assert"
 )
 
-func TestMain(m *testing.M) {
-	mongoconn.ConnectDatabase()
+/*func TestMain(m *testing.M) {
+	database.InitializeDatabase()
 	var gconf models.GlobalConfig
 	gconf.ServerGRPC = "localhost:8081"
 	gconf.PortGRPC = "50051"
 	//err := SetGlobalConfig(gconf)
-	collection := mongoconn.Client.Database("netmaker").Collection("config")
+	collection := REMOVE.Client.Database("netmaker").Collection("config")
 	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
 	defer cancel()
 	//create, _, err := functions.GetGlobalConfig()
@@ -28,7 +24,7 @@ func TestMain(m *testing.M) {
 	//drop network, nodes, and user collections
 	var collections = []string{"networks", "nodes", "users", "dns"}
 	for _, table := range collections {
-		collection := mongoconn.Client.Database("netmaker").Collection(table)
+		collection := REMOVE.Client.Database("netmaker").Collection(table)
 		ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
 		defer cancel()
 		err := collection.Drop(ctx)
@@ -38,7 +34,7 @@ func TestMain(m *testing.M) {
 	}
 	os.Exit(m.Run())
 }
-
+*/
 func TestHasAdmin(t *testing.T) {
 	_, err := DeleteUser("admin")
 	assert.Nil(t, err)
@@ -179,12 +175,12 @@ func TestUpdateUser(t *testing.T) {
 
 func TestValidateUserToken(t *testing.T) {
 	t.Run("EmptyToken", func(t *testing.T) {
-		err := ValidateUserToken("","",false)
+		err := ValidateUserToken("", "", false)
 		assert.NotNil(t, err)
 		assert.Equal(t, "Missing Auth Token.", err.Error())
 	})
 	t.Run("InvalidToken", func(t *testing.T) {
-		err := ValidateUserToken("Bearer: badtoken","",false)
+		err := ValidateUserToken("Bearer: badtoken", "", false)
 		assert.NotNil(t, err)
 		assert.Equal(t, "Error Verifying Auth Token", err.Error())
 	})
@@ -193,7 +189,7 @@ func TestValidateUserToken(t *testing.T) {
 		//need authorization
 	})
 	t.Run("ValidToken", func(t *testing.T) {
-		err := ValidateUserToken("Bearer: secretkey","",true)
+		err := ValidateUserToken("Bearer: secretkey", "", true)
 		assert.Nil(t, err)
 	})
 }

+ 109 - 0
database/database.go

@@ -0,0 +1,109 @@
+package database
+
+import (
+	"encoding/json"
+	"errors"
+	"github.com/rqlite/gorqlite"
+)
+
+const NETWORKS_TABLE_NAME = "networks"
+const NODES_TABLE_NAME = "nodes"
+const USERS_TABLE_NAME = "users"
+const DNS_TABLE_NAME = "dns"
+const EXT_CLIENT_TABLE_NAME = "extclients"
+const INT_CLIENTS_TABLE_NAME = "intclients"
+const DATABASE_FILENAME = "netmaker.db"
+
+var Database gorqlite.Connection
+
+func InitializeDatabase() error {
+
+	conn, err := gorqlite.Open("http://")
+	if err != nil {
+		return err
+	}
+
+	// sqliteDatabase, _ := sql.Open("sqlite3", "./database/"+dbFilename)
+	Database = conn
+	Database.SetConsistencyLevel("strong")
+	createTables()
+	return nil
+}
+
+func createTables() {
+	createTable(NETWORKS_TABLE_NAME)
+	createTable(NODES_TABLE_NAME)
+	createTable(USERS_TABLE_NAME)
+	createTable(DNS_TABLE_NAME)
+	createTable(EXT_CLIENT_TABLE_NAME)
+	createTable(INT_CLIENTS_TABLE_NAME)
+}
+
+func createTable(tableName string) error {
+	_, err := Database.WriteOne("CREATE TABLE IF NOT EXISTS " + tableName + " (key TEXT NOT NULL UNIQUE PRIMARY KEY, value TEXT)")
+	if err != nil {
+		return err
+	}
+	return nil
+}
+
+func isJSONString(value string) bool {
+	var jsonInt interface{}
+	return json.Unmarshal([]byte(value), &jsonInt) == nil
+}
+
+func Insert(key string, value string, tableName string) error {
+	if key != "" && value != "" && isJSONString(value) {
+		_, err := Database.WriteOne("INSERT OR REPLACE INTO " + tableName + " (key, value) VALUES ('" + key + "', '" + value + "')")
+		if err != nil {
+			return err
+		}
+		return nil
+	} else {
+		return errors.New("invalid insert " + key + " : " + value)
+	}
+}
+
+func DeleteRecord(tableName string, key string) error {
+	_, err := Database.WriteOne("DELETE FROM " + tableName + " WHERE key = \"" + key + "\"")
+	if err != nil {
+		return err
+	}
+	return nil
+}
+
+func DeleteAllRecords(tableName string) error {
+	_, err := Database.WriteOne("DELETE TABLE " + tableName)
+	if err != nil {
+		return err
+	}
+	err = createTable(tableName)
+	if err != nil {
+		return err
+	}
+	return nil
+}
+
+func FetchRecord(tableName string, key string) (string, error) {
+	results, err := FetchRecords(tableName)
+	if err != nil {
+		return "", err
+	}
+	return results[key], nil
+}
+
+func FetchRecords(tableName string) (map[string]string, error) {
+	row, err := Database.QueryOne("SELECT * FROM " + tableName + " ORDER BY key")
+	if err != nil {
+		return nil, err
+	}
+	records := make(map[string]string)
+	for row.Next() { // Iterate and fetch the records from result cursor
+		var key string
+		var value string
+		row.Scan(&key, &value)
+		records[key] = value
+	}
+	// log.Println(records)
+	return records, nil
+}

+ 166 - 18
docs/quick-start.rst

@@ -1,33 +1,181 @@
-===========
-Quick Start
-===========
+====================
+Quick Install
+=====================
 
 Introduction
 ==============
 
-This is a guide to getting up and running with Netmaker as quickly as possible. 
+This is an **opinionated** guide for getting up and running with Netmaker as quickly as possible. If this configuration does not fit your use case, see the Advanced Installation docs. 
+
+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.
 
-By default, Netmaker ships with DNS Mode, Client Mode, and Secure GRPC enabled. However, these features require special permissions and are not necessary for a simple setup, so we are going to deploy without them. To learn more about enabling these features, check out the :doc:`installation docs <./server-installation>`.
+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.
 
-Prerequisites
+
+0. Prerequisites
 ==================
- #. A Linux server to host Netmaker, with an external IP reachable by your nodes (will be referred to as **your-host** in  document).
+-  **Virtual Machine**
+   
+   - 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
+   - Ubuntu  20.04 Installed
+
+- **Domain**
+
+  - A publicly owned domain (e.x. example.com, mysite.biz) 
+  - Permission and access to modify DNS records via DNS service (e.x: Route53)
+
+
+
  #. Docker and Docker Compose installed on the above server. Follow the official `Docker instructions <https://docs.docker.com/engine/install/>`_ for installing Docker and Docker Compose on your system.
  #. All network nodes should be systemd-based (see Compatibility under :doc:`Architecture <./architecture>` docs)
 
-Install
-==============
-#. ``ssh root@your-host``
-#. ``wget -O docker-compose.yml https://raw.githubusercontent.com/gravitl/netmaker/master/compose/docker-compose.slim.yml``
-#. ``sed -i ‘s/HOST_IP/< Insert your-host IP Address Here >/g’ docker-compose.yml``
-#. ``docker-compose up -d``
+1. Install Dependencies
+========================
 
-Navigate to the IP address of your host in the browser. You should see the below screen. If not, please see the Quick Start section of the :doc:`troubleshooting <./support>` docs.
+  ``ssh root@your-host``
 
-.. image:: images/create-user.png
-   :width: 80%
-   :alt: Create User Screen
-   :align: center
+Install Docker
+---------------
+Begin by installing the community version of Docker and docker-compose (there are issues with the snap version).
+
+``sudo apt-get remove docker docker-engine docker.io containerd runc``
+ 
+``sudo apt-get update``
+ 
+    ``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``
+  
+``sudo apt-get update``
+  
+``sudo apt-get install docker-ce docker-ce-cli containerd.io``
+
+``sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose``
+
+``sudo chmod +x /usr/local/bin/docker-compose``
+
+``docker --version``
+
+``docker-compose --version``
+
+At this point Docker should be installed.
+
+Install Dependencies
+-----------------------------
+
+``sudo apt install wireguard wireguard-tools nginx certbot python3-certbot-nginx net-tools``
+
+ 
+2. Prepare VM
+===============================
+
+Prepare Domain
+----------------------------
+1. Choose a base domain or subdomain for Netmaker. If you own **example.com**, this should be something like **netmaker.example.com** 
+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:
+
+    - dashboard.netmaker.example.com
+
+    - api.netmaker.example.com
+
+    - grpc.netmaker.example.com
+
+Moving forward we will refer to your base domain using **<your base domain>**. Replace these references with your domain (e.g. netmaker.example.com).
+
+4. ``nslookup host.<your base domain>`` (inserting your domain) should now return the IP of your VM.
+
+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>”``
+
+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.
+
+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``
+
+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.
+
+Prepare Nginx
+-----------------
+
+Nginx will serve the SSL certificate with your chosen domain and forward traffic to netmaker.
+
+Add the nginx configuration file:
+
+``wget https://github.com/gravitl/netmaker/TEMPLATE.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``
+
+``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
+
+``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
+
+===========
+Quick Start
+===========
 
 Setup
 =================

+ 183 - 508
functions/helpers.go

@@ -5,7 +5,6 @@
 package functions
 
 import (
-	"context"
 	"encoding/base64"
 	"encoding/json"
 	"errors"
@@ -16,13 +15,9 @@ import (
 	"strings"
 	"time"
 
+	"github.com/gravitl/netmaker/database"
 	"github.com/gravitl/netmaker/models"
-	"github.com/gravitl/netmaker/mongoconn"
 	"github.com/gravitl/netmaker/servercfg"
-	"go.mongodb.org/mongo-driver/bson"
-	"go.mongodb.org/mongo-driver/bson/primitive"
-	"go.mongodb.org/mongo-driver/mongo"
-	"go.mongodb.org/mongo-driver/mongo/options"
 )
 
 func PrintUserLog(username string, message string, loglevel int) {
@@ -32,9 +27,46 @@ func PrintUserLog(username string, message string, loglevel int) {
 	}
 }
 
+func ParseNetwork(value string) (models.Network, error) {
+	var network models.Network
+	err := json.Unmarshal([]byte(value), &network)
+	return network, err
+}
+
+func ParseNode(value string) (models.Node, error) {
+	var node models.Node
+	err := json.Unmarshal([]byte(value), &node)
+	return node, err
+}
+
+func ParseExtClient(value string) (models.ExtClient, error) {
+	var extClient models.ExtClient
+	err := json.Unmarshal([]byte(value), &extClient)
+	return extClient, err
+}
+
+func ParseIntClient(value string) (models.IntClient, error) {
+	var intClient models.IntClient
+	err := json.Unmarshal([]byte(value), &intClient)
+	return intClient, err
+}
+
 //Takes in an arbitrary field and value for field and checks to see if any other
 //node has that value for the same field within the network
 
+func GetUser(username string) (models.User, error) {
+
+	var user models.User
+	record, err := database.FetchRecord(database.USERS_TABLE_NAME, username)
+	if err != nil {
+		return user, err
+	}
+	if err = json.Unmarshal([]byte(record), &user); err != nil {
+		return models.User{}, err
+	}
+	return user, err
+}
+
 func SliceContains(slice []string, item string) bool {
 	set := make(map[string]struct{}, len(slice))
 	for _, s := range slice {
@@ -56,8 +88,8 @@ func CreateServerToken(netID string) (string, error) {
 
 	var accessToken models.AccessToken
 	servervals := models.ServerConfig{
-		APIConnString:  "127.0.0.1" + servercfg.GetAPIPort(),
-		GRPCConnString: "127.0.0.1" + servercfg.GetGRPCPort(),
+		APIConnString:  "127.0.0.1:" + servercfg.GetAPIPort(),
+		GRPCConnString: "127.0.0.1:" + servercfg.GetGRPCPort(),
 		GRPCSSL:        "off",
 	}
 	accessToken.ServerConfig = servervals
@@ -65,7 +97,7 @@ func CreateServerToken(netID string) (string, error) {
 	accessToken.ClientConfig.Key = GenKey()
 
 	accesskey.Name = GenKeyName()
-	accesskey.Value = GenKey()
+	accesskey.Value = accessToken.ClientConfig.Key
 	accesskey.Uses = 1
 
 	tokenjson, err := json.Marshal(accessToken)
@@ -76,179 +108,91 @@ func CreateServerToken(netID string) (string, error) {
 	accesskey.AccessString = base64.StdEncoding.EncodeToString([]byte(tokenjson))
 
 	network.AccessKeys = append(network.AccessKeys, accesskey)
-
-	collection := mongoconn.Client.Database("netmaker").Collection("networks")
-
-	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-
-	// Create filter
-	filter := bson.M{"netid": netID}
-
-	// prepare update model.
-	update := bson.D{
-		{"$set", bson.D{
-			{"accesskeys", network.AccessKeys},
-		}},
+	if data, err := json.Marshal(network); err != nil {
+		return "", err
+	} else {
+		database.Insert(netID, string(data), database.NETWORKS_TABLE_NAME)
 	}
 
-	errN := collection.FindOneAndUpdate(ctx, filter, update).Decode(&network)
-
-	defer cancel()
-
-	if errN != nil {
-		return "", errN
-	}
 	return accesskey.AccessString, nil
 }
 
 func GetPeersList(networkName string) ([]models.PeersResponse, error) {
 
 	var peers []models.PeersResponse
-
-	//Connection mongoDB with mongoconn class
-	collection := mongoconn.Client.Database("netmaker").Collection("nodes")
-
-	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-
-	//Get all nodes in the relevant network which are NOT in pending state
-	filter := bson.M{"network": networkName, "ispending": false}
-	cur, err := collection.Find(ctx, filter)
-
+	collection, err := database.FetchRecords(database.NODES_TABLE_NAME)
 	if err != nil {
 		return peers, err
 	}
 
-	// Close the cursor once finished and cancel if it takes too long
-	defer cancel()
-
-	for cur.Next(context.TODO()) {
+	for _, value := range collection {
 
 		var peer models.PeersResponse
-		err := cur.Decode(&peer)
+		err := json.Unmarshal([]byte(value), &peer)
 		if err != nil {
-			log.Fatal(err)
+			continue // try the rest
 		}
-
-		// add the node to our node array
-		//maybe better to just return this? But then that's just GetNodes...
 		peers = append(peers, peer)
 	}
 
-	//Uh oh, fatal error! This needs some better error handling
-	//TODO: needs appropriate error handling so the server doesnt shut down.
-	if err := cur.Err(); err != nil {
-		log.Fatal(err)
-	}
-
 	return peers, err
 }
 
 func GetIntPeersList() ([]models.PeersResponse, error) {
 
 	var peers []models.PeersResponse
-
-	collection := mongoconn.Client.Database("netmaker").Collection("intclients")
-
-	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-
-	filter := bson.M{"isserver": ""}
-
-	cur, err := collection.Find(ctx, filter)
+	records, err := database.FetchRecords(database.INT_CLIENTS_TABLE_NAME)
 
 	if err != nil {
 		return peers, err
 	}
+	// parse the peers
 
-	// Close the cursor once finished and cancel if it takes too long
-	defer cancel()
-
-	for cur.Next(context.TODO()) {
+	for _, value := range records {
 
 		var peer models.PeersResponse
-		err := cur.Decode(&peer)
+		err := json.Unmarshal([]byte(value), &peer)
 		if err != nil {
 			log.Fatal(err)
 		}
-
 		// add the node to our node array
 		//maybe better to just return this? But then that's just GetNodes...
 		peers = append(peers, peer)
 	}
 
-	//Uh oh, fatal error! This needs some better error handling
-	//TODO: needs appropriate error handling so the server doesnt shut down.
-	if err := cur.Err(); err != nil {
-		log.Fatal(err)
-	}
-
 	return peers, err
 }
 
-func IsFieldUnique(network string, field string, value string) bool {
-
-	var node models.Node
-	isunique := true
-
-	collection := mongoconn.Client.Database("netmaker").Collection("nodes")
-	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-
-	filter := bson.M{field: value, "network": network}
-
-	err := collection.FindOne(ctx, filter).Decode(&node)
-
-	defer cancel()
-
-	if err != nil {
-		return isunique
-	}
-
-	if node.Name != "" {
-		isunique = false
-	}
-
-	return isunique
-}
-
-func ServerIntClientExists() (bool, error) {
-
-	collection := mongoconn.Client.Database("netmaker").Collection("intclients")
+func GetServerIntClient() (*models.IntClient, error) {
 
-	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-
-	filter := bson.M{"isserver": "yes"}
-
-	var result bson.M
-	err := collection.FindOne(ctx, filter).Decode(&result)
-
-	defer cancel()
-
-	if err != nil {
-		if err == mongo.ErrNoDocuments {
-			return false, nil
+	intClients, err := database.FetchRecords(database.INT_CLIENTS_TABLE_NAME)
+	for _, value := range intClients {
+		var intClient models.IntClient
+		err = json.Unmarshal([]byte(value), &intClient)
+		if err != nil {
+			return nil, err
+		}
+		if intClient.IsServer == "yes" && intClient.Network == "comms" {
+			return &intClient, nil
 		}
 	}
-	return true, err
+	return nil, err
 }
 
 func NetworkExists(name string) (bool, error) {
 
-	collection := mongoconn.Client.Database("netmaker").Collection("networks")
-
-	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-
-	filter := bson.M{"netid": name}
-
-	var result bson.M
-	err := collection.FindOne(ctx, filter).Decode(&result)
-
-	defer cancel()
-
-	if err != nil {
-		if err == mongo.ErrNoDocuments {
-			return false, nil
-		}
+	var network string
+	var err error
+	if network, err = database.FetchRecord(database.NETWORKS_TABLE_NAME, name); err != nil {
+		return false, err
+	}
+	return len(network) > 0, nil
+}
+func GetRecordKey(id string, network string) (string, error) {
+	if id == "" || network == "" {
+		return "", errors.New("unable to get record key")
 	}
-	return true, err
+	return id + "###" + network, nil
 }
 
 //TODO: This is  very inefficient (N-squared). Need to find a better way.
@@ -256,25 +200,15 @@ func NetworkExists(name string) (bool, error) {
 //for each node, it gets a unique address. That requires checking against all other nodes once more
 func UpdateNetworkNodeAddresses(networkName string) error {
 
-	//Connection mongoDB with mongoconn class
-	collection := mongoconn.Client.Database("netmaker").Collection("nodes")
-
-	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-
-	filter := bson.M{"network": networkName}
-	cur, err := collection.Find(ctx, filter)
-
+	collections, err := database.FetchRecords(database.NODES_TABLE_NAME)
 	if err != nil {
 		return err
 	}
 
-	defer cancel()
-
-	for cur.Next(context.TODO()) {
+	for _, value := range collections {
 
 		var node models.Node
-
-		err := cur.Decode(&node)
+		err := json.Unmarshal([]byte(value), &node)
 		if err != nil {
 			fmt.Println("error in node address assignment!")
 			return err
@@ -285,42 +219,30 @@ func UpdateNetworkNodeAddresses(networkName string) error {
 			return iperr
 		}
 
-		filter := bson.M{"macaddress": node.MacAddress}
-		update := bson.D{{"$set", bson.D{{"address", ipaddr}}}}
-
-		errN := collection.FindOneAndUpdate(ctx, filter, update).Decode(&node)
-
-		defer cancel()
-		if errN != nil {
-			return errN
+		node.Address = ipaddr
+		data, err := json.Marshal(&node)
+		if err != nil {
+			return err
 		}
+		database.Insert(node.MacAddress, string(data), database.NODES_TABLE_NAME)
 	}
 
-	return err
+	return nil
 }
 
-//TODO TODO TODO!!!!!
-func UpdateNetworkPrivateAddresses(networkName string) error {
-
-	//Connection mongoDB with mongoconn class
-	collection := mongoconn.Client.Database("netmaker").Collection("nodes")
+func UpdateNetworkLocalAddresses(networkName string) error {
 
-	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-
-	filter := bson.M{"network": networkName}
-	cur, err := collection.Find(ctx, filter)
+	collection, err := database.FetchRecords(database.NODES_TABLE_NAME)
 
 	if err != nil {
 		return err
 	}
 
-	defer cancel()
-
-	for cur.Next(context.TODO()) {
+	for _, value := range collection {
 
 		var node models.Node
 
-		err := cur.Decode(&node)
+		err := json.Unmarshal([]byte(value), &node)
 		if err != nil {
 			fmt.Println("error in node address assignment!")
 			return err
@@ -331,34 +253,30 @@ func UpdateNetworkPrivateAddresses(networkName string) error {
 			return iperr
 		}
 
-		filter := bson.M{"macaddress": node.MacAddress}
-		update := bson.D{{"$set", bson.D{{"address", ipaddr}}}}
-
-		errN := collection.FindOneAndUpdate(ctx, filter, update).Decode(&node)
-
-		defer cancel()
-		if errN != nil {
-			return errN
+		node.Address = ipaddr
+		newNodeData, err := json.Marshal(&node)
+		if err != nil {
+			fmt.Println("error in node  address assignment!")
+			return err
 		}
+		database.Insert(node.MacAddress, string(newNodeData), database.NODES_TABLE_NAME)
 	}
 
-	return err
+	return nil
 }
 
-//Checks to see if any other networks have the same name (id)
-func IsNetworkNameUnique(name string) (bool, error) {
+func IsNetworkDisplayNameUnique(name string) (bool, error) {
 
 	isunique := true
 
-	dbs, err := ListNetworks()
-
+	dbs, err := models.GetNetworks()
 	if err != nil {
 		return false, err
 	}
 
 	for i := 0; i < len(dbs); i++ {
 
-		if name == dbs[i].NetID {
+		if name == dbs[i].DisplayName {
 			isunique = false
 		}
 	}
@@ -366,80 +284,45 @@ func IsNetworkNameUnique(name string) (bool, error) {
 	return isunique, nil
 }
 
-func IsNetworkDisplayNameUnique(name string) (bool, error) {
-
-	isunique := true
+func IsMacAddressUnique(macaddress string, networkName string) (bool, error) {
 
-	dbs, err := ListNetworks()
+	collection, err := database.FetchRecords(database.NODES_TABLE_NAME)
 	if err != nil {
 		return false, err
 	}
-
-	for i := 0; i < len(dbs); i++ {
-
-		if name == dbs[i].DisplayName {
-			isunique = false
+	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 isunique, nil
+	return true, nil
 }
 
 func GetNetworkNodeNumber(networkName string) (int, error) {
 
-	collection := mongoconn.Client.Database("netmaker").Collection("nodes")
-
-	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-
-	filter := bson.M{"network": networkName}
-	count, err := collection.CountDocuments(ctx, filter)
-	returncount := int(count)
-
-	//not sure if this is the right way of handling this error...
-	if err != nil {
-		return 9999, err
-	}
-
-	defer cancel()
-
-	return returncount, err
-}
-
-//Kind  of a weird name. Should just be GetNetworks I think. Consider changing.
-//Anyway, returns all the networks
-func ListNetworks() ([]models.Network, error) {
-
-	var networks []models.Network
-
-	collection := mongoconn.Client.Database("netmaker").Collection("networks")
-
-	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-
-	cur, err := collection.Find(ctx, bson.M{}, options.Find().SetProjection(bson.M{"_id": 0}))
-
+	collection, err := database.FetchRecords(database.NODES_TABLE_NAME)
+	count := 0
 	if err != nil {
-		return networks, err
+		return count, err
 	}
-
-	defer cancel()
-
-	for cur.Next(context.TODO()) {
-
-		var network models.Network
-		err := cur.Decode(&network)
-		if err != nil {
-			return networks, err
+	for _, value := range collection {
+		var node models.Node
+		if err = json.Unmarshal([]byte(value), &node); err != nil {
+			return count, err
+		} else {
+			if node.Network == networkName {
+				count++
+			}
 		}
-
-		// add network our array
-		networks = append(networks, network)
-	}
-
-	if err := cur.Err(); err != nil {
-		return networks, err
 	}
 
-	return networks, err
+	return count, nil
 }
 
 //Checks to see if access key is valid
@@ -470,7 +353,7 @@ func IsKeyValid(networkname string, keyvalue string) bool {
 
 func IsKeyValidGlobal(keyvalue string) bool {
 
-	networks, _ := ListNetworks()
+	networks, _ := models.GetNetworks()
 	var key models.AccessKey
 	foundkey := false
 	isvalid := false
@@ -502,20 +385,13 @@ func IsKeyValidGlobal(keyvalue string) bool {
 func GetParentNetwork(networkname string) (models.Network, error) {
 
 	var network models.Network
-
-	collection := mongoconn.Client.Database("netmaker").Collection("networks")
-
-	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-
-	filter := bson.M{"netid": networkname}
-	err := collection.FindOne(ctx, filter).Decode(&network)
-
-	defer cancel()
-
+	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 models.Network{}, err
+	}
 	return network, nil
 }
 
@@ -545,31 +421,6 @@ func IsBase64(s string) bool {
 	return err == nil
 }
 
-//This should probably just be called GetNode
-//It returns a node based on the ID of the node.
-//Why do we need this?
-//TODO: Check references. This seems unnecessary.
-func GetNodeObj(id primitive.ObjectID) models.Node {
-
-	var node models.Node
-
-	collection := mongoconn.Client.Database("netmaker").Collection("nodes")
-	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-
-	filter := bson.M{"_id": id}
-	err := collection.FindOne(ctx, filter).Decode(&node)
-
-	defer cancel()
-
-	if err != nil {
-		fmt.Println(err)
-		fmt.Println("Did not get the node...")
-		return node
-	}
-	fmt.Println("Got node " + node.Name)
-	return node
-}
-
 //This  checks to  make sure a network name is valid.
 //Switch to REGEX?
 func NameInNetworkCharSet(name string) bool {
@@ -616,47 +467,42 @@ func GetNodeByMacAddress(network string, macaddress string) (models.Node, error)
 
 	var node models.Node
 
-	filter := bson.M{"macaddress": macaddress, "network": network}
-
-	collection := mongoconn.Client.Database("netmaker").Collection("nodes")
-
-	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-
-	err := collection.FindOne(ctx, filter).Decode(&node)
-
-	defer cancel()
-
+	key, err := GetRecordKey(macaddress, network)
 	if err != nil {
 		return node, err
 	}
+
+	record, err := database.FetchRecord(database.NODES_TABLE_NAME, key)
+	if err != nil {
+		return models.Node{}, err
+	}
+
+	if err = json.Unmarshal([]byte(record), &node); err != nil {
+		return models.Node{}, err
+	}
+
 	return node, nil
 }
 
 func DeleteAllIntClients() error {
-	collection := mongoconn.Client.Database("netmaker").Collection("intclients")
-	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-	// Filter out them ID's again
-	err := collection.Drop(ctx)
+	err := database.DeleteAllRecords(database.INT_CLIENTS_TABLE_NAME)
 	if err != nil {
 		return err
 	}
-	defer cancel()
 	return nil
 }
 
 func GetAllIntClients() ([]models.IntClient, error) {
-	var client models.IntClient
 	var clients []models.IntClient
-	collection := mongoconn.Client.Database("netmaker").Collection("intclients")
-	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-	// Filter out them ID's again
-	cur, err := collection.Find(ctx, bson.M{}, options.Find().SetProjection(bson.M{"_id": 0}))
+	collection, err := database.FetchRecords(database.INT_CLIENTS_TABLE_NAME)
+
 	if err != nil {
-		return []models.IntClient{}, err
+		return clients, err
 	}
-	defer cancel()
-	for cur.Next(context.TODO()) {
-		err := cur.Decode(&client)
+
+	for _, value := range collection {
+		var client models.IntClient
+		err := json.Unmarshal([]byte(value), &client)
 		if err != nil {
 			return []models.IntClient{}, err
 		}
@@ -664,26 +510,20 @@ func GetAllIntClients() ([]models.IntClient, error) {
 		clients = append(clients, client)
 	}
 
-	//TODO: Fatal error
-	if err := cur.Err(); err != nil {
-		return []models.IntClient{}, err
-	}
 	return clients, nil
 }
 
 func GetAllExtClients() ([]models.ExtClient, error) {
-	var extclient models.ExtClient
 	var extclients []models.ExtClient
-	collection := mongoconn.Client.Database("netmaker").Collection("extclients")
-	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-	// Filter out them ID's again
-	cur, err := collection.Find(ctx, bson.M{}, options.Find().SetProjection(bson.M{"_id": 0}))
+	collection, err := database.FetchRecords(database.EXT_CLIENT_TABLE_NAME)
+
 	if err != nil {
-		return []models.ExtClient{}, err
+		return extclients, err
 	}
-	defer cancel()
-	for cur.Next(context.TODO()) {
-		err := cur.Decode(&extclient)
+
+	for _, value := range collection {
+		var extclient models.ExtClient
+		err := json.Unmarshal([]byte(value), &extclient)
 		if err != nil {
 			return []models.ExtClient{}, err
 		}
@@ -691,10 +531,6 @@ func GetAllExtClients() ([]models.ExtClient, error) {
 		extclients = append(extclients, extclient)
 	}
 
-	//TODO: Fatal error
-	if err := cur.Err(); err != nil {
-		return []models.ExtClient{}, err
-	}
 	return extclients, nil
 }
 
@@ -724,11 +560,11 @@ func UniqueAddress(networkName string) (string, error) {
 			continue
 		}
 		if networkName == "comms" {
-			if IsIPUniqueClients(networkName, ip.String()) {
+			if IsIPUnique(networkName, ip.String(), database.INT_CLIENTS_TABLE_NAME, false) {
 				return ip.String(), err
 			}
 		} else {
-			if IsIPUnique(networkName, ip.String()) && IsIPUniqueExtClients(networkName, ip.String()) {
+			if IsIPUnique(networkName, ip.String(), database.NODES_TABLE_NAME, false) && IsIPUnique(networkName, ip.String(), database.EXT_CLIENT_TABLE_NAME, false) {
 				return ip.String(), err
 			}
 		}
@@ -747,7 +583,7 @@ func UniqueAddress6(networkName string) (string, error) {
 		fmt.Println("Network Not Found")
 		return "", err
 	}
-	if network.IsDualStack == nil || *network.IsDualStack == false {
+	if network.IsDualStack == "no" {
 		if networkName != "comms" {
 			return "", nil
 		}
@@ -765,11 +601,11 @@ func UniqueAddress6(networkName string) (string, error) {
 			continue
 		}
 		if networkName == "comms" {
-			if IsIP6UniqueClients(networkName, ip.String()) {
+			if IsIPUnique(networkName, ip.String(), database.INT_CLIENTS_TABLE_NAME, true) {
 				return ip.String(), err
 			}
 		} else {
-			if IsIP6Unique(networkName, ip.String()) {
+			if IsIPUnique(networkName, ip.String(), database.NODES_TABLE_NAME, true) {
 				return ip.String(), err
 			}
 		}
@@ -814,136 +650,31 @@ func GenKeyName() string {
 	return "key" + string(b)
 }
 
-func IsIPUniqueExtClients(network string, ip string) bool {
-
-	var extclient models.ExtClient
-
-	isunique := true
-
-	collection := mongoconn.Client.Database("netmaker").Collection("extclients")
-	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-
-	filter := bson.M{"address": ip, "network": network}
-
-	err := collection.FindOne(ctx, filter).Decode(&extclient)
-
-	defer cancel()
-
-	if err != nil {
-		return isunique
-	}
-
-	if extclient.Address == ip {
-		isunique = false
-	}
-	return isunique
-}
-
-//checks if IP is unique in the address range
-//used by UniqueAddress
-func IsIPUnique(network string, ip string) bool {
-
-	var node models.Node
-
-	isunique := true
-
-	collection := mongoconn.Client.Database("netmaker").Collection("nodes")
-	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-
-	filter := bson.M{"address": ip, "network": network}
-
-	err := collection.FindOne(ctx, filter).Decode(&node)
-
-	defer cancel()
-
-	if err != nil {
-		return isunique
-	}
-
-	if node.Address == ip {
-		isunique = false
-	}
-	return isunique
-}
-
-//checks if IP is unique in the address range
-//used by UniqueAddress
-func IsIP6Unique(network string, ip string) bool {
-
-	var node models.Node
-
-	isunique := true
-
-	collection := mongoconn.Client.Database("netmaker").Collection("nodes")
-	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-
-	filter := bson.M{"address6": ip, "network": network}
-
-	err := collection.FindOne(ctx, filter).Decode(&node)
-
-	defer cancel()
-
-	if err != nil {
-		return isunique
-	}
-
-	if node.Address6 == ip {
-		isunique = false
-	}
-	return isunique
-}
-
-//checks if IP is unique in the address range
-//used by UniqueAddress
-func IsIP6UniqueClients(network string, ip string) bool {
-
-	var client models.IntClient
+func IsIPUnique(network string, ip string, tableName string, isIpv6 bool) bool {
 
 	isunique := true
-
-	collection := mongoconn.Client.Database("netmaker").Collection("intclients")
-	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-
-	filter := bson.M{"address6": ip, "network": network}
-
-	err := collection.FindOne(ctx, filter).Decode(&client)
-
-	defer cancel()
+	collection, err := database.FetchRecords(tableName)
 
 	if err != nil {
 		return isunique
 	}
 
-	if client.Address6 == ip {
-		isunique = false
-	}
-	return isunique
-}
-
-//checks if IP is unique in the address range
-//used by UniqueAddress
-func IsIPUniqueClients(network string, ip string) bool {
-
-	var client models.IntClient
-
-	isunique := true
-
-	collection := mongoconn.Client.Database("netmaker").Collection("intclients")
-	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-
-	filter := bson.M{"address": ip, "network": network}
-
-	err := collection.FindOne(ctx, filter).Decode(&client)
-
-	defer cancel()
-
-	if err != nil {
-		return isunique
+	for _, value := range collection { // filter
+		var node models.Node
+		if err = json.Unmarshal([]byte(value), &node); err != nil {
+			continue
+		}
+		if isIpv6 {
+			if node.Address6 == ip && node.Network == network {
+				return false
+			}
+		} else {
+			if node.Address == ip && node.Network == network {
+				return false
+			}
+		}
 	}
 
-	if client.Address == ip {
-		isunique = false
-	}
 	return isunique
 }
 
@@ -964,31 +695,18 @@ func DecrimentKey(networkName string, keyvalue string) {
 		if currentkey.Value == keyvalue {
 			network.AccessKeys[i].Uses--
 			if network.AccessKeys[i].Uses < 1 {
-				//this is the part where it will call the delete
-				//not sure if there's edge cases I'm missing
-				DeleteKey(network, i)
-				return
+				network.AccessKeys = append(network.AccessKeys[:i],
+					network.AccessKeys[i+1:]...)
+				break
 			}
 		}
 	}
 
-	collection := mongoconn.Client.Database("netmaker").Collection("networks")
-
-	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-
-	filter := bson.M{"netid": network.NetID}
-
-	update := bson.D{
-		{"$set", bson.D{
-			{"accesskeys", network.AccessKeys},
-		}},
-	}
-	errN := collection.FindOneAndUpdate(ctx, filter, update).Decode(&network)
-
-	defer cancel()
-
-	if errN != nil {
+	if newNetworkData, err := json.Marshal(&network); err != nil {
+		PrintUserLog("netmaker", "failed to decrement key", 2)
 		return
+	} else {
+		database.Insert(network.NetID, string(newNetworkData), database.NETWORKS_TABLE_NAME)
 	}
 }
 
@@ -998,26 +716,10 @@ func DeleteKey(network models.Network, i int) {
 	network.AccessKeys = append(network.AccessKeys[:i],
 		network.AccessKeys[i+1:]...)
 
-	collection := mongoconn.Client.Database("netmaker").Collection("networks")
-
-	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-
-	// Create filter
-	filter := bson.M{"netid": network.NetID}
-
-	// prepare update model.
-	update := bson.D{
-		{"$set", bson.D{
-			{"accesskeys", network.AccessKeys},
-		}},
-	}
-
-	errN := collection.FindOneAndUpdate(ctx, filter, update).Decode(&network)
-
-	defer cancel()
-
-	if errN != nil {
+	if networkData, err := json.Marshal(&network); err != nil {
 		return
+	} else {
+		database.Insert(network.NetID, string(networkData), database.NETWORKS_TABLE_NAME)
 	}
 }
 
@@ -1030,30 +732,3 @@ func Inc(ip net.IP) {
 		}
 	}
 }
-
-func GetAllNodes() ([]models.Node, error) {
-	var node models.Node
-	var nodes []models.Node
-	collection := mongoconn.Client.Database("netmaker").Collection("nodes")
-	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-	// Filter out them ID's again
-	cur, err := collection.Find(ctx, bson.M{}, options.Find().SetProjection(bson.M{"_id": 0}))
-	if err != nil {
-		return []models.Node{}, err
-	}
-	defer cancel()
-	for cur.Next(context.TODO()) {
-		err := cur.Decode(&node)
-		if err != nil {
-			return []models.Node{}, err
-		}
-		// add node to our array
-		nodes = append(nodes, node)
-	}
-
-	//TODO: Fatal error
-	if err := cur.Err(); err != nil {
-		return []models.Node{}, err
-	}
-	return nodes, nil
-}

+ 5 - 1
go.mod

@@ -3,13 +3,17 @@ module github.com/gravitl/netmaker
 go 1.15
 
 require (
-	github.com/davecgh/go-spew v1.1.1 // indirect
+	github.com/aws/aws-sdk-go v1.34.28
+	github.com/davecgh/go-spew v1.1.1
 	github.com/dgrijalva/jwt-go v3.2.0+incompatible
 	github.com/go-playground/validator/v10 v10.5.0
+	github.com/go-sql-driver/mysql v1.6.0 // indirect
 	github.com/golang/protobuf v1.5.2
 	github.com/gorilla/handlers v1.5.1
 	github.com/gorilla/mux v1.8.0
 	github.com/jinzhu/copier v0.3.2 // indirect
+	github.com/mattn/go-sqlite3 v1.14.8
+	github.com/rqlite/gorqlite v0.0.0-20210514125552-08ff1e76b22f
 	github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e
 	github.com/stretchr/testify v1.6.1
 	github.com/txn2/txeh v1.3.0

+ 6 - 0
go.sum

@@ -34,6 +34,8 @@ github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+
 github.com/go-playground/validator/v10 v10.5.0 h1:X9rflw/KmpACwT8zdrm1upefpvdy6ur8d1kWyq6sg3E=
 github.com/go-playground/validator/v10 v10.5.0/go.mod h1:xm76BBt941f7yWdGnI2DVPFFg1UK3YY04qifoXU3lOk=
 github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
+github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
+github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
 github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=
 github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
 github.com/gobuffalo/attrs v0.0.0-20190224210810-a9411de4debd/go.mod h1:4duuawTqi2wkkpB4ePgWMaai6/Kc6WEz83bhFwpHzj0=
@@ -119,6 +121,8 @@ github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgx
 github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
 github.com/markbates/oncer v0.0.0-20181203154359-bf2de49a0be2/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE=
 github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0=
+github.com/mattn/go-sqlite3 v1.14.8 h1:gDp86IdQsN/xWjIEmr9MF6o9mpksUgh0fu+9ByFxzIU=
+github.com/mattn/go-sqlite3 v1.14.8/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
 github.com/mdlayher/genetlink v1.0.0 h1:OoHN1OdyEIkScEmRgxLEe2M9U8ClMytqA5niynLtfj0=
 github.com/mdlayher/genetlink v1.0.0/go.mod h1:0rJ0h4itni50A86M2kHcgS85ttZazNt7a8H2a2cw0Gc=
 github.com/mdlayher/netlink v0.0.0-20190409211403-11939a169225/go.mod h1:eQB3mZE4aiYnlUsyGGCOpPETfdQq4Jhsgf1fk3cwQaA=
@@ -142,6 +146,8 @@ github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:
 github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
 github.com/rogpeppe/go-internal v1.2.2/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
 github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
+github.com/rqlite/gorqlite v0.0.0-20210514125552-08ff1e76b22f h1:BSnJgAfHzEp7o8PYJ7YfwAVHhqu7BYUTggcn/LGlUWY=
+github.com/rqlite/gorqlite v0.0.0-20210514125552-08ff1e76b22f/go.mod h1:UW/gxgQwSePTvL1KA8QEHsXeYHP4xkoXgbDdN781p34=
 github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo=
 github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
 github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q=

+ 1569 - 915
grpc/node.pb.go

@@ -1,1436 +1,2090 @@
 // Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// 	protoc-gen-go v1.25.0-devel
+// 	protoc        v3.14.0
 // source: grpc/node.proto
 
 package nodepb
 
 import (
-	fmt "fmt"
-	proto "github.com/golang/protobuf/proto"
-	math "math"
+	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+	reflect "reflect"
+	sync "sync"
 )
 
-// Reference imports to suppress errors if they are not otherwise used.
-var _ = proto.Marshal
-var _ = fmt.Errorf
-var _ = math.Inf
-
-// This is a compile-time assertion to ensure that this generated file
-// is compatible with the proto package it is being compiled against.
-// A compilation error at this line likely means your copy of the
-// proto package needs to be updated.
-const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
+const (
+	// Verify that this generated code is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+	// Verify that runtime/protoimpl is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
 
 type LoginRequest struct {
-	Macaddress           string   `protobuf:"bytes,1,opt,name=macaddress,proto3" json:"macaddress,omitempty"`
-	Password             string   `protobuf:"bytes,2,opt,name=password,proto3" json:"password,omitempty"`
-	Network              string   `protobuf:"bytes,3,opt,name=network,proto3" json:"network,omitempty"`
-	XXX_NoUnkeyedLiteral struct{} `json:"-"`
-	XXX_unrecognized     []byte   `json:"-"`
-	XXX_sizecache        int32    `json:"-"`
-}
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
 
-func (m *LoginRequest) Reset()         { *m = LoginRequest{} }
-func (m *LoginRequest) String() string { return proto.CompactTextString(m) }
-func (*LoginRequest) ProtoMessage()    {}
-func (*LoginRequest) Descriptor() ([]byte, []int) {
-	return fileDescriptor_d13bd996b67da4ef, []int{0}
+	Macaddress string `protobuf:"bytes,1,opt,name=macaddress,proto3" json:"macaddress,omitempty"`
+	Password   string `protobuf:"bytes,2,opt,name=password,proto3" json:"password,omitempty"`
+	Network    string `protobuf:"bytes,3,opt,name=network,proto3" json:"network,omitempty"`
 }
 
-func (m *LoginRequest) XXX_Unmarshal(b []byte) error {
-	return xxx_messageInfo_LoginRequest.Unmarshal(m, b)
-}
-func (m *LoginRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
-	return xxx_messageInfo_LoginRequest.Marshal(b, m, deterministic)
-}
-func (m *LoginRequest) XXX_Merge(src proto.Message) {
-	xxx_messageInfo_LoginRequest.Merge(m, src)
+func (x *LoginRequest) Reset() {
+	*x = LoginRequest{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_grpc_node_proto_msgTypes[0]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
 }
-func (m *LoginRequest) XXX_Size() int {
-	return xxx_messageInfo_LoginRequest.Size(m)
+
+func (x *LoginRequest) String() string {
+	return protoimpl.X.MessageStringOf(x)
 }
-func (m *LoginRequest) XXX_DiscardUnknown() {
-	xxx_messageInfo_LoginRequest.DiscardUnknown(m)
+
+func (*LoginRequest) ProtoMessage() {}
+
+func (x *LoginRequest) ProtoReflect() protoreflect.Message {
+	mi := &file_grpc_node_proto_msgTypes[0]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
 }
 
-var xxx_messageInfo_LoginRequest proto.InternalMessageInfo
+// Deprecated: Use LoginRequest.ProtoReflect.Descriptor instead.
+func (*LoginRequest) Descriptor() ([]byte, []int) {
+	return file_grpc_node_proto_rawDescGZIP(), []int{0}
+}
 
-func (m *LoginRequest) GetMacaddress() string {
-	if m != nil {
-		return m.Macaddress
+func (x *LoginRequest) GetMacaddress() string {
+	if x != nil {
+		return x.Macaddress
 	}
 	return ""
 }
 
-func (m *LoginRequest) GetPassword() string {
-	if m != nil {
-		return m.Password
+func (x *LoginRequest) GetPassword() string {
+	if x != nil {
+		return x.Password
 	}
 	return ""
 }
 
-func (m *LoginRequest) GetNetwork() string {
-	if m != nil {
-		return m.Network
+func (x *LoginRequest) GetNetwork() string {
+	if x != nil {
+		return x.Network
 	}
 	return ""
 }
 
 type LoginResponse struct {
-	Accesstoken          string   `protobuf:"bytes,1,opt,name=accesstoken,proto3" json:"accesstoken,omitempty"`
-	XXX_NoUnkeyedLiteral struct{} `json:"-"`
-	XXX_unrecognized     []byte   `json:"-"`
-	XXX_sizecache        int32    `json:"-"`
-}
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
 
-func (m *LoginResponse) Reset()         { *m = LoginResponse{} }
-func (m *LoginResponse) String() string { return proto.CompactTextString(m) }
-func (*LoginResponse) ProtoMessage()    {}
-func (*LoginResponse) Descriptor() ([]byte, []int) {
-	return fileDescriptor_d13bd996b67da4ef, []int{1}
+	Accesstoken string `protobuf:"bytes,1,opt,name=accesstoken,proto3" json:"accesstoken,omitempty"`
 }
 
-func (m *LoginResponse) XXX_Unmarshal(b []byte) error {
-	return xxx_messageInfo_LoginResponse.Unmarshal(m, b)
-}
-func (m *LoginResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
-	return xxx_messageInfo_LoginResponse.Marshal(b, m, deterministic)
-}
-func (m *LoginResponse) XXX_Merge(src proto.Message) {
-	xxx_messageInfo_LoginResponse.Merge(m, src)
+func (x *LoginResponse) Reset() {
+	*x = LoginResponse{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_grpc_node_proto_msgTypes[1]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
 }
-func (m *LoginResponse) XXX_Size() int {
-	return xxx_messageInfo_LoginResponse.Size(m)
+
+func (x *LoginResponse) String() string {
+	return protoimpl.X.MessageStringOf(x)
 }
-func (m *LoginResponse) XXX_DiscardUnknown() {
-	xxx_messageInfo_LoginResponse.DiscardUnknown(m)
+
+func (*LoginResponse) ProtoMessage() {}
+
+func (x *LoginResponse) ProtoReflect() protoreflect.Message {
+	mi := &file_grpc_node_proto_msgTypes[1]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
 }
 
-var xxx_messageInfo_LoginResponse proto.InternalMessageInfo
+// Deprecated: Use LoginResponse.ProtoReflect.Descriptor instead.
+func (*LoginResponse) Descriptor() ([]byte, []int) {
+	return file_grpc_node_proto_rawDescGZIP(), []int{1}
+}
 
-func (m *LoginResponse) GetAccesstoken() string {
-	if m != nil {
-		return m.Accesstoken
+func (x *LoginResponse) GetAccesstoken() string {
+	if x != nil {
+		return x.Accesstoken
 	}
 	return ""
 }
 
 type Node struct {
-	Id                   string   `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
-	Name                 string   `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"`
-	Address              string   `protobuf:"bytes,3,opt,name=address,proto3" json:"address,omitempty"`
-	Address6             string   `protobuf:"bytes,26,opt,name=address6,proto3" json:"address6,omitempty"`
-	Listenport           int32    `protobuf:"varint,4,opt,name=listenport,proto3" json:"listenport,omitempty"`
-	Publickey            string   `protobuf:"bytes,5,opt,name=publickey,proto3" json:"publickey,omitempty"`
-	Endpoint             string   `protobuf:"bytes,6,opt,name=endpoint,proto3" json:"endpoint,omitempty"`
-	Macaddress           string   `protobuf:"bytes,7,opt,name=macaddress,proto3" json:"macaddress,omitempty"`
-	Password             string   `protobuf:"bytes,8,opt,name=password,proto3" json:"password,omitempty"`
-	Nodenetwork          string   `protobuf:"bytes,9,opt,name=nodenetwork,proto3" json:"nodenetwork,omitempty"`
-	Ispending            bool     `protobuf:"varint,10,opt,name=ispending,proto3" json:"ispending,omitempty"`
-	Postup               string   `protobuf:"bytes,11,opt,name=postup,proto3" json:"postup,omitempty"`
-	Postdown             string   `protobuf:"bytes,12,opt,name=postdown,proto3" json:"postdown,omitempty"`
-	Keepalive            int32    `protobuf:"varint,13,opt,name=keepalive,proto3" json:"keepalive,omitempty"`
-	Saveconfig           bool     `protobuf:"varint,14,opt,name=saveconfig,proto3" json:"saveconfig,omitempty"`
-	Accesskey            string   `protobuf:"bytes,15,opt,name=accesskey,proto3" json:"accesskey,omitempty"`
-	Interface            string   `protobuf:"bytes,16,opt,name=interface,proto3" json:"interface,omitempty"`
-	Lastcheckin          string   `protobuf:"bytes,17,opt,name=lastcheckin,proto3" json:"lastcheckin,omitempty"`
-	Lastmodified         string   `protobuf:"bytes,18,opt,name=lastmodified,proto3" json:"lastmodified,omitempty"`
-	Checkininterval      int32    `protobuf:"varint,19,opt,name=checkininterval,proto3" json:"checkininterval,omitempty"`
-	Localaddress         string   `protobuf:"bytes,20,opt,name=localaddress,proto3" json:"localaddress,omitempty"`
-	Postchanges          string   `protobuf:"bytes,21,opt,name=postchanges,proto3" json:"postchanges,omitempty"`
-	Allowedips           string   `protobuf:"bytes,22,opt,name=allowedips,proto3" json:"allowedips,omitempty"`
-	Islocal              bool     `protobuf:"varint,23,opt,name=islocal,proto3" json:"islocal,omitempty"`
-	Isingressgateway     bool     `protobuf:"varint,28,opt,name=isingressgateway,proto3" json:"isingressgateway,omitempty"`
-	Ingressgatewayrange  string   `protobuf:"bytes,29,opt,name=ingressgatewayrange,proto3" json:"ingressgatewayrange,omitempty"`
-	Isdualstack          bool     `protobuf:"varint,27,opt,name=isdualstack,proto3" json:"isdualstack,omitempty"`
-	Dnsoff               bool     `protobuf:"varint,24,opt,name=dnsoff,proto3" json:"dnsoff,omitempty"`
-	Localrange           string   `protobuf:"bytes,25,opt,name=localrange,proto3" json:"localrange,omitempty"`
-	XXX_NoUnkeyedLiteral struct{} `json:"-"`
-	XXX_unrecognized     []byte   `json:"-"`
-	XXX_sizecache        int32    `json:"-"`
-}
-
-func (m *Node) Reset()         { *m = Node{} }
-func (m *Node) String() string { return proto.CompactTextString(m) }
-func (*Node) ProtoMessage()    {}
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Id                  string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
+	Name                string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"`
+	Address             string `protobuf:"bytes,3,opt,name=address,proto3" json:"address,omitempty"`
+	Address6            string `protobuf:"bytes,26,opt,name=address6,proto3" json:"address6,omitempty"`
+	Listenport          int32  `protobuf:"varint,4,opt,name=listenport,proto3" json:"listenport,omitempty"`
+	Publickey           string `protobuf:"bytes,5,opt,name=publickey,proto3" json:"publickey,omitempty"`
+	Endpoint            string `protobuf:"bytes,6,opt,name=endpoint,proto3" json:"endpoint,omitempty"`
+	Macaddress          string `protobuf:"bytes,7,opt,name=macaddress,proto3" json:"macaddress,omitempty"`
+	Password            string `protobuf:"bytes,8,opt,name=password,proto3" json:"password,omitempty"`
+	Nodenetwork         string `protobuf:"bytes,9,opt,name=nodenetwork,proto3" json:"nodenetwork,omitempty"`
+	Ispending           bool   `protobuf:"varint,10,opt,name=ispending,proto3" json:"ispending,omitempty"`
+	Postup              string `protobuf:"bytes,11,opt,name=postup,proto3" json:"postup,omitempty"`
+	Postdown            string `protobuf:"bytes,12,opt,name=postdown,proto3" json:"postdown,omitempty"`
+	Keepalive           int32  `protobuf:"varint,13,opt,name=keepalive,proto3" json:"keepalive,omitempty"`
+	Saveconfig          string `protobuf:"bytes,14,opt,name=saveconfig,proto3" json:"saveconfig,omitempty"`
+	Accesskey           string `protobuf:"bytes,15,opt,name=accesskey,proto3" json:"accesskey,omitempty"`
+	Interface           string `protobuf:"bytes,16,opt,name=interface,proto3" json:"interface,omitempty"`
+	Lastcheckin         string `protobuf:"bytes,17,opt,name=lastcheckin,proto3" json:"lastcheckin,omitempty"`
+	Lastmodified        string `protobuf:"bytes,18,opt,name=lastmodified,proto3" json:"lastmodified,omitempty"`
+	Checkininterval     int32  `protobuf:"varint,19,opt,name=checkininterval,proto3" json:"checkininterval,omitempty"`
+	Localaddress        string `protobuf:"bytes,20,opt,name=localaddress,proto3" json:"localaddress,omitempty"`
+	Postchanges         string `protobuf:"bytes,21,opt,name=postchanges,proto3" json:"postchanges,omitempty"`
+	Allowedips          string `protobuf:"bytes,22,opt,name=allowedips,proto3" json:"allowedips,omitempty"`
+	Islocal             bool   `protobuf:"varint,23,opt,name=islocal,proto3" json:"islocal,omitempty"`
+	Isingressgateway    bool   `protobuf:"varint,28,opt,name=isingressgateway,proto3" json:"isingressgateway,omitempty"`
+	Ingressgatewayrange string `protobuf:"bytes,29,opt,name=ingressgatewayrange,proto3" json:"ingressgatewayrange,omitempty"`
+	Isdualstack         bool   `protobuf:"varint,27,opt,name=isdualstack,proto3" json:"isdualstack,omitempty"`
+	Dnsoff              bool   `protobuf:"varint,24,opt,name=dnsoff,proto3" json:"dnsoff,omitempty"`
+	Localrange          string `protobuf:"bytes,25,opt,name=localrange,proto3" json:"localrange,omitempty"`
+	Udpholepunch        string `protobuf:"bytes,30,opt,name=udpholepunch,proto3" json:"udpholepunch,omitempty"`
+}
+
+func (x *Node) Reset() {
+	*x = Node{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_grpc_node_proto_msgTypes[2]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *Node) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Node) ProtoMessage() {}
+
+func (x *Node) ProtoReflect() protoreflect.Message {
+	mi := &file_grpc_node_proto_msgTypes[2]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use Node.ProtoReflect.Descriptor instead.
 func (*Node) Descriptor() ([]byte, []int) {
-	return fileDescriptor_d13bd996b67da4ef, []int{2}
-}
-
-func (m *Node) XXX_Unmarshal(b []byte) error {
-	return xxx_messageInfo_Node.Unmarshal(m, b)
-}
-func (m *Node) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
-	return xxx_messageInfo_Node.Marshal(b, m, deterministic)
-}
-func (m *Node) XXX_Merge(src proto.Message) {
-	xxx_messageInfo_Node.Merge(m, src)
-}
-func (m *Node) XXX_Size() int {
-	return xxx_messageInfo_Node.Size(m)
-}
-func (m *Node) XXX_DiscardUnknown() {
-	xxx_messageInfo_Node.DiscardUnknown(m)
+	return file_grpc_node_proto_rawDescGZIP(), []int{2}
 }
 
-var xxx_messageInfo_Node proto.InternalMessageInfo
-
-func (m *Node) GetId() string {
-	if m != nil {
-		return m.Id
+func (x *Node) GetId() string {
+	if x != nil {
+		return x.Id
 	}
 	return ""
 }
 
-func (m *Node) GetName() string {
-	if m != nil {
-		return m.Name
+func (x *Node) GetName() string {
+	if x != nil {
+		return x.Name
 	}
 	return ""
 }
 
-func (m *Node) GetAddress() string {
-	if m != nil {
-		return m.Address
+func (x *Node) GetAddress() string {
+	if x != nil {
+		return x.Address
 	}
 	return ""
 }
 
-func (m *Node) GetAddress6() string {
-	if m != nil {
-		return m.Address6
+func (x *Node) GetAddress6() string {
+	if x != nil {
+		return x.Address6
 	}
 	return ""
 }
 
-func (m *Node) GetListenport() int32 {
-	if m != nil {
-		return m.Listenport
+func (x *Node) GetListenport() int32 {
+	if x != nil {
+		return x.Listenport
 	}
 	return 0
 }
 
-func (m *Node) GetPublickey() string {
-	if m != nil {
-		return m.Publickey
+func (x *Node) GetPublickey() string {
+	if x != nil {
+		return x.Publickey
 	}
 	return ""
 }
 
-func (m *Node) GetEndpoint() string {
-	if m != nil {
-		return m.Endpoint
+func (x *Node) GetEndpoint() string {
+	if x != nil {
+		return x.Endpoint
 	}
 	return ""
 }
 
-func (m *Node) GetMacaddress() string {
-	if m != nil {
-		return m.Macaddress
+func (x *Node) GetMacaddress() string {
+	if x != nil {
+		return x.Macaddress
 	}
 	return ""
 }
 
-func (m *Node) GetPassword() string {
-	if m != nil {
-		return m.Password
+func (x *Node) GetPassword() string {
+	if x != nil {
+		return x.Password
 	}
 	return ""
 }
 
-func (m *Node) GetNodenetwork() string {
-	if m != nil {
-		return m.Nodenetwork
+func (x *Node) GetNodenetwork() string {
+	if x != nil {
+		return x.Nodenetwork
 	}
 	return ""
 }
 
-func (m *Node) GetIspending() bool {
-	if m != nil {
-		return m.Ispending
+func (x *Node) GetIspending() bool {
+	if x != nil {
+		return x.Ispending
 	}
 	return false
 }
 
-func (m *Node) GetPostup() string {
-	if m != nil {
-		return m.Postup
+func (x *Node) GetPostup() string {
+	if x != nil {
+		return x.Postup
 	}
 	return ""
 }
 
-func (m *Node) GetPostdown() string {
-	if m != nil {
-		return m.Postdown
+func (x *Node) GetPostdown() string {
+	if x != nil {
+		return x.Postdown
 	}
 	return ""
 }
 
-func (m *Node) GetKeepalive() int32 {
-	if m != nil {
-		return m.Keepalive
+func (x *Node) GetKeepalive() int32 {
+	if x != nil {
+		return x.Keepalive
 	}
 	return 0
 }
 
-func (m *Node) GetSaveconfig() bool {
-	if m != nil {
-		return m.Saveconfig
+func (x *Node) GetSaveconfig() string {
+	if x != nil {
+		return x.Saveconfig
 	}
-	return false
+	return ""
 }
 
-func (m *Node) GetAccesskey() string {
-	if m != nil {
-		return m.Accesskey
+func (x *Node) GetAccesskey() string {
+	if x != nil {
+		return x.Accesskey
 	}
 	return ""
 }
 
-func (m *Node) GetInterface() string {
-	if m != nil {
-		return m.Interface
+func (x *Node) GetInterface() string {
+	if x != nil {
+		return x.Interface
 	}
 	return ""
 }
 
-func (m *Node) GetLastcheckin() string {
-	if m != nil {
-		return m.Lastcheckin
+func (x *Node) GetLastcheckin() string {
+	if x != nil {
+		return x.Lastcheckin
 	}
 	return ""
 }
 
-func (m *Node) GetLastmodified() string {
-	if m != nil {
-		return m.Lastmodified
+func (x *Node) GetLastmodified() string {
+	if x != nil {
+		return x.Lastmodified
 	}
 	return ""
 }
 
-func (m *Node) GetCheckininterval() int32 {
-	if m != nil {
-		return m.Checkininterval
+func (x *Node) GetCheckininterval() int32 {
+	if x != nil {
+		return x.Checkininterval
 	}
 	return 0
 }
 
-func (m *Node) GetLocaladdress() string {
-	if m != nil {
-		return m.Localaddress
+func (x *Node) GetLocaladdress() string {
+	if x != nil {
+		return x.Localaddress
 	}
 	return ""
 }
 
-func (m *Node) GetPostchanges() string {
-	if m != nil {
-		return m.Postchanges
+func (x *Node) GetPostchanges() string {
+	if x != nil {
+		return x.Postchanges
 	}
 	return ""
 }
 
-func (m *Node) GetAllowedips() string {
-	if m != nil {
-		return m.Allowedips
+func (x *Node) GetAllowedips() string {
+	if x != nil {
+		return x.Allowedips
 	}
 	return ""
 }
 
-func (m *Node) GetIslocal() bool {
-	if m != nil {
-		return m.Islocal
+func (x *Node) GetIslocal() bool {
+	if x != nil {
+		return x.Islocal
 	}
 	return false
 }
 
-func (m *Node) GetIsingressgateway() bool {
-	if m != nil {
-		return m.Isingressgateway
+func (x *Node) GetIsingressgateway() bool {
+	if x != nil {
+		return x.Isingressgateway
 	}
 	return false
 }
 
-func (m *Node) GetIngressgatewayrange() string {
-	if m != nil {
-		return m.Ingressgatewayrange
+func (x *Node) GetIngressgatewayrange() string {
+	if x != nil {
+		return x.Ingressgatewayrange
 	}
 	return ""
 }
 
-func (m *Node) GetIsdualstack() bool {
-	if m != nil {
-		return m.Isdualstack
+func (x *Node) GetIsdualstack() bool {
+	if x != nil {
+		return x.Isdualstack
 	}
 	return false
 }
 
-func (m *Node) GetDnsoff() bool {
-	if m != nil {
-		return m.Dnsoff
+func (x *Node) GetDnsoff() bool {
+	if x != nil {
+		return x.Dnsoff
 	}
 	return false
 }
 
-func (m *Node) GetLocalrange() string {
-	if m != nil {
-		return m.Localrange
+func (x *Node) GetLocalrange() string {
+	if x != nil {
+		return x.Localrange
 	}
 	return ""
 }
 
-type CheckInResponse struct {
-	Success              bool     `protobuf:"varint,1,opt,name=success,proto3" json:"success,omitempty"`
-	Needpeerupdate       bool     `protobuf:"varint,2,opt,name=needpeerupdate,proto3" json:"needpeerupdate,omitempty"`
-	Needconfigupdate     bool     `protobuf:"varint,3,opt,name=needconfigupdate,proto3" json:"needconfigupdate,omitempty"`
-	Nodemessage          string   `protobuf:"bytes,4,opt,name=nodemessage,proto3" json:"nodemessage,omitempty"`
-	Ispending            bool     `protobuf:"varint,5,opt,name=ispending,proto3" json:"ispending,omitempty"`
-	Needkeyupdate        bool     `protobuf:"varint,6,opt,name=needkeyupdate,proto3" json:"needkeyupdate,omitempty"`
-	Needdelete           bool     `protobuf:"varint,7,opt,name=needdelete,proto3" json:"needdelete,omitempty"`
-	XXX_NoUnkeyedLiteral struct{} `json:"-"`
-	XXX_unrecognized     []byte   `json:"-"`
-	XXX_sizecache        int32    `json:"-"`
-}
-
-func (m *CheckInResponse) Reset()         { *m = CheckInResponse{} }
-func (m *CheckInResponse) String() string { return proto.CompactTextString(m) }
-func (*CheckInResponse) ProtoMessage()    {}
-func (*CheckInResponse) Descriptor() ([]byte, []int) {
-	return fileDescriptor_d13bd996b67da4ef, []int{3}
+func (x *Node) GetUdpholepunch() string {
+	if x != nil {
+		return x.Udpholepunch
+	}
+	return ""
 }
 
-func (m *CheckInResponse) XXX_Unmarshal(b []byte) error {
-	return xxx_messageInfo_CheckInResponse.Unmarshal(m, b)
-}
-func (m *CheckInResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
-	return xxx_messageInfo_CheckInResponse.Marshal(b, m, deterministic)
+type CheckInResponse struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Success          bool   `protobuf:"varint,1,opt,name=success,proto3" json:"success,omitempty"`
+	Needpeerupdate   bool   `protobuf:"varint,2,opt,name=needpeerupdate,proto3" json:"needpeerupdate,omitempty"`
+	Needconfigupdate bool   `protobuf:"varint,3,opt,name=needconfigupdate,proto3" json:"needconfigupdate,omitempty"`
+	Nodemessage      string `protobuf:"bytes,4,opt,name=nodemessage,proto3" json:"nodemessage,omitempty"`
+	Ispending        bool   `protobuf:"varint,5,opt,name=ispending,proto3" json:"ispending,omitempty"`
+	Needkeyupdate    bool   `protobuf:"varint,6,opt,name=needkeyupdate,proto3" json:"needkeyupdate,omitempty"`
+	Needdelete       bool   `protobuf:"varint,7,opt,name=needdelete,proto3" json:"needdelete,omitempty"`
 }
-func (m *CheckInResponse) XXX_Merge(src proto.Message) {
-	xxx_messageInfo_CheckInResponse.Merge(m, src)
+
+func (x *CheckInResponse) Reset() {
+	*x = CheckInResponse{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_grpc_node_proto_msgTypes[3]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
 }
-func (m *CheckInResponse) XXX_Size() int {
-	return xxx_messageInfo_CheckInResponse.Size(m)
+
+func (x *CheckInResponse) String() string {
+	return protoimpl.X.MessageStringOf(x)
 }
-func (m *CheckInResponse) XXX_DiscardUnknown() {
-	xxx_messageInfo_CheckInResponse.DiscardUnknown(m)
+
+func (*CheckInResponse) ProtoMessage() {}
+
+func (x *CheckInResponse) ProtoReflect() protoreflect.Message {
+	mi := &file_grpc_node_proto_msgTypes[3]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
 }
 
-var xxx_messageInfo_CheckInResponse proto.InternalMessageInfo
+// Deprecated: Use CheckInResponse.ProtoReflect.Descriptor instead.
+func (*CheckInResponse) Descriptor() ([]byte, []int) {
+	return file_grpc_node_proto_rawDescGZIP(), []int{3}
+}
 
-func (m *CheckInResponse) GetSuccess() bool {
-	if m != nil {
-		return m.Success
+func (x *CheckInResponse) GetSuccess() bool {
+	if x != nil {
+		return x.Success
 	}
 	return false
 }
 
-func (m *CheckInResponse) GetNeedpeerupdate() bool {
-	if m != nil {
-		return m.Needpeerupdate
+func (x *CheckInResponse) GetNeedpeerupdate() bool {
+	if x != nil {
+		return x.Needpeerupdate
 	}
 	return false
 }
 
-func (m *CheckInResponse) GetNeedconfigupdate() bool {
-	if m != nil {
-		return m.Needconfigupdate
+func (x *CheckInResponse) GetNeedconfigupdate() bool {
+	if x != nil {
+		return x.Needconfigupdate
 	}
 	return false
 }
 
-func (m *CheckInResponse) GetNodemessage() string {
-	if m != nil {
-		return m.Nodemessage
+func (x *CheckInResponse) GetNodemessage() string {
+	if x != nil {
+		return x.Nodemessage
 	}
 	return ""
 }
 
-func (m *CheckInResponse) GetIspending() bool {
-	if m != nil {
-		return m.Ispending
+func (x *CheckInResponse) GetIspending() bool {
+	if x != nil {
+		return x.Ispending
 	}
 	return false
 }
 
-func (m *CheckInResponse) GetNeedkeyupdate() bool {
-	if m != nil {
-		return m.Needkeyupdate
+func (x *CheckInResponse) GetNeedkeyupdate() bool {
+	if x != nil {
+		return x.Needkeyupdate
 	}
 	return false
 }
 
-func (m *CheckInResponse) GetNeeddelete() bool {
-	if m != nil {
-		return m.Needdelete
+func (x *CheckInResponse) GetNeeddelete() bool {
+	if x != nil {
+		return x.Needdelete
 	}
 	return false
 }
 
 type PeersResponse struct {
-	Isegressgateway      bool     `protobuf:"varint,1,opt,name=isegressgateway,proto3" json:"isegressgateway,omitempty"`
-	Egressgatewayrange   string   `protobuf:"bytes,2,opt,name=egressgatewayrange,proto3" json:"egressgatewayrange,omitempty"`
-	Ingressgatewayrange  string   `protobuf:"bytes,9,opt,name=ingressgatewayrange,proto3" json:"ingressgatewayrange,omitempty"`
-	Publickey            string   `protobuf:"bytes,5,opt,name=publickey,proto3" json:"publickey,omitempty"`
-	Endpoint             string   `protobuf:"bytes,6,opt,name=endpoint,proto3" json:"endpoint,omitempty"`
-	Address              string   `protobuf:"bytes,3,opt,name=address,proto3" json:"address,omitempty"`
-	Address6             string   `protobuf:"bytes,8,opt,name=address6,proto3" json:"address6,omitempty"`
-	Listenport           int32    `protobuf:"varint,4,opt,name=listenport,proto3" json:"listenport,omitempty"`
-	Localaddress         string   `protobuf:"bytes,7,opt,name=localaddress,proto3" json:"localaddress,omitempty"`
-	Keepalive            int32    `protobuf:"varint,13,opt,name=keepalive,proto3" json:"keepalive,omitempty"`
-	XXX_NoUnkeyedLiteral struct{} `json:"-"`
-	XXX_unrecognized     []byte   `json:"-"`
-	XXX_sizecache        int32    `json:"-"`
-}
-
-func (m *PeersResponse) Reset()         { *m = PeersResponse{} }
-func (m *PeersResponse) String() string { return proto.CompactTextString(m) }
-func (*PeersResponse) ProtoMessage()    {}
-func (*PeersResponse) Descriptor() ([]byte, []int) {
-	return fileDescriptor_d13bd996b67da4ef, []int{4}
-}
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
 
-func (m *PeersResponse) XXX_Unmarshal(b []byte) error {
-	return xxx_messageInfo_PeersResponse.Unmarshal(m, b)
-}
-func (m *PeersResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
-	return xxx_messageInfo_PeersResponse.Marshal(b, m, deterministic)
+	Isegressgateway     bool   `protobuf:"varint,1,opt,name=isegressgateway,proto3" json:"isegressgateway,omitempty"`
+	Egressgatewayranges string `protobuf:"bytes,2,opt,name=egressgatewayranges,proto3" json:"egressgatewayranges,omitempty"`
+	Ingressgatewayrange string `protobuf:"bytes,9,opt,name=ingressgatewayrange,proto3" json:"ingressgatewayrange,omitempty"`
+	Publickey           string `protobuf:"bytes,5,opt,name=publickey,proto3" json:"publickey,omitempty"`
+	Endpoint            string `protobuf:"bytes,6,opt,name=endpoint,proto3" json:"endpoint,omitempty"`
+	Address             string `protobuf:"bytes,3,opt,name=address,proto3" json:"address,omitempty"`
+	Address6            string `protobuf:"bytes,8,opt,name=address6,proto3" json:"address6,omitempty"`
+	Listenport          int32  `protobuf:"varint,4,opt,name=listenport,proto3" json:"listenport,omitempty"`
+	Localaddress        string `protobuf:"bytes,7,opt,name=localaddress,proto3" json:"localaddress,omitempty"`
+	Keepalive           int32  `protobuf:"varint,13,opt,name=keepalive,proto3" json:"keepalive,omitempty"`
 }
-func (m *PeersResponse) XXX_Merge(src proto.Message) {
-	xxx_messageInfo_PeersResponse.Merge(m, src)
+
+func (x *PeersResponse) Reset() {
+	*x = PeersResponse{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_grpc_node_proto_msgTypes[4]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
 }
-func (m *PeersResponse) XXX_Size() int {
-	return xxx_messageInfo_PeersResponse.Size(m)
+
+func (x *PeersResponse) String() string {
+	return protoimpl.X.MessageStringOf(x)
 }
-func (m *PeersResponse) XXX_DiscardUnknown() {
-	xxx_messageInfo_PeersResponse.DiscardUnknown(m)
+
+func (*PeersResponse) ProtoMessage() {}
+
+func (x *PeersResponse) ProtoReflect() protoreflect.Message {
+	mi := &file_grpc_node_proto_msgTypes[4]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
 }
 
-var xxx_messageInfo_PeersResponse proto.InternalMessageInfo
+// Deprecated: Use PeersResponse.ProtoReflect.Descriptor instead.
+func (*PeersResponse) Descriptor() ([]byte, []int) {
+	return file_grpc_node_proto_rawDescGZIP(), []int{4}
+}
 
-func (m *PeersResponse) GetIsegressgateway() bool {
-	if m != nil {
-		return m.Isegressgateway
+func (x *PeersResponse) GetIsegressgateway() bool {
+	if x != nil {
+		return x.Isegressgateway
 	}
 	return false
 }
 
-func (m *PeersResponse) GetEgressgatewayrange() string {
-	if m != nil {
-		return m.Egressgatewayrange
+func (x *PeersResponse) GetEgressgatewayranges() string {
+	if x != nil {
+		return x.Egressgatewayranges
 	}
 	return ""
 }
 
-func (m *PeersResponse) GetIngressgatewayrange() string {
-	if m != nil {
-		return m.Ingressgatewayrange
+func (x *PeersResponse) GetIngressgatewayrange() string {
+	if x != nil {
+		return x.Ingressgatewayrange
 	}
 	return ""
 }
 
-func (m *PeersResponse) GetPublickey() string {
-	if m != nil {
-		return m.Publickey
+func (x *PeersResponse) GetPublickey() string {
+	if x != nil {
+		return x.Publickey
 	}
 	return ""
 }
 
-func (m *PeersResponse) GetEndpoint() string {
-	if m != nil {
-		return m.Endpoint
+func (x *PeersResponse) GetEndpoint() string {
+	if x != nil {
+		return x.Endpoint
 	}
 	return ""
 }
 
-func (m *PeersResponse) GetAddress() string {
-	if m != nil {
-		return m.Address
+func (x *PeersResponse) GetAddress() string {
+	if x != nil {
+		return x.Address
 	}
 	return ""
 }
 
-func (m *PeersResponse) GetAddress6() string {
-	if m != nil {
-		return m.Address6
+func (x *PeersResponse) GetAddress6() string {
+	if x != nil {
+		return x.Address6
 	}
 	return ""
 }
 
-func (m *PeersResponse) GetListenport() int32 {
-	if m != nil {
-		return m.Listenport
+func (x *PeersResponse) GetListenport() int32 {
+	if x != nil {
+		return x.Listenport
 	}
 	return 0
 }
 
-func (m *PeersResponse) GetLocaladdress() string {
-	if m != nil {
-		return m.Localaddress
+func (x *PeersResponse) GetLocaladdress() string {
+	if x != nil {
+		return x.Localaddress
 	}
 	return ""
 }
 
-func (m *PeersResponse) GetKeepalive() int32 {
-	if m != nil {
-		return m.Keepalive
+func (x *PeersResponse) GetKeepalive() int32 {
+	if x != nil {
+		return x.Keepalive
 	}
 	return 0
 }
 
 type ExtPeersResponse struct {
-	Publickey            string   `protobuf:"bytes,5,opt,name=publickey,proto3" json:"publickey,omitempty"`
-	Endpoint             string   `protobuf:"bytes,6,opt,name=endpoint,proto3" json:"endpoint,omitempty"`
-	Address              string   `protobuf:"bytes,3,opt,name=address,proto3" json:"address,omitempty"`
-	Address6             string   `protobuf:"bytes,8,opt,name=address6,proto3" json:"address6,omitempty"`
-	Listenport           int32    `protobuf:"varint,4,opt,name=listenport,proto3" json:"listenport,omitempty"`
-	Localaddress         string   `protobuf:"bytes,7,opt,name=localaddress,proto3" json:"localaddress,omitempty"`
-	Keepalive            int32    `protobuf:"varint,13,opt,name=keepalive,proto3" json:"keepalive,omitempty"`
-	XXX_NoUnkeyedLiteral struct{} `json:"-"`
-	XXX_unrecognized     []byte   `json:"-"`
-	XXX_sizecache        int32    `json:"-"`
-}
-
-func (m *ExtPeersResponse) Reset()         { *m = ExtPeersResponse{} }
-func (m *ExtPeersResponse) String() string { return proto.CompactTextString(m) }
-func (*ExtPeersResponse) ProtoMessage()    {}
-func (*ExtPeersResponse) Descriptor() ([]byte, []int) {
-	return fileDescriptor_d13bd996b67da4ef, []int{5}
-}
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
 
-func (m *ExtPeersResponse) XXX_Unmarshal(b []byte) error {
-	return xxx_messageInfo_ExtPeersResponse.Unmarshal(m, b)
-}
-func (m *ExtPeersResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
-	return xxx_messageInfo_ExtPeersResponse.Marshal(b, m, deterministic)
+	Publickey    string `protobuf:"bytes,5,opt,name=publickey,proto3" json:"publickey,omitempty"`
+	Endpoint     string `protobuf:"bytes,6,opt,name=endpoint,proto3" json:"endpoint,omitempty"`
+	Address      string `protobuf:"bytes,3,opt,name=address,proto3" json:"address,omitempty"`
+	Address6     string `protobuf:"bytes,8,opt,name=address6,proto3" json:"address6,omitempty"`
+	Listenport   int32  `protobuf:"varint,4,opt,name=listenport,proto3" json:"listenport,omitempty"`
+	Localaddress string `protobuf:"bytes,7,opt,name=localaddress,proto3" json:"localaddress,omitempty"`
+	Keepalive    int32  `protobuf:"varint,13,opt,name=keepalive,proto3" json:"keepalive,omitempty"`
 }
-func (m *ExtPeersResponse) XXX_Merge(src proto.Message) {
-	xxx_messageInfo_ExtPeersResponse.Merge(m, src)
+
+func (x *ExtPeersResponse) Reset() {
+	*x = ExtPeersResponse{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_grpc_node_proto_msgTypes[5]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
 }
-func (m *ExtPeersResponse) XXX_Size() int {
-	return xxx_messageInfo_ExtPeersResponse.Size(m)
+
+func (x *ExtPeersResponse) String() string {
+	return protoimpl.X.MessageStringOf(x)
 }
-func (m *ExtPeersResponse) XXX_DiscardUnknown() {
-	xxx_messageInfo_ExtPeersResponse.DiscardUnknown(m)
+
+func (*ExtPeersResponse) ProtoMessage() {}
+
+func (x *ExtPeersResponse) ProtoReflect() protoreflect.Message {
+	mi := &file_grpc_node_proto_msgTypes[5]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
 }
 
-var xxx_messageInfo_ExtPeersResponse proto.InternalMessageInfo
+// Deprecated: Use ExtPeersResponse.ProtoReflect.Descriptor instead.
+func (*ExtPeersResponse) Descriptor() ([]byte, []int) {
+	return file_grpc_node_proto_rawDescGZIP(), []int{5}
+}
 
-func (m *ExtPeersResponse) GetPublickey() string {
-	if m != nil {
-		return m.Publickey
+func (x *ExtPeersResponse) GetPublickey() string {
+	if x != nil {
+		return x.Publickey
 	}
 	return ""
 }
 
-func (m *ExtPeersResponse) GetEndpoint() string {
-	if m != nil {
-		return m.Endpoint
+func (x *ExtPeersResponse) GetEndpoint() string {
+	if x != nil {
+		return x.Endpoint
 	}
 	return ""
 }
 
-func (m *ExtPeersResponse) GetAddress() string {
-	if m != nil {
-		return m.Address
+func (x *ExtPeersResponse) GetAddress() string {
+	if x != nil {
+		return x.Address
 	}
 	return ""
 }
 
-func (m *ExtPeersResponse) GetAddress6() string {
-	if m != nil {
-		return m.Address6
+func (x *ExtPeersResponse) GetAddress6() string {
+	if x != nil {
+		return x.Address6
 	}
 	return ""
 }
 
-func (m *ExtPeersResponse) GetListenport() int32 {
-	if m != nil {
-		return m.Listenport
+func (x *ExtPeersResponse) GetListenport() int32 {
+	if x != nil {
+		return x.Listenport
 	}
 	return 0
 }
 
-func (m *ExtPeersResponse) GetLocaladdress() string {
-	if m != nil {
-		return m.Localaddress
+func (x *ExtPeersResponse) GetLocaladdress() string {
+	if x != nil {
+		return x.Localaddress
 	}
 	return ""
 }
 
-func (m *ExtPeersResponse) GetKeepalive() int32 {
-	if m != nil {
-		return m.Keepalive
+func (x *ExtPeersResponse) GetKeepalive() int32 {
+	if x != nil {
+		return x.Keepalive
 	}
 	return 0
 }
 
 type Client struct {
-	Privatekey           string   `protobuf:"bytes,1,opt,name=privatekey,proto3" json:"privatekey,omitempty"`
-	Publickey            string   `protobuf:"bytes,2,opt,name=publickey,proto3" json:"publickey,omitempty"`
-	Accesskey            string   `protobuf:"bytes,3,opt,name=accesskey,proto3" json:"accesskey,omitempty"`
-	Address              string   `protobuf:"bytes,4,opt,name=address,proto3" json:"address,omitempty"`
-	Address6             string   `protobuf:"bytes,5,opt,name=address6,proto3" json:"address6,omitempty"`
-	Serverwgendpoint     string   `protobuf:"bytes,6,opt,name=serverwgendpoint,proto3" json:"serverwgendpoint,omitempty"`
-	Serverport           string   `protobuf:"bytes,7,opt,name=serverport,proto3" json:"serverport,omitempty"`
-	Serverkey            string   `protobuf:"bytes,8,opt,name=serverkey,proto3" json:"serverkey,omitempty"`
-	XXX_NoUnkeyedLiteral struct{} `json:"-"`
-	XXX_unrecognized     []byte   `json:"-"`
-	XXX_sizecache        int32    `json:"-"`
-}
-
-func (m *Client) Reset()         { *m = Client{} }
-func (m *Client) String() string { return proto.CompactTextString(m) }
-func (*Client) ProtoMessage()    {}
-func (*Client) Descriptor() ([]byte, []int) {
-	return fileDescriptor_d13bd996b67da4ef, []int{6}
-}
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
 
-func (m *Client) XXX_Unmarshal(b []byte) error {
-	return xxx_messageInfo_Client.Unmarshal(m, b)
+	Privatekey       string `protobuf:"bytes,1,opt,name=privatekey,proto3" json:"privatekey,omitempty"`
+	Publickey        string `protobuf:"bytes,2,opt,name=publickey,proto3" json:"publickey,omitempty"`
+	Accesskey        string `protobuf:"bytes,3,opt,name=accesskey,proto3" json:"accesskey,omitempty"`
+	Address          string `protobuf:"bytes,4,opt,name=address,proto3" json:"address,omitempty"`
+	Address6         string `protobuf:"bytes,5,opt,name=address6,proto3" json:"address6,omitempty"`
+	Serverwgendpoint string `protobuf:"bytes,6,opt,name=serverwgendpoint,proto3" json:"serverwgendpoint,omitempty"`
+	Serverport       string `protobuf:"bytes,7,opt,name=serverport,proto3" json:"serverport,omitempty"`
+	Serverkey        string `protobuf:"bytes,8,opt,name=serverkey,proto3" json:"serverkey,omitempty"`
 }
-func (m *Client) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
-	return xxx_messageInfo_Client.Marshal(b, m, deterministic)
-}
-func (m *Client) XXX_Merge(src proto.Message) {
-	xxx_messageInfo_Client.Merge(m, src)
+
+func (x *Client) Reset() {
+	*x = Client{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_grpc_node_proto_msgTypes[6]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
 }
-func (m *Client) XXX_Size() int {
-	return xxx_messageInfo_Client.Size(m)
+
+func (x *Client) String() string {
+	return protoimpl.X.MessageStringOf(x)
 }
-func (m *Client) XXX_DiscardUnknown() {
-	xxx_messageInfo_Client.DiscardUnknown(m)
+
+func (*Client) ProtoMessage() {}
+
+func (x *Client) ProtoReflect() protoreflect.Message {
+	mi := &file_grpc_node_proto_msgTypes[6]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
 }
 
-var xxx_messageInfo_Client proto.InternalMessageInfo
+// Deprecated: Use Client.ProtoReflect.Descriptor instead.
+func (*Client) Descriptor() ([]byte, []int) {
+	return file_grpc_node_proto_rawDescGZIP(), []int{6}
+}
 
-func (m *Client) GetPrivatekey() string {
-	if m != nil {
-		return m.Privatekey
+func (x *Client) GetPrivatekey() string {
+	if x != nil {
+		return x.Privatekey
 	}
 	return ""
 }
 
-func (m *Client) GetPublickey() string {
-	if m != nil {
-		return m.Publickey
+func (x *Client) GetPublickey() string {
+	if x != nil {
+		return x.Publickey
 	}
 	return ""
 }
 
-func (m *Client) GetAccesskey() string {
-	if m != nil {
-		return m.Accesskey
+func (x *Client) GetAccesskey() string {
+	if x != nil {
+		return x.Accesskey
 	}
 	return ""
 }
 
-func (m *Client) GetAddress() string {
-	if m != nil {
-		return m.Address
+func (x *Client) GetAddress() string {
+	if x != nil {
+		return x.Address
 	}
 	return ""
 }
 
-func (m *Client) GetAddress6() string {
-	if m != nil {
-		return m.Address6
+func (x *Client) GetAddress6() string {
+	if x != nil {
+		return x.Address6
 	}
 	return ""
 }
 
-func (m *Client) GetServerwgendpoint() string {
-	if m != nil {
-		return m.Serverwgendpoint
+func (x *Client) GetServerwgendpoint() string {
+	if x != nil {
+		return x.Serverwgendpoint
 	}
 	return ""
 }
 
-func (m *Client) GetServerport() string {
-	if m != nil {
-		return m.Serverport
+func (x *Client) GetServerport() string {
+	if x != nil {
+		return x.Serverport
 	}
 	return ""
 }
 
-func (m *Client) GetServerkey() string {
-	if m != nil {
-		return m.Serverkey
+func (x *Client) GetServerkey() string {
+	if x != nil {
+		return x.Serverkey
 	}
 	return ""
 }
 
 type CreateNodeReq struct {
-	Node                 *Node    `protobuf:"bytes,1,opt,name=node,proto3" json:"node,omitempty"`
-	XXX_NoUnkeyedLiteral struct{} `json:"-"`
-	XXX_unrecognized     []byte   `json:"-"`
-	XXX_sizecache        int32    `json:"-"`
-}
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
 
-func (m *CreateNodeReq) Reset()         { *m = CreateNodeReq{} }
-func (m *CreateNodeReq) String() string { return proto.CompactTextString(m) }
-func (*CreateNodeReq) ProtoMessage()    {}
-func (*CreateNodeReq) Descriptor() ([]byte, []int) {
-	return fileDescriptor_d13bd996b67da4ef, []int{7}
+	Node *Node `protobuf:"bytes,1,opt,name=node,proto3" json:"node,omitempty"` // Node id blank
 }
 
-func (m *CreateNodeReq) XXX_Unmarshal(b []byte) error {
-	return xxx_messageInfo_CreateNodeReq.Unmarshal(m, b)
-}
-func (m *CreateNodeReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
-	return xxx_messageInfo_CreateNodeReq.Marshal(b, m, deterministic)
-}
-func (m *CreateNodeReq) XXX_Merge(src proto.Message) {
-	xxx_messageInfo_CreateNodeReq.Merge(m, src)
+func (x *CreateNodeReq) Reset() {
+	*x = CreateNodeReq{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_grpc_node_proto_msgTypes[7]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
 }
-func (m *CreateNodeReq) XXX_Size() int {
-	return xxx_messageInfo_CreateNodeReq.Size(m)
+
+func (x *CreateNodeReq) String() string {
+	return protoimpl.X.MessageStringOf(x)
 }
-func (m *CreateNodeReq) XXX_DiscardUnknown() {
-	xxx_messageInfo_CreateNodeReq.DiscardUnknown(m)
+
+func (*CreateNodeReq) ProtoMessage() {}
+
+func (x *CreateNodeReq) ProtoReflect() protoreflect.Message {
+	mi := &file_grpc_node_proto_msgTypes[7]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
 }
 
-var xxx_messageInfo_CreateNodeReq proto.InternalMessageInfo
+// Deprecated: Use CreateNodeReq.ProtoReflect.Descriptor instead.
+func (*CreateNodeReq) Descriptor() ([]byte, []int) {
+	return file_grpc_node_proto_rawDescGZIP(), []int{7}
+}
 
-func (m *CreateNodeReq) GetNode() *Node {
-	if m != nil {
-		return m.Node
+func (x *CreateNodeReq) GetNode() *Node {
+	if x != nil {
+		return x.Node
 	}
 	return nil
 }
 
 type CreateNodeRes struct {
-	Node                 *Node    `protobuf:"bytes,1,opt,name=node,proto3" json:"node,omitempty"`
-	XXX_NoUnkeyedLiteral struct{} `json:"-"`
-	XXX_unrecognized     []byte   `json:"-"`
-	XXX_sizecache        int32    `json:"-"`
-}
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
 
-func (m *CreateNodeRes) Reset()         { *m = CreateNodeRes{} }
-func (m *CreateNodeRes) String() string { return proto.CompactTextString(m) }
-func (*CreateNodeRes) ProtoMessage()    {}
-func (*CreateNodeRes) Descriptor() ([]byte, []int) {
-	return fileDescriptor_d13bd996b67da4ef, []int{8}
+	Node *Node `protobuf:"bytes,1,opt,name=node,proto3" json:"node,omitempty"` // Node id filled in
 }
 
-func (m *CreateNodeRes) XXX_Unmarshal(b []byte) error {
-	return xxx_messageInfo_CreateNodeRes.Unmarshal(m, b)
-}
-func (m *CreateNodeRes) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
-	return xxx_messageInfo_CreateNodeRes.Marshal(b, m, deterministic)
-}
-func (m *CreateNodeRes) XXX_Merge(src proto.Message) {
-	xxx_messageInfo_CreateNodeRes.Merge(m, src)
+func (x *CreateNodeRes) Reset() {
+	*x = CreateNodeRes{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_grpc_node_proto_msgTypes[8]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
 }
-func (m *CreateNodeRes) XXX_Size() int {
-	return xxx_messageInfo_CreateNodeRes.Size(m)
+
+func (x *CreateNodeRes) String() string {
+	return protoimpl.X.MessageStringOf(x)
 }
-func (m *CreateNodeRes) XXX_DiscardUnknown() {
-	xxx_messageInfo_CreateNodeRes.DiscardUnknown(m)
+
+func (*CreateNodeRes) ProtoMessage() {}
+
+func (x *CreateNodeRes) ProtoReflect() protoreflect.Message {
+	mi := &file_grpc_node_proto_msgTypes[8]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
 }
 
-var xxx_messageInfo_CreateNodeRes proto.InternalMessageInfo
+// Deprecated: Use CreateNodeRes.ProtoReflect.Descriptor instead.
+func (*CreateNodeRes) Descriptor() ([]byte, []int) {
+	return file_grpc_node_proto_rawDescGZIP(), []int{8}
+}
 
-func (m *CreateNodeRes) GetNode() *Node {
-	if m != nil {
-		return m.Node
+func (x *CreateNodeRes) GetNode() *Node {
+	if x != nil {
+		return x.Node
 	}
 	return nil
 }
 
 type UpdateNodeReq struct {
-	Node                 *Node    `protobuf:"bytes,1,opt,name=node,proto3" json:"node,omitempty"`
-	XXX_NoUnkeyedLiteral struct{} `json:"-"`
-	XXX_unrecognized     []byte   `json:"-"`
-	XXX_sizecache        int32    `json:"-"`
-}
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
 
-func (m *UpdateNodeReq) Reset()         { *m = UpdateNodeReq{} }
-func (m *UpdateNodeReq) String() string { return proto.CompactTextString(m) }
-func (*UpdateNodeReq) ProtoMessage()    {}
-func (*UpdateNodeReq) Descriptor() ([]byte, []int) {
-	return fileDescriptor_d13bd996b67da4ef, []int{9}
+	Node *Node `protobuf:"bytes,1,opt,name=node,proto3" json:"node,omitempty"`
 }
 
-func (m *UpdateNodeReq) XXX_Unmarshal(b []byte) error {
-	return xxx_messageInfo_UpdateNodeReq.Unmarshal(m, b)
-}
-func (m *UpdateNodeReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
-	return xxx_messageInfo_UpdateNodeReq.Marshal(b, m, deterministic)
-}
-func (m *UpdateNodeReq) XXX_Merge(src proto.Message) {
-	xxx_messageInfo_UpdateNodeReq.Merge(m, src)
+func (x *UpdateNodeReq) Reset() {
+	*x = UpdateNodeReq{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_grpc_node_proto_msgTypes[9]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
 }
-func (m *UpdateNodeReq) XXX_Size() int {
-	return xxx_messageInfo_UpdateNodeReq.Size(m)
+
+func (x *UpdateNodeReq) String() string {
+	return protoimpl.X.MessageStringOf(x)
 }
-func (m *UpdateNodeReq) XXX_DiscardUnknown() {
-	xxx_messageInfo_UpdateNodeReq.DiscardUnknown(m)
+
+func (*UpdateNodeReq) ProtoMessage() {}
+
+func (x *UpdateNodeReq) ProtoReflect() protoreflect.Message {
+	mi := &file_grpc_node_proto_msgTypes[9]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
 }
 
-var xxx_messageInfo_UpdateNodeReq proto.InternalMessageInfo
+// Deprecated: Use UpdateNodeReq.ProtoReflect.Descriptor instead.
+func (*UpdateNodeReq) Descriptor() ([]byte, []int) {
+	return file_grpc_node_proto_rawDescGZIP(), []int{9}
+}
 
-func (m *UpdateNodeReq) GetNode() *Node {
-	if m != nil {
-		return m.Node
+func (x *UpdateNodeReq) GetNode() *Node {
+	if x != nil {
+		return x.Node
 	}
 	return nil
 }
 
 type UpdateNodeRes struct {
-	Node                 *Node    `protobuf:"bytes,1,opt,name=node,proto3" json:"node,omitempty"`
-	XXX_NoUnkeyedLiteral struct{} `json:"-"`
-	XXX_unrecognized     []byte   `json:"-"`
-	XXX_sizecache        int32    `json:"-"`
-}
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
 
-func (m *UpdateNodeRes) Reset()         { *m = UpdateNodeRes{} }
-func (m *UpdateNodeRes) String() string { return proto.CompactTextString(m) }
-func (*UpdateNodeRes) ProtoMessage()    {}
-func (*UpdateNodeRes) Descriptor() ([]byte, []int) {
-	return fileDescriptor_d13bd996b67da4ef, []int{10}
+	Node *Node `protobuf:"bytes,1,opt,name=node,proto3" json:"node,omitempty"`
 }
 
-func (m *UpdateNodeRes) XXX_Unmarshal(b []byte) error {
-	return xxx_messageInfo_UpdateNodeRes.Unmarshal(m, b)
-}
-func (m *UpdateNodeRes) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
-	return xxx_messageInfo_UpdateNodeRes.Marshal(b, m, deterministic)
-}
-func (m *UpdateNodeRes) XXX_Merge(src proto.Message) {
-	xxx_messageInfo_UpdateNodeRes.Merge(m, src)
+func (x *UpdateNodeRes) Reset() {
+	*x = UpdateNodeRes{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_grpc_node_proto_msgTypes[10]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
 }
-func (m *UpdateNodeRes) XXX_Size() int {
-	return xxx_messageInfo_UpdateNodeRes.Size(m)
+
+func (x *UpdateNodeRes) String() string {
+	return protoimpl.X.MessageStringOf(x)
 }
-func (m *UpdateNodeRes) XXX_DiscardUnknown() {
-	xxx_messageInfo_UpdateNodeRes.DiscardUnknown(m)
+
+func (*UpdateNodeRes) ProtoMessage() {}
+
+func (x *UpdateNodeRes) ProtoReflect() protoreflect.Message {
+	mi := &file_grpc_node_proto_msgTypes[10]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
 }
 
-var xxx_messageInfo_UpdateNodeRes proto.InternalMessageInfo
+// Deprecated: Use UpdateNodeRes.ProtoReflect.Descriptor instead.
+func (*UpdateNodeRes) Descriptor() ([]byte, []int) {
+	return file_grpc_node_proto_rawDescGZIP(), []int{10}
+}
 
-func (m *UpdateNodeRes) GetNode() *Node {
-	if m != nil {
-		return m.Node
+func (x *UpdateNodeRes) GetNode() *Node {
+	if x != nil {
+		return x.Node
 	}
 	return nil
 }
 
 type ReadNodeReq struct {
-	Macaddress           string   `protobuf:"bytes,1,opt,name=macaddress,proto3" json:"macaddress,omitempty"`
-	Network              string   `protobuf:"bytes,2,opt,name=network,proto3" json:"network,omitempty"`
-	XXX_NoUnkeyedLiteral struct{} `json:"-"`
-	XXX_unrecognized     []byte   `json:"-"`
-	XXX_sizecache        int32    `json:"-"`
-}
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
 
-func (m *ReadNodeReq) Reset()         { *m = ReadNodeReq{} }
-func (m *ReadNodeReq) String() string { return proto.CompactTextString(m) }
-func (*ReadNodeReq) ProtoMessage()    {}
-func (*ReadNodeReq) Descriptor() ([]byte, []int) {
-	return fileDescriptor_d13bd996b67da4ef, []int{11}
+	Macaddress string `protobuf:"bytes,1,opt,name=macaddress,proto3" json:"macaddress,omitempty"`
+	Network    string `protobuf:"bytes,2,opt,name=network,proto3" json:"network,omitempty"`
 }
 
-func (m *ReadNodeReq) XXX_Unmarshal(b []byte) error {
-	return xxx_messageInfo_ReadNodeReq.Unmarshal(m, b)
-}
-func (m *ReadNodeReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
-	return xxx_messageInfo_ReadNodeReq.Marshal(b, m, deterministic)
-}
-func (m *ReadNodeReq) XXX_Merge(src proto.Message) {
-	xxx_messageInfo_ReadNodeReq.Merge(m, src)
+func (x *ReadNodeReq) Reset() {
+	*x = ReadNodeReq{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_grpc_node_proto_msgTypes[11]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
 }
-func (m *ReadNodeReq) XXX_Size() int {
-	return xxx_messageInfo_ReadNodeReq.Size(m)
+
+func (x *ReadNodeReq) String() string {
+	return protoimpl.X.MessageStringOf(x)
 }
-func (m *ReadNodeReq) XXX_DiscardUnknown() {
-	xxx_messageInfo_ReadNodeReq.DiscardUnknown(m)
+
+func (*ReadNodeReq) ProtoMessage() {}
+
+func (x *ReadNodeReq) ProtoReflect() protoreflect.Message {
+	mi := &file_grpc_node_proto_msgTypes[11]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
 }
 
-var xxx_messageInfo_ReadNodeReq proto.InternalMessageInfo
+// Deprecated: Use ReadNodeReq.ProtoReflect.Descriptor instead.
+func (*ReadNodeReq) Descriptor() ([]byte, []int) {
+	return file_grpc_node_proto_rawDescGZIP(), []int{11}
+}
 
-func (m *ReadNodeReq) GetMacaddress() string {
-	if m != nil {
-		return m.Macaddress
+func (x *ReadNodeReq) GetMacaddress() string {
+	if x != nil {
+		return x.Macaddress
 	}
 	return ""
 }
 
-func (m *ReadNodeReq) GetNetwork() string {
-	if m != nil {
-		return m.Network
+func (x *ReadNodeReq) GetNetwork() string {
+	if x != nil {
+		return x.Network
 	}
 	return ""
 }
 
 type ReadNodeRes struct {
-	Node                 *Node    `protobuf:"bytes,1,opt,name=node,proto3" json:"node,omitempty"`
-	XXX_NoUnkeyedLiteral struct{} `json:"-"`
-	XXX_unrecognized     []byte   `json:"-"`
-	XXX_sizecache        int32    `json:"-"`
-}
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
 
-func (m *ReadNodeRes) Reset()         { *m = ReadNodeRes{} }
-func (m *ReadNodeRes) String() string { return proto.CompactTextString(m) }
-func (*ReadNodeRes) ProtoMessage()    {}
-func (*ReadNodeRes) Descriptor() ([]byte, []int) {
-	return fileDescriptor_d13bd996b67da4ef, []int{12}
+	Node *Node `protobuf:"bytes,1,opt,name=node,proto3" json:"node,omitempty"`
 }
 
-func (m *ReadNodeRes) XXX_Unmarshal(b []byte) error {
-	return xxx_messageInfo_ReadNodeRes.Unmarshal(m, b)
-}
-func (m *ReadNodeRes) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
-	return xxx_messageInfo_ReadNodeRes.Marshal(b, m, deterministic)
-}
-func (m *ReadNodeRes) XXX_Merge(src proto.Message) {
-	xxx_messageInfo_ReadNodeRes.Merge(m, src)
+func (x *ReadNodeRes) Reset() {
+	*x = ReadNodeRes{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_grpc_node_proto_msgTypes[12]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
 }
-func (m *ReadNodeRes) XXX_Size() int {
-	return xxx_messageInfo_ReadNodeRes.Size(m)
+
+func (x *ReadNodeRes) String() string {
+	return protoimpl.X.MessageStringOf(x)
 }
-func (m *ReadNodeRes) XXX_DiscardUnknown() {
-	xxx_messageInfo_ReadNodeRes.DiscardUnknown(m)
+
+func (*ReadNodeRes) ProtoMessage() {}
+
+func (x *ReadNodeRes) ProtoReflect() protoreflect.Message {
+	mi := &file_grpc_node_proto_msgTypes[12]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
 }
 
-var xxx_messageInfo_ReadNodeRes proto.InternalMessageInfo
+// Deprecated: Use ReadNodeRes.ProtoReflect.Descriptor instead.
+func (*ReadNodeRes) Descriptor() ([]byte, []int) {
+	return file_grpc_node_proto_rawDescGZIP(), []int{12}
+}
 
-func (m *ReadNodeRes) GetNode() *Node {
-	if m != nil {
-		return m.Node
+func (x *ReadNodeRes) GetNode() *Node {
+	if x != nil {
+		return x.Node
 	}
 	return nil
 }
 
 type DeleteNodeReq struct {
-	Macaddress           string   `protobuf:"bytes,1,opt,name=macaddress,proto3" json:"macaddress,omitempty"`
-	NetworkName          string   `protobuf:"bytes,2,opt,name=networkName,proto3" json:"networkName,omitempty"`
-	XXX_NoUnkeyedLiteral struct{} `json:"-"`
-	XXX_unrecognized     []byte   `json:"-"`
-	XXX_sizecache        int32    `json:"-"`
-}
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
 
-func (m *DeleteNodeReq) Reset()         { *m = DeleteNodeReq{} }
-func (m *DeleteNodeReq) String() string { return proto.CompactTextString(m) }
-func (*DeleteNodeReq) ProtoMessage()    {}
-func (*DeleteNodeReq) Descriptor() ([]byte, []int) {
-	return fileDescriptor_d13bd996b67da4ef, []int{13}
+	Macaddress  string `protobuf:"bytes,1,opt,name=macaddress,proto3" json:"macaddress,omitempty"`
+	NetworkName string `protobuf:"bytes,2,opt,name=networkName,proto3" json:"networkName,omitempty"`
 }
 
-func (m *DeleteNodeReq) XXX_Unmarshal(b []byte) error {
-	return xxx_messageInfo_DeleteNodeReq.Unmarshal(m, b)
-}
-func (m *DeleteNodeReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
-	return xxx_messageInfo_DeleteNodeReq.Marshal(b, m, deterministic)
-}
-func (m *DeleteNodeReq) XXX_Merge(src proto.Message) {
-	xxx_messageInfo_DeleteNodeReq.Merge(m, src)
+func (x *DeleteNodeReq) Reset() {
+	*x = DeleteNodeReq{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_grpc_node_proto_msgTypes[13]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
 }
-func (m *DeleteNodeReq) XXX_Size() int {
-	return xxx_messageInfo_DeleteNodeReq.Size(m)
+
+func (x *DeleteNodeReq) String() string {
+	return protoimpl.X.MessageStringOf(x)
 }
-func (m *DeleteNodeReq) XXX_DiscardUnknown() {
-	xxx_messageInfo_DeleteNodeReq.DiscardUnknown(m)
+
+func (*DeleteNodeReq) ProtoMessage() {}
+
+func (x *DeleteNodeReq) ProtoReflect() protoreflect.Message {
+	mi := &file_grpc_node_proto_msgTypes[13]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
 }
 
-var xxx_messageInfo_DeleteNodeReq proto.InternalMessageInfo
+// Deprecated: Use DeleteNodeReq.ProtoReflect.Descriptor instead.
+func (*DeleteNodeReq) Descriptor() ([]byte, []int) {
+	return file_grpc_node_proto_rawDescGZIP(), []int{13}
+}
 
-func (m *DeleteNodeReq) GetMacaddress() string {
-	if m != nil {
-		return m.Macaddress
+func (x *DeleteNodeReq) GetMacaddress() string {
+	if x != nil {
+		return x.Macaddress
 	}
 	return ""
 }
 
-func (m *DeleteNodeReq) GetNetworkName() string {
-	if m != nil {
-		return m.NetworkName
+func (x *DeleteNodeReq) GetNetworkName() string {
+	if x != nil {
+		return x.NetworkName
 	}
 	return ""
 }
 
 type DeleteNodeRes struct {
-	Success              bool     `protobuf:"varint,1,opt,name=success,proto3" json:"success,omitempty"`
-	XXX_NoUnkeyedLiteral struct{} `json:"-"`
-	XXX_unrecognized     []byte   `json:"-"`
-	XXX_sizecache        int32    `json:"-"`
-}
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
 
-func (m *DeleteNodeRes) Reset()         { *m = DeleteNodeRes{} }
-func (m *DeleteNodeRes) String() string { return proto.CompactTextString(m) }
-func (*DeleteNodeRes) ProtoMessage()    {}
-func (*DeleteNodeRes) Descriptor() ([]byte, []int) {
-	return fileDescriptor_d13bd996b67da4ef, []int{14}
+	Success bool `protobuf:"varint,1,opt,name=success,proto3" json:"success,omitempty"`
 }
 
-func (m *DeleteNodeRes) XXX_Unmarshal(b []byte) error {
-	return xxx_messageInfo_DeleteNodeRes.Unmarshal(m, b)
-}
-func (m *DeleteNodeRes) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
-	return xxx_messageInfo_DeleteNodeRes.Marshal(b, m, deterministic)
-}
-func (m *DeleteNodeRes) XXX_Merge(src proto.Message) {
-	xxx_messageInfo_DeleteNodeRes.Merge(m, src)
+func (x *DeleteNodeRes) Reset() {
+	*x = DeleteNodeRes{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_grpc_node_proto_msgTypes[14]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
 }
-func (m *DeleteNodeRes) XXX_Size() int {
-	return xxx_messageInfo_DeleteNodeRes.Size(m)
+
+func (x *DeleteNodeRes) String() string {
+	return protoimpl.X.MessageStringOf(x)
 }
-func (m *DeleteNodeRes) XXX_DiscardUnknown() {
-	xxx_messageInfo_DeleteNodeRes.DiscardUnknown(m)
+
+func (*DeleteNodeRes) ProtoMessage() {}
+
+func (x *DeleteNodeRes) ProtoReflect() protoreflect.Message {
+	mi := &file_grpc_node_proto_msgTypes[14]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
 }
 
-var xxx_messageInfo_DeleteNodeRes proto.InternalMessageInfo
+// Deprecated: Use DeleteNodeRes.ProtoReflect.Descriptor instead.
+func (*DeleteNodeRes) Descriptor() ([]byte, []int) {
+	return file_grpc_node_proto_rawDescGZIP(), []int{14}
+}
 
-func (m *DeleteNodeRes) GetSuccess() bool {
-	if m != nil {
-		return m.Success
+func (x *DeleteNodeRes) GetSuccess() bool {
+	if x != nil {
+		return x.Success
 	}
 	return false
 }
 
 type GetPeersReq struct {
-	Macaddress           string   `protobuf:"bytes,1,opt,name=macaddress,proto3" json:"macaddress,omitempty"`
-	Network              string   `protobuf:"bytes,2,opt,name=network,proto3" json:"network,omitempty"`
-	XXX_NoUnkeyedLiteral struct{} `json:"-"`
-	XXX_unrecognized     []byte   `json:"-"`
-	XXX_sizecache        int32    `json:"-"`
-}
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
 
-func (m *GetPeersReq) Reset()         { *m = GetPeersReq{} }
-func (m *GetPeersReq) String() string { return proto.CompactTextString(m) }
-func (*GetPeersReq) ProtoMessage()    {}
-func (*GetPeersReq) Descriptor() ([]byte, []int) {
-	return fileDescriptor_d13bd996b67da4ef, []int{15}
+	Macaddress string `protobuf:"bytes,1,opt,name=macaddress,proto3" json:"macaddress,omitempty"`
+	Network    string `protobuf:"bytes,2,opt,name=network,proto3" json:"network,omitempty"`
 }
 
-func (m *GetPeersReq) XXX_Unmarshal(b []byte) error {
-	return xxx_messageInfo_GetPeersReq.Unmarshal(m, b)
-}
-func (m *GetPeersReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
-	return xxx_messageInfo_GetPeersReq.Marshal(b, m, deterministic)
-}
-func (m *GetPeersReq) XXX_Merge(src proto.Message) {
-	xxx_messageInfo_GetPeersReq.Merge(m, src)
+func (x *GetPeersReq) Reset() {
+	*x = GetPeersReq{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_grpc_node_proto_msgTypes[15]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
 }
-func (m *GetPeersReq) XXX_Size() int {
-	return xxx_messageInfo_GetPeersReq.Size(m)
+
+func (x *GetPeersReq) String() string {
+	return protoimpl.X.MessageStringOf(x)
 }
-func (m *GetPeersReq) XXX_DiscardUnknown() {
-	xxx_messageInfo_GetPeersReq.DiscardUnknown(m)
+
+func (*GetPeersReq) ProtoMessage() {}
+
+func (x *GetPeersReq) ProtoReflect() protoreflect.Message {
+	mi := &file_grpc_node_proto_msgTypes[15]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
 }
 
-var xxx_messageInfo_GetPeersReq proto.InternalMessageInfo
+// Deprecated: Use GetPeersReq.ProtoReflect.Descriptor instead.
+func (*GetPeersReq) Descriptor() ([]byte, []int) {
+	return file_grpc_node_proto_rawDescGZIP(), []int{15}
+}
 
-func (m *GetPeersReq) GetMacaddress() string {
-	if m != nil {
-		return m.Macaddress
+func (x *GetPeersReq) GetMacaddress() string {
+	if x != nil {
+		return x.Macaddress
 	}
 	return ""
 }
 
-func (m *GetPeersReq) GetNetwork() string {
-	if m != nil {
-		return m.Network
+func (x *GetPeersReq) GetNetwork() string {
+	if x != nil {
+		return x.Network
 	}
 	return ""
 }
 
 type GetExtPeersReq struct {
-	Macaddress           string   `protobuf:"bytes,1,opt,name=macaddress,proto3" json:"macaddress,omitempty"`
-	Network              string   `protobuf:"bytes,2,opt,name=network,proto3" json:"network,omitempty"`
-	XXX_NoUnkeyedLiteral struct{} `json:"-"`
-	XXX_unrecognized     []byte   `json:"-"`
-	XXX_sizecache        int32    `json:"-"`
-}
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
 
-func (m *GetExtPeersReq) Reset()         { *m = GetExtPeersReq{} }
-func (m *GetExtPeersReq) String() string { return proto.CompactTextString(m) }
-func (*GetExtPeersReq) ProtoMessage()    {}
-func (*GetExtPeersReq) Descriptor() ([]byte, []int) {
-	return fileDescriptor_d13bd996b67da4ef, []int{16}
+	Macaddress string `protobuf:"bytes,1,opt,name=macaddress,proto3" json:"macaddress,omitempty"`
+	Network    string `protobuf:"bytes,2,opt,name=network,proto3" json:"network,omitempty"`
 }
 
-func (m *GetExtPeersReq) XXX_Unmarshal(b []byte) error {
-	return xxx_messageInfo_GetExtPeersReq.Unmarshal(m, b)
-}
-func (m *GetExtPeersReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
-	return xxx_messageInfo_GetExtPeersReq.Marshal(b, m, deterministic)
-}
-func (m *GetExtPeersReq) XXX_Merge(src proto.Message) {
-	xxx_messageInfo_GetExtPeersReq.Merge(m, src)
+func (x *GetExtPeersReq) Reset() {
+	*x = GetExtPeersReq{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_grpc_node_proto_msgTypes[16]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
 }
-func (m *GetExtPeersReq) XXX_Size() int {
-	return xxx_messageInfo_GetExtPeersReq.Size(m)
+
+func (x *GetExtPeersReq) String() string {
+	return protoimpl.X.MessageStringOf(x)
 }
-func (m *GetExtPeersReq) XXX_DiscardUnknown() {
-	xxx_messageInfo_GetExtPeersReq.DiscardUnknown(m)
+
+func (*GetExtPeersReq) ProtoMessage() {}
+
+func (x *GetExtPeersReq) ProtoReflect() protoreflect.Message {
+	mi := &file_grpc_node_proto_msgTypes[16]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
 }
 
-var xxx_messageInfo_GetExtPeersReq proto.InternalMessageInfo
+// Deprecated: Use GetExtPeersReq.ProtoReflect.Descriptor instead.
+func (*GetExtPeersReq) Descriptor() ([]byte, []int) {
+	return file_grpc_node_proto_rawDescGZIP(), []int{16}
+}
 
-func (m *GetExtPeersReq) GetMacaddress() string {
-	if m != nil {
-		return m.Macaddress
+func (x *GetExtPeersReq) GetMacaddress() string {
+	if x != nil {
+		return x.Macaddress
 	}
 	return ""
 }
 
-func (m *GetExtPeersReq) GetNetwork() string {
-	if m != nil {
-		return m.Network
+func (x *GetExtPeersReq) GetNetwork() string {
+	if x != nil {
+		return x.Network
 	}
 	return ""
 }
 
 type GetPeersRes struct {
-	Peers                *PeersResponse `protobuf:"bytes,1,opt,name=peers,proto3" json:"peers,omitempty"`
-	XXX_NoUnkeyedLiteral struct{}       `json:"-"`
-	XXX_unrecognized     []byte         `json:"-"`
-	XXX_sizecache        int32          `json:"-"`
-}
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
 
-func (m *GetPeersRes) Reset()         { *m = GetPeersRes{} }
-func (m *GetPeersRes) String() string { return proto.CompactTextString(m) }
-func (*GetPeersRes) ProtoMessage()    {}
-func (*GetPeersRes) Descriptor() ([]byte, []int) {
-	return fileDescriptor_d13bd996b67da4ef, []int{17}
+	Peers *PeersResponse `protobuf:"bytes,1,opt,name=peers,proto3" json:"peers,omitempty"`
 }
 
-func (m *GetPeersRes) XXX_Unmarshal(b []byte) error {
-	return xxx_messageInfo_GetPeersRes.Unmarshal(m, b)
-}
-func (m *GetPeersRes) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
-	return xxx_messageInfo_GetPeersRes.Marshal(b, m, deterministic)
-}
-func (m *GetPeersRes) XXX_Merge(src proto.Message) {
-	xxx_messageInfo_GetPeersRes.Merge(m, src)
+func (x *GetPeersRes) Reset() {
+	*x = GetPeersRes{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_grpc_node_proto_msgTypes[17]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
 }
-func (m *GetPeersRes) XXX_Size() int {
-	return xxx_messageInfo_GetPeersRes.Size(m)
+
+func (x *GetPeersRes) String() string {
+	return protoimpl.X.MessageStringOf(x)
 }
-func (m *GetPeersRes) XXX_DiscardUnknown() {
-	xxx_messageInfo_GetPeersRes.DiscardUnknown(m)
+
+func (*GetPeersRes) ProtoMessage() {}
+
+func (x *GetPeersRes) ProtoReflect() protoreflect.Message {
+	mi := &file_grpc_node_proto_msgTypes[17]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
 }
 
-var xxx_messageInfo_GetPeersRes proto.InternalMessageInfo
+// Deprecated: Use GetPeersRes.ProtoReflect.Descriptor instead.
+func (*GetPeersRes) Descriptor() ([]byte, []int) {
+	return file_grpc_node_proto_rawDescGZIP(), []int{17}
+}
 
-func (m *GetPeersRes) GetPeers() *PeersResponse {
-	if m != nil {
-		return m.Peers
+func (x *GetPeersRes) GetPeers() *PeersResponse {
+	if x != nil {
+		return x.Peers
 	}
 	return nil
 }
 
 type GetExtPeersRes struct {
-	Extpeers             *ExtPeersResponse `protobuf:"bytes,1,opt,name=extpeers,proto3" json:"extpeers,omitempty"`
-	XXX_NoUnkeyedLiteral struct{}          `json:"-"`
-	XXX_unrecognized     []byte            `json:"-"`
-	XXX_sizecache        int32             `json:"-"`
-}
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
 
-func (m *GetExtPeersRes) Reset()         { *m = GetExtPeersRes{} }
-func (m *GetExtPeersRes) String() string { return proto.CompactTextString(m) }
-func (*GetExtPeersRes) ProtoMessage()    {}
-func (*GetExtPeersRes) Descriptor() ([]byte, []int) {
-	return fileDescriptor_d13bd996b67da4ef, []int{18}
+	Extpeers *ExtPeersResponse `protobuf:"bytes,1,opt,name=extpeers,proto3" json:"extpeers,omitempty"`
 }
 
-func (m *GetExtPeersRes) XXX_Unmarshal(b []byte) error {
-	return xxx_messageInfo_GetExtPeersRes.Unmarshal(m, b)
-}
-func (m *GetExtPeersRes) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
-	return xxx_messageInfo_GetExtPeersRes.Marshal(b, m, deterministic)
-}
-func (m *GetExtPeersRes) XXX_Merge(src proto.Message) {
-	xxx_messageInfo_GetExtPeersRes.Merge(m, src)
+func (x *GetExtPeersRes) Reset() {
+	*x = GetExtPeersRes{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_grpc_node_proto_msgTypes[18]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
 }
-func (m *GetExtPeersRes) XXX_Size() int {
-	return xxx_messageInfo_GetExtPeersRes.Size(m)
+
+func (x *GetExtPeersRes) String() string {
+	return protoimpl.X.MessageStringOf(x)
 }
-func (m *GetExtPeersRes) XXX_DiscardUnknown() {
-	xxx_messageInfo_GetExtPeersRes.DiscardUnknown(m)
+
+func (*GetExtPeersRes) ProtoMessage() {}
+
+func (x *GetExtPeersRes) ProtoReflect() protoreflect.Message {
+	mi := &file_grpc_node_proto_msgTypes[18]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
 }
 
-var xxx_messageInfo_GetExtPeersRes proto.InternalMessageInfo
+// Deprecated: Use GetExtPeersRes.ProtoReflect.Descriptor instead.
+func (*GetExtPeersRes) Descriptor() ([]byte, []int) {
+	return file_grpc_node_proto_rawDescGZIP(), []int{18}
+}
 
-func (m *GetExtPeersRes) GetExtpeers() *ExtPeersResponse {
-	if m != nil {
-		return m.Extpeers
+func (x *GetExtPeersRes) GetExtpeers() *ExtPeersResponse {
+	if x != nil {
+		return x.Extpeers
 	}
 	return nil
 }
 
 type CheckInReq struct {
-	Node                 *Node    `protobuf:"bytes,1,opt,name=node,proto3" json:"node,omitempty"`
-	XXX_NoUnkeyedLiteral struct{} `json:"-"`
-	XXX_unrecognized     []byte   `json:"-"`
-	XXX_sizecache        int32    `json:"-"`
-}
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
 
-func (m *CheckInReq) Reset()         { *m = CheckInReq{} }
-func (m *CheckInReq) String() string { return proto.CompactTextString(m) }
-func (*CheckInReq) ProtoMessage()    {}
-func (*CheckInReq) Descriptor() ([]byte, []int) {
-	return fileDescriptor_d13bd996b67da4ef, []int{19}
+	Node *Node `protobuf:"bytes,1,opt,name=node,proto3" json:"node,omitempty"` //   bool postchanges = 2;
 }
 
-func (m *CheckInReq) XXX_Unmarshal(b []byte) error {
-	return xxx_messageInfo_CheckInReq.Unmarshal(m, b)
-}
-func (m *CheckInReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
-	return xxx_messageInfo_CheckInReq.Marshal(b, m, deterministic)
-}
-func (m *CheckInReq) XXX_Merge(src proto.Message) {
-	xxx_messageInfo_CheckInReq.Merge(m, src)
+func (x *CheckInReq) Reset() {
+	*x = CheckInReq{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_grpc_node_proto_msgTypes[19]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
 }
-func (m *CheckInReq) XXX_Size() int {
-	return xxx_messageInfo_CheckInReq.Size(m)
+
+func (x *CheckInReq) String() string {
+	return protoimpl.X.MessageStringOf(x)
 }
-func (m *CheckInReq) XXX_DiscardUnknown() {
-	xxx_messageInfo_CheckInReq.DiscardUnknown(m)
+
+func (*CheckInReq) ProtoMessage() {}
+
+func (x *CheckInReq) ProtoReflect() protoreflect.Message {
+	mi := &file_grpc_node_proto_msgTypes[19]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
 }
 
-var xxx_messageInfo_CheckInReq proto.InternalMessageInfo
+// Deprecated: Use CheckInReq.ProtoReflect.Descriptor instead.
+func (*CheckInReq) Descriptor() ([]byte, []int) {
+	return file_grpc_node_proto_rawDescGZIP(), []int{19}
+}
 
-func (m *CheckInReq) GetNode() *Node {
-	if m != nil {
-		return m.Node
+func (x *CheckInReq) GetNode() *Node {
+	if x != nil {
+		return x.Node
 	}
 	return nil
 }
 
 type CheckInRes struct {
-	Checkinresponse      *CheckInResponse `protobuf:"bytes,1,opt,name=checkinresponse,proto3" json:"checkinresponse,omitempty"`
-	XXX_NoUnkeyedLiteral struct{}         `json:"-"`
-	XXX_unrecognized     []byte           `json:"-"`
-	XXX_sizecache        int32            `json:"-"`
-}
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
 
-func (m *CheckInRes) Reset()         { *m = CheckInRes{} }
-func (m *CheckInRes) String() string { return proto.CompactTextString(m) }
-func (*CheckInRes) ProtoMessage()    {}
-func (*CheckInRes) Descriptor() ([]byte, []int) {
-	return fileDescriptor_d13bd996b67da4ef, []int{20}
+	Checkinresponse *CheckInResponse `protobuf:"bytes,1,opt,name=checkinresponse,proto3" json:"checkinresponse,omitempty"`
 }
 
-func (m *CheckInRes) XXX_Unmarshal(b []byte) error {
-	return xxx_messageInfo_CheckInRes.Unmarshal(m, b)
-}
-func (m *CheckInRes) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
-	return xxx_messageInfo_CheckInRes.Marshal(b, m, deterministic)
-}
-func (m *CheckInRes) XXX_Merge(src proto.Message) {
-	xxx_messageInfo_CheckInRes.Merge(m, src)
+func (x *CheckInRes) Reset() {
+	*x = CheckInRes{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_grpc_node_proto_msgTypes[20]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
 }
-func (m *CheckInRes) XXX_Size() int {
-	return xxx_messageInfo_CheckInRes.Size(m)
+
+func (x *CheckInRes) String() string {
+	return protoimpl.X.MessageStringOf(x)
 }
-func (m *CheckInRes) XXX_DiscardUnknown() {
-	xxx_messageInfo_CheckInRes.DiscardUnknown(m)
+
+func (*CheckInRes) ProtoMessage() {}
+
+func (x *CheckInRes) ProtoReflect() protoreflect.Message {
+	mi := &file_grpc_node_proto_msgTypes[20]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
 }
 
-var xxx_messageInfo_CheckInRes proto.InternalMessageInfo
+// Deprecated: Use CheckInRes.ProtoReflect.Descriptor instead.
+func (*CheckInRes) Descriptor() ([]byte, []int) {
+	return file_grpc_node_proto_rawDescGZIP(), []int{20}
+}
 
-func (m *CheckInRes) GetCheckinresponse() *CheckInResponse {
-	if m != nil {
-		return m.Checkinresponse
+func (x *CheckInRes) GetCheckinresponse() *CheckInResponse {
+	if x != nil {
+		return x.Checkinresponse
 	}
 	return nil
 }
 
-func init() {
-	proto.RegisterType((*LoginRequest)(nil), "node.LoginRequest")
-	proto.RegisterType((*LoginResponse)(nil), "node.LoginResponse")
-	proto.RegisterType((*Node)(nil), "node.Node")
-	proto.RegisterType((*CheckInResponse)(nil), "node.CheckInResponse")
-	proto.RegisterType((*PeersResponse)(nil), "node.PeersResponse")
-	proto.RegisterType((*ExtPeersResponse)(nil), "node.ExtPeersResponse")
-	proto.RegisterType((*Client)(nil), "node.Client")
-	proto.RegisterType((*CreateNodeReq)(nil), "node.CreateNodeReq")
-	proto.RegisterType((*CreateNodeRes)(nil), "node.CreateNodeRes")
-	proto.RegisterType((*UpdateNodeReq)(nil), "node.UpdateNodeReq")
-	proto.RegisterType((*UpdateNodeRes)(nil), "node.UpdateNodeRes")
-	proto.RegisterType((*ReadNodeReq)(nil), "node.ReadNodeReq")
-	proto.RegisterType((*ReadNodeRes)(nil), "node.ReadNodeRes")
-	proto.RegisterType((*DeleteNodeReq)(nil), "node.DeleteNodeReq")
-	proto.RegisterType((*DeleteNodeRes)(nil), "node.DeleteNodeRes")
-	proto.RegisterType((*GetPeersReq)(nil), "node.GetPeersReq")
-	proto.RegisterType((*GetExtPeersReq)(nil), "node.GetExtPeersReq")
-	proto.RegisterType((*GetPeersRes)(nil), "node.GetPeersRes")
-	proto.RegisterType((*GetExtPeersRes)(nil), "node.GetExtPeersRes")
-	proto.RegisterType((*CheckInReq)(nil), "node.CheckInReq")
-	proto.RegisterType((*CheckInRes)(nil), "node.CheckInRes")
-}
-
-func init() { proto.RegisterFile("grpc/node.proto", fileDescriptor_d13bd996b67da4ef) }
-
-var fileDescriptor_d13bd996b67da4ef = []byte{
-	// 1113 bytes of a gzipped FileDescriptorProto
-	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xdc, 0x57, 0x4f, 0x6f, 0x23, 0x35,
-	0x14, 0x57, 0xd2, 0xa6, 0x49, 0x5f, 0x9a, 0xb6, 0xeb, 0xee, 0x16, 0x13, 0x96, 0x55, 0x15, 0x21,
-	0xd4, 0x5d, 0xd1, 0xa6, 0x14, 0x69, 0x85, 0xc4, 0x01, 0x89, 0x2e, 0xaa, 0x40, 0xb0, 0x82, 0x41,
-	0x5c, 0xb8, 0xb9, 0x33, 0x2f, 0xb3, 0x56, 0xa6, 0xf6, 0x74, 0xec, 0x24, 0xdb, 0x3b, 0xdc, 0xf8,
-	0x42, 0x7c, 0x1f, 0xae, 0x7c, 0x07, 0xe4, 0x3f, 0x93, 0xf1, 0x4c, 0xd3, 0x3f, 0xcb, 0xde, 0xb8,
-	0x8d, 0x7f, 0x7e, 0x7f, 0x7f, 0xcf, 0xef, 0xd9, 0x03, 0x3b, 0x69, 0x91, 0xc7, 0x63, 0x21, 0x13,
-	0x3c, 0xce, 0x0b, 0xa9, 0x25, 0x59, 0x37, 0xdf, 0xa3, 0x04, 0xb6, 0x7e, 0x90, 0x29, 0x17, 0x11,
-	0x5e, 0xcd, 0x50, 0x69, 0xf2, 0x0c, 0xe0, 0x92, 0xc5, 0x2c, 0x49, 0x0a, 0x54, 0x8a, 0xb6, 0x0e,
-	0x5a, 0x87, 0x9b, 0x51, 0x80, 0x90, 0x21, 0xf4, 0x72, 0xa6, 0xd4, 0x42, 0x16, 0x09, 0x6d, 0xdb,
-	0xdd, 0xe5, 0x9a, 0x50, 0xe8, 0x0a, 0xd4, 0x0b, 0x59, 0x4c, 0xe9, 0x9a, 0xdd, 0x2a, 0x97, 0xa3,
-	0xcf, 0x61, 0xe0, 0xbd, 0xa8, 0x5c, 0x0a, 0x85, 0xe4, 0x00, 0xfa, 0x2c, 0x8e, 0x51, 0x29, 0x2d,
-	0xa7, 0x28, 0xbc, 0x9f, 0x10, 0x1a, 0xfd, 0xd9, 0x85, 0xf5, 0xd7, 0x32, 0x41, 0xb2, 0x0d, 0x6d,
-	0x9e, 0x78, 0x89, 0x36, 0x4f, 0x08, 0x81, 0x75, 0xc1, 0x2e, 0xd1, 0x7b, 0xb7, 0xdf, 0xc6, 0x73,
-	0x19, 0xb2, 0xf7, 0x1c, 0xc4, 0xeb, 0x3f, 0x5f, 0xd2, 0xa1, 0x8b, 0xb7, 0x5c, 0x9b, 0x5c, 0x33,
-	0xae, 0x34, 0x8a, 0x5c, 0x16, 0x9a, 0xae, 0x1f, 0xb4, 0x0e, 0x3b, 0x51, 0x80, 0x90, 0xa7, 0xb0,
-	0x99, 0xcf, 0x2e, 0x32, 0x1e, 0x4f, 0xf1, 0x9a, 0x76, 0xac, 0x72, 0x05, 0x18, 0xcb, 0x28, 0x92,
-	0x5c, 0x72, 0xa1, 0xe9, 0x86, 0xb3, 0x5c, 0xae, 0x1b, 0x2c, 0x76, 0xef, 0x64, 0xb1, 0xd7, 0x60,
-	0xf1, 0x00, 0xfa, 0xa6, 0x32, 0x25, 0x93, 0x9b, 0x8e, 0x9a, 0x00, 0x32, 0x71, 0x71, 0x95, 0xa3,
-	0x48, 0xb8, 0x48, 0x29, 0x1c, 0xb4, 0x0e, 0x7b, 0x51, 0x05, 0x90, 0x7d, 0xd8, 0xc8, 0xa5, 0xd2,
-	0xb3, 0x9c, 0xf6, 0xad, 0xaa, 0x5f, 0x59, 0x9f, 0x52, 0xe9, 0x44, 0x2e, 0x04, 0xdd, 0xf2, 0x3e,
-	0xfd, 0xda, 0x58, 0x9c, 0x22, 0xe6, 0x2c, 0xe3, 0x73, 0xa4, 0x03, 0x4b, 0x44, 0x05, 0x98, 0x6c,
-	0x14, 0x9b, 0x63, 0x2c, 0xc5, 0x84, 0xa7, 0x74, 0xdb, 0x3a, 0x0c, 0x10, 0xa3, 0xed, 0x2a, 0x67,
-	0x78, 0xda, 0x71, 0x3c, 0x2d, 0x01, 0x1b, 0xad, 0xd0, 0x58, 0x4c, 0x58, 0x8c, 0x74, 0xd7, 0xed,
-	0x2e, 0x01, 0x93, 0x6d, 0xc6, 0x94, 0x8e, 0xdf, 0x60, 0x3c, 0xe5, 0x82, 0x3e, 0x72, 0xd9, 0x06,
-	0x10, 0x19, 0xc1, 0x96, 0x59, 0x5e, 0xca, 0x84, 0x4f, 0x38, 0x26, 0x94, 0x58, 0x91, 0x1a, 0x46,
-	0x0e, 0x61, 0xc7, 0x8b, 0x5b, 0xcb, 0x73, 0x96, 0xd1, 0x3d, 0x9b, 0x45, 0x13, 0xb6, 0xd6, 0x64,
-	0xcc, 0xb2, 0xb2, 0x36, 0x8f, 0xbd, 0xb5, 0x00, 0x33, 0x31, 0x19, 0x66, 0xe2, 0x37, 0x4c, 0xa4,
-	0xa8, 0xe8, 0x13, 0x17, 0x53, 0x00, 0x19, 0x46, 0x58, 0x96, 0xc9, 0x05, 0x26, 0x3c, 0x57, 0x74,
-	0xdf, 0xd5, 0xb7, 0x42, 0xcc, 0x79, 0xe4, 0xca, 0xda, 0xa4, 0x1f, 0x58, 0xba, 0xca, 0x25, 0x79,
-	0x01, 0xbb, 0x5c, 0x71, 0x91, 0x1a, 0x47, 0x29, 0xd3, 0xb8, 0x60, 0xd7, 0xf4, 0xa9, 0x15, 0xb9,
-	0x81, 0x93, 0x13, 0xd8, 0xab, 0x23, 0x85, 0xf1, 0x4e, 0x3f, 0xb6, 0xee, 0x56, 0x6d, 0x99, 0xc8,
-	0xb9, 0x4a, 0x66, 0x2c, 0x53, 0x9a, 0xc5, 0x53, 0xfa, 0x91, 0x35, 0x1c, 0x42, 0xe6, 0x74, 0x24,
-	0x42, 0xc9, 0xc9, 0x84, 0x52, 0xbb, 0xe9, 0x57, 0xb6, 0x17, 0x4c, 0x80, 0xce, 0xc5, 0x87, 0x2e,
-	0xa3, 0x0a, 0x19, 0xfd, 0xd1, 0x86, 0x9d, 0x33, 0xc3, 0xe5, 0x77, 0x55, 0x13, 0x53, 0xe8, 0xaa,
-	0x99, 0xad, 0xb3, 0x6d, 0xcf, 0x5e, 0x54, 0x2e, 0xc9, 0xa7, 0xb0, 0x2d, 0x10, 0x93, 0x1c, 0xb1,
-	0x98, 0xe5, 0x09, 0xd3, 0xae, 0x5b, 0x7b, 0x51, 0x03, 0x35, 0x6c, 0x18, 0xc4, 0x9d, 0x23, 0x2f,
-	0xb9, 0xe6, 0xd8, 0x68, 0xe2, 0x65, 0x5f, 0x5c, 0xa2, 0x52, 0x2c, 0x45, 0xdb, 0xae, 0xbe, 0x2f,
-	0x3c, 0x54, 0xef, 0x8b, 0x4e, 0xb3, 0x2f, 0x3e, 0x81, 0x81, 0xb1, 0x39, 0xc5, 0x6b, 0xef, 0x68,
-	0xc3, 0x4a, 0xd4, 0x41, 0xc3, 0x83, 0x01, 0x12, 0xcc, 0x50, 0xa3, 0xed, 0xdc, 0x5e, 0x14, 0x20,
-	0xa3, 0x7f, 0xda, 0x30, 0xf8, 0x09, 0xb1, 0x50, 0x4b, 0x16, 0x0e, 0x61, 0x87, 0x2b, 0xac, 0x15,
-	0xd4, 0xb1, 0xd1, 0x84, 0xc9, 0x31, 0x10, 0xbc, 0x59, 0x4e, 0x37, 0xc7, 0x56, 0xec, 0xdc, 0x56,
-	0xff, 0xcd, 0xdb, 0xeb, 0xff, 0xdf, 0x27, 0xd6, 0xc3, 0x26, 0x68, 0xef, 0x1d, 0x27, 0x68, 0xb3,
-	0xdb, 0xba, 0x2b, 0xba, 0xed, 0xce, 0xd9, 0x33, 0xfa, 0xbb, 0x05, 0xbb, 0xdf, 0xbe, 0xd5, 0x75,
-	0xca, 0xff, 0x7f, 0x69, 0xfe, 0xde, 0x86, 0x8d, 0xb3, 0x8c, 0xa3, 0xbb, 0x3b, 0xf2, 0x82, 0xcf,
-	0x99, 0x46, 0x93, 0x9d, 0xbf, 0x81, 0x2b, 0xa4, 0x9e, 0x7c, 0xbb, 0x99, 0x7c, 0x6d, 0x16, 0xaf,
-	0x35, 0x67, 0x71, 0x90, 0xfe, 0xfa, 0xed, 0xe9, 0x77, 0x1a, 0xe9, 0xbf, 0x80, 0x5d, 0x85, 0xc5,
-	0x1c, 0x8b, 0x45, 0xda, 0x20, 0xf6, 0x06, 0x6e, 0xef, 0x0a, 0x8b, 0x59, 0xaa, 0xfc, 0xcd, 0x57,
-	0x21, 0x26, 0x3e, 0xb7, 0x32, 0xf1, 0x39, 0x9e, 0x2b, 0x60, 0x34, 0x86, 0xc1, 0x59, 0x81, 0x4c,
-	0xa3, 0xb9, 0xf9, 0x23, 0xbc, 0x22, 0xcf, 0xc0, 0x3e, 0x53, 0x2c, 0x0d, 0xfd, 0x53, 0x38, 0xb6,
-	0xef, 0x17, 0xbb, 0xe9, 0x9e, 0x2f, 0x0d, 0x05, 0xf5, 0x10, 0x85, 0x5f, 0x6d, 0xa7, 0xbf, 0x83,
-	0x87, 0x50, 0xe1, 0x7e, 0x0f, 0xe7, 0xd0, 0x8f, 0x90, 0x25, 0x95, 0xfd, 0xbb, 0x1f, 0x54, 0xc1,
-	0xa3, 0xa9, 0x5d, 0x7f, 0x34, 0x1d, 0x85, 0x86, 0xee, 0xf7, 0xfb, 0x33, 0x0c, 0x5e, 0xd9, 0x19,
-	0xf5, 0x50, 0xcf, 0x66, 0xa0, 0x3a, 0x57, 0xaf, 0xab, 0xf7, 0x54, 0x08, 0x8d, 0x9e, 0xd7, 0x4d,
-	0xaa, 0xdb, 0x27, 0xbe, 0xc9, 0xfa, 0x1c, 0xcb, 0x36, 0x7d, 0x9f, 0xac, 0xbf, 0x87, 0xed, 0x73,
-	0xd4, 0x55, 0xcb, 0xbf, 0x8f, 0xad, 0x2f, 0xc3, 0xa0, 0x14, 0x79, 0x0e, 0x1d, 0x73, 0xf7, 0x28,
-	0x4f, 0xe1, 0x9e, 0xa3, 0xb0, 0x36, 0x5a, 0x22, 0x27, 0x31, 0x7a, 0xd5, 0x88, 0x42, 0x91, 0x53,
-	0xe8, 0xe1, 0x5b, 0x1d, 0xea, 0xef, 0x3b, 0xfd, 0xe6, 0x74, 0x8a, 0x96, 0x72, 0xa3, 0xcf, 0x00,
-	0x96, 0x77, 0xe6, 0xfd, 0x27, 0xed, 0xc7, 0x40, 0x5a, 0x91, 0xaf, 0x97, 0x4f, 0x9a, 0xc2, 0x1b,
-	0xf6, 0x8a, 0x4f, 0x9c, 0x62, 0xe3, 0x32, 0x8e, 0x9a, 0xd2, 0xa7, 0x7f, 0xad, 0x41, 0xdf, 0x58,
-	0xff, 0x05, 0x8b, 0x39, 0x8f, 0xcd, 0x6d, 0xd2, 0xb1, 0x6f, 0x70, 0x42, 0x9c, 0x81, 0xf0, 0xd9,
-	0x3f, 0xdc, 0xab, 0x61, 0x7e, 0xcc, 0xbe, 0x04, 0xa8, 0x9a, 0x8b, 0x78, 0x91, 0x5a, 0x7f, 0x0e,
-	0x57, 0x80, 0x8a, 0x9c, 0x40, 0xaf, 0x3c, 0xb8, 0xe4, 0x91, 0x13, 0x08, 0x3a, 0x62, 0x78, 0x03,
-	0x52, 0xc6, 0x53, 0xd5, 0x64, 0xa5, 0xa7, 0x5a, 0x9f, 0x0e, 0x57, 0x80, 0x56, 0xaf, 0x3a, 0xa0,
-	0xa5, 0x5e, 0xad, 0x0b, 0x86, 0x2b, 0x40, 0x5b, 0xcc, 0xf2, 0x60, 0x94, 0x11, 0x06, 0xa7, 0x77,
-	0x78, 0x03, 0x52, 0x27, 0x2d, 0xf2, 0x95, 0x3d, 0x4c, 0x65, 0xb5, 0xc9, 0xe3, 0xa5, 0x4c, 0x70,
-	0x56, 0x87, 0xab, 0x50, 0xa3, 0x7c, 0x04, 0x5d, 0x5f, 0x30, 0xb2, 0xdb, 0xa8, 0xdf, 0xd5, 0xb0,
-	0x89, 0xa8, 0x6f, 0xc6, 0xbf, 0x1d, 0xa5, 0x52, 0xa6, 0x19, 0x1e, 0xa7, 0x32, 0x63, 0x22, 0x3d,
-	0x96, 0x45, 0x3a, 0xb6, 0xbf, 0x6d, 0x17, 0xb3, 0xc9, 0x58, 0x5f, 0xe7, 0xa8, 0xc6, 0x53, 0x21,
-	0x17, 0xc2, 0xfe, 0xd0, 0xe5, 0x17, 0x17, 0x1b, 0x76, 0xf3, 0x8b, 0x7f, 0x03, 0x00, 0x00, 0xff,
-	0xff, 0xf1, 0xb2, 0x6f, 0x12, 0xe6, 0x0d, 0x00, 0x00,
+var File_grpc_node_proto protoreflect.FileDescriptor
+
+var file_grpc_node_proto_rawDesc = []byte{
+	0x0a, 0x0f, 0x67, 0x72, 0x70, 0x63, 0x2f, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74,
+	0x6f, 0x12, 0x04, 0x6e, 0x6f, 0x64, 0x65, 0x22, 0x64, 0x0a, 0x0c, 0x4c, 0x6f, 0x67, 0x69, 0x6e,
+	0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x6d, 0x61, 0x63, 0x61, 0x64,
+	0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6d, 0x61, 0x63,
+	0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77,
+	0x6f, 0x72, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77,
+	0x6f, 0x72, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x18, 0x03,
+	0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x22, 0x31, 0x0a,
+	0x0d, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x20,
+	0x0a, 0x0b, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20,
+	0x01, 0x28, 0x09, 0x52, 0x0b, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x74, 0x6f, 0x6b, 0x65, 0x6e,
+	0x22, 0xb0, 0x07, 0x0a, 0x04, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18,
+	0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d,
+	0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a,
+	0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07,
+	0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x61, 0x64, 0x64, 0x72, 0x65,
+	0x73, 0x73, 0x36, 0x18, 0x1a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x61, 0x64, 0x64, 0x72, 0x65,
+	0x73, 0x73, 0x36, 0x12, 0x1e, 0x0a, 0x0a, 0x6c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x70, 0x6f, 0x72,
+	0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 0x6c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x70,
+	0x6f, 0x72, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x6b, 0x65, 0x79,
+	0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x6b, 0x65,
+	0x79, 0x12, 0x1a, 0x0a, 0x08, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x06, 0x20,
+	0x01, 0x28, 0x09, 0x52, 0x08, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x1e, 0x0a,
+	0x0a, 0x6d, 0x61, 0x63, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28,
+	0x09, 0x52, 0x0a, 0x6d, 0x61, 0x63, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x1a, 0x0a,
+	0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52,
+	0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x20, 0x0a, 0x0b, 0x6e, 0x6f, 0x64,
+	0x65, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b,
+	0x6e, 0x6f, 0x64, 0x65, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x12, 0x1c, 0x0a, 0x09, 0x69,
+	0x73, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09,
+	0x69, 0x73, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x6f, 0x73,
+	0x74, 0x75, 0x70, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x70, 0x6f, 0x73, 0x74, 0x75,
+	0x70, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x6f, 0x73, 0x74, 0x64, 0x6f, 0x77, 0x6e, 0x18, 0x0c, 0x20,
+	0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x6f, 0x73, 0x74, 0x64, 0x6f, 0x77, 0x6e, 0x12, 0x1c, 0x0a,
+	0x09, 0x6b, 0x65, 0x65, 0x70, 0x61, 0x6c, 0x69, 0x76, 0x65, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x05,
+	0x52, 0x09, 0x6b, 0x65, 0x65, 0x70, 0x61, 0x6c, 0x69, 0x76, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x73,
+	0x61, 0x76, 0x65, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x09, 0x52,
+	0x0a, 0x73, 0x61, 0x76, 0x65, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x1c, 0x0a, 0x09, 0x61,
+	0x63, 0x63, 0x65, 0x73, 0x73, 0x6b, 0x65, 0x79, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09,
+	0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x6b, 0x65, 0x79, 0x12, 0x1c, 0x0a, 0x09, 0x69, 0x6e, 0x74,
+	0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x18, 0x10, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x69, 0x6e,
+	0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x6c, 0x61, 0x73, 0x74, 0x63,
+	0x68, 0x65, 0x63, 0x6b, 0x69, 0x6e, 0x18, 0x11, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x6c, 0x61,
+	0x73, 0x74, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x69, 0x6e, 0x12, 0x22, 0x0a, 0x0c, 0x6c, 0x61, 0x73,
+	0x74, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, 0x64, 0x18, 0x12, 0x20, 0x01, 0x28, 0x09, 0x52,
+	0x0c, 0x6c, 0x61, 0x73, 0x74, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, 0x64, 0x12, 0x28, 0x0a,
+	0x0f, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x69, 0x6e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c,
+	0x18, 0x13, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0f, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x69, 0x6e, 0x69,
+	0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x12, 0x22, 0x0a, 0x0c, 0x6c, 0x6f, 0x63, 0x61, 0x6c,
+	0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x14, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x6c,
+	0x6f, 0x63, 0x61, 0x6c, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x70,
+	0x6f, 0x73, 0x74, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x18, 0x15, 0x20, 0x01, 0x28, 0x09,
+	0x52, 0x0b, 0x70, 0x6f, 0x73, 0x74, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x12, 0x1e, 0x0a,
+	0x0a, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x69, 0x70, 0x73, 0x18, 0x16, 0x20, 0x01, 0x28,
+	0x09, 0x52, 0x0a, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x69, 0x70, 0x73, 0x12, 0x18, 0x0a,
+	0x07, 0x69, 0x73, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x18, 0x17, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07,
+	0x69, 0x73, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x12, 0x2a, 0x0a, 0x10, 0x69, 0x73, 0x69, 0x6e, 0x67,
+	0x72, 0x65, 0x73, 0x73, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x18, 0x1c, 0x20, 0x01, 0x28,
+	0x08, 0x52, 0x10, 0x69, 0x73, 0x69, 0x6e, 0x67, 0x72, 0x65, 0x73, 0x73, 0x67, 0x61, 0x74, 0x65,
+	0x77, 0x61, 0x79, 0x12, 0x30, 0x0a, 0x13, 0x69, 0x6e, 0x67, 0x72, 0x65, 0x73, 0x73, 0x67, 0x61,
+	0x74, 0x65, 0x77, 0x61, 0x79, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x18, 0x1d, 0x20, 0x01, 0x28, 0x09,
+	0x52, 0x13, 0x69, 0x6e, 0x67, 0x72, 0x65, 0x73, 0x73, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79,
+	0x72, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x69, 0x73, 0x64, 0x75, 0x61, 0x6c, 0x73,
+	0x74, 0x61, 0x63, 0x6b, 0x18, 0x1b, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x69, 0x73, 0x64, 0x75,
+	0x61, 0x6c, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x6e, 0x73, 0x6f, 0x66,
+	0x66, 0x18, 0x18, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x64, 0x6e, 0x73, 0x6f, 0x66, 0x66, 0x12,
+	0x1e, 0x0a, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x18, 0x19, 0x20,
+	0x01, 0x28, 0x09, 0x52, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x12,
+	0x22, 0x0a, 0x0c, 0x75, 0x64, 0x70, 0x68, 0x6f, 0x6c, 0x65, 0x70, 0x75, 0x6e, 0x63, 0x68, 0x18,
+	0x1e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x75, 0x64, 0x70, 0x68, 0x6f, 0x6c, 0x65, 0x70, 0x75,
+	0x6e, 0x63, 0x68, 0x22, 0x85, 0x02, 0x0a, 0x0f, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x49, 0x6e, 0x52,
+	0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65,
+	0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73,
+	0x73, 0x12, 0x26, 0x0a, 0x0e, 0x6e, 0x65, 0x65, 0x64, 0x70, 0x65, 0x65, 0x72, 0x75, 0x70, 0x64,
+	0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x6e, 0x65, 0x65, 0x64, 0x70,
+	0x65, 0x65, 0x72, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x2a, 0x0a, 0x10, 0x6e, 0x65, 0x65,
+	0x64, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x18, 0x03, 0x20,
+	0x01, 0x28, 0x08, 0x52, 0x10, 0x6e, 0x65, 0x65, 0x64, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75,
+	0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x6e, 0x6f, 0x64, 0x65, 0x6d, 0x65, 0x73,
+	0x73, 0x61, 0x67, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x6e, 0x6f, 0x64, 0x65,
+	0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x69, 0x73, 0x70, 0x65, 0x6e,
+	0x64, 0x69, 0x6e, 0x67, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x69, 0x73, 0x70, 0x65,
+	0x6e, 0x64, 0x69, 0x6e, 0x67, 0x12, 0x24, 0x0a, 0x0d, 0x6e, 0x65, 0x65, 0x64, 0x6b, 0x65, 0x79,
+	0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0d, 0x6e, 0x65,
+	0x65, 0x64, 0x6b, 0x65, 0x79, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x6e,
+	0x65, 0x65, 0x64, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52,
+	0x0a, 0x6e, 0x65, 0x65, 0x64, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x22, 0xef, 0x02, 0x0a, 0x0d,
+	0x50, 0x65, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x28, 0x0a,
+	0x0f, 0x69, 0x73, 0x65, 0x67, 0x72, 0x65, 0x73, 0x73, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79,
+	0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x69, 0x73, 0x65, 0x67, 0x72, 0x65, 0x73, 0x73,
+	0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x12, 0x30, 0x0a, 0x13, 0x65, 0x67, 0x72, 0x65, 0x73,
+	0x73, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x18, 0x02,
+	0x20, 0x01, 0x28, 0x09, 0x52, 0x13, 0x65, 0x67, 0x72, 0x65, 0x73, 0x73, 0x67, 0x61, 0x74, 0x65,
+	0x77, 0x61, 0x79, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x12, 0x30, 0x0a, 0x13, 0x69, 0x6e, 0x67,
+	0x72, 0x65, 0x73, 0x73, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x72, 0x61, 0x6e, 0x67, 0x65,
+	0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x13, 0x69, 0x6e, 0x67, 0x72, 0x65, 0x73, 0x73, 0x67,
+	0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x70,
+	0x75, 0x62, 0x6c, 0x69, 0x63, 0x6b, 0x65, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09,
+	0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x6b, 0x65, 0x79, 0x12, 0x1a, 0x0a, 0x08, 0x65, 0x6e, 0x64,
+	0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x65, 0x6e, 0x64,
+	0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73,
+	0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12,
+	0x1a, 0x0a, 0x08, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x36, 0x18, 0x08, 0x20, 0x01, 0x28,
+	0x09, 0x52, 0x08, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x36, 0x12, 0x1e, 0x0a, 0x0a, 0x6c,
+	0x69, 0x73, 0x74, 0x65, 0x6e, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52,
+	0x0a, 0x6c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x22, 0x0a, 0x0c, 0x6c,
+	0x6f, 0x63, 0x61, 0x6c, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28,
+	0x09, 0x52, 0x0c, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12,
+	0x1c, 0x0a, 0x09, 0x6b, 0x65, 0x65, 0x70, 0x61, 0x6c, 0x69, 0x76, 0x65, 0x18, 0x0d, 0x20, 0x01,
+	0x28, 0x05, 0x52, 0x09, 0x6b, 0x65, 0x65, 0x70, 0x61, 0x6c, 0x69, 0x76, 0x65, 0x22, 0xe4, 0x01,
+	0x0a, 0x10, 0x45, 0x78, 0x74, 0x50, 0x65, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
+	0x73, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x6b, 0x65, 0x79, 0x18,
+	0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x6b, 0x65, 0x79,
+	0x12, 0x1a, 0x0a, 0x08, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x06, 0x20, 0x01,
+	0x28, 0x09, 0x52, 0x08, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x18, 0x0a, 0x07,
+	0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61,
+	0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73,
+	0x73, 0x36, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73,
+	0x73, 0x36, 0x12, 0x1e, 0x0a, 0x0a, 0x6c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x70, 0x6f, 0x72, 0x74,
+	0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 0x6c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x70, 0x6f,
+	0x72, 0x74, 0x12, 0x22, 0x0a, 0x0c, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x61, 0x64, 0x64, 0x72, 0x65,
+	0x73, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x61,
+	0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x6b, 0x65, 0x65, 0x70, 0x61, 0x6c,
+	0x69, 0x76, 0x65, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x6b, 0x65, 0x65, 0x70, 0x61,
+	0x6c, 0x69, 0x76, 0x65, 0x22, 0x84, 0x02, 0x0a, 0x06, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x12,
+	0x1e, 0x0a, 0x0a, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20,
+	0x01, 0x28, 0x09, 0x52, 0x0a, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x6b, 0x65, 0x79, 0x12,
+	0x1c, 0x0a, 0x09, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01,
+	0x28, 0x09, 0x52, 0x09, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x6b, 0x65, 0x79, 0x12, 0x1c, 0x0a,
+	0x09, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x6b, 0x65, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09,
+	0x52, 0x09, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x6b, 0x65, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x61,
+	0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64,
+	0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73,
+	0x36, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73,
+	0x36, 0x12, 0x2a, 0x0a, 0x10, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x77, 0x67, 0x65, 0x6e, 0x64,
+	0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x73, 0x65, 0x72,
+	0x76, 0x65, 0x72, 0x77, 0x67, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x1e, 0x0a,
+	0x0a, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28,
+	0x09, 0x52, 0x0a, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x1c, 0x0a,
+	0x09, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x6b, 0x65, 0x79, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09,
+	0x52, 0x09, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x6b, 0x65, 0x79, 0x22, 0x2f, 0x0a, 0x0d, 0x43,
+	0x72, 0x65, 0x61, 0x74, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, 0x12, 0x1e, 0x0a, 0x04,
+	0x6e, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0a, 0x2e, 0x6e, 0x6f, 0x64,
+	0x65, 0x2e, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x04, 0x6e, 0x6f, 0x64, 0x65, 0x22, 0x2f, 0x0a, 0x0d,
+	0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x73, 0x12, 0x1e, 0x0a,
+	0x04, 0x6e, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0a, 0x2e, 0x6e, 0x6f,
+	0x64, 0x65, 0x2e, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x04, 0x6e, 0x6f, 0x64, 0x65, 0x22, 0x2f, 0x0a,
+	0x0d, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, 0x12, 0x1e,
+	0x0a, 0x04, 0x6e, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0a, 0x2e, 0x6e,
+	0x6f, 0x64, 0x65, 0x2e, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x04, 0x6e, 0x6f, 0x64, 0x65, 0x22, 0x2f,
+	0x0a, 0x0d, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x73, 0x12,
+	0x1e, 0x0a, 0x04, 0x6e, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0a, 0x2e,
+	0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x04, 0x6e, 0x6f, 0x64, 0x65, 0x22,
+	0x47, 0x0a, 0x0b, 0x52, 0x65, 0x61, 0x64, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, 0x12, 0x1e,
+	0x0a, 0x0a, 0x6d, 0x61, 0x63, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01,
+	0x28, 0x09, 0x52, 0x0a, 0x6d, 0x61, 0x63, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x18,
+	0x0a, 0x07, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52,
+	0x07, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x22, 0x2d, 0x0a, 0x0b, 0x52, 0x65, 0x61, 0x64,
+	0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x73, 0x12, 0x1e, 0x0a, 0x04, 0x6e, 0x6f, 0x64, 0x65, 0x18,
+	0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0a, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x4e, 0x6f, 0x64,
+	0x65, 0x52, 0x04, 0x6e, 0x6f, 0x64, 0x65, 0x22, 0x51, 0x0a, 0x0d, 0x44, 0x65, 0x6c, 0x65, 0x74,
+	0x65, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, 0x12, 0x1e, 0x0a, 0x0a, 0x6d, 0x61, 0x63, 0x61,
+	0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6d, 0x61,
+	0x63, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x6e, 0x65, 0x74, 0x77,
+	0x6f, 0x72, 0x6b, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x6e,
+	0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x29, 0x0a, 0x0d, 0x44, 0x65,
+	0x6c, 0x65, 0x74, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x73,
+	0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x73, 0x75,
+	0x63, 0x63, 0x65, 0x73, 0x73, 0x22, 0x47, 0x0a, 0x0b, 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72,
+	0x73, 0x52, 0x65, 0x71, 0x12, 0x1e, 0x0a, 0x0a, 0x6d, 0x61, 0x63, 0x61, 0x64, 0x64, 0x72, 0x65,
+	0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6d, 0x61, 0x63, 0x61, 0x64, 0x64,
+	0x72, 0x65, 0x73, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x18,
+	0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x22, 0x4a,
+	0x0a, 0x0e, 0x47, 0x65, 0x74, 0x45, 0x78, 0x74, 0x50, 0x65, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71,
+	0x12, 0x1e, 0x0a, 0x0a, 0x6d, 0x61, 0x63, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01,
+	0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6d, 0x61, 0x63, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73,
+	0x12, 0x18, 0x0a, 0x07, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28,
+	0x09, 0x52, 0x07, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x22, 0x38, 0x0a, 0x0b, 0x47, 0x65,
+	0x74, 0x50, 0x65, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x12, 0x29, 0x0a, 0x05, 0x70, 0x65, 0x65,
+	0x72, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e,
+	0x50, 0x65, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x05, 0x70,
+	0x65, 0x65, 0x72, 0x73, 0x22, 0x44, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x45, 0x78, 0x74, 0x50, 0x65,
+	0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x12, 0x32, 0x0a, 0x08, 0x65, 0x78, 0x74, 0x70, 0x65, 0x65,
+	0x72, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e,
+	0x45, 0x78, 0x74, 0x50, 0x65, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
+	0x52, 0x08, 0x65, 0x78, 0x74, 0x70, 0x65, 0x65, 0x72, 0x73, 0x22, 0x2c, 0x0a, 0x0a, 0x43, 0x68,
+	0x65, 0x63, 0x6b, 0x49, 0x6e, 0x52, 0x65, 0x71, 0x12, 0x1e, 0x0a, 0x04, 0x6e, 0x6f, 0x64, 0x65,
+	0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0a, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x4e, 0x6f,
+	0x64, 0x65, 0x52, 0x04, 0x6e, 0x6f, 0x64, 0x65, 0x22, 0x4d, 0x0a, 0x0a, 0x43, 0x68, 0x65, 0x63,
+	0x6b, 0x49, 0x6e, 0x52, 0x65, 0x73, 0x12, 0x3f, 0x0a, 0x0f, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x69,
+	0x6e, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32,
+	0x15, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x49, 0x6e, 0x52, 0x65,
+	0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x0f, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x69, 0x6e, 0x72,
+	0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0xb9, 0x03, 0x0a, 0x0b, 0x4e, 0x6f, 0x64, 0x65,
+	0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x30, 0x0a, 0x05, 0x4c, 0x6f, 0x67, 0x69, 0x6e,
+	0x12, 0x12, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x71,
+	0x75, 0x65, 0x73, 0x74, 0x1a, 0x13, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x4c, 0x6f, 0x67, 0x69,
+	0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x36, 0x0a, 0x0a, 0x43, 0x72, 0x65,
+	0x61, 0x74, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x13, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x43,
+	0x72, 0x65, 0x61, 0x74, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x13, 0x2e, 0x6e,
+	0x6f, 0x64, 0x65, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65,
+	0x73, 0x12, 0x30, 0x0a, 0x08, 0x52, 0x65, 0x61, 0x64, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x11, 0x2e,
+	0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x52, 0x65, 0x61, 0x64, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71,
+	0x1a, 0x11, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x52, 0x65, 0x61, 0x64, 0x4e, 0x6f, 0x64, 0x65,
+	0x52, 0x65, 0x73, 0x12, 0x36, 0x0a, 0x0a, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4e, 0x6f, 0x64,
+	0x65, 0x12, 0x13, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4e,
+	0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x13, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x55, 0x70,
+	0x64, 0x61, 0x74, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x73, 0x12, 0x36, 0x0a, 0x0a, 0x44,
+	0x65, 0x6c, 0x65, 0x74, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x13, 0x2e, 0x6e, 0x6f, 0x64, 0x65,
+	0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x13,
+	0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4e, 0x6f, 0x64, 0x65,
+	0x52, 0x65, 0x73, 0x12, 0x32, 0x0a, 0x08, 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x73, 0x12,
+	0x11, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x73, 0x52,
+	0x65, 0x71, 0x1a, 0x11, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x65, 0x65,
+	0x72, 0x73, 0x52, 0x65, 0x73, 0x30, 0x01, 0x12, 0x3b, 0x0a, 0x0b, 0x47, 0x65, 0x74, 0x45, 0x78,
+	0x74, 0x50, 0x65, 0x65, 0x72, 0x73, 0x12, 0x14, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x47, 0x65,
+	0x74, 0x45, 0x78, 0x74, 0x50, 0x65, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x1a, 0x14, 0x2e, 0x6e,
+	0x6f, 0x64, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x45, 0x78, 0x74, 0x50, 0x65, 0x65, 0x72, 0x73, 0x52,
+	0x65, 0x73, 0x30, 0x01, 0x12, 0x2d, 0x0a, 0x07, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x49, 0x6e, 0x12,
+	0x10, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x49, 0x6e, 0x52, 0x65,
+	0x71, 0x1a, 0x10, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x49, 0x6e,
+	0x52, 0x65, 0x73, 0x42, 0x2f, 0x5a, 0x2d, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x67, 0x6f,
+	0x6c, 0x61, 0x6e, 0x67, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75,
+	0x66, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2f, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x2f, 0x6e, 0x6f,
+	0x64, 0x65, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+}
+
+var (
+	file_grpc_node_proto_rawDescOnce sync.Once
+	file_grpc_node_proto_rawDescData = file_grpc_node_proto_rawDesc
+)
+
+func file_grpc_node_proto_rawDescGZIP() []byte {
+	file_grpc_node_proto_rawDescOnce.Do(func() {
+		file_grpc_node_proto_rawDescData = protoimpl.X.CompressGZIP(file_grpc_node_proto_rawDescData)
+	})
+	return file_grpc_node_proto_rawDescData
+}
+
+var file_grpc_node_proto_msgTypes = make([]protoimpl.MessageInfo, 21)
+var file_grpc_node_proto_goTypes = []interface{}{
+	(*LoginRequest)(nil),     // 0: node.LoginRequest
+	(*LoginResponse)(nil),    // 1: node.LoginResponse
+	(*Node)(nil),             // 2: node.Node
+	(*CheckInResponse)(nil),  // 3: node.CheckInResponse
+	(*PeersResponse)(nil),    // 4: node.PeersResponse
+	(*ExtPeersResponse)(nil), // 5: node.ExtPeersResponse
+	(*Client)(nil),           // 6: node.Client
+	(*CreateNodeReq)(nil),    // 7: node.CreateNodeReq
+	(*CreateNodeRes)(nil),    // 8: node.CreateNodeRes
+	(*UpdateNodeReq)(nil),    // 9: node.UpdateNodeReq
+	(*UpdateNodeRes)(nil),    // 10: node.UpdateNodeRes
+	(*ReadNodeReq)(nil),      // 11: node.ReadNodeReq
+	(*ReadNodeRes)(nil),      // 12: node.ReadNodeRes
+	(*DeleteNodeReq)(nil),    // 13: node.DeleteNodeReq
+	(*DeleteNodeRes)(nil),    // 14: node.DeleteNodeRes
+	(*GetPeersReq)(nil),      // 15: node.GetPeersReq
+	(*GetExtPeersReq)(nil),   // 16: node.GetExtPeersReq
+	(*GetPeersRes)(nil),      // 17: node.GetPeersRes
+	(*GetExtPeersRes)(nil),   // 18: node.GetExtPeersRes
+	(*CheckInReq)(nil),       // 19: node.CheckInReq
+	(*CheckInRes)(nil),       // 20: node.CheckInRes
+}
+var file_grpc_node_proto_depIdxs = []int32{
+	2,  // 0: node.CreateNodeReq.node:type_name -> node.Node
+	2,  // 1: node.CreateNodeRes.node:type_name -> node.Node
+	2,  // 2: node.UpdateNodeReq.node:type_name -> node.Node
+	2,  // 3: node.UpdateNodeRes.node:type_name -> node.Node
+	2,  // 4: node.ReadNodeRes.node:type_name -> node.Node
+	4,  // 5: node.GetPeersRes.peers:type_name -> node.PeersResponse
+	5,  // 6: node.GetExtPeersRes.extpeers:type_name -> node.ExtPeersResponse
+	2,  // 7: node.CheckInReq.node:type_name -> node.Node
+	3,  // 8: node.CheckInRes.checkinresponse:type_name -> node.CheckInResponse
+	0,  // 9: node.NodeService.Login:input_type -> node.LoginRequest
+	7,  // 10: node.NodeService.CreateNode:input_type -> node.CreateNodeReq
+	11, // 11: node.NodeService.ReadNode:input_type -> node.ReadNodeReq
+	9,  // 12: node.NodeService.UpdateNode:input_type -> node.UpdateNodeReq
+	13, // 13: node.NodeService.DeleteNode:input_type -> node.DeleteNodeReq
+	15, // 14: node.NodeService.GetPeers:input_type -> node.GetPeersReq
+	16, // 15: node.NodeService.GetExtPeers:input_type -> node.GetExtPeersReq
+	19, // 16: node.NodeService.CheckIn:input_type -> node.CheckInReq
+	1,  // 17: node.NodeService.Login:output_type -> node.LoginResponse
+	8,  // 18: node.NodeService.CreateNode:output_type -> node.CreateNodeRes
+	12, // 19: node.NodeService.ReadNode:output_type -> node.ReadNodeRes
+	10, // 20: node.NodeService.UpdateNode:output_type -> node.UpdateNodeRes
+	14, // 21: node.NodeService.DeleteNode:output_type -> node.DeleteNodeRes
+	17, // 22: node.NodeService.GetPeers:output_type -> node.GetPeersRes
+	18, // 23: node.NodeService.GetExtPeers:output_type -> node.GetExtPeersRes
+	20, // 24: node.NodeService.CheckIn:output_type -> node.CheckInRes
+	17, // [17:25] is the sub-list for method output_type
+	9,  // [9:17] is the sub-list for method input_type
+	9,  // [9:9] is the sub-list for extension type_name
+	9,  // [9:9] is the sub-list for extension extendee
+	0,  // [0:9] is the sub-list for field type_name
+}
+
+func init() { file_grpc_node_proto_init() }
+func file_grpc_node_proto_init() {
+	if File_grpc_node_proto != nil {
+		return
+	}
+	if !protoimpl.UnsafeEnabled {
+		file_grpc_node_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*LoginRequest); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_grpc_node_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*LoginResponse); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_grpc_node_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*Node); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_grpc_node_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*CheckInResponse); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_grpc_node_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*PeersResponse); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_grpc_node_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*ExtPeersResponse); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_grpc_node_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*Client); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_grpc_node_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*CreateNodeReq); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_grpc_node_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*CreateNodeRes); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_grpc_node_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*UpdateNodeReq); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_grpc_node_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*UpdateNodeRes); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_grpc_node_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*ReadNodeReq); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_grpc_node_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*ReadNodeRes); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_grpc_node_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*DeleteNodeReq); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_grpc_node_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*DeleteNodeRes); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_grpc_node_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*GetPeersReq); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_grpc_node_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*GetExtPeersReq); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_grpc_node_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*GetPeersRes); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_grpc_node_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*GetExtPeersRes); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_grpc_node_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*CheckInReq); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_grpc_node_proto_msgTypes[20].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*CheckInRes); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+	}
+	type x struct{}
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+			RawDescriptor: file_grpc_node_proto_rawDesc,
+			NumEnums:      0,
+			NumMessages:   21,
+			NumExtensions: 0,
+			NumServices:   1,
+		},
+		GoTypes:           file_grpc_node_proto_goTypes,
+		DependencyIndexes: file_grpc_node_proto_depIdxs,
+		MessageInfos:      file_grpc_node_proto_msgTypes,
+	}.Build()
+	File_grpc_node_proto = out.File
+	file_grpc_node_proto_rawDesc = nil
+	file_grpc_node_proto_goTypes = nil
+	file_grpc_node_proto_depIdxs = nil
 }

+ 3 - 2
grpc/node.proto

@@ -36,7 +36,7 @@ message Node {
     string postup = 11;
     string postdown = 12;
     int32 keepalive = 13;
-    bool saveconfig = 14;
+    string saveconfig = 14;
     string accesskey = 15;
     string interface = 16;
     string lastcheckin = 17;
@@ -51,6 +51,7 @@ message Node {
     bool isdualstack = 27;
     bool dnsoff = 24;
     string localrange = 25;
+    string udpholepunch = 30;
 }
 
 message CheckInResponse {
@@ -65,7 +66,7 @@ message CheckInResponse {
 
 message PeersResponse {
     bool isegressgateway = 1;
-    string egressgatewayrange = 2;
+    string egressgatewayranges = 2;
     string ingressgatewayrange = 9;
     string publickey = 5;
     string endpoint = 6;

+ 0 - 2
kube/netmaker-template.yaml

@@ -109,8 +109,6 @@ spec:
           value: "secretkey"
         - name: CORS_ALLOWED_ORIGIN
           value: "*"
-        - name: DISABLE_REMOTE_IP_CHECK
-          value: "on"
         - name: MONGO_ADMIN
           value: "mongoadmin"
         - name: MONGO_PASS

+ 105 - 137
main.go

@@ -4,80 +4,73 @@
 package main
 
 import (
-    "log"
-    "github.com/gravitl/netmaker/controllers"
-    "github.com/gravitl/netmaker/servercfg"
-    "github.com/gravitl/netmaker/serverctl"
-    "github.com/gravitl/netmaker/mongoconn"
-    "github.com/gravitl/netmaker/functions"
-    "os"
-    "os/exec"
-    "net"
-    "context"
-    "strconv"
-    "sync"
-    "os/signal"
-    service "github.com/gravitl/netmaker/controllers"
-    nodepb "github.com/gravitl/netmaker/grpc"
-    "google.golang.org/grpc"
+	"log"
+	"net"
+	"os"
+	"os/exec"
+	"os/signal"
+	"strconv"
+	"sync"
+
+	controller "github.com/gravitl/netmaker/controllers"
+	"github.com/gravitl/netmaker/database"
+	"github.com/gravitl/netmaker/functions"
+	nodepb "github.com/gravitl/netmaker/grpc"
+	"github.com/gravitl/netmaker/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
+	defer database.Database.Close()
+	startControllers() // start the grpc or rest endpoints
+}
 
+func checkModes() { // Client Mode Prereq Check
+	var err error
+	cmd := exec.Command("id", "-u")
+	output, err := cmd.Output()
 
-	//Client Mode Prereq Check
-	if servercfg.IsClientMode() {
-		cmd := exec.Command("id", "-u")
-		output, err := cmd.Output()
+	if err != nil {
+		log.Println("Error running 'id -u' for prereq check. Please investigate or disable client mode.")
+		log.Fatal(err)
+	}
+	uid, err := strconv.Atoi(string(output[:len(output)-1]))
+	if err != nil {
+		log.Println("Error retrieving uid from 'id -u' for prereq check. Please investigate or disable client mode.")
+		log.Fatal(err)
+	}
+	if uid != 0 {
+		log.Fatal("To run in client mode requires root privileges. Either disable client mode or run with sudo.")
+	}
 
+	if servercfg.IsDNSMode() {
+		err := functions.SetDNSDir()
 		if err != nil {
-			log.Println("Error running 'id -u' for prereq check. Please investigate or disable client mode.")
 			log.Fatal(err)
 		}
-		i, err := strconv.Atoi(string(output[:len(output)-1]))
-		if err != nil {
-                        log.Println("Error retrieving uid from 'id -u' for prereq check. Please investigate or disable client mode.")
-			log.Fatal(err)
-		}
-		if i != 0 {
-			log.Fatal("To run in client mode requires root privileges. Either disable client mode or run with sudo.")
-		}
 	}
-        if servercfg.IsDNSMode() {
-                err := functions.SetDNSDir()
-                if err != nil {
-                        log.Fatal(err)
-                }
-        }
 
-	//Start Mongodb
-	mongoconn.ConnectDatabase()
-
-	installserver := false
-
-	//Create the default network (default: 10.10.10.0/24)
-	created, err := serverctl.CreateDefaultNetwork()
-	if err != nil {
-		log.Printf("Error creating default network: %v", err)
-	}
+}
 
-	if created && servercfg.IsClientMode() {
-		installserver = true
-	}
+func initialize() {
+	database.InitializeDatabase()
 	if servercfg.IsGRPCWireGuard() {
-                err = serverctl.InitServerWireGuard()
-		//err = serverctl.ReconfigureServerWireGuard()
-	        if err != nil {
-	                log.Fatal(err)
+		if err := serverctl.InitServerWireGuard(); err != nil {
+			log.Fatal(err)
 		}
 	}
+	functions.PrintUserLog("netmaker", "successfully created db tables if not present", 1)
+}
 
+func startControllers() {
 	var waitnetwork sync.WaitGroup
-
 	//Run Agent Server
 	if servercfg.IsAgentBackend() {
-	        if !(servercfg.DisableRemoteIPCheck()) && servercfg.GetGRPCHost() == "127.0.0.1" {
+		if !(servercfg.DisableRemoteIPCheck()) && servercfg.GetGRPCHost() == "127.0.0.1" {
 			err := servercfg.SetHost()
 			if err != nil {
 				log.Println("Unable to Set host. Exiting...")
@@ -85,23 +78,23 @@ func main() {
 			}
 		}
 		waitnetwork.Add(1)
-		go runGRPC(&waitnetwork, installserver)
+		go runGRPC(&waitnetwork)
 	}
-        if servercfg.IsDNSMode() {
+	if servercfg.IsDNSMode() {
 		err := controller.SetDNS()
-                if err != nil {
-                        log.Fatal(err)
-                }
-        }
+		if err != nil {
+			log.Fatal(err)
+		}
+	}
 	//Run Rest Server
 	if servercfg.IsRestBackend() {
-                if !servercfg.DisableRemoteIPCheck() && servercfg.GetAPIHost() == "127.0.0.1" {
-                        err := servercfg.SetHost()
-                        if err != nil {
-                                log.Println("Unable to Set host. Exiting...")
-                                log.Fatal(err)
-                        }
-                }
+		if !servercfg.DisableRemoteIPCheck() && servercfg.GetAPIHost() == "127.0.0.1" {
+			err := servercfg.SetHost()
+			if err != nil {
+				log.Println("Unable to Set host. Exiting...")
+				log.Fatal(err)
+			}
+		}
 		waitnetwork.Add(1)
 		controller.HandleRESTRequests(&waitnetwork)
 	}
@@ -112,88 +105,63 @@ func main() {
 	log.Println("exiting")
 }
 
-
-func runGRPC(wg *sync.WaitGroup, installserver bool) {
-
+func runGRPC(wg *sync.WaitGroup) {
 
 	defer wg.Done()
 
-        // Configure 'log' package to give file name and line number on eg. log.Fatal
-        // Pipe flags to one another (log.LstdFLags = log.Ldate | log.Ltime)
-        log.SetFlags(log.LstdFlags | log.Lshortfile)
+	// Configure 'log' package to give file name and line number on eg. log.Fatal
+	// Pipe flags to one another (log.LstdFLags = log.Ldate | log.Ltime)
+	log.SetFlags(log.LstdFlags | log.Lshortfile)
 
 	grpcport := servercfg.GetGRPCPort()
 
 	listener, err := net.Listen("tcp", ":"+grpcport)
-        // Handle errors if any
-        if err != nil {
-                log.Fatalf("Unable to listen on port " + grpcport + ", error: %v", err)
-        }
-
-         s := grpc.NewServer(
-		 authServerUnaryInterceptor(),
-		 authServerStreamInterceptor(),
-	 )
-         // Create NodeService type 
-         srv := &service.NodeServiceServer{}
-
-         // Register the service with the server 
-         nodepb.RegisterNodeServiceServer(s, srv)
-
-         srv.NodeDB = mongoconn.NodeDB
-
-        // Start the server in a child routine
-        go func() {
-                if err := s.Serve(listener); err != nil {
-                        log.Fatalf("Failed to serve: %v", err)
-                }
-        }()
-        log.Println("Agent Server succesfully started on port " + grpcport + " (gRPC)")
-
-	if installserver {
-			success := true
-			if !servercfg.DisableDefaultNet() {
-	                        log.Println("Adding server to default network")
-				success, err = serverctl.AddNetwork("default")
-			}
-			if err != nil {
-                                log.Printf("Error adding to default network: %v", err)
-				log.Println("Unable to add server to network. Continuing.")
-				log.Println("Please investigate client installation on server.")
-			} else if !success {
-                                log.Println("Unable to add server to network. Continuing.")
-                                log.Println("Please investigate client installation on server.")
-			} else{
-                                log.Println("Server successfully added to default network.")
-			}
+	// Handle errors if any
+	if err != nil {
+		log.Fatalf("Unable to listen on port "+grpcport+", error: %v", err)
 	}
-        log.Println("Setup complete. You are ready to begin using netmaker.")
-
-        // Right way to stop the server using a SHUTDOWN HOOK
-        // Create a channel to receive OS signals
-        c := make(chan os.Signal)
-
-        // Relay os.Interrupt to our channel (os.Interrupt = CTRL+C)
-        // Ignore other incoming signals
-        signal.Notify(c, os.Interrupt)
-
-        // Block main routine until a signal is received
-        // As long as user doesn't press CTRL+C a message is not passed and our main routine keeps running
-        <-c
-
-        // After receiving CTRL+C Properly stop the server
-        log.Println("Stopping the Agent server...")
-        s.Stop()
-        listener.Close()
-        log.Println("Agent server closed..")
-        log.Println("Closing MongoDB connection")
-        mongoconn.Client.Disconnect(context.TODO())
-        log.Println("MongoDB connection closed.")
+
+	s := grpc.NewServer(
+		authServerUnaryInterceptor(),
+		authServerStreamInterceptor(),
+	)
+	// Create NodeService type
+	srv := &controller.NodeServiceServer{}
+
+	// Register the service with the server
+	nodepb.RegisterNodeServiceServer(s, srv)
+
+	// Start the server in a child routine
+	go func() {
+		if err := s.Serve(listener); err != nil {
+			log.Fatalf("Failed to serve: %v", err)
+		}
+	}()
+	log.Println("Agent Server succesfully started on port " + grpcport + " (gRPC)")
+
+	// Right way to stop the server using a SHUTDOWN HOOK
+	// Create a channel to receive OS signals
+	c := make(chan os.Signal)
+
+	// Relay os.Interrupt to our channel (os.Interrupt = CTRL+C)
+	// Ignore other incoming signals
+	signal.Notify(c, os.Interrupt)
+
+	// Block main routine until a signal is received
+	// As long as user doesn't press CTRL+C a message is not passed and our main routine keeps running
+	<-c
+
+	// After receiving CTRL+C Properly stop the server
+	log.Println("Stopping the Agent server...")
+	s.Stop()
+	listener.Close()
+	log.Println("Agent server closed..")
+	log.Println("Closed DB connection.")
 }
 
 func authServerUnaryInterceptor() grpc.ServerOption {
 	return grpc.UnaryInterceptor(controller.AuthServerUnaryInterceptor)
 }
 func authServerStreamInterceptor() grpc.ServerOption {
-        return grpc.StreamInterceptor(controller.AuthServerStreamInterceptor)
+	return grpc.StreamInterceptor(controller.AuthServerStreamInterceptor)
 }

+ 1 - 1
models/dnsEntry.go

@@ -3,6 +3,6 @@ package models
 
 type DNSEntry struct {
 	Address string `json:"address" bson:"address" validate:"required,ip"`
-	Name    string `json:"name" bson:"name" validate:"required,alphanum,name_unique,max=120"`
+	Name    string `json:"name" bson:"name" validate:"required,name_unique,min=1,max=192"`
 	Network string `json:"network" bson:"network" validate:"network_exists"`
 }

+ 277 - 78
models/network.go

@@ -1,74 +1,206 @@
 package models
 
 import (
-	//  "../mongoconn"
+	"encoding/json"
+	"errors"
+	"fmt"
+	"reflect"
+	"strings"
 	"time"
 
-	"go.mongodb.org/mongo-driver/bson/primitive"
+	"github.com/go-playground/validator/v10"
+	"github.com/gravitl/netmaker/database"
 )
 
 //Network Struct
 //At  some point, need to replace all instances of Name with something else like  Identifier
 type Network struct {
-	ID           primitive.ObjectID `json:"_id,omitempty" bson:"_id,omitempty"`
-	AddressRange string             `json:"addressrange" bson:"addressrange" validate:"required,cidr"`
-	// bug in validator --- required_with does not work with bools  issue#683
-	//	AddressRange6          string             `json:"addressrange6" bson:"addressrange6" validate:"required_with=isdualstack true,cidrv6"`
-	AddressRange6 string `json:"addressrange6" bson:"addressrange6" validate:"addressrange6_valid"`
-	//can't have min=1 with omitempty
-	DisplayName         string      `json:"displayname,omitempty" bson:"displayname,omitempty" validate:"omitempty,min=1,max=20,displayname_valid"`
-	NetID               string      `json:"netid" bson:"netid" validate:"required,min=1,max=12,netid_valid"`
-	NodesLastModified   int64       `json:"nodeslastmodified" bson:"nodeslastmodified"`
-	NetworkLastModified int64       `json:"networklastmodified" bson:"networklastmodified"`
-	DefaultInterface    string      `json:"defaultinterface" bson:"defaultinterface"`
-	DefaultListenPort   int32       `json:"defaultlistenport,omitempty" bson:"defaultlistenport,omitempty" validate:"omitempty,min=1024,max=65535"`
-	NodeLimit	    int32       `json:"nodelimit" bson:"nodelimit"`
-	DefaultPostUp       string      `json:"defaultpostup" bson:"defaultpostup"`
-	DefaultPostDown     string      `json:"defaultpostdown" bson:"defaultpostdown"`
-	KeyUpdateTimeStamp  int64       `json:"keyupdatetimestamp" bson:"keyupdatetimestamp"`
-	DefaultKeepalive    int32       `json:"defaultkeepalive" bson:"defaultkeepalive" validate:"omitempty,max=1000"`
-	DefaultSaveConfig   *bool       `json:"defaultsaveconfig" bson:"defaultsaveconfig"`
-	AccessKeys          []AccessKey `json:"accesskeys" bson:"accesskeys"`
-	AllowManualSignUp   *bool       `json:"allowmanualsignup" bson:"allowmanualsignup"`
-	IsLocal             *bool       `json:"islocal" bson:"islocal"`
-	IsDualStack         *bool       `json:"isdualstack" bson:"isdualstack"`
-	IsIPv4         string       `json:"isipv4" bson:"isipv4"`
-	IsIPv6         string       `json:"isipv6" bson:"isipv6"`
-	IsGRPCHub         string       `json:"isgrpchub" bson:"isgrpchub"`
-	LocalRange          string      `json:"localrange" bson:"localrange" validate:"omitempty,cidr"`
-	//can't have min=1 with omitempty
-	DefaultCheckInInterval int32 `json:"checkininterval,omitempty" bson:"checkininterval,omitempty" validate:"omitempty,numeric,min=2,max=100000"`
-}
-type NetworkUpdate struct {
-	ID           primitive.ObjectID `json:"_id,omitempty" bson:"_id,omitempty"`
-	AddressRange string             `json:"addressrange" bson:"addressrange" validate:"omitempty,cidr"`
-
-	// bug in validator --- required_with does not work with bools  issue#683
-	//	AddressRange6          string             `json:"addressrange6" bson:"addressrange6" validate:"required_with=isdualstack true,cidrv6"`
-	AddressRange6 string `json:"addressrange6" bson:"addressrange6" validate:"omitempty,cidr"`
-	//can't have min=1 with omitempty
-	DisplayName         string      `json:"displayname,omitempty" bson:"displayname,omitempty" validate:"omitempty,netid_valid,min=1,max=20"`
-	NetID               string      `json:"netid" bson:"netid" validate:"omitempty,netid_valid,min=1,max=15"`
-	NodesLastModified   int64       `json:"nodeslastmodified" bson:"nodeslastmodified"`
-	NetworkLastModified int64       `json:"networklastmodified" bson:"networklastmodified"`
-	DefaultInterface    string      `json:"defaultinterface" bson:"defaultinterface"`
-	DefaultListenPort   int32       `json:"defaultlistenport,omitempty" bson:"defaultlistenport,omitempty" validate:"omitempty,min=1024,max=65535"`
-	NodeLimit	    int32       `json:"nodelimit" bson:"nodelimit"`
-	DefaultPostUp       string      `json:"defaultpostup" bson:"defaultpostup"`
-	DefaultPostDown     string      `json:"defaultpostdown" bson:"defaultpostdown"`
-	KeyUpdateTimeStamp  int64       `json:"keyupdatetimestamp" bson:"keyupdatetimestamp"`
-	DefaultKeepalive    int32       `json:"defaultkeepalive" bson:"defaultkeepalive" validate:"omitempty,max=1000"`
-	DefaultSaveConfig   *bool       `json:"defaultsaveconfig" bson:"defaultsaveconfig"`
-	AccessKeys          []AccessKey `json:"accesskeys" bson:"accesskeys"`
-	AllowManualSignUp   *bool       `json:"allowmanualsignup" bson:"allowmanualsignup"`
-	IsLocal             *bool       `json:"islocal" bson:"islocal"`
-	IsDualStack         *bool       `json:"isdualstack" bson:"isdualstack"`
-        IsIPv4         string       `json:"isipv4" bson:"isipv4"`
-        IsIPv6         string       `json:"isipv6" bson:"isipv6"`
-        IsGRPCHub         string       `json:"isgrpchub" bson:"isgrpchub"`
-	LocalRange          string      `json:"localrange" bson:"localrange" validate:"omitempty,cidr"`
-	//can't have min=1 with omitempty
-	DefaultCheckInInterval int32 `json:"checkininterval,omitempty" bson:"checkininterval,omitempty" validate:"omitempty,numeric,min=2,max=100000"`
+	AddressRange           string      `json:"addressrange" bson:"addressrange" validate:"required,cidr"`
+	AddressRange6          string      `json:"addressrange6" bson:"addressrange6" validate:"regexp=^s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:)))(%.+)?s*(\/([0-9]|[1-9][0-9]|1[0-1][0-9]|12[0-8]))?$"`
+	DisplayName            string      `json:"displayname,omitempty" bson:"displayname,omitempty" validate:"omitempty,min=1,max=20,displayname_valid"`
+	NetID                  string      `json:"netid" bson:"netid" validate:"required,min=1,max=12,netid_valid"`
+	NodesLastModified      int64       `json:"nodeslastmodified" bson:"nodeslastmodified"`
+	NetworkLastModified    int64       `json:"networklastmodified" bson:"networklastmodified"`
+	DefaultInterface       string      `json:"defaultinterface" bson:"defaultinterface" validate:"min=1,max=15"`
+	DefaultListenPort      int32       `json:"defaultlistenport,omitempty" bson:"defaultlistenport,omitempty" validate:"omitempty,min=1024,max=65535"`
+	NodeLimit              int32       `json:"nodelimit" bson:"nodelimit"`
+	DefaultPostUp          string      `json:"defaultpostup" bson:"defaultpostup"`
+	DefaultPostDown        string      `json:"defaultpostdown" bson:"defaultpostdown"`
+	KeyUpdateTimeStamp     int64       `json:"keyupdatetimestamp" bson:"keyupdatetimestamp"`
+	DefaultKeepalive       int32       `json:"defaultkeepalive" bson:"defaultkeepalive" validate:"omitempty,max=1000"`
+	DefaultSaveConfig      string      `json:"defaultsaveconfig" bson:"defaultsaveconfig" validate:"checkyesorno"`
+	AccessKeys             []AccessKey `json:"accesskeys" bson:"accesskeys"`
+	AllowManualSignUp      string      `json:"allowmanualsignup" bson:"allowmanualsignup" validate:"checkyesorno"`
+	IsLocal                string      `json:"islocal" bson:"islocal" validate:"checkyesorno"`
+	IsDualStack            string      `json:"isdualstack" bson:"isdualstack" validate:"checkyesorno"`
+	IsIPv4                 string      `json:"isipv4" bson:"isipv4" validate:"checkyesorno"`
+	IsIPv6                 string      `json:"isipv6" bson:"isipv6" validate:"checkyesorno"`
+	IsGRPCHub              string      `json:"isgrpchub" bson:"isgrpchub" validate:"checkyesorno"`
+	LocalRange             string      `json:"localrange" bson:"localrange" validate:"omitempty,cidr"`
+	DefaultCheckInInterval int32       `json:"checkininterval,omitempty" bson:"checkininterval,omitempty" validate:"omitempty,numeric,min=2,max=100000"`
+	DefaultUDPHolePunch    string      `json:"defaultudpholepunch" bson:"defaultudpholepunch" validate:"checkyesorno"`
+}
+
+type SaveData struct { // put sensitive fields here
+	NetID string `json:"netid" bson:"netid" validate:"required,min=1,max=12,netid_valid"`
+}
+
+const STRING_FIELD_TYPE = "string"
+const INT64_FIELD_TYPE = "int64"
+const INT32_FIELD_TYPE = "int32"
+const ACCESS_KEY_TYPE = "[]AccessKey"
+
+var FIELD_TYPES = []string{STRING_FIELD_TYPE, INT64_FIELD_TYPE, INT32_FIELD_TYPE, ACCESS_KEY_TYPE}
+
+var FIELDS = map[string][]string{
+	// "id":                  {"ID", "string"},
+	"addressrange":        {"AddressRange", STRING_FIELD_TYPE},
+	"addressrange6":       {"AddressRange6", STRING_FIELD_TYPE},
+	"displayname":         {"DisplayName", STRING_FIELD_TYPE},
+	"netid":               {"NetID", STRING_FIELD_TYPE},
+	"nodeslastmodified":   {"NodesLastModified", INT64_FIELD_TYPE},
+	"networklastmodified": {"NetworkLastModified", INT64_FIELD_TYPE},
+	"defaultinterface":    {"DefaultInterface", STRING_FIELD_TYPE},
+	"defaultlistenport":   {"DefaultListenPort", INT32_FIELD_TYPE},
+	"nodelimit":           {"NodeLimit", INT32_FIELD_TYPE},
+	"defaultpostup":       {"DefaultPostUp", STRING_FIELD_TYPE},
+	"defaultpostdown":     {"DefaultPostDown", STRING_FIELD_TYPE},
+	"keyupdatetimestamp":  {"KeyUpdateTimeStamp", INT64_FIELD_TYPE},
+	"defaultkeepalive":    {"DefaultKeepalive", INT32_FIELD_TYPE},
+	"defaultsaveconfig":   {"DefaultSaveConfig", STRING_FIELD_TYPE},
+	"accesskeys":          {"AccessKeys", ACCESS_KEY_TYPE},
+	"allowmanualsignup":   {"AllowManualSignUp", STRING_FIELD_TYPE},
+	"islocal":             {"IsLocal", STRING_FIELD_TYPE},
+	"isdualstack":         {"IsDualStack", STRING_FIELD_TYPE},
+	"isipv4":              {"IsIPv4", STRING_FIELD_TYPE},
+	"isipv6":              {"IsIPv6", STRING_FIELD_TYPE},
+	"isgrpchub":           {"IsGRPCHub", STRING_FIELD_TYPE},
+	"localrange":          {"LocalRange", STRING_FIELD_TYPE},
+	"checkininterval":     {"DefaultCheckInInterval", INT32_FIELD_TYPE},
+	"defaultudpholepunch": {"DefaultUDPHolePunch", STRING_FIELD_TYPE},
+}
+
+func (network *Network) FieldExists(field string) bool {
+	return len(FIELDS[field]) > 0
+}
+
+func (network *Network) NetIDInNetworkCharSet() bool {
+
+	charset := "abcdefghijklmnopqrstuvwxyz1234567890-_."
+
+	for _, char := range network.NetID {
+		if !strings.Contains(charset, strings.ToLower(string(char))) {
+			return false
+		}
+	}
+	return true
+}
+
+func (network *Network) DisplayNameInNetworkCharSet() bool {
+
+	charset := "abcdefghijklmnopqrstuvwxyz1234567890-_./;% ^#()!@$*"
+
+	for _, char := range network.DisplayName {
+		if !strings.Contains(charset, strings.ToLower(string(char))) {
+			return false
+		}
+	}
+	return true
+}
+
+// Anyway, returns all the networks
+func GetNetworks() ([]Network, error) {
+	var networks []Network
+
+	collection, err := database.FetchRecords(database.NETWORKS_TABLE_NAME)
+
+	if err != nil {
+		return networks, err
+	}
+
+	for _, value := range collection {
+		var network Network
+		if err := json.Unmarshal([]byte(value), &network); err != nil {
+			return networks, err
+		}
+		// add network our array
+		networks = append(networks, network)
+	}
+
+	return networks, err
+}
+
+func (network *Network) IsNetworkDisplayNameUnique() (bool, error) {
+
+	isunique := true
+
+	records, err := GetNetworks()
+
+	if err != nil {
+		return false, err
+	}
+
+	for i := 0; i < len(records); i++ {
+
+		if network.NetID == records[i].DisplayName {
+			isunique = false
+		}
+	}
+
+	return isunique, nil
+}
+
+//Checks to see if any other networks have the same name (id)
+func (network *Network) IsNetworkNameUnique() (bool, error) {
+
+	isunique := true
+
+	dbs, err := GetNetworks()
+
+	if err != nil {
+		return false, err
+	}
+
+	for i := 0; i < len(dbs); i++ {
+
+		if network.NetID == dbs[i].NetID {
+			isunique = false
+		}
+	}
+
+	return isunique, nil
+}
+
+func (network *Network) Validate(isUpdate bool) error {
+	v := validator.New()
+	_ = v.RegisterValidation("netid_valid", func(fl validator.FieldLevel) bool {
+		inCharSet := network.NetIDInNetworkCharSet()
+		if isUpdate {
+			return inCharSet
+		}
+		isFieldUnique, _ := network.IsNetworkNameUnique()
+		return isFieldUnique && inCharSet
+	})
+	//
+	_ = v.RegisterValidation("displayname_valid", func(fl validator.FieldLevel) bool {
+		isFieldUnique, _ := network.IsNetworkDisplayNameUnique()
+		inCharSet := network.DisplayNameInNetworkCharSet()
+		if isUpdate {
+			return inCharSet
+		}
+		return isFieldUnique && inCharSet
+	})
+	_ = v.RegisterValidation("checkyesorno", func(fl validator.FieldLevel) bool {
+		return CheckYesOrNo(fl)
+	})
+	err := v.Struct(network)
+	if err != nil {
+		for _, e := range err.(validator.ValidationErrors) {
+			fmt.Println(e)
+		}
+	}
+
+	return err
 }
 
 //TODO:
@@ -82,6 +214,15 @@ func (network *Network) SetNetworkLastModified() {
 }
 
 func (network *Network) SetDefaults() {
+	if network.DefaultUDPHolePunch == "" {
+		network.DefaultUDPHolePunch = "yes"
+	}
+	if network.IsLocal == "" {
+		network.IsLocal = "no"
+	}
+	if network.IsGRPCHub == "" {
+		network.IsGRPCHub = "no"
+	}
 	if network.DisplayName == "" {
 		network.DisplayName = network.NetID
 	}
@@ -95,34 +236,92 @@ func (network *Network) SetDefaults() {
 	if network.DefaultListenPort == 0 {
 		network.DefaultListenPort = 51821
 	}
-        if network.NodeLimit == 0 {
-                network.NodeLimit = 999999999
-        }
-	if network.DefaultPostDown == "" {
-
+	if network.NodeLimit == 0 {
+		network.NodeLimit = 999999999
 	}
-	if network.DefaultSaveConfig == nil {
-		defaultsave := true
-		network.DefaultSaveConfig = &defaultsave
+	if network.DefaultSaveConfig == "" {
+		network.DefaultSaveConfig = "no"
 	}
 	if network.DefaultKeepalive == 0 {
 		network.DefaultKeepalive = 20
 	}
-	if network.DefaultPostUp == "" {
-	}
 	//Check-In Interval for Nodes, In Seconds
 	if network.DefaultCheckInInterval == 0 {
 		network.DefaultCheckInInterval = 30
 	}
-	if network.AllowManualSignUp == nil {
-		signup := false
-		network.AllowManualSignUp = &signup
+	if network.AllowManualSignUp == "" {
+		network.AllowManualSignUp = "no"
 	}
-	if (network.IsDualStack != nil) && *network.IsDualStack {
+	if network.IsDualStack == "" {
+		network.IsDualStack = "no"
+	}
+	if network.IsDualStack == "yes" {
 		network.IsIPv6 = "yes"
 		network.IsIPv4 = "yes"
-	} else if network.IsGRPCHub != "yes" {
-                network.IsIPv6 = "no"
-                network.IsIPv4 = "yes"
+	} else {
+		network.IsIPv6 = "no"
+		network.IsIPv4 = "yes"
 	}
 }
+
+func (network *Network) CopyValues(newNetwork *Network, fieldName string) {
+	reflection := reflect.ValueOf(newNetwork)
+	value := reflect.Indirect(reflection).FieldByName(FIELDS[fieldName][0])
+	if value.IsValid() && len(FIELDS[fieldName]) == 2 {
+		fieldData := FIELDS[fieldName]
+		for _, indexVal := range FIELD_TYPES {
+			if indexVal == fieldData[1] {
+				currentReflection := reflect.ValueOf(network)
+				reflect.Indirect(currentReflection).FieldByName(FIELDS[fieldName][0]).Set(value)
+			}
+		}
+	}
+}
+
+func (currentNetwork *Network) Update(newNetwork *Network) (bool, bool, error) {
+	if err := newNetwork.Validate(true); err != nil {
+		return false, false, err
+	}
+	if newNetwork.NetID == currentNetwork.NetID {
+		hasrangeupdate := newNetwork.AddressRange != currentNetwork.AddressRange
+		localrangeupdate := newNetwork.LocalRange != currentNetwork.LocalRange
+		if data, err := json.Marshal(newNetwork); err != nil {
+			return false, false, err
+		} else {
+			newNetwork.SetNetworkLastModified()
+			err = database.Insert(newNetwork.NetID, string(data), database.NETWORKS_TABLE_NAME)
+			return hasrangeupdate, localrangeupdate, err
+		}
+	}
+	// copy values
+	return false, false, errors.New("failed to update network " + newNetwork.NetID + ", cannot change netid.")
+}
+
+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
+}
+
+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
+}

+ 306 - 136
models/node.go

@@ -1,138 +1,58 @@
 package models
 
 import (
-	"context"
+	"encoding/json"
+	"errors"
 	"math/rand"
 	"net"
+	"strings"
 	"time"
 
-	"github.com/gravitl/netmaker/mongoconn"
-	"go.mongodb.org/mongo-driver/bson"
-	"go.mongodb.org/mongo-driver/bson/primitive"
+	"github.com/go-playground/validator/v10"
+	"github.com/gravitl/netmaker/database"
+	"golang.org/x/crypto/bcrypt"
 )
 
 const charset = "abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
-
+const TEN_YEARS_IN_SECONDS = 300000000
 var seededRand *rand.Rand = rand.New(
 	rand.NewSource(time.Now().UnixNano()))
 
 //node struct
 type Node struct {
-	ID                  primitive.ObjectID `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          *bool              `json:"saveconfig" bson:"saveconfig"`
-	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           bool               `json:"ispending" bson:"ispending"`
-	IsEgressGateway           bool               `json:"isegressgateway" bson:"isegressgateway"`
-	IsIngressGateway           bool               `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"`
-}
-
-//node update struct --- only validations are different
-type NodeUpdate struct {
-	ID                  primitive.ObjectID `json:"_id,omitempty" bson:"_id,omitempty"`
-	Address             string             `json:"address" bson:"address" validate:"omitempty,ip"`
-	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:"omitempty,base64"`
-	Endpoint            string             `json:"endpoint" bson:"endpoint" validate:"omitempty,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          *bool              `json:"saveconfig" bson:"saveconfig"`
-	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"`
-	CheckInInterval     int32              `json:"checkininterval" bson:"checkininterval"`
-	Password            string             `json:"password" bson:"password" validate:"omitempty,min=5"`
-	Network             string             `json:"network" bson:"network" validate:"network_exists"`
-	IsPending           bool               `json:"ispending" bson:"ispending"`
-	IsIngressGateway           bool               `json:"isingressgateway" bson:"isingressgateway"`
-	IsEgressGateway           bool               `json:"isegressgateway" bson:"isegressgateway"`
-        IngressGatewayRange        string             `json:"ingressgatewayrange" bson:"ingressgatewayrange"`
-	EgressGatewayRanges        []string             `json:"egressgatewayranges" bson:"egressgatewayranges"`
-	PostChanges         string             `json:"postchanges" bson:"postchanges"`
-	StaticIP         string             `json:"staticip" bson:"staticip"`
-	StaticPubKey         string             `json:"staticpubkey" bson:"staticpubkey"`
-}
-
-//Duplicated function for NodeUpdates
-func (node *NodeUpdate) GetNetwork() (Network, error) {
-
-	var network Network
-
-	collection := mongoconn.NetworkDB
-	//collection := mongoconn.Client.Database("netmaker").Collection("networks")
-
-	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-
-	filter := bson.M{"netid": node.Network}
-	err := collection.FindOne(ctx, filter).Decode(&network)
-
-	defer cancel()
-
-	if err != nil {
-		//log.Fatal(err)
-		return network, err
-	}
-
-	return network, err
-}
-
-//TODO: Contains a fatal error return. Need to change
-//Used in contexts where it's not the Parent network.
-func (node *Node) GetNetwork() (Network, error) {
-
-	var network Network
-
-	//collection := mongoconn.NetworkDB
-	collection := mongoconn.Client.Database("netmaker").Collection("networks")
-
-	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-
-	filter := bson.M{"netid": node.Network}
-	err := collection.FindOne(ctx, filter).Decode(&network)
-
-	defer cancel()
-
-	if err != nil {
-		//log.Fatal(err)
-		return network, err
-	}
-
-	return network, err
+	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"`
 }
 
 //TODO:
@@ -149,8 +69,12 @@ func (node *Node) SetLastPeerUpdate() {
 	node.LastPeerUpdate = time.Now().Unix()
 }
 
+func (node *Node) SetID() {
+	node.ID = node.MacAddress + "###" + node.Network
+}
+
 func (node *Node) SetExpirationDateTime() {
-	node.ExpirationDateTime = time.Unix(33174902665, 0).Unix()
+	node.ExpirationDateTime = time.Now().Unix() + TEN_YEARS_IN_SECONDS
 }
 
 func (node *Node) SetDefaultName() {
@@ -161,6 +85,19 @@ func (node *Node) SetDefaultName() {
 	}
 }
 
+func (node *Node) GetNetwork() (Network, error) {
+
+	var network Network
+	networkData, err := database.FetchRecord(database.NETWORKS_TABLE_NAME, node.Network)
+	if err != nil {
+		return network, err
+	}
+	if err = json.Unmarshal([]byte(networkData), &network); err != nil {
+		return Network{}, err
+	}
+	return network, nil
+}
+
 //TODO: I dont know why this exists
 //This should exist on the node.go struct. I'm sure there was a reason?
 func (node *Node) SetDefaults() {
@@ -168,21 +105,16 @@ func (node *Node) SetDefaults() {
 	//TODO: Maybe I should make Network a part of the node struct. Then we can just query the Network object for stuff.
 	parentNetwork, _ := node.GetNetwork()
 
-	node.ExpirationDateTime = time.Unix(33174902665, 0).Unix()
+	node.ExpirationDateTime = time.Now().Unix() + TEN_YEARS_IN_SECONDS
 
 	if node.ListenPort == 0 {
 		node.ListenPort = parentNetwork.DefaultListenPort
 	}
-	if node.PostDown == "" {
-		//Empty because we dont set it
-		//may want to set it to something in the future
-	}
-	//TODO: This is dumb and doesn't work
-	//Need to change
-	if node.SaveConfig == nil {
-		if parentNetwork.DefaultSaveConfig != nil {
-			defaultsave := *parentNetwork.DefaultSaveConfig
-			node.SaveConfig = &defaultsave
+	if node.SaveConfig == "" {
+		if parentNetwork.DefaultSaveConfig != "" {
+			node.SaveConfig = parentNetwork.DefaultSaveConfig
+		} else {
+			node.SaveConfig = "yes"
 		}
 	}
 	if node.Interface == "" {
@@ -198,12 +130,159 @@ func (node *Node) SetDefaults() {
 	if node.StaticIP == "" {
 		node.StaticIP = "no"
 	}
-        if node.StaticPubKey == "" {
-                node.StaticPubKey = "no"
-        }
-
+	if node.StaticPubKey == "" {
+		node.StaticPubKey = "no"
+	}
+	if node.UDPHolePunch == "" {
+		node.UDPHolePunch = parentNetwork.DefaultUDPHolePunch
+		if node.UDPHolePunch == "" {
+			node.UDPHolePunch = "yes"
+		}
+	}
 	node.CheckInInterval = parentNetwork.DefaultCheckInInterval
 
+	node.SetLastModified()
+	node.SetDefaultName()
+	node.SetLastCheckIn()
+	node.SetLastPeerUpdate()
+	node.SetID()
+	node.KeyUpdateTimeStamp = time.Now().Unix()
+}
+
+func (newNode *Node) Fill(currentNode *Node) {
+	if newNode.ID == "" {
+		newNode.ID = currentNode.ID
+	}
+	if newNode.Address == "" {
+		newNode.Address = currentNode.Address
+	}
+	if newNode.Address6 == "" {
+		newNode.Address6 = currentNode.Address6
+	}
+	if newNode.LocalAddress == "" {
+		newNode.LocalAddress = currentNode.LocalAddress
+	}
+	if newNode.Name == "" {
+		newNode.Name = currentNode.Name
+	}
+	if newNode.ListenPort == 0 {
+		newNode.ListenPort = currentNode.ListenPort
+	}
+	if newNode.PublicKey == "" {
+		newNode.PublicKey = currentNode.PublicKey
+	} else {
+		newNode.KeyUpdateTimeStamp = time.Now().Unix()
+	}
+	if newNode.Endpoint == "" {
+		newNode.Endpoint = currentNode.Endpoint
+	}
+	if newNode.PostUp == "" {
+		newNode.PostUp = currentNode.PostUp
+	}
+	if newNode.PostDown == "" {
+		newNode.PostDown = currentNode.PostDown
+	}
+	if newNode.AllowedIPs == nil {
+		newNode.AllowedIPs = currentNode.AllowedIPs
+	}
+	if newNode.PersistentKeepalive == 0 {
+		newNode.PersistentKeepalive = currentNode.PersistentKeepalive
+	}
+	if newNode.SaveConfig == "" {
+		newNode.SaveConfig = currentNode.SaveConfig
+	}
+	if newNode.AccessKey == "" {
+		newNode.AccessKey = currentNode.AccessKey
+	}
+	if newNode.Interface == "" {
+		newNode.Interface = currentNode.Interface
+	}
+	if newNode.LastModified == 0 {
+		newNode.LastModified = currentNode.LastModified
+	}
+	if newNode.KeyUpdateTimeStamp == 0 {
+		newNode.LastModified = currentNode.LastModified
+	}
+	if newNode.ExpirationDateTime == 0 {
+		newNode.ExpirationDateTime = currentNode.ExpirationDateTime
+	}
+	if newNode.LastPeerUpdate == 0 {
+		newNode.LastPeerUpdate = currentNode.LastPeerUpdate
+	}
+	if newNode.LastCheckIn == 0 {
+		newNode.LastCheckIn = currentNode.LastCheckIn
+	}
+	if newNode.MacAddress == "" {
+		newNode.MacAddress = currentNode.MacAddress
+	}
+	if newNode.CheckInInterval == 0 {
+		newNode.CheckInInterval = currentNode.CheckInInterval
+	}
+	if newNode.Password != "" {
+		err := bcrypt.CompareHashAndPassword([]byte(newNode.Password), []byte(currentNode.Password))
+		if err != nil && currentNode.Password != newNode.Password {
+			hash, err := bcrypt.GenerateFromPassword([]byte(newNode.Password), 5)
+			if err == nil {
+				newNode.Password = string(hash)
+			}
+		}
+	} else {
+		newNode.Password = currentNode.Password
+	}
+	if newNode.Network == "" {
+		newNode.Network = currentNode.Network
+	}
+	if newNode.IsPending == "" {
+		newNode.IsPending = currentNode.IsPending
+	}
+	if newNode.IsEgressGateway == "" {
+		newNode.IsEgressGateway = currentNode.IsEgressGateway
+	}
+	if newNode.IsIngressGateway == "" {
+		newNode.IsIngressGateway = currentNode.IsIngressGateway
+	}
+	if newNode.EgressGatewayRanges == nil {
+		newNode.EgressGatewayRanges = currentNode.EgressGatewayRanges
+	}
+	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.UDPHolePunch == "" {
+		newNode.UDPHolePunch = currentNode.SaveConfig
+	}
+
+	newNode.PostChanges = "no"
+}
+
+func (currentNode *Node) Update(newNode *Node) error {
+        newNode.Fill(currentNode)
+	if err := newNode.Validate(true); err != nil {
+		return err
+	}
+	newNode.SetID()
+	if newNode.ID == currentNode.ID {
+		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 errors.New("failed to update node " + newNode.MacAddress + ", cannot change macaddress.")
 }
 
 func StringWithCharset(length int, charset string) string {
@@ -220,3 +299,94 @@ func StringWithCharset(length int, charset string) string {
 func IsIpv4Net(host string) bool {
 	return net.ParseIP(host) != nil
 }
+
+func (node *Node) Validate(isUpdate bool) error {
+	v := validator.New()
+	_ = v.RegisterValidation("macaddress_unique", func(fl validator.FieldLevel) bool {
+		if isUpdate {
+			return true
+		}
+		isFieldUnique, _ := node.IsIDUnique()
+		return isFieldUnique
+	})
+	_ = v.RegisterValidation("network_exists", func(fl validator.FieldLevel) bool {
+		_, err := node.GetNetwork()
+		return err == nil
+	})
+	_ = v.RegisterValidation("in_charset", func(fl validator.FieldLevel) bool {
+		isgood := node.NameInNodeCharSet()
+		return isgood
+	})
+	_ = v.RegisterValidation("checkyesorno", func(fl validator.FieldLevel) bool {
+		return CheckYesOrNo(fl)
+	})
+	err := v.Struct(node)
+
+	return err
+}
+
+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
+}
+
+func (node *Node) NameInNodeCharSet() bool {
+
+	charset := "abcdefghijklmnopqrstuvwxyz1234567890-"
+
+	for _, char := range node.Name {
+		if !strings.Contains(charset, strings.ToLower(string(char))) {
+			return false
+		}
+	}
+	return true
+}
+
+func GetAllNodes() ([]Node, error) {
+	var nodes []Node
+
+	collection, err := database.FetchRecords(database.NODES_TABLE_NAME)
+	if err != nil {
+		return []Node{}, err
+	}
+
+	for _, value := range collection {
+		var node Node
+		if err := json.Unmarshal([]byte(value), &node); err != nil {
+			return []Node{}, err
+		}
+		// add node to our array
+		nodes = append(nodes, node)
+	}
+
+	return nodes, nil
+}
+
+func GetNode(macaddress string, network string) (Node, error) {
+
+	var node Node
+
+	key, err := GetID(macaddress, network)
+	if err != nil {
+		return node, err
+	}
+	data, err := database.FetchRecord(database.NODES_TABLE_NAME, key)
+	if err != nil {
+		return node, err
+	}
+	if err = json.Unmarshal([]byte(data), &node); err != nil {
+		return node, err
+	}
+
+	return node, err
+}
+
+func GetID(macaddress string, network string) (string, error) {
+	if macaddress == "" || network == "" {
+		return "", errors.New("unable to get record key")
+	}
+	return macaddress + "###" + network, nil
+}

+ 21 - 15
models/structs.go

@@ -8,10 +8,16 @@ type AuthParams struct {
 }
 
 type User struct {
-	UserName string `json:"username" bson:"username" validate:"min=3,max=40,regexp=^(([a-zA-Z,\-,\.]*)|([A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,4})){3,40}$"`
-	Password string `json:"password" bson:"password" validate:"required,min=5"`
+	UserName string   `json:"username" bson:"username" validate:"min=3,max=40,regexp=^(([a-zA-Z,\-,\.]*)|([A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,4})){3,40}$"`
+	Password string   `json:"password" bson:"password" validate:"required,min=5"`
 	Networks []string `json:"networks" bson:"networks"`
-	IsAdmin  bool   `json:"isadmin" bson:"isadmin"`
+	IsAdmin  bool     `json:"isadmin" bson:"isadmin"`
+}
+
+type ReturnUser struct {
+	UserName string   `json:"username" bson:"username" validate:"min=3,max=40,regexp=^(([a-zA-Z,\-,\.]*)|([A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,4})){3,40}$"`
+	Networks []string `json:"networks" bson:"networks"`
+	IsAdmin  bool     `json:"isadmin" bson:"isadmin"`
 }
 
 type UserAuthParams struct {
@@ -92,27 +98,27 @@ type CheckInResponse struct {
 }
 
 type PeersResponse struct {
+	PublicKey          string `json:"publickey" bson:"publickey"`
+	Endpoint           string `json:"endpoint" bson:"endpoint"`
+	Address            string `json:"address" bson:"address"`
+	Address6           string `json:"address6" bson:"address6"`
+	LocalAddress       string `json:"localaddress" bson:"localaddress"`
+	IsEgressGateway    string   `json:"isegressgateway" bson:"isegressgateway"`
+	EgressGatewayRanges string `json:"egressgatewayrange" bson:"egressgatewayrange"`
+	ListenPort         int32  `json:"listenport" bson:"listenport"`
+	KeepAlive          int32  `json:"persistentkeepalive" bson:"persistentkeepalive"`
+}
+
+type ExtPeersResponse struct {
 	PublicKey    string `json:"publickey" bson:"publickey"`
 	Endpoint     string `json:"endpoint" bson:"endpoint"`
 	Address      string `json:"address" bson:"address"`
 	Address6     string `json:"address6" bson:"address6"`
 	LocalAddress string `json:"localaddress" bson:"localaddress"`
-	IsEgressGateway    bool   `json:"isegressgateway" bson:"isegressgateway"`
-	EgressGatewayRange string `json:"egressgatewayrange" bson:"egressgatewayrange"`
 	ListenPort   int32  `json:"listenport" bson:"listenport"`
 	KeepAlive    int32  `json:"persistentkeepalive" bson:"persistentkeepalive"`
 }
 
-type ExtPeersResponse struct {
-        PublicKey    string `json:"publickey" bson:"publickey"`
-        Endpoint     string `json:"endpoint" bson:"endpoint"`
-        Address      string `json:"address" bson:"address"`
-        Address6     string `json:"address6" bson:"address6"`
-        LocalAddress string `json:"localaddress" bson:"localaddress"`
-        ListenPort   int32  `json:"listenport" bson:"listenport"`
-        KeepAlive    int32  `json:"persistentkeepalive" bson:"persistentkeepalive"`
-}
-
 type EgressGatewayRequest struct {
 	NodeID      string   `json:"nodeid" bson:"nodeid"`
 	NetID       string   `json:"netid" bson:"netid"`

+ 16 - 0
models/validation.go

@@ -0,0 +1,16 @@
+package models
+
+import (
+	"regexp"
+
+	"github.com/go-playground/validator/v10"
+)
+
+func CheckYesOrNo(fl validator.FieldLevel) bool {
+	return fl.Field().String() == "yes" || fl.Field().String() == "no"
+}
+
+func CheckRegex(fl validator.FieldLevel) bool {
+	re := regexp.MustCompile(fl.Param())
+	return re.MatchString(fl.Field().String())
+}

+ 0 - 67
mongoconn/mongoconn.go

@@ -1,67 +0,0 @@
-package mongoconn
-
-import (
-	"context"
-	"log"
-	"go.mongodb.org/mongo-driver/mongo"
-	"go.mongodb.org/mongo-driver/mongo/options"
-        "github.com/gravitl/netmaker/servercfg"
-)
-
-var Client *mongo.Client
-var NodeDB *mongo.Collection
-var NetworkDB *mongo.Collection
-var user string
-var pass string
-var host string
-var port string
-var opts string
-
-func setVars() {
-	user = servercfg.GetMongoUser()
-	pass = servercfg.GetMongoPass()
-	host = servercfg.GetMongoHost()
-	port = servercfg.GetMongoPort()
-	opts = servercfg.GetMongoOpts()
-}
-
-func ConnectDatabase() {
-    // Set client options
-
-    setVars()
-
-    clientOptions := options.Client().ApplyURI( "mongodb://" +
-						user + ":" +
-						pass + "@" +
-						host + ":" +
-						port +
-						opts )
-
-    // Connect to MongoDB
-    log.Println("Connecting to MongoDB at " + host + ":" + port + "...")
-    client, err := mongo.Connect(context.TODO(), clientOptions)
-    Client = client
-    if err != nil {
-	log.Println("Error encountered connecting to MongoDB. Terminating.")
-        log.Fatal(err)
-    }
-
-    // Check the connection
-    err = Client.Ping(context.TODO(), nil)
-
-    if err != nil {
-	log.Println("Error encountered pinging MongoDB. Terminating.")
-        log.Fatal(err)
-    }
-
-    NodeDB = Client.Database("netmaker").Collection("nodes")
-    NetworkDB = Client.Database("netmaker").Collection("networks")
-
-    log.Println("MongoDB Connected.")
-}
-
-// ErrorResponse : This is error model.
-type ErrorResponse struct {
-	StatusCode   int    `json:"status"`
-	ErrorMessage string `json:"message"`
-}

+ 353 - 347
netclient/config/config.go

@@ -2,166 +2,171 @@ package config
 
 import (
 	//"github.com/davecgh/go-spew/spew"
-	"github.com/urfave/cli/v2"
-	"os"
-        "encoding/base64"
+	"encoding/base64"
+	"encoding/json"
 	"errors"
 	"fmt"
 	"log"
-        "encoding/json"
-	"gopkg.in/yaml.v3"
+	"os"
+
 	nodepb "github.com/gravitl/netmaker/grpc"
 	"github.com/gravitl/netmaker/models"
+	"github.com/urfave/cli/v2"
+	"gopkg.in/yaml.v3"
 )
+
 type GlobalConfig struct {
 	GRPCWireGuard string `yaml:"grpcwg"`
-	Client models.IntClient
+	Client        models.IntClient
 }
 
 type ClientConfig struct {
-	Server ServerConfig `yaml:"server"`
-	Node NodeConfig `yaml:"node"`
-	Network string `yaml:"network"`
-	Daemon string `yaml:"daemon"`
-	OperatingSystem string `yaml:"operatingsystem"`
+	Server          ServerConfig `yaml:"server"`
+	Node            NodeConfig   `yaml:"node"`
+	Network         string       `yaml:"network"`
+	Daemon          string       `yaml:"daemon"`
+	OperatingSystem string       `yaml:"operatingsystem"`
 }
 type ServerConfig struct {
-        CoreDNSAddr string `yaml:"corednsaddr"`
-        GRPCAddress string `yaml:"grpcaddress"`
-        APIAddress string `yaml:"apiaddress"`
-        AccessKey string `yaml:"accesskey"`
-        GRPCSSL string `yaml:"grpcssl"`
-        GRPCWireGuard string `yaml:"grpcwg"`
+	CoreDNSAddr   string `yaml:"corednsaddr"`
+	GRPCAddress   string `yaml:"grpcaddress"`
+	APIAddress    string `yaml:"apiaddress"`
+	AccessKey     string `yaml:"accesskey"`
+	GRPCSSL       string `yaml:"grpcssl"`
+	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"`
+	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"`
+	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{
+func Write(config *ClientConfig, network string) error {
 	if network == "" {
 		err := errors.New("No network provided. Exiting.")
 		return err
 	}
-        _, err := os.Stat("/etc/netclient") 
+	_, err := os.Stat("/etc/netclient")
 	if os.IsNotExist(err) {
-		      os.Mkdir("/etc/netclient", 744)
+		os.Mkdir("/etc/netclient", 744)
 	} else if err != nil {
-                return err
-        }
+		return err
+	}
 	home := "/etc/netclient"
 
-        file := fmt.Sprintf(home + "/netconfig-" + network)
-        f, err := os.OpenFile(file, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.ModePerm)
-        defer f.Close()
+	file := fmt.Sprintf(home + "/netconfig-" + network)
+	f, err := os.OpenFile(file, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.ModePerm)
+	defer f.Close()
 
 	err = yaml.NewEncoder(f).Encode(config)
 	if err != nil {
 		return err
 	}
-        return err
+	return err
 }
+
 //reading in the env file
-func WriteGlobal(config *GlobalConfig) error{
-        _, err := os.Stat("/etc/netclient") 
-        if os.IsNotExist(err) {
-                      os.Mkdir("/etc/netclient", 744)
-        } else if err != nil {
-                return err
-        }
-        home := "/etc/netclient"
+func WriteGlobal(config *GlobalConfig) error {
+	_, err := os.Stat("/etc/netclient")
+	if os.IsNotExist(err) {
+		os.Mkdir("/etc/netclient", 744)
+	} else if err != nil {
+		return err
+	}
+	home := "/etc/netclient"
 
-        if err != nil {
-                log.Fatal(err)
-        }
-        file := fmt.Sprintf(home + "/netconfig-global-001")
-        f, err := os.OpenFile(file, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.ModePerm)
-        defer f.Close()
+	if err != nil {
+		log.Fatal(err)
+	}
+	file := fmt.Sprintf(home + "/netconfig-global-001")
+	f, err := os.OpenFile(file, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.ModePerm)
+	defer f.Close()
 
-        err = yaml.NewEncoder(f).Encode(config)
-        if err != nil {
-                return err
-        }
-        return err
+	err = yaml.NewEncoder(f).Encode(config)
+	if err != nil {
+		return err
+	}
+	return err
 }
-func WriteServer(server string, accesskey string, network string) error{
-        if network == "" {
-                err := errors.New("No network provided. Exiting.")
-                return err
-        }
-        nofile := false
-        //home, err := homedir.Dir()
-        _, err := os.Stat("/etc/netclient")
+func WriteServer(server string, accesskey string, network string) error {
+	if network == "" {
+		err := errors.New("No network provided. Exiting.")
+		return err
+	}
+	nofile := false
+	//home, err := homedir.Dir()
+	_, err := os.Stat("/etc/netclient")
 	if os.IsNotExist(err) {
-                os.Mkdir("/etc/netclient", 744)
-        } else if err != nil {
+		os.Mkdir("/etc/netclient", 744)
+	} else if err != nil {
 		fmt.Println("couldnt find or create /etc/netclient")
-                return err
-        }
-        home := "/etc/netclient"
+		return err
+	}
+	home := "/etc/netclient"
 
 	file := fmt.Sprintf(home + "/netconfig-" + network)
-        //f, err := os.Open(file)
-        f, err := os.OpenFile(file, os.O_CREATE|os.O_RDWR, 0666)
+	//f, err := os.Open(file)
+	f, err := os.OpenFile(file, os.O_CREATE|os.O_RDWR, 0666)
 	//f, err := ioutil.ReadFile(file)
-        if err != nil {
+	if err != nil {
 		fmt.Println("couldnt open netconfig-" + network)
 		fmt.Println(err)
-                nofile = true
+		nofile = true
 		//err = nil
 		return err
-        }
-        defer f.Close()
+	}
+	defer f.Close()
 
 	//cfg := &ClientConfig{}
 	var cfg ClientConfig
 
-        if !nofile {
+	if !nofile {
 		fmt.Println("Writing to existing config file at " + home + "/netconfig-" + network)
-                decoder := yaml.NewDecoder(f)
-                err = decoder.Decode(&cfg)
+		decoder := yaml.NewDecoder(f)
+		err = decoder.Decode(&cfg)
 		//err = yaml.Unmarshal(f, &cfg)
-                if err != nil {
+		if err != nil {
 			//fmt.Println(err)
-                        //return err
-                }
+			//return err
+		}
 		f.Close()
 		f, err = os.OpenFile(file, os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0666)
-	        if err != nil {
+		if err != nil {
 			fmt.Println("couldnt open netconfig")
 			fmt.Println(err)
 			nofile = true
@@ -170,10 +175,10 @@ func WriteServer(server string, accesskey string, network string) error{
 		}
 		defer f.Close()
 
-                if err != nil {
-                        fmt.Println("trouble opening file")
-                        fmt.Println(err)
-                }
+		if err != nil {
+			fmt.Println("trouble opening file")
+			fmt.Println(err)
+		}
 
 		cfg.Server.GRPCAddress = server
 		cfg.Server.AccessKey = accesskey
@@ -181,36 +186,34 @@ func WriteServer(server string, accesskey string, network string) error{
 		err = yaml.NewEncoder(f).Encode(cfg)
 		//_, err = yaml.Marshal(f, &cfg)
 		if err != nil {
-                        fmt.Println("trouble encoding file")
-                        return err
-                }
+			fmt.Println("trouble encoding file")
+			return err
+		}
 	} else {
-                fmt.Println("Creating new config file at " + home + "/netconfig-" + network)
+		fmt.Println("Creating new config file at " + home + "/netconfig-" + network)
 
-                cfg.Server.GRPCAddress = server
-                cfg.Server.AccessKey = accesskey
+		cfg.Server.GRPCAddress = server
+		cfg.Server.AccessKey = accesskey
 
-                newf, err := os.Create(home + "/netconfig-" + network)
-                err = yaml.NewEncoder(newf).Encode(cfg)
-                defer newf.Close()
-                if err != nil {
-                        return err
-                }
-        }
+		newf, err := os.Create(home + "/netconfig-" + network)
+		err = yaml.NewEncoder(newf).Encode(cfg)
+		defer newf.Close()
+		if err != nil {
+			return err
+		}
+	}
 
-        return err
+	return err
 }
 
-
-
-func(config *ClientConfig) ReadConfig() {
+func (config *ClientConfig) ReadConfig() {
 
 	nofile := false
 	//home, err := homedir.Dir()
 	home := "/etc/netclient"
 	file := fmt.Sprintf(home + "/netconfig-" + config.Network)
 	//f, err := os.Open(file)
-        f, err := os.OpenFile(file, os.O_RDONLY, 0666)
+	f, err := os.OpenFile(file, os.O_RDONLY, 0666)
 	if err != nil {
 		fmt.Println("trouble opening file")
 		fmt.Println(err)
@@ -233,153 +236,156 @@ func(config *ClientConfig) ReadConfig() {
 		}
 	}
 }
-func ModGlobalConfig(cfg models.IntClient) error{
-        var modconfig GlobalConfig
-        var err error
-        if FileExists("/etc/netclient/netconfig-global-001") {
-                useconfig, err := ReadGlobalConfig()
-                if err != nil {
-                        return err
-                }
-                modconfig = *useconfig
-        }
-        if cfg.ServerWGPort != ""{
-                modconfig.Client.ServerWGPort = cfg.ServerWGPort
-        }
-        if cfg.ServerGRPCPort != ""{
-                modconfig.Client.ServerGRPCPort = cfg.ServerGRPCPort
-        }
-        if cfg.ServerAPIPort != ""{
-                modconfig.Client.ServerAPIPort = cfg.ServerAPIPort
-        }
-        if cfg.PublicKey != ""{
-                modconfig.Client.PublicKey = cfg.PublicKey
-        }
-        if cfg.PrivateKey != ""{
-                modconfig.Client.PrivateKey = cfg.PrivateKey
-        }
-        if cfg.ServerPublicEndpoint != ""{
-                modconfig.Client.ServerPublicEndpoint = cfg.ServerPublicEndpoint
-        }
-        if cfg.ServerPrivateAddress != ""{
-                modconfig.Client.ServerPrivateAddress = cfg.ServerPrivateAddress
-        }
-	if cfg.Address != ""{
-                modconfig.Client.Address = cfg.Address
-        }
-        if cfg.Address6 != ""{
-                modconfig.Client.Address6 = cfg.Address6
-        }
-        if cfg.Network != ""{
-                modconfig.Client.Network = cfg.Network
-        }
-        if cfg.ServerKey != ""{
-                modconfig.Client.ServerKey = cfg.ServerKey
-        }
-        if cfg.AccessKey != ""{
-                modconfig.Client.AccessKey = cfg.AccessKey
-        }
-        if cfg.ClientID != ""{
-                modconfig.Client.ClientID = cfg.ClientID
-        }
-
-        err = WriteGlobal(&modconfig)
-        return err
+func ModGlobalConfig(cfg models.IntClient) error {
+	var modconfig GlobalConfig
+	var err error
+	if FileExists("/etc/netclient/netconfig-global-001") {
+		useconfig, err := ReadGlobalConfig()
+		if err != nil {
+			return err
+		}
+		modconfig = *useconfig
+	}
+	if cfg.ServerWGPort != "" {
+		modconfig.Client.ServerWGPort = cfg.ServerWGPort
+	}
+	if cfg.ServerGRPCPort != "" {
+		modconfig.Client.ServerGRPCPort = cfg.ServerGRPCPort
+	}
+	if cfg.ServerAPIPort != "" {
+		modconfig.Client.ServerAPIPort = cfg.ServerAPIPort
+	}
+	if cfg.PublicKey != "" {
+		modconfig.Client.PublicKey = cfg.PublicKey
+	}
+	if cfg.PrivateKey != "" {
+		modconfig.Client.PrivateKey = cfg.PrivateKey
+	}
+	if cfg.ServerPublicEndpoint != "" {
+		modconfig.Client.ServerPublicEndpoint = cfg.ServerPublicEndpoint
+	}
+	if cfg.ServerPrivateAddress != "" {
+		modconfig.Client.ServerPrivateAddress = cfg.ServerPrivateAddress
+	}
+	if cfg.Address != "" {
+		modconfig.Client.Address = cfg.Address
+	}
+	if cfg.Address6 != "" {
+		modconfig.Client.Address6 = cfg.Address6
+	}
+	if cfg.Network != "" {
+		modconfig.Client.Network = cfg.Network
+	}
+	if cfg.ServerKey != "" {
+		modconfig.Client.ServerKey = cfg.ServerKey
+	}
+	if cfg.AccessKey != "" {
+		modconfig.Client.AccessKey = cfg.AccessKey
+	}
+	if cfg.ClientID != "" {
+		modconfig.Client.ClientID = cfg.ClientID
+	}
+	err = WriteGlobal(&modconfig)
+	return err
 }
 
-
-
-func ModConfig(node *nodepb.Node) error{
-        network := node.Nodenetwork
-        if network == "" {
-                return errors.New("No Network Provided")
-        }
+func ModConfig(node *nodepb.Node) error {
+	network := node.Nodenetwork
+	if network == "" {
+		return errors.New("No Network Provided")
+	}
 	var modconfig ClientConfig
 	var err error
-	if FileExists("/etc/netclient/netconfig-"+network) {
+	if FileExists("/etc/netclient/netconfig-" + network) {
 		useconfig, err := ReadConfig(network)
 		if err != nil {
 			return err
 		}
 		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 := 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.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"
+		nodecfg.IsIngressGateway = "no"
 	}
-        if node.Localrange != "" && node.Islocal {
-                nodecfg.IsLocal = "yes"
-                nodecfg.LocalRange = node.Localrange
-        }
-        modconfig.Node = nodecfg
-        err = Write(&modconfig, network)
-        return err
+	if node.Localrange != "" && node.Islocal {
+		nodecfg.IsLocal = "yes"
+		nodecfg.LocalRange = node.Localrange
+	}
+	modconfig.Node = nodecfg
+	err = Write(&modconfig, network)
+	return err
 }
 
-func GetCLIConfig(c *cli.Context) (ClientConfig, error){
+func GetCLIConfig(c *cli.Context) (ClientConfig, error) {
 	var cfg ClientConfig
 	if c.String("token") != "" {
-                tokenbytes, err := base64.StdEncoding.DecodeString(c.String("token"))
-                if err  != nil {
+		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 )
+			log.Println("error converting token json to object", tokenbytes)
 			return cfg, err
 		}
 
@@ -391,17 +397,17 @@ func GetCLIConfig(c *cli.Context) (ClientConfig, error){
 				cfg.Server.APIAddress = cfg.Server.APIAddress + ":" + accesstoken.ServerConfig.APIPort
 			}
 		}
-                if accesstoken.ServerConfig.GRPCConnString != "" {
-                        cfg.Server.GRPCAddress = accesstoken.ServerConfig.GRPCConnString
-                } else {
-                        cfg.Server.GRPCAddress = accesstoken.ServerConfig.GRPCHost
-                        if accesstoken.ServerConfig.GRPCPort != "" {
-                                cfg.Server.GRPCAddress = cfg.Server.GRPCAddress + ":" + accesstoken.ServerConfig.GRPCPort
-                        }
-                }
-                cfg.Network = accesstoken.ClientConfig.Network
-                cfg.Node.Network = accesstoken.ClientConfig.Network
-                cfg.Server.AccessKey = accesstoken.ClientConfig.Key
+		if accesstoken.ServerConfig.GRPCConnString != "" {
+			cfg.Server.GRPCAddress = accesstoken.ServerConfig.GRPCConnString
+		} else {
+			cfg.Server.GRPCAddress = accesstoken.ServerConfig.GRPCHost
+			if accesstoken.ServerConfig.GRPCPort != "" {
+				cfg.Server.GRPCAddress = cfg.Server.GRPCAddress + ":" + accesstoken.ServerConfig.GRPCPort
+			}
+		}
+		cfg.Network = accesstoken.ClientConfig.Network
+		cfg.Node.Network = accesstoken.ClientConfig.Network
+		cfg.Server.AccessKey = accesstoken.ClientConfig.Key
 		cfg.Node.LocalRange = accesstoken.ClientConfig.LocalRange
 		cfg.Server.GRPCSSL = accesstoken.ServerConfig.GRPCSSL
 		cfg.Server.GRPCWireGuard = accesstoken.WG.GRPCWireGuard
@@ -409,9 +415,9 @@ func GetCLIConfig(c *cli.Context) (ClientConfig, error){
 		if c.String("grpcserver") != "" {
 			cfg.Server.GRPCAddress = c.String("grpcserver")
 		}
-                if c.String("apiserver") != "" {
-                        cfg.Server.APIAddress = c.String("apiserver")
-                }
+		if c.String("apiserver") != "" {
+			cfg.Server.APIAddress = c.String("apiserver")
+		}
 		if c.String("key") != "" {
 			cfg.Server.AccessKey = c.String("key")
 		}
@@ -422,26 +428,26 @@ func GetCLIConfig(c *cli.Context) (ClientConfig, error){
 		if c.String("localrange") != "" {
 			cfg.Node.LocalRange = c.String("localrange")
 		}
-                if c.String("grpcssl") != "" {
-                        cfg.Server.GRPCSSL = c.String("grpcssl")
-                }
-                if c.String("corednsaddr") != "" {
-                        cfg.Server.CoreDNSAddr = c.String("corednsaddr")
-                }
-                if c.String("grpcwg") != "" {
-                        cfg.Server.GRPCWireGuard = c.String("grpcwg")
-                }
+		if c.String("grpcssl") != "" {
+			cfg.Server.GRPCSSL = c.String("grpcssl")
+		}
+		if c.String("corednsaddr") != "" {
+			cfg.Server.CoreDNSAddr = c.String("corednsaddr")
+		}
+		if c.String("grpcwg") != "" {
+			cfg.Server.GRPCWireGuard = c.String("grpcwg")
+		}
 
 	} else {
 		cfg.Server.GRPCAddress = c.String("grpcserver")
 		cfg.Server.APIAddress = c.String("apiserver")
 		cfg.Server.AccessKey = c.String("key")
-                cfg.Network = c.String("network")
-                cfg.Node.Network = c.String("network")
-                cfg.Node.LocalRange = c.String("localrange")
-                cfg.Server.GRPCWireGuard = c.String("grpcwg")
-                cfg.Server.GRPCSSL = c.String("grpcssl")
-                cfg.Server.CoreDNSAddr = c.String("corednsaddr")
+		cfg.Network = c.String("network")
+		cfg.Node.Network = c.String("network")
+		cfg.Node.LocalRange = c.String("localrange")
+		cfg.Server.GRPCWireGuard = c.String("grpcwg")
+		cfg.Server.GRPCSSL = c.String("grpcssl")
+		cfg.Server.CoreDNSAddr = c.String("corednsaddr")
 	}
 	cfg.Node.Name = c.String("name")
 	cfg.Node.Interface = c.String("interface")
@@ -464,11 +470,12 @@ func GetCLIConfig(c *cli.Context) (ClientConfig, error){
 	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){
+func GetCLIConfigRegister(c *cli.Context) (GlobalConfig, error) {
 	var cfg GlobalConfig
 	if c.String("token") != "" {
 		tokenbytes, err := base64.StdEncoding.DecodeString(c.String("token"))
@@ -476,11 +483,11 @@ func GetCLIConfigRegister(c *cli.Context) (GlobalConfig, error){
 			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
-                }
+		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
@@ -488,54 +495,53 @@ func GetCLIConfigRegister(c *cli.Context) (GlobalConfig, error){
 			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
-                        }
-                }
+		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")
+		cfg.Client.ServerKey = accesstoken.WG.GRPCWGPubKey
 
-        return cfg, nil
-}
+		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
+}
 
 func ReadConfig(network string) (*ClientConfig, error) {
-        if network == "" {
-                err := errors.New("No network provided. Exiting.")
-                return nil, err
-        }
+	if network == "" {
+		err := errors.New("No network provided. Exiting.")
+		return nil, err
+	}
 	nofile := false
 	home := "/etc/netclient"
 	file := fmt.Sprintf(home + "/netconfig-" + network)
@@ -560,33 +566,33 @@ func ReadConfig(network string) (*ClientConfig, error) {
 }
 
 func ReadGlobalConfig() (*GlobalConfig, error) {
-        nofile := false
-        home := "/etc/netclient"
-        file := fmt.Sprintf(home + "/netconfig-global-001")
-        f, err := os.Open(file)
+	nofile := false
+	home := "/etc/netclient"
+	file := fmt.Sprintf(home + "/netconfig-global-001")
+	f, err := os.Open(file)
 
-        if err != nil {
-                nofile = true
-        }
-        defer f.Close()
+	if err != nil {
+		nofile = true
+	}
+	defer f.Close()
 
-        var cfg GlobalConfig
+	var cfg GlobalConfig
 
-        if !nofile {
-                decoder := yaml.NewDecoder(f)
-                err = decoder.Decode(&cfg)
-                if err != nil {
-                        fmt.Println("trouble decoding file")
-                        return nil, err
-                }
-        }
-        return &cfg, err
+	if !nofile {
+		decoder := yaml.NewDecoder(f)
+		err = decoder.Decode(&cfg)
+		if err != nil {
+			fmt.Println("trouble decoding file")
+			return nil, err
+		}
+	}
+	return &cfg, 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()
 }

+ 2 - 2
netclient/functions/checkin.go

@@ -237,7 +237,7 @@ func CheckIn(cliconf config.ClientConfig) error {
                 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,
                         }
@@ -252,7 +252,7 @@ func CheckIn(cliconf config.ClientConfig) error {
 			return err
                         log.Fatalf("Error: %v", err)
                 }
-		err = wireguard.SetWGConfig(network)
+		//err = wireguard.SetWGConfig(network)
                 if err != nil {
 			return err
                         log.Fatalf("Error: %v", err)

+ 126 - 124
netclient/functions/join.go

@@ -1,23 +1,24 @@
 package functions
 
 import (
-	"google.golang.org/grpc/credentials"
+	"context"
 	"crypto/tls"
-	"fmt"
 	"errors"
-	"context"
+	"fmt"
 	"log"
-	"net"
 	"math/rand"
+	"net"
 	"time"
-        "github.com/gravitl/netmaker/netclient/config"
-        "github.com/gravitl/netmaker/netclient/wireguard"
-        "github.com/gravitl/netmaker/netclient/server"
-        "github.com/gravitl/netmaker/netclient/local"
-        nodepb "github.com/gravitl/netmaker/grpc"
+
+	nodepb "github.com/gravitl/netmaker/grpc"
+	"github.com/gravitl/netmaker/netclient/config"
+	"github.com/gravitl/netmaker/netclient/local"
+	"github.com/gravitl/netmaker/netclient/server"
+	"github.com/gravitl/netmaker/netclient/wireguard"
 	"golang.zx2c4.com/wireguard/wgctrl"
-        "google.golang.org/grpc"
 	"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
+	"google.golang.org/grpc"
+	"google.golang.org/grpc/credentials"
 	//homedir "github.com/mitchellh/go-homedir"
 )
 
@@ -25,7 +26,7 @@ func JoinNetwork(cfg config.ClientConfig) error {
 
 	hasnet := local.HasNetwork(cfg.Network)
 	if hasnet {
-		   err := errors.New("ALREADY_INSTALLED. Netclient appears to already be installed for " + cfg.Network + ". To re-install, please remove by executing 'sudo netclient leave -n " + cfg.Network + "'. Then re-run the install command.")
+		err := errors.New("ALREADY_INSTALLED. Netclient appears to already be installed for " + cfg.Network + ". To re-install, please remove by executing 'sudo netclient leave -n " + cfg.Network + "'. Then re-run the install command.")
 		return err
 	}
 	log.Println("attempting to join " + cfg.Network + " at " + cfg.Server.GRPCAddress)
@@ -34,73 +35,73 @@ func JoinNetwork(cfg config.ClientConfig) error {
 		return err
 	}
 
-        wgclient, err := wgctrl.New()
-        if err != nil {
+	wgclient, err := wgctrl.New()
+	if err != nil {
 		return err
-        }
-        defer wgclient.Close()
+	}
+	defer wgclient.Close()
 	if cfg.Node.Network == "" {
 		return errors.New("no network provided")
 	}
 	if cfg.Node.LocalRange != "" {
-	if cfg.Node.LocalAddress == "" {
-		log.Println("local vpn, getting local address from range: " + cfg.Node.LocalRange)
-		ifaces, err := net.Interfaces()
-                if err != nil {
-                        return err
-                }
-		_, localrange, err := net.ParseCIDR(cfg.Node.LocalRange)
-		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
+		if cfg.Node.LocalAddress == "" {
+			log.Println("local vpn, getting local address from range: " + cfg.Node.LocalRange)
+			ifaces, err := net.Interfaces()
+			if err != nil {
+				return err
 			}
-			addrs, err := i.Addrs()
+			_, localrange, err := net.ParseCIDR(cfg.Node.LocalRange)
 			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()
-						if cfg.Node.IsLocal == "yes" {
-							found = localrange.Contains(ip)
-						} else {
-							found = true
+
+			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()
+							if cfg.Node.IsLocal == "yes" {
+								found = localrange.Contains(ip)
+							} else {
+								found = true
+							}
 						}
-					}
-				case *net.IPAddr:
-					if  !found {
-						ip = v.IP
-						local = ip.String()
-						if cfg.Node.IsLocal == "yes" {
-							found = localrange.Contains(ip)
+					case *net.IPAddr:
+						if !found {
+							ip = v.IP
+							local = ip.String()
+							if cfg.Node.IsLocal == "yes" {
+								found = localrange.Contains(ip)
 
-						} else {
-							found = true
+							} else {
+								found = true
+							}
 						}
 					}
 				}
 			}
+			cfg.Node.LocalAddress = local
 		}
-		cfg.Node.LocalAddress = local
-	}
 	}
 	if cfg.Node.Password == "" {
 		cfg.Node.Password = GenPass()
 	}
-        if cfg.Node.Endpoint == "" {
+	if cfg.Node.Endpoint == "" {
 		if cfg.Node.IsLocal == "yes" && cfg.Node.LocalAddress != "" {
 			cfg.Node.Endpoint = cfg.Node.LocalAddress
 		} else {
@@ -111,9 +112,9 @@ func JoinNetwork(cfg config.ClientConfig) error {
 				return err
 			}
 		}
-        } else {
-                cfg.Node.Endpoint = cfg.Node.Endpoint
-        }
+	} else {
+		cfg.Node.Endpoint = cfg.Node.Endpoint
+	}
 	if cfg.Node.PrivateKey == "" {
 		privatekey, err := wgtypes.GeneratePrivateKey()
 		if err != nil {
@@ -130,7 +131,7 @@ func JoinNetwork(cfg config.ClientConfig) error {
 		} else if len(macs) == 0 {
 			log.Fatal()
 		} else {
-			cfg.Node.MacAddress  = macs[0]
+			cfg.Node.MacAddress = macs[0]
 		}
 	}
 	if cfg.Node.Port == 0 {
@@ -148,48 +149,50 @@ func JoinNetwork(cfg config.ClientConfig) error {
 	}
 	conn, err := grpc.Dial(cfg.Server.GRPCAddress, requestOpts)
 
-        if err != nil {
-                log.Fatalf("Unable to establish client connection to " + cfg.Server.GRPCAddress + ": %v", err)
-        }
+	if err != nil {
+		log.Fatalf("Unable to establish client connection to "+cfg.Server.GRPCAddress+": %v", err)
+	}
 
-        wcclient = nodepb.NewNodeServiceClient(conn)
+	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,
+	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,
-        }
-        err = config.ModConfig(postnode)
-        if err != nil {
+		Interface:    cfg.Node.Interface,
+		Publickey:    cfg.Node.PublicKey,
+		Name:         cfg.Node.Name,
+		Endpoint:     cfg.Node.Endpoint,
+		Saveconfig:     cfg.Node.SaveConfig,
+		Udpholepunch:     cfg.Node.UDPHolePunch,
+	}
+	err = config.ModConfig(postnode)
+	if err != nil {
 		return err
-        }
+	}
 
-        res, err := wcclient.CreateNode(
-                context.TODO(),
-                &nodepb.CreateNodeReq{
-                        Node: postnode,
-                },
-        )
-        if err != nil {
-                return err
-        }
+	res, err := wcclient.CreateNode(
+		context.TODO(),
+		&nodepb.CreateNodeReq{
+			Node: postnode,
+		},
+	)
+	if err != nil {
+		return err
+	}
 	log.Println("node created on remote server...updating configs")
-        node := res.Node
-        if err != nil {
-                return err
-        }
+	node := res.Node
+	if err != nil {
+		return err
+	}
 
-       if node.Dnsoff==true  {
+	if node.Dnsoff == true {
 		cfg.Node.DNS = "yes"
 	}
 	if !(cfg.Node.IsLocal == "yes") && node.Islocal && node.Localrange != "" {
@@ -199,15 +202,15 @@ func JoinNetwork(cfg config.ClientConfig) error {
 		}
 		node.Endpoint = node.Localaddress
 	}
-        err = config.ModConfig(node)
-        if err != nil {
-                return err
-        }
+	err = config.ModConfig(node)
+	if err != nil {
+		return err
+	}
 
 	if node.Ispending {
 		fmt.Println("Node is marked as PENDING.")
 		fmt.Println("Awaiting approval from Admin before configuring WireGuard.")
-	        if cfg.Daemon != "off" {
+		if cfg.Daemon != "off" {
 			err = local.ConfigureSystemD(cfg.Network)
 			return err
 		}
@@ -217,23 +220,23 @@ func JoinNetwork(cfg config.ClientConfig) error {
 
 	if err != nil {
 		log.Println("failed to retrieve peers")
-                return err
-        }
+		return err
+	}
 	err = wireguard.StorePrivKey(cfg.Node.PrivateKey, cfg.Network)
-        if err != nil {
-                return err
-        }
-        log.Println("starting wireguard")
+	if err != nil {
+		return err
+	}
+	log.Println("starting wireguard")
 	err = wireguard.InitWireguard(node, cfg.Node.PrivateKey, peers, hasGateway, gateways)
-        if err != nil {
-                return err
-        }
+	if err != nil {
+		return err
+	}
 	if cfg.Daemon != "off" {
 		err = local.ConfigureSystemD(cfg.Network)
 	}
-        if err != nil {
-                return err
-        }
+	if err != nil {
+		return err
+	}
 
 	return err
 }
@@ -241,16 +244,15 @@ func JoinNetwork(cfg config.ClientConfig) error {
 //generate an access key value
 func GenPass() string {
 
-        var seededRand *rand.Rand = rand.New(
-                rand.NewSource(time.Now().UnixNano()))
+	var seededRand *rand.Rand = rand.New(
+		rand.NewSource(time.Now().UnixNano()))
 
-        length := 16
-        charset := "abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
+	length := 16
+	charset := "abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
 
-        b := make([]byte, length)
-        for i := range b {
-                b[i] = charset[seededRand.Intn(len(charset))]
-        }
-        return string(b)
+	b := make([]byte, length)
+	for i := range b {
+		b[i] = charset[seededRand.Intn(len(charset))]
+	}
+	return string(b)
 }
-

+ 2 - 2
netclient/local/dns.go

@@ -40,12 +40,12 @@ func UpdateDNS(ifacename string, network string, nameserver string) error {
                         _, err = exec.Command("resolvectl", "domain", ifacename, "~"+network).Output()
                         if err != nil {
                                 log.Println(err)
-                                log.Println("WARNING: Error encountered setting dns. Aborted setting dns.")
+                                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 dns. Aborted setting dns.")
+                                        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 {

+ 370 - 364
netclient/main.go

@@ -1,379 +1,385 @@
 package main
 
 import (
-    "errors"
-    "github.com/gravitl/netmaker/netclient/command"
-    "github.com/gravitl/netmaker/netclient/config"
-    "github.com/urfave/cli/v2"
-    "log"
-    "os"
-    "os/exec"
-    "strconv"
+	"errors"
+	"log"
+	"os"
+	"os/exec"
+	"strconv"
+
+	"github.com/gravitl/netmaker/netclient/command"
+	"github.com/gravitl/netmaker/netclient/config"
+	"github.com/urfave/cli/v2"
 )
 
 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"
-
-    cliFlags := []cli.Flag{
-        &cli.StringFlag{
-            Name:  "network",
-            Aliases: []string{"n"},
-            EnvVars: []string{"NETCLIENT_NETWORK"},
-	    Value: "all",
-	    Usage: "Network to perform specified action against.",
-        },
-        &cli.StringFlag{
-            Name:  "password",
-            Aliases: []string{"p"},
-            EnvVars: []string{"NETCLIENT_PASSWORD"},
-            Value: "badpassword",
-            Usage: "Password for authenticating with netmaker.",
-        },
-        &cli.StringFlag{
-            Name:  "endpoint",
-            Aliases: []string{"e"},
-            EnvVars: []string{"NETCLIENT_ENDPOINT"},
-            Value: "",
-            Usage: "Reachable (usually public) address for WireGuard (not the private WG address).",
-        },
-        &cli.StringFlag{
-            Name:  "macaddress",
-            Aliases: []string{"m"},
-            EnvVars: []string{"NETCLIENT_MACADDRESS"},
-            Value: "",
-            Usage: "Mac Address for this machine. Used as a unique identifier within Netmaker network.",
-        },
-        &cli.StringFlag{
-            Name:  "publickey",
-            Aliases: []string{"pubkey"},
-            EnvVars: []string{"NETCLIENT_PUBLICKEY"},
-            Value: "",
-            Usage: "Public Key for WireGuard Interface.",
-        },
-        &cli.StringFlag{
-            Name:  "privatekey",
-            Aliases: []string{"privkey"},
-            EnvVars: []string{"NETCLIENT_PRIVATEKEY"},
-            Value: "",
-            Usage: "Private Key for WireGuard Interface.",
-        },
-        &cli.StringFlag{
-            Name:  "port",
-            EnvVars: []string{"NETCLIENT_PORT"},
-            Value: "",
-            Usage: "Port for WireGuard Interface.",
-        },
-        &cli.IntFlag{
-            Name:  "keepalive",
-            EnvVars: []string{"NETCLIENT_KEEPALIVE"},
-            Value: 0,
-            Usage: "Default PersistentKeepAlive for Peers in WireGuard Interface.",
-        },
-        &cli.StringFlag{
-            Name:  "operatingsystem",
-            Aliases: []string{"os"},
-            EnvVars: []string{"NETCLIENT_OS"},
-            Value: "",
-            Usage: "Identifiable name for machine within Netmaker network.",
-        },
-        &cli.StringFlag{
-            Name:  "name",
-            EnvVars: []string{"NETCLIENT_NAME"},
-            Value: "",
-            Usage: "Identifiable name for machine within Netmaker network.",
-        },
-        &cli.StringFlag{
-            Name:  "localaddress",
-            EnvVars: []string{"NETCLIENT_LOCALADDRESS"},
-            Value: "",
-            Usage: "Local address for machine. Can be used in place of Endpoint for machines on the same LAN.",
-        },
-        &cli.StringFlag{
-            Name:  "address",
-            Aliases: []string{"a"},
-            EnvVars: []string{"NETCLIENT_ADDRESS"},
-            Value: "",
-            Usage: "WireGuard address for machine within Netmaker network.",
-        },
-        &cli.StringFlag{
-            Name:  "addressIPv6",
-            Aliases: []string{"a6"},
-            EnvVars: []string{"NETCLIENT_ADDRESSIPV6"},
-            Value: "",
-            Usage: "WireGuard address for machine within Netmaker network.",
-        },
-        &cli.StringFlag{
-            Name:  "interface",
-            Aliases: []string{"i"},
-            EnvVars: []string{"NETCLIENT_INTERFACE"},
-            Value: "",
-            Usage: "WireGuard local network interface name.",
-        },
-        &cli.StringFlag{
-            Name:  "apiserver",
-            EnvVars: []string{"NETCLIENT_API_SERVER"},
-            Value: "",
-	    Usage: "Address + GRPC Port (e.g. 1.2.3.4:50051) of Netmaker server.",
-        },
-        &cli.StringFlag{
-            Name:  "grpcserver",
-            EnvVars: []string{"NETCLIENT_GRPC_SERVER"},
-            Value: "",
-            Usage: "Address + API Port (e.g. 1.2.3.4:8081) of Netmaker server.",
-        },
-        &cli.StringFlag{
-            Name:  "key",
-            Aliases: []string{"k"},
-            EnvVars: []string{"NETCLIENT_ACCESSKEY"},
-            Value: "",
-            Usage: "Access Key for signing up machine with Netmaker server during initial 'add'.",
-        },
-        &cli.StringFlag{
-            Name:  "token",
-            Aliases: []string{"t"},
-            EnvVars: []string{"NETCLIENT_ACCESSTOKEN"},
-            Value: "",
-            Usage: "Access Token for signing up machine with Netmaker server during initial 'add'.",
-        },
-        &cli.StringFlag{
-            Name:  "localrange",
-            EnvVars: []string{"NETCLIENT_LOCALRANGE"},
-            Value: "",
-            Usage: "Local Range if network is local, for instance 192.168.1.0/24.",
-        },
-        &cli.StringFlag{
-            Name:  "dns",
-            EnvVars: []string{"NETCLIENT_DNS"},
-            Value: "on",
-            Usage: "Sets private dns if 'on'. Ignores if 'off'. Will retrieve from network if unset.",
-        },
-        &cli.StringFlag{
-            Name:  "islocal",
-            EnvVars: []string{"NETCLIENT_IS_LOCAL"},
-            Value: "",
-            Usage: "Sets endpoint to local address if 'yes'. Ignores if 'no'. Will retrieve from network if unset.",
-        },
-        &cli.StringFlag{
-            Name:  "isdualstack",
-            EnvVars: []string{"NETCLIENT_IS_DUALSTACK"},
-            Value: "",
-            Usage: "Sets ipv6 address if 'yes'. Ignores if 'no'. Will retrieve from network if unset.",
-        },
-        &cli.StringFlag{
-            Name:  "ipforwarding",
-            EnvVars: []string{"NETCLIENT_IPFORWARDING"},
-            Value: "on",
-	    Usage: "Sets ip forwarding on if 'on'. Ignores if 'off'. On by default.",
-        },
-        &cli.StringFlag{
-            Name:  "postup",
-            EnvVars: []string{"NETCLIENT_POSTUP"},
-            Value: "",
-            Usage: "Sets PostUp command for WireGuard.",
-        },
-        &cli.StringFlag{
-            Name:  "postdown",
-            EnvVars: []string{"NETCLIENT_POSTDOWN"},
-            Value: "",
-            Usage: "Sets PostDown command for WireGuard.",
-        },
-        &cli.StringFlag{
-            Name:  "daemon",
-            EnvVars: []string{"NETCLIENT_DAEMON"},
-            Value: "on",
-            Usage: "Installs daemon if 'on'. Ignores if 'off'. On by default.",
-        },
-        &cli.StringFlag{
-            Name:  "roaming",
-            EnvVars: []string{"NETCLIENT_ROAMING"},
-            Value: "on",
-            Usage: "Checks for IP changes if 'on'. Ignores if 'off'. On by default.",
-        },
-    }
+	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.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)
-		if err != nil {
-			return err
-		}
-		if cfg.Network == "all" {
-			err = errors.New("No network provided.")
-			return err
-		}
-                if cfg.Server.GRPCAddress == "" {
-                        err = errors.New("No server address provided.")
-                        return err
-                }
-		err = command.Join(cfg)
-                return err
-            },
-        },
-        {
-            Name:  "leave",
-            Usage: "Leave a Netmaker network.",
-            Flags: cliFlags,
-            // the action, or code that will be executed when
-            // we execute our `ns` command
-            Action: func(c *cli.Context) error {
-                cfg, err := config.GetCLIConfig(c)
-                if err != nil {
-                        return err
-                }
-                err = command.Leave(cfg)
-                return err
-            },
-        },
-        {
-            Name:  "checkin",
-            Usage: "Checks for local changes and then checks into the specified Netmaker network to ask about remote changes.",
-            Flags: cliFlags,
-            // the action, or code that will be executed when
-            // we execute our `ns` command
-            Action: func(c *cli.Context) error {
-                cfg, err := config.GetCLIConfig(c)
-                if err != nil {
-                        return err
-                }
-                err = command.CheckIn(cfg)
-                return err
-            },
-        },
-        {
-            Name:  "push",
-            Usage: "Push configuration changes to server.",
-            Flags: cliFlags,
-            // the action, or code that will be executed when
-            // we execute our `ns` command
-            Action: func(c *cli.Context) error {
-                cfg, err := config.GetCLIConfig(c)
-                if err != nil {
-                        return err
-                }
-                err = command.Push(cfg)
-                return err
-            },
-        },
-        {
-            Name:  "pull",
-            Usage: "Pull latest configuration and peers from server.",
-            Flags: cliFlags,
-            // the action, or code that will be executed when
-            // we execute our `ns` command
-            Action: func(c *cli.Context) error {
-                cfg, err := config.GetCLIConfig(c)
-                if err != nil {
-                        return err
-                }
-                err = command.Pull(cfg)
-                return err
-            },
-        },
-        {
-            Name:  "list",
-            Usage: "Get list of networks.",
-            Flags: cliFlags,
-            // the action, or code that will be executed when
-            // we execute our `ns` command
-            Action: func(c *cli.Context) error {
-                cfg, err := config.GetCLIConfig(c)
-                if err != nil {
-                        return err
-                }
-                err = command.List(cfg)
-                return err
-            },
-        },
-        {
-            Name:  "uninstall",
-            Usage: "Uninstall the netclient system service.",
-            Flags: cliFlags,
-            // the action, or code that will be executed when
-            // we execute our `ns` command
-            Action: func(c *cli.Context) error {
-                cfg, err := config.ReadGlobalConfig()
-                if err != nil {
-                        return err
-                }
-                var gconf config.GlobalConfig
-		gconf = *cfg
-		err = command.Uninstall(gconf)
-                return err
-            },
-        },
-        {
-            Name:  "unregister",
-            Usage: "Unregister the netclient from secure server GRPC.",
-            Flags: cliFlags,
-            // the action, or code that will be executed when
-            // we execute our `ns` command
-            Action: func(c *cli.Context) error {
-                cfg, err := config.ReadGlobalConfig()
-                if err != nil {
-                        return err
-                }
-                var gconf config.GlobalConfig
-                gconf = *cfg
-                err = command.Unregister(gconf)
-                return err
-            },
-        },
-    }
+	cliFlags := []cli.Flag{
+		&cli.StringFlag{
+			Name:    "network",
+			Aliases: []string{"n"},
+			EnvVars: []string{"NETCLIENT_NETWORK"},
+			Value:   "all",
+			Usage:   "Network to perform specified action against.",
+		},
+		&cli.StringFlag{
+			Name:    "password",
+			Aliases: []string{"p"},
+			EnvVars: []string{"NETCLIENT_PASSWORD"},
+			Value:   "badpassword",
+			Usage:   "Password for authenticating with netmaker.",
+		},
+		&cli.StringFlag{
+			Name:    "endpoint",
+			Aliases: []string{"e"},
+			EnvVars: []string{"NETCLIENT_ENDPOINT"},
+			Value:   "",
+			Usage:   "Reachable (usually public) address for WireGuard (not the private WG address).",
+		},
+		&cli.StringFlag{
+			Name:    "macaddress",
+			Aliases: []string{"m"},
+			EnvVars: []string{"NETCLIENT_MACADDRESS"},
+			Value:   "",
+			Usage:   "Mac Address for this machine. Used as a unique identifier within Netmaker network.",
+		},
+		&cli.StringFlag{
+			Name:    "publickey",
+			Aliases: []string{"pubkey"},
+			EnvVars: []string{"NETCLIENT_PUBLICKEY"},
+			Value:   "",
+			Usage:   "Public Key for WireGuard Interface.",
+		},
+		&cli.StringFlag{
+			Name:    "privatekey",
+			Aliases: []string{"privkey"},
+			EnvVars: []string{"NETCLIENT_PRIVATEKEY"},
+			Value:   "",
+			Usage:   "Private Key for WireGuard Interface.",
+		},
+		&cli.StringFlag{
+			Name:    "port",
+			EnvVars: []string{"NETCLIENT_PORT"},
+			Value:   "",
+			Usage:   "Port for WireGuard Interface.",
+		},
+		&cli.IntFlag{
+			Name:    "keepalive",
+			EnvVars: []string{"NETCLIENT_KEEPALIVE"},
+			Value:   0,
+			Usage:   "Default PersistentKeepAlive for Peers in WireGuard Interface.",
+		},
+		&cli.StringFlag{
+			Name:    "operatingsystem",
+			Aliases: []string{"os"},
+			EnvVars: []string{"NETCLIENT_OS"},
+			Value:   "",
+			Usage:   "Identifiable name for machine within Netmaker network.",
+		},
+		&cli.StringFlag{
+			Name:    "name",
+			EnvVars: []string{"NETCLIENT_NAME"},
+			Value:   "",
+			Usage:   "Identifiable name for machine within Netmaker network.",
+		},
+		&cli.StringFlag{
+			Name:    "localaddress",
+			EnvVars: []string{"NETCLIENT_LOCALADDRESS"},
+			Value:   "",
+			Usage:   "Local address for machine. Can be used in place of Endpoint for machines on the same LAN.",
+		},
+		&cli.StringFlag{
+			Name:    "address",
+			Aliases: []string{"a"},
+			EnvVars: []string{"NETCLIENT_ADDRESS"},
+			Value:   "",
+			Usage:   "WireGuard address for machine within Netmaker network.",
+		},
+		&cli.StringFlag{
+			Name:    "addressIPv6",
+			Aliases: []string{"a6"},
+			EnvVars: []string{"NETCLIENT_ADDRESSIPV6"},
+			Value:   "",
+			Usage:   "WireGuard address for machine within Netmaker network.",
+		},
+		&cli.StringFlag{
+			Name:    "interface",
+			Aliases: []string{"i"},
+			EnvVars: []string{"NETCLIENT_INTERFACE"},
+			Value:   "",
+			Usage:   "WireGuard local network interface name.",
+		},
+		&cli.StringFlag{
+			Name:    "apiserver",
+			EnvVars: []string{"NETCLIENT_API_SERVER"},
+			Value:   "",
+			Usage:   "Address + GRPC Port (e.g. 1.2.3.4:50051) of Netmaker server.",
+		},
+		&cli.StringFlag{
+			Name:    "grpcserver",
+			EnvVars: []string{"NETCLIENT_GRPC_SERVER"},
+			Value:   "",
+			Usage:   "Address + API Port (e.g. 1.2.3.4:8081) of Netmaker server.",
+		},
+		&cli.StringFlag{
+			Name:    "key",
+			Aliases: []string{"k"},
+			EnvVars: []string{"NETCLIENT_ACCESSKEY"},
+			Value:   "",
+			Usage:   "Access Key for signing up machine with Netmaker server during initial 'add'.",
+		},
+		&cli.StringFlag{
+			Name:    "token",
+			Aliases: []string{"t"},
+			EnvVars: []string{"NETCLIENT_ACCESSTOKEN"},
+			Value:   "",
+			Usage:   "Access Token for signing up machine with Netmaker server during initial 'add'.",
+		},
+		&cli.StringFlag{
+			Name:    "localrange",
+			EnvVars: []string{"NETCLIENT_LOCALRANGE"},
+			Value:   "",
+			Usage:   "Local Range if network is local, for instance 192.168.1.0/24.",
+		},
+		&cli.StringFlag{
+			Name:    "dns",
+			EnvVars: []string{"NETCLIENT_DNS"},
+			Value:   "on",
+			Usage:   "Sets private dns if 'on'. Ignores if 'off'. Will retrieve from network if unset.",
+		},
+		&cli.StringFlag{
+			Name:    "islocal",
+			EnvVars: []string{"NETCLIENT_IS_LOCAL"},
+			Value:   "",
+			Usage:   "Sets endpoint to local address if 'yes'. Ignores if 'no'. Will retrieve from network if unset.",
+		},
+		&cli.StringFlag{
+			Name:    "isdualstack",
+			EnvVars: []string{"NETCLIENT_IS_DUALSTACK"},
+			Value:   "",
+			Usage:   "Sets ipv6 address if 'yes'. Ignores if 'no'. Will retrieve from network if unset.",
+		},
+		&cli.StringFlag{
+			Name:    "udpholepunch",
+			EnvVars: []string{"NETCLIENT_UDP_HOLEPUNCH"},
+			Value:   "",
+			Usage:   "Turns on udp holepunching if 'yes'. Ignores if 'no'. Will retrieve from network if unset.",
+		},
+		&cli.StringFlag{
+			Name:    "ipforwarding",
+			EnvVars: []string{"NETCLIENT_IPFORWARDING"},
+			Value:   "on",
+			Usage:   "Sets ip forwarding on if 'on'. Ignores if 'off'. On by default.",
+		},
+		&cli.StringFlag{
+			Name:    "postup",
+			EnvVars: []string{"NETCLIENT_POSTUP"},
+			Value:   "",
+			Usage:   "Sets PostUp command for WireGuard.",
+		},
+		&cli.StringFlag{
+			Name:    "postdown",
+			EnvVars: []string{"NETCLIENT_POSTDOWN"},
+			Value:   "",
+			Usage:   "Sets PostDown command for WireGuard.",
+		},
+		&cli.StringFlag{
+			Name:    "daemon",
+			EnvVars: []string{"NETCLIENT_DAEMON"},
+			Value:   "on",
+			Usage:   "Installs daemon if 'on'. Ignores if 'off'. On by default.",
+		},
+		&cli.StringFlag{
+			Name:    "roaming",
+			EnvVars: []string{"NETCLIENT_ROAMING"},
+			Value:   "on",
+			Usage:   "Checks for IP changes if 'on'. Ignores if 'off'. On by default.",
+		},
+	}
 
-    // start our application
-         getID := exec.Command("id", "-u")
-         out, err := getID.Output()
+	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)
+				if err != nil {
+					return err
+				}
+				if cfg.Network == "all" {
+					err = errors.New("No network provided.")
+					return err
+				}
+				if cfg.Server.GRPCAddress == "" {
+					err = errors.New("No server address provided.")
+					return err
+				}
+				err = command.Join(cfg)
+				return err
+			},
+		},
+		{
+			Name:  "leave",
+			Usage: "Leave a Netmaker network.",
+			Flags: cliFlags,
+			// the action, or code that will be executed when
+			// we execute our `ns` command
+			Action: func(c *cli.Context) error {
+				cfg, err := config.GetCLIConfig(c)
+				if err != nil {
+					return err
+				}
+				err = command.Leave(cfg)
+				return err
+			},
+		},
+		{
+			Name:  "checkin",
+			Usage: "Checks for local changes and then checks into the specified Netmaker network to ask about remote changes.",
+			Flags: cliFlags,
+			// the action, or code that will be executed when
+			// we execute our `ns` command
+			Action: func(c *cli.Context) error {
+				cfg, err := config.GetCLIConfig(c)
+				if err != nil {
+					return err
+				}
+				err = command.CheckIn(cfg)
+				return err
+			},
+		},
+		{
+			Name:  "push",
+			Usage: "Push configuration changes to server.",
+			Flags: cliFlags,
+			// the action, or code that will be executed when
+			// we execute our `ns` command
+			Action: func(c *cli.Context) error {
+				cfg, err := config.GetCLIConfig(c)
+				if err != nil {
+					return err
+				}
+				err = command.Push(cfg)
+				return err
+			},
+		},
+		{
+			Name:  "pull",
+			Usage: "Pull latest configuration and peers from server.",
+			Flags: cliFlags,
+			// the action, or code that will be executed when
+			// we execute our `ns` command
+			Action: func(c *cli.Context) error {
+				cfg, err := config.GetCLIConfig(c)
+				if err != nil {
+					return err
+				}
+				err = command.Pull(cfg)
+				return err
+			},
+		},
+		{
+			Name:  "list",
+			Usage: "Get list of networks.",
+			Flags: cliFlags,
+			// the action, or code that will be executed when
+			// we execute our `ns` command
+			Action: func(c *cli.Context) error {
+				cfg, err := config.GetCLIConfig(c)
+				if err != nil {
+					return err
+				}
+				err = command.List(cfg)
+				return err
+			},
+		},
+		{
+			Name:  "uninstall",
+			Usage: "Uninstall the netclient system service.",
+			Flags: cliFlags,
+			// the action, or code that will be executed when
+			// we execute our `ns` command
+			Action: func(c *cli.Context) error {
+				cfg, err := config.ReadGlobalConfig()
+				if err != nil {
+					return err
+				}
+				var gconf config.GlobalConfig
+				gconf = *cfg
+				err = command.Uninstall(gconf)
+				return err
+			},
+		},
+		{
+			Name:  "unregister",
+			Usage: "Unregister the netclient from secure server GRPC.",
+			Flags: cliFlags,
+			// the action, or code that will be executed when
+			// we execute our `ns` command
+			Action: func(c *cli.Context) error {
+				cfg, err := config.ReadGlobalConfig()
+				if err != nil {
+					return err
+				}
+				var gconf config.GlobalConfig
+				gconf = *cfg
+				err = command.Unregister(gconf)
+				return err
+			},
+		},
+	}
 
-         if err != nil {
-                 log.Fatal(err)
-         }
-         id, err := strconv.Atoi(string(out[:len(out)-1]))
+	// start our application
+	getID := exec.Command("id", "-u")
+	out, err := getID.Output()
 
-         if err != nil {
-                 log.Fatal(err)
-         }
+	if err != nil {
+		log.Fatal(err)
+	}
+	id, err := strconv.Atoi(string(out[:len(out)-1]))
 
-         if id != 0 {
-                 log.Fatal("This program must be run with elevated privileges (sudo). This program installs a SystemD service and configures WireGuard and networking rules. Please re-run with sudo/root.")
-         }
+	if err != nil {
+		log.Fatal(err)
+	}
 
+	if id != 0 {
+		log.Fatal("This program must be run with elevated privileges (sudo). This program installs a SystemD service and configures WireGuard and networking rules. Please re-run with sudo/root.")
+	}
 
-        _, err = exec.LookPath("wg")
-        if err != nil {
-                log.Println(err)
-                log.Fatal("WireGuard not installed. Please install WireGuard (wireguard-tools) and try again.")
-        }
+	_, err = exec.LookPath("wg")
+	if err != nil {
+		log.Println(err)
+		log.Fatal("WireGuard not installed. Please install WireGuard (wireguard-tools) and try again.")
+	}
 
-    err = app.Run(os.Args)
-    if err != nil {
-        log.Fatal(err)
-    }
+	err = app.Run(os.Args)
+	if err != nil {
+		log.Fatal(err)
+	}
 }

+ 21 - 5
netclient/server/grpc.go

@@ -1,7 +1,8 @@
 package server
 
 import (
-        "google.golang.org/grpc/credentials"
+"github.com/davecgh/go-spew/spew"
+	"google.golang.org/grpc/credentials"
         "crypto/tls"
 	"fmt"
 	"context"
@@ -45,6 +46,8 @@ func GetNode(network string) nodepb.Node {
 	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 {
@@ -137,6 +140,7 @@ func GetPeers(macaddress string, network string, server string, dualstack bool,
         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)
         }
@@ -190,6 +194,7 @@ func GetPeers(macaddress string, network string, server string, dualstack bool,
                         return peers, hasGateway, gateways, err
                         }
                 }
+	        spew.Dump(res.Peers)
                 pubkey, err := wgtypes.ParseKey(res.Peers.Publickey)
                 if err != nil {
                         fmt.Println("error parsing key")
@@ -216,16 +221,20 @@ func GetPeers(macaddress string, network string, server string, dualstack bool,
                 allowedips = append(allowedips, peeraddr)
                 if res.Peers.Isegressgateway {
                         hasGateway = true
-                        gateways = append(gateways,res.Peers.Egressgatewayrange)
-                        _, ipnet, err := net.ParseCIDR(res.Peers.Egressgatewayrange)
+			log.Println(peeraddr.String(),"HAS GATEWAY",res.Peers.Egressgatewayranges)
+			ranges := strings.Split(res.Peers.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: "  + res.Peers.Egressgatewayrange)
+                                fmt.Println("    Gateway Range: "  + iprange)
                                 allowedips = append(allowedips, *ipnet)
                         }
+			}
                 }
                 if res.Peers.Address6 != "" && dualstack {
                         var addr6 = net.IPNet{
@@ -234,7 +243,14 @@ func GetPeers(macaddress string, network string, server string, dualstack bool,
                         }
                         allowedips = append(allowedips, addr6)
                 }
-                if keepalive != 0 {
+                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,

+ 290 - 285
netclient/wireguard/kernel.go

@@ -1,186 +1,184 @@
 package wireguard
 
 import (
-	//"github.com/davecgh/go-spew/spew"
-        "google.golang.org/grpc/credentials"
-        "crypto/tls"
-	"fmt"
-	"strconv"
-	"errors"
+	"github.com/davecgh/go-spew/spew"
 	"context"
-        "io/ioutil"
-	"strings"
+	"crypto/tls"
+	"errors"
+	"fmt"
+	"io/ioutil"
 	"log"
 	"net"
 	"os"
 	"os/exec"
-        "github.com/gravitl/netmaker/netclient/config"
-        "github.com/gravitl/netmaker/netclient/local"
-        "github.com/gravitl/netmaker/netclient/auth"
-        "github.com/gravitl/netmaker/netclient/server"
-        nodepb "github.com/gravitl/netmaker/grpc"
-        "github.com/gravitl/netmaker/models"
+	"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"
-        "google.golang.org/grpc"
-	"google.golang.org/grpc/metadata"
 	"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)
+	//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
-        }
+	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" )
+	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()
+	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 != "" {
+	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)
-                }
-        }
+		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 peeraddr = net.IPNet{
+		IP:   net.ParseIP(client.ServerPrivateAddress),
+		Mask: net.CIDRMask(32, 32),
+	}
 	var allowedips []net.IPNet
-        allowedips = append(allowedips, peeraddr)
+	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,
-        }
+		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
-                }
-        }
+	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
-        }
+	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 *nodepb.Node, privkey string, peers []wgtypes.PeerConfig, hasGateway bool, gateways []string) error {
 
-        //spew.Dump(node)
-        //spew.Dump(peers)
 	ipExec, err := exec.LookPath("ip")
-	if err !=  nil {
+	if err != nil {
 		return err
 	}
 	key, err := wgtypes.ParseKey(privkey)
-        if err !=  nil {
-                return err
-        }
+	if err != nil {
+		return err
+	}
 
-        wgclient, err := wgctrl.New()
-	//modcfg := config.Config
-	//modcfg.ReadConfig()
+	wgclient, err := wgctrl.New()
+	if err != nil {
+		return err
+	}
 	modcfg, err := config.ReadConfig(node.Nodenetwork)
 	if err != nil {
-                return err
-        }
-
-
+		return err
+	}
 	nodecfg := modcfg.Node
 	servercfg := modcfg.Server
 
-
-        if err != nil {
-                log.Fatalf("failed to open client: %v", err)
-        }
-        defer wgclient.Close()
+	if err != nil {
+		log.Fatalf("failed to open client: %v", err)
+	}
+	defer wgclient.Close()
 
 	ifacename := node.Interface
 	if nodecfg.Interface != "" {
 		ifacename = nodecfg.Interface
 	} else if node.Interface != "" {
 		ifacename = node.Interface
-	} else  {
+	} else {
 		log.Fatal("no interface to configure")
 	}
 	if node.Address == "" {
@@ -188,68 +186,75 @@ func InitWireguard(node *nodepb.Node, privkey string, peers []wgtypes.PeerConfig
 	}
 	nameserver := servercfg.CoreDNSAddr
 	network := node.Nodenetwork
-        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,
-        }
-
-         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
+	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,
+	}
+
+	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
+		}
 	}
 	match := false
 	addrs, _ := currentiface.Addrs()
 	for _, a := range addrs {
-		if strings.Contains(a.String(), node.Address){
+		if strings.Contains(a.String(), node.Address) {
 			match = true
 		}
 	}
 	if !match {
-        err = cmdIPAddrAdd.Run()
-        if  err  !=  nil {
-		fmt.Println("Error adding address")
-                //return err
-        }
+		err = cmdIPAddrAdd.Run()
+		if err != nil {
+			fmt.Println("Error adding address")
+			//return err
+		}
 	}
 	var nodeport int
 	nodeport = int(node.Listenport)
 
-	//pubkey := privkey.PublicKey()
-	conf := wgtypes.Config{
-		PrivateKey: &key,
-		ListenPort: &nodeport,
-		ReplacePeers: true,
-		Peers: peers,
+	conf := wgtypes.Config{}
+	if nodecfg.UDPHolePunch == "yes" && nodecfg.Name != "netmaker" {
+		conf = wgtypes.Config{
+			PrivateKey:   &key,
+			ReplacePeers: true,
+			Peers:        peers,
+		}
+	} else {
+		conf = wgtypes.Config{
+			PrivateKey:   &key,
+			ListenPort:   &nodeport,
+			ReplacePeers: true,
+			Peers:        peers,
+		}
 	}
 	_, err = wgclient.Device(ifacename)
-        if err != nil {
-                if os.IsNotExist(err) {
-                        fmt.Println("Device does not exist: ")
-                        fmt.Println(err)
-                } else {
-                        log.Fatalf("Unknown config error: %v", err)
-                }
-        }
+	if err != nil {
+		if os.IsNotExist(err) {
+			fmt.Println("Device does not exist: ")
+			fmt.Println(err)
+		} else {
+			log.Fatalf("Unknown config error: %v", err)
+		}
+	}
 
 	err = wgclient.ConfigureDevice(ifacename, conf)
 
@@ -262,27 +267,27 @@ func InitWireguard(node *nodepb.Node, privkey string, peers []wgtypes.PeerConfig
 		}
 	}
 	//=========DNS Setup==========\\
+	log.Println("NODECFG.DNS:",nodecfg.DNS)
 	if nodecfg.DNS == "on" {
 		_ = local.UpdateDNS(ifacename, network, nameserver)
 	}
-        //=========End DNS Setup=======\\
-
+	//=========End DNS Setup=======\\
 
-        cmdIPLinkUp := &exec.Cmd {
-                Path: ipExec,
-                Args: []string{ ipExec, "link", "set", "up", "dev", ifacename},
-                Stdout: os.Stdout,
-                Stderr: os.Stdout,
-        }
+	cmdIPLinkUp := &exec.Cmd{
+		Path:   ipExec,
+		Args:   []string{ipExec, "link", "set", "up", "dev", ifacename},
+		Stdout: os.Stdout,
+		Stderr: os.Stdout,
+	}
 
-	cmdIPLinkDown := &exec.Cmd {
-                Path: ipExec,
-                Args: []string{ ipExec, "link", "set", "down", "dev", ifacename},
-                Stdout: os.Stdout,
-                Stderr: os.Stdout,
-        }
-        err = cmdIPLinkDown.Run()
-        if nodecfg.PostDown != "" {
+	cmdIPLinkDown := &exec.Cmd{
+		Path:   ipExec,
+		Args:   []string{ipExec, "link", "set", "down", "dev", ifacename},
+		Stdout: os.Stdout,
+		Stderr: os.Stdout,
+	}
+	err = cmdIPLinkDown.Run()
+	if nodecfg.PostDown != "" {
 		runcmds := strings.Split(nodecfg.PostDown, "; ")
 		err = local.RunCmds(runcmds)
 		if err != nil {
@@ -291,69 +296,71 @@ func InitWireguard(node *nodepb.Node, privkey string, peers []wgtypes.PeerConfig
 	}
 
 	err = cmdIPLinkUp.Run()
-        if  err  !=  nil {
-                return err
-        }
+	if err != nil {
+		return err
+	}
 
 	if nodecfg.PostUp != "" {
-                runcmds := strings.Split(nodecfg.PostUp, "; ")
-                err = local.RunCmds(runcmds)
-                if err != nil {
-                        fmt.Println("Error encountered running PostUp: " + err.Error())
-                }
-        }
-	if (hasGateway) {
-		for _, gateway := range gateways {
-			out, err := exec.Command(ipExec,"-4","route","add",gateway,"dev",ifacename).Output()
-                fmt.Println(string(out))
+		runcmds := strings.Split(nodecfg.PostUp, "; ")
+		err = local.RunCmds(runcmds)
 		if err != nil {
-                        fmt.Println("Error encountered adding gateway: " + err.Error())
-                }
+			fmt.Println("Error encountered running PostUp: " + err.Error())
+		}
+	}
+	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()
+			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 {
 		fmt.Println("Adding address: " + node.Address6)
-                out, err := exec.Command(ipExec, "address", "add", "dev", ifacename, node.Address6+"/64").Output()
-                if err != nil {
-                        fmt.Println(out)
-                        fmt.Println("Error encountered adding ipv6: " + err.Error())
-                }
+		out, err := exec.Command(ipExec, "address", "add", "dev", ifacename, node.Address6+"/64").Output()
+		if err != nil {
+			fmt.Println(out)
+			fmt.Println("Error encountered adding ipv6: " + err.Error())
+		}
 	}
 
 	return err
 }
 
-
 func SetWGKeyConfig(network string, serveraddr string) error {
 
-        ctx := context.Background()
-        var header metadata.MD
+	ctx := context.Background()
+	var header metadata.MD
 
-        cfg, err := config.ReadConfig(network)
-        if err != nil {
-                return err
-        }
+	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)
-        }
+	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
-        }
+	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)
 
@@ -367,65 +374,63 @@ func SetWGKeyConfig(network string, serveraddr string) error {
 	node.Publickey = publickey.String()
 
 	err = StorePrivKey(privkeystring, network)
-        if err != nil {
-                return err
-        }
-        err = config.ModConfig(&node)
-        if err != nil {
-                return err
-        }
-
+	if err != nil {
+		return err
+	}
+	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)
-        if err != nil {
-                return err
-                log.Fatalf("Error: %v", err)
-        }
-
-        return err
-}
+	req := &nodepb.UpdateNodeReq{
+		Node: &postnode,
+	}
+
+	_, err = wcclient.UpdateNode(ctx, req, grpc.Header(&header))
+	if err != nil {
+		return err
+	}
+	err = SetWGConfig(network)
+	if err != nil {
+		return err
+		log.Fatalf("Error: %v", err)
+	}
 
+	return err
+}
 
 func SetWGConfig(network string) error {
 
-        cfg, err := config.ReadConfig(network)
-        if err != nil {
-                return err
-        }
+	cfg, err := config.ReadConfig(network)
+	if err != nil {
+		return err
+	}
 	servercfg := cfg.Server
-        nodecfg := cfg.Node
-        node := server.GetNode(network)
+	nodecfg := cfg.Node
+	node := server.GetNode(network)
 
 	peers, hasGateway, gateways, err := server.GetPeers(node.Macaddress, nodecfg.Network, servercfg.GRPCAddress, node.Isdualstack, node.Isingressgateway)
-        if err != nil {
-                return err
-        }
+	if err != nil {
+		return err
+	}
 	privkey, err := RetrievePrivKey(network)
-        if err != nil {
-                return err
-        }
+	if err != nil {
+		return err
+	}
 
-        err = InitWireguard(&node, privkey, peers, hasGateway, gateways)
-        if err != nil {
-                return err
-        }
+	err = InitWireguard(&node, privkey, peers, hasGateway, gateways)
+	if err != nil {
+		return err
+	}
 
 	return err
 }
 
-func StorePrivKey(key string, network string) error{
+func StorePrivKey(key string, network string) error {
 	d1 := []byte(key)
-	err := ioutil.WriteFile("/etc/netclient/wgkey-" + network, d1, 0644)
+	err := ioutil.WriteFile("/etc/netclient/wgkey-"+network, d1, 0644)
 	return err
 }
 

+ 96 - 0
nginx/netmaker-nginx-dns.conf

@@ -0,0 +1,96 @@
+user www-data;
+worker_processes auto;
+pid /run/nginx.pid;
+include /etc/nginx/modules-enabled/*.conf;
+
+events {
+	worker_connections 768;
+	# multi_accept on;
+}
+
+http {
+
+	##
+	# Basic Settings
+	##
+
+	sendfile on;
+	tcp_nopush on;
+	tcp_nodelay on;
+	keepalive_timeout 65;
+	types_hash_max_size 2048;
+	# server_tokens off;
+
+	# server_names_hash_bucket_size 64;
+	# server_name_in_redirect off;
+
+	include /etc/nginx/mime.types;
+	default_type application/octet-stream;
+
+	##
+	# SSL Settings
+	##
+
+	ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; # Dropping SSLv3, ref: POODLE
+	ssl_prefer_server_ciphers on;
+
+	##
+	# Logging Settings
+	##
+
+	access_log /var/log/nginx/access.log;
+	error_log /var/log/nginx/error.log;
+
+	##
+	# Gzip Settings
+	##
+
+	gzip on;
+
+	# gzip_vary on;
+	# gzip_proxied any;
+	# gzip_comp_level 6;
+	# gzip_buffers 16 8k;
+	# gzip_http_version 1.1;
+	# gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
+
+	##
+	# Virtual Host Configs
+	##
+
+	include /etc/nginx/conf.d/*.conf;
+	include /etc/nginx/sites-enabled/*;
+}
+
+
+#mail {
+#	# See sample authentication script at:
+#	# http://wiki.nginx.org/ImapAuthenticateWithApachePhpScript
+# 
+#	# auth_http localhost/auth.php;
+#	# pop3_capabilities "TOP" "USER";
+#	# imap_capabilities "IMAP4rev1" "UIDPLUS";
+# 
+#	server {
+#		listen     localhost:110;
+#		protocol   pop3;
+#		proxy      on;
+#	}
+# 
+#	server {
+#		listen     localhost:143;
+#		protocol   imap;
+#		proxy      on;
+#	}
+#}
+stream {
+	upstream dns_servers {
+                server 127.0.0.1:5353;
+	}
+        server {
+                listen 53 udp;
+                listen 53;
+                proxy_pass dns_servers;
+        	error_log  /var/log/nginx/dns.log info;
+        }
+}

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

@@ -0,0 +1,45 @@
+server {
+    listen 443 ssl;
+    listen [::]:443 ssl;
+    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; 
+    location / {
+        proxy_pass http://127.0.0.1:8082;
+     }
+}
+server {
+    listen 443 ssl;
+    listen [::]:443 ssl;
+    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;
+
+    location / {
+        proxy_pass http://127.0.0.1:8081;
+        proxy_set_header                Host api.NETMAKER_BASE_DOMAIN;
+        proxy_pass_request_headers      on;
+        }
+}
+server {
+    listen 1443 ssl http2;
+    server_name grpc.NETMAKER_BASE_DOMAIN
+    ssl_certificate /etc/letsencrypt/live/NETMAKER_BASE_DOMAIN/fullchain.pem; 
+    ssl_certificate_key /etc/letsencrypt/live/NETMAKER_BASE_DOMAIN/privkey.pem; 
+    include /etc/letsencrypt/options-ssl-nginx.conf; 
+    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; 
+
+        # Forces the header to be the one that is visible from the outside
+        proxy_set_header                Host api.NETMAKER_BASE_DOMAIN; # Please change to your URL
+
+        # Pass all headers through to the backend
+        proxy_pass_request_headers      on;
+
+        location / {
+            grpc_pass grpc://127.0.0.1:50051;
+        }
+}

+ 0 - 53
servercfg/mongoconf.go

@@ -1,53 +0,0 @@
-package servercfg
-
-import (
-        "github.com/gravitl/netmaker/config"
-        "os"
-)
-
-func GetMongoUser() string {
-	user := "mongoadmin"
-	if os.Getenv("MONGO_ADMIN") != "" {
-		user = os.Getenv("MONGO_ADMIN")
-	} else if  config.Config.MongoConn.User != "" {
-		user = config.Config.MongoConn.User
-	}
-	return user
-}
-func GetMongoPass() string {
-        pass := "mongopass"
-        if os.Getenv("MONGO_PASS") != "" {
-                pass = os.Getenv("MONGO_PASS")
-        } else if  config.Config.MongoConn.Pass != "" {
-                pass = config.Config.MongoConn.Pass
-        }
-        return pass
-}
-func GetMongoHost() string {
-        host := "127.0.0.1"
-        if os.Getenv("MONGO_HOST") != "" {
-                host = os.Getenv("MONGO_HOST")
-        } else if  config.Config.MongoConn.Host != "" {
-                host = config.Config.MongoConn.Host
-        }
-        return host
-}
-func GetMongoPort() string {
-        port := "27017"
-        if os.Getenv("MONGO_PORT") != "" {
-                port = os.Getenv("MONGO_PORT")
-        } else if  config.Config.MongoConn.Port != "" {
-                port = config.Config.MongoConn.Port
-        }
-        return port
-}
-func GetMongoOpts() string {
-        opts := "/?authSource=admin"
-        if os.Getenv("MONGO_OPTS") != "" {
-                opts = os.Getenv("MONGO_OPTS")
-        } else if  config.Config.MongoConn.Opts != "" {
-                opts = config.Config.MongoConn.Opts
-        }
-        return opts
-}
-

+ 2 - 2
servercfg/serverconf.go

@@ -87,6 +87,7 @@ func GetAPIConnString() string {
 }
 func GetAPIHost() string {
 	serverhost := "127.0.0.1"
+	remoteip, _ := GetPublicIP()
 	if os.Getenv("SERVER_HTTP_HOST") != "" {
 		serverhost = os.Getenv("SERVER_HTTP_HOST")
 	} else if config.Config.Server.APIHost != "" {
@@ -94,7 +95,6 @@ func GetAPIHost() string {
 	} else if os.Getenv("SERVER_HOST") != "" {
 		serverhost = os.Getenv("SERVER_HOST")
 	} else {
-		remoteip, _ := GetPublicIP()
 		if remoteip != "" {
 			serverhost = remoteip
 		}
@@ -144,6 +144,7 @@ func GetCoreDNSAddr() string {
 
 func GetGRPCHost() string {
 	serverhost := "127.0.0.1"
+	remoteip, _ := GetPublicIP()
 	if IsGRPCWireGuard() {
 		serverhost = GetGRPCWGAddress()
 	} else {
@@ -154,7 +155,6 @@ func GetGRPCHost() string {
 		} else if os.Getenv("SERVER_HOST") != "" {
 			serverhost = os.Getenv("SERVER_HOST")
 		} else {
-			remoteip, _ := GetPublicIP()
 			if remoteip != "" {
 				serverhost = remoteip
 			}

+ 129 - 187
serverctl/serverctl.go

@@ -1,238 +1,180 @@
 package serverctl
 
 import (
-        "log"
+	"encoding/json"
+	"errors"
+	"io"
+	"log"
+	"os"
+	"os/exec"
+	"time"
+
+	"github.com/gravitl/netmaker/database"
 	"github.com/gravitl/netmaker/functions"
 	"github.com/gravitl/netmaker/models"
-	"github.com/gravitl/netmaker/mongoconn"
 	"github.com/gravitl/netmaker/servercfg"
-        "go.mongodb.org/mongo-driver/bson"
-        "go.mongodb.org/mongo-driver/mongo/options"
-	"io"
-	"time"
-	"context"
-	"errors"
-        "os"
-        "os/exec"
 )
 
-func CreateDefaultNetwork() (bool, error) {
-
-        log.Println("Creating default network...")
-
-        iscreated := false
-        exists, err := functions.NetworkExists("default")
-
-        if exists || err != nil {
-                log.Println("Default network already exists. Skipping...")
-                return iscreated, err
-        } else {
-
-        var network models.Network
-
-        network.NetID = "default"
-        network.AddressRange = "10.10.10.0/24"
-        network.DisplayName = "default"
-        network.SetDefaults()
-        network.SetNodesLastModified()
-        network.SetNetworkLastModified()
-        network.KeyUpdateTimeStamp = time.Now().Unix()
-        priv := false
-        network.IsLocal = &priv
-        network.KeyUpdateTimeStamp = time.Now().Unix()
-        allow := true
-        network.AllowManualSignUp = &allow
-
-        collection := mongoconn.Client.Database("netmaker").Collection("networks")
-        ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-
-        // insert our network into the network table
-        _, err = collection.InsertOne(ctx, network)
-        defer cancel()
-
-        }
-        if err == nil {
-                iscreated = true
-        }
-        return iscreated, err
-
-
-}
-
 func GetServerWGConf() (models.IntClient, error) {
-        var server models.IntClient
-        collection := mongoconn.Client.Database("netmaker").Collection("intclients")
-        ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-	filter := bson.M{"network": "comms", "isserver": "yes"}
-        err := collection.FindOne(ctx, filter, options.FindOne().SetProjection(bson.M{"_id": 0})).Decode(&server)
-	defer cancel()
-
-	return server, err
+	var server models.IntClient
+	collection, err := database.FetchRecords(database.INT_CLIENTS_TABLE_NAME)
+	if err != nil {
+		return models.IntClient{}, errors.New("could not find comms server")
+	}
+	for _, value := range collection {
+		json.Unmarshal([]byte(value), &server)
+		if server.Network == "comms" && server.IsServer == "yes" {
+			return server, nil
+		}
+	}
+	return models.IntClient{}, errors.New("could not find comms server")
 }
 
-
 func CreateCommsNetwork() (bool, error) {
 
-        iscreated := false
-        exists, err := functions.NetworkExists("comms")
-
-        if exists || err != nil {
-                log.Println("comms network already exists. Skipping...")
-                return true, nil
-        } else {
-
-        var network models.Network
-
-        network.NetID = "comms"
-	network.IsIPv6 = "no"
-	network.IsIPv4 = "yes"
-	network.IsGRPCHub = "yes"
-        network.AddressRange = servercfg.GetGRPCWGAddressRange()
-        network.DisplayName = "comms"
-        network.SetDefaults()
-        network.SetNodesLastModified()
-        network.SetNetworkLastModified()
-        network.KeyUpdateTimeStamp = time.Now().Unix()
-        priv := false
-        network.IsLocal = &priv
-        network.KeyUpdateTimeStamp = time.Now().Unix()
-
-        log.Println("Creating comms network...")
-
-        collection := mongoconn.Client.Database("netmaker").Collection("networks")
-        ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-
-        // insert our network into the network table
-        _, err = collection.InsertOne(ctx, network)
-        defer cancel()
-
-        }
-        if err == nil {
-                iscreated = true
-        }
-        return iscreated, err
-}
-
-func DownloadNetclient() error {
-	/*
-	// Get the data
-	resp, err := http.Get("https://github.com/gravitl/netmaker/releases/download/latest/netclient")
-	if err != nil {
-                log.Println("could not download netclient")
-		return err
+	iscreated := false
+	exists, err := functions.NetworkExists("comms")
+
+	if exists || err != nil {
+		log.Println("comms network already exists. Skipping...")
+		return true, err
+	} else {
+		var network models.Network
+
+		network.NetID = "comms"
+		network.IsIPv6 = "no"
+		network.IsIPv4 = "yes"
+		network.IsGRPCHub = "yes"
+		network.AddressRange = servercfg.GetGRPCWGAddressRange()
+		network.DisplayName = "comms"
+		network.SetDefaults()
+		network.SetNodesLastModified()
+		network.SetNetworkLastModified()
+		network.KeyUpdateTimeStamp = time.Now().Unix()
+		network.IsLocal = "no"
+		network.KeyUpdateTimeStamp = time.Now().Unix()
+
+		log.Println("Creating comms network...")
+		value, err := json.Marshal(network)
+		if err != nil {
+			return false, err
+		}
+		database.Insert(network.NetID, string(value), database.NETWORKS_TABLE_NAME)
+	}
+	if err == nil {
+		iscreated = true
 	}
-	defer resp.Body.Close()
+	return iscreated, err
+}
 
-	// Create the file
-	out, err := os.Create("/etc/netclient/netclient")
-        */
-        if !FileExists("/etc/netclient/netclient") {
+func InstallNetclient() error {
+	if !FileExists("/etc/netclient/netclient") {
 		_, err := copy("./netclient/netclient", "/etc/netclient/netclient")
-	if err != nil {
-                log.Println("could not create /etc/netclient")
-		return err
-	}
+		if err != nil {
+			log.Println("could not create /etc/netclient")
+			return err
+		}
 	}
-	//defer out.Close()
-
-	// Write the body to file
-	//_, err = io.Copy(out, resp.Body)
 	return nil
 }
 
 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 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)
-        err = os.Chmod(dst, 0755)
-        if err != nil {
-                log.Println(err)
-        }
-        return nBytes, err
+	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
 }
 
 func RemoveNetwork(network string) (bool, error) {
 	_, err := os.Stat("/etc/netclient/netclient")
-        if err != nil {
-                log.Println("could not find /etc/netclient")
+	if err != nil {
+		log.Println("could not find /etc/netclient")
 		return false, err
 	}
-        cmdoutput, err := exec.Command("/etc/netclient/netclient","leave","-n",network).Output()
-        if err != nil {
-                log.Println(string(cmdoutput))
-                return false, err
-        }
-        log.Println("Server removed from network " + network)
-        return true, err
+	cmdoutput, err := exec.Command("/etc/netclient/netclient", "leave", "-n", network).Output()
+	if err != nil {
+		log.Println(string(cmdoutput))
+		return false, err
+	}
+	log.Println("Server removed from network " + network)
+	return true, err
 
 }
 
 func AddNetwork(network string) (bool, error) {
 	pubip, err := servercfg.GetPublicIP()
-        if err != nil {
-                log.Println("could not get public IP.")
-                return false, err
-        }
+	if err != nil {
+		log.Println("could not get public IP.")
+		return false, err
+	}
 
 	_, err = os.Stat("/etc/netclient")
-        if os.IsNotExist(err) {
-                os.Mkdir("/etc/netclient", 744)
-        } else if err != nil {
-                log.Println("could not find or create /etc/netclient")
-                return false, err
+	if os.IsNotExist(err) {
+		os.Mkdir("/etc/netclient", 744)
+	} else if err != nil {
+		log.Println("could not find or create /etc/netclient")
+		return false, err
 	}
 	token, err := functions.CreateServerToken(network)
 	if err != nil {
-                log.Println("could not create server token for " + network)
+		log.Println("could not create server token for " + network)
 		return false, err
-        }
-        _, err = os.Stat("/etc/netclient/netclient")
+	}
+	_, err = os.Stat("/etc/netclient/netclient")
 	if os.IsNotExist(err) {
-		err = DownloadNetclient()
+		err = InstallNetclient()
 		if err != nil {
 			return false, err
 		}
 	}
-        err = os.Chmod("/etc/netclient/netclient", 0755)
-        if err != nil {
-                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)
-	out, err := exec.Command("/etc/netclient/netclient","join","-t",token,"-name","netmaker","-endpoint",pubip).Output()
-        if string(out) != "" {
-	        log.Println(string(out))
+	err = os.Chmod("/etc/netclient/netclient", 0755)
+	if err != nil {
+		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)
+
+	joinCMD := exec.Command("/etc/netclient/netclient", "join", "-t", token, "-name", "netmaker", "-endpoint", pubip)
+	err = joinCMD.Start()
+	if err != nil {
+		log.Println(err)
 	}
+	log.Println("Waiting for join command to finish...")
+	err = joinCMD.Wait()
 	if err != nil {
-                return false, errors.New(string(out) + err.Error())
-        }
+		log.Println("Command finished with error: %v", err)
+		return false, err
+	}
 	log.Println("Server added to network " + network)
 	return true, err
 }
-

+ 100 - 77
serverctl/wireguard.go

@@ -1,21 +1,22 @@
 package serverctl
 
 import (
-        //"github.com/davecgh/go-spew/spew"
-	"os"
+	//"github.com/davecgh/go-spew/spew"
+
+	"encoding/json"
+	"errors"
 	"log"
-	"context"
-	"time"
 	"net"
+	"os"
 	"strconv"
-	"errors"
+
+	"github.com/gravitl/netmaker/database"
+	"github.com/gravitl/netmaker/functions"
+	"github.com/gravitl/netmaker/models"
+	"github.com/gravitl/netmaker/servercfg"
 	"github.com/vishvananda/netlink"
 	"golang.zx2c4.com/wireguard/wgctrl"
 	"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
-        "github.com/gravitl/netmaker/servercfg"
-        "github.com/gravitl/netmaker/functions"
-        "github.com/gravitl/netmaker/models"
-        "github.com/gravitl/netmaker/mongoconn"
 )
 
 func InitServerWireGuard() error {
@@ -50,9 +51,9 @@ func InitServerWireGuard() error {
 	}
 
 	err = netlink.AddrAdd(wglink, address)
-        if err != nil && !os.IsExist(err){
-                        return err
-        }
+	if err != nil && !os.IsExist(err) {
+		return err
+	}
 	err = netlink.LinkSetUp(wglink)
 	if err != nil {
 		log.Println("could not bring up wireguard interface")
@@ -69,105 +70,104 @@ func InitServerWireGuard() error {
 	client.Address = servercfg.GetGRPCWGAddress()
 	client.IsServer = "yes"
 	client.Network = "comms"
-	exists, _ := functions.ServerIntClientExists()
-	if exists {
-
+	exists, _ := functions.GetServerIntClient()
+	if exists != nil {
+		err = RegisterServer(client)
 	}
-	err = RegisterServer(client)
-        return err
+	return err
 }
 
 func DeleteServerClient() error {
 	return nil
 }
 
-
 func RegisterServer(client models.IntClient) error {
-        if client.PrivateKey == "" {
-                privateKey, err := wgtypes.GeneratePrivateKey()
-                if err != nil {
-                        return err
-                }
-
-                client.PrivateKey = privateKey.String()
-                client.PublicKey = privateKey.PublicKey().String()
-        }
-
-        if client.Address == "" {
-                newAddress, err := functions.UniqueAddress(client.Network)
-                if err != nil {
-                        return err
-                }
+	if client.PrivateKey == "" {
+		privateKey, err := wgtypes.GeneratePrivateKey()
+		if err != nil {
+			return err
+		}
+
+		client.PrivateKey = privateKey.String()
+		client.PublicKey = privateKey.PublicKey().String()
+	}
+
+	if client.Address == "" {
+		newAddress, err := functions.UniqueAddress(client.Network)
+		if err != nil {
+			return err
+		}
 		if newAddress == "" {
 			return errors.New("Could not retrieve address")
 		}
-                client.Address = newAddress
-        }
-	if client.Network == "" { client.Network = "comms" }
-        client.ServerKey = client.PublicKey
-
-        collection := mongoconn.Client.Database("netmaker").Collection("intclients")
-        ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
-        // insert our network into the network table
-        _, err := collection.InsertOne(ctx, client)
-        defer cancel()
+		client.Address = newAddress
+	}
+	if client.Network == "" {
+		client.Network = "comms"
+	}
+	client.ServerKey = client.PublicKey
+	value, err := json.Marshal(client)
+	if err != nil {
+		return err
+	}
+	database.Insert(client.PublicKey, string(value), database.INT_CLIENTS_TABLE_NAME)
 
-        ReconfigureServerWireGuard()
+	ReconfigureServerWireGuard()
 
-        return err
+	return err
 }
 
 func ReconfigureServerWireGuard() error {
-	server, err := GetServerWGConf()
+	server, err := functions.GetServerIntClient()
 	if err != nil {
-                return err
-        }
+		return err
+	}
 	serverkey, err := wgtypes.ParseKey(server.PrivateKey)
-        if err != nil {
-                return err
-        }
+	if err != nil {
+		return err
+	}
 	serverport, err := strconv.Atoi(servercfg.GetGRPCWGPort())
-        if err != nil {
-                return err
-        }
+	if err != nil {
+		return err
+	}
 
 	peers, err := functions.GetIntPeersList()
-        if err != nil {
-                return err
-        }
+	if err != nil {
+		return err
+	}
 	wgserver, err := wgctrl.New()
 	if err != nil {
 		return err
 	}
-        var serverpeers []wgtypes.PeerConfig
+	var serverpeers []wgtypes.PeerConfig
 	for _, peer := range peers {
 
-                pubkey, err := wgtypes.ParseKey(peer.PublicKey)
+		pubkey, err := wgtypes.ParseKey(peer.PublicKey)
 		if err != nil {
 			return err
 		}
-                var peercfg wgtypes.PeerConfig
-                var allowedips []net.IPNet
-                if peer.Address != "" {
+		var peercfg wgtypes.PeerConfig
+		var allowedips []net.IPNet
+		if peer.Address != "" {
 			var peeraddr = net.IPNet{
-	                        IP: net.ParseIP(peer.Address),
-	                        Mask: net.CIDRMask(32, 32),
-	                }
-	                allowedips = append(allowedips, peeraddr)
+				IP:   net.ParseIP(peer.Address),
+				Mask: net.CIDRMask(32, 32),
+			}
+			allowedips = append(allowedips, peeraddr)
 		}
 		if peer.Address6 != "" {
-                        var addr6 = net.IPNet{
-                                IP: net.ParseIP(peer.Address6),
-                                Mask: net.CIDRMask(128, 128),
-                        }
-                        allowedips = append(allowedips, addr6)
-                }
+			var addr6 = net.IPNet{
+				IP:   net.ParseIP(peer.Address6),
+				Mask: net.CIDRMask(128, 128),
+			}
+			allowedips = append(allowedips, addr6)
+		}
 		peercfg = wgtypes.PeerConfig{
-                        PublicKey: pubkey,
-                        ReplaceAllowedIPs: true,
-                        AllowedIPs: allowedips,
-                }
-                serverpeers = append(serverpeers, peercfg)
+			PublicKey:         pubkey,
+			ReplaceAllowedIPs: true,
+			AllowedIPs:        allowedips,
+		}
+		serverpeers = append(serverpeers, peercfg)
 	}
 
 	wgconf := wgtypes.Config{
@@ -183,3 +183,26 @@ func ReconfigureServerWireGuard() error {
 	}
 	return nil
 }
+
+func GetPeers(networkName string) (map[string]string, error) {
+	peers := make(map[string]string)
+	network, err := functions.GetParentNetwork(networkName)
+	if err != nil {
+		return peers, err
+	}
+	iface := network.DefaultInterface
+
+	client, err := wgctrl.New()
+	if err != nil {
+		return peers, err
+	}
+	device, err := client.Device(iface)
+	if err != nil {
+		return nil, err
+	}
+	for _, peer := range device.Peers {
+		peers[peer.PublicKey.String()] = peer.Endpoint.String()
+	}
+
+	return peers, nil
+}

+ 1 - 1
test/api_test.go

@@ -12,7 +12,7 @@ import (
 
 	controller "github.com/gravitl/netmaker/controllers"
 	"github.com/gravitl/netmaker/models"
-	"github.com/gravitl/netmaker/mongoconn"
+	""
 	"github.com/stretchr/testify/assert"
 )
 

+ 1 - 1
test/groupcreate.sh

@@ -15,4 +15,4 @@ EOF
 
 POST_JSON=$(generate_post_json)
 
-curl --max-time 5.0 -d "$POST_JSON" -H 'Content-Type: application/json' -H "authorization: Bearer secretkey" localhost:8082/api/networks
+curl --max-time 5.0 -d "$POST_JSON" -H 'Content-Type: application/json' -H "authorization: Bearer secretkey" localhost:8081/api/networks

+ 3 - 3
test/nodecreate.sh

@@ -3,7 +3,7 @@
 PUBKEY="DM5qhLAE20PG9BbfBCger+Ac9D2NDOwCtY1rbYDLf34="
 IPADDR="69.173.21.202"
 MACADDRESS="59:2a:9c:d4:e2:49"
-ACCESSKEY="9ktiHcUWay2MSKsY"
+ACCESSKEY="6Cc1m3x0B0LQhHWF"
 PASSWORD="ppppppp"
 
 generate_post_json ()
@@ -15,12 +15,12 @@ generate_post_json ()
   "macaddress": "$MACADDRESS",
   "password": "$PASSWORD",
   "localaddress": "172.123.123.3",
-  "accesskey": "$ACCESSKEY"
+  "accesskey": "zKfzHn9W6uL5KuIg"
 }
 EOF
 }
 
 POST_JSON=$(generate_post_json)
 
-curl --max-time 5.0 -d "$POST_JSON" -H 'Content-Type: application/json' -H "authorization: Bearer secretkey" localhost:8081/api/nodes/default
+curl --max-time 5.0 -d "$POST_JSON" -H 'Content-Type: application/json' -H "authorization: Bearer secretkey" localhost:8081/api/nodes/skynet