Browse Source

Merge pull request #677 from gravitl/feature_v0.10.0_route_consolidate

Feature v0.10.0 route consolidate
dcarns 3 years ago
parent
commit
c87968f97b

+ 1 - 1
netclient/functions/daemon.go

@@ -354,7 +354,7 @@ func UpdatePeers(client mqtt.Client, msg mqtt.Message) {
 			return
 			return
 		}
 		}
 		//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.Address, 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

+ 21 - 5
netclient/local/routes.go

@@ -7,8 +7,10 @@ import (
 	"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
 	"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
 )
 )
 
 
+// TODO handle ipv6 in future
+
 // SetPeerRoutes - sets/removes ip routes for each peer on a network
 // 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, currentNodeAddr string, oldPeers map[string][]net.IPNet, newPeers []wgtypes.PeerConfig) {
 	// traverse through all recieved peers
 	// traverse through all recieved peers
 	for _, peer := range newPeers {
 	for _, peer := range newPeers {
 		// if pubkey found in existing peers, check against existing peer
 		// if pubkey found in existing peers, check against existing peer
@@ -17,14 +19,14 @@ func SetPeerRoutes(iface string, oldPeers map[string][]net.IPNet, newPeers []wgt
 			// traverse IPs, check to see if old peer contains each IP
 			// traverse IPs, check to see if old peer contains each IP
 			for _, allowedIP := range peer.AllowedIPs { // compare new ones (if any) to old ones
 			for _, allowedIP := range peer.AllowedIPs { // compare new ones (if any) to old ones
 				if !ncutils.IPNetSliceContains(currPeerAllowedIPs, allowedIP) {
 				if !ncutils.IPNetSliceContains(currPeerAllowedIPs, allowedIP) {
-					if err := setRoute(iface, &allowedIP); err != nil {
+					if err := setRoute(iface, &allowedIP, allowedIP.IP.String()); err != nil {
 						ncutils.PrintLog(err.Error(), 1)
 						ncutils.PrintLog(err.Error(), 1)
 					}
 					}
 				}
 				}
 			}
 			}
 			for _, allowedIP := range currPeerAllowedIPs { // compare old ones (if any) to new ones
 			for _, allowedIP := range currPeerAllowedIPs { // compare old ones (if any) to new ones
 				if !ncutils.IPNetSliceContains(peer.AllowedIPs, allowedIP) {
 				if !ncutils.IPNetSliceContains(peer.AllowedIPs, allowedIP) {
-					if err := deleteRoute(iface, &allowedIP); err != nil {
+					if err := deleteRoute(iface, &allowedIP, allowedIP.IP.String()); err != nil {
 						ncutils.PrintLog(err.Error(), 1)
 						ncutils.PrintLog(err.Error(), 1)
 					}
 					}
 				}
 				}
@@ -32,7 +34,7 @@ func SetPeerRoutes(iface string, oldPeers map[string][]net.IPNet, newPeers []wgt
 			delete(oldPeers, peer.PublicKey.String()) // remove peer as it was found and processed
 			delete(oldPeers, peer.PublicKey.String()) // remove peer as it was found and processed
 		} else {
 		} else {
 			for _, allowedIP := range peer.AllowedIPs { // add all routes as peer doesn't exist
 			for _, allowedIP := range peer.AllowedIPs { // add all routes as peer doesn't exist
-				if err := setRoute(iface, &allowedIP); err != nil {
+				if err := setRoute(iface, &allowedIP, allowedIP.String()); err != nil {
 					ncutils.PrintLog(err.Error(), 1)
 					ncutils.PrintLog(err.Error(), 1)
 				}
 				}
 			}
 			}
@@ -42,7 +44,21 @@ func SetPeerRoutes(iface string, oldPeers map[string][]net.IPNet, newPeers []wgt
 	// traverse through all remaining existing peers
 	// traverse through all remaining existing peers
 	for _, allowedIPs := range oldPeers {
 	for _, allowedIPs := range oldPeers {
 		for _, allowedIP := range allowedIPs {
 		for _, allowedIP := range allowedIPs {
-			deleteRoute(iface, &allowedIP)
+			deleteRoute(iface, &allowedIP, allowedIP.IP.String())
 		}
 		}
 	}
 	}
 }
 }
+
+// SetCurrentPeerRoutes - sets all the current peers
+func SetCurrentPeerRoutes(iface, currentAddr string, peers []wgtypes.Peer) {
+	for _, peer := range peers {
+		for _, allowedIP := range peer.AllowedIPs {
+			setRoute(iface, &allowedIP, currentAddr)
+		}
+	}
+}
+
+// SetCIDRRoute - sets the CIDR route, used on join and restarts
+func SetCIDRRoute(iface, currentAddr string, cidr *net.IPNet) {
+	setCidr(iface, currentAddr, cidr)
+}

+ 37 - 0
netclient/local/routes_darwin.go

@@ -0,0 +1,37 @@
+package local
+
+import (
+	"net"
+	"strings"
+
+	"github.com/gravitl/netmaker/netclient/ncutils"
+)
+
+// route -n add -net 10.0.0.0/8 192.168.0.254
+// networksetup -setadditionalroutes Ethernet 192.168.1.0 255.255.255.0 10.0.0.2 persistent
+func setRoute(iface string, addr *net.IPNet, address string) error {
+	var err error
+	var out string
+	var inetx = "inet"
+	if strings.Contains(addr.IP.String(), ":") {
+		inetx = "inet6"
+	}
+	out, err = ncutils.RunCmd("route -n get -"+inetx+" "+addr.IP.String(), true)
+	if err != nil {
+		return err
+	}
+	if !(strings.Contains(out, iface)) {
+		_, err = ncutils.RunCmd("route -q -n add -"+inetx+" "+addr.String()+" -interface "+iface, true)
+	}
+	return err
+}
+
+func deleteRoute(iface string, addr *net.IPNet, address string) error {
+	var err error
+	_, err = ncutils.RunCmd("route -q -n delete "+addr.String(), true)
+	return err
+}
+
+func setCidr(iface, address string, addr *net.IPNet) {
+	ncutils.RunCmd("route -q -n add -net "+addr.String()+" "+address, true)
+}

+ 23 - 0
netclient/local/routes_freebsd.go

@@ -0,0 +1,23 @@
+package local
+
+import (
+	"net"
+
+	"github.com/gravitl/netmaker/netclient/ncutils"
+)
+
+func setRoute(iface string, addr *net.IPNet, address string) error {
+	var err error
+	_, _ = ncutils.RunCmd("route add -net "+addr.String()+" -interface "+iface, true)
+	return err
+}
+
+func deleteRoute(iface string, addr *net.IPNet, address string) error {
+	var err error
+	_, err = ncutils.RunCmd("route delete -net "+addr.String()+" -interface "+iface, true)
+	return err
+}
+
+func setCidr(iface, address string, addr *net.IPNet) {
+	ncutils.RunCmd("route add -net "+addr.String()+" -interface "+iface, true)
+}

+ 6 - 5
netclient/local/routes_linux.go

@@ -1,6 +1,3 @@
-//go:build linux
-// +build linux
-
 package local
 package local
 
 
 import (
 import (
@@ -12,14 +9,18 @@ import (
 	"github.com/gravitl/netmaker/netclient/ncutils"
 	"github.com/gravitl/netmaker/netclient/ncutils"
 )
 )
 
 
-func setRoute(iface string, addr *net.IPNet) error {
+func setRoute(iface string, addr *net.IPNet, address string) error {
 	var err error
 	var err error
 	_, err = ncutils.RunCmd(fmt.Sprintf("ip route add %s dev %s", addr.String(), iface), true)
 	_, err = ncutils.RunCmd(fmt.Sprintf("ip route add %s dev %s", addr.String(), iface), true)
 	return err
 	return err
 }
 }
 
 
-func deleteRoute(iface string, addr *net.IPNet) error {
+func deleteRoute(iface string, addr *net.IPNet, address string) error {
 	var err error
 	var err error
 	_, err = ncutils.RunCmd(fmt.Sprintf("ip route del %s dev %s", addr.String(), iface), true)
 	_, err = ncutils.RunCmd(fmt.Sprintf("ip route del %s dev %s", addr.String(), iface), true)
 	return err
 	return err
 }
 }
+
+func setCidr(iface, address string, addr *net.IPNet) {
+	ncutils.RunCmd("ip -4 route add "+addr.String()+" dev "+iface, false)
+}

+ 0 - 33
netclient/local/routes_other.go

@@ -1,33 +0,0 @@
-//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
-}

+ 28 - 0
netclient/local/routes_windows.go

@@ -0,0 +1,28 @@
+package local
+
+import (
+	"net"
+	"time"
+
+	"github.com/gravitl/netmaker/netclient/ncutils"
+)
+
+func setRoute(iface string, addr *net.IPNet, address string) error {
+	var err error
+	_, err = ncutils.RunCmd("route -p add "+addr.IP.String()+" mask "+addr.Mask.String()+" "+address, true)
+	time.Sleep(time.Second >> 2)
+	ncutils.RunCmd("route change "+addr.IP.String()+" mask "+addr.Mask.String()+" "+address, true)
+	return err
+}
+
+func deleteRoute(iface string, addr *net.IPNet, address string) error {
+	var err error
+	_, err = ncutils.RunCmd("route delete "+addr.IP.String()+" mask "+addr.Mask.String()+" "+address, true)
+	return err
+}
+
+func setCidr(iface, address string, addr *net.IPNet) {
+	ncutils.RunCmd("route -p add "+addr.IP.String()+" mask "+addr.Mask.String()+" "+address, true)
+	time.Sleep(time.Second >> 2)
+	ncutils.RunCmd("route change "+addr.IP.String()+" mask "+addr.Mask.String()+" "+address, true)
+}

+ 43 - 51
netclient/wireguard/common.go

@@ -1,7 +1,7 @@
 package wireguard
 package wireguard
 
 
 import (
 import (
-	"errors"
+	"fmt"
 	"log"
 	"log"
 	"net"
 	"net"
 	"runtime"
 	"runtime"
@@ -25,7 +25,7 @@ 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, currentNodeAddr 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 oldPeerAllowedIps = make(map[string][]net.IPNet, len(peers))
 	var err error
 	var err error
@@ -107,7 +107,7 @@ func SetPeers(iface string, keepalive int32, peers []wgtypes.PeerConfig) error {
 		err = SetMacPeerRoutes(iface)
 		err = SetMacPeerRoutes(iface)
 		return err
 		return err
 	} else if ncutils.IsLinux() {
 	} else if ncutils.IsLinux() {
-		local.SetPeerRoutes(iface, oldPeerAllowedIps, peers)
+		local.SetPeerRoutes(iface, currentNodeAddr, oldPeerAllowedIps, peers)
 	}
 	}
 
 
 	return nil
 	return nil
@@ -157,60 +157,52 @@ func InitWireguard(node *models.Node, privkey string, peers []wgtypes.PeerConfig
 
 
 	// spin up userspace / windows interface + apply the conf file
 	// spin up userspace / windows interface + apply the conf file
 	confPath := ncutils.GetNetclientPathSpecific() + ifacename + ".conf"
 	confPath := ncutils.GetNetclientPathSpecific() + ifacename + ".conf"
-	var deviceiface string
-	if ncutils.IsMac() {
+	var deviceiface = ifacename
+	if ncutils.IsMac() { // if node is Mac (Darwin) get the tunnel name first
 		deviceiface, err = local.GetMacIface(node.Address)
 		deviceiface, err = local.GetMacIface(node.Address)
 		if err != nil || deviceiface == "" {
 		if err != nil || deviceiface == "" {
 			deviceiface = ifacename
 			deviceiface = ifacename
 		}
 		}
 	}
 	}
-	if syncconf {
+	// ensure you clear any existing interface first
+	d, _ := wgclient.Device(deviceiface)
+	for d != nil && d.Name == deviceiface {
+		RemoveConf(ifacename, false) // remove interface first
+		time.Sleep(time.Second >> 2)
+		d, _ = wgclient.Device(deviceiface)
+	}
+
+	ApplyConf(node, deviceiface, confPath) // Apply initially
+
+	ncutils.PrintLog("waiting for interface...", 1) // ensure interface is created
+	output, _ := ncutils.RunCmd("wg", false)
+	starttime := time.Now()
+	ifaceReady := false
+	for !strings.Contains(output, ifacename) && !(time.Now().After(starttime.Add(time.Second << 4))) {
+		output, _ = ncutils.RunCmd("wg", false)
+		err = ApplyConf(node, ifacename, confPath)
+		time.Sleep(time.Second)
+		ifaceReady = !strings.Contains(output, ifacename)
+	}
+	newDevice, devErr := wgclient.Device(deviceiface)
+	if !ifaceReady || devErr != nil {
+		return fmt.Errorf("could not reliably create interface, please check wg installation and retry")
+	}
+	ncutils.PrintLog("interface ready - netclient engage", 1)
+
+	if syncconf { // should never be called really.
 		err = SyncWGQuickConf(ifacename, confPath)
 		err = SyncWGQuickConf(ifacename, confPath)
-	} else {
-		if !ncutils.IsMac() {
-			d, _ := wgclient.Device(deviceiface)
-			for d != nil && d.Name == deviceiface {
-				RemoveConf(ifacename, false) // remove interface first
-				time.Sleep(time.Second >> 2)
-				d, _ = wgclient.Device(deviceiface)
-			}
-		}
-		if !ncutils.IsWindows() {
-			err = ApplyConf(*node, ifacename, confPath)
-			if err != nil {
-				ncutils.PrintLog("failed to create wireguard interface", 1)
-				return err
-			}
+	}
+	currentPeers := newDevice.Peers
+	if len(currentPeers) == 0 { // if no peers currently, apply cidr
+		_, cidr, cidrErr := net.ParseCIDR(modcfg.NetworkSettings.AddressRange)
+		if cidrErr == nil {
+			local.SetCIDRRoute(ifacename, node.Address, cidr)
 		} else {
 		} else {
-			var output string
-			starttime := time.Now()
-			RemoveConf(ifacename, false)
-			time.Sleep(time.Second >> 2)
-			ncutils.PrintLog("waiting for interface...", 1)
-			for !strings.Contains(output, ifacename) && !(time.Now().After(starttime.Add(time.Duration(10) * time.Second))) {
-				output, _ = ncutils.RunCmd("wg", false)
-				err = ApplyConf(*node, ifacename, confPath)
-				time.Sleep(time.Second)
-			}
-			if !strings.Contains(output, ifacename) {
-				return errors.New("could not create wg interface for " + ifacename)
-			}
-			ip, mask, err := ncutils.GetNetworkIPMask(nodecfg.NetworkSettings.AddressRange)
-			if err != nil {
-				log.Println(err.Error())
-				return err
-			}
-			ncutils.RunCmd("route add "+ip+" mask "+mask+" "+node.Address, true)
-			time.Sleep(time.Second >> 2)
-			ncutils.RunCmd("route change "+ip+" mask "+mask+" "+node.Address, true)
+			ncutils.PrintLog("could not set cidr route properly: "+cidrErr.Error(), 1)
 		}
 		}
-	}
-
-	//extra network route setting
-	if ncutils.IsFreeBSD() {
-		_, _ = ncutils.RunCmd("route add -net "+nodecfg.NetworkSettings.AddressRange+" -interface "+ifacename, true)
-	} else if ncutils.IsLinux() {
-		_, _ = ncutils.RunCmd("ip -4 route add "+nodecfg.NetworkSettings.AddressRange+" dev "+ifacename, false)
+	} else { // if peers, apply each
+		local.SetCurrentPeerRoutes(ifacename, node.Address, currentPeers[:])
 	}
 	}
 
 
 	return err
 	return err
@@ -243,7 +235,7 @@ func SetWGConfig(network string, peerupdate bool) error {
 				return err
 				return err
 			}
 			}
 		}
 		}
-		err = SetPeers(iface, nodecfg.PersistentKeepalive, peers)
+		err = SetPeers(iface, nodecfg.Address, nodecfg.PersistentKeepalive, peers)
 	} else if peerupdate {
 	} else if peerupdate {
 		err = InitWireguard(&nodecfg, privkey, peers, hasGateway, gateways, true)
 		err = InitWireguard(&nodecfg, privkey, peers, hasGateway, gateways, true)
 	} else {
 	} else {
@@ -272,7 +264,7 @@ func RemoveConf(iface string, printlog bool) error {
 }
 }
 
 
 // ApplyConf - applys a conf on disk to WireGuard interface
 // ApplyConf - applys a conf on disk to WireGuard interface
-func ApplyConf(node models.Node, ifacename string, confPath string) error {
+func ApplyConf(node *models.Node, ifacename string, confPath string) error {
 	os := runtime.GOOS
 	os := runtime.GOOS
 	var err error
 	var err error
 	switch os {
 	switch os {

+ 2 - 2
netclient/wireguard/mac.go

@@ -13,7 +13,7 @@ import (
 )
 )
 
 
 // WgQuickDownMac - bring down mac interface, remove routes, and run post-down commands
 // WgQuickDownMac - bring down mac interface, remove routes, and run post-down commands
-func WgQuickDownMac(node models.Node, iface string) error {
+func WgQuickDownMac(node *models.Node, iface string) error {
 	if err := RemoveConfMac(iface); err != nil {
 	if err := RemoveConfMac(iface); err != nil {
 		return err
 		return err
 	}
 	}
@@ -34,7 +34,7 @@ func RemoveConfMac(iface string) error {
 }
 }
 
 
 // WgQuickUpMac - bring up mac interface and set routes
 // WgQuickUpMac - bring up mac interface and set routes
-func WgQuickUpMac(node models.Node, iface string, confPath string) error {
+func WgQuickUpMac(node *models.Node, iface string, confPath string) error {
 	var err error
 	var err error
 	var realIface string
 	var realIface string
 	realIface, err = getRealIface(iface)
 	realIface, err = getRealIface(iface)

+ 1 - 1
netclient/wireguard/unix.go

@@ -73,7 +73,7 @@ func ApplyWGQuickConf(confPath string, ifacename string) error {
 }
 }
 
 
 // ApplyMacOSConf - applies system commands similar to wg-quick using golang for MacOS
 // ApplyMacOSConf - applies system commands similar to wg-quick using golang for MacOS
-func ApplyMacOSConf(node models.Node, ifacename string, confPath string) error {
+func ApplyMacOSConf(node *models.Node, ifacename string, confPath string) error {
 	var err error
 	var err error
 	_ = WgQuickDownMac(node, ifacename)
 	_ = WgQuickDownMac(node, ifacename)
 	err = WgQuickUpMac(node, ifacename, confPath)
 	err = WgQuickUpMac(node, ifacename, confPath)