diff --git a/hscontrol/policy/v2/types.go b/hscontrol/policy/v2/types.go index cc194e29..00870741 100644 --- a/hscontrol/policy/v2/types.go +++ b/hscontrol/policy/v2/types.go @@ -578,7 +578,7 @@ func (h *Host) Resolve(p *Policy, _ types.Users, nodes views.Slice[types.NodeVie return newResolvedAddresses(h.resolve(p, nil, nodes)) } -func (h *Host) resolve(p *Policy, _ types.Users, nodes views.Slice[types.NodeView]) (*netipx.IPSet, error) { +func (h *Host) resolve(p *Policy, _ types.Users, _ views.Slice[types.NodeView]) (*netipx.IPSet, error) { var ( ips netipx.IPSetBuilder errs []error @@ -594,25 +594,11 @@ func (h *Host) resolve(p *Policy, _ types.Users, nodes views.Slice[types.NodeVie errs = append(errs, err) } + // Address-based aliases (host names) resolve to exactly the + // literal prefix from the hosts map. They do NOT expand to + // include the matching node's other IP addresses. ips.AddPrefix(netip.Prefix(pref)) - // If the IP is a single host, look for a node to ensure we add all the IPs of - // the node to the IPSet. - appendIfNodeHasIP(nodes, &ips, netip.Prefix(pref)) - - // TODO(kradalby): I am a bit unsure what is the correct way to do this, - // should a host with a non single IP be able to resolve the full host (inc all IPs). - ipsTemp, err := ips.IPSet() - if err != nil { - errs = append(errs, err) - } - - for _, node := range nodes.All() { - if node.InIPSet(ipsTemp) { - node.AppendToIPSet(&ips) - } - } - return buildIPSetMultiErr(&ips, errs) } @@ -679,34 +665,20 @@ func (p *Prefix) Resolve(_ *Policy, _ types.Users, nodes views.Slice[types.NodeV return newResolvedAddresses(p.resolve(nil, nil, nodes)) } -func (p *Prefix) resolve(_ *Policy, _ types.Users, nodes views.Slice[types.NodeView]) (*netipx.IPSet, error) { +func (p *Prefix) resolve(_ *Policy, _ types.Users, _ views.Slice[types.NodeView]) (*netipx.IPSet, error) { var ( ips netipx.IPSetBuilder errs []error ) + // Address-based aliases resolve to exactly the literal prefix. + // Unlike identity-based aliases (tags, users, groups), they do + // NOT expand to include the matching node's other IP addresses. ips.AddPrefix(netip.Prefix(*p)) - // If the IP is a single host, look for a node to ensure we add all the IPs of - // the node to the IPSet. - appendIfNodeHasIP(nodes, &ips, netip.Prefix(*p)) return buildIPSetMultiErr(&ips, errs) } -// appendIfNodeHasIP appends the IPs of the nodes to the IPSet if the node has the -// IP address in the prefix. -func appendIfNodeHasIP(nodes views.Slice[types.NodeView], ips *netipx.IPSetBuilder, pref netip.Prefix) { - if !pref.IsSingleIP() && !tsaddr.IsTailscaleIP(pref.Addr()) { - return - } - - for _, node := range nodes.All() { - if node.HasIP(pref.Addr()) { - node.AppendToIPSet(ips) - } - } -} - // AutoGroup is a special string which is always prefixed with `autogroup:`. type AutoGroup string diff --git a/hscontrol/types/node.go b/hscontrol/types/node.go index d16e0dd5..928c9221 100644 --- a/hscontrol/types/node.go +++ b/hscontrol/types/node.go @@ -297,25 +297,18 @@ func (node *Node) InIPSet(set *netipx.IPSet) bool { return slices.ContainsFunc(node.IPs(), set.Contains) } -// AppendToIPSet adds the individual ips in NodeAddresses to a -// given netipx.IPSetBuilder. +// AppendToIPSet adds all IP addresses of the node to the given +// netipx.IPSetBuilder. For identity-based aliases (tags, users, +// groups, autogroups), both IPv4 and IPv6 must be included to +// match Tailscale's behavior in the FilterRule wire format. func (node *Node) AppendToIPSet(build *netipx.IPSetBuilder) { if node.IPv4 != nil { build.Add(*node.IPv4) - return } if node.IPv6 != nil { build.Add(*node.IPv6) } - - // TODO(kradalby): Evaluate what we want to do here: - // Tailscale only adds the IPv4 addresses to any packet filter rule that is resolved to a given node. - // Presumably, it will add the IPv4 if a node does not have an IPv4. - // Until this change, we always added both, and that might be something people are dependent on, and we might want to keep it. - // for _, ip := range node.IPs() { - // build.Add(ip) - // } } func (node *Node) CanAccess(matchers []matcher.Match, node2 *Node) bool {