| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262 | package logicimport (	"encoding/json"	"errors"	"fmt"	"net"	"github.com/gravitl/netmaker/database"	"github.com/gravitl/netmaker/logger"	"github.com/gravitl/netmaker/logic/acls/nodeacls"	"github.com/gravitl/netmaker/models"	"golang.zx2c4.com/wireguard/wgctrl/wgtypes")// CreateRelay - creates a relayfunc CreateRelay(relay models.RelayRequest) ([]models.Client, models.Node, error) {	var relayedClients []models.Client	node, err := GetNodeByID(relay.NodeID)	if err != nil {		return relayedClients, models.Node{}, err	}	host, err := GetHost(node.HostID.String())	if err != nil {		return relayedClients, models.Node{}, err	}	if host.OS != "linux" {		return relayedClients, models.Node{}, fmt.Errorf("only linux machines can be relay nodes")	}	err = ValidateRelay(relay)	if err != nil {		return relayedClients, models.Node{}, err	}	node.IsRelay = true	node.RelayedNodes = relay.RelayedNodes	node.SetLastModified()	nodeData, err := json.Marshal(&node)	if err != nil {		return relayedClients, node, err	}	if err = database.Insert(node.ID.String(), string(nodeData), database.NODES_TABLE_NAME); err != nil {		return relayedClients, models.Node{}, err	}	relayedClients = SetRelayedNodes(true, relay.NodeID, relay.RelayedNodes)	for _, relayed := range relayedClients {		data, err := json.Marshal(&relayed.Node)		if err != nil {			logger.Log(0, "marshalling relayed node", err.Error())			continue		}		if err := database.Insert(relayed.Node.ID.String(), string(data), database.NODES_TABLE_NAME); err != nil {			logger.Log(0, "inserting relayed node", err.Error())			continue		}	}	return relayedClients, node, nil}// SetRelayedNodes- sets and saves node as relayedfunc SetRelayedNodes(setRelayed bool, relay string, relayed []string) []models.Client {	var returnnodes []models.Client	for _, id := range relayed {		node, err := GetNodeByID(id)		if err != nil {			logger.Log(0, "setRelayedNodes.GetNodebyID", err.Error())			continue		}		node.IsRelayed = setRelayed		if node.IsRelayed {			node.RelayedBy = relay		} else {			node.RelayedBy = ""		}		node.SetLastModified()		data, err := json.Marshal(&node)		if err != nil {			logger.Log(0, "setRelayedNodes.Marshal", err.Error())			continue		}		if err := database.Insert(node.ID.String(), string(data), database.NODES_TABLE_NAME); err != nil {			logger.Log(0, "setRelayedNodes.Insert", err.Error())			continue		}		host, err := GetHost(node.HostID.String())		if err == nil {			returnnodes = append(returnnodes, models.Client{				Host: *host,				Node: node,			})		}	}	return returnnodes}// ValidateRelay - checks if relay is validfunc ValidateRelay(relay models.RelayRequest) error {	var err error	//isIp := functions.IsIpCIDR(gateway.RangeString)	empty := len(relay.RelayedNodes) == 0	if empty {		err = errors.New("relayed nodes cannot be empty")	}	return err}// UpdateRelayed - updates relay nodesfunc UpdateRelayed(relay string, oldNodes []string, newNodes []string) []models.Client {	_ = SetRelayedNodes(false, relay, oldNodes)	return SetRelayedNodes(true, relay, newNodes)}// DeleteRelay - deletes a relayfunc DeleteRelay(network, nodeid string) ([]models.Client, models.Node, error) {	var returnClients []models.Client	node, err := GetNodeByID(nodeid)	if err != nil {		return returnClients, models.Node{}, err	}	returnClients = SetRelayedNodes(false, nodeid, node.RelayedNodes)	node.IsRelay = false	node.RelayedNodes = []string{}	node.SetLastModified()	data, err := json.Marshal(&node)	if err != nil {		return returnClients, models.Node{}, err	}	if err = database.Insert(nodeid, string(data), database.NODES_TABLE_NAME); err != nil {		return returnClients, models.Node{}, err	}	return returnClients, node, nil}func getRelayedAddresses(id string) []net.IPNet {	addrs := []net.IPNet{}	node, err := GetNodeByID(id)	if err != nil {		logger.Log(0, "getRelayedAddresses: "+err.Error())		return addrs	}	if node.Address.IP != nil {		node.Address.Mask = net.CIDRMask(32, 32)		addrs = append(addrs, node.Address)	}	if node.Address6.IP != nil {		node.Address6.Mask = net.CIDRMask(128, 128)		addrs = append(addrs, node.Address6)	}	return addrs}// peerUpdateForRelayed - returns the peerConfig for a relayed nodefunc peerUpdateForRelayed(client *models.Client, peers []models.Client) []wgtypes.PeerConfig {	peerConfig := []wgtypes.PeerConfig{}	if !client.Node.IsRelayed {		logger.Log(0, "GetPeerUpdateForRelayed called for non-relayed node ", client.Host.Name)		return []wgtypes.PeerConfig{}	}	relayNode, err := GetNodeByID(client.Node.RelayedBy)	if err != nil {		logger.Log(0, "error retrieving relay node", err.Error())		return []wgtypes.PeerConfig{}	}	host, err := GetHost(relayNode.HostID.String())	if err != nil {		return []wgtypes.PeerConfig{}	}	relay := models.Client{		Host: *host,		Node: relayNode,	}	for _, peer := range peers {		if peer.Host.ID == client.Host.ID {			continue		}		if peer.Host.ID == relay.Host.ID { // add relay as a peer			update := peerUpdateForRelayedByRelay(client, &relay)			peerConfig = append(peerConfig, update)			continue		}		update := wgtypes.PeerConfig{			PublicKey: peer.Host.PublicKey,			Remove:    true,		}		peerConfig = append(peerConfig, update)	}	return peerConfig}// peerUpdateForRelayedByRelay - returns the peerConfig for a node relayed by relayfunc peerUpdateForRelayedByRelay(relayed, relay *models.Client) wgtypes.PeerConfig {	if relayed.Node.RelayedBy != relay.Node.ID.String() {		logger.Log(0, "peerUpdateForRelayedByRelay called with invalid parameters")		return wgtypes.PeerConfig{}	}	update := wgtypes.PeerConfig{		PublicKey:         relay.Host.PublicKey,		ReplaceAllowedIPs: true,		Endpoint: &net.UDPAddr{			IP:   relay.Host.EndpointIP,			Port: relay.Host.ListenPort,		},		PersistentKeepaliveInterval: &relay.Node.PersistentKeepalive,	}	if relay.Node.Address.IP != nil {		relay.Node.Address.Mask = net.CIDRMask(32, 32)		update.AllowedIPs = append(update.AllowedIPs, relay.Node.Address)	}	if relay.Node.Address6.IP != nil {		relay.Node.Address6.Mask = net.CIDRMask(128, 128)		update.AllowedIPs = append(update.AllowedIPs, relay.Node.Address6)	}	if relay.Node.IsEgressGateway {		update.AllowedIPs = append(update.AllowedIPs, getEgressIPs(relay)...)	}	if relay.Node.IsIngressGateway {		update.AllowedIPs = append(update.AllowedIPs, getIngressIPs(relay)...)	}	peers, err := GetNetworkClients(relay.Node.Network)	if err != nil {		logger.Log(0, "error getting network clients", err.Error())		return update	}	for _, peer := range peers {		if peer.Host.ID == relayed.Host.ID || peer.Host.ID == relay.Host.ID {			continue		}		if nodeacls.AreNodesAllowed(nodeacls.NetworkID(relayed.Node.Network), nodeacls.NodeID(relayed.Node.ID.String()), nodeacls.NodeID(peer.Node.ID.String())) {			update.AllowedIPs = append(update.AllowedIPs, AddAllowedIPs(&peer)...)		}	}	return update}// peerUpdateForRelay - returns the peerConfig for a relayfunc peerUpdateForRelay(relay *models.Client, peers []models.Client) []wgtypes.PeerConfig {	peerConfig := []wgtypes.PeerConfig{}	if !relay.Node.IsRelay {		logger.Log(0, "GetPeerUpdateForRelay called for non-relay node ", relay.Host.Name)		return []wgtypes.PeerConfig{}	}	for _, peer := range peers {		if peer.Host.ID == relay.Host.ID {			continue		}		update := wgtypes.PeerConfig{			PublicKey:         peer.Host.PublicKey,			ReplaceAllowedIPs: true,			Remove:            false,			Endpoint: &net.UDPAddr{				IP:   peer.Host.EndpointIP,				Port: peer.Host.ListenPort,			},			PersistentKeepaliveInterval: &peer.Node.PersistentKeepalive,		}		if nodeacls.AreNodesAllowed(nodeacls.NetworkID(relay.Node.Network), nodeacls.NodeID(relay.Node.ID.String()), nodeacls.NodeID(peer.Node.ID.String())) {			update.AllowedIPs = append(update.AllowedIPs, AddAllowedIPs(&peer)...)			peerConfig = append(peerConfig, update)		}	}	return peerConfig}
 |