Browse Source

adding extclient functionality

afeiszli 4 years ago
parent
commit
29e332edf7

+ 43 - 0
controllers/common.go

@@ -58,6 +58,49 @@ func GetPeersList(networkName string) ([]models.PeersResponse, error) {
 	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, "gatewayid": 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 {

+ 2 - 0
controllers/controller.go

@@ -31,6 +31,8 @@ func HandleRESTRequests(wg *sync.WaitGroup) {
     dnsHandlers(r)
     fileHandlers(r)
     serverHandlers(r)
+    extClientHandlers(r)
+
 
 		port := servercfg.GetAPIPort()
 

+ 413 - 0
controllers/extClientHttpController.go

@@ -0,0 +1,413 @@
+package controller
+
+import (
+	"context"
+	"encoding/json"
+	"errors"
+	"fmt"
+
+	// "fmt"
+	"net/http"
+	"time"
+
+	"github.com/gorilla/mux"
+	"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"
+)
+
+func extClientHandlers(r *mux.Router) {
+
+	r.HandleFunc("/api/extclients", securityCheck(http.HandlerFunc(getAllExtClients))).Methods("GET")
+	r.HandleFunc("/api/extclients/{network}", securityCheck(http.HandlerFunc(getNetworkExtClients))).Methods("GET")
+	r.HandleFunc("/api/extclients/{network}/{clientid}", securityCheck(http.HandlerFunc(getExtClient))).Methods("GET")
+	r.HandleFunc("/api/extclients/{network}/{clientid}/{type}", securityCheck(http.HandlerFunc(getExtClientConf))).Methods("GET")
+	r.HandleFunc("/api/extclients/{network}/{clientid}", securityCheck(http.HandlerFunc(updateExtClient))).Methods("PUT")
+	r.HandleFunc("/api/extclients/{network}/{clientid}", securityCheck(http.HandlerFunc(deleteExtClient))).Methods("DELETE")
+	r.HandleFunc("/api/extclients/{network}/{macaddress}", securityCheck(http.HandlerFunc(createExtClient))).Methods("POST")
+}
+
+// TODO: Implement Validation
+func ValidateExtClientCreate(networkName string, extclient models.ExtClient) error {
+	// 	v := validator.New()
+	// 	_ = v.RegisterValidation("macaddress_unique", func(fl validator.FieldLevel) bool {
+	// 		var isFieldUnique bool = functions.IsFieldUnique(networkName, "macaddress", extclient.MacAddress)
+	// 		return isFieldUnique
+	// 	})
+	// 	_ = v.RegisterValidation("network_exists", func(fl validator.FieldLevel) bool {
+	// 		_, err := extclient.GetNetwork()
+	// 		return err == nil
+	// 	})
+	// 	err := v.Struct(extclient)
+
+	// 	if err != nil {
+	// 		for _, e := range err.(validator.ValidationErrors) {
+	// 			fmt.Println(e)
+	// 		}
+	// 	}
+	return nil
+}
+
+// TODO: Implement Validation
+func ValidateExtClientUpdate(networkName string, extclient models.ExtClient) error {
+	// v := validator.New()
+	// _ = v.RegisterValidation("network_exists", func(fl validator.FieldLevel) bool {
+	// 	_, err := extclient.GetNetwork()
+	// 	return err == nil
+	// })
+	// err := v.Struct(extclient)
+	// if err != nil {
+	// 	for _, e := range err.(validator.ValidationErrors) {
+	// 		fmt.Println(e)
+	// 	}
+	// }
+	return nil
+}
+
+func checkIngressExists(network string, macaddress string) bool {
+	node, err := functions.GetNodeByMacAddress(network, macaddress)
+	if err != nil {
+		return false
+	}
+	return node.IsIngressGateway
+}
+
+//Gets all extclients associated with network, including pending extclients
+func getNetworkExtClients(w http.ResponseWriter, r *http.Request) {
+
+	w.Header().Set("Content-Type", "application/json")
+
+	var extclients []models.ExtClient
+	var params = mux.Vars(r)
+	extclients, err := GetNetworkExtClients(params["network"])
+	if err != nil {
+		returnErrorResponse(w, r, formatError(err, "internal"))
+		return
+	}
+
+	//Returns all the extclients in JSON format
+	w.WriteHeader(http.StatusOK)
+	json.NewEncoder(w).Encode(extclients)
+}
+
+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}))
+	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
+		var extclient models.ExtClient
+		err := cur.Decode(&extclient)
+		if err != nil {
+			return []models.ExtClient{}, err
+		}
+		// 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
+}
+
+//A separate function to get all extclients, not just extclients for a particular network.
+//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 getAllExtClients(w http.ResponseWriter, r *http.Request) {
+	w.Header().Set("Content-Type", "application/json")
+	extclients, err := functions.GetAllExtClients()
+	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(extclients)
+}
+
+//Get an individual extclient. Nothin fancy here folks.
+func getExtClient(w http.ResponseWriter, r *http.Request) {
+	// set header.
+	w.Header().Set("Content-Type", "application/json")
+
+	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)
+	if err != nil {
+		returnErrorResponse(w, r, formatError(err, "internal"))
+		return
+	}
+
+	defer cancel()
+
+	w.WriteHeader(http.StatusOK)
+	json.NewEncoder(w).Encode(extclient)
+}
+
+//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)
+
+        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)
+        if err != nil {
+                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)
+		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
+        }
+
+	config := fmt.Sprintf(`[Interface]
+Address = %s
+PrivateKey = %s
+
+[Peer]
+PublicKey = %s
+AllowedIPs = %s
+Endpoint = %s
+
+`, extclient.Address + "/32",
+   extclient.PrivateKey,
+   gwnode.PublicKey,
+   network.AddressRange,
+   network.DefaultKeepalive)
+
+	if params["type"] == "qr" {
+		bytes, err := qrcode.Encode(config, qrcode.Medium, 220)
+		if err != nil {
+			returnErrorResponse(w, r, formatError(err, "internal"))
+			return
+		}
+		w.Header().Set("Content-Type", "image/png")
+		w.WriteHeader(http.StatusOK)
+		_, err = w.Write(bytes)
+		if err != nil {
+			returnErrorResponse(w, r, formatError(err, "internal"))
+			return
+		}
+		return
+	}
+
+	if params["type"] == "file" {
+		name := extclient.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"))
+		}
+		return
+	}
+
+        defer cancel()
+
+        w.WriteHeader(http.StatusOK)
+        json.NewEncoder(w).Encode(extclient)
+}
+
+func CreateExtClient(extclient models.ExtClient) error {
+	fmt.Println(extclient)
+	// Generate Private Key for new ExtClient
+	if extclient.PrivateKey == "" {
+		privateKey, err := wgtypes.GeneratePrivateKey()
+		if err != nil {
+			return err
+		}
+
+		extclient.PrivateKey = privateKey.String()
+		extclient.PublicKey = privateKey.PublicKey().String()
+	}
+
+	if extclient.Address == "" {
+		newAddress, err := functions.UniqueAddress(extclient.Network)
+		if err != nil {
+			return err
+		}
+		extclient.Address = newAddress
+	}
+
+	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()
+	return err
+}
+
+//This one's a doozy
+//To create a extclient
+//Must have valid key and be unique
+func createExtClient(w http.ResponseWriter, r *http.Request) {
+	w.Header().Set("Content-Type", "application/json")
+
+	var params = mux.Vars(r)
+
+	networkName := params["network"]
+	macaddress := params["macaddress"]
+	//Check if network exists  first
+	//TODO: This is inefficient. Let's find a better way.
+	//Just a few rows down we grab the network anyway
+	ingressExists := checkIngressExists(networkName, macaddress)
+	if !ingressExists {
+		returnErrorResponse(w, r, formatError(errors.New("ingress does not exist"), "internal"))
+		return
+	}
+
+	var extclient models.ExtClient
+	extclient.Network = networkName
+	extclient.IngressGatewayID = macaddress
+
+	//get extclient from body of request
+	err := json.NewDecoder(r.Body).Decode(&extclient)
+	if err != nil {
+		returnErrorResponse(w, r, formatError(err, "internal"))
+		return
+	}
+	err = ValidateExtClientCreate(params["network"], extclient)
+	if err != nil {
+		returnErrorResponse(w, r, formatError(err, "badrequest"))
+		return
+	}
+
+	err = CreateExtClient(extclient)
+	if err != nil {
+		returnErrorResponse(w, r, formatError(err, "internal"))
+		return
+	}
+	w.WriteHeader(http.StatusOK)
+}
+
+func updateExtClient(w http.ResponseWriter, r *http.Request) {
+	w.Header().Set("Content-Type", "application/json")
+
+	var params = mux.Vars(r)
+
+	var newExtClient models.ExtClient
+	var oldExtClient models.ExtClient
+	// we decode our body request params
+	_ = json.NewDecoder(r.Body).Decode(&newExtClient)
+	// TODO: Validation for update.
+	// err := ValidateExtClientUpdate(params["network"], params["clientid"], newExtClient)
+	// if err != nil {
+	// 	returnErrorResponse(w, r, formatError(err, "badrequest"))
+	// 	return
+	// }
+	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)
+	if err != nil {
+		returnErrorResponse(w, r, formatError(err, "internal"))
+		return
+	}
+	success, err := DeleteExtClient(params["network"], params["clientid"])
+	if err != nil {
+		returnErrorResponse(w, r, formatError(err, "internal"))
+		return
+	} else if !success {
+		returnErrorResponse(w, r, formatError(err, "internal"))
+		return
+	}
+
+	oldExtClient.ClientID = newExtClient.ClientID
+	CreateExtClient(oldExtClient)
+	if err != nil {
+		returnErrorResponse(w, r, formatError(err, "internal"))
+		return
+	}
+
+	w.WriteHeader(http.StatusOK)
+	json.NewEncoder(w).Encode(oldExtClient)
+}
+
+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
+	}
+
+	defer cancel()
+
+	fmt.Println("Deleted extclient client " + clientid + " from network " + network)
+	return deleted, err
+}
+
+//Delete a extclient
+//Pretty straightforward
+func deleteExtClient(w http.ResponseWriter, r *http.Request) {
+	// Set header
+	w.Header().Set("Content-Type", "application/json")
+
+	// get params
+	var params = mux.Vars(r)
+
+	success, 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
+	}
+	returnSuccessResponse(w, r, params["clientid"]+" deleted.")
+}

+ 42 - 2
controllers/nodeGrpcController.go

@@ -347,8 +347,8 @@ func (s *NodeServiceServer) GetPeers(req *nodepb.GetPeersReq, stream nodepb.Node
 				Address:      peers[i].Address,
 				Address6:     peers[i].Address6,
 				Endpoint:     peers[i].Endpoint,
-				Gatewayrange: peers[i].GatewayRange,
-				Isgateway:    peers[i].IsGateway,
+				Egressgatewayrange: peers[i].EgressGatewayRange,
+				Isegressgateway:    peers[i].IsEgressGateway,
 				Publickey:    peers[i].PublicKey,
 				Keepalive:    peers[i].KeepAlive,
 				Listenport:   peers[i].ListenPort,
@@ -369,3 +369,43 @@ 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
+}

+ 27 - 27
controllers/nodeHttpController.go

@@ -26,10 +26,10 @@ func nodeHandlers(r *mux.Router) {
 	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(createGateway))).Methods("POST")
-	r.HandleFunc("/api/nodes/{network}/{macaddress}/deletegateway", authorize(true, "master", http.HandlerFunc(deleteGateway))).Methods("DELETE")
-	r.HandleFunc("/api/nodes/{network}/{macaddress}/createingress", securityCheck(http.HandlerFunc(createIngress))).Methods("POST")
-	r.HandleFunc("/api/nodes/{network}/{macaddress}/deleteingress", securityCheck(http.HandlerFunc(deleteIngress))).Methods("DELETE")
+	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}/createingress", securityCheck(http.HandlerFunc(createIngressGateway))).Methods("POST")
+	r.HandleFunc("/api/nodes/{network}/{macaddress}/deleteingress", securityCheck(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}", createNode).Methods("POST")
 	r.HandleFunc("/api/nodes/adm/{network}/lastmodified", authorize(true, "network", http.HandlerFunc(getLastModified))).Methods("GET")
@@ -526,8 +526,8 @@ func UncordonNode(network, macaddress string) (models.Node, error) {
 	return node, nil
 }
 
-func createGateway(w http.ResponseWriter, r *http.Request) {
-	var gateway models.GatewayRequest
+func createEgressGateway(w http.ResponseWriter, r *http.Request) {
+	var gateway models.EgressGatewayRequest
 	var params = mux.Vars(r)
 	w.Header().Set("Content-Type", "application/json")
 	err := json.NewDecoder(r.Body).Decode(&gateway)
@@ -537,7 +537,7 @@ func createGateway(w http.ResponseWriter, r *http.Request) {
 	}
 	gateway.NetID = params["network"]
 	gateway.NodeID = params["macaddress"]
-	node, err := CreateGateway(gateway)
+	node, err := CreateEgressGateway(gateway)
 	if err != nil {
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
@@ -546,18 +546,18 @@ func createGateway(w http.ResponseWriter, r *http.Request) {
 	json.NewEncoder(w).Encode(node)
 }
 
-func CreateGateway(gateway models.GatewayRequest) (models.Node, error) {
+func CreateEgressGateway(gateway models.EgressGatewayRequest) (models.Node, error) {
 	node, err := functions.GetNodeByMacAddress(gateway.NetID, gateway.NodeID)
 	if err != nil {
 		return models.Node{}, err
 	}
-	err = ValidateGateway(gateway)
+	err = ValidateEgressGateway(gateway)
 	if err != nil {
 		return models.Node{}, err
 	}
 	var nodechange models.Node
-	nodechange.IsGateway = true
-	nodechange.GatewayRange = gateway.RangeString
+	nodechange.IsEgressGateway = true
+	nodechange.EgressGatewayRange = gateway.RangeString
 	if gateway.PostUp == "" {
 		nodechange.PostUp = "iptables -A FORWARD -i " + node.Interface + " -j ACCEPT; iptables -t nat -A POSTROUTING -o " + gateway.Interface + " -j MASQUERADE"
 	} else {
@@ -579,8 +579,8 @@ func CreateGateway(gateway models.GatewayRequest) (models.Node, error) {
 		{"$set", bson.D{
 			{"postup", nodechange.PostUp},
 			{"postdown", nodechange.PostDown},
-			{"isgateway", nodechange.IsGateway},
-			{"gatewayrange", nodechange.GatewayRange},
+			{"isgateway", nodechange.IsEgressGateway},
+			{"gatewayrange", nodechange.EgressGatewayRange},
 			{"lastmodified", nodechange.LastModified},
 		}},
 	}
@@ -602,7 +602,7 @@ func CreateGateway(gateway models.GatewayRequest) (models.Node, error) {
 	return node, nil
 }
 
-func ValidateGateway(gateway models.GatewayRequest) error {
+func ValidateEgressGateway(gateway models.EgressGatewayRequest) error {
 	var err error
 	isIp := functions.IsIpCIDR(gateway.RangeString)
 	empty := gateway.RangeString == ""
@@ -616,10 +616,10 @@ func ValidateGateway(gateway models.GatewayRequest) error {
 	return err
 }
 
-func deleteGateway(w http.ResponseWriter, r *http.Request) {
+func deleteEgressGateway(w http.ResponseWriter, r *http.Request) {
 	w.Header().Set("Content-Type", "application/json")
 	var params = mux.Vars(r)
-	node, err := DeleteGateway(params["network"], params["macaddress"])
+	node, err := DeleteEgressGateway(params["network"], params["macaddress"])
 	if err != nil {
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
@@ -628,7 +628,7 @@ func deleteGateway(w http.ResponseWriter, r *http.Request) {
 	json.NewEncoder(w).Encode(node)
 }
 
-func DeleteGateway(network, macaddress string) (models.Node, error) {
+func DeleteEgressGateway(network, macaddress string) (models.Node, error) {
 
 	var nodeupdate models.Node
 	var nodechange models.Node
@@ -637,8 +637,8 @@ func DeleteGateway(network, macaddress string) (models.Node, error) {
 		return models.Node{}, err
 	}
 
-	nodechange.IsGateway = false
-	nodechange.GatewayRange = ""
+	nodechange.IsEgressGateway = false
+	nodechange.EgressGatewayRange = ""
 	nodechange.PostUp = ""
 	nodechange.PostDown = ""
 
@@ -652,8 +652,8 @@ func DeleteGateway(network, macaddress string) (models.Node, error) {
 		{"$set", bson.D{
 			{"postup", nodechange.PostUp},
 			{"postdown", nodechange.PostDown},
-			{"isgateway", nodechange.IsGateway},
-			{"gatewayrange", nodechange.GatewayRange},
+			{"isgateway", nodechange.IsEgressGateway},
+			{"gatewayrange", nodechange.EgressGatewayRange},
 			{"lastmodified", nodechange.LastModified},
 		}},
 	}
@@ -674,10 +674,10 @@ func DeleteGateway(network, macaddress string) (models.Node, error) {
 	return node, nil
 }
 // == INGRESS ==
-func createIngress(w http.ResponseWriter, r *http.Request) {
+func createIngressGateway(w http.ResponseWriter, r *http.Request) {
 	var params = mux.Vars(r)
 	w.Header().Set("Content-Type", "application/json")
-	node, err := CreateIngress(params["network"], params["macaddress"])
+	node, err := CreateIngressGateway(params["network"], params["macaddress"])
 	if err != nil {
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
@@ -686,7 +686,7 @@ func createIngress(w http.ResponseWriter, r *http.Request) {
 	json.NewEncoder(w).Encode(node)
 }
 
-func CreateIngress(network string, macaddress string) (models.Node, error) {
+func CreateIngressGateway(network string, macaddress string) (models.Node, error) {
 	node, err := functions.GetNodeByMacAddress(network, macaddress)
 	if err != nil {
 		return models.Node{}, err
@@ -717,10 +717,10 @@ func CreateIngress(network string, macaddress string) (models.Node, error) {
 	return node, nil
 }
 
-func deleteIngress(w http.ResponseWriter, r *http.Request) {
+func deleteIngressGateway(w http.ResponseWriter, r *http.Request) {
 	w.Header().Set("Content-Type", "application/json")
 	var params = mux.Vars(r)
-	node, err := DeleteIngress(params["network"], params["macaddress"])
+	node, err := DeleteIngressGateway(params["network"], params["macaddress"])
 	if err != nil {
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
@@ -729,7 +729,7 @@ func deleteIngress(w http.ResponseWriter, r *http.Request) {
 	json.NewEncoder(w).Encode(node)
 }
 
-func DeleteIngress(network, macaddress string) (models.Node, error) {
+func DeleteIngressGateway(network, macaddress string) (models.Node, error) {
 
 	var nodeupdate models.Node
 	node, err := functions.GetNodeByMacAddress(network, macaddress)

+ 56 - 28
functions/helpers.go

@@ -481,6 +481,34 @@ func GetNodeByMacAddress(network string, macaddress string) (models.Node, error)
 	return node, 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}))
+        if err != nil {
+                return []models.ExtClient{}, err
+        }
+        defer cancel()
+        for cur.Next(context.TODO()) {
+                err := cur.Decode(&extclient)
+                if err != nil {
+                        return []models.ExtClient{}, err
+                }
+                // add node to our array
+                extclients = append(extclients, extclient)
+        }
+
+        //TODO: Fatal error
+        if err := cur.Err(); err != nil {
+                return []models.ExtClient{}, err
+        }
+        return extclients, nil
+}
+
+
 //This returns a unique address for a node to use
 //it iterates through the list of IP's in the subnet
 //and checks against all nodes to see if it's taken, until it finds one.
@@ -506,7 +534,7 @@ func UniqueAddress(networkName string) (string, error) {
 			offset = false
 			continue
 		}
-		if IsIPUnique(networkName, ip.String()) {
+		if IsIPUnique(networkName, ip.String())  && IsIPUniqueExtClients(networkName, ip.String()) {
 			return ip.String(), err
 		}
 	}
@@ -582,6 +610,33 @@ 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 {
+                fmt.Println(err)
+                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 {
@@ -749,30 +804,3 @@ func GetAllNodes() ([]models.ReturnNode, error) {
 	return nodes, nil
 }
 
-func GetAllExternals() ([]models.ReturnNode, error) {
-	var node models.ReturnNode
-	var nodes []models.ReturnNode
-	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.ReturnNode{}, err
-	}
-	defer cancel()
-	for cur.Next(context.TODO()) {
-		err := cur.Decode(&node)
-		if err != nil {
-			return []models.ReturnNode{}, err
-		}
-		// add node to our array
-		nodes = append(nodes, node)
-	}
-
-	//TODO: Fatal error
-	if err := cur.Err(); err != nil {
-		return []models.ReturnNode{}, err
-	}
-	return nodes, nil
-}
-

+ 895 - 1224
grpc/node.pb.go

@@ -1,1647 +1,1318 @@
 // Code generated by protoc-gen-go. DO NOT EDIT.
-// versions:
-// 	protoc-gen-go v1.25.0-devel
-// 	protoc        v3.14.0
 // source: grpc/node.proto
 
 package nodepb
 
 import (
-	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
-	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
-	reflect "reflect"
-	sync "sync"
+	fmt "fmt"
+	proto "github.com/golang/protobuf/proto"
+	math "math"
 )
 
-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)
-)
+// Reference imports to suppress errors if they are not otherwise used.
+var _ = proto.Marshal
+var _ = fmt.Errorf
+var _ = math.Inf
 
-type LoginRequest struct {
-	state         protoimpl.MessageState
-	sizeCache     protoimpl.SizeCache
-	unknownFields protoimpl.UnknownFields
+// 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
 
-	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"`
+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:"-"`
 }
 
-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) 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}
 }
 
-func (x *LoginRequest) String() string {
-	return protoimpl.X.MessageStringOf(x)
+func (m *LoginRequest) XXX_Unmarshal(b []byte) error {
+	return xxx_messageInfo_LoginRequest.Unmarshal(m, b)
 }
-
-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)
+func (m *LoginRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	return xxx_messageInfo_LoginRequest.Marshal(b, m, deterministic)
 }
-
-// Deprecated: Use LoginRequest.ProtoReflect.Descriptor instead.
-func (*LoginRequest) Descriptor() ([]byte, []int) {
-	return file_grpc_node_proto_rawDescGZIP(), []int{0}
+func (m *LoginRequest) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_LoginRequest.Merge(m, src)
+}
+func (m *LoginRequest) XXX_Size() int {
+	return xxx_messageInfo_LoginRequest.Size(m)
+}
+func (m *LoginRequest) XXX_DiscardUnknown() {
+	xxx_messageInfo_LoginRequest.DiscardUnknown(m)
 }
 
-func (x *LoginRequest) GetMacaddress() string {
-	if x != nil {
-		return x.Macaddress
+var xxx_messageInfo_LoginRequest proto.InternalMessageInfo
+
+func (m *LoginRequest) GetMacaddress() string {
+	if m != nil {
+		return m.Macaddress
 	}
 	return ""
 }
 
-func (x *LoginRequest) GetPassword() string {
-	if x != nil {
-		return x.Password
+func (m *LoginRequest) GetPassword() string {
+	if m != nil {
+		return m.Password
 	}
 	return ""
 }
 
-func (x *LoginRequest) GetNetwork() string {
-	if x != nil {
-		return x.Network
+func (m *LoginRequest) GetNetwork() string {
+	if m != nil {
+		return m.Network
 	}
 	return ""
 }
 
 type LoginResponse struct {
-	state         protoimpl.MessageState
-	sizeCache     protoimpl.SizeCache
-	unknownFields protoimpl.UnknownFields
-
-	Accesstoken string `protobuf:"bytes,1,opt,name=accesstoken,proto3" json:"accesstoken,omitempty"`
+	Accesstoken          string   `protobuf:"bytes,1,opt,name=accesstoken,proto3" json:"accesstoken,omitempty"`
+	XXX_NoUnkeyedLiteral struct{} `json:"-"`
+	XXX_unrecognized     []byte   `json:"-"`
+	XXX_sizecache        int32    `json:"-"`
 }
 
-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) 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}
 }
 
-func (x *LoginResponse) String() string {
-	return protoimpl.X.MessageStringOf(x)
+func (m *LoginResponse) XXX_Unmarshal(b []byte) error {
+	return xxx_messageInfo_LoginResponse.Unmarshal(m, b)
 }
-
-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)
+func (m *LoginResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	return xxx_messageInfo_LoginResponse.Marshal(b, m, deterministic)
 }
-
-// Deprecated: Use LoginResponse.ProtoReflect.Descriptor instead.
-func (*LoginResponse) Descriptor() ([]byte, []int) {
-	return file_grpc_node_proto_rawDescGZIP(), []int{1}
+func (m *LoginResponse) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_LoginResponse.Merge(m, src)
+}
+func (m *LoginResponse) XXX_Size() int {
+	return xxx_messageInfo_LoginResponse.Size(m)
 }
+func (m *LoginResponse) XXX_DiscardUnknown() {
+	xxx_messageInfo_LoginResponse.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_LoginResponse proto.InternalMessageInfo
 
-func (x *LoginResponse) GetAccesstoken() string {
-	if x != nil {
-		return x.Accesstoken
+func (m *LoginResponse) GetAccesstoken() string {
+	if m != nil {
+		return m.Accesstoken
 	}
 	return ""
 }
 
 type Node struct {
-	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      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"`
-	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"`
-}
-
-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.
+	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"`
+	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()    {}
 func (*Node) Descriptor() ([]byte, []int) {
-	return file_grpc_node_proto_rawDescGZIP(), []int{2}
+	return fileDescriptor_d13bd996b67da4ef, []int{2}
 }
 
-func (x *Node) GetId() string {
-	if x != nil {
-		return x.Id
+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)
+}
+
+var xxx_messageInfo_Node proto.InternalMessageInfo
+
+func (m *Node) GetId() string {
+	if m != nil {
+		return m.Id
 	}
 	return ""
 }
 
-func (x *Node) GetName() string {
-	if x != nil {
-		return x.Name
+func (m *Node) GetName() string {
+	if m != nil {
+		return m.Name
 	}
 	return ""
 }
 
-func (x *Node) GetAddress() string {
-	if x != nil {
-		return x.Address
+func (m *Node) GetAddress() string {
+	if m != nil {
+		return m.Address
 	}
 	return ""
 }
 
-func (x *Node) GetAddress6() string {
-	if x != nil {
-		return x.Address6
+func (m *Node) GetAddress6() string {
+	if m != nil {
+		return m.Address6
 	}
 	return ""
 }
 
-func (x *Node) GetListenport() int32 {
-	if x != nil {
-		return x.Listenport
+func (m *Node) GetListenport() int32 {
+	if m != nil {
+		return m.Listenport
 	}
 	return 0
 }
 
-func (x *Node) GetPublickey() string {
-	if x != nil {
-		return x.Publickey
+func (m *Node) GetPublickey() string {
+	if m != nil {
+		return m.Publickey
 	}
 	return ""
 }
 
-func (x *Node) GetEndpoint() string {
-	if x != nil {
-		return x.Endpoint
+func (m *Node) GetEndpoint() string {
+	if m != nil {
+		return m.Endpoint
 	}
 	return ""
 }
 
-func (x *Node) GetMacaddress() string {
-	if x != nil {
-		return x.Macaddress
+func (m *Node) GetMacaddress() string {
+	if m != nil {
+		return m.Macaddress
 	}
 	return ""
 }
 
-func (x *Node) GetPassword() string {
-	if x != nil {
-		return x.Password
+func (m *Node) GetPassword() string {
+	if m != nil {
+		return m.Password
 	}
 	return ""
 }
 
-func (x *Node) GetNodenetwork() string {
-	if x != nil {
-		return x.Nodenetwork
+func (m *Node) GetNodenetwork() string {
+	if m != nil {
+		return m.Nodenetwork
 	}
 	return ""
 }
 
-func (x *Node) GetIspending() bool {
-	if x != nil {
-		return x.Ispending
+func (m *Node) GetIspending() bool {
+	if m != nil {
+		return m.Ispending
 	}
 	return false
 }
 
-func (x *Node) GetPostup() string {
-	if x != nil {
-		return x.Postup
+func (m *Node) GetPostup() string {
+	if m != nil {
+		return m.Postup
 	}
 	return ""
 }
 
-func (x *Node) GetPostdown() string {
-	if x != nil {
-		return x.Postdown
+func (m *Node) GetPostdown() string {
+	if m != nil {
+		return m.Postdown
 	}
 	return ""
 }
 
-func (x *Node) GetKeepalive() int32 {
-	if x != nil {
-		return x.Keepalive
+func (m *Node) GetKeepalive() int32 {
+	if m != nil {
+		return m.Keepalive
 	}
 	return 0
 }
 
-func (x *Node) GetSaveconfig() bool {
-	if x != nil {
-		return x.Saveconfig
+func (m *Node) GetSaveconfig() bool {
+	if m != nil {
+		return m.Saveconfig
 	}
 	return false
 }
 
-func (x *Node) GetAccesskey() string {
-	if x != nil {
-		return x.Accesskey
+func (m *Node) GetAccesskey() string {
+	if m != nil {
+		return m.Accesskey
 	}
 	return ""
 }
 
-func (x *Node) GetInterface() string {
-	if x != nil {
-		return x.Interface
+func (m *Node) GetInterface() string {
+	if m != nil {
+		return m.Interface
 	}
 	return ""
 }
 
-func (x *Node) GetLastcheckin() string {
-	if x != nil {
-		return x.Lastcheckin
+func (m *Node) GetLastcheckin() string {
+	if m != nil {
+		return m.Lastcheckin
 	}
 	return ""
 }
 
-func (x *Node) GetLastmodified() string {
-	if x != nil {
-		return x.Lastmodified
+func (m *Node) GetLastmodified() string {
+	if m != nil {
+		return m.Lastmodified
 	}
 	return ""
 }
 
-func (x *Node) GetCheckininterval() int32 {
-	if x != nil {
-		return x.Checkininterval
+func (m *Node) GetCheckininterval() int32 {
+	if m != nil {
+		return m.Checkininterval
 	}
 	return 0
 }
 
-func (x *Node) GetLocaladdress() string {
-	if x != nil {
-		return x.Localaddress
+func (m *Node) GetLocaladdress() string {
+	if m != nil {
+		return m.Localaddress
 	}
 	return ""
 }
 
-func (x *Node) GetPostchanges() string {
-	if x != nil {
-		return x.Postchanges
+func (m *Node) GetPostchanges() string {
+	if m != nil {
+		return m.Postchanges
 	}
 	return ""
 }
 
-func (x *Node) GetAllowedips() string {
-	if x != nil {
-		return x.Allowedips
+func (m *Node) GetAllowedips() string {
+	if m != nil {
+		return m.Allowedips
 	}
 	return ""
 }
 
-func (x *Node) GetIslocal() bool {
-	if x != nil {
-		return x.Islocal
+func (m *Node) GetIslocal() bool {
+	if m != nil {
+		return m.Islocal
 	}
 	return false
 }
 
-func (x *Node) GetIsdualstack() bool {
-	if x != nil {
-		return x.Isdualstack
+func (m *Node) GetIsingressgateway() bool {
+	if m != nil {
+		return m.Isingressgateway
 	}
 	return false
 }
 
-func (x *Node) GetDnsoff() bool {
-	if x != nil {
-		return x.Dnsoff
+func (m *Node) GetIsdualstack() bool {
+	if m != nil {
+		return m.Isdualstack
 	}
 	return false
 }
 
-func (x *Node) GetLocalrange() string {
-	if x != nil {
-		return x.Localrange
+func (m *Node) GetDnsoff() bool {
+	if m != nil {
+		return m.Dnsoff
+	}
+	return false
+}
+
+func (m *Node) GetLocalrange() string {
+	if m != nil {
+		return m.Localrange
 	}
 	return ""
 }
 
 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"`
+	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 *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_Unmarshal(b []byte) error {
+	return xxx_messageInfo_CheckInResponse.Unmarshal(m, b)
 }
-
-func (x *CheckInResponse) String() string {
-	return protoimpl.X.MessageStringOf(x)
+func (m *CheckInResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	return xxx_messageInfo_CheckInResponse.Marshal(b, m, deterministic)
 }
-
-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)
+func (m *CheckInResponse) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_CheckInResponse.Merge(m, src)
 }
-
-// Deprecated: Use CheckInResponse.ProtoReflect.Descriptor instead.
-func (*CheckInResponse) Descriptor() ([]byte, []int) {
-	return file_grpc_node_proto_rawDescGZIP(), []int{3}
+func (m *CheckInResponse) XXX_Size() int {
+	return xxx_messageInfo_CheckInResponse.Size(m)
+}
+func (m *CheckInResponse) XXX_DiscardUnknown() {
+	xxx_messageInfo_CheckInResponse.DiscardUnknown(m)
 }
 
-func (x *CheckInResponse) GetSuccess() bool {
-	if x != nil {
-		return x.Success
+var xxx_messageInfo_CheckInResponse proto.InternalMessageInfo
+
+func (m *CheckInResponse) GetSuccess() bool {
+	if m != nil {
+		return m.Success
 	}
 	return false
 }
 
-func (x *CheckInResponse) GetNeedpeerupdate() bool {
-	if x != nil {
-		return x.Needpeerupdate
+func (m *CheckInResponse) GetNeedpeerupdate() bool {
+	if m != nil {
+		return m.Needpeerupdate
 	}
 	return false
 }
 
-func (x *CheckInResponse) GetNeedconfigupdate() bool {
-	if x != nil {
-		return x.Needconfigupdate
+func (m *CheckInResponse) GetNeedconfigupdate() bool {
+	if m != nil {
+		return m.Needconfigupdate
 	}
 	return false
 }
 
-func (x *CheckInResponse) GetNodemessage() string {
-	if x != nil {
-		return x.Nodemessage
+func (m *CheckInResponse) GetNodemessage() string {
+	if m != nil {
+		return m.Nodemessage
 	}
 	return ""
 }
 
-func (x *CheckInResponse) GetIspending() bool {
-	if x != nil {
-		return x.Ispending
+func (m *CheckInResponse) GetIspending() bool {
+	if m != nil {
+		return m.Ispending
 	}
 	return false
 }
 
-func (x *CheckInResponse) GetNeedkeyupdate() bool {
-	if x != nil {
-		return x.Needkeyupdate
+func (m *CheckInResponse) GetNeedkeyupdate() bool {
+	if m != nil {
+		return m.Needkeyupdate
 	}
 	return false
 }
 
-func (x *CheckInResponse) GetNeeddelete() bool {
-	if x != nil {
-		return x.Needdelete
+func (m *CheckInResponse) GetNeeddelete() bool {
+	if m != nil {
+		return m.Needdelete
 	}
 	return false
 }
 
 type PeersResponse struct {
-	state         protoimpl.MessageState
-	sizeCache     protoimpl.SizeCache
-	unknownFields protoimpl.UnknownFields
-
-	Isgateway    bool   `protobuf:"varint,1,opt,name=isgateway,proto3" json:"isgateway,omitempty"`
-	Gatewayrange string `protobuf:"bytes,2,opt,name=gatewayrange,proto3" json:"gatewayrange,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"`
+	Isegressgateway      bool     `protobuf:"varint,1,opt,name=isegressgateway,proto3" json:"isegressgateway,omitempty"`
+	Egressgatewayrange   string   `protobuf:"bytes,2,opt,name=egressgatewayrange,proto3" json:"egressgatewayrange,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}
 }
 
-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_Unmarshal(b []byte) error {
+	return xxx_messageInfo_PeersResponse.Unmarshal(m, b)
 }
-
-func (x *PeersResponse) String() string {
-	return protoimpl.X.MessageStringOf(x)
+func (m *PeersResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	return xxx_messageInfo_PeersResponse.Marshal(b, m, deterministic)
 }
-
-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)
+func (m *PeersResponse) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_PeersResponse.Merge(m, src)
 }
-
-// Deprecated: Use PeersResponse.ProtoReflect.Descriptor instead.
-func (*PeersResponse) Descriptor() ([]byte, []int) {
-	return file_grpc_node_proto_rawDescGZIP(), []int{4}
+func (m *PeersResponse) XXX_Size() int {
+	return xxx_messageInfo_PeersResponse.Size(m)
+}
+func (m *PeersResponse) XXX_DiscardUnknown() {
+	xxx_messageInfo_PeersResponse.DiscardUnknown(m)
 }
 
-func (x *PeersResponse) GetIsgateway() bool {
-	if x != nil {
-		return x.Isgateway
+var xxx_messageInfo_PeersResponse proto.InternalMessageInfo
+
+func (m *PeersResponse) GetIsegressgateway() bool {
+	if m != nil {
+		return m.Isegressgateway
 	}
 	return false
 }
 
-func (x *PeersResponse) GetGatewayrange() string {
-	if x != nil {
-		return x.Gatewayrange
+func (m *PeersResponse) GetEgressgatewayrange() string {
+	if m != nil {
+		return m.Egressgatewayrange
 	}
 	return ""
 }
 
-func (x *PeersResponse) GetPublickey() string {
-	if x != nil {
-		return x.Publickey
+func (m *PeersResponse) GetPublickey() string {
+	if m != nil {
+		return m.Publickey
 	}
 	return ""
 }
 
-func (x *PeersResponse) GetEndpoint() string {
-	if x != nil {
-		return x.Endpoint
+func (m *PeersResponse) GetEndpoint() string {
+	if m != nil {
+		return m.Endpoint
 	}
 	return ""
 }
 
-func (x *PeersResponse) GetAddress() string {
-	if x != nil {
-		return x.Address
+func (m *PeersResponse) GetAddress() string {
+	if m != nil {
+		return m.Address
 	}
 	return ""
 }
 
-func (x *PeersResponse) GetAddress6() string {
-	if x != nil {
-		return x.Address6
+func (m *PeersResponse) GetAddress6() string {
+	if m != nil {
+		return m.Address6
 	}
 	return ""
 }
 
-func (x *PeersResponse) GetListenport() int32 {
-	if x != nil {
-		return x.Listenport
+func (m *PeersResponse) GetListenport() int32 {
+	if m != nil {
+		return m.Listenport
 	}
 	return 0
 }
 
-func (x *PeersResponse) GetLocaladdress() string {
-	if x != nil {
-		return x.Localaddress
+func (m *PeersResponse) GetLocaladdress() string {
+	if m != nil {
+		return m.Localaddress
 	}
 	return ""
 }
 
-func (x *PeersResponse) GetKeepalive() int32 {
-	if x != nil {
-		return x.Keepalive
+func (m *PeersResponse) GetKeepalive() int32 {
+	if m != nil {
+		return m.Keepalive
 	}
 	return 0
 }
 
-type CreateNodeReq struct {
-	state         protoimpl.MessageState
-	sizeCache     protoimpl.SizeCache
-	unknownFields protoimpl.UnknownFields
-
-	Node *Node `protobuf:"bytes,1,opt,name=node,proto3" json:"node,omitempty"` // Node id blank
+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 (x *CreateNodeReq) Reset() {
-	*x = CreateNodeReq{}
-	if protoimpl.UnsafeEnabled {
-		mi := &file_grpc_node_proto_msgTypes[5]
-		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
-		ms.StoreMessageInfo(mi)
-	}
+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}
 }
 
-func (x *CreateNodeReq) String() string {
-	return protoimpl.X.MessageStringOf(x)
+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)
+}
+func (m *ExtPeersResponse) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_ExtPeersResponse.Merge(m, src)
+}
+func (m *ExtPeersResponse) XXX_Size() int {
+	return xxx_messageInfo_ExtPeersResponse.Size(m)
+}
+func (m *ExtPeersResponse) XXX_DiscardUnknown() {
+	xxx_messageInfo_ExtPeersResponse.DiscardUnknown(m)
 }
 
-func (*CreateNodeReq) ProtoMessage() {}
+var xxx_messageInfo_ExtPeersResponse proto.InternalMessageInfo
 
-func (x *CreateNodeReq) 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
+func (m *ExtPeersResponse) GetPublickey() string {
+	if m != nil {
+		return m.Publickey
 	}
-	return mi.MessageOf(x)
+	return ""
 }
 
-// Deprecated: Use CreateNodeReq.ProtoReflect.Descriptor instead.
-func (*CreateNodeReq) Descriptor() ([]byte, []int) {
-	return file_grpc_node_proto_rawDescGZIP(), []int{5}
+func (m *ExtPeersResponse) GetEndpoint() string {
+	if m != nil {
+		return m.Endpoint
+	}
+	return ""
 }
 
-func (x *CreateNodeReq) GetNode() *Node {
-	if x != nil {
-		return x.Node
+func (m *ExtPeersResponse) GetAddress() string {
+	if m != nil {
+		return m.Address
 	}
-	return nil
+	return ""
 }
 
-type CreateNodeRes struct {
-	state         protoimpl.MessageState
-	sizeCache     protoimpl.SizeCache
-	unknownFields protoimpl.UnknownFields
+func (m *ExtPeersResponse) GetAddress6() string {
+	if m != nil {
+		return m.Address6
+	}
+	return ""
+}
 
-	Node *Node `protobuf:"bytes,1,opt,name=node,proto3" json:"node,omitempty"` // Node id filled in
+func (m *ExtPeersResponse) GetListenport() int32 {
+	if m != nil {
+		return m.Listenport
+	}
+	return 0
 }
 
-func (x *CreateNodeRes) Reset() {
-	*x = CreateNodeRes{}
-	if protoimpl.UnsafeEnabled {
-		mi := &file_grpc_node_proto_msgTypes[6]
-		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
-		ms.StoreMessageInfo(mi)
+func (m *ExtPeersResponse) GetLocaladdress() string {
+	if m != nil {
+		return m.Localaddress
 	}
+	return ""
 }
 
-func (x *CreateNodeRes) String() string {
-	return protoimpl.X.MessageStringOf(x)
+func (m *ExtPeersResponse) GetKeepalive() int32 {
+	if m != nil {
+		return m.Keepalive
+	}
+	return 0
 }
 
-func (*CreateNodeRes) ProtoMessage() {}
+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:"-"`
+}
 
-func (x *CreateNodeRes) 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)
+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{6}
 }
 
-// Deprecated: Use CreateNodeRes.ProtoReflect.Descriptor instead.
-func (*CreateNodeRes) Descriptor() ([]byte, []int) {
-	return file_grpc_node_proto_rawDescGZIP(), []int{6}
+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 (m *CreateNodeReq) XXX_Size() int {
+	return xxx_messageInfo_CreateNodeReq.Size(m)
+}
+func (m *CreateNodeReq) XXX_DiscardUnknown() {
+	xxx_messageInfo_CreateNodeReq.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_CreateNodeReq proto.InternalMessageInfo
 
-func (x *CreateNodeRes) GetNode() *Node {
-	if x != nil {
-		return x.Node
+func (m *CreateNodeReq) GetNode() *Node {
+	if m != nil {
+		return m.Node
 	}
 	return nil
 }
 
-type UpdateNodeReq struct {
-	state         protoimpl.MessageState
-	sizeCache     protoimpl.SizeCache
-	unknownFields protoimpl.UnknownFields
-
-	Node *Node `protobuf:"bytes,1,opt,name=node,proto3" json:"node,omitempty"`
+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:"-"`
 }
 
-func (x *UpdateNodeReq) Reset() {
-	*x = UpdateNodeReq{}
-	if protoimpl.UnsafeEnabled {
-		mi := &file_grpc_node_proto_msgTypes[7]
-		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
-		ms.StoreMessageInfo(mi)
-	}
+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{7}
 }
 
-func (x *UpdateNodeReq) String() string {
-	return protoimpl.X.MessageStringOf(x)
+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 (m *CreateNodeRes) XXX_Size() int {
+	return xxx_messageInfo_CreateNodeRes.Size(m)
+}
+func (m *CreateNodeRes) XXX_DiscardUnknown() {
+	xxx_messageInfo_CreateNodeRes.DiscardUnknown(m)
 }
 
-func (*UpdateNodeReq) ProtoMessage() {}
+var xxx_messageInfo_CreateNodeRes proto.InternalMessageInfo
 
-func (x *UpdateNodeReq) 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
+func (m *CreateNodeRes) GetNode() *Node {
+	if m != nil {
+		return m.Node
 	}
-	return mi.MessageOf(x)
+	return nil
 }
 
-// Deprecated: Use UpdateNodeReq.ProtoReflect.Descriptor instead.
+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:"-"`
+}
+
+func (m *UpdateNodeReq) Reset()         { *m = UpdateNodeReq{} }
+func (m *UpdateNodeReq) String() string { return proto.CompactTextString(m) }
+func (*UpdateNodeReq) ProtoMessage()    {}
 func (*UpdateNodeReq) Descriptor() ([]byte, []int) {
-	return file_grpc_node_proto_rawDescGZIP(), []int{7}
+	return fileDescriptor_d13bd996b67da4ef, []int{8}
+}
+
+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 (m *UpdateNodeReq) XXX_Size() int {
+	return xxx_messageInfo_UpdateNodeReq.Size(m)
+}
+func (m *UpdateNodeReq) XXX_DiscardUnknown() {
+	xxx_messageInfo_UpdateNodeReq.DiscardUnknown(m)
 }
 
-func (x *UpdateNodeReq) GetNode() *Node {
-	if x != nil {
-		return x.Node
+var xxx_messageInfo_UpdateNodeReq proto.InternalMessageInfo
+
+func (m *UpdateNodeReq) GetNode() *Node {
+	if m != nil {
+		return m.Node
 	}
 	return nil
 }
 
 type UpdateNodeRes struct {
-	state         protoimpl.MessageState
-	sizeCache     protoimpl.SizeCache
-	unknownFields protoimpl.UnknownFields
-
-	Node *Node `protobuf:"bytes,1,opt,name=node,proto3" json:"node,omitempty"`
+	Node                 *Node    `protobuf:"bytes,1,opt,name=node,proto3" json:"node,omitempty"`
+	XXX_NoUnkeyedLiteral struct{} `json:"-"`
+	XXX_unrecognized     []byte   `json:"-"`
+	XXX_sizecache        int32    `json:"-"`
 }
 
-func (x *UpdateNodeRes) Reset() {
-	*x = UpdateNodeRes{}
-	if protoimpl.UnsafeEnabled {
-		mi := &file_grpc_node_proto_msgTypes[8]
-		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
-		ms.StoreMessageInfo(mi)
-	}
+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{9}
 }
 
-func (x *UpdateNodeRes) String() string {
-	return protoimpl.X.MessageStringOf(x)
+func (m *UpdateNodeRes) XXX_Unmarshal(b []byte) error {
+	return xxx_messageInfo_UpdateNodeRes.Unmarshal(m, b)
 }
-
-func (*UpdateNodeRes) ProtoMessage() {}
-
-func (x *UpdateNodeRes) 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)
+func (m *UpdateNodeRes) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	return xxx_messageInfo_UpdateNodeRes.Marshal(b, m, deterministic)
 }
-
-// Deprecated: Use UpdateNodeRes.ProtoReflect.Descriptor instead.
-func (*UpdateNodeRes) Descriptor() ([]byte, []int) {
-	return file_grpc_node_proto_rawDescGZIP(), []int{8}
+func (m *UpdateNodeRes) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_UpdateNodeRes.Merge(m, src)
+}
+func (m *UpdateNodeRes) XXX_Size() int {
+	return xxx_messageInfo_UpdateNodeRes.Size(m)
+}
+func (m *UpdateNodeRes) XXX_DiscardUnknown() {
+	xxx_messageInfo_UpdateNodeRes.DiscardUnknown(m)
 }
 
-func (x *UpdateNodeRes) GetNode() *Node {
-	if x != nil {
-		return x.Node
+var xxx_messageInfo_UpdateNodeRes proto.InternalMessageInfo
+
+func (m *UpdateNodeRes) GetNode() *Node {
+	if m != nil {
+		return m.Node
 	}
 	return nil
 }
 
 type ReadNodeReq struct {
-	state         protoimpl.MessageState
-	sizeCache     protoimpl.SizeCache
-	unknownFields protoimpl.UnknownFields
-
-	Macaddress string `protobuf:"bytes,1,opt,name=macaddress,proto3" json:"macaddress,omitempty"`
-	Network    string `protobuf:"bytes,2,opt,name=network,proto3" json:"network,omitempty"`
+	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:"-"`
 }
 
-func (x *ReadNodeReq) Reset() {
-	*x = ReadNodeReq{}
-	if protoimpl.UnsafeEnabled {
-		mi := &file_grpc_node_proto_msgTypes[9]
-		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
-		ms.StoreMessageInfo(mi)
-	}
+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{10}
 }
 
-func (x *ReadNodeReq) String() string {
-	return protoimpl.X.MessageStringOf(x)
+func (m *ReadNodeReq) XXX_Unmarshal(b []byte) error {
+	return xxx_messageInfo_ReadNodeReq.Unmarshal(m, b)
 }
-
-func (*ReadNodeReq) ProtoMessage() {}
-
-func (x *ReadNodeReq) 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)
+func (m *ReadNodeReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	return xxx_messageInfo_ReadNodeReq.Marshal(b, m, deterministic)
 }
-
-// Deprecated: Use ReadNodeReq.ProtoReflect.Descriptor instead.
-func (*ReadNodeReq) Descriptor() ([]byte, []int) {
-	return file_grpc_node_proto_rawDescGZIP(), []int{9}
+func (m *ReadNodeReq) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_ReadNodeReq.Merge(m, src)
+}
+func (m *ReadNodeReq) XXX_Size() int {
+	return xxx_messageInfo_ReadNodeReq.Size(m)
+}
+func (m *ReadNodeReq) XXX_DiscardUnknown() {
+	xxx_messageInfo_ReadNodeReq.DiscardUnknown(m)
 }
 
-func (x *ReadNodeReq) GetMacaddress() string {
-	if x != nil {
-		return x.Macaddress
+var xxx_messageInfo_ReadNodeReq proto.InternalMessageInfo
+
+func (m *ReadNodeReq) GetMacaddress() string {
+	if m != nil {
+		return m.Macaddress
 	}
 	return ""
 }
 
-func (x *ReadNodeReq) GetNetwork() string {
-	if x != nil {
-		return x.Network
+func (m *ReadNodeReq) GetNetwork() string {
+	if m != nil {
+		return m.Network
 	}
 	return ""
 }
 
 type ReadNodeRes struct {
-	state         protoimpl.MessageState
-	sizeCache     protoimpl.SizeCache
-	unknownFields protoimpl.UnknownFields
-
-	Node *Node `protobuf:"bytes,1,opt,name=node,proto3" json:"node,omitempty"`
+	Node                 *Node    `protobuf:"bytes,1,opt,name=node,proto3" json:"node,omitempty"`
+	XXX_NoUnkeyedLiteral struct{} `json:"-"`
+	XXX_unrecognized     []byte   `json:"-"`
+	XXX_sizecache        int32    `json:"-"`
 }
 
-func (x *ReadNodeRes) Reset() {
-	*x = ReadNodeRes{}
-	if protoimpl.UnsafeEnabled {
-		mi := &file_grpc_node_proto_msgTypes[10]
-		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
-		ms.StoreMessageInfo(mi)
-	}
+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{11}
 }
 
-func (x *ReadNodeRes) String() string {
-	return protoimpl.X.MessageStringOf(x)
+func (m *ReadNodeRes) XXX_Unmarshal(b []byte) error {
+	return xxx_messageInfo_ReadNodeRes.Unmarshal(m, b)
 }
-
-func (*ReadNodeRes) ProtoMessage() {}
-
-func (x *ReadNodeRes) 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)
+func (m *ReadNodeRes) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	return xxx_messageInfo_ReadNodeRes.Marshal(b, m, deterministic)
 }
-
-// Deprecated: Use ReadNodeRes.ProtoReflect.Descriptor instead.
-func (*ReadNodeRes) Descriptor() ([]byte, []int) {
-	return file_grpc_node_proto_rawDescGZIP(), []int{10}
+func (m *ReadNodeRes) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_ReadNodeRes.Merge(m, src)
 }
+func (m *ReadNodeRes) XXX_Size() int {
+	return xxx_messageInfo_ReadNodeRes.Size(m)
+}
+func (m *ReadNodeRes) XXX_DiscardUnknown() {
+	xxx_messageInfo_ReadNodeRes.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_ReadNodeRes proto.InternalMessageInfo
 
-func (x *ReadNodeRes) GetNode() *Node {
-	if x != nil {
-		return x.Node
+func (m *ReadNodeRes) GetNode() *Node {
+	if m != nil {
+		return m.Node
 	}
 	return nil
 }
 
 type DeleteNodeReq struct {
-	state         protoimpl.MessageState
-	sizeCache     protoimpl.SizeCache
-	unknownFields protoimpl.UnknownFields
-
-	Macaddress  string `protobuf:"bytes,1,opt,name=macaddress,proto3" json:"macaddress,omitempty"`
-	NetworkName string `protobuf:"bytes,2,opt,name=networkName,proto3" json:"networkName,omitempty"`
+	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:"-"`
 }
 
-func (x *DeleteNodeReq) Reset() {
-	*x = DeleteNodeReq{}
-	if protoimpl.UnsafeEnabled {
-		mi := &file_grpc_node_proto_msgTypes[11]
-		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
-		ms.StoreMessageInfo(mi)
-	}
+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{12}
 }
 
-func (x *DeleteNodeReq) String() string {
-	return protoimpl.X.MessageStringOf(x)
+func (m *DeleteNodeReq) XXX_Unmarshal(b []byte) error {
+	return xxx_messageInfo_DeleteNodeReq.Unmarshal(m, b)
 }
-
-func (*DeleteNodeReq) ProtoMessage() {}
-
-func (x *DeleteNodeReq) 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)
+func (m *DeleteNodeReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	return xxx_messageInfo_DeleteNodeReq.Marshal(b, m, deterministic)
 }
-
-// Deprecated: Use DeleteNodeReq.ProtoReflect.Descriptor instead.
-func (*DeleteNodeReq) Descriptor() ([]byte, []int) {
-	return file_grpc_node_proto_rawDescGZIP(), []int{11}
+func (m *DeleteNodeReq) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_DeleteNodeReq.Merge(m, src)
+}
+func (m *DeleteNodeReq) XXX_Size() int {
+	return xxx_messageInfo_DeleteNodeReq.Size(m)
 }
+func (m *DeleteNodeReq) XXX_DiscardUnknown() {
+	xxx_messageInfo_DeleteNodeReq.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_DeleteNodeReq proto.InternalMessageInfo
 
-func (x *DeleteNodeReq) GetMacaddress() string {
-	if x != nil {
-		return x.Macaddress
+func (m *DeleteNodeReq) GetMacaddress() string {
+	if m != nil {
+		return m.Macaddress
 	}
 	return ""
 }
 
-func (x *DeleteNodeReq) GetNetworkName() string {
-	if x != nil {
-		return x.NetworkName
+func (m *DeleteNodeReq) GetNetworkName() string {
+	if m != nil {
+		return m.NetworkName
 	}
 	return ""
 }
 
 type DeleteNodeRes struct {
-	state         protoimpl.MessageState
-	sizeCache     protoimpl.SizeCache
-	unknownFields protoimpl.UnknownFields
-
-	Success bool `protobuf:"varint,1,opt,name=success,proto3" json:"success,omitempty"`
+	Success              bool     `protobuf:"varint,1,opt,name=success,proto3" json:"success,omitempty"`
+	XXX_NoUnkeyedLiteral struct{} `json:"-"`
+	XXX_unrecognized     []byte   `json:"-"`
+	XXX_sizecache        int32    `json:"-"`
 }
 
-func (x *DeleteNodeRes) Reset() {
-	*x = DeleteNodeRes{}
-	if protoimpl.UnsafeEnabled {
-		mi := &file_grpc_node_proto_msgTypes[12]
-		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
-		ms.StoreMessageInfo(mi)
-	}
+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{13}
 }
 
-func (x *DeleteNodeRes) String() string {
-	return protoimpl.X.MessageStringOf(x)
+func (m *DeleteNodeRes) XXX_Unmarshal(b []byte) error {
+	return xxx_messageInfo_DeleteNodeRes.Unmarshal(m, b)
 }
-
-func (*DeleteNodeRes) ProtoMessage() {}
-
-func (x *DeleteNodeRes) 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)
+func (m *DeleteNodeRes) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	return xxx_messageInfo_DeleteNodeRes.Marshal(b, m, deterministic)
 }
-
-// Deprecated: Use DeleteNodeRes.ProtoReflect.Descriptor instead.
-func (*DeleteNodeRes) Descriptor() ([]byte, []int) {
-	return file_grpc_node_proto_rawDescGZIP(), []int{12}
+func (m *DeleteNodeRes) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_DeleteNodeRes.Merge(m, src)
+}
+func (m *DeleteNodeRes) XXX_Size() int {
+	return xxx_messageInfo_DeleteNodeRes.Size(m)
+}
+func (m *DeleteNodeRes) XXX_DiscardUnknown() {
+	xxx_messageInfo_DeleteNodeRes.DiscardUnknown(m)
 }
 
-func (x *DeleteNodeRes) GetSuccess() bool {
-	if x != nil {
-		return x.Success
+var xxx_messageInfo_DeleteNodeRes proto.InternalMessageInfo
+
+func (m *DeleteNodeRes) GetSuccess() bool {
+	if m != nil {
+		return m.Success
 	}
 	return false
 }
 
 type GetPeersReq struct {
-	state         protoimpl.MessageState
-	sizeCache     protoimpl.SizeCache
-	unknownFields protoimpl.UnknownFields
+	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:"-"`
+}
 
-	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) Reset()         { *m = GetPeersReq{} }
+func (m *GetPeersReq) String() string { return proto.CompactTextString(m) }
+func (*GetPeersReq) ProtoMessage()    {}
+func (*GetPeersReq) Descriptor() ([]byte, []int) {
+	return fileDescriptor_d13bd996b67da4ef, []int{14}
 }
 
-func (x *GetPeersReq) Reset() {
-	*x = GetPeersReq{}
-	if protoimpl.UnsafeEnabled {
-		mi := &file_grpc_node_proto_msgTypes[13]
-		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
-		ms.StoreMessageInfo(mi)
+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 (m *GetPeersReq) XXX_Size() int {
+	return xxx_messageInfo_GetPeersReq.Size(m)
+}
+func (m *GetPeersReq) XXX_DiscardUnknown() {
+	xxx_messageInfo_GetPeersReq.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_GetPeersReq proto.InternalMessageInfo
+
+func (m *GetPeersReq) GetMacaddress() string {
+	if m != nil {
+		return m.Macaddress
 	}
+	return ""
 }
 
-func (x *GetPeersReq) String() string {
-	return protoimpl.X.MessageStringOf(x)
+func (m *GetPeersReq) GetNetwork() string {
+	if m != nil {
+		return m.Network
+	}
+	return ""
 }
 
-func (*GetPeersReq) ProtoMessage() {}
+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:"-"`
+}
 
-func (x *GetPeersReq) 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)
+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{15}
 }
 
-// Deprecated: Use GetPeersReq.ProtoReflect.Descriptor instead.
-func (*GetPeersReq) Descriptor() ([]byte, []int) {
-	return file_grpc_node_proto_rawDescGZIP(), []int{13}
+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 (m *GetExtPeersReq) XXX_Size() int {
+	return xxx_messageInfo_GetExtPeersReq.Size(m)
+}
+func (m *GetExtPeersReq) XXX_DiscardUnknown() {
+	xxx_messageInfo_GetExtPeersReq.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_GetExtPeersReq proto.InternalMessageInfo
 
-func (x *GetPeersReq) GetMacaddress() string {
-	if x != nil {
-		return x.Macaddress
+func (m *GetExtPeersReq) GetMacaddress() string {
+	if m != nil {
+		return m.Macaddress
 	}
 	return ""
 }
 
-func (x *GetPeersReq) GetNetwork() string {
-	if x != nil {
-		return x.Network
+func (m *GetExtPeersReq) GetNetwork() string {
+	if m != nil {
+		return m.Network
 	}
 	return ""
 }
 
 type GetPeersRes struct {
-	state         protoimpl.MessageState
-	sizeCache     protoimpl.SizeCache
-	unknownFields protoimpl.UnknownFields
-
-	Peers *PeersResponse `protobuf:"bytes,1,opt,name=peers,proto3" json:"peers,omitempty"`
+	Peers                *PeersResponse `protobuf:"bytes,1,opt,name=peers,proto3" json:"peers,omitempty"`
+	XXX_NoUnkeyedLiteral struct{}       `json:"-"`
+	XXX_unrecognized     []byte         `json:"-"`
+	XXX_sizecache        int32          `json:"-"`
 }
 
-func (x *GetPeersRes) Reset() {
-	*x = GetPeersRes{}
-	if protoimpl.UnsafeEnabled {
-		mi := &file_grpc_node_proto_msgTypes[14]
-		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
-		ms.StoreMessageInfo(mi)
-	}
+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{16}
 }
 
-func (x *GetPeersRes) String() string {
-	return protoimpl.X.MessageStringOf(x)
+func (m *GetPeersRes) XXX_Unmarshal(b []byte) error {
+	return xxx_messageInfo_GetPeersRes.Unmarshal(m, b)
 }
-
-func (*GetPeersRes) ProtoMessage() {}
-
-func (x *GetPeersRes) 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)
+func (m *GetPeersRes) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	return xxx_messageInfo_GetPeersRes.Marshal(b, m, deterministic)
 }
-
-// Deprecated: Use GetPeersRes.ProtoReflect.Descriptor instead.
-func (*GetPeersRes) Descriptor() ([]byte, []int) {
-	return file_grpc_node_proto_rawDescGZIP(), []int{14}
+func (m *GetPeersRes) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_GetPeersRes.Merge(m, src)
+}
+func (m *GetPeersRes) XXX_Size() int {
+	return xxx_messageInfo_GetPeersRes.Size(m)
 }
+func (m *GetPeersRes) XXX_DiscardUnknown() {
+	xxx_messageInfo_GetPeersRes.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_GetPeersRes proto.InternalMessageInfo
 
-func (x *GetPeersRes) GetPeers() *PeersResponse {
-	if x != nil {
-		return x.Peers
+func (m *GetPeersRes) GetPeers() *PeersResponse {
+	if m != nil {
+		return m.Peers
 	}
 	return nil
 }
 
-type CheckInReq struct {
-	state         protoimpl.MessageState
-	sizeCache     protoimpl.SizeCache
-	unknownFields protoimpl.UnknownFields
-
-	Node *Node `protobuf:"bytes,1,opt,name=node,proto3" json:"node,omitempty"` //   bool postchanges = 2;
+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:"-"`
 }
 
-func (x *CheckInReq) Reset() {
-	*x = CheckInReq{}
-	if protoimpl.UnsafeEnabled {
-		mi := &file_grpc_node_proto_msgTypes[15]
-		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
-		ms.StoreMessageInfo(mi)
-	}
+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{17}
 }
 
-func (x *CheckInReq) String() string {
-	return protoimpl.X.MessageStringOf(x)
+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 (m *GetExtPeersRes) XXX_Size() int {
+	return xxx_messageInfo_GetExtPeersRes.Size(m)
+}
+func (m *GetExtPeersRes) XXX_DiscardUnknown() {
+	xxx_messageInfo_GetExtPeersRes.DiscardUnknown(m)
 }
 
-func (*CheckInReq) ProtoMessage() {}
+var xxx_messageInfo_GetExtPeersRes proto.InternalMessageInfo
 
-func (x *CheckInReq) 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
+func (m *GetExtPeersRes) GetExtpeers() *ExtPeersResponse {
+	if m != nil {
+		return m.Extpeers
 	}
-	return mi.MessageOf(x)
+	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:"-"`
 }
 
-// Deprecated: Use CheckInReq.ProtoReflect.Descriptor instead.
+func (m *CheckInReq) Reset()         { *m = CheckInReq{} }
+func (m *CheckInReq) String() string { return proto.CompactTextString(m) }
+func (*CheckInReq) ProtoMessage()    {}
 func (*CheckInReq) Descriptor() ([]byte, []int) {
-	return file_grpc_node_proto_rawDescGZIP(), []int{15}
+	return fileDescriptor_d13bd996b67da4ef, []int{18}
+}
+
+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 (m *CheckInReq) XXX_Size() int {
+	return xxx_messageInfo_CheckInReq.Size(m)
+}
+func (m *CheckInReq) XXX_DiscardUnknown() {
+	xxx_messageInfo_CheckInReq.DiscardUnknown(m)
 }
 
-func (x *CheckInReq) GetNode() *Node {
-	if x != nil {
-		return x.Node
+var xxx_messageInfo_CheckInReq proto.InternalMessageInfo
+
+func (m *CheckInReq) GetNode() *Node {
+	if m != nil {
+		return m.Node
 	}
 	return nil
 }
 
 type CheckInRes struct {
-	state         protoimpl.MessageState
-	sizeCache     protoimpl.SizeCache
-	unknownFields protoimpl.UnknownFields
-
-	Checkinresponse *CheckInResponse `protobuf:"bytes,1,opt,name=checkinresponse,proto3" json:"checkinresponse,omitempty"`
+	Checkinresponse      *CheckInResponse `protobuf:"bytes,1,opt,name=checkinresponse,proto3" json:"checkinresponse,omitempty"`
+	XXX_NoUnkeyedLiteral struct{}         `json:"-"`
+	XXX_unrecognized     []byte           `json:"-"`
+	XXX_sizecache        int32            `json:"-"`
 }
 
-func (x *CheckInRes) Reset() {
-	*x = CheckInRes{}
-	if protoimpl.UnsafeEnabled {
-		mi := &file_grpc_node_proto_msgTypes[16]
-		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
-		ms.StoreMessageInfo(mi)
-	}
+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{19}
 }
 
-func (x *CheckInRes) String() string {
-	return protoimpl.X.MessageStringOf(x)
+func (m *CheckInRes) XXX_Unmarshal(b []byte) error {
+	return xxx_messageInfo_CheckInRes.Unmarshal(m, b)
 }
-
-func (*CheckInRes) ProtoMessage() {}
-
-func (x *CheckInRes) 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)
+func (m *CheckInRes) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	return xxx_messageInfo_CheckInRes.Marshal(b, m, deterministic)
 }
-
-// Deprecated: Use CheckInRes.ProtoReflect.Descriptor instead.
-func (*CheckInRes) Descriptor() ([]byte, []int) {
-	return file_grpc_node_proto_rawDescGZIP(), []int{16}
+func (m *CheckInRes) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_CheckInRes.Merge(m, src)
+}
+func (m *CheckInRes) XXX_Size() int {
+	return xxx_messageInfo_CheckInRes.Size(m)
+}
+func (m *CheckInRes) XXX_DiscardUnknown() {
+	xxx_messageInfo_CheckInRes.DiscardUnknown(m)
 }
 
-func (x *CheckInRes) GetCheckinresponse() *CheckInResponse {
-	if x != nil {
-		return x.Checkinresponse
+var xxx_messageInfo_CheckInRes proto.InternalMessageInfo
+
+func (m *CheckInRes) GetCheckinresponse() *CheckInResponse {
+	if m != nil {
+		return m.Checkinresponse
 	}
 	return nil
 }
 
-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, 0xae, 0x06, 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, 0x08, 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, 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, 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, 0xa3, 0x02, 0x0a, 0x0d, 0x50, 0x65,
-	0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x69,
-	0x73, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09,
-	0x69, 0x73, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x12, 0x22, 0x0a, 0x0c, 0x67, 0x61, 0x74,
-	0x65, 0x77, 0x61, 0x79, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52,
-	0x0c, 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,
-	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, 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, 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, 0xfc, 0x02, 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, 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, 17)
-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
-	(*CreateNodeReq)(nil),   // 5: node.CreateNodeReq
-	(*CreateNodeRes)(nil),   // 6: node.CreateNodeRes
-	(*UpdateNodeReq)(nil),   // 7: node.UpdateNodeReq
-	(*UpdateNodeRes)(nil),   // 8: node.UpdateNodeRes
-	(*ReadNodeReq)(nil),     // 9: node.ReadNodeReq
-	(*ReadNodeRes)(nil),     // 10: node.ReadNodeRes
-	(*DeleteNodeReq)(nil),   // 11: node.DeleteNodeReq
-	(*DeleteNodeRes)(nil),   // 12: node.DeleteNodeRes
-	(*GetPeersReq)(nil),     // 13: node.GetPeersReq
-	(*GetPeersRes)(nil),     // 14: node.GetPeersRes
-	(*CheckInReq)(nil),      // 15: node.CheckInReq
-	(*CheckInRes)(nil),      // 16: 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
-	2,  // 6: node.CheckInReq.node:type_name -> node.Node
-	3,  // 7: node.CheckInRes.checkinresponse:type_name -> node.CheckInResponse
-	0,  // 8: node.NodeService.Login:input_type -> node.LoginRequest
-	5,  // 9: node.NodeService.CreateNode:input_type -> node.CreateNodeReq
-	9,  // 10: node.NodeService.ReadNode:input_type -> node.ReadNodeReq
-	7,  // 11: node.NodeService.UpdateNode:input_type -> node.UpdateNodeReq
-	11, // 12: node.NodeService.DeleteNode:input_type -> node.DeleteNodeReq
-	13, // 13: node.NodeService.GetPeers:input_type -> node.GetPeersReq
-	15, // 14: node.NodeService.CheckIn:input_type -> node.CheckInReq
-	1,  // 15: node.NodeService.Login:output_type -> node.LoginResponse
-	6,  // 16: node.NodeService.CreateNode:output_type -> node.CreateNodeRes
-	10, // 17: node.NodeService.ReadNode:output_type -> node.ReadNodeRes
-	8,  // 18: node.NodeService.UpdateNode:output_type -> node.UpdateNodeRes
-	12, // 19: node.NodeService.DeleteNode:output_type -> node.DeleteNodeRes
-	14, // 20: node.NodeService.GetPeers:output_type -> node.GetPeersRes
-	16, // 21: node.NodeService.CheckIn:output_type -> node.CheckInRes
-	15, // [15:22] is the sub-list for method output_type
-	8,  // [8:15] is the sub-list for method input_type
-	8,  // [8:8] is the sub-list for extension type_name
-	8,  // [8:8] is the sub-list for extension extendee
-	0,  // [0:8] 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.(*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[6].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[7].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[8].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[9].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[10].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[11].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[12].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[13].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[14].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[15].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[16].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:   17,
-			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
+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((*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{
+	// 1020 bytes of a gzipped FileDescriptorProto
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xdc, 0x57, 0xdb, 0x6e, 0x1b, 0xc5,
+	0x1b, 0x97, 0x9d, 0x93, 0xf3, 0x39, 0x4e, 0xd2, 0x49, 0x9b, 0xff, 0xfc, 0x4d, 0x55, 0x45, 0x16,
+	0x42, 0x29, 0x22, 0x76, 0x08, 0x52, 0x85, 0xc4, 0x05, 0x12, 0x2d, 0x8a, 0x40, 0x50, 0xc1, 0x22,
+	0x6e, 0xb8, 0x9b, 0xec, 0x7c, 0xde, 0x8e, 0xbc, 0x99, 0xd9, 0xec, 0x8c, 0xe3, 0xe6, 0x01, 0x78,
+	0x28, 0xc4, 0x9b, 0x70, 0xcd, 0x83, 0xa0, 0x39, 0xac, 0x77, 0x76, 0x63, 0x92, 0x54, 0xb9, 0xe3,
+	0x6e, 0xbf, 0xdf, 0x7c, 0xe7, 0xa3, 0x0d, 0x7b, 0x59, 0x59, 0xa4, 0x13, 0xa9, 0x38, 0x8e, 0x8b,
+	0x52, 0x19, 0x45, 0xd6, 0xed, 0xf7, 0x88, 0xc3, 0xce, 0x0f, 0x2a, 0x13, 0x32, 0xc1, 0xab, 0x39,
+	0x6a, 0x43, 0x5e, 0x00, 0x5c, 0xb2, 0x94, 0x71, 0x5e, 0xa2, 0xd6, 0xb4, 0x73, 0xd4, 0x39, 0xde,
+	0x4e, 0x22, 0x84, 0x0c, 0xa1, 0x57, 0x30, 0xad, 0x17, 0xaa, 0xe4, 0xb4, 0xeb, 0x5e, 0x97, 0x34,
+	0xa1, 0xb0, 0x25, 0xd1, 0x2c, 0x54, 0x39, 0xa3, 0x6b, 0xee, 0xa9, 0x22, 0x47, 0x9f, 0xc3, 0x20,
+	0x58, 0xd1, 0x85, 0x92, 0x1a, 0xc9, 0x11, 0xf4, 0x59, 0x9a, 0xa2, 0xd6, 0x46, 0xcd, 0x50, 0x06,
+	0x3b, 0x31, 0x34, 0xfa, 0x6b, 0x13, 0xd6, 0xdf, 0x2a, 0x8e, 0x64, 0x17, 0xba, 0x82, 0x07, 0x8e,
+	0xae, 0xe0, 0x84, 0xc0, 0xba, 0x64, 0x97, 0x18, 0xac, 0xbb, 0x6f, 0x6b, 0xb9, 0x72, 0x39, 0x58,
+	0x8e, 0xfc, 0x0d, 0x9f, 0xaf, 0xe8, 0xd0, 0xfb, 0x5b, 0xd1, 0x36, 0xd6, 0x5c, 0x68, 0x83, 0xb2,
+	0x50, 0xa5, 0xa1, 0xeb, 0x47, 0x9d, 0xe3, 0x8d, 0x24, 0x42, 0xc8, 0x73, 0xd8, 0x2e, 0xe6, 0x17,
+	0xb9, 0x48, 0x67, 0x78, 0x43, 0x37, 0x9c, 0x70, 0x0d, 0x58, 0xcd, 0x28, 0x79, 0xa1, 0x84, 0x34,
+	0x74, 0xd3, 0x6b, 0xae, 0xe8, 0x56, 0x16, 0xb7, 0xee, 0xcc, 0x62, 0xaf, 0x95, 0xc5, 0x23, 0xe8,
+	0xdb, 0xca, 0x54, 0x99, 0xdc, 0xf6, 0xa9, 0x89, 0x20, 0xeb, 0x97, 0xd0, 0x05, 0x4a, 0x2e, 0x64,
+	0x46, 0xe1, 0xa8, 0x73, 0xdc, 0x4b, 0x6a, 0x80, 0x1c, 0xc2, 0x66, 0xa1, 0xb4, 0x99, 0x17, 0xb4,
+	0xef, 0x44, 0x03, 0xe5, 0x6c, 0x2a, 0x6d, 0xb8, 0x5a, 0x48, 0xba, 0x13, 0x6c, 0x06, 0xda, 0x6a,
+	0x9c, 0x21, 0x16, 0x2c, 0x17, 0xd7, 0x48, 0x07, 0x2e, 0x11, 0x35, 0x60, 0xa3, 0xd1, 0xec, 0x1a,
+	0x53, 0x25, 0xa7, 0x22, 0xa3, 0xbb, 0xce, 0x60, 0x84, 0x58, 0x69, 0x5f, 0x39, 0x9b, 0xa7, 0x3d,
+	0x9f, 0xa7, 0x25, 0xe0, 0xbc, 0x95, 0x06, 0xcb, 0x29, 0x4b, 0x91, 0xee, 0xfb, 0xd7, 0x25, 0x60,
+	0xa3, 0xcd, 0x99, 0x36, 0xe9, 0x3b, 0x4c, 0x67, 0x42, 0xd2, 0x27, 0x3e, 0xda, 0x08, 0x22, 0x23,
+	0xd8, 0xb1, 0xe4, 0xa5, 0xe2, 0x62, 0x2a, 0x90, 0x53, 0xe2, 0x58, 0x1a, 0x18, 0x39, 0x86, 0xbd,
+	0xc0, 0xee, 0x34, 0x5f, 0xb3, 0x9c, 0x1e, 0xb8, 0x28, 0xda, 0xb0, 0xd3, 0xa6, 0x52, 0x96, 0x57,
+	0xb5, 0x79, 0x1a, 0xb4, 0x45, 0x98, 0xf5, 0xc9, 0x66, 0x26, 0x7d, 0xc7, 0x64, 0x86, 0x9a, 0x3e,
+	0xf3, 0x3e, 0x45, 0x90, 0xcd, 0x08, 0xcb, 0x73, 0xb5, 0x40, 0x2e, 0x0a, 0x4d, 0x0f, 0x7d, 0x7d,
+	0x6b, 0xc4, 0xf6, 0xa3, 0xd0, 0x4e, 0x27, 0xfd, 0x9f, 0x4b, 0x57, 0x45, 0x92, 0x4f, 0x61, 0x5f,
+	0x68, 0x21, 0x33, 0x6b, 0x28, 0x63, 0x06, 0x17, 0xec, 0x86, 0x3e, 0x77, 0x2c, 0xb7, 0x70, 0xeb,
+	0x87, 0xd0, 0x7c, 0xce, 0x72, 0x6d, 0x58, 0x3a, 0xa3, 0x1f, 0x39, 0xb6, 0x18, 0xb2, 0xb5, 0xe6,
+	0x52, 0xab, 0xe9, 0x94, 0x52, 0xf7, 0x18, 0x28, 0xd7, 0xd9, 0xd6, 0x5c, 0x69, 0xdd, 0xa5, 0xff,
+	0xf7, 0xfe, 0xd5, 0xc8, 0xe8, 0xf7, 0x2e, 0xec, 0xbd, 0xb6, 0x99, 0xf9, 0xae, 0x1e, 0x49, 0x0a,
+	0x5b, 0x7a, 0xee, 0xaa, 0xe6, 0x86, 0xad, 0x97, 0x54, 0x24, 0xf9, 0x04, 0x76, 0x25, 0x22, 0x2f,
+	0x10, 0xcb, 0x79, 0xc1, 0x99, 0xf1, 0xb3, 0xd7, 0x4b, 0x5a, 0xa8, 0x8d, 0xcd, 0x22, 0xbe, 0x2b,
+	0x02, 0xe7, 0x9a, 0x8f, 0xad, 0x8d, 0x57, 0x5d, 0x7e, 0x89, 0x5a, 0xb3, 0x0c, 0xdd, 0xf0, 0x85,
+	0x2e, 0x0f, 0x50, 0xb3, 0xcb, 0x37, 0xda, 0x5d, 0xfe, 0x31, 0x0c, 0xac, 0xce, 0x19, 0xde, 0x04,
+	0x43, 0x9b, 0x8e, 0xa3, 0x09, 0xda, 0x3c, 0x58, 0x80, 0x63, 0x8e, 0x06, 0xdd, 0x1c, 0xf6, 0x92,
+	0x08, 0x19, 0xfd, 0xd9, 0x85, 0xc1, 0x4f, 0x88, 0xa5, 0x5e, 0x66, 0xe1, 0x18, 0xf6, 0x84, 0xc6,
+	0x46, 0x79, 0x7c, 0x36, 0xda, 0x30, 0x19, 0x03, 0x69, 0x00, 0x3e, 0xd7, 0x7e, 0x2b, 0xad, 0x78,
+	0x79, 0xc4, 0x36, 0x79, 0xd8, 0x76, 0xeb, 0x7d, 0xe0, 0x76, 0x6b, 0x4f, 0xc2, 0xd6, 0x8a, 0x49,
+	0xb8, 0x73, 0x2f, 0x8c, 0xfe, 0xee, 0xc0, 0xfe, 0xb7, 0xef, 0x4d, 0x33, 0x81, 0xff, 0xbd, 0x30,
+	0x27, 0x30, 0x78, 0x5d, 0x22, 0x33, 0x68, 0xcf, 0x51, 0x82, 0x57, 0xe4, 0x05, 0xb8, 0xdb, 0xe9,
+	0x1a, 0xa3, 0x7f, 0x06, 0x63, 0x77, 0x54, 0xdd, 0xa3, 0xbf, 0xa9, 0x2d, 0x01, 0xfd, 0x10, 0x81,
+	0x5f, 0x5d, 0xc3, 0x7e, 0x80, 0x85, 0x58, 0xe0, 0x7e, 0x0b, 0xe7, 0xd0, 0x4f, 0x90, 0xf1, 0x5a,
+	0xff, 0xdd, 0x57, 0x3e, 0xba, 0xe4, 0xdd, 0xe6, 0x25, 0x3f, 0x89, 0x15, 0xdd, 0x6f, 0xf7, 0x67,
+	0x18, 0xbc, 0x71, 0xa3, 0xf6, 0x50, 0xcb, 0x76, 0x2f, 0x78, 0x53, 0x6f, 0xeb, 0x23, 0x1f, 0x43,
+	0xa3, 0x97, 0x4d, 0x95, 0xfa, 0xdf, 0x17, 0x97, 0x8d, 0xfa, 0x1c, 0xab, 0xfe, 0x7c, 0x4c, 0xd4,
+	0xdf, 0xc3, 0xee, 0x39, 0x9a, 0xba, 0xd7, 0x1f, 0xa3, 0xeb, 0xcb, 0xd8, 0x29, 0x4d, 0x5e, 0xc2,
+	0x86, 0x5d, 0xa1, 0x3a, 0xa4, 0xf0, 0xc0, 0xa7, 0xb0, 0x31, 0x53, 0x89, 0xe7, 0x18, 0xbd, 0x69,
+	0x79, 0xa1, 0xc9, 0x19, 0xf4, 0xf0, 0xbd, 0x89, 0xe5, 0x0f, 0xbd, 0x7c, 0x7b, 0x2c, 0x93, 0x25,
+	0xdf, 0xe8, 0x33, 0x80, 0xe5, 0xea, 0xbf, 0xbf, 0xd3, 0x7e, 0x8c, 0xb8, 0x35, 0xf9, 0x7a, 0x79,
+	0x67, 0xcb, 0xa0, 0x38, 0x08, 0x3e, 0xf3, 0x82, 0xad, 0x9b, 0x92, 0xb4, 0xb9, 0xcf, 0xfe, 0x58,
+	0x83, 0xbe, 0xd5, 0xfe, 0x0b, 0x96, 0xd7, 0x22, 0x45, 0x72, 0x0a, 0x1b, 0xee, 0x87, 0x21, 0x21,
+	0x5e, 0x41, 0xfc, 0x5b, 0x74, 0x78, 0xd0, 0xc0, 0xc2, 0x7e, 0x79, 0x05, 0x50, 0x0f, 0x17, 0x09,
+	0x2c, 0x8d, 0xf9, 0x1c, 0xae, 0x00, 0x35, 0x39, 0x85, 0x5e, 0xd5, 0xb8, 0xe4, 0x89, 0x67, 0x88,
+	0x26, 0x62, 0x78, 0x0b, 0xd2, 0xd6, 0x52, 0x3d, 0x64, 0x95, 0xa5, 0xc6, 0x9c, 0x0e, 0x57, 0x80,
+	0x4e, 0xae, 0x6e, 0xd0, 0x4a, 0xae, 0x31, 0x05, 0xc3, 0x15, 0xa0, 0x2b, 0x66, 0xd5, 0x18, 0x95,
+	0x87, 0x51, 0xf7, 0x0e, 0x6f, 0x41, 0xfa, 0xb4, 0x43, 0xbe, 0x72, 0xcd, 0x54, 0x55, 0x9b, 0x3c,
+	0x5d, 0xf2, 0x44, 0xbd, 0x3a, 0x5c, 0x85, 0x5a, 0xe1, 0x13, 0xd8, 0x0a, 0x05, 0x23, 0xfb, 0xad,
+	0xfa, 0x5d, 0x0d, 0xdb, 0x88, 0xfe, 0x66, 0xf2, 0xdb, 0x49, 0xa6, 0x54, 0x96, 0xe3, 0x38, 0x53,
+	0x39, 0x93, 0xd9, 0x58, 0x95, 0xd9, 0xc4, 0xfd, 0x97, 0xb8, 0x98, 0x4f, 0x27, 0xe6, 0xa6, 0x40,
+	0x3d, 0x99, 0x49, 0xb5, 0x90, 0xee, 0x5f, 0x46, 0x71, 0x71, 0xb1, 0xe9, 0x1e, 0xbf, 0xf8, 0x27,
+	0x00, 0x00, 0xff, 0xff, 0x4a, 0xa4, 0x7a, 0x56, 0x7b, 0x0c, 0x00, 0x00,
 }

+ 23 - 2
grpc/node.proto

@@ -9,6 +9,7 @@ service NodeService {
     rpc UpdateNode(UpdateNodeReq) returns (UpdateNodeRes);
     rpc DeleteNode(DeleteNodeReq) returns (DeleteNodeRes);
     rpc GetPeers(GetPeersReq) returns (stream GetPeersRes);
+    rpc GetExtPeers(GetExtPeersReq) returns (stream GetExtPeersRes);
     rpc CheckIn(CheckInReq) returns (CheckInRes);
 }
 
@@ -45,6 +46,7 @@ message Node {
     string postchanges = 21;
     string allowedips = 22;
     bool islocal = 23;
+    bool isingressgateway = 28;
     bool isdualstack = 27;
     bool dnsoff = 24;
     string localrange = 25;
@@ -61,8 +63,18 @@ message CheckInResponse {
 }
 
 message PeersResponse {
-    bool isgateway = 1;
-    string gatewayrange = 2;
+    bool isegressgateway = 1;
+    string egressgatewayrange = 2;
+    string publickey = 5;
+    string endpoint = 6;
+    string address = 3;
+    string address6 = 8;
+    int32 listenport = 4;
+    string localaddress = 7;
+    int32 keepalive = 13;
+}
+
+message ExtPeersResponse {
     string publickey = 5;
     string endpoint = 6;
     string address = 3;
@@ -111,10 +123,19 @@ message GetPeersReq {
     string network = 2;
 }
 
+message GetExtPeersReq {
+    string macaddress = 1;
+    string network = 2;
+}
+
 message GetPeersRes {
     PeersResponse peers = 1;
 }
 
+message GetExtPeersRes {
+    ExtPeersResponse extpeers = 1;
+}
+
 message CheckInReq {
     Node node = 1;
  //   bool postchanges = 2;

+ 63 - 0
grpc/node_grpc.pb.go

@@ -24,6 +24,7 @@ type NodeServiceClient interface {
 	UpdateNode(ctx context.Context, in *UpdateNodeReq, opts ...grpc.CallOption) (*UpdateNodeRes, error)
 	DeleteNode(ctx context.Context, in *DeleteNodeReq, opts ...grpc.CallOption) (*DeleteNodeRes, error)
 	GetPeers(ctx context.Context, in *GetPeersReq, opts ...grpc.CallOption) (NodeService_GetPeersClient, error)
+	GetExtPeers(ctx context.Context, in *GetExtPeersReq, opts ...grpc.CallOption) (NodeService_GetExtPeersClient, error)
 	CheckIn(ctx context.Context, in *CheckInReq, opts ...grpc.CallOption) (*CheckInRes, error)
 }
 
@@ -112,6 +113,38 @@ func (x *nodeServiceGetPeersClient) Recv() (*GetPeersRes, error) {
 	return m, nil
 }
 
+func (c *nodeServiceClient) GetExtPeers(ctx context.Context, in *GetExtPeersReq, opts ...grpc.CallOption) (NodeService_GetExtPeersClient, error) {
+	stream, err := c.cc.NewStream(ctx, &NodeService_ServiceDesc.Streams[1], "/node.NodeService/GetExtPeers", opts...)
+	if err != nil {
+		return nil, err
+	}
+	x := &nodeServiceGetExtPeersClient{stream}
+	if err := x.ClientStream.SendMsg(in); err != nil {
+		return nil, err
+	}
+	if err := x.ClientStream.CloseSend(); err != nil {
+		return nil, err
+	}
+	return x, nil
+}
+
+type NodeService_GetExtPeersClient interface {
+	Recv() (*GetExtPeersRes, error)
+	grpc.ClientStream
+}
+
+type nodeServiceGetExtPeersClient struct {
+	grpc.ClientStream
+}
+
+func (x *nodeServiceGetExtPeersClient) Recv() (*GetExtPeersRes, error) {
+	m := new(GetExtPeersRes)
+	if err := x.ClientStream.RecvMsg(m); err != nil {
+		return nil, err
+	}
+	return m, nil
+}
+
 func (c *nodeServiceClient) CheckIn(ctx context.Context, in *CheckInReq, opts ...grpc.CallOption) (*CheckInRes, error) {
 	out := new(CheckInRes)
 	err := c.cc.Invoke(ctx, "/node.NodeService/CheckIn", in, out, opts...)
@@ -131,6 +164,7 @@ type NodeServiceServer interface {
 	UpdateNode(context.Context, *UpdateNodeReq) (*UpdateNodeRes, error)
 	DeleteNode(context.Context, *DeleteNodeReq) (*DeleteNodeRes, error)
 	GetPeers(*GetPeersReq, NodeService_GetPeersServer) error
+	GetExtPeers(*GetExtPeersReq, NodeService_GetExtPeersServer) error
 	CheckIn(context.Context, *CheckInReq) (*CheckInRes, error)
 	mustEmbedUnimplementedNodeServiceServer()
 }
@@ -157,6 +191,9 @@ func (UnimplementedNodeServiceServer) DeleteNode(context.Context, *DeleteNodeReq
 func (UnimplementedNodeServiceServer) GetPeers(*GetPeersReq, NodeService_GetPeersServer) error {
 	return status.Errorf(codes.Unimplemented, "method GetPeers not implemented")
 }
+func (UnimplementedNodeServiceServer) GetExtPeers(*GetExtPeersReq, NodeService_GetExtPeersServer) error {
+	return status.Errorf(codes.Unimplemented, "method GetExtPeers not implemented")
+}
 func (UnimplementedNodeServiceServer) CheckIn(context.Context, *CheckInReq) (*CheckInRes, error) {
 	return nil, status.Errorf(codes.Unimplemented, "method CheckIn not implemented")
 }
@@ -284,6 +321,27 @@ func (x *nodeServiceGetPeersServer) Send(m *GetPeersRes) error {
 	return x.ServerStream.SendMsg(m)
 }
 
+func _NodeService_GetExtPeers_Handler(srv interface{}, stream grpc.ServerStream) error {
+	m := new(GetExtPeersReq)
+	if err := stream.RecvMsg(m); err != nil {
+		return err
+	}
+	return srv.(NodeServiceServer).GetExtPeers(m, &nodeServiceGetExtPeersServer{stream})
+}
+
+type NodeService_GetExtPeersServer interface {
+	Send(*GetExtPeersRes) error
+	grpc.ServerStream
+}
+
+type nodeServiceGetExtPeersServer struct {
+	grpc.ServerStream
+}
+
+func (x *nodeServiceGetExtPeersServer) Send(m *GetExtPeersRes) error {
+	return x.ServerStream.SendMsg(m)
+}
+
 func _NodeService_CheckIn_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
 	in := new(CheckInReq)
 	if err := dec(in); err != nil {
@@ -340,6 +398,11 @@ var NodeService_ServiceDesc = grpc.ServiceDesc{
 			Handler:       _NodeService_GetPeers_Handler,
 			ServerStreams: true,
 		},
+		{
+			StreamName:    "GetExtPeers",
+			Handler:       _NodeService_GetExtPeers_Handler,
+			ServerStreams: true,
+		},
 	},
 	Metadata: "grpc/node.proto",
 }

+ 45 - 0
models/extclient.go

@@ -0,0 +1,45 @@
+package models
+
+import (
+	"go.mongodb.org/mongo-driver/bson/primitive"
+)
+//What the client needs to get
+/*
+
+[Interface]
+# The address their computer will use on the network
+Address = 10.0.0.8/32 # The Address they'll use on the network
+PrivateKey = XXXXXXXXXXXXXXXX # The private key they'll use
+
+
+# All of this info can come from the node!!
+[Peer]
+# Ingress Gateway's wireguard public key
+PublicKey = CcZHeaO08z55/x3FXdsSGmOQvZG32SvHlrwHnsWlGTs=
+
+# Public IP address of the Ingress Gateway
+# Use the floating IP address if you created one for your VPN server
+Endpoint = 123.123.123.123:51820
+
+# 10.0.0.0/24 is the VPN sub
+
+*/
+
+
+// External Struct
+// == BACKEND FIELDS ==
+// PrivateKey, PublicKey, Address (Private), LastModified, IngressEndpoint
+// == FRONTEND FIELDS ==
+// ClientID, Network, IngressGateway
+type ExtClient struct {
+	ID             primitive.ObjectID `json:"_id,omitempty" bson:"_id,omitempty"`
+	ClientID       string             `json:"clientid" bson:"clientid"`
+	Description       string             `json:"description" bson:"description"`
+	PrivateKey     string             `json:"privatekey" bson:"privatekey"`
+	PublicKey      string             `json:"publickey" bson:"publickey"`
+	Network        string             `json:"network" bson:"network"`
+	Address        string             `json:"address" bson:"address"`
+	LastModified   int64              `json:"lastmodified" bson:"lastmodified"`
+	IngressGatewayID string             `json:"ingressgatewayid" bson:"ingressgatewayid"`
+	IngressGatewayEnpoint string             `json:"ingressgatewayendpoint" bson:"ingressgatewayendpoint"`
+}

+ 0 - 18
models/external.go

@@ -1,18 +0,0 @@
-package models
-
-import (
-	"go.mongodb.org/mongo-driver/bson/primitive"
-)
-
-//External Struct
-//At  some point, need to replace all instances of Name with something else like  Identifier
-type External struct {
-	ID           primitive.ObjectID `json:"_id,omitempty" bson:"_id,omitempty"`
-	ClientID       		string		`json:"clientid" bson:"clientid"`
-	PrivateKey 			string		`json:"privatekey" bson:"privatekey"`
-	PublicKey  			string		`json:"publickey" bson:"publickey"`
-	Network				string		`json:"network" bson:"network"`
-	Address         	string		`json:"address" bson:"address"`
-	LastModified    	string		`json:"lastmodified" bson:"lastmodified"`
-	IngressGateway		string		`json:"ingressgateway" bson:"ingressgateway"`
-}

+ 6 - 4
models/node.go

@@ -43,8 +43,9 @@ type Node struct {
 	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"`
-	IsGateway           bool               `json:"isgateway" bson:"isgateway"`
-	GatewayRange        string             `json:"gatewayrange" bson:"gatewayrange"`
+	IsEgressGateway           bool               `json:"isegressgateway" bson:"isegressgateway"`
+	IsIngressGateway           bool               `json:"isingressgateway" bson:"isingressgateway"`
+	EgressGatewayRange        string             `json:"gatewayrange" bson:"gatewayrange"`
 	PostChanges         string             `json:"postchanges" bson:"postchanges"`
 }
 
@@ -75,8 +76,9 @@ type NodeUpdate struct {
 	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"`
-	IsGateway           bool               `json:"isgateway" bson:"isgateway"`
-	GatewayRange        string             `json:"gatewayrange" bson:"gatewayrange"`
+	IsIngressGateway           bool               `json:"isingressgateway" bson:"isingressgateway"`
+	IsEgressGateway           bool               `json:"isegressgateway" bson:"isegressgateway"`
+	EgressGatewayRange        string             `json:"gatewayrange" bson:"gatewayrange"`
 	PostChanges         string             `json:"postchanges" bson:"postchanges"`
 }
 

+ 3 - 2
models/returnNode.go

@@ -19,8 +19,9 @@ type ReturnNode struct {
 	Interface	string `json:"interface" bson:"interface"`
 	Network	string `json:"network" bson:"network"`
 	IsPending	*bool `json:"ispending" bson:"ispending"`
-	IsGateway	*bool `json:"isgateway" bson:"isgateway"`
-	GatewayRange	string `json:"gatewayrange" bson:"gatewayrange"`
+	IsEgressGateway	*bool `json:"isegressgateway" bson:"isegressgateway"`
+	IsIngressGateway	*bool `json:"isingressgateway" bson:"isingressgateway"`
+	EgressGatewayRange	string `json:"egressgatewayrange" bson:"egressgatewayrange"`
         LocalAddress    string `json:"localaddress" bson:"localaddress" validate:"localaddress_check"`
         ExpirationDateTime      int64 `json:"expdatetime" bson:"expdatetime"`
 }

+ 13 - 3
models/structs.go

@@ -95,13 +95,23 @@ type PeersResponse struct {
 	Address      string `json:"address" bson:"address"`
 	Address6     string `json:"address6" bson:"address6"`
 	LocalAddress string `json:"localaddress" bson:"localaddress"`
-	IsGateway    bool   `json:"isgateway" bson:"isgateway"`
-	GatewayRange string `json:"gatewayrange" bson:"gatewayrange"`
+	IsEgressGateway    bool   `json:"isgateway" bson:"isgateway"`
+	EgressGatewayRange string `json:"gatewayrange" bson:"gatewayrange"`
 	ListenPort   int32  `json:"listenport" bson:"listenport"`
 	KeepAlive    int32  `json:"persistentkeepalive" bson:"persistentkeepalive"`
 }
 
-type GatewayRequest struct {
+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"`
 	RangeString string   `json:"rangestring" bson:"rangestring"`

+ 2 - 139
netclient/functions/common.go

@@ -2,12 +2,10 @@ package functions
 
 import (
 	"fmt"
-	"time"
 	"errors"
 	"context"
         "net/http"
         "io/ioutil"
-	"io"
 	"strings"
 	"log"
 	"net"
@@ -454,7 +452,7 @@ func Install(accesskey string, password string, server string, network string, n
 		}
 	}
 
-	peers, hasGateway, gateways, err := getPeers(node.Macaddress, network, server, node.Isdualstack)
+	peers, hasGateway, gateways, err := getPeers(node.Macaddress, network, server, node.Isdualstack, node.Isingressgateway)
 
 	if err != nil {
                 return err
@@ -931,7 +929,7 @@ func setWGConfig(network string) error {
         nodecfg := cfg.Node
         node := getNode(network)
 
-	peers, hasGateway, gateways, err := getPeers(node.Macaddress, nodecfg.Network, servercfg.Address, node.Isdualstack)
+	peers, hasGateway, gateways, err := getPeers(node.Macaddress, nodecfg.Network, servercfg.Address, node.Isdualstack, node.Isingressgateway)
         if err != nil {
                 return err
         }
@@ -1451,138 +1449,3 @@ func DeleteInterface(ifacename string, postdown string) error{
         }
         return err
 }
-
-func getPeers(macaddress string, network string, server string, dualstack bool) ([]wgtypes.PeerConfig, bool, []string, error) {
-        //need to  implement checkin on server side
-	hasGateway := false
-	var gateways []string
-	var peers []wgtypes.PeerConfig
-	var wcclient nodepb.NodeServiceClient
-        cfg, err := config.ReadConfig(network)
-        if err != nil {
-		log.Fatalf("Issue retrieving config for network: " + network +  ". Please investigate: %v", err)
-        }
-        nodecfg := cfg.Node
-	keepalive := nodecfg.KeepAlive
-	keepalivedur, err := time.ParseDuration(strconv.FormatInt(int64(keepalive), 10) + "s")
-        if err != nil {
-                log.Fatalf("Issue with format of keepalive value. Please update netconfig: %v", err)
-        }
-
-
-	fmt.Println("Registering with GRPC Server")
-	requestOpts := grpc.WithInsecure()
-	conn, err := grpc.Dial(server, requestOpts)
-	if err != nil {
-		log.Fatalf("Unable to establish client connection to localhost:50051: %v", err)
-	}
-	// Instantiate the BlogServiceClient with our client connection to the server
-	wcclient = nodepb.NewNodeServiceClient(conn)
-
-	req := &nodepb.GetPeersReq{
-		Macaddress: macaddress,
-                Network: network,
-        }
-        ctx := context.Background()
-	fmt.Println("Authenticating with GRPC Server")
-	ctx, err = SetJWT(wcclient, network)
-        if err != nil {
-		fmt.Println("Failed to authenticate.")
-                return peers, hasGateway, gateways, err
-        }
-        var header metadata.MD
-
-        stream, err := wcclient.GetPeers(ctx, req, grpc.Header(&header))
-	if err != nil {
-                fmt.Println("Error retrieving peers")
-                fmt.Println(err)
-		return nil, hasGateway, gateways, err
-        }
-	fmt.Println("Parsing peers response")
-	for {
-		res, err := stream.Recv()
-                // If end of stream, break the loop
-
-		if err == io.EOF {
-			break
-                }
-                // if err, return an error
-                if err != nil {
-			if strings.Contains(err.Error(), "mongo: no documents in result") {
-				continue
-			} else {
-			fmt.Println("ERROR ENCOUNTERED WITH RESPONSE")
-			fmt.Println(res)
-                        return peers, hasGateway, gateways, err
-			}
-                }
-		pubkey, err := wgtypes.ParseKey(res.Peers.Publickey)
-                if err != nil {
-			fmt.Println("error parsing key")
-                        return peers, hasGateway, gateways, err
-                }
-
-                if nodecfg.PublicKey == res.Peers.Publickey {
-                        fmt.Println("Peer is self. Skipping")
-                        continue
-                }
-                if nodecfg.Endpoint == res.Peers.Endpoint {
-                        fmt.Println("Peer is self. Skipping")
-                        continue
-                }
-
-		var peer wgtypes.PeerConfig
-		var peeraddr = net.IPNet{
-			IP: net.ParseIP(res.Peers.Address),
-                        Mask: net.CIDRMask(32, 32),
-		}
-		var allowedips []net.IPNet
-		allowedips = append(allowedips, peeraddr)
-		if res.Peers.Isgateway {
-			hasGateway = true
-			gateways = append(gateways,res.Peers.Gatewayrange)
-			_, ipnet, err := net.ParseCIDR(res.Peers.Gatewayrange)
-			if err != nil {
-				fmt.Println("ERROR ENCOUNTERED SETTING GATEWAY")
-				fmt.Println("NOT SETTING GATEWAY")
-				fmt.Println(err)
-			} else {
-				fmt.Println("    Gateway Range: "  + res.Peers.Gatewayrange)
-				allowedips = append(allowedips, *ipnet)
-			}
-		}
-                if res.Peers.Address6 != "" && dualstack {
-			var addr6 = net.IPNet{
-	                        IP: net.ParseIP(res.Peers.Address6),
-	                        Mask: net.CIDRMask(128, 128),
-	                }
-                        allowedips = append(allowedips, addr6)
-                }
-		if keepalive != 0 {
-		peer = wgtypes.PeerConfig{
-			PublicKey: pubkey,
-			PersistentKeepaliveInterval: &keepalivedur,
-			Endpoint: &net.UDPAddr{
-				IP:   net.ParseIP(res.Peers.Endpoint),
-				Port: int(res.Peers.Listenport),
-			},
-			ReplaceAllowedIPs: true,
-                        AllowedIPs: allowedips,
-			}
-		} else {
-                peer = wgtypes.PeerConfig{
-                        PublicKey: pubkey,
-                        Endpoint: &net.UDPAddr{
-                                IP:   net.ParseIP(res.Peers.Endpoint),
-                                Port: int(res.Peers.Listenport),
-                        },
-                        ReplaceAllowedIPs: true,
-                        AllowedIPs: allowedips,
-			}
-		}
-		peers = append(peers, peer)
-
-        }
-	fmt.Println("Finished parsing peers response")
-	return peers, hasGateway, gateways, err
-}

+ 283 - 0
netclient/functions/peers.go

@@ -0,0 +1,283 @@
+package functions
+
+import (
+        "fmt"
+        "time"
+        "context"
+        "io"
+        "strings"
+        "log"
+        "net"
+        "strconv"
+        "github.com/gravitl/netmaker/netclient/config"
+        nodepb "github.com/gravitl/netmaker/grpc"
+        "google.golang.org/grpc"
+        "google.golang.org/grpc/metadata"
+        "golang.zx2c4.com/wireguard/wgctrl/wgtypes"
+        //homedir "github.com/mitchellh/go-homedir"
+)
+
+func getPeers(macaddress string, network string, server string, dualstack bool, isIngressGateway bool) ([]wgtypes.PeerConfig, bool, []string, error) {
+        //need to  implement checkin on server side
+        hasGateway := false
+        var gateways []string
+        var peers []wgtypes.PeerConfig
+        var wcclient nodepb.NodeServiceClient
+        cfg, err := config.ReadConfig(network)
+        if err != nil {
+                log.Fatalf("Issue retrieving config for network: " + network +  ". Please investigate: %v", err)
+        }
+        nodecfg := cfg.Node
+        keepalive := nodecfg.KeepAlive
+        keepalivedur, err := time.ParseDuration(strconv.FormatInt(int64(keepalive), 10) + "s")
+        if err != nil {
+                log.Fatalf("Issue with format of keepalive value. Please update netconfig: %v", err)
+        }
+
+
+        fmt.Println("Registering with GRPC Server")
+        requestOpts := grpc.WithInsecure()
+        conn, err := grpc.Dial(server, requestOpts)
+        if err != nil {
+                log.Fatalf("Unable to establish client connection to localhost:50051: %v", err)
+        }
+        // Instantiate the BlogServiceClient with our client connection to the server
+        wcclient = nodepb.NewNodeServiceClient(conn)
+
+        req := &nodepb.GetPeersReq{
+                Macaddress: macaddress,
+                Network: network,
+        }
+        ctx := context.Background()
+        fmt.Println("Authenticating with GRPC Server")
+        ctx, err = SetJWT(wcclient, network)
+        if err != nil {
+                fmt.Println("Failed to authenticate.")
+                return peers, hasGateway, gateways, err
+        }
+        var header metadata.MD
+
+        stream, err := wcclient.GetPeers(ctx, req, grpc.Header(&header))
+        if err != nil {
+                fmt.Println("Error retrieving peers")
+                fmt.Println(err)
+                return nil, hasGateway, gateways, err
+        }
+        fmt.Println("Parsing peers response")
+        for {
+                res, err := stream.Recv()
+                // If end of stream, break the loop
+
+                if err == io.EOF {
+                        break
+                }
+                // if err, return an error
+                if err != nil {
+                        if strings.Contains(err.Error(), "mongo: no documents in result") {
+                                continue
+                        } else {
+                        fmt.Println("ERROR ENCOUNTERED WITH RESPONSE")
+                        fmt.Println(res)
+                        return peers, hasGateway, gateways, err
+                        }
+                }
+                pubkey, err := wgtypes.ParseKey(res.Peers.Publickey)
+                if err != nil {
+                        fmt.Println("error parsing key")
+                        return peers, hasGateway, gateways, err
+                }
+
+                if nodecfg.PublicKey == res.Peers.Publickey {
+                        fmt.Println("Peer is self. Skipping")
+                        continue
+                }
+                if nodecfg.Endpoint == res.Peers.Endpoint {
+                        fmt.Println("Peer is self. Skipping")
+                        continue
+                }
+
+                var peer wgtypes.PeerConfig
+                var peeraddr = net.IPNet{
+                        IP: net.ParseIP(res.Peers.Address),
+                        Mask: net.CIDRMask(32, 32),
+                }
+                var allowedips []net.IPNet
+                allowedips = append(allowedips, peeraddr)
+                if res.Peers.Isegressgateway {
+                        hasGateway = true
+                        gateways = append(gateways,res.Peers.Egressgatewayrange)
+                        _, ipnet, err := net.ParseCIDR(res.Peers.Egressgatewayrange)
+                        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)
+                                allowedips = append(allowedips, *ipnet)
+                        }
+                }
+                if res.Peers.Address6 != "" && dualstack {
+                        var addr6 = net.IPNet{
+                                IP: net.ParseIP(res.Peers.Address6),
+                                Mask: net.CIDRMask(128, 128),
+                        }
+                        allowedips = append(allowedips, addr6)
+                }
+                if keepalive != 0 {
+                peer = wgtypes.PeerConfig{
+                        PublicKey: pubkey,
+                        PersistentKeepaliveInterval: &keepalivedur,
+                        Endpoint: &net.UDPAddr{
+                                IP:   net.ParseIP(res.Peers.Endpoint),
+                                Port: int(res.Peers.Listenport),
+                        },
+                        ReplaceAllowedIPs: true,
+                        AllowedIPs: allowedips,
+                        }
+                } else {
+                peer = wgtypes.PeerConfig{
+                        PublicKey: pubkey,
+                        Endpoint: &net.UDPAddr{
+                                IP:   net.ParseIP(res.Peers.Endpoint),
+                                Port: int(res.Peers.Listenport),
+                        },
+                        ReplaceAllowedIPs: true,
+                        AllowedIPs: allowedips,
+                        }
+                }
+                peers = append(peers, peer)
+
+        }
+        if isIngressGateway {
+                fmt.Println("Adding external peers...")
+                extPeers, err := getExtPeers(macaddress, network, server, dualstack)
+                if err == nil {
+                        peers = append(peers, extPeers...)
+                        fmt.Println("Added " + strconv.Itoa(len(extPeers)) + " external clients.")
+                } else {
+                        fmt.Println("ERROR RETRIEVING EXTERNAL PEERS")
+                        fmt.Println(err)
+                }
+        }
+        fmt.Println("Finished parsing peers response")
+        return peers, hasGateway, gateways, err
+}
+
+func getExtPeers(macaddress string, network string, server string, dualstack bool) ([]wgtypes.PeerConfig, error) {
+        var peers []wgtypes.PeerConfig
+        var wcclient nodepb.NodeServiceClient
+        cfg, err := config.ReadConfig(network)
+        if err != nil {
+                log.Fatalf("Issue retrieving config for network: " + network +  ". Please investigate: %v", err)
+        }
+        nodecfg := cfg.Node
+        keepalive := nodecfg.KeepAlive
+        keepalivedur, err := time.ParseDuration(strconv.FormatInt(int64(keepalive), 10) + "s")
+        if err != nil {
+                log.Fatalf("Issue with format of keepalive value. Please update netconfig: %v", err)
+        }
+
+
+        fmt.Println("Registering with GRPC Server")
+        requestOpts := grpc.WithInsecure()
+        conn, err := grpc.Dial(server, requestOpts)
+        if err != nil {
+                log.Fatalf("Unable to establish client connection to localhost:50051: %v", err)
+        }
+        // Instantiate the BlogServiceClient with our client connection to the server
+        wcclient = nodepb.NewNodeServiceClient(conn)
+
+        req := &nodepb.GetExtPeersReq{
+                Macaddress: macaddress,
+                Network: network,
+        }
+        ctx := context.Background()
+        fmt.Println("Authenticating with GRPC Server")
+        ctx, err = SetJWT(wcclient, network)
+        if err != nil {
+                fmt.Println("Failed to authenticate.")
+                return peers, err
+        }
+        var header metadata.MD
+
+        stream, err := wcclient.GetExtPeers(ctx, req, grpc.Header(&header))
+        if err != nil {
+                fmt.Println("Error retrieving peers")
+                fmt.Println(err)
+                return nil, err
+        }
+        fmt.Println("Parsing peers response")
+        for {
+                res, err := stream.Recv()
+                // If end of stream, break the loop
+
+                if err == io.EOF {
+                        break
+                }
+                // if err, return an error
+                if err != nil {
+                        if strings.Contains(err.Error(), "mongo: no documents in result") {
+                                continue
+                        } else {
+                        fmt.Println("ERROR ENCOUNTERED WITH RESPONSE")
+                        fmt.Println(res)
+                        return peers, err
+                        }
+                }
+                pubkey, err := wgtypes.ParseKey(res.Extpeers.Publickey)
+                if err != nil {
+                        fmt.Println("error parsing key")
+                        return peers, err
+                }
+
+                if nodecfg.PublicKey == res.Extpeers.Publickey {
+                        fmt.Println("Peer is self. Skipping")
+                        continue
+                }
+                if nodecfg.Endpoint == res.Extpeers.Endpoint {
+                        fmt.Println("Peer is self. Skipping")
+                        continue
+                }
+
+                var peer wgtypes.PeerConfig
+                var peeraddr = net.IPNet{
+                        IP: net.ParseIP(res.Extpeers.Address),
+                        Mask: net.CIDRMask(32, 32),
+                }
+                var allowedips []net.IPNet
+                allowedips = append(allowedips, peeraddr)
+
+		if res.Extpeers.Address6 != "" && dualstack {
+                        var addr6 = net.IPNet{
+                                IP: net.ParseIP(res.Extpeers.Address6),
+                                Mask: net.CIDRMask(128, 128),
+                        }
+                        allowedips = append(allowedips, addr6)
+                }
+                if keepalive != 0 {
+                peer = wgtypes.PeerConfig{
+                        PublicKey: pubkey,
+                        PersistentKeepaliveInterval: &keepalivedur,
+                        Endpoint: &net.UDPAddr{
+                                IP:   net.ParseIP(res.Extpeers.Endpoint),
+                                Port: int(res.Extpeers.Listenport),
+                        },
+                        ReplaceAllowedIPs: true,
+                        AllowedIPs: allowedips,
+                        }
+                } else {
+                peer = wgtypes.PeerConfig{
+                        PublicKey: pubkey,
+                        Endpoint: &net.UDPAddr{
+                                IP:   net.ParseIP(res.Extpeers.Endpoint),
+                                Port: int(res.Extpeers.Listenport),
+                        },
+                        ReplaceAllowedIPs: true,
+                        AllowedIPs: allowedips,
+                        }
+                }
+                peers = append(peers, peer)
+
+        }
+        return peers, err
+}