Skip to content

Commit 7b9c290

Browse files
committed
fix port forwarding with ipv6.disable=1
Make `docker run -p 80:80` functional again on environments with kernel boot parameter `ipv6.disable=1`. Fix moby/moby issue 42288 Signed-off-by: Akihiro Suda <akihiro.suda.cz@hco.ntt.co.jp>
1 parent b350742 commit 7b9c290

2 files changed

Lines changed: 37 additions & 1 deletion

File tree

drivers/bridge/port_mapping.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"errors"
66
"fmt"
77
"net"
8+
"sync"
89

910
"github.com/docker/libnetwork/types"
1011
"github.com/ishidawataru/sctp"
@@ -50,6 +51,13 @@ func (n *bridgeNetwork) allocatePortsInternal(bindings []types.PortBinding, cont
5051
bs = append(bs, bIPv4)
5152
}
5253

54+
// skip adding implicit v6 addr, when the kernel was booted with `ipv6.disable=1`
55+
// https://github.com/moby/moby/issues/42288
56+
isV6Binding := c.HostIP != nil && c.HostIP.To4() == nil
57+
if !isV6Binding && !IsV6Listenable() {
58+
continue
59+
}
60+
5361
// Allocate IPv6 Port mappings
5462
// If the container has no IPv6 address, allow proxying host IPv6 traffic to it
5563
// 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 {
211219

212220
return portmapper.Unmap(host)
213221
}
222+
223+
var (
224+
v6ListenableCached bool
225+
v6ListenableOnce sync.Once
226+
)
227+
228+
// IsV6Listenable returns true when `[::1]:0` is listenable.
229+
// IsV6Listenable returns false mostly when the kernel was booted with `ipv6.disable=1` option.
230+
func IsV6Listenable() bool {
231+
v6ListenableOnce.Do(func() {
232+
ln, err := net.Listen("tcp6", "[::1]:0")
233+
if err != nil {
234+
// When the kernel was booted with `ipv6.disable=1`,
235+
// we get err "listen tcp6 [::1]:0: socket: address family not supported by protocol"
236+
// https://github.com/moby/moby/issues/42288
237+
logrus.Debugf("port_mapping: v6Listenable=false (%v)", err)
238+
} else {
239+
v6ListenableCached = true
240+
ln.Close()
241+
}
242+
})
243+
return v6ListenableCached
244+
}

libnetwork_test.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import (
1616
"github.com/docker/libnetwork/config"
1717
"github.com/docker/libnetwork/datastore"
1818
"github.com/docker/libnetwork/driverapi"
19+
"github.com/docker/libnetwork/drivers/bridge"
1920
"github.com/docker/libnetwork/ipamapi"
2021
"github.com/docker/libnetwork/netlabel"
2122
"github.com/docker/libnetwork/options"
@@ -199,7 +200,11 @@ func TestBridge(t *testing.T) {
199200
if !ok {
200201
t.Fatalf("Unexpected format for port mapping in endpoint operational data")
201202
}
202-
if len(pm) != 10 {
203+
expectedLen := 10
204+
if !bridge.IsV6Listenable() {
205+
expectedLen = 5
206+
}
207+
if len(pm) != expectedLen {
203208
t.Fatalf("Incomplete data for port mapping in endpoint operational data: %d", len(pm))
204209
}
205210
}

0 commit comments

Comments
 (0)