From ea20799925091be8c2424a18d488d1e1e2d00b21 Mon Sep 17 00:00:00 2001 From: Matthew R Kasun Date: Thu, 11 May 2023 18:27:05 -0400 Subject: [PATCH 1/9] revert relays --- cli/cmd/host/create_relay.go | 22 --- cli/cmd/node/create_relay.go | 22 +++ cli/cmd/{host => node}/delete_relay.go | 12 +- cli/cmd/node/flags.go | 2 +- cli/cmd/node/update.go | 6 +- cli/functions/host.go | 17 +- controllers/hosts.go | 40 ----- controllers/node.go | 44 +----- controllers/relay.go | 105 ------------- logic/nodes.go | 46 +----- logic/peers.go | 57 ++----- logic/relay.go | 210 ++++++++----------------- logic/wireguard.go | 6 +- models/api_host.go | 12 -- models/api_node.go | 10 +- models/host.go | 4 - models/node.go | 11 +- models/structs.go | 6 +- 18 files changed, 147 insertions(+), 485 deletions(-) delete mode 100644 cli/cmd/host/create_relay.go create mode 100644 cli/cmd/node/create_relay.go rename cli/cmd/{host => node}/delete_relay.go (51%) diff --git a/cli/cmd/host/create_relay.go b/cli/cmd/host/create_relay.go deleted file mode 100644 index 2344af725..000000000 --- a/cli/cmd/host/create_relay.go +++ /dev/null @@ -1,22 +0,0 @@ -package host - -import ( - "strings" - - "github.com/gravitl/netmaker/cli/functions" - "github.com/spf13/cobra" -) - -var hostCreateRelayCmd = &cobra.Command{ - Use: "create_relay [HOST ID] [RELAYED HOST IDS (comma separated)]", - Args: cobra.ExactArgs(2), - Short: "Turn a Host into a Relay", - Long: `Turn a Host into a Relay`, - Run: func(cmd *cobra.Command, args []string) { - functions.PrettyPrint(functions.CreateRelay(args[0], strings.Split(args[1], ","))) - }, -} - -func init() { - rootCmd.AddCommand(hostCreateRelayCmd) -} diff --git a/cli/cmd/node/create_relay.go b/cli/cmd/node/create_relay.go new file mode 100644 index 000000000..e17dce57f --- /dev/null +++ b/cli/cmd/node/create_relay.go @@ -0,0 +1,22 @@ +package node + +import ( + "strings" + + "github.com/gravitl/netmaker/cli/functions" + "github.com/spf13/cobra" +) + +var hostCreateRelayCmd = &cobra.Command{ + Use: "create_relay [NETWORK][NODE ID] [RELAYED NODE IDS (comma separated)]", + Args: cobra.ExactArgs(3), + Short: "Turn a Node into a Relay", + Long: `Turn a Node into a Relay`, + Run: func(cmd *cobra.Command, args []string) { + functions.PrettyPrint(functions.CreateRelay(args[0], args[1], strings.Split(args[2], ","))) + }, +} + +func init() { + rootCmd.AddCommand(hostCreateRelayCmd) +} diff --git a/cli/cmd/host/delete_relay.go b/cli/cmd/node/delete_relay.go similarity index 51% rename from cli/cmd/host/delete_relay.go rename to cli/cmd/node/delete_relay.go index ccf203e64..91e2522d9 100644 --- a/cli/cmd/host/delete_relay.go +++ b/cli/cmd/node/delete_relay.go @@ -1,4 +1,4 @@ -package host +package node import ( "github.com/gravitl/netmaker/cli/functions" @@ -6,12 +6,12 @@ import ( ) var hostDeleteRelayCmd = &cobra.Command{ - Use: "delete_relay [HOST ID]", - Args: cobra.ExactArgs(1), - Short: "Delete Relay role from a host", - Long: `Delete Relay role from a host`, + Use: "delete_relay [NETWORK] [NODE ID]", + Args: cobra.ExactArgs(2), + Short: "Delete Relay from a node", + Long: `Delete Relay from a node`, Run: func(cmd *cobra.Command, args []string) { - functions.PrettyPrint(functions.DeleteRelay(args[0])) + functions.PrettyPrint(functions.DeleteRelay(args[0], args[1])) }, } diff --git a/cli/cmd/node/flags.go b/cli/cmd/node/flags.go index b7da4d036..48f2f7495 100644 --- a/cli/cmd/node/flags.go +++ b/cli/cmd/node/flags.go @@ -12,7 +12,7 @@ var ( postUp string postDown string keepAlive int - relayAddrs string + relayedNodes string egressGatewayRanges string expirationDateTime int defaultACL bool diff --git a/cli/cmd/node/update.go b/cli/cmd/node/update.go index ce0d98467..e2d2d3836 100644 --- a/cli/cmd/node/update.go +++ b/cli/cmd/node/update.go @@ -35,8 +35,8 @@ var nodeUpdateCmd = &cobra.Command{ node.Address6 = address6 node.LocalAddress = localAddress node.PersistentKeepalive = int32(keepAlive) - if relayAddrs != "" { - node.RelayAddrs = strings.Split(relayAddrs, ",") + if relayedNodes != "" { + node.RelayedNodes = strings.Split(relayedNodes, ",") } if egressGatewayRanges != "" { node.EgressGatewayRanges = strings.Split(egressGatewayRanges, ",") @@ -62,7 +62,7 @@ func init() { nodeUpdateCmd.Flags().StringVar(&postUp, "post_up", "", "Commands to run after node is up `;` separated") nodeUpdateCmd.Flags().StringVar(&postDown, "post_down", "", "Commands to run after node is down `;` separated") nodeUpdateCmd.Flags().IntVar(&keepAlive, "keep_alive", 0, "Interval in which packets are sent to keep connections open with peers") - nodeUpdateCmd.Flags().StringVar(&relayAddrs, "relay_addrs", "", "Addresses for relaying connections if node acts as a relay") + nodeUpdateCmd.Flags().StringVar(&relayedNodes, "relayed_nodes", "", "relayed nodes if node acts as a relay") nodeUpdateCmd.Flags().StringVar(&egressGatewayRanges, "egress_addrs", "", "Addresses for egressing traffic if node acts as an egress") nodeUpdateCmd.Flags().IntVar(&expirationDateTime, "expiry", 0, "UNIX timestamp after which node will lose access to the network") nodeUpdateCmd.Flags().BoolVar(&defaultACL, "acl", false, "Enable default ACL ?") diff --git a/cli/functions/host.go b/cli/functions/host.go index 16fac4243..bfcf0f03b 100644 --- a/cli/functions/host.go +++ b/cli/functions/host.go @@ -36,17 +36,18 @@ func DeleteHostFromNetwork(hostID, network string) *hostNetworksUpdatePayload { return request[hostNetworksUpdatePayload](http.MethodDelete, "/api/hosts/"+hostID+"/networks/"+network, nil) } -// CreateRelay - turn a host into a relay -func CreateRelay(hostID string, relayedHosts []string) *models.ApiHost { - return request[models.ApiHost](http.MethodPost, fmt.Sprintf("/api/hosts/%s/relay", hostID), &models.HostRelayRequest{ - HostID: hostID, - RelayedHosts: relayedHosts, +// CreateRelay - add relay to a node +func CreateRelay(netID, nodeID string, relayedNodes []string) *models.ApiNode { + return request[models.ApiNode](http.MethodPost, fmt.Sprintf("/api/nodes/%s/%s/createrelay", netID, nodeID), &models.RelayRequest{ + NodeID: nodeID, + NetID: netID, + RelayedNodes: relayedNodes, }) } -// DeleteRelay - remove relay role from a host -func DeleteRelay(hostID string) *models.ApiHost { - return request[models.ApiHost](http.MethodDelete, fmt.Sprintf("/api/hosts/%s/relay", hostID), nil) +// DeleteRelay - remove relay from a node +func DeleteRelay(netID, nodeID string) *models.ApiNode { + return request[models.ApiNode](http.MethodDelete, fmt.Sprintf("/api/nodes/%s/%s/deleterelay", netID, nodeID), nil) } // RefreshKeys - refresh wireguard keys diff --git a/controllers/hosts.go b/controllers/hosts.go index 833caa44a..a7617f69f 100644 --- a/controllers/hosts.go +++ b/controllers/hosts.go @@ -6,7 +6,6 @@ import ( "errors" "fmt" "net/http" - "reflect" "github.com/gorilla/mux" "github.com/gravitl/netmaker/logger" @@ -26,8 +25,6 @@ func hostHandlers(r *mux.Router) { r.HandleFunc("/api/hosts/{hostid}", logic.SecurityCheck(true, http.HandlerFunc(deleteHost))).Methods(http.MethodDelete) r.HandleFunc("/api/hosts/{hostid}/networks/{network}", logic.SecurityCheck(true, http.HandlerFunc(addHostToNetwork))).Methods(http.MethodPost) r.HandleFunc("/api/hosts/{hostid}/networks/{network}", logic.SecurityCheck(true, http.HandlerFunc(deleteHostFromNetwork))).Methods(http.MethodDelete) - r.HandleFunc("/api/hosts/{hostid}/relay", logic.SecurityCheck(false, http.HandlerFunc(createHostRelay))).Methods(http.MethodPost) - r.HandleFunc("/api/hosts/{hostid}/relay", logic.SecurityCheck(false, http.HandlerFunc(deleteHostRelay))).Methods(http.MethodDelete) r.HandleFunc("/api/hosts/adm/authenticate", authenticateHost).Methods(http.MethodPost) r.HandleFunc("/api/v1/host", authorize(true, false, "host", http.HandlerFunc(pull))).Methods(http.MethodGet) r.HandleFunc("/api/v1/host/{hostid}/signalpeer", authorize(true, false, "host", http.HandlerFunc(signalPeer))).Methods(http.MethodPost) @@ -143,13 +140,6 @@ func updateHost(w http.ResponseWriter, r *http.Request) { } newHost := newHostData.ConvertAPIHostToNMHost(currHost) - // check if relay information is changed - updateRelay := false - if newHost.IsRelay && len(newHost.RelayedHosts) > 0 { - if len(newHost.RelayedHosts) != len(currHost.RelayedHosts) || !reflect.DeepEqual(newHost.RelayedHosts, currHost.RelayedHosts) { - updateRelay = true - } - } logic.UpdateHost(newHost, currHost) // update the in memory struct values if err = logic.UpsertHost(newHost); err != nil { @@ -157,9 +147,6 @@ func updateHost(w http.ResponseWriter, r *http.Request) { logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal")) return } - if updateRelay { - logic.UpdateHostRelay(currHost.ID.String(), currHost.RelayedHosts, newHost.RelayedHosts) - } // publish host update through MQ if err := mq.HostUpdate(&models.HostUpdate{ Action: models.UpdateHost, @@ -213,33 +200,6 @@ func deleteHost(w http.ResponseWriter, r *http.Request) { logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal")) return } - if currHost.IsRelay { - if _, _, err := logic.DeleteHostRelay(hostid); err != nil { - logger.Log(0, r.Header.Get("user"), "failed to dissociate host from relays:", err.Error()) - logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal")) - return - } - } - if currHost.IsRelayed { - relayHost, err := logic.GetHost(currHost.RelayedBy) - if err != nil { - logger.Log(0, r.Header.Get("user"), "failed to fetch relay host:", err.Error()) - logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal")) - return - } - newRelayedHosts := make([]string, 0) - for _, relayedHostID := range relayHost.RelayedHosts { - if relayedHostID != hostid { - newRelayedHosts = append(newRelayedHosts, relayedHostID) - } - } - relayHost.RelayedHosts = newRelayedHosts - if err := logic.UpsertHost(relayHost); err != nil { - logger.Log(0, r.Header.Get("user"), "failed to update host relays:", err.Error()) - logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal")) - return - } - } if err = logic.RemoveHost(currHost); err != nil { logger.Log(0, r.Header.Get("user"), "failed to delete a host:", err.Error()) logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal")) diff --git a/controllers/node.go b/controllers/node.go index 92852c64b..0e1b7a3b2 100644 --- a/controllers/node.go +++ b/controllers/node.go @@ -4,6 +4,7 @@ import ( "context" "encoding/json" "fmt" + "log" "net/http" "strings" @@ -636,12 +637,12 @@ func updateNode(w http.ResponseWriter, r *http.Request) { } newNode := newData.ConvertToServerNode(¤tNode) relayupdate := false - if currentNode.IsRelay && len(newNode.RelayAddrs) > 0 { - if len(newNode.RelayAddrs) != len(currentNode.RelayAddrs) { + if currentNode.IsRelay && len(newNode.RelayedNodes) > 0 { + if len(newNode.RelayedNodes) != len(currentNode.RelayedNodes) { relayupdate = true } else { - for i, addr := range newNode.RelayAddrs { - if addr != currentNode.RelayAddrs[i] { + for i, node := range newNode.RelayedNodes { + if node != currentNode.RelayedNodes[i] { relayupdate = true } } @@ -654,10 +655,6 @@ func updateNode(w http.ResponseWriter, r *http.Request) { logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal")) return } - relayedUpdate := false - if currentNode.IsRelayed && (currentNode.Address.String() != newNode.Address.String() || currentNode.Address6.String() != newNode.Address6.String()) { - relayedUpdate = true - } ifaceDelta := logic.IfaceDelta(¤tNode, newNode) aclUpdate := currentNode.DefaultACL != newNode.DefaultACL if ifaceDelta && servercfg.Is_EE { @@ -673,17 +670,16 @@ func updateNode(w http.ResponseWriter, r *http.Request) { logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal")) return } + log.Println("relay was updated") if relayupdate { - updatenodes := logic.UpdateRelay(currentNode.Network, currentNode.RelayAddrs, newNode.RelayAddrs) + log.Println("updating relayed nodes") + updatenodes := logic.UpdateRelayed(currentNode.ID.String(), currentNode.RelayedNodes, newNode.RelayedNodes) if len(updatenodes) > 0 { for _, relayedNode := range updatenodes { runUpdates(&relayedNode, false) } } } - if relayedUpdate { - updateRelay(¤tNode, newNode) - } if servercfg.IsDNSMode() { logic.SetDNS() } @@ -781,30 +777,6 @@ func runUpdates(node *models.Node, ifaceDelta bool) { }() } -func updateRelay(oldnode, newnode *models.Node) { - relay := logic.FindRelay(oldnode) - newrelay := relay - //check if node's address has been updated and if so, update the relayAddrs of the relay node with the updated address of the relayed node - if oldnode.Address.String() != newnode.Address.String() { - for i, ip := range newrelay.RelayAddrs { - if ip == oldnode.Address.IP.String() { - newrelay.RelayAddrs = append(newrelay.RelayAddrs[:i], relay.RelayAddrs[i+1:]...) - newrelay.RelayAddrs = append(newrelay.RelayAddrs, newnode.Address.IP.String()) - } - } - } - //check if node's address(v6) has been updated and if so, update the relayAddrs of the relay node with the updated address(v6) of the relayed node - if oldnode.Address6.String() != newnode.Address6.String() { - for i, ip := range newrelay.RelayAddrs { - if ip == oldnode.Address.IP.String() { - newrelay.RelayAddrs = append(newrelay.RelayAddrs[:i], newrelay.RelayAddrs[i+1:]...) - newrelay.RelayAddrs = append(newrelay.RelayAddrs, newnode.Address6.IP.String()) - } - } - } - logic.UpdateNode(relay, newrelay) -} - func doesUserOwnNode(username, network, nodeID string) bool { u, err := logic.GetUser(username) if err != nil { diff --git a/controllers/relay.go b/controllers/relay.go index f82423592..c7c487ffe 100644 --- a/controllers/relay.go +++ b/controllers/relay.go @@ -92,108 +92,3 @@ func deleteRelay(w http.ResponseWriter, r *http.Request) { json.NewEncoder(w).Encode(apiNode) runUpdates(&node, true) } - -// swagger:route POST /api/hosts/{hostid}/relay hosts createHostRelay -// -// Create a relay. -// -// Schemes: https -// -// Security: -// oauth -// -// Responses: -// 200: nodeResponse -func createHostRelay(w http.ResponseWriter, r *http.Request) { - var relay models.HostRelayRequest - var params = mux.Vars(r) - w.Header().Set("Content-Type", "application/json") - err := json.NewDecoder(r.Body).Decode(&relay) - if err != nil { - logger.Log(0, r.Header.Get("user"), "error decoding request body: ", err.Error()) - logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest")) - return - } - relay.HostID = params["hostid"] - relayHost, relayedHosts, err := logic.CreateHostRelay(relay) - if err != nil { - logger.Log(0, r.Header.Get("user"), - fmt.Sprintf("failed to create relay on host [%s]: %v", relay.HostID, err)) - logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal")) - return - } - - if err := mq.HostUpdate(&models.HostUpdate{ - Action: models.UpdateHost, - Host: *relayHost, - }); err != nil { - logger.Log(0, "failed to send host update: ", relayHost.ID.String(), err.Error()) - } - logger.Log(1, r.Header.Get("user"), "created relay on host", relay.HostID) - go func(relayHostID string) { - for _, relayedHost := range relayedHosts { - relayedHost.ProxyEnabled = true - logic.UpsertHost(&relayedHost) - if err := mq.HostUpdate(&models.HostUpdate{ - Action: models.UpdateHost, - Host: relayedHost, - }); err != nil { - logger.Log(0, "failed to send host update: ", relayedHost.ID.String(), err.Error()) - } - } - if err := mq.PublishPeerUpdate(); err != nil { - logger.Log(0, "fail to publish peer update: ", err.Error()) - } - - }(relay.HostID) - - apiHostData := relayHost.ConvertNMHostToAPI() - w.WriteHeader(http.StatusOK) - json.NewEncoder(w).Encode(apiHostData) -} - -// swagger:route DELETE /api/hosts/{hostid}/relay hosts deleteHostRelay -// -// Remove a relay. -// -// Schemes: https -// -// Security: -// oauth -// -// Responses: -// 200: nodeResponse -func deleteHostRelay(w http.ResponseWriter, r *http.Request) { - w.Header().Set("Content-Type", "application/json") - var params = mux.Vars(r) - hostid := params["hostid"] - relayHost, relayed, err := logic.DeleteHostRelay(hostid) - if err != nil { - logger.Log(0, r.Header.Get("user"), "error decoding request body: ", err.Error()) - logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest")) - return - } - logger.Log(1, r.Header.Get("user"), "deleted relay host", hostid) - go func() { - if err := mq.PublishPeerUpdate(); err != nil { - logger.Log(0, "fail to publish peer update: ", err.Error()) - } - if err := mq.HostUpdate(&models.HostUpdate{ - Action: models.UpdateHost, - Host: *relayHost, - }); err != nil { - logger.Log(0, "failed to send host update: ", relayHost.Name, err.Error()) - } - for _, relayedHost := range relayed { - if err := mq.HostUpdate(&models.HostUpdate{ - Action: models.UpdateHost, - Host: relayedHost, - }); err != nil { - logger.Log(0, "failed to send host update: ", relayedHost.Name, err.Error()) - } - } - }() - apiHostData := relayHost.ConvertNMHostToAPI() - w.WriteHeader(http.StatusOK) - json.NewEncoder(w).Encode(apiHostData) -} diff --git a/logic/nodes.go b/logic/nodes.go index 955a7b542..7726efaaa 100644 --- a/logic/nodes.go +++ b/logic/nodes.go @@ -326,34 +326,6 @@ func GetDeletedNodeByMacAddress(network string, macaddress string) (models.Node, return node, nil } -// GetNodeRelay - gets the relay node of a given network -func GetNodeRelay(network string, relayedNodeAddr string) (models.Node, error) { - collection, err := database.FetchRecords(database.NODES_TABLE_NAME) - var relay models.Node - if err != nil { - if database.IsEmptyRecord(err) { - return relay, nil - } - logger.Log(2, err.Error()) - return relay, err - } - for _, value := range collection { - err := json.Unmarshal([]byte(value), &relay) - if err != nil { - logger.Log(2, err.Error()) - continue - } - if relay.IsRelay { - for _, addr := range relay.RelayAddrs { - if addr == relayedNodeAddr { - return relay, nil - } - } - } - } - return relay, errors.New(RELAY_NODE_ERR + " " + relayedNodeAddr) -} - func GetNodeByID(uuid string) (models.Node, error) { var record, err = database.FetchRecord(database.NODES_TABLE_NAME, uuid) if err != nil { @@ -387,24 +359,12 @@ func GetDeletedNodeByID(uuid string) (models.Node, error) { // FindRelay - returns the node that is the relay for a relayed node func FindRelay(node *models.Node) *models.Node { - if !node.IsRelayed { - return nil - } - peers, err := GetNetworkNodes(node.Network) + relay, err := GetNodeByID(node.RelayedBy) if err != nil { + logger.Log(0, "FindRelay: "+err.Error()) return nil } - for _, peer := range peers { - if !peer.IsRelay { - continue - } - for _, ip := range peer.RelayAddrs { - if ip == node.Address.IP.String() || ip == node.Address6.IP.String() { - return &peer - } - } - } - return nil + return &relay } // GetNetworkIngresses - gets the gateways of a network diff --git a/logic/peers.go b/logic/peers.go index c31330f6c..01fb4bdad 100644 --- a/logic/peers.go +++ b/logic/peers.go @@ -29,41 +29,6 @@ func GetProxyUpdateForHost(ctx context.Context, host *models.Host) (models.Proxy Action: models.ProxyUpdate, } peerConfMap := make(map[string]models.PeerConf) - if host.IsRelayed { - relayHost, err := GetHost(host.RelayedBy) - if err == nil { - relayEndpoint, err := net.ResolveUDPAddr("udp", fmt.Sprintf("%s:%d", relayHost.EndpointIP, GetPeerListenPort(relayHost))) - if err != nil { - logger.Log(1, "failed to resolve relay node endpoint: ", err.Error()) - } - proxyPayload.IsRelayed = true - proxyPayload.RelayedTo = relayEndpoint - } else { - logger.Log(0, "couldn't find relay host for: ", host.ID.String()) - } - } - if host.IsRelay { - relayedHosts := GetRelayedHosts(host) - relayPeersMap := make(map[string]models.RelayedConf) - for _, relayedHost := range relayedHosts { - relayedHost := relayedHost - payload, err := GetPeerUpdateForHost(ctx, "", &relayedHost, nil, nil) - if err == nil { - relayedEndpoint, udpErr := net.ResolveUDPAddr("udp", fmt.Sprintf("%s:%d", relayedHost.EndpointIP, GetPeerListenPort(&relayedHost))) - if udpErr == nil { - relayPeersMap[relayedHost.PublicKey.String()] = models.RelayedConf{ - RelayedPeerEndpoint: relayedEndpoint, - RelayedPeerPubKey: relayedHost.PublicKey.String(), - Peers: payload.Peers, - } - } - - } - } - proxyPayload.IsRelay = true - proxyPayload.RelayedPeerConf = relayPeersMap - - } var ingressStatus bool for _, nodeID := range host.Nodes { @@ -101,18 +66,6 @@ func GetProxyUpdateForHost(ctx context.Context, host *models.Host) (models.Proxy } } - if peerHost.IsRelayed && peerHost.RelayedBy != host.ID.String() { - relayHost, err := GetHost(peerHost.RelayedBy) - if err == nil { - relayTo, err := net.ResolveUDPAddr("udp", fmt.Sprintf("%s:%d", relayHost.EndpointIP, GetPeerListenPort(relayHost))) - if err == nil { - currPeerConf.IsRelayed = true - currPeerConf.RelayedTo = relayTo - } - - } - } - peerConfMap[peerHost.PublicKey.String()] = currPeerConf } if node.IsIngressGateway { @@ -195,6 +148,10 @@ func GetPeerUpdateForHost(ctx context.Context, network string, host *models.Host //skip yourself continue } + if peer.IsRelayed { + // skip relayed peers; will be included in relay peer + continue + } var peerConfig wgtypes.PeerConfig peerHost, err := GetHost(peer.HostID.String()) if err != nil { @@ -677,6 +634,12 @@ func getNodeAllowedIPs(peer, node *models.Node) []net.IPNet { egressIPs := getEgressIPs(node, peer) allowedips = append(allowedips, egressIPs...) } + if peer.IsRelay { + for _, relayed := range peer.RelayedNodes { + allowed := getRelayedAddresses(relayed) + allowedips = append(allowedips, allowed...) + } + } return allowedips } diff --git a/logic/relay.go b/logic/relay.go index 89d0138b8..81d5b60d8 100644 --- a/logic/relay.go +++ b/logic/relay.go @@ -4,7 +4,7 @@ import ( "encoding/json" "errors" "fmt" - "time" + "net" "github.com/gravitl/netmaker/database" "github.com/gravitl/netmaker/logger" @@ -31,8 +31,6 @@ func CreateRelay(relay models.RelayRequest) ([]models.Node, models.Node, error) return returnnodes, models.Node{}, err } node.IsRelay = true - node.RelayAddrs = relay.RelayAddrs - node.SetLastModified() nodeData, err := json.Marshal(&node) if err != nil { @@ -41,144 +39,80 @@ func CreateRelay(relay models.RelayRequest) ([]models.Node, models.Node, error) if err = database.Insert(node.ID.String(), string(nodeData), database.NODES_TABLE_NAME); err != nil { return returnnodes, models.Node{}, err } - returnnodes, err = SetRelayedNodes(true, node.Network, node.RelayAddrs) - if err != nil { - return returnnodes, node, err - } - return returnnodes, node, nil -} - -// CreateHostRelay - creates a host relay -func CreateHostRelay(relay models.HostRelayRequest) (relayHost *models.Host, relayedHosts []models.Host, err error) { - - relayHost, err = GetHost(relay.HostID) - if err != nil { - return - } - err = validateHostRelay(relay) - if err != nil { - return - } - relayHost.IsRelay = true - relayHost.ProxyEnabled = true - relayHost.RelayedHosts = relay.RelayedHosts - err = UpsertHost(relayHost) - if err != nil { - return - } - relayedHosts = SetRelayedHosts(true, relay.HostID, relay.RelayedHosts) - return -} - -// SetRelayedHosts - updates the relayed hosts status -func SetRelayedHosts(setRelayed bool, relayHostID string, relayedHostIDs []string) []models.Host { - var relayedHosts []models.Host - for _, relayedHostID := range relayedHostIDs { - host, err := GetHost(relayedHostID) - if err == nil { - if setRelayed { - host.IsRelayed = true - host.RelayedBy = relayHostID - host.ProxyEnabled = true - } else { - host.IsRelayed = false - host.RelayedBy = "" - } - err = UpsertHost(host) - if err == nil { - relayedHosts = append(relayedHosts, *host) - } + returnnodes = SetRelayedNodes(true, relay.NodeID, relay.RelayedNodes) + for _, relayedNode := range returnnodes { + data, err := json.Marshal(&relayedNode) + if err != nil { + logger.Log(0, "marshalling relayed node", err.Error()) + continue + } + if err := database.Insert(relayedNode.ID.String(), string(data), database.NODES_TABLE_NAME); err != nil { + logger.Log(0, "inserting relayed node", err.Error()) + continue } } - return relayedHosts + return returnnodes, node, nil } -// SetRelayedNodes- set relayed nodes -func SetRelayedNodes(setRelayed bool, networkName string, addrs []string) ([]models.Node, error) { +// SetRelayedNodes- sets and saves node as relayed +func SetRelayedNodes(setRelayed bool, relay string, relayed []string) []models.Node { var returnnodes []models.Node - networkNodes, err := GetNetworkNodes(networkName) - if err != nil { - return returnnodes, err - } - for _, node := range networkNodes { - for _, addr := range addrs { - if addr == node.Address.IP.String() || addr == node.Address6.IP.String() { - if setRelayed { - node.IsRelayed = true - } else { - node.IsRelayed = false - } - data, err := json.Marshal(&node) - if err != nil { - return returnnodes, err - } - database.Insert(node.ID.String(), string(data), database.NODES_TABLE_NAME) - returnnodes = append(returnnodes, node) - } + for _, id := range relayed { + node, err := GetNodeByID(id) + if err != nil { + logger.Log(0, "setRelayedNodes.GetNodebyID", err.Error()) + continue } - } - return returnnodes, nil -} -func GetRelayedNodes(relayNode *models.Node) ([]models.Node, error) { - var returnnodes []models.Node - networkNodes, err := GetNetworkNodes(relayNode.Network) - if err != nil { - return returnnodes, err - } - for _, node := range networkNodes { - for _, addr := range relayNode.RelayAddrs { - if addr == node.Address.IP.String() || addr == node.Address6.IP.String() { - returnnodes = append(returnnodes, node) - } + node.IsRelayed = setRelayed + if node.IsRelayed { + node.RelayedBy = relay } - } - return returnnodes, nil -} - -// GetRelayedHosts - gets the relayed hosts of a relay host -func GetRelayedHosts(relayHost *models.Host) []models.Host { - relayedHosts := []models.Host{} - - for _, hostID := range relayHost.RelayedHosts { - relayedHost, err := GetHost(hostID) - if err == nil { - relayedHosts = append(relayedHosts, *relayedHost) + 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 + } + returnnodes = append(returnnodes, node) } - return relayedHosts + return returnnodes } +//func GetRelayedNodes(relayNode *models.Node) (models.Node, error) { +// var returnnodes []models.Node +// networkNodes, err := GetNetworkNodes(relayNode.Network) +// if err != nil { +// return returnnodes, err +// } +// for _, node := range networkNodes { +// for _, addr := range relayNode.RelayAddrs { +// if addr == node.Address.IP.String() || addr == node.Address6.IP.String() { +// returnnodes = append(returnnodes, node) +// } +// } +// } +// return returnnodes, nil +//} + // ValidateRelay - checks if relay is valid func ValidateRelay(relay models.RelayRequest) error { var err error //isIp := functions.IsIpCIDR(gateway.RangeString) - empty := len(relay.RelayAddrs) == 0 + empty := len(relay.RelayedNodes) == 0 if empty { err = errors.New("IP Ranges Cannot Be Empty") } return err } -func validateHostRelay(relay models.HostRelayRequest) error { - if len(relay.RelayedHosts) == 0 { - return errors.New("relayed hosts are empty") - } - return nil -} - -// UpdateRelay - updates a relay -func UpdateRelay(network string, oldAddrs []string, newAddrs []string) []models.Node { - var returnnodes []models.Node - time.Sleep(time.Second / 4) - _, err := SetRelayedNodes(false, network, oldAddrs) - if err != nil { - logger.Log(1, err.Error()) - } - returnnodes, err = SetRelayedNodes(true, network, newAddrs) - if err != nil { - logger.Log(1, err.Error()) - } - return returnnodes +// UpdateRelayed - updates relay nodes +func UpdateRelayed(relay string, oldNodes []string, newNodes []string) []models.Node { + _ = SetRelayedNodes(false, relay, oldNodes) + return SetRelayedNodes(true, relay, newNodes) } // DeleteRelay - deletes a relay @@ -188,15 +122,9 @@ func DeleteRelay(network, nodeid string) ([]models.Node, models.Node, error) { if err != nil { return returnnodes, models.Node{}, err } - returnnodes, err = SetRelayedNodes(false, node.Network, node.RelayAddrs) - if err != nil { - return returnnodes, node, err - } - + returnnodes = SetRelayedNodes(false, nodeid, node.RelayedNodes) node.IsRelay = false - node.RelayAddrs = []string{} node.SetLastModified() - data, err := json.Marshal(&node) if err != nil { return returnnodes, models.Node{}, err @@ -207,24 +135,18 @@ func DeleteRelay(network, nodeid string) ([]models.Node, models.Node, error) { return returnnodes, node, nil } -// DeleteHostRelay - removes host as relay -func DeleteHostRelay(relayHostID string) (relayHost *models.Host, relayedHosts []models.Host, err error) { - relayHost, err = GetHost(relayHostID) +func getRelayedAddresses(id string) []net.IPNet { + addrs := []net.IPNet{} + node, err := GetNodeByID(id) if err != nil { - return + logger.Log(0, "getRelayedAddresses: "+err.Error()) + return addrs } - relayedHosts = SetRelayedHosts(false, relayHostID, relayHost.RelayedHosts) - relayHost.IsRelay = false - relayHost.RelayedHosts = []string{} - err = UpsertHost(relayHost) - if err != nil { - return + if node.Address.IP != nil { + addrs = append(addrs, node.Address) } - return -} - -// UpdateHostRelay - updates the relay host with new relayed hosts -func UpdateHostRelay(relayHostID string, oldRelayedHosts, newRelayedHosts []string) { - _ = SetRelayedHosts(false, relayHostID, oldRelayedHosts) - _ = SetRelayedHosts(true, relayHostID, newRelayedHosts) + if node.Address6.IP != nil { + addrs = append(addrs, node.Address6) + } + return addrs } diff --git a/logic/wireguard.go b/logic/wireguard.go index c26c72174..7ef6cbabf 100644 --- a/logic/wireguard.go +++ b/logic/wireguard.go @@ -29,11 +29,11 @@ func IfaceDelta(currentNode *models.Node, newNode *models.Node) bool { } } if newNode.IsRelay { - if len(currentNode.RelayAddrs) != len(newNode.RelayAddrs) { + if len(currentNode.RelayedNodes) != len(newNode.RelayedNodes) { return true } - for _, address := range newNode.RelayAddrs { - if !StringSliceContains(currentNode.RelayAddrs, address) { + for _, node := range newNode.RelayedNodes { + if !StringSliceContains(currentNode.RelayedNodes, node) { return true } } diff --git a/models/api_host.go b/models/api_host.go index 608d424ca..b5f47776e 100644 --- a/models/api_host.go +++ b/models/api_host.go @@ -29,10 +29,6 @@ type ApiHost struct { Nodes []string `json:"nodes"` ProxyEnabled bool `json:"proxy_enabled" yaml:"proxy_enabled"` IsDefault bool `json:"isdefault" yaml:"isdefault"` - IsRelayed bool `json:"isrelayed" bson:"isrelayed" yaml:"isrelayed"` - RelayedBy string `json:"relayed_by" bson:"relayed_by" yaml:"relayed_by"` - IsRelay bool `json:"isrelay" bson:"isrelay" yaml:"isrelay"` - RelayedHosts []string `json:"relay_hosts" bson:"relay_hosts" yaml:"relay_hosts"` } // Host.ConvertNMHostToAPI - converts a Netmaker host to an API editable host @@ -65,10 +61,6 @@ func (h *Host) ConvertNMHostToAPI() *ApiHost { a.Verbosity = h.Verbosity a.Version = h.Version a.IsDefault = h.IsDefault - a.IsRelay = h.IsRelay - a.RelayedHosts = h.RelayedHosts - a.IsRelayed = h.IsRelayed - a.RelayedBy = h.RelayedBy return &a } @@ -106,10 +98,6 @@ func (a *ApiHost) ConvertAPIHostToNMHost(currentHost *Host) *Host { h.Nodes = currentHost.Nodes h.TrafficKeyPublic = currentHost.TrafficKeyPublic h.OS = currentHost.OS - h.RelayedBy = a.RelayedBy - h.RelayedHosts = a.RelayedHosts - h.IsRelay = a.IsRelay - h.IsRelayed = a.IsRelayed h.ProxyEnabled = a.ProxyEnabled h.IsDefault = a.IsDefault h.NatType = currentHost.NatType diff --git a/models/api_node.go b/models/api_node.go index 8ff6057eb..910c90228 100644 --- a/models/api_node.go +++ b/models/api_node.go @@ -25,11 +25,12 @@ type ApiNode struct { NetworkRange6 string `json:"networkrange6"` IsRelayed bool `json:"isrelayed"` IsRelay bool `json:"isrelay"` + RelayedBy string `json:"relayedby" bson:"relayedby" yaml:"relayedby"` + RelayedNodes []string `json:"relaynodes" yaml:"relayedNodes"` IsEgressGateway bool `json:"isegressgateway"` IsIngressGateway bool `json:"isingressgateway"` EgressGatewayRanges []string `json:"egressgatewayranges"` EgressGatewayNatEnabled bool `json:"egressgatewaynatenabled"` - RelayAddrs []string `json:"relayaddrs"` FailoverNode string `json:"failovernode"` DNSOn bool `json:"dnson"` Server string `json:"server"` @@ -52,6 +53,8 @@ func (a *ApiNode) ConvertToServerNode(currentNode *Node) *Node { convertedNode.HostID, _ = uuid.Parse(a.HostID) convertedNode.IsRelay = a.IsRelay convertedNode.IsRelayed = a.IsRelayed + convertedNode.RelayedBy = a.RelayedBy + convertedNode.RelayedNodes = a.RelayedNodes convertedNode.PendingDelete = a.PendingDelete convertedNode.Failover = a.Failover convertedNode.IsEgressGateway = a.IsEgressGateway @@ -64,7 +67,7 @@ func (a *ApiNode) ConvertToServerNode(currentNode *Node) *Node { convertedNode.EgressGatewayRequest = currentNode.EgressGatewayRequest convertedNode.EgressGatewayNatEnabled = currentNode.EgressGatewayNatEnabled convertedNode.PersistentKeepalive = time.Second * time.Duration(a.PersistentKeepalive) - convertedNode.RelayAddrs = a.RelayAddrs + convertedNode.RelayedNodes = a.RelayedNodes convertedNode.DefaultACL = a.DefaultACL convertedNode.OwnerID = currentNode.OwnerID _, networkRange, err := net.ParseCIDR(a.NetworkRange) @@ -138,11 +141,12 @@ func (nm *Node) ConvertToAPINode() *ApiNode { } apiNode.IsRelayed = nm.IsRelayed apiNode.IsRelay = nm.IsRelay + apiNode.RelayedBy = nm.RelayedBy + apiNode.RelayedNodes = nm.RelayedNodes apiNode.IsEgressGateway = nm.IsEgressGateway apiNode.IsIngressGateway = nm.IsIngressGateway apiNode.EgressGatewayRanges = nm.EgressGatewayRanges apiNode.EgressGatewayNatEnabled = nm.EgressGatewayNatEnabled - apiNode.RelayAddrs = nm.RelayAddrs apiNode.FailoverNode = nm.FailoverNode.String() if isUUIDSet(apiNode.FailoverNode) { apiNode.FailoverNode = "" diff --git a/models/host.go b/models/host.go index 51c6d43ee..2d0d737bd 100644 --- a/models/host.go +++ b/models/host.go @@ -62,10 +62,6 @@ type Host struct { TrafficKeyPublic []byte `json:"traffickeypublic" yaml:"traffickeypublic"` InternetGateway net.UDPAddr `json:"internetgateway" yaml:"internetgateway"` Nodes []string `json:"nodes" yaml:"nodes"` - IsRelayed bool `json:"isrelayed" yaml:"isrelayed"` - RelayedBy string `json:"relayed_by" yaml:"relayed_by"` - IsRelay bool `json:"isrelay" yaml:"isrelay"` - RelayedHosts []string `json:"relay_hosts" yaml:"relay_hosts"` Interfaces []Iface `json:"interfaces" yaml:"interfaces"` DefaultInterface string `json:"defaultinterface" yaml:"defaultinterface"` EndpointIP net.IP `json:"endpointip" yaml:"endpointip"` diff --git a/models/node.go b/models/node.go index 60677af07..21711559a 100644 --- a/models/node.go +++ b/models/node.go @@ -69,6 +69,10 @@ type CommonNode struct { IsEgressGateway bool `json:"isegressgateway" yaml:"isegressgateway"` EgressGatewayRanges []string `json:"egressgatewayranges" bson:"egressgatewayranges" yaml:"egressgatewayranges"` IsIngressGateway bool `json:"isingressgateway" yaml:"isingressgateway"` + IsRelayed bool `json:"isrelayed" bson:"isrelayed" yaml:"isrelayed"` + RelayedBy string `json:"relayedby" bson:"relayedby" yaml:"relayedby"` + IsRelay bool `json:"isrelay" bson:"isrelay" yaml:"isrelay"` + RelayedNodes []string `json:"relaynodes" yaml:"relayedNodes"` DNSOn bool `json:"dnson" yaml:"dnson"` PersistentKeepalive time.Duration `json:"persistentkeepalive" yaml:"persistentkeepalive"` } @@ -85,9 +89,6 @@ type Node struct { EgressGatewayRequest EgressGatewayRequest `json:"egressgatewayrequest" bson:"egressgatewayrequest" yaml:"egressgatewayrequest"` IngressGatewayRange string `json:"ingressgatewayrange" bson:"ingressgatewayrange" yaml:"ingressgatewayrange"` IngressGatewayRange6 string `json:"ingressgatewayrange6" bson:"ingressgatewayrange6" yaml:"ingressgatewayrange6"` - IsRelayed bool `json:"isrelayed" bson:"isrelayed" yaml:"isrelayed"` - IsRelay bool `json:"isrelay" bson:"isrelay" yaml:"isrelay"` - RelayAddrs []string `json:"relayaddrs" bson:"relayaddrs" yaml:"relayaddrs"` // == PRO == DefaultACL string `json:"defaultacl,omitempty" bson:"defaultacl,omitempty" yaml:"defaultacl,omitempty" validate:"checkyesornoorunset"` OwnerID string `json:"ownerid,omitempty" bson:"ownerid,omitempty" yaml:"ownerid,omitempty"` @@ -400,8 +401,8 @@ func (newNode *Node) Fill(currentNode *Node) { // TODO add new field for nftable if newNode.Action == "" { newNode.Action = currentNode.Action } - if newNode.RelayAddrs == nil { - newNode.RelayAddrs = currentNode.RelayAddrs + if newNode.RelayedNodes == nil { + newNode.RelayedNodes = currentNode.RelayedNodes } if newNode.IsRelay != currentNode.IsRelay { newNode.IsRelay = currentNode.IsRelay diff --git a/models/structs.go b/models/structs.go index 9b95b3407..2af2f124b 100644 --- a/models/structs.go +++ b/models/structs.go @@ -159,9 +159,9 @@ type EgressGatewayRequest struct { // RelayRequest - relay request struct type RelayRequest struct { - NodeID string `json:"nodeid" bson:"nodeid"` - NetID string `json:"netid" bson:"netid"` - RelayAddrs []string `json:"relayaddrs" bson:"relayaddrs"` + NodeID string `json:"nodeid" bson:"nodeid"` + NetID string `json:"netid" bson:"netid"` + RelayedNodes []string `json:"relayaddrs" bson:"relayaddrs"` } // HostRelayRequest - struct for host relay creation From 7722cff01eba51327c17c911e97a6c6da8e14c4c Mon Sep 17 00:00:00 2001 From: Abhishek Kondur Date: Thu, 15 Jun 2023 21:39:39 +0530 Subject: [PATCH 2/9] initial relay commit --- controllers/hosts.go | 4 +- controllers/node.go | 22 ++++----- controllers/server.go | 2 +- {controllers => ee/ee_controllers}/relay.go | 55 +++++++++++---------- ee/initialize.go | 1 + logic/gateway.go | 3 ++ logic/nodes.go | 2 +- logic/peers.go | 18 +++++-- logic/relay.go | 13 +++++ models/node.go | 6 +-- models/structs.go | 6 +-- 11 files changed, 79 insertions(+), 53 deletions(-) rename {controllers => ee/ee_controllers}/relay.go (58%) diff --git a/controllers/hosts.go b/controllers/hosts.go index 37e9fcd6d..da329c84b 100644 --- a/controllers/hosts.go +++ b/controllers/hosts.go @@ -26,8 +26,8 @@ func hostHandlers(r *mux.Router) { r.HandleFunc("/api/hosts/{hostid}/networks/{network}", logic.SecurityCheck(true, http.HandlerFunc(addHostToNetwork))).Methods(http.MethodPost) r.HandleFunc("/api/hosts/{hostid}/networks/{network}", logic.SecurityCheck(true, http.HandlerFunc(deleteHostFromNetwork))).Methods(http.MethodDelete) r.HandleFunc("/api/hosts/adm/authenticate", authenticateHost).Methods(http.MethodPost) - r.HandleFunc("/api/v1/host", authorize(true, false, "host", http.HandlerFunc(pull))).Methods(http.MethodGet) - r.HandleFunc("/api/v1/host/{hostid}/signalpeer", authorize(true, false, "host", http.HandlerFunc(signalPeer))).Methods(http.MethodPost) + r.HandleFunc("/api/v1/host", Authorize(true, false, "host", http.HandlerFunc(pull))).Methods(http.MethodGet) + r.HandleFunc("/api/v1/host/{hostid}/signalpeer", Authorize(true, false, "host", http.HandlerFunc(signalPeer))).Methods(http.MethodPost) r.HandleFunc("/api/v1/auth-register/host", socketHandler) } diff --git a/controllers/node.go b/controllers/node.go index a21dafba6..ccb7c5084 100644 --- a/controllers/node.go +++ b/controllers/node.go @@ -24,18 +24,16 @@ var hostIDHeader = "host-id" func nodeHandlers(r *mux.Router) { - r.HandleFunc("/api/nodes", authorize(false, false, "user", http.HandlerFunc(getAllNodes))).Methods(http.MethodGet) - r.HandleFunc("/api/nodes/{network}", authorize(false, true, "network", http.HandlerFunc(getNetworkNodes))).Methods(http.MethodGet) - r.HandleFunc("/api/nodes/{network}/{nodeid}", authorize(true, true, "node", http.HandlerFunc(getNode))).Methods(http.MethodGet) - r.HandleFunc("/api/nodes/{network}/{nodeid}", authorize(false, true, "node", http.HandlerFunc(updateNode))).Methods(http.MethodPut) - r.HandleFunc("/api/nodes/{network}/{nodeid}", authorize(true, true, "node", http.HandlerFunc(deleteNode))).Methods(http.MethodDelete) - r.HandleFunc("/api/nodes/{network}/{nodeid}/createrelay", authorize(false, true, "user", http.HandlerFunc(createRelay))).Methods(http.MethodPost) - r.HandleFunc("/api/nodes/{network}/{nodeid}/deleterelay", authorize(false, true, "user", http.HandlerFunc(deleteRelay))).Methods(http.MethodDelete) - r.HandleFunc("/api/nodes/{network}/{nodeid}/creategateway", authorize(false, true, "user", http.HandlerFunc(createEgressGateway))).Methods(http.MethodPost) - r.HandleFunc("/api/nodes/{network}/{nodeid}/deletegateway", authorize(false, true, "user", http.HandlerFunc(deleteEgressGateway))).Methods(http.MethodDelete) + r.HandleFunc("/api/nodes", Authorize(false, false, "user", http.HandlerFunc(getAllNodes))).Methods(http.MethodGet) + r.HandleFunc("/api/nodes/{network}", Authorize(false, true, "network", http.HandlerFunc(getNetworkNodes))).Methods(http.MethodGet) + r.HandleFunc("/api/nodes/{network}/{nodeid}", Authorize(true, true, "node", http.HandlerFunc(getNode))).Methods(http.MethodGet) + r.HandleFunc("/api/nodes/{network}/{nodeid}", Authorize(false, true, "node", http.HandlerFunc(updateNode))).Methods(http.MethodPut) + r.HandleFunc("/api/nodes/{network}/{nodeid}", Authorize(true, true, "node", http.HandlerFunc(deleteNode))).Methods(http.MethodDelete) + r.HandleFunc("/api/nodes/{network}/{nodeid}/creategateway", Authorize(false, true, "user", http.HandlerFunc(createEgressGateway))).Methods(http.MethodPost) + r.HandleFunc("/api/nodes/{network}/{nodeid}/deletegateway", Authorize(false, true, "user", http.HandlerFunc(deleteEgressGateway))).Methods(http.MethodDelete) r.HandleFunc("/api/nodes/{network}/{nodeid}/createingress", logic.SecurityCheck(false, http.HandlerFunc(createIngressGateway))).Methods(http.MethodPost) r.HandleFunc("/api/nodes/{network}/{nodeid}/deleteingress", logic.SecurityCheck(false, http.HandlerFunc(deleteIngressGateway))).Methods(http.MethodDelete) - r.HandleFunc("/api/nodes/{network}/{nodeid}", authorize(true, true, "node", http.HandlerFunc(updateNode))).Methods(http.MethodPost) + r.HandleFunc("/api/nodes/{network}/{nodeid}", Authorize(true, true, "node", http.HandlerFunc(updateNode))).Methods(http.MethodPost) r.HandleFunc("/api/nodes/adm/{network}/authenticate", authenticate).Methods(http.MethodPost) r.HandleFunc("/api/v1/nodes/migrate", migrate).Methods(http.MethodPost) } @@ -155,7 +153,7 @@ func authenticate(response http.ResponseWriter, request *http.Request) { // even if it's technically ok // This is kind of a poor man's RBAC. There's probably a better/smarter way. // TODO: Consider better RBAC implementations -func authorize(hostAllowed, networkCheck bool, authNetwork string, next http.Handler) http.HandlerFunc { +func Authorize(hostAllowed, networkCheck bool, authNetwork string, next http.Handler) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { var errorResponse = models.ErrorResponse{ Code: http.StatusForbidden, Message: logic.Forbidden_Msg, @@ -634,7 +632,7 @@ func updateNode(w http.ResponseWriter, r *http.Request) { } newNode := newData.ConvertToServerNode(¤tNode) relayupdate := false - if currentNode.IsRelay && len(newNode.RelayedNodes) > 0 { + if servercfg.Is_EE && newNode.IsRelay && len(newNode.RelayedNodes) > 0 { if len(newNode.RelayedNodes) != len(currentNode.RelayedNodes) { relayupdate = true } else { diff --git a/controllers/server.go b/controllers/server.go index a5d6ef662..bcbf7c9a2 100644 --- a/controllers/server.go +++ b/controllers/server.go @@ -20,7 +20,7 @@ func serverHandlers(r *mux.Router) { resp.Write([]byte("Server is up and running!!")) })) r.HandleFunc("/api/server/getconfig", allowUsers(http.HandlerFunc(getConfig))).Methods(http.MethodGet) - r.HandleFunc("/api/server/getserverinfo", authorize(true, false, "node", http.HandlerFunc(getServerInfo))).Methods(http.MethodGet) + r.HandleFunc("/api/server/getserverinfo", Authorize(true, false, "node", http.HandlerFunc(getServerInfo))).Methods(http.MethodGet) r.HandleFunc("/api/server/status", http.HandlerFunc(getStatus)).Methods(http.MethodGet) } diff --git a/controllers/relay.go b/ee/ee_controllers/relay.go similarity index 58% rename from controllers/relay.go rename to ee/ee_controllers/relay.go index c7c487ffe..0818db7fa 100644 --- a/controllers/relay.go +++ b/ee/ee_controllers/relay.go @@ -1,4 +1,4 @@ -package controller +package ee_controllers import ( "encoding/json" @@ -6,12 +6,20 @@ import ( "net/http" "github.com/gorilla/mux" + controller "github.com/gravitl/netmaker/controllers" "github.com/gravitl/netmaker/logger" "github.com/gravitl/netmaker/logic" "github.com/gravitl/netmaker/models" "github.com/gravitl/netmaker/mq" ) +// RelayHandlers - handle EE Relays +func RelayHandlers(r *mux.Router) { + + r.HandleFunc("/api/nodes/{network}/{nodeid}/createrelay", controller.Authorize(false, true, "user", http.HandlerFunc(createRelay))).Methods(http.MethodPost) + r.HandleFunc("/api/nodes/{network}/{nodeid}/deleterelay", controller.Authorize(false, true, "user", http.HandlerFunc(deleteRelay))).Methods(http.MethodDelete) +} + // swagger:route POST /api/nodes/{network}/{nodeid}/createrelay nodes createRelay // // Create a relay. @@ -24,38 +32,29 @@ import ( // Responses: // 200: nodeResponse func createRelay(w http.ResponseWriter, r *http.Request) { - var relay models.RelayRequest + var relayRequest models.RelayRequest var params = mux.Vars(r) w.Header().Set("Content-Type", "application/json") - err := json.NewDecoder(r.Body).Decode(&relay) + err := json.NewDecoder(r.Body).Decode(&relayRequest) if err != nil { logger.Log(0, r.Header.Get("user"), "error decoding request body: ", err.Error()) logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest")) return } - relay.NetID = params["network"] - relay.NodeID = params["nodeid"] - updatenodes, node, err := logic.CreateRelay(relay) + relayRequest.NetID = params["network"] + relayRequest.NodeID = params["nodeid"] + _, relayNode, err := logic.CreateRelay(relayRequest) if err != nil { logger.Log(0, r.Header.Get("user"), - fmt.Sprintf("failed to create relay on node [%s] on network [%s]: %v", relay.NodeID, relay.NetID, err)) + fmt.Sprintf("failed to create relay on node [%s] on network [%s]: %v", relayRequest.NodeID, relayRequest.NetID, err)) logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal")) return } - - logger.Log(1, r.Header.Get("user"), "created relay on node", relay.NodeID, "on network", relay.NetID) - for _, relayedNode := range updatenodes { - - err = mq.NodeUpdate(&relayedNode) - if err != nil { - logger.Log(1, "error sending update to relayed node ", relayedNode.ID.String(), "on network", relay.NetID, ": ", err.Error()) - } - } - - apiNode := node.ConvertToAPINode() + go mq.PublishPeerUpdate() + logger.Log(1, r.Header.Get("user"), "created relay on node", relayRequest.NodeID, "on network", relayRequest.NetID) + apiNode := relayNode.ConvertToAPINode() w.WriteHeader(http.StatusOK) json.NewEncoder(w).Encode(apiNode) - runUpdates(&node, true) } // swagger:route DELETE /api/nodes/{network}/{nodeid}/deleterelay nodes deleteRelay @@ -74,21 +73,25 @@ func deleteRelay(w http.ResponseWriter, r *http.Request) { var params = mux.Vars(r) nodeid := params["nodeid"] netid := params["network"] - updatenodes, node, err := logic.DeleteRelay(netid, nodeid) + updateNodes, node, err := logic.DeleteRelay(netid, nodeid) if err != nil { logger.Log(0, r.Header.Get("user"), "error decoding request body: ", err.Error()) logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest")) return } logger.Log(1, r.Header.Get("user"), "deleted relay server", nodeid, "on network", netid) - for _, relayedNode := range updatenodes { - err = mq.NodeUpdate(&relayedNode) - if err != nil { - logger.Log(1, "error sending update to relayed node ", relayedNode.ID.String(), "on network", netid, ": ", err.Error()) + go func() { + for _, relayedNode := range updateNodes { + err = mq.NodeUpdate(&relayedNode) + if err != nil { + logger.Log(1, "relayed node update ", relayedNode.ID.String(), "on network", relayedNode.Network, ": ", err.Error()) + + } } - } + mq.PublishPeerUpdate() + }() + logger.Log(1, r.Header.Get("user"), "deleted relay on node", node.ID.String(), "on network", node.Network) apiNode := node.ConvertToAPINode() w.WriteHeader(http.StatusOK) json.NewEncoder(w).Encode(apiNode) - runUpdates(&node, true) } diff --git a/ee/initialize.go b/ee/initialize.go index c05082463..ab5e3ba0f 100644 --- a/ee/initialize.go +++ b/ee/initialize.go @@ -22,6 +22,7 @@ func InitEE() { ee_controllers.MetricHandlers, ee_controllers.NetworkUsersHandlers, ee_controllers.UserGroupsHandlers, + ee_controllers.RelayHandlers, ) logic.EnterpriseCheckFuncs = append(logic.EnterpriseCheckFuncs, func() { // == License Handling == diff --git a/logic/gateway.go b/logic/gateway.go index 60b4b7d3a..2677048cc 100644 --- a/logic/gateway.go +++ b/logic/gateway.go @@ -102,6 +102,9 @@ func CreateIngressGateway(netid string, nodeid string, ingress models.IngressReq if err != nil { return models.Node{}, err } + if node.IsRelayed { + return models.Node{}, errors.New("ingress cannot be created on a relayed node") + } host, err := GetHost(node.HostID.String()) if err != nil { return models.Node{}, err diff --git a/logic/nodes.go b/logic/nodes.go index 291a8755e..106bb3524 100644 --- a/logic/nodes.go +++ b/logic/nodes.go @@ -85,7 +85,7 @@ func UpdateNode(currentNode *models.Node, newNode *models.Node) error { } } nodeACLDelta := currentNode.DefaultACL != newNode.DefaultACL - newNode.Fill(currentNode) + newNode.Fill(currentNode, servercfg.Is_EE) // check for un-settable server values if err := ValidateNode(newNode, true); err != nil { diff --git a/logic/peers.go b/logic/peers.go index d2b26bb3a..8c86cda40 100644 --- a/logic/peers.go +++ b/logic/peers.go @@ -155,16 +155,23 @@ func GetPeerUpdateForHost(ctx context.Context, network string, host *models.Host // skip relayed peers; will be included in relay peer continue } - var peerConfig wgtypes.PeerConfig peerHost, err := GetHost(peer.HostID.String()) if err != nil { logger.Log(1, "no peer host", peer.HostID.String(), err.Error()) return models.HostPeerUpdate{}, err } - - peerConfig.PublicKey = peerHost.PublicKey - peerConfig.PersistentKeepaliveInterval = &peer.PersistentKeepalive - peerConfig.ReplaceAllowedIPs = true + peerConfig := wgtypes.PeerConfig{ + PublicKey: peerHost.PublicKey, + PersistentKeepaliveInterval: &peer.PersistentKeepalive, + ReplaceAllowedIPs: true, + } + if node.IsRelayed && node.RelayedBy != peer.ID.String() { + // if node is relayed and peer is not the relay, set remove to true + peerConfig.Remove = true + hostPeerUpdate.Peers = append(hostPeerUpdate.Peers, peerConfig) + peerIndexMap[peerHost.PublicKey.String()] = len(hostPeerUpdate.Peers) - 1 + continue + } uselocal := false if host.EndpointIP.String() == peerHost.EndpointIP.String() { // peer is on same network @@ -262,6 +269,7 @@ func GetPeerUpdateForHost(ctx context.Context, network string, host *models.Host peerAllowedIPs := hostPeerUpdate.Peers[peerIndexMap[peerHost.PublicKey.String()]].AllowedIPs peerAllowedIPs = append(peerAllowedIPs, allowedips...) hostPeerUpdate.Peers[peerIndexMap[peerHost.PublicKey.String()]].AllowedIPs = peerAllowedIPs + hostPeerUpdate.Peers[peerIndexMap[peerHost.PublicKey.String()]].Remove = false hostPeerUpdate.HostPeerIDs[peerHost.PublicKey.String()][peer.ID.String()] = models.IDandAddr{ ID: peer.ID.String(), Address: peer.PrimaryAddress(), diff --git a/logic/relay.go b/logic/relay.go index 81d5b60d8..982fa90ce 100644 --- a/logic/relay.go +++ b/logic/relay.go @@ -31,6 +31,7 @@ func CreateRelay(relay models.RelayRequest) ([]models.Node, models.Node, error) return returnnodes, models.Node{}, err } node.IsRelay = true + node.RelayedNodes = relay.RelayedNodes node.SetLastModified() nodeData, err := json.Marshal(&node) if err != nil { @@ -106,6 +107,15 @@ func ValidateRelay(relay models.RelayRequest) error { if empty { err = errors.New("IP Ranges Cannot Be Empty") } + for _, relayedNodeID := range relay.RelayedNodes { + relayedNode, err := GetNodeByID(relayedNodeID) + if err != nil { + return err + } + if relayedNode.IsIngressGateway { + return errors.New("cannot relay an ingress gateway (" + relayedNodeID + ")") + } + } return err } @@ -124,6 +134,7 @@ func DeleteRelay(network, nodeid string) ([]models.Node, models.Node, error) { } returnnodes = SetRelayedNodes(false, nodeid, node.RelayedNodes) node.IsRelay = false + node.RelayedBy = "" node.SetLastModified() data, err := json.Marshal(&node) if err != nil { @@ -143,9 +154,11 @@ func getRelayedAddresses(id string) []net.IPNet { 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.Address.Mask = net.CIDRMask(128, 128) addrs = append(addrs, node.Address6) } return addrs diff --git a/models/node.go b/models/node.go index 9e7baf300..7b9c32eda 100644 --- a/models/node.go +++ b/models/node.go @@ -351,7 +351,7 @@ func (node *LegacyNode) SetDefaultFailover() { } // Node.Fill - fills other node data into calling node data if not set on calling node -func (newNode *Node) Fill(currentNode *Node) { // TODO add new field for nftables present +func (newNode *Node) Fill(currentNode *Node, isEE bool) { // TODO add new field for nftables present newNode.ID = currentNode.ID newNode.HostID = currentNode.HostID // Revisit the logic for boolean values @@ -405,10 +405,10 @@ func (newNode *Node) Fill(currentNode *Node) { // TODO add new field for nftable if newNode.RelayedNodes == nil { newNode.RelayedNodes = currentNode.RelayedNodes } - if newNode.IsRelay != currentNode.IsRelay { + if newNode.IsRelay != currentNode.IsRelay && isEE { newNode.IsRelay = currentNode.IsRelay } - if newNode.IsRelayed == currentNode.IsRelayed { + if newNode.IsRelayed == currentNode.IsRelayed && isEE { newNode.IsRelayed = currentNode.IsRelayed } if newNode.Server == "" { diff --git a/models/structs.go b/models/structs.go index 310f7ebaa..93ef82955 100644 --- a/models/structs.go +++ b/models/structs.go @@ -153,9 +153,9 @@ type EgressGatewayRequest struct { // RelayRequest - relay request struct type RelayRequest struct { - NodeID string `json:"nodeid" bson:"nodeid"` - NetID string `json:"netid" bson:"netid"` - RelayedNodes []string `json:"relayaddrs" bson:"relayaddrs"` + NodeID string `json:"nodeid"` + NetID string `json:"netid"` + RelayedNodes []string `json:"relayednodes"` } // HostRelayRequest - struct for host relay creation From 5be2d420fc5448bdecc6a22ccd251afcf22d7ca4 Mon Sep 17 00:00:00 2001 From: Abhishek Kondur Date: Thu, 15 Jun 2023 22:55:48 +0530 Subject: [PATCH 3/9] get relayed allowed ips --- logic/peers.go | 112 ++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 87 insertions(+), 25 deletions(-) diff --git a/logic/peers.go b/logic/peers.go index 8c86cda40..38178a893 100644 --- a/logic/peers.go +++ b/logic/peers.go @@ -151,10 +151,7 @@ func GetPeerUpdateForHost(ctx context.Context, network string, host *models.Host //skip yourself continue } - if peer.IsRelayed { - // skip relayed peers; will be included in relay peer - continue - } + peerHost, err := GetHost(peer.HostID.String()) if err != nil { logger.Log(1, "no peer host", peer.HostID.String(), err.Error()) @@ -165,6 +162,13 @@ func GetPeerUpdateForHost(ctx context.Context, network string, host *models.Host PersistentKeepaliveInterval: &peer.PersistentKeepalive, ReplaceAllowedIPs: true, } + if peer.IsRelayed && peer.RelayedBy != node.ID.String() { + // skip relayed peers; will be included in relay peer + peerConfig.Remove = true + hostPeerUpdate.Peers = append(hostPeerUpdate.Peers, peerConfig) + peerIndexMap[peerHost.PublicKey.String()] = len(hostPeerUpdate.Peers) - 1 + continue + } if node.IsRelayed && node.RelayedBy != peer.ID.String() { // if node is relayed and peer is not the relay, set remove to true peerConfig.Remove = true @@ -172,6 +176,7 @@ func GetPeerUpdateForHost(ctx context.Context, network string, host *models.Host peerIndexMap[peerHost.PublicKey.String()] = len(hostPeerUpdate.Peers) - 1 continue } + uselocal := false if host.EndpointIP.String() == peerHost.EndpointIP.String() { // peer is on same network @@ -195,17 +200,6 @@ func GetPeerUpdateForHost(ctx context.Context, network string, host *models.Host peerConfig.Endpoint.Port = peerHost.ListenPort } allowedips := GetAllowedIPs(&node, &peer, nil) - if peer.IsIngressGateway { - for _, entry := range peer.IngressGatewayRange { - _, cidr, err := net.ParseCIDR(string(entry)) - if err == nil { - allowedips = append(allowedips, *cidr) - } - } - } - if peer.IsEgressGateway { - allowedips = append(allowedips, getEgressIPs(&node, &peer)...) - } if peer.Action != models.NODE_DELETE && !peer.PendingDelete && peer.Connected && @@ -267,7 +261,7 @@ func GetPeerUpdateForHost(ctx context.Context, network string, host *models.Host nodePeer = peerConfig } else { peerAllowedIPs := hostPeerUpdate.Peers[peerIndexMap[peerHost.PublicKey.String()]].AllowedIPs - peerAllowedIPs = append(peerAllowedIPs, allowedips...) + peerAllowedIPs = append(peerAllowedIPs, peerConfig.AllowedIPs...) hostPeerUpdate.Peers[peerIndexMap[peerHost.PublicKey.String()]].AllowedIPs = peerAllowedIPs hostPeerUpdate.Peers[peerIndexMap[peerHost.PublicKey.String()]].Remove = false hostPeerUpdate.HostPeerIDs[peerHost.PublicKey.String()][peer.ID.String()] = models.IDandAddr{ @@ -592,14 +586,14 @@ func GetAllowedIPs(node, peer *models.Node, metrics *models.Metrics) []net.IPNet } } } + if node.IsRelayed && node.RelayedBy == peer.ID.String() { + allowedips = append(allowedips, getAllowedIpsForRelayed(node, peer)...) + } return allowedips } -func getEgressIPs(node, peer *models.Node) []net.IPNet { - host, err := GetHost(node.HostID.String()) - if err != nil { - logger.Log(0, "error retrieving host for node", node.ID.String(), err.Error()) - } +func getEgressIPs(peer *models.Node) []net.IPNet { + peerHost, err := GetHost(peer.HostID.String()) if err != nil { logger.Log(0, "error retrieving host for peer", peer.ID.String(), err.Error()) @@ -619,12 +613,12 @@ func getEgressIPs(node, peer *models.Node) []net.IPNet { } // getting the public ip of node if ipnet.Contains(peerHost.EndpointIP) && !internetGateway { // ensuring egress gateway range does not contain endpoint of node - logger.Log(2, "egress IP range of ", iprange, " overlaps with ", host.EndpointIP.String(), ", omitting") + logger.Log(2, "egress IP range of ", iprange, " overlaps with ", peerHost.EndpointIP.String(), ", omitting") continue // skip adding egress range if overlaps with node's ip } // TODO: Could put in a lot of great logic to avoid conflicts / bad routes - if ipnet.Contains(node.LocalAddress.IP) && !internetGateway { // ensuring egress gateway range does not contain public ip of node - logger.Log(2, "egress IP range of ", iprange, " overlaps with ", node.LocalAddress.String(), ", omitting") + if ipnet.Contains(peer.LocalAddress.IP) && !internetGateway { // ensuring egress gateway range does not contain public ip of node + logger.Log(2, "egress IP range of ", iprange, " overlaps with ", peer.LocalAddress.String(), ", omitting") continue // skip adding egress range if overlaps with node's local ip } if err != nil { @@ -655,11 +649,14 @@ func getNodeAllowedIPs(peer, node *models.Node) []net.IPNet { // handle egress gateway peers if peer.IsEgressGateway { //hasGateway = true - egressIPs := getEgressIPs(node, peer) + egressIPs := getEgressIPs(peer) allowedips = append(allowedips, egressIPs...) } if peer.IsRelay { for _, relayed := range peer.RelayedNodes { + if node.ID.String() == relayed { + continue + } allowed := getRelayedAddresses(relayed) allowedips = append(allowedips, allowed...) } @@ -667,6 +664,71 @@ func getNodeAllowedIPs(peer, node *models.Node) []net.IPNet { return allowedips } +// getAllowedIpsForRelayed - returns the peerConfig for a node relayed by relay +func getAllowedIpsForRelayed(relayed, relay *models.Node) (allowedIPs []net.IPNet) { + if relayed.RelayedBy != relay.ID.String() { + logger.Log(0, "peerUpdateForRelayedByRelay called with invalid parameters") + return + } + if relay.Address.IP != nil { + relay.Address.Mask = net.CIDRMask(32, 32) + allowedIPs = append(allowedIPs, relay.Address) + } + if relay.Address6.IP != nil { + relay.Address6.Mask = net.CIDRMask(128, 128) + allowedIPs = append(allowedIPs, relay.Address6) + } + if relay.IsEgressGateway { + allowedIPs = append(allowedIPs, getEgressIPs(relay)...) + } + if relay.IsIngressGateway { + allowedIPs = append(allowedIPs, getIngressIPs(relay)...) + } + peers, err := GetNetworkNodes(relay.Network) + if err != nil { + logger.Log(0, "error getting network clients", err.Error()) + return + } + for _, peer := range peers { + if peer.ID == relayed.ID || peer.ID == relay.ID { + continue + } + if nodeacls.AreNodesAllowed(nodeacls.NetworkID(relayed.Network), nodeacls.NodeID(relayed.ID.String()), nodeacls.NodeID(peer.ID.String())) { + allowedIPs = append(allowedIPs, GetAllowedIPs(relayed, &peer, nil)...) + } + } + return +} + +func getIngressIPs(peer *models.Node) []net.IPNet { + var ingressIPs []net.IPNet + extclients, err := GetNetworkExtClients(peer.Network) + if err != nil { + return ingressIPs + } + for _, ec := range extclients { + if ec.IngressGatewayID == peer.ID.String() { + if ec.Address != "" { + ip, cidr, err := net.ParseCIDR(ec.Address) + if err != nil { + continue + } + cidr.IP = ip + ingressIPs = append(ingressIPs, *cidr) + } + if ec.Address6 != "" { + ip, cidr, err := net.ParseCIDR(ec.Address6) + if err != nil { + continue + } + cidr.IP = ip + ingressIPs = append(ingressIPs, *cidr) + } + } + } + return ingressIPs +} + func getCIDRMaskFromAddr(addr string) net.IPMask { cidr := net.CIDRMask(32, 32) ipAddr, err := netip.ParseAddr(addr) From 561e0460902ecfa4b8faeb4a5610866a24241c81 Mon Sep 17 00:00:00 2001 From: Abhishek Kondur Date: Fri, 16 Jun 2023 13:17:33 +0530 Subject: [PATCH 4/9] add more relay validation checks, peer logic cleanup --- logic/peers.go | 12 ++++-------- logic/relay.go | 9 ++++++++- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/logic/peers.go b/logic/peers.go index 38178a893..024a7d72b 100644 --- a/logic/peers.go +++ b/logic/peers.go @@ -162,15 +162,11 @@ func GetPeerUpdateForHost(ctx context.Context, network string, host *models.Host PersistentKeepaliveInterval: &peer.PersistentKeepalive, ReplaceAllowedIPs: true, } - if peer.IsRelayed && peer.RelayedBy != node.ID.String() { - // skip relayed peers; will be included in relay peer - peerConfig.Remove = true - hostPeerUpdate.Peers = append(hostPeerUpdate.Peers, peerConfig) - peerIndexMap[peerHost.PublicKey.String()] = len(hostPeerUpdate.Peers) - 1 - continue - } - if node.IsRelayed && node.RelayedBy != peer.ID.String() { + if (node.IsRelayed && node.RelayedBy != peer.ID.String()) || (peer.IsRelayed && peer.RelayedBy != node.ID.String()) { // if node is relayed and peer is not the relay, set remove to true + if _, ok := hostPeerUpdate.HostPeerIDs[peerHost.PublicKey.String()]; ok { + continue + } peerConfig.Remove = true hostPeerUpdate.Peers = append(hostPeerUpdate.Peers, peerConfig) peerIndexMap[peerHost.PublicKey.String()] = len(hostPeerUpdate.Peers) - 1 diff --git a/logic/relay.go b/logic/relay.go index 982fa90ce..b644ab191 100644 --- a/logic/relay.go +++ b/logic/relay.go @@ -105,7 +105,14 @@ func ValidateRelay(relay models.RelayRequest) error { //isIp := functions.IsIpCIDR(gateway.RangeString) empty := len(relay.RelayedNodes) == 0 if empty { - err = errors.New("IP Ranges Cannot Be Empty") + return errors.New("IP Ranges Cannot Be Empty") + } + node, err := GetNodeByID(relay.NodeID) + if err != nil { + return err + } + if node.IsRelay { + return errors.New("node is already acting as a relay") } for _, relayedNodeID := range relay.RelayedNodes { relayedNode, err := GetNodeByID(relayedNodeID) From 3817c305176372b9ecc8549f558d5986b2c3015b Mon Sep 17 00:00:00 2001 From: Abhishek Kondur Date: Fri, 16 Jun 2023 19:08:27 +0530 Subject: [PATCH 5/9] rm relayed nodes from relay node when relayed node is deleted --- controllers/node.go | 22 +++++++++++++++++++--- logic/nodes.go | 10 ++++++++++ logic/relay.go | 4 +++- models/structs.go | 2 +- 4 files changed, 33 insertions(+), 5 deletions(-) diff --git a/controllers/node.go b/controllers/node.go index ccb7c5084..d3ab56416 100644 --- a/controllers/node.go +++ b/controllers/node.go @@ -684,8 +684,8 @@ func updateNode(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) json.NewEncoder(w).Encode(apiNode) runUpdates(newNode, ifaceDelta) - go func(aclUpdate bool, newNode *models.Node) { - if aclUpdate { + go func(aclUpdate, relayupdate bool, newNode *models.Node) { + if aclUpdate || relayupdate { if err := mq.PublishPeerUpdate(); err != nil { logger.Log(0, "error during node ACL update for node", newNode.ID.String()) } @@ -693,7 +693,7 @@ func updateNode(w http.ResponseWriter, r *http.Request) { if err := mq.PublishReplaceDNS(¤tNode, newNode, host); err != nil { logger.Log(1, "failed to publish dns update", err.Error()) } - }(aclUpdate, newNode) + }(aclUpdate, relayupdate, newNode) } // swagger:route DELETE /api/nodes/{network}/{nodeid} nodes deleteNode @@ -737,6 +737,22 @@ func deleteNode(w http.ResponseWriter, r *http.Request) { logic.ReturnErrorResponse(w, r, logic.FormatError(fmt.Errorf("failed to delete node"), "internal")) return } + if node.IsRelayed { + // cleanup node from relayednodes on relay node + relayNode, err := logic.GetNodeByID(node.RelayedBy) + if err == nil { + relayedNodes := []string{} + for _, relayedNodeID := range relayNode.RelayedNodes { + if relayedNodeID == node.ID.String() { + continue + } + relayedNodes = append(relayedNodes, relayedNodeID) + } + relayNode.RelayedNodes = relayedNodes + logic.UpsertNode(&relayNode) + } + + } logic.ReturnSuccessResponse(w, r, nodeid+" deleted.") logger.Log(1, r.Header.Get("user"), "Deleted node", nodeid, "from network", params["network"]) if !fromNode { // notify node change diff --git a/logic/nodes.go b/logic/nodes.go index 106bb3524..1becdb64d 100644 --- a/logic/nodes.go +++ b/logic/nodes.go @@ -75,6 +75,16 @@ func UpdateNodeCheckin(node *models.Node) error { return database.Insert(node.ID.String(), string(data), database.NODES_TABLE_NAME) } +// UpsertNode - updates node in the DB +func UpsertNode(newNode *models.Node) error { + newNode.SetLastModified() + data, err := json.Marshal(newNode) + if err != nil { + return err + } + return database.Insert(newNode.ID.String(), string(data), database.NODES_TABLE_NAME) +} + // UpdateNode - takes a node and updates another node with it's values func UpdateNode(currentNode *models.Node, newNode *models.Node) error { if newNode.Address.IP.String() != currentNode.Address.IP.String() { diff --git a/logic/relay.go b/logic/relay.go index b644ab191..03b7eb339 100644 --- a/logic/relay.go +++ b/logic/relay.go @@ -67,6 +67,8 @@ func SetRelayedNodes(setRelayed bool, relay string, relayed []string) []models.N node.IsRelayed = setRelayed if node.IsRelayed { node.RelayedBy = relay + } else { + node.RelayedBy = "" } node.SetLastModified() data, err := json.Marshal(&node) @@ -141,7 +143,7 @@ func DeleteRelay(network, nodeid string) ([]models.Node, models.Node, error) { } returnnodes = SetRelayedNodes(false, nodeid, node.RelayedNodes) node.IsRelay = false - node.RelayedBy = "" + node.RelayedNodes = []string{} node.SetLastModified() data, err := json.Marshal(&node) if err != nil { diff --git a/models/structs.go b/models/structs.go index 93ef82955..2343cf6c0 100644 --- a/models/structs.go +++ b/models/structs.go @@ -155,7 +155,7 @@ type EgressGatewayRequest struct { type RelayRequest struct { NodeID string `json:"nodeid"` NetID string `json:"netid"` - RelayedNodes []string `json:"relayednodes"` + RelayedNodes []string `json:"relayaddrs"` } // HostRelayRequest - struct for host relay creation From e152905cb0b6a278e8c9516fb985e4cd4da9c149 Mon Sep 17 00:00:00 2001 From: Abhishek Kondur Date: Sat, 17 Jun 2023 12:32:28 +0530 Subject: [PATCH 6/9] fix egress updates for relayed nodes --- logic/peers.go | 97 ++++++++++++++++++++++++-------------------------- 1 file changed, 46 insertions(+), 51 deletions(-) diff --git a/logic/peers.go b/logic/peers.go index 024a7d72b..36e485076 100644 --- a/logic/peers.go +++ b/logic/peers.go @@ -162,6 +162,38 @@ func GetPeerUpdateForHost(ctx context.Context, network string, host *models.Host PersistentKeepaliveInterval: &peer.PersistentKeepalive, ReplaceAllowedIPs: true, } + if node.IsIngressGateway || node.IsEgressGateway { + if peer.IsIngressGateway { + _, extPeerIDAndAddrs, err := getExtPeers(&peer) + if err == nil { + for _, extPeerIdAndAddr := range extPeerIDAndAddrs { + extPeerIdAndAddr := extPeerIdAndAddr + nodePeerMap[extPeerIdAndAddr.ID] = models.PeerRouteInfo{ + PeerAddr: net.IPNet{ + IP: net.ParseIP(extPeerIdAndAddr.Address), + Mask: getCIDRMaskFromAddr(extPeerIdAndAddr.Address), + }, + PeerKey: extPeerIdAndAddr.ID, + Allow: true, + ID: extPeerIdAndAddr.ID, + } + } + } + } + if node.IsIngressGateway && peer.IsEgressGateway { + hostPeerUpdate.IngressInfo.EgressRanges = append(hostPeerUpdate.IngressInfo.EgressRanges, + peer.EgressGatewayRanges...) + } + nodePeerMap[peerHost.PublicKey.String()] = models.PeerRouteInfo{ + PeerAddr: net.IPNet{ + IP: net.ParseIP(peer.PrimaryAddress()), + Mask: getCIDRMaskFromAddr(peer.PrimaryAddress()), + }, + PeerKey: peerHost.PublicKey.String(), + Allow: true, + ID: peer.ID.String(), + } + } if (node.IsRelayed && node.RelayedBy != peer.ID.String()) || (peer.IsRelayed && peer.RelayedBy != node.ID.String()) { // if node is relayed and peer is not the relay, set remove to true if _, ok := hostPeerUpdate.HostPeerIDs[peerHost.PublicKey.String()]; ok { @@ -204,39 +236,6 @@ func GetPeerUpdateForHost(ctx context.Context, network string, host *models.Host peerConfig.AllowedIPs = allowedips // only append allowed IPs if valid connection } - if node.IsIngressGateway || node.IsEgressGateway { - if peer.IsIngressGateway { - _, extPeerIDAndAddrs, err := getExtPeers(&peer) - if err == nil { - for _, extPeerIdAndAddr := range extPeerIDAndAddrs { - extPeerIdAndAddr := extPeerIdAndAddr - nodePeerMap[extPeerIdAndAddr.ID] = models.PeerRouteInfo{ - PeerAddr: net.IPNet{ - IP: net.ParseIP(extPeerIdAndAddr.Address), - Mask: getCIDRMaskFromAddr(extPeerIdAndAddr.Address), - }, - PeerKey: extPeerIdAndAddr.ID, - Allow: true, - ID: extPeerIdAndAddr.ID, - } - } - } - } - if node.IsIngressGateway && peer.IsEgressGateway { - hostPeerUpdate.IngressInfo.EgressRanges = append(hostPeerUpdate.IngressInfo.EgressRanges, - peer.EgressGatewayRanges...) - } - nodePeerMap[peerHost.PublicKey.String()] = models.PeerRouteInfo{ - PeerAddr: net.IPNet{ - IP: net.ParseIP(peer.PrimaryAddress()), - Mask: getCIDRMaskFromAddr(peer.PrimaryAddress()), - }, - PeerKey: peerHost.PublicKey.String(), - Allow: true, - ID: peer.ID.String(), - } - } - peerProxyPort := GetProxyListenPort(peerHost) var nodePeer wgtypes.PeerConfig if _, ok := hostPeerUpdate.HostPeerIDs[peerHost.PublicKey.String()]; !ok { @@ -584,6 +583,9 @@ func GetAllowedIPs(node, peer *models.Node, metrics *models.Metrics) []net.IPNet } if node.IsRelayed && node.RelayedBy == peer.ID.String() { allowedips = append(allowedips, getAllowedIpsForRelayed(node, peer)...) + if node.IsEgressGateway { + allowedips = append(allowedips, getEgressIPs(node)...) + } } return allowedips } @@ -649,11 +651,18 @@ func getNodeAllowedIPs(peer, node *models.Node) []net.IPNet { allowedips = append(allowedips, egressIPs...) } if peer.IsRelay { - for _, relayed := range peer.RelayedNodes { - if node.ID.String() == relayed { + for _, relayedNodeID := range peer.RelayedNodes { + if node.ID.String() == relayedNodeID { continue } - allowed := getRelayedAddresses(relayed) + relayedNode, err := GetNodeByID(relayedNodeID) + if err != nil { + continue + } + allowed := getRelayedAddresses(relayedNodeID) + if relayedNode.IsEgressGateway { + allowed = append(allowed, getEgressIPs(&relayedNode)...) + } allowedips = append(allowedips, allowed...) } } @@ -663,23 +672,9 @@ func getNodeAllowedIPs(peer, node *models.Node) []net.IPNet { // getAllowedIpsForRelayed - returns the peerConfig for a node relayed by relay func getAllowedIpsForRelayed(relayed, relay *models.Node) (allowedIPs []net.IPNet) { if relayed.RelayedBy != relay.ID.String() { - logger.Log(0, "peerUpdateForRelayedByRelay called with invalid parameters") + logger.Log(0, "RelayedByRelay called with invalid parameters") return } - if relay.Address.IP != nil { - relay.Address.Mask = net.CIDRMask(32, 32) - allowedIPs = append(allowedIPs, relay.Address) - } - if relay.Address6.IP != nil { - relay.Address6.Mask = net.CIDRMask(128, 128) - allowedIPs = append(allowedIPs, relay.Address6) - } - if relay.IsEgressGateway { - allowedIPs = append(allowedIPs, getEgressIPs(relay)...) - } - if relay.IsIngressGateway { - allowedIPs = append(allowedIPs, getIngressIPs(relay)...) - } peers, err := GetNetworkNodes(relay.Network) if err != nil { logger.Log(0, "error getting network clients", err.Error()) From 62b8c386d15cc142367012c957de4bc562cadb30 Mon Sep 17 00:00:00 2001 From: Abhishek Kondur Date: Sat, 17 Jun 2023 15:44:17 +0530 Subject: [PATCH 7/9] rm unused func --- logic/peers.go | 29 ----------------------------- 1 file changed, 29 deletions(-) diff --git a/logic/peers.go b/logic/peers.go index 36e485076..0ca3cbc28 100644 --- a/logic/peers.go +++ b/logic/peers.go @@ -691,35 +691,6 @@ func getAllowedIpsForRelayed(relayed, relay *models.Node) (allowedIPs []net.IPNe return } -func getIngressIPs(peer *models.Node) []net.IPNet { - var ingressIPs []net.IPNet - extclients, err := GetNetworkExtClients(peer.Network) - if err != nil { - return ingressIPs - } - for _, ec := range extclients { - if ec.IngressGatewayID == peer.ID.String() { - if ec.Address != "" { - ip, cidr, err := net.ParseCIDR(ec.Address) - if err != nil { - continue - } - cidr.IP = ip - ingressIPs = append(ingressIPs, *cidr) - } - if ec.Address6 != "" { - ip, cidr, err := net.ParseCIDR(ec.Address6) - if err != nil { - continue - } - cidr.IP = ip - ingressIPs = append(ingressIPs, *cidr) - } - } - } - return ingressIPs -} - func getCIDRMaskFromAddr(addr string) net.IPMask { cidr := net.CIDRMask(32, 32) ipAddr, err := netip.ParseAddr(addr) From c5629eacfeff52e609e00cd782a94c130c8a60e0 Mon Sep 17 00:00:00 2001 From: Abhishek Kondur Date: Mon, 19 Jun 2023 19:15:19 +0530 Subject: [PATCH 8/9] remove debug logs --- controllers/node.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/controllers/node.go b/controllers/node.go index d3ab56416..476848058 100644 --- a/controllers/node.go +++ b/controllers/node.go @@ -4,7 +4,6 @@ import ( "context" "encoding/json" "fmt" - "log" "net/http" "strings" @@ -665,9 +664,7 @@ func updateNode(w http.ResponseWriter, r *http.Request) { logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal")) return } - log.Println("relay was updated") if relayupdate { - log.Println("updating relayed nodes") updatenodes := logic.UpdateRelayed(currentNode.ID.String(), currentNode.RelayedNodes, newNode.RelayedNodes) if len(updatenodes) > 0 { for _, relayedNode := range updatenodes { From 682e425bab8dac349ac27b6d6c1d1b9624a5b578 Mon Sep 17 00:00:00 2001 From: Abhishek Kondur Date: Mon, 19 Jun 2023 21:53:32 +0530 Subject: [PATCH 9/9] avoid adding egress ranges on the relayed gw node --- logic/peers.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/logic/peers.go b/logic/peers.go index 0ca3cbc28..f642605cb 100644 --- a/logic/peers.go +++ b/logic/peers.go @@ -583,9 +583,7 @@ func GetAllowedIPs(node, peer *models.Node, metrics *models.Metrics) []net.IPNet } if node.IsRelayed && node.RelayedBy == peer.ID.String() { allowedips = append(allowedips, getAllowedIpsForRelayed(node, peer)...) - if node.IsEgressGateway { - allowedips = append(allowedips, getEgressIPs(node)...) - } + } return allowedips }