Browse Source

Merge pull request #655 from gravitl/bugfix_v0.10.0_peers

Bugfix v0.10.0 peers
dcarns 3 years ago
parent
commit
22957457e6

+ 9 - 8
controllers/node.go

@@ -12,6 +12,7 @@ import (
 	"github.com/gravitl/netmaker/logic"
 	"github.com/gravitl/netmaker/models"
 	"github.com/gravitl/netmaker/mq"
+	"github.com/gravitl/netmaker/netclient/ncutils"
 	"github.com/gravitl/netmaker/servercfg"
 	"golang.org/x/crypto/bcrypt"
 )
@@ -406,7 +407,7 @@ func createNode(w http.ResponseWriter, r *http.Request) {
 		return
 	}
 
-	if err = runServerPeerUpdate(node.Network, true); err != nil {
+	if err = runServerPeerUpdate(node.Network, isServer(&node), "node create"); err != nil {
 		logger.Log(1, "internal error when creating node:", node.ID)
 	}
 
@@ -426,7 +427,7 @@ func uncordonNode(w http.ResponseWriter, r *http.Request) {
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 	}
-	if err = runServerPeerUpdate(node.Network, false); err != nil {
+	if err = runServerPeerUpdate(node.Network, isServer(&node), "node uncordon"); err != nil {
 		logger.Log(1, "internal error when approving node:", nodeid)
 	}
 	go func() {
@@ -458,7 +459,7 @@ func createEgressGateway(w http.ResponseWriter, r *http.Request) {
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 	}
-	if err = runServerPeerUpdate(gateway.NetID, true); err != nil {
+	if err = runServerPeerUpdate(gateway.NetID, isServer(&node), "node egress create"); err != nil {
 		logger.Log(1, "internal error when setting peers after creating egress on node:", gateway.NodeID)
 	}
 	go func() {
@@ -484,7 +485,7 @@ func deleteEgressGateway(w http.ResponseWriter, r *http.Request) {
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 	}
-	if err = runServerPeerUpdate(netid, true); err != nil {
+	if err = runServerPeerUpdate(netid, isServer(&node), "egress delete"); err != nil {
 		logger.Log(1, "internal error when setting peers after removing egress on node:", nodeid)
 	}
 	go func() {
@@ -586,7 +587,7 @@ func updateNode(w http.ResponseWriter, r *http.Request) {
 		newNode.PostUp = node.PostUp
 	}
 
-	var shouldPeersUpdate = logic.ShouldPeersUpdate(&node, &newNode)
+	var shouldPeersUpdate = ncutils.IfaceDelta(&node, &newNode)
 
 	err = logic.UpdateNode(&node, &newNode)
 	if err != nil {
@@ -604,7 +605,7 @@ func updateNode(w http.ResponseWriter, r *http.Request) {
 		err = logic.SetDNS()
 	}
 
-	err = runServerPeerUpdate(node.Network, shouldPeersUpdate)
+	err = runServerPeerUpdate(node.Network, shouldPeersUpdate, "node update")
 	if err != nil {
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
@@ -616,7 +617,7 @@ func updateNode(w http.ResponseWriter, r *http.Request) {
 		if err := mq.NodeUpdate(&newNode); err != nil {
 			logger.Log(1, "error publishing node update", err.Error())
 		}
-		if logic.ShouldPeersUpdate(&node, &newNode) {
+		if shouldPeersUpdate {
 			if err := mq.PublishPeerUpdate(&newNode); err != nil {
 				logger.Log(1, "error publishing peer update after node update", err.Error())
 			}
@@ -642,7 +643,7 @@ func deleteNode(w http.ResponseWriter, r *http.Request) {
 		return
 	}
 
-	err = runServerPeerUpdate(node.Network, true)
+	err = runServerPeerUpdate(node.Network, isServer(&node), "node delete")
 	if err != nil {
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return

+ 25 - 18
controllers/node_grpc.go

@@ -12,6 +12,7 @@ import (
 	"github.com/gravitl/netmaker/logic"
 	"github.com/gravitl/netmaker/models"
 	"github.com/gravitl/netmaker/mq"
+	"github.com/gravitl/netmaker/netclient/ncutils"
 	"github.com/gravitl/netmaker/servercfg"
 )
 
@@ -67,18 +68,7 @@ func (s *NodeServiceServer) CreateNode(ctx context.Context, req *nodepb.Object)
 			return nil, errors.New("invalid key, and network does not allow no-key signups")
 		}
 	}
-
-	var serverNodes = logic.GetServerNodes(node.Network)
-	var serverAddrs = make([]models.ServerAddr, len(serverNodes))
-	for i, server := range serverNodes {
-		serverAddrs[i] = models.ServerAddr{
-			ID:       server.ID,
-			IsLeader: logic.IsLeader(&server),
-			Address:  server.Address,
-		}
-	}
-	// TODO consolidate functionality around files
-	node.NetworkSettings.DefaultServerAddrs = serverAddrs
+	getServerAddrs(&node)
 	key, keyErr := logic.RetrievePublicTrafficKey()
 	if keyErr != nil {
 		logger.Log(0, "error retrieving key: ", keyErr.Error())
@@ -110,11 +100,11 @@ func (s *NodeServiceServer) CreateNode(ctx context.Context, req *nodepb.Object)
 		return nil, err
 	}
 	network.NodesLastModified = time.Now().Unix()
-	network.DefaultServerAddrs = serverAddrs
+	network.DefaultServerAddrs = node.NetworkSettings.DefaultServerAddrs
 	if err := logic.SaveNetwork(&network); err != nil {
 		return nil, err
 	}
-	err = runServerPeerUpdate(node.Network, true)
+	err = runServerPeerUpdate(node.Network, isServer(&node), "node_grpc create")
 	if err != nil {
 		logger.Log(1, "internal error when setting peers after node,", node.ID, "was created (gRPC)")
 	}
@@ -146,8 +136,8 @@ func (s *NodeServiceServer) UpdateNode(ctx context.Context, req *nodepb.Object)
 		newnode.PostDown = node.PostDown
 		newnode.PostUp = node.PostUp
 	}
-	var shouldPeersUpdate = logic.ShouldPeersUpdate(&node, &newnode)
-
+	var shouldPeersUpdate = ncutils.IfaceDelta(&node, &newnode)
+	getServerAddrs(&node)
 	err = logic.UpdateNode(&node, &newnode)
 	if err != nil {
 		return nil, err
@@ -160,7 +150,7 @@ func (s *NodeServiceServer) UpdateNode(ctx context.Context, req *nodepb.Object)
 	if errN != nil {
 		return nil, err
 	}
-	err = runServerPeerUpdate(newnode.Network, shouldPeersUpdate)
+	err = runServerPeerUpdate(newnode.Network, shouldPeersUpdate, "node_grpc update")
 	if err != nil {
 		logger.Log(1, "could not update peers on gRPC after node,", newnode.ID, "updated (gRPC), \nerror:", err.Error())
 	}
@@ -170,6 +160,19 @@ func (s *NodeServiceServer) UpdateNode(ctx context.Context, req *nodepb.Object)
 	}, nil
 }
 
+func getServerAddrs(node *models.Node) {
+	var serverNodes = logic.GetServerNodes(node.Network)
+	var serverAddrs = make([]models.ServerAddr, len(serverNodes))
+	for i, server := range serverNodes {
+		serverAddrs[i] = models.ServerAddr{
+			IsLeader: logic.IsLeader(&server),
+			Address:  server.Address,
+		}
+	}
+	// TODO consolidate functionality around files
+	node.NetworkSettings.DefaultServerAddrs = serverAddrs
+}
+
 // NodeServiceServer.DeleteNode - deletes a node and responds over gRPC
 func (s *NodeServiceServer) DeleteNode(ctx context.Context, req *nodepb.Object) (*nodepb.Object, error) {
 
@@ -182,7 +185,7 @@ func (s *NodeServiceServer) DeleteNode(ctx context.Context, req *nodepb.Object)
 	if err != nil {
 		return nil, err
 	}
-	err = runServerPeerUpdate(node.Network, true)
+	err = runServerPeerUpdate(node.Network, false, "node_grpc delete")
 	if err != nil {
 		logger.Log(1, "internal error when setting peers after deleting node:", node.ID, "over gRPC")
 	}
@@ -284,3 +287,7 @@ func getNewOrLegacyNode(data string) (models.Node, error) {
 	}
 	return node, nil
 }
+
+func isServer(node *models.Node) bool {
+	return node.IsServer == "yes"
+}

+ 2 - 2
controllers/relay.go

@@ -27,7 +27,7 @@ func createRelay(w http.ResponseWriter, r *http.Request) {
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 	}
-	if err = runServerPeerUpdate(relay.NetID, true); err != nil {
+	if err = runServerPeerUpdate(relay.NetID, isServer(&node), "relay create"); err != nil {
 		logger.Log(1, "internal error when creating relay on node:", relay.NodeID)
 	}
 	go func() {
@@ -53,7 +53,7 @@ func deleteRelay(w http.ResponseWriter, r *http.Request) {
 		returnErrorResponse(w, r, formatError(err, "internal"))
 		return
 	}
-	if err = runServerPeerUpdate(netid, true); err != nil {
+	if err = runServerPeerUpdate(netid, isServer(&node), "relay delete"); err != nil {
 		logger.Log(1, "internal error when deleting relay on node:", nodeid)
 	}
 	go func() {

+ 3 - 2
controllers/server_util.go

@@ -6,7 +6,8 @@ import (
 	"github.com/gravitl/netmaker/servercfg"
 )
 
-func runServerPeerUpdate(network string, shouldPeerUpdate bool) error {
+func runServerPeerUpdate(network string, ifaceDelta bool, function string) error {
+	logger.Log(0, "running server update from function", function)
 	err := logic.TimerCheckpoint()
 	if err != nil {
 		logger.Log(3, "error occurred on timer,", err.Error())
@@ -22,7 +23,7 @@ func runServerPeerUpdate(network string, shouldPeerUpdate bool) error {
 	if currErr != nil {
 		return currErr
 	}
-	if err = logic.ServerUpdate(&currentServerNode, shouldPeerUpdate); err != nil {
+	if err = logic.ServerUpdate(&currentServerNode, ifaceDelta); err != nil {
 		logger.Log(1, "server node:", currentServerNode.ID, "failed update")
 		return err
 	}

+ 6 - 0
logger/logger.go

@@ -37,6 +37,9 @@ func ResetLogs() {
 
 // Log - handles adding logs
 func Log(verbosity int, message ...string) {
+	var mu sync.Mutex
+	mu.Lock()
+	defer mu.Unlock()
 	var currentTime = time.Now()
 	var currentMessage = makeString(message...)
 	if int32(verbosity) <= getVerbose() && getVerbose() >= 0 {
@@ -102,6 +105,9 @@ func Retrieve(filePath string) string {
 
 // FatalLog - exits os after logging
 func FatalLog(message ...string) {
+	var mu sync.Mutex
+	mu.Lock()
+	defer mu.Unlock()
 	fmt.Printf("[netmaker] Fatal: %s \n", makeString(message...))
 	os.Exit(2)
 }

+ 68 - 57
logic/nodes.go

@@ -91,7 +91,7 @@ func UncordonNode(nodeid string) (models.Node, error) {
 	return node, err
 }
 
-// GetPeers - gets the peers of a given node
+// GetPeers - gets the peers of a given server node
 func GetPeers(node *models.Node) ([]models.Node, error) {
 	if IsLeader(node) {
 		setNetworkServerPeers(node)
@@ -108,6 +108,13 @@ func GetPeers(node *models.Node) ([]models.Node, error) {
 	return peers, nil
 }
 
+// SetIfLeader - gets the peers of a given server node
+func SetPeersIfLeader(node *models.Node) {
+	if IsLeader(node) {
+		setNetworkServerPeers(node)
+	}
+}
+
 // IsLeader - determines if a given server node is a leader
 func IsLeader(node *models.Node) bool {
 	nodes, err := GetSortedNetworkServerNodes(node.Network)
@@ -247,62 +254,66 @@ func CreateNode(node *models.Node) error {
 	return err
 }
 
-// ShouldPeersUpdate - takes old node and sees if certain fields changing would trigger a peer update
-func ShouldPeersUpdate(currentNode *models.Node, newNode *models.Node) bool {
-	SetNodeDefaults(newNode)
-	// single comparison statements
-	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
-}
+// 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
 func GetAllNodes() ([]models.Node, error) {

+ 87 - 14
logic/peers.go

@@ -7,6 +7,7 @@ import (
 	"strings"
 	"time"
 
+	"github.com/gravitl/netmaker/logger"
 	"github.com/gravitl/netmaker/models"
 	"github.com/gravitl/netmaker/netclient/ncutils"
 	"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
@@ -16,12 +17,24 @@ import (
 func GetPeerUpdate(node *models.Node) (models.PeerUpdate, error) {
 	var peerUpdate models.PeerUpdate
 	var peers []wgtypes.PeerConfig
-	networkNodes, err := GetNetworkNodes(node.Network)
+	var serverNodeAddresses = []models.ServerAddr{}
+	currentPeers, err := GetPeers(node)
 	if err != nil {
 		return models.PeerUpdate{}, err
 	}
-	var serverNodeAddresses = []models.ServerAddr{}
-	for _, peer := range networkNodes {
+	// begin translating netclient logic
+	/*
+
+
+		Go through netclient code and put below
+
+
+
+	*/
+	// #1 Set Keepalive values: set_keepalive
+	// #2 Set local address: set_local - could be a LOT BETTER and fix some bugs with additional logic
+	// #3 Set allowedips: set_allowedips
+	for _, peer := range currentPeers {
 		if peer.ID == node.ID {
 			//skip yourself
 			continue
@@ -32,6 +45,7 @@ func GetPeerUpdate(node *models.Node) (models.PeerUpdate, error) {
 		}
 		if node.Endpoint == peer.Endpoint {
 			//peer is on same network
+			// set_local
 			if node.LocalAddress != peer.LocalAddress && peer.LocalAddress != "" {
 				peer.Endpoint = peer.LocalAddress
 			} else {
@@ -43,9 +57,11 @@ func GetPeerUpdate(node *models.Node) (models.PeerUpdate, error) {
 		if err != nil {
 			return models.PeerUpdate{}, err
 		}
+		// set_allowedips
 		allowedips := GetAllowedIPs(node, &peer)
 		var keepalive time.Duration
 		if node.PersistentKeepalive != 0 {
+			// set_keepalive
 			keepalive, _ = time.ParseDuration(strconv.FormatInt(int64(node.PersistentKeepalive), 10) + "s")
 		}
 		var peerData = wgtypes.PeerConfig{
@@ -60,16 +76,73 @@ func GetPeerUpdate(node *models.Node) (models.PeerUpdate, error) {
 			serverNodeAddresses = append(serverNodeAddresses, models.ServerAddr{ID: peer.ID, IsLeader: IsLeader(&peer), Address: peer.Address})
 		}
 	}
+	if node.IsIngressGateway == "yes" {
+		extPeers, err := getExtPeers(node)
+		if err == nil {
+			peers = append(peers, extPeers...)
+		} else {
+			log.Println("ERROR RETRIEVING EXTERNAL PEERS", err)
+		}
+	}
 	peerUpdate.Network = node.Network
 	peerUpdate.Peers = peers
 	peerUpdate.ServerAddrs = serverNodeAddresses
+	/*
+
+
+		End translation of netclient code
+
+
+	*/
 	return peerUpdate, nil
 }
 
+func getExtPeers(node *models.Node) ([]wgtypes.PeerConfig, error) {
+	var peers []wgtypes.PeerConfig
+	extPeers, err := GetExtPeersList(node)
+	if err != nil {
+		return peers, err
+	}
+	for _, extPeer := range extPeers {
+		pubkey, err := wgtypes.ParseKey(extPeer.PublicKey)
+		if err != nil {
+			logger.Log(1, "error parsing ext pub key:", err.Error())
+			continue
+		}
+
+		if node.PublicKey == extPeer.PublicKey {
+			continue
+		}
+
+		var peer wgtypes.PeerConfig
+		var peeraddr = net.IPNet{
+			IP:   net.ParseIP(extPeer.Address),
+			Mask: net.CIDRMask(32, 32),
+		}
+		var allowedips []net.IPNet
+		allowedips = append(allowedips, peeraddr)
+
+		if extPeer.Address6 != "" {
+			var addr6 = net.IPNet{
+				IP:   net.ParseIP(extPeer.Address6),
+				Mask: net.CIDRMask(128, 128),
+			}
+			allowedips = append(allowedips, addr6)
+		}
+		peer = wgtypes.PeerConfig{
+			PublicKey:         pubkey,
+			ReplaceAllowedIPs: true,
+			AllowedIPs:        allowedips,
+		}
+		peers = append(peers, peer)
+	}
+	return peers, nil
+
+}
+
 // GetAllowedIPs - calculates the wireguard allowedip field for a peer of a node based on the peer and node settings
 func GetAllowedIPs(node, peer *models.Node) []net.IPNet {
 	var allowedips []net.IPNet
-	var gateways []string
 	var peeraddr = net.IPNet{
 		IP:   net.ParseIP(peer.Address),
 		Mask: net.CIDRMask(32, 32),
@@ -77,13 +150,13 @@ func GetAllowedIPs(node, peer *models.Node) []net.IPNet {
 	dualstack := false
 	allowedips = append(allowedips, peeraddr)
 	// handle manually set peers
-	for _, allowedIp := range node.AllowedIPs {
+	for _, allowedIp := range peer.AllowedIPs {
 		if _, ipnet, err := net.ParseCIDR(allowedIp); err == nil {
 			nodeEndpointArr := strings.Split(node.Endpoint, ":")
-			if !ipnet.Contains(net.IP(nodeEndpointArr[0])) && ipnet.IP.String() != node.Address { // don't need to add an allowed ip that already exists..
+			if !ipnet.Contains(net.IP(nodeEndpointArr[0])) && ipnet.IP.String() != peer.Address { // don't need to add an allowed ip that already exists..
 				allowedips = append(allowedips, *ipnet)
 			}
-		} else if appendip := net.ParseIP(allowedIp); appendip != nil && allowedIp != node.Address {
+		} else if appendip := net.ParseIP(allowedIp); appendip != nil && allowedIp != peer.Address {
 			ipnet := net.IPNet{
 				IP:   net.ParseIP(allowedIp),
 				Mask: net.CIDRMask(32, 32),
@@ -92,25 +165,25 @@ func GetAllowedIPs(node, peer *models.Node) []net.IPNet {
 		}
 	}
 	// handle egress gateway peers
-	if node.IsEgressGateway == "yes" {
+	if peer.IsEgressGateway == "yes" {
 		//hasGateway = true
-		ranges := node.EgressGatewayRanges
+		ranges := peer.EgressGatewayRanges
 		for _, iprange := range ranges { // go through each cidr for egress gateway
 			_, ipnet, err := net.ParseCIDR(iprange) // confirming it's valid cidr
 			if err != nil {
 				ncutils.PrintLog("could not parse gateway IP range. Not adding "+iprange, 1)
 				continue // if can't parse CIDR
 			}
-			nodeEndpointArr := strings.Split(node.Endpoint, ":") // getting the public ip of node
-			if ipnet.Contains(net.ParseIP(nodeEndpointArr[0])) { // ensuring egress gateway range does not contain public ip of node
+			nodeEndpointArr := strings.Split(peer.Endpoint, ":") // getting the public ip of node
+			if ipnet.Contains(net.ParseIP(nodeEndpointArr[0])) { // ensuring egress gateway range does not contain endpoint of node
 				ncutils.PrintLog("egress IP range of "+iprange+" overlaps with "+node.Endpoint+", omitting", 2)
 				continue // skip adding egress range if overlaps with node's ip
 			}
+			// TODO: Could put in a lot of great logic to avoid conflicts / bad routes
 			if ipnet.Contains(net.ParseIP(node.LocalAddress)) { // ensuring egress gateway range does not contain public ip of node
 				ncutils.PrintLog("egress IP range of "+iprange+" overlaps with "+node.LocalAddress+", omitting", 2)
 				continue // skip adding egress range if overlaps with node's local ip
 			}
-			gateways = append(gateways, iprange)
 			if err != nil {
 				log.Println("ERROR ENCOUNTERED SETTING GATEWAY")
 			} else {
@@ -118,9 +191,9 @@ func GetAllowedIPs(node, peer *models.Node) []net.IPNet {
 			}
 		}
 	}
-	if node.Address6 != "" && dualstack {
+	if peer.Address6 != "" && dualstack {
 		var addr6 = net.IPNet{
-			IP:   net.ParseIP(node.Address6),
+			IP:   net.ParseIP(peer.Address6),
 			Mask: net.CIDRMask(128, 128),
 		}
 		allowedips = append(allowedips, addr6)

+ 4 - 4
logic/server.go

@@ -139,8 +139,8 @@ func ServerJoin(networkSettings *models.Network) error {
 
 // ServerUpdate - updates the server
 // replaces legacy Checkin code
-func ServerUpdate(serverNode *models.Node, shouldPeerUpdate bool) error {
-	var err = serverPull(serverNode, shouldPeerUpdate)
+func ServerUpdate(serverNode *models.Node, ifaceDelta bool) error {
+	var err = serverPull(serverNode, ifaceDelta)
 	if isDeleteError(err) {
 		return DeleteNodeByID(serverNode, true)
 	} else if err != nil {
@@ -365,7 +365,7 @@ func checkNodeActions(node *models.Node) string {
 
 // == Private ==
 
-func serverPull(serverNode *models.Node, onErr bool) error {
+func serverPull(serverNode *models.Node, ifaceDelta bool) error {
 
 	var err error
 	if serverNode.IPForwarding == "yes" {
@@ -375,7 +375,7 @@ func serverPull(serverNode *models.Node, onErr bool) error {
 	}
 	serverNode.OS = runtime.GOOS
 
-	if serverNode.PullChanges == "yes" || onErr {
+	if serverNode.PullChanges == "yes" || ifaceDelta {
 		// check for interface change
 		// checks if address is in use by another interface
 		var oldIfaceName, isIfacePresent = isInterfacePresent(serverNode.Interface, serverNode.Address)

+ 7 - 12
logic/wireguard.go

@@ -223,7 +223,6 @@ func setServerPeers(iface string, keepalive int32, peers []wgtypes.PeerConfig) e
 				}
 			}
 		}
-		udpendpoint := peer.Endpoint.String()
 		var allowedips string
 		var iparr []string
 		for _, ipaddr := range peer.AllowedIPs {
@@ -234,16 +233,10 @@ func setServerPeers(iface string, keepalive int32, peers []wgtypes.PeerConfig) e
 		if keepAliveString == "0" {
 			keepAliveString = "5"
 		}
-		if peer.Endpoint != nil {
-			_, err = ncutils.RunCmd("wg set "+iface+" peer "+peer.PublicKey.String()+
-				" endpoint "+udpendpoint+
-				" persistent-keepalive "+keepAliveString+
-				" allowed-ips "+allowedips, true)
-		} else {
-			_, err = ncutils.RunCmd("wg set "+iface+" peer "+peer.PublicKey.String()+
-				" persistent-keepalive "+keepAliveString+
-				" allowed-ips "+allowedips, true)
-		}
+
+		_, err = ncutils.RunCmd("wg set "+iface+" peer "+peer.PublicKey.String()+
+			" persistent-keepalive "+keepAliveString+
+			" allowed-ips "+allowedips, true)
 		if err != nil {
 			logger.Log(2, "error setting peer", peer.PublicKey.String())
 		}
@@ -253,7 +246,9 @@ func setServerPeers(iface string, keepalive int32, peers []wgtypes.PeerConfig) e
 		if len(currentPeer.AllowedIPs) > 0 {
 			shouldDelete := true
 			for _, peer := range peers {
-				if len(peer.AllowedIPs) > 0 && peer.AllowedIPs[0].String() == currentPeer.AllowedIPs[0].String() {
+				if len(peer.AllowedIPs) > 0 &&
+					(peer.PublicKey.String() == currentPeer.PublicKey.String() ||
+						peer.AllowedIPs[0].String() == currentPeer.AllowedIPs[0].String()) {
 					shouldDelete = false
 				}
 			}

+ 8 - 10
mq/mq.go

@@ -85,15 +85,12 @@ var UpdateNode mqtt.MessageHandler = func(client mqtt.Client, msg mqtt.Message)
 			logger.Log(1, "error unmarshaling payload ", err.Error())
 			return
 		}
-
 		if err := logic.UpdateNode(&currentNode, &newNode); err != nil {
 			logger.Log(1, "error saving node", err.Error())
 		}
-		if logic.ShouldPeersUpdate(&currentNode, &newNode) {
-			if err := PublishPeerUpdate(&newNode); err != nil {
-				logger.Log(1, "error publishing peer update ", err.Error())
-				return
-			}
+		if err := PublishPeerUpdate(&newNode); err != nil {
+			logger.Log(1, "error publishing peer update ", err.Error())
+			return
 		}
 		logger.Log(1, "no need to update peers")
 	}()
@@ -101,21 +98,20 @@ var UpdateNode mqtt.MessageHandler = func(client mqtt.Client, msg mqtt.Message)
 
 // PublishPeerUpdate --- deterines and publishes a peer update to all the peers of a node
 func PublishPeerUpdate(newNode *models.Node) error {
-	if !servercfg.IsMessageQueueBackend() {
-		return nil
-	}
+
 	networkNodes, err := logic.GetNetworkNodes(newNode.Network)
 	if err != nil {
 		logger.Log(1, "err getting Network Nodes", err.Error())
 		return err
 	}
 	for _, node := range networkNodes {
+
 		if node.IsServer == "yes" {
 			continue
 		}
 		peerUpdate, err := logic.GetPeerUpdate(&node)
 		if err != nil {
-			logger.Log(1, "error getting peer update for node ", node.ID, err.Error())
+			logger.Log(1, "error getting peer update for node", node.ID, err.Error())
 			continue
 		}
 		data, err := json.Marshal(&peerUpdate)
@@ -125,6 +121,8 @@ func PublishPeerUpdate(newNode *models.Node) error {
 		}
 		if err = publish(&node, fmt.Sprintf("peers/%s/%s", node.Network, node.ID), data); err != nil {
 			logger.Log(1, "failed to publish peer update for node", node.ID)
+		} else {
+			logger.Log(1, fmt.Sprintf("sent peer update for network, %s and node, %s", node.Network, node.Name))
 		}
 	}
 	return nil

+ 30 - 17
netclient/functions/daemon.go

@@ -181,6 +181,9 @@ func NodeUpdate(client mqtt.Client, msg mqtt.Message) {
 		newNode.PullChanges = "no"
 		//ensure that OS never changes
 		newNode.OS = runtime.GOOS
+		// check if interface needs to delta
+		ifaceDelta := ncutils.IfaceDelta(&cfg.Node, &newNode)
+
 		cfg.Node = newNode
 		switch newNode.Action {
 		case models.NODE_DELETE:
@@ -214,12 +217,22 @@ func NodeUpdate(client mqtt.Client, msg mqtt.Message) {
 			ncutils.Log("error updating wireguard config " + err.Error())
 			return
 		}
-		ncutils.Log("applyWGQuickConf to " + file)
-		err = wireguard.ApplyWGQuickConf(file)
-		if err != nil {
-			ncutils.Log("error restarting wg after node update " + err.Error())
-			return
+		if ifaceDelta {
+			ncutils.Log("applying WG conf to " + file)
+			err = wireguard.ApplyWGQuickConf(file)
+			if err != nil {
+				ncutils.Log("error restarting wg after node update " + err.Error())
+				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
+			}
 		}
+
 		//deal with DNS
 		if newNode.DNSOn == "yes" {
 			ncutils.Log("setting up DNS")
@@ -262,22 +275,22 @@ func UpdatePeers(client mqtt.Client, msg mqtt.Message) {
 		insert(peerUpdate.Network, lastPeerUpdate, string(data))
 		ncutils.Log("update peer handler")
 
+		file := ncutils.GetNetclientPathSpecific() + cfg.Node.Interface + ".conf"
 		var shouldReSub = shouldResub(cfg.Node.NetworkSettings.DefaultServerAddrs, peerUpdate.ServerAddrs)
 		if shouldReSub {
 			Resubscribe(client, &cfg)
 			cfg.Node.NetworkSettings.DefaultServerAddrs = peerUpdate.ServerAddrs
-			file := ncutils.GetNetclientPathSpecific() + cfg.Node.Interface + ".conf"
-			err = wireguard.UpdateWgPeers(file, peerUpdate.Peers)
-			if err != nil {
-				ncutils.Log("error updating wireguard peers" + err.Error())
-				return
-			}
-			ncutils.Log("applyWGQuickConf to " + file)
-			err = wireguard.ApplyWGQuickConf(file)
-			if err != nil {
-				ncutils.Log("error restarting wg after peer update " + err.Error())
-				return
-			}
+		}
+		err = wireguard.UpdateWgPeers(file, peerUpdate.Peers)
+		if err != nil {
+			ncutils.Log("error updating wireguard peers" + err.Error())
+			return
+		}
+		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
 		}
 	}()
 }

+ 72 - 0
netclient/ncutils/iface.go

@@ -0,0 +1,72 @@
+package ncutils
+
+import "github.com/gravitl/netmaker/models"
+
+func IfaceDelta(currentNode *models.Node, newNode *models.Node) bool {
+	// 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
+}
+
+// StringSliceContains - sees if a string slice contains a string element
+func StringSliceContains(slice []string, item string) bool {
+	for _, s := range slice {
+		if s == item {
+			return true
+		}
+	}
+	return false
+}

+ 5 - 2
netclient/wireguard/common.go

@@ -143,7 +143,7 @@ func InitWireguard(node *models.Node, privkey string, peers []wgtypes.PeerConfig
 	if node.Address == "" {
 		log.Fatal("no address to configure")
 	}
-	if node.UDPHolePunch != "yes" {
+	if node.UDPHolePunch == "yes" {
 		node.ListenPort = 0
 	}
 	if err := WriteWgConfig(&modcfg.Node, key.String(), peers); err != nil {
@@ -291,7 +291,7 @@ func WriteWgConfig(node *models.Node, privateKey string, peers []wgtypes.PeerCon
 	}
 	wireguard := ini.Empty(options)
 	wireguard.Section(section_interface).Key("PrivateKey").SetValue(privateKey)
-	if node.ListenPort > 0 {
+	if node.ListenPort > 0 && node.UDPHolePunch != "yes" {
 		wireguard.Section(section_interface).Key("ListenPort").SetValue(strconv.Itoa(int(node.ListenPort)))
 	}
 	if node.Address != "" {
@@ -395,6 +395,9 @@ func UpdateWgInterface(file, privateKey, nameserver string, node models.Node) er
 	if err != nil {
 		return err
 	}
+	if node.UDPHolePunch == "yes" {
+		node.ListenPort = 0
+	}
 	wireguard.Section(section_interface).Key("PrivateKey").SetValue(privateKey)
 	wireguard.Section(section_interface).Key("ListenPort").SetValue(strconv.Itoa(int(node.ListenPort)))
 	if node.Address != "" {