mirror of
				https://github.com/juanfont/headscale.git
				synced 2025-11-04 01:51:04 +01:00 
			
		
		
		
	add autogroup:internet, fix reduce filter rules (#1917)
This commit is contained in:
		
							parent
							
								
									ff427ccb78
								
							
						
					
					
						commit
						87e2ae4d52
					
				@ -56,6 +56,7 @@ after improving the test harness as part of adopting [#1460](https://github.com/
 | 
			
		||||
- Add support for deleting api keys [#1702](https://github.com/juanfont/headscale/pull/1702)
 | 
			
		||||
- Add command to backfill IP addresses for nodes missing IPs from configured prefixes. [#1869](https://github.com/juanfont/headscale/pull/1869)
 | 
			
		||||
- Log available update as warning [#1877](https://github.com/juanfont/headscale/pull/1877)
 | 
			
		||||
- Add `autogroup:internet` to Policy [#1917](https://github.com/juanfont/headscale/pull/1917)
 | 
			
		||||
 | 
			
		||||
## 0.22.3 (2023-05-12)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -36,6 +36,38 @@ const (
 | 
			
		||||
	expectedTokenItems = 2
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var theInternetSet *netipx.IPSet
 | 
			
		||||
 | 
			
		||||
// theInternet returns the IPSet for the Internet.
 | 
			
		||||
// https://www.youtube.com/watch?v=iDbyYGrswtg
 | 
			
		||||
func theInternet() *netipx.IPSet {
 | 
			
		||||
	if theInternetSet != nil {
 | 
			
		||||
		return theInternetSet
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var internetBuilder netipx.IPSetBuilder
 | 
			
		||||
	internetBuilder.AddPrefix(netip.MustParsePrefix("2000::/3"))
 | 
			
		||||
	internetBuilder.AddPrefix(netip.MustParsePrefix("0.0.0.0/0"))
 | 
			
		||||
 | 
			
		||||
	// Delete Private network addresses
 | 
			
		||||
	// https://datatracker.ietf.org/doc/html/rfc1918
 | 
			
		||||
	internetBuilder.RemovePrefix(netip.MustParsePrefix("fc00::/7"))
 | 
			
		||||
	internetBuilder.RemovePrefix(netip.MustParsePrefix("10.0.0.0/8"))
 | 
			
		||||
	internetBuilder.RemovePrefix(netip.MustParsePrefix("172.16.0.0/12"))
 | 
			
		||||
	internetBuilder.RemovePrefix(netip.MustParsePrefix("192.168.0.0/16"))
 | 
			
		||||
 | 
			
		||||
	// Delete Tailscale networks
 | 
			
		||||
	internetBuilder.RemovePrefix(netip.MustParsePrefix("fd7a:115c:a1e0::/48"))
 | 
			
		||||
	internetBuilder.RemovePrefix(netip.MustParsePrefix("100.64.0.0/10"))
 | 
			
		||||
 | 
			
		||||
	// Delete "cant find DHCP networks"
 | 
			
		||||
	internetBuilder.RemovePrefix(netip.MustParsePrefix("fe80::/10")) // link-loca
 | 
			
		||||
	internetBuilder.RemovePrefix(netip.MustParsePrefix("169.254.0.0/16"))
 | 
			
		||||
 | 
			
		||||
	theInternetSet, _ := internetBuilder.IPSet()
 | 
			
		||||
	return theInternetSet
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// For some reason golang.org/x/net/internal/iana is an internal package.
 | 
			
		||||
const (
 | 
			
		||||
	protocolICMP     = 1   // Internet Control Message
 | 
			
		||||
@ -221,28 +253,28 @@ func ReduceFilterRules(node *types.Node, rules []tailcfg.FilterRule) []tailcfg.F
 | 
			
		||||
		// record if the rule is actually relevant for the given node.
 | 
			
		||||
		dests := []tailcfg.NetPortRange{}
 | 
			
		||||
 | 
			
		||||
	DEST_LOOP:
 | 
			
		||||
		for _, dest := range rule.DstPorts {
 | 
			
		||||
			expanded, err := util.ParseIPSet(dest.IP, nil)
 | 
			
		||||
			// Fail closed, if we cant parse it, then we should not allow
 | 
			
		||||
			// access.
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				continue
 | 
			
		||||
				continue DEST_LOOP
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if node.InIPSet(expanded) {
 | 
			
		||||
				dests = append(dests, dest)
 | 
			
		||||
				continue DEST_LOOP
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// If the node exposes routes, ensure they are note removed
 | 
			
		||||
			// when the filters are reduced.
 | 
			
		||||
			if node.Hostinfo != nil {
 | 
			
		||||
				// TODO(kradalby): Evaluate if we should only keep
 | 
			
		||||
				// the routes if the route is enabled. This will
 | 
			
		||||
				// require database access in this part of the code.
 | 
			
		||||
				if len(node.Hostinfo.RoutableIPs) > 0 {
 | 
			
		||||
					for _, routableIP := range node.Hostinfo.RoutableIPs {
 | 
			
		||||
						if expanded.ContainsPrefix(routableIP) {
 | 
			
		||||
						if expanded.OverlapsPrefix(routableIP) {
 | 
			
		||||
							dests = append(dests, dest)
 | 
			
		||||
							continue DEST_LOOP
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
@ -517,6 +549,7 @@ func (pol *ACLPolicy) expandSource(
 | 
			
		||||
// - a host
 | 
			
		||||
// - an ip
 | 
			
		||||
// - a cidr
 | 
			
		||||
// - an autogroup
 | 
			
		||||
// and transform these in IPAddresses.
 | 
			
		||||
func (pol *ACLPolicy) ExpandAlias(
 | 
			
		||||
	nodes types.Nodes,
 | 
			
		||||
@ -542,6 +575,10 @@ func (pol *ACLPolicy) ExpandAlias(
 | 
			
		||||
		return pol.expandIPsFromTag(alias, nodes)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if isAutoGroup(alias) {
 | 
			
		||||
		return expandAutoGroup(alias)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// if alias is a user
 | 
			
		||||
	if ips, err := pol.expandIPsFromUser(alias, nodes); ips != nil {
 | 
			
		||||
		return ips, err
 | 
			
		||||
@ -862,6 +899,16 @@ func (pol *ACLPolicy) expandIPsFromIPPrefix(
 | 
			
		||||
	return build.IPSet()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func expandAutoGroup(alias string) (*netipx.IPSet, error) {
 | 
			
		||||
	switch {
 | 
			
		||||
	case strings.HasPrefix(alias, "autogroup:internet"):
 | 
			
		||||
		return theInternet(), nil
 | 
			
		||||
 | 
			
		||||
	default:
 | 
			
		||||
		return nil, fmt.Errorf("unknown autogroup %q", alias)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func isWildcard(str string) bool {
 | 
			
		||||
	return str == "*"
 | 
			
		||||
}
 | 
			
		||||
@ -874,6 +921,10 @@ func isTag(str string) bool {
 | 
			
		||||
	return strings.HasPrefix(str, "tag:")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func isAutoGroup(str string) bool {
 | 
			
		||||
	return strings.HasPrefix(str, "autogroup:")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// TagsOfNode will return the tags of the current node.
 | 
			
		||||
// Invalid tags are tags added by a user on a node, and that user doesn't have authority to add this tag.
 | 
			
		||||
// Valid tags are tags added by a user that is allowed in the ACL policy to add this tag.
 | 
			
		||||
 | 
			
		||||
@ -1765,6 +1765,108 @@ func TestACLPolicy_generateFilterRules(t *testing.T) {
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// tsExitNodeDest is the list of destination IP ranges that are allowed when
 | 
			
		||||
// you dump the filter list from a Tailscale node connected to Tailscale SaaS.
 | 
			
		||||
var tsExitNodeDest = []tailcfg.NetPortRange{
 | 
			
		||||
	{
 | 
			
		||||
		IP:    "0.0.0.0-9.255.255.255",
 | 
			
		||||
		Ports: tailcfg.PortRangeAny,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		IP:    "11.0.0.0-100.63.255.255",
 | 
			
		||||
		Ports: tailcfg.PortRangeAny,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		IP:    "100.128.0.0-169.253.255.255",
 | 
			
		||||
		Ports: tailcfg.PortRangeAny,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		IP:    "169.255.0.0-172.15.255.255",
 | 
			
		||||
		Ports: tailcfg.PortRangeAny,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		IP:    "172.32.0.0-192.167.255.255",
 | 
			
		||||
		Ports: tailcfg.PortRangeAny,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		IP:    "192.169.0.0-255.255.255.255",
 | 
			
		||||
		Ports: tailcfg.PortRangeAny,
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		IP:    "2000::-3fff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
 | 
			
		||||
		Ports: tailcfg.PortRangeAny,
 | 
			
		||||
	},
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// hsExitNodeDest is the list of destination IP ranges that are allowed when
 | 
			
		||||
// we use headscale "autogroup:internet"
 | 
			
		||||
var hsExitNodeDest = []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 := theInternet()
 | 
			
		||||
 | 
			
		||||
	internetPrefs := internetSet.Prefixes()
 | 
			
		||||
 | 
			
		||||
	for i, _ := range internetPrefs {
 | 
			
		||||
		if internetPrefs[i].String() != hsExitNodeDest[i].IP {
 | 
			
		||||
			t.Errorf("prefix from internet set %q != hsExit list %q", internetPrefs[i].String(), hsExitNodeDest[i].IP)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(internetPrefs) != len(hsExitNodeDest) {
 | 
			
		||||
		t.Fatalf("expected same length of prefixes, internet: %d, hsExit: %d", len(internetPrefs), len(hsExitNodeDest))
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestReduceFilterRules(t *testing.T) {
 | 
			
		||||
	tests := []struct {
 | 
			
		||||
		name  string
 | 
			
		||||
@ -1869,15 +1971,473 @@ func TestReduceFilterRules(t *testing.T) {
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name: "1786-reducing-breaks-exit-nodes-the-client",
 | 
			
		||||
			pol: ACLPolicy{
 | 
			
		||||
				Hosts: Hosts{
 | 
			
		||||
					// Exit node
 | 
			
		||||
					"internal": netip.MustParsePrefix("100.64.0.100/32"),
 | 
			
		||||
				},
 | 
			
		||||
				Groups: Groups{
 | 
			
		||||
					"group:team": {"user3", "user2", "user1"},
 | 
			
		||||
				},
 | 
			
		||||
				ACLs: []ACL{
 | 
			
		||||
					{
 | 
			
		||||
						Action:  "accept",
 | 
			
		||||
						Sources: []string{"group:team"},
 | 
			
		||||
						Destinations: []string{
 | 
			
		||||
							"internal:*",
 | 
			
		||||
						},
 | 
			
		||||
					},
 | 
			
		||||
					{
 | 
			
		||||
						Action:  "accept",
 | 
			
		||||
						Sources: []string{"group:team"},
 | 
			
		||||
						Destinations: []string{
 | 
			
		||||
							"autogroup:internet:*",
 | 
			
		||||
						},
 | 
			
		||||
					},
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			node: &types.Node{
 | 
			
		||||
				IPv4: iap("100.64.0.1"),
 | 
			
		||||
				IPv6: iap("fd7a:115c:a1e0::1"),
 | 
			
		||||
				User: types.User{Name: "user1"},
 | 
			
		||||
			},
 | 
			
		||||
			peers: types.Nodes{
 | 
			
		||||
				&types.Node{
 | 
			
		||||
					IPv4: iap("100.64.0.2"),
 | 
			
		||||
					IPv6: iap("fd7a:115c:a1e0::2"),
 | 
			
		||||
					User: types.User{Name: "user2"},
 | 
			
		||||
				},
 | 
			
		||||
				// "internal" exit node
 | 
			
		||||
				&types.Node{
 | 
			
		||||
					IPv4: iap("100.64.0.100"),
 | 
			
		||||
					IPv6: iap("fd7a:115c:a1e0::100"),
 | 
			
		||||
					User: types.User{Name: "user100"},
 | 
			
		||||
					Hostinfo: &tailcfg.Hostinfo{
 | 
			
		||||
						RoutableIPs: []netip.Prefix{types.ExitRouteV4, types.ExitRouteV6},
 | 
			
		||||
					},
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			want: []tailcfg.FilterRule{},
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name: "1786-reducing-breaks-exit-nodes-the-exit",
 | 
			
		||||
			pol: ACLPolicy{
 | 
			
		||||
				Hosts: Hosts{
 | 
			
		||||
					// Exit node
 | 
			
		||||
					"internal": netip.MustParsePrefix("100.64.0.100/32"),
 | 
			
		||||
				},
 | 
			
		||||
				Groups: Groups{
 | 
			
		||||
					"group:team": {"user3", "user2", "user1"},
 | 
			
		||||
				},
 | 
			
		||||
				ACLs: []ACL{
 | 
			
		||||
					{
 | 
			
		||||
						Action:  "accept",
 | 
			
		||||
						Sources: []string{"group:team"},
 | 
			
		||||
						Destinations: []string{
 | 
			
		||||
							"internal:*",
 | 
			
		||||
						},
 | 
			
		||||
					},
 | 
			
		||||
					{
 | 
			
		||||
						Action:  "accept",
 | 
			
		||||
						Sources: []string{"group:team"},
 | 
			
		||||
						Destinations: []string{
 | 
			
		||||
							"autogroup:internet:*",
 | 
			
		||||
						},
 | 
			
		||||
					},
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			node: &types.Node{
 | 
			
		||||
				IPv4: iap("100.64.0.100"),
 | 
			
		||||
				IPv6: iap("fd7a:115c:a1e0::100"),
 | 
			
		||||
				User: types.User{Name: "user100"},
 | 
			
		||||
				Hostinfo: &tailcfg.Hostinfo{
 | 
			
		||||
					RoutableIPs: []netip.Prefix{types.ExitRouteV4, types.ExitRouteV6},
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			peers: types.Nodes{
 | 
			
		||||
				&types.Node{
 | 
			
		||||
					IPv4: iap("100.64.0.2"),
 | 
			
		||||
					IPv6: iap("fd7a:115c:a1e0::2"),
 | 
			
		||||
					User: types.User{Name: "user2"},
 | 
			
		||||
				},
 | 
			
		||||
				&types.Node{
 | 
			
		||||
					IPv4: iap("100.64.0.1"),
 | 
			
		||||
					IPv6: iap("fd7a:115c:a1e0::1"),
 | 
			
		||||
					User: types.User{Name: "user1"},
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			want: []tailcfg.FilterRule{
 | 
			
		||||
				{
 | 
			
		||||
					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,
 | 
			
		||||
						},
 | 
			
		||||
					},
 | 
			
		||||
				},
 | 
			
		||||
				{
 | 
			
		||||
					SrcIPs:   []string{"100.64.0.1/32", "100.64.0.2/32", "fd7a:115c:a1e0::1/128", "fd7a:115c:a1e0::2/128"},
 | 
			
		||||
					DstPorts: hsExitNodeDest,
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name: "1786-reducing-breaks-exit-nodes-the-example-from-issue",
 | 
			
		||||
			pol: ACLPolicy{
 | 
			
		||||
				Hosts: Hosts{
 | 
			
		||||
					// Exit node
 | 
			
		||||
					"internal": netip.MustParsePrefix("100.64.0.100/32"),
 | 
			
		||||
				},
 | 
			
		||||
				Groups: Groups{
 | 
			
		||||
					"group:team": {"user3", "user2", "user1"},
 | 
			
		||||
				},
 | 
			
		||||
				ACLs: []ACL{
 | 
			
		||||
					{
 | 
			
		||||
						Action:  "accept",
 | 
			
		||||
						Sources: []string{"group:team"},
 | 
			
		||||
						Destinations: []string{
 | 
			
		||||
							"internal:*",
 | 
			
		||||
						},
 | 
			
		||||
					},
 | 
			
		||||
					{
 | 
			
		||||
						Action:  "accept",
 | 
			
		||||
						Sources: []string{"group:team"},
 | 
			
		||||
						Destinations: []string{
 | 
			
		||||
							"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: iap("100.64.0.100"),
 | 
			
		||||
				IPv6: iap("fd7a:115c:a1e0::100"),
 | 
			
		||||
				User: types.User{Name: "user100"},
 | 
			
		||||
				Hostinfo: &tailcfg.Hostinfo{
 | 
			
		||||
					RoutableIPs: []netip.Prefix{types.ExitRouteV4, types.ExitRouteV6},
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			peers: types.Nodes{
 | 
			
		||||
				&types.Node{
 | 
			
		||||
					IPv4: iap("100.64.0.2"),
 | 
			
		||||
					IPv6: iap("fd7a:115c:a1e0::2"),
 | 
			
		||||
					User: types.User{Name: "user2"},
 | 
			
		||||
				},
 | 
			
		||||
				&types.Node{
 | 
			
		||||
					IPv4: iap("100.64.0.1"),
 | 
			
		||||
					IPv6: iap("fd7a:115c:a1e0::1"),
 | 
			
		||||
					User: types.User{Name: "user1"},
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			want: []tailcfg.FilterRule{
 | 
			
		||||
				{
 | 
			
		||||
					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,
 | 
			
		||||
						},
 | 
			
		||||
					},
 | 
			
		||||
				},
 | 
			
		||||
				{
 | 
			
		||||
					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: "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: "fd7a:115c:a1e0::1/128", Ports: tailcfg.PortRangeAny},
 | 
			
		||||
						{IP: "fd7a:115c:a1e0::2/128", Ports: tailcfg.PortRangeAny},
 | 
			
		||||
						{IP: "fd7a:115c:a1e0::100/128", 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},
 | 
			
		||||
					},
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name: "1786-reducing-breaks-exit-nodes-app-connector-like",
 | 
			
		||||
			pol: ACLPolicy{
 | 
			
		||||
				Hosts: Hosts{
 | 
			
		||||
					// Exit node
 | 
			
		||||
					"internal": netip.MustParsePrefix("100.64.0.100/32"),
 | 
			
		||||
				},
 | 
			
		||||
				Groups: Groups{
 | 
			
		||||
					"group:team": {"user3", "user2", "user1"},
 | 
			
		||||
				},
 | 
			
		||||
				ACLs: []ACL{
 | 
			
		||||
					{
 | 
			
		||||
						Action:  "accept",
 | 
			
		||||
						Sources: []string{"group:team"},
 | 
			
		||||
						Destinations: []string{
 | 
			
		||||
							"internal:*",
 | 
			
		||||
						},
 | 
			
		||||
					},
 | 
			
		||||
					{
 | 
			
		||||
						Action:  "accept",
 | 
			
		||||
						Sources: []string{"group:team"},
 | 
			
		||||
						Destinations: []string{
 | 
			
		||||
							"8.0.0.0/8:*",
 | 
			
		||||
							"16.0.0.0/8:*",
 | 
			
		||||
						},
 | 
			
		||||
					},
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			node: &types.Node{
 | 
			
		||||
				IPv4: iap("100.64.0.100"),
 | 
			
		||||
				IPv6: iap("fd7a:115c:a1e0::100"),
 | 
			
		||||
				User: types.User{Name: "user100"},
 | 
			
		||||
				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: iap("100.64.0.2"),
 | 
			
		||||
					IPv6: iap("fd7a:115c:a1e0::2"),
 | 
			
		||||
					User: types.User{Name: "user2"},
 | 
			
		||||
				},
 | 
			
		||||
				&types.Node{
 | 
			
		||||
					IPv4: iap("100.64.0.1"),
 | 
			
		||||
					IPv6: iap("fd7a:115c:a1e0::1"),
 | 
			
		||||
					User: types.User{Name: "user1"},
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			want: []tailcfg.FilterRule{
 | 
			
		||||
				{
 | 
			
		||||
					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,
 | 
			
		||||
						},
 | 
			
		||||
					},
 | 
			
		||||
				},
 | 
			
		||||
				{
 | 
			
		||||
					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:    "8.0.0.0/8",
 | 
			
		||||
							Ports: tailcfg.PortRangeAny,
 | 
			
		||||
						},
 | 
			
		||||
						{
 | 
			
		||||
							IP:    "16.0.0.0/8",
 | 
			
		||||
							Ports: tailcfg.PortRangeAny,
 | 
			
		||||
						},
 | 
			
		||||
					},
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name: "1786-reducing-breaks-exit-nodes-app-connector-like2",
 | 
			
		||||
			pol: ACLPolicy{
 | 
			
		||||
				Hosts: Hosts{
 | 
			
		||||
					// Exit node
 | 
			
		||||
					"internal": netip.MustParsePrefix("100.64.0.100/32"),
 | 
			
		||||
				},
 | 
			
		||||
				Groups: Groups{
 | 
			
		||||
					"group:team": {"user3", "user2", "user1"},
 | 
			
		||||
				},
 | 
			
		||||
				ACLs: []ACL{
 | 
			
		||||
					{
 | 
			
		||||
						Action:  "accept",
 | 
			
		||||
						Sources: []string{"group:team"},
 | 
			
		||||
						Destinations: []string{
 | 
			
		||||
							"internal:*",
 | 
			
		||||
						},
 | 
			
		||||
					},
 | 
			
		||||
					{
 | 
			
		||||
						Action:  "accept",
 | 
			
		||||
						Sources: []string{"group:team"},
 | 
			
		||||
						Destinations: []string{
 | 
			
		||||
							"8.0.0.0/16:*",
 | 
			
		||||
							"16.0.0.0/16:*",
 | 
			
		||||
						},
 | 
			
		||||
					},
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			node: &types.Node{
 | 
			
		||||
				IPv4: iap("100.64.0.100"),
 | 
			
		||||
				IPv6: iap("fd7a:115c:a1e0::100"),
 | 
			
		||||
				User: types.User{Name: "user100"},
 | 
			
		||||
				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: iap("100.64.0.2"),
 | 
			
		||||
					IPv6: iap("fd7a:115c:a1e0::2"),
 | 
			
		||||
					User: types.User{Name: "user2"},
 | 
			
		||||
				},
 | 
			
		||||
				&types.Node{
 | 
			
		||||
					IPv4: iap("100.64.0.1"),
 | 
			
		||||
					IPv6: iap("fd7a:115c:a1e0::1"),
 | 
			
		||||
					User: types.User{Name: "user1"},
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			want: []tailcfg.FilterRule{
 | 
			
		||||
				{
 | 
			
		||||
					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,
 | 
			
		||||
						},
 | 
			
		||||
					},
 | 
			
		||||
				},
 | 
			
		||||
				{
 | 
			
		||||
					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:    "8.0.0.0/16",
 | 
			
		||||
							Ports: tailcfg.PortRangeAny,
 | 
			
		||||
						},
 | 
			
		||||
						{
 | 
			
		||||
							IP:    "16.0.0.0/16",
 | 
			
		||||
							Ports: tailcfg.PortRangeAny,
 | 
			
		||||
						},
 | 
			
		||||
					},
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name: "1817-reduce-breaks-32-mask",
 | 
			
		||||
			pol: ACLPolicy{
 | 
			
		||||
				Hosts: Hosts{
 | 
			
		||||
					"vlan1": netip.MustParsePrefix("172.16.0.0/24"),
 | 
			
		||||
					"dns1":  netip.MustParsePrefix("172.16.0.21/32"),
 | 
			
		||||
				},
 | 
			
		||||
				Groups: Groups{
 | 
			
		||||
					"group:access": {"user1"},
 | 
			
		||||
				},
 | 
			
		||||
				ACLs: []ACL{
 | 
			
		||||
					{
 | 
			
		||||
						Action:  "accept",
 | 
			
		||||
						Sources: []string{"group:access"},
 | 
			
		||||
						Destinations: []string{
 | 
			
		||||
							"tag:access-servers:*",
 | 
			
		||||
							"dns1:*",
 | 
			
		||||
						},
 | 
			
		||||
					},
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			node: &types.Node{
 | 
			
		||||
				IPv4: iap("100.64.0.100"),
 | 
			
		||||
				IPv6: iap("fd7a:115c:a1e0::100"),
 | 
			
		||||
				User: types.User{Name: "user100"},
 | 
			
		||||
				Hostinfo: &tailcfg.Hostinfo{
 | 
			
		||||
					RoutableIPs: []netip.Prefix{netip.MustParsePrefix("172.16.0.0/24")},
 | 
			
		||||
				},
 | 
			
		||||
				ForcedTags: types.StringList{"tag:access-servers"},
 | 
			
		||||
			},
 | 
			
		||||
			peers: types.Nodes{
 | 
			
		||||
				&types.Node{
 | 
			
		||||
					IPv4: iap("100.64.0.1"),
 | 
			
		||||
					IPv6: iap("fd7a:115c:a1e0::1"),
 | 
			
		||||
					User: types.User{Name: "user1"},
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			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,
 | 
			
		||||
						},
 | 
			
		||||
					},
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, tt := range tests {
 | 
			
		||||
		t.Run(tt.name, func(t *testing.T) {
 | 
			
		||||
			rules, _ := tt.pol.CompileFilterRules(
 | 
			
		||||
			got, _ := tt.pol.CompileFilterRules(
 | 
			
		||||
				append(tt.peers, tt.node),
 | 
			
		||||
			)
 | 
			
		||||
 | 
			
		||||
			got := ReduceFilterRules(tt.node, rules)
 | 
			
		||||
			got = ReduceFilterRules(tt.node, got)
 | 
			
		||||
 | 
			
		||||
			if diff := cmp.Diff(tt.want, got); diff != "" {
 | 
			
		||||
				log.Trace().Interface("got", got).Msg("result")
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user