{"action":"created","issue":{"url":"https://api.github.com/repos/docker/docker/issues/10781","labels_url":"https://api.github.com/repos/docker/docker/issues/10781/labels{/name}","comments_url":"https://api.github.com/repos/docker/docker/issues/10781/comments","events_url":"https://api.github.com/repos/docker/docker/issues/10781/events","html_url":"https://github.com/docker/docker/issues/10781","id":57655951,"number":10781,"title":"Recent docker binaries do not add PREROUTING rule","user":{"login":"larsks","id":82622,"avatar_url":"https://avatars.githubusercontent.com/u/82622?v=3","gravatar_id":"","url":"https://api.github.com/users/larsks","html_url":"https://github.com/larsks","followers_url":"https://api.github.com/users/larsks/followers","following_url":"https://api.github.com/users/larsks/following{/other_user}","gists_url":"https://api.github.com/users/larsks/gists{/gist_id}","starred_url":"https://api.github.com/users/larsks/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/larsks/subscriptions","organizations_url":"https://api.github.com/users/larsks/orgs","repos_url":"https://api.github.com/users/larsks/repos","events_url":"https://api.github.com/users/larsks/events{/privacy}","received_events_url":"https://api.github.com/users/larsks/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":6,"created_at":"2015-02-13T21:24:05Z","updated_at":"2015-02-14T02:22:54Z","closed_at":null,"body":"With recent docker binaries (e.g., from `ee95aa1`), Docker is not creating a rule in the iptables `PREROUTING` chain.  Running `docker -D` reveals:\r\n\r\n    DEBU[0000] /sbin/iptables, [--wait -C POSTROUTING -t nat -s 172.17.42.1/16 ! -o docker0 -j MASQUERADE] \r\n    DEBU[0000] /sbin/iptables, [--wait -D FORWARD -i docker0 -o docker0 -j DROP] \r\n    DEBU[0000] /sbin/iptables, [--wait -C FORWARD -i docker0 -o docker0 -j ACCEPT] \r\n    DEBU[0000] /sbin/iptables, [--wait -C FORWARD -i docker0 ! -o docker0 -j ACCEPT] \r\n    DEBU[0000] /sbin/iptables, [--wait -C FORWARD -o docker0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT] \r\n    DEBU[0001] /sbin/iptables, [--wait -t nat -D PREROUTING -m addrtype --dst-type LOCAL -j DOCKER] \r\n    DEBU[0001] /sbin/iptables, [--wait -t nat -D OUTPUT -m addrtype --dst-type LOCAL ! --dst 127.0.0.0/8 -j DOCKER] \r\n    DEBU[0001] /sbin/iptables, [--wait -t nat -D OUTPUT -m addrtype --dst-type LOCAL -j DOCKER] \r\n    DEBU[0001] /sbin/iptables, [--wait -t nat -D PREROUTING -j DOCKER] \r\n    DEBU[0001] /sbin/iptables, [--wait -t nat -D OUTPUT -j DOCKER] \r\n    DEBU[0001] /sbin/iptables, [--wait -t nat -F DOCKER]    \r\n    DEBU[0001] /sbin/iptables, [--wait -t nat -X DOCKER]    \r\n    DEBU[0001] /sbin/iptables, [--wait -t nat -n -L DOCKER] \r\n    DEBU[0001] /sbin/iptables, [--wait -t nat -N DOCKER]    \r\n    DEBU[0001] /sbin/iptables, [--wait -C -m addrtype --dst-type LOCAL] \r\n    DEBU[0001] /sbin/iptables, [--wait -C -m addrtype --dst-type LOCAL ! --dst 127.0.0.0/8] \r\n    DEBU[0001] /sbin/iptables, [--wait -t nat -A OUTPUT -m addrtype --dst-type LOCAL ! --dst 127.0.0.0/8 -j DOCKER] \r\n    DEBU[0001] /sbin/iptables, [--wait -t filter -n -L DOCKER] \r\n    DEBU[0001] /sbin/iptables, [--wait -C FORWARD -o docker0 -j DOCKER] \r\n\r\nYou can see it creating an `OUTPUT` rule, but no `PREROUTING` rule.\r\nThis has several repercussions:\r\n\r\n- Inbound traffic is being handled by the Docker proxy, rather than by\r\n  the kernel.  This has performance implications.\r\n\r\n- Without the `DNAT` rule, inbound traffic is hitting the `INPUT`\r\n  chain rather than the `FORWARD` chain, which has security\r\n  implications (e.g., by bypassing forwarding rules meant to control\r\n  access to containerized services)\r\n"},"comment":{"url":"https://api.github.com/repos/docker/docker/issues/comments/74357433","html_url":"https://github.com/docker/docker/issues/10781#issuecomment-74357433","issue_url":"https://api.github.com/repos/docker/docker/issues/10781","id":74357433,"user":{"login":"larsks","id":82622,"avatar_url":"https://avatars.githubusercontent.com/u/82622?v=3","gravatar_id":"","url":"https://api.github.com/users/larsks","html_url":"https://github.com/larsks","followers_url":"https://api.github.com/users/larsks/followers","following_url":"https://api.github.com/users/larsks/following{/other_user}","gists_url":"https://api.github.com/users/larsks/gists{/gist_id}","starred_url":"https://api.github.com/users/larsks/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/larsks/subscriptions","organizations_url":"https://api.github.com/users/larsks/orgs","repos_url":"https://api.github.com/users/larsks/repos","events_url":"https://api.github.com/users/larsks/events{/privacy}","received_events_url":"https://api.github.com/users/larsks/received_events","type":"User","site_admin":false},"created_at":"2015-02-14T02:22:54Z","updated_at":"2015-02-14T02:22:54Z","body":"This isn't a problem debugging iptables.  The problem is with the code in `iptables.go`, which is clearly not doing the right thing.  Take a walk with me...\r\n\r\nIn `NewChain`, we attempt to set up the linking rule to the `DOCKER` chain in the `nat` table with this code:\r\n\r\n\t\tpreroute := []string{\r\n\t\t\t\"-m\", \"addrtype\",\r\n\t\t\t\"--dst-type\", \"LOCAL\"}\r\n\t\tif !Exists(preroute...) {\r\n\t\t\tif err := c.Prerouting(Append, preroute...); err != nil {\r\n\t\t\t\treturn nil, fmt.Errorf(\"Failed to inject docker in PREROUTING chain: %s\", err)\r\n\t\t\t}\r\n\t\t}\r\n\r\nThis call Exists with the contents of `preroute` (which does not\r\ncontain information about a table, or chain, or an action -- it's just\r\na simple match condition).\r\n\r\nExists then does:\r\n\r\n\tif _, err := Raw(append([]string{\"-C\"}, args...)...); err == nil {\r\n\t\treturn true\r\n\t}\r\n\r\nWhich becomes:\r\n\r\n    iptables -C -m addrtype --dst-type LOCAL\r\n\r\nWhich is simply invalid, because it is missing the name of a chain.  This results in:\r\n\r\n    Bad argument `addrtype'\r\n    Try `iptables -h' or 'iptables --help' for more information.\r\n\r\nBut even given the name of a chain, this call is *still* incorrect,\r\nbecause it doesn't have a `-t <table>` argument, so it always checks\r\nthe `filter` table (whereas in this case it ought to be checking the\r\n`nat` table).\r\n\r\nSo anyway, the call to `iptables` and always fails, but we don't catch\r\nthe failure because the code doesn't differentiate between usage\r\nerrors (errcode == 2) and other failures (errcode == 1).  Since\r\n`iptables` fails, the code continues, and we do this:\r\n\r\n\trule := strings.Replace(strings.Join(args, \" \"), \"-t nat \", \"\", -1)\r\n\texistingRules, _ := exec.Command(\"iptables-save\").Output()\r\n  re := regexp.MustCompile(`[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\/[0-9]{1,2}`)\r\n\r\n\treturn strings.Contains(\r\n\t\tre.ReplaceAllString(string(existingRules), \"?\"),\r\n\t\tre.ReplaceAllString(rule, \"?\"),\r\n\t)\r\n\r\nHere, we're grabbing the entire output of `iptables-save`, and then\r\nwe're looking in it for:\r\n\r\n    -m addrtype --dst-type LOCAL\r\n\r\nAnd if that matches *anywhere*, we decide the rule exists.  In this\r\ncase, on my system, there is another rule in another table, unrelated\r\nto Docker, that looks like this:\r\n\r\n    -A another_chain -p tcp -m tcp --dport 8775 -m addrtype --dst-type LOCAL -j ACCEPT\r\n\r\nWhich, coincidentally, matches.  So we never create the corresponding\r\nrule.\r\n\r\nTo summarize:\r\n\r\n1. We're generating an invalid command line for `iptables`.  This will\r\n   simply never work.\r\n1. We're checking for the *match condition* of a rule against *the\r\n   entire iptables configuration*.  This is almost guaranteed to fail.\r\n   If we at least included the action condition (`-j DOCKER`) we would\r\n   be better off, although we *really* need to limit the check to\r\n   *specific* table and a *specific* chain.\r\n\r\n"}}