policy: use CGNAT/ULA ranges for wildcard resolution

Change Asterix.Resolve() to use Tailscale's CGNAT range (100.64.0.0/10)
and ULA range (fd7a:115c:a1e0::/48) instead of all IPs (0.0.0.0/0 and
::/0).
This better matches Tailscale's security model where wildcard (*) means
"any node in the tailnet" rather than literally "any IP address on the
internet".
Updates #3036

Updates #3036
This commit is contained in:
Kristoffer Dalby
2026-01-23 20:52:35 +00:00
parent ebdbe03639
commit 8baa14ef4a
4 changed files with 410 additions and 412 deletions

View File

@@ -97,10 +97,10 @@ func TestParsing(t *testing.T) {
{ {
SrcIPs: []string{"100.100.101.0/24", "192.168.1.0/24"}, SrcIPs: []string{"100.100.101.0/24", "192.168.1.0/24"},
DstPorts: []tailcfg.NetPortRange{ DstPorts: []tailcfg.NetPortRange{
{IP: "0.0.0.0/0", Ports: tailcfg.PortRange{First: 22, Last: 22}}, {IP: "100.64.0.0/10", Ports: tailcfg.PortRange{First: 22, Last: 22}},
{IP: "0.0.0.0/0", Ports: tailcfg.PortRange{First: 3389, Last: 3389}}, {IP: "100.64.0.0/10", Ports: tailcfg.PortRange{First: 3389, Last: 3389}},
{IP: "::/0", Ports: tailcfg.PortRange{First: 22, Last: 22}}, {IP: "fd7a:115c:a1e0::/48", Ports: tailcfg.PortRange{First: 22, Last: 22}},
{IP: "::/0", Ports: tailcfg.PortRange{First: 3389, Last: 3389}}, {IP: "fd7a:115c:a1e0::/48", Ports: tailcfg.PortRange{First: 3389, Last: 3389}},
{IP: "100.100.100.100/32", Ports: tailcfg.PortRangeAny}, {IP: "100.100.100.100/32", Ports: tailcfg.PortRangeAny},
}, },
IPProto: []int{ProtocolTCP, ProtocolUDP, ProtocolICMP, ProtocolIPv6ICMP}, IPProto: []int{ProtocolTCP, ProtocolUDP, ProtocolICMP, ProtocolIPv6ICMP},
@@ -153,21 +153,21 @@ func TestParsing(t *testing.T) {
}`, }`,
want: []tailcfg.FilterRule{ want: []tailcfg.FilterRule{
{ {
SrcIPs: []string{"0.0.0.0/0", "::/0"}, SrcIPs: []string{"100.64.0.0/10", "fd7a:115c:a1e0::/48"},
DstPorts: []tailcfg.NetPortRange{ DstPorts: []tailcfg.NetPortRange{
{IP: "100.100.100.100/32", Ports: tailcfg.PortRangeAny}, {IP: "100.100.100.100/32", Ports: tailcfg.PortRangeAny},
}, },
IPProto: []int{ProtocolTCP}, IPProto: []int{ProtocolTCP},
}, },
{ {
SrcIPs: []string{"0.0.0.0/0", "::/0"}, SrcIPs: []string{"100.64.0.0/10", "fd7a:115c:a1e0::/48"},
DstPorts: []tailcfg.NetPortRange{ DstPorts: []tailcfg.NetPortRange{
{IP: "100.100.100.100/32", Ports: tailcfg.PortRange{First: 53, Last: 53}}, {IP: "100.100.100.100/32", Ports: tailcfg.PortRange{First: 53, Last: 53}},
}, },
IPProto: []int{ProtocolUDP}, IPProto: []int{ProtocolUDP},
}, },
{ {
SrcIPs: []string{"0.0.0.0/0", "::/0"}, SrcIPs: []string{"100.64.0.0/10", "fd7a:115c:a1e0::/48"},
DstPorts: []tailcfg.NetPortRange{ DstPorts: []tailcfg.NetPortRange{
{IP: "100.100.100.100/32", Ports: tailcfg.PortRangeAny}, {IP: "100.100.100.100/32", Ports: tailcfg.PortRangeAny},
}, },
@@ -201,7 +201,7 @@ func TestParsing(t *testing.T) {
`, `,
want: []tailcfg.FilterRule{ want: []tailcfg.FilterRule{
{ {
SrcIPs: []string{"0.0.0.0/0", "::/0"}, SrcIPs: []string{"100.64.0.0/10", "fd7a:115c:a1e0::/48"},
DstPorts: []tailcfg.NetPortRange{ DstPorts: []tailcfg.NetPortRange{
{IP: "100.100.100.100/32", Ports: tailcfg.PortRangeAny}, {IP: "100.100.100.100/32", Ports: tailcfg.PortRangeAny},
}, },
@@ -346,7 +346,7 @@ func TestParsing(t *testing.T) {
`, `,
want: []tailcfg.FilterRule{ want: []tailcfg.FilterRule{
{ {
SrcIPs: []string{"0.0.0.0/0", "::/0"}, SrcIPs: []string{"100.64.0.0/10", "fd7a:115c:a1e0::/48"},
DstPorts: []tailcfg.NetPortRange{ DstPorts: []tailcfg.NetPortRange{
{IP: "100.100.100.100/32", Ports: tailcfg.PortRangeAny}, {IP: "100.100.100.100/32", Ports: tailcfg.PortRangeAny},
}, },

File diff suppressed because it is too large Load Diff

View File

@@ -122,11 +122,11 @@ func (a Asterix) UnmarshalJSON(b []byte) error {
func (a Asterix) Resolve(_ *Policy, _ types.Users, nodes views.Slice[types.NodeView]) (*netipx.IPSet, error) { func (a Asterix) Resolve(_ *Policy, _ types.Users, nodes views.Slice[types.NodeView]) (*netipx.IPSet, error) {
var ips netipx.IPSetBuilder var ips netipx.IPSetBuilder
// TODO(kradalby): // Use Tailscale's CGNAT range for IPv4 and ULA range for IPv6.
// Should this actually only be the CGNAT spaces? I do not think so, because // This matches Tailscale's behavior where wildcard (*) refers to
// we also want to include subnet routers right? // "any node in the tailnet" which uses these address ranges.
ips.AddPrefix(tsaddr.AllIPv4()) ips.AddPrefix(tsaddr.CGNATRange())
ips.AddPrefix(tsaddr.AllIPv6()) ips.AddPrefix(tsaddr.TailscaleULARange())
return ips.IPSet() return ips.IPSet()
} }

View File

@@ -2101,7 +2101,7 @@ func TestResolvePolicy(t *testing.T) {
{ {
name: "wildcard-alias", name: "wildcard-alias",
toResolve: Wildcard, toResolve: Wildcard,
want: []netip.Prefix{tsaddr.AllIPv4(), tsaddr.AllIPv6()}, want: []netip.Prefix{tsaddr.CGNATRange(), tsaddr.TailscaleULARange()},
}, },
{ {
name: "autogroup-member-comprehensive", name: "autogroup-member-comprehensive",