diff --git a/hack/vendor.sh b/hack/vendor.sh index 9c670b2875..d9a010a139 100755 --- a/hack/vendor.sh +++ b/hack/vendor.sh @@ -17,7 +17,7 @@ clone hg code.google.com/p/go.net 84a4013f96e0 clone hg code.google.com/p/gosqlite 74691fb6f837 #get libnetwork packages -clone git github.com/docker/libnetwork 90638ec9cf7fa7b7f5d0e96b0854f136d66bff92 +clone git github.com/docker/libnetwork e578e95aa101441481411ff1d620f343895f24fe clone git github.com/vishvananda/netns 5478c060110032f972e86a1f844fdb9a2f008f2c clone git github.com/vishvananda/netlink 8eb64238879fed52fd51c5b30ad20b928fb4c36c diff --git a/integration-cli/docker_cli_nat_test.go b/integration-cli/docker_cli_nat_test.go index c013250a1f..582b41dc54 100644 --- a/integration-cli/docker_cli_nat_test.go +++ b/integration-cli/docker_cli_nat_test.go @@ -98,3 +98,20 @@ func (s *DockerSuite) TestNetworkLocalhostTCPNat(c *check.C) { c.Fatalf("Expected message %q but received %q", msg, final) } } + +func (s *DockerSuite) TestNetworkLoopbackNat(c *check.C) { + testRequires(c, SameHostDaemon, NativeExecDriver) + msg := "it works" + startServerContainer(c, msg, 8080) + endpoint := getExternalAddress(c) + runCmd := exec.Command(dockerBinary, "run", "-t", "--net=container:server", "busybox", + "sh", "-c", fmt.Sprintf("stty raw && nc -w 5 %s 8080", endpoint.String())) + out, _, err := runCommandWithOutput(runCmd) + if err != nil { + c.Fatal(out, err) + } + final := strings.TrimRight(string(out), "\n") + if final != msg { + c.Fatalf("Expected message %q but received %q", msg, final) + } +} diff --git a/vendor/src/github.com/docker/libnetwork/drivers/bridge/bridge.go b/vendor/src/github.com/docker/libnetwork/drivers/bridge/bridge.go index 8896bd8483..ccdf204031 100644 --- a/vendor/src/github.com/docker/libnetwork/drivers/bridge/bridge.go +++ b/vendor/src/github.com/docker/libnetwork/drivers/bridge/bridge.go @@ -516,6 +516,13 @@ func (d *driver) CreateEndpoint(nid, eid types.UUID, epInfo driverapi.EndpointIn return err } + if !config.EnableUserlandProxy { + err = netlink.LinkSetHairpin(host, true) + if err != nil { + return err + } + } + // v4 address for the sandbox side pipe interface ip4, err := ipAllocator.RequestIP(n.bridge.bridgeIPv4, nil) if err != nil { diff --git a/vendor/src/github.com/docker/libnetwork/iptables/iptables.go b/vendor/src/github.com/docker/libnetwork/iptables/iptables.go index 4299a7e2b6..481013afab 100644 --- a/vendor/src/github.com/docker/libnetwork/iptables/iptables.go +++ b/vendor/src/github.com/docker/libnetwork/iptables/iptables.go @@ -44,9 +44,10 @@ var ( // Chain defines the iptables chain. type Chain struct { - Name string - Bridge string - Table Table + Name string + Bridge string + Table Table + HairpinMode bool } // ChainError is returned to represent errors during ip table operation. @@ -75,9 +76,10 @@ func initCheck() error { // NewChain adds a new chain to ip table. func NewChain(name, bridge string, table Table, hairpinMode bool) (*Chain, error) { c := &Chain{ - Name: name, - Bridge: bridge, - Table: table, + Name: name, + Bridge: bridge, + Table: table, + HairpinMode: hairpinMode, } if string(c.Table) == "" { @@ -151,12 +153,16 @@ func (c *Chain) Forward(action Action, ip net.IP, port int, proto, destAddr stri // value" by both iptables and ip6tables. daddr = "0/0" } - if output, err := Raw("-t", string(Nat), string(action), c.Name, + args := []string{"-t", string(Nat), string(action), c.Name, "-p", proto, "-d", daddr, "--dport", strconv.Itoa(port), "-j", "DNAT", - "--to-destination", net.JoinHostPort(destAddr, strconv.Itoa(destPort))); err != nil { + "--to-destination", net.JoinHostPort(destAddr, strconv.Itoa(destPort))} + if !c.HairpinMode { + args = append(args, "!", "-i", c.Bridge) + } + if output, err := Raw(args...); err != nil { return err } else if len(output) != 0 { return ChainError{Chain: "FORWARD", Output: output}