began adding macos service/daemon

This commit is contained in:
afeiszli
2021-09-19 14:03:47 -04:00
parent b828f7b6d9
commit a0586ea6d2
27 changed files with 1209 additions and 1034 deletions

View File

@@ -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)

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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)

View File

@@ -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
netclient/daemon/macos.go Normal file
View File

@@ -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
netclient/daemon/systemd.go Normal file
View File

@@ -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/netclient@.service") {
err = ioutil.WriteFile("/etc/systemd/system/netclient@.service", 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 netclient@.service", 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 netclient@.service", 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/netclient@.service") {
err = os.Remove("/etc/systemd/system/netclient@.service")
}
}
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
netclient/daemon/windows.go Normal file
View File

@@ -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
}

View File

@@ -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" {

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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,7 +43,7 @@ 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)
@@ -51,11 +52,11 @@ func JoinNetwork(cfg config.ClientConfig, privateKey string) error {
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 {
@@ -84,7 +85,7 @@ func JoinNetwork(cfg config.ClientConfig, privateKey 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.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
}
@@ -168,38 +169,28 @@ func JoinNetwork(cfg config.ClientConfig, privateKey string) error {
}
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

View File

@@ -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
}

View File

@@ -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)
}
}

View File

@@ -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)
}

View File

@@ -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
return iface, errors.New(string(out))
}
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
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
}
}
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/netclient@.service") {
err = ioutil.WriteFile("/etc/systemd/system/netclient@.service", servicebytes, 0644)
if err != nil {
log.Println(err)
return err
}
if iface == "" {
err = errors.New("could not find iface for ip addr " + addr)
}
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
}
}
_, _ = RunCmd("systemctl enable netclient@.service", true)
_, _ = RunCmd("systemctl daemon-reload", true)
_, _ = RunCmd("systemctl enable netclient-" + network + ".timer", true)
_, _ = RunCmd("systemctl start netclient-" + network + ".timer", true)
return nil
return iface, err
}
func isOnlyService(network string) (bool, error) {
isonly := false
files, err := filepath.Glob("/etc/netclient/netconfig-*")
if err != nil {
return isonly, err
func getLineAfter(value string, a string) string {
// Get substring after a string.
pos := strings.LastIndex(value, a)
if pos == -1 {
return ""
}
count := len(files)
if count == 0 {
isonly = true
adjustedPos := pos + len(a)
if adjustedPos >= len(value) {
return ""
}
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 netclient@.service", 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/netclient@.service") {
err = os.Remove("/etc/systemd/system/netclient@.service")
}
}
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)
}
return nil
}
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)
}
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)
}
}
}
return err
return value[adjustedPos:len(value)]
}
func HasNetwork(network string) bool {
if netclientutils.IsWindows() {
return FileExists(netclientutils.GetNetclientPathSpecific() + "netconfig-" + network)
if ncutils.IsWindows() {
return ncutils.FileExists(ncutils.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)
}
return nBytes, err
return ncutils.FileExists("/etc/systemd/system/netclient-"+network+".timer") ||
ncutils.FileExists(ncutils.GetNetclientPathSpecific()+"netconfig-"+network)
}

View File

@@ -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")
}

View File

@@ -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)
}
}

View File

@@ -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)
}
}

View File

@@ -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
}
}

View File

@@ -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"
@@ -25,7 +24,7 @@ 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))
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)
@@ -80,7 +80,7 @@ func RemoveNetwork(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)
//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
@@ -138,7 +133,7 @@ func GetPeers(macaddress string, network string, server string, dualstack bool,
}
conn, err := grpc.Dial(cfg.Server.GRPCAddress,
netclientutils.GRPCRequestOpts(cfg.Server.GRPCSSL))
ncutils.GRPCRequestOpts(cfg.Server.GRPCSSL))
if err != nil {
log.Fatalf("Unable to establish client connection to localhost:50051: %v", err)
@@ -202,11 +197,11 @@ 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
@@ -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
@@ -288,7 +283,7 @@ 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))
ncutils.GRPCRequestOpts(cfg.Server.GRPCSSL))
if err != nil {
log.Fatalf("Unable to establish client connection to localhost:50051: %v", err)
}

View File

@@ -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
}

View File

@@ -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)
func setKernelDevice(ifacename string, address string) error {
ipExec, err := exec.LookPath("ip")
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()
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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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)