diff --git a/integration/network/bridge/iptablesdoc/generated/new-daemon.md b/integration/network/bridge/iptablesdoc/generated/new-daemon.md index 5934431cd654f..9fcce6f3537bc 100644 --- a/integration/network/bridge/iptablesdoc/generated/new-daemon.md +++ b/integration/network/bridge/iptablesdoc/generated/new-daemon.md @@ -14,8 +14,7 @@ Table `filter`: 2 0 0 ACCEPT 0 -- * * 0.0.0.0/0 0.0.0.0/0 match-set docker-ext-bridges-v4 dst ctstate RELATED,ESTABLISHED 3 0 0 DOCKER-ISOLATION-STAGE-1 0 -- * * 0.0.0.0/0 0.0.0.0/0 4 0 0 DOCKER 0 -- * * 0.0.0.0/0 0.0.0.0/0 match-set docker-ext-bridges-v4 dst - 5 0 0 ACCEPT 0 -- docker0 docker0 0.0.0.0/0 0.0.0.0/0 - 6 0 0 ACCEPT 0 -- docker0 !docker0 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 Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes) num pkts bytes target prot opt in out source destination @@ -51,8 +50,7 @@ Table `filter`: -A FORWARD -m set --match-set docker-ext-bridges-v4 dst -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT -A FORWARD -j DOCKER-ISOLATION-STAGE-1 -A FORWARD -m set --match-set docker-ext-bridges-v4 dst -j DOCKER - -A FORWARD -i docker0 -o docker0 -j ACCEPT - -A FORWARD -i docker0 ! -o docker0 -j ACCEPT + -A FORWARD -i docker0 -j ACCEPT -A DOCKER ! -i docker0 -o docker0 -j DROP -A DOCKER-ISOLATION-STAGE-1 -i docker0 ! -o docker0 -j DOCKER-ISOLATION-STAGE-2 -A DOCKER-ISOLATION-STAGE-2 -o docker0 -j DROP @@ -81,36 +79,25 @@ The FORWARD chain rules are numbered in the output above, they are: 2. Early ACCEPT for any RELATED,ESTABLISHED traffic to a docker bridge. This rule matches against an `ipset` called `docker-ext-bridges-v4` (`v6` for IPv6). The set contains the CIDR address of each docker network, and it is updated as networks - are created and deleted. - So, this rule could be set up during bridge driver initialisation. But, it is - currently set up when a network is created, in [setupIPTables][11]. + are created and deleted. This rule is created during driver initialisation, in + `setupIPChains`. 3. Unconditional jump to DOCKER-ISOLATION-STAGE-1. - Set up during network creation by [setupIPTables][12], which ensures it appears - after the jump to DOCKER-USER (by deleting it and re-creating, while traffic - may be running for other networks). + Also created during driver initialisation, in `setupIPChains`. 4. Jump to DOCKER, for any packet destined for any bridge network, identified by - matching against the `docker-ext-bridge-v[46]` set. Added when the network is - created, in [setupIPTables][13]. + matching against the `docker-ext-bridge-v[46]` set. + Also created during driver initialisation, in `setupIPChains`. The DOCKER chain implements per-port/protocol filtering for each container. - 5. ACCEPT packets flowing between containers within a network, because by default - container isolation is disabled. Also set up when the network is created, in - [setIcc][15]. - 6. ACCEPT any packet leaving a network, also set up when the network is created, in - [setupIPTablesInternal][14]. - + 5. ACCEPT any packet leaving a network, set up when the network is created, in + `setupIPTablesInternal`. Note that this accepts any packet leaving the + network that's made it through the DOCKER and isolation chains, whether the + destination is external or another network. [10]: https://github.com/moby/moby/blob/e05848c0025b67a16aaafa8cdff95d5e2c064105/libnetwork/firewall_linux.go#L50 [11]: https://github.com/robmry/moby/blob/52c89d467fc5326149e4bbb8903d23589b66ff0d/libnetwork/drivers/bridge/setup_ip_tables_linux.go#L230-L232 [12]: https://github.com/robmry/moby/blob/52c89d467fc5326149e4bbb8903d23589b66ff0d/libnetwork/drivers/bridge/setup_ip_tables_linux.go#L227-L229 [13]: https://github.com/robmry/moby/blob/52c89d467fc5326149e4bbb8903d23589b66ff0d/libnetwork/drivers/bridge/setup_ip_tables_linux.go#L223-L226 -[14]: https://github.com/moby/moby/blob/333cfa640239153477bf635a8131734d0e9d099d/libnetwork/drivers/bridge/setup_ip_tables_linux.go#L264 [15]: https://github.com/moby/moby/blob/333cfa640239153477bf635a8131734d0e9d099d/libnetwork/drivers/bridge/setup_ip_tables_linux.go#L343 -_With ICC enabled 5 and 6 could be combined, to ACCEPT anything from the bridge. -But, when ICC is disabled, rule 6 is DROP, so it would need to be placed before -rule 5. Because the rules are generated in different places, that's a slightly -bigger change than it should be._ - The DOCKER chain has a single DROP rule for the bridge network, to drop any packets routed to the network that have not originated in the network. Added by [setDefaultForwardRule][21]. diff --git a/integration/network/bridge/iptablesdoc/generated/swarm-portmap.md b/integration/network/bridge/iptablesdoc/generated/swarm-portmap.md index 943f5f1589494..1455a261a82a7 100644 --- a/integration/network/bridge/iptablesdoc/generated/swarm-portmap.md +++ b/integration/network/bridge/iptablesdoc/generated/swarm-portmap.md @@ -16,10 +16,9 @@ The filter table is: 3 0 0 ACCEPT 0 -- * * 0.0.0.0/0 0.0.0.0/0 match-set docker-ext-bridges-v4 dst ctstate RELATED,ESTABLISHED 4 0 0 DOCKER-ISOLATION-STAGE-1 0 -- * * 0.0.0.0/0 0.0.0.0/0 5 0 0 DOCKER 0 -- * * 0.0.0.0/0 0.0.0.0/0 match-set docker-ext-bridges-v4 dst - 6 0 0 ACCEPT 0 -- docker0 docker0 0.0.0.0/0 0.0.0.0/0 - 7 0 0 ACCEPT 0 -- docker0 !docker0 0.0.0.0/0 0.0.0.0/0 - 8 0 0 DROP 0 -- docker_gwbridge docker_gwbridge 0.0.0.0/0 0.0.0.0/0 - 9 0 0 ACCEPT 0 -- docker_gwbridge !docker_gwbridge 0.0.0.0/0 0.0.0.0/0 + 6 0 0 ACCEPT 0 -- docker0 * 0.0.0.0/0 0.0.0.0/0 + 7 0 0 DROP 0 -- docker_gwbridge docker_gwbridge 0.0.0.0/0 0.0.0.0/0 + 8 0 0 ACCEPT 0 -- docker_gwbridge !docker_gwbridge 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 @@ -66,8 +65,7 @@ The filter table is: -A FORWARD -m set --match-set docker-ext-bridges-v4 dst -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT -A FORWARD -j DOCKER-ISOLATION-STAGE-1 -A FORWARD -m set --match-set docker-ext-bridges-v4 dst -j DOCKER - -A FORWARD -i docker0 -o docker0 -j ACCEPT - -A FORWARD -i docker0 ! -o docker0 -j ACCEPT + -A FORWARD -i docker0 -j ACCEPT -A FORWARD -i docker_gwbridge -o docker_gwbridge -j DROP -A FORWARD -i docker_gwbridge ! -o docker_gwbridge -j ACCEPT -A DOCKER ! -i docker0 -o docker0 -j DROP diff --git a/integration/network/bridge/iptablesdoc/generated/usernet-internal.md b/integration/network/bridge/iptablesdoc/generated/usernet-internal.md index 1696966a3b977..a071562f8116f 100644 --- a/integration/network/bridge/iptablesdoc/generated/usernet-internal.md +++ b/integration/network/bridge/iptablesdoc/generated/usernet-internal.md @@ -1,12 +1,22 @@ -## Container on a user-defined --internal network +## Containers on user-defined --internal networks + +These are the rules for two containers on different `--internal` networks, with and +without inter-container communication. Equivalent to: docker network create \ - -o com.docker.network.bridge.name=bridge1 \ + -o com.docker.network.bridge.name=bridgeICC \ --internal \ --subnet 192.0.2.0/24 --gateway 192.0.2.1 bridge1 - docker run --network bridge1 --name c1 busybox + docker run --network bridgeICC --name c1 busybox + + docker network create \ + -o com.docker.network.bridge.name=bridgeNoICC \ + -o com.docker.network.bridge.enable_icc=true \ + --internal \ + --subnet 198.51.100.0/24 --gateway 198.51.100.1 bridge1 + docker run --network bridgeNoICC --name c1 busybox The filter table is updated as follows: @@ -19,9 +29,9 @@ The filter table is updated as follows: 2 0 0 ACCEPT 0 -- * * 0.0.0.0/0 0.0.0.0/0 match-set docker-ext-bridges-v4 dst ctstate RELATED,ESTABLISHED 3 0 0 DOCKER-ISOLATION-STAGE-1 0 -- * * 0.0.0.0/0 0.0.0.0/0 4 0 0 DOCKER 0 -- * * 0.0.0.0/0 0.0.0.0/0 match-set docker-ext-bridges-v4 dst - 5 0 0 ACCEPT 0 -- docker0 docker0 0.0.0.0/0 0.0.0.0/0 - 6 0 0 ACCEPT 0 -- docker0 !docker0 0.0.0.0/0 0.0.0.0/0 - 7 0 0 ACCEPT 0 -- bridge1 bridge1 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 ACCEPT 0 -- bridgeICC bridgeICC 0.0.0.0/0 0.0.0.0/0 + 7 0 0 DROP 0 -- bridgeNoICC bridgeNoICC 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 @@ -32,9 +42,11 @@ The filter table is updated as follows: Chain DOCKER-ISOLATION-STAGE-1 (1 references) num pkts bytes target prot opt in out source destination - 1 0 0 DROP 0 -- * bridge1 !192.0.2.0/24 0.0.0.0/0 - 2 0 0 DROP 0 -- bridge1 * 0.0.0.0/0 !192.0.2.0/24 - 3 0 0 DOCKER-ISOLATION-STAGE-2 0 -- docker0 !docker0 0.0.0.0/0 0.0.0.0/0 + 1 0 0 DROP 0 -- * bridgeNoICC !198.51.100.0/24 0.0.0.0/0 + 2 0 0 DROP 0 -- bridgeNoICC * 0.0.0.0/0 !198.51.100.0/24 + 3 0 0 DROP 0 -- * bridgeICC !192.0.2.0/24 0.0.0.0/0 + 4 0 0 DROP 0 -- bridgeICC * 0.0.0.0/0 !192.0.2.0/24 + 5 0 0 DOCKER-ISOLATION-STAGE-2 0 -- docker0 !docker0 0.0.0.0/0 0.0.0.0/0 Chain DOCKER-ISOLATION-STAGE-2 (1 references) num pkts bytes target prot opt in out source destination @@ -59,12 +71,14 @@ The filter table is updated as follows: -A FORWARD -m set --match-set docker-ext-bridges-v4 dst -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT -A FORWARD -j DOCKER-ISOLATION-STAGE-1 -A FORWARD -m set --match-set docker-ext-bridges-v4 dst -j DOCKER - -A FORWARD -i docker0 -o docker0 -j ACCEPT - -A FORWARD -i docker0 ! -o docker0 -j ACCEPT - -A FORWARD -i bridge1 -o bridge1 -j ACCEPT + -A FORWARD -i docker0 -j ACCEPT + -A FORWARD -i bridgeICC -o bridgeICC -j ACCEPT + -A FORWARD -i bridgeNoICC -o bridgeNoICC -j DROP -A DOCKER ! -i docker0 -o docker0 -j DROP - -A DOCKER-ISOLATION-STAGE-1 ! -s 192.0.2.0/24 -o bridge1 -j DROP - -A DOCKER-ISOLATION-STAGE-1 ! -d 192.0.2.0/24 -i bridge1 -j DROP + -A DOCKER-ISOLATION-STAGE-1 ! -s 198.51.100.0/24 -o bridgeNoICC -j DROP + -A DOCKER-ISOLATION-STAGE-1 ! -d 198.51.100.0/24 -i bridgeNoICC -j DROP + -A DOCKER-ISOLATION-STAGE-1 ! -s 192.0.2.0/24 -o bridgeICC -j DROP + -A DOCKER-ISOLATION-STAGE-1 ! -d 192.0.2.0/24 -i bridgeICC -j DROP -A DOCKER-ISOLATION-STAGE-1 -i docker0 ! -o docker0 -j DOCKER-ISOLATION-STAGE-2 -A DOCKER-ISOLATION-STAGE-2 -o docker0 -j DROP -A DOCKER-USER -j RETURN @@ -74,7 +88,7 @@ The filter table is updated as follows: By comparison with the [network with external access][1]: -- In the FORWARD chain, there is no ACCEPT rule for outgoing packets `-i bridge1 -o ! bridge1`. +- In the FORWARD chain, there is no ACCEPT rule for outgoing packets (`-i bridgeINC`). - There are no rules for this network in the DOCKER chain. - In DOCKER-ISOLATION-STAGE-1: - Rule 1 drops any packet routed to the network that does not have a source address in the network's subnet. @@ -82,6 +96,10 @@ By comparison with the [network with external access][1]: - There is no jump to DOCKER-ISOLATION-STAGE-2. - DOCKER-ISOLATION-STAGE-2 is unused. +The only difference between `bridgeICC` and `bridgeNoICC` is the rule in the FORWARD +chain. To enable ICC, the rule for packets looping through the bridge is ACCEPT. For +no-ICC it's DROP. + [1]: usernet-portmap.md And the corresponding nat table: diff --git a/integration/network/bridge/iptablesdoc/generated/usernet-portmap-natunprot.md b/integration/network/bridge/iptablesdoc/generated/usernet-portmap-natunprot.md index b38d3b051e174..3d1722bcc5197 100644 --- a/integration/network/bridge/iptablesdoc/generated/usernet-portmap-natunprot.md +++ b/integration/network/bridge/iptablesdoc/generated/usernet-portmap-natunprot.md @@ -19,10 +19,8 @@ The filter table is: 2 0 0 ACCEPT 0 -- * * 0.0.0.0/0 0.0.0.0/0 match-set docker-ext-bridges-v4 dst ctstate RELATED,ESTABLISHED 3 0 0 DOCKER-ISOLATION-STAGE-1 0 -- * * 0.0.0.0/0 0.0.0.0/0 4 0 0 DOCKER 0 -- * * 0.0.0.0/0 0.0.0.0/0 match-set docker-ext-bridges-v4 dst - 5 0 0 ACCEPT 0 -- docker0 docker0 0.0.0.0/0 0.0.0.0/0 - 6 0 0 ACCEPT 0 -- docker0 !docker0 0.0.0.0/0 0.0.0.0/0 - 7 0 0 ACCEPT 0 -- bridge1 bridge1 0.0.0.0/0 0.0.0.0/0 - 8 0 0 ACCEPT 0 -- bridge1 !bridge1 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 ACCEPT 0 -- bridge1 * 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 @@ -61,10 +59,8 @@ The filter table is: -A FORWARD -m set --match-set docker-ext-bridges-v4 dst -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT -A FORWARD -j DOCKER-ISOLATION-STAGE-1 -A FORWARD -m set --match-set docker-ext-bridges-v4 dst -j DOCKER - -A FORWARD -i docker0 -o docker0 -j ACCEPT - -A FORWARD -i docker0 ! -o docker0 -j ACCEPT - -A FORWARD -i bridge1 -o bridge1 -j ACCEPT - -A FORWARD -i bridge1 ! -o bridge1 -j ACCEPT + -A FORWARD -i docker0 -j ACCEPT + -A FORWARD -i bridge1 -j ACCEPT -A DOCKER ! -i docker0 -o docker0 -j DROP -A DOCKER ! -i bridge1 -o bridge1 -j ACCEPT -A DOCKER-ISOLATION-STAGE-1 -i docker0 ! -o docker0 -j DOCKER-ISOLATION-STAGE-2 diff --git a/integration/network/bridge/iptablesdoc/generated/usernet-portmap-noicc.md b/integration/network/bridge/iptablesdoc/generated/usernet-portmap-noicc.md index 23dd40e5b8766..2e0a9de5a2223 100644 --- a/integration/network/bridge/iptablesdoc/generated/usernet-portmap-noicc.md +++ b/integration/network/bridge/iptablesdoc/generated/usernet-portmap-noicc.md @@ -19,10 +19,9 @@ The filter table is: 2 0 0 ACCEPT 0 -- * * 0.0.0.0/0 0.0.0.0/0 match-set docker-ext-bridges-v4 dst ctstate RELATED,ESTABLISHED 3 0 0 DOCKER-ISOLATION-STAGE-1 0 -- * * 0.0.0.0/0 0.0.0.0/0 4 0 0 DOCKER 0 -- * * 0.0.0.0/0 0.0.0.0/0 match-set docker-ext-bridges-v4 dst - 5 0 0 ACCEPT 0 -- docker0 docker0 0.0.0.0/0 0.0.0.0/0 - 6 0 0 ACCEPT 0 -- docker0 !docker0 0.0.0.0/0 0.0.0.0/0 - 7 0 0 DROP 0 -- bridge1 bridge1 0.0.0.0/0 0.0.0.0/0 - 8 0 0 ACCEPT 0 -- bridge1 !bridge1 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 -- bridge1 bridge1 0.0.0.0/0 0.0.0.0/0 + 7 0 0 ACCEPT 0 -- bridge1 !bridge1 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 @@ -62,8 +61,7 @@ The filter table is: -A FORWARD -m set --match-set docker-ext-bridges-v4 dst -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT -A FORWARD -j DOCKER-ISOLATION-STAGE-1 -A FORWARD -m set --match-set docker-ext-bridges-v4 dst -j DOCKER - -A FORWARD -i docker0 -o docker0 -j ACCEPT - -A FORWARD -i docker0 ! -o docker0 -j ACCEPT + -A FORWARD -i docker0 -j ACCEPT -A FORWARD -i bridge1 -o bridge1 -j DROP -A FORWARD -i bridge1 ! -o bridge1 -j ACCEPT -A DOCKER -d 192.0.2.2/32 ! -i bridge1 -o bridge1 -p tcp -m tcp --dport 80 -j ACCEPT @@ -80,11 +78,11 @@ The filter table is: By comparison with [ICC=true][1]: - - Rule 7 in the FORWARD chain replaces an ACCEPT rule that would have followed rule 5, matching the same packets. - - Added in [setIcc][2] + - Rules 6 and 7 replace the accept rule for outgoing packets. + - Rule 6, added by `setIcc`, drops any packet sent from the internal network to itself. + - Rule 7, added by `setupIPTablesInternal` accepts any other outgoing packet. [1]: usernet-portmap.md -[2]: https://github.com/moby/moby/blob/333cfa640239153477bf635a8131734d0e9d099d/libnetwork/drivers/bridge/setup_ip_tables_linux.go#L344 And the corresponding nat table: diff --git a/integration/network/bridge/iptablesdoc/generated/usernet-portmap-noproxy.md b/integration/network/bridge/iptablesdoc/generated/usernet-portmap-noproxy.md index d9f5b96ee9ad6..a75def1483e80 100644 --- a/integration/network/bridge/iptablesdoc/generated/usernet-portmap-noproxy.md +++ b/integration/network/bridge/iptablesdoc/generated/usernet-portmap-noproxy.md @@ -22,10 +22,8 @@ The filter table is the same as with the userland proxy enabled. 2 0 0 ACCEPT 0 -- * * 0.0.0.0/0 0.0.0.0/0 match-set docker-ext-bridges-v4 dst ctstate RELATED,ESTABLISHED 3 0 0 DOCKER-ISOLATION-STAGE-1 0 -- * * 0.0.0.0/0 0.0.0.0/0 4 0 0 DOCKER 0 -- * * 0.0.0.0/0 0.0.0.0/0 match-set docker-ext-bridges-v4 dst - 5 0 0 ACCEPT 0 -- docker0 docker0 0.0.0.0/0 0.0.0.0/0 - 6 0 0 ACCEPT 0 -- docker0 !docker0 0.0.0.0/0 0.0.0.0/0 - 7 0 0 ACCEPT 0 -- bridge1 bridge1 0.0.0.0/0 0.0.0.0/0 - 8 0 0 ACCEPT 0 -- bridge1 !bridge1 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 ACCEPT 0 -- bridge1 * 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 @@ -62,10 +60,8 @@ The filter table is the same as with the userland proxy enabled. -A FORWARD -m set --match-set docker-ext-bridges-v4 dst -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT -A FORWARD -j DOCKER-ISOLATION-STAGE-1 -A FORWARD -m set --match-set docker-ext-bridges-v4 dst -j DOCKER - -A FORWARD -i docker0 -o docker0 -j ACCEPT - -A FORWARD -i docker0 ! -o docker0 -j ACCEPT - -A FORWARD -i bridge1 -o bridge1 -j ACCEPT - -A FORWARD -i bridge1 ! -o bridge1 -j ACCEPT + -A FORWARD -i docker0 -j ACCEPT + -A FORWARD -i bridge1 -j ACCEPT -A DOCKER -d 192.0.2.2/32 ! -i bridge1 -o bridge1 -p tcp -m tcp --dport 80 -j ACCEPT -A DOCKER ! -i docker0 -o docker0 -j DROP -A DOCKER ! -i bridge1 -o bridge1 -j DROP diff --git a/integration/network/bridge/iptablesdoc/generated/usernet-portmap-routed.md b/integration/network/bridge/iptablesdoc/generated/usernet-portmap-routed.md index 4a7ba24b1fa8d..00cbda776dedf 100644 --- a/integration/network/bridge/iptablesdoc/generated/usernet-portmap-routed.md +++ b/integration/network/bridge/iptablesdoc/generated/usernet-portmap-routed.md @@ -19,10 +19,8 @@ The filter table is: 2 0 0 ACCEPT 0 -- * * 0.0.0.0/0 0.0.0.0/0 match-set docker-ext-bridges-v4 dst ctstate RELATED,ESTABLISHED 3 0 0 DOCKER-ISOLATION-STAGE-1 0 -- * * 0.0.0.0/0 0.0.0.0/0 4 0 0 DOCKER 0 -- * * 0.0.0.0/0 0.0.0.0/0 match-set docker-ext-bridges-v4 dst - 5 0 0 ACCEPT 0 -- docker0 docker0 0.0.0.0/0 0.0.0.0/0 - 6 0 0 ACCEPT 0 -- docker0 !docker0 0.0.0.0/0 0.0.0.0/0 - 7 0 0 ACCEPT 0 -- bridge1 bridge1 0.0.0.0/0 0.0.0.0/0 - 8 0 0 ACCEPT 0 -- bridge1 !bridge1 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 ACCEPT 0 -- bridge1 * 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 @@ -65,10 +63,8 @@ The filter table is: -A FORWARD -m set --match-set docker-ext-bridges-v4 dst -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT -A FORWARD -j DOCKER-ISOLATION-STAGE-1 -A FORWARD -m set --match-set docker-ext-bridges-v4 dst -j DOCKER - -A FORWARD -i docker0 -o docker0 -j ACCEPT - -A FORWARD -i docker0 ! -o docker0 -j ACCEPT - -A FORWARD -i bridge1 -o bridge1 -j ACCEPT - -A FORWARD -i bridge1 ! -o bridge1 -j ACCEPT + -A FORWARD -i docker0 -j ACCEPT + -A FORWARD -i bridge1 -j ACCEPT -A DOCKER -d 192.0.2.2/32 ! -i bridge1 -o bridge1 -p tcp -m tcp --dport 80 -j ACCEPT -A DOCKER ! -i docker0 -o docker0 -j DROP -A DOCKER -o bridge1 -p icmp -j ACCEPT diff --git a/integration/network/bridge/iptablesdoc/generated/usernet-portmap.md b/integration/network/bridge/iptablesdoc/generated/usernet-portmap.md index be220b04aa5ed..a9bb5af3bcb39 100644 --- a/integration/network/bridge/iptablesdoc/generated/usernet-portmap.md +++ b/integration/network/bridge/iptablesdoc/generated/usernet-portmap.md @@ -18,10 +18,8 @@ The filter table is updated as follows: 2 0 0 ACCEPT 0 -- * * 0.0.0.0/0 0.0.0.0/0 match-set docker-ext-bridges-v4 dst ctstate RELATED,ESTABLISHED 3 0 0 DOCKER-ISOLATION-STAGE-1 0 -- * * 0.0.0.0/0 0.0.0.0/0 4 0 0 DOCKER 0 -- * * 0.0.0.0/0 0.0.0.0/0 match-set docker-ext-bridges-v4 dst - 5 0 0 ACCEPT 0 -- docker0 docker0 0.0.0.0/0 0.0.0.0/0 - 6 0 0 ACCEPT 0 -- docker0 !docker0 0.0.0.0/0 0.0.0.0/0 - 7 0 0 ACCEPT 0 -- bridge1 bridge1 0.0.0.0/0 0.0.0.0/0 - 8 0 0 ACCEPT 0 -- bridge1 !bridge1 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 ACCEPT 0 -- bridge1 * 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 @@ -61,10 +59,8 @@ The filter table is updated as follows: -A FORWARD -m set --match-set docker-ext-bridges-v4 dst -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT -A FORWARD -j DOCKER-ISOLATION-STAGE-1 -A FORWARD -m set --match-set docker-ext-bridges-v4 dst -j DOCKER - -A FORWARD -i docker0 -o docker0 -j ACCEPT - -A FORWARD -i docker0 ! -o docker0 -j ACCEPT - -A FORWARD -i bridge1 -o bridge1 -j ACCEPT - -A FORWARD -i bridge1 ! -o bridge1 -j ACCEPT + -A FORWARD -i docker0 -j ACCEPT + -A FORWARD -i bridge1 -j ACCEPT -A DOCKER -d 192.0.2.2/32 ! -i bridge1 -o bridge1 -p tcp -m tcp --dport 80 -j ACCEPT -A DOCKER ! -i docker0 -o docker0 -j DROP -A DOCKER ! -i bridge1 -o bridge1 -j DROP @@ -79,8 +75,8 @@ The filter table is updated as follows: Note that: - - In the FORWARD chain, rules 7-8 for the new network have been appended to - the end of the chain. + - In the FORWARD chain, rule 6 for outgoing traffic from the new network has been + appended to the end of the chain. - In the DOCKER-ISOLATION chains, rules equivalent to the docker0 rules have also been inserted for the new bridge. - In the DOCKER chain, there is an ACCEPT rule for TCP port 80 packets routed diff --git a/integration/network/bridge/iptablesdoc/iptablesdoc_linux_test.go b/integration/network/bridge/iptablesdoc/iptablesdoc_linux_test.go index 8ac31f2b401e8..122896a8a7c9b 100644 --- a/integration/network/bridge/iptablesdoc/iptablesdoc_linux_test.go +++ b/integration/network/bridge/iptablesdoc/iptablesdoc_linux_test.go @@ -118,13 +118,22 @@ var index = []section{ { name: "usernet-internal.md", networks: []networkDesc{{ - name: "bridge1", + name: "bridgeICC", internal: true, containers: []ctrDesc{ { name: "c1", }, }, + }, { + name: "bridgeNoICC", + internal: true, + noICC: true, + containers: []ctrDesc{ + { + name: "c1", + }, + }, }}, }, { diff --git a/integration/network/bridge/iptablesdoc/templates/new-daemon.md b/integration/network/bridge/iptablesdoc/templates/new-daemon.md index b532e4e929d81..3470411745cfb 100644 --- a/integration/network/bridge/iptablesdoc/templates/new-daemon.md +++ b/integration/network/bridge/iptablesdoc/templates/new-daemon.md @@ -34,36 +34,25 @@ The FORWARD chain rules are numbered in the output above, they are: 2. Early ACCEPT for any RELATED,ESTABLISHED traffic to a docker bridge. This rule matches against an `ipset` called `docker-ext-bridges-v4` (`v6` for IPv6). The set contains the CIDR address of each docker network, and it is updated as networks - are created and deleted. - So, this rule could be set up during bridge driver initialisation. But, it is - currently set up when a network is created, in [setupIPTables][11]. + are created and deleted. This rule is created during driver initialisation, in + `setupIPChains`. 3. Unconditional jump to DOCKER-ISOLATION-STAGE-1. - Set up during network creation by [setupIPTables][12], which ensures it appears - after the jump to DOCKER-USER (by deleting it and re-creating, while traffic - may be running for other networks). + Also created during driver initialisation, in `setupIPChains`. 4. Jump to DOCKER, for any packet destined for any bridge network, identified by - matching against the `docker-ext-bridge-v[46]` set. Added when the network is - created, in [setupIPTables][13]. + matching against the `docker-ext-bridge-v[46]` set. + Also created during driver initialisation, in `setupIPChains`. The DOCKER chain implements per-port/protocol filtering for each container. - 5. ACCEPT packets flowing between containers within a network, because by default - container isolation is disabled. Also set up when the network is created, in - [setIcc][15]. - 6. ACCEPT any packet leaving a network, also set up when the network is created, in - [setupIPTablesInternal][14]. - + 5. ACCEPT any packet leaving a network, set up when the network is created, in + `setupIPTablesInternal`. Note that this accepts any packet leaving the + network that's made it through the DOCKER and isolation chains, whether the + destination is external or another network. [10]: https://github.com/moby/moby/blob/e05848c0025b67a16aaafa8cdff95d5e2c064105/libnetwork/firewall_linux.go#L50 [11]: https://github.com/robmry/moby/blob/52c89d467fc5326149e4bbb8903d23589b66ff0d/libnetwork/drivers/bridge/setup_ip_tables_linux.go#L230-L232 [12]: https://github.com/robmry/moby/blob/52c89d467fc5326149e4bbb8903d23589b66ff0d/libnetwork/drivers/bridge/setup_ip_tables_linux.go#L227-L229 [13]: https://github.com/robmry/moby/blob/52c89d467fc5326149e4bbb8903d23589b66ff0d/libnetwork/drivers/bridge/setup_ip_tables_linux.go#L223-L226 -[14]: https://github.com/moby/moby/blob/333cfa640239153477bf635a8131734d0e9d099d/libnetwork/drivers/bridge/setup_ip_tables_linux.go#L264 [15]: https://github.com/moby/moby/blob/333cfa640239153477bf635a8131734d0e9d099d/libnetwork/drivers/bridge/setup_ip_tables_linux.go#L343 -_With ICC enabled 5 and 6 could be combined, to ACCEPT anything from the bridge. -But, when ICC is disabled, rule 6 is DROP, so it would need to be placed before -rule 5. Because the rules are generated in different places, that's a slightly -bigger change than it should be._ - The DOCKER chain has a single DROP rule for the bridge network, to drop any packets routed to the network that have not originated in the network. Added by [setDefaultForwardRule][21]. diff --git a/integration/network/bridge/iptablesdoc/templates/usernet-internal.md b/integration/network/bridge/iptablesdoc/templates/usernet-internal.md index 12abe60724da0..183cb7ded76f0 100644 --- a/integration/network/bridge/iptablesdoc/templates/usernet-internal.md +++ b/integration/network/bridge/iptablesdoc/templates/usernet-internal.md @@ -1,12 +1,22 @@ -## Container on a user-defined --internal network +## Containers on user-defined --internal networks + +These are the rules for two containers on different `--internal` networks, with and +without inter-container communication. Equivalent to: docker network create \ - -o com.docker.network.bridge.name=bridge1 \ + -o com.docker.network.bridge.name=bridgeICC \ --internal \ --subnet 192.0.2.0/24 --gateway 192.0.2.1 bridge1 - docker run --network bridge1 --name c1 busybox + docker run --network bridgeICC --name c1 busybox + + docker network create \ + -o com.docker.network.bridge.name=bridgeNoICC \ + -o com.docker.network.bridge.enable_icc=true \ + --internal \ + --subnet 198.51.100.0/24 --gateway 198.51.100.1 bridge1 + docker run --network bridgeNoICC --name c1 busybox The filter table is updated as follows: @@ -21,7 +31,7 @@ The filter table is updated as follows: By comparison with the [network with external access][1]: -- In the FORWARD chain, there is no ACCEPT rule for outgoing packets `-i bridge1 -o ! bridge1`. +- In the FORWARD chain, there is no ACCEPT rule for outgoing packets (`-i bridgeINC`). - There are no rules for this network in the DOCKER chain. - In DOCKER-ISOLATION-STAGE-1: - Rule 1 drops any packet routed to the network that does not have a source address in the network's subnet. @@ -29,6 +39,10 @@ By comparison with the [network with external access][1]: - There is no jump to DOCKER-ISOLATION-STAGE-2. - DOCKER-ISOLATION-STAGE-2 is unused. +The only difference between `bridgeICC` and `bridgeNoICC` is the rule in the FORWARD +chain. To enable ICC, the rule for packets looping through the bridge is ACCEPT. For +no-ICC it's DROP. + [1]: usernet-portmap.md And the corresponding nat table: diff --git a/integration/network/bridge/iptablesdoc/templates/usernet-portmap-noicc.md b/integration/network/bridge/iptablesdoc/templates/usernet-portmap-noicc.md index e11db6a295aa9..e47a8107a72d7 100644 --- a/integration/network/bridge/iptablesdoc/templates/usernet-portmap-noicc.md +++ b/integration/network/bridge/iptablesdoc/templates/usernet-portmap-noicc.md @@ -21,11 +21,11 @@ The filter table is: By comparison with [ICC=true][1]: - - Rule 7 in the FORWARD chain replaces an ACCEPT rule that would have followed rule 5, matching the same packets. - - Added in [setIcc][2] + - Rules 6 and 7 replace the accept rule for outgoing packets. + - Rule 6, added by `setIcc`, drops any packet sent from the internal network to itself. + - Rule 7, added by `setupIPTablesInternal` accepts any other outgoing packet. [1]: usernet-portmap.md -[2]: https://github.com/moby/moby/blob/333cfa640239153477bf635a8131734d0e9d099d/libnetwork/drivers/bridge/setup_ip_tables_linux.go#L344 And the corresponding nat table: diff --git a/integration/network/bridge/iptablesdoc/templates/usernet-portmap.md b/integration/network/bridge/iptablesdoc/templates/usernet-portmap.md index a5a0ce347448f..c7e348c527747 100644 --- a/integration/network/bridge/iptablesdoc/templates/usernet-portmap.md +++ b/integration/network/bridge/iptablesdoc/templates/usernet-portmap.md @@ -20,8 +20,8 @@ The filter table is updated as follows: Note that: - - In the FORWARD chain, rules 7-8 for the new network have been appended to - the end of the chain. + - In the FORWARD chain, rule 6 for outgoing traffic from the new network has been + appended to the end of the chain. - In the DOCKER-ISOLATION chains, rules equivalent to the docker0 rules have also been inserted for the new bridge. - In the DOCKER chain, there is an ACCEPT rule for TCP port 80 packets routed diff --git a/libnetwork/drivers/bridge/setup_ip_tables_linux.go b/libnetwork/drivers/bridge/setup_ip_tables_linux.go index fea34bc15ce80..7e2aa3657ae7f 100644 --- a/libnetwork/drivers/bridge/setup_ip_tables_linux.go +++ b/libnetwork/drivers/bridge/setup_ip_tables_linux.go @@ -360,7 +360,6 @@ func setupNonInternalNetworkRules(ipVer iptables.IPVersion, config *networkConfi natArgs = []string{"-s", addr.String(), "!", "-o", config.BridgeName, "-j", "MASQUERADE"} hpNatArgs = []string{"-m", "addrtype", "--src-type", "LOCAL", "-o", config.BridgeName, "-j", "MASQUERADE"} } - natRule := iptRule{ipv: ipVer, table: iptables.Nat, chain: "POSTROUTING", args: natArgs} hpNatRule := iptRule{ipv: ipVer, table: iptables.Nat, chain: "POSTROUTING", args: hpNatArgs} @@ -387,7 +386,7 @@ func setupNonInternalNetworkRules(ipVer iptables.IPVersion, config *networkConfi } // Set Inter Container Communication. - if err := setIcc(ipVer, config.BridgeName, config.EnableICC, enable); err != nil { + if err := setIcc(ipVer, config.BridgeName, config.EnableICC, false, enable); err != nil { return err } @@ -398,13 +397,38 @@ func setupNonInternalNetworkRules(ipVer iptables.IPVersion, config *networkConfi } } - // Set Accept on all non-intercontainer outgoing packets. - outRule := iptRule{ipv: ipVer, table: iptables.Filter, chain: "FORWARD", args: []string{ + // Handle outgoing packets. This rule was previously added unconditionally + // to ACCEPT packets that weren't ICC - an extra rule was needed to enable + // ICC if needed. Those rules are now combined. So, outRuleNoICC is only + // needed for ICC=false, along with the DROP rule for ICC added by setIcc. + outRuleNoICC := iptRule{ipv: ipVer, table: iptables.Filter, chain: "FORWARD", args: []string{ "-i", config.BridgeName, "!", "-o", config.BridgeName, "-j", "ACCEPT", }} - return appendOrDelChainRule(outRule, "ACCEPT NON_ICC OUTGOING", enable) + if config.EnableICC { + // Remove the legacy rule for ICC (which didn't accept outgoing traffic), if one has been + // left behind by an old daemon. + if err := outRuleNoICC.Delete(); err != nil { + return err + } + // Accept outgoing traffic to anywhere, including other containers on this bridge. + outRuleICC := iptRule{ipv: ipVer, table: iptables.Filter, chain: "FORWARD", args: []string{ + "-i", config.BridgeName, + "-j", "ACCEPT", + }} + if err := appendOrDelChainRule(outRuleICC, "ACCEPT OUTGOING", enable); err != nil { + return err + } + } else { + // Accept outgoing traffic to anywhere, apart from other containers on this bridge. + // setIcc added a DROP rule for ICC traffic. + if err := appendOrDelChainRule(outRuleNoICC, "ACCEPT NON_ICC OUTGOING", enable); err != nil { + return err + } + } + + return nil } func programChainRule(rule iptRule, ruleDescr string, insert bool) error { @@ -433,28 +457,33 @@ func appendOrDelChainRule(rule iptRule, ruleDescr string, append bool) error { return nil } -func setIcc(version iptables.IPVersion, bridgeIface string, iccEnable, insert bool) error { +func setIcc(version iptables.IPVersion, bridgeIface string, iccEnable, internal, insert bool) error { args := []string{"-i", bridgeIface, "-o", bridgeIface, "-j"} acceptRule := iptRule{ipv: version, table: iptables.Filter, chain: "FORWARD", args: append(args, "ACCEPT")} dropRule := iptRule{ipv: version, table: iptables.Filter, chain: "FORWARD", args: append(args, "DROP")} - if insert { - if !iccEnable { - acceptRule.Delete() - if err := dropRule.Append(); err != nil { - return fmt.Errorf("Unable to prevent intercontainer communication: %w", err) - } - } else { - dropRule.Delete() - if err := acceptRule.Append(); err != nil { - return fmt.Errorf("Unable to allow intercontainer communication: %w", err) - } + + // The accept rule is no longer required for a bridge with external connectivity, because + // ICC traffic is allowed by the outgoing-packets rule created by setupIptablesInternal. + // The accept rule is still required for a --internal network because it has no outgoing + // rule. If insert and the rule is not required, an ACCEPT rule for an external network + // may have been left behind by an older version of the daemon so, delete it. + if insert && iccEnable && internal { + if err := acceptRule.Append(); err != nil { + return fmt.Errorf("Unable to allow intercontainer communication: %w", err) + } + } else { + if err := acceptRule.Delete(); err != nil { + log.G(context.TODO()).WithError(err).Warn("Failed to delete legacy ICC accept rule") + } + } + + if insert && !iccEnable { + if err := dropRule.Append(); err != nil { + return fmt.Errorf("Unable to prevent intercontainer communication: %w", err) } } else { - // Remove any ICC rule. - if !iccEnable { - dropRule.Delete() - } else { - acceptRule.Delete() + if err := dropRule.Delete(); err != nil { + log.G(context.TODO()).WithError(err).Warn("Failed to delete ICC drop rule") } } return nil @@ -600,7 +629,7 @@ func setupInternalNetworkRules(bridgeIface string, addr *net.IPNet, icc, insert } // Set Inter Container Communication. - return setIcc(version, bridgeIface, icc, insert) + return setIcc(version, bridgeIface, icc, true, insert) } // clearConntrackEntries flushes conntrack entries matching endpoint IP address