From 558da63444c8de0092c97b6def6214d1a0161493 Mon Sep 17 00:00:00 2001 From: Rob Murray Date: Mon, 24 Feb 2025 21:08:19 +0000 Subject: [PATCH] Jump to DOCKER-INGRESS from DOCKER-FORWARD A jump to DOCKER-INGRESS chain is only created when Swarm needs it. That's always after jumps to DOCKER-USER and DOCKER-FORWARD have been inserted at the top of the FORWARD chain. The DOCKER-INGRESS rule needs to be between those two other jumps. Placing the jump to DOCKER-INGRESS at the top of the DOCKER-FORWARD chain puts it in the right place, without needing to shuffle any other rules around when it's added. Signed-off-by: Rob Murray --- .../iptablesdoc/generated/swarm-portmap.md | 20 +++++++++--------- .../iptablesdoc/templates/swarm-portmap.md | 2 +- libnetwork/service_linux.go | 21 +++++++++++++------ 3 files changed, 26 insertions(+), 17 deletions(-) diff --git a/integration/network/bridge/iptablesdoc/generated/swarm-portmap.md b/integration/network/bridge/iptablesdoc/generated/swarm-portmap.md index 8eeeb4631b..6f3367d6e1 100644 --- a/integration/network/bridge/iptablesdoc/generated/swarm-portmap.md +++ b/integration/network/bridge/iptablesdoc/generated/swarm-portmap.md @@ -12,8 +12,7 @@ The filter table is: Chain FORWARD (policy ACCEPT 0 packets, 0 bytes) num pkts bytes target prot opt in out source destination 1 0 0 DOCKER-USER 0 -- * * 0.0.0.0/0 0.0.0.0/0 - 2 0 0 DOCKER-INGRESS 0 -- * * 0.0.0.0/0 0.0.0.0/0 - 3 0 0 DOCKER-FORWARD 0 -- * * 0.0.0.0/0 0.0.0.0/0 + 2 0 0 DOCKER-FORWARD 0 -- * * 0.0.0.0/0 0.0.0.0/0 Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes) num pkts bytes target prot opt in out source destination @@ -35,12 +34,13 @@ The filter table is: Chain DOCKER-FORWARD (1 references) num pkts bytes target prot opt in out source destination - 1 0 0 DOCKER-CT 0 -- * * 0.0.0.0/0 0.0.0.0/0 - 2 0 0 DOCKER-ISOLATION-STAGE-1 0 -- * * 0.0.0.0/0 0.0.0.0/0 - 3 0 0 DOCKER-BRIDGE 0 -- * * 0.0.0.0/0 0.0.0.0/0 - 4 0 0 ACCEPT 0 -- docker0 * 0.0.0.0/0 0.0.0.0/0 - 5 0 0 DROP 0 -- docker_gwbridge docker_gwbridge 0.0.0.0/0 0.0.0.0/0 - 6 0 0 ACCEPT 0 -- docker_gwbridge !docker_gwbridge 0.0.0.0/0 0.0.0.0/0 + 1 0 0 DOCKER-INGRESS 0 -- * * 0.0.0.0/0 0.0.0.0/0 + 2 0 0 DOCKER-CT 0 -- * * 0.0.0.0/0 0.0.0.0/0 + 3 0 0 DOCKER-ISOLATION-STAGE-1 0 -- * * 0.0.0.0/0 0.0.0.0/0 + 4 0 0 DOCKER-BRIDGE 0 -- * * 0.0.0.0/0 0.0.0.0/0 + 5 0 0 ACCEPT 0 -- docker0 * 0.0.0.0/0 0.0.0.0/0 + 6 0 0 DROP 0 -- docker_gwbridge docker_gwbridge 0.0.0.0/0 0.0.0.0/0 + 7 0 0 ACCEPT 0 -- docker_gwbridge !docker_gwbridge 0.0.0.0/0 0.0.0.0/0 Chain DOCKER-INGRESS (1 references) num pkts bytes target prot opt in out source destination @@ -78,7 +78,6 @@ The filter table is: -N DOCKER-ISOLATION-STAGE-2 -N DOCKER-USER -A FORWARD -j DOCKER-USER - -A FORWARD -j DOCKER-INGRESS -A FORWARD -j DOCKER-FORWARD -A DOCKER ! -i docker0 -o docker0 -j DROP -A DOCKER ! -i docker_gwbridge -o docker_gwbridge -j DROP @@ -86,6 +85,7 @@ The filter table is: -A DOCKER-BRIDGE -o docker_gwbridge -j DOCKER -A DOCKER-CT -o docker0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT -A DOCKER-CT -o docker_gwbridge -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT + -A DOCKER-FORWARD -j DOCKER-INGRESS -A DOCKER-FORWARD -j DOCKER-CT -A DOCKER-FORWARD -j DOCKER-ISOLATION-STAGE-1 -A DOCKER-FORWARD -j DOCKER-BRIDGE @@ -109,7 +109,7 @@ Note that: - There's a bridge network called `docker_gwbridge` for swarm ingress. - Its rules follow the usual pattern for a network with inter-container communication disabled. - There's an additional chain `DOCKER-INGRESS`. - - The jump to `DOCKER-INGRESS` is in the `FORWARD` chain. + - The jump to `DOCKER-INGRESS` is first in the `DOCKER-FORWARD` chain. And the corresponding nat table: diff --git a/integration/network/bridge/iptablesdoc/templates/swarm-portmap.md b/integration/network/bridge/iptablesdoc/templates/swarm-portmap.md index 25ccf6158c..ce372ca0b4 100644 --- a/integration/network/bridge/iptablesdoc/templates/swarm-portmap.md +++ b/integration/network/bridge/iptablesdoc/templates/swarm-portmap.md @@ -20,7 +20,7 @@ Note that: - There's a bridge network called `docker_gwbridge` for swarm ingress. - Its rules follow the usual pattern for a network with inter-container communication disabled. - There's an additional chain `DOCKER-INGRESS`. - - The jump to `DOCKER-INGRESS` is in the `FORWARD` chain. + - The jump to `DOCKER-INGRESS` is first in the `DOCKER-FORWARD` chain. And the corresponding nat table: diff --git a/libnetwork/service_linux.go b/libnetwork/service_linux.go index d7bef874a4..02d652fb66 100644 --- a/libnetwork/service_linux.go +++ b/libnetwork/service_linux.go @@ -13,6 +13,7 @@ import ( "syscall" "github.com/containerd/log" + "github.com/docker/docker/libnetwork/drivers/bridge" "github.com/docker/docker/libnetwork/iptables" "github.com/docker/docker/libnetwork/ns" "github.com/ishidawataru/sctp" @@ -359,13 +360,21 @@ func programIngress(gwIP net.IP, ingressPorts []*PortConfig, isDelete bool) erro } } - if !iptable.Exists(iptables.Filter, "FORWARD", "-j", ingressChain) { - if err := iptable.RawCombinedOutput("-I", "FORWARD", "-j", ingressChain); err != nil { - return fmt.Errorf("failed to add jump rule to %s in filter table forward chain: %v", ingressChain, err) + // The DOCKER-FORWARD chain is created by the bridge driver on startup. It's a stable place to + // put the jump to DOCKER-INGRESS (nothing else will ever be inserted before it, and the jump + // will precede the bridge driver's other rules). + if !iptable.Exists(iptables.Filter, bridge.DockerForwardChain, "-j", ingressChain) { + if err := iptable.RawCombinedOutput("-I", bridge.DockerForwardChain, "-j", ingressChain); err != nil { + return fmt.Errorf("failed to add jump rule to %s in filter table %s chain: %v", + ingressChain, bridge.DockerForwardChain, err) } - // The jump to DOCKER-USER needs to be before the jump to DOCKER-INGRESS. - if err := setupUserChain(iptables.IPv4); err != nil { - log.G(context.TODO()).Warnf("Failed to restore "+userChain+" after creating "+ingressChain+": %v", err) + } + // Remove the jump from FORWARD to DOCKER-INGRESS, if it was created there by a version of + // the daemon older than 28.0.1. + // FIXME(robmry) - should only do this once, on startup. + if iptable.Exists(iptables.Filter, "FORWARD", "-j", ingressChain) { + if err := iptable.RawCombinedOutput("-D", "FORWARD", "-j", ingressChain); err != nil { + log.G(context.TODO()).WithError(err).Debug("Failed to delete jump from FORWARD to " + ingressChain) } }