Browse code

Adding test for docker/docker#8795

When a container was being destroyed was possible to have
flows in conntrack left behind on the host.
If a flow is present into the conntrack table, the packet
processing will skip the POSTROUTING table of iptables and
will use the information in conntrack to do the translation.
For this reason is possible that long lived flows created
towards a container that is destroyed, will actually affect
new flows incoming to the host, creating erroneous conditions
where traffic cannot reach new containers.
The fix takes care of cleaning them up when a container is
destroyed.

The test of this commit is actually reproducing the condition
where an UDP flow is established towards a container that is then
destroyed. The test verifies that the flow established is gone
after the container is destroyed.

Signed-off-by: Flavio Crisciani <flavio.crisciani@docker.com>

Flavio Crisciani authored on 2017/04/11 09:12:14
Showing 1 changed files
... ...
@@ -12,6 +12,7 @@ import (
12 12
 	"os"
13 13
 	"path/filepath"
14 14
 	"strings"
15
+	"syscall"
15 16
 	"time"
16 17
 
17 18
 	"github.com/docker/docker/api/types"
... ...
@@ -1789,3 +1790,56 @@ func (s *DockerNetworkSuite) TestDockerNetworkDisconnectFromBridge(c *check.C) {
1789 1789
 	_, _, err := dockerCmdWithError("network", "disconnect", network, name)
1790 1790
 	c.Assert(err, check.IsNil)
1791 1791
 }
1792
+
1793
+// TestConntrackFlowsLeak covers the failure scenario of ticket: https://github.com/docker/docker/issues/8795
1794
+// Validates that conntrack is correctly cleaned once a container is destroyed
1795
+func (s *DockerNetworkSuite) TestConntrackFlowsLeak(c *check.C) {
1796
+	testRequires(c, IsAmd64, DaemonIsLinux, Network)
1797
+
1798
+	// Create a new network
1799
+	dockerCmd(c, "network", "create", "--subnet=192.168.10.0/24", "--gateway=192.168.10.1", "-o", "com.docker.network.bridge.host_binding_ipv4=192.168.10.1", "testbind")
1800
+	assertNwIsAvailable(c, "testbind")
1801
+
1802
+	// Launch the server, this will remain listening on an exposed port and reply to any request in a ping/pong fashion
1803
+	cmd := "while true; do echo hello | nc -w 1 -lu 8080; done"
1804
+	_, _, err := dockerCmdWithError("run", "-d", "--name", "server", "--net", "testbind", "-p", "8080:8080/udp", "appropriate/nc", "sh", "-c", cmd)
1805
+	c.Assert(err, check.IsNil)
1806
+
1807
+	// Launch a container client, here the objective is to create a flow that is natted in order to expose the bug
1808
+	cmd = "echo world | nc -q 1 -u 192.168.10.1 8080"
1809
+	_, _, err = dockerCmdWithError("run", "-d", "--name", "client", "--net=host", "appropriate/nc", "sh", "-c", cmd)
1810
+	c.Assert(err, check.IsNil)
1811
+
1812
+	// Get all the flows using netlink
1813
+	flows, err := netlink.ConntrackTableList(netlink.ConntrackTable, syscall.AF_INET)
1814
+	c.Assert(err, check.IsNil)
1815
+	var flowMatch int
1816
+	for _, flow := range flows {
1817
+		// count only the flows that we are interested in, skipping others that can be laying around the host
1818
+		if flow.Forward.Protocol == syscall.IPPROTO_UDP &&
1819
+			flow.Forward.DstIP.Equal(net.ParseIP("192.168.10.1")) &&
1820
+			flow.Forward.DstPort == 8080 {
1821
+			flowMatch++
1822
+		}
1823
+	}
1824
+	// The client should have created only 1 flow
1825
+	c.Assert(flowMatch, checker.Equals, 1)
1826
+
1827
+	// Now delete the server, this will trigger the conntrack cleanup
1828
+	err = deleteContainer("server")
1829
+	c.Assert(err, checker.IsNil)
1830
+
1831
+	// Fetch again all the flows and validate that there is no server flow in the conntrack laying around
1832
+	flows, err = netlink.ConntrackTableList(netlink.ConntrackTable, syscall.AF_INET)
1833
+	c.Assert(err, check.IsNil)
1834
+	flowMatch = 0
1835
+	for _, flow := range flows {
1836
+		if flow.Forward.Protocol == syscall.IPPROTO_UDP &&
1837
+			flow.Forward.DstIP.Equal(net.ParseIP("192.168.10.1")) &&
1838
+			flow.Forward.DstPort == 8080 {
1839
+			flowMatch++
1840
+		}
1841
+	}
1842
+	// All the flows have to be gone
1843
+	c.Assert(flowMatch, checker.Equals, 0)
1844
+}