[client] Unify peer and route ACL filtering with multi-source rules (#6322)

* Unify peer and route ACL filtering with multi-source peer rules

* Remove partial userspace firewall mode and open foreign chains via a table-less allower

* Snapshot iptables rule maps before persisting state

* Scope userspace firewall wildcard source rules per address family

* Install nftables peer filter and mangle rules in a single transaction

* Share the iptables jump rule spec between install and cleanup

* Fix legacy ACL source wildcard and keep rollback tracking on delete failure

* Fix CI: recognize multi-value port set lookups in tests and correct PeerIP lint suppression

* Fall back to per-prefix filter rules when ipset is unavailable

* Annotate legacy PeerIP usages in ACL tests and fix import formatting

* Keep firewall rule bookkeeping in step with the kernel on replace and teardown

* Release the routing reference when the route manager shuts down

* Keep set references and rule tracking consistent when a routing rule fails
This commit is contained in:
Viktor Liu
2026-09-03 10:02:50 +02:00
committed by GitHub
parent 6aaeed744e
commit 778b3b3264
81 changed files with 9046 additions and 6686 deletions
@@ -80,7 +80,7 @@ func iptDnatV6(port uint16) fw.ForwardRule {
// and a single DisableRouting drops both back to zero.
func TestIptablesRouting_RepeatedEnableSingleReference(t *testing.T) {
m := newIptRefcountManager(t, true)
state := m.router.ipFwdState
state := m.family4.ipFwdState
require.NoError(t, m.EnableRouting(), "first enable")
require.NoError(t, m.EnableRouting(), "second enable")
@@ -99,7 +99,7 @@ func TestIptablesRouting_RepeatedEnableSingleReference(t *testing.T) {
// DisableRouting does not release references held by active DNAT rules.
func TestIptablesRouting_DisableKeepsDNATReference(t *testing.T) {
m := newIptRefcountManager(t, true)
state := m.router.ipFwdState
state := m.family4.ipFwdState
r1, err := m.AddDNATRule(iptDnatV6(9095))
require.NoError(t, err, "add v6 dnat")
@@ -116,7 +116,7 @@ func TestIptablesRouting_DisableKeepsDNATReference(t *testing.T) {
// TestIptablesDNAT_RefcountBalancedV4 covers a Balanced Add/Delete pair on v4.
func TestIptablesDNAT_RefcountBalancedV4(t *testing.T) {
m := newIptRefcountManager(t, false)
state := m.router.ipFwdState
state := m.family4.ipFwdState
r1, err := m.AddDNATRule(iptDnatV4(7081))
require.NoError(t, err, "add v4 dnat 1")
@@ -145,9 +145,9 @@ func TestIptablesDNAT_RefcountBalancedV4(t *testing.T) {
// decrements back to zero.
func TestIptablesDNAT_RefcountBalancedV6(t *testing.T) {
m := newIptRefcountManager(t, true)
require.NotNil(t, m.router6, "v6 router")
require.Same(t, m.router.ipFwdState, m.router6.ipFwdState, "shared state")
state := m.router.ipFwdState
require.NotNil(t, m.family6, "v6 family")
require.Same(t, m.family4.ipFwdState, m.family6.ipFwdState, "shared state")
state := m.family4.ipFwdState
r1, err := m.AddDNATRule(iptDnatV6(9081))
require.NoError(t, err, "add v6 dnat 1")
@@ -176,7 +176,7 @@ func TestIptablesDNAT_RefcountBalancedV6(t *testing.T) {
// without bumping the refcount.
func TestIptablesDNAT_DuplicateAddNoLeak(t *testing.T) {
m := newIptRefcountManager(t, true)
state := m.router.ipFwdState
state := m.family4.ipFwdState
rule := iptDnatV4(7083)
r1, err := m.AddDNATRule(rule)
@@ -198,7 +198,7 @@ func TestIptablesDNAT_DuplicateAddNoLeak(t *testing.T) {
// neither errors nor releases the refcount.
func TestIptablesDNAT_DeleteMissingNoUnderflow(t *testing.T) {
m := newIptRefcountManager(t, true)
state := m.router.ipFwdState
state := m.family4.ipFwdState
phantom := iptDnatV4(7099)
require.NoError(t, m.DeleteDNATRule(&phantom), "delete missing v4")
@@ -223,7 +223,7 @@ func TestIptablesDNAT_DeleteMissingNoUnderflow(t *testing.T) {
// rule is a no-op.
func TestIptablesDNAT_DoubleDeleteNoUnderflow(t *testing.T) {
m := newIptRefcountManager(t, true)
state := m.router.ipFwdState
state := m.family4.ipFwdState
r1, err := m.AddDNATRule(iptDnatV6(9083))
require.NoError(t, err)