From c40f7510b8a33db77cc845fb0dd3f9df56147c67 Mon Sep 17 00:00:00 2001 From: Tim Beatham Date: Mon, 4 Dec 2023 17:32:50 +0000 Subject: [PATCH 1/3] 41-bugfix-fluctuating-ips IPs of clients fluctuating because there isn't a strict order on clients. Client's need to be processed before the peers. --- pkg/mesh/config.go | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/pkg/mesh/config.go b/pkg/mesh/config.go index 1717eeb..c82da4e 100644 --- a/pkg/mesh/config.go +++ b/pkg/mesh/config.go @@ -4,6 +4,7 @@ import ( "fmt" "net" "slices" + "strings" "time" "github.com/tim-beatham/wgmesh/pkg/conf" @@ -52,7 +53,7 @@ func (m *WgMeshConfigApplyer) convertMeshNode(node MeshNode, device *wgtypes.Dev allowedips := make([]net.IPNet, 1) allowedips[0] = *node.GetWgHost() - clients, ok := peerToClients[node.GetWgHost().String()] + clients, ok := peerToClients[pubKey.String()] if ok { allowedips = append(allowedips, clients...) @@ -162,12 +163,21 @@ func (m *WgMeshConfigApplyer) updateWgConf(mesh MeshProvider) error { } nodes := lib.MapValues(snap.GetNodes()) + + slices.SortFunc(nodes, func(a, b MeshNode) int { + return strings.Compare(string(a.GetType()), string(b.GetType())) + }) + peerConfigs := make([]wgtypes.PeerConfig, len(nodes)) peers := lib.Filter(nodes, func(mn MeshNode) bool { return mn.GetType() == conf.PEER_ROLE }) + clients := lib.Filter(nodes, func(mn MeshNode) bool { + return mn.GetType() == conf.CLIENT_ROLE + }) + var count int = 0 self, err := m.meshManager.GetSelf(mesh.GetMeshId()) @@ -182,12 +192,12 @@ func (m *WgMeshConfigApplyer) updateWgConf(mesh MeshProvider) error { dev, _ := mesh.GetDevice() - for _, n := range nodes { + for _, n := range clients { if NodeEquals(n, self) { continue } - if n.GetType() == conf.CLIENT_ROLE && len(peers) > 0 && self.GetType() == conf.CLIENT_ROLE { + if len(peers) > 0 && self.GetType() == conf.CLIENT_ROLE { hashFunc := func(mn MeshNode) int { pubKey, _ := mn.GetPublicKey() return lib.HashString(pubKey.String()) @@ -195,17 +205,20 @@ func (m *WgMeshConfigApplyer) updateWgConf(mesh MeshProvider) error { peer := lib.ConsistentHash(peers, n, hashFunc, hashFunc) - clients, ok := peerToClients[peer.GetWgHost().String()] + pubKey, _ := peer.GetPublicKey() + + clients, ok := peerToClients[pubKey.String()] if !ok { clients = make([]net.IPNet, 0) - peerToClients[peer.GetWgHost().String()] = clients + peerToClients[pubKey.String()] = clients } - peerToClients[peer.GetWgHost().String()] = append(clients, *n.GetWgHost()) - continue + peerToClients[pubKey.String()] = append(clients, *n.GetWgHost()) } + } + for _, n := range peers { peer, err := m.convertMeshNode(n, dev, peerToClients, routes) if err != nil { From 245a2c5f588efc7492f4351d9124a41e2d0da84d Mon Sep 17 00:00:00 2001 From: Tim Beatham Date: Mon, 4 Dec 2023 17:40:24 +0000 Subject: [PATCH 2/3] 41-bugfix-fluctuating-ips If the node is a peer then add the client in the WG configuration. --- pkg/mesh/config.go | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/pkg/mesh/config.go b/pkg/mesh/config.go index c82da4e..328bacb 100644 --- a/pkg/mesh/config.go +++ b/pkg/mesh/config.go @@ -197,7 +197,17 @@ func (m *WgMeshConfigApplyer) updateWgConf(mesh MeshProvider) error { continue } - if len(peers) > 0 && self.GetType() == conf.CLIENT_ROLE { + if self.GetType() == conf.PEER_ROLE { + client, err := m.convertMeshNode(n, dev, peerToClients, routes) + + if err != nil { + return err + } + + peerConfigs[count] = *client + count++ + + } else if len(peers) > 0 && self.GetType() == conf.CLIENT_ROLE { hashFunc := func(mn MeshNode) int { pubKey, _ := mn.GetPublicKey() return lib.HashString(pubKey.String()) @@ -219,6 +229,10 @@ func (m *WgMeshConfigApplyer) updateWgConf(mesh MeshProvider) error { } for _, n := range peers { + if NodeEquals(n, self) { + continue + } + peer, err := m.convertMeshNode(n, dev, peerToClients, routes) if err != nil { From 1b18d89c9f04e3826e15f148f06d750c5a56bbcc Mon Sep 17 00:00:00 2001 From: Tim Beatham Date: Tue, 5 Dec 2023 02:00:16 +0000 Subject: [PATCH 3/3] 41-bugfix-fluctuating-ips Fluctuating ips creating hub and spoke. --- pkg/mesh/config.go | 166 ++++++++++++++++++++++++++++++--------------- 1 file changed, 112 insertions(+), 54 deletions(-) diff --git a/pkg/mesh/config.go b/pkg/mesh/config.go index 328bacb..f156259 100644 --- a/pkg/mesh/config.go +++ b/pkg/mesh/config.go @@ -155,68 +155,70 @@ func (m *WgMeshConfigApplyer) getRoutes(meshProvider MeshProvider) map[string][] return routes } -func (m *WgMeshConfigApplyer) updateWgConf(mesh MeshProvider) error { - snap, err := mesh.GetMesh() - - if err != nil { - return err +// getCorrespondignPeer: gets the peer corresponding to the client +func (m *WgMeshConfigApplyer) getCorrespondingPeer(peers []MeshNode, client MeshNode) MeshNode { + hashFunc := func(mn MeshNode) int { + pubKey, _ := mn.GetPublicKey() + return lib.HashString(pubKey.String()) } - nodes := lib.MapValues(snap.GetNodes()) - - slices.SortFunc(nodes, func(a, b MeshNode) int { - return strings.Compare(string(a.GetType()), string(b.GetType())) - }) - - peerConfigs := make([]wgtypes.PeerConfig, len(nodes)) - - peers := lib.Filter(nodes, func(mn MeshNode) bool { - return mn.GetType() == conf.PEER_ROLE - }) - - clients := lib.Filter(nodes, func(mn MeshNode) bool { - return mn.GetType() == conf.CLIENT_ROLE - }) - - var count int = 0 + peer := lib.ConsistentHash(peers, client, hashFunc, hashFunc) + return peer +} +func (m *WgMeshConfigApplyer) getClientConfig(mesh MeshProvider, peers []MeshNode, clients []MeshNode) (*wgtypes.Config, error) { self, err := m.meshManager.GetSelf(mesh.GetMeshId()) if err != nil { - return err + return nil, err } + peer := m.getCorrespondingPeer(peers, self) + + pubKey, _ := peer.GetPublicKey() + + keepAlive := time.Duration(m.config.KeepAliveWg) * time.Second + endpoint, err := net.ResolveUDPAddr("udp", peer.GetWgEndpoint()) + + if err != nil { + return nil, err + } + + allowedips := make([]net.IPNet, 1) + _, ipnet, _ := net.ParseCIDR("::/0") + allowedips[0] = *ipnet + + peerCfgs := make([]wgtypes.PeerConfig, 1) + + peerCfgs[0] = wgtypes.PeerConfig{ + PublicKey: pubKey, + Endpoint: endpoint, + PersistentKeepaliveInterval: &keepAlive, + AllowedIPs: allowedips, + } + + cfg := wgtypes.Config{ + Peers: peerCfgs, + } + + return &cfg, err +} + +func (m *WgMeshConfigApplyer) getPeerConfig(mesh MeshProvider, peers []MeshNode, clients []MeshNode, dev *wgtypes.Device) (*wgtypes.Config, error) { peerToClients := make(map[string][]net.IPNet) routes := m.getRoutes(mesh) installedRoutes := make([]lib.Route, 0) + peerConfigs := make([]wgtypes.PeerConfig, 0) + self, err := m.meshManager.GetSelf(mesh.GetMeshId()) - dev, _ := mesh.GetDevice() + if err != nil { + return nil, err + } for _, n := range clients { - if NodeEquals(n, self) { - continue - } - - if self.GetType() == conf.PEER_ROLE { - client, err := m.convertMeshNode(n, dev, peerToClients, routes) - - if err != nil { - return err - } - - peerConfigs[count] = *client - count++ - - } else if len(peers) > 0 && self.GetType() == conf.CLIENT_ROLE { - hashFunc := func(mn MeshNode) int { - pubKey, _ := mn.GetPublicKey() - return lib.HashString(pubKey.String()) - } - - peer := lib.ConsistentHash(peers, n, hashFunc, hashFunc) - + if len(peers) > 0 { + peer := m.getCorrespondingPeer(peers, n) pubKey, _ := peer.GetPublicKey() - clients, ok := peerToClients[pubKey.String()] if !ok { @@ -225,6 +227,16 @@ func (m *WgMeshConfigApplyer) updateWgConf(mesh MeshProvider) error { } peerToClients[pubKey.String()] = append(clients, *n.GetWgHost()) + + if NodeEquals(self, peer) { + cfg, err := m.convertMeshNode(n, dev, peerToClients, routes) + + if err != nil { + return nil, err + } + + peerConfigs = append(peerConfigs, *cfg) + } } } @@ -236,7 +248,7 @@ func (m *WgMeshConfigApplyer) updateWgConf(mesh MeshProvider) error { peer, err := m.convertMeshNode(n, dev, peerToClients, routes) if err != nil { - return err + return nil, err } for _, route := range peer.AllowedIPs { @@ -251,21 +263,66 @@ func (m *WgMeshConfigApplyer) updateWgConf(mesh MeshProvider) error { } } - peerConfigs[count] = *peer - count++ + peerConfigs = append(peerConfigs, *peer) } cfg := wgtypes.Config{ - Peers: peerConfigs, + Peers: peerConfigs, + ReplacePeers: true, } - err = m.meshManager.GetClient().ConfigureDevice(dev.Name, cfg) + err = m.routeInstaller.InstallRoutes(dev.Name, installedRoutes...) + return &cfg, err +} + +func (m *WgMeshConfigApplyer) updateWgConf(mesh MeshProvider) error { + snap, err := mesh.GetMesh() if err != nil { return err } - return m.routeInstaller.InstallRoutes(dev.Name, installedRoutes...) + nodes := lib.MapValues(snap.GetNodes()) + dev, _ := mesh.GetDevice() + + slices.SortFunc(nodes, func(a, b MeshNode) int { + return strings.Compare(string(a.GetType()), string(b.GetType())) + }) + + peers := lib.Filter(nodes, func(mn MeshNode) bool { + return mn.GetType() == conf.PEER_ROLE + }) + + clients := lib.Filter(nodes, func(mn MeshNode) bool { + return mn.GetType() == conf.CLIENT_ROLE + }) + + self, err := m.meshManager.GetSelf(mesh.GetMeshId()) + + if err != nil { + return err + } + + var cfg *wgtypes.Config = nil + + switch self.GetType() { + case conf.PEER_ROLE: + cfg, err = m.getPeerConfig(mesh, peers, clients, dev) + case conf.CLIENT_ROLE: + cfg, err = m.getClientConfig(mesh, peers, clients) + } + + if err != nil { + return err + } + + err = m.meshManager.GetClient().ConfigureDevice(dev.Name, *cfg) + + if err != nil { + return err + } + + return nil } func (m *WgMeshConfigApplyer) ApplyConfig() error { @@ -294,7 +351,8 @@ func (m *WgMeshConfigApplyer) RemovePeers(meshId string) error { } m.meshManager.GetClient().ConfigureDevice(dev.Name, wgtypes.Config{ - Peers: make([]wgtypes.PeerConfig, 0), + Peers: make([]wgtypes.PeerConfig, 0), + ReplacePeers: true, }) return nil