When Docker Compose is used to deploy container(s) bound to localhost, the guest agent binds the port to the loopback address on the host. However, the service remains inaccessible due to TCP (RST) resets. This issue affects both container engines. Below are the specific details for each container engine:
Moby:
When a container is created using Docker Compose, the API propagates a map of network names to network settings. This PR checks for the container.NetworkSettings.Networks property to handle network configuration correctly.
Additionally, Docker Compose, by default, creates the following rules in the DOCKER chain:
The second rule can be problematic because it uses a wildcard IPv6 address (::), which can match any incoming TCP traffic
destined for port 80. If no service is listening on IPv6, this can result in a TCP RST (reset) response sent back to the client.
To prevent this issue, we delete the wildcard IPv6 rule before adding our custom rule:
Note: Even if the enable_ipv6 property is set to false in Docker's Compose configuration, Docker still creates the
wildcard IPv6 rule in iptables. Therefore, we must manually remove it to avoid this issue.
Containerd:
Previously, the network name was extracted from the following path (/etc/cni/net.d/) of the CNI plugin, and the code was always looking at nerdctl-bridge.conflist, regardless of the actual container network configuration. This approach didn't work in scenarios where the CNI plugin creates additional entries under /etc/cni/net.d/, such as with Docker Compose deployments.
To resolve this, the new approach retrieves the network name from the container's labels instead of relying on the net.d path. This change ensures compatibility with setups like the following Docker Compose configuration:
The new approach ensures that when a service binds to localhost, an additional iptables rule is added in the corresponding CNI chain to allow traffic to the destination IP (anywhere) instead of restricting it to localhost only.
When Docker Compose is used to deploy container(s) bound to localhost, the guest agent binds the port to the loopback address on the host. However, the service remains inaccessible due to TCP (RST) resets. This issue affects both container engines. Below are the specific details for each container engine:
Moby: When a container is created using Docker Compose, the API propagates a map of network names to network settings. This PR checks for the
container.NetworkSettings.Networks
property to handle network configuration correctly.Additionally, Docker Compose, by default, creates the following rules in the DOCKER chain:
The second rule can be problematic because it uses a wildcard IPv6 address (::), which can match any incoming TCP traffic destined for port 80. If no service is listening on IPv6, this can result in a TCP RST (reset) response sent back to the client.
To prevent this issue, we delete the wildcard IPv6 rule before adding our custom rule:
Note: Even if the
enable_ipv6
property is set tofalse
in Docker's Compose configuration, Docker still creates the wildcard IPv6 rule in iptables. Therefore, we must manually remove it to avoid this issue.Containerd:
Previously, the network name was extracted from the following path (
/etc/cni/net.d/
) of the CNI plugin, and the code was always looking atnerdctl-bridge.conflist
, regardless of the actual container network configuration. This approach didn't work in scenarios where the CNI plugin creates additional entries under/etc/cni/net.d/
, such as with Docker Compose deployments.To resolve this, the new approach retrieves the network name from the container's labels instead of relying on the
net.d
path. This change ensures compatibility with setups like the following Docker Compose configuration:With this setup, the following iptables rules are created for each service in their corresponding CNI chain:
For nginx service (ports bound to 127.0.0.1:99:80):
For nginx2 service (ports bound to 101:80):
The new approach ensures that when a service binds to localhost, an additional iptables rule is added in the corresponding CNI chain to allow traffic to the destination IP (anywhere) instead of restricting it to localhost only.
Fixes: https://github.com/rancher-sandbox/rancher-desktop/issues/7720 and a user comment here: https://github.com/rancher-sandbox/rancher-desktop/issues/6515#issuecomment-2225114007