From bfd09a1f7535f73ac133cb3ba0d5cf421113c030 Mon Sep 17 00:00:00 2001 From: Matthew R Kasun Date: Wed, 5 Jan 2022 10:05:51 -0500 Subject: [PATCH] subscribed message handlers implemented --- go.mod | 1 + go.sum | 2 + models/mqtt.go | 14 ++++ netclient/functions/daemon.go | 75 +++++++++++++++++++++ netclient/wireguard/common.go | 123 ++++++++++++++++++++++++++++++++++ 5 files changed, 215 insertions(+) create mode 100644 models/mqtt.go diff --git a/go.mod b/go.mod index dcc6b758..b8b169d9 100644 --- a/go.mod +++ b/go.mod @@ -48,4 +48,5 @@ require ( github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect google.golang.org/appengine v1.4.0 // indirect + gopkg.in/ini.v1 v1.66.2 // indirect ) diff --git a/go.sum b/go.sum index dce93b9d..84dbc91f 100644 --- a/go.sum +++ b/go.sum @@ -292,6 +292,8 @@ gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/ini.v1 v1.66.2 h1:XfR1dOYubytKy4Shzc2LHrrGhU0lDCfDGG1yLPmpgsI= +gopkg.in/ini.v1 v1.66.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/models/mqtt.go b/models/mqtt.go new file mode 100644 index 00000000..a7e87e1f --- /dev/null +++ b/models/mqtt.go @@ -0,0 +1,14 @@ +package models + +import "golang.zx2c4.com/wireguard/wgctrl/wgtypes" + +type PeerUpdate struct { + Network string + Interface string + Peers []wgtypes.Peer +} + +type KeyUpdate struct { + Network string + Interface string +} diff --git a/netclient/functions/daemon.go b/netclient/functions/daemon.go index 45a49d9b..fc926bda 100644 --- a/netclient/functions/daemon.go +++ b/netclient/functions/daemon.go @@ -11,9 +11,12 @@ import ( "time" mqtt "github.com/eclipse/paho.mqtt.golang" + "github.com/gravitl/netmaker/models" "github.com/gravitl/netmaker/netclient/config" "github.com/gravitl/netmaker/netclient/ncutils" + "github.com/gravitl/netmaker/netclient/wireguard" "golang.zx2c4.com/wireguard/wgctrl" + "golang.zx2c4.com/wireguard/wgctrl/wgtypes" ) // Daemon runs netclient daemon from command line @@ -81,16 +84,88 @@ var All mqtt.MessageHandler = func(client mqtt.Client, msg mqtt.Message) { // NodeUpdate -- mqtt message handler for /update/ topic var NodeUpdate mqtt.MessageHandler = func(client mqtt.Client, msg mqtt.Message) { ncutils.Log("received message to update node " + string(msg.Payload())) + //potentiall blocking i/o so do this in a go routine + go func() { + var data models.Node + err := json.Unmarshal(msg.Payload(), &data) + if err != nil { + ncutils.Log("error unmarshalling node update data" + err.Error()) + return + } + var cfg config.ClientConfig + cfg.Network = data.Network + cfg.ReadConfig() + nameserver := cfg.Server.CoreDNSAddr + privateKey, err := wireguard.RetrievePrivKey(data.Network) + if err := wireguard.UpdateWgInterface(cfg.Node.Interface, privateKey, nameserver, data); err != nil { + ncutils.Log("error updating wireguard config " + err.Error()) + return + } + // path hardcoded for now... should be updated + err = wireguard.ApplyWGQuickConf("/etc/netclient/config/" + cfg.Node.Interface + ".conf") + if err != nil { + ncutils.Log("error restarting wg after peer update " + err.Error()) + return + } + }() } // UpdatePeers -- mqtt message handler for /update/peers/ topic var UpdatePeers mqtt.MessageHandler = func(client mqtt.Client, msg mqtt.Message) { ncutils.Log("received message to update peers " + string(msg.Payload())) + //potentiall blocking i/o so do this in a go routine + go func() { + var peerUpdate models.PeerUpdate + err := json.Unmarshal(msg.Payload(), &peerUpdate) + if err != nil { + ncutils.Log("error unmarshalling peer data") + return + } + var cfg config.ClientConfig + cfg.Network = peerUpdate.Network + cfg.ReadConfig() + err = wireguard.UpdateWgPeers(cfg.Node.Interface, peerUpdate.Peers) + if err != nil { + ncutils.Log("error updating peers" + err.Error()) + return + } + // path hardcoded for now... should be updated + err = wireguard.ApplyWGQuickConf("/etc/netclient/config/" + cfg.Node.Interface + ".conf") + if err != nil { + ncutils.Log("error restarting wg after peer update " + err.Error()) + return + } + }() } // UpdateKeys -- mqtt message handler for /update/keys/ topic var UpdateKeys mqtt.MessageHandler = func(client mqtt.Client, msg mqtt.Message) { ncutils.Log("received message to update keys " + string(msg.Payload())) + //potentiall blocking i/o so do this in a go routine + go func() { + var data models.KeyUpdate + if err := json.Unmarshal(msg.Payload(), &data); err != nil { + ncutils.Log("error unmarshalling key update data" + err.Error()) + return + } + var cfg config.ClientConfig + cfg.Network = data.Network + cfg.ReadConfig() + key, err := wgtypes.GeneratePrivateKey() + if err != nil { + ncutils.Log("error generating privatekey " + err.Error()) + return + } + if err := wireguard.UpdatePrivateKey(data.Interface, key.String()); err != nil { + ncutils.Log("error updating wireguard key " + err.Error()) + return + } + publicKey := key.PublicKey() + if token := client.Publish("update/publickey/"+cfg.Node.ID, 0, false, publicKey.String()); token.Wait() && token.Error() != nil { + ncutils.Log("error publishing publickey update " + token.Error().Error()) + } + client.Disconnect(250) + }() } // Checkin -- go routine that checks for public or local ip changes, publishes changes diff --git a/netclient/wireguard/common.go b/netclient/wireguard/common.go index e264cab6..b954dee6 100644 --- a/netclient/wireguard/common.go +++ b/netclient/wireguard/common.go @@ -16,6 +16,7 @@ import ( "github.com/gravitl/netmaker/netclient/server" "golang.zx2c4.com/wireguard/wgctrl" "golang.zx2c4.com/wireguard/wgctrl/wgtypes" + "gopkg.in/ini.v1" ) // SetPeers - sets peers on a given WireGuard interface @@ -280,3 +281,125 @@ func ApplyConf(confPath string) error { } return err } + +// WriteWgConfig - creates a wireguard config file +func WriteWgConfig(cfg config.ClientConfig, privateKey string, peers []wgtypes.Peer) error { + options := ini.LoadOptions{ + AllowNonUniqueSections: true, + AllowShadows: true, + } + wireguard := ini.Empty(options) + wireguard.Section("Interface").Key("PrivateKey").SetValue(privateKey) + wireguard.Section("Interface").Key("ListenPort").SetValue(strconv.Itoa(int(cfg.Node.ListenPort))) + if cfg.Node.Address != "" { + wireguard.Section("Interface").Key("Address").SetValue(cfg.Node.Address) + } + if cfg.Node.Address6 != "" { + wireguard.Section("Interface").Key("Address").SetValue(cfg.Node.Address6) + } + if cfg.Node.DNSOn == "yes" { + wireguard.Section("Interface").Key("DNS").SetValue(cfg.Server.CoreDNSAddr) + } + if cfg.Node.PostUp != "" { + wireguard.Section("Interface").Key("PostUp").SetValue(cfg.Node.PostUp) + } + if cfg.Node.PostDown != "" { + wireguard.Section("Interface").Key("PostDown").SetValue(cfg.Node.PostDown) + } + for i, peer := range peers { + wireguard.SectionWithIndex("Peer", i).Key("PublicKey").SetValue(peer.PublicKey.String()) + if peer.PresharedKey.String() != "" { + wireguard.SectionWithIndex("Peer", i).Key("PreSharedKey").SetValue(peer.PresharedKey.String()) + } + if peer.AllowedIPs != nil { + var allowedIPs string + for _, ip := range peer.AllowedIPs { + allowedIPs = allowedIPs + ", " + ip.String() + } + wireguard.SectionWithIndex("Peer", i).Key("AllowedIps").SetValue(allowedIPs) + } + if peer.Endpoint != nil { + wireguard.SectionWithIndex("Peer", i).Key("Endpoint").SetValue(peer.Endpoint.String()) + } + } + if err := wireguard.SaveTo("/etc/netclient/config" + cfg.Node.Interface + ".conf"); err != nil { + return err + } + return nil +} + +// UpdateWgPeers - updates the peers of a network +func UpdateWgPeers(wgInterface string, peers []wgtypes.Peer) error { + //update to get path properly + file := "/etc/netclient/config/" + wgInterface + ".conf" + wireguard, err := ini.ShadowLoad(file) + if err != nil { + return err + } + for i, peer := range peers { + wireguard.SectionWithIndex("Peer", i).Key("PublicKey").SetValue(peer.PublicKey.String()) + if peer.PresharedKey.String() != "" { + wireguard.SectionWithIndex("Peer", i).Key("PreSharedKey").SetValue(peer.PresharedKey.String()) + } + if peer.AllowedIPs != nil { + var allowedIPs string + for _, ip := range peer.AllowedIPs { + allowedIPs = allowedIPs + ", " + ip.String() + } + wireguard.SectionWithIndex("Peer", i).Key("AllowedIps").SetValue(allowedIPs) + } + if peer.Endpoint != nil { + wireguard.SectionWithIndex("Peer", i).Key("Endpoint").SetValue(peer.Endpoint.String()) + } + } + if err := wireguard.SaveTo(file); err != nil { + return err + } + return nil +} + +// UpdateWgInterface - updates the interface section of a wireguard config file +func UpdateWgInterface(wgInterface, privateKey, nameserver string, node models.Node) error { + //update to get path properly + file := "/etc/netclient/config/" + wgInterface + ".conf" + wireguard, err := ini.ShadowLoad(file) + if err != nil { + return err + } + wireguard.Section("Interface").Key("PrivateKey").SetValue(privateKey) + wireguard.Section("Interface").Key("ListenPort").SetValue(strconv.Itoa(int(node.ListenPort))) + if node.Address != "" { + wireguard.Section("Interface").Key("Address").SetValue(node.Address) + } + if node.Address6 != "" { + wireguard.Section("Interface").Key("Address").SetValue(node.Address6) + } + if node.DNSOn == "yes" { + wireguard.Section("Interface").Key("DNS").SetValue(nameserver) + } + if node.PostUp != "" { + wireguard.Section("Interface").Key("PostUp").SetValue(node.PostUp) + } + if node.PostDown != "" { + wireguard.Section("Interface").Key("PostDown").SetValue(node.PostDown) + } + if err := wireguard.SaveTo(file); err != nil { + return err + } + return nil +} + +// UpdatePrivateKey - updates the private key of a wireguard config file +func UpdatePrivateKey(wgInterface, privateKey string) error { + //update to get path properly + file := "/etc/netclient/config/" + wgInterface + ".conf" + wireguard, err := ini.ShadowLoad(file) + if err != nil { + return err + } + wireguard.Section("Interface").Key("PrivateKey").SetValue(privateKey) + if err := wireguard.SaveTo(file); err != nil { + return err + } + return nil +}