Browse Source

Merge pull request #280 from gravitl/feature_v0.8_relay

Feature v0.8 relay
Alex 3 years ago
parent
commit
bfcc9c4c8a

+ 52 - 13
controllers/common.go

@@ -14,8 +14,30 @@ import (
 	"golang.org/x/crypto/bcrypt"
 	"golang.org/x/crypto/bcrypt"
 )
 )
 
 
-func GetPeersList(networkName string) ([]models.Node, error) {
+func GetPeersList(networkName string, excludeDoNotPropagate bool, relayedNodeAddr string) ([]models.Node, error) {
+	var peers []models.Node
+	var relayNode models.Node
+	var err error
+	if relayedNodeAddr == "" {
+		peers, err = GetNodePeers(networkName, excludeDoNotPropagate)
 
 
+	} else {
+		relayNode, err = GetNodeRelay(networkName, relayedNodeAddr)
+		if relayNode.Address != "" {
+			relayNode = setPeerInfo(relayNode)
+			network, err := models.GetNetwork(networkName)
+			if err == nil {
+				relayNode.AllowedIPs = append(relayNode.AllowedIPs,network.AddressRange)
+			} else {
+				relayNode.AllowedIPs = append(relayNode.AllowedIPs,relayNode.RelayAddrs...)
+			}	
+			peers = append(peers,relayNode)
+		}
+	}
+	return peers, err
+}
+
+func GetNodePeers(networkName string, excludeDoNotPropagate bool) ([]models.Node, error) {
 	var peers []models.Node
 	var peers []models.Node
 	collection, err := database.FetchRecords(database.NODES_TABLE_NAME)
 	collection, err := database.FetchRecords(database.NODES_TABLE_NAME)
 	if err != nil {
 	if err != nil {
@@ -41,14 +63,10 @@ func GetPeersList(networkName string) ([]models.Node, error) {
 			peer.EgressGatewayRanges = node.EgressGatewayRanges
 			peer.EgressGatewayRanges = node.EgressGatewayRanges
 			peer.IsEgressGateway = node.IsEgressGateway
 			peer.IsEgressGateway = node.IsEgressGateway
 		}
 		}
-		if node.Network == networkName && node.IsPending != "yes" {
-			peer.PublicKey = node.PublicKey
-			peer.Endpoint = node.Endpoint
-			peer.LocalAddress = node.LocalAddress
-			peer.ListenPort = node.ListenPort
-			peer.AllowedIPs = node.AllowedIPs
-			peer.Address = node.Address
-			peer.Address6 = node.Address6
+		allow := node.DoNotPropagate != "yes" || !excludeDoNotPropagate
+		
+		if node.Network == networkName && node.IsPending != "yes" && allow {
+			peer = setPeerInfo(node)
 			if node.UDPHolePunch == "yes" && errN == nil && functions.CheckEndpoint(udppeers[node.PublicKey]) {
 			if node.UDPHolePunch == "yes" && errN == nil && functions.CheckEndpoint(udppeers[node.PublicKey]) {
 				endpointstring := udppeers[node.PublicKey]
 				endpointstring := udppeers[node.PublicKey]
 				endpointarr := strings.Split(endpointstring, ":")
 				endpointarr := strings.Split(endpointstring, ":")
@@ -60,17 +78,38 @@ func GetPeersList(networkName string) ([]models.Node, error) {
 					}
 					}
 				}
 				}
 			}
 			}
-			functions.PrintUserLog(models.NODE_SERVER_NAME, "adding to peer list: "+peer.MacAddress+" "+peer.Endpoint, 3)
+			if node.IsRelay == "yes" {
+				network, err := models.GetNetwork(networkName)
+				if err == nil {
+					peer.AllowedIPs = append(peer.AllowedIPs,network.AddressRange)
+				} else {
+					peer.AllowedIPs = append(peer.AllowedIPs,node.RelayAddrs...)
+				}
+			}
 			peers = append(peers, peer)
 			peers = append(peers, peer)
 		}
 		}
 	}
 	}
-	if err != nil {
-		return peers, err
-	}
 
 
 	return peers, err
 	return peers, err
 }
 }
 
 
+
+
+func setPeerInfo(node models.Node) models.Node {
+	var peer models.Node
+	peer.RelayAddrs = node.RelayAddrs
+	peer.IsRelay = node.IsRelay
+	peer.DoNotPropagate = node.DoNotPropagate
+	peer.PublicKey = node.PublicKey
+	peer.Endpoint = node.Endpoint
+	peer.LocalAddress = node.LocalAddress
+	peer.ListenPort = node.ListenPort
+	peer.AllowedIPs = node.AllowedIPs
+	peer.Address = node.Address
+	peer.Address6 = node.Address6
+	return peer
+}
+
 func GetExtPeersList(macaddress string, networkName string) ([]models.ExtPeersResponse, error) {
 func GetExtPeersList(macaddress string, networkName string) ([]models.ExtPeersResponse, error) {
 
 
 	var peers []models.ExtPeersResponse
 	var peers []models.ExtPeersResponse

+ 3 - 3
controllers/common_test.go

@@ -13,20 +13,20 @@ func TestGetPeerList(t *testing.T) {
 	deleteAllNetworks()
 	deleteAllNetworks()
 	createNet()
 	createNet()
 	t.Run("NoNodes", func(t *testing.T) {
 	t.Run("NoNodes", func(t *testing.T) {
-		peers, err := GetPeersList("skynet")
+		peers, err := GetPeersList("skynet", false, "")
 		assert.Nil(t, err)
 		assert.Nil(t, err)
 		assert.Nil(t, peers)
 		assert.Nil(t, peers)
 	})
 	})
 	node := createTestNode()
 	node := createTestNode()
 	t.Run("One Node", func(t *testing.T) {
 	t.Run("One Node", func(t *testing.T) {
-		peers, err := GetPeersList("skynet")
+		peers, err := GetPeersList("skynet", false, "")
 		assert.Nil(t, err)
 		assert.Nil(t, err)
 		assert.Equal(t, node.Address, peers[0].Address)
 		assert.Equal(t, node.Address, peers[0].Address)
 	})
 	})
 	t.Run("Multiple Nodes", func(t *testing.T) {
 	t.Run("Multiple Nodes", func(t *testing.T) {
 		createnode := models.Node{PublicKey: "RM5qhLAE20PG9BbfBCger+Ac9D2NDOwCtY1rbYDLf34=", Endpoint: "10.0.0.2", MacAddress: "02:02:03:04:05:06", Password: "password", Network: "skynet"}
 		createnode := models.Node{PublicKey: "RM5qhLAE20PG9BbfBCger+Ac9D2NDOwCtY1rbYDLf34=", Endpoint: "10.0.0.2", MacAddress: "02:02:03:04:05:06", Password: "password", Network: "skynet"}
 		CreateNode(createnode, "skynet")
 		CreateNode(createnode, "skynet")
-		peers, err := GetPeersList("skynet")
+		peers, err := GetPeersList("skynet", false, "")
 		assert.Nil(t, err)
 		assert.Nil(t, err)
 		assert.Equal(t, len(peers), 2)
 		assert.Equal(t, len(peers), 2)
 		foundNodeEndpoint := false
 		foundNodeEndpoint := false

+ 20 - 2
controllers/nodeGrpcController.go

@@ -97,11 +97,24 @@ func (s *NodeServiceServer) UpdateNode(ctx context.Context, req *nodepb.Object)
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
-
+	relayupdate := false
+	if node.IsRelay == "yes" && len(newnode.RelayAddrs) > 0 {
+		for i, addr := range newnode.RelayAddrs {
+			if addr != node.RelayAddrs[i] {
+				relayupdate = true
+			}
+		}		
+	}
 	err = node.Update(&newnode)
 	err = node.Update(&newnode)
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
+	if relayupdate {
+		UpdateRelay(node.Network, node.RelayAddrs, newnode.RelayAddrs)
+		if err = functions.NetworkNodesUpdatePullChanges(node.Network); err != nil {
+			functions.PrintUserLog("netmaker", "error setting relay updates: " + err.Error(), 1)			
+		}
+	}
 	nodeData, err := json.Marshal(&newnode)
 	nodeData, err := json.Marshal(&newnode)
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
@@ -137,7 +150,12 @@ func (s *NodeServiceServer) GetPeers(ctx context.Context, req *nodepb.Object) (*
 		if node.IsServer == "yes" {
 		if node.IsServer == "yes" {
 			SetNetworkServerPeers(macAndNetwork[1])
 			SetNetworkServerPeers(macAndNetwork[1])
 		}
 		}
-		peers, err := GetPeersList(macAndNetwork[1])
+		excludeDoNotPropagate := node.IsRelay != "yes"
+		var relayedNode string 
+		if node.DoNotPropagate == "yes" {
+			relayedNode = node.Address
+		}
+		peers, err := GetPeersList(macAndNetwork[1], excludeDoNotPropagate, relayedNode)
 		if err != nil {
 		if err != nil {
 			return nil, err
 			return nil, err
 		}
 		}

+ 20 - 0
controllers/nodeHttpController.go

@@ -22,6 +22,8 @@ func nodeHandlers(r *mux.Router) {
 	r.HandleFunc("/api/nodes/{network}/{macaddress}", authorize(true, "node", http.HandlerFunc(getNode))).Methods("GET")
 	r.HandleFunc("/api/nodes/{network}/{macaddress}", authorize(true, "node", http.HandlerFunc(getNode))).Methods("GET")
 	r.HandleFunc("/api/nodes/{network}/{macaddress}", authorize(true, "node", http.HandlerFunc(updateNode))).Methods("PUT")
 	r.HandleFunc("/api/nodes/{network}/{macaddress}", authorize(true, "node", http.HandlerFunc(updateNode))).Methods("PUT")
 	r.HandleFunc("/api/nodes/{network}/{macaddress}", authorize(true, "node", http.HandlerFunc(deleteNode))).Methods("DELETE")
 	r.HandleFunc("/api/nodes/{network}/{macaddress}", authorize(true, "node", http.HandlerFunc(deleteNode))).Methods("DELETE")
+	r.HandleFunc("/api/nodes/{network}/{macaddress}/createrelay", authorize(true, "user", http.HandlerFunc(createRelay))).Methods("POST")
+	r.HandleFunc("/api/nodes/{network}/{macaddress}/deleterelay", authorize(true, "user", http.HandlerFunc(deleteRelay))).Methods("DELETE")
 	r.HandleFunc("/api/nodes/{network}/{macaddress}/creategateway", authorize(true, "user", http.HandlerFunc(createEgressGateway))).Methods("POST")
 	r.HandleFunc("/api/nodes/{network}/{macaddress}/creategateway", authorize(true, "user", http.HandlerFunc(createEgressGateway))).Methods("POST")
 	r.HandleFunc("/api/nodes/{network}/{macaddress}/deletegateway", authorize(true, "user", http.HandlerFunc(deleteEgressGateway))).Methods("DELETE")
 	r.HandleFunc("/api/nodes/{network}/{macaddress}/deletegateway", authorize(true, "user", http.HandlerFunc(deleteEgressGateway))).Methods("DELETE")
 	r.HandleFunc("/api/nodes/{network}/{macaddress}/createingress", securityCheck(false, http.HandlerFunc(createIngressGateway))).Methods("POST")
 	r.HandleFunc("/api/nodes/{network}/{macaddress}/createingress", securityCheck(false, http.HandlerFunc(createIngressGateway))).Methods("POST")
@@ -752,11 +754,29 @@ func updateNode(w http.ResponseWriter, r *http.Request) {
 		return
 		return
 	}
 	}
 	newNode.PullChanges = "yes"
 	newNode.PullChanges = "yes"
+	relayupdate := false
+	if node.IsRelay == "yes" && len(newNode.RelayAddrs) > 0 {
+		if len(newNode.RelayAddrs) != len(node.RelayAddrs) {
+				relayupdate = true
+		} else {
+			for i, addr := range newNode.RelayAddrs {
+					if addr != node.RelayAddrs[i] {
+							relayupdate = true
+					}
+			}
+		}
+	}
 	err = node.Update(&newNode)
 	err = node.Update(&newNode)
 	if err != nil {
 	if err != nil {
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 		return
 	}
 	}
+	if relayupdate {
+		UpdateRelay(node.Network, node.RelayAddrs, newNode.RelayAddrs)
+		if err = functions.NetworkNodesUpdatePullChanges(node.Network); err != nil {
+			functions.PrintUserLog("netmaker", "error setting relay updates: " + err.Error(), 1)			
+		}
+	}
 
 
 	if servercfg.IsDNSMode() {
 	if servercfg.IsDNSMode() {
 		err = SetDNS()
 		err = SetDNS()

+ 198 - 0
controllers/relay.go

@@ -0,0 +1,198 @@
+package controller
+
+import (
+	"encoding/json"
+	"errors"
+	"net/http"
+	"time"
+	"github.com/gorilla/mux"
+	"github.com/gravitl/netmaker/database"
+	"github.com/gravitl/netmaker/functions"
+	"github.com/gravitl/netmaker/models"
+)
+
+func createRelay(w http.ResponseWriter, r *http.Request) {
+	var relay models.RelayRequest
+	var params = mux.Vars(r)
+	w.Header().Set("Content-Type", "application/json")
+	err := json.NewDecoder(r.Body).Decode(&relay)
+	if err != nil {
+		returnErrorResponse(w, r, formatError(err, "internal"))
+		return
+	}
+	relay.NetID = params["network"]
+	relay.NodeID = params["macaddress"]
+	node, err := CreateRelay(relay)
+	if err != nil {
+		returnErrorResponse(w, r, formatError(err, "internal"))
+		return
+	}
+	functions.PrintUserLog(r.Header.Get("user"), "created relay on node "+relay.NodeID+" on network "+relay.NetID, 1)
+	w.WriteHeader(http.StatusOK)
+	json.NewEncoder(w).Encode(node)
+}
+
+func CreateRelay(relay models.RelayRequest) (models.Node, error) {
+	node, err := functions.GetNodeByMacAddress(relay.NetID, relay.NodeID)
+	if node.OS == "windows" { // add in darwin later
+		return models.Node{}, errors.New(node.OS + " is unsupported for relay")
+	}
+	if err != nil {
+		return models.Node{}, err
+	}
+	err = ValidateRelay(relay)
+	if err != nil {
+		return models.Node{}, err
+	}
+	node.IsRelay = "yes"
+	node.RelayAddrs = relay.Addrs
+
+	key, err := functions.GetRecordKey(relay.NodeID, relay.NetID)
+	if err != nil {
+		return node, err
+	}
+	node.SetLastModified()
+	node.PullChanges = "yes"
+	nodeData, err := json.Marshal(&node)
+	if err != nil {
+		return node, err
+	}
+	if err = database.Insert(key, string(nodeData), database.NODES_TABLE_NAME); err != nil {
+		return models.Node{}, err
+	}
+	err = SetNodesDoNotPropagate("yes", node.Network, node.RelayAddrs)
+	if err != nil {
+		return node, err
+	}
+
+	if err = functions.NetworkNodesUpdatePullChanges(node.Network); err != nil {
+		return models.Node{}, err
+	}
+	return node, nil
+}
+
+func SetNodesDoNotPropagate(yesOrno string, networkName string, addrs []string) error {
+
+	collections, err := database.FetchRecords(database.NODES_TABLE_NAME)
+	if err != nil {
+		return err
+	}
+
+	for _, value := range collections {
+
+		var node models.Node
+		err := json.Unmarshal([]byte(value), &node)
+		if err != nil {
+			return err
+		}
+		if node.Network == networkName {
+			for _, addr := range addrs {
+				if addr == node.Address || addr == node.Address6 {
+					node.DoNotPropagate = yesOrno
+					data, err := json.Marshal(&node)
+					if err != nil {
+						return err
+					}
+					node.SetID()
+					database.Insert(node.ID, string(data), database.NODES_TABLE_NAME)
+				}
+			}
+		}
+	}
+	return nil
+}
+
+func ValidateRelay(relay models.RelayRequest) error {
+	var err error
+	//isIp := functions.IsIpCIDR(gateway.RangeString)
+	empty := len(relay.Addrs) == 0
+	if empty {
+		err = errors.New("IP Ranges Cannot Be Empty")
+	}
+	return err
+}
+
+func UpdateRelay(network string, oldAddrs []string, newAddrs []string) {
+	time.Sleep(time.Second/4)	
+	err := SetNodesDoNotPropagate("no", network, oldAddrs)
+	if err != nil {
+		functions.PrintUserLog("netmaker",err.Error(),1)
+	}	
+	err = SetNodesDoNotPropagate("yes", network, newAddrs)
+	if err != nil {
+		functions.PrintUserLog("netmaker",err.Error(),1)
+	}}
+
+func deleteRelay(w http.ResponseWriter, r *http.Request) {
+	w.Header().Set("Content-Type", "application/json")
+	var params = mux.Vars(r)
+	nodeMac := params["macaddress"]
+	netid := params["network"]
+	node, err := DeleteRelay(netid, nodeMac)
+	if err != nil {
+		returnErrorResponse(w, r, formatError(err, "internal"))
+		return
+	}
+	functions.PrintUserLog(r.Header.Get("user"), "deleted egress gateway "+nodeMac+" on network "+netid, 1)
+	w.WriteHeader(http.StatusOK)
+	json.NewEncoder(w).Encode(node)
+}
+
+func DeleteRelay(network, macaddress string) (models.Node, error) {
+
+	node, err := functions.GetNodeByMacAddress(network, macaddress)
+	if err != nil {
+		return models.Node{}, err
+	}
+	err = SetNodesDoNotPropagate("no", node.Network, node.RelayAddrs)
+	if err != nil {
+		return node, err
+	}
+
+	node.IsRelay = "no"
+	node.RelayAddrs = []string{}
+	node.SetLastModified()
+	node.PullChanges = "yes"
+	key, err := functions.GetRecordKey(node.MacAddress, node.Network)
+	if err != nil {
+		return models.Node{}, err
+	}
+	data, err := json.Marshal(&node)
+	if err != nil {
+		return models.Node{}, err
+	}
+	if err = database.Insert(key, string(data), database.NODES_TABLE_NAME); err != nil {
+		return models.Node{}, err
+	}
+	if err = functions.NetworkNodesUpdatePullChanges(network); err != nil {
+		return models.Node{}, err
+	}
+	return node, nil
+}
+
+func GetNodeRelay(network string, relayedNodeAddr string) (models.Node, error){
+	collection, err := database.FetchRecords(database.NODES_TABLE_NAME)
+	var relay models.Node
+	if err != nil {
+		if database.IsEmptyRecord(err) {
+			return relay, nil
+		}
+		functions.PrintUserLog("", err.Error(), 2)
+		return relay, err
+	}
+	for _, value := range collection {
+		err := json.Unmarshal([]byte(value), &relay)
+		if err != nil {
+			functions.PrintUserLog("", err.Error(), 2)
+			continue
+		}
+		if relay.IsRelay == "yes" {
+			for _, addr := range relay.RelayAddrs {
+				if addr == relayedNodeAddr {
+					return relay, nil
+				}
+			}
+		}
+	}
+	return relay, errors.New("could not find relay for node " + relayedNodeAddr)
+}

+ 1 - 1
main.go

@@ -38,7 +38,7 @@ func initialize() { // Client Mode Prereq Check
 	}
 	}
 	log.Println("database successfully connected.")
 	log.Println("database successfully connected.")
 	if servercfg.IsClientMode() {
 	if servercfg.IsClientMode() {
-		output, err := local.RunCmd("id -u")
+		output, err := local.RunCmd("id -u", true)
 		if err != nil {
 		if err != nil {
 			log.Println("Error running 'id -u' for prereq check. Please investigate or disable client mode.")
 			log.Println("Error running 'id -u' for prereq check. Please investigate or disable client mode.")
 			log.Fatal(output, err)
 			log.Fatal(output, err)

+ 29 - 0
models/node.go

@@ -52,10 +52,13 @@ type Node struct {
 	CheckInInterval     int32    `json:"checkininterval" bson:"checkininterval" yaml:"checkininterval"`
 	CheckInInterval     int32    `json:"checkininterval" bson:"checkininterval" yaml:"checkininterval"`
 	Password            string   `json:"password" bson:"password" yaml:"password" validate:"required,min=6"`
 	Password            string   `json:"password" bson:"password" yaml:"password" validate:"required,min=6"`
 	Network             string   `json:"network" bson:"network" yaml:"network" validate:"network_exists"`
 	Network             string   `json:"network" bson:"network" yaml:"network" validate:"network_exists"`
+	DoNotPropagate      string   `json:"donotpropagate" bson:"donotpropagate" yaml:"donotpropagate"`
 	IsPending           string   `json:"ispending" bson:"ispending" yaml:"ispending"`
 	IsPending           string   `json:"ispending" bson:"ispending" yaml:"ispending"`
+	IsRelay				string   `json:"isrelay" bson:"isrelay" yaml:"isrelay"`
 	IsEgressGateway     string   `json:"isegressgateway" bson:"isegressgateway" yaml:"isegressgateway"`
 	IsEgressGateway     string   `json:"isegressgateway" bson:"isegressgateway" yaml:"isegressgateway"`
 	IsIngressGateway    string   `json:"isingressgateway" bson:"isingressgateway" yaml:"isingressgateway"`
 	IsIngressGateway    string   `json:"isingressgateway" bson:"isingressgateway" yaml:"isingressgateway"`
 	EgressGatewayRanges []string `json:"egressgatewayranges" bson:"egressgatewayranges" yaml:"egressgatewayranges"`
 	EgressGatewayRanges []string `json:"egressgatewayranges" bson:"egressgatewayranges" yaml:"egressgatewayranges"`
+	RelayAddrs 			[]string `json:"relayaddrs" bson:"relayaddrs" yaml:"relayaddrs"`
 	IngressGatewayRange string   `json:"ingressgatewayrange" bson:"ingressgatewayrange" yaml:"ingressgatewayrange"`
 	IngressGatewayRange string   `json:"ingressgatewayrange" bson:"ingressgatewayrange" yaml:"ingressgatewayrange"`
 	IsStatic            string   `json:"isstatic" bson:"isstatic" yaml:"isstatic" validate:"checkyesorno"`
 	IsStatic            string   `json:"isstatic" bson:"isstatic" yaml:"isstatic" validate:"checkyesorno"`
 	UDPHolePunch        string   `json:"udpholepunch" bson:"udpholepunch" yaml:"udpholepunch" validate:"checkyesorno"`
 	UDPHolePunch        string   `json:"udpholepunch" bson:"udpholepunch" yaml:"udpholepunch" validate:"checkyesorno"`
@@ -84,6 +87,18 @@ func (node *Node) SetDefaulIsPending() {
 	}
 	}
 }
 }
 
 
+func (node *Node) SetDefaultDoNotPropagate() {
+	if node.DoNotPropagate == "" {
+		node.DoNotPropagate = "no"
+	}
+}
+
+func (node *Node) SetDefaultIsRelay() {
+	if node.IsRelay == "" {
+		node.IsRelay = "no"
+	}
+}
+
 func (node *Node) SetDefaultEgressGateway() {
 func (node *Node) SetDefaultEgressGateway() {
 	if node.IsEgressGateway == "" {
 	if node.IsEgressGateway == "" {
 		node.IsEgressGateway = "no"
 		node.IsEgressGateway = "no"
@@ -269,6 +284,8 @@ func (node *Node) SetDefaults() {
 	node.SetDefaultIngressGateway()
 	node.SetDefaultIngressGateway()
 	node.SetDefaulIsPending()
 	node.SetDefaulIsPending()
 	node.SetDefaultMTU()
 	node.SetDefaultMTU()
+	node.SetDefaultDoNotPropagate()
+	node.SetDefaultIsRelay()
 	node.KeyUpdateTimeStamp = time.Now().Unix()
 	node.KeyUpdateTimeStamp = time.Now().Unix()
 }
 }
 
 
@@ -404,6 +421,18 @@ func (newNode *Node) Fill(currentNode *Node) {
 	if newNode.MTU == 0 {
 	if newNode.MTU == 0 {
 		newNode.MTU = currentNode.MTU
 		newNode.MTU = currentNode.MTU
 	}
 	}
+	if newNode.OS == "" {
+		newNode.OS = currentNode.OS
+	}
+	if newNode.RelayAddrs == nil {
+		newNode.RelayAddrs = currentNode.RelayAddrs
+	}
+	if newNode.IsRelay == "" {
+		newNode.IsRelay = currentNode.IsRelay
+	}
+	if newNode.DoNotPropagate == "" {
+		newNode.DoNotPropagate = currentNode.DoNotPropagate
+	}
 }
 }
 
 
 func (currentNode *Node) Update(newNode *Node) error {
 func (currentNode *Node) Update(newNode *Node) error {

+ 6 - 0
models/structs.go

@@ -128,3 +128,9 @@ type EgressGatewayRequest struct {
 	PostUp      string   `json:"postup" bson:"postup"`
 	PostUp      string   `json:"postup" bson:"postup"`
 	PostDown    string   `json:"postdown" bson:"postdown"`
 	PostDown    string   `json:"postdown" bson:"postdown"`
 }
 }
+
+type RelayRequest struct {
+	NodeID      string   `json:"nodeid" bson:"nodeid"`
+	NetID       string   `json:"netid" bson:"netid"`
+	Addrs      []string `json:"addrs" bson:"addrs"`
+}

+ 1 - 1
netclient/command/commands.go

@@ -26,7 +26,7 @@ func Join(cfg config.ClientConfig, privateKey string) error {
 
 
 	err := functions.JoinNetwork(cfg, privateKey)
 	err := functions.JoinNetwork(cfg, privateKey)
 
 
-	if err != nil {
+	if err != nil && !cfg.DebugJoin {
 		if !strings.Contains(err.Error(), "ALREADY_INSTALLED") {
 		if !strings.Contains(err.Error(), "ALREADY_INSTALLED") {
 			log.Println("Error installing: ", err)
 			log.Println("Error installing: ", err)
 			err = functions.LeaveNetwork(cfg.Network)
 			err = functions.LeaveNetwork(cfg.Network)

+ 1 - 1
netclient/config/config.go

@@ -8,7 +8,6 @@ import (
 	"fmt"
 	"fmt"
 	"log"
 	"log"
 	"os"
 	"os"
-
 	"github.com/gravitl/netmaker/models"
 	"github.com/gravitl/netmaker/models"
 	"github.com/gravitl/netmaker/netclient/netclientutils"
 	"github.com/gravitl/netmaker/netclient/netclientutils"
 	"github.com/urfave/cli/v2"
 	"github.com/urfave/cli/v2"
@@ -26,6 +25,7 @@ type ClientConfig struct {
 	Network         string       `yaml:"network"`
 	Network         string       `yaml:"network"`
 	Daemon          string       `yaml:"daemon"`
 	Daemon          string       `yaml:"daemon"`
 	OperatingSystem string       `yaml:"operatingsystem"`
 	OperatingSystem string       `yaml:"operatingsystem"`
+	DebugJoin		bool		 `yaml:"debugjoin"`
 }
 }
 type ServerConfig struct {
 type ServerConfig struct {
 	CoreDNSAddr   string `yaml:"corednsaddr"`
 	CoreDNSAddr   string `yaml:"corednsaddr"`

+ 4 - 9
netclient/functions/common.go

@@ -178,20 +178,15 @@ func DeleteInterface(ifacename string, postdown string) error {
 	if netclientutils.IsWindows() {
 	if netclientutils.IsWindows() {
 		err = local.RemoveWindowsConf(ifacename)
 		err = local.RemoveWindowsConf(ifacename)
 	} else {
 	} else {
-		ipExec, err := exec.LookPath("ip")
+		ipExec, errN := exec.LookPath("ip")
+		err = errN
 		if err != nil {
 		if err != nil {
 			log.Println(err)
 			log.Println(err)
 		}
 		}
-		out, err := local.RunCmd(ipExec + " link del " + ifacename)
-		if err != nil {
-			log.Println(out, err)
-		}
+		_, err = local.RunCmd(ipExec + " link del " + ifacename, false)
 		if postdown != "" {
 		if postdown != "" {
 			runcmds := strings.Split(postdown, "; ")
 			runcmds := strings.Split(postdown, "; ")
-			err = local.RunCmds(runcmds)
-			if err != nil {
-				log.Println("Error encountered running PostDown: " + err.Error())
-			}
+			err = local.RunCmds(runcmds, true)
 		}
 		}
 	}
 	}
 	return err
 	return err

+ 3 - 6
netclient/local/dns.go

@@ -42,20 +42,17 @@ func UpdateDNS(ifacename string, network string, nameserver string) error {
 		log.Println(err)
 		log.Println(err)
 		log.Println("WARNING: resolvectl not present. Unable to set dns. Install resolvectl or run manually.")
 		log.Println("WARNING: resolvectl not present. Unable to set dns. Install resolvectl or run manually.")
 	} else {
 	} else {
-		_, err = RunCmd("resolvectl domain " + ifacename + " ~" + network)
+		_, err = RunCmd("resolvectl domain " + ifacename + " ~" + network, true)
 		if err != nil {
 		if err != nil {
-			log.Println(err)
 			log.Println("WARNING: Error encountered setting domain on dns. Aborted setting dns.")
 			log.Println("WARNING: Error encountered setting domain on dns. Aborted setting dns.")
 		} else {
 		} else {
-			_, err = RunCmd("resolvectl default-route " + ifacename + " false")
+			_, err = RunCmd("resolvectl default-route " + ifacename + " false", true)
 			if err != nil {
 			if err != nil {
-				log.Println(err)
 				log.Println("WARNING: Error encountered setting default-route on dns. Aborted setting dns.")
 				log.Println("WARNING: Error encountered setting default-route on dns. Aborted setting dns.")
 			} else {
 			} else {
-				_, err = RunCmd("resolvectl dns " + ifacename + " " + nameserver)
+				_, err = RunCmd("resolvectl dns " + ifacename + " " + nameserver, true)
 				if err != nil {
 				if err != nil {
 					log.Println("WARNING: Error encountered running resolvectl dns " + ifacename + " " + nameserver)
 					log.Println("WARNING: Error encountered running resolvectl dns " + ifacename + " " + nameserver)
-					log.Println(err)
 				}
 				}
 			}
 			}
 		}
 		}

+ 30 - 65
netclient/local/local.go

@@ -29,17 +29,15 @@ func SetIPForwarding() error {
 }
 }
 
 
 func SetIPForwardingLinux() error {
 func SetIPForwardingLinux() error {
-	out, err := RunCmd("sysctl net.ipv4.ip_forward")
+	out, err := RunCmd("sysctl net.ipv4.ip_forward", true)
 	if err != nil {
 	if err != nil {
-		log.Println(err)
 		log.Println("WARNING: Error encountered setting ip forwarding. This can break functionality.")
 		log.Println("WARNING: Error encountered setting ip forwarding. This can break functionality.")
 		return err
 		return err
 	} else {
 	} else {
 		s := strings.Fields(string(out))
 		s := strings.Fields(string(out))
 		if s[2] != "1" {
 		if s[2] != "1" {
-			_, err = RunCmd("sysctl -w net.ipv4.ip_forward=1")
+			_, err = RunCmd("sysctl -w net.ipv4.ip_forward=1", true)
 			if err != nil {
 			if err != nil {
-				log.Println(err)
 				log.Println("WARNING: Error encountered setting ip forwarding. You may want to investigate this.")
 				log.Println("WARNING: Error encountered setting ip forwarding. You may want to investigate this.")
 				return err
 				return err
 			}
 			}
@@ -48,23 +46,25 @@ func SetIPForwardingLinux() error {
 	return nil
 	return nil
 }
 }
 
 
-func RunCmd(command string) (string, error) {
+func RunCmd(command string, printerr bool) (string, error) {
 	args := strings.Fields(command)
 	args := strings.Fields(command)
-	out, err := exec.Command(args[0], args[1:]...).Output()
+	out, err := exec.Command(args[0], args[1:]...).CombinedOutput()
+	if err != nil && printerr {
+		log.Println("error running command:",command)
+		log.Println(string(out))
+	}
 	return string(out), err
 	return string(out), err
 }
 }
 
 
-func RunCmds(commands []string) error {
+func RunCmds(commands []string, printerr bool) error {
 	var err error
 	var err error
 	for _, command := range commands {
 	for _, command := range commands {
 		args := strings.Fields(command)
 		args := strings.Fields(command)
-		out, err := exec.Command(args[0], args[1:]...).Output()
-		if string(out) != "" {
+		out, err := exec.Command(args[0], args[1:]...).CombinedOutput()
+		if err != nil && printerr {
+			log.Println("error running command:",command)
 			log.Println(string(out))
 			log.Println(string(out))
 		}
 		}
-		if err != nil {
-			return err
-		}
 	}
 	}
 	return err
 	return err
 }
 }
@@ -175,26 +175,10 @@ WantedBy=timers.target
 		}
 		}
 	}
 	}
 
 
-	_, err = RunCmd("systemctl enable [email protected]")
-	if err != nil {
-		log.Println("Error enabling [email protected]. Please investigate.")
-		log.Println(err)
-	}
-	_, err = RunCmd("systemctl daemon-reload")
-	if err != nil {
-		log.Println("Error reloading system daemons. Please investigate.")
-		log.Println(err)
-	}
-	_, err = RunCmd("systemctl enable netclient-" + network + ".timer")
-	if err != nil {
-		log.Println("Error enabling netclient.timer. Please investigate.")
-		log.Println(err)
-	}
-	_, err = RunCmd("systemctl start netclient-" + network + ".timer")
-	if err != nil {
-		log.Println("Error starting netclient-" + network + ".timer. Please investigate.")
-		log.Println(err)
-	}
+	_, _ = RunCmd("systemctl enable [email protected]", true)
+	_, _ = RunCmd("systemctl daemon-reload", true)
+	_, _ = RunCmd("systemctl enable netclient-" + network + ".timer", true)
+	_, _ = RunCmd("systemctl start netclient-" + network + ".timer", true)
 	return nil
 	return nil
 }
 }
 
 
@@ -221,21 +205,12 @@ func RemoveSystemDServices(network string) error {
 		}
 		}
 
 
 		if fullremove {
 		if fullremove {
-			_, err = RunCmd("systemctl disable [email protected]")
-			if err != nil {
-				log.Println("Error disabling [email protected]. Please investigate.")
-				log.Println(err)
-			}
+			_, err = RunCmd("systemctl disable [email protected]", true)
 		}
 		}
-		_, err = RunCmd("systemctl daemon-reload")
-		if err != nil {
-			log.Println("Error stopping netclient-" + network + ".timer. Please investigate.")
-			log.Println(err)
-		}
-		_, err = RunCmd("systemctl disable netclient-" + network + ".timer")
-		if err != nil {
-			log.Println("Error disabling netclient-" + network + ".timer. Please investigate.")
-			log.Println(err)
+		_, _ = RunCmd("systemctl daemon-reload", true)
+
+		if FileExists("/etc/systemd/system/netclient-" + network + ".timer") {
+			_, _ = RunCmd("systemctl disable netclient-" + network + ".timer", true)
 		}
 		}
 		if fullremove {
 		if fullremove {
 			if FileExists("/etc/systemd/system/[email protected]") {
 			if FileExists("/etc/systemd/system/[email protected]") {
@@ -249,17 +224,8 @@ func RemoveSystemDServices(network string) error {
 			log.Println("Error removing file. Please investigate.")
 			log.Println("Error removing file. Please investigate.")
 			log.Println(err)
 			log.Println(err)
 		}
 		}
-		_, err = RunCmd("systemctl daemon-reload")
-		if err != nil {
-			log.Println("Error reloading system daemons. Please investigate.")
-			log.Println(err)
-		}
-		_, err = RunCmd("systemctl reset-failed")
-		if err != nil {
-			log.Println("Error reseting failed system services. Please investigate.")
-			log.Println(err)
-		}
-		return err
+		_, _ = RunCmd("systemctl daemon-reload", true)
+		_, _ = RunCmd("systemctl reset-failed", true)
 	}
 	}
 	return nil
 	return nil
 }
 }
@@ -291,7 +257,7 @@ func WipeLocal(network string) error {
 
 
 	if ifacename != "" {
 	if ifacename != "" {
 		if netclientutils.IsWindows() {
 		if netclientutils.IsWindows() {
-			if err := RemoveWindowsConf(ifacename); err == nil {
+			if err = RemoveWindowsConf(ifacename); err == nil {
 				log.Println("removed Windows interface", ifacename)
 				log.Println("removed Windows interface", ifacename)
 			}
 			}
 		} else {
 		} else {
@@ -299,16 +265,15 @@ func WipeLocal(network string) error {
 			if err != nil {
 			if err != nil {
 				return err
 				return err
 			}
 			}
-			out, err := RunCmd(ipExec + " link del " + ifacename)
-			if err != nil {
-				log.Println(out, err)
+			out, err := RunCmd(ipExec + " link del " + ifacename, false)
+			dontprint := strings.Contains(out, "does not exist") || strings.Contains(out, "Cannot find device")
+			if err != nil && !dontprint {
+				log.Println("error running command:",ipExec + " link del " + ifacename)
+				log.Println(out)
 			}
 			}
 			if nodecfg.PostDown != "" {
 			if nodecfg.PostDown != "" {
 				runcmds := strings.Split(nodecfg.PostDown, "; ")
 				runcmds := strings.Split(nodecfg.PostDown, "; ")
-				err = RunCmds(runcmds)
-				if err != nil {
-					log.Println("Error encountered running PostDown: " + err.Error())
-				}
+				_ = RunCmds(runcmds, false)
 			}
 			}
 		}
 		}
 	}
 	}

+ 7 - 7
netclient/local/windows.go

@@ -13,7 +13,7 @@ import (
 )
 )
 
 
 func IsWindowsWGInstalled() bool {
 func IsWindowsWGInstalled() bool {
-	out, err := RunCmd("wg help")
+	out, err := RunCmd("wg help", true)
 	if err != nil {
 	if err != nil {
 		return false
 		return false
 	}
 	}
@@ -21,14 +21,14 @@ func IsWindowsWGInstalled() bool {
 }
 }
 
 
 func ApplyWindowsConf(confPath string) error {
 func ApplyWindowsConf(confPath string) error {
-	if _, err := RunCmd("wireguard.exe /installtunnelservice " + confPath); err != nil {
+	if _, err := RunCmd("wireguard.exe /installtunnelservice " + confPath, true); err != nil {
 		return err
 		return err
 	}
 	}
 	return nil
 	return nil
 }
 }
 
 
 func RemoveWindowsConf(ifacename string) error {
 func RemoveWindowsConf(ifacename string) error {
-	if _, err := RunCmd("wireguard.exe /uninstalltunnelservice " + ifacename); err != nil {
+	if _, err := RunCmd("wireguard.exe /uninstalltunnelservice " + ifacename, true); err != nil {
 		return err
 		return err
 	}
 	}
 	return nil
 	return nil
@@ -58,12 +58,12 @@ func writeServiceConfig() error {
 func StopWindowsDaemon() {
 func StopWindowsDaemon() {
 	netclientutils.Log("no networks detected, stopping Windows, Netclient daemon")
 	netclientutils.Log("no networks detected, stopping Windows, Netclient daemon")
 	// stop daemon, will not overwrite
 	// stop daemon, will not overwrite
-	RunCmd(strings.Replace(netclientutils.GetNetclientPathSpecific(), `\\`, `\`, -1) + `winsw.exe stop`)
+	RunCmd(strings.Replace(netclientutils.GetNetclientPathSpecific(), `\\`, `\`, -1) + `winsw.exe stop`, true)
 }
 }
 
 
 func RemoveWindowsDaemon() {
 func RemoveWindowsDaemon() {
 	// uninstall daemon, will not restart or start another
 	// uninstall daemon, will not restart or start another
-	RunCmd(strings.Replace(netclientutils.GetNetclientPathSpecific(), `\\`, `\`, -1) + `winsw.exe uninstall`)
+	RunCmd(strings.Replace(netclientutils.GetNetclientPathSpecific(), `\\`, `\`, -1) + `winsw.exe uninstall`, true)
 	netclientutils.Log("uninstalled Windows, Netclient daemon")
 	netclientutils.Log("uninstalled Windows, Netclient daemon")
 }
 }
 
 
@@ -144,9 +144,9 @@ func CreateAndRunWindowsDaemon() error {
 		netclientutils.Log("finished daemon setup")
 		netclientutils.Log("finished daemon setup")
 	}
 	}
 	// install daemon, will not overwrite
 	// install daemon, will not overwrite
-	RunCmd(strings.Replace(netclientutils.GetNetclientPathSpecific(), `\\`, `\`, -1) + `winsw.exe install`)
+	RunCmd(strings.Replace(netclientutils.GetNetclientPathSpecific(), `\\`, `\`, -1) + `winsw.exe install`, true)
 	// start daemon, will not restart or start another
 	// start daemon, will not restart or start another
-	RunCmd(strings.Replace(netclientutils.GetNetclientPathSpecific(), `\\`, `\`, -1) + `winsw.exe start`)
+	RunCmd(strings.Replace(netclientutils.GetNetclientPathSpecific(), `\\`, `\`, -1) + `winsw.exe start`, true)
 	netclientutils.Log(strings.Replace(netclientutils.GetNetclientPathSpecific(), `\\`, `\`, -1) + `winsw.exe start`)
 	netclientutils.Log(strings.Replace(netclientutils.GetNetclientPathSpecific(), `\\`, `\`, -1) + `winsw.exe start`)
 	return nil
 	return nil
 }
 }

+ 1 - 1
netclient/main.go

@@ -324,7 +324,7 @@ func main() {
 		ncwindows.InitWindows()
 		ncwindows.InitWindows()
 	} else {
 	} else {
 		// start our application
 		// start our application
-		out, err := local.RunCmd("id -u")
+		out, err := local.RunCmd("id -u", true)
 
 
 		if err != nil {
 		if err != nil {
 			log.Fatal(out, err)
 			log.Fatal(out, err)

+ 10 - 4
netclient/server/grpc.go

@@ -19,6 +19,8 @@ import (
 	"google.golang.org/grpc/metadata"
 	"google.golang.org/grpc/metadata"
 )
 )
 
 
+const RELAY_KEEPALIVE_MARKER = "20007ms"
+
 func getGrpcClient(cfg *config.ClientConfig) (nodepb.NodeServiceClient, error) {
 func getGrpcClient(cfg *config.ClientConfig) (nodepb.NodeServiceClient, error) {
 	var wcclient nodepb.NodeServiceClient
 	var wcclient nodepb.NodeServiceClient
 	// == GRPC SETUP ==
 	// == GRPC SETUP ==
@@ -119,7 +121,6 @@ func RemoveNetwork(network string) error {
 }
 }
 
 
 func GetPeers(macaddress string, network string, server string, dualstack bool, isIngressGateway bool) ([]wgtypes.PeerConfig, bool, []string, error) {
 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
 	hasGateway := false
 	var gateways []string
 	var gateways []string
 	var peers []wgtypes.PeerConfig
 	var peers []wgtypes.PeerConfig
@@ -197,10 +198,16 @@ func GetPeers(macaddress string, network string, server string, dualstack bool,
 		for _, allowedIp := range node.AllowedIPs {
 		for _, allowedIp := range node.AllowedIPs {
 			if _, ipnet, err := net.ParseCIDR(allowedIp); err == nil {
 			if _, ipnet, err := net.ParseCIDR(allowedIp); err == nil {
 				nodeEndpointArr := strings.Split(node.Endpoint, ":")
 				nodeEndpointArr := strings.Split(node.Endpoint, ":")
-				if !ipnet.Contains(net.IP(nodeEndpointArr[0])) { // don't need to add an allowed ip that already exists..
+				if !ipnet.Contains(net.IP(nodeEndpointArr[0])) && ipnet.IP.String() != node.Address { // don't need to add an allowed ip that already exists..
 					allowedips = append(allowedips, *ipnet)
 					allowedips = append(allowedips, *ipnet)
 				}
 				}
-			}
+			} else if appendip := net.ParseIP(allowedIp); appendip != nil && allowedIp != node.Address {
+					ipnet := net.IPNet{
+						IP:   net.ParseIP(allowedIp),
+						Mask: net.CIDRMask(32, 32),
+					}
+					allowedips = append(allowedips, ipnet)
+			}		
 		}
 		}
 		// handle egress gateway peers
 		// handle egress gateway peers
 		if node.IsEgressGateway == "yes" {
 		if node.IsEgressGateway == "yes" {
@@ -271,7 +278,6 @@ func GetPeers(macaddress string, network string, server string, dualstack bool,
 	}
 	}
 	return peers, hasGateway, gateways, err
 	return peers, hasGateway, gateways, err
 }
 }
-
 func GetExtPeers(macaddress string, network string, server string, dualstack bool) ([]wgtypes.PeerConfig, error) {
 func GetExtPeers(macaddress string, network string, server string, dualstack bool) ([]wgtypes.PeerConfig, error) {
 	var peers []wgtypes.PeerConfig
 	var peers []wgtypes.PeerConfig
 	var wcclient nodepb.NodeServiceClient
 	var wcclient nodepb.NodeServiceClient

+ 18 - 45
netclient/wireguard/kernel.go

@@ -68,19 +68,9 @@ func InitWireguard(node *models.Node, privkey string, peers []wgtypes.PeerConfig
 			return err
 			return err
 		}
 		}
 
 
-		_, delErr := local.RunCmd("ip link delete dev " + ifacename)
-		addLinkOut, addLinkErr := local.RunCmd(ipExec + " link add dev " + ifacename + " type wireguard")
-		addOut, addErr := local.RunCmd(ipExec + " address add dev " + ifacename + " " + node.Address + "/24")
-		if delErr != nil {
-			// not displaying error
-			// log.Println(delOut, delErr)
-		}
-		if addLinkErr != nil {
-			log.Println(addLinkOut, addLinkErr)
-		}
-		if addErr != nil {
-			log.Println(addOut, addErr)
-		}
+		_, _ = local.RunCmd("ip link delete dev " + ifacename, false)
+		_, _ = local.RunCmd(ipExec + " link add dev " + ifacename + " type wireguard", true)
+		_, _ = local.RunCmd(ipExec + " address add dev " + ifacename + " " + node.Address + "/24", true)
 	}
 	}
 	var nodeport int
 	var nodeport int
 	nodeport = int(node.ListenPort)
 	nodeport = int(node.ListenPort)
@@ -151,47 +141,33 @@ func InitWireguard(node *models.Node, privkey string, peers []wgtypes.PeerConfig
 			_ = local.UpdateDNS(ifacename, network, nameserver)
 			_ = local.UpdateDNS(ifacename, network, nameserver)
 		}
 		}
 		//=========End DNS Setup=======\\
 		//=========End DNS Setup=======\\
-		if _, err := local.RunCmd(ipExec + " link set down dev " + ifacename); err != nil {
+		if _, err := local.RunCmd(ipExec + " link set down dev " + ifacename, false); err != nil {
 			netclientutils.Log("attempted to remove interface before editing")
 			netclientutils.Log("attempted to remove interface before editing")
 			return err
 			return err
 		}
 		}
 
 
 		if nodecfg.PostDown != "" {
 		if nodecfg.PostDown != "" {
 			runcmds := strings.Split(nodecfg.PostDown, "; ")
 			runcmds := strings.Split(nodecfg.PostDown, "; ")
-			err = local.RunCmds(runcmds)
-			if err != nil {
-				fmt.Println("Error encountered running PostDown: " + err.Error())
-			}
+			err = local.RunCmds(runcmds, true)
 		}
 		}
 		// set MTU of node interface
 		// set MTU of node interface
-		if _, err := local.RunCmd(ipExec + " link set mtu " + strconv.Itoa(int(nodecfg.MTU)) + " up dev " + ifacename); err != nil {
+		if _, err := local.RunCmd(ipExec + " link set mtu " + strconv.Itoa(int(nodecfg.MTU)) + " up dev " + ifacename, true); err != nil {
 			netclientutils.Log("failed to create interface with mtu " + ifacename)
 			netclientutils.Log("failed to create interface with mtu " + ifacename)
 			return err
 			return err
 		}
 		}
 
 
 		if nodecfg.PostUp != "" {
 		if nodecfg.PostUp != "" {
 			runcmds := strings.Split(nodecfg.PostUp, "; ")
 			runcmds := strings.Split(nodecfg.PostUp, "; ")
-			err = local.RunCmds(runcmds)
-			if err != nil {
-				fmt.Println("Error encountered running PostUp: " + err.Error())
-			}
+			err = local.RunCmds(runcmds, true)
 		}
 		}
 		if hasGateway {
 		if hasGateway {
 			for _, gateway := range gateways {
 			for _, gateway := range gateways {
-				out, err := local.RunCmd(ipExec + " -4 route add " + gateway + " dev " + ifacename)
-				fmt.Println(string(out))
-				if err != nil {
-					fmt.Println("error encountered adding gateway: " + err.Error())
-				}
+				_, _ = local.RunCmd(ipExec + " -4 route add " + gateway + " dev " + ifacename, true)
 			}
 			}
 		}
 		}
 		if node.Address6 != "" && node.IsDualStack == "yes" {
 		if node.Address6 != "" && node.IsDualStack == "yes" {
-			fmt.Println("adding address: " + node.Address6)
-			out, err := local.RunCmd(ipExec + " address add dev " + ifacename + " " + node.Address6 + "/64")
-			if err != nil {
-				fmt.Println(out)
-				fmt.Println("error encountered adding ipv6: " + err.Error())
-			}
+			log.Println("[netclient] adding address: " + node.Address6, 1)
+			_, _ = local.RunCmd(ipExec + " address add dev " + ifacename + " " + node.Address6 + "/64", true)
 		}
 		}
 	}
 	}
 	return err
 	return err
@@ -287,9 +263,9 @@ func SetPeers(iface string, keepalive int32, peers []wgtypes.PeerConfig) error {
 		for _, currentPeer := range devicePeers {
 		for _, currentPeer := range devicePeers {
 			if currentPeer.AllowedIPs[0].String() == peer.AllowedIPs[0].String() &&
 			if currentPeer.AllowedIPs[0].String() == peer.AllowedIPs[0].String() &&
 				currentPeer.PublicKey.String() != peer.PublicKey.String() {
 				currentPeer.PublicKey.String() != peer.PublicKey.String() {
-				output, err := local.RunCmd("wg set " + iface + " peer " + currentPeer.PublicKey.String() + " remove")
+				_, err := local.RunCmd("wg set " + iface + " peer " + currentPeer.PublicKey.String() + " remove", true)
 				if err != nil {
 				if err != nil {
-					log.Println(output, "error removing peer", peer.Endpoint.String())
+					log.Println("error removing peer", peer.Endpoint.String())
 				}
 				}
 			}
 			}
 		}
 		}
@@ -304,19 +280,18 @@ func SetPeers(iface string, keepalive int32, peers []wgtypes.PeerConfig) error {
 		if keepAliveString == "0" {
 		if keepAliveString == "0" {
 			keepAliveString = "5"
 			keepAliveString = "5"
 		}
 		}
-		var output string
 		if peer.Endpoint != nil {
 		if peer.Endpoint != nil {
-			output, err = local.RunCmd("wg set " + iface + " peer " + peer.PublicKey.String() +
+			_, err = local.RunCmd("wg set " + iface + " peer " + peer.PublicKey.String() +
 				" endpoint " + udpendpoint +
 				" endpoint " + udpendpoint +
 				" persistent-keepalive " + keepAliveString +
 				" persistent-keepalive " + keepAliveString +
-				" allowed-ips " + allowedips)
+				" allowed-ips " + allowedips, true)
 		} else {
 		} else {
-			output, err = local.RunCmd("wg set " + iface + " peer " + peer.PublicKey.String() +
+			_, err = local.RunCmd("wg set " + iface + " peer " + peer.PublicKey.String() +
 				" persistent-keepalive " + keepAliveString +
 				" persistent-keepalive " + keepAliveString +
-				" allowed-ips " + allowedips)
+				" allowed-ips " + allowedips, true)
 		}
 		}
 		if err != nil {
 		if err != nil {
-			log.Println(output, "error setting peer", peer.PublicKey.String(), err)
+			log.Println("error setting peer", peer.PublicKey.String())
 		}
 		}
 	}
 	}
 
 
@@ -328,11 +303,9 @@ func SetPeers(iface string, keepalive int32, peers []wgtypes.PeerConfig) error {
 			}
 			}
 		}
 		}
 		if shouldDelete {
 		if shouldDelete {
-			output, err := local.RunCmd("wg set " + iface + " peer " + currentPeer.PublicKey.String() + " remove")
+			output, err := local.RunCmd("wg set " + iface + " peer " + currentPeer.PublicKey.String() + " remove", true)
 			if err != nil {
 			if err != nil {
 				log.Println(output, "error removing peer", currentPeer.PublicKey.String())
 				log.Println(output, "error removing peer", currentPeer.PublicKey.String())
-			} else {
-				log.Println("removed peer " + currentPeer.PublicKey.String())
 			}
 			}
 		}
 		}
 	}
 	}

+ 5 - 5
serverctl/serverctl.go

@@ -93,12 +93,10 @@ func RemoveNetwork(network string) (bool, error) {
 		log.Println("could not find " + netclientPath + "netclient")
 		log.Println("could not find " + netclientPath + "netclient")
 		return false, err
 		return false, err
 	}
 	}
-	cmdoutput, err := local.RunCmd(netclientPath + "netclient leave -n " + network)
-	if err != nil {
-		log.Println(string(cmdoutput))
-		return false, err
+	_, err = local.RunCmd(netclientPath+"netclient leave -n "+network, true)
+	if err == nil {
+		log.Println("Server removed from network " + network)
 	}
 	}
-	log.Println("Server removed from network " + network)
 	return true, err
 	return true, err
 
 
 }
 }
@@ -138,6 +136,8 @@ func AddNetwork(network string) (bool, error) {
 	functions.PrintUserLog(models.NODE_SERVER_NAME, "executing network join: "+netclientPath+"netclient "+"join "+"-t "+token+" -name "+models.NODE_SERVER_NAME+" -endpoint "+pubip, 0)
 	functions.PrintUserLog(models.NODE_SERVER_NAME, "executing network join: "+netclientPath+"netclient "+"join "+"-t "+token+" -name "+models.NODE_SERVER_NAME+" -endpoint "+pubip, 0)
 
 
 	joinCMD := exec.Command(netclientPath+"netclient", "join", "-t", token, "-name", models.NODE_SERVER_NAME, "-endpoint", pubip)
 	joinCMD := exec.Command(netclientPath+"netclient", "join", "-t", token, "-name", models.NODE_SERVER_NAME, "-endpoint", pubip)
+	joinCMD.Stdout = os.Stdout
+	joinCMD.Stderr = os.Stderr
 	err = joinCMD.Start()
 	err = joinCMD.Start()
 
 
 	if err != nil {
 	if err != nil {