2025-10-23 17:57:41 +02:00
|
|
|
package policyutil_test
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"encoding/json"
|
|
|
|
|
"fmt"
|
|
|
|
|
"net/netip"
|
|
|
|
|
"testing"
|
|
|
|
|
|
|
|
|
|
"github.com/google/go-cmp/cmp"
|
|
|
|
|
"github.com/juanfont/headscale/hscontrol/policy"
|
|
|
|
|
"github.com/juanfont/headscale/hscontrol/policy/policyutil"
|
policy: add ICMP protocols to default and export constants
When ACL rules don't specify a protocol, Headscale now defaults to
[TCP, UDP, ICMP, ICMPv6] instead of just [TCP, UDP], matching
Tailscale's behavior.
Also export protocol number constants (ProtocolTCP, ProtocolUDP, etc.)
for use in external test packages, renaming the string protocol
constants to ProtoNameTCP, ProtoNameUDP, etc. to avoid conflicts.
This resolves 78 ICMP-related TODOs in the Tailscale compatibility
tests, reducing the total from 165 to 87.
Updates #3036
2026-01-23 20:16:02 +00:00
|
|
|
v2 "github.com/juanfont/headscale/hscontrol/policy/v2"
|
2025-10-23 17:57:41 +02:00
|
|
|
"github.com/juanfont/headscale/hscontrol/types"
|
|
|
|
|
"github.com/juanfont/headscale/hscontrol/util"
|
|
|
|
|
"github.com/rs/zerolog/log"
|
|
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
|
"gorm.io/gorm"
|
|
|
|
|
"tailscale.com/net/tsaddr"
|
|
|
|
|
"tailscale.com/tailcfg"
|
2025-12-02 12:01:25 +01:00
|
|
|
"tailscale.com/types/ptr"
|
2025-10-23 17:57:41 +02:00
|
|
|
"tailscale.com/util/must"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
var ap = func(ipStr string) *netip.Addr {
|
|
|
|
|
ip := netip.MustParseAddr(ipStr)
|
|
|
|
|
return &ip
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var p = func(prefStr string) netip.Prefix {
|
|
|
|
|
ip := netip.MustParsePrefix(prefStr)
|
|
|
|
|
return ip
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// hsExitNodeDestForTest is the list of destination IP ranges that are allowed when
|
|
|
|
|
// we use headscale "autogroup:internet".
|
|
|
|
|
var hsExitNodeDestForTest = []tailcfg.NetPortRange{
|
|
|
|
|
{IP: "0.0.0.0/5", Ports: tailcfg.PortRangeAny},
|
|
|
|
|
{IP: "8.0.0.0/7", Ports: tailcfg.PortRangeAny},
|
|
|
|
|
{IP: "11.0.0.0/8", Ports: tailcfg.PortRangeAny},
|
|
|
|
|
{IP: "12.0.0.0/6", Ports: tailcfg.PortRangeAny},
|
|
|
|
|
{IP: "16.0.0.0/4", Ports: tailcfg.PortRangeAny},
|
|
|
|
|
{IP: "32.0.0.0/3", Ports: tailcfg.PortRangeAny},
|
|
|
|
|
{IP: "64.0.0.0/3", Ports: tailcfg.PortRangeAny},
|
|
|
|
|
{IP: "96.0.0.0/6", Ports: tailcfg.PortRangeAny},
|
|
|
|
|
{IP: "100.0.0.0/10", Ports: tailcfg.PortRangeAny},
|
|
|
|
|
{IP: "100.128.0.0/9", Ports: tailcfg.PortRangeAny},
|
|
|
|
|
{IP: "101.0.0.0/8", Ports: tailcfg.PortRangeAny},
|
|
|
|
|
{IP: "102.0.0.0/7", Ports: tailcfg.PortRangeAny},
|
|
|
|
|
{IP: "104.0.0.0/5", Ports: tailcfg.PortRangeAny},
|
|
|
|
|
{IP: "112.0.0.0/4", Ports: tailcfg.PortRangeAny},
|
|
|
|
|
{IP: "128.0.0.0/3", Ports: tailcfg.PortRangeAny},
|
|
|
|
|
{IP: "160.0.0.0/5", Ports: tailcfg.PortRangeAny},
|
|
|
|
|
{IP: "168.0.0.0/8", Ports: tailcfg.PortRangeAny},
|
|
|
|
|
{IP: "169.0.0.0/9", Ports: tailcfg.PortRangeAny},
|
|
|
|
|
{IP: "169.128.0.0/10", Ports: tailcfg.PortRangeAny},
|
|
|
|
|
{IP: "169.192.0.0/11", Ports: tailcfg.PortRangeAny},
|
|
|
|
|
{IP: "169.224.0.0/12", Ports: tailcfg.PortRangeAny},
|
|
|
|
|
{IP: "169.240.0.0/13", Ports: tailcfg.PortRangeAny},
|
|
|
|
|
{IP: "169.248.0.0/14", Ports: tailcfg.PortRangeAny},
|
|
|
|
|
{IP: "169.252.0.0/15", Ports: tailcfg.PortRangeAny},
|
|
|
|
|
{IP: "169.255.0.0/16", Ports: tailcfg.PortRangeAny},
|
|
|
|
|
{IP: "170.0.0.0/7", Ports: tailcfg.PortRangeAny},
|
|
|
|
|
{IP: "172.0.0.0/12", Ports: tailcfg.PortRangeAny},
|
|
|
|
|
{IP: "172.32.0.0/11", Ports: tailcfg.PortRangeAny},
|
|
|
|
|
{IP: "172.64.0.0/10", Ports: tailcfg.PortRangeAny},
|
|
|
|
|
{IP: "172.128.0.0/9", Ports: tailcfg.PortRangeAny},
|
|
|
|
|
{IP: "173.0.0.0/8", Ports: tailcfg.PortRangeAny},
|
|
|
|
|
{IP: "174.0.0.0/7", Ports: tailcfg.PortRangeAny},
|
|
|
|
|
{IP: "176.0.0.0/4", Ports: tailcfg.PortRangeAny},
|
|
|
|
|
{IP: "192.0.0.0/9", Ports: tailcfg.PortRangeAny},
|
|
|
|
|
{IP: "192.128.0.0/11", Ports: tailcfg.PortRangeAny},
|
|
|
|
|
{IP: "192.160.0.0/13", Ports: tailcfg.PortRangeAny},
|
|
|
|
|
{IP: "192.169.0.0/16", Ports: tailcfg.PortRangeAny},
|
|
|
|
|
{IP: "192.170.0.0/15", Ports: tailcfg.PortRangeAny},
|
|
|
|
|
{IP: "192.172.0.0/14", Ports: tailcfg.PortRangeAny},
|
|
|
|
|
{IP: "192.176.0.0/12", Ports: tailcfg.PortRangeAny},
|
|
|
|
|
{IP: "192.192.0.0/10", Ports: tailcfg.PortRangeAny},
|
|
|
|
|
{IP: "193.0.0.0/8", Ports: tailcfg.PortRangeAny},
|
|
|
|
|
{IP: "194.0.0.0/7", Ports: tailcfg.PortRangeAny},
|
|
|
|
|
{IP: "196.0.0.0/6", Ports: tailcfg.PortRangeAny},
|
|
|
|
|
{IP: "200.0.0.0/5", Ports: tailcfg.PortRangeAny},
|
|
|
|
|
{IP: "208.0.0.0/4", Ports: tailcfg.PortRangeAny},
|
|
|
|
|
{IP: "224.0.0.0/3", Ports: tailcfg.PortRangeAny},
|
|
|
|
|
{IP: "2000::/3", Ports: tailcfg.PortRangeAny},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestTheInternet(t *testing.T) {
|
|
|
|
|
internetSet := util.TheInternet()
|
|
|
|
|
|
|
|
|
|
internetPrefs := internetSet.Prefixes()
|
|
|
|
|
|
|
|
|
|
for i := range internetPrefs {
|
|
|
|
|
if internetPrefs[i].String() != hsExitNodeDestForTest[i].IP {
|
|
|
|
|
t.Errorf(
|
|
|
|
|
"prefix from internet set %q != hsExit list %q",
|
|
|
|
|
internetPrefs[i].String(),
|
|
|
|
|
hsExitNodeDestForTest[i].IP,
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if len(internetPrefs) != len(hsExitNodeDestForTest) {
|
|
|
|
|
t.Fatalf(
|
|
|
|
|
"expected same length of prefixes, internet: %d, hsExit: %d",
|
|
|
|
|
len(internetPrefs),
|
|
|
|
|
len(hsExitNodeDestForTest),
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestReduceFilterRules(t *testing.T) {
|
|
|
|
|
users := types.Users{
|
|
|
|
|
types.User{Model: gorm.Model{ID: 1}, Name: "mickael"},
|
|
|
|
|
types.User{Model: gorm.Model{ID: 2}, Name: "user1"},
|
|
|
|
|
types.User{Model: gorm.Model{ID: 3}, Name: "user2"},
|
|
|
|
|
types.User{Model: gorm.Model{ID: 4}, Name: "user100"},
|
|
|
|
|
types.User{Model: gorm.Model{ID: 5}, Name: "user3"},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
tests := []struct {
|
|
|
|
|
name string
|
|
|
|
|
node *types.Node
|
|
|
|
|
peers types.Nodes
|
|
|
|
|
pol string
|
|
|
|
|
want []tailcfg.FilterRule
|
|
|
|
|
}{
|
|
|
|
|
{
|
|
|
|
|
name: "host1-can-reach-host2-no-rules",
|
|
|
|
|
pol: `
|
|
|
|
|
{
|
|
|
|
|
"acls": [
|
|
|
|
|
{
|
|
|
|
|
"action": "accept",
|
|
|
|
|
"proto": "",
|
|
|
|
|
"src": [
|
|
|
|
|
"100.64.0.1"
|
|
|
|
|
],
|
|
|
|
|
"dst": [
|
|
|
|
|
"100.64.0.2:*"
|
|
|
|
|
]
|
|
|
|
|
}
|
|
|
|
|
],
|
|
|
|
|
}
|
|
|
|
|
`,
|
|
|
|
|
node: &types.Node{
|
|
|
|
|
IPv4: ap("100.64.0.1"),
|
|
|
|
|
IPv6: ap("fd7a:115c:a1e0:ab12:4843:2222:6273:2221"),
|
2025-12-02 12:01:25 +01:00
|
|
|
User: ptr.To(users[0]),
|
2025-10-23 17:57:41 +02:00
|
|
|
},
|
|
|
|
|
peers: types.Nodes{
|
|
|
|
|
&types.Node{
|
|
|
|
|
IPv4: ap("100.64.0.2"),
|
|
|
|
|
IPv6: ap("fd7a:115c:a1e0:ab12:4843:2222:6273:2222"),
|
2025-12-02 12:01:25 +01:00
|
|
|
User: ptr.To(users[0]),
|
2025-10-23 17:57:41 +02:00
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
want: []tailcfg.FilterRule{},
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "1604-subnet-routers-are-preserved",
|
|
|
|
|
pol: `
|
|
|
|
|
{
|
|
|
|
|
"groups": {
|
|
|
|
|
"group:admins": [
|
|
|
|
|
"user1@"
|
|
|
|
|
]
|
|
|
|
|
},
|
|
|
|
|
"acls": [
|
|
|
|
|
{
|
|
|
|
|
"action": "accept",
|
|
|
|
|
"proto": "",
|
|
|
|
|
"src": [
|
|
|
|
|
"group:admins"
|
|
|
|
|
],
|
|
|
|
|
"dst": [
|
|
|
|
|
"group:admins:*"
|
|
|
|
|
]
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"action": "accept",
|
|
|
|
|
"proto": "",
|
|
|
|
|
"src": [
|
|
|
|
|
"group:admins"
|
|
|
|
|
],
|
|
|
|
|
"dst": [
|
|
|
|
|
"10.33.0.0/16:*"
|
|
|
|
|
]
|
|
|
|
|
}
|
|
|
|
|
],
|
|
|
|
|
}
|
|
|
|
|
`,
|
|
|
|
|
node: &types.Node{
|
|
|
|
|
IPv4: ap("100.64.0.1"),
|
|
|
|
|
IPv6: ap("fd7a:115c:a1e0::1"),
|
2025-12-02 12:01:25 +01:00
|
|
|
User: ptr.To(users[1]),
|
2025-10-23 17:57:41 +02:00
|
|
|
Hostinfo: &tailcfg.Hostinfo{
|
|
|
|
|
RoutableIPs: []netip.Prefix{
|
|
|
|
|
netip.MustParsePrefix("10.33.0.0/16"),
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
peers: types.Nodes{
|
|
|
|
|
&types.Node{
|
|
|
|
|
IPv4: ap("100.64.0.2"),
|
|
|
|
|
IPv6: ap("fd7a:115c:a1e0::2"),
|
2025-12-02 12:01:25 +01:00
|
|
|
User: ptr.To(users[1]),
|
2025-10-23 17:57:41 +02:00
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
want: []tailcfg.FilterRule{
|
2026-01-24 07:49:39 +00:00
|
|
|
// Merged: Both ACL rules combined (same SrcIPs and IPProto)
|
2025-10-23 17:57:41 +02:00
|
|
|
{
|
|
|
|
|
SrcIPs: []string{
|
|
|
|
|
"100.64.0.1/32",
|
|
|
|
|
"100.64.0.2/32",
|
|
|
|
|
"fd7a:115c:a1e0::1/128",
|
|
|
|
|
"fd7a:115c:a1e0::2/128",
|
|
|
|
|
},
|
|
|
|
|
DstPorts: []tailcfg.NetPortRange{
|
|
|
|
|
{
|
|
|
|
|
IP: "100.64.0.1/32",
|
|
|
|
|
Ports: tailcfg.PortRangeAny,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
IP: "fd7a:115c:a1e0::1/128",
|
|
|
|
|
Ports: tailcfg.PortRangeAny,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
IP: "10.33.0.0/16",
|
|
|
|
|
Ports: tailcfg.PortRangeAny,
|
|
|
|
|
},
|
|
|
|
|
},
|
policy: add ICMP protocols to default and export constants
When ACL rules don't specify a protocol, Headscale now defaults to
[TCP, UDP, ICMP, ICMPv6] instead of just [TCP, UDP], matching
Tailscale's behavior.
Also export protocol number constants (ProtocolTCP, ProtocolUDP, etc.)
for use in external test packages, renaming the string protocol
constants to ProtoNameTCP, ProtoNameUDP, etc. to avoid conflicts.
This resolves 78 ICMP-related TODOs in the Tailscale compatibility
tests, reducing the total from 165 to 87.
Updates #3036
2026-01-23 20:16:02 +00:00
|
|
|
IPProto: []int{v2.ProtocolTCP, v2.ProtocolUDP, v2.ProtocolICMP, v2.ProtocolIPv6ICMP},
|
2025-10-23 17:57:41 +02:00
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "1786-reducing-breaks-exit-nodes-the-client",
|
|
|
|
|
pol: `
|
|
|
|
|
{
|
|
|
|
|
"groups": {
|
|
|
|
|
"group:team": [
|
|
|
|
|
"user3@",
|
|
|
|
|
"user2@",
|
|
|
|
|
"user1@"
|
|
|
|
|
]
|
|
|
|
|
},
|
|
|
|
|
"hosts": {
|
|
|
|
|
"internal": "100.64.0.100/32"
|
|
|
|
|
},
|
|
|
|
|
"acls": [
|
|
|
|
|
{
|
|
|
|
|
"action": "accept",
|
|
|
|
|
"proto": "",
|
|
|
|
|
"src": [
|
|
|
|
|
"group:team"
|
|
|
|
|
],
|
|
|
|
|
"dst": [
|
|
|
|
|
"internal:*"
|
|
|
|
|
]
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"action": "accept",
|
|
|
|
|
"proto": "",
|
|
|
|
|
"src": [
|
|
|
|
|
"group:team"
|
|
|
|
|
],
|
|
|
|
|
"dst": [
|
|
|
|
|
"autogroup:internet:*"
|
|
|
|
|
]
|
|
|
|
|
}
|
|
|
|
|
],
|
|
|
|
|
}
|
|
|
|
|
`,
|
|
|
|
|
node: &types.Node{
|
|
|
|
|
IPv4: ap("100.64.0.1"),
|
|
|
|
|
IPv6: ap("fd7a:115c:a1e0::1"),
|
2025-12-02 12:01:25 +01:00
|
|
|
User: ptr.To(users[1]),
|
2025-10-23 17:57:41 +02:00
|
|
|
},
|
|
|
|
|
peers: types.Nodes{
|
|
|
|
|
&types.Node{
|
|
|
|
|
IPv4: ap("100.64.0.2"),
|
|
|
|
|
IPv6: ap("fd7a:115c:a1e0::2"),
|
2025-12-02 12:01:25 +01:00
|
|
|
User: ptr.To(users[2]),
|
2025-10-23 17:57:41 +02:00
|
|
|
},
|
|
|
|
|
// "internal" exit node
|
|
|
|
|
&types.Node{
|
|
|
|
|
IPv4: ap("100.64.0.100"),
|
|
|
|
|
IPv6: ap("fd7a:115c:a1e0::100"),
|
2025-12-02 12:01:25 +01:00
|
|
|
User: ptr.To(users[3]),
|
2025-10-23 17:57:41 +02:00
|
|
|
Hostinfo: &tailcfg.Hostinfo{
|
|
|
|
|
RoutableIPs: tsaddr.ExitRoutes(),
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
want: []tailcfg.FilterRule{},
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "1786-reducing-breaks-exit-nodes-the-exit",
|
|
|
|
|
pol: `
|
|
|
|
|
{
|
|
|
|
|
"groups": {
|
|
|
|
|
"group:team": [
|
|
|
|
|
"user3@",
|
|
|
|
|
"user2@",
|
|
|
|
|
"user1@"
|
|
|
|
|
]
|
|
|
|
|
},
|
|
|
|
|
"hosts": {
|
|
|
|
|
"internal": "100.64.0.100/32"
|
|
|
|
|
},
|
|
|
|
|
"acls": [
|
|
|
|
|
{
|
|
|
|
|
"action": "accept",
|
|
|
|
|
"proto": "",
|
|
|
|
|
"src": [
|
|
|
|
|
"group:team"
|
|
|
|
|
],
|
|
|
|
|
"dst": [
|
|
|
|
|
"internal:*"
|
|
|
|
|
]
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"action": "accept",
|
|
|
|
|
"proto": "",
|
|
|
|
|
"src": [
|
|
|
|
|
"group:team"
|
|
|
|
|
],
|
|
|
|
|
"dst": [
|
|
|
|
|
"autogroup:internet:*"
|
|
|
|
|
]
|
|
|
|
|
}
|
|
|
|
|
],
|
|
|
|
|
}
|
|
|
|
|
`,
|
|
|
|
|
node: &types.Node{
|
|
|
|
|
IPv4: ap("100.64.0.100"),
|
|
|
|
|
IPv6: ap("fd7a:115c:a1e0::100"),
|
2025-12-02 12:01:25 +01:00
|
|
|
User: ptr.To(users[3]),
|
2025-10-23 17:57:41 +02:00
|
|
|
Hostinfo: &tailcfg.Hostinfo{
|
|
|
|
|
RoutableIPs: tsaddr.ExitRoutes(),
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
peers: types.Nodes{
|
|
|
|
|
&types.Node{
|
|
|
|
|
IPv4: ap("100.64.0.2"),
|
|
|
|
|
IPv6: ap("fd7a:115c:a1e0::2"),
|
2025-12-02 12:01:25 +01:00
|
|
|
User: ptr.To(users[2]),
|
2025-10-23 17:57:41 +02:00
|
|
|
},
|
|
|
|
|
&types.Node{
|
|
|
|
|
IPv4: ap("100.64.0.1"),
|
|
|
|
|
IPv6: ap("fd7a:115c:a1e0::1"),
|
2025-12-02 12:01:25 +01:00
|
|
|
User: ptr.To(users[1]),
|
2025-10-23 17:57:41 +02:00
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
want: []tailcfg.FilterRule{
|
2026-01-28 13:08:38 +00:00
|
|
|
// Only the internal:* rule generates filters.
|
|
|
|
|
// autogroup:internet does NOT generate packet filters - it's handled
|
|
|
|
|
// by exit node routing via AllowedIPs, not by packet filtering.
|
2025-10-23 17:57:41 +02:00
|
|
|
{
|
|
|
|
|
SrcIPs: []string{"100.64.0.1/32", "100.64.0.2/32", "fd7a:115c:a1e0::1/128", "fd7a:115c:a1e0::2/128"},
|
2026-01-28 13:08:38 +00:00
|
|
|
DstPorts: []tailcfg.NetPortRange{
|
2025-10-23 17:57:41 +02:00
|
|
|
{
|
|
|
|
|
IP: "100.64.0.100/32",
|
|
|
|
|
Ports: tailcfg.PortRangeAny,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
IP: "fd7a:115c:a1e0::100/128",
|
|
|
|
|
Ports: tailcfg.PortRangeAny,
|
|
|
|
|
},
|
2026-01-28 13:08:38 +00:00
|
|
|
},
|
policy: add ICMP protocols to default and export constants
When ACL rules don't specify a protocol, Headscale now defaults to
[TCP, UDP, ICMP, ICMPv6] instead of just [TCP, UDP], matching
Tailscale's behavior.
Also export protocol number constants (ProtocolTCP, ProtocolUDP, etc.)
for use in external test packages, renaming the string protocol
constants to ProtoNameTCP, ProtoNameUDP, etc. to avoid conflicts.
This resolves 78 ICMP-related TODOs in the Tailscale compatibility
tests, reducing the total from 165 to 87.
Updates #3036
2026-01-23 20:16:02 +00:00
|
|
|
IPProto: []int{v2.ProtocolTCP, v2.ProtocolUDP, v2.ProtocolICMP, v2.ProtocolIPv6ICMP},
|
2025-10-23 17:57:41 +02:00
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "1786-reducing-breaks-exit-nodes-the-example-from-issue",
|
|
|
|
|
pol: `
|
|
|
|
|
{
|
|
|
|
|
"groups": {
|
|
|
|
|
"group:team": [
|
|
|
|
|
"user3@",
|
|
|
|
|
"user2@",
|
|
|
|
|
"user1@"
|
|
|
|
|
]
|
|
|
|
|
},
|
|
|
|
|
"hosts": {
|
|
|
|
|
"internal": "100.64.0.100/32"
|
|
|
|
|
},
|
|
|
|
|
"acls": [
|
|
|
|
|
{
|
|
|
|
|
"action": "accept",
|
|
|
|
|
"proto": "",
|
|
|
|
|
"src": [
|
|
|
|
|
"group:team"
|
|
|
|
|
],
|
|
|
|
|
"dst": [
|
|
|
|
|
"internal:*"
|
|
|
|
|
]
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"action": "accept",
|
|
|
|
|
"proto": "",
|
|
|
|
|
"src": [
|
|
|
|
|
"group:team"
|
|
|
|
|
],
|
|
|
|
|
"dst": [
|
|
|
|
|
"0.0.0.0/5:*",
|
|
|
|
|
"8.0.0.0/7:*",
|
|
|
|
|
"11.0.0.0/8:*",
|
|
|
|
|
"12.0.0.0/6:*",
|
|
|
|
|
"16.0.0.0/4:*",
|
|
|
|
|
"32.0.0.0/3:*",
|
|
|
|
|
"64.0.0.0/2:*",
|
|
|
|
|
"128.0.0.0/3:*",
|
|
|
|
|
"160.0.0.0/5:*",
|
|
|
|
|
"168.0.0.0/6:*",
|
|
|
|
|
"172.0.0.0/12:*",
|
|
|
|
|
"172.32.0.0/11:*",
|
|
|
|
|
"172.64.0.0/10:*",
|
|
|
|
|
"172.128.0.0/9:*",
|
|
|
|
|
"173.0.0.0/8:*",
|
|
|
|
|
"174.0.0.0/7:*",
|
|
|
|
|
"176.0.0.0/4:*",
|
|
|
|
|
"192.0.0.0/9:*",
|
|
|
|
|
"192.128.0.0/11:*",
|
|
|
|
|
"192.160.0.0/13:*",
|
|
|
|
|
"192.169.0.0/16:*",
|
|
|
|
|
"192.170.0.0/15:*",
|
|
|
|
|
"192.172.0.0/14:*",
|
|
|
|
|
"192.176.0.0/12:*",
|
|
|
|
|
"192.192.0.0/10:*",
|
|
|
|
|
"193.0.0.0/8:*",
|
|
|
|
|
"194.0.0.0/7:*",
|
|
|
|
|
"196.0.0.0/6:*",
|
|
|
|
|
"200.0.0.0/5:*",
|
|
|
|
|
"208.0.0.0/4:*"
|
|
|
|
|
]
|
|
|
|
|
}
|
|
|
|
|
],
|
|
|
|
|
}
|
|
|
|
|
`,
|
|
|
|
|
node: &types.Node{
|
|
|
|
|
IPv4: ap("100.64.0.100"),
|
|
|
|
|
IPv6: ap("fd7a:115c:a1e0::100"),
|
2025-12-02 12:01:25 +01:00
|
|
|
User: ptr.To(users[3]),
|
2025-10-23 17:57:41 +02:00
|
|
|
Hostinfo: &tailcfg.Hostinfo{
|
|
|
|
|
RoutableIPs: tsaddr.ExitRoutes(),
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
peers: types.Nodes{
|
|
|
|
|
&types.Node{
|
|
|
|
|
IPv4: ap("100.64.0.2"),
|
|
|
|
|
IPv6: ap("fd7a:115c:a1e0::2"),
|
2025-12-02 12:01:25 +01:00
|
|
|
User: ptr.To(users[2]),
|
2025-10-23 17:57:41 +02:00
|
|
|
},
|
|
|
|
|
&types.Node{
|
|
|
|
|
IPv4: ap("100.64.0.1"),
|
|
|
|
|
IPv6: ap("fd7a:115c:a1e0::1"),
|
2025-12-02 12:01:25 +01:00
|
|
|
User: ptr.To(users[1]),
|
2025-10-23 17:57:41 +02:00
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
want: []tailcfg.FilterRule{
|
2026-01-24 07:49:39 +00:00
|
|
|
// Merged: Both ACL rules combined (same SrcIPs and IPProto)
|
2025-10-23 17:57:41 +02:00
|
|
|
{
|
|
|
|
|
SrcIPs: []string{"100.64.0.1/32", "100.64.0.2/32", "fd7a:115c:a1e0::1/128", "fd7a:115c:a1e0::2/128"},
|
|
|
|
|
DstPorts: []tailcfg.NetPortRange{
|
|
|
|
|
{
|
|
|
|
|
IP: "100.64.0.100/32",
|
|
|
|
|
Ports: tailcfg.PortRangeAny,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
IP: "fd7a:115c:a1e0::100/128",
|
|
|
|
|
Ports: tailcfg.PortRangeAny,
|
|
|
|
|
},
|
|
|
|
|
{IP: "0.0.0.0/5", Ports: tailcfg.PortRangeAny},
|
|
|
|
|
{IP: "8.0.0.0/7", Ports: tailcfg.PortRangeAny},
|
|
|
|
|
{IP: "11.0.0.0/8", Ports: tailcfg.PortRangeAny},
|
|
|
|
|
{IP: "12.0.0.0/6", Ports: tailcfg.PortRangeAny},
|
|
|
|
|
{IP: "16.0.0.0/4", Ports: tailcfg.PortRangeAny},
|
|
|
|
|
{IP: "32.0.0.0/3", Ports: tailcfg.PortRangeAny},
|
|
|
|
|
{IP: "64.0.0.0/2", Ports: tailcfg.PortRangeAny},
|
|
|
|
|
{IP: "128.0.0.0/3", Ports: tailcfg.PortRangeAny},
|
|
|
|
|
{IP: "160.0.0.0/5", Ports: tailcfg.PortRangeAny},
|
|
|
|
|
{IP: "168.0.0.0/6", Ports: tailcfg.PortRangeAny},
|
|
|
|
|
{IP: "172.0.0.0/12", Ports: tailcfg.PortRangeAny},
|
|
|
|
|
{IP: "172.32.0.0/11", Ports: tailcfg.PortRangeAny},
|
|
|
|
|
{IP: "172.64.0.0/10", Ports: tailcfg.PortRangeAny},
|
|
|
|
|
{IP: "172.128.0.0/9", Ports: tailcfg.PortRangeAny},
|
|
|
|
|
{IP: "173.0.0.0/8", Ports: tailcfg.PortRangeAny},
|
|
|
|
|
{IP: "174.0.0.0/7", Ports: tailcfg.PortRangeAny},
|
|
|
|
|
{IP: "176.0.0.0/4", Ports: tailcfg.PortRangeAny},
|
|
|
|
|
{IP: "192.0.0.0/9", Ports: tailcfg.PortRangeAny},
|
|
|
|
|
{IP: "192.128.0.0/11", Ports: tailcfg.PortRangeAny},
|
|
|
|
|
{IP: "192.160.0.0/13", Ports: tailcfg.PortRangeAny},
|
|
|
|
|
{IP: "192.169.0.0/16", Ports: tailcfg.PortRangeAny},
|
|
|
|
|
{IP: "192.170.0.0/15", Ports: tailcfg.PortRangeAny},
|
|
|
|
|
{IP: "192.172.0.0/14", Ports: tailcfg.PortRangeAny},
|
|
|
|
|
{IP: "192.176.0.0/12", Ports: tailcfg.PortRangeAny},
|
|
|
|
|
{IP: "192.192.0.0/10", Ports: tailcfg.PortRangeAny},
|
|
|
|
|
{IP: "193.0.0.0/8", Ports: tailcfg.PortRangeAny},
|
|
|
|
|
{IP: "194.0.0.0/7", Ports: tailcfg.PortRangeAny},
|
|
|
|
|
{IP: "196.0.0.0/6", Ports: tailcfg.PortRangeAny},
|
|
|
|
|
{IP: "200.0.0.0/5", Ports: tailcfg.PortRangeAny},
|
|
|
|
|
{IP: "208.0.0.0/4", Ports: tailcfg.PortRangeAny},
|
|
|
|
|
},
|
policy: add ICMP protocols to default and export constants
When ACL rules don't specify a protocol, Headscale now defaults to
[TCP, UDP, ICMP, ICMPv6] instead of just [TCP, UDP], matching
Tailscale's behavior.
Also export protocol number constants (ProtocolTCP, ProtocolUDP, etc.)
for use in external test packages, renaming the string protocol
constants to ProtoNameTCP, ProtoNameUDP, etc. to avoid conflicts.
This resolves 78 ICMP-related TODOs in the Tailscale compatibility
tests, reducing the total from 165 to 87.
Updates #3036
2026-01-23 20:16:02 +00:00
|
|
|
IPProto: []int{v2.ProtocolTCP, v2.ProtocolUDP, v2.ProtocolICMP, v2.ProtocolIPv6ICMP},
|
2025-10-23 17:57:41 +02:00
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "1786-reducing-breaks-exit-nodes-app-connector-like",
|
|
|
|
|
pol: `
|
|
|
|
|
{
|
|
|
|
|
"groups": {
|
|
|
|
|
"group:team": [
|
|
|
|
|
"user3@",
|
|
|
|
|
"user2@",
|
|
|
|
|
"user1@"
|
|
|
|
|
]
|
|
|
|
|
},
|
|
|
|
|
"hosts": {
|
|
|
|
|
"internal": "100.64.0.100/32"
|
|
|
|
|
},
|
|
|
|
|
"acls": [
|
|
|
|
|
{
|
|
|
|
|
"action": "accept",
|
|
|
|
|
"proto": "",
|
|
|
|
|
"src": [
|
|
|
|
|
"group:team"
|
|
|
|
|
],
|
|
|
|
|
"dst": [
|
|
|
|
|
"internal:*"
|
|
|
|
|
]
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"action": "accept",
|
|
|
|
|
"proto": "",
|
|
|
|
|
"src": [
|
|
|
|
|
"group:team"
|
|
|
|
|
],
|
|
|
|
|
"dst": [
|
|
|
|
|
"8.0.0.0/8:*",
|
|
|
|
|
"16.0.0.0/8:*"
|
|
|
|
|
]
|
|
|
|
|
}
|
|
|
|
|
],
|
|
|
|
|
}
|
|
|
|
|
`,
|
|
|
|
|
node: &types.Node{
|
|
|
|
|
IPv4: ap("100.64.0.100"),
|
|
|
|
|
IPv6: ap("fd7a:115c:a1e0::100"),
|
2025-12-02 12:01:25 +01:00
|
|
|
User: ptr.To(users[3]),
|
2025-10-23 17:57:41 +02:00
|
|
|
Hostinfo: &tailcfg.Hostinfo{
|
|
|
|
|
RoutableIPs: []netip.Prefix{netip.MustParsePrefix("8.0.0.0/16"), netip.MustParsePrefix("16.0.0.0/16")},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
peers: types.Nodes{
|
|
|
|
|
&types.Node{
|
|
|
|
|
IPv4: ap("100.64.0.2"),
|
|
|
|
|
IPv6: ap("fd7a:115c:a1e0::2"),
|
2025-12-02 12:01:25 +01:00
|
|
|
User: ptr.To(users[2]),
|
2025-10-23 17:57:41 +02:00
|
|
|
},
|
|
|
|
|
&types.Node{
|
|
|
|
|
IPv4: ap("100.64.0.1"),
|
|
|
|
|
IPv6: ap("fd7a:115c:a1e0::1"),
|
2025-12-02 12:01:25 +01:00
|
|
|
User: ptr.To(users[1]),
|
2025-10-23 17:57:41 +02:00
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
want: []tailcfg.FilterRule{
|
2026-01-24 07:49:39 +00:00
|
|
|
// Merged: Both ACL rules combined (same SrcIPs and IPProto)
|
2025-10-23 17:57:41 +02:00
|
|
|
{
|
|
|
|
|
SrcIPs: []string{"100.64.0.1/32", "100.64.0.2/32", "fd7a:115c:a1e0::1/128", "fd7a:115c:a1e0::2/128"},
|
|
|
|
|
DstPorts: []tailcfg.NetPortRange{
|
|
|
|
|
{
|
|
|
|
|
IP: "100.64.0.100/32",
|
|
|
|
|
Ports: tailcfg.PortRangeAny,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
IP: "fd7a:115c:a1e0::100/128",
|
|
|
|
|
Ports: tailcfg.PortRangeAny,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
IP: "8.0.0.0/8",
|
|
|
|
|
Ports: tailcfg.PortRangeAny,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
IP: "16.0.0.0/8",
|
|
|
|
|
Ports: tailcfg.PortRangeAny,
|
|
|
|
|
},
|
|
|
|
|
},
|
policy: add ICMP protocols to default and export constants
When ACL rules don't specify a protocol, Headscale now defaults to
[TCP, UDP, ICMP, ICMPv6] instead of just [TCP, UDP], matching
Tailscale's behavior.
Also export protocol number constants (ProtocolTCP, ProtocolUDP, etc.)
for use in external test packages, renaming the string protocol
constants to ProtoNameTCP, ProtoNameUDP, etc. to avoid conflicts.
This resolves 78 ICMP-related TODOs in the Tailscale compatibility
tests, reducing the total from 165 to 87.
Updates #3036
2026-01-23 20:16:02 +00:00
|
|
|
IPProto: []int{v2.ProtocolTCP, v2.ProtocolUDP, v2.ProtocolICMP, v2.ProtocolIPv6ICMP},
|
2025-10-23 17:57:41 +02:00
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "1786-reducing-breaks-exit-nodes-app-connector-like2",
|
|
|
|
|
pol: `
|
|
|
|
|
{
|
|
|
|
|
"groups": {
|
|
|
|
|
"group:team": [
|
|
|
|
|
"user3@",
|
|
|
|
|
"user2@",
|
|
|
|
|
"user1@"
|
|
|
|
|
]
|
|
|
|
|
},
|
|
|
|
|
"hosts": {
|
|
|
|
|
"internal": "100.64.0.100/32"
|
|
|
|
|
},
|
|
|
|
|
"acls": [
|
|
|
|
|
{
|
|
|
|
|
"action": "accept",
|
|
|
|
|
"proto": "",
|
|
|
|
|
"src": [
|
|
|
|
|
"group:team"
|
|
|
|
|
],
|
|
|
|
|
"dst": [
|
|
|
|
|
"internal:*"
|
|
|
|
|
]
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"action": "accept",
|
|
|
|
|
"proto": "",
|
|
|
|
|
"src": [
|
|
|
|
|
"group:team"
|
|
|
|
|
],
|
|
|
|
|
"dst": [
|
|
|
|
|
"8.0.0.0/16:*",
|
|
|
|
|
"16.0.0.0/16:*"
|
|
|
|
|
]
|
|
|
|
|
}
|
|
|
|
|
],
|
|
|
|
|
}
|
|
|
|
|
`,
|
|
|
|
|
node: &types.Node{
|
|
|
|
|
IPv4: ap("100.64.0.100"),
|
|
|
|
|
IPv6: ap("fd7a:115c:a1e0::100"),
|
2025-12-02 12:01:25 +01:00
|
|
|
User: ptr.To(users[3]),
|
2025-10-23 17:57:41 +02:00
|
|
|
Hostinfo: &tailcfg.Hostinfo{
|
|
|
|
|
RoutableIPs: []netip.Prefix{netip.MustParsePrefix("8.0.0.0/8"), netip.MustParsePrefix("16.0.0.0/8")},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
peers: types.Nodes{
|
|
|
|
|
&types.Node{
|
|
|
|
|
IPv4: ap("100.64.0.2"),
|
|
|
|
|
IPv6: ap("fd7a:115c:a1e0::2"),
|
2025-12-02 12:01:25 +01:00
|
|
|
User: ptr.To(users[2]),
|
2025-10-23 17:57:41 +02:00
|
|
|
},
|
|
|
|
|
&types.Node{
|
|
|
|
|
IPv4: ap("100.64.0.1"),
|
|
|
|
|
IPv6: ap("fd7a:115c:a1e0::1"),
|
2025-12-02 12:01:25 +01:00
|
|
|
User: ptr.To(users[1]),
|
2025-10-23 17:57:41 +02:00
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
want: []tailcfg.FilterRule{
|
2026-01-24 07:49:39 +00:00
|
|
|
// Merged: Both ACL rules combined (same SrcIPs and IPProto)
|
2025-10-23 17:57:41 +02:00
|
|
|
{
|
|
|
|
|
SrcIPs: []string{"100.64.0.1/32", "100.64.0.2/32", "fd7a:115c:a1e0::1/128", "fd7a:115c:a1e0::2/128"},
|
|
|
|
|
DstPorts: []tailcfg.NetPortRange{
|
|
|
|
|
{
|
|
|
|
|
IP: "100.64.0.100/32",
|
|
|
|
|
Ports: tailcfg.PortRangeAny,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
IP: "fd7a:115c:a1e0::100/128",
|
|
|
|
|
Ports: tailcfg.PortRangeAny,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
IP: "8.0.0.0/16",
|
|
|
|
|
Ports: tailcfg.PortRangeAny,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
IP: "16.0.0.0/16",
|
|
|
|
|
Ports: tailcfg.PortRangeAny,
|
|
|
|
|
},
|
|
|
|
|
},
|
policy: add ICMP protocols to default and export constants
When ACL rules don't specify a protocol, Headscale now defaults to
[TCP, UDP, ICMP, ICMPv6] instead of just [TCP, UDP], matching
Tailscale's behavior.
Also export protocol number constants (ProtocolTCP, ProtocolUDP, etc.)
for use in external test packages, renaming the string protocol
constants to ProtoNameTCP, ProtoNameUDP, etc. to avoid conflicts.
This resolves 78 ICMP-related TODOs in the Tailscale compatibility
tests, reducing the total from 165 to 87.
Updates #3036
2026-01-23 20:16:02 +00:00
|
|
|
IPProto: []int{v2.ProtocolTCP, v2.ProtocolUDP, v2.ProtocolICMP, v2.ProtocolIPv6ICMP},
|
2025-10-23 17:57:41 +02:00
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "1817-reduce-breaks-32-mask",
|
|
|
|
|
pol: `
|
|
|
|
|
{
|
|
|
|
|
"tagOwners": {
|
|
|
|
|
"tag:access-servers": ["user100@"],
|
|
|
|
|
},
|
|
|
|
|
"groups": {
|
|
|
|
|
"group:access": [
|
|
|
|
|
"user1@"
|
|
|
|
|
]
|
|
|
|
|
},
|
|
|
|
|
"hosts": {
|
|
|
|
|
"dns1": "172.16.0.21/32",
|
|
|
|
|
"vlan1": "172.16.0.0/24"
|
|
|
|
|
},
|
|
|
|
|
"acls": [
|
|
|
|
|
{
|
|
|
|
|
"action": "accept",
|
|
|
|
|
"proto": "",
|
|
|
|
|
"src": [
|
|
|
|
|
"group:access"
|
|
|
|
|
],
|
|
|
|
|
"dst": [
|
|
|
|
|
"tag:access-servers:*",
|
|
|
|
|
"dns1:*"
|
|
|
|
|
]
|
|
|
|
|
}
|
|
|
|
|
],
|
|
|
|
|
}
|
|
|
|
|
`,
|
|
|
|
|
node: &types.Node{
|
|
|
|
|
IPv4: ap("100.64.0.100"),
|
|
|
|
|
IPv6: ap("fd7a:115c:a1e0::100"),
|
2025-12-02 12:01:25 +01:00
|
|
|
User: ptr.To(users[3]),
|
2025-10-23 17:57:41 +02:00
|
|
|
Hostinfo: &tailcfg.Hostinfo{
|
|
|
|
|
RoutableIPs: []netip.Prefix{netip.MustParsePrefix("172.16.0.0/24")},
|
|
|
|
|
},
|
2025-12-02 12:01:25 +01:00
|
|
|
Tags: []string{"tag:access-servers"},
|
2025-10-23 17:57:41 +02:00
|
|
|
},
|
|
|
|
|
peers: types.Nodes{
|
|
|
|
|
&types.Node{
|
|
|
|
|
IPv4: ap("100.64.0.1"),
|
|
|
|
|
IPv6: ap("fd7a:115c:a1e0::1"),
|
2025-12-02 12:01:25 +01:00
|
|
|
User: ptr.To(users[1]),
|
2025-10-23 17:57:41 +02:00
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
want: []tailcfg.FilterRule{
|
|
|
|
|
{
|
|
|
|
|
SrcIPs: []string{"100.64.0.1/32", "fd7a:115c:a1e0::1/128"},
|
|
|
|
|
DstPorts: []tailcfg.NetPortRange{
|
|
|
|
|
{
|
|
|
|
|
IP: "100.64.0.100/32",
|
|
|
|
|
Ports: tailcfg.PortRangeAny,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
IP: "fd7a:115c:a1e0::100/128",
|
|
|
|
|
Ports: tailcfg.PortRangeAny,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
IP: "172.16.0.21/32",
|
|
|
|
|
Ports: tailcfg.PortRangeAny,
|
|
|
|
|
},
|
|
|
|
|
},
|
policy: add ICMP protocols to default and export constants
When ACL rules don't specify a protocol, Headscale now defaults to
[TCP, UDP, ICMP, ICMPv6] instead of just [TCP, UDP], matching
Tailscale's behavior.
Also export protocol number constants (ProtocolTCP, ProtocolUDP, etc.)
for use in external test packages, renaming the string protocol
constants to ProtoNameTCP, ProtoNameUDP, etc. to avoid conflicts.
This resolves 78 ICMP-related TODOs in the Tailscale compatibility
tests, reducing the total from 165 to 87.
Updates #3036
2026-01-23 20:16:02 +00:00
|
|
|
IPProto: []int{v2.ProtocolTCP, v2.ProtocolUDP, v2.ProtocolICMP, v2.ProtocolIPv6ICMP},
|
2025-10-23 17:57:41 +02:00
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "2365-only-route-policy",
|
|
|
|
|
pol: `
|
|
|
|
|
{
|
|
|
|
|
"hosts": {
|
|
|
|
|
"router": "100.64.0.1/32",
|
|
|
|
|
"node": "100.64.0.2/32"
|
|
|
|
|
},
|
|
|
|
|
"acls": [
|
|
|
|
|
{
|
|
|
|
|
"action": "accept",
|
|
|
|
|
"src": [
|
|
|
|
|
"*"
|
|
|
|
|
],
|
|
|
|
|
"dst": [
|
|
|
|
|
"router:8000"
|
|
|
|
|
]
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"action": "accept",
|
|
|
|
|
"src": [
|
|
|
|
|
"node"
|
|
|
|
|
],
|
|
|
|
|
"dst": [
|
|
|
|
|
"172.26.0.0/16:*"
|
|
|
|
|
]
|
|
|
|
|
}
|
|
|
|
|
],
|
|
|
|
|
}
|
|
|
|
|
`,
|
|
|
|
|
node: &types.Node{
|
|
|
|
|
IPv4: ap("100.64.0.2"),
|
|
|
|
|
IPv6: ap("fd7a:115c:a1e0::2"),
|
2025-12-02 12:01:25 +01:00
|
|
|
User: ptr.To(users[3]),
|
2025-10-23 17:57:41 +02:00
|
|
|
},
|
|
|
|
|
peers: types.Nodes{
|
|
|
|
|
&types.Node{
|
|
|
|
|
IPv4: ap("100.64.0.1"),
|
|
|
|
|
IPv6: ap("fd7a:115c:a1e0::1"),
|
2025-12-02 12:01:25 +01:00
|
|
|
User: ptr.To(users[1]),
|
2025-10-23 17:57:41 +02:00
|
|
|
Hostinfo: &tailcfg.Hostinfo{
|
|
|
|
|
RoutableIPs: []netip.Prefix{p("172.16.0.0/24"), p("10.10.11.0/24"), p("10.10.12.0/24")},
|
|
|
|
|
},
|
|
|
|
|
ApprovedRoutes: []netip.Prefix{p("172.16.0.0/24"), p("10.10.11.0/24"), p("10.10.12.0/24")},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
want: []tailcfg.FilterRule{},
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for _, tt := range tests {
|
|
|
|
|
for idx, pmf := range policy.PolicyManagerFuncsForTest([]byte(tt.pol)) {
|
|
|
|
|
t.Run(fmt.Sprintf("%s-index%d", tt.name, idx), func(t *testing.T) {
|
2026-02-06 21:45:32 +01:00
|
|
|
var (
|
|
|
|
|
pm policy.PolicyManager
|
|
|
|
|
err error
|
|
|
|
|
)
|
|
|
|
|
|
2025-10-23 17:57:41 +02:00
|
|
|
pm, err = pmf(users, append(tt.peers, tt.node).ViewSlice())
|
|
|
|
|
require.NoError(t, err)
|
2026-02-06 21:45:32 +01:00
|
|
|
|
2025-10-23 17:57:41 +02:00
|
|
|
got, _ := pm.Filter()
|
|
|
|
|
t.Logf("full filter:\n%s", must.Get(json.MarshalIndent(got, "", " ")))
|
|
|
|
|
got = policyutil.ReduceFilterRules(tt.node.View(), got)
|
|
|
|
|
|
|
|
|
|
if diff := cmp.Diff(tt.want, got); diff != "" {
|
|
|
|
|
log.Trace().Interface("got", got).Msg("result")
|
|
|
|
|
t.Errorf("TestReduceFilterRules() unexpected result (-want +got):\n%s", diff)
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|