Преглед изворни кода

Merge pull request #2635 from AkihiroSuda/ipv6disable

fix port forwarding with ipv6.disable=1
Sebastiaan van Stijn пре 4 година
родитељ
комит
c1437c2f42
2 измењених фајлова са 37 додато и 1 уклоњено
  1. 31 0
      libnetwork/drivers/bridge/port_mapping.go
  2. 6 1
      libnetwork/libnetwork_test.go

+ 31 - 0
libnetwork/drivers/bridge/port_mapping.go

@@ -5,6 +5,7 @@ import (
 	"errors"
 	"fmt"
 	"net"
+	"sync"
 
 	"github.com/docker/libnetwork/types"
 	"github.com/ishidawataru/sctp"
@@ -50,6 +51,13 @@ func (n *bridgeNetwork) allocatePortsInternal(bindings []types.PortBinding, cont
 			bs = append(bs, bIPv4)
 		}
 
+		// skip adding implicit v6 addr, when the kernel was booted with `ipv6.disable=1`
+		// https://github.com/moby/moby/issues/42288
+		isV6Binding := c.HostIP != nil && c.HostIP.To4() == nil
+		if !isV6Binding && !IsV6Listenable() {
+			continue
+		}
+
 		// Allocate IPv6 Port mappings
 		// If the container has no IPv6 address, allow proxying host IPv6 traffic to it
 		// by setting up the binding with the IPv4 interface if the userland proxy is enabled
@@ -211,3 +219,26 @@ func (n *bridgeNetwork) releasePort(bnd types.PortBinding) error {
 
 	return portmapper.Unmap(host)
 }
+
+var (
+	v6ListenableCached bool
+	v6ListenableOnce   sync.Once
+)
+
+// IsV6Listenable returns true when `[::1]:0` is listenable.
+// IsV6Listenable returns false mostly when the kernel was booted with `ipv6.disable=1` option.
+func IsV6Listenable() bool {
+	v6ListenableOnce.Do(func() {
+		ln, err := net.Listen("tcp6", "[::1]:0")
+		if err != nil {
+			// When the kernel was booted with `ipv6.disable=1`,
+			// we get err "listen tcp6 [::1]:0: socket: address family not supported by protocol"
+			// https://github.com/moby/moby/issues/42288
+			logrus.Debugf("port_mapping: v6Listenable=false (%v)", err)
+		} else {
+			v6ListenableCached = true
+			ln.Close()
+		}
+	})
+	return v6ListenableCached
+}

+ 6 - 1
libnetwork/libnetwork_test.go

@@ -16,6 +16,7 @@ import (
 	"github.com/docker/libnetwork/config"
 	"github.com/docker/libnetwork/datastore"
 	"github.com/docker/libnetwork/driverapi"
+	"github.com/docker/libnetwork/drivers/bridge"
 	"github.com/docker/libnetwork/ipamapi"
 	"github.com/docker/libnetwork/netlabel"
 	"github.com/docker/libnetwork/options"
@@ -199,7 +200,11 @@ func TestBridge(t *testing.T) {
 	if !ok {
 		t.Fatalf("Unexpected format for port mapping in endpoint operational data")
 	}
-	if len(pm) != 10 {
+	expectedLen := 10
+	if !bridge.IsV6Listenable() {
+		expectedLen = 5
+	}
+	if len(pm) != expectedLen {
 		t.Fatalf("Incomplete data for port mapping in endpoint operational data: %d", len(pm))
 	}
 }