Description
When a location has nodes with multiple disjoint allowedLocationIPs CIDRs (e.g., 192.168.102.0/23 and 10.10.0.0/16), traffic between those subnets within the same location is incorrectly MASQUERADEd.
Root cause
pkg/mesh/routes.go:405-408 creates per-CIDR POSTROUTING rules for same-location segments:
POSTROUTING -d 192.168.102.0/23 -j KILO-NAT
POSTROUTING -d 10.10.0.0/16 -j KILO-NAT
Traffic from 10.10.0.5 (inside the second CIDR) to 192.168.102.10 (inside the first CIDR) enters KILO-NAT. Since there is no RETURN rule for 192.168.102.10 (only for specific node IPs), it falls through to MASQUERADE. Both subnets are local to the same site, so this NAT is unnecessary and harmful.
The annotation is parsed via strings.Split(",") in backend.go:331, so multiple CIDRs per node are supported. filterAllowedLocationIPs deduplicates across locations but not within the same location, so disjoint CIDRs within one location survive.
Affected granularity modes
The code path runs in all granularity modes (the only condition is t.location == s.location), but in practice this is primarily relevant to cross-mesh granularity where allowed-location-ips is commonly used.
Steps to reproduce
- Deploy 2+ nodes in the same
kilo.squat.ai/location
- Set different
kilo.squat.ai/allowed-location-ips on each (e.g., 192.168.102.0/23 on node A, 10.10.0.0/16 on node B)
- Send traffic from a host on
10.10.0.0/16 to a host on 192.168.102.0/23
- Observe that the source IP is rewritten by MASQUERADE
Proposed fix
Exclude the union of all same-location allowedLocationIPs from the source match:
POSTROUTING -d 192.168.102.0/23 ! -s 192.168.102.0/23 ! -s 10.10.0.0/16 -j KILO-NAT
POSTROUTING -d 10.10.0.0/16 ! -s 192.168.102.0/23 ! -s 10.10.0.0/16 -j KILO-NAT
Alternatively, use an ipset containing all same-location CIDRs for cleaner matching at scale.
Description
When a location has nodes with multiple disjoint
allowedLocationIPsCIDRs (e.g.,192.168.102.0/23and10.10.0.0/16), traffic between those subnets within the same location is incorrectly MASQUERADEd.Root cause
pkg/mesh/routes.go:405-408creates per-CIDR POSTROUTING rules for same-location segments:Traffic from
10.10.0.5(inside the second CIDR) to192.168.102.10(inside the first CIDR) enters KILO-NAT. Since there is no RETURN rule for192.168.102.10(only for specific node IPs), it falls through to MASQUERADE. Both subnets are local to the same site, so this NAT is unnecessary and harmful.The annotation is parsed via
strings.Split(",")inbackend.go:331, so multiple CIDRs per node are supported.filterAllowedLocationIPsdeduplicates across locations but not within the same location, so disjoint CIDRs within one location survive.Affected granularity modes
The code path runs in all granularity modes (the only condition is
t.location == s.location), but in practice this is primarily relevant to cross-mesh granularity whereallowed-location-ipsis commonly used.Steps to reproduce
kilo.squat.ai/locationkilo.squat.ai/allowed-location-ipson each (e.g.,192.168.102.0/23on node A,10.10.0.0/16on node B)10.10.0.0/16to a host on192.168.102.0/23Proposed fix
Exclude the union of all same-location
allowedLocationIPsfrom the source match:Alternatively, use an ipset containing all same-location CIDRs for cleaner matching at scale.