From c41880fe4a20461e808b05dccfad62521706d30c Mon Sep 17 00:00:00 2001 From: Akihiro Suda Date: Wed, 9 Jul 2025 17:12:23 +0900 Subject: [PATCH 1/2] CI: test portfwd issue (`w3m -dump` hangs) Test for issue 3685 Signed-off-by: Akihiro Suda --- .github/workflows/test.yml | 9 +++++---- hack/test-templates.sh | 8 ++++++++ 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 2da2b42be72..da61fd8025a 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -264,7 +264,8 @@ jobs: # QEMU: required by Lima itself # bash: required by test-templates.sh (OS version of bash is too old) # coreutils: required by test-templates.sh for the "timeout" command - run: brew install qemu bash coreutils + # w3m : required by test-templates.sh for port forwarding tests + run: brew install qemu bash coreutils w3m - name: "Adjust LIMACTL_CREATE_ARGS" run: echo "LIMACTL_CREATE_ARGS=${LIMACTL_CREATE_ARGS} --vm-type=qemu" >>$GITHUB_ENV - name: "Inject `no_timer_check` to kernel cmdline" @@ -331,7 +332,7 @@ jobs: - name: Install test dependencies run: | sudo apt-get update - sudo apt-get install -y --no-install-recommends ovmf qemu-system-x86 qemu-utils + sudo apt-get install -y --no-install-recommends ovmf qemu-system-x86 qemu-utils w3m sudo modprobe kvm # `sudo usermod -aG kvm $(whoami)` does not take an effect on GHA sudo chown $(whoami) /dev/kvm @@ -430,7 +431,7 @@ jobs: with: template: templates/default.yaml - name: Install test dependencies - run: brew install qemu bash coreutils + run: brew install qemu bash coreutils w3m - name: Install socket_vmnet env: SOCKET_VMNET_VERSION: v1.2.0 @@ -525,7 +526,7 @@ jobs: with: template: templates/${{ matrix.template }} - name: Install test dependencies - run: brew install bash coreutils + run: brew install bash coreutils w3m - name: Uninstall qemu run: brew uninstall --ignore-dependencies --force qemu - name: Test diff --git a/hack/test-templates.sh b/hack/test-templates.sh index 0dd6f75c335..94cc70b294b 100755 --- a/hack/test-templates.sh +++ b/hack/test-templates.sh @@ -381,6 +381,14 @@ if [[ -n ${CHECKS["port-forwards"]} ]]; then limactl shell "$NAME" $sudo $CONTAINER_ENGINE rm -f nginx fi fi + if [[ ${NAME} != "alpine"* ]] && command -v w3m >/dev/null; then + INFO "Testing https://github.com/lima-vm/lima/issues/3685 ([gRPC portfwd] client connection is not closed immediately when server closed the connection)" + # Skip the test on Alpine, as systemd-run is missing + limactl shell "$NAME" systemd-run --user python3 -m http.server 3685 + # curl is not enough to reproduce https://github.com/lima-vm/lima/issues/3685 + # `w3m -dump` exits with status code 0 even on "Can't load" error. + timeout 30s bash -euxc "until w3m -dump http://localhost:3685 | grep -v \"w3m: Can't load\"; do sleep 3; done" + fi fi set +x fi From 6ca9e7f3971f8d8f6cbf8605b8eed38c5b3ec8ae Mon Sep 17 00:00:00 2001 From: Akihiro Suda Date: Wed, 9 Jul 2025 19:23:53 +0900 Subject: [PATCH 2/2] portfwdserver: use `tcpproxy` to fix `w3m -dump` issue Fix issue 3685 Signed-off-by: Akihiro Suda --- hack/test-templates.sh | 3 ++- pkg/portfwdserver/server.go | 33 ++++++++++++++++++++++++++++++++- 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/hack/test-templates.sh b/hack/test-templates.sh index 94cc70b294b..365c5cc5522 100755 --- a/hack/test-templates.sh +++ b/hack/test-templates.sh @@ -381,9 +381,10 @@ if [[ -n ${CHECKS["port-forwards"]} ]]; then limactl shell "$NAME" $sudo $CONTAINER_ENGINE rm -f nginx fi fi - if [[ ${NAME} != "alpine"* ]] && command -v w3m >/dev/null; then + if [[ ${NAME} != "alpine"* && ${NAME} != "wsl2"* ]] && command -v w3m >/dev/null; then INFO "Testing https://github.com/lima-vm/lima/issues/3685 ([gRPC portfwd] client connection is not closed immediately when server closed the connection)" # Skip the test on Alpine, as systemd-run is missing + # Skip the test on WSL2, as port forwarding is half broken https://github.com/lima-vm/lima/pull/3686#issuecomment-3034842616 limactl shell "$NAME" systemd-run --user python3 -m http.server 3685 # curl is not enough to reproduce https://github.com/lima-vm/lima/issues/3685 # `w3m -dump` exits with status code 0 even on "Can't load" error. diff --git a/pkg/portfwdserver/server.go b/pkg/portfwdserver/server.go index 54f48a6e0af..3ded422b45a 100644 --- a/pkg/portfwdserver/server.go +++ b/pkg/portfwdserver/server.go @@ -4,11 +4,16 @@ package portfwdserver import ( + "context" "errors" "io" "net" + "os" + "strings" "time" + "github.com/containers/gvisor-tap-vsock/pkg/tcpproxy" + "github.com/lima-vm/lima/pkg/bicopy" "github.com/lima-vm/lima/pkg/guestagent/api" ) @@ -35,7 +40,23 @@ func (s *TunnelServer) Start(stream api.GuestService_TunnelServer) error { return err } rw := &GRPCServerRW{stream: stream, id: in.Id} - bicopy.Bicopy(rw, conn, nil) + + // FIXME: consolidate bicopy and tcpproxy into one + // + // The bicopy package does not seem to work with `w3m -dump`: + // https://github.com/lima-vm/lima/issues/3685 + // + // However, the tcpproxy package can't pass the CI for WSL2 (experimental): + // https://github.com/lima-vm/lima/pull/3686#issuecomment-3034842616 + if wsl2, _ := seemsWSL2(); wsl2 { + bicopy.Bicopy(rw, conn, nil) + } else { + proxy := tcpproxy.DialProxy{DialContext: func(_ context.Context, _, _ string) (net.Conn, error) { + return conn, nil + }} + proxy.HandleConn(rw) + } + return nil } @@ -83,3 +104,13 @@ func (g *GRPCServerRW) SetReadDeadline(_ time.Time) error { func (g *GRPCServerRW) SetWriteDeadline(_ time.Time) error { return nil } + +// seemsWSL2 returns whether lima.env contains LIMA_CIDATA_VMTYPE=wsl2 . +// This is a temporary workaround and has to be removed. +func seemsWSL2() (bool, error) { + b, err := os.ReadFile("/mnt/lima-cidata/lima.env") + if err != nil { + return false, err + } + return strings.Contains(string(b), "LIMA_CIDATA_VMTYPE=wsl2"), nil +}