|
@@ -4,227 +4,254 @@ import (
|
|
|
"encoding/json"
|
|
|
"errors"
|
|
|
"fmt"
|
|
|
- "time"
|
|
|
+ "net"
|
|
|
|
|
|
"github.com/gravitl/netmaker/database"
|
|
|
"github.com/gravitl/netmaker/logger"
|
|
|
"github.com/gravitl/netmaker/models"
|
|
|
+ "golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
|
|
)
|
|
|
|
|
|
// CreateRelay - creates a relay
|
|
|
-func CreateRelay(relay models.RelayRequest) ([]models.Node, models.Node, error) {
|
|
|
- var returnnodes []models.Node
|
|
|
-
|
|
|
+func CreateRelay(relay models.RelayRequest) ([]models.Client, models.Node, error) {
|
|
|
+ var relayedClients []models.Client
|
|
|
node, err := GetNodeByID(relay.NodeID)
|
|
|
if err != nil {
|
|
|
- return returnnodes, models.Node{}, err
|
|
|
+ return relayedClients, models.Node{}, err
|
|
|
}
|
|
|
host, err := GetHost(node.HostID.String())
|
|
|
if err != nil {
|
|
|
- return returnnodes, models.Node{}, err
|
|
|
+ return relayedClients, models.Node{}, err
|
|
|
}
|
|
|
if host.OS != "linux" {
|
|
|
- return returnnodes, models.Node{}, fmt.Errorf("only linux machines can be relay nodes")
|
|
|
+ return relayedClients, models.Node{}, fmt.Errorf("only linux machines can be relay nodes")
|
|
|
}
|
|
|
err = ValidateRelay(relay)
|
|
|
if err != nil {
|
|
|
- return returnnodes, models.Node{}, err
|
|
|
+ return relayedClients, models.Node{}, err
|
|
|
}
|
|
|
node.IsRelay = true
|
|
|
- node.RelayAddrs = relay.RelayAddrs
|
|
|
-
|
|
|
+ node.RelayedNodes = relay.RelayedNodes
|
|
|
node.SetLastModified()
|
|
|
nodeData, err := json.Marshal(&node)
|
|
|
if err != nil {
|
|
|
- return returnnodes, node, err
|
|
|
+ return relayedClients, node, err
|
|
|
}
|
|
|
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
|
|
|
+ return relayedClients, models.Node{}, err
|
|
|
}
|
|
|
- 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)
|
|
|
- }
|
|
|
+ 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 relayedHosts
|
|
|
+ return relayedClients, node, nil
|
|
|
}
|
|
|
|
|
|
-// SetRelayedNodes- set relayed nodes
|
|
|
-func SetRelayedNodes(setRelayed bool, networkName string, addrs []string) ([]models.Node, error) {
|
|
|
- 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)
|
|
|
- }
|
|
|
+// SetRelayedNodes- sets and saves node as relayed
|
|
|
+func 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
|
|
|
}
|
|
|
- }
|
|
|
- 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
|
|
|
+ } else {
|
|
|
+ node.RelayedBy = ""
|
|
|
}
|
|
|
- }
|
|
|
- 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)
|
|
|
+ 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 {
|
|
|
- relayedHosts = append(relayedHosts, *relayedHost)
|
|
|
+ returnnodes = append(returnnodes, models.Client{
|
|
|
+ Host: *host,
|
|
|
+ Node: node,
|
|
|
+ })
|
|
|
}
|
|
|
}
|
|
|
- return relayedHosts
|
|
|
+ return returnnodes
|
|
|
}
|
|
|
|
|
|
// 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")
|
|
|
+ err = errors.New("relayed nodes 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.Client {
|
|
|
+ _ = SetRelayedNodes(false, relay, oldNodes)
|
|
|
+ return SetRelayedNodes(true, relay, newNodes)
|
|
|
}
|
|
|
|
|
|
// DeleteRelay - deletes a relay
|
|
|
-func DeleteRelay(network, nodeid string) ([]models.Node, models.Node, error) {
|
|
|
- var returnnodes []models.Node
|
|
|
+func DeleteRelay(network, nodeid string) ([]models.Client, models.Node, error) {
|
|
|
+ var returnClients []models.Client
|
|
|
node, err := GetNodeByID(nodeid)
|
|
|
if err != nil {
|
|
|
- return returnnodes, models.Node{}, err
|
|
|
- }
|
|
|
- returnnodes, err = SetRelayedNodes(false, node.Network, node.RelayAddrs)
|
|
|
- if err != nil {
|
|
|
- return returnnodes, node, err
|
|
|
+ return returnClients, models.Node{}, err
|
|
|
}
|
|
|
|
|
|
+ returnClients = SetRelayedNodes(false, nodeid, node.RelayedNodes)
|
|
|
node.IsRelay = false
|
|
|
- node.RelayAddrs = []string{}
|
|
|
+ node.RelayedNodes = []string{}
|
|
|
node.SetLastModified()
|
|
|
-
|
|
|
data, err := json.Marshal(&node)
|
|
|
if err != nil {
|
|
|
- return returnnodes, models.Node{}, err
|
|
|
+ return returnClients, models.Node{}, err
|
|
|
}
|
|
|
if err = database.Insert(nodeid, string(data), database.NODES_TABLE_NAME); err != nil {
|
|
|
- return returnnodes, models.Node{}, err
|
|
|
+ return returnClients, models.Node{}, err
|
|
|
}
|
|
|
- return returnnodes, node, nil
|
|
|
+ return returnClients, 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
|
|
|
+ }
|
|
|
+ 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 node
|
|
|
+func 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 relay
|
|
|
+func 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)
|
|
|
}
|
|
|
- relayedHosts = SetRelayedHosts(false, relayHostID, relayHost.RelayedHosts)
|
|
|
- relayHost.IsRelay = false
|
|
|
- relayHost.RelayedHosts = []string{}
|
|
|
- err = UpsertHost(relayHost)
|
|
|
+ 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 {
|
|
|
- return
|
|
|
+ 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
|
|
|
+ }
|
|
|
+ update.AllowedIPs = append(update.AllowedIPs, AddAllowedIPs(&peer)...)
|
|
|
}
|
|
|
- return
|
|
|
+ return update
|
|
|
}
|
|
|
|
|
|
-// UpdateHostRelay - updates the relay host with new relayed hosts
|
|
|
-func UpdateHostRelay(relayHostID string, oldRelayedHosts, newRelayedHosts []string) {
|
|
|
- _ = SetRelayedHosts(false, relayHostID, oldRelayedHosts)
|
|
|
- _ = SetRelayedHosts(true, relayHostID, newRelayedHosts)
|
|
|
+// peerUpdateForRelay - returns the peerConfig for a relay
|
|
|
+func 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,
|
|
|
+ }
|
|
|
+ update.AllowedIPs = append(update.AllowedIPs, AddAllowedIPs(&peer)...)
|
|
|
+ peerConfig = append(peerConfig, update)
|
|
|
+ }
|
|
|
+ return peerConfig
|
|
|
}
|