Bläddra i källkod

Merge pull request #1216 from gravitl/v0.14.3

V0.14.3
Alex Feiszli 3 år sedan
förälder
incheckning
83424183ff

+ 1 - 0
.github/ISSUE_TEMPLATE/bug-report.yml

@@ -31,6 +31,7 @@ body:
       label: Version
       description: What version are you running?
       options:
+        - v0.14.3      
         - v0.14.2
         - v0.14.1
         - v0.14.0      

+ 1 - 1
.github/workflows/publish-docker.yml

@@ -76,5 +76,5 @@ jobs:
           context: .
           platforms: linux/amd64, linux/arm64
           push: true
-          tags: ${{ github.repository }}:${{ env.TAG }}
+          tags: ${{ github.repository }}:${{ env.TAG }}, ${{ github.repository }}:latest
           build-args: version=${{ env.TAG }}

+ 1 - 1
README.md

@@ -10,7 +10,7 @@ a platform for modern, blazing fast virtual networks
 
 <p align="center">
   <a href="https://github.com/gravitl/netmaker/releases">
-    <img src="https://img.shields.io/badge/Version-0.14.2-informational?style=flat-square" />
+    <img src="https://img.shields.io/badge/Version-0.14.3-informational?style=flat-square" />
   </a>
   <a href="https://hub.docker.com/r/gravitl/netmaker/tags">
     <img src="https://img.shields.io/docker/pulls/gravitl/netmaker?label=downloads" />

+ 2 - 2
compose/docker-compose.contained.yml

@@ -3,7 +3,7 @@ version: "3.4"
 services:
   netmaker:
     container_name: netmaker
-    image: gravitl/netmaker:v0.14.2
+    image: gravitl/netmaker:v0.14.3
     volumes:
       - dnsconfig:/root/config/dnsconfig
       - sqldata:/root/data
@@ -43,7 +43,7 @@ services:
     container_name: netmaker-ui
     depends_on:
       - netmaker
-    image: gravitl/netmaker-ui:v0.14.2
+    image: gravitl/netmaker-ui:v0.14.3
     links:
       - "netmaker:api"
     environment:

+ 2 - 2
compose/docker-compose.hostnetwork.yml

@@ -3,7 +3,7 @@ version: "3.4"
 services:
   netmaker:
     container_name: netmaker
-    image: gravitl/netmaker:v0.14.2
+    image: gravitl/netmaker:v0.14.3
     volumes:
       - dnsconfig:/root/config/dnsconfig
       - /usr/bin/wg:/usr/bin/wg
@@ -38,7 +38,7 @@ services:
     container_name: netmaker-ui
     depends_on:
       - netmaker
-    image: gravitl/netmaker-ui:v0.14.2
+    image: gravitl/netmaker-ui:v0.14.3
     links:
       - "netmaker:api"
     ports:

+ 2 - 2
compose/docker-compose.nocaddy.yml

@@ -3,7 +3,7 @@ version: "3.4"
 services:
   netmaker:
     container_name: netmaker
-    image: gravitl/netmaker:v0.14.2
+    image: gravitl/netmaker:v0.14.3
     volumes:
       - dnsconfig:/root/config/dnsconfig
       - sqldata:/root/data
@@ -44,7 +44,7 @@ services:
     container_name: netmaker-ui
     depends_on:
       - netmaker
-    image: gravitl/netmaker-ui:v0.14.2
+    image: gravitl/netmaker-ui:v0.14.3
     links:
       - "netmaker:api"
     ports:

+ 2 - 2
compose/docker-compose.nodns.yml

@@ -3,7 +3,7 @@ version: "3.4"
 services:
   netmaker:
     container_name: netmaker
-    image: gravitl/netmaker:v0.14.2
+    image: gravitl/netmaker:v0.14.3
     volumes:
       - dnsconfig:/root/config/dnsconfig
       - sqldata:/root/data
@@ -45,7 +45,7 @@ services:
     container_name: netmaker-ui
     depends_on:
       - netmaker
-    image: gravitl/netmaker-ui:v0.14.2
+    image: gravitl/netmaker-ui:v0.14.3
     links:
       - "netmaker:api"
     ports:

+ 31 - 1
controllers/node.go

@@ -635,6 +635,10 @@ func updateNode(w http.ResponseWriter, r *http.Request) {
 			}
 		}
 	}
+	relayedUpdate := false
+	if node.IsRelayed == "yes" && (node.Address != newNode.Address || node.Address6 != newNode.Address6) {
+		relayedUpdate = true
+	}
 
 	if !servercfg.GetRce() {
 		newNode.PostDown = node.PostDown
@@ -659,7 +663,9 @@ func updateNode(w http.ResponseWriter, r *http.Request) {
 			}
 		}
 	}
-
+	if relayedUpdate {
+		updateRelay(&node, &newNode)
+	}
 	if servercfg.IsDNSMode() {
 		logic.SetDNS()
 	}
@@ -758,3 +764,27 @@ func runForceServerUpdate(node *models.Node) {
 func isServer(node *models.Node) bool {
 	return node.IsServer == "yes"
 }
+
+func updateRelay(oldnode, newnode *models.Node) {
+	relay := logic.FindRelay(oldnode)
+	newrelay := relay
+	//check if node's address has been updated and if so, update the relayAddrs of the relay node with the updated address of the relayed node
+	if oldnode.Address != newnode.Address {
+		for i, ip := range newrelay.RelayAddrs {
+			if ip == oldnode.Address {
+				newrelay.RelayAddrs = append(newrelay.RelayAddrs[:i], relay.RelayAddrs[i+1:]...)
+				newrelay.RelayAddrs = append(newrelay.RelayAddrs, newnode.Address)
+			}
+		}
+	}
+	//check if node's address(v6) has been updated and if so, update the relayAddrs of the relay node with the updated address(v6) of the relayed node
+	if oldnode.Address6 != newnode.Address6 {
+		for i, ip := range newrelay.RelayAddrs {
+			if ip == oldnode.Address {
+				newrelay.RelayAddrs = append(newrelay.RelayAddrs[:i], newrelay.RelayAddrs[i+1:]...)
+				newrelay.RelayAddrs = append(newrelay.RelayAddrs, newnode.Address6)
+			}
+		}
+	}
+	logic.UpdateNode(relay, newrelay)
+}

+ 3 - 3
go.mod

@@ -3,7 +3,7 @@ module github.com/gravitl/netmaker
 go 1.18
 
 require (
-	github.com/eclipse/paho.mqtt.golang v1.3.5
+	github.com/eclipse/paho.mqtt.golang v1.4.1
 	github.com/go-playground/validator/v10 v10.11.0
 	github.com/golang-jwt/jwt/v4 v4.4.1
 	github.com/golang/protobuf v1.5.2 // indirect
@@ -14,7 +14,7 @@ require (
 	github.com/mattn/go-sqlite3 v1.14.10
 	github.com/rqlite/gorqlite v0.0.0-20210514125552-08ff1e76b22f
 	github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e
-	github.com/stretchr/testify v1.7.1
+	github.com/stretchr/testify v1.7.2
 	github.com/txn2/txeh v1.3.0
 	github.com/urfave/cli/v2 v2.8.1
 	golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd
@@ -26,7 +26,7 @@ require (
 	golang.zx2c4.com/wireguard/wgctrl v0.0.0-20220324164955-056925b7df31
 	google.golang.org/protobuf v1.28.0 // indirect
 	gopkg.in/ini.v1 v1.66.6
-	gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
+	gopkg.in/yaml.v3 v3.0.1
 )
 
 require (

+ 6 - 5
go.sum

@@ -48,8 +48,8 @@ github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKoh
 github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
 github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw=
 github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
-github.com/eclipse/paho.mqtt.golang v1.3.5 h1:sWtmgNxYM9P2sP+xEItMozsR3w0cqZFlqnNN1bdl41Y=
-github.com/eclipse/paho.mqtt.golang v1.3.5/go.mod h1:eTzb4gxwwyWpqBUHGQZ4ABAV7+Jgm1PklsYT/eo8Hcc=
+github.com/eclipse/paho.mqtt.golang v1.4.1 h1:tUSpviiL5G3P9SZZJPC4ZULZJsxQKXxfENpMvdbAXAI=
+github.com/eclipse/paho.mqtt.golang v1.4.1/go.mod h1:JGt0RsEwEX+Xa/agj90YJ9d9DH2b7upDZMK9HRbFvCA=
 github.com/felixge/httpsnoop v1.0.1 h1:lvB5Jl89CsZtGIWuTcDM1E/vkVs49/Ml7JJe07l8SPQ=
 github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
 github.com/fredbi/uri v0.0.0-20181227131451-3dcfdacbaaf3 h1:FDqhDm7pcsLhhWl1QtD8vlzI4mm59llRvNzrFg6/LAA=
@@ -229,8 +229,8 @@ github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81P
 github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
 github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
 github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
-github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY=
-github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.7.2 h1:4jaiDzPyXQvSd7D0EjG45355tLlV3VOECpq10pLC+8s=
+github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
 github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
 github.com/txn2/txeh v1.3.0 h1:vnbv63htVMZCaQgLqVBxKvj2+HHHFUzNW7I183zjg3E=
 github.com/txn2/txeh v1.3.0/go.mod h1:O7M6gUTPeMF+vsa4c4Ipx3JDkOYrruB1Wry8QRsMcw8=
@@ -383,6 +383,7 @@ gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
 gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
 gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
-gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
 gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
+gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=

+ 1 - 1
logic/networks.go

@@ -583,7 +583,7 @@ func NetIDInNetworkCharSet(network *models.Network) bool {
 	charset := "abcdefghijklmnopqrstuvwxyz1234567890-_."
 
 	for _, char := range network.NetID {
-		if !strings.Contains(charset, strings.ToLower(string(char))) {
+		if !strings.Contains(charset, string(char)) {
 			return false
 		}
 	}

+ 46 - 21
logic/nodes.go

@@ -5,7 +5,6 @@ import (
 	"errors"
 	"fmt"
 	"sort"
-	"strings"
 	"time"
 
 	"github.com/go-playground/validator/v10"
@@ -96,25 +95,6 @@ func UncordonNode(nodeid string) (models.Node, error) {
 	return node, err
 }
 
-// GetPeers - gets the peers of a given server node
-func GetPeers(node *models.Node) ([]models.Node, error) {
-	if IsLeader(node) {
-		setNetworkServerPeers(node)
-	}
-	peers, err := GetPeersList(node)
-	if err != nil {
-		if strings.Contains(err.Error(), RELAY_NODE_ERR) {
-			peers, err = PeerListUnRelay(node.ID, node.Network)
-			if err != nil {
-				return nil, err
-			}
-		} else {
-			return nil, err
-		}
-	}
-	return peers, nil
-}
-
 // SetIfLeader - gets the peers of a given server node
 func SetPeersIfLeader(node *models.Node) {
 	if IsLeader(node) {
@@ -180,6 +160,12 @@ func UpdateNode(currentNode *models.Node, newNode *models.Node) error {
 func DeleteNodeByID(node *models.Node, exterminate bool) error {
 	var err error
 	var key = node.ID
+	//delete any ext clients as required
+	if node.IsIngressGateway == "yes" {
+		if err := DeleteGatewayExtClients(node.ID, node.Network); err != nil {
+			logger.Log(0, "failed to deleted ext clients", err.Error())
+		}
+	}
 	if !exterminate {
 		node.Action = models.NODE_DELETE
 		nodedata, err := json.Marshal(&node)
@@ -207,7 +193,7 @@ func DeleteNodeByID(node *models.Node, exterminate bool) error {
 		// ignoring for now, could hit a nil pointer if delete called twice
 		logger.Log(2, "attempted to remove node ACL for node", node.Name, node.ID)
 	}
-
+	removeZombie <- node.ID
 	return removeLocalServer(node)
 }
 
@@ -307,6 +293,7 @@ func CreateNode(node *models.Node) error {
 	if err != nil {
 		return err
 	}
+	CheckZombies(node)
 
 	nodebytes, err := json.Marshal(&node)
 	if err != nil {
@@ -675,3 +662,41 @@ func unsetHub(networkName string) error {
 	}
 	return nil
 }
+
+// FindRelay - returns the node that is the relay for a relayed node
+func FindRelay(node *models.Node) *models.Node {
+	if node.IsRelayed == "no" {
+		return nil
+	}
+	peers, err := GetNetworkNodes(node.Network)
+	if err != nil {
+		return nil
+	}
+	for _, peer := range peers {
+		if peer.IsRelay == "no" {
+			continue
+		}
+		for _, ip := range peer.RelayAddrs {
+			if ip == node.Address || ip == node.Address6 {
+				return &peer
+			}
+		}
+	}
+	return nil
+}
+
+func findNode(ip string) (*models.Node, error) {
+	nodes, err := GetAllNodes()
+	if err != nil {
+		return nil, err
+	}
+	for _, node := range nodes {
+		if node.Address == ip {
+			return &node, nil
+		}
+		if node.Address6 == ip {
+			return &node, nil
+		}
+	}
+	return nil, errors.New("node not found")
+}

+ 223 - 195
logic/peers.go

@@ -1,6 +1,7 @@
 package logic
 
 import (
+	"errors"
 	"fmt"
 	"log"
 	"net"
@@ -11,223 +12,60 @@ import (
 	"github.com/c-robinson/iplib"
 	"github.com/gravitl/netmaker/database"
 	"github.com/gravitl/netmaker/logger"
-	"github.com/gravitl/netmaker/logic/acls"
 	"github.com/gravitl/netmaker/logic/acls/nodeacls"
 	"github.com/gravitl/netmaker/models"
+	"github.com/gravitl/netmaker/netclient/ncutils"
 	"github.com/gravitl/netmaker/servercfg"
 	"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
 )
 
-// GetNodePeers - fetches peers for a given node
-func GetNodePeers(network *models.Network, nodeid string, excludeRelayed bool, isP2S bool) ([]models.Node, error) {
-	var peers []models.Node
-
-	// networkNodes = all nodes in network
-	// egressNetworkNodes = all egress gateways in network
-	var networkNodes, egressNetworkNodes, err = getNetworkEgressAndNodes(network.NetID)
-	if err != nil {
-		return peers, nil
-	}
+// GetPeerUpdate - gets a wireguard peer config for each peer of a node
+func GetPeerUpdate(node *models.Node) (models.PeerUpdate, error) {
+	var peerUpdate models.PeerUpdate
+	var peers []wgtypes.PeerConfig
+	var serverNodeAddresses = []models.ServerAddr{}
 
 	// udppeers = the peers parsed from the local interface
 	// gives us correct port to reach
-	udppeers, errN := database.GetPeers(network.NetID)
+	udppeers, errN := database.GetPeers(node.Network)
 	if errN != nil {
 		logger.Log(2, errN.Error())
 	}
 
-	// gets all the ACL rules
-	currentNetworkACLs, aclErr := nodeacls.FetchAllACLs(nodeacls.NetworkID(network.NetID))
-	if aclErr != nil {
-		return peers, aclErr
-	}
-
-	/*
-		at this point we have 4 lists of node information:
-		- networkNodes: all nodes in network (models.Node)
-		- egressNetworkNodes: all egress gateways in network (models.Node)
-		- udppeers: all peers in database (parsed by server off of active WireGuard interface)
-		- currentNetworkACLs: all ACL rules associated with the network
-		- peers: a currently empty list that will be filled and returned
-
-	*/
-
-	// we now parse through all networkNodes and format properly to set as "peers"
-	for _, node := range networkNodes {
-
-		// skip over any node that is disallowed by ACL rules
-		if !currentNetworkACLs.IsAllowed(acls.AclID(nodeid), acls.AclID(node.ID)) {
-			continue
-		}
-
-		// create an empty model to fill with peer info
-		var peer = models.Node{}
-
-		// set egress gateway information if it's an egress gateway
-		if node.IsEgressGateway == "yes" { // handle egress stuff
-			peer.EgressGatewayRanges = node.EgressGatewayRanges
-			peer.IsEgressGateway = node.IsEgressGateway
-		}
-
-		// set ingress gateway information
-		peer.IsIngressGateway = node.IsIngressGateway
-
-		/*
-			- similar to ACLs, we must determine if peer is allowed based on Relay information
-			- if the nodes is "not relayed" (not behind a relay), it is ok
-			- if the node IS relayed, but excludeRelay has not been marked, it is ok
-			- excludeRelayed is marked for any node that is NOT a Relay Server
-			- therefore, the peer is allowed as long as it is not "relayed", or the node it is being sent to is its relay server
-		*/
-		allow := node.IsRelayed != "yes" || !excludeRelayed
-
-		// confirm conditions allow node to be added as peer
-		// node should be in same network, not pending, and "allowed" based on above logic
-		if node.Network == network.NetID && node.IsPending != "yes" && allow {
-
-			// node info is cleansed to remove sensitive info using setPeerInfo
-			peer = setPeerInfo(&node)
-
-			// Sets ListenPort to UDP Hole Punching Port assuming:
-			// - UDP Hole Punching is enabled
-			// - udppeers retrieval did not return an error
-			// - the endpoint is valid
-			if node.UDPHolePunch == "yes" && errN == nil && CheckEndpoint(udppeers[node.PublicKey]) {
-				endpointstring := udppeers[node.PublicKey]
-				endpointarr := strings.Split(endpointstring, ":")
-				if len(endpointarr) == 2 {
-					port, err := strconv.Atoi(endpointarr[1])
-					if err == nil {
-						peer.ListenPort = int32(port)
-					}
-				}
-			}
-
-			// if udp hole punching is on, but the node's port is still set to default (e.g. 51821), use the LocalListenPort
-			// or, if port is for some reason zero use the LocalListenPort
-			// but only do this if LocalListenPort is not zero
-			if node.UDPHolePunch == "yes" &&
-				((peer.ListenPort == node.ListenPort || peer.ListenPort == 0) && node.LocalListenPort != 0) {
-				peer.ListenPort = node.LocalListenPort
-			}
-
-			// if the node is a relay, append the network cidr and any relayed egress ranges
-			if node.IsRelay == "yes" { // TODO, check if addressrange6 needs to be appended
-				peer.AllowedIPs = append(peer.AllowedIPs, network.AddressRange)
-				for _, egressNode := range egressNetworkNodes {
-					if egressNode.IsRelayed == "yes" && StringSliceContains(node.RelayAddrs, egressNode.Address) {
-						peer.AllowedIPs = append(peer.AllowedIPs, egressNode.EgressGatewayRanges...)
-					}
-				}
-			}
-
-			// if the node is an ingress gateway, append all the extclient allowedips
-			if peer.IsIngressGateway == "yes" { // handle ingress stuff
-				if currentExtClients, err := GetExtPeersList(&node); err == nil {
-					for i := range currentExtClients {
-						if network.IsIPv4 == "yes" && currentExtClients[i].Address != "" {
-							peer.AllowedIPs = append(peer.AllowedIPs, currentExtClients[i].Address)
-						}
-						if network.IsIPv6 == "yes" && currentExtClients[i].Address6 != "" {
-							peer.AllowedIPs = append(peer.AllowedIPs, currentExtClients[i].Address6)
-						}
-					}
-				}
-			}
-
-			// dont appent if this isn't a p2p network or if ACLs disallow
-			if (!isP2S || peer.IsHub == "yes") && currentNetworkACLs.IsAllowed(acls.AclID(nodeid), acls.AclID(node.ID)) {
-				peers = append(peers, peer)
-			}
-		}
-	}
-
-	return peers, err
-}
-
-// GetPeersList - gets the peers of a given network
-func GetPeersList(refnode *models.Node) ([]models.Node, error) {
-	var peers []models.Node
-	var err error
-	var isP2S bool
-	var networkName = refnode.Network
-	var excludeRelayed = refnode.IsRelay != "yes"
-	var relayedNodeAddr string
-	if refnode.IsRelayed == "yes" {
-		relayedNodeAddr = refnode.Address
-	}
-
-	network, err := GetNetwork(networkName)
+	currentPeers, err := GetNetworkNodes(node.Network)
 	if err != nil {
-		return peers, err
-	} else if network.IsPointToSite == "yes" && refnode.IsHub != "yes" {
-		isP2S = true
-	}
-	if refnode.IsRelayed != "yes" {
-		// if the node is not being relayed, retrieve peers as normal
-		peers, err = GetNodePeers(&network, refnode.ID, excludeRelayed, isP2S)
-	} else {
-		var relayNode models.Node
-		// If this node IS being relayed node, we must first retrieve its relay
-		relayNode, err = GetNodeRelay(networkName, relayedNodeAddr)
-		if relayNode.Address != "" && err == nil {
-			// we must cleanse sensitive info from the relay node
-			var peerNode = setPeerInfo(&relayNode)
-
-			// we must append the CIDR to the relay so the relayed node can reach the network
-			peerNode.AllowedIPs = append(peerNode.AllowedIPs, network.AddressRange)
-
-			// we must append the egress ranges to the relay so the relayed node can reach egress
-			var _, egressNetworkNodes, err = getNetworkEgressAndNodes(networkName)
-			if err == nil {
-				for _, egress := range egressNetworkNodes {
-					if egress.Address != relayedNodeAddr {
-						peerNode.AllowedIPs = append(peerNode.AllowedIPs, egress.EgressGatewayRanges...)
-					}
-				}
-			}
-
-			// get the other peers that are behind the Relay
-			// we dont want to go through the relay to reach them
-			// I'm not sure if this is actually a good call to have this here
-			// may want to test without it, I think it may return bad info
-			nodepeers, err := GetNodePeers(&network, refnode.ID, false, isP2S)
-			if err == nil && peerNode.UDPHolePunch == "yes" {
-				for _, nodepeer := range nodepeers {
-
-					// im not sure if this is good either
-					if nodepeer.Address == peerNode.Address {
-						// peerNode.Endpoint = nodepeer.Endpoint
-						peerNode.ListenPort = nodepeer.ListenPort
-					}
-				}
-			}
-			if !isP2S || peerNode.IsHub == "yes" {
-				peers = append(peers, peerNode)
-			}
-		}
+		return models.PeerUpdate{}, err
 	}
-	return peers, err
-}
 
-// GetPeerUpdate - gets a wireguard peer config for each peer of a node
-func GetPeerUpdate(node *models.Node) (models.PeerUpdate, error) {
-	var peerUpdate models.PeerUpdate
-	var peers []wgtypes.PeerConfig
-	var serverNodeAddresses = []models.ServerAddr{}
-	currentPeers, err := GetPeers(node)
-	if err != nil {
-		return models.PeerUpdate{}, err
+	if node.IsRelayed == "yes" {
+		return GetPeerUpdateForRelayedNode(node, udppeers)
 	}
 
 	// #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 the node is not a server, set the endpoint
+		var setEndpoint = !(node.IsServer == "yes")
+
 		if peer.ID == node.ID {
 			//skip yourself
 			continue
 		}
+		if peer.IsRelayed == "yes" {
+			if !(node.IsRelay == "yes" && ncutils.StringSliceContains(node.RelayAddrs, peer.PrimaryAddress())) {
+				//skip -- will be added to relay
+				continue
+			} else if node.IsRelay == "yes" && ncutils.StringSliceContains(node.RelayAddrs, peer.PrimaryAddress()) {
+				// dont set peer endpoint if it's relayed by node
+				setEndpoint = false
+			}
+		}
+		if !nodeacls.AreNodesAllowed(nodeacls.NetworkID(node.Network), nodeacls.NodeID(node.ID), nodeacls.NodeID(peer.ID)) {
+			//skip if not permitted by acl
+			continue
+		}
 		pubkey, err := wgtypes.ParseKey(peer.PublicKey)
 		if err != nil {
 			return models.PeerUpdate{}, err
@@ -244,10 +82,41 @@ func GetPeerUpdate(node *models.Node) (models.PeerUpdate, error) {
 				continue
 			}
 		}
-		endpoint := peer.Endpoint + ":" + strconv.FormatInt(int64(peer.ListenPort), 10)
-		address, err := net.ResolveUDPAddr("udp", endpoint)
-		if err != nil {
-			return models.PeerUpdate{}, err
+
+		// set address if setEndpoint is true
+		// otherwise, will get inserted as empty value
+		var address *net.UDPAddr
+
+		// Sets ListenPort to UDP Hole Punching Port assuming:
+		// - UDP Hole Punching is enabled
+		// - udppeers retrieval did not return an error
+		// - the endpoint is valid
+		if setEndpoint {
+
+			var setUDPPort = false
+			if peer.UDPHolePunch == "yes" && errN == nil && CheckEndpoint(udppeers[peer.PublicKey]) {
+				endpointstring := udppeers[peer.PublicKey]
+				endpointarr := strings.Split(endpointstring, ":")
+				if len(endpointarr) == 2 {
+					port, err := strconv.Atoi(endpointarr[1])
+					if err == nil {
+						setUDPPort = true
+						peer.ListenPort = int32(port)
+					}
+				}
+			}
+			// if udp hole punching is on, but udp hole punching did not set it, use the LocalListenPort instead
+			// or, if port is for some reason zero use the LocalListenPort
+			// but only do this if LocalListenPort is not zero
+			if ((peer.UDPHolePunch == "yes" && !setUDPPort) || peer.ListenPort == 0) && peer.LocalListenPort != 0 {
+				peer.ListenPort = peer.LocalListenPort
+			}
+
+			endpoint := peer.Endpoint + ":" + strconv.FormatInt(int64(peer.ListenPort), 10)
+			address, err = net.ResolveUDPAddr("udp", endpoint)
+			if err != nil {
+				return models.PeerUpdate{}, err
+			}
 		}
 		// set_allowedips
 		allowedips := GetAllowedIPs(node, &peer)
@@ -263,6 +132,7 @@ func GetPeerUpdate(node *models.Node) (models.PeerUpdate, error) {
 			AllowedIPs:                  allowedips,
 			PersistentKeepaliveInterval: &keepalive,
 		}
+
 		peers = append(peers, peerData)
 		if peer.IsServer == "yes" {
 			serverNodeAddresses = append(serverNodeAddresses, models.ServerAddr{IsLeader: IsLeader(&peer), Address: peer.Address})
@@ -406,6 +276,52 @@ func GetAllowedIPs(node, peer *models.Node) []net.IPNet {
 			}
 		}
 	}
+	// handle ingress gateway peers
+	if peer.IsIngressGateway == "yes" {
+		extPeers, err := getExtPeers(peer)
+		if err != nil {
+			logger.Log(2, "could not retrieve ext peers for ", peer.Name, err.Error())
+		}
+		for _, extPeer := range extPeers {
+			allowedips = append(allowedips, extPeer.AllowedIPs...)
+		}
+	}
+	// handle relay gateway peers
+	if peer.IsRelay == "yes" {
+		for _, ip := range peer.RelayAddrs {
+			//find node ID of relayed peer
+			relayedPeer, err := findNode(ip)
+			if err != nil {
+				logger.Log(0, "failed to find node for ip ", ip, err.Error())
+				continue
+			}
+			if relayedPeer == nil {
+				continue
+			}
+			if relayedPeer.ID == node.ID {
+				//skip self
+				continue
+			}
+			//check if acl permits comms
+			if !nodeacls.AreNodesAllowed(nodeacls.NetworkID(node.Network), nodeacls.NodeID(node.ID), nodeacls.NodeID(relayedPeer.ID)) {
+				continue
+			}
+			if iplib.Version(net.ParseIP(ip)) == 4 {
+				relayAddr := net.IPNet{
+					IP:   net.ParseIP(ip),
+					Mask: net.CIDRMask(32, 32),
+				}
+				allowedips = append(allowedips, relayAddr)
+			}
+			if iplib.Version(net.ParseIP(ip)) == 6 {
+				relayAddr := net.IPNet{
+					IP:   net.ParseIP(ip),
+					Mask: net.CIDRMask(128, 128),
+				}
+				allowedips = append(allowedips, relayAddr)
+			}
+		}
+	}
 	return allowedips
 }
 
@@ -425,3 +341,115 @@ func getPeerDNS(network string) string {
 	}
 	return dns
 }
+
+// GetPeerUpdateForRelayedNode - calculates peer update for a relayed node by getting the relay
+// copying the relay node's allowed ips and making appropriate substitutions
+func GetPeerUpdateForRelayedNode(node *models.Node, udppeers map[string]string) (models.PeerUpdate, error) {
+	var peerUpdate models.PeerUpdate
+	var peers []wgtypes.PeerConfig
+	var serverNodeAddresses = []models.ServerAddr{}
+	var allowedips []net.IPNet
+	//find node that is relaying us
+	relay := FindRelay(node)
+	if relay == nil {
+		return models.PeerUpdate{}, errors.New("not found")
+	}
+
+	//add relay to lists of allowed ip
+	if relay.Address != "" {
+		relayIP := net.IPNet{
+			IP:   net.ParseIP(relay.Address),
+			Mask: net.CIDRMask(32, 32),
+		}
+		allowedips = append(allowedips, relayIP)
+	}
+	if relay.Address6 != "" {
+		relayIP6 := net.IPNet{
+			IP:   net.ParseIP(relay.Address6),
+			Mask: net.CIDRMask(128, 128),
+		}
+		allowedips = append(allowedips, relayIP6)
+	}
+	//get PeerUpdate for relayed node
+	relayPeerUpdate, err := GetPeerUpdate(relay)
+	if err != nil {
+		return models.PeerUpdate{}, err
+	}
+	//add the relays allowed ips from all of the relay's peers
+	for _, peer := range relayPeerUpdate.Peers {
+		allowedips = append(allowedips, peer.AllowedIPs...)
+	}
+	//delete any ips not permitted by acl
+	for i := len(allowedips) - 1; i >= 0; i-- {
+		target, err := findNode(allowedips[i].IP.String())
+		if err != nil {
+			logger.Log(0, "failed to find node for ip", allowedips[i].IP.String(), err.Error())
+			continue
+		}
+		if target == nil {
+			logger.Log(0, "failed to find node for ip", allowedips[i].IP.String())
+			continue
+		}
+		if !nodeacls.AreNodesAllowed(nodeacls.NetworkID(node.Network), nodeacls.NodeID(node.ID), nodeacls.NodeID(target.ID)) {
+			logger.Log(0, "deleting node from relayednode per acl", node.Name, target.Name)
+			allowedips = append(allowedips[:i], allowedips[i+1:]...)
+		}
+	}
+	//delete self from allowed ips
+	for i := len(allowedips) - 1; i >= 0; i-- {
+		if allowedips[i].IP.String() == node.Address || allowedips[i].IP.String() == node.Address6 {
+			allowedips = append(allowedips[:i], allowedips[i+1:]...)
+		}
+	}
+
+	pubkey, err := wgtypes.ParseKey(relay.PublicKey)
+	if err != nil {
+		return models.PeerUpdate{}, err
+	}
+	var setUDPPort = false
+	if relay.UDPHolePunch == "yes" && CheckEndpoint(udppeers[relay.PublicKey]) {
+		endpointstring := udppeers[relay.PublicKey]
+		endpointarr := strings.Split(endpointstring, ":")
+		if len(endpointarr) == 2 {
+			port, err := strconv.Atoi(endpointarr[1])
+			if err == nil {
+				setUDPPort = true
+				relay.ListenPort = int32(port)
+			}
+		}
+	}
+	// if udp hole punching is on, but udp hole punching did not set it, use the LocalListenPort instead
+	// or, if port is for some reason zero use the LocalListenPort
+	// but only do this if LocalListenPort is not zero
+	if ((relay.UDPHolePunch == "yes" && !setUDPPort) || relay.ListenPort == 0) && relay.LocalListenPort != 0 {
+		relay.ListenPort = relay.LocalListenPort
+	}
+
+	endpoint := relay.Endpoint + ":" + strconv.FormatInt(int64(relay.ListenPort), 10)
+	address, err := net.ResolveUDPAddr("udp", endpoint)
+	if err != nil {
+		return models.PeerUpdate{}, err
+	}
+	var keepalive time.Duration
+	if node.PersistentKeepalive != 0 {
+		// set_keepalive
+		keepalive, _ = time.ParseDuration(strconv.FormatInt(int64(node.PersistentKeepalive), 10) + "s")
+	}
+	var peerData = wgtypes.PeerConfig{
+		PublicKey:                   pubkey,
+		Endpoint:                    address,
+		ReplaceAllowedIPs:           true,
+		AllowedIPs:                  allowedips,
+		PersistentKeepaliveInterval: &keepalive,
+	}
+	peers = append(peers, peerData)
+	if relay.IsServer == "yes" {
+		serverNodeAddresses = append(serverNodeAddresses, models.ServerAddr{IsLeader: IsLeader(relay), Address: relay.Address})
+	}
+	peerUpdate.Network = node.Network
+	peerUpdate.ServerVersion = servercfg.Version
+	peerUpdate.Peers = peers
+	peerUpdate.ServerAddrs = serverNodeAddresses
+	peerUpdate.DNS = getPeerDNS(node.Network)
+	return peerUpdate, nil
+}

+ 11 - 55
logic/relay.go

@@ -37,7 +37,7 @@ func CreateRelay(relay models.RelayRequest) ([]models.Node, models.Node, error)
 	if err = database.Insert(node.ID, string(nodeData), database.NODES_TABLE_NAME); err != nil {
 		return returnnodes, models.Node{}, err
 	}
-	returnnodes, err = SetRelayedNodes("yes", node.Network, node.RelayAddrs)
+	returnnodes, err = SetRelayedNodes(true, node.Network, node.RelayAddrs)
 	if err != nil {
 		return returnnodes, node, err
 	}
@@ -48,32 +48,20 @@ func CreateRelay(relay models.RelayRequest) ([]models.Node, models.Node, error)
 }
 
 // SetRelayedNodes- set relayed nodes
-func SetRelayedNodes(yesOrno string, networkName string, addrs []string) ([]models.Node, error) {
+func SetRelayedNodes(setRelayed bool, networkName string, addrs []string) ([]models.Node, error) {
 	var returnnodes []models.Node
-	collections, err := database.FetchRecords(database.NODES_TABLE_NAME)
+	networkNodes, err := GetNetworkNodes(networkName)
 	if err != nil {
 		return returnnodes, err
 	}
-	network, err := GetNetworkSettings(networkName)
-	if err != nil {
-		return returnnodes, err
-	}
-
-	for _, value := range collections {
-
-		var node models.Node
-		err := json.Unmarshal([]byte(value), &node)
-		if err != nil {
-			return returnnodes, err
-		}
-		if node.Network == networkName && !(node.IsServer == "yes") {
+	for _, node := range networkNodes {
+		if node.IsServer != "yes" {
 			for _, addr := range addrs {
 				if addr == node.Address || addr == node.Address6 {
-					node.IsRelayed = yesOrno
-					if yesOrno == "yes" {
-						node.UDPHolePunch = "no"
+					if setRelayed {
+						node.IsRelayed = "yes"
 					} else {
-						node.UDPHolePunch = network.DefaultUDPHolePunch
+						node.IsRelayed = "no"
 					}
 					data, err := json.Marshal(&node)
 					if err != nil {
@@ -88,38 +76,6 @@ func SetRelayedNodes(yesOrno string, networkName string, addrs []string) ([]mode
 	return returnnodes, nil
 }
 
-// SetNodeIsRelayed - Sets IsRelayed to on or off for relay
-func SetNodeIsRelayed(yesOrno string, id string) (models.Node, error) {
-	node, err := GetNodeByID(id)
-	if err != nil {
-		return node, err
-	}
-	network, err := GetNetworkByNode(&node)
-	if err != nil {
-		return node, err
-	}
-	node.IsRelayed = yesOrno
-	if yesOrno == "yes" {
-		node.UDPHolePunch = "no"
-	} else {
-		node.UDPHolePunch = network.DefaultUDPHolePunch
-	}
-	data, err := json.Marshal(&node)
-	if err != nil {
-		return node, err
-	}
-	return node, database.Insert(node.ID, string(data), database.NODES_TABLE_NAME)
-}
-
-// PeerListUnRelay - call this function if a relayed node fails to get its relay: unrelays node and gets new peer list
-func PeerListUnRelay(id string, network string) ([]models.Node, error) {
-	node, err := SetNodeIsRelayed("no", id)
-	if err != nil {
-		return nil, err
-	}
-	return GetPeersList(&node)
-}
-
 // ValidateRelay - checks if relay is valid
 func ValidateRelay(relay models.RelayRequest) error {
 	var err error
@@ -135,11 +91,11 @@ func ValidateRelay(relay models.RelayRequest) error {
 func UpdateRelay(network string, oldAddrs []string, newAddrs []string) []models.Node {
 	var returnnodes []models.Node
 	time.Sleep(time.Second / 4)
-	returnnodes, err := SetRelayedNodes("no", network, oldAddrs)
+	_, err := SetRelayedNodes(false, network, oldAddrs)
 	if err != nil {
 		logger.Log(1, err.Error())
 	}
-	returnnodes, err = SetRelayedNodes("yes", network, newAddrs)
+	returnnodes, err = SetRelayedNodes(true, network, newAddrs)
 	if err != nil {
 		logger.Log(1, err.Error())
 	}
@@ -153,7 +109,7 @@ func DeleteRelay(network, nodeid string) ([]models.Node, models.Node, error) {
 	if err != nil {
 		return returnnodes, models.Node{}, err
 	}
-	_, err = SetRelayedNodes("no", node.Network, node.RelayAddrs)
+	returnnodes, err = SetRelayedNodes(false, node.Network, node.RelayAddrs)
 	if err != nil {
 		return returnnodes, node, err
 	}

+ 16 - 204
logic/server.go

@@ -6,14 +6,9 @@ import (
 	"net"
 	"os"
 	"runtime"
-	"strconv"
 	"strings"
-	"time"
 
-	"github.com/c-robinson/iplib"
 	"github.com/gravitl/netmaker/logger"
-	"github.com/gravitl/netmaker/logic/acls"
-	"github.com/gravitl/netmaker/logic/acls/nodeacls"
 	"github.com/gravitl/netmaker/models"
 	"github.com/gravitl/netmaker/netclient/ncutils"
 	"github.com/gravitl/netmaker/servercfg"
@@ -193,210 +188,27 @@ func ServerUpdate(serverNode *models.Node, ifaceDelta bool) error {
 
 // GetServerPeers - gets peers of server
 func GetServerPeers(serverNode *models.Node) ([]wgtypes.PeerConfig, bool, []string, error) {
-	hasGateway := false
-	var gateways []string
-	var peers []wgtypes.PeerConfig
-	var nodes []models.Node // fill above fields from server or client
-	var err error
-
-	nodes, err = GetPeers(serverNode)
-	if err != nil {
-		return nil, hasGateway, gateways, err
-	}
-
-	keepalive := serverNode.PersistentKeepalive
-	keepalivedur, err := time.ParseDuration(strconv.FormatInt(int64(keepalive), 10) + "s")
+	update, err := GetPeerUpdate(serverNode)
 	if err != nil {
-		logger.Log(1, "Issue with format of keepalive duration value, Please view server config:", err.Error())
-		return nil, hasGateway, gateways, err
-	}
-
-	currentNetworkACL, err := nodeacls.FetchAllACLs(nodeacls.NetworkID(serverNode.Network))
-	if err != nil {
-		logger.Log(1, "could not fetch current ACL list, proceeding with all peers")
-	}
-
-	for _, node := range nodes {
-		pubkey, err := wgtypes.ParseKey(node.PublicKey)
-		if err != nil {
-			logger.Log(1, "error parsing key", pubkey.String())
-			return peers, hasGateway, gateways, err
-		}
-
-		if serverNode.PublicKey == node.PublicKey {
-			continue
-		}
-		if serverNode.Endpoint == node.Endpoint {
-			if serverNode.LocalAddress != node.LocalAddress && node.LocalAddress != "" {
-				node.Endpoint = node.LocalAddress
-			} else {
-				continue
+		return []wgtypes.PeerConfig{}, false, []string{}, err
+	}
+
+	// this is temporary code, should be removed by 0.14.4
+	// refactor server routing to use client-side routing code
+	var hasGateways = false
+	var gateways = []string{}
+	nodes, err := GetNetworkNodes(serverNode.Network)
+	if err == nil {
+		for _, node := range nodes {
+			if node.IsEgressGateway == "yes" {
+				gateways = append(gateways, node.EgressGatewayRanges...)
 			}
 		}
-		if currentNetworkACL != nil && currentNetworkACL.IsAllowed(acls.AclID(serverNode.ID), acls.AclID(node.ID)) {
-			continue
-		}
-
-		var peer wgtypes.PeerConfig
-		var allowedips = []net.IPNet{}
-		if node.Address != "" {
-			var peeraddr = net.IPNet{
-				IP:   net.ParseIP(node.Address),
-				Mask: net.CIDRMask(32, 32),
-			}
-			if peeraddr.IP != nil && peeraddr.Mask != nil {
-				allowedips = append(allowedips, peeraddr)
-			}
-		}
-
-		if node.Address6 != "" {
-			var addr6 = net.IPNet{
-				IP:   net.ParseIP(node.Address6),
-				Mask: net.CIDRMask(128, 128),
-			}
-			if addr6.IP != nil && addr6.Mask != nil {
-				allowedips = append(allowedips, addr6)
-			}
-		}
-
-		// handle manually set peers
-		for _, allowedIp := range node.AllowedIPs {
-			if iplib.Version(net.ParseIP(allowedIp)) == 4 {
-				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..
-						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)
-				}
-			} else if iplib.Version(net.ParseIP(allowedIp)) == 6 {
-				//ipnet : = iplib.Net6FromStr(allowedIp).IP()
-				ipnet := net.IPNet{
-					IP:   iplib.Net6FromStr(allowedIp).IP(),
-					Mask: net.CIDRMask(128, 128),
-				}
-				allowedips = append(allowedips, ipnet)
-			}
-		}
-		// handle egress gateway peers
-		if node.IsEgressGateway == "yes" {
-			hasGateway = true
-			ranges := node.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 {
-					logger.Log(1, "could not parse gateway IP range. Not adding", iprange)
-					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
-					logger.Log(2, "egress IP range of", iprange, "overlaps with", node.Endpoint, ", omitting")
-					continue // skip adding egress range if overlaps with node's ip
-				}
-				if ipnet.Contains(net.ParseIP(serverNode.LocalAddress)) { // ensuring egress gateway range does not contain public ip of node
-					logger.Log(2, "egress IP range of", iprange, "overlaps with", serverNode.LocalAddress, ", omitting")
-					continue // skip adding egress range if overlaps with node's local ip
-				}
-				gateways = append(gateways, iprange)
-				if err != nil {
-					logger.Log(1, "ERROR ENCOUNTERED SETTING GATEWAY:", err.Error())
-				} else {
-					allowedips = append(allowedips, *ipnet)
-				}
-			}
-		}
-
-		peer = wgtypes.PeerConfig{
-			PublicKey:                   pubkey,
-			PersistentKeepaliveInterval: &(keepalivedur),
-			ReplaceAllowedIPs:           true,
-			AllowedIPs:                  allowedips,
-		}
-
-		peers = append(peers, peer)
-	}
-	if serverNode.IsIngressGateway == "yes" {
-		extPeers, err := GetServerExtPeers(serverNode)
-		if err == nil {
-			peers = append(peers, extPeers...)
-		} else {
-			logger.Log(1, "ERROR RETRIEVING EXTERNAL PEERS ON SERVER:", err.Error())
-		}
-		extPeers = nil
-	}
-	return peers, hasGateway, gateways, err
-}
-
-// GetServerExtPeers - gets the extpeers for a client
-func GetServerExtPeers(serverNode *models.Node) ([]wgtypes.PeerConfig, error) {
-	var peers []wgtypes.PeerConfig
-	var extPeers []models.Node
-	var err error
-	var tempPeers []models.ExtPeersResponse
-
-	tempPeers, err = GetExtPeersList(serverNode)
-	if err != nil {
-		return nil, err
+		hasGateways = len(gateways) > 0
 	}
+	// end temporary code
 
-	for i := 0; i < len(tempPeers); i++ {
-		extPeers = append(extPeers, models.Node{
-			Address:             tempPeers[i].Address,
-			Address6:            tempPeers[i].Address6,
-			Endpoint:            tempPeers[i].Endpoint,
-			PublicKey:           tempPeers[i].PublicKey,
-			PersistentKeepalive: tempPeers[i].KeepAlive,
-			ListenPort:          tempPeers[i].ListenPort,
-			LocalAddress:        tempPeers[i].LocalAddress,
-		})
-	}
-	for _, extPeer := range extPeers {
-		pubkey, err := wgtypes.ParseKey(extPeer.PublicKey)
-		if err != nil {
-			return peers, err
-		}
-
-		if serverNode.PublicKey == extPeer.PublicKey {
-			continue
-		}
-		var allowedips = []net.IPNet{}
-
-		var peer wgtypes.PeerConfig
-		if extPeer.Address != "" {
-			newAddr := net.IPNet{
-				IP:   net.ParseIP(extPeer.Address),
-				Mask: net.CIDRMask(32, 32),
-			}
-			if &newAddr != nil {
-				allowedips = append(allowedips, newAddr)
-			}
-		}
-
-		if extPeer.Address6 != "" {
-			newAddr6 := net.IPNet{
-				IP:   net.ParseIP(extPeer.Address6),
-				Mask: net.CIDRMask(128, 128),
-			}
-			if &newAddr6 != nil {
-				allowedips = append(allowedips, newAddr6)
-			}
-		}
-		peer = wgtypes.PeerConfig{
-			PublicKey:         pubkey,
-			ReplaceAllowedIPs: true,
-			AllowedIPs:        allowedips,
-		}
-		peers = append(peers, peer)
-		allowedips = nil
-	}
-	tempPeers = nil
-	extPeers = nil
-	return peers, err
+	return update.Peers, hasGateways, gateways, nil
 }
 
 // == Private ==

+ 0 - 55
logic/util.go

@@ -115,61 +115,6 @@ func RandomString(length int) string {
 
 // == Private Methods ==
 
-// getNetworkEgressAndNodes - returns two slices, #1 is all nodes in the network, #2 is the egress nodes in the network
-func getNetworkEgressAndNodes(networkName string) ([]models.Node, []models.Node, error) {
-	var networkNodes, egressNetworkNodes []models.Node
-	collection, err := database.FetchRecords(database.NODES_TABLE_NAME)
-	if err != nil {
-		if database.IsEmptyRecord(err) {
-			return networkNodes, egressNetworkNodes, nil
-		}
-		logger.Log(2, err.Error())
-		return nil, nil, err
-	}
-
-	for _, value := range collection {
-		var node = models.Node{}
-		err := json.Unmarshal([]byte(value), &node)
-		if err != nil {
-			logger.Log(2, err.Error())
-			continue
-		}
-		if node.Network == networkName {
-			networkNodes = append(networkNodes, node)
-			if node.IsEgressGateway == "yes" {
-				egressNetworkNodes = append(egressNetworkNodes, node)
-			}
-		}
-	}
-	return networkNodes, egressNetworkNodes, nil
-}
-
-func setPeerInfo(node *models.Node) models.Node {
-	var peer models.Node
-	peer.RelayAddrs = node.RelayAddrs
-	peer.IsRelay = node.IsRelay
-	peer.IsServer = node.IsServer
-	peer.IsRelayed = node.IsRelayed
-	peer.PublicKey = node.PublicKey
-	peer.Endpoint = node.Endpoint
-	peer.Name = node.Name
-	peer.Network = node.Network
-	peer.LocalAddress = node.LocalAddress
-	peer.LocalListenPort = node.LocalListenPort
-	peer.ListenPort = node.ListenPort
-	peer.AllowedIPs = node.AllowedIPs
-	peer.UDPHolePunch = node.UDPHolePunch
-	peer.Address = node.Address
-	peer.Address6 = node.Address6
-	peer.IsHub = node.IsHub
-	peer.EgressGatewayRanges = node.EgressGatewayRanges
-	peer.IsEgressGateway = node.IsEgressGateway
-	peer.IngressGatewayRange = node.IngressGatewayRange
-	peer.IsIngressGateway = node.IsIngressGateway
-	peer.IsPending = node.IsPending
-	return peer
-}
-
 func setIPForwardingLinux() error {
 	out, err := ncutils.RunCmd("sysctl net.ipv4.ip_forward", true)
 	if err != nil {

+ 106 - 0
logic/zombie.go

@@ -0,0 +1,106 @@
+package logic
+
+import (
+	"context"
+	"time"
+
+	"github.com/gravitl/netmaker/logger"
+	"github.com/gravitl/netmaker/models"
+)
+
+const (
+	// ZOMBIE_TIMEOUT - timeout in seconds for checking zombie status
+	ZOMBIE_TIMEOUT = 60
+	// ZOMBIE_DELETE_TIME - timeout in minutes for zombie node deletion
+	ZOMBIE_DELETE_TIME = 10
+)
+
+var (
+	zombies      []string
+	removeZombie chan string = make(chan (string))
+	newZombie    chan string = make(chan (string))
+)
+
+// CheckZombies - checks if new node has same macaddress as existing node
+// if so, existing node is added to zombie node quarantine list
+func CheckZombies(newnode *models.Node) {
+	nodes, err := GetNetworkNodes(newnode.Network)
+	if err != nil {
+		logger.Log(1, "Failed to retrieve network nodes", newnode.Network, err.Error())
+		return
+	}
+	for _, node := range nodes {
+		if node.MacAddress == newnode.MacAddress {
+			newZombie <- node.ID
+		}
+	}
+}
+
+// ManageZombies - goroutine which adds/removes/deletes nodes from the zombie node quarantine list
+func ManageZombies(ctx context.Context) {
+	for {
+		select {
+		case <-ctx.Done():
+			return
+		case id := <-newZombie:
+			logger.Log(1, "adding", id, "to zombie quaratine list")
+			zombies = append(zombies, id)
+		case id := <-removeZombie:
+			found := false
+			for i, zombie := range zombies {
+				if zombie == id {
+					logger.Log(1, "removing zombie from quaratine list", zombie)
+					zombies = append(zombies[:i], zombies[i+1:]...)
+					found = true
+				}
+			}
+			if !found {
+				logger.Log(3, "no zombies found")
+			}
+		case <-time.After(time.Second * ZOMBIE_TIMEOUT):
+			for i, zombie := range zombies {
+				node, err := GetNodeByID(zombie)
+				if err != nil {
+					logger.Log(1, "error retrieving zombie node", zombie, err.Error())
+					continue
+				}
+				if time.Since(time.Unix(node.LastCheckIn, 0)) > time.Minute*ZOMBIE_DELETE_TIME {
+					if err := DeleteNodeByID(&node, true); err != nil {
+						logger.Log(1, "error deleting zombie node", zombie, err.Error())
+						continue
+					}
+					logger.Log(1, "deleting zombie node", node.Name)
+					zombies = append(zombies[:i], zombies[i+1:]...)
+				}
+			}
+		}
+	}
+}
+
+// InitializeZombies - populates the zombie quarantine list (should be called from initialization)
+func InitalizeZombies() {
+	nodes, err := GetAllNodes()
+	if err != nil {
+		logger.Log(1, "failed to retrieve nodes", err.Error())
+		return
+	}
+	for _, node := range nodes {
+		othernodes, err := GetNetworkNodes(node.Network)
+		if err != nil {
+			logger.Log(1, "failled to retrieve nodes for network", node.Network, err.Error())
+			continue
+		}
+		for _, othernode := range othernodes {
+			if node.ID == othernode.ID {
+				continue
+			}
+			if node.MacAddress == othernode.MacAddress {
+				if node.LastCheckIn > othernode.LastCheckIn {
+					zombies = append(zombies, othernode.ID)
+				} else {
+					zombies = append(zombies, node.ID)
+				}
+			}
+		}
+	}
+}

+ 2 - 0
main.go

@@ -127,6 +127,7 @@ func initialize() { // Client Mode Prereq Check
 			logger.Log(0, "error occurred when notifying nodes of startup", err.Error())
 		}
 	}
+	logic.InitalizeZombies()
 }
 
 func startControllers() {
@@ -169,6 +170,7 @@ func runMessageQueue(wg *sync.WaitGroup) {
 	var client = mq.SetupMQTT(false) // Set up the subscription listener
 	ctx, cancel := context.WithCancel(context.Background())
 	go mq.Keepalive(ctx)
+	go logic.ManageZombies(ctx)
 	quit := make(chan os.Signal, 1)
 	signal.Notify(quit, syscall.SIGTERM, os.Interrupt)
 	<-quit

+ 1 - 0
models/node.go

@@ -396,6 +396,7 @@ func (newNode *Node) Fill(currentNode *Node) {
 	if newNode.Server == "" {
 		newNode.Server = currentNode.Server
 	}
+	newNode.TrafficKeys = currentNode.TrafficKeys
 }
 
 // StringWithCharset - returns random string inside defined charset

+ 1 - 1
netclient/functions/join.go

@@ -192,7 +192,7 @@ func JoinNetwork(cfg *config.ClientConfig, privateKey string) error {
 		return err
 	}
 	if cfg.Server.Server == "" {
-		return errors.New("did not recieve broker address from registration")
+		return errors.New("did not receive broker address from registration")
 	}
 	// update server with latest data
 	if err := PublishNodeUpdate(cfg); err != nil {

+ 2 - 2
netclient/functions/mqhandlers.go

@@ -244,7 +244,7 @@ func setHostDNS(dns, iface string, windows bool) error {
 	if err != nil {
 		return err
 	}
-	profile.Name = iface
+	profile.Name = strings.ToLower(iface)
 	profile.Status = types.Enabled
 	if err := hosts.ReplaceProfile(profile); err != nil {
 		return err
@@ -264,7 +264,7 @@ func removeHostDNS(iface string, windows bool) error {
 	if err != nil {
 		return err
 	}
-	if err := hosts.RemoveProfile(iface); err != nil {
+	if err := hosts.RemoveProfile(strings.ToLower(iface)); err != nil {
 		if err == types.ErrUnknownProfile {
 			return nil
 		}

+ 12 - 27
netclient/local/routes.go

@@ -11,41 +11,26 @@ import (
 // TODO handle ipv6 in future
 
 // SetPeerRoutes - sets/removes ip routes for each peer on a network
-func SetPeerRoutes(iface string, oldPeers map[string][]net.IPNet, newPeers []wgtypes.PeerConfig) {
+func SetPeerRoutes(iface string, oldPeers map[string]bool, 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, allowedIP.IP.String()); err != nil {
-						logger.Log(1, err.Error())
-					}
-				}
-			}
-			for _, allowedIP := range currPeerAllowedIPs { // compare old ones (if any) to new ones
-				if !ncutils.IPNetSliceContains(peer.AllowedIPs, allowedIP) {
-					if err := deleteRoute(iface, &allowedIP, allowedIP.IP.String()); err != nil {
-						logger.Log(1, err.Error())
-					}
-				}
-			}
-			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, allowedIP.String()); err != nil {
+		for _, allowedIP := range peer.AllowedIPs {
+			if !oldPeers[allowedIP.String()] {
+				if err := setRoute(iface, &allowedIP, allowedIP.IP.String()); err != nil {
 					logger.Log(1, err.Error())
 				}
+			} else {
+				delete(oldPeers, allowedIP.String())
 			}
 		}
 	}
-
 	// traverse through all remaining existing peers
-	for _, allowedIPs := range oldPeers {
-		for _, allowedIP := range allowedIPs {
-			deleteRoute(iface, &allowedIP, allowedIP.IP.String())
+	for i, _ := range oldPeers {
+		ip, err := ncutils.GetIPNetFromString(i)
+		if err != nil {
+			logger.Log(1, err.Error())
+		} else {
+			deleteRoute(iface, &ip, ip.IP.String())
 		}
 	}
 }

+ 26 - 0
netclient/ncutils/netclientutils.go

@@ -19,6 +19,7 @@ import (
 	"strings"
 	"time"
 
+	"github.com/c-robinson/iplib"
 	"github.com/gravitl/netmaker/logger"
 	"github.com/gravitl/netmaker/models"
 	"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
@@ -593,3 +594,28 @@ func MakeRandomString(n int) string {
 	}
 	return string(result)
 }
+
+func GetIPNetFromString(ip string) (net.IPNet, error) {
+	var ipnet *net.IPNet
+	var err error
+	// parsing as a CIDR first. If valid CIDR, append
+	if _, cidr, err := net.ParseCIDR(ip); err == nil {
+		ipnet = cidr
+	} else { // parsing as an IP second. If valid IP, check if ipv4 or ipv6, then append
+		if iplib.Version(net.ParseIP(ip)) == 4 {
+			ipnet = &net.IPNet{
+				IP:   net.ParseIP(ip),
+				Mask: net.CIDRMask(32, 32),
+			}
+		} else if iplib.Version(net.ParseIP(ip)) == 6 {
+			ipnet = &net.IPNet{
+				IP:   net.ParseIP(ip),
+				Mask: net.CIDRMask(128, 128),
+			}
+		}
+	}
+	if ipnet == nil {
+		err = errors.New(ip + " is not a valid ip or cidr")
+	}
+	return *ipnet, err
+}

+ 1 - 1
netclient/netclient.exe.manifest.xml

@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
 <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
     <assemblyIdentity
-            version="0.14.2.0"
+            version="0.14.3.0"
             processorArchitecture="*"
             name="netclient.exe"
             type="win32"

+ 3 - 3
netclient/versioninfo.json

@@ -3,13 +3,13 @@
         "FileVersion": {
             "Major": 0,
             "Minor": 14,
-            "Patch": 2,
+            "Patch": 3,
             "Build": 0
         },
         "ProductVersion": {
             "Major": 0,
             "Minor": 14,
-            "Patch": 2,
+            "Patch": 3,
             "Build": 0
         },
         "FileFlagsMask": "3f",
@@ -29,7 +29,7 @@
         "OriginalFilename": "",
         "PrivateBuild": "",
         "ProductName": "Netclient",
-        "ProductVersion": "v0.14.2.0",
+        "ProductVersion": "v0.14.3.0",
         "SpecialBuild": ""
     },
     "VarFileInfo": {

+ 5 - 2
netclient/wireguard/common.go

@@ -28,7 +28,8 @@ const (
 func SetPeers(iface string, node *models.Node, peers []wgtypes.PeerConfig) error {
 	var devicePeers []wgtypes.Peer
 	var keepalive = node.PersistentKeepalive
-	var oldPeerAllowedIps = make(map[string][]net.IPNet, len(peers))
+	var oldPeerAllowedIps = make(map[string]bool, len(peers))
+
 	var err error
 	devicePeers, err = GetDevicePeers(iface)
 	if err != nil {
@@ -106,7 +107,9 @@ func SetPeers(iface string, node *models.Node, peers []wgtypes.PeerConfig) error
 						log.Println(output, "error removing peer", currentPeer.PublicKey.String())
 					}
 				}
-				oldPeerAllowedIps[currentPeer.PublicKey.String()] = currentPeer.AllowedIPs
+				for _, ip := range currentPeer.AllowedIPs {
+					oldPeerAllowedIps[ip.String()] = true
+				}
 			}
 		}
 	}