Refactor iptables chain detection to centralize and default to DOCKER-USER
continuous-integration/drone/push Build is passing
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:
@@ -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
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -27,6 +28,7 @@ type IPTablesAPI interface {
|
||||
// Manager manages iptables rules via the iptables/iptables-legacy CLI
|
||||
type Manager struct {
|
||||
binary string
|
||||
chain string // "DOCKER-USER" or "FORWARD"
|
||||
debug bool
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
logger.Info("IPTABLES: using default iptables binary")
|
||||
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"
|
||||
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, " ")
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user