Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -542,6 +542,7 @@ RUN --mount=type=cache,sharing=locked,id=moby-dev-aptlib,target=/var/lib/apt \
libprotobuf-c1 \
libyajl2 \
net-tools \
netcat-openbsd \
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this only for our tests, or is this a new dependency we should have installed (and to be added as "requires" in our packages?)

I can't find a direct reference to this in this PR; was it accidentally left behind (for local debugging?)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

patch \
pigz \
sudo \
Expand Down
7 changes: 7 additions & 0 deletions daemon/info_unix.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"os"
"os/exec"
"path/filepath"
"strconv"
"strings"

runcoptions "github.com/containerd/containerd/api/types/runc/options"
Expand Down Expand Up @@ -159,6 +160,12 @@ func (daemon *Daemon) fillPlatformInfo(ctx context.Context, v *system.Info, sysI
if !v.IPv4Forwarding {
v.Warnings = append(v.Warnings, "WARNING: IPv4 forwarding is disabled")
}
if filtering, _ := strconv.ParseBool(os.Getenv("DOCKER_DISABLE_INPUT_IFACE_FILTERING")); filtering {
v.Warnings = append(v.Warnings,
"WARNING: input interface filtering is disabled on port mappings, this might be insecure",
"DEPRECATED: DOCKER_DISABLE_INPUT_IFACE_FILTERING is deprecated and will be removed in a future release",
)
}
return nil
}

Expand Down
8 changes: 8 additions & 0 deletions integration/internal/network/ops.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,14 @@ func WithIPv6() func(*network.CreateOptions) {
}
}

// WithIPv6Disabled makes sure IPv6 is disabled on the network.
func WithIPv6Disabled() func(*network.CreateOptions) {
return func(n *network.CreateOptions) {
enable := false
n.EnableIPv6 = &enable
}
}

// WithInternal enables Internal flag on the create network request
func WithInternal() func(*network.CreateOptions) {
return func(n *network.CreateOptions) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
## Container on a user-defined network, with a port published on a specific HostIP

Adding a network running a container with a mapped port, equivalent to:

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

The filter and nat tables are the same as with no HostIP specified.

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

Chain DOCKER (1 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
2 0 0 DROP 0 -- !docker0 docker0 0.0.0.0/0 0.0.0.0/0
3 0 0 DROP 0 -- !bridge1 bridge1 0.0.0.0/0 0.0.0.0/0

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 -- docker0 !docker0 0.0.0.0/0 0.0.0.0/0
2 0 0 DOCKER-ISOLATION-STAGE-2 0 -- bridge1 !bridge1 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

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 -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 -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
-A DOCKER-ISOLATION-STAGE-1 -i docker0 ! -o docker0 -j DOCKER-ISOLATION-STAGE-2
-A DOCKER-ISOLATION-STAGE-1 -i bridge1 ! -o bridge1 -j DOCKER-ISOLATION-STAGE-2
-A DOCKER-ISOLATION-STAGE-2 -o bridge1 -j DROP
-A DOCKER-ISOLATION-STAGE-2 -o docker0 -j DROP
-A DOCKER-USER -j RETURN


</details>

<details>
<summary>NAT table</summary>

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 RETURN 0 -- bridge1 * 0.0.0.0/0 0.0.0.0/0
2 0 0 RETURN 0 -- docker0 * 0.0.0.0/0 0.0.0.0/0
3 0 0 DNAT 6 -- !bridge1 * 0.0.0.0/0 127.0.0.1 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 -j RETURN
-A DOCKER -i docker0 -j RETURN
-A DOCKER -d 127.0.0.1/32 ! -i bridge1 -p tcp -m tcp --dport 8080 -j DNAT --to-destination 192.0.2.2:80


</details>

The raw table is:

Chain PREROUTING (policy ACCEPT 0 packets, 0 bytes)
num pkts bytes target prot opt in out source destination
1 0 0 ACCEPT 6 -- * * 0.0.0.0/0 127.0.0.1 tcp dpt:8080 ADDRTYPE match dst-type LOCAL limit-in
2 0 0 DROP 6 -- * * 0.0.0.0/0 127.0.0.1 tcp dpt:8080

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


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

-P PREROUTING ACCEPT
-P OUTPUT ACCEPT
-A PREROUTING -d 127.0.0.1/32 -p tcp -m tcp --dport 8080 -m addrtype --dst-type LOCAL --limit-iface-in -j ACCEPT
-A PREROUTING -d 127.0.0.1/32 -p tcp -m tcp --dport 8080 -j DROP


</details>

The difference from [port mapping with no HostIP][0] is:

- An ACCEPT rule is added to the PREROUTING chain to drop packets targeting the
mapped port and coming from the interface that has the HostIP assigned.
- And a DROP rule is added too, to drop packets targeting the mapped port but
didn't pass the previous check.

[0]: usernet-portmap.md
1 change: 1 addition & 0 deletions integration/network/bridge/iptablesdoc/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,4 @@ Scenarios:
- [Container on a routed-mode network, with a published port](generated/usernet-portmap-routed.md)
- [Container on a nat-unprotected network, with a published port](generated/usernet-portmap-natunprot.md)
- [Swarm service, with a published port](generated/swarm-portmap.md)
- [Container on a user-defined network, with a port published on a specific HostIP](generated/usernet-portmap-hostip.md)
16 changes: 16 additions & 0 deletions integration/network/bridge/iptablesdoc/iptablesdoc_linux_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,18 @@ var index = []section{
},
}},
},
{
name: "usernet-portmap-hostip.md",
networks: []networkDesc{{
name: "bridge1",
containers: []ctrDesc{
{
name: "c1",
portMappings: nat.PortMap{"80/tcp": {{HostIP: "127.0.0.1", HostPort: "8080"}}},
},
},
}},
},
}

// iptCmdType is used to look up iptCmds in the markdown (can't use an int
Expand All @@ -188,6 +200,8 @@ const (
iptCmdSFilterDocker4 iptCmdType = "SFilterDocker4"
iptCmdLNat4 iptCmdType = "LNat4"
iptCmdSNat4 iptCmdType = "SNat4"
iptCmdLRaw4 iptCmdType = "LRaw4"
iptCmdSRaw4 iptCmdType = "SRaw4"
)

var iptCmds = map[iptCmdType][]string{
Expand All @@ -198,6 +212,8 @@ var iptCmds = map[iptCmdType][]string{
iptCmdSFilterDocker4: {"iptables", "-S", "DOCKER"},
iptCmdLNat4: {"iptables", "-nvL", "--line-numbers", "-t", "nat"},
iptCmdSNat4: {"iptables", "-S", "-t", "nat"},
iptCmdLRaw4: {"iptables", "-nvL", "--line-numbers", "-t", "raw"},
iptCmdSRaw4: {"iptables", "-S", "-t", "raw"},
}

func TestBridgeIptablesDoc(t *testing.T) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
## Container on a user-defined network, with a port published on a specific HostIP

Adding a network running a container with a mapped port, equivalent to:

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

The filter and nat tables are the same as with no HostIP specified.

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

{{index . "LFilter4"}}

{{index . "SFilter4"}}

</details>

<details>
<summary>NAT table</summary>

{{index . "LNat4"}}

{{index . "SNat4"}}

</details>

The raw table is:

{{index . "LRaw4"}}

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

{{index . "SRaw4"}}

</details>

The difference from [port mapping with no HostIP][0] is:

- An ACCEPT rule is added to the PREROUTING chain to drop packets targeting the
mapped port and coming from the interface that has the HostIP assigned.
- And a DROP rule is added too, to drop packets targeting the mapped port but
didn't pass the previous check.

[0]: usernet-portmap.md
Loading