Merge pull request #1905 from gravitl/netclient_refactor_peer_updates

host based peer updates
This commit is contained in:
dcarns 2023-01-09 10:36:31 -05:00 committed by GitHub
commit 48af36a1b5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 327 additions and 146 deletions

View file

@ -7,7 +7,6 @@ import (
"net/http" "net/http"
"strings" "strings"
"github.com/google/uuid"
"github.com/gorilla/mux" "github.com/gorilla/mux"
proxy_models "github.com/gravitl/netclient/nmproxy/models" proxy_models "github.com/gravitl/netclient/nmproxy/models"
"github.com/gravitl/netmaker/database" "github.com/gravitl/netmaker/database"
@ -442,6 +441,13 @@ func getNode(w http.ResponseWriter, r *http.Request) {
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal")) logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
return return
} }
hostPeerUpdate, err := logic.GetPeerUpdateForHost(host)
if err != nil && !database.IsEmptyRecord(err) {
logger.Log(0, r.Header.Get("user"),
fmt.Sprintf("error fetching wg peers config for host [ %s ]: %v", host.ID.String(), err))
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
return
}
server := servercfg.GetServerInfo() server := servercfg.GetServerInfo()
network, err := logic.GetNetwork(node.Network) network, err := logic.GetNetwork(node.Network)
if err != nil { if err != nil {
@ -453,7 +459,9 @@ func getNode(w http.ResponseWriter, r *http.Request) {
legacy := node.Legacy(host, &server, &network) legacy := node.Legacy(host, &server, &network)
response := models.NodeGet{ response := models.NodeGet{
Node: *legacy, Node: *legacy,
Host: *host,
Peers: peerUpdate.Peers, Peers: peerUpdate.Peers,
HostPeers: hostPeerUpdate.Peers,
ServerConfig: server, ServerConfig: server,
PeerIDs: peerUpdate.PeerIDs, PeerIDs: peerUpdate.PeerIDs,
} }
@ -637,19 +645,18 @@ func createNode(w http.ResponseWriter, r *http.Request) {
return return
} }
} }
peerUpdate, err := logic.GetPeerUpdate(&data.Node, &data.Host) hostPeerUpdate, err := logic.GetPeerUpdateForHost(&data.Host)
if err != nil && !database.IsEmptyRecord(err) { if err != nil && !database.IsEmptyRecord(err) {
logger.Log(0, r.Header.Get("user"), logger.Log(0, r.Header.Get("user"),
fmt.Sprintf("error fetching wg peers config for node [ %s ]: %v", data.Node.ID.String(), err)) fmt.Sprintf("error fetching wg peers config for host [ %s ]: %v", data.Host.ID.String(), err))
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal")) logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
return return
} }
data.Node.Peers = peerUpdate.Peers
response := models.NodeJoinResponse{ response := models.NodeJoinResponse{
Node: data.Node, Node: data.Node,
ServerConfig: server, ServerConfig: server,
PeerIDs: peerUpdate.PeerIDs, Host: data.Host,
Peers: hostPeerUpdate.Peers,
} }
logger.Log(1, r.Header.Get("user"), "created new node", data.Host.Name, "on network", networkName) logger.Log(1, r.Header.Get("user"), "created new node", data.Host.Name, "on network", networkName)
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
@ -1061,28 +1068,14 @@ func deleteNode(w http.ResponseWriter, r *http.Request) {
}, &node) }, &node)
} }
if fromNode { if fromNode {
// check if server should be removed from mq // update networks for host mq client
// err is irrelevent currNets := logic.GetHostNetworks(host.ID.String())
nodes, _ := logic.GetAllNodes() if len(currNets) > 0 {
var foundNode models.Node mq.ModifyClient(&mq.MqClient{
for _, nodetocheck := range nodes { ID: host.ID.String(),
if nodetocheck.HostID == node.HostID { Text: host.Name,
foundNode = nodetocheck Networks: currNets,
break })
}
}
// TODO: Address how to remove host
if foundNode.HostID != uuid.Nil {
if err = logic.DissasociateNodeFromHost(&foundNode, host); err == nil {
currNets := logic.GetHostNetworks(host.ID.String())
if len(currNets) > 0 {
mq.ModifyClient(&mq.MqClient{
ID: host.ID.String(),
Text: host.Name,
Networks: currNets,
})
}
}
} }
} }
logic.ReturnSuccessResponse(w, r, nodeid+" deleted.") logic.ReturnSuccessResponse(w, r, nodeid+" deleted.")
@ -1091,12 +1084,11 @@ func deleteNode(w http.ResponseWriter, r *http.Request) {
runUpdates(&node, false) runUpdates(&node, false)
return return
} }
go func() { go func(network string) {
if err := mq.PublishPeerUpdate(node.Network, false); err != nil { if err := mq.PublishPeerUpdate(network, false); err != nil {
logger.Log(1, "error publishing peer update ", err.Error()) logger.Log(1, "error publishing peer update ", err.Error())
return
} }
}() }(node.Network)
} }

View file

@ -48,9 +48,9 @@ func GetNetworkNodes(network string) ([]models.Node, error) {
// UpdateNode - takes a node and updates another node with it's values // UpdateNode - takes a node and updates another node with it's values
func UpdateNode(currentNode *models.Node, newNode *models.Node) error { func UpdateNode(currentNode *models.Node, newNode *models.Node) error {
if newNode.Address.String() != currentNode.Address.String() { if newNode.Address.IP.String() != currentNode.Address.IP.String() {
if network, err := GetParentNetwork(newNode.Network); err == nil { if network, err := GetParentNetwork(newNode.Network); err == nil {
if !IsAddressInCIDR(newNode.Address.String(), network.AddressRange) { if !IsAddressInCIDR(newNode.Address.IP.String(), network.AddressRange) {
return fmt.Errorf("invalid address provided; out of network range for node %s", newNode.ID) return fmt.Errorf("invalid address provided; out of network range for node %s", newNode.ID)
} }
} }

View file

@ -193,6 +193,127 @@ func GetPeersForProxy(node *models.Node, onlyPeers bool) (proxy_models.ProxyMana
return proxyPayload, nil return proxyPayload, nil
} }
// GetPeerUpdateForHost - gets the consolidated peer update for the host from all networks
func GetPeerUpdateForHost(host *models.Host) (models.HostPeerUpdate, error) {
hostPeerUpdate := models.HostPeerUpdate{
Network: make(map[string]models.NetworkInfo),
PeerIDs: make(models.HostPeerMap),
ServerVersion: servercfg.GetVersion(),
ServerAddrs: []models.ServerAddr{},
}
log.Println("peer update for host ", host.ID.String())
peerIndexMap := make(map[string]int)
for _, nodeID := range host.Nodes {
node, err := GetNodeByID(nodeID)
if err != nil {
continue
}
if !node.Connected {
continue
}
hostPeerUpdate.Network[node.Network] = models.NetworkInfo{
DNS: getPeerDNS(node.Network),
}
currentPeers, err := GetNetworkNodes(node.Network)
if err != nil {
log.Println("no network nodes")
return models.HostPeerUpdate{}, err
}
for _, peer := range currentPeers {
if peer.ID == node.ID {
log.Println("peer update, skipping self")
//skip yourself
continue
}
var peerConfig wgtypes.PeerConfig
peerHost, err := GetHost(peer.HostID.String())
if err != nil {
log.Println("no peer host", err)
return models.HostPeerUpdate{}, err
}
if !peer.Connected {
log.Println("peer update, skipping unconnected node")
//skip unconnected nodes
continue
}
if !nodeacls.AreNodesAllowed(nodeacls.NetworkID(node.Network), nodeacls.NodeID(node.ID.String()), nodeacls.NodeID(peer.ID.String())) {
log.Println("peer update, skipping node for acl")
//skip if not permitted by acl
continue
}
peerConfig.PublicKey = peerHost.PublicKey
peerConfig.PersistentKeepaliveInterval = &peer.PersistentKeepalive
peerConfig.ReplaceAllowedIPs = true
uselocal := false
if host.EndpointIP.String() == peerHost.EndpointIP.String() {
//peer is on same network
// set to localaddress
uselocal = true
if node.LocalAddress.IP == nil {
// use public endpint
uselocal = false
}
if node.LocalAddress.String() == peer.LocalAddress.String() {
uselocal = false
}
}
peerConfig.Endpoint = &net.UDPAddr{
IP: peerHost.EndpointIP,
Port: peerHost.ListenPort,
}
if !host.ProxyEnabled && peerHost.ProxyEnabled {
peerConfig.Endpoint.Port = peerHost.ProxyListenPort
}
if uselocal {
peerConfig.Endpoint.IP = peer.LocalAddress.IP
}
allowedips := getNodeAllowedIPs(&peer, &node)
if peer.IsIngressGateway {
for _, entry := range peer.IngressGatewayRange {
_, cidr, err := net.ParseCIDR(string(entry))
if err == nil {
allowedips = append(allowedips, *cidr)
}
}
}
if peer.IsRelay {
allowedips = append(allowedips, getRelayAllowedIPs(&node, &peer)...)
}
if peer.IsEgressGateway {
allowedips = append(allowedips, getEgressIPs(&node, &peer)...)
}
peerConfig.AllowedIPs = allowedips
if _, ok := hostPeerUpdate.PeerIDs[peerHost.PublicKey.String()]; !ok {
hostPeerUpdate.PeerIDs[peerHost.PublicKey.String()] = make(map[string]models.IDandAddr)
hostPeerUpdate.Peers = append(hostPeerUpdate.Peers, peerConfig)
peerIndexMap[peerHost.PublicKey.String()] = len(hostPeerUpdate.Peers) - 1
hostPeerUpdate.PeerIDs[peerHost.PublicKey.String()][peer.ID.String()] = models.IDandAddr{
ID: peer.ID.String(),
Address: peer.PrimaryAddress(),
Name: peerHost.Name,
Network: peer.Network,
}
} else {
peerAllowedIPs := hostPeerUpdate.Peers[peerIndexMap[peerHost.PublicKey.String()]].AllowedIPs
peerAllowedIPs = append(peerAllowedIPs, allowedips...)
hostPeerUpdate.Peers[peerIndexMap[peerHost.PublicKey.String()]].AllowedIPs = peerAllowedIPs
hostPeerUpdate.PeerIDs[peerHost.PublicKey.String()][peer.ID.String()] = models.IDandAddr{
ID: peer.ID.String(),
Address: peer.PrimaryAddress(),
Name: peerHost.Name,
Network: peer.Network,
}
}
}
}
return hostPeerUpdate, nil
}
// GetPeerUpdate - gets a wireguard peer config for each peer of a node // GetPeerUpdate - gets a wireguard peer config for each peer of a node
func GetPeerUpdate(node *models.Node, host *models.Host) (models.PeerUpdate, error) { func GetPeerUpdate(node *models.Node, host *models.Host) (models.PeerUpdate, error) {
log.Println("peer update for node ", node.ID) log.Println("peer update for node ", node.ID)
@ -731,6 +852,7 @@ func getPeerDNS(network string) string {
host, err := GetHost(node.HostID.String()) host, err := GetHost(node.HostID.String())
if err != nil { if err != nil {
logger.Log(0, "error retrieving host for node", node.ID.String(), err.Error()) logger.Log(0, "error retrieving host for node", node.ID.String(), err.Error())
continue
} }
dns = dns + fmt.Sprintf("%s %s.%s\n", nodes[i].Address, host.Name, nodes[i].Network) dns = dns + fmt.Sprintf("%s %s.%s\n", nodes[i].Address, host.Name, nodes[i].Network)
} }

View file

@ -34,7 +34,8 @@ func CheckZombies(newnode *models.Node, mac net.HardwareAddr) {
for _, node := range nodes { for _, node := range nodes {
host, err := GetHost(node.HostID.String()) host, err := GetHost(node.HostID.String())
if err != nil { if err != nil {
// should we delete the node if host not found ??
continue
} }
if host.MacAddress.String() == mac.String() { if host.MacAddress.String() == mac.String() {
logger.Log(0, "adding ", node.ID.String(), " to zombie list") logger.Log(0, "adding ", node.ID.String(), " to zombie list")

View file

@ -59,7 +59,6 @@ func (a *ApiNode) ConvertToServerNode(currentNode *Node) *Node {
convertedNode.IsRelay = a.IsRelay convertedNode.IsRelay = a.IsRelay
convertedNode.IsRelayed = a.IsRelayed convertedNode.IsRelayed = a.IsRelayed
convertedNode.PendingDelete = a.PendingDelete convertedNode.PendingDelete = a.PendingDelete
convertedNode.Peers = currentNode.Peers
convertedNode.Failover = a.Failover convertedNode.Failover = a.Failover
convertedNode.IsEgressGateway = a.IsEgressGateway convertedNode.IsEgressGateway = a.IsEgressGateway
convertedNode.IsIngressGateway = a.IsIngressGateway convertedNode.IsIngressGateway = a.IsIngressGateway

View file

@ -37,11 +37,15 @@ type IDandAddr struct {
Address string `json:"address" bson:"address" yaml:"address"` Address string `json:"address" bson:"address" yaml:"address"`
Name string `json:"name" bson:"name" yaml:"name"` Name string `json:"name" bson:"name" yaml:"name"`
IsServer string `json:"isserver" bson:"isserver" yaml:"isserver" validate:"checkyesorno"` IsServer string `json:"isserver" bson:"isserver" yaml:"isserver" validate:"checkyesorno"`
Network string `json:"network" bson:"network" yaml:"network" validate:"network"`
} }
// PeerMap - peer map for ids and addresses in metrics // PeerMap - peer map for ids and addresses in metrics
type PeerMap map[string]IDandAddr type PeerMap map[string]IDandAddr
// HostPeerMap - host peer map for ids and addresses
type HostPeerMap map[string]map[string]IDandAddr
// MetricsMap - map for holding multiple metrics in memory // MetricsMap - map for holding multiple metrics in memory
type MetricsMap map[string]Metrics type MetricsMap map[string]Metrics

View file

@ -16,6 +16,21 @@ type PeerUpdate struct {
ProxyUpdate proxy_models.ProxyManagerPayload `json:"proxy_update" bson:"proxy_update" yaml:"proxy_update"` ProxyUpdate proxy_models.ProxyManagerPayload `json:"proxy_update" bson:"proxy_update" yaml:"proxy_update"`
} }
// HostPeerUpdate - struct for host peer updates
type HostPeerUpdate struct {
ServerVersion string `json:"serverversion" bson:"serverversion" yaml:"serverversion"`
ServerAddrs []ServerAddr `json:"serveraddrs" bson:"serveraddrs" yaml:"serveraddrs"`
Network map[string]NetworkInfo `json:"network" bson:"network" yaml:"network"`
Peers []wgtypes.PeerConfig `json:"peers" bson:"peers" yaml:"peers"`
PeerIDs HostPeerMap `json:"peerids" bson:"peerids" yaml:"peerids"`
ProxyUpdate proxy_models.ProxyManagerPayload `json:"proxy_update" bson:"proxy_update" yaml:"proxy_update"`
}
// NetworkInfo - struct for network info
type NetworkInfo struct {
DNS string `json:"dns" bson:"dns" yaml:"dns"`
}
// KeyUpdate - key update struct // KeyUpdate - key update struct
type KeyUpdate struct { type KeyUpdate struct {
Network string `json:"network" bson:"network"` Network string `json:"network" bson:"network"`

View file

@ -56,26 +56,25 @@ type Iface struct {
// CommonNode - represents a commonn node data elements shared by netmaker and netclient // CommonNode - represents a commonn node data elements shared by netmaker and netclient
type CommonNode struct { type CommonNode struct {
ID uuid.UUID `json:"id" yaml:"id"` ID uuid.UUID `json:"id" yaml:"id"`
HostID uuid.UUID `json:"hostid" yaml:"hostid"` HostID uuid.UUID `json:"hostid" yaml:"hostid"`
Network string `json:"network" yaml:"network"` Network string `json:"network" yaml:"network"`
NetworkRange net.IPNet `json:"networkrange" yaml:"networkrange"` NetworkRange net.IPNet `json:"networkrange" yaml:"networkrange"`
NetworkRange6 net.IPNet `json:"networkrange6" yaml:"networkrange6"` NetworkRange6 net.IPNet `json:"networkrange6" yaml:"networkrange6"`
InternetGateway *net.UDPAddr `json:"internetgateway" yaml:"internetgateway"` InternetGateway *net.UDPAddr `json:"internetgateway" yaml:"internetgateway"`
Server string `json:"server" yaml:"server"` Server string `json:"server" yaml:"server"`
Connected bool `json:"connected" yaml:"connected"` Connected bool `json:"connected" yaml:"connected"`
Address net.IPNet `json:"address" yaml:"address"` Address net.IPNet `json:"address" yaml:"address"`
Address6 net.IPNet `json:"address6" yaml:"address6"` Address6 net.IPNet `json:"address6" yaml:"address6"`
PostUp string `json:"postup" yaml:"postup"` PostUp string `json:"postup" yaml:"postup"`
PostDown string `json:"postdown" yaml:"postdown"` PostDown string `json:"postdown" yaml:"postdown"`
Action string `json:"action" yaml:"action"` Action string `json:"action" yaml:"action"`
LocalAddress net.IPNet `json:"localaddress" yaml:"localaddress"` LocalAddress net.IPNet `json:"localaddress" yaml:"localaddress"`
IsLocal bool `json:"islocal" yaml:"islocal"` IsLocal bool `json:"islocal" yaml:"islocal"`
IsEgressGateway bool `json:"isegressgateway" yaml:"isegressgateway"` IsEgressGateway bool `json:"isegressgateway" yaml:"isegressgateway"`
IsIngressGateway bool `json:"isingressgateway" yaml:"isingressgateway"` IsIngressGateway bool `json:"isingressgateway" yaml:"isingressgateway"`
DNSOn bool `json:"dnson" yaml:"dnson"` DNSOn bool `json:"dnson" yaml:"dnson"`
PersistentKeepalive time.Duration `json:"persistentkeepalive" yaml:"persistentkeepalive"` PersistentKeepalive time.Duration `json:"persistentkeepalive" yaml:"persistentkeepalive"`
Peers []wgtypes.PeerConfig `json:"peers" yaml:"peers"`
} }
// Node - a model of a network node // Node - a model of a network node
@ -365,7 +364,7 @@ func (node *LegacyNode) SetDefaultFailover() {
// Node.Fill - fills other node data into calling node data if not set on calling node // 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) { // TODO add new field for nftables present
newNode.ID = currentNode.ID newNode.ID = currentNode.ID
newNode.HostID = currentNode.HostID
// Revisit the logic for boolean values // Revisit the logic for boolean values
// TODO ---- !!!!!!!!!!!!!!!!!!!!!!!!!!!! // TODO ---- !!!!!!!!!!!!!!!!!!!!!!!!!!!!
// TODO ---- !!!!!!!!!!!!!!!!!!!!!!!!!! // TODO ---- !!!!!!!!!!!!!!!!!!!!!!!!!!
@ -435,9 +434,6 @@ func (newNode *Node) Fill(currentNode *Node) { // TODO add new field for nftable
if newNode.Server == "" { if newNode.Server == "" {
newNode.Server = currentNode.Server newNode.Server = currentNode.Server
} }
if newNode.Connected != currentNode.Connected {
newNode.Connected = currentNode.Connected
}
if newNode.DefaultACL == "" { if newNode.DefaultACL == "" {
newNode.DefaultACL = currentNode.DefaultACL newNode.DefaultACL = currentNode.DefaultACL
} }
@ -499,17 +495,23 @@ func (ln *LegacyNode) ConvertToNewNode() (*Host, *Node) {
host.HostPass = ln.Password host.HostPass = ln.Password
host.Name = ln.Name host.Name = ln.Name
host.ListenPort = int(ln.ListenPort) host.ListenPort = int(ln.ListenPort)
_, cidr, _ := net.ParseCIDR(ln.LocalAddress) if _, cidr, err := net.ParseCIDR(ln.LocalAddress); err == nil {
_, cidr, _ = net.ParseCIDR(ln.LocalRange) host.LocalRange = *cidr
host.LocalRange = *cidr } else {
if _, cidr, err := net.ParseCIDR(ln.LocalRange); err == nil {
host.LocalRange = *cidr
}
}
host.LocalListenPort = int(ln.LocalListenPort) host.LocalListenPort = int(ln.LocalListenPort)
host.ProxyListenPort = int(ln.ProxyListenPort) host.ProxyListenPort = int(ln.ProxyListenPort)
host.MTU = int(ln.MTU) host.MTU = int(ln.MTU)
host.PublicKey, _ = wgtypes.ParseKey(ln.PublicKey) host.PublicKey, _ = wgtypes.ParseKey(ln.PublicKey)
host.MacAddress, _ = net.ParseMAC(ln.MacAddress) host.MacAddress, _ = net.ParseMAC(ln.MacAddress)
host.TrafficKeyPublic = ln.TrafficKeys.Mine host.TrafficKeyPublic = ln.TrafficKeys.Mine
gateway, _ := net.ResolveUDPAddr("udp", ln.InternetGateway) gateway, err := net.ResolveUDPAddr("udp", ln.InternetGateway)
host.InternetGateway = *gateway if err == nil {
host.InternetGateway = *gateway
}
id, _ := uuid.Parse(ln.ID) id, _ := uuid.Parse(ln.ID)
host.Nodes = append(host.Nodes, id.String()) host.Nodes = append(host.Nodes, id.String())
host.Interfaces = ln.Interfaces host.Interfaces = ln.Interfaces
@ -519,16 +521,26 @@ func (ln *LegacyNode) ConvertToNewNode() (*Host, *Node) {
id, _ := uuid.Parse(ln.ID) id, _ := uuid.Parse(ln.ID)
node.ID = id node.ID = id
node.Network = ln.Network node.Network = ln.Network
_, cidr, _ := net.ParseCIDR(ln.NetworkSettings.AddressRange) if _, cidr, err := net.ParseCIDR(ln.NetworkSettings.AddressRange); err == nil {
node.NetworkRange = *cidr node.NetworkRange = *cidr
_, cidr, _ = net.ParseCIDR(ln.NetworkSettings.AddressRange6) }
node.NetworkRange6 = *cidr if _, cidr, err := net.ParseCIDR(ln.NetworkSettings.AddressRange6); err == nil {
node.NetworkRange6 = *cidr
}
node.Server = ln.Server node.Server = ln.Server
node.Connected = parseBool(ln.Connected) node.Connected = parseBool(ln.Connected)
_, cidr, _ = net.ParseCIDR(ln.Address) if ln.Address != "" {
node.Address = *cidr node.Address = net.IPNet{
_, cidr, _ = net.ParseCIDR(ln.Address6) IP: net.ParseIP(ln.Address),
node.Address6 = *cidr Mask: net.CIDRMask(32, 32),
}
}
if ln.Address6 != "" {
node.Address = net.IPNet{
IP: net.ParseIP(ln.Address6),
Mask: net.CIDRMask(128, 128),
}
}
node.PostUp = ln.PostUp node.PostUp = ln.PostUp
node.PostDown = ln.PostDown node.PostDown = ln.PostDown
node.Action = ln.Action node.Action = ln.Action

View file

@ -205,16 +205,17 @@ type NodeGet struct {
Node LegacyNode `json:"node" bson:"node" yaml:"node"` Node LegacyNode `json:"node" bson:"node" yaml:"node"`
Host Host `json:"host" yaml:"host"` Host Host `json:"host" yaml:"host"`
Peers []wgtypes.PeerConfig `json:"peers" bson:"peers" yaml:"peers"` Peers []wgtypes.PeerConfig `json:"peers" bson:"peers" yaml:"peers"`
HostPeers []wgtypes.PeerConfig `json:"host_peers" bson:"host_peers" yaml:"host_peers"`
ServerConfig ServerConfig `json:"serverconfig" bson:"serverconfig" yaml:"serverconfig"` ServerConfig ServerConfig `json:"serverconfig" bson:"serverconfig" yaml:"serverconfig"`
PeerIDs PeerMap `json:"peerids,omitempty" bson:"peerids,omitempty" yaml:"peerids,omitempty"` PeerIDs PeerMap `json:"peerids,omitempty" bson:"peerids,omitempty" yaml:"peerids,omitempty"`
} }
// NodeJoinResponse data returned to node in response to join // NodeJoinResponse data returned to node in response to join
type NodeJoinResponse struct { type NodeJoinResponse struct {
Node Node `json:"node" bson:"node" yaml:"node"` Node Node `json:"node" bson:"node" yaml:"node"`
Host Host `json:"host" yaml:"host"` Host Host `json:"host" yaml:"host"`
ServerConfig ServerConfig `json:"serverconfig" bson:"serverconfig" yaml:"serverconfig"` ServerConfig ServerConfig `json:"serverconfig" bson:"serverconfig" yaml:"serverconfig"`
PeerIDs PeerMap `json:"peerids,omitempty" bson:"peerids,omitempty" yaml:"peerids,omitempty"` Peers []wgtypes.PeerConfig `json:"peers" bson:"peers" yaml:"peers"`
} }
// ServerConfig - struct for dealing with the server information for a netclient // ServerConfig - struct for dealing with the server information for a netclient

View file

@ -13,7 +13,7 @@ func ModifyClient(client *MqClient) error {
roles := []MqDynSecRole{ roles := []MqDynSecRole{
{ {
Rolename: HostRole, Rolename: HostGenericRole,
Priority: -1, Priority: -1,
}, },
} }
@ -43,6 +43,7 @@ func ModifyClient(client *MqClient) error {
// DeleteMqClient - removes a client from the DynSec system // DeleteMqClient - removes a client from the DynSec system
func DeleteMqClient(hostID string) error { func DeleteMqClient(hostID string) error {
deleteHostRole(hostID)
event := MqDynsecPayload{ event := MqDynsecPayload{
Commands: []MqDynSecCmd{ Commands: []MqDynSecCmd{
{ {
@ -57,9 +58,17 @@ func DeleteMqClient(hostID string) error {
// CreateMqClient - creates an MQ DynSec client // CreateMqClient - creates an MQ DynSec client
func CreateMqClient(client *MqClient) error { func CreateMqClient(client *MqClient) error {
err := createHostRole(client.ID)
if err != nil {
return err
}
roles := []MqDynSecRole{ roles := []MqDynSecRole{
{ {
Rolename: HostRole, Rolename: HostGenericRole,
Priority: -1,
},
{
Rolename: getHostRoleName(client.ID),
Priority: -1, Priority: -1,
}, },
} }

View file

@ -19,8 +19,8 @@ const (
exporterRole = "exporter" exporterRole = "exporter"
// constant for node role // constant for node role
NodeRole = "node" NodeRole = "node"
// HostRole constant for host role // HostGenericRole constant for host role
HostRole = "host" HostGenericRole = "host"
// const for dynamic security file // const for dynamic security file
dynamicSecurityFile = "dynamic-security.json" dynamicSecurityFile = "dynamic-security.json"
@ -66,7 +66,7 @@ var (
Acls: fetchServerAcls(), Acls: fetchServerAcls(),
}, },
{ {
Rolename: HostRole, Rolename: HostGenericRole,
Acls: fetchNodeAcls(), Acls: fetchNodeAcls(),
}, },
exporterMQRole, exporterMQRole,
@ -169,6 +169,18 @@ func ListClients(client mqtt.Client) (ListClientsData, error) {
return resp, errors.New("resp not found") return resp, errors.New("resp not found")
} }
// fetches host related acls
func fetchHostAcls(hostID string) []Acl {
return []Acl{
{
AclType: "publishClientReceive",
Topic: fmt.Sprintf("peers/host/%s/#", hostID),
Priority: -1,
Allow: true,
},
}
}
// FetchNetworkAcls - fetches network acls // FetchNetworkAcls - fetches network acls
func FetchNetworkAcls(network string) []Acl { func FetchNetworkAcls(network string) []Acl {
return []Acl{ return []Acl{
@ -220,6 +232,20 @@ func DeleteNetworkRole(network string) error {
return publishEventToDynSecTopic(event) return publishEventToDynSecTopic(event)
} }
func deleteHostRole(hostID string) error {
// Deletes the hostID role from MQ
event := MqDynsecPayload{
Commands: []MqDynSecCmd{
{
Command: DeleteRoleCmd,
RoleName: getHostRoleName(hostID),
},
},
}
return publishEventToDynSecTopic(event)
}
// CreateNetworkRole - createss a network role from DynSec system // CreateNetworkRole - createss a network role from DynSec system
func CreateNetworkRole(network string) error { func CreateNetworkRole(network string) error {
// Create Role with acls for the network // Create Role with acls for the network
@ -237,6 +263,27 @@ func CreateNetworkRole(network string) error {
return publishEventToDynSecTopic(event) return publishEventToDynSecTopic(event)
} }
// creates role for the host with ID.
func createHostRole(hostID string) error {
// Create Role with acls for the host
event := MqDynsecPayload{
Commands: []MqDynSecCmd{
{
Command: CreateRoleCmd,
RoleName: getHostRoleName(hostID),
Textname: "host role with Acls for hosts",
Acls: fetchHostAcls(hostID),
},
},
}
return publishEventToDynSecTopic(event)
}
func getHostRoleName(hostID string) string {
return fmt.Sprintf("host-%s", hostID)
}
// serverAcls - fetches server role related acls // serverAcls - fetches server role related acls
func fetchServerAcls() []Acl { func fetchServerAcls() []Acl {
return []Acl{ return []Acl{
@ -252,6 +299,12 @@ func fetchServerAcls() []Acl {
Priority: -1, Priority: -1,
Allow: true, Allow: true,
}, },
{
AclType: "publishClientSend",
Topic: "peers/host/#",
Priority: -1,
Allow: true,
},
{ {
AclType: "publishClientSend", AclType: "publishClientSend",
Topic: "update/#", Topic: "update/#",

View file

@ -90,19 +90,20 @@ func UpdateNode(client mqtt.Client, msg mqtt.Message) {
logger.Log(1, "failed to decrypt message for node ", id, decryptErr.Error()) logger.Log(1, "failed to decrypt message for node ", id, decryptErr.Error())
return return
} }
var newNode models.Node var oldNode models.LegacyNode
if err := json.Unmarshal(decrypted, &newNode); err != nil { if err := json.Unmarshal(decrypted, &oldNode); err != nil {
logger.Log(1, "error unmarshaling payload ", err.Error()) logger.Log(1, "error unmarshaling payload ", err.Error())
return return
} }
ifaceDelta := logic.IfaceDelta(&currentNode, &newNode) _, newNode := oldNode.ConvertToNewNode()
ifaceDelta := logic.IfaceDelta(&currentNode, newNode)
if servercfg.Is_EE && ifaceDelta { if servercfg.Is_EE && ifaceDelta {
if err = logic.EnterpriseResetAllPeersFailovers(currentNode.ID.String(), currentNode.Network); err != nil { if err = logic.EnterpriseResetAllPeersFailovers(currentNode.ID.String(), currentNode.Network); err != nil {
logger.Log(1, "failed to reset failover list during node update", currentNode.ID.String(), currentNode.Network) logger.Log(1, "failed to reset failover list during node update", currentNode.ID.String(), currentNode.Network)
} }
} }
newNode.SetLastCheckIn() newNode.SetLastCheckIn()
if err := logic.UpdateNode(&currentNode, &newNode); err != nil { if err := logic.UpdateNode(&currentNode, newNode); err != nil {
logger.Log(1, "error saving node", err.Error()) logger.Log(1, "error saving node", err.Error())
return return
} }
@ -165,9 +166,13 @@ func UpdateMetrics(client mqtt.Client, msg mqtt.Message) {
if shouldUpdate { if shouldUpdate {
logger.Log(2, "updating peers after node", currentNode.ID.String(), currentNode.Network, "detected connectivity issues") logger.Log(2, "updating peers after node", currentNode.ID.String(), currentNode.Network, "detected connectivity issues")
if err = PublishSinglePeerUpdate(&currentNode); err != nil { host, err := logic.GetHost(currentNode.HostID.String())
logger.Log(0, "failed to publish update after failover peer change for node", currentNode.ID.String(), currentNode.Network) if err == nil {
if err = PublishSingleHostUpdate(host); err != nil {
logger.Log(0, "failed to publish update after failover peer change for node", currentNode.ID.String(), currentNode.Network)
}
} }
} }
logger.Log(1, "updated node metrics", id) logger.Log(1, "updated node metrics", id)

View file

@ -14,20 +14,21 @@ import (
"github.com/gravitl/netmaker/serverctl" "github.com/gravitl/netmaker/serverctl"
) )
// PublishPeerUpdate --- deterines and publishes a peer update to all the peers of a node // PublishPeerUpdate --- determines and publishes a peer update to all the hosts
func PublishPeerUpdate(network string, publishToSelf bool) error { func PublishPeerUpdate(network string, publishToSelf bool) error {
if !servercfg.IsMessageQueueBackend() { if !servercfg.IsMessageQueueBackend() {
return nil return nil
} }
networkNodes, err := logic.GetNetworkNodes(network)
hosts, err := logic.GetAllHosts()
if err != nil { if err != nil {
logger.Log(1, "err getting Network Nodes", err.Error()) logger.Log(1, "err getting all hosts", err.Error())
return err return err
} }
for _, node := range networkNodes { for _, host := range hosts {
err = PublishSinglePeerUpdate(&node) err = PublishSingleHostUpdate(&host)
if err != nil { if err != nil {
logger.Log(1, "failed to publish peer update to node", node.ID.String(), "on network", node.Network, ":", err.Error()) logger.Log(1, "failed to publish peer update to host", host.ID.String(), ": ", err.Error())
} }
} }
return err return err
@ -47,24 +48,20 @@ func PublishProxyPeerUpdate(node *models.Node) error {
return nil return nil
} }
// PublishSinglePeerUpdate --- determines and publishes a peer update to one node // PublishSingleHostUpdate --- determines and publishes a peer update to one host
func PublishSinglePeerUpdate(node *models.Node) error { func PublishSingleHostUpdate(host *models.Host) error {
host, err := logic.GetHost(node.HostID.String())
if err != nil {
return nil
}
peerUpdate, err := logic.GetPeerUpdate(node, host) peerUpdate, err := logic.GetPeerUpdateForHost(host)
if err != nil { if err != nil {
return err return err
} }
if host.ProxyEnabled { if host.ProxyEnabled {
proxyUpdate, err := logic.GetPeersForProxy(node, false) // proxyUpdate, err := logic.GetPeersForProxy(node, false)
if err != nil { // if err != nil {
return err // return err
} // }
proxyUpdate.Action = proxy_models.AddNetwork // proxyUpdate.Action = proxy_models.AddNetwork
peerUpdate.ProxyUpdate = proxyUpdate // peerUpdate.ProxyUpdate = proxyUpdate
} }
@ -72,36 +69,12 @@ func PublishSinglePeerUpdate(node *models.Node) error {
if err != nil { if err != nil {
return err return err
} }
return publish(node, fmt.Sprintf("peers/%s/%s", node.Network, node.ID), data) return publish(host, fmt.Sprintf("peers/host/%s/%s", host.ID.String(), servercfg.GetServer()), data)
} }
// PublishPeerUpdate --- publishes a peer update to all the peers of a node // PublishPeerUpdate --- publishes a peer update to all the peers of a node
func PublishExtPeerUpdate(node *models.Node) error { func PublishExtPeerUpdate(node *models.Node) error {
host, err := logic.GetHost(node.HostID.String())
if err != nil {
return nil
}
if !servercfg.IsMessageQueueBackend() {
return nil
}
peerUpdate, err := logic.GetPeerUpdate(node, host)
if err != nil {
return err
}
data, err := json.Marshal(&peerUpdate)
if err != nil {
return err
}
if host.ProxyEnabled {
proxyUpdate, err := logic.GetPeersForProxy(node, false)
if err == nil {
peerUpdate.ProxyUpdate = proxyUpdate
}
}
if err = publish(node, fmt.Sprintf("peers/%s/%s", node.Network, node.ID), data); err != nil {
return err
}
go PublishPeerUpdate(node.Network, false) go PublishPeerUpdate(node.Network, false)
return nil return nil
} }
@ -126,7 +99,7 @@ func NodeUpdate(node *models.Node) error {
logger.Log(2, "error marshalling node update ", err.Error()) logger.Log(2, "error marshalling node update ", err.Error())
return err return err
} }
if err = publish(node, fmt.Sprintf("update/%s/%s", node.Network, node.ID), data); err != nil { if err = publish(host, fmt.Sprintf("update/%s/%s", node.Network, node.ID), data); err != nil {
logger.Log(2, "error publishing node update to peer ", node.ID.String(), err.Error()) logger.Log(2, "error publishing node update to peer ", node.ID.String(), err.Error())
return err return err
} }
@ -156,7 +129,7 @@ func ProxyUpdate(proxyPayload *proxy_models.ProxyManagerPayload, node *models.No
logger.Log(2, "error marshalling node update ", err.Error()) logger.Log(2, "error marshalling node update ", err.Error())
return err return err
} }
if err = publish(node, fmt.Sprintf("proxy/%s/%s", node.Network, node.ID), data); err != nil { if err = publish(host, fmt.Sprintf("proxy/%s/%s", node.Network, node.ID), data); err != nil {
logger.Log(2, "error publishing proxy update to peer ", node.ID.String(), err.Error()) logger.Log(2, "error publishing proxy update to peer ", node.ID.String(), err.Error())
return err return err
} }
@ -166,7 +139,7 @@ func ProxyUpdate(proxyPayload *proxy_models.ProxyManagerPayload, node *models.No
// sendPeers - retrieve networks, send peer ports to all peers // sendPeers - retrieve networks, send peer ports to all peers
func sendPeers() { func sendPeers() {
networks, err := logic.GetNetworks() hosts, err := logic.GetAllHosts()
if err != nil { if err != nil {
logger.Log(1, "error retrieving networks for keepalive", err.Error()) logger.Log(1, "error retrieving networks for keepalive", err.Error())
} }
@ -191,13 +164,12 @@ func sendPeers() {
//collectServerMetrics(networks[:]) //collectServerMetrics(networks[:])
} }
for _, network := range networks { for _, host := range hosts {
if force { if force {
logger.Log(2, "sending scheduled peer update (5 min)") logger.Log(2, "sending scheduled peer update (5 min)")
err = PublishPeerUpdate(network.NetID, false) err = PublishSingleHostUpdate(&host)
if err != nil { if err != nil {
logger.Log(1, "error publishing udp port updates for network", network.NetID) logger.Log(1, "error publishing peer updates for host: ", host.ID.String(), " Err: ", err.Error())
logger.Log(1, err.Error())
} }
} }
} }

View file

@ -40,7 +40,7 @@ func decryptMsg(node *models.Node, msg []byte) ([]byte, error) {
return ncutils.DeChunk(msg, nodePubTKey, serverPrivTKey) return ncutils.DeChunk(msg, nodePubTKey, serverPrivTKey)
} }
func encryptMsg(node *models.Node, msg []byte) ([]byte, error) { func encryptMsg(host *models.Host, msg []byte) ([]byte, error) {
// fetch server public key to be certain hasn't changed in transit // fetch server public key to be certain hasn't changed in transit
trafficKey, trafficErr := logic.RetrievePrivateTrafficKey() trafficKey, trafficErr := logic.RetrievePrivateTrafficKey()
if trafficErr != nil { if trafficErr != nil {
@ -52,10 +52,6 @@ func encryptMsg(node *models.Node, msg []byte) ([]byte, error) {
return nil, err return nil, err
} }
host, err := logic.GetHost(node.HostID.String())
if err != nil {
return nil, err
}
nodePubKey, err := ncutils.ConvertBytesToKey(host.TrafficKeyPublic) nodePubKey, err := ncutils.ConvertBytesToKey(host.TrafficKeyPublic)
if err != nil { if err != nil {
return nil, err return nil, err
@ -68,8 +64,8 @@ func encryptMsg(node *models.Node, msg []byte) ([]byte, error) {
return ncutils.Chunk(msg, nodePubKey, serverPrivKey) return ncutils.Chunk(msg, nodePubKey, serverPrivKey)
} }
func publish(node *models.Node, dest string, msg []byte) error { func publish(host *models.Host, dest string, msg []byte) error {
encrypted, encryptErr := encryptMsg(node, msg) encrypted, encryptErr := encryptMsg(host, msg)
if encryptErr != nil { if encryptErr != nil {
return encryptErr return encryptErr
} }