diff --git a/integration/networking/bridge_test.go b/integration/networking/bridge_test.go index e3d1fe2a36..8f54234406 100644 --- a/integration/networking/bridge_test.go +++ b/integration/networking/bridge_test.go @@ -477,3 +477,60 @@ func TestDefaultBridgeAddresses(t *testing.T) { }) } } + +// Test that a container on an 'internal' network has IP connectivity with +// the host (on its own subnet, because the n/w bridge has an address on that +// subnet, and it's in the host's namespace). +// Regression test for https://github.com/moby/moby/issues/47329 +func TestInternalNwConnectivity(t *testing.T) { + skip.If(t, testEnv.DaemonInfo.OSType == "windows") + + ctx := setupTest(t) + + d := daemon.New(t) + d.StartWithBusybox(ctx, t, "-D", "--experimental", "--ip6tables") + defer d.Stop(t) + + c := d.NewClientT(t) + defer c.Close() + + const bridgeName = "intnw" + const gw4 = "172.30.0.1" + const gw6 = "fda9:4130:4715::1234" + network.CreateNoError(ctx, t, c, bridgeName, + network.WithInternal(), + network.WithIPv6(), + network.WithIPAM("172.30.0.0/24", gw4), + network.WithIPAM("fda9:4130:4715::/64", gw6), + network.WithDriver("bridge"), + network.WithOption("com.docker.network.bridge.name", bridgeName), + ) + defer network.RemoveNoError(ctx, t, c, bridgeName) + + const ctrName = "intctr" + id := container.Run(ctx, t, c, + container.WithName(ctrName), + container.WithImage("busybox:latest"), + container.WithCmd("top"), + container.WithNetworkMode(bridgeName), + ) + defer c.ContainerRemove(ctx, id, containertypes.RemoveOptions{Force: true}) + + execCtx, cancel := context.WithTimeout(ctx, 20*time.Second) + defer cancel() + + res := container.ExecT(execCtx, t, c, id, []string{"ping", "-c1", "-W3", gw4}) + assert.Check(t, is.Equal(res.ExitCode, 0)) + assert.Check(t, is.Equal(res.Stderr(), "")) + assert.Check(t, is.Contains(res.Stdout(), "1 packets transmitted, 1 packets received")) + + res = container.ExecT(execCtx, t, c, id, []string{"ping6", "-c1", "-W3", gw6}) + assert.Check(t, is.Equal(res.ExitCode, 0)) + assert.Check(t, is.Equal(res.Stderr(), "")) + assert.Check(t, is.Contains(res.Stdout(), "1 packets transmitted, 1 packets received")) + + // Addresses outside the internal subnet must not be accessible. + res = container.ExecT(execCtx, t, c, id, []string{"ping", "-c1", "-W3", "8.8.8.8"}) + assert.Check(t, is.Equal(res.ExitCode, 1)) + assert.Check(t, is.Contains(res.Stderr(), "Network is unreachable")) +} diff --git a/libnetwork/drivers/bridge/setup_ipv4_linux.go b/libnetwork/drivers/bridge/setup_ipv4_linux.go index 0940745c23..6b925190ce 100644 --- a/libnetwork/drivers/bridge/setup_ipv4_linux.go +++ b/libnetwork/drivers/bridge/setup_ipv4_linux.go @@ -32,10 +32,6 @@ func setupBridgeIPv4(config *networkConfiguration, i *bridgeInterface) error { // are decoupled, we should assign it only when it's really needed. i.bridgeIPv4 = config.AddressIPv4 - if config.Internal { - return nil - } - if !config.InhibitIPv4 { addrv4List, err := i.addresses(netlink.FAMILY_V4) if err != nil { @@ -57,8 +53,10 @@ func setupBridgeIPv4(config *networkConfiguration, i *bridgeInterface) error { } } - // Store the default gateway - i.gatewayIPv4 = config.AddressIPv4.IP + if !config.Internal { + // Store the default gateway + i.gatewayIPv4 = config.AddressIPv4.IP + } return nil } diff --git a/libnetwork/drivers/bridge/setup_verify_linux.go b/libnetwork/drivers/bridge/setup_verify_linux.go index a39d750346..b7ddbcf814 100644 --- a/libnetwork/drivers/bridge/setup_verify_linux.go +++ b/libnetwork/drivers/bridge/setup_verify_linux.go @@ -20,12 +20,12 @@ func setupVerifyAndReconcileIPv4(config *networkConfiguration, i *bridgeInterfac addrv4, _ := selectIPv4Address(addrsv4, config.AddressIPv4) // Verify that the bridge has an IPv4 address. - if !config.Internal && addrv4.IPNet == nil { + if addrv4.IPNet == nil { return &ErrNoIPAddr{} } // Verify that the bridge IPv4 address matches the requested configuration. - if config.AddressIPv4 != nil && addrv4.IPNet != nil && !addrv4.IP.Equal(config.AddressIPv4.IP) { + if config.AddressIPv4 != nil && !addrv4.IP.Equal(config.AddressIPv4.IP) { return &IPv4AddrNoMatchError{IP: addrv4.IP, CfgIP: config.AddressIPv4.IP} }