mirror of
https://github.com/juanfont/headscale.git
synced 2026-09-12 03:31:34 +09:00
2c76d5c5b7
Go 1.27 allows setting promoted fields of embedded structs directly in composite literals, so gorm.Model wrappers go away. Plus strings.Cut, errors.AsType, reflect.TypeAssert and one gofumpt nit.
137 lines
3.7 KiB
Go
137 lines
3.7 KiB
Go
package v2
|
|
|
|
import (
|
|
"net/netip"
|
|
"testing"
|
|
|
|
"github.com/juanfont/headscale/hscontrol/types"
|
|
"github.com/stretchr/testify/require"
|
|
"tailscale.com/tailcfg"
|
|
)
|
|
|
|
// TestNodeNeedsPeerRecompute pins which node roles force peers to recompute
|
|
// their netmap when the node's online state changes. An ordinary node only
|
|
// needs the lightweight online/offline peer patch; subnet routers, relay
|
|
// targets, and via targets change what peers compute and therefore need a
|
|
// full recompute. The predicate is keyed on the flipping node, so an ordinary
|
|
// node in a tailnet that uses relay or via elsewhere must still be classified
|
|
// as not needing a recompute.
|
|
func TestNodeNeedsPeerRecompute(t *testing.T) {
|
|
users := types.Users{
|
|
{ID: 1, Name: "user1", Email: "user1@headscale.net"},
|
|
}
|
|
|
|
const allowAll = `{"acls":[{"action":"accept","src":["*"],"dst":["*:*"]}]}`
|
|
|
|
relayPol := `{
|
|
"tagOwners": {"tag:relay": ["user1@"]},
|
|
"grants": [
|
|
{"src": ["*"], "dst": ["tag:relay"], "app": {"tailscale.com/cap/relay": [{}]}}
|
|
]
|
|
}`
|
|
|
|
viaPol := `{
|
|
"tagOwners": {"tag:via": ["user1@"]},
|
|
"grants": [
|
|
{"src": ["*"], "dst": ["10.0.0.0/24"], "ip": ["*"], "via": ["tag:via"]}
|
|
]
|
|
}`
|
|
|
|
taildrivePol := `{
|
|
"tagOwners": {"tag:drive": ["user1@"]},
|
|
"grants": [
|
|
{"src": ["*"], "dst": ["tag:drive"], "app": {"tailscale.com/cap/drive": [{}]}}
|
|
]
|
|
}`
|
|
|
|
ordinary := node("ordinary", "100.64.0.1", "fd7a:115c:a1e0::1", users[0])
|
|
ordinary.ID = 1
|
|
|
|
subnetRouter := node("subnet", "100.64.0.2", "fd7a:115c:a1e0::2", users[0])
|
|
subnetRouter.ID = 2
|
|
subnetRouter.Hostinfo = &tailcfg.Hostinfo{
|
|
RoutableIPs: []netip.Prefix{netip.MustParsePrefix("10.0.0.0/24")},
|
|
}
|
|
subnetRouter.ApprovedRoutes = []netip.Prefix{netip.MustParsePrefix("10.0.0.0/24")}
|
|
|
|
relayTarget := node("relay", "100.64.0.3", "fd7a:115c:a1e0::3", users[0])
|
|
relayTarget.ID = 3
|
|
relayTarget.Tags = []string{"tag:relay"}
|
|
|
|
viaTarget := node("via", "100.64.0.4", "fd7a:115c:a1e0::4", users[0])
|
|
viaTarget.ID = 4
|
|
viaTarget.Tags = []string{"tag:via"}
|
|
|
|
driveTarget := node("drive", "100.64.0.5", "fd7a:115c:a1e0::5", users[0])
|
|
driveTarget.ID = 5
|
|
driveTarget.Tags = []string{"tag:drive"}
|
|
|
|
tests := []struct {
|
|
name string
|
|
pol string
|
|
nodes types.Nodes
|
|
subject *types.Node
|
|
want bool
|
|
}{
|
|
{
|
|
name: "ordinary node under allow-all does not need recompute",
|
|
pol: allowAll,
|
|
nodes: types.Nodes{ordinary},
|
|
subject: ordinary,
|
|
want: false,
|
|
},
|
|
{
|
|
name: "subnet router needs recompute",
|
|
pol: allowAll,
|
|
nodes: types.Nodes{subnetRouter},
|
|
subject: subnetRouter,
|
|
want: true,
|
|
},
|
|
{
|
|
name: "relay target needs recompute",
|
|
pol: relayPol,
|
|
nodes: types.Nodes{relayTarget, ordinary},
|
|
subject: relayTarget,
|
|
want: true,
|
|
},
|
|
{
|
|
name: "ordinary node in a relay-using tailnet does not need recompute",
|
|
pol: relayPol,
|
|
nodes: types.Nodes{relayTarget, ordinary},
|
|
subject: ordinary,
|
|
want: false,
|
|
},
|
|
{
|
|
name: "via target needs recompute",
|
|
pol: viaPol,
|
|
nodes: types.Nodes{viaTarget, ordinary},
|
|
subject: viaTarget,
|
|
want: true,
|
|
},
|
|
{
|
|
name: "ordinary node in a via-using tailnet does not need recompute",
|
|
pol: viaPol,
|
|
nodes: types.Nodes{viaTarget, ordinary},
|
|
subject: ordinary,
|
|
want: false,
|
|
},
|
|
{
|
|
name: "taildrive target does not need recompute",
|
|
pol: taildrivePol,
|
|
nodes: types.Nodes{driveTarget, ordinary},
|
|
subject: driveTarget,
|
|
want: false,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
pm, err := NewPolicyManager([]byte(tt.pol), users, tt.nodes.ViewSlice())
|
|
require.NoError(t, err)
|
|
|
|
got := pm.NodeNeedsPeerRecompute(tt.subject.View())
|
|
require.Equal(t, tt.want, got)
|
|
})
|
|
}
|
|
}
|