mirror of
https://github.com/gravitl/netmaker.git
synced 2024-11-15 14:20:25 +08:00
403 lines
11 KiB
Go
403 lines
11 KiB
Go
package functions
|
|
|
|
import (
|
|
"fmt"
|
|
"encoding/json"
|
|
"errors"
|
|
"context"
|
|
"net/http"
|
|
"io/ioutil"
|
|
"strings"
|
|
"log"
|
|
"net"
|
|
"os"
|
|
"os/exec"
|
|
"github.com/gravitl/netmaker/netclient/config"
|
|
"github.com/gravitl/netmaker/netclient/local"
|
|
"github.com/gravitl/netmaker/netclient/auth"
|
|
nodepb "github.com/gravitl/netmaker/grpc"
|
|
"golang.zx2c4.com/wireguard/wgctrl"
|
|
"google.golang.org/grpc"
|
|
"google.golang.org/grpc/metadata"
|
|
//homedir "github.com/mitchellh/go-homedir"
|
|
)
|
|
|
|
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
|
|
}
|
|
|
|
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) {
|
|
|
|
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
|
|
}
|
|
|
|
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 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 needInterfaceUpdate(ctx context.Context, mac string, network string, iface string) (bool, string, error) {
|
|
var header metadata.MD
|
|
req := &nodepb.ReadNodeReq{
|
|
Macaddress: mac,
|
|
Network: network,
|
|
}
|
|
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)
|
|
}
|
|
|
|
nodecfg := modcfg.Node
|
|
var node nodepb.Node
|
|
|
|
node.Name = nodecfg.Name
|
|
node.Interface = nodecfg.Interface
|
|
node.Nodenetwork = nodecfg.Network
|
|
node.Localaddress = nodecfg.LocalAddress
|
|
node.Address = nodecfg.WGAddress
|
|
node.Address6 = nodecfg.WGAddress6
|
|
node.Listenport = nodecfg.Port
|
|
node.Keepalive = nodecfg.KeepAlive
|
|
node.Postup = nodecfg.PostUp
|
|
node.Postdown = nodecfg.PostDown
|
|
node.Publickey = nodecfg.PublicKey
|
|
node.Macaddress = nodecfg.MacAddress
|
|
node.Endpoint = nodecfg.Endpoint
|
|
node.Password = nodecfg.Password
|
|
if nodecfg.DNS == "on" {
|
|
node.Dnsoff = true
|
|
} else {
|
|
node.Dnsoff = false
|
|
}
|
|
if nodecfg.IsDualStack == "yes" {
|
|
node.Isdualstack = true
|
|
} else {
|
|
node.Isdualstack = false
|
|
}
|
|
if nodecfg.IsIngressGateway == "yes" {
|
|
node.Isingressgateway = true
|
|
} else {
|
|
node.Isingressgateway = false
|
|
}
|
|
return node
|
|
}
|
|
|
|
func Uninstall() error {
|
|
networks, err := GetNetworks()
|
|
if err != nil {
|
|
log.Println("unable to retrieve networks: ", err)
|
|
log.Println("continuing uninstall without leaving networks")
|
|
} else {
|
|
for _, network := range networks {
|
|
err = LeaveNetwork(network)
|
|
if err != nil {
|
|
log.Println("Encounter issue leaving network " + network + ": ", err)
|
|
}
|
|
}
|
|
}
|
|
return err
|
|
}
|
|
|
|
func LeaveNetwork(network string) error {
|
|
//need to implement checkin on server side
|
|
cfg, err := config.ReadConfig(network)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
servercfg := cfg.Server
|
|
node := cfg.Node
|
|
|
|
var wcclient nodepb.NodeServiceClient
|
|
var requestOpts grpc.DialOption
|
|
requestOpts = grpc.WithInsecure()
|
|
conn, err := grpc.Dial(servercfg.GRPCAddress, requestOpts)
|
|
if err != nil {
|
|
log.Printf("Unable to establish client connection to " + servercfg.GRPCAddress + ": %v", err)
|
|
}else {
|
|
wcclient = nodepb.NewNodeServiceClient(conn)
|
|
|
|
ctx := context.Background()
|
|
ctx, err = auth.SetJWT(wcclient, network)
|
|
if err != nil {
|
|
log.Printf("Failed to authenticate: %v", err)
|
|
} else {
|
|
var header metadata.MD
|
|
_, err = wcclient.DeleteNode(
|
|
ctx,
|
|
&nodepb.DeleteNodeReq{
|
|
Macaddress: node.MacAddress,
|
|
NetworkName: node.Network,
|
|
},
|
|
grpc.Header(&header),
|
|
)
|
|
if err != nil {
|
|
log.Printf("Encountered error deleting node: %v", err)
|
|
fmt.Println(err)
|
|
} else {
|
|
fmt.Println("delete node " + node.MacAddress + "from remote server on network " + node.Network)
|
|
}
|
|
}
|
|
}
|
|
err = local.WipeLocal(network)
|
|
if err != nil {
|
|
log.Printf("Unable to wipe local config: %v", err)
|
|
}
|
|
err = local.RemoveSystemDServices(network)
|
|
return err
|
|
}
|
|
|
|
func DeleteInterface(ifacename string, postdown string) error{
|
|
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)
|
|
}
|
|
if postdown != "" {
|
|
runcmds := strings.Split(postdown, "; ")
|
|
err = local.RunCmds(runcmds)
|
|
if err != nil {
|
|
fmt.Println("Error encountered running PostDown: " + err.Error())
|
|
}
|
|
}
|
|
return err
|
|
}
|
|
|
|
|
|
func List() error{
|
|
|
|
networks, err := GetNetworks()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
for _, network := range networks {
|
|
cfg, err := config.ReadConfig(network)
|
|
if err == nil {
|
|
//cfg2 := *cfg
|
|
listconfig := &config.ListConfig{
|
|
Name: cfg.Node.Name,
|
|
Interface: cfg.Node.Interface,
|
|
PrivateIPv4: cfg.Node.WGAddress,
|
|
PrivateIPv6: cfg.Node.WGAddress6,
|
|
PublicEndpoint: cfg.Node.Endpoint,
|
|
}
|
|
jsoncfg, _ := json.Marshal(listconfig)
|
|
fmt.Println(network + ": " + string(jsoncfg))
|
|
} else {
|
|
fmt.Println(network + ": Could not retrieve network configuration.")
|
|
}
|
|
}
|
|
return nil
|
|
|
|
}
|
|
|
|
func GetNetworks() ([]string, error) {
|
|
var networks []string
|
|
files, err := ioutil.ReadDir("/etc/netclient")
|
|
if err != nil {
|
|
return networks, err
|
|
}
|
|
for _, f := range files {
|
|
if strings.Contains(f.Name(), "netconfig-") && !strings.Contains(f.Name(), "global-001"){
|
|
networkname := stringAfter(f.Name(), "netconfig-")
|
|
networks = append(networks, networkname)
|
|
}
|
|
}
|
|
return networks, err
|
|
}
|
|
|
|
func stringAfter(original string, substring string) string {
|
|
position := strings.LastIndex(original, substring)
|
|
if position == -1 {
|
|
return ""
|
|
}
|
|
adjustedPosition := position + len(substring)
|
|
|
|
if adjustedPosition >= len(original) {
|
|
return ""
|
|
}
|
|
return original[adjustedPosition:len(original)]
|
|
}
|