ipn: reject advertised routes with non-address bits set (#18649)

* ipn: reject advertised routes with non-address bits set

The config file path, EditPrefs local API, and App Connector API were
accepting invalid subnet route prefixes with non-address bits set (e.g.,
2a01:4f9:c010:c015::1/64 instead of 2a01:4f9:c010:c015::/64). All three
paths now reject prefixes where prefix != prefix.Masked() with an error
message indicating the expected masked form.

Updates tailscale/corp#36738

Signed-off-by: Brendan Creane <bcreane@gmail.com>

* address review comments

Signed-off-by: Brendan Creane <bcreane@gmail.com>

---------

Signed-off-by: Brendan Creane <bcreane@gmail.com>
This commit is contained in:
Brendan Creane
2026-03-20 10:10:43 -07:00
committed by GitHub
parent 79f71beb24
commit ffa7df2789
4 changed files with 198 additions and 0 deletions
+18
View File
@@ -4152,6 +4152,9 @@ func (b *LocalBackend) checkPrefsLocked(p *ipn.Prefs) error {
if err := b.checkAutoUpdatePrefsLocked(p); err != nil {
errs = append(errs, err)
}
if err := checkAdvertiseRoutes(p); err != nil {
errs = append(errs, err)
}
return errors.Join(errs...)
}
@@ -4249,6 +4252,18 @@ func (b *LocalBackend) checkAutoUpdatePrefsLocked(p *ipn.Prefs) error {
return nil
}
// checkAdvertiseRoutes validates that all advertised routes have
// properly masked prefixes (no non-address bits set).
func checkAdvertiseRoutes(p *ipn.Prefs) error {
var errs []error
for _, route := range p.AdvertiseRoutes {
if route != route.Masked() {
errs = append(errs, fmt.Errorf("route %s has non-address bits set; expected %s", route, route.Masked()))
}
}
return errors.Join(errs...)
}
// SetUseExitNodeEnabled turns on or off the most recently selected exit node.
//
// On success, it returns the resulting prefs (or current prefs, in the case of no change).
@@ -7260,6 +7275,9 @@ func (b *LocalBackend) AdvertiseRoute(ipps ...netip.Prefix) error {
var newRoutes []netip.Prefix
for _, ipp := range ipps {
if ipp != ipp.Masked() {
return fmt.Errorf("route %s has non-address bits set; expected %s", ipp, ipp.Masked())
}
if !allowedAutoRoute(ipp) {
continue
}