From ef5295cda40d3d2babb5ce85ffcf67371c3ecb47 Mon Sep 17 00:00:00 2001 From: Rob Murray Date: Wed, 6 Mar 2024 16:31:30 +0000 Subject: [PATCH] Don't configure IPv6 addr/gw when IPv6 disabled. When IPv6 is disabled in a container by, for example, using the --sysctl option - an IPv6 address/gateway is still allocated. Don't attempt to apply that config because doing so enables IPv6 on the interface. Signed-off-by: Rob Murray --- integration/networking/bridge_test.go | 67 +++++++++++++++++++++++++++ libnetwork/sandbox_linux.go | 15 ++++-- 2 files changed, 79 insertions(+), 3 deletions(-) diff --git a/integration/networking/bridge_test.go b/integration/networking/bridge_test.go index 6007449cd6..03001ed11a 100644 --- a/integration/networking/bridge_test.go +++ b/integration/networking/bridge_test.go @@ -3,6 +3,7 @@ package networking import ( "context" "fmt" + "regexp" "testing" "time" @@ -12,6 +13,7 @@ import ( "github.com/docker/docker/integration/internal/network" "github.com/docker/docker/testutil" "github.com/docker/docker/testutil/daemon" + "github.com/google/go-cmp/cmp/cmpopts" "gotest.tools/v3/assert" is "gotest.tools/v3/assert/cmp" "gotest.tools/v3/skip" @@ -594,3 +596,68 @@ func TestInternalNwConnectivity(t *testing.T) { assert.Check(t, is.Equal(res.ExitCode, 1)) assert.Check(t, is.Contains(res.Stderr(), "Network is unreachable")) } + +// Check that the container's interface has no IPv6 address when IPv6 is +// disabled in a container via sysctl. +func TestDisableIPv6Addrs(t *testing.T) { + skip.If(t, testEnv.DaemonInfo.OSType == "windows") + + ctx := setupTest(t) + d := daemon.New(t) + d.StartWithBusybox(ctx, t) + defer d.Stop(t) + + c := d.NewClientT(t) + defer c.Close() + + testcases := []struct { + name string + sysctls map[string]string + expIPv6 bool + }{ + { + name: "IPv6 enabled", + expIPv6: true, + }, + { + name: "IPv6 disabled", + sysctls: map[string]string{"net.ipv6.conf.all.disable_ipv6": "1"}, + }, + } + + const netName = "testnet" + network.CreateNoError(ctx, t, c, netName, + network.WithIPv6(), + network.WithIPAM("fda0:ef3d:6430:abcd::/64", "fda0:ef3d:6430:abcd::1"), + ) + defer network.RemoveNoError(ctx, t, c, netName) + + inet6RE := regexp.MustCompile(`inet6[ \t]+[0-9a-f:]*`) + + for _, tc := range testcases { + t.Run(tc.name, func(t *testing.T) { + ctx := testutil.StartSpan(ctx, t) + + opts := []func(config *container.TestContainerConfig){ + container.WithCmd("ip", "a"), + container.WithNetworkMode(netName), + } + if len(tc.sysctls) > 0 { + opts = append(opts, container.WithSysctls(tc.sysctls)) + } + + runRes := container.RunAttach(ctx, t, c, opts...) + defer c.ContainerRemove(ctx, runRes.ContainerID, + containertypes.RemoveOptions{Force: true}, + ) + + stdout := runRes.Stdout.String() + inet6 := inet6RE.FindAllString(stdout, -1) + if tc.expIPv6 { + assert.Check(t, len(inet6) > 0, "Expected IPv6 addresses but found none.") + } else { + assert.Check(t, is.DeepEqual(inet6, []string{}, cmpopts.EquateEmpty())) + } + }) + } +} diff --git a/libnetwork/sandbox_linux.go b/libnetwork/sandbox_linux.go index 21c43f755d..9f3c057bab 100644 --- a/libnetwork/sandbox_linux.go +++ b/libnetwork/sandbox_linux.go @@ -90,8 +90,12 @@ func (sb *Sandbox) updateGateway(ep *Endpoint) error { return fmt.Errorf("failed to set gateway while updating gateway: %v", err) } - if err := osSbox.SetGatewayIPv6(joinInfo.gw6); err != nil { - return fmt.Errorf("failed to set IPv6 gateway while updating gateway: %v", err) + // If IPv6 has been disabled in the sandbox a gateway may still have been + // configured, don't attempt to apply it. + if ipv6, ok := sb.ipv6Enabled(); !ok || ipv6 { + if err := osSbox.SetGatewayIPv6(joinInfo.gw6); err != nil { + return fmt.Errorf("failed to set IPv6 gateway while updating gateway: %v", err) + } } return nil @@ -279,7 +283,12 @@ func (sb *Sandbox) populateNetworkResources(ep *Endpoint) error { ifaceOptions = append(ifaceOptions, osl.WithIPv4Address(i.addr), osl.WithRoutes(i.routes)) if i.addrv6 != nil && i.addrv6.IP.To16() != nil { - ifaceOptions = append(ifaceOptions, osl.WithIPv6Address(i.addrv6)) + // If IPv6 has been disabled in the Sandbox, an IPv6 address will still have + // been allocated. Don't apply it, because doing so would enable IPv6 on the + // interface. + if ipv6, ok := sb.ipv6Enabled(); !ok || ipv6 { + ifaceOptions = append(ifaceOptions, osl.WithIPv6Address(i.addrv6)) + } } if len(i.llAddrs) != 0 { ifaceOptions = append(ifaceOptions, osl.WithLinkLocalAddresses(i.llAddrs))