From a33ff31a59d801b7c66e0b9c7b0a095775fc05ca Mon Sep 17 00:00:00 2001 From: afeiszli Date: Wed, 16 Feb 2022 20:19:51 -0500 Subject: [PATCH] adding logic for nodes without wg-quick --- netclient/functions/daemon.go | 1 + netclient/ncutils/netclientutils.go | 6 ++ netclient/wireguard/common.go | 18 +++- netclient/wireguard/noquick.go | 134 ++++++++++++++++++++++++++++ netclient/wireguard/unix.go | 1 + 5 files changed, 159 insertions(+), 1 deletion(-) create mode 100644 netclient/wireguard/noquick.go diff --git a/netclient/functions/daemon.go b/netclient/functions/daemon.go index a371444b..31b34452 100644 --- a/netclient/functions/daemon.go +++ b/netclient/functions/daemon.go @@ -299,6 +299,7 @@ func NodeUpdate(client mqtt.Client, msg mqtt.Message) { // ncutils.Log("error resubscribing after interface change " + err.Error()) // return // } + // set MTU of node interface if newNode.DNSOn == "yes" { for _, server := range newNode.NetworkSettings.DefaultServerAddrs { if server.IsLeader { diff --git a/netclient/ncutils/netclientutils.go b/netclient/ncutils/netclientutils.go index 1b28728c..5d8355a7 100644 --- a/netclient/ncutils/netclientutils.go +++ b/netclient/ncutils/netclientutils.go @@ -102,6 +102,12 @@ func IsFreeBSD() bool { return runtime.GOOS == "freebsd" } +// HasWGQuick - checks if WGQuick command is present +func HasWgQuick() bool { + cmd, err := exec.LookPath("wg-quick") + return err == nil && cmd != "" +} + // GetWireGuard - checks if wg is installed func GetWireGuard() string { userspace := os.Getenv("WG_QUICK_USERSPACE_IMPLEMENTATION") diff --git a/netclient/wireguard/common.go b/netclient/wireguard/common.go index 4fa8cce9..439e9437 100644 --- a/netclient/wireguard/common.go +++ b/netclient/wireguard/common.go @@ -206,7 +206,13 @@ func InitWireguard(node *models.Node, privkey string, peers []wgtypes.PeerConfig if syncconf { // should never be called really. err = SyncWGQuickConf(ifacename, confPath) } - + if !ncutils.HasWgQuick() && ncutils.IsLinux() { + err = SetPeers(ifacename, node.Address, node.PersistentKeepalive, peers) + if err != nil { + ncutils.PrintLog("error setting peers: "+err.Error(), 1) + } + time.Sleep(time.Second) + } _, cidr, cidrErr := net.ParseCIDR(modcfg.NetworkSettings.AddressRange) if cidrErr == nil { local.SetCIDRRoute(ifacename, node.Address, cidr) @@ -260,8 +266,13 @@ func SetWGConfig(network string, peerupdate bool) error { // RemoveConf - removes a configuration for a given WireGuard interface func RemoveConf(iface string, printlog bool) error { os := runtime.GOOS + if !ncutils.HasWgQuick() { + os = "nowgquick" + } var err error switch os { + case "nowgquick": + err = RemoveWithoutWGQuick(iface) case "windows": err = RemoveWindowsConf(iface, printlog) case "darwin": @@ -276,8 +287,13 @@ func RemoveConf(iface string, printlog bool) error { // ApplyConf - applys a conf on disk to WireGuard interface func ApplyConf(node *models.Node, ifacename string, confPath string) error { os := runtime.GOOS + if ncutils.IsLinux() && !ncutils.HasWgQuick() { + os = "nowgquick" + } var err error switch os { + case "nowgquick": + err = ApplyWithoutWGQuick(node, ifacename, confPath) case "windows": _ = ApplyWindowsConf(confPath) case "darwin": diff --git a/netclient/wireguard/noquick.go b/netclient/wireguard/noquick.go new file mode 100644 index 00000000..e1cc8322 --- /dev/null +++ b/netclient/wireguard/noquick.go @@ -0,0 +1,134 @@ +package wireguard + +import ( + "errors" + "os" + "os/exec" + "strconv" + "strings" + + "github.com/gravitl/netmaker/logger" + "github.com/gravitl/netmaker/models" + "github.com/gravitl/netmaker/netclient/config" + "github.com/gravitl/netmaker/netclient/ncutils" + "golang.zx2c4.com/wireguard/wgctrl" + "golang.zx2c4.com/wireguard/wgctrl/wgtypes" +) + +// 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 { + + ipExec, err := exec.LookPath("ip") + if err != nil { + return err + } + wgclient, err := wgctrl.New() + if err != nil { + return err + } + defer wgclient.Close() + + privkey, err := RetrievePrivKey(node.Network) + if err != nil { + return err + } + key, err := wgtypes.ParseKey(privkey) + if err != nil { + return err + } + conf := wgtypes.Config{} + nodeport := int(node.ListenPort) + if node.UDPHolePunch == "yes" && + node.IsServer == "no" && + node.IsIngressGateway != "yes" && + node.IsStatic != "yes" { + conf = wgtypes.Config{ + PrivateKey: &key, + } + } else { + conf = wgtypes.Config{ + PrivateKey: &key, + ListenPort: &nodeport, + } + } + + netmaskArr := strings.Split(node.NetworkSettings.AddressRange, "/") + var netmask = "32" + if len(netmaskArr) == 2 { + netmask = netmaskArr[1] + } + setKernelDevice(ifacename, node.Address, netmask) + + _, err = wgclient.Device(ifacename) + if err != nil { + if !os.IsNotExist(err) { + return errors.New("Unknown config error: " + err.Error()) + } + } + err = wgclient.ConfigureDevice(ifacename, conf) + if err != nil { + if os.IsNotExist(err) { + ncutils.PrintLog("Could not configure device: "+err.Error(), 0) + } + } + if _, err := ncutils.RunCmd(ipExec+" link set down dev "+ifacename, false); err != nil { + logger.Log(2, "attempted to remove interface before editing") + return err + } + if node.PostDown != "" { + runcmds := strings.Split(node.PostDown, "; ") + _ = ncutils.RunCmds(runcmds, false) + } + // set MTU of node interface + if _, err := ncutils.RunCmd(ipExec+" link set mtu "+strconv.Itoa(int(node.MTU))+" up dev "+ifacename, true); err != nil { + logger.Log(2, "failed to create interface with mtu", strconv.Itoa(int(node.MTU)), "-", ifacename) + return err + } + if node.PostUp != "" { + runcmds := strings.Split(node.PostUp, "; ") + _ = ncutils.RunCmds(runcmds, true) + } + if node.Address6 != "" && node.IsDualStack == "yes" { + logger.Log(1, "adding address:", node.Address6) + _, _ = ncutils.RunCmd(ipExec+" address add dev "+ifacename+" "+node.Address6+"/64", true) + } + return nil +} + +func RemoveWithoutWGQuick(ifacename string) error { + ipExec, err := exec.LookPath("ip") + if err != nil { + return err + } + out, err := ncutils.RunCmd(ipExec+" link del "+ifacename, false) + dontprint := strings.Contains(out, "does not exist") || strings.Contains(out, "Cannot find device") + if err != nil && !dontprint { + logger.Log(1, "error running command:", ipExec, "link del", ifacename) + logger.Log(1, out) + } + network := strings.ReplaceAll(ifacename, "nm-", "") + nodeconf, err := config.ReadConfig(network) + if nodeconf != nil && err == nil { + if nodeconf.Node.PostDown != "" { + runcmds := strings.Split(nodeconf.Node.PostDown, "; ") + _ = ncutils.RunCmds(runcmds, false) + } + } else if err != nil { + ncutils.PrintLog("error retrieving config: "+err.Error(), 1) + } + return err +} + +func setKernelDevice(ifacename, address, mask string) error { + ipExec, err := exec.LookPath("ip") + if err != nil { + return err + } + + // == best effort == + ncutils.RunCmd("ip link delete dev "+ifacename, false) + ncutils.RunCmd(ipExec+" link add dev "+ifacename+" type wireguard", true) + ncutils.RunCmd(ipExec+" address add dev "+ifacename+" "+address+"/"+mask, true) // this was a bug waiting to happen + + return nil +} diff --git a/netclient/wireguard/unix.go b/netclient/wireguard/unix.go index 8c120a59..e9e5969e 100644 --- a/netclient/wireguard/unix.go +++ b/netclient/wireguard/unix.go @@ -65,6 +65,7 @@ func ApplyWGQuickConf(confPath string, ifacename string) error { ncutils.RunCmd("wg-quick down "+confPath, true) } _, err = ncutils.RunCmd("wg-quick up "+confPath, true) + return err } }