From c761353e7c75e4ffa90b80f3b5df40473d59620a Mon Sep 17 00:00:00 2001 From: Rob Murray Date: Wed, 7 Feb 2024 18:53:27 +0000 Subject: [PATCH] Make 'internal' bridge networks accessible from host Prior to release 25.0.0, the bridge in an internal network was assigned an IP address - making the internal network accessible from the host, giving containers on the network access to anything listening on the bridge's address (or INADDR_ANY on the host). This change restores that behaviour. It does not restore the default route that was configured in the container, because packets sent outside the internal network's subnet have always been dropped. So, a 'connect()' to an address outside the subnet will still fail fast. Signed-off-by: Rob Murray (cherry picked from commit 419f5a637230570ec44c32f889f981f67ce15793) Signed-off-by: Albin Kerouanton --- integration/networking/bridge_test.go | 57 +++++++++++++++++++ libnetwork/drivers/bridge/setup_ipv4_linux.go | 10 ++-- .../drivers/bridge/setup_verify_linux.go | 4 +- 3 files changed, 63 insertions(+), 8 deletions(-) diff --git a/integration/networking/bridge_test.go b/integration/networking/bridge_test.go index e3d1fe2a361cc..8f542344067b1 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 0940745c23b4c..6b925190ce1b8 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 a39d7503460c5..b7ddbcf8143ad 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} }