netmaker/netclient/functions/common.go

1454 lines
42 KiB
Go
Raw Normal View History

2021-03-26 00:17:52 +08:00
package functions
import (
"fmt"
"errors"
2021-03-26 00:17:52 +08:00
"context"
"net/http"
"io/ioutil"
"strings"
"log"
"net"
"os"
"strconv"
"os/exec"
"github.com/gravitl/netmaker/netclient/config"
nodepb "github.com/gravitl/netmaker/grpc"
"golang.zx2c4.com/wireguard/wgctrl"
"google.golang.org/grpc"
"encoding/base64"
2021-03-26 00:17:52 +08:00
"google.golang.org/grpc/metadata"
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
2021-03-26 10:29:36 +08:00
//homedir "github.com/mitchellh/go-homedir"
2021-03-26 00:17:52 +08:00
)
var (
wcclient nodepb.NodeServiceClient
)
func ListPorts() error{
wgclient, err := wgctrl.New()
if err != nil {
return err
}
devices, err := wgclient.Devices()
if err != nil {
return err
}
fmt.Println("Here are your ports:")
for _, i := range devices {
fmt.Println(i.ListenPort)
}
return err
}
func GetFreePort(rangestart int32) (int32, error){
wgclient, err := wgctrl.New()
if err != nil {
return 0, err
}
devices, err := wgclient.Devices()
if err != nil {
return 0, err
}
var portno int32
portno = 0
for x := rangestart; x <= 60000; x++ {
conflict := false
for _, i := range devices {
if int32(i.ListenPort) == x {
conflict = true
break;
}
}
if conflict {
continue
}
portno = x
break
}
return portno, err
}
2021-05-06 21:25:05 +08:00
func Install(accesskey string, password string, server string, network string, noauto bool, accesstoken string, inputname string, pubip string, dnsoff bool, ipforward string) error {
tserver := ""
tnetwork := ""
tkey := ""
2021-04-13 11:19:01 +08:00
trange := ""
var localrange *net.IPNet
islocal := false
if FileExists("/etc/systemd/system/netclient-"+network+".timer") ||
FileExists("/etc/netclient/netconfig-"+network) {
err := errors.New("ALREADY_INSTALLED. Netclient appears to already be installed for network " + network + ". To re-install, please remove by executing 'sudo netclient -c remove -n " + network + "'. Then re-run the install command.")
2021-04-08 21:04:21 +08:00
return err
}
if accesstoken != "" && accesstoken != "badtoken" {
btoken, err := base64.StdEncoding.DecodeString(accesstoken)
if err != nil {
log.Fatalf("Something went wrong decoding your token: %v", err)
}
token := string(btoken)
tokenvals := strings.Split(token, "|")
tserver = tokenvals[0]
tnetwork = tokenvals[1]
tkey = tokenvals[2]
2021-04-13 11:19:01 +08:00
trange = tokenvals[3]
printrange := ""
if server == "localhost:50051" {
2021-04-13 11:19:01 +08:00
server = tserver
}
if network == "nonetwork" {
network = tnetwork
2021-04-13 11:19:01 +08:00
}
if accesskey == "badkey" {
2021-04-13 11:19:01 +08:00
accesskey = tkey
}
fmt.Println(trange)
2021-04-13 11:19:01 +08:00
if trange != "" {
fmt.Println("This is a local network. Proceeding with local address as endpoint.")
2021-04-13 11:19:01 +08:00
islocal = true
_, localrange, err = net.ParseCIDR(trange)
if err == nil {
printrange = localrange.String()
} else {
//localrange = ""
}
2021-04-13 11:19:01 +08:00
} else {
printrange = "Not a local network. Will use public address for endpoint."
2021-04-13 11:19:01 +08:00
}
fmt.Println("Decoded values from token:")
fmt.Println(" Server: " + server)
fmt.Println(" Network: " + network)
fmt.Println(" Key: " + accesskey)
fmt.Println(" Local Range: " + printrange)
}
2021-03-26 00:17:52 +08:00
wgclient, err := wgctrl.New()
if err != nil {
log.Fatalf("failed to open client: %v", err)
}
defer wgclient.Close()
cfg, err := config.ReadConfig(network)
if err != nil {
log.Printf("No Config Yet. Will Write: %v", err)
}
nodecfg := cfg.Node
servercfg := cfg.Server
2021-03-26 00:17:52 +08:00
fmt.Println("SERVER SETTINGS:")
2021-05-06 08:51:59 +08:00
nodecfg.DNSOff = dnsoff
2021-05-06 21:25:05 +08:00
nodecfg.IPForwarding = ipforward
2021-05-06 08:51:59 +08:00
2021-03-26 00:17:52 +08:00
if server == "" {
if servercfg.Address == "" && tserver == "" {
2021-03-26 00:17:52 +08:00
log.Fatal("no server provided")
} else {
server = servercfg.Address
}
}
fmt.Println(" Server: " + server)
if accesskey == "" {
if servercfg.AccessKey == "" && tkey == "" {
2021-03-26 00:17:52 +08:00
fmt.Println("no access key provided.Proceeding anyway.")
} else {
accesskey = servercfg.AccessKey
}
}
fmt.Println(" AccessKey: " + accesskey)
err = config.WriteServer(server, accesskey, network)
2021-03-26 00:17:52 +08:00
if err != nil {
fmt.Println("Error encountered while writing Server Config.")
return err
}
fmt.Println("NODE REQUESTING SETTINGS:")
if password == "" {
if nodecfg.Password == "" {
//create error here
log.Fatal("no password provided")
} else {
password = nodecfg.Password
}
}
fmt.Println(" Password: " + password)
if network == "badnetwork" {
if nodecfg.Network == "" && tnetwork == "" {
2021-03-26 00:17:52 +08:00
//create error here
log.Fatal("no network provided")
2021-03-26 00:17:52 +08:00
} else {
network = nodecfg.Network
2021-03-26 00:17:52 +08:00
}
}
fmt.Println(" Network: " + network)
2021-03-26 00:17:52 +08:00
var macaddress string
var localaddress string
var listenport int32
var keepalive int32
var publickey wgtypes.Key
var privatekey wgtypes.Key
var privkeystring string
var endpoint string
2021-04-15 10:59:25 +08:00
var postup string
var postdown string
2021-03-26 00:17:52 +08:00
var name string
var wginterface string
if nodecfg.LocalAddress == "" {
ifaces, err := net.Interfaces()
if err != nil {
return err
}
var local string
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 err
}
for _, addr := range addrs {
var ip net.IP
switch v := addr.(type) {
case *net.IPNet:
if !found {
ip = v.IP
local = ip.String()
2021-04-13 11:19:01 +08:00
if islocal {
found = localrange.Contains(ip)
} else {
found = true
}
2021-03-26 00:17:52 +08:00
}
case *net.IPAddr:
if !found {
ip = v.IP
local = ip.String()
2021-04-13 11:19:01 +08:00
if islocal {
found = localrange.Contains(ip)
} else {
found = true
}
2021-03-26 00:17:52 +08:00
}
}
}
}
localaddress = local
} else {
localaddress = nodecfg.LocalAddress
}
fmt.Println(" Local Address: " + localaddress)
2021-05-05 05:36:55 +08:00
if pubip != "" && pubip != "nopubip" {
endpoint = pubip
} else {
if nodecfg.Endpoint == "" {
if islocal && localaddress != "" {
endpoint = localaddress
fmt.Println("Endpoint is local. Setting to address: " + endpoint)
} else {
endpoint, err = getPublicIP()
if err != nil {
fmt.Println("Error setting endpoint.")
return err
}
fmt.Println("Endpoint is public. Setting to address: " + endpoint)
}
} else {
endpoint = nodecfg.Endpoint
fmt.Println("Endpoint set in config. Setting to address: " + endpoint)
}
2021-05-05 05:36:55 +08:00
}
fmt.Println(" Endpoint: " + endpoint)
2021-03-26 00:17:52 +08:00
if nodecfg.Name != "" {
name = nodecfg.Name
}
if inputname != "" && inputname != "noname" {
name = inputname
}
2021-03-26 00:17:52 +08:00
fmt.Println(" Name: " + name)
if nodecfg.Interface != "" {
wginterface = nodecfg.Interface
}
fmt.Println(" Interface: " + wginterface)
2021-04-15 10:59:25 +08:00
if nodecfg.PostUp != "" {
postup = nodecfg.PostUp
}
fmt.Println(" PostUp: " + postup)
if nodecfg.PostDown!= "" {
postdown = nodecfg.PostDown
}
fmt.Println(" PostDown: " + postdown)
2021-03-26 00:17:52 +08:00
if nodecfg.KeepAlive != 0 {
keepalive = nodecfg.KeepAlive
}
fmt.Println(" KeepAlive: " + wginterface)
if nodecfg.Port != 0 {
listenport = nodecfg.Port
}
if listenport == 0 {
listenport, err = GetFreePort(51821)
if err != nil {
fmt.Printf("Error retrieving port: %v", err)
}
}
fmt.Printf(" Port: %v", listenport)
fmt.Println("")
2021-03-26 00:17:52 +08:00
if nodecfg.PrivateKey != "" {
privkeystring = nodecfg.PrivateKey
privatekey, err := wgtypes.ParseKey(nodecfg.PrivateKey)
if err != nil {
log.Fatal(err)
}
if nodecfg.PublicKey != "" {
publickey, err = wgtypes.ParseKey(nodecfg.PublicKey)
if err != nil {
log.Fatal(err)
}
} else {
publickey = privatekey.PublicKey()
}
} else {
privatekey, err := wgtypes.GeneratePrivateKey()
if err != nil {
log.Fatal(err)
}
privkeystring = privatekey.String()
publickey = privatekey.PublicKey()
}
if nodecfg.MacAddress != "" {
macaddress = nodecfg.MacAddress
} else {
macs, err := getMacAddr()
if err != nil {
return err
} else if len(macs) == 0 {
log.Fatal()
} else {
macaddress = macs[0]
}
}
fmt.Println(" Mac Address: " + macaddress)
fmt.Println(" Private Key: " + privatekey.String())
fmt.Println(" Public Key: " + publickey.String())
var wcclient nodepb.NodeServiceClient
var requestOpts grpc.DialOption
requestOpts = grpc.WithInsecure()
conn, err := grpc.Dial(server, requestOpts)
if err != nil {
log.Fatalf("Unable to establish client connection to localhost:50051: %v", err)
}
wcclient = nodepb.NewNodeServiceClient(conn)
postnode := &nodepb.Node{
Password: password,
Macaddress: macaddress,
Accesskey: accesskey,
Nodenetwork: network,
2021-03-26 00:17:52 +08:00
Listenport: listenport,
2021-04-15 10:59:25 +08:00
Postup: postup,
Postdown: postdown,
2021-03-26 00:17:52 +08:00
Keepalive: keepalive,
Localaddress: localaddress,
Interface: wginterface,
Publickey: publickey.String(),
Name: name,
Endpoint: endpoint,
}
2021-03-26 10:29:36 +08:00
fmt.Println("Writing node settings to netconfig file.")
2021-03-26 00:17:52 +08:00
err = modConfig(postnode)
if err != nil {
return err
}
res, err := wcclient.CreateNode(
context.TODO(),
&nodepb.CreateNodeReq{
Node: postnode,
},
)
if err != nil {
return err
}
node := res.Node
fmt.Println("Setting local config from server response")
if err != nil {
return err
}
fmt.Println("NODE RECIEVED SETTINGS: ")
fmt.Println(" Password: " + node.Password)
fmt.Println(" WG Address: " + node.Address)
2021-05-06 21:25:05 +08:00
fmt.Println(" WG ipv6 Address: " + node.Address6)
fmt.Println(" Network: " + node.Nodenetwork)
2021-03-26 00:17:52 +08:00
fmt.Println(" Public Endpoint: " + node.Endpoint)
fmt.Println(" Local Address: " + node.Localaddress)
fmt.Println(" Name: " + node.Name)
fmt.Println(" Interface: " + node.Interface)
2021-04-15 10:59:25 +08:00
fmt.Println(" PostUp: " + node.Postup)
fmt.Println(" PostDown: " + node.Postdown)
2021-03-26 00:17:52 +08:00
fmt.Println(" Port: " + strconv.FormatInt(int64(node.Listenport), 10))
fmt.Println(" KeepAlive: " + strconv.FormatInt(int64(node.Keepalive), 10))
fmt.Println(" Public Key: " + node.Publickey)
fmt.Println(" Mac Address: " + node.Macaddress)
fmt.Println(" Is Local?: " + strconv.FormatBool(node.Islocal))
2021-05-06 21:25:05 +08:00
fmt.Println(" Is Dual Stack?: " + strconv.FormatBool(node.Isdualstack))
2021-05-20 10:08:54 +08:00
fmt.Println(" Is Ingress Gateway?: " + strconv.FormatBool(node.Isingressgateway))
fmt.Println(" Local Range: " + node.Localrange)
2021-05-06 21:25:05 +08:00
if node.Dnsoff==true && !nodecfg.DNSOff {
nodecfg.DNSOff = true
}
if !islocal && node.Islocal && node.Localrange != "" {
fmt.Println("Resetting local settings for local network.")
node.Localaddress, err = getLocalIP(node.Localrange)
if err != nil {
return err
}
node.Endpoint = node.Localaddress
}
2021-03-26 00:17:52 +08:00
err = modConfig(node)
if err != nil {
return err
}
if node.Ispending {
fmt.Println("Node is marked as PENDING.")
fmt.Println("Awaiting approval from Admin before configuring WireGuard.")
if !noauto {
2021-03-26 10:29:36 +08:00
fmt.Println("Configuring Netmaker Service.")
err = ConfigureSystemD(network)
2021-03-26 00:17:52 +08:00
return err
}
}
2021-05-20 01:59:10 +08:00
peers, hasGateway, gateways, err := getPeers(node.Macaddress, network, server, node.Isdualstack, node.Isingressgateway)
2021-03-26 00:17:52 +08:00
if err != nil {
return err
}
fmt.Println("retrived peers, setting wireguard config.")
err = storePrivKey(privkeystring, network)
2021-03-26 00:17:52 +08:00
if err != nil {
return err
}
err = initWireguard(node, privkeystring, peers, hasGateway, gateways)
2021-03-26 00:17:52 +08:00
if err != nil {
return err
}
if !noauto {
err = ConfigureSystemD(network)
2021-03-26 00:17:52 +08:00
}
if err != nil {
return err
}
return err
}
func getLocalIP(localrange string) (string, error) {
_, localRange, err := net.ParseCIDR(localrange)
if err != nil {
return "", err
}
ifaces, err := net.Interfaces()
if err != nil {
return "", err
}
var local string
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 "", err
}
for _, addr := range addrs {
var ip net.IP
switch v := addr.(type) {
case *net.IPNet:
if !found {
ip = v.IP
local = ip.String()
found = localRange.Contains(ip)
}
case *net.IPAddr:
if !found {
ip = v.IP
local = ip.String()
found = localRange.Contains(ip)
}
}
}
}
if !found || local == "" {
return "", errors.New("Failed to find local IP in range " + localrange)
}
return local, nil
}
func getPublicIP() (string, error) {
2021-05-06 04:42:17 +08:00
iplist := []string{"http://ip.client.gravitl.com","https://ifconfig.me", "http://api.ipify.org", "http://ipinfo.io/ip"}
endpoint := ""
var err error
for _, ipserver := range iplist {
resp, err := http.Get(ipserver)
if err != nil {
continue
}
defer resp.Body.Close()
if resp.StatusCode == http.StatusOK {
bodyBytes, err := ioutil.ReadAll(resp.Body)
if err != nil {
continue
}
endpoint = string(bodyBytes)
break
}
}
if err == nil && endpoint == "" {
err = errors.New("Public Address Not Found.")
}
return endpoint, err
}
2021-03-26 00:17:52 +08:00
func modConfig(node *nodepb.Node) error{
network := node.Nodenetwork
if network == "" {
return errors.New("No Network Provided")
}
modconfig, err := config.ReadConfig(network)
if err != nil {
return err
}
2021-03-26 00:17:52 +08:00
nodecfg := modconfig.Node
if node.Name != ""{
nodecfg.Name = node.Name
}
if node.Interface != ""{
nodecfg.Interface = node.Interface
}
if node.Nodenetwork != ""{
nodecfg.Network = node.Nodenetwork
2021-03-26 00:17:52 +08:00
}
if node.Macaddress != ""{
nodecfg.MacAddress = node.Macaddress
}
if node.Localaddress != ""{
nodecfg.LocalAddress = node.Localaddress
}
2021-04-15 10:59:25 +08:00
if node.Postup != ""{
nodecfg.PostUp = node.Postup
}
if node.Postdown != ""{
nodecfg.PostDown = node.Postdown
}
2021-03-26 00:17:52 +08:00
if node.Listenport != 0{
nodecfg.Port = node.Listenport
}
if node.Keepalive != 0{
nodecfg.KeepAlive = node.Keepalive
}
if node.Publickey != ""{
nodecfg.PublicKey = node.Publickey
}
if node.Endpoint != ""{
nodecfg.Endpoint = node.Endpoint
}
if node.Password != ""{
nodecfg.Password = node.Password
}
if node.Address != ""{
nodecfg.WGAddress = node.Address
}
2021-05-06 21:25:05 +08:00
if node.Address6 != ""{
nodecfg.WGAddress6 = node.Address6
2021-05-06 08:51:59 +08:00
}
2021-03-26 00:17:52 +08:00
if node.Postchanges != "" {
nodecfg.PostChanges = node.Postchanges
}
2021-05-06 21:25:05 +08:00
if node.Dnsoff == true {
nodecfg.DNSOff = node.Dnsoff
}
if node.Isdualstack == true {
nodecfg.IsDualStack = true
}
2021-05-20 10:08:54 +08:00
nodecfg.IsIngressGateway = node.Isingressgateway
if node.Localrange != "" && node.Islocal {
nodecfg.IsLocal = true
nodecfg.LocalRange = node.Localrange
}
2021-03-26 00:17:52 +08:00
modconfig.Node = nodecfg
err = config.Write(modconfig, network)
2021-03-26 00:17:52 +08:00
return err
}
func getMacAddr() ([]string, error) {
ifas, err := net.Interfaces()
if err != nil {
return nil, err
}
var as []string
for _, ifa := range ifas {
a := ifa.HardwareAddr.String()
if a != "" {
as = append(as, a)
}
}
return as, nil
}
func initWireguard(node *nodepb.Node, privkey string, peers []wgtypes.PeerConfig, hasGateway bool, gateways []string) error {
2021-03-26 00:17:52 +08:00
ipExec, err := exec.LookPath("ip")
if err != nil {
return err
}
key, err := wgtypes.ParseKey(privkey)
if err != nil {
return err
}
wgclient, err := wgctrl.New()
//modcfg := config.Config
//modcfg.ReadConfig()
modcfg, err := config.ReadConfig(node.Nodenetwork)
if err != nil {
return err
}
2021-03-26 00:17:52 +08:00
nodecfg := modcfg.Node
2021-05-06 21:25:05 +08:00
servercfg := modcfg.Server
2021-03-26 00:17:52 +08:00
fmt.Println("beginning local WG config")
if err != nil {
log.Fatalf("failed to open client: %v", err)
}
defer wgclient.Close()
fmt.Println("setting local settings")
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")
}
2021-05-06 21:25:05 +08:00
nameserver := servercfg.Address
nameserver = strings.Split(nameserver, ":")[0]
network := node.Nodenetwork
if nodecfg.Network != "" {
network = nodecfg.Network
} else if node.Nodenetwork != "" {
network = node.Nodenetwork
}
2021-03-26 00:17:52 +08:00
cmdIPDevLinkAdd := &exec.Cmd {
Path: ipExec,
Args: []string{ ipExec, "link", "add", "dev", ifacename, "type", "wireguard" },
Stdout: os.Stdout,
Stderr: os.Stdout,
}
cmdIPAddrAdd := &exec.Cmd {
Path: ipExec,
Args: []string{ ipExec, "address", "add", "dev", ifacename, node.Address+"/24"},
Stdout: os.Stdout,
Stderr: os.Stdout,
}
2021-03-26 12:04:04 +08:00
currentiface, err := net.InterfaceByName(ifacename)
if err != nil {
err = cmdIPDevLinkAdd.Run()
2021-03-26 00:17:52 +08:00
if err != nil && !strings.Contains(err.Error(), "exists") {
fmt.Println("Error creating interface")
//fmt.Println(err.Error())
//return err
}
2021-03-26 12:04:04 +08:00
}
match := false
addrs, _ := currentiface.Addrs()
for _, a := range addrs {
if strings.Contains(a.String(), node.Address){
match = true
}
}
if !match {
2021-03-26 00:17:52 +08:00
err = cmdIPAddrAdd.Run()
if err != nil {
fmt.Println("Error adding address")
//return err
}
2021-03-26 12:04:04 +08:00
}
2021-03-26 00:17:52 +08:00
var nodeport int
nodeport = int(node.Listenport)
fmt.Println("setting WG config from node and peers")
//pubkey := privkey.PublicKey()
conf := wgtypes.Config{
PrivateKey: &key,
ListenPort: &nodeport,
ReplacePeers: true,
Peers: peers,
}
_, 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)
}
}
fmt.Println("configuring WG device")
err = wgclient.ConfigureDevice(ifacename, conf)
if err != nil {
if os.IsNotExist(err) {
fmt.Println("Device does not exist: ")
fmt.Println(err)
} else {
2021-03-26 12:04:04 +08:00
fmt.Printf("This is inconvenient: %v", err)
2021-03-26 00:17:52 +08:00
}
}
2021-05-06 21:25:05 +08:00
//=========DNS Setup==========\\
if nodecfg.DNSOff != true {
_, err := exec.LookPath("resolvectl")
if err != nil {
fmt.Println(err)
fmt.Println("WARNING: resolvectl not present. Unable to set dns. Install resolvectl or run manually.")
} else {
_, err = exec.Command("resolvectl", "domain", ifacename, "~"+network).Output()
if err != nil {
fmt.Println(err)
fmt.Println("WARNING: Error encountered setting dns. Aborted setting dns.")
} else {
_, err = exec.Command("resolvectl", "default-route", ifacename, "false").Output()
if err != nil {
fmt.Println(err)
fmt.Println("WARNING: Error encountered setting dns. Aborted setting dns.")
} else {
_, err = exec.Command("resolvectl", "dns", ifacename, nameserver).Output()
fmt.Println(err)
}
}
}
}
//=========End DNS Setup=======\\
2021-03-26 00:17:52 +08:00
cmdIPLinkUp := &exec.Cmd {
Path: ipExec,
Args: []string{ ipExec, "link", "set", "up", "dev", ifacename},
Stdout: os.Stdout,
Stderr: os.Stdout,
}
cmdIPLinkDown := &exec.Cmd {
Path: ipExec,
Args: []string{ ipExec, "link", "set", "down", "dev", ifacename},
Stdout: os.Stdout,
Stderr: os.Stdout,
}
err = cmdIPLinkDown.Run()
2021-04-15 21:48:14 +08:00
if nodecfg.PostDown != "" {
runcmds := strings.Split(nodecfg.PostDown, "; ")
err = runCmds(runcmds)
if err != nil {
fmt.Println("Error encountered running PostDown: " + err.Error())
}
}
err = cmdIPLinkUp.Run()
if err != nil {
return err
}
if nodecfg.PostUp != "" {
2021-04-15 21:48:14 +08:00
runcmds := strings.Split(nodecfg.PostUp, "; ")
err = runCmds(runcmds)
if err != nil {
fmt.Println("Error encountered running PostUp: " + err.Error())
}
}
if (hasGateway) {
for _, gateway := range gateways {
out, err := exec.Command(ipExec,"-4","route","add",gateway,"dev",ifacename).Output()
fmt.Println(string(out))
if err != nil {
fmt.Println("Error encountered adding gateway: " + err.Error())
}
2021-05-06 22:16:34 +08:00
}
}
2021-05-06 21:25:05 +08:00
if (node.Address6 != "" && node.Isdualstack) {
2021-05-06 22:16:34 +08:00
fmt.Println("Adding address: " + node.Address6)
out, err := exec.Command(ipExec, "address", "add", "dev", ifacename, node.Address6+"/64").Output()
2021-05-06 21:25:05 +08:00
if err != nil {
2021-05-06 22:16:34 +08:00
fmt.Println(out)
2021-05-06 21:25:05 +08:00
fmt.Println("Error encountered adding ipv6: " + err.Error())
}
}
2021-03-26 00:17:52 +08:00
return err
}
2021-04-15 21:48:14 +08:00
func runCmds(commands []string) error {
var err error
for _, command := range commands {
fmt.Println("Running command: " + command)
args := strings.Fields(command)
out, err := exec.Command(args[0], args[1:]...).Output()
fmt.Println(string(out))
if err != nil {
return err
}
}
return err
}
2021-03-26 00:17:52 +08:00
2021-04-06 06:09:21 +08:00
func setWGKeyConfig(network string, serveraddr string) error {
ctx := context.Background()
var header metadata.MD
var wcclient nodepb.NodeServiceClient
var requestOpts grpc.DialOption
requestOpts = grpc.WithInsecure()
conn, err := grpc.Dial(serveraddr, requestOpts)
if err != nil {
fmt.Printf("Cant dial GRPC server: %v", err)
return err
}
wcclient = nodepb.NewNodeServiceClient(conn)
fmt.Println("Authenticating with GRPC Server")
ctx, err = SetJWT(wcclient, network)
if err != nil {
fmt.Printf("Failed to authenticate: %v", err)
return err
}
fmt.Println("Authenticated")
node := getNode(network)
privatekey, err := wgtypes.GeneratePrivateKey()
if err != nil {
return err
}
privkeystring := privatekey.String()
publickey := privatekey.PublicKey()
node.Publickey = publickey.String()
2021-04-06 08:47:19 +08:00
err = storePrivKey(privkeystring, network)
2021-04-06 06:09:21 +08:00
if err != nil {
return err
}
err = modConfig(&node)
if err != nil {
return err
}
postnode := getNode(network)
req := &nodepb.UpdateNodeReq{
Node: &postnode,
}
_, err = wcclient.UpdateNode(ctx, req, grpc.Header(&header))
if err != nil {
return err
}
err = setWGConfig(network)
if err != nil {
return err
log.Fatalf("Error: %v", err)
}
return err
}
func setWGConfig(network string) error {
cfg, err := config.ReadConfig(network)
if err != nil {
return err
}
servercfg := cfg.Server
nodecfg := cfg.Node
node := getNode(network)
2021-03-26 00:17:52 +08:00
2021-05-20 01:59:10 +08:00
peers, hasGateway, gateways, err := getPeers(node.Macaddress, nodecfg.Network, servercfg.Address, node.Isdualstack, node.Isingressgateway)
2021-03-26 00:17:52 +08:00
if err != nil {
return err
}
2021-04-06 08:47:19 +08:00
privkey, err := retrievePrivKey(network)
2021-03-26 00:17:52 +08:00
if err != nil {
return err
}
err = initWireguard(&node, privkey, peers, hasGateway, gateways)
2021-03-26 00:17:52 +08:00
if err != nil {
return err
}
return err
}
2021-04-06 08:47:19 +08:00
func storePrivKey(key string, network string) error{
2021-03-26 00:17:52 +08:00
d1 := []byte(key)
2021-04-06 08:47:19 +08:00
err := ioutil.WriteFile("/etc/netclient/wgkey-" + network, d1, 0644)
2021-03-26 00:17:52 +08:00
return err
}
2021-04-06 08:47:19 +08:00
func retrievePrivKey(network string) (string, error) {
dat, err := ioutil.ReadFile("/etc/netclient/wgkey-" + network)
2021-03-26 00:17:52 +08:00
return string(dat), err
}
func getPrivateAddr() (string, error) {
ifaces, err := net.Interfaces()
if err != nil {
return "", err
}
var local string
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 "", err
}
for _, addr := range addrs {
var ip net.IP
switch v := addr.(type) {
case *net.IPNet:
if !found {
ip = v.IP
local = ip.String()
found = true
}
case *net.IPAddr:
if !found {
ip = v.IP
local = ip.String()
found = true
}
}
}
}
if !found {
err := errors.New("Local Address Not Found.")
return "", err
}
return local, err
}
func CheckIn(network string) error {
node := getNode(network)
cfg, err := config.ReadConfig(network)
if err != nil {
return err
}
nodecfg := cfg.Node
servercfg := cfg.Server
2021-03-26 10:29:36 +08:00
fmt.Println("Checking into server: " + servercfg.Address)
setupcheck := true
2021-03-26 23:14:19 +08:00
ipchange := false
2021-03-26 00:17:52 +08:00
2021-05-06 21:25:05 +08:00
if !(nodecfg.IPForwarding == "off") {
out, err := exec.Command("sysctl", "net.ipv4.ip_forward").Output()
if err != nil {
fmt.Println(err)
fmt.Println("WARNING: Error encountered setting ip forwarding. This can break functionality.")
} else {
s := strings.Fields(string(out))
if s[2] != "1" {
_, err = exec.Command("sysctl", "-w", "net.ipv4.ip_forward=1").Output()
if err != nil {
fmt.Println(err)
fmt.Println("WARNING: Error encountered setting ip forwarding. You may want to investigate this.")
}
}
2021-05-06 08:51:59 +08:00
}
}
if !nodecfg.RoamingOff {
if !nodecfg.IsLocal {
fmt.Println("Checking to see if public addresses have changed")
extIP, err := getPublicIP()
if err != nil {
fmt.Printf("Error encountered checking ip addresses: %v", err)
}
if nodecfg.Endpoint != extIP && extIP != "" {
fmt.Println("Endpoint has changed from " +
nodecfg.Endpoint + " to " + extIP)
fmt.Println("Updating address")
nodecfg.Endpoint = extIP
nodecfg.PostChanges = "true"
node.Endpoint = extIP
node.Postchanges = "true"
2021-03-26 23:14:19 +08:00
ipchange = true
}
intIP, err := getPrivateAddr()
if err != nil {
fmt.Printf("Error encountered checking ip addresses: %v", err)
}
if nodecfg.LocalAddress != intIP && intIP != "" {
fmt.Println("Local Address has changed from " +
nodecfg.LocalAddress + " to " + intIP)
fmt.Println("Updating address")
nodecfg.LocalAddress = intIP
nodecfg.PostChanges = "true"
node.Localaddress = intIP
node.Postchanges = "true"
2021-03-26 23:14:19 +08:00
ipchange = true
}
} else {
fmt.Println("Checking to see if local addresses have changed")
localIP, err := getLocalIP(nodecfg.LocalRange)
if err != nil {
fmt.Printf("Error encountered checking ip addresses: %v", err)
}
if nodecfg.Endpoint != localIP && localIP != "" {
fmt.Println("Endpoint has changed from " +
nodecfg.Endpoint + " to " + localIP)
fmt.Println("Updating address")
nodecfg.Endpoint = localIP
nodecfg.LocalAddress = localIP
nodecfg.PostChanges = "true"
node.Endpoint = localIP
node.Localaddress = localIP
node.Postchanges = "true"
ipchange = true
}
}
if node.Postchanges != "true" {
fmt.Println("Addresses have not changed.")
}
}
2021-03-26 23:14:19 +08:00
if ipchange {
err := modConfig(&node)
if err != nil {
return err
log.Fatalf("Error: %v", err)
}
err = setWGConfig(network)
2021-03-26 23:14:19 +08:00
if err != nil {
return err
log.Fatalf("Error: %v", err)
}
node = getNode(network)
cfg, err := config.ReadConfig(network)
if err != nil {
return err
}
nodecfg = cfg.Node
2021-03-26 23:14:19 +08:00
}
2021-03-26 00:17:52 +08:00
var wcclient nodepb.NodeServiceClient
var requestOpts grpc.DialOption
requestOpts = grpc.WithInsecure()
conn, err := grpc.Dial(servercfg.Address, requestOpts)
if err != nil {
2021-03-26 10:29:36 +08:00
fmt.Printf("Cant dial GRPC server: %v", err)
2021-03-26 00:17:52 +08:00
return err
}
wcclient = nodepb.NewNodeServiceClient(conn)
ctx := context.Background()
fmt.Println("Authenticating with GRPC Server")
ctx, err = SetJWT(wcclient, network)
2021-03-26 00:17:52 +08:00
if err != nil {
2021-03-26 10:29:36 +08:00
fmt.Printf("Failed to authenticate: %v", err)
2021-03-26 00:17:52 +08:00
return err
}
fmt.Println("Authenticated")
2021-03-26 10:29:36 +08:00
fmt.Println("Checking In.")
2021-03-26 00:17:52 +08:00
var header metadata.MD
2021-04-13 13:19:44 +08:00
node.Nodenetwork = network
2021-03-26 00:17:52 +08:00
checkinres, err := wcclient.CheckIn(
ctx,
&nodepb.CheckInReq{
Node: &node,
},
grpc.Header(&header),
)
if err != nil {
2021-03-26 10:29:36 +08:00
if checkinres != nil && checkinres.Checkinresponse.Ispending {
fmt.Println("Node is in pending status. Waiting for Admin approval of node before making further updates.")
2021-03-26 10:29:36 +08:00
return nil
}
fmt.Printf("Unable to process Check In request: %v", err)
2021-03-26 00:17:52 +08:00
return err
}
fmt.Println("Checked in.")
if checkinres.Checkinresponse.Ispending {
fmt.Println("Node is in pending status. Waiting for Admin approval of node before making further updates.")
2021-03-26 00:17:52 +08:00
return err
}
2021-03-26 12:04:04 +08:00
newinterface := getNode(network).Interface
2021-03-26 12:04:04 +08:00
readreq := &nodepb.ReadNodeReq{
Macaddress: node.Macaddress,
Network: node.Nodenetwork,
2021-03-26 12:04:04 +08:00
}
readres, err := wcclient.ReadNode(ctx, readreq, grpc.Header(&header))
if err != nil {
fmt.Printf("Error: %v", err)
} else {
currentiface := readres.Node.Interface
ifaceupdate := newinterface != currentiface
if err != nil {
log.Printf("Error retrieving interface: %v", err)
}
if ifaceupdate {
2021-03-26 23:14:19 +08:00
fmt.Println("Interface update: " + currentiface +
" >>>> " + newinterface)
2021-04-15 21:48:14 +08:00
err := DeleteInterface(currentiface, nodecfg.PostDown)
2021-03-26 12:04:04 +08:00
if err != nil {
fmt.Println("ERROR DELETING INTERFACE: " + currentiface)
}
err = setWGConfig(network)
2021-04-19 22:49:52 +08:00
if err != nil {
log.Printf("Error updating interface: %v", err)
}
}
2021-03-26 12:04:04 +08:00
}
2021-03-26 00:17:52 +08:00
if checkinres.Checkinresponse.Needconfigupdate {
fmt.Println("Server has requested that node update config.")
fmt.Println("Updating config from remote server.")
req := &nodepb.ReadNodeReq{
Macaddress: node.Macaddress,
Network: node.Nodenetwork,
2021-03-26 00:17:52 +08:00
}
readres, err := wcclient.ReadNode(ctx, req, grpc.Header(&header))
if err != nil {
return err
log.Fatalf("Error: %v", err)
}
err = modConfig(readres.Node)
if err != nil {
return err
log.Fatalf("Error: %v", err)
}
err = setWGConfig(network)
2021-03-26 00:17:52 +08:00
if err != nil {
return err
log.Fatalf("Error: %v", err)
}
2021-03-26 10:29:36 +08:00
setupcheck = false
2021-03-26 00:17:52 +08:00
} else if nodecfg.PostChanges == "true" {
fmt.Println("Node has requested to update remote config.")
fmt.Println("Posting local config to remote server.")
postnode := getNode(network)
2021-03-26 12:04:04 +08:00
2021-03-26 00:17:52 +08:00
req := &nodepb.UpdateNodeReq{
Node: &postnode,
}
2021-03-26 12:04:04 +08:00
res, err := wcclient.UpdateNode(ctx, req, grpc.Header(&header))
2021-03-26 00:17:52 +08:00
if err != nil {
return err
log.Fatalf("Error: %v", err)
}
res.Node.Postchanges = "false"
err = modConfig(res.Node)
if err != nil {
return err
log.Fatalf("Error: %v", err)
}
err = setWGConfig(network)
2021-03-26 00:17:52 +08:00
if err != nil {
return err
log.Fatalf("Error: %v", err)
}
2021-03-26 10:29:36 +08:00
setupcheck = false
2021-03-26 00:17:52 +08:00
}
2021-04-06 06:09:21 +08:00
if checkinres.Checkinresponse.Needkeyupdate {
fmt.Println("Server has requested that node update key pairs.")
fmt.Println("Proceeding to re-generate key pairs for Wiregard.")
err = setWGKeyConfig(network, servercfg.Address)
if err != nil {
return err
log.Fatalf("Unable to process reset keys request: %v", err)
}
setupcheck = false
}
2021-03-26 00:17:52 +08:00
if checkinres.Checkinresponse.Needpeerupdate {
fmt.Println("Server has requested that node update peer list.")
fmt.Println("Updating peer list from remote server.")
err = setWGConfig(network)
2021-03-26 00:17:52 +08:00
if err != nil {
return err
log.Fatalf("Unable to process Set Peers request: %v", err)
}
2021-03-26 10:29:36 +08:00
setupcheck = false
2021-03-26 00:17:52 +08:00
}
2021-04-06 08:47:19 +08:00
if checkinres.Checkinresponse.Needdelete {
fmt.Println("This machine got the delete signal. Deleting.")
err := Remove(network)
if err != nil {
return err
log.Fatalf("Error: %v", err)
}
}
2021-03-26 10:29:36 +08:00
if setupcheck {
iface := nodecfg.Interface
_, err := net.InterfaceByName(iface)
if err != nil {
fmt.Println("interface " + iface + " does not currently exist. Setting up WireGuard.")
err = setWGKeyConfig(network, servercfg.Address)
2021-03-26 10:29:36 +08:00
if err != nil {
return err
log.Fatalf("Error: %v", err)
}
}
}
2021-03-26 00:17:52 +08:00
return nil
}
2021-03-26 12:04:04 +08:00
func needInterfaceUpdate(ctx context.Context, mac string, network string, iface string) (bool, string, error) {
2021-03-26 12:04:04 +08:00
var header metadata.MD
req := &nodepb.ReadNodeReq{
Macaddress: mac,
Network: network,
2021-03-26 12:04:04 +08:00
}
readres, err := wcclient.ReadNode(ctx, req, grpc.Header(&header))
if err != nil {
return false, "", err
log.Fatalf("Error: %v", err)
}
oldiface := readres.Node.Interface
return iface != oldiface, oldiface, err
}
func getNode(network string) nodepb.Node {
modcfg, err := config.ReadConfig(network)
if err != nil {
log.Fatalf("Error: %v", err)
}
2021-03-26 00:17:52 +08:00
nodecfg := modcfg.Node
var node nodepb.Node
node.Name = nodecfg.Name
node.Interface = nodecfg.Interface
node.Nodenetwork = nodecfg.Network
2021-03-26 00:17:52 +08:00
node.Localaddress = nodecfg.LocalAddress
node.Address = nodecfg.WGAddress
2021-05-06 21:25:05 +08:00
node.Address6 = nodecfg.WGAddress6
2021-03-26 00:17:52 +08:00
node.Listenport = nodecfg.Port
node.Keepalive = nodecfg.KeepAlive
node.Postup = nodecfg.PostUp
2021-04-13 14:55:49 +08:00
node.Postdown = nodecfg.PostDown
2021-03-26 00:17:52 +08:00
node.Publickey = nodecfg.PublicKey
node.Macaddress = nodecfg.MacAddress
node.Endpoint = nodecfg.Endpoint
node.Password = nodecfg.Password
2021-05-06 21:25:05 +08:00
node.Dnsoff = nodecfg.DNSOff
node.Isdualstack = nodecfg.IsDualStack
2021-05-20 10:08:54 +08:00
node.Isingressgateway = nodecfg.IsIngressGateway
2021-03-26 00:17:52 +08:00
return node
}
func Remove(network string) error {
2021-03-26 00:17:52 +08:00
//need to implement checkin on server side
cfg, err := config.ReadConfig(network)
if err != nil {
return err
}
servercfg := cfg.Server
node := cfg.Node
2021-03-26 00:17:52 +08:00
fmt.Println("Deleting remote node with MAC: " + node.MacAddress)
var wcclient nodepb.NodeServiceClient
var requestOpts grpc.DialOption
requestOpts = grpc.WithInsecure()
conn, err := grpc.Dial(servercfg.Address, requestOpts)
2021-03-26 10:29:36 +08:00
if err != nil {
log.Printf("Unable to establish client connection to " + servercfg.Address + ": %v", err)
//return err
}else {
2021-03-26 00:17:52 +08:00
wcclient = nodepb.NewNodeServiceClient(conn)
ctx := context.Background()
fmt.Println("Authenticating with GRPC Server")
ctx, err = SetJWT(wcclient, network)
2021-03-26 00:17:52 +08:00
if err != nil {
//return err
log.Printf("Failed to authenticate: %v", err)
} else {
2021-03-26 00:17:52 +08:00
fmt.Println("Authenticated")
var header metadata.MD
_, err = wcclient.DeleteNode(
ctx,
&nodepb.DeleteNodeReq{
Macaddress: node.MacAddress,
NetworkName: node.Network,
2021-03-26 00:17:52 +08:00
},
grpc.Header(&header),
)
if err != nil {
log.Printf("Encountered error deleting node: %v", err)
2021-03-26 00:17:52 +08:00
fmt.Println(err)
} else {
fmt.Println("Deleted node " + node.MacAddress)
}
}
}
err = WipeLocal(network)
2021-03-26 00:17:52 +08:00
if err != nil {
log.Printf("Unable to wipe local config: %v", err)
2021-03-26 00:17:52 +08:00
}
err = RemoveSystemDServices(network)
2021-03-26 00:17:52 +08:00
if err != nil {
return err
log.Printf("Unable to remove systemd services: %v", err)
2021-03-26 00:17:52 +08:00
}
fmt.Printf("Please investigate any stated errors to ensure proper removal.")
fmt.Printf("Failure to delete node from server via gRPC will mean node still exists and needs to be manually deleted by administrator.")
2021-03-26 00:17:52 +08:00
return nil
}
func WipeLocal(network string) error{
cfg, err := config.ReadConfig(network)
if err != nil {
return err
}
nodecfg := cfg.Node
2021-03-26 00:17:52 +08:00
ifacename := nodecfg.Interface
2021-03-26 10:29:36 +08:00
//home, err := homedir.Dir()
home := "/etc/netclient"
err = os.Remove(home + "/netconfig-" + network)
2021-03-26 00:17:52 +08:00
if err != nil {
fmt.Println(err)
}
2021-04-07 21:53:27 +08:00
err = os.Remove(home + "/nettoken-" + network)
2021-03-26 00:17:52 +08:00
if err != nil {
fmt.Println(err)
}
2021-04-07 21:53:27 +08:00
err = os.Remove(home + "/wgkey-" + network)
if err != nil {
fmt.Println(err)
}
2021-03-26 00:17:52 +08:00
ipExec, err := exec.LookPath("ip")
if ifacename != "" {
2021-03-26 00:17:52 +08:00
cmdIPLinkDel := &exec.Cmd {
Path: ipExec,
Args: []string{ ipExec, "link", "del", ifacename },
Stdout: os.Stdout,
Stderr: os.Stdout,
}
err = cmdIPLinkDel.Run()
if err != nil {
fmt.Println(err)
}
2021-04-15 21:48:14 +08:00
if nodecfg.PostDown != "" {
runcmds := strings.Split(nodecfg.PostDown, "; ")
err = runCmds(runcmds)
if err != nil {
fmt.Println("Error encountered running PostDown: " + err.Error())
}
}
}
2021-03-26 00:17:52 +08:00
return err
}
2021-04-15 21:48:14 +08:00
func DeleteInterface(ifacename string, postdown string) error{
2021-03-26 10:29:36 +08:00
ipExec, err := exec.LookPath("ip")
cmdIPLinkDel := &exec.Cmd {
Path: ipExec,
Args: []string{ ipExec, "link", "del", ifacename },
Stdout: os.Stdout,
Stderr: os.Stdout,
}
err = cmdIPLinkDel.Run()
if err != nil {
fmt.Println(err)
}
2021-04-15 21:48:14 +08:00
if postdown != "" {
runcmds := strings.Split(postdown, "; ")
err = runCmds(runcmds)
if err != nil {
fmt.Println("Error encountered running PostDown: " + err.Error())
}
}
2021-03-26 10:29:36 +08:00
return err
}