Browse Source

Merge pull request #1468 from gravitl/feature_v0.14.9_node_disconnect

Feature v0.14.9 node disconnect
Alex Feiszli 2 years ago
parent
commit
eec81e1849

+ 1 - 0
logic/nodes.go

@@ -433,6 +433,7 @@ func SetNodeDefaults(node *models.Node) {
 	node.SetDefaultIsDocker()
 	node.SetDefaultIsK8S()
 	node.SetDefaultIsHub()
+	node.SetDefaultConnected()
 }
 
 // GetRecordKey - get record key

+ 1 - 1
logic/server.go

@@ -154,7 +154,7 @@ func ServerJoin(networkSettings *models.Network) (models.Node, error) {
 		return returnNode, err
 	}
 
-	err = wireguard.InitWireguard(node, privateKey, peers.Peers, false)
+	err = wireguard.InitWireguard(node, privateKey, peers.Peers)
 	if err != nil {
 		return returnNode, err
 	}

+ 2 - 1
logic/wireguard.go

@@ -58,6 +58,7 @@ func IfaceDelta(currentNode *models.Node, newNode *models.Node) bool {
 		newNode.MTU != currentNode.MTU ||
 		newNode.PersistentKeepalive != currentNode.PersistentKeepalive ||
 		newNode.DNSOn != currentNode.DNSOn ||
+		newNode.Connected != currentNode.Connected ||
 		len(newNode.AllowedIPs) != len(currentNode.AllowedIPs) {
 		return true
 	}
@@ -139,7 +140,7 @@ func setWGConfig(node *models.Node, peerupdate bool) error {
 		}
 		logger.Log(2, "updated peers on server", node.Name)
 	} else {
-		err = wireguard.InitWireguard(node, privkey, peers.Peers, false)
+		err = wireguard.InitWireguard(node, privkey, peers.Peers)
 		logger.Log(3, "finished setting wg config on server", node.Name)
 	}
 	return err

+ 15 - 0
models/node.go

@@ -93,6 +93,7 @@ type Node struct {
 	TrafficKeys     TrafficKeys `json:"traffickeys" bson:"traffickeys" yaml:"traffickeys"`
 	FirewallInUse   string      `json:"firewallinuse" bson:"firewallinuse" yaml:"firewallinuse"`
 	InternetGateway string      `json:"internetgateway" bson:"internetgateway" yaml:"internetgateway"`
+	Connected       string      `json:"connected" bson:"connected" yaml:"connected" validate:"checkyesorno"`
 }
 
 // NodesArray - used for node sorting
@@ -121,6 +122,16 @@ func (node *Node) PrimaryAddress() string {
 	return node.Address6
 }
 
+// Node.SetDefaultConnected
+func (node *Node) SetDefaultConnected() {
+	if node.Connected == "" {
+		node.Connected = "yes"
+	}
+	if node.IsServer == "yes" {
+		node.Connected = "yes"
+	}
+}
+
 // Node.SetDefaultMTU - sets default MTU of a node
 func (node *Node) SetDefaultMTU() {
 	if node.MTU == 0 {
@@ -382,6 +393,7 @@ func (newNode *Node) Fill(currentNode *Node) { // TODO add new field for nftable
 	}
 	if newNode.IsServer == "yes" {
 		newNode.IsStatic = "yes"
+		newNode.Connected = "yes"
 	}
 	if newNode.MTU == 0 {
 		newNode.MTU = currentNode.MTU
@@ -413,6 +425,9 @@ func (newNode *Node) Fill(currentNode *Node) { // TODO add new field for nftable
 	if newNode.Server == "" {
 		newNode.Server = currentNode.Server
 	}
+	if newNode.Connected == "" {
+		newNode.Connected = currentNode.Connected
+	}
 	newNode.TrafficKeys = currentNode.TrafficKeys
 }
 

+ 26 - 0
netclient/cli_options/cmds.go

@@ -104,6 +104,32 @@ func GetCommands(cliFlags []cli.Flag) []*cli.Command {
 				return command.Install()
 			},
 		},
+		{
+			Name:  "connect",
+			Usage: "connect netclient to a given network if disconnected",
+			Flags: cliFlags,
+			Action: func(c *cli.Context) error {
+				parseVerbosity(c)
+				cfg, _, err := config.GetCLIConfig(c)
+				if err != nil {
+					return err
+				}
+				return command.Connect(cfg)
+			},
+		},
+		{
+			Name:  "disconnect",
+			Usage: "disconnect netclient from a given network if connected",
+			Flags: cliFlags,
+			Action: func(c *cli.Context) error {
+				parseVerbosity(c)
+				cfg, _, err := config.GetCLIConfig(c)
+				if err != nil {
+					return err
+				}
+				return command.Disconnect(cfg)
+			},
+		},
 	}
 }
 

+ 25 - 0
netclient/command/commands.go

@@ -3,6 +3,7 @@ package command
 import (
 	"crypto/ed25519"
 	"crypto/rand"
+	"fmt"
 	"strings"
 
 	"github.com/gravitl/netmaker/logger"
@@ -142,3 +143,27 @@ func Daemon() error {
 func Install() error {
 	return functions.Install()
 }
+
+// Connect - re-instates a connection of a node
+func Connect(cfg config.ClientConfig) error {
+	networkName := cfg.Network
+	if networkName == "" {
+		networkName = cfg.Node.Network
+	}
+	if networkName == "all" {
+		return fmt.Errorf("no network specified")
+	}
+	return functions.Connect(networkName)
+}
+
+// Disconnect - disconnects a connection of a node
+func Disconnect(cfg config.ClientConfig) error {
+	networkName := cfg.Network
+	if networkName == "" {
+		networkName = cfg.Node.Network
+	}
+	if networkName == "all" {
+		return fmt.Errorf("no network specified")
+	}
+	return functions.Disconnect(networkName)
+}

+ 3 - 0
netclient/functions/clientconfig.go

@@ -43,6 +43,9 @@ func UpdateClientConfig() {
 			if err := PublishNodeUpdate(&cfg); err != nil {
 				logger.Log(0, "error publishing node update during schema change", err.Error())
 			}
+			if err := config.ModNodeConfig(&cfg.Node); err != nil {
+				logger.Log(0, "error saving local config for node,", cfg.Node.Name, ", on network,", cfg.Node.Network)
+			}
 		}
 	}
 	logger.Log(0, "finished updates")

+ 54 - 0
netclient/functions/connection.go

@@ -0,0 +1,54 @@
+package functions
+
+import (
+	"fmt"
+
+	"github.com/gravitl/netmaker/logger"
+	"github.com/gravitl/netmaker/netclient/config"
+	"github.com/gravitl/netmaker/netclient/ncutils"
+	"github.com/gravitl/netmaker/netclient/wireguard"
+)
+
+// Connect - will attempt to connect a node on given network
+func Connect(network string) error {
+	cfg, err := config.ReadConfig(network)
+	if err != nil {
+		return err
+	}
+	if cfg.Node.Connected == "yes" {
+		return fmt.Errorf("node already connected")
+	}
+	cfg.Node.Connected = "yes"
+	filePath := ncutils.GetNetclientPathSpecific() + cfg.Node.Interface + ".conf"
+
+	if err = wireguard.ApplyConf(&cfg.Node, cfg.Node.Interface, filePath); err != nil {
+		return err
+	}
+	if err := PublishNodeUpdate(cfg); err != nil {
+		logger.Log(0, "network:", cfg.Node.Network, "could not publish connection change, it will likely get reverted")
+	}
+
+	return config.ModNodeConfig(&cfg.Node)
+}
+
+// Disconnect - attempts to disconnect a node on given network
+func Disconnect(network string) error {
+	cfg, err := config.ReadConfig(network)
+	if err != nil {
+		return err
+	}
+	if cfg.Node.Connected == "no" {
+		return fmt.Errorf("node already disconnected")
+	}
+	cfg.Node.Connected = "no"
+	filePath := ncutils.GetNetclientPathSpecific() + cfg.Node.Interface + ".conf"
+
+	if err = wireguard.ApplyConf(&cfg.Node, cfg.Node.Interface, filePath); err != nil {
+		return err
+	}
+	if err := PublishNodeUpdate(cfg); err != nil {
+		logger.Log(0, "network:", cfg.Node.Network, "could not publish connection change, it will likely get reverted")
+	}
+
+	return config.ModNodeConfig(&cfg.Node)
+}

+ 1 - 1
netclient/functions/join.go

@@ -211,7 +211,7 @@ func JoinNetwork(cfg *config.ClientConfig, privateKey string) error {
 	}
 
 	logger.Log(0, "starting wireguard")
-	err = wireguard.InitWireguard(&node, privateKey, nodeGET.Peers[:], false)
+	err = wireguard.InitWireguard(&node, privateKey, nodeGET.Peers[:])
 	if err != nil {
 		return err
 	}

+ 1 - 0
netclient/functions/upgrades/upgrades.go

@@ -4,6 +4,7 @@ func init() {
 	addUpgrades([]UpgradeInfo{
 		upgrade0145,
 		upgrade0146,
+		upgrade0148,
 	})
 }
 

+ 22 - 0
netclient/functions/upgrades/v0-14-8.go

@@ -0,0 +1,22 @@
+package upgrades
+
+import (
+	"github.com/gravitl/netmaker/netclient/config"
+)
+
+var upgrade0148 = UpgradeInfo{
+	RequiredVersions: []string{
+		"v0.14.5",
+		"v0.14.6",
+		"v0.14.7",
+	},
+	NewVersion: "v0.14.8",
+	OP:         update0148,
+}
+
+func update0148(cfg *config.ClientConfig) {
+	// set connect default if not present 14.X -> 14.8
+	if cfg.Node.Connected == "" {
+		cfg.Node.SetDefaultConnected()
+	}
+}

+ 1 - 0
netclient/ncutils/iface.go

@@ -22,6 +22,7 @@ func IfaceDelta(currentNode *models.Node, newNode *models.Node) bool {
 		newNode.IsPending != currentNode.IsPending ||
 		newNode.PersistentKeepalive != currentNode.PersistentKeepalive ||
 		newNode.DNSOn != currentNode.DNSOn ||
+		newNode.Connected != currentNode.Connected ||
 		len(newNode.AllowedIPs) != len(currentNode.AllowedIPs) {
 		return true
 	}

+ 8 - 13
netclient/wireguard/common.go

@@ -123,7 +123,7 @@ func SetPeers(iface string, node *models.Node, peers []wgtypes.PeerConfig) error
 }
 
 // Initializes a WireGuard interface
-func InitWireguard(node *models.Node, privkey string, peers []wgtypes.PeerConfig, syncconf bool) error {
+func InitWireguard(node *models.Node, privkey string, peers []wgtypes.PeerConfig) error {
 
 	key, err := wgtypes.ParseKey(privkey)
 	if err != nil {
@@ -191,10 +191,7 @@ func InitWireguard(node *models.Node, privkey string, peers []wgtypes.PeerConfig
 		}
 	}
 	logger.Log(1, "interface ready - netclient.. ENGAGE")
-	if syncconf { // should never be called really.
-		fmt.Println("why here")
-		err = SyncWGQuickConf(ifacename, confPath)
-	}
+
 	if !ncutils.HasWgQuick() && ncutils.IsLinux() {
 		err = SetPeers(ifacename, node, peers)
 		if err != nil {
@@ -248,12 +245,9 @@ func SetWGConfig(network string, peerupdate bool, peers []wgtypes.PeerConfig) er
 			}
 		}
 		err = SetPeers(iface, &cfg.Node, peers)
-	} else if peerupdate {
-		err = InitWireguard(&cfg.Node, privkey, peers, true)
 	} else {
-		err = InitWireguard(&cfg.Node, privkey, peers, false)
+		err = InitWireguard(&cfg.Node, privkey, peers)
 	}
-
 	return err
 }
 
@@ -284,16 +278,17 @@ func ApplyConf(node *models.Node, ifacename string, confPath string) error {
 	if ncutils.IsLinux() && !ncutils.HasWgQuick() {
 		os = "nowgquick"
 	}
+	var isConnected = node.Connected != "no"
 	var err error
 	switch os {
 	case "windows":
-		ApplyWindowsConf(confPath)
+		ApplyWindowsConf(confPath, isConnected)
 	case "darwin":
-		ApplyMacOSConf(node, ifacename, confPath)
+		ApplyMacOSConf(node, ifacename, confPath, isConnected)
 	case "nowgquick":
-		ApplyWithoutWGQuick(node, ifacename, confPath)
+		ApplyWithoutWGQuick(node, ifacename, confPath, isConnected)
 	default:
-		ApplyWGQuickConf(confPath, ifacename)
+		ApplyWGQuickConf(confPath, ifacename, isConnected)
 	}
 
 	var nodeCfg config.ClientConfig

+ 15 - 3
netclient/wireguard/noquick.go

@@ -2,6 +2,7 @@ package wireguard
 
 import (
 	"errors"
+	"fmt"
 	"os"
 	"os/exec"
 	"strconv"
@@ -15,8 +16,10 @@ import (
 	"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
 )
 
+const disconnect_error = "node disconnected"
+
 // ApplyWithoutWGQuick - Function for running the equivalent of "wg-quick up" for linux if wg-quick is missing
-func ApplyWithoutWGQuick(node *models.Node, ifacename string, confPath string) error {
+func ApplyWithoutWGQuick(node *models.Node, ifacename, confPath string, isConnected bool) error {
 
 	ipExec, err := exec.LookPath("ip")
 	if err != nil {
@@ -72,7 +75,12 @@ func ApplyWithoutWGQuick(node *models.Node, ifacename string, confPath string) e
 		mask6 = netmask
 		address6 = node.Address6
 	}
-	setKernelDevice(ifacename, address4, mask4, address6, mask6)
+	err = setKernelDevice(ifacename, address4, mask4, address6, mask6, isConnected)
+	if err != nil {
+		if err.Error() == disconnect_error {
+			return nil
+		}
+	}
 
 	_, err = wgclient.Device(ifacename)
 	if err != nil {
@@ -140,7 +148,7 @@ func RemoveWithoutWGQuick(ifacename string) error {
 	return err
 }
 
-func setKernelDevice(ifacename, address4, mask4, address6, mask6 string) error {
+func setKernelDevice(ifacename, address4, mask4, address6, mask6 string, isConnected bool) error {
 	ipExec, err := exec.LookPath("ip")
 	if err != nil {
 		return err
@@ -148,6 +156,10 @@ func setKernelDevice(ifacename, address4, mask4, address6, mask6 string) error {
 
 	// == best effort ==
 	ncutils.RunCmd("ip link delete dev "+ifacename, false)
+	if !isConnected {
+		return fmt.Errorf(disconnect_error)
+	}
+
 	ncutils.RunCmd(ipExec+" link add dev "+ifacename+" type wireguard", true)
 	if address4 != "" {
 		ncutils.RunCmd(ipExec+" address add dev "+ifacename+" "+address4+"/"+mask4, true)

+ 9 - 35
netclient/wireguard/unix.go

@@ -2,9 +2,7 @@ package wireguard
 
 import (
 	"fmt"
-	"log"
 	"os"
-	"regexp"
 
 	"github.com/gravitl/netmaker/logger"
 	"github.com/gravitl/netmaker/models"
@@ -12,9 +10,9 @@ import (
 )
 
 // ApplyWGQuickConf - applies wg-quick commands if os supports
-func ApplyWGQuickConf(confPath string, ifacename string) error {
+func ApplyWGQuickConf(confPath, ifacename string, isConnected bool) error {
 	if ncutils.IsWindows() {
-		return ApplyWindowsConf(confPath)
+		return ApplyWindowsConf(confPath, isConnected)
 	} else {
 		_, err := os.Stat(confPath)
 		if err != nil {
@@ -24,6 +22,9 @@ func ApplyWGQuickConf(confPath string, ifacename string) error {
 		if ncutils.IfaceExists(ifacename) {
 			ncutils.RunCmd("wg-quick down "+confPath, true)
 		}
+		if !isConnected {
+			return nil
+		}
 		_, err = ncutils.RunCmd("wg-quick up "+confPath, true)
 
 		return err
@@ -31,40 +32,13 @@ func ApplyWGQuickConf(confPath string, ifacename string) error {
 }
 
 // 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, confPath string, isConnected bool) error {
 	var err error
 	_ = WgQuickDownMac(node, ifacename)
-	err = WgQuickUpMac(node, ifacename, confPath)
-	return err
-}
-
-// SyncWGQuickConf - formats config file and runs sync command
-func SyncWGQuickConf(iface string, confPath string) error {
-	var tmpConf = confPath + ".sync.tmp"
-	var confCmd = "wg-quick strip "
-	if ncutils.IsMac() {
-		confCmd = "grep -v -e Address -e MTU -e PostUp -e PostDown "
-	}
-	confRaw, err := ncutils.RunCmd(confCmd+confPath, false)
-	if err != nil {
-		return err
-	}
-	regex := regexp.MustCompile(".*Warning.*\n")
-	conf := regex.ReplaceAllString(confRaw, "")
-	err = os.WriteFile(tmpConf, []byte(conf), 0600)
-	if err != nil {
-		return err
-	}
-	_, err = ncutils.RunCmd("wg syncconf "+iface+" "+tmpConf, true)
-	if err != nil {
-		log.Println(err.Error())
-		logger.Log(0, "error syncing conf, resetting")
-		err = ApplyWGQuickConf(confPath, iface)
-	}
-	errN := os.Remove(tmpConf)
-	if errN != nil {
-		logger.Log(0, errN.Error())
+	if !isConnected {
+		return nil
 	}
+	err = WgQuickUpMac(node, ifacename, confPath)
 	return err
 }
 

+ 4 - 1
netclient/wireguard/windows.go

@@ -8,7 +8,10 @@ import (
 )
 
 // ApplyWindowsConf - applies the WireGuard configuration file on Windows
-func ApplyWindowsConf(confPath string) error {
+func ApplyWindowsConf(confPath string, isConnected bool) error {
+	if !isConnected {
+		return nil
+	}
 	var commandLine = fmt.Sprintf(`wireguard.exe /installtunnelservice "%s"`, confPath)
 	if _, err := ncutils.RunCmdFormatted(commandLine, false); err != nil {
 		return err