2022-02-17 04:40:51 +08:00
|
|
|
package mq
|
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/json"
|
2023-09-28 18:28:19 +08:00
|
|
|
|
2022-02-17 04:40:51 +08:00
|
|
|
mqtt "github.com/eclipse/paho.mqtt.golang"
|
2023-03-04 00:11:02 +08:00
|
|
|
"github.com/google/uuid"
|
2022-02-17 04:40:51 +08:00
|
|
|
"github.com/gravitl/netmaker/database"
|
2023-12-14 02:46:57 +08:00
|
|
|
"github.com/gravitl/netmaker/logger"
|
2022-02-17 04:40:51 +08:00
|
|
|
"github.com/gravitl/netmaker/logic"
|
2023-02-18 00:32:02 +08:00
|
|
|
"github.com/gravitl/netmaker/logic/hostactions"
|
2022-02-17 04:40:51 +08:00
|
|
|
"github.com/gravitl/netmaker/models"
|
2022-02-17 22:08:20 +08:00
|
|
|
"github.com/gravitl/netmaker/netclient/ncutils"
|
2022-09-14 03:25:56 +08:00
|
|
|
"github.com/gravitl/netmaker/servercfg"
|
2023-06-07 01:47:16 +08:00
|
|
|
"golang.org/x/exp/slog"
|
2022-02-17 04:40:51 +08:00
|
|
|
)
|
|
|
|
|
2023-09-01 10:12:05 +08:00
|
|
|
// UpdateMetrics message Handler -- handles updates from client nodes for metrics
|
|
|
|
var UpdateMetrics = func(client mqtt.Client, msg mqtt.Message) {
|
|
|
|
}
|
|
|
|
|
2024-01-16 01:47:36 +08:00
|
|
|
var UpdateMetricsFallBack = func(nodeid string, newMetrics models.Metrics) {}
|
|
|
|
|
2022-05-09 21:49:17 +08:00
|
|
|
// DefaultHandler default message queue handler -- NOT USED
|
2022-02-17 04:40:51 +08:00
|
|
|
func DefaultHandler(client mqtt.Client, msg mqtt.Message) {
|
2023-06-07 01:47:16 +08:00
|
|
|
slog.Info("mqtt default handler", "topic", msg.Topic(), "message", msg.Payload())
|
2022-02-17 04:40:51 +08:00
|
|
|
}
|
|
|
|
|
2023-03-01 23:39:11 +08:00
|
|
|
// UpdateNode message Handler -- handles updates from client nodes
|
|
|
|
func UpdateNode(client mqtt.Client, msg mqtt.Message) {
|
2023-09-01 10:12:05 +08:00
|
|
|
id, err := GetID(msg.Topic())
|
2023-03-01 23:39:11 +08:00
|
|
|
if err != nil {
|
2023-06-07 01:47:16 +08:00
|
|
|
slog.Error("error getting node.ID ", "topic", msg.Topic(), "error", err)
|
2023-03-01 23:39:11 +08:00
|
|
|
return
|
|
|
|
}
|
|
|
|
currentNode, err := logic.GetNodeByID(id)
|
|
|
|
if err != nil {
|
2023-06-07 01:47:16 +08:00
|
|
|
slog.Error("error getting node", "id", id, "error", err)
|
2023-03-01 23:39:11 +08:00
|
|
|
return
|
|
|
|
}
|
2023-09-01 10:12:05 +08:00
|
|
|
decrypted, decryptErr := DecryptMsg(¤tNode, msg.Payload())
|
2023-03-01 23:39:11 +08:00
|
|
|
if decryptErr != nil {
|
2023-06-07 01:47:16 +08:00
|
|
|
slog.Error("failed to decrypt message for node", "id", id, "error", decryptErr)
|
2023-03-01 23:39:11 +08:00
|
|
|
return
|
|
|
|
}
|
|
|
|
var newNode models.Node
|
|
|
|
if err := json.Unmarshal(decrypted, &newNode); err != nil {
|
2023-06-07 01:47:16 +08:00
|
|
|
slog.Error("error unmarshaling payload", "error", err)
|
2023-03-01 23:39:11 +08:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
ifaceDelta := logic.IfaceDelta(¤tNode, &newNode)
|
|
|
|
newNode.SetLastCheckIn()
|
|
|
|
if err := logic.UpdateNode(¤tNode, &newNode); err != nil {
|
2023-06-07 01:47:16 +08:00
|
|
|
slog.Error("error saving node", "id", id, "error", err)
|
2023-03-01 23:39:11 +08:00
|
|
|
return
|
|
|
|
}
|
|
|
|
if ifaceDelta { // reduce number of unneeded updates, by only sending on iface changes
|
2023-11-15 23:53:52 +08:00
|
|
|
if !newNode.Connected {
|
|
|
|
err = PublishDeletedNodePeerUpdate(&newNode)
|
|
|
|
host, err := logic.GetHost(newNode.HostID.String())
|
|
|
|
if err != nil {
|
|
|
|
slog.Error("failed to get host for the node", "nodeid", newNode.ID.String(), "error", err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
allNodes, err := logic.GetAllNodes()
|
|
|
|
if err == nil {
|
2024-01-11 18:29:19 +08:00
|
|
|
PublishSingleHostPeerUpdate(host, allNodes, nil, nil, false)
|
2023-11-15 23:53:52 +08:00
|
|
|
}
|
|
|
|
} else {
|
2024-01-11 18:29:19 +08:00
|
|
|
err = PublishPeerUpdate(false)
|
2023-11-15 23:53:52 +08:00
|
|
|
}
|
|
|
|
if err != nil {
|
2023-06-07 01:47:16 +08:00
|
|
|
slog.Warn("error updating peers when node informed the server of an interface change", "nodeid", currentNode.ID, "error", err)
|
2023-03-01 23:39:11 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-06-07 01:47:16 +08:00
|
|
|
slog.Info("updated node", "id", id, "newnodeid", newNode.ID)
|
2023-03-01 23:39:11 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// UpdateHost message Handler -- handles host updates from clients
|
|
|
|
func UpdateHost(client mqtt.Client, msg mqtt.Message) {
|
2023-09-01 10:12:05 +08:00
|
|
|
id, err := GetID(msg.Topic())
|
2023-03-01 23:39:11 +08:00
|
|
|
if err != nil {
|
2023-06-07 01:47:16 +08:00
|
|
|
slog.Error("error getting host.ID sent on ", "topic", msg.Topic(), "error", err)
|
2023-03-01 23:39:11 +08:00
|
|
|
return
|
|
|
|
}
|
|
|
|
currentHost, err := logic.GetHost(id)
|
|
|
|
if err != nil {
|
2023-06-07 01:47:16 +08:00
|
|
|
slog.Error("error getting host", "id", id, "error", err)
|
2023-03-01 23:39:11 +08:00
|
|
|
return
|
|
|
|
}
|
|
|
|
decrypted, decryptErr := decryptMsgWithHost(currentHost, msg.Payload())
|
|
|
|
if decryptErr != nil {
|
2024-04-11 23:48:57 +08:00
|
|
|
slog.Error("failed to decrypt message for host", "id", id, "name", currentHost.Name, "error", decryptErr)
|
2023-03-01 23:39:11 +08:00
|
|
|
return
|
|
|
|
}
|
|
|
|
var hostUpdate models.HostUpdate
|
|
|
|
if err := json.Unmarshal(decrypted, &hostUpdate); err != nil {
|
2023-06-07 01:47:16 +08:00
|
|
|
slog.Error("error unmarshaling payload", "error", err)
|
2023-03-01 23:39:11 +08:00
|
|
|
return
|
|
|
|
}
|
2023-06-07 01:47:16 +08:00
|
|
|
slog.Info("recieved host update", "name", hostUpdate.Host.Name, "id", hostUpdate.Host.ID)
|
2023-03-01 23:39:11 +08:00
|
|
|
var sendPeerUpdate bool
|
2024-01-11 18:29:19 +08:00
|
|
|
var replacePeers bool
|
2023-03-01 23:39:11 +08:00
|
|
|
switch hostUpdate.Action {
|
2023-03-18 03:58:06 +08:00
|
|
|
case models.CheckIn:
|
2023-12-21 14:43:06 +08:00
|
|
|
sendPeerUpdate = HandleHostCheckin(&hostUpdate.Host, currentHost)
|
2023-03-01 23:39:11 +08:00
|
|
|
case models.Acknowledgement:
|
|
|
|
hu := hostactions.GetAction(currentHost.ID.String())
|
|
|
|
if hu != nil {
|
|
|
|
if err = HostUpdate(hu); err != nil {
|
2023-06-07 01:47:16 +08:00
|
|
|
slog.Error("failed to send new node to host", "name", hostUpdate.Host.Name, "id", currentHost.ID, "error", err)
|
2022-02-17 04:40:51 +08:00
|
|
|
return
|
2023-03-01 23:39:11 +08:00
|
|
|
} else {
|
2023-03-21 20:25:51 +08:00
|
|
|
if servercfg.GetBrokerType() == servercfg.EmqxBrokerType {
|
2024-01-25 17:41:16 +08:00
|
|
|
if err = emqx.AppendNodeUpdateACL(hu.Host.ID.String(), hu.Node.Network, hu.Node.ID.String(), servercfg.GetServer()); err != nil {
|
2023-06-07 01:47:16 +08:00
|
|
|
slog.Error("failed to add ACLs for EMQX node", "error", err)
|
2023-03-21 20:25:51 +08:00
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
2023-06-28 23:35:21 +08:00
|
|
|
nodes, err := logic.GetAllNodes()
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
2024-01-11 18:29:19 +08:00
|
|
|
if err = PublishSingleHostPeerUpdate(currentHost, nodes, nil, nil, false); err != nil {
|
2023-06-07 01:47:16 +08:00
|
|
|
slog.Error("failed peers publish after join acknowledged", "name", hostUpdate.Host.Name, "id", currentHost.ID, "error", err)
|
2023-03-01 23:39:11 +08:00
|
|
|
return
|
|
|
|
}
|
2022-02-17 04:40:51 +08:00
|
|
|
}
|
|
|
|
}
|
2023-03-01 23:39:11 +08:00
|
|
|
case models.UpdateHost:
|
2023-04-18 06:20:09 +08:00
|
|
|
if hostUpdate.Host.PublicKey != currentHost.PublicKey {
|
|
|
|
//remove old peer entry
|
2024-01-11 18:29:19 +08:00
|
|
|
replacePeers = true
|
2023-04-18 06:20:09 +08:00
|
|
|
}
|
2023-03-01 23:39:11 +08:00
|
|
|
sendPeerUpdate = logic.UpdateHostFromClient(&hostUpdate.Host, currentHost)
|
|
|
|
err := logic.UpsertHost(currentHost)
|
|
|
|
if err != nil {
|
2023-06-07 01:47:16 +08:00
|
|
|
slog.Error("failed to update host", "id", currentHost.ID, "error", err)
|
2022-02-17 04:40:51 +08:00
|
|
|
return
|
|
|
|
}
|
2023-03-01 23:39:11 +08:00
|
|
|
case models.DeleteHost:
|
|
|
|
if servercfg.GetBrokerType() == servercfg.EmqxBrokerType {
|
|
|
|
// delete EMQX credentials for host
|
2024-01-25 17:41:16 +08:00
|
|
|
if err := emqx.DeleteEmqxUser(currentHost.ID.String()); err != nil {
|
2023-06-07 01:47:16 +08:00
|
|
|
slog.Error("failed to remove host credentials from EMQX", "id", currentHost.ID, "error", err)
|
2023-03-01 23:39:11 +08:00
|
|
|
}
|
2022-09-08 18:19:10 +08:00
|
|
|
}
|
2023-11-10 15:37:38 +08:00
|
|
|
|
|
|
|
// notify of deleted peer change
|
|
|
|
go func(host models.Host) {
|
|
|
|
for _, nodeID := range host.Nodes {
|
|
|
|
node, err := logic.GetNodeByID(nodeID)
|
|
|
|
if err == nil {
|
|
|
|
var gwClients []models.ExtClient
|
|
|
|
if node.IsIngressGateway {
|
|
|
|
gwClients = logic.GetGwExtclients(node.ID.String(), node.Network)
|
|
|
|
}
|
|
|
|
go PublishMqUpdatesForDeletedNode(node, false, gwClients)
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}(*currentHost)
|
|
|
|
|
2023-03-01 23:39:11 +08:00
|
|
|
if err := logic.DisassociateAllNodesFromHost(currentHost.ID.String()); err != nil {
|
2023-06-07 01:47:16 +08:00
|
|
|
slog.Error("failed to delete all nodes of host", "id", currentHost.ID, "error", err)
|
2022-12-21 04:29:09 +08:00
|
|
|
return
|
|
|
|
}
|
2023-03-01 23:39:11 +08:00
|
|
|
if err := logic.RemoveHostByID(currentHost.ID.String()); err != nil {
|
2023-06-07 01:47:16 +08:00
|
|
|
slog.Error("failed to delete host", "id", currentHost.ID, "error", err)
|
2022-02-17 04:40:51 +08:00
|
|
|
return
|
|
|
|
}
|
2023-12-20 14:24:53 +08:00
|
|
|
if servercfg.IsDNSMode() {
|
|
|
|
logic.SetDNS()
|
|
|
|
}
|
2023-03-01 23:39:11 +08:00
|
|
|
sendPeerUpdate = true
|
2023-12-14 02:46:57 +08:00
|
|
|
case models.SignalHost:
|
|
|
|
signalPeer(hostUpdate.Signal)
|
2023-04-28 16:36:28 +08:00
|
|
|
|
2023-03-01 23:39:11 +08:00
|
|
|
}
|
2022-03-29 05:26:03 +08:00
|
|
|
|
2023-03-01 23:39:11 +08:00
|
|
|
if sendPeerUpdate {
|
2024-01-11 18:29:19 +08:00
|
|
|
err := PublishPeerUpdate(replacePeers)
|
2023-03-01 23:39:11 +08:00
|
|
|
if err != nil {
|
2023-06-07 01:47:16 +08:00
|
|
|
slog.Error("failed to publish peer update", "error", err)
|
2023-03-01 23:39:11 +08:00
|
|
|
}
|
|
|
|
}
|
2022-09-14 03:25:56 +08:00
|
|
|
}
|
|
|
|
|
2023-12-14 02:46:57 +08:00
|
|
|
func signalPeer(signal models.Signal) {
|
|
|
|
|
|
|
|
if signal.ToHostPubKey == "" {
|
|
|
|
msg := "insufficient data to signal peer"
|
|
|
|
logger.Log(0, msg)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
signal.IsPro = servercfg.IsPro
|
|
|
|
peerHost, err := logic.GetHost(signal.ToHostID)
|
|
|
|
if err != nil {
|
2024-04-12 20:52:03 +08:00
|
|
|
slog.Error("failed to signal, peer host not found", "error", err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
peerNode, err := logic.GetNodeByID(signal.ToNodeID)
|
|
|
|
if err != nil {
|
|
|
|
slog.Error("failed to signal, node not found", "error", err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
node, err := logic.GetNodeByID(signal.FromNodeID)
|
|
|
|
if err != nil {
|
|
|
|
slog.Error("failed to signal, peer node not found", "error", err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if peerNode.IsIngressGateway || node.IsIngressGateway || peerNode.IsInternetGateway || node.IsInternetGateway {
|
|
|
|
signal.Action = ""
|
2023-12-14 02:46:57 +08:00
|
|
|
return
|
|
|
|
}
|
|
|
|
err = HostUpdate(&models.HostUpdate{
|
|
|
|
Action: models.SignalHost,
|
|
|
|
Host: *peerHost,
|
|
|
|
Signal: signal,
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
slog.Error("failed to publish signal to peer", "error", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-02-17 04:40:51 +08:00
|
|
|
// ClientPeerUpdate message handler -- handles updating peers after signal from client nodes
|
|
|
|
func ClientPeerUpdate(client mqtt.Client, msg mqtt.Message) {
|
2023-09-01 10:12:05 +08:00
|
|
|
id, err := GetID(msg.Topic())
|
2023-03-01 23:39:11 +08:00
|
|
|
if err != nil {
|
2023-06-07 01:47:16 +08:00
|
|
|
slog.Error("error getting node.ID sent on ", "topic", msg.Topic(), "error", err)
|
2023-03-01 23:39:11 +08:00
|
|
|
return
|
|
|
|
}
|
|
|
|
currentNode, err := logic.GetNodeByID(id)
|
|
|
|
if err != nil {
|
2023-06-07 01:47:16 +08:00
|
|
|
slog.Error("error getting node", "id", id, "error", err)
|
2023-03-01 23:39:11 +08:00
|
|
|
return
|
|
|
|
}
|
2023-09-01 10:12:05 +08:00
|
|
|
decrypted, decryptErr := DecryptMsg(¤tNode, msg.Payload())
|
2023-03-01 23:39:11 +08:00
|
|
|
if decryptErr != nil {
|
2023-06-07 01:47:16 +08:00
|
|
|
slog.Error("failed to decrypt message for node", "id", id, "error", decryptErr)
|
2023-03-01 23:39:11 +08:00
|
|
|
return
|
|
|
|
}
|
|
|
|
switch decrypted[0] {
|
|
|
|
case ncutils.ACK:
|
|
|
|
// do we still need this
|
|
|
|
case ncutils.DONE:
|
2024-01-11 18:29:19 +08:00
|
|
|
if err = PublishPeerUpdate(false); err != nil {
|
2023-06-07 01:47:16 +08:00
|
|
|
slog.Error("error publishing peer update for node", "id", currentNode.ID, "error", err)
|
2022-02-17 04:40:51 +08:00
|
|
|
return
|
|
|
|
}
|
2022-05-12 21:18:33 +08:00
|
|
|
}
|
2023-03-01 23:39:11 +08:00
|
|
|
|
2023-06-07 01:47:16 +08:00
|
|
|
slog.Info("sent peer updates after signal received from", "id", id)
|
2022-05-12 21:18:33 +08:00
|
|
|
}
|
2022-09-14 03:25:56 +08:00
|
|
|
|
2023-12-21 14:43:06 +08:00
|
|
|
func HandleHostCheckin(h, currentHost *models.Host) bool {
|
2023-03-18 03:58:06 +08:00
|
|
|
if h == nil {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
for i := range currentHost.Nodes {
|
|
|
|
currNodeID := currentHost.Nodes[i]
|
|
|
|
node, err := logic.GetNodeByID(currNodeID)
|
|
|
|
if err != nil {
|
|
|
|
if database.IsEmptyRecord(err) {
|
|
|
|
fakeNode := models.Node{}
|
|
|
|
fakeNode.ID, _ = uuid.Parse(currNodeID)
|
|
|
|
fakeNode.Action = models.NODE_DELETE
|
|
|
|
fakeNode.PendingDelete = true
|
|
|
|
if err := NodeUpdate(&fakeNode); err != nil {
|
2023-06-07 01:47:16 +08:00
|
|
|
slog.Warn("failed to inform host to remove node", "host", currentHost.Name, "hostid", currentHost.ID, "nodeid", currNodeID, "error", err)
|
2023-03-18 03:58:06 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
continue
|
|
|
|
}
|
2023-03-22 05:47:15 +08:00
|
|
|
if err := logic.UpdateNodeCheckin(&node); err != nil {
|
2023-06-07 01:47:16 +08:00
|
|
|
slog.Warn("failed to update node on checkin", "nodeid", node.ID, "error", err)
|
2023-03-18 03:58:06 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for i := range h.Interfaces {
|
|
|
|
h.Interfaces[i].AddressString = h.Interfaces[i].Address.String()
|
|
|
|
}
|
2023-05-31 11:40:05 +08:00
|
|
|
/// version or firewall in use change does not require a peerUpdate
|
|
|
|
if h.Version != currentHost.Version || h.FirewallInUse != currentHost.FirewallInUse {
|
|
|
|
currentHost.FirewallInUse = h.FirewallInUse
|
|
|
|
currentHost.Version = h.Version
|
|
|
|
if err := logic.UpsertHost(currentHost); err != nil {
|
2023-06-07 01:47:16 +08:00
|
|
|
slog.Error("failed to update host after check-in", "name", h.Name, "id", h.ID, "error", err)
|
2023-05-31 11:40:05 +08:00
|
|
|
return false
|
|
|
|
}
|
|
|
|
}
|
2023-03-24 03:37:11 +08:00
|
|
|
ifaceDelta := len(h.Interfaces) != len(currentHost.Interfaces) ||
|
|
|
|
!h.EndpointIP.Equal(currentHost.EndpointIP) ||
|
|
|
|
(len(h.NatType) > 0 && h.NatType != currentHost.NatType) ||
|
2023-06-29 00:40:25 +08:00
|
|
|
h.DefaultInterface != currentHost.DefaultInterface ||
|
2024-04-11 20:07:45 +08:00
|
|
|
(h.ListenPort != 0 && h.ListenPort != currentHost.ListenPort) ||
|
|
|
|
(h.WgPublicListenPort != 0 && h.WgPublicListenPort != currentHost.WgPublicListenPort) || (!h.EndpointIPv6.Equal(currentHost.EndpointIPv6))
|
2023-03-24 03:37:11 +08:00
|
|
|
if ifaceDelta { // only save if something changes
|
|
|
|
currentHost.EndpointIP = h.EndpointIP
|
2024-04-11 20:07:45 +08:00
|
|
|
currentHost.EndpointIPv6 = h.EndpointIPv6
|
2023-03-24 03:37:11 +08:00
|
|
|
currentHost.Interfaces = h.Interfaces
|
|
|
|
currentHost.DefaultInterface = h.DefaultInterface
|
|
|
|
currentHost.NatType = h.NatType
|
2023-06-29 00:40:25 +08:00
|
|
|
if h.ListenPort != 0 {
|
|
|
|
currentHost.ListenPort = h.ListenPort
|
|
|
|
}
|
|
|
|
if h.WgPublicListenPort != 0 {
|
|
|
|
currentHost.WgPublicListenPort = h.WgPublicListenPort
|
|
|
|
}
|
2023-03-24 03:37:11 +08:00
|
|
|
if err := logic.UpsertHost(currentHost); err != nil {
|
2023-06-07 01:47:16 +08:00
|
|
|
slog.Error("failed to update host after check-in", "name", h.Name, "id", h.ID, "error", err)
|
2023-03-24 03:37:11 +08:00
|
|
|
return false
|
|
|
|
}
|
2023-06-07 01:47:16 +08:00
|
|
|
slog.Info("updated host after check-in", "name", currentHost.Name, "id", currentHost.ID)
|
2023-03-18 03:58:06 +08:00
|
|
|
}
|
|
|
|
|
2023-06-07 01:47:16 +08:00
|
|
|
slog.Info("check-in processed for host", "name", h.Name, "id", h.ID)
|
2023-03-22 05:47:15 +08:00
|
|
|
return ifaceDelta
|
2023-03-18 03:58:06 +08:00
|
|
|
}
|