ipn/ipnlocal: re-advertise appc routes on startup (#14609)

There's at least one example of stored routes and advertised routes
getting out of sync. I don't know how they got there yet, but this would
backfill missing advertised routes on startup from stored routes.

Also add logging in LocalBackend.AdvertiseRoute to record when new
routes actually get put into prefs.

Updates #14606

Signed-off-by: Andrew Lytvynov <awly@tailscale.com>
This commit is contained in:
Andrew Lytvynov
2025-01-15 13:32:13 -08:00
committed by GitHub
parent fcf90260ce
commit 1b303ee5ba
2 changed files with 79 additions and 3 deletions

View File

@@ -4319,6 +4319,33 @@ func (b *LocalBackend) reconfigAppConnectorLocked(nm *netmap.NetworkMap, prefs i
b.appConnector.UpdateDomainsAndRoutes(domains, routes)
}
func (b *LocalBackend) readvertiseAppConnectorRoutes() {
var domainRoutes map[string][]netip.Addr
b.mu.Lock()
if b.appConnector != nil {
domainRoutes = b.appConnector.DomainRoutes()
}
b.mu.Unlock()
if domainRoutes == nil {
return
}
// Re-advertise the stored routes, in case stored state got out of
// sync with previously advertised routes in prefs.
var prefixes []netip.Prefix
for _, ips := range domainRoutes {
for _, ip := range ips {
prefixes = append(prefixes, netip.PrefixFrom(ip, ip.BitLen()))
}
}
// Note: AdvertiseRoute will trim routes that are already
// advertised, so if everything is already being advertised this is
// a noop.
if err := b.AdvertiseRoute(prefixes...); err != nil {
b.logf("error advertising stored app connector routes: %v", err)
}
}
// authReconfig pushes a new configuration into wgengine, if engine
// updates are not currently blocked, based on the cached netmap and
// user prefs.
@@ -4397,6 +4424,7 @@ func (b *LocalBackend) authReconfig() {
}
b.initPeerAPIListener()
b.readvertiseAppConnectorRoutes()
}
// shouldUseOneCGNATRoute reports whether we should prefer to make one big
@@ -7111,7 +7139,7 @@ var ErrDisallowedAutoRoute = errors.New("route is not allowed")
// If the route is disallowed, ErrDisallowedAutoRoute is returned.
func (b *LocalBackend) AdvertiseRoute(ipps ...netip.Prefix) error {
finalRoutes := b.Prefs().AdvertiseRoutes().AsSlice()
newRoutes := false
var newRoutes []netip.Prefix
for _, ipp := range ipps {
if !allowedAutoRoute(ipp) {
@@ -7127,13 +7155,14 @@ func (b *LocalBackend) AdvertiseRoute(ipps ...netip.Prefix) error {
}
finalRoutes = append(finalRoutes, ipp)
newRoutes = true
newRoutes = append(newRoutes, ipp)
}
if !newRoutes {
if len(newRoutes) == 0 {
return nil
}
b.logf("advertising new app connector routes: %v", newRoutes)
_, err := b.EditPrefs(&ipn.MaskedPrefs{
Prefs: ipn.Prefs{
AdvertiseRoutes: finalRoutes,