mirror of
https://github.com/gravitl/netmaker.git
synced 2025-10-10 13:57:48 +08:00
mac client semi-functional
This commit is contained in:
parent
685689df1d
commit
5c7fabda71
6 changed files with 308 additions and 10 deletions
39
docker/Dockerfile-netclient-kernel
Normal file
39
docker/Dockerfile-netclient-kernel
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
FROM debian:buster as builder
|
||||||
|
# add glib support daemon manager
|
||||||
|
|
||||||
|
RUN apt update -y && apt install -y wget bash gcc musl-dev openssl golang git build-essential libmnl-dev iptables
|
||||||
|
|
||||||
|
RUN wget -O go.tgz https://dl.google.com/go/go1.17.1.linux-amd64.tar.gz
|
||||||
|
|
||||||
|
RUN tar -C /usr/local -xzf go.tgz
|
||||||
|
|
||||||
|
WORKDIR /usr/local/go/src
|
||||||
|
|
||||||
|
RUN chmod +x make.bash
|
||||||
|
|
||||||
|
RUN ./make.bash
|
||||||
|
|
||||||
|
ENV PATH="/usr/local/go/bin:$PATH"
|
||||||
|
|
||||||
|
ENV GOPATH=/opt/go/
|
||||||
|
|
||||||
|
ENV PATH=$PATH:$GOPATH/bin
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
ENV GO111MODULE=auto
|
||||||
|
|
||||||
|
RUN GOOS=linux GOARCH=amd64 CGO_ENABLED=0 /usr/local/go/bin/go build -ldflags="-w -s" -o netclient-app netclient/main.go
|
||||||
|
|
||||||
|
FROM debian:buster
|
||||||
|
|
||||||
|
WORKDIR /root/
|
||||||
|
|
||||||
|
RUN apt update -y && apt install -y bash curl wget traceroute procps dnsutils iptables openresolv iproute2
|
||||||
|
COPY --from=builder /app/netclient-app ./netclient
|
||||||
|
COPY --from=builder /app/scripts/netclient.sh .
|
||||||
|
RUN chmod 0755 netclient && chmod 0755 netclient.sh
|
||||||
|
|
||||||
|
ENTRYPOINT ["/bin/sh", "./netclient.sh"]
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"net"
|
"net"
|
||||||
|
@ -318,6 +319,38 @@ func GetNetclientPathSpecific() string {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetNewIface(dir string) (string, error) {
|
||||||
|
files, _ := ioutil.ReadDir(dir)
|
||||||
|
var newestFile string
|
||||||
|
var newestTime int64 = 0
|
||||||
|
var err error
|
||||||
|
for _, f := range files {
|
||||||
|
fi, err := os.Stat(dir + f.Name())
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
currTime := fi.ModTime().Unix()
|
||||||
|
if currTime > newestTime && strings.Contains(f.Name(), ".sock") {
|
||||||
|
newestTime = currTime
|
||||||
|
newestFile = f.Name()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
resultArr := strings.Split(newestFile, ".")
|
||||||
|
if resultArr[0] == "" {
|
||||||
|
err = errors.New("sock file does not exist")
|
||||||
|
}
|
||||||
|
return resultArr[0], err
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetFileAsString(path string) (string, error) {
|
||||||
|
content, err := os.ReadFile(path)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
text := string(content)
|
||||||
|
return text, err
|
||||||
|
}
|
||||||
|
|
||||||
// GetNetclientPathSpecific - gets specific netclient config path
|
// GetNetclientPathSpecific - gets specific netclient config path
|
||||||
func GetWGPathSpecific() string {
|
func GetWGPathSpecific() string {
|
||||||
if IsWindows() {
|
if IsWindows() {
|
||||||
|
|
BIN
netclient/netclient-darwin
Executable file
BIN
netclient/netclient-darwin
Executable file
Binary file not shown.
|
@ -159,22 +159,28 @@ func InitWireguard(node *models.Node, privkey string, peers []wgtypes.PeerConfig
|
||||||
// spin up userspace / windows interface + apply the conf file
|
// spin up userspace / windows interface + apply the conf file
|
||||||
var deviceiface string
|
var deviceiface string
|
||||||
if ncutils.IsMac() {
|
if ncutils.IsMac() {
|
||||||
|
log.Println("DELETE ME: check for local iface")
|
||||||
deviceiface, err = local.GetMacIface(node.Address)
|
deviceiface, err = local.GetMacIface(node.Address)
|
||||||
if err != nil || deviceiface == "" {
|
if err != nil || deviceiface == "" {
|
||||||
deviceiface = ifacename
|
deviceiface = ifacename
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if syncconf {
|
if syncconf {
|
||||||
|
log.Println("DELETE ME: syncconf")
|
||||||
err = SyncWGQuickConf(ifacename, confPath)
|
err = SyncWGQuickConf(ifacename, confPath)
|
||||||
} else {
|
} else {
|
||||||
|
if !ncutils.IsMac() {
|
||||||
|
log.Println("DELETE ME: get device")
|
||||||
d, _ := wgclient.Device(deviceiface)
|
d, _ := wgclient.Device(deviceiface)
|
||||||
for d != nil && d.Name == deviceiface {
|
for d != nil && d.Name == deviceiface {
|
||||||
RemoveConf(ifacename, false) // remove interface first
|
RemoveConf(ifacename, false) // remove interface first
|
||||||
time.Sleep(time.Second >> 2)
|
time.Sleep(time.Second >> 2)
|
||||||
d, _ = wgclient.Device(deviceiface)
|
d, _ = wgclient.Device(deviceiface)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if !ncutils.IsWindows() {
|
if !ncutils.IsWindows() {
|
||||||
err = ApplyConf(confPath)
|
log.Println("DELETE ME: apply conf")
|
||||||
|
err = ApplyConf(*node, ifacename, confPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ncutils.PrintLog("failed to create wireguard interface", 1)
|
ncutils.PrintLog("failed to create wireguard interface", 1)
|
||||||
return err
|
return err
|
||||||
|
@ -187,7 +193,7 @@ func InitWireguard(node *models.Node, privkey string, peers []wgtypes.PeerConfig
|
||||||
ncutils.PrintLog("waiting for interface...", 1)
|
ncutils.PrintLog("waiting for interface...", 1)
|
||||||
for !strings.Contains(output, ifacename) && !(time.Now().After(starttime.Add(time.Duration(10) * time.Second))) {
|
for !strings.Contains(output, ifacename) && !(time.Now().After(starttime.Add(time.Duration(10) * time.Second))) {
|
||||||
output, _ = ncutils.RunCmd("wg", false)
|
output, _ = ncutils.RunCmd("wg", false)
|
||||||
err = ApplyConf(confPath)
|
err = ApplyConf(*node, ifacename, confPath)
|
||||||
time.Sleep(time.Second)
|
time.Sleep(time.Second)
|
||||||
}
|
}
|
||||||
if !strings.Contains(output, ifacename) {
|
if !strings.Contains(output, ifacename) {
|
||||||
|
@ -259,8 +265,9 @@ func RemoveConf(iface string, printlog bool) error {
|
||||||
var err error
|
var err error
|
||||||
switch os {
|
switch os {
|
||||||
case "windows":
|
case "windows":
|
||||||
|
|
||||||
err = RemoveWindowsConf(iface, printlog)
|
err = RemoveWindowsConf(iface, printlog)
|
||||||
|
case "darwin":
|
||||||
|
err = WgQuickDownShortMac(iface)
|
||||||
default:
|
default:
|
||||||
confPath := ncutils.GetNetclientPathSpecific() + iface + ".conf"
|
confPath := ncutils.GetNetclientPathSpecific() + iface + ".conf"
|
||||||
err = RemoveWGQuickConf(confPath, printlog)
|
err = RemoveWGQuickConf(confPath, printlog)
|
||||||
|
@ -269,12 +276,14 @@ func RemoveConf(iface string, printlog bool) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ApplyConf - applys a conf on disk to WireGuard interface
|
// ApplyConf - applys a conf on disk to WireGuard interface
|
||||||
func ApplyConf(confPath string) error {
|
func ApplyConf(node models.Node, ifacename string, confPath string) error {
|
||||||
os := runtime.GOOS
|
os := runtime.GOOS
|
||||||
var err error
|
var err error
|
||||||
switch os {
|
switch os {
|
||||||
case "windows":
|
case "windows":
|
||||||
_ = ApplyWindowsConf(confPath)
|
_ = ApplyWindowsConf(confPath)
|
||||||
|
case "darwin":
|
||||||
|
_ = ApplyMacOSConf(node, ifacename, confPath)
|
||||||
default:
|
default:
|
||||||
err = ApplyWGQuickConf(confPath)
|
err = ApplyWGQuickConf(confPath)
|
||||||
}
|
}
|
||||||
|
|
205
netclient/wireguard/mac.go
Normal file
205
netclient/wireguard/mac.go
Normal file
|
@ -0,0 +1,205 @@
|
||||||
|
package wireguard
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/gravitl/netmaker/models"
|
||||||
|
"github.com/gravitl/netmaker/netclient/ncutils"
|
||||||
|
)
|
||||||
|
|
||||||
|
func AddInterface(iface string) (string, error) {
|
||||||
|
ncutils.RunCmd("mkdir -p /var/run/wireguard/", true)
|
||||||
|
ncutils.RunCmd("wireguard-go utun", true)
|
||||||
|
return ncutils.GetNewIface("/var/run/wireguard/")
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetRealIface(iface string) (string, error) {
|
||||||
|
ncutils.RunCmd("wg show interfaces", false)
|
||||||
|
ifacePath := "/var/run/wireguard/" + iface + ".name"
|
||||||
|
if !(ncutils.FileExists(ifacePath)) {
|
||||||
|
return "", errors.New(ifacePath + " does not exist")
|
||||||
|
}
|
||||||
|
realIfaceName, err := ncutils.GetFileAsString(ifacePath)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
if !(ncutils.FileExists("/var/run/wireguard/" + realIfaceName + ".sock")) {
|
||||||
|
return "", errors.New("interface file does not exist")
|
||||||
|
}
|
||||||
|
return realIfaceName, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func DeleteRoutes(iface string) error {
|
||||||
|
realIface, err := GetRealIface(iface)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
var inets = [2]string{"inet", "inet6"}
|
||||||
|
for _, inet := range inets {
|
||||||
|
ifaceList, err := ncutils.RunCmd("netstat -nr -f "+inet+" | grep -e "+realIface+" | awk '{print $1}'", true)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
destinations := strings.Split(ifaceList, "\n")
|
||||||
|
|
||||||
|
for _, i := range destinations {
|
||||||
|
ncutils.RunCmd("route -q -n delete -"+inet+" "+i, true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// wg-quick deletes ENDPOINTS here (runs 'route -q delete' for each peer endpoint on the interface.)
|
||||||
|
// We don't believe this is necessary.
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func DeleteInterface(iface string) error {
|
||||||
|
var err error
|
||||||
|
if iface != "" {
|
||||||
|
ncutils.RunCmd("rm -f /var/run/wireguard/"+iface+".sock", true)
|
||||||
|
}
|
||||||
|
_, err = ncutils.RunCmd("ifconfig "+iface+" down", false)
|
||||||
|
if strings.Contains(err.Error(), "does not exist") {
|
||||||
|
err = nil
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func UpInterface(iface string) error {
|
||||||
|
var err error
|
||||||
|
_, err = ncutils.RunCmd("ifconfig "+iface+" up", true)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func AddAddress(iface string, addr string) error {
|
||||||
|
var err error
|
||||||
|
if strings.Contains(addr, ":") {
|
||||||
|
_, err = ncutils.RunCmd("ifconfig "+iface+" inet6 "+addr+" alias", true)
|
||||||
|
} else {
|
||||||
|
_, err = ncutils.RunCmd("ifconfig "+iface+" inet "+addr+" 255.255.255.0 alias", true)
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetMTU(iface string, mtu int) error {
|
||||||
|
var err error
|
||||||
|
if mtu == 0 {
|
||||||
|
mtu = 1280
|
||||||
|
}
|
||||||
|
_, err = ncutils.RunCmd("ifconfig "+iface+" mtu "+strconv.Itoa(mtu), true)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func AddRoute(addr string, iface string) error {
|
||||||
|
var err error
|
||||||
|
var out string
|
||||||
|
var inetx = "inet"
|
||||||
|
if strings.Contains(addr, ":") {
|
||||||
|
inetx = "inet6"
|
||||||
|
}
|
||||||
|
out, err = ncutils.RunCmd("route -n get -"+inetx+" "+addr, true)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if out == "" {
|
||||||
|
_, err = ncutils.RunCmd("route -q -n add -"+inetx+" "+addr+" -interface "+iface, true)
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetConfig(realIface string, confPath string) error {
|
||||||
|
confString := GetConfig(confPath)
|
||||||
|
err := os.WriteFile(confPath+".tmp", []byte(confString), 0644)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_, err = ncutils.RunCmd("wg setconf "+realIface+" "+confPath+".tmp", true)
|
||||||
|
os.Remove(confPath + ".tmp")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetConfig(path string) string {
|
||||||
|
var confCmd = "grep -v -e Address -e MTU -e PostUp -e PostDown "
|
||||||
|
confRaw, _ := ncutils.RunCmd(confCmd+path, false)
|
||||||
|
return confRaw
|
||||||
|
}
|
||||||
|
|
||||||
|
func WgQuickUpMac(node models.Node, iface string, confPath string) error {
|
||||||
|
var err error
|
||||||
|
var realIface string
|
||||||
|
DeleteInterface(iface)
|
||||||
|
DeleteRoutes(iface)
|
||||||
|
|
||||||
|
realIface, err = AddInterface(iface)
|
||||||
|
if err != nil {
|
||||||
|
ncutils.PrintLog("error creating wg interface", 1)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
time.Sleep(1)
|
||||||
|
err = SetConfig(realIface, confPath)
|
||||||
|
if err != nil {
|
||||||
|
ncutils.PrintLog("error setting config for "+realIface, 1)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
var ips []string
|
||||||
|
ips = append(node.AllowedIPs, node.Address)
|
||||||
|
ips = append(ips, node.Address6)
|
||||||
|
for _, i := range ips {
|
||||||
|
if i != "" {
|
||||||
|
err = AddAddress(realIface, i)
|
||||||
|
if err != nil {
|
||||||
|
ncutils.PrintLog("error adding address "+i+" on interface "+realIface, 1)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SetMTU(realIface, int(node.MTU))
|
||||||
|
err = UpInterface(realIface)
|
||||||
|
if err != nil {
|
||||||
|
ncutils.PrintLog("error turning on interface "+iface, 1)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for _, i := range ips {
|
||||||
|
if i != "" {
|
||||||
|
err = AddRoute(i, realIface)
|
||||||
|
if err != nil {
|
||||||
|
ncutils.PrintLog("error adding route to "+realIface+" for "+i, 1)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//next, wg-quick runs set_endpoint_direct_route
|
||||||
|
//next, wg-quick runs monitor_daemon
|
||||||
|
time.Sleep(1)
|
||||||
|
if node.PostUp != "" {
|
||||||
|
runcmds := strings.Split(node.PostUp, "; ")
|
||||||
|
ncutils.RunCmds(runcmds, true)
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func WgQuickDownShortMac(iface string) error {
|
||||||
|
var err error
|
||||||
|
realIface, err := GetRealIface(iface)
|
||||||
|
if realIface != "" {
|
||||||
|
err = DeleteInterface(iface)
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func WgQuickDownMac(node models.Node, iface string) error {
|
||||||
|
var err error
|
||||||
|
realIface, err := GetRealIface(iface)
|
||||||
|
if realIface != "" {
|
||||||
|
err = DeleteInterface(iface)
|
||||||
|
} else if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if node.PostDown != "" {
|
||||||
|
runcmds := strings.Split(node.PostDown, "; ")
|
||||||
|
ncutils.RunCmds(runcmds, true)
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
|
@ -58,10 +58,22 @@ func ApplyWGQuickConf(confPath string) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ApplyMacOSConf - applies system commands similar to wg-quick using golang for MacOS
|
||||||
|
func ApplyMacOSConf(node models.Node, ifacename string, confPath string) error {
|
||||||
|
var err error
|
||||||
|
err = WgQuickDownMac(node, ifacename)
|
||||||
|
err = WgQuickUpMac(node, ifacename, confPath)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
// SyncWGQuickConf - formats config file and runs sync command
|
// SyncWGQuickConf - formats config file and runs sync command
|
||||||
func SyncWGQuickConf(iface string, confPath string) error {
|
func SyncWGQuickConf(iface string, confPath string) error {
|
||||||
var tmpConf = confPath + ".sync.tmp"
|
var tmpConf = confPath + ".sync.tmp"
|
||||||
confRaw, err := ncutils.RunCmd("wg-quick strip "+confPath, false)
|
var confCmd = "wg-quick strip "
|
||||||
|
if ncutils.IsMac() {
|
||||||
|
confCmd = "grep -v -e Address -e MTU -e PostUp -e PostDown "
|
||||||
|
}
|
||||||
|
confRaw, err := ncutils.RunCmd(confCmd+confPath, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue