Refactor iptables chain detection to centralize and default to DOCKER-USER
continuous-integration/drone/push Build is passing

Move chain detection logic from firewall to iptables manager for better encapsulation. The manager now auto-detects both the iptables binary and chain (DOCKER-USER or FORWARD) based on the presence of the Docker-managed chain, but always defaults to DOCKER-USER for consistency. This simplifies firewall code and ensures proper Docker integration regardless of iptables version.
This commit is contained in:
gyurix
2026-06-16 12:46:25 +02:00
parent 77f80dea1b
commit d5757e623a
4 changed files with 39 additions and 14 deletions
+2 -5
View File
@@ -204,11 +204,8 @@ func (o *Orchestrator) applyForwardRule(ctx context.Context, cfg *config.Network
logger.Info("FIREWALL: forward rule: from=%q (IP=%s) to=%q (IP=%s) proto=%s port=%s",
policy.From, sourceIP, policy.To, targetIP, proto, port)
// Determine the chain: use DOCKER-USER (iptables-legacy) or FORWARD
chain := "FORWARD"
if o.iptablesMgr.Binary() == "/usr/sbin/iptables-legacy" {
chain = "DOCKER-USER"
}
// Use the auto-detected chain (DOCKER-USER or FORWARD)
chain := o.iptablesMgr.Chain()
logger.Debug("FIREWALL: using iptables chain=%s (binary=%s)", chain, o.iptablesMgr.Binary())
// Ensure established/related rule exists at the top
+3 -3
View File
@@ -108,9 +108,9 @@ func TestReconcilePoliciesForwardRule(t *testing.T) {
t.Error("InsertForwardAccept was not called")
}
// Should use FORWARD chain (not iptables-legacy)
if iptables.InsertForwardAcceptChain != "FORWARD" {
t.Errorf("expected FORWARD chain, got %s", iptables.InsertForwardAcceptChain)
// Should use DOCKER-USER chain (default, even with non-legacy iptables)
if iptables.InsertForwardAcceptChain != "DOCKER-USER" {
t.Errorf("expected DOCKER-USER chain, got %s", iptables.InsertForwardAcceptChain)
}
}
+29 -6
View File
@@ -11,6 +11,7 @@ import (
// IPTablesAPI defines the interface for iptables operations, enabling mock implementations for testing
type IPTablesAPI interface {
Binary() string
Chain() string
EnsureIPForward() error
EnsureEstablishedRelated(chain string) error
DeleteLine(chain string, lineNum string) error
@@ -26,8 +27,9 @@ type IPTablesAPI interface {
// Manager manages iptables rules via the iptables/iptables-legacy CLI
type Manager struct {
binary string
debug bool
binary string
chain string // "DOCKER-USER" or "FORWARD"
debug bool
}
// Ensure Manager implements IPTablesAPI
@@ -40,18 +42,34 @@ func NewManager(debug bool) *Manager {
return m
}
// detectBinary checks if iptables-legacy is available (matching shell script logic)
// detectBinary checks which iptables binary has the DOCKER-USER chain (Docker-managed)
func (m *Manager) detectBinary() {
logger.Info("IPTABLES: detecting iptables binary")
logger.Info("IPTABLES: detecting iptables binary and Docker chain")
// Check iptables-legacy first
cmd := exec.Command("/usr/sbin/iptables-legacy", "-L")
output, err := cmd.CombinedOutput()
if err == nil && strings.Contains(string(output), "DOCKER-USER") {
m.binary = "/usr/sbin/iptables-legacy"
logger.Info("IPTABLES: detected iptables-legacy (DOCKER-USER chain present)")
m.chain = "DOCKER-USER"
logger.Info("IPTABLES: detected iptables-legacy with DOCKER-USER chain")
return
}
// Check default iptables (may be nft-based)
cmd2 := exec.Command("/usr/sbin/iptables", "-L")
output2, err2 := cmd2.CombinedOutput()
if err2 == nil && strings.Contains(string(output2), "DOCKER-USER") {
m.binary = "/usr/sbin/iptables"
m.chain = "DOCKER-USER"
logger.Info("IPTABLES: detected iptables with DOCKER-USER chain")
return
}
// No DOCKER-USER chain found — default to DOCKER-USER for ACCEPT rules
m.binary = "/usr/sbin/iptables"
logger.Info("IPTABLES: using default iptables binary")
m.chain = "DOCKER-USER"
logger.Info("IPTABLES: no DOCKER-USER chain detected, defaulting to DOCKER-USER with default iptables")
}
// Binary returns the detected iptables binary path
@@ -59,6 +77,11 @@ func (m *Manager) Binary() string {
return m.binary
}
// Chain returns the firewall chain to use for FORWARD rules (DOCKER-USER or FORWARD)
func (m *Manager) Chain() string {
return m.chain
}
// run executes an iptables command on the host
func (m *Manager) run(args ...string) error {
cmdStr := m.binary + " " + strings.Join(args, " ")
+5
View File
@@ -163,6 +163,11 @@ func (m *MockIPTablesManager) Binary() string {
return m.BinaryResult
}
func (m *MockIPTablesManager) Chain() string {
// Default to DOCKER-USER (matches production behavior)
return "DOCKER-USER"
}
func (m *MockIPTablesManager) EnsureIPForward() error {
m.EnsureIPForwardCalled = true
return m.EnsureIPForwardErr