From c91dc7e6dc890529222d9e2ca92860d4ef2a9dd7 Mon Sep 17 00:00:00 2001 From: Rob Murray Date: Mon, 15 Jul 2024 12:28:39 +0100 Subject: [PATCH 1/2] Reject Windows network creation with IPv4 disabled. Signed-off-by: Rob Murray --- integration/network/nat/main_windows_test.go | 56 ++++++++++++++++++++ integration/network/nat/nat_windows_test.go | 24 +++++++++ libnetwork/drivers/windows/windows.go | 6 +++ 3 files changed, 86 insertions(+) create mode 100644 integration/network/nat/main_windows_test.go create mode 100644 integration/network/nat/nat_windows_test.go diff --git a/integration/network/nat/main_windows_test.go b/integration/network/nat/main_windows_test.go new file mode 100644 index 0000000000..d26214081a --- /dev/null +++ b/integration/network/nat/main_windows_test.go @@ -0,0 +1,56 @@ +package nat // import "github.com/docker/docker/integration/network/nat" + +import ( + "context" + "os" + "testing" + + "github.com/docker/docker/testutil" + "github.com/docker/docker/testutil/environment" + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/codes" +) + +var ( + testEnv *environment.Execution + baseContext context.Context +) + +func TestMain(m *testing.M) { + shutdown := testutil.ConfigureTracing() + ctx, span := otel.Tracer("").Start(context.Background(), "integration/network/nat.TestMain") + baseContext = ctx + + var err error + testEnv, err = environment.New(ctx) + if err != nil { + span.SetStatus(codes.Error, err.Error()) + span.End() + shutdown(ctx) + panic(err) + } + + err = environment.EnsureFrozenImagesLinux(ctx, testEnv) + if err != nil { + span.SetStatus(codes.Error, err.Error()) + span.End() + shutdown(ctx) + panic(err) + } + + testEnv.Print() + code := m.Run() + if code != 0 { + span.SetStatus(codes.Error, "m.Run() returned non-zero exit code") + } + span.End() + shutdown(ctx) + os.Exit(code) +} + +func setupTest(t *testing.T) context.Context { + ctx := testutil.StartSpan(baseContext, t) + environment.ProtectAll(ctx, t, testEnv) + t.Cleanup(func() { testEnv.Clean(ctx, t) }) + return ctx +} diff --git a/integration/network/nat/nat_windows_test.go b/integration/network/nat/nat_windows_test.go new file mode 100644 index 0000000000..61e071e60e --- /dev/null +++ b/integration/network/nat/nat_windows_test.go @@ -0,0 +1,24 @@ +package nat // import "github.com/docker/docker/integration/network/nat" + +import ( + "testing" + + "github.com/docker/docker/integration/internal/network" + "gotest.tools/v3/assert" + is "gotest.tools/v3/assert/cmp" +) + +func TestWindowsNoDisableIPv4(t *testing.T) { + ctx := setupTest(t) + c := testEnv.APIClient() + + _, err := network.Create(ctx, c, "ipv6only", + network.WithDriver("nat"), + network.WithIPv4(false), + ) + // This error message should change to "IPv4 cannot be disabled on Windows" + // when "--experimental" is no longer required to disable IPv4. But, there's + // no way to start a second daemon with "--experimental" in Windows CI. + assert.Check(t, is.ErrorContains(err, + "IPv4 can only be disabled if experimental features are enabled")) +} diff --git a/libnetwork/drivers/windows/windows.go b/libnetwork/drivers/windows/windows.go index 495a8b7fbd..2fb76324e2 100644 --- a/libnetwork/drivers/windows/windows.go +++ b/libnetwork/drivers/windows/windows.go @@ -285,6 +285,12 @@ func (d *driver) CreateNetwork(id string, option map[string]interface{}, nInfo d return fmt.Errorf("Unknown generic data option") } + if v, ok := option[netlabel.EnableIPv4]; ok { + if enable_IPv4, ok := v.(bool); ok && !enable_IPv4 { + return types.InvalidParameterErrorf("IPv4 cannot be disabled on Windows") + } + } + // Parse and validate the config. It should not conflict with existing networks' config config, err := d.parseNetworkOptions(id, genData) if err != nil { From 034a5a8986092964edeea7ba81001fc389e4ed51 Mon Sep 17 00:00:00 2001 From: Rob Murray Date: Mon, 15 Jul 2024 12:25:05 +0100 Subject: [PATCH 2/2] Reject swarm n/w creation with IPv4 disabled. Signed-off-by: Rob Murray --- integration/service/network_test.go | 19 +++++++++++++++++++ libnetwork/controller.go | 3 +++ 2 files changed, 22 insertions(+) diff --git a/integration/service/network_test.go b/integration/service/network_test.go index ba4a18a68c..a8dd2e955c 100644 --- a/integration/service/network_test.go +++ b/integration/service/network_test.go @@ -9,6 +9,7 @@ import ( "github.com/docker/docker/integration/internal/container" net "github.com/docker/docker/integration/internal/network" "github.com/docker/docker/integration/internal/swarm" + "github.com/docker/docker/testutil/daemon" "gotest.tools/v3/assert" is "gotest.tools/v3/assert/cmp" "gotest.tools/v3/skip" @@ -115,3 +116,21 @@ func TestDockerNetworkReConnect(t *testing.T) { assert.NilError(t, err) assert.Check(t, is.DeepEqual(n1, n2)) } + +// Check that a swarm-scoped network can't have EnableIPv4=false. +func TestSwarmNoDisableIPv4(t *testing.T) { + skip.If(t, testEnv.DaemonInfo.OSType == "windows") + ctx := setupTest(t) + + d := swarm.NewSwarm(ctx, t, testEnv, daemon.WithExperimental()) + defer d.Stop(t) + client := d.NewClientT(t) + defer client.Close() + + _, err := net.Create(ctx, client, "overlay-v6-only", + net.WithDriver("overlay"), + net.WithAttachable(), + net.WithIPv4(false), + ) + assert.Check(t, is.ErrorContains(err, "IPv4 cannot be disabled in a Swarm scoped network")) +} diff --git a/libnetwork/controller.go b/libnetwork/controller.go index 1e3d211248..0a8fe2e062 100644 --- a/libnetwork/controller.go +++ b/libnetwork/controller.go @@ -550,6 +550,9 @@ func (c *Controller) NewNetwork(networkType, name string, id string, options ... if (caps.DataScope == scope.Global || nw.scope == scope.Swarm) && c.isSwarmNode() && !nw.dynamic { if c.isManager() { + if !nw.enableIPv4 { + return nil, types.InvalidParameterErrorf("IPv4 cannot be disabled in a Swarm scoped network") + } // For non-distributed controlled environment, globalscoped non-dynamic networks are redirected to Manager return nil, ManagerRedirectError(name) }