@@ -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
6062type 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.
180210func (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