Browse Source

Merge pull request #666 from gravitl/feature_v0.10.0_client_refactor1

Feature v0.10.0 client refactor1
dcarns 3 years ago
parent
commit
959a688426

+ 19 - 1
controllers/network.go

@@ -123,7 +123,7 @@ func updateNetwork(w http.ResponseWriter, r *http.Request) {
 		newNetwork.DefaultPostUp = network.DefaultPostUp
 		newNetwork.DefaultPostUp = network.DefaultPostUp
 	}
 	}
 
 
-	rangeupdate, localrangeupdate, err := logic.UpdateNetwork(&network, &newNetwork)
+	rangeupdate, localrangeupdate, holepunchupdate, err := logic.UpdateNetwork(&network, &newNetwork)
 	if err != nil {
 	if err != nil {
 		returnErrorResponse(w, r, formatError(err, "badrequest"))
 		returnErrorResponse(w, r, formatError(err, "badrequest"))
 		return
 		return
@@ -148,6 +148,24 @@ func updateNetwork(w http.ResponseWriter, r *http.Request) {
 			return
 			return
 		}
 		}
 	}
 	}
+	if holepunchupdate {
+		err = logic.UpdateNetworkHolePunching(network.NetID, newNetwork.DefaultUDPHolePunch)
+		if err != nil {
+			returnErrorResponse(w, r, formatError(err, "internal"))
+			return
+		}
+	}
+	if rangeupdate || localrangeupdate || holepunchupdate {
+		nodes, err := logic.GetNetworkNodes(network.NetID)
+		if err != nil {
+			returnErrorResponse(w, r, formatError(err, "internal"))
+			return
+		}
+		for _, node := range nodes {
+			runUpdates(&node, true)
+		}
+	}
+
 	logger.Log(1, r.Header.Get("user"), "updated network", netname)
 	logger.Log(1, r.Header.Get("user"), "updated network", netname)
 	w.WriteHeader(http.StatusOK)
 	w.WriteHeader(http.StatusOK)
 	json.NewEncoder(w).Encode(newNetwork)
 	json.NewEncoder(w).Encode(newNetwork)

+ 22 - 23
controllers/node_grpc.go

@@ -11,6 +11,7 @@ import (
 	"github.com/gravitl/netmaker/logger"
 	"github.com/gravitl/netmaker/logger"
 	"github.com/gravitl/netmaker/logic"
 	"github.com/gravitl/netmaker/logic"
 	"github.com/gravitl/netmaker/models"
 	"github.com/gravitl/netmaker/models"
+	"github.com/gravitl/netmaker/mq"
 	"github.com/gravitl/netmaker/servercfg"
 	"github.com/gravitl/netmaker/servercfg"
 	"github.com/gravitl/netmaker/serverctl"
 	"github.com/gravitl/netmaker/serverctl"
 )
 )
@@ -104,6 +105,27 @@ func (s *NodeServiceServer) CreateNode(ctx context.Context, req *nodepb.Object)
 
 
 	runUpdates(&node, false)
 	runUpdates(&node, false)
 
 
+	go func(node *models.Node) {
+		if node.UDPHolePunch == "yes" {
+			var currentServerNode, getErr = logic.GetNetworkServerLeader(node.Network)
+			if getErr != nil {
+				return
+			}
+			for i := 0; i < 5; i++ {
+				if logic.HasPeerConnected(node) {
+					if logic.ShouldPublishPeerPorts(&currentServerNode) {
+						err = mq.PublishPeerUpdate(&currentServerNode)
+						if err != nil {
+							logger.Log(1, "error publishing port updates when node", node.Name, "joined")
+						}
+						break
+					}
+				}
+				time.Sleep(time.Second << 1) // allow time for client to startup
+			}
+		}
+	}(&node)
+
 	return response, nil
 	return response, nil
 }
 }
 
 
@@ -164,7 +186,6 @@ func getServerAddrs(node *models.Node) {
 		serverAddrs = append(serverAddrs, models.ServerAddr{
 		serverAddrs = append(serverAddrs, models.ServerAddr{
 			IsLeader: logic.IsLeader(&node),
 			IsLeader: logic.IsLeader(&node),
 			Address:  node.Address,
 			Address:  node.Address,
-			ID:       node.ID,
 		})
 		})
 	}
 	}
 
 
@@ -261,29 +282,7 @@ func (s *NodeServiceServer) GetExtPeers(ctx context.Context, req *nodepb.Object)
 }
 }
 
 
 // == private methods ==
 // == private methods ==
-/*
-func getNewOrLegacyNode(data string) (models.Node, error) {
-	var reqNode, node models.Node
-	var err error
 
 
-	if err = json.Unmarshal([]byte(data), &reqNode); err != nil {
-		oldID := strings.Split(data, "###") // handle legacy client IDs
-		if len(oldID) == 2 {
-			if node, err = logic.GetNodeByID(reqNode.ID); err != nil {
-				return models.Node{}, err
-			}
-		} else {
-			return models.Node{}, err
-		}
-	} else {
-		node, err = logic.GetNodeByID(reqNode.ID)
-		if err != nil {
-			return models.Node{}, err
-		}
-	}
-	return node, nil
-}
-*/
 func getNodeFromRequestData(data string) (models.Node, error) {
 func getNodeFromRequestData(data string) (models.Node, error) {
 	var reqNode models.Node
 	var reqNode models.Node
 	var err error
 	var err error

+ 1 - 5
controllers/server_util.go

@@ -23,14 +23,10 @@ func runServerPeerUpdate(node *models.Node, ifaceDelta bool) error {
 	if servercfg.IsClientMode() != "on" {
 	if servercfg.IsClientMode() != "on" {
 		return nil
 		return nil
 	}
 	}
-	var currentServerNodeID, getErr = logic.GetNetworkServerNodeID(node.Network)
+	var currentServerNode, getErr = logic.GetNetworkServerLeader(node.Network)
 	if err != nil {
 	if err != nil {
 		return getErr
 		return getErr
 	}
 	}
-	var currentServerNode, currErr = logic.GetNodeByID(currentServerNodeID)
-	if currErr != nil {
-		return currErr
-	}
 	if err = logic.ServerUpdate(&currentServerNode, ifaceDelta); err != nil {
 	if err = logic.ServerUpdate(&currentServerNode, ifaceDelta); err != nil {
 		logger.Log(1, "server node:", currentServerNode.ID, "failed update")
 		logger.Log(1, "server node:", currentServerNode.ID, "failed update")
 		return err
 		return err

+ 29 - 6
logic/networks.go

@@ -389,7 +389,7 @@ func UpdateNetworkLocalAddresses(networkName string) error {
 			node.Address = ipaddr
 			node.Address = ipaddr
 			newNodeData, err := json.Marshal(&node)
 			newNodeData, err := json.Marshal(&node)
 			if err != nil {
 			if err != nil {
-				fmt.Println("error in node  address assignment!")
+				logger.Log(1, "error in node  address assignment!")
 				return err
 				return err
 			}
 			}
 			database.Insert(node.ID, string(newNodeData), database.NODES_TABLE_NAME)
 			database.Insert(node.ID, string(newNodeData), database.NODES_TABLE_NAME)
@@ -399,6 +399,28 @@ func UpdateNetworkLocalAddresses(networkName string) error {
 	return nil
 	return nil
 }
 }
 
 
+// UpdateNetworkLocalAddresses - updates network localaddresses
+func UpdateNetworkHolePunching(networkName string, holepunch string) error {
+
+	nodes, err := GetNetworkNodes(networkName)
+	if err != nil {
+		return err
+	}
+
+	for _, node := range nodes {
+		if node.IsServer != "yes" {
+			node.UDPHolePunch = holepunch
+			newNodeData, err := json.Marshal(&node)
+			if err != nil {
+				logger.Log(1, "error in node hole punch assignment")
+				return err
+			}
+			database.Insert(node.ID, string(newNodeData), database.NODES_TABLE_NAME)
+		}
+	}
+	return nil
+}
+
 // RemoveNetworkNodeIPv6Addresses - removes network node IPv6 addresses
 // RemoveNetworkNodeIPv6Addresses - removes network node IPv6 addresses
 func RemoveNetworkNodeIPv6Addresses(networkName string) error {
 func RemoveNetworkNodeIPv6Addresses(networkName string) error {
 
 
@@ -509,23 +531,24 @@ func IsNetworkNameUnique(network *models.Network) (bool, error) {
 }
 }
 
 
 // UpdateNetwork - updates a network with another network's fields
 // UpdateNetwork - updates a network with another network's fields
-func UpdateNetwork(currentNetwork *models.Network, newNetwork *models.Network) (bool, bool, error) {
+func UpdateNetwork(currentNetwork *models.Network, newNetwork *models.Network) (bool, bool, bool, error) {
 	if err := ValidateNetwork(newNetwork, true); err != nil {
 	if err := ValidateNetwork(newNetwork, true); err != nil {
-		return false, false, err
+		return false, false, false, err
 	}
 	}
 	if newNetwork.NetID == currentNetwork.NetID {
 	if newNetwork.NetID == currentNetwork.NetID {
 		hasrangeupdate := newNetwork.AddressRange != currentNetwork.AddressRange
 		hasrangeupdate := newNetwork.AddressRange != currentNetwork.AddressRange
 		localrangeupdate := newNetwork.LocalRange != currentNetwork.LocalRange
 		localrangeupdate := newNetwork.LocalRange != currentNetwork.LocalRange
+		hasholepunchupdate := newNetwork.DefaultUDPHolePunch != currentNetwork.DefaultUDPHolePunch
 		data, err := json.Marshal(newNetwork)
 		data, err := json.Marshal(newNetwork)
 		if err != nil {
 		if err != nil {
-			return false, false, err
+			return false, false, false, err
 		}
 		}
 		newNetwork.SetNetworkLastModified()
 		newNetwork.SetNetworkLastModified()
 		err = database.Insert(newNetwork.NetID, string(data), database.NETWORKS_TABLE_NAME)
 		err = database.Insert(newNetwork.NetID, string(data), database.NETWORKS_TABLE_NAME)
-		return hasrangeupdate, localrangeupdate, err
+		return hasrangeupdate, localrangeupdate, hasholepunchupdate, err
 	}
 	}
 	// copy values
 	// copy values
-	return false, false, errors.New("failed to update network " + newNetwork.NetID + ", cannot change netid.")
+	return false, false, false, errors.New("failed to update network " + newNetwork.NetID + ", cannot change netid.")
 }
 }
 
 
 // Inc - increments an IP
 // Inc - increments an IP

+ 24 - 80
logic/nodes.go

@@ -5,7 +5,6 @@ import (
 	"errors"
 	"errors"
 	"fmt"
 	"fmt"
 	"sort"
 	"sort"
-	"strings"
 	"time"
 	"time"
 
 
 	"github.com/go-playground/validator/v10"
 	"github.com/go-playground/validator/v10"
@@ -237,7 +236,6 @@ func CreateNode(node *models.Node) error {
 		return fmt.Errorf("invalid address: ipv6 " + node.Address6 + " is not unique")
 		return fmt.Errorf("invalid address: ipv6 " + node.Address6 + " is not unique")
 	}
 	}
 
 
-	// TODO: This covers legacy nodes, eventually want to remove legacy check
 	node.ID = uuid.NewString()
 	node.ID = uuid.NewString()
 
 
 	//Create a JWT for the node
 	//Create a JWT for the node
@@ -269,67 +267,6 @@ func CreateNode(node *models.Node) error {
 	return err
 	return err
 }
 }
 
 
-// IfaceDelta - is there interface changes
-// func IfaceDelta(currentNode *models.Node, newNode *models.Node) bool {
-// 	SetNodeDefaults(newNode)
-// 	// single comparison statements
-// 	if currentNode.IsServer != "yes" {
-// 		return false
-// 	}
-
-// 	if newNode.Endpoint != currentNode.Endpoint ||
-// 		newNode.LocalAddress != currentNode.LocalAddress ||
-// 		newNode.PublicKey != currentNode.PublicKey ||
-// 		newNode.Address != currentNode.Address ||
-// 		newNode.IsEgressGateway != currentNode.IsEgressGateway ||
-// 		newNode.IsIngressGateway != currentNode.IsIngressGateway ||
-// 		newNode.IsRelay != currentNode.IsRelay ||
-// 		newNode.UDPHolePunch != currentNode.UDPHolePunch ||
-// 		newNode.IsPending != currentNode.IsPending ||
-// 		newNode.PersistentKeepalive != currentNode.PersistentKeepalive ||
-// 		len(newNode.ExcludedAddrs) != len(currentNode.ExcludedAddrs) ||
-// 		len(newNode.AllowedIPs) != len(currentNode.AllowedIPs) {
-// 		return true
-// 	}
-
-// 	// multi-comparison statements
-// 	if newNode.IsDualStack == "yes" {
-// 		if newNode.Address6 != currentNode.Address6 {
-// 			return true
-// 		}
-// 	}
-
-// 	if newNode.IsEgressGateway == "yes" {
-// 		if len(currentNode.EgressGatewayRanges) != len(newNode.EgressGatewayRanges) {
-// 			return true
-// 		}
-// 		for _, address := range newNode.EgressGatewayRanges {
-// 			if !StringSliceContains(currentNode.EgressGatewayRanges, address) {
-// 				return true
-// 			}
-// 		}
-// 	}
-
-// 	if newNode.IsRelay == "yes" {
-// 		if len(currentNode.RelayAddrs) != len(newNode.RelayAddrs) {
-// 			return true
-// 		}
-// 		for _, address := range newNode.RelayAddrs {
-// 			if !StringSliceContains(currentNode.RelayAddrs, address) {
-// 				return true
-// 			}
-// 		}
-// 	}
-
-// 	for _, address := range newNode.AllowedIPs {
-// 		if !StringSliceContains(currentNode.AllowedIPs, address) {
-// 			return true
-// 		}
-// 	}
-
-// 	return false
-// }
-
 // GetAllNodes - returns all nodes in the DB
 // GetAllNodes - returns all nodes in the DB
 func GetAllNodes() ([]models.Node, error) {
 func GetAllNodes() ([]models.Node, error) {
 	var nodes []models.Node
 	var nodes []models.Node
@@ -602,28 +539,35 @@ func GetDeletedNodeByID(uuid string) (models.Node, error) {
 }
 }
 
 
 // GetNetworkServerNodeID - get network server node ID if exists
 // GetNetworkServerNodeID - get network server node ID if exists
-func GetNetworkServerNodeID(network string) (string, error) {
-	var nodes, err = GetNetworkNodes(network)
+func GetNetworkServerLeader(network string) (models.Node, error) {
+	nodes, err := GetSortedNetworkServerNodes(network)
 	if err != nil {
 	if err != nil {
-		return "", err
+		return models.Node{}, err
 	}
 	}
 	for _, node := range nodes {
 	for _, node := range nodes {
-		if node.IsServer == "yes" {
-			if servercfg.GetNodeID() != "" {
-				if servercfg.GetNodeID() == node.MacAddress {
-					if strings.Contains(node.ID, "###") {
-						DeleteNodeByMacAddress(&node, true)
-						logger.Log(1, "deleted legacy server node on network "+node.Network)
-						return "", errors.New("deleted legacy server node on network " + node.Network)
-					}
-					return node.ID, nil
-				}
-				continue
-			}
-			return node.ID, nil
+		if IsLeader(&node) {
+			return node, nil
+		}
+	}
+	return models.Node{}, errors.New("could not find server leader")
+}
+
+// GetNetworkServerNodeID - get network server node ID if exists
+func GetNetworkServerLocal(network string) (models.Node, error) {
+	nodes, err := GetSortedNetworkServerNodes(network)
+	if err != nil {
+		return models.Node{}, err
+	}
+	mac := servercfg.GetNodeID()
+	if mac == "" {
+		return models.Node{}, fmt.Errorf("error retrieving local server node: server node ID is unset")
+	}
+	for _, node := range nodes {
+		if mac == node.MacAddress {
+			return node, nil
 		}
 		}
 	}
 	}
-	return "", errors.New("could not find server node")
+	return models.Node{}, errors.New("could not find node for local server")
 }
 }
 
 
 // validateServer - make sure servers dont change port or address
 // validateServer - make sure servers dont change port or address

+ 1 - 1
logic/peers.go

@@ -73,7 +73,7 @@ func GetPeerUpdate(node *models.Node) (models.PeerUpdate, error) {
 		}
 		}
 		peers = append(peers, peerData)
 		peers = append(peers, peerData)
 		if peer.IsServer == "yes" {
 		if peer.IsServer == "yes" {
-			serverNodeAddresses = append(serverNodeAddresses, models.ServerAddr{ID: peer.ID, IsLeader: IsLeader(&peer), Address: peer.Address})
+			serverNodeAddresses = append(serverNodeAddresses, models.ServerAddr{IsLeader: IsLeader(&peer), Address: peer.Address})
 		}
 		}
 	}
 	}
 	if node.IsIngressGateway == "yes" {
 	if node.IsIngressGateway == "yes" {

+ 21 - 0
logic/wireguard.go

@@ -25,6 +25,27 @@ func RemoveConf(iface string, printlog bool) error {
 	return err
 	return err
 }
 }
 
 
+// HasPeerConnected - checks if a client node has connected over WG
+func HasPeerConnected(node *models.Node) bool {
+	client, err := wgctrl.New()
+	if err != nil {
+		return false
+	}
+	defer client.Close()
+	device, err := client.Device(node.Interface)
+	if err != nil {
+		return false
+	}
+	for _, peer := range device.Peers {
+		if peer.PublicKey.String() == node.PublicKey {
+			if peer.Endpoint != nil {
+				return true
+			}
+		}
+	}
+	return false
+}
+
 // == Private Functions ==
 // == Private Functions ==
 
 
 // gets the server peers locally
 // gets the server peers locally

+ 0 - 1
models/structs.go

@@ -177,7 +177,6 @@ type Telemetry struct {
 
 
 // ServerAddr - to pass to clients to tell server addresses and if it's the leader or not
 // ServerAddr - to pass to clients to tell server addresses and if it's the leader or not
 type ServerAddr struct {
 type ServerAddr struct {
-	ID       string `json:"id" bson:"id" yaml:"id"`
 	IsLeader bool   `json:"isleader" bson:"isleader" yaml:"isleader"`
 	IsLeader bool   `json:"isleader" bson:"isleader" yaml:"isleader"`
 	Address  string `json:"address" bson:"address" yaml:"address"`
 	Address  string `json:"address" bson:"address" yaml:"address"`
 }
 }

+ 10 - 11
mq/mq.go

@@ -195,13 +195,7 @@ func Keepalive(ctx context.Context) {
 				logger.Log(1, "error retrieving networks for keepalive", err.Error())
 				logger.Log(1, "error retrieving networks for keepalive", err.Error())
 			}
 			}
 			for _, network := range networks {
 			for _, network := range networks {
-				var id string
-				for _, servAddr := range network.DefaultServerAddrs {
-					if servAddr.IsLeader {
-						id = servAddr.ID
-					}
-				}
-				serverNode, errN := logic.GetNodeByID(id)
+				serverNode, errN := logic.GetNetworkServerLeader(network.NetID)
 				if errN == nil {
 				if errN == nil {
 					serverNode.SetLastCheckIn()
 					serverNode.SetLastCheckIn()
 					logic.UpdateNode(&serverNode, &serverNode)
 					logic.UpdateNode(&serverNode, &serverNode)
@@ -210,14 +204,19 @@ func Keepalive(ctx context.Context) {
 					}
 					}
 					err = PublishPeerUpdate(&serverNode)
 					err = PublishPeerUpdate(&serverNode)
 					if err != nil {
 					if err != nil {
-						logger.Log(1, "error publishing udp port updates", err.Error())
+						logger.Log(1, "error publishing udp port updates for network", network.NetID)
+						logger.Log(1, errN.Error())
 					}
 					}
+				} else {
+					logger.Log(1, "unable to retrieve leader for network ", network.NetID)
+					logger.Log(1, errN.Error())
+					continue
 				}
 				}
-				if id == "" {
-					logger.Log(0, "leader not defined for network", network.NetID)
+				if serverNode.Address == "" {
+					logger.Log(1, "leader not defined for network ", network.NetID)
 					continue
 					continue
 				}
 				}
-				if token := client.Publish("serverkeepalive/"+id, 0, false, servercfg.GetVersion()); token.Wait() && token.Error() != nil {
+				if token := client.Publish("serverkeepalive/"+network.NetID, 0, false, servercfg.GetVersion()); token.Wait() && token.Error() != nil {
 					logger.Log(1, "error publishing server keepalive for network", network.NetID, token.Error().Error())
 					logger.Log(1, "error publishing server keepalive for network", network.NetID, token.Error().Error())
 				} else {
 				} else {
 					logger.Log(2, "keepalive sent for network", network.NetID)
 					logger.Log(2, "keepalive sent for network", network.NetID)

+ 15 - 15
netclient/cli_options/cmds.go

@@ -62,21 +62,21 @@ func GetCommands(cliFlags []cli.Flag) []*cli.Command {
 				return err
 				return err
 			},
 			},
 		},
 		},
-		{
-			Name:  "push",
-			Usage: "Push configuration changes to server.",
-			Flags: cliFlags,
-			// the action, or code that will be executed when
-			// we execute our `ns` command
-			Action: func(c *cli.Context) error {
-				cfg, _, err := config.GetCLIConfig(c)
-				if err != nil {
-					return err
-				}
-				err = command.Push(cfg)
-				return err
-			},
-		},
+		// {
+		// 	Name:  "push",
+		// 	Usage: "Push configuration changes to server.",
+		// 	Flags: cliFlags,
+		// 	// the action, or code that will be executed when
+		// 	// we execute our `ns` command
+		// 	Action: func(c *cli.Context) error {
+		// 		cfg, _, err := config.GetCLIConfig(c)
+		// 		if err != nil {
+		// 			return err
+		// 		}
+		// 		err = command.Push(cfg)
+		// 		return err
+		// 	},
+		// },
 		{
 		{
 			Name:  "pull",
 			Name:  "pull",
 			Usage: "Pull latest configuration and peers from server.",
 			Usage: "Pull latest configuration and peers from server.",

+ 7 - 2
netclient/functions/common.go

@@ -185,7 +185,7 @@ func LeaveNetwork(network string) error {
 			}
 			}
 		}
 		}
 	}
 	}
-	//extra network route setting required for freebsd and windows
+	// extra network route setting required for freebsd and windows, TODO mac??
 	if ncutils.IsWindows() {
 	if ncutils.IsWindows() {
 		ip, mask, err := ncutils.GetNetworkIPMask(node.NetworkSettings.AddressRange)
 		ip, mask, err := ncutils.GetNetworkIPMask(node.NetworkSettings.AddressRange)
 		if err != nil {
 		if err != nil {
@@ -197,7 +197,12 @@ func LeaveNetwork(network string) error {
 	} else if ncutils.IsLinux() {
 	} else if ncutils.IsLinux() {
 		_, _ = ncutils.RunCmd("ip -4 route del "+node.NetworkSettings.AddressRange+" dev "+node.Interface, false)
 		_, _ = ncutils.RunCmd("ip -4 route del "+node.NetworkSettings.AddressRange+" dev "+node.Interface, false)
 	}
 	}
-	return RemoveLocalInstance(cfg, network)
+
+	currentNets, err := ncutils.GetSystemNetworks()
+	if err != nil || len(currentNets) <= 1 {
+		return RemoveLocalInstance(cfg, network)
+	}
+	return daemon.Restart()
 }
 }
 
 
 // RemoveLocalInstance - remove all netclient files locally for a network
 // RemoveLocalInstance - remove all netclient files locally for a network

+ 76 - 87
netclient/functions/daemon.go

@@ -3,7 +3,6 @@ package functions
 import (
 import (
 	"context"
 	"context"
 	"encoding/json"
 	"encoding/json"
-	"errors"
 	"fmt"
 	"fmt"
 	"os"
 	"os"
 	"os/signal"
 	"os/signal"
@@ -30,17 +29,31 @@ var messageCache = new(sync.Map)
 const lastNodeUpdate = "lnu"
 const lastNodeUpdate = "lnu"
 const lastPeerUpdate = "lpu"
 const lastPeerUpdate = "lpu"
 
 
+type cachedMessage struct {
+	Message  string
+	LastSeen time.Time
+}
+
 func insert(network, which, cache string) {
 func insert(network, which, cache string) {
-	// var mu sync.Mutex
-	// mu.Lock()
-	// defer mu.Unlock()
-	messageCache.Store(fmt.Sprintf("%s%s", network, which), cache)
+	var newMessage = cachedMessage{
+		Message:  cache,
+		LastSeen: time.Now(),
+	}
+	ncutils.Log("storing new message: " + cache)
+	messageCache.Store(fmt.Sprintf("%s%s", network, which), newMessage)
 }
 }
 
 
 func read(network, which string) string {
 func read(network, which string) string {
 	val, isok := messageCache.Load(fmt.Sprintf("%s%s", network, which))
 	val, isok := messageCache.Load(fmt.Sprintf("%s%s", network, which))
 	if isok {
 	if isok {
-		return fmt.Sprintf("%v", val)
+		var readMessage = val.(cachedMessage)                        // fetch current cached message
+		if time.Now().After(readMessage.LastSeen.Add(time.Minute)) { // check if message has been there over a minute
+			messageCache.Delete(fmt.Sprintf("%s%s", network, which)) // remove old message if expired
+			ncutils.Log("cached message expired")
+			return ""
+		}
+		ncutils.Log("cache hit, skipping probably " + readMessage.Message)
+		return readMessage.Message // return current message if not expired
 	}
 	}
 	return ""
 	return ""
 }
 }
@@ -108,19 +121,27 @@ func MessageQueue(ctx context.Context, network string) {
 	var cfg config.ClientConfig
 	var cfg config.ClientConfig
 	cfg.Network = network
 	cfg.Network = network
 	ncutils.Log("pulling latest config for " + cfg.Network)
 	ncutils.Log("pulling latest config for " + cfg.Network)
-	sleepTime := 2
-	for {
-		_, err := Pull(network, true)
-		if err == nil {
-			break
-		}
-		if sleepTime > 3600 {
-			sleepTime = 3600
+	var configPath = fmt.Sprintf("%sconfig/netconfig-%s", ncutils.GetNetclientPathSpecific(), network)
+	fileInfo, err := os.Stat(configPath)
+	if err != nil {
+		ncutils.Log("could not stat config file: " + configPath)
+	}
+	// speed up UDP rest
+	if time.Now().After(fileInfo.ModTime().Add(time.Minute)) {
+		sleepTime := 2
+		for {
+			_, err := Pull(network, true)
+			if err == nil {
+				break
+			}
+			if sleepTime > 3600 {
+				sleepTime = 3600
+			}
+			ncutils.Log("failed to pull for network " + network)
+			ncutils.Log(fmt.Sprintf("waiting %d seconds to retry...", sleepTime))
+			time.Sleep(time.Second * time.Duration(sleepTime))
+			sleepTime = sleepTime * 2
 		}
 		}
-		ncutils.Log("failed to pull for network " + network)
-		ncutils.Log(fmt.Sprintf("waiting %d seconds to retry...", sleepTime))
-		time.Sleep(time.Second * time.Duration(sleepTime))
-		sleepTime = sleepTime * 2
 	}
 	}
 	time.Sleep(time.Second << 1)
 	time.Sleep(time.Second << 1)
 	cfg.ReadConfig()
 	cfg.ReadConfig()
@@ -147,25 +168,24 @@ func MessageQueue(ctx context.Context, network string) {
 	if cfg.DebugOn {
 	if cfg.DebugOn {
 		ncutils.Log(fmt.Sprintf("subscribed to peer updates for node %s peers/%s/%s", cfg.Node.Name, cfg.Node.Network, cfg.Node.ID))
 		ncutils.Log(fmt.Sprintf("subscribed to peer updates for node %s peers/%s/%s", cfg.Node.Name, cfg.Node.Network, cfg.Node.ID))
 	}
 	}
-	var id string
 	var found bool
 	var found bool
 	for _, server := range cfg.NetworkSettings.DefaultServerAddrs {
 	for _, server := range cfg.NetworkSettings.DefaultServerAddrs {
-		if server.IsLeader {
-			id = server.ID
+		if !server.IsLeader {
+			continue
 		}
 		}
 		if server.Address != "" {
 		if server.Address != "" {
-			if token := client.Subscribe("serverkeepalive/"+id, 0, mqtt.MessageHandler(ServerKeepAlive)); token.Wait() && token.Error() != nil {
+			if token := client.Subscribe("serverkeepalive/"+cfg.Node.Network, 0, mqtt.MessageHandler(ServerKeepAlive)); token.Wait() && token.Error() != nil {
 				ncutils.Log(token.Error().Error())
 				ncutils.Log(token.Error().Error())
 				return
 				return
 			}
 			}
 			found = true
 			found = true
 			if cfg.DebugOn {
 			if cfg.DebugOn {
-				ncutils.Log("subscribed to server keepalives for server " + id)
+				ncutils.Log("subscribed to server keepalives for server " + cfg.Node.Network)
 			}
 			}
 		}
 		}
 	}
 	}
 	if !found {
 	if !found {
-		ncutils.Log("leader not defined for network " + cfg.Network)
+		ncutils.Log("leader not defined for network " + cfg.Node.Network)
 	}
 	}
 	defer client.Disconnect(250)
 	defer client.Disconnect(250)
 	go MonitorKeepalive(ctx, client, &cfg)
 	go MonitorKeepalive(ctx, client, &cfg)
@@ -219,6 +239,7 @@ func NodeUpdate(client mqtt.Client, msg mqtt.Message) {
 		newNode.OS = runtime.GOOS
 		newNode.OS = runtime.GOOS
 		// check if interface needs to delta
 		// check if interface needs to delta
 		ifaceDelta := ncutils.IfaceDelta(&cfg.Node, &newNode)
 		ifaceDelta := ncutils.IfaceDelta(&cfg.Node, &newNode)
+		shouldDNSChange := cfg.Node.DNSOn != newNode.DNSOn
 
 
 		cfg.Node = newNode
 		cfg.Node = newNode
 		switch newNode.Action {
 		switch newNode.Action {
@@ -265,24 +286,18 @@ func NodeUpdate(client mqtt.Client, msg mqtt.Message) {
 				ncutils.Log("error resubscribing after interface change " + err.Error())
 				ncutils.Log("error resubscribing after interface change " + err.Error())
 				return
 				return
 			}
 			}
-		}
-		/*
-			else {
-				ncutils.Log("syncing conf to " + file)
-				err = wireguard.SyncWGQuickConf(cfg.Node.Interface, file)
-				if err != nil {
-					ncutils.Log("error syncing wg after peer update " + err.Error())
-					return
+			if newNode.DNSOn == "yes" {
+				ncutils.Log("setting up DNS")
+				for _, server := range cfg.Node.NetworkSettings.DefaultServerAddrs {
+					if server.IsLeader {
+						go setDNS(cfg.Node.Interface, cfg.Network, server.Address)
+						break
+					}
 				}
 				}
 			}
 			}
-		*/
+		}
 		//deal with DNS
 		//deal with DNS
-		if newNode.DNSOn == "yes" {
-			ncutils.Log("setting up DNS")
-			if err = local.UpdateDNS(cfg.Node.Interface, cfg.Network, cfg.Server.CoreDNSAddr); err != nil {
-				ncutils.Log("error applying dns" + err.Error())
-			}
-		} else {
+		if newNode.DNSOn != "yes" && shouldDNSChange && cfg.Node.Interface != "" {
 			ncutils.Log("settng DNS off")
 			ncutils.Log("settng DNS off")
 			_, err := ncutils.RunCmd("/usr/bin/resolvectl revert "+cfg.Node.Interface, true)
 			_, err := ncutils.RunCmd("/usr/bin/resolvectl revert "+cfg.Node.Interface, true)
 			if err != nil {
 			if err != nil {
@@ -311,14 +326,12 @@ func UpdatePeers(client mqtt.Client, msg mqtt.Message) {
 			return
 			return
 		}
 		}
 		// see if cache hit, if so skip
 		// see if cache hit, if so skip
-		/*
-			var currentMessage = read(peerUpdate.Network, lastPeerUpdate)
-			if currentMessage == string(data) {
-				return
-			}
-		*/
+		var currentMessage = read(peerUpdate.Network, lastPeerUpdate)
+		if currentMessage == string(data) {
+			ncutils.Log("cache hit")
+			return
+		}
 		insert(peerUpdate.Network, lastPeerUpdate, string(data))
 		insert(peerUpdate.Network, lastPeerUpdate, string(data))
-		ncutils.Log("update peer handler")
 
 
 		file := ncutils.GetNetclientPathSpecific() + cfg.Node.Interface + ".conf"
 		file := ncutils.GetNetclientPathSpecific() + cfg.Node.Interface + ".conf"
 		err = wireguard.UpdateWgPeers(file, peerUpdate.Peers)
 		err = wireguard.UpdateWgPeers(file, peerUpdate.Peers)
@@ -326,31 +339,25 @@ func UpdatePeers(client mqtt.Client, msg mqtt.Message) {
 			ncutils.Log("error updating wireguard peers" + err.Error())
 			ncutils.Log("error updating wireguard peers" + err.Error())
 			return
 			return
 		}
 		}
-		ncutils.Log("syncing conf to " + file)
 		//err = wireguard.SyncWGQuickConf(cfg.Node.Interface, file)
 		//err = wireguard.SyncWGQuickConf(cfg.Node.Interface, file)
 		err = wireguard.SetPeers(cfg.Node.Interface, cfg.Node.PersistentKeepalive, peerUpdate.Peers)
 		err = wireguard.SetPeers(cfg.Node.Interface, cfg.Node.PersistentKeepalive, peerUpdate.Peers)
 		if err != nil {
 		if err != nil {
 			ncutils.Log("error syncing wg after peer update " + err.Error())
 			ncutils.Log("error syncing wg after peer update " + err.Error())
 			return
 			return
 		}
 		}
+		ncutils.Log(fmt.Sprintf("received peer update on network, %s", cfg.Network))
 	}()
 	}()
 }
 }
 
 
 // MonitorKeepalive - checks time last server keepalive received.  If more than 3+ minutes, notify and resubscribe
 // MonitorKeepalive - checks time last server keepalive received.  If more than 3+ minutes, notify and resubscribe
 func MonitorKeepalive(ctx context.Context, client mqtt.Client, cfg *config.ClientConfig) {
 func MonitorKeepalive(ctx context.Context, client mqtt.Client, cfg *config.ClientConfig) {
-	var id string
-	for _, servAddr := range cfg.NetworkSettings.DefaultServerAddrs {
-		if servAddr.IsLeader {
-			id = servAddr.ID
-		}
-	}
 	for {
 	for {
 		select {
 		select {
 		case <-ctx.Done():
 		case <-ctx.Done():
 			return
 			return
 		case <-time.After(time.Second * 150):
 		case <-time.After(time.Second * 150):
 			var keepalivetime time.Time
 			var keepalivetime time.Time
-			keepaliveval, ok := keepalive.Load(id)
+			keepaliveval, ok := keepalive.Load(cfg.Node.Network)
 			if ok {
 			if ok {
 				keepalivetime = keepaliveval.(time.Time)
 				keepalivetime = keepaliveval.(time.Time)
 			} else {
 			} else {
@@ -370,15 +377,7 @@ func MonitorKeepalive(ctx context.Context, client mqtt.Client, cfg *config.Clien
 
 
 // ServerKeepAlive -- handler to react to keepalive messages published by server
 // ServerKeepAlive -- handler to react to keepalive messages published by server
 func ServerKeepAlive(client mqtt.Client, msg mqtt.Message) {
 func ServerKeepAlive(client mqtt.Client, msg mqtt.Message) {
-	// var mu sync.Mutex
-	// mu.Lock()
-	// defer mu.Unlock()
-	serverid, err := getID(msg.Topic())
-	if err != nil {
-		ncutils.Log("invalid ID in serverkeepalive topic")
-	}
-	keepalive.Store(serverid, time.Now())
-	// ncutils.Log("keepalive from server")
+	keepalive.Store(parseNetworkFromTopic(msg.Topic()), time.Now())
 }
 }
 
 
 // Resubscribe --- handles resubscribing if needed
 // Resubscribe --- handles resubscribing if needed
@@ -398,25 +397,24 @@ func Resubscribe(client mqtt.Client, cfg *config.ClientConfig) error {
 			ncutils.Log("error resubscribing to peers for " + cfg.Node.Network)
 			ncutils.Log("error resubscribing to peers for " + cfg.Node.Network)
 			return token.Error()
 			return token.Error()
 		}
 		}
-		var id string
 		var found bool
 		var found bool
 		for _, server := range cfg.NetworkSettings.DefaultServerAddrs {
 		for _, server := range cfg.NetworkSettings.DefaultServerAddrs {
-			if server.IsLeader {
-				id = server.ID
+			if !server.IsLeader {
+				continue
 			}
 			}
 			if server.Address != "" {
 			if server.Address != "" {
-				if token := client.Subscribe("serverkeepalive/"+id, 0, mqtt.MessageHandler(ServerKeepAlive)); token.Wait() && token.Error() != nil {
+				if token := client.Subscribe("serverkeepalive/"+cfg.Node.Network, 0, mqtt.MessageHandler(ServerKeepAlive)); token.Wait() && token.Error() != nil {
 					ncutils.Log("error resubscribing to serverkeepalive for " + cfg.Node.Network)
 					ncutils.Log("error resubscribing to serverkeepalive for " + cfg.Node.Network)
 					return token.Error()
 					return token.Error()
 				}
 				}
 				found = true
 				found = true
 				if cfg.DebugOn {
 				if cfg.DebugOn {
-					ncutils.Log("subscribed to server keepalives for server " + id)
+					ncutils.Log("subscribed to server keepalives for server " + cfg.Node.Network)
 				}
 				}
 			}
 			}
 		}
 		}
 		if !found {
 		if !found {
-			ncutils.Log("leader not defined for network " + cfg.Network)
+			ncutils.Log("leader not defined for network " + cfg.Node.Network)
 		}
 		}
 		ncutils.Log("finished re subbing")
 		ncutils.Log("finished re subbing")
 		return nil
 		return nil
@@ -568,24 +566,15 @@ func decryptMsg(cfg *config.ClientConfig, msg []byte) ([]byte, error) {
 	return ncutils.BoxDecrypt(msg, serverPubKey, diskKey)
 	return ncutils.BoxDecrypt(msg, serverPubKey, diskKey)
 }
 }
 
 
-func shouldResub(currentServers, newServers []models.ServerAddr) bool {
-	if len(currentServers) != len(newServers) {
-		return true
+func setDNS(iface, network, address string) {
+	var reachable bool
+	for counter := 0; !reachable && counter < 5; counter++ {
+		reachable = local.IsDNSReachable(address)
+		time.Sleep(time.Second << 1)
 	}
 	}
-	for _, srv := range currentServers {
-		if !ncutils.ServerAddrSliceContains(newServers, srv) {
-			return true
-		}
-	}
-	return false
-}
-
-func getID(topic string) (string, error) {
-	parts := strings.Split(topic, "/")
-	count := len(parts)
-	if count == 1 {
-		return "", errors.New("invalid topic")
+	if !reachable {
+		ncutils.Log("not setting dns, server unreachable: " + address)
+	} else if err := local.UpdateDNS(iface, network, address); err != nil {
+		ncutils.Log("error applying dns" + err.Error())
 	}
 	}
-	//the last part of the topic will be the network.ID
-	return parts[count-1], nil
 }
 }

+ 2 - 2
netclient/functions/join.go

@@ -109,9 +109,9 @@ func JoinNetwork(cfg config.ClientConfig, privateKey string) error {
 	}
 	}
 
 
 	if ncutils.IsLinux() {
 	if ncutils.IsLinux() {
-		_, err := exec.LookPath("resolvconf")
+		_, err := exec.LookPath("resolvectl")
 		if err != nil {
 		if err != nil {
-			ncutils.PrintLog("resolvconf not present", 2)
+			ncutils.PrintLog("resolvectl not present", 2)
 			ncutils.PrintLog("unable to configure DNS automatically, disabling automated DNS management", 2)
 			ncutils.PrintLog("unable to configure DNS automatically, disabling automated DNS management", 2)
 			cfg.Node.DNSOn = "no"
 			cfg.Node.DNSOn = "no"
 		}
 		}

+ 35 - 0
netclient/local/dns.go

@@ -1,8 +1,11 @@
 package local
 package local
 
 
 import (
 import (
+	"fmt"
+	"net"
 	"os"
 	"os"
 	"strings"
 	"strings"
+	"time"
 
 
 	//"github.com/davecgh/go-spew/spew"
 	//"github.com/davecgh/go-spew/spew"
 	"log"
 	"log"
@@ -11,6 +14,8 @@ import (
 	"github.com/gravitl/netmaker/netclient/ncutils"
 	"github.com/gravitl/netmaker/netclient/ncutils"
 )
 )
 
 
+const DNS_UNREACHABLE_ERROR = "nameserver unreachable"
+
 // SetDNS - sets the DNS of a local machine
 // SetDNS - sets the DNS of a local machine
 func SetDNS(nameserver string) error {
 func SetDNS(nameserver string) error {
 	bytes, err := os.ReadFile("/etc/resolv.conf")
 	bytes, err := os.ReadFile("/etc/resolv.conf")
@@ -35,9 +40,21 @@ func SetDNS(nameserver string) error {
 
 
 // UpdateDNS - updates local DNS of client
 // UpdateDNS - updates local DNS of client
 func UpdateDNS(ifacename string, network string, nameserver string) error {
 func UpdateDNS(ifacename string, network string, nameserver string) error {
+	if ifacename == "" {
+		return fmt.Errorf("cannot set dns: interface name is blank")
+	}
+	if network == "" {
+		return fmt.Errorf("cannot set dns: network name is blank")
+	}
+	if nameserver == "" {
+		return fmt.Errorf("cannot set dns: nameserver is blank")
+	}
 	if ncutils.IsWindows() {
 	if ncutils.IsWindows() {
 		return nil
 		return nil
 	}
 	}
+	if !IsDNSReachable(nameserver) {
+		return fmt.Errorf(DNS_UNREACHABLE_ERROR + " : " + nameserver + ":53")
+	}
 	_, err := exec.LookPath("resolvectl")
 	_, err := exec.LookPath("resolvectl")
 	if err != nil {
 	if err != nil {
 		log.Println(err)
 		log.Println(err)
@@ -60,3 +77,21 @@ func UpdateDNS(ifacename string, network string, nameserver string) error {
 	}
 	}
 	return err
 	return err
 }
 }
+
+func IsDNSReachable(nameserver string) bool {
+	port := "53"
+	protocols := [2]string{"tcp", "udp"}
+	for _, proto := range protocols {
+		timeout := time.Second
+		conn, err := net.DialTimeout(proto, net.JoinHostPort(nameserver, port), timeout)
+		if err != nil {
+			return false
+		}
+		if conn != nil {
+			defer conn.Close()
+		} else {
+			return false
+		}
+	}
+	return true
+}

+ 48 - 0
netclient/local/routes.go

@@ -0,0 +1,48 @@
+package local
+
+import (
+	"net"
+
+	"github.com/gravitl/netmaker/netclient/ncutils"
+	"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
+)
+
+// SetPeerRoutes - sets/removes ip routes for each peer on a network
+func SetPeerRoutes(iface string, oldPeers map[string][]net.IPNet, newPeers []wgtypes.PeerConfig) {
+	// traverse through all recieved peers
+	for _, peer := range newPeers {
+		// if pubkey found in existing peers, check against existing peer
+		currPeerAllowedIPs := oldPeers[peer.PublicKey.String()]
+		if currPeerAllowedIPs != nil {
+			// traverse IPs, check to see if old peer contains each IP
+			for _, allowedIP := range peer.AllowedIPs { // compare new ones (if any) to old ones
+				if !ncutils.IPNetSliceContains(currPeerAllowedIPs, allowedIP) {
+					if err := setRoute(iface, &allowedIP); err != nil {
+						ncutils.PrintLog(err.Error(), 1)
+					}
+				}
+			}
+			for _, allowedIP := range currPeerAllowedIPs { // compare old ones (if any) to new ones
+				if !ncutils.IPNetSliceContains(peer.AllowedIPs, allowedIP) {
+					if err := deleteRoute(iface, &allowedIP); err != nil {
+						ncutils.PrintLog(err.Error(), 1)
+					}
+				}
+			}
+			delete(oldPeers, peer.PublicKey.String()) // remove peer as it was found and processed
+		} else {
+			for _, allowedIP := range peer.AllowedIPs { // add all routes as peer doesn't exist
+				if err := setRoute(iface, &allowedIP); err != nil {
+					ncutils.PrintLog(err.Error(), 1)
+				}
+			}
+		}
+	}
+
+	// traverse through all remaining existing peers
+	for _, allowedIPs := range oldPeers {
+		for _, allowedIP := range allowedIPs {
+			deleteRoute(iface, &allowedIP)
+		}
+	}
+}

+ 25 - 0
netclient/local/routes_linux.go

@@ -0,0 +1,25 @@
+//go:build linux
+// +build linux
+
+package local
+
+import (
+	//"github.com/davecgh/go-spew/spew"
+
+	"fmt"
+	"net"
+
+	"github.com/gravitl/netmaker/netclient/ncutils"
+)
+
+func setRoute(iface string, addr *net.IPNet) error {
+	var err error
+	_, err = ncutils.RunCmd(fmt.Sprintf("ip route add %s dev %s", addr.String(), iface), true)
+	return err
+}
+
+func deleteRoute(iface string, addr *net.IPNet) error {
+	var err error
+	_, err = ncutils.RunCmd(fmt.Sprintf("ip route del %s dev %s", addr.String(), iface), true)
+	return err
+}

+ 33 - 0
netclient/local/routes_other.go

@@ -0,0 +1,33 @@
+//go:build !linux
+// +build !linux
+
+package local
+
+import (
+	//"github.com/davecgh/go-spew/spew"
+
+	"fmt"
+	"net"
+
+	"github.com/gravitl/netmaker/netclient/ncutils"
+)
+
+//"github.com/davecgh/go-spew/spew"
+
+/*
+
+These functions are not used. These should only be called by Linux (see routes_linux.go). These routes return nothing if called.
+
+*/
+
+func setRoute(iface string, addr *net.IPNet) error {
+	var err error
+	_, err = ncutils.RunCmd(fmt.Sprintf("ip route add %s dev %s", addr.String(), iface), true)
+	return err
+}
+
+func deleteRoute(iface string, addr *net.IPNet) error {
+	var err error
+	_, err = ncutils.RunCmd(fmt.Sprintf("ip route del %s dev %s", addr.String(), iface), true)
+	return err
+}

+ 11 - 0
netclient/ncutils/iface.go

@@ -18,6 +18,7 @@ func IfaceDelta(currentNode *models.Node, newNode *models.Node) bool {
 		newNode.UDPHolePunch != currentNode.UDPHolePunch ||
 		newNode.UDPHolePunch != currentNode.UDPHolePunch ||
 		newNode.IsPending != currentNode.IsPending ||
 		newNode.IsPending != currentNode.IsPending ||
 		newNode.PersistentKeepalive != currentNode.PersistentKeepalive ||
 		newNode.PersistentKeepalive != currentNode.PersistentKeepalive ||
+		newNode.DNSOn != currentNode.DNSOn ||
 		len(newNode.ExcludedAddrs) != len(currentNode.ExcludedAddrs) ||
 		len(newNode.ExcludedAddrs) != len(currentNode.ExcludedAddrs) ||
 		len(newNode.AllowedIPs) != len(currentNode.AllowedIPs) {
 		len(newNode.AllowedIPs) != len(currentNode.AllowedIPs) {
 		return true
 		return true
@@ -70,6 +71,16 @@ func StringSliceContains(slice []string, item string) bool {
 	return false
 	return false
 }
 }
 
 
+// IPNetSliceContains - sees if a string slice contains a string element
+func IPNetSliceContains(slice []net.IPNet, item net.IPNet) bool {
+	for _, s := range slice {
+		if s.String() == item.String() {
+			return true
+		}
+	}
+	return false
+}
+
 // IfaceExists - return true if you can find the iface
 // IfaceExists - return true if you can find the iface
 func IfaceExists(ifacename string) bool {
 func IfaceExists(ifacename string) bool {
 	localnets, err := net.Interfaces()
 	localnets, err := net.Interfaces()

+ 5 - 1
netclient/wireguard/common.go

@@ -3,6 +3,7 @@ package wireguard
 import (
 import (
 	"errors"
 	"errors"
 	"log"
 	"log"
+	"net"
 	"runtime"
 	"runtime"
 	"strconv"
 	"strconv"
 	"strings"
 	"strings"
@@ -25,8 +26,8 @@ const (
 
 
 // SetPeers - sets peers on a given WireGuard interface
 // SetPeers - sets peers on a given WireGuard interface
 func SetPeers(iface string, keepalive int32, peers []wgtypes.PeerConfig) error {
 func SetPeers(iface string, keepalive int32, peers []wgtypes.PeerConfig) error {
-
 	var devicePeers []wgtypes.Peer
 	var devicePeers []wgtypes.Peer
+	var oldPeerAllowedIps = make(map[string][]net.IPNet, len(peers))
 	var err error
 	var err error
 	if ncutils.IsFreeBSD() {
 	if ncutils.IsFreeBSD() {
 		if devicePeers, err = ncutils.GetPeers(iface); err != nil {
 		if devicePeers, err = ncutils.GetPeers(iface); err != nil {
@@ -100,10 +101,13 @@ func SetPeers(iface string, keepalive int32, peers []wgtypes.PeerConfig) error {
 				log.Println(output, "error removing peer", currentPeer.PublicKey.String())
 				log.Println(output, "error removing peer", currentPeer.PublicKey.String())
 			}
 			}
 		}
 		}
+		oldPeerAllowedIps[currentPeer.PublicKey.String()] = currentPeer.AllowedIPs
 	}
 	}
 	if ncutils.IsMac() {
 	if ncutils.IsMac() {
 		err = SetMacPeerRoutes(iface)
 		err = SetMacPeerRoutes(iface)
 		return err
 		return err
+	} else if ncutils.IsLinux() {
+		local.SetPeerRoutes(iface, oldPeerAllowedIps, peers)
 	}
 	}
 
 
 	return nil
 	return nil

+ 3 - 0
netclient/wireguard/unix.go

@@ -65,6 +65,9 @@ func ApplyWGQuickConf(confPath string, ifacename string) error {
 			ncutils.RunCmd("wg-quick down "+confPath, true)
 			ncutils.RunCmd("wg-quick down "+confPath, true)
 		}
 		}
 		_, err = ncutils.RunCmd("wg-quick up "+confPath, true)
 		_, err = ncutils.RunCmd("wg-quick up "+confPath, true)
+		// if err != nil {
+		// 	return err
+		// }
 		return err
 		return err
 	}
 	}
 }
 }

+ 2 - 6
serverctl/serverctl.go

@@ -44,12 +44,8 @@ func SyncServerNetwork(network string) error {
 		}
 		}
 	}
 	}
 
 
-	serverNodeID, err := logic.GetNetworkServerNodeID(network)
-	if !ifaceExists && (err == nil && serverNodeID != "") {
-		serverNode, err := logic.GetNodeByID(serverNodeID)
-		if err != nil {
-			return err
-		}
+	serverNode, err := logic.GetNetworkServerLocal(network)
+	if !ifaceExists && (err == nil && serverNode.ID != "") {
 		return logic.ServerUpdate(&serverNode, true)
 		return logic.ServerUpdate(&serverNode, true)
 	} else if !ifaceExists {
 	} else if !ifaceExists {
 		_, err := logic.ServerJoin(&serverNetworkSettings)
 		_, err := logic.ServerJoin(&serverNetworkSettings)