| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302 | package logicimport (	"context"	"errors"	"net"	"sync"	"github.com/google/uuid"	"github.com/gravitl/netmaker/db"	"github.com/gravitl/netmaker/logger"	"github.com/gravitl/netmaker/logic"	"github.com/gravitl/netmaker/models"	"github.com/gravitl/netmaker/schema"	"github.com/gravitl/netmaker/servercfg"	"golang.org/x/exp/slog")var autoRelayCtxMutex = &sync.RWMutex{}var autoRelayCacheMutex = &sync.RWMutex{}var autoRelayCache = make(map[models.NetworkID][]string)func InitAutoRelayCache() {	autoRelayCacheMutex.Lock()	defer autoRelayCacheMutex.Unlock()	allNodes, err := logic.GetAllNodes()	if err != nil {		return	}	for _, node := range allNodes {		if node.IsAutoRelay {			autoRelayCache[models.NetworkID(node.Network)] = append(autoRelayCache[models.NetworkID(node.Network)], node.ID.String())		}	}}func SetAutoRelay(node *models.Node) {	node.IsAutoRelay = true}func CheckAutoRelayCtx(autoRelayNode, victimNode, peerNode models.Node) error {	autoRelayCtxMutex.RLock()	defer autoRelayCtxMutex.RUnlock()	if peerNode.AutoRelayedPeers == nil {		return nil	}	if victimNode.AutoRelayedPeers == nil {		return nil	}	if peerNode.Mutex != nil {		peerNode.Mutex.Lock()	}	_, peerHasAutoRelayed := peerNode.AutoRelayedPeers[victimNode.ID.String()]	if peerNode.Mutex != nil {		peerNode.Mutex.Unlock()	}	if victimNode.Mutex != nil {		victimNode.Mutex.Lock()	}	_, victimHasAutoRelayed := victimNode.AutoRelayedPeers[peerNode.ID.String()]	if victimNode.Mutex != nil {		victimNode.Mutex.Unlock()	}	if peerHasAutoRelayed && victimHasAutoRelayed &&		victimNode.AutoRelayedBy == autoRelayNode.ID && peerNode.AutoRelayedBy == autoRelayNode.ID {		return errors.New("auto relay ctx is already set")	}	return nil}func SetAutoRelayCtx(autoRelayNode, victimNode, peerNode models.Node) error {	autoRelayCtxMutex.Lock()	defer autoRelayCtxMutex.Unlock()	if peerNode.AutoRelayedPeers == nil {		peerNode.AutoRelayedPeers = make(map[string]struct{})	}	if victimNode.AutoRelayedPeers == nil {		victimNode.AutoRelayedPeers = make(map[string]struct{})	}	if peerNode.Mutex != nil {		peerNode.Mutex.Lock()	}	_, peerHasAutoRelayed := peerNode.AutoRelayedPeers[victimNode.ID.String()]	if peerNode.Mutex != nil {		peerNode.Mutex.Unlock()	}	if victimNode.Mutex != nil {		victimNode.Mutex.Lock()	}	_, victimHasAutoRelayed := victimNode.AutoRelayedPeers[peerNode.ID.String()]	if victimNode.Mutex != nil {		victimNode.Mutex.Unlock()	}	if peerHasAutoRelayed && victimHasAutoRelayed &&		victimNode.AutoRelayedBy == autoRelayNode.ID && peerNode.AutoRelayedBy == autoRelayNode.ID {		return errors.New("auto relay ctx is already set")	}	if peerNode.Mutex != nil {		peerNode.Mutex.Lock()	}	peerNode.AutoRelayedPeers[victimNode.ID.String()] = struct{}{}	if peerNode.Mutex != nil {		peerNode.Mutex.Unlock()	}	if victimNode.Mutex != nil {		victimNode.Mutex.Lock()	}	victimNode.AutoRelayedPeers[peerNode.ID.String()] = struct{}{}	if victimNode.Mutex != nil {		victimNode.Mutex.Unlock()	}	victimNode.AutoRelayedBy = autoRelayNode.ID	// peerNode.AutoRelayedBy = autoRelayNode.ID	if err := logic.UpsertNode(&victimNode); err != nil {		return err	}	if err := logic.UpsertNode(&peerNode); err != nil {		return err	}	return nil}// GetAutoRelayNode - gets the host acting as autoRelayfunc GetAutoRelayNode(network string, allNodes []models.Node) (models.Node, error) {	nodes := logic.GetNetworkNodesMemory(allNodes, network)	for _, node := range nodes {		if node.IsAutoRelay {			return node, nil		}	}	return models.Node{}, errors.New("auto relay not found")}func RemoveAutoRelayFromCache(network string) {	autoRelayCacheMutex.Lock()	defer autoRelayCacheMutex.Unlock()	delete(autoRelayCache, models.NetworkID(network))}func SetAutoRelayInCache(node models.Node) {	autoRelayCacheMutex.Lock()	defer autoRelayCacheMutex.Unlock()	autoRelayCache[models.NetworkID(node.Network)] = append(autoRelayCache[models.NetworkID(node.Network)], node.ID.String())}// DoesAutoRelayExist - checks if autorelay exists already in the networkfunc DoesAutoRelayExist(network string) (autoRelayNodes []models.Node) {	autoRelayCacheMutex.RLock()	defer autoRelayCacheMutex.RUnlock()	if !servercfg.CacheEnabled() {		nodes, _ := logic.GetNetworkNodes(network)		for _, node := range nodes {			if node.IsAutoRelay {				autoRelayNodes = append(autoRelayNodes, node)			}		}	}	if nodeIDs, ok := autoRelayCache[models.NetworkID(network)]; ok {		for _, nodeID := range nodeIDs {			autoRelayNode, err := logic.GetNodeByID(nodeID)			if err == nil {				autoRelayNodes = append(autoRelayNodes, autoRelayNode)			}		}	}	return}// ResetAutoRelayedPeer - removes auto relayed over node from network peersfunc ResetAutoRelayedPeer(autoRelayedNode *models.Node) error {	nodes, err := logic.GetNetworkNodes(autoRelayedNode.Network)	if err != nil {		return err	}	autoRelayedNode.AutoRelayedBy = uuid.Nil	autoRelayedNode.AutoRelayedPeers = make(map[string]struct{})	err = logic.UpsertNode(autoRelayedNode)	if err != nil {		return err	}	for _, node := range nodes {		if node.AutoRelayedPeers == nil || node.ID == autoRelayedNode.ID {			continue		}		delete(node.AutoRelayedPeers, autoRelayedNode.ID.String())		logic.UpsertNode(&node)	}	return nil}// ResetAutoRelay - reset autorelayed peersfunc ResetAutoRelay(autoRelayNode *models.Node) error {	// Unset autorelayed peers	nodes, err := logic.GetNetworkNodes(autoRelayNode.Network)	if err != nil {		return err	}	for _, node := range nodes {		if node.AutoRelayedBy == autoRelayNode.ID {			node.AutoRelayedBy = uuid.Nil			node.AutoRelayedPeers = make(map[string]struct{})			logic.UpsertNode(&node)			for _, peer := range nodes {				if peer.ID == node.ID {					continue				}				if _, ok := peer.AutoRelayedPeers[node.ID.String()]; ok {					delete(peer.AutoRelayedPeers, node.ID.String())					logic.UpsertNode(&peer)				}			}		}	}	return nil}// GetAutoRelayPeerIps - adds the autorelayed peerIps by the peerfunc GetAutoRelayPeerIps(peer, node *models.Node) []net.IPNet {	allowedips := []net.IPNet{}	eli, _ := (&schema.Egress{Network: node.Network}).ListByNetwork(db.WithContext(context.TODO()))	acls, _ := logic.ListAclsByNetwork(models.NetworkID(node.Network))	for autoRelayedpeerID := range node.AutoRelayedPeers {		autoRelayedpeer, err := logic.GetNodeByID(autoRelayedpeerID)		if err == nil && (autoRelayedpeer.AutoRelayedBy == peer.ID || node.AutoRelayedBy == peer.ID) {			logic.GetNodeEgressInfo(&autoRelayedpeer, eli, acls)			if autoRelayedpeer.Address.IP != nil {				allowed := net.IPNet{					IP:   autoRelayedpeer.Address.IP,					Mask: net.CIDRMask(32, 32),				}				allowedips = append(allowedips, allowed)			}			if autoRelayedpeer.Address6.IP != nil {				allowed := net.IPNet{					IP:   autoRelayedpeer.Address6.IP,					Mask: net.CIDRMask(128, 128),				}				allowedips = append(allowedips, allowed)			}			if autoRelayedpeer.EgressDetails.IsEgressGateway {				allowedips = append(allowedips, logic.GetEgressIPs(&autoRelayedpeer)...)			}			if autoRelayedpeer.IsRelay {				for _, id := range autoRelayedpeer.RelayedNodes {					rNode, _ := logic.GetNodeByID(id)					logic.GetNodeEgressInfo(&rNode, eli, acls)					if rNode.Address.IP != nil {						allowed := net.IPNet{							IP:   rNode.Address.IP,							Mask: net.CIDRMask(32, 32),						}						allowedips = append(allowedips, allowed)					}					if rNode.Address6.IP != nil {						allowed := net.IPNet{							IP:   rNode.Address6.IP,							Mask: net.CIDRMask(128, 128),						}						allowedips = append(allowedips, allowed)					}					if rNode.EgressDetails.IsEgressGateway {						allowedips = append(allowedips, logic.GetEgressIPs(&rNode)...)					}				}			}			// handle ingress gateway peers			if autoRelayedpeer.IsIngressGateway {				extPeers, _, _, err := logic.GetExtPeers(&autoRelayedpeer, node)				if err != nil {					logger.Log(2, "could not retrieve ext peers for ", peer.ID.String(), err.Error())				}				for _, extPeer := range extPeers {					allowedips = append(allowedips, extPeer.AllowedIPs...)				}			}		}	}	return allowedips}func CreateAutoRelay(node models.Node) error {	host, err := logic.GetHost(node.HostID.String())	if err != nil {		return err	}	if host.OS != models.OS_Types.Linux {		return errors.New("only linux nodes are allowed to be set as autoRelay")	}	if node.IsRelayed {		return errors.New("relayed node cannot be set as autoRelay")	}	node.IsAutoRelay = true	err = logic.UpsertNode(&node)	if err != nil {		slog.Error("failed to upsert node", "node", node.ID.String(), "error", err)		return err	}	if servercfg.CacheEnabled() {		SetAutoRelayInCache(node)	}	return nil}
 |