| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766 | package logicimport (	"encoding/binary"	"encoding/json"	"errors"	"fmt"	"net"	"os/exec"	"strings"	"time"	"github.com/go-playground/validator/v10"	"github.com/gravitl/netmaker/database"	"github.com/gravitl/netmaker/logger"	"github.com/gravitl/netmaker/models"	"github.com/gravitl/netmaker/netclient/ncutils"	"github.com/gravitl/netmaker/validation")// GetNetworks - returns all networks from databasefunc GetNetworks() ([]models.Network, error) {	var networks []models.Network	collection, err := database.FetchRecords(database.NETWORKS_TABLE_NAME)	if err != nil {		return networks, err	}	for _, value := range collection {		var network models.Network		if err := json.Unmarshal([]byte(value), &network); err != nil {			return networks, err		}		// add network our array		networks = append(networks, network)	}	return networks, err}// DeleteNetwork - deletes a networkfunc DeleteNetwork(network string) error {	nodeCount, err := GetNetworkNonServerNodeCount(network)	if nodeCount == 0 || database.IsEmptyRecord(err) {		// delete server nodes first then db records		servers, err := GetSortedNetworkServerNodes(network)		if err == nil {			for _, s := range servers {				if err = DeleteNodeByID(&s, true); err != nil {					logger.Log(2, "could not removed server", s.Name, "before deleting network", network)				} else {					logger.Log(2, "removed server", s.Name, "before deleting network", network)				}			}		} else {			logger.Log(1, "could not remove servers before deleting network", network)		}		return database.DeleteRecord(database.NETWORKS_TABLE_NAME, network)	}	return errors.New("node check failed. All nodes must be deleted before deleting network")}// CreateNetwork - creates a network in databasefunc CreateNetwork(network models.Network) error {	network.SetDefaults()	network.SetNodesLastModified()	network.SetNetworkLastModified()	network.KeyUpdateTimeStamp = time.Now().Unix()	err := ValidateNetwork(&network, false)	if err != nil {		//returnErrorResponse(w, r, formatError(err, "badrequest"))		return err	}	data, err := json.Marshal(&network)	if err != nil {		return err	}	if err = database.Insert(network.NetID, string(data), database.NETWORKS_TABLE_NAME); err != nil {		return err	}	return err}// NetworkNodesUpdatePullChanges - tells nodes on network to pullfunc NetworkNodesUpdatePullChanges(networkName string) error {	collections, err := database.FetchRecords(database.NODES_TABLE_NAME)	if err != nil {		if database.IsEmptyRecord(err) {			return nil		}		return err	}	for _, value := range collections {		var node models.Node		err := json.Unmarshal([]byte(value), &node)		if err != nil {			fmt.Println("error in node address assignment!")			return err		}		if node.Network == networkName {			node.PullChanges = "yes"			data, err := json.Marshal(&node)			if err != nil {				return err			}			database.Insert(node.ID, string(data), database.NODES_TABLE_NAME)		}	}	return nil}// GetNetworkNonServerNodeCount - get number of network non server nodesfunc GetNetworkNonServerNodeCount(networkName string) (int, error) {	collection, err := database.FetchRecords(database.NODES_TABLE_NAME)	count := 0	if err != nil && !database.IsEmptyRecord(err) {		return count, err	}	for _, value := range collection {		var node models.Node		if err = json.Unmarshal([]byte(value), &node); err != nil {			return count, err		} else {			if node.Network == networkName && node.IsServer != "yes" {				count++			}		}	}	return count, nil}// GetParentNetwork - get parent networkfunc GetParentNetwork(networkname string) (models.Network, error) {	var network models.Network	networkData, err := database.FetchRecord(database.NETWORKS_TABLE_NAME, networkname)	if err != nil {		return network, err	}	if err = json.Unmarshal([]byte(networkData), &network); err != nil {		return models.Network{}, err	}	return network, nil}// GetParentNetwork - get parent networkfunc GetNetworkSettings(networkname string) (models.Network, error) {	var network models.Network	networkData, err := database.FetchRecord(database.NETWORKS_TABLE_NAME, networkname)	if err != nil {		return network, err	}	if err = json.Unmarshal([]byte(networkData), &network); err != nil {		return models.Network{}, err	}	network.AccessKeys = []models.AccessKey{}	return network, nil}// UniqueAddress - see if address is uniquefunc UniqueAddress(networkName string) (string, error) {	var network models.Network	network, err := GetParentNetwork(networkName)	if err != nil {		fmt.Println("UniqueAddress encountered  an error")		return "666", err	}	offset := true	ip, ipnet, err := net.ParseCIDR(network.AddressRange)	if err != nil {		fmt.Println("UniqueAddress encountered  an error")		return "666", err	}	for ip := ip.Mask(ipnet.Mask); ipnet.Contains(ip); Inc(ip) {		if offset {			offset = false			continue		}		if networkName == "comms" {			if IsIPUnique(networkName, ip.String(), database.INT_CLIENTS_TABLE_NAME, false) {				return ip.String(), err			}		} else {			if IsIPUnique(networkName, ip.String(), database.NODES_TABLE_NAME, false) && IsIPUnique(networkName, ip.String(), database.EXT_CLIENT_TABLE_NAME, false) {				return ip.String(), err			}		}	}	//TODO	err1 := errors.New("ERROR: No unique addresses available. Check network subnet.")	return "W1R3: NO UNIQUE ADDRESSES AVAILABLE", err1}// UniqueAddressServer - get unique address starting from last availablefunc UniqueAddressServer(networkName string) (string, error) {	var network models.Network	network, err := GetParentNetwork(networkName)	if err != nil {		logger.Log(0, "UniqueAddressServer encountered  an error")		return "666", err	}	_, ipv4Net, err := net.ParseCIDR(network.AddressRange)	if err != nil {		logger.Log(0, "UniqueAddressServer encountered  an error")		return "666", err	}	// convert IPNet struct mask and address to uint32	// network is BigEndian	mask := binary.BigEndian.Uint32(ipv4Net.Mask)	start := binary.BigEndian.Uint32(ipv4Net.IP)	// find the final address	finish := (start & mask) | (mask ^ 0xffffffff)	// loop through addresses as uint32	for i := finish - 1; i > start; i-- {		// convert back to net.IP		ip := make(net.IP, 4)		binary.BigEndian.PutUint32(ip, i)		if IsIPUnique(networkName, ip.String(), database.NODES_TABLE_NAME, false) && IsIPUnique(networkName, ip.String(), database.EXT_CLIENT_TABLE_NAME, false) {			return ip.String(), err		}	}	return "W1R3: NO UNIQUE ADDRESSES AVAILABLE", fmt.Errorf("no unique server addresses found")}// IsIPUnique - checks if an IP is uniquefunc IsIPUnique(network string, ip string, tableName string, isIpv6 bool) bool {	isunique := true	collection, err := database.FetchRecords(tableName)	if err != nil {		return isunique	}	for _, value := range collection { // filter		var node models.Node		if err = json.Unmarshal([]byte(value), &node); err != nil {			continue		}		if isIpv6 {			if node.Address6 == ip && node.Network == network {				return false			}		} else {			if node.Address == ip && node.Network == network {				return false			}		}	}	return isunique}// UniqueAddress6 - see if ipv6 address is uniquefunc UniqueAddress6(networkName string) (string, error) {	var network models.Network	network, err := GetParentNetwork(networkName)	if err != nil {		fmt.Println("Network Not Found")		return "", err	}	if network.IsDualStack == "no" {		return "", nil	}	offset := true	ip, ipnet, err := net.ParseCIDR(network.AddressRange6)	if err != nil {		fmt.Println("UniqueAddress6 encountered  an error")		return "666", err	}	for ip := ip.Mask(ipnet.Mask); ipnet.Contains(ip); Inc(ip) {		if offset {			offset = false			continue		}		if IsIPUnique(networkName, ip.String(), database.NODES_TABLE_NAME, true) {			return ip.String(), err		}	}	//TODO	err1 := errors.New("ERROR: No unique addresses available. Check network subnet.")	return "W1R3: NO UNIQUE ADDRESSES AVAILABLE", err1}// GetLocalIP - gets the local ipfunc 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}// UpdateNetworkLocalAddresses - updates network localaddressesfunc UpdateNetworkLocalAddresses(networkName string) error {	collection, err := database.FetchRecords(database.NODES_TABLE_NAME)	if err != nil {		return err	}	for _, value := range collection {		var node models.Node		err := json.Unmarshal([]byte(value), &node)		if err != nil {			fmt.Println("error in node address assignment!")			return err		}		if node.Network == networkName {			ipaddr, iperr := UniqueAddress(networkName)			if iperr != nil {				fmt.Println("error in node  address assignment!")				return iperr			}			node.Address = ipaddr			newNodeData, err := json.Marshal(&node)			if err != nil {				logger.Log(1, "error in node  address assignment!")				return err			}			database.Insert(node.ID, string(newNodeData), database.NODES_TABLE_NAME)		}	}	return nil}// UpdateNetworkLocalAddresses - updates network localaddressesfunc UpdateNetworkHolePunching(networkName string, holepunch string) error {	nodes, err := GetNetworkNodes(networkName)	if err != nil {		return err	}	for _, node := range nodes {		if node.IsServer != "yes" {			node.UDPHolePunch = holepunch			newNodeData, err := json.Marshal(&node)			if err != nil {				logger.Log(1, "error in node hole punch assignment")				return err			}			database.Insert(node.ID, string(newNodeData), database.NODES_TABLE_NAME)		}	}	return nil}// RemoveNetworkNodeIPv6Addresses - removes network node IPv6 addressesfunc RemoveNetworkNodeIPv6Addresses(networkName string) error {	collections, err := database.FetchRecords(database.NODES_TABLE_NAME)	if err != nil {		return err	}	for _, value := range collections {		var node models.Node		err := json.Unmarshal([]byte(value), &node)		if err != nil {			fmt.Println("error in node address assignment!")			return err		}		if node.Network == networkName {			node.IsDualStack = "no"			node.Address6 = ""			node.PullChanges = "yes"			data, err := json.Marshal(&node)			if err != nil {				return err			}			database.Insert(node.ID, string(data), database.NODES_TABLE_NAME)		}	}	return nil}// UpdateNetworkNodeAddresses - updates network node addressesfunc UpdateNetworkNodeAddresses(networkName string) error {	collections, err := database.FetchRecords(database.NODES_TABLE_NAME)	if err != nil {		return err	}	for _, value := range collections {		var node models.Node		err := json.Unmarshal([]byte(value), &node)		if err != nil {			fmt.Println("error in node address assignment!")			return err		}		if node.Network == networkName {			ipaddr, iperr := UniqueAddress(networkName)			if iperr != nil {				fmt.Println("error in node  address assignment!")				return iperr			}			node.Address = ipaddr			node.PullChanges = "yes"			data, err := json.Marshal(&node)			if err != nil {				return err			}			database.Insert(node.ID, string(data), database.NODES_TABLE_NAME)		}	}	return nil}// IsNetworkDisplayNameUnique - checks if displayname is unique from other networksfunc IsNetworkDisplayNameUnique(network *models.Network) (bool, error) {	isunique := true	records, err := GetNetworks()	if err != nil && !database.IsEmptyRecord(err) {		return false, err	}	for i := 0; i < len(records); i++ {		if network.NetID == records[i].DisplayName {			isunique = false		}	}	return isunique, nil}// IsNetworkNameUnique - checks to see if any other networks have the same name (id)func IsNetworkNameUnique(network *models.Network) (bool, error) {	isunique := true	dbs, err := GetNetworks()	if err != nil && !database.IsEmptyRecord(err) {		return false, err	}	for i := 0; i < len(dbs); i++ {		if network.NetID == dbs[i].NetID {			isunique = false		}	}	return isunique, nil}// UpdateNetwork - updates a network with another network's fieldsfunc UpdateNetwork(currentNetwork *models.Network, newNetwork *models.Network) (bool, bool, bool, error) {	if err := ValidateNetwork(newNetwork, true); err != nil {		return false, false, false, err	}	if newNetwork.NetID == currentNetwork.NetID {		hasrangeupdate := newNetwork.AddressRange != currentNetwork.AddressRange		localrangeupdate := newNetwork.LocalRange != currentNetwork.LocalRange		hasholepunchupdate := newNetwork.DefaultUDPHolePunch != currentNetwork.DefaultUDPHolePunch		data, err := json.Marshal(newNetwork)		if err != nil {			return false, false, false, err		}		newNetwork.SetNetworkLastModified()		err = database.Insert(newNetwork.NetID, string(data), database.NETWORKS_TABLE_NAME)		return hasrangeupdate, localrangeupdate, hasholepunchupdate, err	}	// copy values	return false, false, false, errors.New("failed to update network " + newNetwork.NetID + ", cannot change netid.")}// Inc - increments an IPfunc Inc(ip net.IP) {	for j := len(ip) - 1; j >= 0; j-- {		ip[j]++		if ip[j] > 0 {			break		}	}}// GetNetwork - gets a network from databasefunc GetNetwork(networkname string) (models.Network, error) {	var network models.Network	networkData, err := database.FetchRecord(database.NETWORKS_TABLE_NAME, networkname)	if err != nil {		return network, err	}	if err = json.Unmarshal([]byte(networkData), &network); err != nil {		return models.Network{}, err	}	return network, nil}// Network.NetIDInNetworkCharSet - checks if a netid of a network uses valid charactersfunc NetIDInNetworkCharSet(network *models.Network) bool {	charset := "abcdefghijklmnopqrstuvwxyz1234567890-_."	for _, char := range network.NetID {		if !strings.Contains(charset, strings.ToLower(string(char))) {			return false		}	}	return true}// Network.Validate - validates fields of an network structfunc ValidateNetwork(network *models.Network, isUpdate bool) error {	v := validator.New()	_ = v.RegisterValidation("netid_valid", func(fl validator.FieldLevel) bool {		inCharSet := NetIDInNetworkCharSet(network)		if isUpdate {			return inCharSet		}		isFieldUnique, _ := IsNetworkNameUnique(network)		return isFieldUnique && inCharSet	})	//	_ = v.RegisterValidation("displayname_valid", func(fl validator.FieldLevel) bool {		isFieldUnique, _ := IsNetworkDisplayNameUnique(network)		inCharSet := network.DisplayNameInNetworkCharSet()		if isUpdate {			return inCharSet		}		return isFieldUnique && inCharSet	})	_ = v.RegisterValidation("checkyesorno", func(fl validator.FieldLevel) bool {		return validation.CheckYesOrNo(fl)	})	err := v.Struct(network)	if err != nil {		for _, e := range err.(validator.ValidationErrors) {			fmt.Println(e)		}	}	return err}// ParseNetwork - parses a network into a modelfunc ParseNetwork(value string) (models.Network, error) {	var network models.Network	err := json.Unmarshal([]byte(value), &network)	return network, err}// ValidateNetworkUpdate - checks if network is valid to updatefunc ValidateNetworkUpdate(network models.Network) error {	v := validator.New()	_ = v.RegisterValidation("netid_valid", func(fl validator.FieldLevel) bool {		if fl.Field().String() == "" {			return true		}		inCharSet := nameInNetworkCharSet(fl.Field().String())		return inCharSet	})	err := v.Struct(network)	if err != nil {		for _, e := range err.(validator.ValidationErrors) {			logger.Log(1, "validator", e.Error())		}	}	return err}// KeyUpdate - updates keys on networkfunc KeyUpdate(netname string) (models.Network, error) {	err := networkNodesUpdateAction(netname, models.NODE_UPDATE_KEY)	if err != nil {		return models.Network{}, err	}	return models.Network{}, nil}//SaveNetwork - save network struct to databasefunc SaveNetwork(network *models.Network) error {	data, err := json.Marshal(network)	if err != nil {		return err	}	if err := database.Insert(network.NetID, string(data), database.NETWORKS_TABLE_NAME); err != nil {		return err	}	return nil}// == Private ==func networkNodesUpdateAction(networkName string, action string) error {	collections, err := database.FetchRecords(database.NODES_TABLE_NAME)	if err != nil {		if database.IsEmptyRecord(err) {			return nil		}		return err	}	for _, value := range collections {		var node models.Node		err := json.Unmarshal([]byte(value), &node)		if err != nil {			fmt.Println("error in node address assignment!")			return err		}		if action == models.NODE_UPDATE_KEY && node.IsStatic == "yes" {			continue		}		if node.Network == networkName {			node.Action = action			data, err := json.Marshal(&node)			if err != nil {				return err			}			database.Insert(node.ID, string(data), database.NODES_TABLE_NAME)		}	}	return nil}func nameInNetworkCharSet(name string) bool {	charset := "abcdefghijklmnopqrstuvwxyz1234567890-_."	for _, char := range name {		if !strings.Contains(charset, strings.ToLower(string(char))) {			return false		}	}	return true}func deleteInterface(ifacename string, postdown string) error {	var err error	if !ncutils.IsKernel() {		err = RemoveConf(ifacename, true)	} else {		ipExec, errN := exec.LookPath("ip")		err = errN		if err != nil {			logger.Log(1, err.Error())		}		_, err = ncutils.RunCmd(ipExec+" link del "+ifacename, false)		if postdown != "" {			runcmds := strings.Split(postdown, "; ")			err = ncutils.RunCmds(runcmds, false)		}	}	return err}func isInterfacePresent(iface string, address string) (string, bool) {	var interfaces []net.Interface	var err error	interfaces, err = net.Interfaces()	if err != nil {		logger.Log(0, "ERROR: could not read interfaces")		return "", true	}	for _, currIface := range interfaces {		var currAddrs []net.Addr		currAddrs, err = currIface.Addrs()		if err != nil || len(currAddrs) == 0 {			continue		}		for _, addr := range currAddrs {			if strings.Contains(addr.String(), address) && currIface.Name != iface {				logger.Log(2, "found iface", addr.String(), currIface.Name)				interfaces = nil				currAddrs = nil				return currIface.Name, false			}		}		currAddrs = nil	}	interfaces = nil	logger.Log(2, "failed to find iface", iface)	return "", true}
 |