mirror of
https://github.com/juanfont/headscale.git
synced 2026-04-23 09:08:44 +02:00
policy/v2: preserve non-wildcard source IPs alongside wildcard ranges
When an ACL source list contains a wildcard (*) alongside explicit sources (tags, groups, hosts, etc.), Tailscale preserves the individual IPs from non-wildcard sources in SrcIPs alongside the merged wildcard CGNAT ranges. Previously, headscale's IPSetBuilder would merge all sources into a single set, absorbing the explicit IPs into the wildcard range. Track non-wildcard resolved addresses separately during source resolution, then append their individual IP strings to the output when a wildcard is also present. This fixes the remaining 5 ACL compat test failures (K01 and M06 subtests). Updates #2180
This commit is contained in:
@@ -232,8 +232,13 @@ func (pol *Policy) compileGrantWithAutogroupSelf(
|
|||||||
var rules []tailcfg.FilterRule
|
var rules []tailcfg.FilterRule
|
||||||
|
|
||||||
var resolvedSrcs []ResolvedAddresses
|
var resolvedSrcs []ResolvedAddresses
|
||||||
|
// Track non-wildcard source IPs separately. When the grant has a
|
||||||
|
// wildcard (*) source plus explicit sources (tags, groups, etc.),
|
||||||
|
// Tailscale preserves the explicit IPs alongside the wildcard
|
||||||
|
// CGNAT ranges rather than merging them into the IPSet.
|
||||||
|
var nonWildcardSrcs []ResolvedAddresses
|
||||||
|
|
||||||
for _, src := range grant.Sources {
|
for i, src := range grant.Sources {
|
||||||
if ag, ok := src.(*AutoGroup); ok && ag.Is(AutoGroupSelf) {
|
if ag, ok := src.(*AutoGroup); ok && ag.Is(AutoGroupSelf) {
|
||||||
return nil, errSelfInSources
|
return nil, errSelfInSources
|
||||||
}
|
}
|
||||||
@@ -245,6 +250,9 @@ func (pol *Policy) compileGrantWithAutogroupSelf(
|
|||||||
|
|
||||||
if ips != nil {
|
if ips != nil {
|
||||||
resolvedSrcs = append(resolvedSrcs, ips)
|
resolvedSrcs = append(resolvedSrcs, ips)
|
||||||
|
if _, isWildcard := grant.Sources[i].(Asterix); !isWildcard {
|
||||||
|
nonWildcardSrcs = append(nonWildcardSrcs, ips)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -275,8 +283,31 @@ func (pol *Policy) compileGrantWithAutogroupSelf(
|
|||||||
destPorts := pol.destinationsToNetPortRange(users, nodes, otherDests, ipp.Ports)
|
destPorts := pol.destinationsToNetPortRange(users, nodes, otherDests, ipp.Ports)
|
||||||
|
|
||||||
if len(destPorts) > 0 {
|
if len(destPorts) > 0 {
|
||||||
|
srcIPStrs := srcIPsWithRoutes(srcResolved, hasWildcard, nodes)
|
||||||
|
|
||||||
|
// When sources include a wildcard (*) alongside
|
||||||
|
// explicit sources (tags, groups, etc.), Tailscale
|
||||||
|
// preserves the individual IPs from non-wildcard
|
||||||
|
// sources alongside the merged wildcard CGNAT
|
||||||
|
// ranges rather than absorbing them.
|
||||||
|
if hasWildcard && len(nonWildcardSrcs) > 0 {
|
||||||
|
seen := make(map[string]bool, len(srcIPStrs))
|
||||||
|
for _, s := range srcIPStrs {
|
||||||
|
seen[s] = true
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, ips := range nonWildcardSrcs {
|
||||||
|
for _, s := range ips.Strings() {
|
||||||
|
if !seen[s] {
|
||||||
|
seen[s] = true
|
||||||
|
srcIPStrs = append(srcIPStrs, s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
rules = append(rules, tailcfg.FilterRule{
|
rules = append(rules, tailcfg.FilterRule{
|
||||||
SrcIPs: srcIPsWithRoutes(srcResolved, hasWildcard, nodes),
|
SrcIPs: srcIPStrs,
|
||||||
DstPorts: destPorts,
|
DstPorts: destPorts,
|
||||||
IPProto: ipp.Protocol.toIANAProtocolNumbers(),
|
IPProto: ipp.Protocol.toIANAProtocolNumbers(),
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1897,6 +1897,7 @@ func aclToGrants(acl ACL) []Grant {
|
|||||||
// preserve policy order, but ACLs with groups, users, tags, or
|
// preserve policy order, but ACLs with groups, users, tags, or
|
||||||
// hosts emit non-self rules first.
|
// hosts emit non-self rules first.
|
||||||
hasNonAutogroup := false
|
hasNonAutogroup := false
|
||||||
|
|
||||||
for _, dst := range acl.Destinations {
|
for _, dst := range acl.Destinations {
|
||||||
if _, ok := dst.Alias.(*AutoGroup); !ok {
|
if _, ok := dst.Alias.(*AutoGroup); !ok {
|
||||||
hasNonAutogroup = true
|
hasNonAutogroup = true
|
||||||
|
|||||||
Reference in New Issue
Block a user