Always allow access to published ports on addresses in gateway mode "routed" networks#50140
Conversation
3c5d730 to
97baaa3
Compare
97baaa3 to
908a742
Compare
566f890 to
6d1c709
Compare
6d1c709 to
6722745
Compare
6722745 to
f6f8444
Compare
| // If the network is IPv4-only, this endpoint is the container's IPv6 gateway, | ||
| // and IPv4 addresses are published to the host - when it's acting as the IPv6 | ||
| // gateway, bindings may be set up to proxy from host IPv6 to endpoint IPv4. | ||
| proxy4To6 := ep.addr != nil && ep.addrv6 == nil && !n.gwMode(firewaller.IPv4).routed() |
There was a problem hiding this comment.
proxy4To6 should be proxy6To4 to follow existing code (e.g. NoProxy6To4).
f6f8444 to
561ac3e
Compare
| // If the network is IPv4-only, this endpoint is the container's IPv6 gateway, | ||
| // and IPv4 addresses are published to the host - when it's acting as the IPv6 | ||
| // gateway, bindings may be set up to proxy from host IPv6 to endpoint IPv4. | ||
| proxy6To4 := ep.addr != nil && ep.addrv6 == nil && !n.gwMode(firewaller.IPv4).routed() | ||
|
|
||
| // Drop IPv4 bindings if this endpoint is not the IPv4 gateway, unless the | ||
| // network is "routed" (routed bindings get dropped unconditionally by Leave). | ||
| drop4 := !pbmReq.ipv4 && !n.gwMode(firewaller.IPv4).routed() | ||
|
|
||
| // Drop IPv6 bindings if this endpoint is not the IPv6 gateway, unless the IPv6 | ||
| // network is "routed" (routed bindings get dropped unconditionally by Leave), | ||
| // or there may be mappings proxying between host IPv6 and container IPv4. | ||
| drop6 := !pbmReq.ipv6 && (!n.gwMode(firewaller.IPv6).routed() || proxy6To4) |
There was a problem hiding this comment.
Based on our Slack discussion, I think you don't need to check proxy6To4 in drop6, because pbmReq.ipv6 is set to true when the current endpoint is the IPv6 gateway, or when the container has no IPv6 gateway at all and the current endpoint is the IPv4 gateway.
moby/daemon/libnetwork/drivers/bridge/bridge_linux.go
Lines 1537 to 1542 in e1281f0
So, you can probably replace drop6 with:
drop6 := !pbmReq.ipv6 && !n.gwMode(firewaller.IPv6).routed()
Also, I think it's quite confusing to say Drop IPv6 bindings if this endpoint is not the IPv6 gateway while pbmReq.ipv6 is set true when there's no IPv6 gateway.
When an endpoint in a gateway mode "nat" network is selected as a container's default gateway, the bridge driver sets up bindings between host and container ports (NAT, userland proxy etc). When gateway mode "routed" was added as an alternative to the default "nat" mode - port bindings followed the same rules. But, unlike "nat" mode, there's no host port binding to set up - there's routing between remote client and the container, so it doesn't matter what the default gateway is. So, in "routed" mode, set up the rules to make a container's published ports accessible when the endpoint is added, and remove those rules when the endpoint is removed (when the container is disconnected from the endpoint's network). Port mappings are only provided by ProgramExternalConnectivity, they can't be set up during the Join. So, include routed bindings in the port bindings mode that's stored as part of endpoint state - and use that to work out whether to add or remove bindings. Signed-off-by: Rob Murray <rob.murray@docker.com>
561ac3e to
30752f0
Compare
| drop4 := !pbmReq.ipv4 && !n.gwMode(firewaller.IPv4).routed() | ||
|
|
||
| // Drop IPv6 bindings if this endpoint is not the IPv6 gateway, and not proxying | ||
| // from host IPv6 to container IPv6 because there is no IPv6 gateway - unless the |
There was a problem hiding this comment.
😅
| // from host IPv6 to container IPv6 because there is no IPv6 gateway - unless the | |
| // from host IPv6 to container IPv4 because there is no IPv6 gateway - unless the |
- What I did
When an endpoint in a gateway mode "nat" network is selected as a container's default gateway, the bridge driver sets up
bindings between host and container ports (NAT, userland proxy etc).
When gateway mode "routed" was added as an alternative to the default "nat" mode - port bindings followed the same rules. But, unlike "nat" mode, there's no host port binding to set up - there's routing between remote client and the container, so it doesn't matter what the default gateway is.
So, in "routed" mode, set up the rules to make a container's published ports accessible when the endpoint is added, and remove those rules when the endpoint is removed (when the container is disconnected from the endpoint's network).
- How I did it
- How to verify it
Existing tests, particularly the ones in
integration/networking/port_mapping_linux_test.go, includingNew integration test that checks ports in routed-mode networks are accessible when a nat-mode network is the gateway.
- Human readable description for the release notes
- Published ports are now always accessible in networks with gateway mode "routed". Previously, rules to open those ports were only added when the routed mode network was selected as the container's default gateway.