mirror of
https://github.com/juanfont/headscale.git
synced 2026-11-04 04:34:07 +09:00
mapper: send a router all of its own routes
Its AllowedIPs held only the primaries the policy let it reach. It now holds every approved route, and PrimaryRoutes the ones it serves.
This commit is contained in:
1 parent
ffd4f34841
commit
4e433f7a04
4 files changed
+19
-204
No files matched your search
@@ -8,7 +8,6 @@ import (
|
||||
"slices"
|
||||
"time"
|
||||
|
||||
"github.com/juanfont/headscale/hscontrol/policy"
|
||||
policyv2 "github.com/juanfont/headscale/hscontrol/policy/v2"
|
||||
"github.com/juanfont/headscale/hscontrol/types"
|
||||
"github.com/juanfont/headscale/hscontrol/util/zlog/zf"
|
||||
@@ -88,15 +87,12 @@ func (b *MapResponseBuilder) WithSelfNode() *MapResponseBuilder {
|
||||
return b
|
||||
}
|
||||
|
||||
_, matchers := b.mapper.state.Filter()
|
||||
|
||||
tailnode, err := nv.TailNode(
|
||||
b.capVer,
|
||||
func(id types.NodeID) []netip.Prefix {
|
||||
// Self node: include own primaries + exit routes (no via steering for self).
|
||||
primaries := policy.ReduceRoutes(nv, b.mapper.state.GetNodePrimaryRoutes(id), matchers)
|
||||
|
||||
return slices.Concat(primaries, nv.ExitRoutes())
|
||||
func(types.NodeID) []netip.Prefix {
|
||||
// A router holds every route it is approved for, whatever
|
||||
// its own policy reaches.
|
||||
return nv.AllApprovedRoutes()
|
||||
},
|
||||
b.mapper.cfg,
|
||||
b.mapper.state.NodeCapMap(nv.ID()),
|
||||
@@ -106,6 +102,13 @@ func (b *MapResponseBuilder) WithSelfNode() *MapResponseBuilder {
|
||||
return b
|
||||
}
|
||||
|
||||
// PrimaryRoutes is what the router serves: the routes it is primary
|
||||
// for, under the rule its peers get them by.
|
||||
tailnode.PrimaryRoutes = slices.DeleteFunc(
|
||||
b.mapper.state.GetNodePrimaryRoutes(nv.ID()),
|
||||
func(p netip.Prefix) bool { return !b.mapper.cfg.ServesRoute(p) },
|
||||
)
|
||||
|
||||
b.resp.Node = tailnode
|
||||
|
||||
return b
|
||||
|
||||
@@ -114,19 +114,6 @@ var mapStreamSkipReasons = map[string]string{
|
||||
"route-announce/RA9/srv/presence": policyResponseToEveryNode,
|
||||
"route-announce/RA9/wit/presence": policyResponseToEveryNode,
|
||||
|
||||
"route-announce/RA0/rtr/self-routes": selfRoutesReduced,
|
||||
"route-announce/RA1/rtr/self-routes": selfRoutesReduced,
|
||||
"route-announce/RA2/rtr/self-routes": selfRoutesReduced,
|
||||
"route-announce/RA3/rtr/self-routes": selfRoutesReduced,
|
||||
"route-announce/RA4/rtr/self-routes": selfRoutesReduced,
|
||||
"route-announce/RA5/rtr/self-routes": selfRoutesReduced,
|
||||
"route-announce/RA6/rtr/self-routes": selfRoutesReduced,
|
||||
"route-announce/RA7/rtr/self-routes": selfRoutesReduced,
|
||||
"route-announce/RA8/rtr/self-routes": selfRoutesReduced,
|
||||
"route-announce/RA9/rtr/self-routes": selfRoutesReduced,
|
||||
"route-announce/RA10/rtr/self-routes": selfRoutesReduced,
|
||||
"route-announce/RA11/rtr/self-routes": selfRoutesReduced,
|
||||
|
||||
"policy-generation/G2/thor-1/peers": sameUserPeers,
|
||||
"policy-generation/G2/thor-2/peers": sameUserPeers,
|
||||
"policy-generation/G3/thor-1/peers": sameUserPeers,
|
||||
|
||||
@@ -373,50 +373,7 @@ var routeOverlapCompatTests = []string{
|
||||
// routeOverlapSkipReasons lists checks where headscale differs from SaaS,
|
||||
// keyed <test_id>/<node>/<check>. A listed check that matches fails, so a fix
|
||||
// must delete its entry.
|
||||
var routeOverlapSkipReasons = map[string]string{
|
||||
// Once a router is sent its own routes, its self-primary also needs the
|
||||
// approved singles in the tailnet range left unserved.
|
||||
"routes-t1-auto-v4-default/ovl-r-ctrl/self-allowed": selfRoutesReduced,
|
||||
"routes-t1-auto-v4-default/ovl-r-ctrl/self-primary": selfRoutesReduced,
|
||||
"routes-t1-auto-v4-default/ovl-r-host4/self-allowed": selfRoutesReduced,
|
||||
"routes-t1-auto-v4-default/ovl-r-narrow/self-allowed": selfRoutesReduced,
|
||||
"routes-t1-auto-v4-default/ovl-r-narrow/self-primary": selfRoutesReduced,
|
||||
"routes-t2-auto-v6-default/ovl-r-host6/self-allowed": selfRoutesReduced,
|
||||
"routes-t2-auto-v6-default/ovl-r-mapped/self-allowed": selfRoutesReduced,
|
||||
"routes-t2-auto-v6-default/ovl-r-mapped/self-primary": selfRoutesReduced,
|
||||
"routes-t2-auto-v6-default/ovl-r-narrow/self-allowed": selfRoutesReduced,
|
||||
"routes-t2-auto-v6-default/ovl-r-narrow/self-primary": selfRoutesReduced,
|
||||
"routes-t2-auto-v6-default/ovl-r-via/self-allowed": selfRoutesReduced,
|
||||
"routes-t2-auto-v6-default/ovl-r-via/self-primary": selfRoutesReduced,
|
||||
"routes-t3-auto-narrow-keys/ovl-r-ctrl/self-allowed": selfRoutesReduced,
|
||||
"routes-t3-auto-narrow-keys/ovl-r-ctrl/self-primary": selfRoutesReduced,
|
||||
"routes-t3-auto-narrow-keys/ovl-r-host4/self-allowed": selfRoutesReduced,
|
||||
"routes-t3-auto-narrow-keys/ovl-r-host6/self-allowed": selfRoutesReduced,
|
||||
"routes-t3-auto-narrow-keys/ovl-r-narrow/self-allowed": selfRoutesReduced,
|
||||
"routes-t3-auto-narrow-keys/ovl-r-narrow/self-primary": selfRoutesReduced,
|
||||
"routes-t3-auto-narrow-keys/ovl-r-via/self-allowed": selfRoutesReduced,
|
||||
"routes-t3-auto-narrow-keys/ovl-r-via/self-primary": selfRoutesReduced,
|
||||
"routes-t4-admin/ovl-r-ctrl/self-allowed": selfRoutesReduced,
|
||||
"routes-t4-admin/ovl-r-ctrl/self-primary": selfRoutesReduced,
|
||||
"routes-t4-admin/ovl-r-host4/self-allowed": selfRoutesReduced,
|
||||
"routes-t4-admin/ovl-r-host6/self-allowed": selfRoutesReduced,
|
||||
"routes-t4-admin/ovl-r-mapped/self-allowed": selfRoutesReduced,
|
||||
"routes-t4-admin/ovl-r-mapped/self-primary": selfRoutesReduced,
|
||||
"routes-t4-admin/ovl-r-narrow/self-allowed": selfRoutesReduced,
|
||||
"routes-t4-admin/ovl-r-narrow/self-primary": selfRoutesReduced,
|
||||
"routes-t4-admin/ovl-r-via/self-allowed": selfRoutesReduced,
|
||||
"routes-t4-admin/ovl-r-via/self-primary": selfRoutesReduced,
|
||||
"routes-t5-oauth-routes-scope/ovl-r-ctrl/self-allowed": selfRoutesReduced,
|
||||
"routes-t5-oauth-routes-scope/ovl-r-ctrl/self-primary": selfRoutesReduced,
|
||||
"routes-t5-oauth-routes-scope/ovl-r-host4/self-allowed": selfRoutesReduced,
|
||||
"routes-t5-oauth-routes-scope/ovl-r-host6/self-allowed": selfRoutesReduced,
|
||||
"routes-t5-oauth-routes-scope/ovl-r-mapped/self-allowed": selfRoutesReduced,
|
||||
"routes-t5-oauth-routes-scope/ovl-r-mapped/self-primary": selfRoutesReduced,
|
||||
"routes-t5-oauth-routes-scope/ovl-r-narrow/self-allowed": selfRoutesReduced,
|
||||
"routes-t5-oauth-routes-scope/ovl-r-narrow/self-primary": selfRoutesReduced,
|
||||
"routes-t5-oauth-routes-scope/ovl-r-via/self-allowed": selfRoutesReduced,
|
||||
"routes-t5-oauth-routes-scope/ovl-r-via/self-primary": selfRoutesReduced,
|
||||
}
|
||||
var routeOverlapSkipReasons = map[string]string{}
|
||||
|
||||
// routeOverlapNotCompared lists, by key prefix, checks left out: SaaS's
|
||||
// answer there is in doubt, so it is no reference.
|
||||
@@ -643,8 +600,9 @@ func sortedStrings(s []string) string {
|
||||
|
||||
// TestRoutesNodeRangeSingleNotServed checks that a router's approved single
|
||||
// addresses inside the node ranges, in either spelling, reach no viewer
|
||||
// through a plain grant or a via grant. They stay approved, the router's own
|
||||
// entry keeps them, and its wider route is still served.
|
||||
// through a plain grant or a via grant. They stay approved and in the
|
||||
// router's own AllowedIPs, never in its PrimaryRoutes, and its wider route
|
||||
// is still served.
|
||||
func TestRoutesNodeRangeSingleNotServed(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
@@ -704,9 +662,9 @@ func TestRoutesNodeRangeSingleNotServed(t *testing.T) {
|
||||
|
||||
return ok && views.SliceContains(p.PrimaryRoutes(), subnet)
|
||||
})
|
||||
router.WaitForCondition(t, "router holds its routes", 15*time.Second,
|
||||
router.WaitForCondition(t, "router serves its subnet", 15*time.Second,
|
||||
func(nm *netmap.NetworkMap) bool {
|
||||
return views.SliceContains(nm.SelfNode.AllowedIPs(), subnet)
|
||||
return views.SliceContains(nm.SelfNode.PrimaryRoutes(), subnet)
|
||||
})
|
||||
|
||||
peer, _ := viewer.PeerByName("router")
|
||||
@@ -719,6 +677,8 @@ func TestRoutesNodeRangeSingleNotServed(t *testing.T) {
|
||||
"%s served in PrimaryRoutes", single)
|
||||
assert.Truef(t, views.SliceContains(self.AllowedIPs(), single),
|
||||
"%s missing from the router's own AllowedIPs", single)
|
||||
assert.Falsef(t, views.SliceContains(self.PrimaryRoutes(), single),
|
||||
"%s in the router's own PrimaryRoutes", single)
|
||||
}
|
||||
|
||||
node, ok := srv.State().GetNodeByID(routerID)
|
||||
|
||||
@@ -107,139 +107,6 @@ var routesMapCompatTests = []struct {
|
||||
var viaCompatSkipReasons = map[string]string{
|
||||
"tagged-self": "TAGGED_SELF_PROFILE: SaaS gives a tagged node a profile of its own, headscale the shared tagged-devices one",
|
||||
|
||||
// SaaS sends a router every approved route in its own AllowedIPs and
|
||||
// every route it is primary for in PrimaryRoutes.
|
||||
"grant-v11/blastoise/self-routes": selfRoutesReduced,
|
||||
"grant-v11/squirtle/self-routes": selfRoutesReduced,
|
||||
"grant-v12/blastoise/self-routes": selfRoutesReduced,
|
||||
"grant-v12/squirtle/self-routes": selfRoutesReduced,
|
||||
"grant-v13/blastoise/self-routes": selfRoutesReduced,
|
||||
"grant-v13/squirtle/self-routes": selfRoutesReduced,
|
||||
|
||||
"routes-a1-wildcard-acl-includes-routes-in-srcips/butterfree/self-routes": selfRoutesReduced,
|
||||
"routes-a2-tag-based-acl-excludes-routes/butterfree/self-routes": selfRoutesReduced,
|
||||
"routes-a2-tag-based-acl-excludes-routes/caterpie/self-routes": selfRoutesReduced,
|
||||
"routes-a2-tag-based-acl-excludes-routes/metapod/self-routes": selfRoutesReduced,
|
||||
"routes-a2-tag-based-acl-excludes-routes/squirtle/self-routes": selfRoutesReduced,
|
||||
"routes-a2-tag-based-acl-excludes-routes/wartortle/self-routes": selfRoutesReduced,
|
||||
"routes-a3-explicit-subnet-filter-to-router/butterfree/self-routes": selfRoutesReduced,
|
||||
"routes-a3-explicit-subnet-filter-to-router/metapod/self-routes": selfRoutesReduced,
|
||||
"routes-a3-explicit-subnet-filter-to-router/wartortle/self-routes": selfRoutesReduced,
|
||||
"routes-a4-multiple-routes-same-router/butterfree/self-routes": selfRoutesReduced,
|
||||
"routes-a4-multiple-routes-same-router/caterpie/self-routes": selfRoutesReduced,
|
||||
"routes-a4-multiple-routes-same-router/metapod/self-routes": selfRoutesReduced,
|
||||
"routes-a4-multiple-routes-same-router/squirtle/self-routes": selfRoutesReduced,
|
||||
"routes-e1-ha-two-routers-same-subnet/butterfree/self-routes": selfRoutesReduced,
|
||||
"routes-e1-ha-two-routers-same-subnet/caterpie/self-routes": selfRoutesReduced,
|
||||
"routes-e1-ha-two-routers-same-subnet/squirtle/self-routes": selfRoutesReduced,
|
||||
"routes-e1-ha-two-routers-same-subnet/wartortle/self-routes": selfRoutesReduced,
|
||||
"routes-e2-ha-primary-in-allowedips/butterfree/self-routes": selfRoutesReduced,
|
||||
"routes-e2-ha-primary-in-allowedips/caterpie/self-routes": selfRoutesReduced,
|
||||
"routes-e2-ha-primary-in-allowedips/squirtle/self-routes": selfRoutesReduced,
|
||||
"routes-e2-ha-primary-in-allowedips/wartortle/self-routes": selfRoutesReduced,
|
||||
"routes-f2-subnet-as-acl-source/butterfree/self-routes": selfRoutesReduced,
|
||||
"routes-f2-subnet-as-acl-source/caterpie/self-routes": selfRoutesReduced,
|
||||
"routes-f2-subnet-as-acl-source/metapod/self-routes": selfRoutesReduced,
|
||||
"routes-f2-subnet-as-acl-source/squirtle/self-routes": selfRoutesReduced,
|
||||
"routes-f2-subnet-as-acl-source/wartortle/self-routes": selfRoutesReduced,
|
||||
"routes-f3-wildcard-src-specific-dst/butterfree/self-routes": selfRoutesReduced,
|
||||
"routes-f3-wildcard-src-specific-dst/metapod/self-routes": selfRoutesReduced,
|
||||
"routes-f3-wildcard-src-specific-dst/wartortle/self-routes": selfRoutesReduced,
|
||||
"routes-h1-wildcard-srcips-format/butterfree/self-routes": selfRoutesReduced,
|
||||
"routes-h1-wildcard-srcips-format/metapod/self-routes": selfRoutesReduced,
|
||||
"routes-pa1-partial-route-approval/butterfree/self-routes": selfRoutesReduced,
|
||||
"routes-m1-wildcard-src-multi-range/r-exit/self-routes": selfRoutesReduced,
|
||||
"routes-m1-wildcard-src-multi-range/r-multi/self-routes": selfRoutesReduced,
|
||||
"routes-m2-member-partial-subnet/r-exit/self-routes": selfRoutesReduced,
|
||||
"routes-m2-member-partial-subnet/r-multi/self-routes": selfRoutesReduced,
|
||||
"routes-m3-subnet-route-as-src/r-exit/self-routes": selfRoutesReduced,
|
||||
"routes-m3-subnet-route-as-src/r-multi/self-routes": selfRoutesReduced,
|
||||
"routes-m4-member-self/r-exit/self-routes": selfRoutesReduced,
|
||||
"routes-m4-member-self/r-multi/self-routes": selfRoutesReduced,
|
||||
"routes-m6-subnet-to-subnet-multi-route/r-exit/self-routes": selfRoutesReduced,
|
||||
"routes-m6-subnet-to-subnet-multi-route/r-multi/self-routes": selfRoutesReduced,
|
||||
|
||||
"via-grant-v14/blastoise/self-routes": selfRoutesReduced,
|
||||
"via-grant-v14/fearow/self-routes": selfRoutesReduced,
|
||||
"via-grant-v14/spearow/self-routes": selfRoutesReduced,
|
||||
"via-grant-v14/squirtle/self-routes": selfRoutesReduced,
|
||||
"via-grant-v15/blastoise/self-routes": selfRoutesReduced,
|
||||
"via-grant-v15/fearow/self-routes": selfRoutesReduced,
|
||||
"via-grant-v15/spearow/self-routes": selfRoutesReduced,
|
||||
"via-grant-v15/squirtle/self-routes": selfRoutesReduced,
|
||||
"via-grant-v16/blastoise/self-routes": selfRoutesReduced,
|
||||
"via-grant-v16/fearow/self-routes": selfRoutesReduced,
|
||||
"via-grant-v16/spearow/self-routes": selfRoutesReduced,
|
||||
"via-grant-v16/squirtle/self-routes": selfRoutesReduced,
|
||||
"via-grant-v26/blastoise/self-routes": selfRoutesReduced,
|
||||
"via-grant-v26/fearow/self-routes": selfRoutesReduced,
|
||||
"via-grant-v26/spearow/self-routes": selfRoutesReduced,
|
||||
"via-grant-v26/squirtle/self-routes": selfRoutesReduced,
|
||||
"via-grant-v27/blastoise/self-routes": selfRoutesReduced,
|
||||
"via-grant-v27/fearow/self-routes": selfRoutesReduced,
|
||||
"via-grant-v27/spearow/self-routes": selfRoutesReduced,
|
||||
"via-grant-v27/squirtle/self-routes": selfRoutesReduced,
|
||||
"via-grant-v28/blastoise/self-routes": selfRoutesReduced,
|
||||
"via-grant-v28/fearow/self-routes": selfRoutesReduced,
|
||||
"via-grant-v28/spearow/self-routes": selfRoutesReduced,
|
||||
"via-grant-v28/squirtle/self-routes": selfRoutesReduced,
|
||||
"via-grant-v29/blastoise/self-routes": selfRoutesReduced,
|
||||
"via-grant-v29/fearow/self-routes": selfRoutesReduced,
|
||||
"via-grant-v29/spearow/self-routes": selfRoutesReduced,
|
||||
"via-grant-v29/squirtle/self-routes": selfRoutesReduced,
|
||||
"via-grant-v30/blastoise/self-routes": selfRoutesReduced,
|
||||
"via-grant-v30/fearow/self-routes": selfRoutesReduced,
|
||||
"via-grant-v30/spearow/self-routes": selfRoutesReduced,
|
||||
"via-grant-v30/squirtle/self-routes": selfRoutesReduced,
|
||||
"via-grant-v31/blastoise/self-routes": selfRoutesReduced,
|
||||
"via-grant-v31/fearow/self-routes": selfRoutesReduced,
|
||||
"via-grant-v31/spearow/self-routes": selfRoutesReduced,
|
||||
"via-grant-v31/squirtle/self-routes": selfRoutesReduced,
|
||||
"via-grant-v32/blastoise/self-routes": selfRoutesReduced,
|
||||
"via-grant-v32/fearow/self-routes": selfRoutesReduced,
|
||||
"via-grant-v32/spearow/self-routes": selfRoutesReduced,
|
||||
"via-grant-v32/squirtle/self-routes": selfRoutesReduced,
|
||||
"via-grant-v33/blastoise/self-routes": selfRoutesReduced,
|
||||
"via-grant-v33/fearow/self-routes": selfRoutesReduced,
|
||||
"via-grant-v33/spearow/self-routes": selfRoutesReduced,
|
||||
"via-grant-v33/squirtle/self-routes": selfRoutesReduced,
|
||||
"via-grant-v34/blastoise/self-routes": selfRoutesReduced,
|
||||
"via-grant-v34/fearow/self-routes": selfRoutesReduced,
|
||||
"via-grant-v34/spearow/self-routes": selfRoutesReduced,
|
||||
"via-grant-v34/squirtle/self-routes": selfRoutesReduced,
|
||||
"via-grant-v35/blastoise/self-routes": selfRoutesReduced,
|
||||
"via-grant-v35/fearow/self-routes": selfRoutesReduced,
|
||||
"via-grant-v35/spearow/self-routes": selfRoutesReduced,
|
||||
"via-grant-v35/squirtle/self-routes": selfRoutesReduced,
|
||||
"via-grant-v36/blastoise/self-routes": selfRoutesReduced,
|
||||
"via-grant-v36/fearow/self-routes": selfRoutesReduced,
|
||||
"via-grant-v36/spearow/self-routes": selfRoutesReduced,
|
||||
"via-grant-v36/squirtle/self-routes": selfRoutesReduced,
|
||||
"via-grant-v47/blastoise/self-routes": selfRoutesReduced,
|
||||
"via-grant-v47/fearow/self-routes": selfRoutesReduced,
|
||||
"via-grant-v47/spearow/self-routes": selfRoutesReduced,
|
||||
"via-grant-v47/squirtle/self-routes": selfRoutesReduced,
|
||||
"via-grant-v48/blastoise/self-routes": selfRoutesReduced,
|
||||
"via-grant-v48/fearow/self-routes": selfRoutesReduced,
|
||||
"via-grant-v48/spearow/self-routes": selfRoutesReduced,
|
||||
"via-grant-v48/squirtle/self-routes": selfRoutesReduced,
|
||||
"via-grant-v49/blastoise/self-routes": selfRoutesReduced,
|
||||
"via-grant-v49/fearow/self-routes": selfRoutesReduced,
|
||||
"via-grant-v49/spearow/self-routes": selfRoutesReduced,
|
||||
"via-grant-v49/squirtle/self-routes": selfRoutesReduced,
|
||||
"via-grant-v50/blastoise/self-routes": selfRoutesReduced,
|
||||
"via-grant-v50/fearow/self-routes": selfRoutesReduced,
|
||||
"via-grant-v50/spearow/self-routes": selfRoutesReduced,
|
||||
"via-grant-v50/squirtle/self-routes": selfRoutesReduced,
|
||||
"via-grant-v63/blastoise/self-routes": selfRoutesReduced,
|
||||
"via-grant-v63/fearow/self-routes": selfRoutesReduced,
|
||||
"via-grant-v63/spearow/self-routes": selfRoutesReduced,
|
||||
"via-grant-v63/squirtle/self-routes": selfRoutesReduced,
|
||||
"via-grant-v66/blastoise/self-routes": selfRoutesReduced,
|
||||
"via-grant-v66/squirtle/self-routes": selfRoutesReduced,
|
||||
"via-grant-v67/blastoise/self-routes": selfRoutesReduced,
|
||||
"via-grant-v67/squirtle/self-routes": selfRoutesReduced,
|
||||
|
||||
"routes-m1-wildcard-src-multi-range/srv/peer-allowed-ips": exitRoutesOnOverlap,
|
||||
"routes-m6-subnet-to-subnet-multi-route/r-multi/peer-allowed-ips": exitRoutesOnOverlap,
|
||||
|
||||
@@ -257,8 +124,6 @@ const exitRoutesOnOverlap = "EXIT_ROUTES_ON_OVERLAP: headscale offers a peer's e
|
||||
|
||||
const sameUserPeers = "SAME_USER_PEERS: SaaS lists a user's own devices as each other's peers with no rule linking them; headscale peers only what the policy links"
|
||||
|
||||
const selfRoutesReduced = "SELF_ROUTES_REDUCED: headscale sends a router only the primary routes its policy lets it reach"
|
||||
|
||||
// TestRoutesMapCompat replays routesMapCompatTests through
|
||||
// [runViaMapCompat].
|
||||
func TestRoutesMapCompat(t *testing.T) {
|
||||
|
||||
Reference in new issue
Block a user