incusd/firewall/nftables: Use a bridges set for cross-bridge NAT exclusions

Signed-off-by: Stéphane Graber <stgraber@stgraber.org>
This commit is contained in:
Stéphane Graber 2026-07-27 09:38:26 -04:00
parent 1f0ce8eabe
commit caf303482b
No known key found for this signature in database
GPG Key ID: C638974D64792D67
2 changed files with 28 additions and 3 deletions

View File

@ -262,6 +262,18 @@ func (d Nftables) NetworkSetup(networkName string, opts Opts) error {
}
}
// Add the network to the managed bridges set, traffic between those isn't NAT-ed.
tplFields := map[string]any{
"namespace": nftablesNamespace,
"family": "inet",
"networkName": networkName,
}
err := d.applyNftConfig(nftablesNetBridgesSet, tplFields)
if err != nil {
return fmt.Errorf("Failed adding network %q to the managed bridges set: %w", networkName, err)
}
if opts.SNATV4 != nil || opts.SNATV6 != nil {
err := d.NetworkSetupOutboundNAT(networkName, opts.SNATV4, opts.SNATV6)
if err != nil {
@ -320,6 +332,10 @@ func (d Nftables) NetworkClear(networkName string, _ bool, _ []uint) error {
return fmt.Errorf("Failed clearing nftables rules for network %q: %w", networkName, err)
}
// Remove the network from the managed bridges set.
// This will fail if the set doesn't exist or the network was never added to it.
_, _ = subprocess.RunCommand("nft", "delete", "element", "inet", nftablesNamespace, "bridges", fmt.Sprintf("{ %q }", networkName))
// Attempt to delete our address sets.
// This will fail so long as there are still rules referencing them (other networks).
_ = d.RemoveIncusAddressSets("bridge")

View File

@ -26,14 +26,23 @@ chain fwd{{.chainSeparator}}{{.networkName}} {
}
`))
var nftablesNetBridgesSet = template.Must(template.New("nftablesNetBridgesSet").Parse(`
set bridges {
type ifname
elements = { "{{.networkName}}" }
}
`))
var nftablesNetOutboundNAT = template.Must(template.New("nftablesNetOutboundNAT").Parse(`
set bridges {
type ifname
}
chain pstrt{{.chainSeparator}}{{.networkName}} {
type nat hook postrouting priority 100; policy accept;
{{ range $ipFamily, $config := .rules }}
{{ range $config.ExcludeInterfaces }}
{{$ipFamily}} saddr {{$config.Subnet}} oifname "{{.}}" accept
{{ end }}
{{$ipFamily}} saddr {{$config.Subnet}} oifname @bridges accept
{{ if $config.SNATAddress }}
{{$ipFamily}} saddr {{$config.Subnet}} {{$ipFamily}} daddr != {{$config.Subnet}} snat {{$config.SNATAddress}}
{{ else }}