From 06c9c72269ef57d5664ac609c03b8846a518b2ba Mon Sep 17 00:00:00 2001 From: Rob Murray Date: Fri, 13 Sep 2024 19:55:56 +0100 Subject: [PATCH 01/12] Update dlv in the dev-env Signed-off-by: Rob Murray (cherry picked from commit 8b0e94ffaf7ea7d42391a3961e795b33976256c9) Signed-off-by: Austin Vazquez --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 622f4b4443cee..d72159ee1eee9 100644 --- a/Dockerfile +++ b/Dockerfile @@ -147,7 +147,7 @@ RUN git init . && git remote add origin "https://github.com/go-delve/delve.git" # from the https://github.com/go-delve/delve repository. # It can be used to run Docker with a possibility of # attaching debugger to it. -ARG DELVE_VERSION=v1.21.1 +ARG DELVE_VERSION=v1.23.0 RUN git fetch -q --depth 1 origin "${DELVE_VERSION}" +refs/tags/*:refs/tags/* && git checkout -q FETCH_HEAD FROM base AS delve-supported From 176e04d73b4f3f0a460159e6606c033bdac58830 Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Mon, 16 Sep 2024 09:57:39 +0200 Subject: [PATCH 02/12] man: fix duplicate word in --feature flag description Signed-off-by: Sebastiaan van Stijn (cherry picked from commit 2b6550bb2e4d462d8afa687b59766bb13783ef1f) Signed-off-by: Sebastiaan van Stijn --- man/dockerd.8.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/man/dockerd.8.md b/man/dockerd.8.md index 47391497c4c16..ebcb3691be7aa 100644 --- a/man/dockerd.8.md +++ b/man/dockerd.8.md @@ -224,7 +224,7 @@ $ sudo dockerd --add-runtime runc=runc --add-runtime custom=/usr/local/bin/my-ru Enable the daemon experimental features. **--feature**=*NAME*=**true**|**false** - Enable or disable feature feature in the daemon. This option corresponds + Enable or disable a feature in the daemon. This option corresponds with the "features" field in the daemon.json configuration file. Using both the command-line option and the "features" field in the configuration file produces an error. The feature option can be specified multiple times From bae46f6463ef7c3558b6be6e964d8236204a1c14 Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Mon, 16 Sep 2024 10:26:20 +0200 Subject: [PATCH 03/12] man: dockerd: value is optional for --feature flag The --feature flag allows the boolean value to be omitted. If only a name is provided, the default is "true". Signed-off-by: Sebastiaan van Stijn (cherry picked from commit 50e83a0713b750d7d63e25482b4df3deefb5827d) Signed-off-by: Sebastiaan van Stijn --- man/dockerd.8.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/man/dockerd.8.md b/man/dockerd.8.md index ebcb3691be7aa..c93f809991db4 100644 --- a/man/dockerd.8.md +++ b/man/dockerd.8.md @@ -31,7 +31,7 @@ dockerd - Enable daemon mode [**--exec-opt**[=*[]*]] [**--exec-root**[=*/var/run/docker*]] [**--experimental**[=**false**]] -[**--feature**[=*NAME*=**true**|**false**] +[**--feature**[=*NAME*[=**true**|**false**]] [**--fixed-cidr**[=*FIXED-CIDR*]] [**--fixed-cidr-v6**[=*FIXED-CIDR-V6*]] [**-G**|**--group**[=*docker*]] @@ -223,13 +223,13 @@ $ sudo dockerd --add-runtime runc=runc --add-runtime custom=/usr/local/bin/my-ru **--experimental**="" Enable the daemon experimental features. -**--feature**=*NAME*=**true**|**false** +**--feature**=*NAME*[=**true**|**false**] Enable or disable a feature in the daemon. This option corresponds with the "features" field in the daemon.json configuration file. Using both the command-line option and the "features" field in the configuration file produces an error. The feature option can be specified multiple times to configure multiple features. - Usage example: `--feature containerd-snapshotter=true` + Usage example: `--feature containerd-snapshotter` or `--feature containerd-snapshotter=true`. **--fixed-cidr**="" IPv4 subnet for fixed IPs (e.g., 10.20.0.0/16); this subnet must be nested in From 6d4a507acc5b7ec771b98614cb348749bb39cab3 Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Mon, 16 Sep 2024 10:22:30 +0200 Subject: [PATCH 04/12] internal/opts: SetOpts,NamedSetOpts: test for optional value The value is optional for SetOpts (and NamedSetOpts), and implied "true" when omitted. This patch adds a test-case for this. Signed-off-by: Sebastiaan van Stijn (cherry picked from commit 758cca60367672e745e9c82d82dcdc6408129ccd) Signed-off-by: Sebastiaan van Stijn --- internal/opts/opts_test.go | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/internal/opts/opts_test.go b/internal/opts/opts_test.go index 954c5baab3b5e..17edeb5f98f38 100644 --- a/internal/opts/opts_test.go +++ b/internal/opts/opts_test.go @@ -14,11 +14,12 @@ func TestSetOpts(t *testing.T) { assert.NilError(t, o.Set("feature-b=true")) assert.NilError(t, o.Set("feature-c=0")) assert.NilError(t, o.Set("feature-d=false")) + assert.NilError(t, o.Set("feature-e")) - expected := "map[feature-a:true feature-b:true feature-c:false feature-d:false]" + expected := "map[feature-a:true feature-b:true feature-c:false feature-d:false feature-e:true]" assert.Check(t, is.Equal(expected, o.String())) - expectedValue := map[string]bool{"feature-a": true, "feature-b": true, "feature-c": false, "feature-d": false} + expectedValue := map[string]bool{"feature-a": true, "feature-b": true, "feature-c": false, "feature-d": false, "feature-e": true} assert.Check(t, is.DeepEqual(expectedValue, o.GetAll())) err := o.Set("feature=not-a-bool") @@ -34,11 +35,12 @@ func TestNamedSetOpts(t *testing.T) { assert.NilError(t, o.Set("feature-b=true")) assert.NilError(t, o.Set("feature-c=0")) assert.NilError(t, o.Set("feature-d=false")) + assert.NilError(t, o.Set("feature-e")) - expected := "map[feature-a:true feature-b:true feature-c:false feature-d:false]" + expected := "map[feature-a:true feature-b:true feature-c:false feature-d:false feature-e:true]" assert.Check(t, is.Equal(expected, o.String())) - expectedValue := map[string]bool{"feature-a": true, "feature-b": true, "feature-c": false, "feature-d": false} + expectedValue := map[string]bool{"feature-a": true, "feature-b": true, "feature-c": false, "feature-d": false, "feature-e": true} assert.Check(t, is.DeepEqual(expectedValue, o.GetAll())) err := o.Set("feature=not-a-bool") From 487a2f5314a5aa896114529c667a7902dbdba7a3 Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Mon, 16 Sep 2024 10:39:20 +0200 Subject: [PATCH 05/12] internal/opts: SetOpts.Set: remove redundant var assignment Signed-off-by: Sebastiaan van Stijn (cherry picked from commit 908bb959e794f0c794c062415315b5af4fd13246) Signed-off-by: Sebastiaan van Stijn --- internal/opts/opts.go | 1 - 1 file changed, 1 deletion(-) diff --git a/internal/opts/opts.go b/internal/opts/opts.go index 71a01731201ae..5c9c1d03688a3 100644 --- a/internal/opts/opts.go +++ b/internal/opts/opts.go @@ -20,7 +20,6 @@ func (opts *SetOpts) Set(value string) error { var isSet bool if !found { isSet = true - k = value } else { var err error isSet, err = strconv.ParseBool(v) From 82cf1385901e16b9e4ec45ef1f4a1c3504c84210 Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Mon, 16 Sep 2024 11:00:06 +0200 Subject: [PATCH 06/12] internal/opts: SetOpts: invalidate empty option-names Signed-off-by: Sebastiaan van Stijn (cherry picked from commit c2fc1f4a409c583ec74f874a1268bff22953555d) Signed-off-by: Sebastiaan van Stijn --- internal/opts/opts.go | 4 ++++ internal/opts/opts_test.go | 8 ++++++++ 2 files changed, 12 insertions(+) diff --git a/internal/opts/opts.go b/internal/opts/opts.go index 5c9c1d03688a3..d518fbb690106 100644 --- a/internal/opts/opts.go +++ b/internal/opts/opts.go @@ -1,6 +1,7 @@ package opts import ( + "errors" "fmt" "strconv" "strings" @@ -17,6 +18,9 @@ type SetOpts struct { // internal map, by splitting on '='. func (opts *SetOpts) Set(value string) error { k, v, found := strings.Cut(value, "=") + if k == "" { + return errors.New("invalid option name: " + value) + } var isSet bool if !found { isSet = true diff --git a/internal/opts/opts_test.go b/internal/opts/opts_test.go index 17edeb5f98f38..70263d75aef16 100644 --- a/internal/opts/opts_test.go +++ b/internal/opts/opts_test.go @@ -24,6 +24,10 @@ func TestSetOpts(t *testing.T) { err := o.Set("feature=not-a-bool") assert.Check(t, is.Error(err, `strconv.ParseBool: parsing "not-a-bool": invalid syntax`)) + err = o.Set("feature=") + assert.Check(t, is.Error(err, `strconv.ParseBool: parsing "": invalid syntax`)) + err = o.Set("=true") + assert.Check(t, is.Error(err, `invalid option name: =true`)) } func TestNamedSetOpts(t *testing.T) { @@ -45,4 +49,8 @@ func TestNamedSetOpts(t *testing.T) { err := o.Set("feature=not-a-bool") assert.Check(t, is.Error(err, `strconv.ParseBool: parsing "not-a-bool": invalid syntax`)) + err = o.Set("feature=") + assert.Check(t, is.Error(err, `strconv.ParseBool: parsing "": invalid syntax`)) + err = o.Set("=true") + assert.Check(t, is.Error(err, `invalid option name: =true`)) } From e928a0d22d33df6ac76a540de47132c731c5c298 Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Mon, 16 Sep 2024 12:41:23 +0200 Subject: [PATCH 07/12] man: dockerd: add description for --log-format option This option was added in a08abec9f8d59eaa44c375900e254384a68c5a31, as part of Docker v25.0, but did not update the docs and manpage. Signed-off-by: Sebastiaan van Stijn (cherry picked from commit 45a9dde660b665ab9bd541ec4b2836cc6755864e) Signed-off-by: Sebastiaan van Stijn --- man/dockerd.8.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/man/dockerd.8.md b/man/dockerd.8.md index c93f809991db4..4f2d4b809b302 100644 --- a/man/dockerd.8.md +++ b/man/dockerd.8.md @@ -53,6 +53,7 @@ dockerd - Enable daemon mode [**--label**[=*[]*]] [**--live-restore**[=**false**]] [**--log-driver**[=*json-file*]] +[**--log-format**="*text*|*json*"] [**--log-opt**[=*map[]*]] [**--mtu**[=*0*]] [**--max-concurrent-downloads**[=*3*]] @@ -333,6 +334,9 @@ unix://[/path/to/socket] to use. Default driver for container logs. Default is **json-file**. **Warning**: **docker logs** command works only for **json-file** logging driver. +**--log-format**="*text*|*json*" + Set the format for logs produced by the daemon. Default is "text". + **--log-opt**=[] Logging driver specific options. From 576fc88b1af1434de8fa753814320f7920d2670a Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Mon, 16 Sep 2024 14:51:15 +0200 Subject: [PATCH 08/12] Dockerfile: update buildx to v0.17.1 Update the buildx cli plugin used in the dev-container full diff: https://github.com/docker/buildx/compare/0.17.0...0.17.1 Signed-off-by: Sebastiaan van Stijn (cherry picked from commit 3d4831a23f577a9c0a53cf266f1694798cd5abff) Signed-off-by: Sebastiaan van Stijn --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index d72159ee1eee9..5044caf9613ba 100644 --- a/Dockerfile +++ b/Dockerfile @@ -12,7 +12,7 @@ ARG DOCKERCLI_VERSION=v27.2.1 # cli version used for integration-cli tests ARG DOCKERCLI_INTEGRATION_REPOSITORY="https://github.com/docker/cli.git" ARG DOCKERCLI_INTEGRATION_VERSION=v17.06.2-ce -ARG BUILDX_VERSION=0.17.0 +ARG BUILDX_VERSION=0.17.1 ARG COMPOSE_VERSION=v2.29.2 ARG SYSTEMD="false" From 8adc8e405db4115871ad5f8bdd3155f8f162493b Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Mon, 16 Sep 2024 14:54:35 +0200 Subject: [PATCH 09/12] Dockerfile: update compose to v2.29.4 Update the compose cli plugin used in the dev-container full diff: https://github.com/docker/compose/compare/v2.29.2...v2.29.4 Signed-off-by: Sebastiaan van Stijn (cherry picked from commit 605f51172ae0d5d043c137611b73d11d732a2ec5) Signed-off-by: Sebastiaan van Stijn --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 5044caf9613ba..f401f3a53ef87 100644 --- a/Dockerfile +++ b/Dockerfile @@ -13,7 +13,7 @@ ARG DOCKERCLI_VERSION=v27.2.1 ARG DOCKERCLI_INTEGRATION_REPOSITORY="https://github.com/docker/cli.git" ARG DOCKERCLI_INTEGRATION_VERSION=v17.06.2-ce ARG BUILDX_VERSION=0.17.1 -ARG COMPOSE_VERSION=v2.29.2 +ARG COMPOSE_VERSION=v2.29.4 ARG SYSTEMD="false" ARG DOCKER_STATIC=1 From 5c499fc4b249708619b4225de00c50c861bcfc08 Mon Sep 17 00:00:00 2001 From: Rob Murray Date: Thu, 12 Sep 2024 17:06:59 +0100 Subject: [PATCH 10/12] Only enable bridge netfiltering when needed Kernel module br_netfilter is loaded when the daemon starts with either iptables or ip6tables enabled. That automatically sets: net.bridge.bridge-nf-call-arptables = 1 net.bridge.bridge-nf-call-ip6tables = 1 net.bridge.bridge-nf-call-iptables = 1 So, when: - docker was running happily with iptables=false, and - no explicit ip6tables=false, and - br_netfilter was not loaded ... the change in moby 27.0 to enable ip6tables by default, resulted in net.bridge.bridge-nf-call-iptables being enabled. If the host also had a firewall with default-drop on its forward chain - that resulted in packets getting dropped between containers on a bridge network. So, only try to load br_netfilter when it's needed - it's only needed to implement "--icc=false", which can only be used when iptables or ip6tables is enabled. Signed-off-by: Rob Murray (cherry picked from commit db25b0dcd0461802289e962aa0df3abd323d1994) Signed-off-by: Rob Murray --- libnetwork/drivers/bridge/bridge_linux.go | 10 ---------- libnetwork/drivers/bridge/setup_bridgenetfiltering.go | 7 +++++++ 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/libnetwork/drivers/bridge/bridge_linux.go b/libnetwork/drivers/bridge/bridge_linux.go index 853a1068ea0ef..4fae4ebd04ec8 100644 --- a/libnetwork/drivers/bridge/bridge_linux.go +++ b/libnetwork/drivers/bridge/bridge_linux.go @@ -5,8 +5,6 @@ import ( "fmt" "net" "net/netip" - "os" - "os/exec" "strconv" "sync" @@ -482,14 +480,6 @@ func (d *driver) configure(option map[string]interface{}) error { return &ErrInvalidDriverConfig{} } - if config.EnableIPTables || config.EnableIP6Tables { - if _, err := os.Stat("/proc/sys/net/bridge"); err != nil { - if out, err := exec.Command("modprobe", "-va", "bridge", "br_netfilter").CombinedOutput(); err != nil { - log.G(context.TODO()).Warnf("Running modprobe bridge br_netfilter failed with message: %s, error: %v", out, err) - } - } - } - if config.EnableIPTables { removeIPChains(iptables.IPv4) diff --git a/libnetwork/drivers/bridge/setup_bridgenetfiltering.go b/libnetwork/drivers/bridge/setup_bridgenetfiltering.go index 21719b0beaf8f..9fb367d9fbe6c 100644 --- a/libnetwork/drivers/bridge/setup_bridgenetfiltering.go +++ b/libnetwork/drivers/bridge/setup_bridgenetfiltering.go @@ -7,6 +7,7 @@ import ( "errors" "fmt" "os" + "os/exec" "syscall" "github.com/containerd/log" @@ -46,6 +47,12 @@ func setupIPv6BridgeNetFiltering(config *networkConfiguration, _ *bridgeInterfac // Enable bridge net filtering if not already enabled. See GitHub issue #11404 func enableBridgeNetFiltering(nfParam string) error { + if _, err := os.Stat("/proc/sys/net/bridge"); err != nil { + if out, err := exec.Command("modprobe", "-va", "bridge", "br_netfilter").CombinedOutput(); err != nil { + log.G(context.TODO()).WithError(err).Errorf("Running modprobe bridge br_netfilter failed with message: %s", out) + return fmt.Errorf("cannot restrict inter-container communication: modprobe br_netfilter failed: %w", err) + } + } enabled, err := getKernelBoolParam(nfParam) if err != nil { var pathErr *os.PathError From cd21af7e411c114dcc877cead6456d3dda8ef9cc Mon Sep 17 00:00:00 2001 From: Rob Murray Date: Thu, 27 Jun 2024 13:38:20 +0100 Subject: [PATCH 11/12] Do not DNAT packets from WSL2's loopback0 When running WSL2 with mirrored mode networking, add an iptables rule to skip DNAT for packets arriving on interface loopback0 that are addressed to a localhost address - they're from the Windows host. Signed-off-by: Rob Murray (cherry picked from commit f9c01034131dd3e6b80e3bd605b4b38fcda4ee00) Signed-off-by: Rob Murray --- .../drivers/bridge/setup_ip_tables_linux.go | 88 +++++++++++++++++++ .../bridge/setup_ip_tables_linux_test.go | 74 ++++++++++++++++ 2 files changed, 162 insertions(+) diff --git a/libnetwork/drivers/bridge/setup_ip_tables_linux.go b/libnetwork/drivers/bridge/setup_ip_tables_linux.go index dd8810fbbd8a0..3d6150d7556ae 100644 --- a/libnetwork/drivers/bridge/setup_ip_tables_linux.go +++ b/libnetwork/drivers/bridge/setup_ip_tables_linux.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" "net" + "os" "strings" "github.com/containerd/log" @@ -32,6 +33,11 @@ const ( IsolationChain2 = "DOCKER-ISOLATION-STAGE-2" ) +// Path to the executable installed in Linux under WSL2 that reports on +// WSL config. https://github.com/microsoft/WSL/releases/tag/2.0.4 +// Can be modified by tests. +var wslinfoPath = "/usr/bin/wslinfo" + func setupIPChains(config configuration, version iptables.IPVersion) (natChain *iptables.ChainInfo, filterChain *iptables.ChainInfo, isolationChain1 *iptables.ChainInfo, isolationChain2 *iptables.ChainInfo, retErr error) { // Sanity check. if version == iptables.IPv4 && !config.EnableIPTables { @@ -99,6 +105,10 @@ func setupIPChains(config configuration, version iptables.IPVersion) (natChain * return nil, nil, nil, nil, err } + if err := mirroredWSL2Workaround(config, version); err != nil { + return nil, nil, nil, nil, err + } + return natChain, filterChain, isolationChain1, isolationChain2, nil } @@ -502,3 +512,81 @@ func clearConntrackEntries(nlh *netlink.Handle, ep *bridgeEndpoint) { iptables.DeleteConntrackEntries(nlh, ipv4List, ipv6List) iptables.DeleteConntrackEntriesByPort(nlh, types.UDP, udpPorts) } + +// mirroredWSL2Workaround adds or removes an IPv4 NAT rule, depending on whether +// docker's host Linux appears to be a guest running under WSL2 in with mirrored +// mode networking. +// https://learn.microsoft.com/en-us/windows/wsl/networking#mirrored-mode-networking +// +// Without mirrored mode networking, or for a packet sent from Linux, packets +// sent to 127.0.0.1 are processed as outgoing - they hit the nat-OUTPUT chain, +// which does not jump to the nat-DOCKER chain because the rule has an exception +// for "-d 127.0.0.0/8". The default action on the nat-OUTPUT chain is ACCEPT (by +// default), so the packet is delivered to 127.0.0.1 on lo, where docker-proxy +// picks it up and acts as a man-in-the-middle; it receives the packet and +// re-sends it to the container (or acks a SYN and sets up a second TCP +// connection to the container). So, the container sees packets arrive with a +// source address belonging to the network's bridge, and it is able to reply to +// that address. +// +// In WSL2's mirrored networking mode, Linux has a loopback0 device as well as lo +// (which owns 127.0.0.1 as normal). Packets sent to 127.0.0.1 from Windows to a +// server listening on Linux's 127.0.0.1 are delivered via loopback0, and +// processed as packets arriving from outside the Linux host (which they are). +// +// So, these packets hit the nat-PREROUTING chain instead of nat-OUTPUT. It would +// normally be impossible for a packet ->127.0.0.1 to arrive from outside the +// host, so the nat-PREROUTING jump to nat-DOCKER has no exception for it. The +// packet is processed by a per-bridge DNAT rule in that chain, so it is +// delivered directly to the container (not via docker-proxy) with source address +// 127.0.0.1, so the container can't respond. +// +// DNAT is normally skipped by RETURN rules in the nat-DOCKER chain for packets +// arriving from any other bridge network. Similarly, this function adds (or +// removes) a rule to RETURN early for packets delivered via loopback0 with +// destination 127.0.0.0/8. +func mirroredWSL2Workaround(config configuration, ipv iptables.IPVersion) error { + // WSL2 does not (currently) support Windows<->Linux communication via ::1. + if ipv != iptables.IPv4 { + return nil + } + return programChainRule(mirroredWSL2Rule(), "WSL2 loopback", insertMirroredWSL2Rule(config)) +} + +// insertMirroredWSL2Rule returns true if the NAT rule for mirrored WSL2 workaround +// is required. It is required if: +// - the userland proxy is running. If not, there's nothing on the host to catch +// the packet, so the loopback0 rule as wouldn't be useful. However, without +// the workaround, with improvements in WSL2 v2.3.11, and without userland proxy +// running - no workaround is needed, the normal DNAT/masquerading works. +// - and, the host Linux appears to be running under Windows WSL2 with mirrored +// mode networking. If a loopback0 device exists, and there's an executable at +// /usr/bin/wslinfo, infer that this is WSL2 with mirrored networking. ("wslinfo +// --networking-mode" reports "mirrored", but applying the workaround for WSL2's +// loopback device when it's not needed is low risk, compared with executing +// wslinfo with dockerd's elevated permissions.) +func insertMirroredWSL2Rule(config configuration) bool { + if !config.EnableUserlandProxy || config.UserlandProxyPath == "" { + return false + } + if _, err := netlink.LinkByName("loopback0"); err != nil { + if !errors.As(err, &netlink.LinkNotFoundError{}) { + log.G(context.TODO()).WithError(err).Warn("Failed to check for WSL interface") + } + return false + } + stat, err := os.Stat(wslinfoPath) + if err != nil { + return false + } + return stat.Mode().IsRegular() && (stat.Mode().Perm()&0111) != 0 +} + +func mirroredWSL2Rule() iptRule { + return iptRule{ + ipv: iptables.IPv4, + table: iptables.Nat, + chain: DockerChain, + args: []string{"-i", "loopback0", "-d", "127.0.0.0/8", "-j", "RETURN"}, + } +} diff --git a/libnetwork/drivers/bridge/setup_ip_tables_linux_test.go b/libnetwork/drivers/bridge/setup_ip_tables_linux_test.go index 440286cd73476..17e573b6f7c68 100644 --- a/libnetwork/drivers/bridge/setup_ip_tables_linux_test.go +++ b/libnetwork/drivers/bridge/setup_ip_tables_linux_test.go @@ -2,6 +2,8 @@ package bridge import ( "net" + "os" + "path/filepath" "testing" "github.com/docker/docker/internal/testutils/netnsutils" @@ -10,6 +12,7 @@ import ( "github.com/docker/docker/libnetwork/netlabel" "github.com/vishvananda/netlink" "gotest.tools/v3/assert" + is "gotest.tools/v3/assert/cmp" ) const ( @@ -374,3 +377,74 @@ func TestOutgoingNATRules(t *testing.T) { }) } } + +func TestMirroredWSL2Workaround(t *testing.T) { + for _, tc := range []struct { + desc string + loopback0 bool + userlandProxy bool + wslinfoPerm os.FileMode // 0 for no-file + expLoopback0Rule bool + }{ + { + desc: "No loopback0", + }, + { + desc: "WSL2 mirrored", + loopback0: true, + userlandProxy: true, + wslinfoPerm: 0777, + expLoopback0Rule: true, + }, + { + desc: "loopback0 but wslinfo not executable", + loopback0: true, + userlandProxy: true, + wslinfoPerm: 0666, + }, + { + desc: "loopback0 but no wslinfo", + loopback0: true, + userlandProxy: true, + }, + { + desc: "loopback0 but no userland proxy", + loopback0: true, + wslinfoPerm: 0777, + }, + } { + t.Run(tc.desc, func(t *testing.T) { + defer netnsutils.SetupTestOSContext(t)() + + if tc.loopback0 { + loopback0 := &netlink.Dummy{ + LinkAttrs: netlink.LinkAttrs{ + Name: "loopback0", + }, + } + err := netlink.LinkAdd(loopback0) + assert.NilError(t, err) + } + + if tc.wslinfoPerm != 0 { + wslinfoPathOrig := wslinfoPath + defer func() { + wslinfoPath = wslinfoPathOrig + }() + tmpdir := t.TempDir() + wslinfoPath = filepath.Join(tmpdir, "wslinfo") + err := os.WriteFile(wslinfoPath, []byte("#!/bin/sh\necho dummy file\n"), tc.wslinfoPerm) + assert.NilError(t, err) + } + + config := configuration{EnableIPTables: true} + if tc.userlandProxy { + config.UserlandProxyPath = "some-proxy" + config.EnableUserlandProxy = true + } + _, _, _, _, err := setupIPChains(config, iptables.IPv4) + assert.NilError(t, err) + assert.Check(t, is.Equal(mirroredWSL2Rule().Exists(), tc.expLoopback0Rule)) + }) + } +} From a6b772b24cbfa5c1aab2dc31c5283f7a9bac80f4 Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Wed, 18 Sep 2024 10:29:58 +0200 Subject: [PATCH 12/12] gha: govulncheck: make sure read permissions are set If any permission is set, any permission not included in the list is implicitly set to "none". see https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#permissions The govulncheck check need read permissions, which is not problematic for public repositories, but may be needed when running in a private fork (such as those used for security releases). Signed-off-by: Sebastiaan van Stijn (cherry picked from commit 4f1d739de55c4e5c4c8e5ce191e2000ec96ef111) Signed-off-by: Sebastiaan van Stijn --- .github/workflows/ci.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a4b21e3745abb..b1a390f564efb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -136,6 +136,8 @@ jobs: permissions: # required to write sarif report security-events: write + # required to check out the repository + contents: read steps: - name: Checkout