Files
moby/integration/network/bridge/iptablesdoc/generated/usernet-portmap-natunprot.md
Rob Murray 1ad9599da7 Drop DOCKER-ISOLATION rules
The Inter-Network Communication rules in the iptables chains
DOCKER-ISOLATION-STAGE-1 / DOCKER-ISOLATION-STAGE-2 (which are
called from filter-FORWARD) currently:
- Block access from containers in one bridge network, to ports
  published to host addresses by containers in other bridge
  networks, when the userland-proxy is disabled.
  - But, that access is allowed when the proxy is enabled.
- Block access to all ports on container addresses in gateway
  mode "nat-unprotected" networks.
  - But, those ports can be accessed from anywhere else, including
    other hosts. Just not other bridge networks.
- Allow access from containers in "nat" bridge networks to published
  ports on container addresses in "routed" networks. But, to do that,
  extra INC rules are added for the routed network.

The INC rules are no longer needed to block access from containers
in one network to unpublished ports on container addresses in
other networks. Direct routing to containers in NAT networks is
blocked by the "raw-PREROUTING" rules that block access from
untrusted interfaces (all interfaces apart from the network's
own bridge).

Drop these INC rules to resolve the inconsistencies listed above,
with this change:
- Published ports on host addresses can be accessed from containers
  in other networks (even without the userland-proxy).
- The rules for direct routing between bridge networks are the same
  as the rules for direct routing from outside the Docker host
  (allowed for gw modes "routed" and "nat-unprotected", disallowed
  for "nat").

Fewer rules, so it's simpler, and perhaps slightly faster.

Internal networks (with no access to networks outside the host)
are also implemented using rules in the DOCKER-ISOLATION chains.
This change moves those rules to a new chain, DOCKER-INTERNAL,
and drops the DOCKER-ISOLATION chains.

Signed-off-by: Rob Murray <rob.murray@docker.com>
2025-06-16 14:54:31 +01:00

6.7 KiB

Container on a nat-unprotected network, with a published port

Running the daemon with the userland proxy disable then, as before, adding a network running a container with a mapped port, equivalent to:

docker network create \
  -o com.docker.network.bridge.name=bridge1 \
  -o com.docker.network.bridge.gateway_mode_ipv4=nat-unprotected \
  --subnet 192.0.2.0/24 --gateway 192.0.2.1 bridge1
docker run --network bridge1 -p 8080:80 --name c1 busybox

The filter table is:

Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
num   pkts bytes target     prot opt in     out     source               destination         

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

Chain DOCKER (2 references)
num   pkts bytes target     prot opt in     out     source               destination         
1        0     0 DROP       0    --  !docker0 docker0  0.0.0.0/0            0.0.0.0/0           
2        0     0 ACCEPT     0    --  !bridge1 bridge1  0.0.0.0/0            0.0.0.0/0           

Chain DOCKER-BRIDGE (1 references)
num   pkts bytes target     prot opt in     out     source               destination         
1        0     0 DOCKER     0    --  *      docker0  0.0.0.0/0            0.0.0.0/0           
2        0     0 DOCKER     0    --  *      bridge1  0.0.0.0/0            0.0.0.0/0           

Chain DOCKER-CT (1 references)
num   pkts bytes target     prot opt in     out     source               destination         
1        0     0 ACCEPT     0    --  *      docker0  0.0.0.0/0            0.0.0.0/0            ctstate RELATED,ESTABLISHED
2        0     0 ACCEPT     0    --  *      bridge1  0.0.0.0/0            0.0.0.0/0            ctstate RELATED,ESTABLISHED

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-INTERNAL  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 ACCEPT     0    --  bridge1 *       0.0.0.0/0            0.0.0.0/0           

Chain DOCKER-INTERNAL (1 references)
num   pkts bytes target     prot opt in     out     source               destination         

Chain DOCKER-USER (1 references)
num   pkts bytes target     prot opt in     out     source               destination         
iptables commands
-P INPUT ACCEPT
-P FORWARD ACCEPT
-P OUTPUT ACCEPT
-N DOCKER
-N DOCKER-BRIDGE
-N DOCKER-CT
-N DOCKER-FORWARD
-N DOCKER-INTERNAL
-N DOCKER-USER
-A FORWARD -j DOCKER-USER
-A FORWARD -j DOCKER-FORWARD
-A DOCKER ! -i docker0 -o docker0 -j DROP
-A DOCKER ! -i bridge1 -o bridge1 -j ACCEPT
-A DOCKER-BRIDGE -o docker0 -j DOCKER
-A DOCKER-BRIDGE -o bridge1 -j DOCKER
-A DOCKER-CT -o docker0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A DOCKER-CT -o bridge1 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A DOCKER-FORWARD -j DOCKER-CT
-A DOCKER-FORWARD -j DOCKER-INTERNAL
-A DOCKER-FORWARD -j DOCKER-BRIDGE
-A DOCKER-FORWARD -i docker0 -j ACCEPT
-A DOCKER-FORWARD -i bridge1 -j ACCEPT

Differences from nat mode:

  • In the DOCKER chain:
    • Where nat mode appended a default-DROP rule for any packets not accepted by the per-port/protocol rules, nat-unprotected appends a default-ACCEPT rule. setDefaultForwardRule
      • The ACCEPT rule is needed in case the filter-FORWARD chain's default policy is DROP.
    • Because the default for this network is ACCEPT, there is no per-port/protocol rule to ACCEPT packets for the published port 80/tcp, setPerPortIptables doesn't set it up.
      • If the userland proxy is enabled, it is still started.

The nat table is identical to nat mode.

nat table
Chain PREROUTING (policy ACCEPT 0 packets, 0 bytes)
num   pkts bytes target     prot opt in     out     source               destination         
1        0     0 DOCKER     0    --  *      *       0.0.0.0/0            0.0.0.0/0            ADDRTYPE match dst-type LOCAL

Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
num   pkts bytes target     prot opt in     out     source               destination         

Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
num   pkts bytes target     prot opt in     out     source               destination         
1        0     0 DOCKER     0    --  *      *       0.0.0.0/0           !127.0.0.0/8          ADDRTYPE match dst-type LOCAL

Chain POSTROUTING (policy ACCEPT 0 packets, 0 bytes)
num   pkts bytes target     prot opt in     out     source               destination         
1        0     0 MASQUERADE  0    --  *      !bridge1  192.0.2.0/24         0.0.0.0/0           
2        0     0 MASQUERADE  0    --  *      !docker0  172.17.0.0/16        0.0.0.0/0           

Chain DOCKER (2 references)
num   pkts bytes target     prot opt in     out     source               destination         
1        0     0 DNAT       6    --  !bridge1 *       0.0.0.0/0            0.0.0.0/0            tcp dpt:8080 to:192.0.2.2:80


-P PREROUTING ACCEPT
-P INPUT ACCEPT
-P OUTPUT ACCEPT
-P POSTROUTING ACCEPT
-N DOCKER
-A PREROUTING -m addrtype --dst-type LOCAL -j DOCKER
-A OUTPUT ! -d 127.0.0.0/8 -m addrtype --dst-type LOCAL -j DOCKER
-A POSTROUTING -s 192.0.2.0/24 ! -o bridge1 -j MASQUERADE
-A POSTROUTING -s 172.17.0.0/16 ! -o docker0 -j MASQUERADE
-A DOCKER ! -i bridge1 -p tcp -m tcp --dport 8080 -j DNAT --to-destination 192.0.2.2:80