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 <rob.murray@docker.com>
This commit is contained in:
Rob Murray
2025-02-24 21:08:19 +00:00
parent f92fdfecbf
commit 558da63444
3 changed files with 26 additions and 17 deletions

View File

@@ -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:

View File

@@ -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:

View File

@@ -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)
}
}