Browse Source

began adding macos service/daemon

afeiszli 3 years ago
parent
commit
a0586ea6d2

+ 2 - 2
main.go

@@ -17,7 +17,7 @@ import (
 	"github.com/gravitl/netmaker/functions"
 	nodepb "github.com/gravitl/netmaker/grpc"
 	"github.com/gravitl/netmaker/models"
-	"github.com/gravitl/netmaker/netclient/local"
+	"github.com/gravitl/netmaker/netclient/ncutils"
 	"github.com/gravitl/netmaker/servercfg"
 	"google.golang.org/grpc"
 )
@@ -38,7 +38,7 @@ func initialize() { // Client Mode Prereq Check
 	}
 	log.Println("database successfully connected.")
 	if servercfg.IsClientMode() {
-		output, err := local.RunCmd("id -u", true)
+		output, err := ncutils.RunCmd("id -u", true)
 		if err != nil {
 			log.Println("Error running 'id -u' for prereq check. Please investigate or disable client mode.")
 			log.Fatal(output, err)

+ 5 - 5
netclient/auth/auth.go

@@ -6,7 +6,7 @@ import (
 
 	"github.com/gravitl/netmaker/models"
 	"github.com/gravitl/netmaker/netclient/config"
-	"github.com/gravitl/netmaker/netclient/netclientutils"
+	"github.com/gravitl/netmaker/netclient/ncutils"
 
 	//    "os"
 	"context"
@@ -20,7 +20,7 @@ import (
 
 // CreateJWT func will used to create the JWT while signing in and signing out
 func SetJWT(client nodepb.NodeServiceClient, network string) (context.Context, error) {
-	home := netclientutils.GetNetclientPathSpecific()
+	home := ncutils.GetNetclientPathSpecific()
 	tokentext, err := ioutil.ReadFile(home + "nettoken-" + network)
 	if err != nil {
 		err = AutoLogin(client, network)
@@ -42,7 +42,7 @@ func SetJWT(client nodepb.NodeServiceClient, network string) (context.Context, e
 }
 
 func AutoLogin(client nodepb.NodeServiceClient, network string) error {
-	home := netclientutils.GetNetclientPathSpecific()
+	home := ncutils.GetNetclientPathSpecific()
 	cfg, err := config.ReadConfig(network)
 	if err != nil {
 		return err
@@ -79,12 +79,12 @@ func AutoLogin(client nodepb.NodeServiceClient, network string) error {
 
 func StoreSecret(key string, network string) error {
 	d1 := []byte(key)
-	err := ioutil.WriteFile(netclientutils.GetNetclientPathSpecific()+"secret-"+network, d1, 0644)
+	err := ioutil.WriteFile(ncutils.GetNetclientPathSpecific()+"secret-"+network, d1, 0644)
 	return err
 }
 
 func RetrieveSecret(network string) (string, error) {
-	dat, err := ioutil.ReadFile(netclientutils.GetNetclientPathSpecific() + "secret-" + network)
+	dat, err := ioutil.ReadFile(ncutils.GetNetclientPathSpecific() + "secret-" + network)
 	return string(dat), err
 }
 

+ 35 - 35
netclient/command/commands.go

@@ -8,9 +8,9 @@ import (
 
 	nodepb "github.com/gravitl/netmaker/grpc"
 	"github.com/gravitl/netmaker/netclient/config"
+	"github.com/gravitl/netmaker/netclient/daemon"
 	"github.com/gravitl/netmaker/netclient/functions"
-	"github.com/gravitl/netmaker/netclient/local"
-	"github.com/gravitl/netmaker/netclient/netclientutils"
+	"github.com/gravitl/netmaker/netclient/ncutils"
 	"golang.zx2c4.com/wireguard/wgctrl"
 )
 
@@ -28,34 +28,30 @@ func Join(cfg config.ClientConfig, privateKey string) error {
 
 	if err != nil && !cfg.DebugJoin {
 		if !strings.Contains(err.Error(), "ALREADY_INSTALLED") {
-			log.Println("Error installing: ", err)
+			ncutils.PrintLog("error installing: "+err.Error(), 1)
 			err = functions.LeaveNetwork(cfg.Network)
 			if err != nil {
-				err = local.WipeLocal(cfg.Network)
+				err = functions.WipeLocal(cfg.Network)
 				if err != nil {
-					log.Println("Error removing artifacts: ", err)
+					ncutils.PrintLog("error removing artifacts: "+err.Error(), 1)
 				}
 			}
 			if cfg.Daemon != "off" {
-				if netclientutils.IsLinux() {
-					err = local.RemoveSystemDServices(cfg.Network)
+				if ncutils.IsLinux() {
+					err = daemon.RemoveSystemDServices(cfg.Network)
 				}
 				if err != nil {
-					log.Println("Error removing services: ", err)
+					ncutils.PrintLog("error removing services: "+err.Error(), 1)
 				}
 			}
+		} else {
+			ncutils.PrintLog("success", 0)
 		}
 		return err
 	}
-	log.Println("joined " + cfg.Network)
+	ncutils.PrintLog("joined "+cfg.Network, 1)
 	if cfg.Daemon != "off" {
-		if netclientutils.IsWindows() {
-			err = local.CreateAndRunWindowsDaemon()
-		} else if netclientutils.IsMac() {
-			err = local.CreateAndRunMacDaemon()
-		} else {
-			err = functions.InstallDaemon(cfg)
-		}
+		err = daemon.InstallDaemon(cfg)
 	}
 	return err
 }
@@ -75,13 +71,13 @@ func RunUserspaceDaemon() {
 func CheckIn(cfg config.ClientConfig) error {
 	var err error
 	if cfg.Network == "" {
-		log.Println("Required, '-n'. No network provided. Exiting.")
+		ncutils.PrintLog("required, '-n', exiting", 0)
 		os.Exit(1)
 	} else if cfg.Network == "all" {
-		log.Println("Running CheckIn for all networks.")
+		ncutils.PrintLog("running checkin for all networks", 1)
 		networks, err := functions.GetNetworks()
 		if err != nil {
-			log.Println("Error retrieving networks. Exiting.")
+			ncutils.PrintLog("error retrieving networks, exiting", 1)
 			return err
 		}
 		for _, network := range networks {
@@ -91,14 +87,14 @@ func CheckIn(cfg config.ClientConfig) error {
 			}
 			err = functions.CheckConfig(*currConf)
 			if err != nil {
-				log.Printf("Error checking in for "+network+" network: ", err)
+				ncutils.PrintLog("error checking in for "+network+" network: "+err.Error(), 1)
 			} else {
-				log.Println("checked in successfully for " + network)
+				ncutils.PrintLog("checked in successfully for "+network, 1)
 			}
 		}
 		if len(networks) == 0 {
-			if netclientutils.IsWindows() { // Windows specific - there are no netclients, so stop daemon process
-				local.StopWindowsDaemon()
+			if ncutils.IsWindows() { // Windows specific - there are no netclients, so stop daemon process
+				daemon.StopWindowsDaemon()
 			}
 		}
 		err = nil
@@ -111,43 +107,46 @@ func CheckIn(cfg config.ClientConfig) error {
 func Leave(cfg config.ClientConfig) error {
 	err := functions.LeaveNetwork(cfg.Network)
 	if err != nil {
-		log.Println("Error attempting to leave network " + cfg.Network)
+		ncutils.PrintLog("error attempting to leave network "+cfg.Network, 1)
+	} else {
+		ncutils.PrintLog("success", 0)
 	}
 	return err
 }
 
 func Push(cfg config.ClientConfig) error {
 	var err error
-	if cfg.Network == "all" || netclientutils.IsWindows() {
-		log.Println("No network selected. Running Push for all networks.")
+	if cfg.Network == "all" || ncutils.IsWindows() {
+		ncutils.PrintLog("pushing config to server for all networks.", 0)
 		networks, err := functions.GetNetworks()
 		if err != nil {
-			log.Println("Error retrieving networks. Exiting.")
+			ncutils.PrintLog("error retrieving networks, exiting.", 0)
 			return err
 		}
 		for _, network := range networks {
 			err = functions.Push(network)
 			if err != nil {
-				log.Printf("Error pushing network configs for "+network+" network: ", err)
+				log.Printf("error pushing network configs for "+network+" network: ", err)
 			} else {
-				log.Println("pushed network config for " + network)
+				ncutils.PrintLog("pushed network config for "+network, 1)
 			}
 		}
 		err = nil
 	} else {
 		err = functions.Push(cfg.Network)
 	}
-	log.Println("Completed pushing network configs to remote server.")
+	ncutils.PrintLog("completed pushing network configs to remote server", 1)
+	ncutils.PrintLog("success", 1)
 	return err
 }
 
 func Pull(cfg config.ClientConfig) error {
 	var err error
 	if cfg.Network == "all" {
-		log.Println("No network selected. Running Pull for all networks.")
+		ncutils.PrintLog("No network selected. Running Pull for all networks.", 0)
 		networks, err := functions.GetNetworks()
 		if err != nil {
-			log.Println("Error retrieving networks. Exiting.")
+			ncutils.PrintLog("Error retrieving networks. Exiting.", 1)
 			return err
 		}
 		for _, network := range networks {
@@ -155,14 +154,15 @@ func Pull(cfg config.ClientConfig) error {
 			if err != nil {
 				log.Printf("Error pulling network config for "+network+" network: ", err)
 			} else {
-				log.Println("pulled network config for " + network)
+				ncutils.PrintLog("pulled network config for "+network, 1)
 			}
 		}
 		err = nil
 	} else {
 		_, err = functions.Pull(cfg.Network, true)
 	}
-	log.Println("Completed pulling network and peer configs.")
+	ncutils.PrintLog("reset network and peer configs", 1)
+	ncutils.PrintLog("success", 1)
 	return err
 }
 
@@ -172,7 +172,7 @@ func List(cfg config.ClientConfig) error {
 }
 
 func Uninstall() error {
-	log.Println("Uninstalling netclient")
+	ncutils.PrintLog("uninstalling netclient", 0)
 	err := functions.Uninstall()
 	return err
 }

+ 13 - 12
netclient/config/config.go

@@ -8,8 +8,9 @@ import (
 	"fmt"
 	"log"
 	"os"
+
 	"github.com/gravitl/netmaker/models"
-	"github.com/gravitl/netmaker/netclient/netclientutils"
+	"github.com/gravitl/netmaker/netclient/ncutils"
 	"github.com/urfave/cli/v2"
 	"gopkg.in/yaml.v3"
 )
@@ -25,7 +26,7 @@ type ClientConfig struct {
 	Network         string       `yaml:"network"`
 	Daemon          string       `yaml:"daemon"`
 	OperatingSystem string       `yaml:"operatingsystem"`
-	DebugJoin		bool		 `yaml:"debugjoin"`
+	DebugJoin       bool         `yaml:"debugjoin"`
 }
 type ServerConfig struct {
 	CoreDNSAddr   string `yaml:"corednsaddr"`
@@ -42,13 +43,13 @@ func Write(config *ClientConfig, network string) error {
 		err := errors.New("no network provided - exiting")
 		return err
 	}
-	_, err := os.Stat(netclientutils.GetNetclientPath())
+	_, err := os.Stat(ncutils.GetNetclientPath())
 	if os.IsNotExist(err) {
-		os.Mkdir(netclientutils.GetNetclientPath(), 0744)
+		os.Mkdir(ncutils.GetNetclientPath(), 0744)
 	} else if err != nil {
 		return err
 	}
-	home := netclientutils.GetNetclientPathSpecific()
+	home := ncutils.GetNetclientPathSpecific()
 
 	file := fmt.Sprintf(home + "netconfig-" + network)
 	f, err := os.OpenFile(file, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.ModePerm)
@@ -71,14 +72,14 @@ func WriteServer(server string, accesskey string, network string) error {
 	}
 	nofile := false
 	//home, err := homedir.Dir()
-	_, err := os.Stat(netclientutils.GetNetclientPath())
+	_, err := os.Stat(ncutils.GetNetclientPath())
 	if os.IsNotExist(err) {
-		os.Mkdir(netclientutils.GetNetclientPath(), 0744)
+		os.Mkdir(ncutils.GetNetclientPath(), 0744)
 	} else if err != nil {
-		fmt.Println("couldnt find or create", netclientutils.GetNetclientPath())
+		fmt.Println("couldnt find or create", ncutils.GetNetclientPath())
 		return err
 	}
-	home := netclientutils.GetNetclientPathSpecific()
+	home := ncutils.GetNetclientPathSpecific()
 
 	file := fmt.Sprintf(home + "netconfig-" + network)
 	//f, err := os.Open(file)
@@ -151,7 +152,7 @@ func (config *ClientConfig) ReadConfig() {
 
 	nofile := false
 	//home, err := homedir.Dir()
-	home := netclientutils.GetNetclientPathSpecific()
+	home := ncutils.GetNetclientPathSpecific()
 	file := fmt.Sprintf(home + "netconfig-" + config.Network)
 	//f, err := os.Open(file)
 	f, err := os.OpenFile(file, os.O_RDONLY, 0666)
@@ -186,7 +187,7 @@ func ModConfig(node *models.Node) error {
 	}
 	var modconfig ClientConfig
 	var err error
-	if FileExists(netclientutils.GetNetclientPathSpecific() + "netconfig-" + network) {
+	if FileExists(ncutils.GetNetclientPathSpecific() + "netconfig-" + network) {
 		useconfig, err := ReadConfig(network)
 		if err != nil {
 			return err
@@ -306,7 +307,7 @@ func ReadConfig(network string) (*ClientConfig, error) {
 		return nil, err
 	}
 	nofile := false
-	home := netclientutils.GetNetclientPathSpecific()
+	home := ncutils.GetNetclientPathSpecific()
 	file := fmt.Sprintf(home + "netconfig-" + network)
 	f, err := os.Open(file)
 

+ 24 - 0
netclient/daemon/common.go

@@ -0,0 +1,24 @@
+package daemon
+
+import (
+	"errors"
+	"runtime"
+
+	"github.com/gravitl/netmaker/netclient/config"
+)
+
+func InstallDaemon(cfg config.ClientConfig) error {
+	os := runtime.GOOS
+	var err error
+	switch os {
+	case "windows":
+		err = SetupWindowsDaemon()
+	case "darwin":
+		err = errors.New("need to implement macos daemon0")
+	case "linux":
+		err = SetupSystemDDaemon(cfg.Network)
+	default:
+		err = errors.New("this os is not yet supported for daemon mode. Run join cmd with flag '--daemon off'")
+	}
+	return err
+}

+ 76 - 0
netclient/daemon/macos.go

@@ -0,0 +1,76 @@
+package daemon
+
+import (
+	"fmt"
+	"log"
+	"os"
+	"text/template"
+
+	"github.com/gravitl/netmaker/netclient/ncutils"
+)
+
+const MAC_SERVICE_NAME = "com.gravitl.netclient"
+
+func CreateAndRunMacDaemon() error {
+	_, err := os.Stat("~/Library/LaunchAgents")
+	if os.IsNotExist(err) {
+		os.Mkdir("~/Library/LaunchAgents", 0744)
+	}
+	err = CreateMacService(MAC_SERVICE_NAME)
+	if err != nil {
+		return err
+	}
+	_, err = ncutils.RunCmd("launchctl load ~/Library/LaunchAgents/"+MAC_SERVICE_NAME+".plist", true)
+	return err
+}
+
+func CleanupMac() {
+	//StopWindowsDaemon()
+	//RemoveWindowsDaemon()
+	//os.RemoveAll(ncutils.GetNetclientPath())
+	log.Println("TODO: Not implemented yet")
+}
+
+func CreateMacService(servicename string) error {
+	tdata := MacTemplateData{
+		Label:     servicename,
+		Program:   "/etc/netclient/netclient",
+		KeepAlive: true,
+		RunAtLoad: true,
+	}
+	fileLoc := fmt.Sprintf("%s/Library/LaunchAgents/%s.plist", os.Getenv("HOME"), tdata.Label)
+	launchdFile, err := os.Open(fileLoc)
+	if err != nil {
+		return err
+	}
+	launchdTemplate := template.Must(template.New("launchdTemplate").Parse(MacTemplate()))
+	return launchdTemplate.Execute(launchdFile, tdata)
+}
+
+func MacTemplate() string {
+	return `
+<?xml version='1.0' encoding='UTF-8'?>
+ <!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\" >
+ <plist version='1.0'>
+   <dict>
+     <key>Label</key><string>{{.Label}}</string>
+     <key>Program</key><string>{{.Program}}</string>
+     <key>StandardOutPath</key><string>/tmp/{{.Label}}.out.log</string>
+     <key>StandardErrorPath</key><string>/tmp/{{.Label}}.err.log</string>
+     <key>KeepAlive</key><{{.KeepAlive}}/>
+     <key>RunAtLoad</key><{{.RunAtLoad}}/>
+	 <key>StartCalendarInterval</key>
+	 <dict>
+	 	<key>Minute</key>
+	 	<value>*/1</value>
+   	 </dict>
+</plist>
+`
+}
+
+type MacTemplateData struct {
+	Label     string
+	Program   string
+	KeepAlive bool
+	RunAtLoad bool
+}

+ 150 - 0
netclient/daemon/systemd.go

@@ -0,0 +1,150 @@
+package daemon
+
+import (
+	//"github.com/davecgh/go-spew/spew"
+
+	"io/ioutil"
+	"log"
+	"os"
+	"path/filepath"
+
+	"github.com/gravitl/netmaker/netclient/ncutils"
+)
+
+func SetupSystemDDaemon(network string) error {
+	if ncutils.IsWindows() {
+		return nil
+	}
+	dir, err := filepath.Abs(filepath.Dir(os.Args[0]))
+	if err != nil {
+		return err
+	}
+	binarypath := dir + "/netclient"
+
+	_, err = os.Stat("/etc/netclient")
+	if os.IsNotExist(err) {
+		os.Mkdir("/etc/netclient", 744)
+	} else if err != nil {
+		log.Println("couldnt find or create /etc/netclient")
+		return err
+	}
+
+	if !ncutils.FileExists("/usr/local/bin/netclient") {
+		os.Symlink("/etc/netclient/netclient", "/usr/local/bin/netclient")
+	}
+	if !ncutils.FileExists("/etc/netclient/netclient") {
+		_, err = ncutils.Copy(binarypath, "/etc/netclient/netclient")
+		if err != nil {
+			log.Println(err)
+			return err
+		}
+	}
+
+	systemservice := `[Unit]
+Description=Network Check
+Wants=netclient.timer
+
+[Service]
+Type=simple
+ExecStart=/etc/netclient/netclient checkin -n %i
+
+[Install]
+WantedBy=multi-user.target
+`
+
+	systemtimer := `[Unit]
+Description=Calls the Netmaker Mesh Client Service
+
+`
+	systemtimer = systemtimer + "Requires=netclient@" + network + ".service"
+
+	systemtimer = systemtimer +
+		`
+
+[Timer]
+
+`
+	systemtimer = systemtimer + "Unit=netclient@" + network + ".service"
+
+	systemtimer = systemtimer +
+		`
+
+OnCalendar=*:*:0/30
+
+[Install]
+WantedBy=timers.target
+`
+
+	servicebytes := []byte(systemservice)
+	timerbytes := []byte(systemtimer)
+
+	if !ncutils.FileExists("/etc/systemd/system/[email protected]") {
+		err = ioutil.WriteFile("/etc/systemd/system/[email protected]", servicebytes, 0644)
+		if err != nil {
+			log.Println(err)
+			return err
+		}
+	}
+
+	if !ncutils.FileExists("/etc/systemd/system/netclient-" + network + ".timer") {
+		err = ioutil.WriteFile("/etc/systemd/system/netclient-"+network+".timer", timerbytes, 0644)
+		if err != nil {
+			log.Println(err)
+			return err
+		}
+	}
+
+	_, _ = ncutils.RunCmd("systemctl enable [email protected]", true)
+	_, _ = ncutils.RunCmd("systemctl daemon-reload", true)
+	_, _ = ncutils.RunCmd("systemctl enable netclient-"+network+".timer", true)
+	_, _ = ncutils.RunCmd("systemctl start netclient-"+network+".timer", true)
+	return nil
+}
+
+func RemoveSystemDServices(network string) error {
+	//sysExec, err := exec.LookPath("systemctl")
+	if !ncutils.IsWindows() {
+		fullremove, err := isOnlyService(network)
+		if err != nil {
+			log.Println(err)
+		}
+
+		if fullremove {
+			_, err = ncutils.RunCmd("systemctl disable [email protected]", true)
+		}
+		_, _ = ncutils.RunCmd("systemctl daemon-reload", true)
+
+		if ncutils.FileExists("/etc/systemd/system/netclient-" + network + ".timer") {
+			_, _ = ncutils.RunCmd("systemctl disable netclient-"+network+".timer", true)
+		}
+		if fullremove {
+			if ncutils.FileExists("/etc/systemd/system/[email protected]") {
+				err = os.Remove("/etc/systemd/system/[email protected]")
+			}
+		}
+		if ncutils.FileExists("/etc/systemd/system/netclient-" + network + ".timer") {
+			err = os.Remove("/etc/systemd/system/netclient-" + network + ".timer")
+		}
+		if err != nil {
+			log.Println("Error removing file. Please investigate.")
+			log.Println(err)
+		}
+		_, _ = ncutils.RunCmd("systemctl daemon-reload", true)
+		_, _ = ncutils.RunCmd("systemctl reset-failed", true)
+	}
+	return nil
+}
+
+func isOnlyService(network string) (bool, error) {
+	isonly := false
+	files, err := filepath.Glob("/etc/netclient/netconfig-*")
+	if err != nil {
+		return isonly, err
+	}
+	count := len(files)
+	if count == 0 {
+		isonly = true
+	}
+	return isonly, err
+
+}

+ 140 - 0
netclient/daemon/windows.go

@@ -0,0 +1,140 @@
+package daemon
+
+import (
+	"fmt"
+	"io"
+	"io/ioutil"
+	"log"
+	"net/http"
+	"os"
+	"strings"
+
+	"github.com/gravitl/netmaker/netclient/ncutils"
+)
+
+func SetupWindowsDaemon() error {
+
+	if !ncutils.FileExists(ncutils.GetNetclientPathSpecific() + "winsw.xml") {
+		if err := writeServiceConfig(); err != nil {
+			return err
+		}
+	}
+
+	if !ncutils.FileExists(ncutils.GetNetclientPathSpecific() + "winsw.exe") {
+		ncutils.Log("performing first time daemon setup")
+		if !ncutils.FileExists(".\\winsw.exe") {
+			err := downloadWinsw()
+			if err != nil {
+				return err
+			}
+		}
+		err := copyWinswOver()
+		if err != nil {
+			return err
+		}
+		ncutils.Log("finished daemon setup")
+	}
+	// install daemon, will not overwrite
+	ncutils.RunCmd(strings.Replace(ncutils.GetNetclientPathSpecific(), `\\`, `\`, -1)+`winsw.exe install`, true)
+	// start daemon, will not restart or start another
+	ncutils.RunCmd(strings.Replace(ncutils.GetNetclientPathSpecific(), `\\`, `\`, -1)+`winsw.exe start`, true)
+	ncutils.Log(strings.Replace(ncutils.GetNetclientPathSpecific(), `\\`, `\`, -1) + `winsw.exe start`)
+	return nil
+}
+
+func CleanupWindows() {
+	if !ncutils.FileExists(ncutils.GetNetclientPathSpecific() + "winsw.xml") {
+		writeServiceConfig()
+	}
+	StopWindowsDaemon()
+	RemoveWindowsDaemon()
+	os.RemoveAll(ncutils.GetNetclientPath())
+	log.Println("Netclient on Windows, uninstalled")
+}
+
+func writeServiceConfig() error {
+	serviceConfigPath := ncutils.GetNetclientPathSpecific() + "winsw.xml"
+	scriptString := fmt.Sprintf(`<service>
+<id>netclient</id>
+<name>Netclient</name>
+<description>Connects Windows nodes to one or more Netmaker networks.</description>
+<executable>%v</executable>
+<log mode="roll"></log>
+</service>
+`, strings.Replace(ncutils.GetNetclientPathSpecific()+"netclient.exe", `\\`, `\`, -1))
+	if !ncutils.FileExists(serviceConfigPath) {
+		err := ioutil.WriteFile(serviceConfigPath, []byte(scriptString), 0644)
+		if err != nil {
+			return err
+		}
+		ncutils.Log("wrote the daemon config file to the Netclient directory")
+	}
+	return nil
+}
+
+// == Daemon ==
+func StopWindowsDaemon() {
+	ncutils.Log("no networks detected, stopping Windows, Netclient daemon")
+	// stop daemon, will not overwrite
+	ncutils.RunCmd(strings.Replace(ncutils.GetNetclientPathSpecific(), `\\`, `\`, -1)+`winsw.exe stop`, true)
+}
+
+func RemoveWindowsDaemon() {
+	// uninstall daemon, will not restart or start another
+	ncutils.RunCmd(strings.Replace(ncutils.GetNetclientPathSpecific(), `\\`, `\`, -1)+`winsw.exe uninstall`, true)
+	ncutils.Log("uninstalled Windows, Netclient daemon")
+}
+
+func copyWinswOver() error {
+
+	input, err := ioutil.ReadFile(".\\winsw.exe")
+	if err != nil {
+		ncutils.Log("failed to find winsw.exe")
+		return err
+	}
+	if err = ioutil.WriteFile(ncutils.GetNetclientPathSpecific()+"winsw.exe", input, 0644); err != nil {
+		ncutils.Log("failed to copy winsw.exe to " + ncutils.GetNetclientPath())
+		return err
+	}
+	if err = os.Remove(".\\winsw.exe"); err != nil {
+		ncutils.Log("failed to cleanup local winsw.exe, feel free to delete it")
+		return err
+	}
+	ncutils.Log("finished copying winsw.exe")
+	return nil
+}
+
+func downloadWinsw() error {
+	fullURLFile := "https://github.com/winsw/winsw/releases/download/v2.11.0/WinSW-x64.exe"
+	fileName := "winsw.exe"
+
+	// Create the file
+	file, err := os.Create(fileName)
+	if err != nil {
+		ncutils.Log("could not create file on OS for Winsw")
+		return err
+	}
+	client := http.Client{
+		CheckRedirect: func(r *http.Request, via []*http.Request) error {
+			r.URL.Opaque = r.URL.Path
+			return nil
+		},
+	}
+	// Put content on file
+	ncutils.Log("downloading service tool...")
+	resp, err := client.Get(fullURLFile)
+	if err != nil {
+		ncutils.Log("could not GET Winsw")
+		return err
+	}
+	defer resp.Body.Close()
+
+	_, err = io.Copy(file, resp.Body)
+	if err != nil {
+		ncutils.Log("could not mount winsw.exe")
+		return err
+	}
+	defer file.Close()
+	ncutils.Log("finished downloading Winsw")
+	return nil
+}

+ 28 - 29
netclient/functions/checkin.go

@@ -3,7 +3,6 @@ package functions
 import (
 	"encoding/json"
 	"errors"
-	"log"
 	"os"
 	"runtime"
 	"strings"
@@ -13,7 +12,7 @@ import (
 	"github.com/gravitl/netmaker/netclient/auth"
 	"github.com/gravitl/netmaker/netclient/config"
 	"github.com/gravitl/netmaker/netclient/local"
-	"github.com/gravitl/netmaker/netclient/netclientutils"
+	"github.com/gravitl/netmaker/netclient/ncutils"
 	"github.com/gravitl/netmaker/netclient/wireguard"
 	"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
 	"google.golang.org/grpc"
@@ -30,37 +29,37 @@ func checkIP(node *models.Node, servercfg config.ServerConfig, cliconf config.Cl
 	var err error
 	if node.Roaming == "yes" && node.IsStatic != "yes" {
 		if node.IsLocal == "no" {
-			extIP, err := netclientutils.GetPublicIP()
+			extIP, err := ncutils.GetPublicIP()
 			if err != nil {
-				log.Println("error encountered checking ip addresses:", err)
+				ncutils.PrintLog("error encountered checking ip addresses: "+err.Error(), 1)
 			}
 			if node.Endpoint != extIP && extIP != "" {
-				log.Println("Endpoint has changed from " +
-					node.Endpoint + " to " + extIP)
-				log.Println("Updating address")
+				ncutils.PrintLog("endpoint has changed from "+
+					node.Endpoint+" to "+extIP, 1)
+				ncutils.PrintLog("updating address", 1)
 				node.Endpoint = extIP
 				ipchange = true
 			}
 			intIP, err := getPrivateAddr()
 			if err != nil {
-				log.Println("error encountered checking ip addresses:", err)
+				ncutils.PrintLog("error encountered checking ip addresses: "+err.Error(), 1)
 			}
 			if node.LocalAddress != intIP && intIP != "" {
-				log.Println("Local Address has changed from " +
-					node.LocalAddress + " to " + intIP)
-				log.Println("Updating address")
+				ncutils.PrintLog("local Address has changed from "+
+					node.LocalAddress+" to "+intIP, 1)
+				ncutils.PrintLog("updating address", 1)
 				node.LocalAddress = intIP
 				ipchange = true
 			}
 		} else {
-			localIP, err := netclientutils.GetLocalIP(node.LocalRange)
+			localIP, err := ncutils.GetLocalIP(node.LocalRange)
 			if err != nil {
-				log.Println("error encountered checking ip addresses:", err)
+				ncutils.PrintLog("error encountered checking ip addresses: "+err.Error(), 1)
 			}
 			if node.Endpoint != localIP && localIP != "" {
-				log.Println("Endpoint has changed from " +
-					node.Endpoint + " to " + localIP)
-				log.Println("Updating address")
+				ncutils.PrintLog("endpoint has changed from "+
+					node.Endpoint+" to "+localIP, 1)
+				ncutils.PrintLog("updating address", 1)
 				node.Endpoint = localIP
 				node.LocalAddress = localIP
 				ipchange = true
@@ -70,12 +69,12 @@ func checkIP(node *models.Node, servercfg config.ServerConfig, cliconf config.Cl
 	if ipchange {
 		err = config.ModConfig(node)
 		if err != nil {
-			log.Println("Error:", err)
+			ncutils.PrintLog("error modifying config file: "+err.Error(), 1)
 			return false
 		}
 		err = wireguard.SetWGConfig(network, false)
 		if err != nil {
-			log.Println("Error:", err)
+			ncutils.PrintLog("error setting wireguard config: "+err.Error(), 1)
 			return false
 		}
 	}
@@ -96,14 +95,14 @@ func checkNodeActions(node *models.Node, networkName string, servercfg config.Se
 		node.IsStatic != "yes" {
 		err := wireguard.SetWGKeyConfig(networkName, servercfg.GRPCAddress)
 		if err != nil {
-			log.Println("Unable to process reset keys request:", err)
+			ncutils.PrintLog("unable to process reset keys request: "+err.Error(), 1)
 			return ""
 		}
 	}
 	if node.Action == models.NODE_DELETE || localNode.Action == models.NODE_DELETE {
 		err := RemoveLocalInstance(cfg, networkName)
 		if err != nil {
-			log.Println("Error:", err)
+			ncutils.PrintLog("error deleting locally: "+err.Error(), 1)
 		}
 		return models.NODE_DELETE
 	}
@@ -161,22 +160,22 @@ func Pull(network string, manual bool) (*models.Node, error) {
 	servercfg := cfg.Server
 	var header metadata.MD
 
-	if cfg.Node.IPForwarding == "yes" && !netclientutils.IsWindows() {
+	if cfg.Node.IPForwarding == "yes" && !ncutils.IsWindows() {
 		if err = local.SetIPForwarding(); err != nil {
 			return nil, err
 		}
 	}
 	conn, err := grpc.Dial(cfg.Server.GRPCAddress,
-		netclientutils.GRPCRequestOpts(cfg.Server.GRPCSSL))
+		ncutils.GRPCRequestOpts(cfg.Server.GRPCSSL))
 	if err != nil {
-		log.Println("Cant dial GRPC server:", err)
+		ncutils.PrintLog("Cant dial GRPC server: "+err.Error(), 1)
 		return nil, err
 	}
 	wcclient := nodepb.NewNodeServiceClient(conn)
 
 	ctx, err := auth.SetJWT(wcclient, network)
 	if err != nil {
-		log.Println("Failed to authenticate:", err)
+		ncutils.PrintLog("Failed to authenticate: "+err.Error(), 1)
 		return nil, err
 	}
 
@@ -198,7 +197,7 @@ func Pull(network string, manual bool) (*models.Node, error) {
 		// check for interface change
 		if cfg.Node.Interface != resNode.Interface {
 			if err = DeleteInterface(cfg.Node.Interface, cfg.Node.PostDown); err != nil {
-				log.Println("could not delete old interface", cfg.Node.Interface)
+				ncutils.PrintLog("could not delete old interface "+cfg.Node.Interface, 1)
 			}
 		}
 		resNode.PullChanges = "no"
@@ -230,7 +229,7 @@ func Pull(network string, manual bool) (*models.Node, error) {
 			}
 		}
 	}
-	if netclientutils.IsLinux() {
+	if ncutils.IsLinux() {
 		setDNS(&resNode, servercfg, &cfg.Node)
 	}
 
@@ -249,16 +248,16 @@ func Push(network string) error {
 
 	var wcclient nodepb.NodeServiceClient
 	conn, err := grpc.Dial(cfg.Server.GRPCAddress,
-		netclientutils.GRPCRequestOpts(cfg.Server.GRPCSSL))
+		ncutils.GRPCRequestOpts(cfg.Server.GRPCSSL))
 	if err != nil {
-		log.Println("Cant dial GRPC server:", err)
+		ncutils.PrintLog("Cant dial GRPC server: "+err.Error(), 1)
 		return err
 	}
 	wcclient = nodepb.NewNodeServiceClient(conn)
 
 	ctx, err := auth.SetJWT(wcclient, network)
 	if err != nil {
-		log.Println("Failed to authenticate:", err)
+		ncutils.PrintLog("Failed to authenticate with server: "+err.Error(), 1)
 		return err
 	}
 	if postnode.IsPending != "yes" {

+ 136 - 29
netclient/functions/common.go

@@ -8,6 +8,7 @@ import (
 	"io/ioutil"
 	"log"
 	"net"
+	"os"
 	"os/exec"
 	"strings"
 
@@ -15,8 +16,9 @@ import (
 	"github.com/gravitl/netmaker/models"
 	"github.com/gravitl/netmaker/netclient/auth"
 	"github.com/gravitl/netmaker/netclient/config"
-	"github.com/gravitl/netmaker/netclient/local"
-	"github.com/gravitl/netmaker/netclient/netclientutils"
+	"github.com/gravitl/netmaker/netclient/daemon"
+	"github.com/gravitl/netmaker/netclient/ncutils"
+	"github.com/gravitl/netmaker/netclient/wireguard"
 	"golang.zx2c4.com/wireguard/wgctrl"
 	"google.golang.org/grpc"
 	"google.golang.org/grpc/metadata"
@@ -92,21 +94,21 @@ func GetNode(network string) models.Node {
 func Uninstall() error {
 	networks, err := GetNetworks()
 	if err != nil {
-		log.Println("unable to retrieve networks: ", err)
-		log.Println("continuing uninstall without leaving networks")
+		ncutils.PrintLog("unable to retrieve networks: "+err.Error(), 1)
+		ncutils.PrintLog("continuing uninstall without leaving networks", 1)
 	} else {
 		for _, network := range networks {
 			err = LeaveNetwork(network)
 			if err != nil {
-				log.Println("Encounter issue leaving network "+network+": ", err)
+				ncutils.PrintLog("Encounter issue leaving network "+network+": "+err.Error(), 1)
 			}
 		}
 	}
 	// clean up OS specific stuff
-	if netclientutils.IsWindows() {
-		local.CleanupWindows()
-	} else if netclientutils.IsWindows() {
-		local.CleanupMac()
+	if ncutils.IsWindows() {
+		daemon.CleanupWindows()
+	} else if ncutils.IsWindows() {
+		daemon.CleanupMac()
 	}
 
 	return err
@@ -123,7 +125,7 @@ func LeaveNetwork(network string) error {
 
 	var wcclient nodepb.NodeServiceClient
 	conn, err := grpc.Dial(cfg.Server.GRPCAddress,
-		netclientutils.GRPCRequestOpts(cfg.Server.GRPCSSL))
+		ncutils.GRPCRequestOpts(cfg.Server.GRPCSSL))
 	if err != nil {
 		log.Printf("Unable to establish client connection to "+servercfg.GRPCAddress+": %v", err)
 	} else {
@@ -134,9 +136,9 @@ func LeaveNetwork(network string) error {
 		if err != nil {
 			log.Printf("Failed to authenticate: %v", err)
 		} else {
-			if netclientutils.IsWindows() {
-				local.RemoveWindowsConf(node.Interface)
-				log.Println("removed Windows tunnel " + node.Interface)
+			if !ncutils.IsKernel() {
+				//wireguard.RemoveConf(node.Interface, true)
+				//ncutils.PrintLog("removed network tunnel "+node.Interface, 1)
 			}
 			node.SetID()
 			var header metadata.MD
@@ -149,10 +151,9 @@ func LeaveNetwork(network string) error {
 				grpc.Header(&header),
 			)
 			if err != nil {
-				log.Printf("Encountered error deleting node: %v", err)
-				log.Println(err)
+				ncutils.PrintLog("encountered error deleting node: "+err.Error(), 1)
 			} else {
-				log.Println("Removed machine from " + node.Network + " network on remote server")
+				ncutils.PrintLog("removed machine from "+node.Network+" network on remote server", 1)
 			}
 		}
 	}
@@ -160,17 +161,19 @@ func LeaveNetwork(network string) error {
 }
 
 func RemoveLocalInstance(cfg *config.ClientConfig, networkName string) error {
-	err := local.WipeLocal(networkName)
+	err := WipeLocal(networkName)
 	if err != nil {
-		log.Printf("Unable to wipe local config: %v", err)
+		ncutils.PrintLog("unable to wipe local config", 1)
 	} else {
-		log.Println("Removed " + networkName + " network locally")
+		ncutils.PrintLog("removed "+networkName+" network locally", 1)
 	}
 	if cfg.Daemon != "off" {
-		if netclientutils.IsWindows() {
+		if ncutils.IsWindows() {
 			// TODO: Remove job?
+		} else if ncutils.IsMac() {
+			//TODO: Delete mac daemon
 		} else {
-			err = local.RemoveSystemDServices(networkName)
+			err = daemon.RemoveSystemDServices(networkName)
 		}
 	}
 	return err
@@ -178,18 +181,18 @@ func RemoveLocalInstance(cfg *config.ClientConfig, networkName string) error {
 
 func DeleteInterface(ifacename string, postdown string) error {
 	var err error
-	if netclientutils.IsWindows() {
-		err = local.RemoveWindowsConf(ifacename)
+	if !ncutils.IsKernel() {
+		err = wireguard.RemoveConf(ifacename, true)
 	} else {
 		ipExec, errN := exec.LookPath("ip")
 		err = errN
 		if err != nil {
-			log.Println(err)
+			ncutils.PrintLog(err.Error(), 1)
 		}
-		_, err = local.RunCmd(ipExec+" link del "+ifacename, false)
+		_, err = ncutils.RunCmd(ipExec+" link del "+ifacename, false)
 		if postdown != "" {
 			runcmds := strings.Split(postdown, "; ")
-			err = local.RunCmds(runcmds, true)
+			err = ncutils.RunCmds(runcmds, true)
 		}
 	}
 	return err
@@ -212,9 +215,9 @@ func List() error {
 					"PrivateIPv6":    cfg.Node.Address6,
 					"PublicEndpoint": cfg.Node.Endpoint,
 				})
-			log.Println(network + ": " + string(jsoncfg))
+			fmt.Println(network + ": " + string(jsoncfg))
 		} else {
-			log.Println(network + ": Could not retrieve network configuration.")
+			ncutils.PrintLog(network+": Could not retrieve network configuration.", 1)
 		}
 	}
 	return nil
@@ -222,7 +225,7 @@ func List() error {
 
 func GetNetworks() ([]string, error) {
 	var networks []string
-	files, err := ioutil.ReadDir(netclientutils.GetNetclientPath())
+	files, err := ioutil.ReadDir(ncutils.GetNetclientPath())
 	if err != nil {
 		return networks, err
 	}
@@ -247,3 +250,107 @@ func stringAfter(original string, substring string) string {
 	}
 	return original[adjustedPosition:len(original)]
 }
+
+func WipeLocal(network string) error {
+	cfg, err := config.ReadConfig(network)
+	if err != nil {
+		return err
+	}
+	nodecfg := cfg.Node
+	ifacename := nodecfg.Interface
+
+	if ifacename != "" {
+		if !ncutils.IsKernel() {
+			if err = wireguard.RemoveConf(ifacename, true); err == nil {
+				ncutils.PrintLog("removed WireGuard interface: "+ifacename, 1)
+			}
+		} else {
+			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 {
+				ncutils.PrintLog("error running command: "+ipExec+" link del "+ifacename, 1)
+				ncutils.PrintLog(out, 1)
+			}
+			if nodecfg.PostDown != "" {
+				runcmds := strings.Split(nodecfg.PostDown, "; ")
+				_ = ncutils.RunCmds(runcmds, false)
+			}
+		}
+	}
+	home := ncutils.GetNetclientPathSpecific()
+	if ncutils.FileExists(home + "netconfig-" + network) {
+		_ = os.Remove(home + "netconfig-" + network)
+	}
+	if ncutils.FileExists(home + "nettoken-" + network) {
+		_ = os.Remove(home + "nettoken-" + network)
+	}
+	if ncutils.FileExists(home + "secret-" + network) {
+		_ = os.Remove(home + "secret-" + network)
+	}
+	if ncutils.FileExists(home + "wgkey-" + network) {
+		_ = os.Remove(home + "wgkey-" + network)
+	}
+	if ncutils.FileExists(home + "nm-" + network + ".conf") {
+		_ = os.Remove(home + "nm-" + network + ".conf")
+	}
+	return err
+}
+
+func getLocalIP(node models.Node) string {
+
+	var local string
+
+	ifaces, err := net.Interfaces()
+	if err != nil {
+		return local
+	}
+	_, localrange, err := net.ParseCIDR(node.LocalRange)
+	if err != nil {
+		return local
+	}
+
+	found := false
+	for _, i := range ifaces {
+		if i.Flags&net.FlagUp == 0 {
+			continue // interface down
+		}
+		if i.Flags&net.FlagLoopback != 0 {
+			continue // loopback interface
+		}
+		addrs, err := i.Addrs()
+		if err != nil {
+			return local
+		}
+		for _, addr := range addrs {
+			var ip net.IP
+			switch v := addr.(type) {
+			case *net.IPNet:
+				if !found {
+					ip = v.IP
+					local = ip.String()
+					if node.IsLocal == "yes" {
+						found = localrange.Contains(ip)
+					} else {
+						found = true
+					}
+				}
+			case *net.IPAddr:
+				if !found {
+					ip = v.IP
+					local = ip.String()
+					if node.IsLocal == "yes" {
+						found = localrange.Contains(ip)
+
+					} else {
+						found = true
+					}
+				}
+			}
+		}
+	}
+	return local
+}

+ 0 - 13
netclient/functions/install.go

@@ -1,13 +0,0 @@
-package functions
-
-import (
-	"github.com/gravitl/netmaker/netclient/config"
-	"github.com/gravitl/netmaker/netclient/local"
-)
-
-func InstallDaemon(cfg config.ClientConfig) error {
-
-	var err error
-	err = local.ConfigureSystemD(cfg.Network)
-	return err
-}

+ 23 - 32
netclient/functions/join.go

@@ -11,8 +11,9 @@ import (
 	"github.com/gravitl/netmaker/models"
 	"github.com/gravitl/netmaker/netclient/auth"
 	"github.com/gravitl/netmaker/netclient/config"
+	"github.com/gravitl/netmaker/netclient/daemon"
 	"github.com/gravitl/netmaker/netclient/local"
-	"github.com/gravitl/netmaker/netclient/netclientutils"
+	"github.com/gravitl/netmaker/netclient/ncutils"
 	"github.com/gravitl/netmaker/netclient/server"
 	"github.com/gravitl/netmaker/netclient/wireguard"
 	"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
@@ -27,7 +28,7 @@ func JoinNetwork(cfg config.ClientConfig, privateKey string) error {
 		return err
 	}
 
-	netclientutils.Log("attempting to join " + cfg.Network + " at " + cfg.Server.GRPCAddress)
+	ncutils.Log("joining " + cfg.Network + " at " + cfg.Server.GRPCAddress)
 	err := config.Write(&cfg, cfg.Network)
 	if err != nil {
 		return err
@@ -42,20 +43,20 @@ func JoinNetwork(cfg config.ClientConfig, privateKey string) error {
 		cfg.Node.LocalAddress = getLocalIP(cfg.Node)
 	}
 	if cfg.Node.Password == "" {
-		cfg.Node.Password = netclientutils.GenPass()
+		cfg.Node.Password = ncutils.GenPass()
 	}
 	auth.StoreSecret(cfg.Node.Password, cfg.Node.Network)
 
-	// set endpoint if blank. set to local if local net, retrieve from function if not 
+	// set endpoint if blank. set to local if local net, retrieve from function if not
 	if cfg.Node.Endpoint == "" {
 		if cfg.Node.IsLocal == "yes" && cfg.Node.LocalAddress != "" {
 			cfg.Node.Endpoint = cfg.Node.LocalAddress
 		} else {
-			cfg.Node.Endpoint, err = netclientutils.GetPublicIP()
+			cfg.Node.Endpoint, err = ncutils.GetPublicIP()
 
 		}
 		if err != nil || cfg.Node.Endpoint == "" {
-			netclientutils.Log("Error setting cfg.Node.Endpoint.")
+			ncutils.Log("Error setting cfg.Node.Endpoint.")
 			return err
 		}
 	}
@@ -71,7 +72,7 @@ func JoinNetwork(cfg config.ClientConfig, privateKey string) error {
 
 	// Find and set node MacAddress
 	if cfg.Node.MacAddress == "" {
-		macs, err := netclientutils.GetMacAddr()
+		macs, err := ncutils.GetMacAddr()
 		if err != nil {
 			return err
 		} else if len(macs) == 0 {
@@ -83,8 +84,8 @@ func JoinNetwork(cfg config.ClientConfig, privateKey string) error {
 
 	var wcclient nodepb.NodeServiceClient
 
-	conn, err := grpc.Dial(cfg.Server.GRPCAddress, 
-		netclientutils.GRPCRequestOpts(cfg.Server.GRPCSSL))
+	conn, err := grpc.Dial(cfg.Server.GRPCAddress,
+		ncutils.GRPCRequestOpts(cfg.Server.GRPCSSL))
 
 	if err != nil {
 		log.Fatalf("Unable to establish client connection to "+cfg.Server.GRPCAddress+": %v", err)
@@ -129,7 +130,7 @@ func JoinNetwork(cfg config.ClientConfig, privateKey string) error {
 	if err != nil {
 		return err
 	}
-	log.Println("node created on remote server...updating configs")
+	ncutils.PrintLog("node created on remote server...updating configs", 1)
 
 	nodeData := res.Data
 	var node models.Node
@@ -138,14 +139,14 @@ func JoinNetwork(cfg config.ClientConfig, privateKey string) error {
 	}
 
 	// get free port based on returned default listen port
-	node.ListenPort, err = netclientutils.GetFreePort(node.ListenPort)
+	node.ListenPort, err = ncutils.GetFreePort(node.ListenPort)
 	if err != nil {
 		fmt.Printf("Error retrieving port: %v", err)
 	}
-	
+
 	// safety check. If returned node from server is local, but not currently configured as local, set to local addr
 	if cfg.Node.IsLocal != "yes" && node.IsLocal == "yes" && node.LocalRange != "" {
-		node.LocalAddress, err = netclientutils.GetLocalIP(node.LocalRange)
+		node.LocalAddress, err = ncutils.GetLocalIP(node.LocalRange)
 		if err != nil {
 			return err
 		}
@@ -161,45 +162,35 @@ func JoinNetwork(cfg config.ClientConfig, privateKey string) error {
 		return err
 	}
 
-	// pushing any local changes to server before starting wireguard 
+	// pushing any local changes to server before starting wireguard
 	err = Push(cfg.Network)
 	if err != nil {
 		return err
 	}
 
 	if node.IsPending == "yes" {
-		netclientutils.Log("Node is marked as PENDING.")
-		netclientutils.Log("Awaiting approval from Admin before configuring WireGuard.")
+		ncutils.Log("Node is marked as PENDING.")
+		ncutils.Log("Awaiting approval from Admin before configuring WireGuard.")
 		if cfg.Daemon != "off" {
-			if netclientutils.IsWindows() {
-				// handle daemon here..
-				err = local.CreateAndRunWindowsDaemon()
-			} else {
-				err = local.ConfigureSystemD(cfg.Network)
-			}
-			return err
+			return daemon.InstallDaemon(cfg)
 		}
 	}
 
-	netclientutils.Log("retrieving remote peers")
+	ncutils.Log("retrieving remote peers")
 	peers, hasGateway, gateways, err := server.GetPeers(node.MacAddress, cfg.Network, cfg.Server.GRPCAddress, node.IsDualStack == "yes", node.IsIngressGateway == "yes")
 
-	if err != nil && !netclientutils.IsEmptyRecord(err) {
-		netclientutils.Log("failed to retrieve peers")
+	if err != nil && !ncutils.IsEmptyRecord(err) {
+		ncutils.Log("failed to retrieve peers")
 		return err
 	}
 
-	netclientutils.Log("starting wireguard")
+	ncutils.Log("starting wireguard")
 	err = wireguard.InitWireguard(&node, privateKey, peers, hasGateway, gateways)
 	if err != nil {
 		return err
 	}
 	if cfg.Daemon != "off" {
-		if netclientutils.IsWindows() {
-			err = local.CreateAndRunWindowsDaemon()
-		} else {
-			err = local.ConfigureSystemD(cfg.Network)
-		}
+		err = daemon.InstallDaemon(cfg)
 	}
 	if err != nil {
 		return err

+ 0 - 62
netclient/functions/joinutils.go

@@ -1,62 +0,0 @@
-package functions
-
-import (
-	"github.com/gravitl/netmaker/models"
-	"net"
-)
-
-
-func getLocalIP(node models.Node) string{
-
-	var local string
-
-	ifaces, err := net.Interfaces()
-	if err != nil {
-		return local
-	}
-	_, localrange, err := net.ParseCIDR(node.LocalRange)
-	if err != nil {
-		return local
-	}
-
-	found := false
-	for _, i := range ifaces {
-		if i.Flags&net.FlagUp == 0 {
-			continue // interface down
-		}
-		if i.Flags&net.FlagLoopback != 0 {
-			continue // loopback interface
-		}
-		addrs, err := i.Addrs()
-		if err != nil {
-			return local
-		}
-		for _, addr := range addrs {
-			var ip net.IP
-			switch v := addr.(type) {
-			case *net.IPNet:
-				if !found {
-					ip = v.IP
-					local = ip.String()
-					if node.IsLocal == "yes" {
-						found = localrange.Contains(ip)
-					} else {
-						found = true
-					}
-				}
-			case *net.IPAddr:
-				if !found {
-					ip = v.IP
-					local = ip.String()
-					if node.IsLocal == "yes" {
-						found = localrange.Contains(ip)
-
-					} else {
-						found = true
-					}
-				}
-			}
-		}
-	}
-	return local
-}

+ 0 - 12
netclient/functions/logging.go

@@ -1,12 +0,0 @@
-package functions
-
-import (
-	"log"
-)
-
-func PrintLog(message string, loglevel int) {
-	log.SetFlags(log.Flags() &^ (log.Llongfile | log.Lshortfile))
-	if loglevel == 0 {
-			log.Println(message)
-	}
-}

+ 5 - 5
netclient/local/dns.go

@@ -9,7 +9,7 @@ import (
 	"log"
 	"os/exec"
 
-	"github.com/gravitl/netmaker/netclient/netclientutils"
+	"github.com/gravitl/netmaker/netclient/ncutils"
 )
 
 func SetDNS(nameserver string) error {
@@ -34,7 +34,7 @@ func SetDNS(nameserver string) error {
 }
 
 func UpdateDNS(ifacename string, network string, nameserver string) error {
-	if netclientutils.IsWindows() {
+	if ncutils.IsWindows() {
 		return nil
 	}
 	_, err := exec.LookPath("resolvectl")
@@ -42,15 +42,15 @@ func UpdateDNS(ifacename string, network string, nameserver string) error {
 		log.Println(err)
 		log.Println("WARNING: resolvectl not present. Unable to set dns. Install resolvectl or run manually.")
 	} else {
-		_, err = RunCmd("resolvectl domain " + ifacename + " ~" + network, true)
+		_, err = ncutils.RunCmd("resolvectl domain "+ifacename+" ~"+network, true)
 		if err != nil {
 			log.Println("WARNING: Error encountered setting domain on dns. Aborted setting dns.")
 		} else {
-			_, err = RunCmd("resolvectl default-route " + ifacename + " false", true)
+			_, err = ncutils.RunCmd("resolvectl default-route "+ifacename+" false", true)
 			if err != nil {
 				log.Println("WARNING: Error encountered setting default-route on dns. Aborted setting dns.")
 			} else {
-				_, err = RunCmd("resolvectl dns " + ifacename + " " + nameserver, true)
+				_, err = ncutils.RunCmd("resolvectl dns "+ifacename+" "+nameserver, true)
 				if err != nil {
 					log.Println("WARNING: Error encountered running resolvectl dns " + ifacename + " " + nameserver)
 				}

+ 38 - 257
netclient/local/local.go

@@ -3,17 +3,11 @@ package local
 import (
 	//"github.com/davecgh/go-spew/spew"
 	"errors"
-	"io"
-	"io/ioutil"
 	"log"
-	"os"
-	"os/exec"
-	"path/filepath"
 	"runtime"
 	"strings"
 
-	"github.com/gravitl/netmaker/netclient/config"
-	"github.com/gravitl/netmaker/netclient/netclientutils"
+	"github.com/gravitl/netmaker/netclient/ncutils"
 )
 
 func SetIPForwarding() error {
@@ -22,6 +16,8 @@ func SetIPForwarding() error {
 	switch os {
 	case "linux":
 		err = SetIPForwardingLinux()
+	case "darwin":
+		err = SetIPForwardingMac()
 	default:
 		err = errors.New("This OS is not supported")
 	}
@@ -29,14 +25,14 @@ func SetIPForwarding() error {
 }
 
 func SetIPForwardingLinux() error {
-	out, err := RunCmd("sysctl net.ipv4.ip_forward", true)
+	out, err := ncutils.RunCmd("sysctl net.ipv4.ip_forward", true)
 	if err != nil {
 		log.Println("WARNING: Error encountered setting ip forwarding. This can break functionality.")
 		return err
 	} else {
 		s := strings.Fields(string(out))
 		if s[2] != "1" {
-			_, err = RunCmd("sysctl -w net.ipv4.ip_forward=1", true)
+			_, err = ncutils.RunCmd("sysctl -w net.ipv4.ip_forward=1", true)
 			if err != nil {
 				log.Println("WARNING: Error encountered setting ip forwarding. You may want to investigate this.")
 				return err
@@ -46,274 +42,59 @@ func SetIPForwardingLinux() error {
 	return nil
 }
 
-func RunCmd(command string, printerr bool) (string, error) {
-	args := strings.Fields(command)
-	out, err := exec.Command(args[0], args[1:]...).CombinedOutput()
-	if err != nil && printerr {
-		log.Println("error running command:",command)
-		log.Println(string(out))
-	}
-	return string(out), err
-}
-
-func RunCmds(commands []string, printerr bool) error {
-	var err error
-	for _, command := range commands {
-		args := strings.Fields(command)
-		out, err := exec.Command(args[0], args[1:]...).CombinedOutput()
-		if err != nil && printerr {
-			log.Println("error running command:",command)
-			log.Println(string(out))
-		}
+func SetIPForwardingMac() error {
+	_, err := ncutils.RunCmd("sysctl -w net.inet.ip.forwarding=1", true)
+	if err != nil {
+		log.Println("WARNING: Error encountered setting ip forwarding. This can break functionality.")
 	}
 	return err
 }
 
-func FileExists(f string) bool {
-	info, err := os.Stat(f)
-	if os.IsNotExist(err) {
+func IsWGInstalled() bool {
+	out, err := ncutils.RunCmd("wg help", true)
+	if err != nil {
 		return false
 	}
-	return !info.IsDir()
+	return strings.Contains(out, "Available subcommand")
 }
 
-func ConfigureSystemD(network string) error {
-	/*
-		path, err := os.Getwd()
-		if err != nil {
-			log.Println(err)
-			return err
-		}
-	*/
-	//binarypath := path  + "/netclient"
-	if netclientutils.IsWindows() {
-		return nil
-	}
-	dir, err := filepath.Abs(filepath.Dir(os.Args[0]))
+func GetMacIface(addr string) (string, error) {
+	out, err := ncutils.RunCmd("route get "+addr, false)
+	var iface string
 	if err != nil {
-		return err
-	}
-	binarypath := dir + "/netclient"
-
-	_, err = os.Stat("/etc/netclient")
-	if os.IsNotExist(err) {
-		os.Mkdir("/etc/netclient", 744)
-	} else if err != nil {
-		log.Println("couldnt find or create /etc/netclient")
-		return err
-	}
-
-	if !FileExists("/usr/local/bin/netclient") {
-		os.Symlink("/etc/netclient/netclient", "/usr/local/bin/netclient")
-		/*
-			_, err = copy(binarypath, "/usr/local/bin/netclient")
-			if err != nil {
-				log.Println(err)
-				return err
-			}
-		*/
-	}
-	if !FileExists("/etc/netclient/netclient") {
-		_, err = copy(binarypath, "/etc/netclient/netclient")
-		if err != nil {
-			log.Println(err)
-			return err
-		}
-	}
-
-	systemservice := `[Unit]
-Description=Network Check
-Wants=netclient.timer
-
-[Service]
-Type=simple
-ExecStart=/etc/netclient/netclient checkin -n %i
-
-[Install]
-WantedBy=multi-user.target
-`
-
-	systemtimer := `[Unit]
-Description=Calls the Netmaker Mesh Client Service
-
-`
-	systemtimer = systemtimer + "Requires=netclient@" + network + ".service"
-
-	systemtimer = systemtimer +
-		`
-
-[Timer]
-
-`
-	systemtimer = systemtimer + "Unit=netclient@" + network + ".service"
-
-	systemtimer = systemtimer +
-		`
-
-OnCalendar=*:*:0/30
-
-[Install]
-WantedBy=timers.target
-`
-
-	servicebytes := []byte(systemservice)
-	timerbytes := []byte(systemtimer)
-
-	if !FileExists("/etc/systemd/system/[email protected]") {
-		err = ioutil.WriteFile("/etc/systemd/system/[email protected]", servicebytes, 0644)
-		if err != nil {
-			log.Println(err)
-			return err
-		}
+		return iface, errors.New(string(out))
 	}
-
-	if !FileExists("/etc/systemd/system/netclient-" + network + ".timer") {
-		err = ioutil.WriteFile("/etc/systemd/system/netclient-"+network+".timer", timerbytes, 0644)
-		if err != nil {
-			log.Println(err)
-			return err
+	for _, line := range strings.Split(strings.TrimSuffix(string(out), "\n"), "\n") {
+		if strings.Contains(line, "interface: ") {
+			iface = getLineAfter(string(out), "interface: ")
+			iface = strings.Split(iface, "\n")[0]
+			break
 		}
 	}
-
-	_, _ = RunCmd("systemctl enable [email protected]", true)
-	_, _ = RunCmd("systemctl daemon-reload", true)
-	_, _ = RunCmd("systemctl enable netclient-" + network + ".timer", true)
-	_, _ = RunCmd("systemctl start netclient-" + network + ".timer", true)
-	return nil
-}
-
-func isOnlyService(network string) (bool, error) {
-	isonly := false
-	files, err := filepath.Glob("/etc/netclient/netconfig-*")
-	if err != nil {
-		return isonly, err
-	}
-	count := len(files)
-	if count == 0 {
-		isonly = true
-	}
-	return isonly, err
-
-}
-
-func RemoveSystemDServices(network string) error {
-	//sysExec, err := exec.LookPath("systemctl")
-	if !netclientutils.IsWindows() {
-		fullremove, err := isOnlyService(network)
-		if err != nil {
-			log.Println(err)
-		}
-
-		if fullremove {
-			_, err = RunCmd("systemctl disable [email protected]", true)
-		}
-		_, _ = RunCmd("systemctl daemon-reload", true)
-
-		if FileExists("/etc/systemd/system/netclient-" + network + ".timer") {
-			_, _ = RunCmd("systemctl disable netclient-" + network + ".timer", true)
-		}
-		if fullremove {
-			if FileExists("/etc/systemd/system/[email protected]") {
-				err = os.Remove("/etc/systemd/system/[email protected]")
-			}
-		}
-		if FileExists("/etc/systemd/system/netclient-" + network + ".timer") {
-			err = os.Remove("/etc/systemd/system/netclient-" + network + ".timer")
-		}
-		if err != nil {
-			log.Println("Error removing file. Please investigate.")
-			log.Println(err)
-		}
-		_, _ = RunCmd("systemctl daemon-reload", true)
-		_, _ = RunCmd("systemctl reset-failed", true)
+	if iface == "" {
+		err = errors.New("could not find iface for ip addr " + addr)
 	}
-	return nil
+	return iface, err
 }
 
-func WipeLocal(network string) error {
-	cfg, err := config.ReadConfig(network)
-	if err != nil {
-		return err
-	}
-	nodecfg := cfg.Node
-	ifacename := nodecfg.Interface
-
-	home := netclientutils.GetNetclientPathSpecific()
-	if FileExists(home + "netconfig-" + network) {
-		_ = os.Remove(home + "netconfig-" + network)
+func getLineAfter(value string, a string) string {
+	// Get substring after a string.
+	pos := strings.LastIndex(value, a)
+	if pos == -1 {
+		return ""
 	}
-	if FileExists(home + "nettoken-" + network) {
-		_ = os.Remove(home + "nettoken-" + network)
-	}
-	if FileExists(home + "secret-" + network) {
-		_ = os.Remove(home + "secret-" + network)
-	}
-	if FileExists(home + "wgkey-" + network) {
-		_ = os.Remove(home + "wgkey-" + network)
-	}
-	if FileExists(home + "nm-" + network + ".conf") {
-		_ = os.Remove(home + "nm-" + network + ".conf")
-	}
-
-	if ifacename != "" {
-		if netclientutils.IsWindows() {
-			if err = RemoveWindowsConf(ifacename); err == nil {
-				log.Println("removed Windows interface", ifacename)
-			}
-		} else {
-			ipExec, err := exec.LookPath("ip")
-			if err != nil {
-				return err
-			}
-			out, err := RunCmd(ipExec + " link del " + ifacename, false)
-			dontprint := strings.Contains(out, "does not exist") || strings.Contains(out, "Cannot find device")
-			if err != nil && !dontprint {
-				log.Println("error running command:",ipExec + " link del " + ifacename)
-				log.Println(out)
-			}
-			if nodecfg.PostDown != "" {
-				runcmds := strings.Split(nodecfg.PostDown, "; ")
-				_ = RunCmds(runcmds, false)
-			}
-		}
+	adjustedPos := pos + len(a)
+	if adjustedPos >= len(value) {
+		return ""
 	}
-	return err
+	return value[adjustedPos:len(value)]
 }
 
 func HasNetwork(network string) bool {
 
-	if netclientutils.IsWindows() {
-		return FileExists(netclientutils.GetNetclientPathSpecific() + "netconfig-" + network)
-	}
-	return FileExists("/etc/systemd/system/netclient-"+network+".timer") ||
-		FileExists(netclientutils.GetNetclientPathSpecific()+"netconfig-"+network)
-}
-
-func copy(src, dst string) (int64, error) {
-	sourceFileStat, err := os.Stat(src)
-	if err != nil {
-		return 0, err
-	}
-
-	if !sourceFileStat.Mode().IsRegular() {
-		return 0, errors.New(src + " is not a regular file")
-	}
-
-	source, err := os.Open(src)
-	if err != nil {
-		return 0, err
-	}
-	defer source.Close()
-
-	destination, err := os.Create(dst)
-	if err != nil {
-		return 0, err
-	}
-	defer destination.Close()
-	nBytes, err := io.Copy(destination, source)
-	err = os.Chmod(dst, 0755)
-	if err != nil {
-		log.Println(err)
+	if ncutils.IsWindows() {
+		return ncutils.FileExists(ncutils.GetNetclientPathSpecific() + "netconfig-" + network)
 	}
-	return nBytes, err
+	return ncutils.FileExists("/etc/systemd/system/netclient-"+network+".timer") ||
+		ncutils.FileExists(ncutils.GetNetclientPathSpecific()+"netconfig-"+network)
 }

+ 0 - 175
netclient/local/windows.go

@@ -1,175 +0,0 @@
-package local
-
-import (
-	"errors"
-	"fmt"
-	"io"
-	"io/ioutil"
-	"log"
-	"net/http"
-	"os"
-	"strings"
-
-	"github.com/gravitl/netmaker/netclient/netclientutils"
-)
-
-func IsWindowsWGInstalled() bool {
-	out, err := RunCmd("wg help", true)
-	if err != nil {
-		return false
-	}
-	return strings.Contains(out, "Available subcommand")
-}
-
-func ApplyWindowsConf(confPath string) error {
-	if _, err := RunCmd("wireguard.exe /installtunnelservice "+confPath, true); err != nil {
-		return err
-	}
-	return nil
-}
-
-func RemoveWindowsConf(ifacename string) error {
-	if _, err := RunCmd("wireguard.exe /uninstalltunnelservice "+ifacename, true); err != nil {
-		return err
-	}
-	return nil
-}
-
-func writeServiceConfig() error {
-	serviceConfigPath := netclientutils.GetNetclientPathSpecific() + "winsw.xml"
-	scriptString := fmt.Sprintf(`<service>
-<id>netclient</id>
-<name>Netclient</name>
-<description>Connects Windows nodes to one or more Netmaker networks.</description>
-<executable>%v</executable>
-<log mode="roll"></log>
-</service>
-`, strings.Replace(netclientutils.GetNetclientPathSpecific()+"netclient.exe", `\\`, `\`, -1))
-	if !FileExists(serviceConfigPath) {
-		err := ioutil.WriteFile(serviceConfigPath, []byte(scriptString), 0644)
-		if err != nil {
-			return err
-		}
-		netclientutils.Log("wrote the daemon config file to the Netclient directory")
-	}
-	return nil
-}
-
-// == Daemon ==
-func StopWindowsDaemon() {
-	netclientutils.Log("no networks detected, stopping Windows, Netclient daemon")
-	// stop daemon, will not overwrite
-	RunCmd(strings.Replace(netclientutils.GetNetclientPathSpecific(), `\\`, `\`, -1)+`winsw.exe stop`, true)
-}
-
-func RemoveWindowsDaemon() {
-	// uninstall daemon, will not restart or start another
-	RunCmd(strings.Replace(netclientutils.GetNetclientPathSpecific(), `\\`, `\`, -1)+`winsw.exe uninstall`, true)
-	netclientutils.Log("uninstalled Windows, Netclient daemon")
-}
-
-func copyWinswOver() error {
-
-	input, err := ioutil.ReadFile(".\\winsw.exe")
-	if err != nil {
-		netclientutils.Log("failed to find winsw.exe")
-		return err
-	}
-	if err = ioutil.WriteFile(netclientutils.GetNetclientPathSpecific()+"winsw.exe", input, 0644); err != nil {
-		netclientutils.Log("failed to copy winsw.exe to " + netclientutils.GetNetclientPath())
-		return err
-	}
-	if err = os.Remove(".\\winsw.exe"); err != nil {
-		netclientutils.Log("failed to cleanup local winsw.exe, feel free to delete it")
-		return err
-	}
-	netclientutils.Log("finished copying winsw.exe")
-	return nil
-}
-
-func downloadWinsw() error {
-	fullURLFile := "https://github.com/winsw/winsw/releases/download/v2.11.0/WinSW-x64.exe"
-	fileName := "winsw.exe"
-
-	// Create the file
-	file, err := os.Create(fileName)
-	if err != nil {
-		netclientutils.Log("could not create file on OS for Winsw")
-		return err
-	}
-	client := http.Client{
-		CheckRedirect: func(r *http.Request, via []*http.Request) error {
-			r.URL.Opaque = r.URL.Path
-			return nil
-		},
-	}
-	// Put content on file
-	netclientutils.Log("downloading service tool...")
-	resp, err := client.Get(fullURLFile)
-	if err != nil {
-		netclientutils.Log("could not GET Winsw")
-		return err
-	}
-	defer resp.Body.Close()
-
-	_, err = io.Copy(file, resp.Body)
-	if err != nil {
-		netclientutils.Log("could not mount winsw.exe")
-		return err
-	}
-	defer file.Close()
-	netclientutils.Log("finished downloading Winsw")
-	return nil
-}
-
-func CreateAndRunMacDaemon() error {
-	log.Println("TODO: Create Mac Daemon")
-	return errors.New("no mac daemon yet")
-}
-
-func CreateAndRunWindowsDaemon() error {
-
-	if !FileExists(netclientutils.GetNetclientPathSpecific() + "winsw.xml") {
-		if err := writeServiceConfig(); err != nil {
-			return err
-		}
-	}
-
-	if !FileExists(netclientutils.GetNetclientPathSpecific() + "winsw.exe") {
-		netclientutils.Log("performing first time daemon setup")
-		if !FileExists(".\\winsw.exe") {
-			err := downloadWinsw()
-			if err != nil {
-				return err
-			}
-		}
-		err := copyWinswOver()
-		if err != nil {
-			return err
-		}
-		netclientutils.Log("finished daemon setup")
-	}
-	// install daemon, will not overwrite
-	RunCmd(strings.Replace(netclientutils.GetNetclientPathSpecific(), `\\`, `\`, -1)+`winsw.exe install`, true)
-	// start daemon, will not restart or start another
-	RunCmd(strings.Replace(netclientutils.GetNetclientPathSpecific(), `\\`, `\`, -1)+`winsw.exe start`, true)
-	netclientutils.Log(strings.Replace(netclientutils.GetNetclientPathSpecific(), `\\`, `\`, -1) + `winsw.exe start`)
-	return nil
-}
-
-func CleanupWindows() {
-	if !FileExists(netclientutils.GetNetclientPathSpecific() + "winsw.xml") {
-		writeServiceConfig()
-	}
-	StopWindowsDaemon()
-	RemoveWindowsDaemon()
-	os.RemoveAll(netclientutils.GetNetclientPath())
-	log.Println("Netclient on Windows, uninstalled")
-}
-
-func CleanupMac() {
-	//StopWindowsDaemon()
-	//RemoveWindowsDaemon()
-	//os.RemoveAll(netclientutils.GetNetclientPath())
-	log.Println("TODO: Not implemented yet")
-}

+ 14 - 13
netclient/main.go

@@ -8,14 +8,15 @@ import (
 	"os"
 	"os/exec"
 	"os/signal"
+	"runtime/debug"
 	"strconv"
 	"syscall"
-	"runtime/debug"
+
 	"github.com/gravitl/netmaker/netclient/command"
 	"github.com/gravitl/netmaker/netclient/config"
 	"github.com/gravitl/netmaker/netclient/local"
+	"github.com/gravitl/netmaker/netclient/ncutils"
 	"github.com/gravitl/netmaker/netclient/ncwindows"
-	"github.com/gravitl/netmaker/netclient/netclientutils"
 	"github.com/urfave/cli/v2"
 )
 
@@ -23,7 +24,7 @@ func main() {
 	app := cli.NewApp()
 	app.Name = "Netclient CLI"
 	app.Usage = "Netmaker's netclient agent and CLI. Used to perform interactions with Netmaker server and set local WireGuard config."
-	app.Version = "v0.7.3"
+	app.Version = "v0.8.0"
 
 	cliFlags := []cli.Flag{
 		&cli.StringFlag{
@@ -320,11 +321,11 @@ func main() {
 
 	setGarbageCollection()
 
-	if netclientutils.IsWindows() {
+	if ncutils.IsWindows() {
 		ncwindows.InitWindows()
 	} else {
 		// start our application
-		out, err := local.RunCmd("id -u", true)
+		out, err := ncutils.RunCmd("id -u", true)
 
 		if err != nil {
 			log.Fatal(out, err)
@@ -345,12 +346,12 @@ func main() {
 			log.Fatal("WireGuard not installed. Please install WireGuard (wireguard-tools) and try again.")
 		}
 	}
-	if netclientutils.IsWindows() {
-		if !local.IsWindowsWGInstalled() {
-			log.Fatal("Please install Windows WireGuard before using Gravitl Netclient. https://download.wireguard.com/windows-client/wireguard-installer.exe")
+	if !ncutils.IsKernel() {
+		if !local.IsWGInstalled() {
+			log.Fatal("Please install Windows WireGuard before using Gravitl Netclient. https://download.wireguard.com")
 		}
 	}
-	if len(os.Args) == 1 && netclientutils.IsWindows() {
+	if len(os.Args) == 1 && ncutils.IsWindows() {
 		c := make(chan os.Signal)
 		signal.Notify(c, os.Interrupt, syscall.SIGTERM)
 		go func() {
@@ -367,9 +368,9 @@ func main() {
 	}
 }
 
-func setGarbageCollection(){
-	_, gcset := os.LookupEnv("GOGC");
+func setGarbageCollection() {
+	_, gcset := os.LookupEnv("GOGC")
 	if !gcset {
-		debug.SetGCPercent(netclientutils.DEFAULT_GC_PERCENT)
+		debug.SetGCPercent(ncutils.DEFAULT_GC_PERCENT)
 	}
-}
+}

+ 82 - 2
netclient/netclientutils/netclientutils.go → netclient/ncutils/netclientutils.go

@@ -1,15 +1,17 @@
-package netclientutils
+package ncutils
 
 import (
 	"crypto/tls"
 	"errors"
 	"fmt"
+	"io"
 	"io/ioutil"
 	"log"
 	"math/rand"
 	"net"
 	"net/http"
 	"os"
+	"os/exec"
 	"runtime"
 	"strconv"
 	"strings"
@@ -39,13 +41,20 @@ func IsWindows() bool {
 }
 
 func IsMac() bool {
-	return runtime.GOOS == "macos"
+	return runtime.GOOS == "darwin"
 }
 
 func IsLinux() bool {
 	return runtime.GOOS == "linux"
 }
 
+func IsKernel() bool {
+	//TODO
+	//Replace && true with some config file value
+	//This value should be something like kernelmode, which should be 'on' by default.
+	return IsLinux() && true
+}
+
 // == database returned nothing error ==
 func IsEmptyRecord(err error) bool {
 	if err == nil {
@@ -256,6 +265,8 @@ func GetHomeDirWindows() string {
 func GetNetclientPath() string {
 	if IsWindows() {
 		return WINDOWS_APP_DATA_PATH
+	} else if IsMac() {
+		return "/etc/netclient/"
 	} else {
 		return LINUX_APP_DATA_PATH
 	}
@@ -264,6 +275,8 @@ func GetNetclientPath() string {
 func GetNetclientPathSpecific() string {
 	if IsWindows() {
 		return WINDOWS_APP_DATA_PATH + "\\"
+	} else if IsMac() {
+		return "/etc/netclient/"
 	} else {
 		return LINUX_APP_DATA_PATH + "/"
 	}
@@ -278,3 +291,70 @@ func GRPCRequestOpts(isSecure string) grpc.DialOption {
 	}
 	return requestOpts
 }
+
+func Copy(src, dst string) (int64, error) {
+	sourceFileStat, err := os.Stat(src)
+	if err != nil {
+		return 0, err
+	}
+
+	if !sourceFileStat.Mode().IsRegular() {
+		return 0, errors.New(src + " is not a regular file")
+	}
+
+	source, err := os.Open(src)
+	if err != nil {
+		return 0, err
+	}
+	defer source.Close()
+
+	destination, err := os.Create(dst)
+	if err != nil {
+		return 0, err
+	}
+	defer destination.Close()
+	nBytes, err := io.Copy(destination, source)
+	err = os.Chmod(dst, 0755)
+	if err != nil {
+		log.Println(err)
+	}
+	return nBytes, err
+}
+
+func RunCmd(command string, printerr bool) (string, error) {
+	args := strings.Fields(command)
+	out, err := exec.Command(args[0], args[1:]...).CombinedOutput()
+	if err != nil && printerr {
+		log.Println("error running command:", command)
+		log.Println(strings.TrimSuffix(string(out), "\n"))
+	}
+	return string(out), err
+}
+
+func RunCmds(commands []string, printerr bool) error {
+	var err error
+	for _, command := range commands {
+		args := strings.Fields(command)
+		out, err := exec.Command(args[0], args[1:]...).CombinedOutput()
+		if err != nil && printerr {
+			log.Println("error running command:", command)
+			log.Println(strings.TrimSuffix(string(out), "\n"))
+		}
+	}
+	return err
+}
+
+func FileExists(f string) bool {
+	info, err := os.Stat(f)
+	if os.IsNotExist(err) {
+		return false
+	}
+	return !info.IsDir()
+}
+
+func PrintLog(message string, loglevel int) {
+	log.SetFlags(log.Flags() &^ (log.Llongfile | log.Lshortfile))
+	if loglevel < 2 {
+		log.Println("[netclient]", message)
+	}
+}

+ 7 - 7
netclient/ncwindows/windows.go

@@ -5,21 +5,21 @@ import (
 	"log"
 	"os"
 
-	"github.com/gravitl/netmaker/netclient/netclientutils"
+	"github.com/gravitl/netmaker/netclient/ncutils"
 )
 
 // Initialize windows directory & files and such
 func InitWindows() {
 
-	_, directoryErr := os.Stat(netclientutils.GetNetclientPath()) // Check if data directory exists or not
-	if os.IsNotExist(directoryErr) {                              // create a data directory
-		os.Mkdir(netclientutils.GetNetclientPath(), 0755)
+	_, directoryErr := os.Stat(ncutils.GetNetclientPath()) // Check if data directory exists or not
+	if os.IsNotExist(directoryErr) {                       // create a data directory
+		os.Mkdir(ncutils.GetNetclientPath(), 0755)
 	}
 	wdPath, wdErr := os.Getwd() // get the current working directory
 	if wdErr != nil {
 		log.Fatal("failed to get current directory..")
 	}
-	_, dataNetclientErr := os.Stat(netclientutils.GetNetclientPathSpecific() + "netclient.exe")
+	_, dataNetclientErr := os.Stat(ncutils.GetNetclientPathSpecific() + "netclient.exe")
 	_, currentNetclientErr := os.Stat(wdPath + "\\netclient.exe")
 	if os.IsNotExist(dataNetclientErr) { // check and see if netclient.exe is in appdata
 		if currentNetclientErr == nil { // copy it if it exists locally
@@ -28,8 +28,8 @@ func InitWindows() {
 				log.Println("failed to find netclient.exe")
 				return
 			}
-			if err = ioutil.WriteFile(netclientutils.GetNetclientPathSpecific()+"netclient.exe", input, 0644); err != nil {
-				log.Println("failed to copy netclient.exe to", netclientutils.GetNetclientPath())
+			if err = ioutil.WriteFile(ncutils.GetNetclientPathSpecific()+"netclient.exe", input, 0644); err != nil {
+				log.Println("failed to copy netclient.exe to", ncutils.GetNetclientPath())
 				return
 			}
 		}

+ 20 - 25
netclient/server/grpc.go

@@ -11,9 +11,8 @@ import (
 	nodepb "github.com/gravitl/netmaker/grpc"
 	"github.com/gravitl/netmaker/models"
 	"github.com/gravitl/netmaker/netclient/auth"
-	"github.com/gravitl/netmaker/netclient/netclientutils"
 	"github.com/gravitl/netmaker/netclient/config"
-	"github.com/gravitl/netmaker/netclient/local"
+	"github.com/gravitl/netmaker/netclient/ncutils"
 	"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
 	"google.golang.org/grpc"
 	"google.golang.org/grpc/metadata"
@@ -24,8 +23,8 @@ const RELAY_KEEPALIVE_MARKER = "20007ms"
 func getGrpcClient(cfg *config.ClientConfig) (nodepb.NodeServiceClient, error) {
 	var wcclient nodepb.NodeServiceClient
 	// == GRPC SETUP ==
-	conn, err := grpc.Dial(cfg.Server.GRPCAddress, 
-		netclientutils.GRPCRequestOpts(cfg.Server.GRPCSSL))
+	conn, err := grpc.Dial(cfg.Server.GRPCAddress,
+		ncutils.GRPCRequestOpts(cfg.Server.GRPCSSL))
 
 	if err != nil {
 		return nil, err
@@ -68,6 +67,7 @@ func CheckIn(network string) (*models.Node, error) {
 	return &node, err
 }
 
+/*
 func RemoveNetwork(network string) error {
 	//need to  implement checkin on server side
 	cfg, err := config.ReadConfig(network)
@@ -79,8 +79,8 @@ func RemoveNetwork(network string) error {
 	log.Println("Deleting remote node with MAC: " + node.MacAddress)
 
 	var wcclient nodepb.NodeServiceClient
-	conn, err := grpc.Dial(cfg.Server.GRPCAddress, 
-		netclientutils.GRPCRequestOpts(cfg.Server.GRPCSSL))
+	conn, err := grpc.Dial(cfg.Server.GRPCAddress,
+		ncutils.GRPCRequestOpts(cfg.Server.GRPCSSL))
 	if err != nil {
 		log.Printf("Unable to establish client connection to "+servercfg.GRPCAddress+": %v", err)
 		//return err
@@ -110,16 +110,11 @@ func RemoveNetwork(network string) error {
 			}
 		}
 	}
-	err = local.WipeLocal(network)
-	if err != nil {
-		log.Printf("Unable to wipe local config: %v", err)
-	}
-	if cfg.Daemon != "off" {
-		err = local.RemoveSystemDServices(network)
-	}
+	//err = functions.RemoveLocalInstance(network)
+
 	return err
 }
-
+*/
 func GetPeers(macaddress string, network string, server string, dualstack bool, isIngressGateway bool) ([]wgtypes.PeerConfig, bool, []string, error) {
 	hasGateway := false
 	var gateways []string
@@ -137,8 +132,8 @@ func GetPeers(macaddress string, network string, server string, dualstack bool,
 		log.Fatalf("Issue with format of keepalive value. Please update netconfig: %v", err)
 	}
 
-	conn, err := grpc.Dial(cfg.Server.GRPCAddress, 
-		netclientutils.GRPCRequestOpts(cfg.Server.GRPCSSL))
+	conn, err := grpc.Dial(cfg.Server.GRPCAddress,
+		ncutils.GRPCRequestOpts(cfg.Server.GRPCSSL))
 
 	if err != nil {
 		log.Fatalf("Unable to establish client connection to localhost:50051: %v", err)
@@ -202,12 +197,12 @@ func GetPeers(macaddress string, network string, server string, dualstack bool,
 					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)
-			}		
+				ipnet := net.IPNet{
+					IP:   net.ParseIP(allowedIp),
+					Mask: net.CIDRMask(32, 32),
+				}
+				allowedips = append(allowedips, ipnet)
+			}
 		}
 		// handle egress gateway peers
 		if node.IsEgressGateway == "yes" {
@@ -273,7 +268,7 @@ func GetPeers(macaddress string, network string, server string, dualstack bool,
 		if err == nil {
 			peers = append(peers, extPeers...)
 		} else {
-			log.Println("ERROR RETRIEVING EXTERNAL PEERS",err)
+			log.Println("ERROR RETRIEVING EXTERNAL PEERS", err)
 		}
 	}
 	return peers, hasGateway, gateways, err
@@ -287,8 +282,8 @@ func GetExtPeers(macaddress string, network string, server string, dualstack boo
 	}
 	nodecfg := cfg.Node
 
-	conn, err := grpc.Dial(cfg.Server.GRPCAddress, 
-		netclientutils.GRPCRequestOpts(cfg.Server.GRPCSSL))	
+	conn, err := grpc.Dial(cfg.Server.GRPCAddress,
+		ncutils.GRPCRequestOpts(cfg.Server.GRPCSSL))
 	if err != nil {
 		log.Fatalf("Unable to establish client connection to localhost:50051: %v", err)
 	}

+ 306 - 0
netclient/wireguard/common.go

@@ -0,0 +1,306 @@
+package wireguard
+
+import (
+	"fmt"
+	"io/ioutil"
+	"log"
+	"os"
+	"os/exec"
+	"runtime"
+	"strconv"
+	"strings"
+
+	"github.com/gravitl/netmaker/models"
+	"github.com/gravitl/netmaker/netclient/config"
+	"github.com/gravitl/netmaker/netclient/local"
+	"github.com/gravitl/netmaker/netclient/ncutils"
+	"github.com/gravitl/netmaker/netclient/server"
+	"golang.zx2c4.com/wireguard/wgctrl"
+	"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
+	//homedir "github.com/mitchellh/go-homedir"
+)
+
+func SetPeers(iface string, keepalive int32, peers []wgtypes.PeerConfig) error {
+
+	client, err := wgctrl.New()
+	if err != nil {
+		ncutils.PrintLog("failed to start wgctrl", 0)
+		return err
+	}
+	device, err := client.Device(iface)
+	if err != nil {
+		ncutils.PrintLog("failed to parse interface", 0)
+		return err
+	}
+	devicePeers := device.Peers
+	if len(devicePeers) > 1 && len(peers) == 0 {
+		ncutils.PrintLog("no peers pulled", 1)
+		return err
+	}
+
+	for _, peer := range peers {
+
+		for _, currentPeer := range devicePeers {
+			if currentPeer.AllowedIPs[0].String() == peer.AllowedIPs[0].String() &&
+				currentPeer.PublicKey.String() != peer.PublicKey.String() {
+				_, err := ncutils.RunCmd("wg set "+iface+" peer "+currentPeer.PublicKey.String()+" remove", true)
+				if err != nil {
+					log.Println("error removing peer", peer.Endpoint.String())
+				}
+			}
+		}
+		udpendpoint := peer.Endpoint.String()
+		var allowedips string
+		var iparr []string
+		for _, ipaddr := range peer.AllowedIPs {
+			iparr = append(iparr, ipaddr.String())
+		}
+		allowedips = strings.Join(iparr, ",")
+		keepAliveString := strconv.Itoa(int(keepalive))
+		if keepAliveString == "0" {
+			keepAliveString = "5"
+		}
+		if peer.Endpoint != nil {
+			_, err = ncutils.RunCmd("wg set "+iface+" peer "+peer.PublicKey.String()+
+				" endpoint "+udpendpoint+
+				" persistent-keepalive "+keepAliveString+
+				" allowed-ips "+allowedips, true)
+		} else {
+			_, err = ncutils.RunCmd("wg set "+iface+" peer "+peer.PublicKey.String()+
+				" persistent-keepalive "+keepAliveString+
+				" allowed-ips "+allowedips, true)
+		}
+		if err != nil {
+			log.Println("error setting peer", peer.PublicKey.String())
+		}
+	}
+
+	for _, currentPeer := range devicePeers {
+		shouldDelete := true
+		for _, peer := range peers {
+			if peer.AllowedIPs[0].String() == currentPeer.AllowedIPs[0].String() {
+				shouldDelete = false
+			}
+		}
+		if shouldDelete {
+			output, err := ncutils.RunCmd("wg set "+iface+" peer "+currentPeer.PublicKey.String()+" remove", true)
+			if err != nil {
+				log.Println(output, "error removing peer", currentPeer.PublicKey.String())
+			}
+		}
+	}
+
+	return nil
+}
+
+func InitWireguard(node *models.Node, privkey string, peers []wgtypes.PeerConfig, hasGateway bool, gateways []string) error {
+
+	key, err := wgtypes.ParseKey(privkey)
+	if err != nil {
+		return err
+	}
+
+	wgclient, err := wgctrl.New()
+	if err != nil {
+		return err
+	}
+	modcfg, err := config.ReadConfig(node.Network)
+	if err != nil {
+		return err
+	}
+	nodecfg := modcfg.Node
+	servercfg := modcfg.Server
+
+	if err != nil {
+		log.Fatalf("failed to open client: %v", err)
+	}
+	defer wgclient.Close()
+
+	ifacename := node.Interface
+	if nodecfg.Interface != "" {
+		ifacename = nodecfg.Interface
+	} else if node.Interface != "" {
+		ifacename = node.Interface
+	} else {
+		log.Fatal("no interface to configure")
+	}
+	if node.Address == "" {
+		log.Fatal("no address to configure")
+	}
+	nameserver := servercfg.CoreDNSAddr
+	network := node.Network
+	if nodecfg.Network != "" {
+		network = nodecfg.Network
+	} else if node.Network != "" {
+		network = node.Network
+	}
+
+	if ncutils.IsKernel() {
+		setKernelDevice(ifacename, node.Address)
+	}
+
+	var nodeport int
+	nodeport = int(node.ListenPort)
+	conf := wgtypes.Config{}
+	if nodecfg.UDPHolePunch == "yes" &&
+		nodecfg.IsServer == "no" &&
+		nodecfg.IsIngressGateway != "yes" &&
+		nodecfg.IsStatic != "yes" {
+		conf = wgtypes.Config{
+			PrivateKey:   &key,
+			ReplacePeers: true,
+			Peers:        peers,
+		}
+	} else {
+		conf = wgtypes.Config{
+			PrivateKey:   &key,
+			ListenPort:   &nodeport,
+			ReplacePeers: true,
+			Peers:        peers,
+		}
+	}
+	if !ncutils.IsKernel() {
+		var newConf string
+		if node.UDPHolePunch != "yes" {
+			newConf, _ = ncutils.CreateUserSpaceConf(node.Address, key.String(), strconv.FormatInt(int64(node.ListenPort), 10), node.MTU, node.PersistentKeepalive, peers)
+		} else {
+			newConf, _ = ncutils.CreateUserSpaceConf(node.Address, key.String(), "", node.MTU, node.PersistentKeepalive, peers)
+		}
+		confPath := ncutils.GetNetclientPathSpecific() + node.Interface + ".conf"
+		ncutils.PrintLog("writing wg conf file to: "+confPath, 1)
+		err = ioutil.WriteFile(confPath, []byte(newConf), 0644)
+		if err != nil {
+			ncutils.PrintLog("error writing wg conf file to "+confPath+": "+err.Error(), 1)
+			return err
+		}
+		// spin up userspace / windows interface + apply the conf file
+		_ = RemoveConf(node.Interface, false) // remove interface first
+		err = ApplyConf(confPath)
+		if err != nil {
+			ncutils.PrintLog("failed to create wireguard interface", 1)
+			return err
+		}
+	} else {
+		ipExec, err := exec.LookPath("ip")
+		if err != nil {
+			return err
+		}
+
+		_, err = wgclient.Device(ifacename)
+		if err != nil {
+			if os.IsNotExist(err) {
+				fmt.Println("Device does not exist: ")
+				fmt.Println(err)
+			} else {
+				log.Fatalf("Unknown config error: %v", err)
+			}
+		}
+
+		err = wgclient.ConfigureDevice(ifacename, conf)
+		if err != nil {
+			if os.IsNotExist(err) {
+				fmt.Println("Device does not exist: ")
+				fmt.Println(err)
+			} else {
+				fmt.Printf("This is inconvenient: %v", err)
+			}
+		}
+
+		//=========DNS Setup==========\\
+		if nodecfg.DNSOn == "yes" {
+			_ = local.UpdateDNS(ifacename, network, nameserver)
+		}
+		//=========End DNS Setup=======\\
+		if _, err := ncutils.RunCmd(ipExec+" link set down dev "+ifacename, false); err != nil {
+			ncutils.Log("attempted to remove interface before editing")
+			return err
+		}
+
+		if nodecfg.PostDown != "" {
+			runcmds := strings.Split(nodecfg.PostDown, "; ")
+			_ = ncutils.RunCmds(runcmds, true)
+		}
+		// set MTU of node interface
+		if _, err := ncutils.RunCmd(ipExec+" link set mtu "+strconv.Itoa(int(nodecfg.MTU))+" up dev "+ifacename, true); err != nil {
+			ncutils.Log("failed to create interface with mtu " + ifacename)
+			return err
+		}
+
+		if nodecfg.PostUp != "" {
+			runcmds := strings.Split(nodecfg.PostUp, "; ")
+			_ = ncutils.RunCmds(runcmds, true)
+		}
+		if hasGateway {
+			for _, gateway := range gateways {
+				_, _ = ncutils.RunCmd(ipExec+" -4 route add "+gateway+" dev "+ifacename, true)
+			}
+		}
+		if node.Address6 != "" && node.IsDualStack == "yes" {
+			log.Println("[netclient] adding address: "+node.Address6, 1)
+			_, _ = ncutils.RunCmd(ipExec+" address add dev "+ifacename+" "+node.Address6+"/64", true)
+		}
+	}
+	return err
+}
+
+func SetWGConfig(network string, peerupdate bool) error {
+
+	cfg, err := config.ReadConfig(network)
+	if err != nil {
+		return err
+	}
+	servercfg := cfg.Server
+	nodecfg := cfg.Node
+
+	peers, hasGateway, gateways, err := server.GetPeers(nodecfg.MacAddress, nodecfg.Network, servercfg.GRPCAddress, nodecfg.IsDualStack == "yes", nodecfg.IsIngressGateway == "yes")
+	if err != nil {
+		return err
+	}
+	privkey, err := RetrievePrivKey(network)
+	if err != nil {
+		return err
+	}
+	if peerupdate {
+		var iface string
+		iface = nodecfg.Interface
+		if ncutils.IsMac() {
+			iface, err = local.GetMacIface(nodecfg.Address)
+			if err != nil {
+				return err
+			}
+		}
+		err = SetPeers(iface, nodecfg.PersistentKeepalive, peers)
+	} else {
+		err = InitWireguard(&nodecfg, privkey, peers, hasGateway, gateways)
+	}
+	if err != nil {
+		return err
+	}
+
+	return err
+}
+
+func RemoveConf(iface string, printlog bool) error {
+	os := runtime.GOOS
+	var err error
+	switch os {
+	case "windows":
+		err = RemoveWindowsConf(iface, printlog)
+	default:
+		confPath := ncutils.GetNetclientPathSpecific() + iface + ".conf"
+		err = RemoveWGQuickConf(confPath, printlog)
+	}
+	return err
+}
+
+func ApplyConf(confPath string) error {
+	os := runtime.GOOS
+	var err error
+	switch os {
+	case "windows":
+		err = ApplyWindowsConf(confPath)
+	default:
+		err = ApplyWGQuickConf(confPath)
+	}
+	return err
+}

+ 6 - 310
netclient/wireguard/kernel.go

@@ -1,325 +1,21 @@
 package wireguard
 
 import (
-	"fmt"
-	"io/ioutil"
-	"log"
-	"os"
 	"os/exec"
-	"strconv"
-	"strings"
 
-	"github.com/gravitl/netmaker/models"
-	"github.com/gravitl/netmaker/netclient/config"
-	"github.com/gravitl/netmaker/netclient/local"
-	"github.com/gravitl/netmaker/netclient/netclientutils"
-	"github.com/gravitl/netmaker/netclient/server"
-	"golang.zx2c4.com/wireguard/wgctrl"
-	"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
+	"github.com/gravitl/netmaker/netclient/ncutils"
 	//homedir "github.com/mitchellh/go-homedir"
 )
 
-func InitWireguard(node *models.Node, privkey string, peers []wgtypes.PeerConfig, hasGateway bool, gateways []string) error {
-
-	key, err := wgtypes.ParseKey(privkey)
-	if err != nil {
-		return err
-	}
-
-	wgclient, err := wgctrl.New()
-	if err != nil {
-		return err
-	}
-	modcfg, err := config.ReadConfig(node.Network)
-	if err != nil {
-		return err
-	}
-	nodecfg := modcfg.Node
-	servercfg := modcfg.Server
-
-	if err != nil {
-		log.Fatalf("failed to open client: %v", err)
-	}
-	defer wgclient.Close()
-
-	ifacename := node.Interface
-	if nodecfg.Interface != "" {
-		ifacename = nodecfg.Interface
-	} else if node.Interface != "" {
-		ifacename = node.Interface
-	} else {
-		log.Fatal("no interface to configure")
-	}
-	if node.Address == "" {
-		log.Fatal("no address to configure")
-	}
-	nameserver := servercfg.CoreDNSAddr
-	network := node.Network
-	if nodecfg.Network != "" {
-		network = nodecfg.Network
-	} else if node.Network != "" {
-		network = node.Network
-	}
-
-	if !netclientutils.IsWindows() {
-
-		ipExec, err := exec.LookPath("ip")
-		if err != nil {
-			return err
-		}
-
-		_, _ = local.RunCmd("ip link delete dev " + ifacename, false)
-		_, _ = local.RunCmd(ipExec + " link add dev " + ifacename + " type wireguard", true)
-		_, _ = local.RunCmd(ipExec + " address add dev " + ifacename + " " + node.Address + "/24", true)
-	}
-	var nodeport int
-	nodeport = int(node.ListenPort)
-	conf := wgtypes.Config{}
-	if nodecfg.UDPHolePunch == "yes" &&
-		nodecfg.IsServer == "no" &&
-		nodecfg.IsIngressGateway != "yes" &&
-		nodecfg.IsStatic != "yes" {
-		conf = wgtypes.Config{
-			PrivateKey:   &key,
-			ReplacePeers: true,
-			Peers:        peers,
-		}
-	} else {
-		conf = wgtypes.Config{
-			PrivateKey:   &key,
-			ListenPort:   &nodeport,
-			ReplacePeers: true,
-			Peers:        peers,
-		}
-	}
-	if netclientutils.IsWindows() {
-		var newConf string
-		if node.UDPHolePunch != "yes" {
-			newConf, _ = netclientutils.CreateUserSpaceConf(node.Address, key.String(), strconv.FormatInt(int64(node.ListenPort), 10), node.MTU, node.PersistentKeepalive, peers)
-		} else {
-			newConf, _ = netclientutils.CreateUserSpaceConf(node.Address, key.String(), "", node.MTU, node.PersistentKeepalive, peers)
-		}
-		confPath := netclientutils.GetNetclientPathSpecific() + node.Interface + ".conf"
-		err = ioutil.WriteFile(confPath, []byte(newConf), 0644)
-		if err != nil {
-			return err
-		}
-		// spin up userspace / windows interface + apply the conf file
-		err := local.RemoveWindowsConf(node.Interface) // remove interface first
-		if err != nil {
-			log.Println("attempted to remove pre-existing windows interface before updating")
-		}
-		local.ApplyWindowsConf(confPath)
-	} else {
-		ipExec, err := exec.LookPath("ip")
-		if err != nil {
-			return err
-		}
-
-		_, err = wgclient.Device(ifacename)
-		if err != nil {
-			if os.IsNotExist(err) {
-				fmt.Println("Device does not exist: ")
-				fmt.Println(err)
-			} else {
-				log.Fatalf("Unknown config error: %v", err)
-			}
-		}
-		
-		err = wgclient.ConfigureDevice(ifacename, conf)
-		if err != nil {
-			if os.IsNotExist(err) {
-				fmt.Println("Device does not exist: ")
-				fmt.Println(err)
-			} else {
-				fmt.Printf("This is inconvenient: %v", err)
-			}
-		}
-
-		//=========DNS Setup==========\\
-		if nodecfg.DNSOn == "yes" {
-			_ = local.UpdateDNS(ifacename, network, nameserver)
-		}
-		//=========End DNS Setup=======\\
-		if _, err := local.RunCmd(ipExec + " link set down dev " + ifacename, false); err != nil {
-			netclientutils.Log("attempted to remove interface before editing")
-			return err
-		}
-
-		if nodecfg.PostDown != "" {
-			runcmds := strings.Split(nodecfg.PostDown, "; ")
-			err = local.RunCmds(runcmds, true)
-		}
-		// set MTU of node interface
-		if _, err := local.RunCmd(ipExec + " link set mtu " + strconv.Itoa(int(nodecfg.MTU)) + " up dev " + ifacename, true); err != nil {
-			netclientutils.Log("failed to create interface with mtu " + ifacename)
-			return err
-		}
-
-		if nodecfg.PostUp != "" {
-			runcmds := strings.Split(nodecfg.PostUp, "; ")
-			err = local.RunCmds(runcmds, true)
-		}
-		if hasGateway {
-			for _, gateway := range gateways {
-				_, _ = local.RunCmd(ipExec + " -4 route add " + gateway + " dev " + ifacename, true)
-			}
-		}
-		if node.Address6 != "" && node.IsDualStack == "yes" {
-			log.Println("[netclient] adding address: " + node.Address6, 1)
-			_, _ = local.RunCmd(ipExec + " address add dev " + ifacename + " " + node.Address6 + "/64", true)
-		}
-	}
-	return err
-}
-
-func SetWGKeyConfig(network string, serveraddr string) error {
-
-	cfg, err := config.ReadConfig(network)
-	if err != nil {
-		return err
-	}
-
-	node := cfg.Node
-
-	privatekey, err := wgtypes.GeneratePrivateKey()
+func setKernelDevice(ifacename string, address string) error {
+	ipExec, err := exec.LookPath("ip")
 	if err != nil {
 		return err
 	}
-	privkeystring := privatekey.String()
-	publickey := privatekey.PublicKey()
 
-	node.PublicKey = publickey.String()
-
-	err = StorePrivKey(privkeystring, network)
-	if err != nil {
-		return err
-	}
-	if node.Action == models.NODE_UPDATE_KEY {
-		node.Action = models.NODE_NOOP
-	}
-	err = config.ModConfig(&node)
-	if err != nil {
-		return err
-	}
-
-	err = SetWGConfig(network, false)
-	if err != nil {
-		return err
-	}
-
-	return err
-}
-
-func SetWGConfig(network string, peerupdate bool) error {
-
-	cfg, err := config.ReadConfig(network)
-	if err != nil {
-		return err
-	}
-	servercfg := cfg.Server
-	nodecfg := cfg.Node
-
-	peers, hasGateway, gateways, err := server.GetPeers(nodecfg.MacAddress, nodecfg.Network, servercfg.GRPCAddress, nodecfg.IsDualStack == "yes", nodecfg.IsIngressGateway == "yes")
-	if err != nil {
-		return err
-	}
-	privkey, err := RetrievePrivKey(network)
-	if err != nil {
-		return err
-	}
-	if peerupdate {
-		err = SetPeers(nodecfg.Interface, nodecfg.PersistentKeepalive, peers)
-	} else {
-		err = InitWireguard(&nodecfg, privkey, peers, hasGateway, gateways)
-	}
-	if err != nil {
-		return err
-	}
-
-	return err
-}
-
-func SetPeers(iface string, keepalive int32, peers []wgtypes.PeerConfig) error {
-
-	client, err := wgctrl.New()
-	if err != nil {
-		log.Println("failed to start wgctrl")
-		return err
-	}
-	device, err := client.Device(iface)
-	if err != nil {
-		log.Println("failed to parse interface")
-		return err
-	}
-	devicePeers := device.Peers
-	if len(devicePeers) > 1 && len(peers) == 0 {
-		log.Println("no peers pulled")
-		return err
-	}
-
-	for _, peer := range peers {
-
-		for _, currentPeer := range devicePeers {
-			if currentPeer.AllowedIPs[0].String() == peer.AllowedIPs[0].String() &&
-				currentPeer.PublicKey.String() != peer.PublicKey.String() {
-				_, err := local.RunCmd("wg set " + iface + " peer " + currentPeer.PublicKey.String() + " remove", true)
-				if err != nil {
-					log.Println("error removing peer", peer.Endpoint.String())
-				}
-			}
-		}
-		udpendpoint := peer.Endpoint.String()
-		var allowedips string
-		var iparr []string
-		for _, ipaddr := range peer.AllowedIPs {
-			iparr = append(iparr, ipaddr.String())
-		}
-		allowedips = strings.Join(iparr, ",")
-		keepAliveString := strconv.Itoa(int(keepalive))
-		if keepAliveString == "0" {
-			keepAliveString = "5"
-		}
-		if peer.Endpoint != nil {
-			_, err = local.RunCmd("wg set " + iface + " peer " + peer.PublicKey.String() +
-				" endpoint " + udpendpoint +
-				" persistent-keepalive " + keepAliveString +
-				" allowed-ips " + allowedips, true)
-		} else {
-			_, err = local.RunCmd("wg set " + iface + " peer " + peer.PublicKey.String() +
-				" persistent-keepalive " + keepAliveString +
-				" allowed-ips " + allowedips, true)
-		}
-		if err != nil {
-			log.Println("error setting peer", peer.PublicKey.String())
-		}
-	}
-
-	for _, currentPeer := range devicePeers {
-		shouldDelete := true
-		for _, peer := range peers {
-			if peer.AllowedIPs[0].String() == currentPeer.AllowedIPs[0].String() {
-				shouldDelete = false
-			}
-		}
-		if shouldDelete {
-			output, err := local.RunCmd("wg set " + iface + " peer " + currentPeer.PublicKey.String() + " remove", true)
-			if err != nil {
-				log.Println(output, "error removing peer", currentPeer.PublicKey.String())
-			}
-		}
-	}
+	_, _ = 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+"/24", true)
 
 	return nil
 }
-
-func StorePrivKey(key string, network string) error {
-	d1 := []byte(key)
-	err := ioutil.WriteFile(netclientutils.GetNetclientPathSpecific()+"wgkey-"+network, d1, 0644)
-	return err
-}
-
-func RetrievePrivKey(network string) (string, error) {
-	dat, err := ioutil.ReadFile(netclientutils.GetNetclientPathSpecific() + "wgkey-" + network)
-	return string(dat), err
-}

+ 74 - 0
netclient/wireguard/unix.go

@@ -0,0 +1,74 @@
+package wireguard
+
+import (
+	"io/ioutil"
+
+	"github.com/gravitl/netmaker/models"
+	"github.com/gravitl/netmaker/netclient/config"
+	"github.com/gravitl/netmaker/netclient/ncutils"
+	"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
+	//homedir "github.com/mitchellh/go-homedir"
+)
+
+func SetWGKeyConfig(network string, serveraddr string) error {
+
+	cfg, err := config.ReadConfig(network)
+	if err != nil {
+		return err
+	}
+
+	node := cfg.Node
+
+	privatekey, err := wgtypes.GeneratePrivateKey()
+	if err != nil {
+		return err
+	}
+	privkeystring := privatekey.String()
+	publickey := privatekey.PublicKey()
+
+	node.PublicKey = publickey.String()
+
+	err = StorePrivKey(privkeystring, network)
+	if err != nil {
+		return err
+	}
+	if node.Action == models.NODE_UPDATE_KEY {
+		node.Action = models.NODE_NOOP
+	}
+	err = config.ModConfig(&node)
+	if err != nil {
+		return err
+	}
+
+	err = SetWGConfig(network, false)
+	if err != nil {
+		return err
+	}
+
+	return err
+}
+
+func ApplyWGQuickConf(confPath string) error {
+	if _, err := ncutils.RunCmd("wg-quick up "+confPath, true); err != nil {
+		return err
+	}
+	return nil
+}
+
+func RemoveWGQuickConf(confPath string, printlog bool) error {
+	if _, err := ncutils.RunCmd("wg-quick down "+confPath, printlog); err != nil {
+		return err
+	}
+	return nil
+}
+
+func StorePrivKey(key string, network string) error {
+	d1 := []byte(key)
+	err := ioutil.WriteFile(ncutils.GetNetclientPathSpecific()+"wgkey-"+network, d1, 0644)
+	return err
+}
+
+func RetrievePrivKey(network string) (string, error) {
+	dat, err := ioutil.ReadFile(ncutils.GetNetclientPathSpecific() + "wgkey-" + network)
+	return string(dat), err
+}

+ 17 - 0
netclient/wireguard/windows.go

@@ -0,0 +1,17 @@
+package wireguard
+
+import "github.com/gravitl/netmaker/netclient/ncutils"
+
+func ApplyWindowsConf(confPath string) error {
+	if _, err := ncutils.RunCmd("wireguard.exe /installtunnelservice "+confPath, true); err != nil {
+		return err
+	}
+	return nil
+}
+
+func RemoveWindowsConf(ifacename string, printlog bool) error {
+	if _, err := ncutils.RunCmd("wireguard.exe /uninstalltunnelservice "+ifacename, printlog); err != nil {
+		return err
+	}
+	return nil
+}

+ 1 - 1
servercfg/serverconf.go

@@ -73,7 +73,7 @@ func GetAPIConnString() string {
 	return conn
 }
 func GetVersion() string {
-	version := "0.7.3"
+	version := "0.8.0"
 	if config.Config.Server.Version != "" {
 		version = config.Config.Server.Version
 	}

+ 7 - 8
serverctl/serverctl.go

@@ -11,8 +11,7 @@ import (
 	"github.com/gravitl/netmaker/database"
 	"github.com/gravitl/netmaker/functions"
 	"github.com/gravitl/netmaker/models"
-	"github.com/gravitl/netmaker/netclient/local"
-	"github.com/gravitl/netmaker/netclient/netclientutils"
+	"github.com/gravitl/netmaker/netclient/ncutils"
 	"github.com/gravitl/netmaker/servercfg"
 )
 
@@ -33,10 +32,10 @@ func GetServerWGConf() (models.IntClient, error) {
 
 func InstallNetclient() error {
 
-	netclientPath := netclientutils.GetNetclientPathSpecific()
+	netclientPath := ncutils.GetNetclientPathSpecific()
 	if !FileExists(netclientPath + "netclient") {
 		var err error
-		if netclientutils.IsWindows() {
+		if ncutils.IsWindows() {
 			_, err = copy(".\\netclient\\netclient", netclientPath+"netclient")
 		} else {
 			_, err = copy("./netclient/netclient", netclientPath+"netclient")
@@ -87,13 +86,13 @@ func copy(src, dst string) (int64, error) {
 }
 
 func RemoveNetwork(network string) (bool, error) {
-	netclientPath := netclientutils.GetNetclientPathSpecific()
+	netclientPath := ncutils.GetNetclientPathSpecific()
 	_, err := os.Stat(netclientPath + "netclient")
 	if err != nil {
 		log.Println("could not find " + netclientPath + "netclient")
 		return false, err
 	}
-	_, err = local.RunCmd(netclientPath+"netclient leave -n "+network, true)
+	_, err = ncutils.RunCmd(netclientPath+"netclient leave -n "+network, true)
 	if err == nil {
 		log.Println("Server removed from network " + network)
 	}
@@ -107,8 +106,8 @@ func AddNetwork(network string) (bool, error) {
 		log.Println("could not get public IP.")
 		return false, err
 	}
-	netclientDir := netclientutils.GetNetclientPath()
-	netclientPath := netclientutils.GetNetclientPathSpecific()
+	netclientDir := ncutils.GetNetclientPath()
+	netclientPath := ncutils.GetNetclientPathSpecific()
 	_, err = os.Stat(netclientDir)
 	if os.IsNotExist(err) {
 		os.Mkdir(netclientDir, 744)