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",
|
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)
|
policy.From, sourceIP, policy.To, targetIP, proto, port)
|
||||||
|
|
||||||
// Determine the chain: use DOCKER-USER (iptables-legacy) or FORWARD
|
// Use the auto-detected chain (DOCKER-USER or FORWARD)
|
||||||
chain := "FORWARD"
|
chain := o.iptablesMgr.Chain()
|
||||||
if o.iptablesMgr.Binary() == "/usr/sbin/iptables-legacy" {
|
|
||||||
chain = "DOCKER-USER"
|
|
||||||
}
|
|
||||||
logger.Debug("FIREWALL: using iptables chain=%s (binary=%s)", chain, o.iptablesMgr.Binary())
|
logger.Debug("FIREWALL: using iptables chain=%s (binary=%s)", chain, o.iptablesMgr.Binary())
|
||||||
|
|
||||||
// Ensure established/related rule exists at the top
|
// Ensure established/related rule exists at the top
|
||||||
|
|||||||
@@ -108,9 +108,9 @@ func TestReconcilePoliciesForwardRule(t *testing.T) {
|
|||||||
t.Error("InsertForwardAccept was not called")
|
t.Error("InsertForwardAccept was not called")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Should use FORWARD chain (not iptables-legacy)
|
// Should use DOCKER-USER chain (default, even with non-legacy iptables)
|
||||||
if iptables.InsertForwardAcceptChain != "FORWARD" {
|
if iptables.InsertForwardAcceptChain != "DOCKER-USER" {
|
||||||
t.Errorf("expected FORWARD chain, got %s", iptables.InsertForwardAcceptChain)
|
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
|
// IPTablesAPI defines the interface for iptables operations, enabling mock implementations for testing
|
||||||
type IPTablesAPI interface {
|
type IPTablesAPI interface {
|
||||||
Binary() string
|
Binary() string
|
||||||
|
Chain() string
|
||||||
EnsureIPForward() error
|
EnsureIPForward() error
|
||||||
EnsureEstablishedRelated(chain string) error
|
EnsureEstablishedRelated(chain string) error
|
||||||
DeleteLine(chain string, lineNum 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
|
// Manager manages iptables rules via the iptables/iptables-legacy CLI
|
||||||
type Manager struct {
|
type Manager struct {
|
||||||
binary string
|
binary string
|
||||||
debug bool
|
chain string // "DOCKER-USER" or "FORWARD"
|
||||||
|
debug bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure Manager implements IPTablesAPI
|
// Ensure Manager implements IPTablesAPI
|
||||||
@@ -40,18 +42,34 @@ func NewManager(debug bool) *Manager {
|
|||||||
return m
|
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() {
|
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")
|
cmd := exec.Command("/usr/sbin/iptables-legacy", "-L")
|
||||||
output, err := cmd.CombinedOutput()
|
output, err := cmd.CombinedOutput()
|
||||||
if err == nil && strings.Contains(string(output), "DOCKER-USER") {
|
if err == nil && strings.Contains(string(output), "DOCKER-USER") {
|
||||||
m.binary = "/usr/sbin/iptables-legacy"
|
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
|
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"
|
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
|
// Binary returns the detected iptables binary path
|
||||||
@@ -59,6 +77,11 @@ func (m *Manager) Binary() string {
|
|||||||
return m.binary
|
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
|
// run executes an iptables command on the host
|
||||||
func (m *Manager) run(args ...string) error {
|
func (m *Manager) run(args ...string) error {
|
||||||
cmdStr := m.binary + " " + strings.Join(args, " ")
|
cmdStr := m.binary + " " + strings.Join(args, " ")
|
||||||
|
|||||||
@@ -163,6 +163,11 @@ func (m *MockIPTablesManager) Binary() string {
|
|||||||
return m.BinaryResult
|
return m.BinaryResult
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *MockIPTablesManager) Chain() string {
|
||||||
|
// Default to DOCKER-USER (matches production behavior)
|
||||||
|
return "DOCKER-USER"
|
||||||
|
}
|
||||||
|
|
||||||
func (m *MockIPTablesManager) EnsureIPForward() error {
|
func (m *MockIPTablesManager) EnsureIPForward() error {
|
||||||
m.EnsureIPForwardCalled = true
|
m.EnsureIPForwardCalled = true
|
||||||
return m.EnsureIPForwardErr
|
return m.EnsureIPForwardErr
|
||||||
|
|||||||
Reference in New Issue
Block a user