Skip to content

Commit babace5

Browse files
committed
Handle discovered Endpoints in topology to enable NAT 2 NAT
1 parent 2b2437b commit babace5

3 files changed

Lines changed: 273 additions & 220 deletions

File tree

pkg/mesh/mesh.go

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -389,6 +389,7 @@ func (m *Mesh) handleLocal(n *Node) {
389389
PersistentKeepalive: n.PersistentKeepalive,
390390
Subnet: n.Subnet,
391391
WireGuardIP: m.wireGuardIP,
392+
DiscoveredEndpoints: n.DiscoveredEndpoints,
392393
}
393394
if !nodesAreEqual(n, local) {
394395
level.Debug(m.logger).Log("msg", "local node differs from backend")
@@ -469,7 +470,7 @@ func (m *Mesh) applyTopology() {
469470
return
470471
}
471472
oldConf := wireguard.Parse(oldConfRaw)
472-
natEndpoints := updateNATEndpoints(nodes, peers, oldConf, m.logger)
473+
natEndpoints := discoverNATEndpoints(nodes, peers, oldConf, m.logger)
473474
nodes[m.hostname].DiscoveredEndpoints = natEndpoints
474475
m.nodes[m.hostname].DiscoveredEndpoints = natEndpoints
475476
t, err := NewTopology(nodes, peers, m.granularity, m.hostname, nodes[m.hostname].Endpoint.Port, m.priv, m.subnet, nodes[m.hostname].PersistentKeepalive)
@@ -792,9 +793,8 @@ func linkByIndex(index int) (netlink.Link, error) {
792793
return link, nil
793794
}
794795

795-
// updateNATEndpoints ensures that nodes and peers behind NAT update
796-
// their endpoints from the WireGuard configuration so they can roam.
797-
func updateNATEndpoints(nodes map[string]*Node, peers map[string]*Peer, conf *wireguard.Conf, logger log.Logger) map[string]*wireguard.Endpoint {
796+
// discoverNATEndpoints uses the node's WireGuard configuration to returns a list of the most recently discovered endpoints for all nodes and peers behind NAT so that they can roam.
797+
func discoverNATEndpoints(nodes map[string]*Node, peers map[string]*Peer, conf *wireguard.Conf, logger log.Logger) map[string]*wireguard.Endpoint {
798798
natEndpoints := make(map[string]*wireguard.Endpoint)
799799
keys := make(map[string]*wireguard.Peer)
800800
for i := range conf.Peers {
@@ -808,15 +808,13 @@ func updateNATEndpoints(nodes map[string]*Node, peers map[string]*Peer, conf *wi
808808
if !n.Endpoint.Equal(peer.Endpoint) {
809809
natEndpoints[string(n.Key)] = peer.Endpoint
810810
}
811-
n.Endpoint = peer.Endpoint
812811
}
813812
}
814813
for _, p := range peers {
815814
if peer, ok := keys[string(p.PublicKey)]; ok && p.PersistentKeepalive > 0 {
816815
if !p.Endpoint.Equal(peer.Endpoint) {
817816
natEndpoints[string(p.PublicKey)] = peer.Endpoint
818817
}
819-
p.Endpoint = peer.Endpoint
820818
}
821819
}
822820
level.Debug(logger).Log("msg", "Discovered WireGuard NAT Endpoints", "DiscoveredEndpoints", natEndpoints)

pkg/mesh/topology.go

Lines changed: 44 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -55,12 +55,15 @@ type Topology struct {
5555
// the IP is the 0th address in the subnet, i.e. the CIDR
5656
// is equal to the Kilo subnet.
5757
wireGuardCIDR *net.IPNet
58+
// discoveredEndpoints is the updated map of valid discovered Endpoints
59+
discoveredEndpoints map[string]*wireguard.Endpoint
5860
}
5961

6062
type segment struct {
61-
allowedIPs []*net.IPNet
62-
endpoint *wireguard.Endpoint
63-
key []byte
63+
allowedIPs []*net.IPNet
64+
endpoint *wireguard.Endpoint
65+
key []byte
66+
persistentKeepalive int
6467
// Location is the logical location of this segment.
6568
location string
6669

@@ -106,7 +109,7 @@ func NewTopology(nodes map[string]*Node, peers map[string]*Peer, granularity Gra
106109
localLocation = nodeLocationPrefix + hostname
107110
}
108111

109-
t := Topology{key: key, port: port, hostname: hostname, location: localLocation, persistentKeepalive: persistentKeepalive, privateIP: nodes[hostname].InternalIP, subnet: nodes[hostname].Subnet, wireGuardCIDR: subnet}
112+
t := Topology{key: key, port: port, hostname: hostname, location: localLocation, persistentKeepalive: persistentKeepalive, privateIP: nodes[hostname].InternalIP, subnet: nodes[hostname].Subnet, wireGuardCIDR: subnet, discoveredEndpoints: make(map[string]*wireguard.Endpoint)}
110113
for location := range topoMap {
111114
// Sort the location so the result is stable.
112115
sort.Slice(topoMap[location], func(i, j int) bool {
@@ -134,14 +137,15 @@ func NewTopology(nodes map[string]*Node, peers map[string]*Peer, granularity Gra
134137
hostnames = append(hostnames, node.Name)
135138
}
136139
t.segments = append(t.segments, &segment{
137-
allowedIPs: allowedIPs,
138-
endpoint: topoMap[location][leader].Endpoint,
139-
key: topoMap[location][leader].Key,
140-
location: location,
141-
cidrs: cidrs,
142-
hostnames: hostnames,
143-
leader: leader,
144-
privateIPs: privateIPs,
140+
allowedIPs: allowedIPs,
141+
endpoint: topoMap[location][leader].Endpoint,
142+
key: topoMap[location][leader].Key,
143+
persistentKeepalive: topoMap[location][leader].PersistentKeepalive,
144+
location: location,
145+
cidrs: cidrs,
146+
hostnames: hostnames,
147+
leader: leader,
148+
privateIPs: privateIPs,
145149
})
146150
}
147151
// Sort the Topology segments so the result is stable.
@@ -159,6 +163,10 @@ func NewTopology(nodes map[string]*Node, peers map[string]*Peer, granularity Gra
159163
// We need to defensively deduplicate peer allowed IPs. If two peers claim the same IP,
160164
// the WireGuard configuration could flap, causing the interface to churn.
161165
t.peers = deduplicatePeerIPs(t.peers)
166+
// Copy the host node DiscoveredEndpoints in the topology as a starting point.
167+
for key := range nodes[hostname].DiscoveredEndpoints {
168+
t.discoveredEndpoints[key] = nodes[hostname].DiscoveredEndpoints[key]
169+
}
162170
// Allocate IPs to the segment leaders in a stable, coordination-free manner.
163171
a := newAllocator(*subnet)
164172
for _, segment := range t.segments {
@@ -171,11 +179,33 @@ func NewTopology(nodes map[string]*Node, peers map[string]*Peer, granularity Gra
171179
if t.leader && segment.location == t.location {
172180
t.wireGuardCIDR = &net.IPNet{IP: ipNet.IP, Mask: subnet.Mask}
173181
}
182+
183+
// Now that the topology is ordered, update the discoveredEndpoints map
184+
// add new ones by going through the ordered topology: segments, nodes
185+
for _, node := range topoMap[segment.location] {
186+
for key := range node.DiscoveredEndpoints {
187+
if _, ok := t.discoveredEndpoints[key]; !ok {
188+
t.discoveredEndpoints[key] = node.DiscoveredEndpoints[key]
189+
}
190+
}
191+
}
174192
}
175193

176194
return &t, nil
177195
}
178196

197+
func (t *Topology) updateEndpoint(endpoint *wireguard.Endpoint, key []byte, persistentKeepalive int) *wireguard.Endpoint {
198+
// Do not update non-nat peers
199+
if persistentKeepalive == 0 {
200+
return endpoint
201+
}
202+
e, ok := t.discoveredEndpoints[string(key)]
203+
if ok {
204+
return e
205+
}
206+
return endpoint
207+
}
208+
179209
// Conf generates a WireGuard configuration file for a given Topology.
180210
func (t *Topology) Conf() *wireguard.Conf {
181211
c := &wireguard.Conf{
@@ -190,7 +220,7 @@ func (t *Topology) Conf() *wireguard.Conf {
190220
}
191221
peer := &wireguard.Peer{
192222
AllowedIPs: s.allowedIPs,
193-
Endpoint: s.endpoint,
223+
Endpoint: t.updateEndpoint(s.endpoint, s.key, s.persistentKeepalive),
194224
PersistentKeepalive: t.persistentKeepalive,
195225
PublicKey: s.key,
196226
}
@@ -199,7 +229,7 @@ func (t *Topology) Conf() *wireguard.Conf {
199229
for _, p := range t.peers {
200230
peer := &wireguard.Peer{
201231
AllowedIPs: p.AllowedIPs,
202-
Endpoint: p.Endpoint,
232+
Endpoint: t.updateEndpoint(p.Endpoint, p.PublicKey, p.PersistentKeepalive),
203233
PersistentKeepalive: t.persistentKeepalive,
204234
PresharedKey: p.PresharedKey,
205235
PublicKey: p.PublicKey,

0 commit comments

Comments
 (0)