diff --git a/ipn/ipnlocal/local.go b/ipn/ipnlocal/local.go index af69d00b5..81a516073 100644 --- a/ipn/ipnlocal/local.go +++ b/ipn/ipnlocal/local.go @@ -2397,9 +2397,20 @@ func peerRoutes(peers []wgcfg.Peer, cgnatThreshold int) (routes []netaddr.IPPref } else { routes = append(routes, cgNATIPs...) } + + sort.Slice(routes, func(i, j int) bool { + return ipPrefixLess(routes[i], routes[j]) + }) return routes } +func ipPrefixLess(ri, rj netaddr.IPPrefix) bool { + if ri.IP() == rj.IP() { + return ri.Bits() < rj.Bits() + } + return ri.IP().Less(rj.IP()) +} + // routerConfig produces a router.Config from a wireguard config and IPN prefs. func (b *LocalBackend) routerConfig(cfg *wgcfg.Config, prefs *ipn.Prefs) *router.Config { rs := &router.Config{ diff --git a/ipn/ipnlocal/local_test.go b/ipn/ipnlocal/local_test.go index cd8d8e004..8a0df2867 100644 --- a/ipn/ipnlocal/local_test.go +++ b/ipn/ipnlocal/local_test.go @@ -302,8 +302,31 @@ func TestPeerRoutes(t *testing.T) { }, }, want: []netaddr.IPPrefix{ - pp("fd7a:115c:a1e0::/48"), pp("100.64.0.0/10"), + pp("fd7a:115c:a1e0::/48"), + }, + }, + { + name: "output-should-be-sorted", + peers: []wgcfg.Peer{ + { + AllowedIPs: []netaddr.IPPrefix{ + pp("100.64.0.2/32"), + pp("10.0.0.0/16"), + }, + }, + { + AllowedIPs: []netaddr.IPPrefix{ + pp("100.64.0.1/32"), + pp("10.0.0.0/8"), + }, + }, + }, + want: []netaddr.IPPrefix{ + pp("10.0.0.0/8"), + pp("10.0.0.0/16"), + pp("100.64.0.1/32"), + pp("100.64.0.2/32"), }, }, }