fix(network-go): handle reconnection gracefully and fix DNAT rule issues
continuous-integration/drone/push Build is passing
continuous-integration/drone/push Build is passing
- Ignore "endpoint already exists" error in ConnectContainer on re-reconciliation - Improve iptables comment generation to avoid trailing dashes - Enhance DNAT rule logic: try multiple selectors and fall back to host rules - Add missing "-t nat" flag in InsertPreroutingRuleOnInterface
This commit is contained in:
@@ -123,6 +123,10 @@ func (c *Client) ConnectContainer(ctx context.Context, containerName, networkNam
|
||||
|
||||
err := c.cli.NetworkConnect(ctx, networkName, containerName, endpointSettings)
|
||||
if err != nil {
|
||||
// "endpoint with name ... already exists" is expected on re-reconciliation
|
||||
if strings.Contains(err.Error(), "already exists") {
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("failed to connect container %s to network %s: %w", containerName, networkName, err)
|
||||
}
|
||||
return nil
|
||||
|
||||
@@ -110,9 +110,17 @@ func (o *Orchestrator) reconcilePolicies(ctx context.Context, cfg *config.Networ
|
||||
port := strconv.Itoa(policy.Port)
|
||||
|
||||
// Build comment for iptables (matches shell script's NAME-COMMENT pattern)
|
||||
comment := policy.ServiceName
|
||||
// Use Name if present, otherwise ServiceName, to avoid trailing dashes
|
||||
comment := ""
|
||||
if policy.Name != "" {
|
||||
comment = policy.Name + "-" + policy.ServiceName
|
||||
comment = policy.Name
|
||||
}
|
||||
if policy.ServiceName != "" {
|
||||
if comment != "" {
|
||||
comment += "-" + policy.ServiceName
|
||||
} else {
|
||||
comment = policy.ServiceName
|
||||
}
|
||||
}
|
||||
|
||||
// CASE 1: Rule with "from" field — this is a FORWARD ACCEPT rule
|
||||
@@ -158,7 +166,6 @@ func (o *Orchestrator) applyForwardRule(ctx context.Context, cfg *config.Network
|
||||
}
|
||||
|
||||
func (o *Orchestrator) applyNATRule(ctx context.Context, cfg *config.NetworksConfig, policy config.PolicyConfig, proto, port, comment string) {
|
||||
selector := policy.Selector
|
||||
to := policy.To
|
||||
|
||||
// Resolve "to" as target IP
|
||||
@@ -170,22 +177,35 @@ func (o *Orchestrator) applyNATRule(ctx context.Context, cfg *config.NetworksCon
|
||||
}
|
||||
|
||||
if policy.Nat == "dnat" {
|
||||
// Get the container PID for nsenter
|
||||
pid, err := o.dockerClient.GetContainerPID(ctx, selector)
|
||||
if err != nil {
|
||||
log.Printf("FIREWALL: WARNING cannot get PID for container %s: %v, trying host rules", selector, err)
|
||||
// Fall back to host-level PREROUTING
|
||||
if policy.Iface != "" {
|
||||
if err := o.iptablesMgr.InsertPreroutingRuleOnInterface(policy.Iface, proto, port, targetIP, port, comment); err != nil {
|
||||
log.Printf("FIREWALL: ERROR inserting interface PREROUTING rule: %v", err)
|
||||
}
|
||||
}
|
||||
return
|
||||
// Determine the best container selector from the policy: try Selector, then ContainerName, then Name
|
||||
selector := policy.Selector
|
||||
if selector == "" {
|
||||
selector = policy.ContainerName
|
||||
}
|
||||
if selector == "" {
|
||||
selector = policy.Name
|
||||
}
|
||||
|
||||
// Insert DNAT PREROUTING inside container namespace
|
||||
if err := o.iptablesMgr.InsertPreroutingRuleInContainer(pid, "0.0.0.0/0", proto, port, targetIP, port, comment); err != nil {
|
||||
log.Printf("FIREWALL: ERROR inserting container PREROUTING rule: %v", err)
|
||||
// Try to insert rules inside the container namespace via nsenter
|
||||
usedContainer := false
|
||||
if selector != "" {
|
||||
pid, err := o.dockerClient.GetContainerPID(ctx, selector)
|
||||
if err == nil {
|
||||
if err := o.iptablesMgr.InsertPreroutingRuleInContainer(pid, "0.0.0.0/0", proto, port, targetIP, port, comment); err != nil {
|
||||
log.Printf("FIREWALL: ERROR inserting container PREROUTING rule: %v", err)
|
||||
} else {
|
||||
usedContainer = true
|
||||
}
|
||||
} else {
|
||||
log.Printf("FIREWALL: WARNING cannot get PID for container %s: %v, trying host rules", selector, err)
|
||||
}
|
||||
}
|
||||
|
||||
// Fall back to host-level PREROUTING if container not used
|
||||
if !usedContainer && policy.Iface != "" {
|
||||
if err := o.iptablesMgr.InsertPreroutingRuleOnInterface(policy.Iface, proto, port, targetIP, port, comment); err != nil {
|
||||
log.Printf("FIREWALL: ERROR inserting interface PREROUTING rule: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -236,7 +236,7 @@ func (m *Manager) InsertPreroutingRule(sourceIP, proto, sourcePort, targetIP, ta
|
||||
// InsertPreroutingRuleOnInterface inserts a DNAT PREROUTING rule on a specific interface
|
||||
func (m *Manager) InsertPreroutingRuleOnInterface(iface, proto, sourcePort, targetIP, targetPort, comment string) error {
|
||||
args := []string{
|
||||
"-w", "-I", "PREROUTING",
|
||||
"-w", "-t", "nat", "-I", "PREROUTING",
|
||||
"-i", iface,
|
||||
"-p", proto,
|
||||
"--dport", sourcePort,
|
||||
|
||||
Reference in New Issue
Block a user