mirror of
				https://github.com/gravitl/netmaker.git
				synced 2025-10-31 12:16:29 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			590 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			590 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package wireguard
 | |
| 
 | |
| import (
 | |
| 	"fmt"
 | |
| 	"net"
 | |
| 	"runtime"
 | |
| 	"strconv"
 | |
| 	"strings"
 | |
| 	"time"
 | |
| 
 | |
| 	"github.com/gravitl/netmaker/logger"
 | |
| 	"github.com/gravitl/netmaker/models"
 | |
| 	"github.com/gravitl/netmaker/netclient/config"
 | |
| 	"github.com/gravitl/netmaker/netclient/local"
 | |
| 	"github.com/gravitl/netmaker/netclient/ncutils"
 | |
| 	"golang.zx2c4.com/wireguard/wgctrl"
 | |
| 	"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
 | |
| 	"gopkg.in/ini.v1"
 | |
| )
 | |
| 
 | |
| const (
 | |
| 	section_interface = "Interface"
 | |
| 	section_peers     = "Peer"
 | |
| )
 | |
| 
 | |
| // SetPeers - sets peers on a given WireGuard interface
 | |
| func SetPeers(iface string, node *models.Node, peers []wgtypes.PeerConfig) error {
 | |
| 	var devicePeers []wgtypes.Peer
 | |
| 	var keepalive = node.PersistentKeepalive
 | |
| 	var oldPeerAllowedIps = make(map[string]bool, len(peers))
 | |
| 	var err error
 | |
| 	devicePeers, err = GetDevicePeers(iface)
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	if len(devicePeers) > 1 && len(peers) == 0 {
 | |
| 		logger.Log(1, "no peers pulled")
 | |
| 		return err
 | |
| 	}
 | |
| 	for _, peer := range peers {
 | |
| 		// make sure peer has AllowedIP's before comparison
 | |
| 		hasPeerIP := len(peer.AllowedIPs) > 0
 | |
| 		for _, currentPeer := range devicePeers {
 | |
| 			// make sure currenPeer has AllowedIP's before comparison
 | |
| 			hascurrentPeerIP := len(currentPeer.AllowedIPs) > 0
 | |
| 
 | |
| 			if hasPeerIP && hascurrentPeerIP &&
 | |
| 				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 {
 | |
| 					logger.Log(0, "error removing peer", peer.Endpoint.String())
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 		udpendpoint := peer.Endpoint.String()
 | |
| 		var allowedips string
 | |
| 		var iparr []string
 | |
| 		for _, ipaddr := range peer.AllowedIPs {
 | |
| 			if hasPeerIP {
 | |
| 				iparr = append(iparr, ipaddr.String())
 | |
| 			}
 | |
| 		}
 | |
| 		if len(iparr) > 0 {
 | |
| 			allowedips = strings.Join(iparr, ",")
 | |
| 		}
 | |
| 		keepAliveString := strconv.Itoa(int(keepalive))
 | |
| 		if keepAliveString == "0" {
 | |
| 			keepAliveString = "15"
 | |
| 		}
 | |
| 		if node.IsServer == "yes" || peer.Endpoint == nil {
 | |
| 			_, err = ncutils.RunCmd("wg set "+iface+" peer "+peer.PublicKey.String()+
 | |
| 				" persistent-keepalive "+keepAliveString+
 | |
| 				" allowed-ips "+allowedips, true)
 | |
| 		} else {
 | |
| 			_, err = ncutils.RunCmd("wg set "+iface+" peer "+peer.PublicKey.String()+
 | |
| 				" endpoint "+udpendpoint+
 | |
| 				" persistent-keepalive "+keepAliveString+
 | |
| 				" allowed-ips "+allowedips, true)
 | |
| 		}
 | |
| 		if err != nil {
 | |
| 			logger.Log(0, "error setting peer", peer.PublicKey.String())
 | |
| 		}
 | |
| 	}
 | |
| 	if len(devicePeers) > 0 {
 | |
| 		for _, currentPeer := range devicePeers {
 | |
| 			shouldDelete := true
 | |
| 			if len(peers) > 0 {
 | |
| 				for _, peer := range peers {
 | |
| 
 | |
| 					if len(peer.AllowedIPs) > 0 && len(currentPeer.AllowedIPs) > 0 &&
 | |
| 						peer.AllowedIPs[0].String() == currentPeer.AllowedIPs[0].String() {
 | |
| 						shouldDelete = false
 | |
| 					}
 | |
| 					// re-check this if logic is not working, added in case of allowedips not working
 | |
| 					if peer.PublicKey.String() == currentPeer.PublicKey.String() {
 | |
| 						shouldDelete = false
 | |
| 					}
 | |
| 				}
 | |
| 				if shouldDelete {
 | |
| 					output, err := ncutils.RunCmd("wg set "+iface+" peer "+currentPeer.PublicKey.String()+" remove", true)
 | |
| 					if err != nil {
 | |
| 						logger.Log(0, output, "error removing peer", currentPeer.PublicKey.String())
 | |
| 					}
 | |
| 				}
 | |
| 				for _, ip := range currentPeer.AllowedIPs {
 | |
| 					oldPeerAllowedIps[ip.String()] = true
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	// if routes are wrong, come back to this, but should work...I would think. Or we should get it working.
 | |
| 	if len(peers) > 0 {
 | |
| 		local.SetPeerRoutes(iface, oldPeerAllowedIps, peers)
 | |
| 	}
 | |
| 
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| // Initializes a WireGuard interface
 | |
| func InitWireguard(node *models.Node, privkey string, peers []wgtypes.PeerConfig) error {
 | |
| 
 | |
| 	key, err := wgtypes.ParseKey(privkey)
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	wgclient, err := wgctrl.New()
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 	defer wgclient.Close()
 | |
| 	//nodecfg := modcfg.Node
 | |
| 	var ifacename string
 | |
| 	if node.Interface != "" {
 | |
| 		ifacename = node.Interface
 | |
| 	} else {
 | |
| 		return fmt.Errorf("no interface to configure")
 | |
| 	}
 | |
| 	if node.PrimaryAddress() == "" {
 | |
| 		return fmt.Errorf("no address to configure")
 | |
| 	}
 | |
| 	if err := WriteWgConfig(node, key.String(), peers); err != nil {
 | |
| 		logger.Log(1, "error writing wg conf file: ", err.Error())
 | |
| 		return err
 | |
| 	}
 | |
| 	// spin up userspace / windows interface + apply the conf file
 | |
| 	confPath := ncutils.GetNetclientPathSpecific() + ifacename + ".conf"
 | |
| 	var deviceiface = ifacename
 | |
| 	var mErr error
 | |
| 	if ncutils.IsMac() { // if node is Mac (Darwin) get the tunnel name first
 | |
| 		deviceiface, mErr = local.GetMacIface(node.PrimaryAddress())
 | |
| 		if mErr != nil || deviceiface == "" {
 | |
| 			deviceiface = ifacename
 | |
| 		}
 | |
| 	}
 | |
| 	// ensure you clear any existing interface first
 | |
| 	RemoveConfGraceful(deviceiface)
 | |
| 	ApplyConf(node, ifacename, confPath)      // Apply initially
 | |
| 	logger.Log(1, "waiting for interface...") // ensure interface is created
 | |
| 	output, _ := ncutils.RunCmd("wg", false)
 | |
| 	starttime := time.Now()
 | |
| 	ifaceReady := strings.Contains(output, deviceiface)
 | |
| 	for !ifaceReady && !(time.Now().After(starttime.Add(time.Second << 4))) {
 | |
| 		if ncutils.IsMac() { // if node is Mac (Darwin) get the tunnel name first
 | |
| 			deviceiface, mErr = local.GetMacIface(node.PrimaryAddress())
 | |
| 			if mErr != nil || deviceiface == "" {
 | |
| 				deviceiface = ifacename
 | |
| 			}
 | |
| 		}
 | |
| 		output, _ = ncutils.RunCmd("wg", false)
 | |
| 		err = ApplyConf(node, node.Interface, confPath)
 | |
| 		time.Sleep(time.Second)
 | |
| 		ifaceReady = strings.Contains(output, deviceiface)
 | |
| 	}
 | |
| 	//wgclient does not work well on freebsd
 | |
| 	if node.OS == "freebsd" {
 | |
| 		if !ifaceReady {
 | |
| 			return fmt.Errorf("could not reliably create interface, please check wg installation and retry")
 | |
| 		}
 | |
| 	} else {
 | |
| 		_, devErr := wgclient.Device(deviceiface)
 | |
| 		if !ifaceReady || devErr != nil {
 | |
| 			fmt.Printf("%v\n", devErr)
 | |
| 			return fmt.Errorf("could not reliably create interface, please check wg installation and retry")
 | |
| 		}
 | |
| 	}
 | |
| 	logger.Log(1, "interface ready - netclient.. ENGAGE")
 | |
| 
 | |
| 	if !ncutils.HasWgQuick() && ncutils.IsLinux() {
 | |
| 		err = SetPeers(ifacename, node, peers)
 | |
| 		if err != nil {
 | |
| 			logger.Log(1, "error setting peers: ", err.Error())
 | |
| 		}
 | |
| 
 | |
| 		time.Sleep(time.Second)
 | |
| 	}
 | |
| 
 | |
| 	//ipv4
 | |
| 	if node.Address != "" {
 | |
| 		_, cidr, cidrErr := net.ParseCIDR(node.NetworkSettings.AddressRange)
 | |
| 		if cidrErr == nil {
 | |
| 			local.SetCIDRRoute(ifacename, node.Address, cidr)
 | |
| 		} else {
 | |
| 			logger.Log(1, "could not set cidr route properly: ", cidrErr.Error())
 | |
| 		}
 | |
| 		local.SetCurrentPeerRoutes(ifacename, node.Address, peers)
 | |
| 	}
 | |
| 	if node.Address6 != "" {
 | |
| 		//ipv6
 | |
| 		_, cidr, cidrErr := net.ParseCIDR(node.NetworkSettings.AddressRange6)
 | |
| 		if cidrErr == nil {
 | |
| 			local.SetCIDRRoute(ifacename, node.Address6, cidr)
 | |
| 		} else {
 | |
| 			logger.Log(1, "could not set cidr route properly: ", cidrErr.Error())
 | |
| 		}
 | |
| 		local.SetCurrentPeerRoutes(ifacename, node.Address6, peers)
 | |
| 	}
 | |
| 	return err
 | |
| }
 | |
| 
 | |
| // SetWGConfig - sets the WireGuard Config of a given network and checks if it needs a peer update
 | |
| func SetWGConfig(network string, peerupdate bool, peers []wgtypes.PeerConfig) error {
 | |
| 
 | |
| 	cfg, err := config.ReadConfig(network)
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 	privkey, err := RetrievePrivKey(network)
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 	if peerupdate && !ncutils.IsFreeBSD() && !(ncutils.IsLinux() && !ncutils.IsKernel()) {
 | |
| 		var iface string
 | |
| 		iface = cfg.Node.Interface
 | |
| 		if ncutils.IsMac() {
 | |
| 			iface, err = local.GetMacIface(cfg.Node.PrimaryAddress())
 | |
| 			if err != nil {
 | |
| 				return err
 | |
| 			}
 | |
| 		}
 | |
| 		err = SetPeers(iface, &cfg.Node, peers)
 | |
| 	} else {
 | |
| 		err = InitWireguard(&cfg.Node, privkey, peers)
 | |
| 	}
 | |
| 	return err
 | |
| }
 | |
| 
 | |
| // RemoveConf - removes a configuration for a given WireGuard interface
 | |
| func RemoveConf(iface string, printlog bool) error {
 | |
| 	os := runtime.GOOS
 | |
| 	if ncutils.IsLinux() && !ncutils.HasWgQuick() {
 | |
| 		os = "nowgquick"
 | |
| 	}
 | |
| 	var err error
 | |
| 	switch os {
 | |
| 	case "nowgquick":
 | |
| 		err = RemoveWithoutWGQuick(iface)
 | |
| 	case "windows":
 | |
| 		err = RemoveWindowsConf(iface, printlog)
 | |
| 	default:
 | |
| 		confPath := ncutils.GetNetclientPathSpecific() + iface + ".conf"
 | |
| 		err = RemoveWGQuickConf(confPath, printlog)
 | |
| 	}
 | |
| 	return err
 | |
| }
 | |
| 
 | |
| // ApplyConf - applys a conf on disk to WireGuard interface
 | |
| func ApplyConf(node *models.Node, ifacename string, confPath string) error {
 | |
| 	os := runtime.GOOS
 | |
| 	if ncutils.IsLinux() && !ncutils.HasWgQuick() {
 | |
| 		os = "nowgquick"
 | |
| 	}
 | |
| 	var isConnected = node.Connected != "no"
 | |
| 	var err error
 | |
| 	switch os {
 | |
| 	case "windows":
 | |
| 		ApplyWindowsConf(confPath, ifacename, isConnected)
 | |
| 	case "nowgquick":
 | |
| 		ApplyWithoutWGQuick(node, ifacename, confPath, isConnected)
 | |
| 	default:
 | |
| 		ApplyWGQuickConf(confPath, ifacename, isConnected)
 | |
| 	}
 | |
| 
 | |
| 	var nodeCfg config.ClientConfig
 | |
| 	nodeCfg.Network = node.Network
 | |
| 	if !(node.IsServer == "yes") {
 | |
| 		nodeCfg.ReadConfig()
 | |
| 		if nodeCfg.NetworkSettings.AddressRange != "" {
 | |
| 			ip, cidr, err := net.ParseCIDR(nodeCfg.NetworkSettings.AddressRange)
 | |
| 			if err == nil {
 | |
| 				local.SetCIDRRoute(node.Interface, ip.String(), cidr)
 | |
| 			}
 | |
| 		}
 | |
| 		if nodeCfg.NetworkSettings.AddressRange6 != "" {
 | |
| 			ip, cidr, err := net.ParseCIDR(nodeCfg.NetworkSettings.AddressRange6)
 | |
| 			if err == nil {
 | |
| 				local.SetCIDRRoute(node.Interface, ip.String(), cidr)
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 	return err
 | |
| }
 | |
| 
 | |
| // WriteWgConfig - creates a wireguard config file
 | |
| func WriteWgConfig(node *models.Node, privateKey string, peers []wgtypes.PeerConfig) error {
 | |
| 	options := ini.LoadOptions{
 | |
| 		AllowNonUniqueSections: true,
 | |
| 		AllowShadows:           true,
 | |
| 	}
 | |
| 	wireguard := ini.Empty(options)
 | |
| 	wireguard.Section(section_interface).Key("PrivateKey").SetValue(privateKey)
 | |
| 	if node.ListenPort > 0 && node.UDPHolePunch != "yes" {
 | |
| 		wireguard.Section(section_interface).Key("ListenPort").SetValue(strconv.Itoa(int(node.ListenPort)))
 | |
| 	}
 | |
| 	addrString := node.Address
 | |
| 	if node.Address6 != "" {
 | |
| 		if addrString != "" {
 | |
| 			addrString += ","
 | |
| 		}
 | |
| 		addrString += node.Address6
 | |
| 	}
 | |
| 	wireguard.Section(section_interface).Key("Address").SetValue(addrString)
 | |
| 	// need to figure out DNS
 | |
| 	//if node.DNSOn == "yes" {
 | |
| 	//	wireguard.Section(section_interface).Key("DNS").SetValue(cfg.Server.CoreDNSAddr)
 | |
| 	//}
 | |
| 	//need to split postup/postdown because ini lib adds a ` and the ` breaks freebsd
 | |
| 	//works fine on others
 | |
| 	if node.PostUp != "" {
 | |
| 		if node.OS == "freebsd" {
 | |
| 			parts := strings.Split(node.PostUp, " ; ")
 | |
| 			for i, part := range parts {
 | |
| 				if i == 0 {
 | |
| 					wireguard.Section(section_interface).Key("PostUp").SetValue(part)
 | |
| 				}
 | |
| 				wireguard.Section(section_interface).Key("PostUp").AddShadow(part)
 | |
| 			}
 | |
| 		} else {
 | |
| 			wireguard.Section(section_interface).Key("PostUp").SetValue((node.PostUp))
 | |
| 		}
 | |
| 	}
 | |
| 	if node.PostDown != "" {
 | |
| 		if node.OS == "freebsd" {
 | |
| 			parts := strings.Split(node.PostDown, " ; ")
 | |
| 			for i, part := range parts {
 | |
| 				if i == 0 {
 | |
| 					wireguard.Section(section_interface).Key("PostDown").SetValue(part)
 | |
| 				}
 | |
| 				wireguard.Section(section_interface).Key("PostDown").AddShadow(part)
 | |
| 			}
 | |
| 		} else {
 | |
| 			wireguard.Section(section_interface).Key("PostDown").SetValue((node.PostDown))
 | |
| 		}
 | |
| 	}
 | |
| 	if node.MTU != 0 {
 | |
| 		wireguard.Section(section_interface).Key("MTU").SetValue(strconv.FormatInt(int64(node.MTU), 10))
 | |
| 	}
 | |
| 	for i, peer := range peers {
 | |
| 		wireguard.SectionWithIndex(section_peers, i).Key("PublicKey").SetValue(peer.PublicKey.String())
 | |
| 		if peer.PresharedKey != nil {
 | |
| 			wireguard.SectionWithIndex(section_peers, i).Key("PreSharedKey").SetValue(peer.PresharedKey.String())
 | |
| 		}
 | |
| 		if peer.AllowedIPs != nil {
 | |
| 			var allowedIPs string
 | |
| 			for i, ip := range peer.AllowedIPs {
 | |
| 				if i == 0 {
 | |
| 					allowedIPs = ip.String()
 | |
| 				} else {
 | |
| 					allowedIPs = allowedIPs + ", " + ip.String()
 | |
| 				}
 | |
| 			}
 | |
| 			wireguard.SectionWithIndex(section_peers, i).Key("AllowedIps").SetValue(allowedIPs)
 | |
| 		}
 | |
| 		if peer.Endpoint != nil {
 | |
| 			wireguard.SectionWithIndex(section_peers, i).Key("Endpoint").SetValue(peer.Endpoint.String())
 | |
| 		}
 | |
| 
 | |
| 		if peer.PersistentKeepaliveInterval != nil && peer.PersistentKeepaliveInterval.Seconds() > 0 {
 | |
| 			wireguard.SectionWithIndex(section_peers, i).Key("PersistentKeepalive").SetValue(strconv.FormatInt((int64)(peer.PersistentKeepaliveInterval.Seconds()), 10))
 | |
| 		}
 | |
| 	}
 | |
| 	if err := wireguard.SaveTo(ncutils.GetNetclientPathSpecific() + node.Interface + ".conf"); err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| // UpdateWgPeers - updates the peers of a network
 | |
| func UpdateWgPeers(file string, peers []wgtypes.PeerConfig) (*net.UDPAddr, error) {
 | |
| 	var internetGateway *net.UDPAddr
 | |
| 	options := ini.LoadOptions{
 | |
| 		AllowNonUniqueSections: true,
 | |
| 		AllowShadows:           true,
 | |
| 	}
 | |
| 	wireguard, err := ini.LoadSources(options, file)
 | |
| 	if err != nil {
 | |
| 		return internetGateway, err
 | |
| 	}
 | |
| 	//delete the peers sections as they are going to be replaced
 | |
| 	wireguard.DeleteSection(section_peers)
 | |
| 	for i, peer := range peers {
 | |
| 		wireguard.SectionWithIndex(section_peers, i).Key("PublicKey").SetValue(peer.PublicKey.String())
 | |
| 		if peer.PresharedKey != nil {
 | |
| 			wireguard.SectionWithIndex(section_peers, i).Key("PreSharedKey").SetValue(peer.PresharedKey.String())
 | |
| 		}
 | |
| 		if peer.AllowedIPs != nil {
 | |
| 			var allowedIPs string
 | |
| 			for i, ip := range peer.AllowedIPs {
 | |
| 				if i == 0 {
 | |
| 					allowedIPs = ip.String()
 | |
| 				} else {
 | |
| 					allowedIPs = allowedIPs + ", " + ip.String()
 | |
| 				}
 | |
| 			}
 | |
| 			wireguard.SectionWithIndex(section_peers, i).Key("AllowedIps").SetValue(allowedIPs)
 | |
| 			if strings.Contains(allowedIPs, "0.0.0.0/0") || strings.Contains(allowedIPs, "::/0") {
 | |
| 				internetGateway = peer.Endpoint
 | |
| 			}
 | |
| 		}
 | |
| 		if peer.Endpoint != nil {
 | |
| 			wireguard.SectionWithIndex(section_peers, i).Key("Endpoint").SetValue(peer.Endpoint.String())
 | |
| 		}
 | |
| 		if peer.PersistentKeepaliveInterval != nil && peer.PersistentKeepaliveInterval.Seconds() > 0 {
 | |
| 			wireguard.SectionWithIndex(section_peers, i).Key("PersistentKeepalive").SetValue(strconv.FormatInt((int64)(peer.PersistentKeepaliveInterval.Seconds()), 10))
 | |
| 		}
 | |
| 	}
 | |
| 	if err := wireguard.SaveTo(file); err != nil {
 | |
| 		return internetGateway, err
 | |
| 	}
 | |
| 	return internetGateway, nil
 | |
| }
 | |
| 
 | |
| // UpdateWgInterface - updates the interface section of a wireguard config file
 | |
| func UpdateWgInterface(file, privateKey, nameserver string, node models.Node) error {
 | |
| 	options := ini.LoadOptions{
 | |
| 		AllowNonUniqueSections: true,
 | |
| 		AllowShadows:           true,
 | |
| 	}
 | |
| 	wireguard, err := ini.LoadSources(options, file)
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 	if node.UDPHolePunch == "yes" {
 | |
| 		node.ListenPort = 0
 | |
| 	}
 | |
| 	wireguard.DeleteSection(section_interface)
 | |
| 	wireguard.Section(section_interface).Key("PrivateKey").SetValue(privateKey)
 | |
| 	wireguard.Section(section_interface).Key("ListenPort").SetValue(strconv.Itoa(int(node.ListenPort)))
 | |
| 	addrString := node.Address
 | |
| 	if node.Address6 != "" {
 | |
| 		if addrString != "" {
 | |
| 			addrString += ","
 | |
| 		}
 | |
| 		addrString += node.Address6
 | |
| 	}
 | |
| 	wireguard.Section(section_interface).Key("Address").SetValue(addrString)
 | |
| 	//if node.DNSOn == "yes" {
 | |
| 	//	wireguard.Section(section_interface).Key("DNS").SetValue(nameserver)
 | |
| 	//}
 | |
| 	//need to split postup/postdown because ini lib adds a quotes which breaks freebsd
 | |
| 	if node.PostUp != "" {
 | |
| 		if node.OS == "freebsd" {
 | |
| 			parts := strings.Split(node.PostUp, " ; ")
 | |
| 			for i, part := range parts {
 | |
| 				if i == 0 {
 | |
| 					wireguard.Section(section_interface).Key("PostUp").SetValue(part)
 | |
| 				}
 | |
| 				wireguard.Section(section_interface).Key("PostUp").AddShadow(part)
 | |
| 			}
 | |
| 		} else {
 | |
| 			wireguard.Section(section_interface).Key("PostUp").SetValue(node.PostUp)
 | |
| 		}
 | |
| 	}
 | |
| 	if node.PostDown != "" {
 | |
| 		if node.OS == "freebsd" {
 | |
| 			parts := strings.Split(node.PostDown, " ; ")
 | |
| 			for i, part := range parts {
 | |
| 				if i == 0 {
 | |
| 					wireguard.Section(section_interface).Key("PostDown").SetValue(part)
 | |
| 				}
 | |
| 				wireguard.Section(section_interface).Key("PostDown").AddShadow(part)
 | |
| 			}
 | |
| 		} else {
 | |
| 			wireguard.Section(section_interface).Key("PostDown").SetValue(node.PostDown)
 | |
| 		}
 | |
| 	}
 | |
| 	if node.MTU != 0 {
 | |
| 		wireguard.Section(section_interface).Key("MTU").SetValue(strconv.FormatInt(int64(node.MTU), 10))
 | |
| 	}
 | |
| 	if err := wireguard.SaveTo(file); err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| // UpdatePrivateKey - updates the private key of a wireguard config file
 | |
| func UpdatePrivateKey(file, privateKey string) error {
 | |
| 	options := ini.LoadOptions{
 | |
| 		AllowNonUniqueSections: true,
 | |
| 		AllowShadows:           true,
 | |
| 	}
 | |
| 	wireguard, err := ini.LoadSources(options, file)
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 	wireguard.Section(section_interface).Key("PrivateKey").SetValue(privateKey)
 | |
| 	if err := wireguard.SaveTo(file); err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| // UpdateKeepAlive - updates the persistentkeepalive of all peers
 | |
| func UpdateKeepAlive(file string, keepalive int32) error {
 | |
| 	options := ini.LoadOptions{
 | |
| 		AllowNonUniqueSections: true,
 | |
| 		AllowShadows:           true,
 | |
| 	}
 | |
| 	wireguard, err := ini.LoadSources(options, file)
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 	peers, err := wireguard.SectionsByName(section_peers)
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 	newvalue := strconv.Itoa(int(keepalive))
 | |
| 	for i := range peers {
 | |
| 		wireguard.SectionWithIndex(section_peers, i).Key("PersistentKeepALive").SetValue(newvalue)
 | |
| 	}
 | |
| 	if err := wireguard.SaveTo(file); err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| // RemoveConfGraceful - Run remove conf and wait for it to actually be gone before proceeding
 | |
| func RemoveConfGraceful(ifacename string) {
 | |
| 	// ensure you clear any existing interface first
 | |
| 	wgclient, err := wgctrl.New()
 | |
| 	if err != nil {
 | |
| 		logger.Log(0, "could not create wgclient")
 | |
| 		return
 | |
| 	}
 | |
| 	defer wgclient.Close()
 | |
| 	d, _ := wgclient.Device(ifacename)
 | |
| 	startTime := time.Now()
 | |
| 	for d != nil && d.Name == ifacename {
 | |
| 		if err = RemoveConf(ifacename, false); err != nil { // remove interface first
 | |
| 			if strings.Contains(err.Error(), "does not exist") {
 | |
| 				err = nil
 | |
| 				break
 | |
| 			}
 | |
| 		}
 | |
| 		time.Sleep(time.Second >> 2)
 | |
| 		d, _ = wgclient.Device(ifacename)
 | |
| 		if time.Now().After(startTime.Add(time.Second << 4)) {
 | |
| 			break
 | |
| 		}
 | |
| 	}
 | |
| 	time.Sleep(time.Second << 1)
 | |
| }
 | |
| 
 | |
| // GetDevicePeers - gets the current device's peers
 | |
| func GetDevicePeers(iface string) ([]wgtypes.Peer, error) {
 | |
| 	if ncutils.IsFreeBSD() {
 | |
| 		if devicePeers, err := ncutils.GetPeers(iface); err != nil {
 | |
| 			return nil, err
 | |
| 		} else {
 | |
| 			return devicePeers, nil
 | |
| 		}
 | |
| 	} else {
 | |
| 		client, err := wgctrl.New()
 | |
| 		if err != nil {
 | |
| 			logger.Log(0, "failed to start wgctrl")
 | |
| 			return nil, err
 | |
| 		}
 | |
| 		defer client.Close()
 | |
| 		device, err := client.Device(iface)
 | |
| 		if err != nil {
 | |
| 			logger.Log(0, "failed to parse interface", iface)
 | |
| 			return nil, err
 | |
| 		}
 | |
| 		return device.Peers, nil
 | |
| 	}
 | |
| }
 | 
