Skip to content

Commit

Permalink
Add iptables doc for a gateway-mode=routed network
Browse files Browse the repository at this point in the history
Signed-off-by: Rob Murray <[email protected]>
  • Loading branch information
robmry committed Oct 15, 2024
1 parent 19328fd commit 59cf8e8
Show file tree
Hide file tree
Showing 4 changed files with 210 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
## Container on a routed-mode network, with a published port

Running the daemon with the userland proxy disabled 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=routed \
--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 the same as with the userland proxy enabled.

_Note that this means inter-network communication is disabled as-normal so,
although published ports will be directly accessible from a remote host
they are not accessible from containers in neighbouring docker networks
on the same host._

<details>
<summary>Filter table</summary>

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-ISOLATION-STAGE-1 0 -- * * 0.0.0.0/0 0.0.0.0/0
3 0 0 ACCEPT 0 -- * bridge1 0.0.0.0/0 0.0.0.0/0 ctstate RELATED,ESTABLISHED
4 0 0 DOCKER 0 -- * bridge1 0.0.0.0/0 0.0.0.0/0
5 0 0 ACCEPT 0 -- bridge1 !bridge1 0.0.0.0/0 0.0.0.0/0
6 0 0 ACCEPT 0 -- bridge1 bridge1 0.0.0.0/0 0.0.0.0/0
7 0 0 ACCEPT 0 -- * docker0 0.0.0.0/0 0.0.0.0/0 ctstate RELATED,ESTABLISHED
8 0 0 DOCKER 0 -- * docker0 0.0.0.0/0 0.0.0.0/0
9 0 0 ACCEPT 0 -- docker0 !docker0 0.0.0.0/0 0.0.0.0/0
10 0 0 ACCEPT 0 -- docker0 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

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

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

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

Chain DOCKER-USER (1 references)
num pkts bytes target prot opt in out source destination
1 0 0 RETURN 0 -- * * 0.0.0.0/0 0.0.0.0/0


-P INPUT ACCEPT
-P FORWARD ACCEPT
-P OUTPUT ACCEPT
-N DOCKER
-N DOCKER-ISOLATION-STAGE-1
-N DOCKER-ISOLATION-STAGE-2
-N DOCKER-USER
-A FORWARD -j DOCKER-USER
-A FORWARD -j DOCKER-ISOLATION-STAGE-1
-A FORWARD -o bridge1 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -o bridge1 -j DOCKER
-A FORWARD -i bridge1 ! -o bridge1 -j ACCEPT
-A FORWARD -i bridge1 -o bridge1 -j ACCEPT
-A FORWARD -o docker0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -o docker0 -j DOCKER
-A FORWARD -i docker0 ! -o docker0 -j ACCEPT
-A FORWARD -i docker0 -o docker0 -j ACCEPT
-A DOCKER -d 192.0.2.2/32 ! -i bridge1 -o bridge1 -p tcp -m tcp --dport 80 -j ACCEPT
-A DOCKER-ISOLATION-STAGE-1 -i bridge1 ! -o bridge1 -j DOCKER-ISOLATION-STAGE-2
-A DOCKER-ISOLATION-STAGE-1 -i docker0 ! -o docker0 -j DOCKER-ISOLATION-STAGE-2
-A DOCKER-ISOLATION-STAGE-1 -j RETURN
-A DOCKER-ISOLATION-STAGE-2 -o bridge1 -j DROP
-A DOCKER-ISOLATION-STAGE-2 -o docker0 -j DROP
-A DOCKER-ISOLATION-STAGE-2 -j RETURN
-A DOCKER-USER -j RETURN


</details>

The nat table is:

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 -- * !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 RETURN 0 -- docker0 * 0.0.0.0/0 0.0.0.0/0


<details>
<summary>iptables commands</summary>

-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 172.17.0.0/16 ! -o docker0 -j MASQUERADE
-A DOCKER -i docker0 -j RETURN


</details>

Differences from [nat mode][1]:

- In the POSTROUTING chain:
- No MASQUERADE rule for traffic from the bridge network to elsewhere. [setupIPTablesInternal][2]
- No MASQUERADE rule for traffic from the bridge network to itself on published port 80 (port
mapping is skipped). [attemptBindHostPorts][3]
- In the DOCKER chain:
- No early return ("skip DNAT") for traffic from the bridge network. [setupIPTablesInternal][4]
- No DNAT rule for the published port (port mapping is skipped). [attemptBindHostPorts][3]

_And, the userland proxy won't be started for mapped ports._

[1]: usernet-portmap.md
[2]: https://github.com/moby/moby/blob/333cfa640239153477bf635a8131734d0e9d099d/libnetwork/drivers/bridge/setup_ip_tables_linux.go#L294
[3]: https://github.com/moby/moby/blob/675c2ac2db93e38bb9c5a6615d4155a969535fd9/libnetwork/drivers/bridge/port_mapping_linux.go#L477-L479
[4]: https://github.com/moby/moby/blob/333cfa640239153477bf635a8131734d0e9d099d/libnetwork/drivers/bridge/setup_ip_tables_linux.go#L290
1 change: 1 addition & 0 deletions integration/network/bridge/iptablesdoc/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,4 @@ Scenarios:
- [Container on a user-defined network, with a published port, no userland proxy](generated/usernet-portmap-noproxy.md)
- [Container on a user-defined network with inter-container communication disabled, with a published port](generated/usernet-portmap-noicc.md)
- [Container on a user-defined --internal network](generated/usernet-internal.md)
- [Container on a routed-mode network, with a published port](generated/usernet-portmap-routed.md)
13 changes: 13 additions & 0 deletions integration/network/bridge/iptablesdoc/iptablesdoc_linux_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,19 @@ var index = []section{
},
}},
},
{
name: "usernet-portmap-routed.md",
networks: []bridgeNetwork{{
bridge: "bridge1",
gwMode: "routed",
containers: []ctr{
{
name: "c1",
portMappings: nat.PortMap{"80/tcp": {{HostPort: "8080"}}},
},
},
}},
},
}

// iptCmdType is used to look up iptCmds in the markdown (can't use an int
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
## Container on a routed-mode network, with a published port

Running the daemon with the userland proxy disabled 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=routed \
--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 the same as with the userland proxy enabled.

_Note that this means inter-network communication is disabled as-normal so,
although published ports will be directly accessible from a remote host
they are not accessible from containers in neighbouring docker networks
on the same host._

<details>
<summary>Filter table</summary>

{{index . "LFilter4"}}

{{index . "SFilter4"}}

</details>

The nat table is:

{{index . "LNat4"}}

<details>
<summary>iptables commands</summary>

{{index . "SNat4"}}

</details>

Differences from [nat mode][1]:

- In the POSTROUTING chain:
- No MASQUERADE rule for traffic from the bridge network to elsewhere. [setupIPTablesInternal][2]
- No MASQUERADE rule for traffic from the bridge network to itself on published port 80 (port
mapping is skipped). [attemptBindHostPorts][3]
- In the DOCKER chain:
- No early return ("skip DNAT") for traffic from the bridge network. [setupIPTablesInternal][4]
- No DNAT rule for the published port (port mapping is skipped). [attemptBindHostPorts][3]

_And, the userland proxy won't be started for mapped ports._

[1]: usernet-portmap.md
[2]: https://github.com/moby/moby/blob/333cfa640239153477bf635a8131734d0e9d099d/libnetwork/drivers/bridge/setup_ip_tables_linux.go#L294
[3]: https://github.com/moby/moby/blob/675c2ac2db93e38bb9c5a6615d4155a969535fd9/libnetwork/drivers/bridge/port_mapping_linux.go#L477-L479
[4]: https://github.com/moby/moby/blob/333cfa640239153477bf635a8131734d0e9d099d/libnetwork/drivers/bridge/setup_ip_tables_linux.go#L290

0 comments on commit 59cf8e8

Please sign in to comment.