New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
userland-proxy: false
does not clean-up NAT rule when switching to userland-proxy: true
#44721
Comments
Identified where bug is occurringI have found from diffing
The third
Reproduction details/etc/docker/daemon.json content{
"ipv6": true,
"fixed-cidr-v6": "fd00:1111:2222::/48",
"ip6tables": true,
"experimental" : true,
"userland-proxy": true
} I updated the
|
userland-proxy: false
carries over to userland-proxy: true
userland-proxy: false
does not clean-up NAT rule when switching to userland-proxy: true
Reproduction with workaround fixDemonstrates that this is the cause of the bug observed. Workaround is to manually remove the NAT rule from
Before starting this, change TEST_IP to an IP on an interface, it could be a public IPv4 address too. TEST_IP=http://192.168.1.42 \
&& echo '{ "userland-proxy": false }' > /etc/docker/daemon.json \
&& systemctl restart docker \
&& docker run --rm -d -p 80:80 traefik/whoami \
&& (curl -s "${TEST_IP}" | grep RemoteAddr) \
&& echo '{ "userland-proxy": true }' > /etc/docker/daemon.json \
&& systemctl restart docker \
&& docker run --rm -d -p 80:80 traefik/whoami \
&& (curl -s "${TEST_IP}" | grep RemoteAddr) \
&& iptables -t nat -D POSTROUTING -o docker0 -m addrtype --src-type LOCAL -j MASQUERADE \
&& (curl -s "${TEST_IP}" | grep RemoteAddr)
|
I would say this issue is partially related to #14856:
|
Oh I completely agree that not needing a workaround would be preferred! I just wanted to raise awareness that defaulting to
Agreed 👍 The rules seem to be properly cleaned up when toggling |
When userland-proxy was turned off and on again, the iptables nat rule doing hairpinning wasn't properly removed. This fix makes sure that nat rule is removed whenever the bridge is torn down or hairpinning is disabled (through setting userland-proxy to true). Fixes moby#44721.
When userland-proxy is turned off and on again, the iptables nat rule doing hairpinning isn't properly removed. This fix makes sure this nat rule is removed whenever the bridge is torn down or hairpinning is disabled (through setting userland-proxy to true). Unlike for ip masquerading and ICC, the `programChainRule()` call setting up the "MASQ LOCAL HOST" rule has to be called unconditionally because the hairpin parameter isn't restored from the driver store, but always comes from the driver config. Fixes moby#44721.
When userland-proxy is turned off and on again, the iptables nat rule doing hairpinning isn't properly removed. This fix makes sure this nat rule is removed whenever the bridge is torn down or hairpinning is disabled (through setting userland-proxy to true). Unlike for ip masquerading and ICC, the `programChainRule()` call setting up the "MASQ LOCAL HOST" rule has to be called unconditionally because the hairpin parameter isn't restored from the driver store, but always comes from the driver config. For the "SKIP DNAT" rule, things are a bit different: this rule is always deleted by `removeIPChains()` when the bridge driver is initialized. Fixes moby#44721.
When userland-proxy is turned off and on again, the iptables nat rule doing hairpinning isn't properly removed. This fix makes sure this nat rule is removed whenever the bridge is torn down or hairpinning is disabled (through setting userland-proxy to true). Unlike for ip masquerading and ICC, the `programChainRule()` call setting up the "MASQ LOCAL HOST" rule has to be called unconditionally because the hairpin parameter isn't restored from the driver store, but always comes from the driver config. For the "SKIP DNAT" rule, things are a bit different: this rule is always deleted by `removeIPChains()` when the bridge driver is initialized. Fixes moby#44721. Signed-off-by: Albin Kerouanton <albinker@gmail.com>
When userland-proxy is turned off and on again, the iptables nat rule doing hairpinning isn't properly removed. This fix makes sure this nat rule is removed whenever the bridge is torn down or hairpinning is disabled (through setting userland-proxy to true). Unlike for ip masquerading and ICC, the `programChainRule()` call setting up the "MASQ LOCAL HOST" rule has to be called unconditionally because the hairpin parameter isn't restored from the driver store, but always comes from the driver config. For the "SKIP DNAT" rule, things are a bit different: this rule is always deleted by `removeIPChains()` when the bridge driver is initialized. Fixes moby#44721. Signed-off-by: Albin Kerouanton <albinker@gmail.com>
When userland-proxy is turned off and on again, the iptables nat rule doing hairpinning isn't properly removed. This fix makes sure this nat rule is removed whenever the bridge is torn down or hairpinning is disabled (through setting userland-proxy to true). Unlike for ip masquerading and ICC, the `programChainRule()` call setting up the "MASQ LOCAL HOST" rule has to be called unconditionally because the hairpin parameter isn't restored from the driver store, but always comes from the driver config. For the "SKIP DNAT" rule, things are a bit different: this rule is always deleted by `removeIPChains()` when the bridge driver is initialized. Fixes moby#44721. Signed-off-by: Albin Kerouanton <albinker@gmail.com> (cherry picked from commit 566a2e4) Signed-off-by: Albin Kerouanton <albinker@gmail.com>
Description
Network behaviour from
userland-proxy: false
carries over touserland-proxy: true
.Docker networks (at least with the default bridge, or custom bridges) are not behaving deterministically for
userland-proxy: true
, based on these two configs:userland-proxy: true
(no switch fromuserland-proxy: false
involved).userland-proxy: false
set, and then afterwards switches touserland-proxy: true
.This is a niche bug. It will only be visible when adjusting this configuration without restarting the system. Thus likely only to occur while learning / debugging docker networking with this feature involved (commonly seen with IPv6 config advice / discussions).
I found this confusing to track down, but I am not sure what is going on behind the scenes to cause this.
Reproduction
Steps
Pay attention to the
userland-proxy
state and theoutputs:
value:echo '{ "userland-proxy": true }' > /etc/docker/daemon.json
systemctl restart docker
docker network create test
docker run --rm -d -p 80:80 --network test --name bug traefik/whoami
curl -s http://192.168.1.42 | grep RemoteAddr
(outputs:RemoteAddr: 192.168.1.42
)docker stop bug
echo '{ "userland-proxy": false }' > /etc/docker/daemon.json
systemctl restart docker
docker run --rm -d -p 80:80 --network test --name bug traefik/whoami
curl -s http://192.168.1.42 | grep RemoteAddr
(outputs:RemoteAddr: 172.23.0.1
)echo '{ "userland-proxy": true }' > /etc/docker/daemon.json
systemctl restart docker
docker run --rm -d -p 80:80 --network test --name bug traefik/whoami
curl -s http://192.168.1.42 | grep RemoteAddr
(outputs:RemoteAddr: 172.23.0.1
)Reproduction notes
NOTE: To reproduce:
192.168.1.42
should be substituted for an IP on the hosts local interfaces, I've used the router assigned IP here, but have also reproduced with public IP (v4 and v6 addresses) from a VPS too.172.x.0.1
obviously being the docker network gateway connected to that container (it does not need to be a custom network, the default bridge network also exhibits this bug).userland-proxy: true
is only to showcase that the expected value appears by default. The bug itself is specifically theuserland-proxy: false
touserland-proxy: true
change.dockerd --userland-proxy=true
anddockerd --userland-proxy=false
to toggle instead of thedaemon.json
config, same issue.userland-proxy: true
, then test it it will resolve the correct remote address IP, while the earlier network remains affected from the previoususerland-proxy: false
changes until the system restarts.Copy & paste shell commands:
Expected behavior
userland-proxy: false
touserland-proxy: true
should not cause existing networks to behave differently than those created withuserland-proxy: true
(with no prior switch touserland-proxy: false
involved). Both networks should behave the same way whenuserland-proxy: true
is applied.More info
docker version
docker info
Additional Observations
When
userland-proxy: false
:iptables
/ip6tables
NAT is disabled).userland-proxy: false
also leads tocurl http://[::1]
timing out (curl http://127.0.0.1
would work however), while IPv6 addresses associated to other interfaces than the loopback were at least connecting.When
userland-proxy: true
:curl http://[::1]
would now connect, and it will always return the expected docker network gateway IP matching that protocol (if there was an IPv6 enabled docker network + withip6tables
+experimental
enabled indaemon.json
, otherwise IPv4 gateway IP returned).--network host
would also report loopback IP instead of the gateway IP, but that's not a concern here).userland-proxy: false
in this case (for IPv4, and with relevant IPv6 config, the IPv6 equivalent gateway when appropriate instead of the IPv4 gateway)/etc/docker/daemon.json
used for enabling IPv6 with NAT on default docker bridge (so that containers report back the expected IPv4 / IPv6 address as remote):NOTE: I have verified the bug without any of the IPv6 / experimental config present as well. Still affects IPv4.
The text was updated successfully, but these errors were encountered: