From 8004d1b68afc24fa698d99b22cd491133d23a37d Mon Sep 17 00:00:00 2001 From: Nino Kodabande Date: Mon, 19 Aug 2024 10:18:03 -0700 Subject: [PATCH 1/7] Remove vtunnel project out of the main repo Signed-off-by: Nino Kodabande --- src/go/vtunnel/README.md | 78 ---- src/go/vtunnel/cmd/host_windows.go | 64 --- src/go/vtunnel/cmd/peer_linux.go | 67 --- src/go/vtunnel/cmd/root.go | 44 -- src/go/vtunnel/go.mod | 27 -- src/go/vtunnel/go.sum | 54 --- src/go/vtunnel/main.go | 20 - src/go/vtunnel/pkg/config/config.go | 50 --- src/go/vtunnel/pkg/vmsock/conn_linux.go | 92 ----- src/go/vtunnel/pkg/vmsock/conn_windows.go | 206 ---------- src/go/vtunnel/pkg/vmsock/constants.go | 16 - src/go/vtunnel/test/e2e/connectivity_test.go | 411 ------------------- 12 files changed, 1129 deletions(-) delete mode 100644 src/go/vtunnel/README.md delete mode 100644 src/go/vtunnel/cmd/host_windows.go delete mode 100644 src/go/vtunnel/cmd/peer_linux.go delete mode 100644 src/go/vtunnel/cmd/root.go delete mode 100644 src/go/vtunnel/go.mod delete mode 100644 src/go/vtunnel/go.sum delete mode 100644 src/go/vtunnel/main.go delete mode 100644 src/go/vtunnel/pkg/config/config.go delete mode 100644 src/go/vtunnel/pkg/vmsock/conn_linux.go delete mode 100644 src/go/vtunnel/pkg/vmsock/conn_windows.go delete mode 100644 src/go/vtunnel/pkg/vmsock/constants.go delete mode 100644 src/go/vtunnel/test/e2e/connectivity_test.go diff --git a/src/go/vtunnel/README.md b/src/go/vtunnel/README.md deleted file mode 100644 index ba396fd5b76..00000000000 --- a/src/go/vtunnel/README.md +++ /dev/null @@ -1,78 +0,0 @@ -# vtunnel - -Vtunnel is a virtual tunnel that leverages AF_VSOCK virtual sockets. Vtunnel runs two processes: - - host process that runs on the host machine - - peer process that runs inside a Hyper-V VM (e.g. WSL). - -## Host - -The host process can be configured with an upstream HTTP/TCP server to forward the requests to. The tunnel accepts the incoming vsock requests over AF_VSOCK and for every request it creates a connection to the given upstream server to pipe the data forward. - -## Peer - -The Peer process starts a TCP server inside the Hyper-V VM and listens for all the incoming requests; once a request is received it forwards it over the AF_SOCK to the host. - -```mermaid -flowchart LR; - subgraph Host["HOST"] - UpstreamServer("Upstream HTTP/TCP Server") - HostProcess("Vtunnel Host") - UpstreamServer <---> |over TCP| HostProcess - end - subgraph VM["WSL VM"] - Peer("Vtunnel Peer") - Client("client") - Peer <---> |over TCP| Client - end - HostProcess <---> |AF_VSOCK| Peer -``` -## E2E test - -You can simply run the e2e test: -```pwsh - go test -v .\test\e2e\connectivity_test.go -``` - -## Manual Testing - - - You will need to build the binaries for both Host and Peer processes: -```bash - GOOS=windows go build - GOOS=linux go build -``` -- Creat a configuration file; below is an example of a `config.yaml`. -- The `upstream-server-address` can be in IP:Port format if upstream server is a - TCP server; alternatively it can be be a named pipe server address, e.g. - `npipe:////./pipe/my-upstream-server`. The `npipe://` prefix is required. - **Note** same configuration file can be used for both Peer and Host processes. - ```yaml - tunnel: - - name: tcpTunnel - handshake-port: 9090 - vsock-host-port: 8989 - peer-address: 127.0.0.1 - peer-port: 3030 - upstream-server-address: 127.0.0.1:4444 - - name: npipeTunnel - handshake-port: 9091 - vsock-host-port: 8990 - peer-address: 127.0.0.1 - peer-port: 4040 - upstream-server-address: npipe:////./pipe/my-upstream-server - ``` - - Move the `vtunnel` executable to the Hyper-V VM and run the Peer process: - ```bash - ./vtunnel peer --config-path config.yaml - ``` - - Use netcat or a similar approach to run a HTTP/TCP server on the host machine: - ```pwsh - python3 -m http.server 4444 --bind 127.0.0.1 - ``` - - Run the host process on windows: - ```pwsh - .\vtunnel.exe host --config-path config.yaml - ``` - - Using Curl or similar utilities send a request to the Peer TCP server inside the VM. - ```bash - curl localhost:3030 - ``` \ No newline at end of file diff --git a/src/go/vtunnel/cmd/host_windows.go b/src/go/vtunnel/cmd/host_windows.go deleted file mode 100644 index 2302206c756..00000000000 --- a/src/go/vtunnel/cmd/host_windows.go +++ /dev/null @@ -1,64 +0,0 @@ -/* -Copyright © 2022 SUSE LLC - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ -package cmd - -import ( - "context" - - "github.com/sirupsen/logrus" - "github.com/spf13/cobra" - "golang.org/x/sync/errgroup" - - "github.com/rancher-sandbox/rancher-desktop/src/go/vtunnel/pkg/config" - "github.com/rancher-sandbox/rancher-desktop/src/go/vtunnel/pkg/vmsock" -) - -// hostCmd represents the host command -var hostCmd = &cobra.Command{ - Use: "host", - Short: "vtunnel host process", - Long: `vtunnel host process runs on the host machine and binds to localhost -and a given port acting as a host end of the tunnel.`, - RunE: func(cmd *cobra.Command, args []string) error { - cmd.SilenceUsage = true - configPath, err := cmd.Flags().GetString("config-path") - if err != nil { - return err - } - conf, err := config.NewConfig(configPath) - if err != nil { - return err - } - errs, _ := errgroup.WithContext(context.Background()) - for _, tun := range conf.Tunnel { - hostConnector := vmsock.HostConnector{ - UpstreamServerAddress: tun.UpstreamServerAddress, - VsockListenPort: tun.VsockHostPort, - PeerHandshakePort: tun.HandshakePort, - } - errs.Go(hostConnector.ListenAndDial) - } - return errs.Wait() - }, -} - -func init() { - hostCmd.Flags().String("config-path", "", "Path to the vtunnel's yaml configuration file") - if err := hostCmd.MarkFlagRequired("config-path"); err != nil { - logrus.WithError(err).Fatal("Failed to set up flags") - } - rootCmd.AddCommand(hostCmd) -} diff --git a/src/go/vtunnel/cmd/peer_linux.go b/src/go/vtunnel/cmd/peer_linux.go deleted file mode 100644 index ffceaaaf317..00000000000 --- a/src/go/vtunnel/cmd/peer_linux.go +++ /dev/null @@ -1,67 +0,0 @@ -/* -Copyright © 2022 SUSE LLC - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ -package cmd - -import ( - "context" - - "github.com/sirupsen/logrus" - "github.com/spf13/cobra" - "golang.org/x/sync/errgroup" - - "github.com/rancher-sandbox/rancher-desktop/src/go/vtunnel/pkg/config" - "github.com/rancher-sandbox/rancher-desktop/src/go/vtunnel/pkg/vmsock" -) - -// peerCmd represents the peer command -var peerCmd = &cobra.Command{ - Use: "peer", - Short: "vtunnel peer process", - Long: `vtunnel peer process runs in the WSL VM and binds to a given -IP and port acting as a peer end of the tunnel.`, - RunE: func(cmd *cobra.Command, args []string) error { - cmd.SilenceUsage = true - path, err := cmd.Flags().GetString("config-path") - if err != nil { - return err - } - conf, err := config.NewConfig(path) - if err != nil { - return err - } - - errs, _ := errgroup.WithContext(context.Background()) - for _, tun := range conf.Tunnel { - peerConnector := vmsock.PeerConnector{ - IPv4ListenAddress: tun.PeerAddress, - TCPListenPort: tun.PeerPort, - VsockHandshakePort: tun.HandshakePort, - VsockHostPort: tun.VsockHostPort, - } - go peerConnector.ListenAndHandshake() - errs.Go(peerConnector.ListenTCP) - } - return errs.Wait() - }, -} - -func init() { - peerCmd.Flags().String("config-path", "", "Path to the vtunnel's yaml configuration file") - if err := peerCmd.MarkFlagRequired("config-path"); err != nil { - logrus.WithError(err).Fatal("Failed to set up flags") - } - rootCmd.AddCommand(peerCmd) -} diff --git a/src/go/vtunnel/cmd/root.go b/src/go/vtunnel/cmd/root.go deleted file mode 100644 index 89d0cb9e396..00000000000 --- a/src/go/vtunnel/cmd/root.go +++ /dev/null @@ -1,44 +0,0 @@ -/* -Copyright © 2022 SUSE LLC - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ -package cmd - -import ( - "os" - - "github.com/sirupsen/logrus" - "github.com/spf13/cobra" -) - -// rootCmd represents the base command when called without any subcommands -var rootCmd = &cobra.Command{ - Use: "vtunnel", - Short: "A TCP Tunnel over AF_VSOCK", - Long: `vtunnel is a network communication tunnel that bridges the host and the WSL VM -communications over TCP. The tunnel's peer process listens on a provided IP:HOST inside the WSL VM. -The host process on windows forwards the TCP payload to a given address over TCP.`, -} - -// Execute adds all child commands to the root command and sets flags appropriately. -// This is called by main.main(). It only needs to happen once to the rootCmd. -func Execute() { - writer := logrus.New().Writer() - defer writer.Close() - rootCmd.SetErr(writer) - err := rootCmd.Execute() - if err != nil { - os.Exit(1) - } -} diff --git a/src/go/vtunnel/go.mod b/src/go/vtunnel/go.mod deleted file mode 100644 index 865f9803f13..00000000000 --- a/src/go/vtunnel/go.mod +++ /dev/null @@ -1,27 +0,0 @@ -module github.com/rancher-sandbox/rancher-desktop/src/go/vtunnel - -go 1.21 - -require ( - github.com/Microsoft/go-winio v0.6.2 - github.com/google/uuid v1.6.0 - github.com/linuxkit/virtsock v0.0.0-20220523201153-1a23e78aa7a2 - github.com/rancher-sandbox/rancher-desktop/src/go/wsl-helper v0.0.0-20220526041742-c1ed19db6a88 - github.com/sirupsen/logrus v1.9.3 - github.com/spf13/cobra v1.8.1 - github.com/stretchr/testify v1.9.0 - golang.org/x/sync v0.8.0 - golang.org/x/sys v0.24.0 - gopkg.in/yaml.v3 v3.0.1 -) - -require ( - github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect - github.com/inconshreveable/mousetrap v1.1.0 // indirect - github.com/kr/pretty v0.3.1 // indirect - github.com/pkg/errors v0.9.1 // indirect - github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect - github.com/rogpeppe/go-internal v1.12.0 // indirect - github.com/spf13/pflag v1.0.5 // indirect - gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect -) diff --git a/src/go/vtunnel/go.sum b/src/go/vtunnel/go.sum deleted file mode 100644 index d811cca026f..00000000000 --- a/src/go/vtunnel/go.sum +++ /dev/null @@ -1,54 +0,0 @@ -github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= -github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= -github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= -github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= -github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= -github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= -github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= -github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= -github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= -github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/linuxkit/virtsock v0.0.0-20220523201153-1a23e78aa7a2 h1:DZMFueDbfz6PNc1GwDRA8+6lBx1TB9UnxDQliCqR73Y= -github.com/linuxkit/virtsock v0.0.0-20220523201153-1a23e78aa7a2/go.mod h1:SWzULI85WerrFt3u+nIm5F9l7EvxZTKQvd0InF3nmgM= -github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= -github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= -github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= -github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/rancher-sandbox/rancher-desktop/src/go/wsl-helper v0.0.0-20220526041742-c1ed19db6a88 h1:Vu8SbEI3X24DWuDDoqmDfax3ejQHSUydG3tpJSBauTU= -github.com/rancher-sandbox/rancher-desktop/src/go/wsl-helper v0.0.0-20220526041742-c1ed19db6a88/go.mod h1:ARlcfTpJPOEcGXWwYoi5f/k7zb8g35ib3MiFtIlKaUc= -github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= -github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= -github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= -github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= -github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= -github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= -github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= -github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= -github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= -github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= -golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg= -golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= -gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/src/go/vtunnel/main.go b/src/go/vtunnel/main.go deleted file mode 100644 index 15796add8cc..00000000000 --- a/src/go/vtunnel/main.go +++ /dev/null @@ -1,20 +0,0 @@ -/* -Copyright © 2022 SUSE LLC -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package main - -import "github.com/rancher-sandbox/rancher-desktop/src/go/vtunnel/cmd" - -func main() { - cmd.Execute() -} diff --git a/src/go/vtunnel/pkg/config/config.go b/src/go/vtunnel/pkg/config/config.go deleted file mode 100644 index cebf829e4eb..00000000000 --- a/src/go/vtunnel/pkg/config/config.go +++ /dev/null @@ -1,50 +0,0 @@ -/* -Copyright © 2022 SUSE LLC - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ -package config - -import ( - "os" - - "gopkg.in/yaml.v3" -) - -type Tunnel struct { - Name string `yaml:"name"` - HandshakePort uint32 `yaml:"handshake-port"` - VsockHostPort uint32 `yaml:"vsock-host-port"` - PeerAddress string `yaml:"peer-address"` - PeerPort int `yaml:"peer-port"` - UpstreamServerAddress string `yaml:"upstream-server-address"` -} -type Config struct { - Tunnel []Tunnel `yaml:"tunnel"` -} - -func NewConfig(path string) (*Config, error) { - conf := &Config{} - file, err := os.Open(path) - if err != nil { - return nil, err - } - defer file.Close() - - d := yaml.NewDecoder(file) - if err := d.Decode(&conf); err != nil { - return nil, err - } - - return conf, nil -} diff --git a/src/go/vtunnel/pkg/vmsock/conn_linux.go b/src/go/vtunnel/pkg/vmsock/conn_linux.go deleted file mode 100644 index 2ef90f00e57..00000000000 --- a/src/go/vtunnel/pkg/vmsock/conn_linux.go +++ /dev/null @@ -1,92 +0,0 @@ -/* -Copyright © 2022 SUSE LLC -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package vmsock - -import ( - "fmt" - "net" - - "github.com/linuxkit/virtsock/pkg/vsock" - "github.com/sirupsen/logrus" - - "github.com/rancher-sandbox/rancher-desktop/src/go/wsl-helper/pkg/dockerproxy/util" -) - -type PeerConnector struct { - IPv4ListenAddress string - TCPListenPort int - VsockHandshakePort uint32 - VsockHostPort uint32 -} - -// ListenAndHandshake listens for incoming VSOCK connections from the Host process -// The handshake is performed once during startup/restart to make sure that -// host process is talking to a right hyper-v VM (most likely WSL) -func (p *PeerConnector) ListenAndHandshake() { - l, err := vsock.Listen(vsock.CIDAny, p.VsockHandshakePort) - if err != nil { - logrus.Fatalf("PeerHandshake listen for incoming vsock: %v", err) - } - defer l.Close() - - for { - conn, err := l.Accept() - if err != nil { - logrus.Errorf("PeerHandshake accepting incoming socket connection: %v", err) - continue - } - _, err = conn.Write([]byte(SeedPhrase)) - if err != nil { - logrus.Errorf("PeerHandshake writing seed phrase: %v", err) - } - - conn.Close() - logrus.Info("successful handshake with vsock-host") - } -} - -// ListenTCP starts a tcp listener and accepts TCP connections on a given port and addr -// when a new connection is accepted, ListenTCP handles the connection by establishing -// virtual socket to the host and sends the packets over the AF_VSOCK -func (p *PeerConnector) ListenTCP() error { - l, err := net.ListenTCP("tcp", &net.TCPAddr{IP: net.ParseIP(p.IPv4ListenAddress), Port: p.TCPListenPort}) - if err != nil { - return fmt.Errorf("ListenTCP: %w", err) - } - defer l.Close() - - for { - conn, err := l.Accept() - if err != nil { - logrus.Errorf("ListenTCP accept connection: %v", err) - continue - } - go p.handleTCP(conn) - } -} - -func (p *PeerConnector) handleTCP(tConn net.Conn) { - defer tConn.Close() - vConn, err := vsock.Dial(vsock.CIDHost, p.VsockHostPort) - if err != nil { - logrus.Fatalf("handleTCP dial to vsock host: %v", err) - } - defer vConn.Close() - - err = util.Pipe(tConn, vConn) - if err != nil { - logrus.Errorf("handleTCP, stream error: %v", err) - return - } -} diff --git a/src/go/vtunnel/pkg/vmsock/conn_windows.go b/src/go/vtunnel/pkg/vmsock/conn_windows.go deleted file mode 100644 index 66c55ac9c72..00000000000 --- a/src/go/vtunnel/pkg/vmsock/conn_windows.go +++ /dev/null @@ -1,206 +0,0 @@ -/* -Copyright © 2022 SUSE LLC -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package vmsock - -import ( - "errors" - "fmt" - "io" - "net" - "strings" - "syscall" - "time" - - "github.com/Microsoft/go-winio" - "github.com/linuxkit/virtsock/pkg/hvsock" - "github.com/sirupsen/logrus" - "golang.org/x/sys/windows/registry" - - "github.com/rancher-sandbox/rancher-desktop/src/go/wsl-helper/pkg/dockerproxy/util" -) - -const ( - timeoutSeconds = 10 - npipePrefix = "npipe://" -) - -type HostConnector struct { - UpstreamServerAddress string - VsockListenPort uint32 - PeerHandshakePort uint32 -} - -// ListenAndDial listens for VSOCK connections from -// the peer and dials into the provided TCP address to pipe -// the payload. -func (h *HostConnector) ListenAndDial() error { - vl, err := h.vsockListen() - if err != nil { - return err - } - - for { - conn, err := vl.Accept() - if err != nil { - logrus.Errorf("ListenAndDial accept connection: %v") - continue - } - go h.handleConn(conn) - } -} - -func (h *HostConnector) handleConn(vConn net.Conn) { - var conn net.Conn - var err error - logrus.Debugf("handleConn dialing into upstream: %v", h.UpstreamServerAddress) - if strings.HasPrefix(h.UpstreamServerAddress, npipePrefix) { - conn, err = winio.DialPipe(h.UpstreamServerAddress[len(npipePrefix):], nil) - } else { - conn, err = net.Dial("tcp", h.UpstreamServerAddress) - } - if err != nil { - logrus.Errorf("handleConn failed dialing into %s: %v", h.UpstreamServerAddress, err) - return - } - defer conn.Close() - if err := util.Pipe(vConn, conn); err != nil { - // this can be caused by an upstream named pipe - // when the write is completed, however, the - // connection is closed immediately after write - if errors.Is(err, syscall.ERROR_BROKEN_PIPE) { - return - } - logrus.Errorf("handleConn, stream error: %v", err) - } -} - -func (h *HostConnector) vsockListen() (net.Listener, error) { - vmGuid, err := h.vmGuid() - if err != nil { - return nil, fmt.Errorf("vsockListen, could not determine VM GUID: %v", err) - } - svcPort, err := hvsock.GUIDFromString(winio.VsockServiceID(h.VsockListenPort).String()) - if err != nil { - return nil, fmt.Errorf("vsockListen, could not parse Hyper-v service GUID: %v", err) - } - - addr := hvsock.Addr{ - VMID: vmGuid, - ServiceID: svcPort, - } - - return hvsock.Listen(addr) -} - -// vmGuid retrieves the GUID for a correct hyper-v VM (most likely WSL). -// It performs a handshake with a running peer process in the WSL distro -// to make sure we establish the AF_VSOCK connection with a right VM. -func (h *HostConnector) vmGuid() (hvsock.GUID, error) { - key, err := registry.OpenKey( - registry.LOCAL_MACHINE, - `SOFTWARE\Microsoft\Windows NT\CurrentVersion\HostComputeService\VolatileStore\ComputeSystem`, - registry.ENUMERATE_SUB_KEYS) - if err != nil { - return hvsock.GUIDZero, fmt.Errorf("could not open registry key, is WSL VM running? %v", err) - } - defer key.Close() - - names, err := key.ReadSubKeyNames(0) - if err != nil { - return hvsock.GUIDZero, fmt.Errorf("machine IDs can not be read in registry: %v", err) - } - if len(names) == 0 { - return hvsock.GUIDZero, errors.New("no running WSL VM found") - } - - found := make(chan hvsock.GUID, len(names)) - done := make(chan bool, len(names)) - defer close(done) - - for _, name := range names { - vmGuid, err := hvsock.GUIDFromString(name) - if err != nil { - logrus.Errorf("invalid VM name: [%s], err: %v", name, err) - continue - } - go h.handshake(vmGuid, found, done) - } - return tryFindGuid(found) -} - -// handshake attempts to perform a handshake by verifying the seed with a running -// af_vsock peer in WSL distro, it attempts once per second -func (h *HostConnector) handshake(vmGuid hvsock.GUID, found chan<- hvsock.GUID, done <-chan bool) { - svcPort, err := hvsock.GUIDFromString(winio.VsockServiceID(h.PeerHandshakePort).String()) - if err != nil { - logrus.Errorf("hostHandshake parsing svc port: %v", err) - } - addr := hvsock.Addr{ - VMID: vmGuid, - ServiceID: svcPort, - } - - attemptInterval := time.NewTicker(time.Second * 1) - attempt := 1 - for { - select { - case <-done: - logrus.Infof("attempt to handshake with [%s], goroutine is terminated", vmGuid.String()) - return - case <-attemptInterval.C: - conn, err := hvsock.Dial(addr) - if err != nil { - attempt++ - logrus.Debugf("handshake attempt[%v] to dial into VM, looking for vsock-peer", attempt) - continue - } - seed, err := readSeed(conn) - if err != nil { - logrus.Errorf("hosthandshake attempt to read the seed: %v", err) - } - if err := conn.Close(); err != nil { - logrus.Errorf("hosthandshake closing connection: %v", err) - } - if seed == SeedPhrase { - logrus.Infof("successfully established a handshake with a peer: %s on port: %v", vmGuid.String(), h.PeerHandshakePort) - found <- vmGuid - return - } - logrus.Infof("hosthandshake failed to match the seed phrase with a peer running in: %s", vmGuid.String()) - return - } - } -} - -// tryFindGuid waits on a found channel to receive a GUID until -// deadline of 10s is reached -func tryFindGuid(found chan hvsock.GUID) (hvsock.GUID, error) { - bailOut := time.After(time.Second * timeoutSeconds) - for { - select { - case vmGuid := <-found: - return vmGuid, nil - case <-bailOut: - return hvsock.GUIDZero, errors.New("could not find vsock-peer process on any hyper-v VM(s)") - } - } -} - -func readSeed(conn net.Conn) (string, error) { - seed := make([]byte, len(SeedPhrase)) - if _, err := io.ReadFull(conn, seed); err != nil { - return "", err - } - return string(seed), nil -} diff --git a/src/go/vtunnel/pkg/vmsock/constants.go b/src/go/vtunnel/pkg/vmsock/constants.go deleted file mode 100644 index 60ffe27887a..00000000000 --- a/src/go/vtunnel/pkg/vmsock/constants.go +++ /dev/null @@ -1,16 +0,0 @@ -/* -Copyright © 2022 SUSE LLC -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package vmsock - -const SeedPhrase = "github.com/rancher-sandbox/rancher-desktop-vtunnel" diff --git a/src/go/vtunnel/test/e2e/connectivity_test.go b/src/go/vtunnel/test/e2e/connectivity_test.go deleted file mode 100644 index bc3ab47232f..00000000000 --- a/src/go/vtunnel/test/e2e/connectivity_test.go +++ /dev/null @@ -1,411 +0,0 @@ -//go:build windows - -/* -Copyright © 2022 SUSE LLC - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package e2e - -import ( - "bytes" - "errors" - "fmt" - "io" - "net/http" - "net/http/httptest" - "os" - "os/exec" - "path/filepath" - "strings" - "testing" - "time" - - "github.com/Microsoft/go-winio" - "github.com/google/uuid" - "github.com/sirupsen/logrus" - "github.com/stretchr/testify/require" - "gopkg.in/yaml.v3" - - "github.com/rancher-sandbox/rancher-desktop/src/go/vtunnel/pkg/config" -) - -var ( - tarballVersion = "0.27" - wslTarballName = fmt.Sprintf("distro-%s.tar", tarballVersion) - wslTarballURL = fmt.Sprintf( - "https://github.com/rancher-sandbox/rancher-desktop-wsl-distro/releases/download/v%s/%s", - tarballVersion, - wslTarballName) - wslDistroName = "vtunnel-e2e-test" - // TCP connect test ports - handShakePortT = 9091 - handShakePortT2 = 9092 - vSockHostPortT = 8989 - vSockHostPortT2 = 9999 - peerTCPPortT = 3131 - peerTCPPortT2 = 4141 - // Named Pipe connect test ports - handShakePortN = 9093 - handShakePortN2 = 9094 - vSockHostPortN = 8979 - vSockHostPortN2 = 9989 - peerTCPPortN = 3132 - peerTCPPortN2 = 4142 - - configFile = "config.yaml" - tryInterval = time.Second * 2 - nPipeEndpoint = "npipe:////./pipe/vtunnel-e2e" - tmpDir string - configPath string -) - -func TestNamedPipeConnect(t *testing.T) { - id1, id2 := 1, 2 - nPipeFile1 := fmt.Sprintf("%v-%v-%v", nPipeEndpoint, id1, uuid.New()) - go startNPipeEchoServer(t, nPipeFile1) - - nPipeFile2 := fmt.Sprintf("%v-%v-%v", nPipeEndpoint, id2, uuid.New()) - go startNPipeEchoServer(t, nPipeFile2) - - t.Log("Creating a test config.yaml") - - conf := &config.Config{ - Tunnel: []config.Tunnel{ - { - HandshakePort: uint32(handShakePortN), - VsockHostPort: uint32(vSockHostPortN), - PeerAddress: "127.0.0.1", - PeerPort: peerTCPPortN, - UpstreamServerAddress: nPipeFile1, - }, - { - HandshakePort: uint32(handShakePortN2), - VsockHostPort: uint32(vSockHostPortN2), - PeerAddress: "127.0.0.1", - PeerPort: peerTCPPortN2, - UpstreamServerAddress: nPipeFile2, - }, - }, - } - - data, err := yaml.Marshal(conf) - require.NoError(t, err, "Failed marshaling config into yaml") - - err = os.WriteFile(configPath, data, 0644) - require.NoError(t, err, "Failed writing config.yaml file") - - t.Logf("Starting vtunnel peer process in wsl [%v]", wslDistroName) - peerCmd := cmdExec( - tmpDir, - "wsl", "--user", "root", - "--distribution", wslDistroName, - "--exec", "./main", "peer", - "--config-path", configFile) - - err = peerCmd.Start() - require.NoError(t, err, "Starting vtunnel peer process failed") - - defer func() { - _ = peerCmd.Process.Kill() - }() - - t.Log("Starting vtunnel host process") - vtunHostPath := filepath.Join(tmpDir, "main.exe") - hostCmd := cmdExec( - tmpDir, - vtunHostPath, "host", - "--config-path", configFile) - - err = hostCmd.Start() - require.NoError(t, err, "Starting vtunnel host process failed") - - defer func() { - _ = hostCmd.Process.Kill() - }() - - t.Log("Confirming vtunnel peer process is up") - peerCmdTimeout := time.Second * 10 - - err = confirm(func() bool { - p, err := os.FindProcess(peerCmd.Process.Pid) - if err != nil { - t.Logf("looking for vtunnel peer process PID: %v", err) - return false - } - return p.Pid == peerCmd.Process.Pid - }, tryInterval, peerCmdTimeout) - - require.NoError(t, err, "failed to confirm vtunnel peer process is running") - - t.Logf("Sending a request to npipe [%v] via vtunnel peer process in [%v] over: 127.0.0.1:%v", nPipeFile1, wslDistroName, peerTCPPortN) - peerAddr1 := fmt.Sprintf("127.0.0.1:%v", peerTCPPortN) - out, err := cmdRunWithOutput("wsl", "--distribution", wslDistroName, "--exec", "curl", "--http0.9", "--verbose", "--fail-with-body", peerAddr1) - require.NoError(t, err, "failed sending request to vtunnel peer process") - require.Contains(t, out, fmt.Sprintf("vtunnel named pipe %v called.", nPipeFile1)) - - t.Logf("Sending a request to npipe [%v] via vtunnel peer process in [%v] over: 127.0.0.1:%v", nPipeFile2, wslDistroName, peerTCPPortN2) - peerAddr2 := fmt.Sprintf("127.0.0.1:%v", peerTCPPortN2) - out, err = cmdRunWithOutput("wsl", "--distribution", wslDistroName, "--exec", "curl", "--http0.9", "--verbose", "--fail-with-body", peerAddr2) - require.NoError(t, err, "failed sending request to vtunnel peer process") - require.Contains(t, out, fmt.Sprintf("vtunnel named pipe %v called.", nPipeFile2)) -} - -func TestTCPConnect(t *testing.T) { - ts := startHTTPServer(1) - testHTTPServerAddr := strings.TrimPrefix(ts.URL, "http://") - - ts2 := startHTTPServer(2) - testHTTPServerAddr2 := strings.TrimPrefix(ts2.URL, "http://") - - defer ts.Close() - t.Logf("Started a test HTTP server in the host machine listening on [%v]", testHTTPServerAddr) - - t.Log("Creating a test config.yaml") - conf := &config.Config{ - Tunnel: []config.Tunnel{ - { - HandshakePort: uint32(handShakePortT), - VsockHostPort: uint32(vSockHostPortT), - PeerAddress: "127.0.0.1", - PeerPort: peerTCPPortT, - UpstreamServerAddress: testHTTPServerAddr, - }, - { - HandshakePort: uint32(handShakePortT2), - VsockHostPort: uint32(vSockHostPortT2), - PeerAddress: "127.0.0.1", - PeerPort: peerTCPPortT2, - UpstreamServerAddress: testHTTPServerAddr2, - }, - }, - } - - data, err := yaml.Marshal(conf) - require.NoError(t, err, "Failed marshaling config into yaml") - - err = os.WriteFile(configPath, data, 0644) - require.NoError(t, err, "Failed writing config.yaml file") - - t.Logf("Starting vtunnel peer process in wsl [%v]", wslDistroName) - peerCmd := cmdExec( - tmpDir, - "wsl", "--user", "root", - "--distribution", wslDistroName, - "--exec", "./main", "peer", - "--config-path", configFile) - - err = peerCmd.Start() - require.NoError(t, err, "Starting vtunnel peer process failed") - - defer func() { - _ = peerCmd.Process.Kill() - }() - - t.Log("Starting vtunnel host process") - vtunHostPath := filepath.Join(tmpDir, "main.exe") - hostCmd := cmdExec( - tmpDir, - vtunHostPath, "host", - "--config-path", configFile) - - err = hostCmd.Start() - require.NoError(t, err, "Starting vtunnel host process failed") - defer func() { - _ = hostCmd.Process.Kill() - }() - - t.Log("Confirming vtunnel peer process is up") - peerCmdTimeout := time.Second * 10 - err = confirm(func() bool { - p, err := os.FindProcess(peerCmd.Process.Pid) - if err != nil { - t.Logf("looking for vtunnel peer process PID: %v", err) - return false - } - return p.Pid == peerCmd.Process.Pid - }, tryInterval, peerCmdTimeout) - require.NoError(t, err, "failed to confirm vtunnel peer process is running") - - t.Logf("Sending a request to vtunnel peer process in [%v] over: 127.0.0.1:%v", wslDistroName, peerTCPPortT) - peerAddr1 := fmt.Sprintf("127.0.0.1:%v", peerTCPPortT) - out, err := cmdRunWithOutput("wsl", "--distribution", wslDistroName, "--exec", "curl", "--verbose", "--fail-with-body", peerAddr1) - require.NoError(t, err, "Failed sending request to vtunnel peer process") - require.Contains(t, out, "vtunnel host 1 called.") - - t.Logf("Sending a request to vtunnel peer process in [%v] over: 127.0.0.1:%v", wslDistroName, peerTCPPortT2) - peerAddr2 := fmt.Sprintf("127.0.0.1:%v", peerTCPPortT2) - out, err = cmdRunWithOutput("wsl", "--distribution", wslDistroName, "--exec", "curl", "--verbose", "--fail-with-body", peerAddr2) - require.NoError(t, err, "Failed sending request to vtunnel peer process") - require.Contains(t, out, "vtunnel host 2 called.") -} - -func TestMain(m *testing.M) { - var err error - tmpDir, err = os.MkdirTemp("", "vtunnel-e2e-test") - requireNoErrorf(err, "Failed to create a temp directory") - defer os.RemoveAll(tmpDir) - - configPath = filepath.Join(tmpDir, configFile) - - logrus.Info("Building vtunnel host binary") - err = buildBinaries("../../main.go", "windows", tmpDir) - requireNoErrorf(err, "Failed building vtunnel.exe") - - logrus.Info("Building vtunnel peer binary") - err = buildBinaries("../../main.go", "linux", tmpDir) - requireNoErrorf(err, "Failed building vtunnel") - - tarballPath := filepath.Join(os.TempDir(), wslTarballName) - _, err = os.Stat(tarballPath) - if err != nil { - if errors.Is(err, os.ErrNotExist) { - err = downloadFile(tarballPath, wslTarballURL) - requireNoErrorf(err, "Failed to download wsl distro tarball %v", wslTarballName) - } - requireNoErrorf(err, "Failed to retrieve file info for %v", tarballPath) - } - - logrus.Infof("Creating %v wsl distro", wslDistroName) - // wsl --import --version 2 - err = cmdExec( - tmpDir, - "wsl", - "--import", - wslDistroName, - ".", - tarballPath, - "--version", - "2").Run() - requireNoErrorf(err, "Failed to install distro %v", wslDistroName) - - // It takes a long time to start a new distro, - // 20 sec is a long time but that's actually how long - // it takes to start a distro without any flakiness - timeout := time.Second * 20 - err = confirm(func() bool { - // Run `wslpath` to see if the distribution is registered; this avoids - // parsing the output of `wsl --list` to avoid having to handle UTF-16. - out, err := cmdRunWithOutput("wsl", "--distribution", wslDistroName, "--exec", "/bin/wslpath", ".") - if err != nil { - return false - } - // We expect `wslpath` to output a single dot for the given command. - return strings.TrimSpace(out) == "." - }, tryInterval, timeout) - requireNoErrorf(err, "Failed to check if %v wsl distro is running", wslDistroName) - - // run test - code := m.Run() - - logrus.Infof("Deleting %v wsl distro", wslDistroName) - err = cmdExec("", "wsl", "--unregister", wslDistroName).Run() - requireNoErrorf(err, "Failed to unregister distro %v", wslDistroName) - - os.Exit(code) -} - -func startNPipeEchoServer(t *testing.T, uri string) { - t.Logf("starting a named pipe server listening on: %v", uri) - l, err := winio.ListenPipe(uri[len("npipe://"):], nil) - require.NoError(t, err, "Failed to listen on named pipe: %v", nPipeEndpoint) - for { - c, err := l.Accept() - if err != nil { - require.NoError(t, err, "accepting incoming named pipe connection: %w") - } - _, err = c.Write([]byte(fmt.Sprintf("vtunnel named pipe %v called.", uri))) - require.NoError(t, err, "Failed to write to named pipe: %v", nPipeEndpoint) - // allow a bit of time before closing the connection immediately - // so downstream can completed conn exchange - time.Sleep(time.Second * 2) - c.Close() - } -} - -func startHTTPServer(id int) *httptest.Server { - return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - fmt.Fprintf(w, "vtunnel host %v called.", id) - })) -} - -func confirm(command func() bool, interval, timeout time.Duration) error { - tick := time.NewTicker(interval) - terminate := time.After(timeout) - - for { - select { - case <-tick.C: - if command() { - return nil - } - case <-terminate: - return fmt.Errorf("Failed to run within %v", timeout) - } - } -} - -func buildBinaries(path, goos, tmpDir string) error { - buildCmd := exec.Command("go", "build", "-o", tmpDir, path) - buildCmd.Env = append(os.Environ(), fmt.Sprintf("GOOS=%s", goos)) - buildCmd.Stdout = os.Stdout - buildCmd.Stderr = os.Stderr - - return buildCmd.Run() -} - -func cmdRunWithOutput(command string, args ...string) (string, error) { - var outBuf, errBuf bytes.Buffer - cmd := exec.Command(command, args...) - cmd.Stdout = &outBuf - cmd.Stderr = &errBuf - err := cmd.Run() - if err != nil { - return errBuf.String(), err - } - return outBuf.String(), nil -} - -func cmdExec(execDir, command string, args ...string) *exec.Cmd { - cmd := exec.Command(command, args...) - if execDir != "" { - cmd.Dir = execDir - } - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - return cmd -} - -func downloadFile(path, url string) error { - logrus.Infof("Dowloading %v wsl distro tarball", wslTarballName) - resp, err := http.Get(url) // nolint:gosec // wsl-distro release URL - if err != nil { - return err - } - defer resp.Body.Close() - - out, err := os.Create(path) - if err != nil { - return err - } - defer out.Close() - if _, err := io.Copy(out, resp.Body); err != nil { - return err - } - return nil -} - -func requireNoErrorf(err error, format string, args ...interface{}) { - if err != nil { - logrus.Fatalf(format, args...) - } -} From e8f321a840f7cb7698ce76d61059843a887e1fe7 Mon Sep 17 00:00:00 2001 From: Nino Kodabande Date: Mon, 19 Aug 2024 10:18:37 -0700 Subject: [PATCH 2/7] Remove vtunnel from dependabot Signed-off-by: Nino Kodabande --- .github/dependabot.yml | 8 -------- 1 file changed, 8 deletions(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 9b47ffd235a..d2e3932657e 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -106,14 +106,6 @@ updates: labels: ["component/dependencies"] reviewers: [ "jandubois" ] - - package-ecosystem: "gomod" - directory: "/src/go/vtunnel" - schedule: - interval: "daily" - open-pull-requests-limit: 1 - labels: ["component/dependencies"] - reviewers: [ "Nino-K" ] - - package-ecosystem: "gomod" directory: "/src/go/wsl-helper" schedule: From 199284fdb1b9de946eb8e262cf92737bc97fd730 Mon Sep 17 00:00:00 2001 From: Nino Kodabande Date: Mon, 19 Aug 2024 10:21:09 -0700 Subject: [PATCH 3/7] Remove vtunnel.exe out of build signing config Signed-off-by: Nino Kodabande --- build/signing-config-win.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/build/signing-config-win.yaml b/build/signing-config-win.yaml index 694667f3c25..9b888ca9e0a 100644 --- a/build/signing-config-win.yaml +++ b/build/signing-config-win.yaml @@ -30,5 +30,4 @@ resources/resources/win32/internal: - host-switch.exe - privileged-service.exe - steve.exe -- vtunnel.exe - wsl-helper.exe From 43f287c2f9424ccd2ea6afb25ecf2ef7b7c44493 Mon Sep 17 00:00:00 2001 From: Nino Kodabande Date: Mon, 19 Aug 2024 10:48:33 -0700 Subject: [PATCH 4/7] remove vtunnel out of go.work Signed-off-by: Nino Kodabande --- go.work | 1 - 1 file changed, 1 deletion(-) diff --git a/go.work b/go.work index 47b9096eedd..26c068eb792 100644 --- a/go.work +++ b/go.work @@ -13,6 +13,5 @@ use ( ./src/go/networking ./src/go/privileged-service ./src/go/rdctl - ./src/go/vtunnel ./src/go/wsl-helper ) From c416f1fb73d497f012ef7db0b46637ea156a1827 Mon Sep 17 00:00:00 2001 From: Nino Kodabande Date: Mon, 19 Aug 2024 10:50:58 -0700 Subject: [PATCH 5/7] Remove all vtunnel references out of the src Signed-off-by: Nino Kodabande --- e2e/credentials-server.e2e.spec.ts | 32 +---- .../scripts/rancher-desktop-guestagent.initd | 1 - .../assets/scripts/service-vtunnel-peer.initd | 16 --- pkg/rancher-desktop/backend/wsl.ts | 59 +--------- .../main/commandServer/httpCommandServer.ts | 15 --- .../httpCredentialHelperServer.ts | 12 -- .../main/networking/vtunnel.ts | 111 ------------------ scripts/postinstall.ts | 2 - 8 files changed, 2 insertions(+), 246 deletions(-) delete mode 100644 pkg/rancher-desktop/assets/scripts/service-vtunnel-peer.initd delete mode 100644 pkg/rancher-desktop/main/networking/vtunnel.ts diff --git a/e2e/credentials-server.e2e.spec.ts b/e2e/credentials-server.e2e.spec.ts index 06761abd253..fe7e5cef3b1 100644 --- a/e2e/credentials-server.e2e.spec.ts +++ b/e2e/credentials-server.e2e.spec.ts @@ -31,11 +31,8 @@ import { expect, test } from '@playwright/test'; import fetch from 'node-fetch'; import { NavPage } from './pages/nav-page'; -import { - getFullPathForTool, retry, startSlowerDesktop, teardown, tool, -} from './utils/TestUtils'; +import { getFullPathForTool, startSlowerDesktop, teardown, tool } from './utils/TestUtils'; -import { defaultSettings } from '@pkg/config/settings'; import { ServerState } from '@pkg/main/commandServer/httpCommandServer'; import { spawnFile } from '@pkg/utils/childProcess'; import paths from '@pkg/utils/paths'; @@ -109,7 +106,6 @@ function haveCredentialServerHelper(): boolean { const describeWithCreds = haveCredentialServerHelper() ? test.describe : test.describe.skip; const describeCredHelpers = credStore === 'none' ? test.describe.skip : test.describe; -const testWin32 = os.platform() === 'win32' ? test : test.skip; const testUnix = os.platform() === 'win32' ? test.skip : test; describeWithCreds('Credentials server', () => { @@ -334,32 +330,6 @@ describeWithCreds('Credentials server', () => { // behavior is all over the place. Fails with osxkeychain, succeeds with wincred. }); - // On Windows, we need to wait for the vtunnel proxy to be established. - testWin32('ensure vtunnel proxy is ready', () => { - const isTunnel = defaultSettings.experimental.virtualMachine.networkingTunnel; - - test.skip(isTunnel, 'vtunnel process is not needed when network tunnel is enabled'); - const args = ['--distribution', 'rancher-desktop', '--exec', - 'curl', '--verbose', '--user', `${ serverState.user }:${ serverState.password }`, - 'http://localhost:3030/']; - - return retry(async() => { - try { - await spawnFile('wsl.exe', args); - } catch (ex: any) { - const curlExitReason = { - 7: 'Failed to connect to host', - 56: 'Failure in receiving network data', - }; - - if (!curlExitReason) { - throw ex; - } - throw new Error(`curl failed with ${ ex } (${ curlExitReason })`); - } - }); - }); - test('it should complain about an unrecognized command', async() => { const badCommand = 'gazornaanplatt'; const stdout = await doRequest(badCommand); diff --git a/pkg/rancher-desktop/assets/scripts/rancher-desktop-guestagent.initd b/pkg/rancher-desktop/assets/scripts/rancher-desktop-guestagent.initd index fcf7ced3fc7..a437867a149 100644 --- a/pkg/rancher-desktop/assets/scripts/rancher-desktop-guestagent.initd +++ b/pkg/rancher-desktop/assets/scripts/rancher-desktop-guestagent.initd @@ -2,7 +2,6 @@ # shellcheck shell=ksh depend() { - after vtunnel-peer after network-online } diff --git a/pkg/rancher-desktop/assets/scripts/service-vtunnel-peer.initd b/pkg/rancher-desktop/assets/scripts/service-vtunnel-peer.initd deleted file mode 100644 index 8bafebeff79..00000000000 --- a/pkg/rancher-desktop/assets/scripts/service-vtunnel-peer.initd +++ /dev/null @@ -1,16 +0,0 @@ -#!/sbin/openrc-run - -# This script is used to manage vtunnel's peer process via OpenRC. - -# shellcheck shell=ksh - -name="vtunnel-peer" -description="Rancher Desktop peer process for vtunnel" - -supervisor=supervise-daemon -command="'${VTUNNEL_PEER_BINARY:-/usr/local/bin/vtunnel}'" -command_args="peer --config-path '${CONFIG_PATH}'" - -VTUNNEL_PEER_LOGFILE="${VTUNNEL_PEER_LOGFILE:-${LOG_DIR:-/var/log}/${RC_SVCNAME}.log}" -output_log="'${VTUNNEL_PEER_LOGFILE}'" -error_log="'${VTUNNEL_PEER_LOGFILE}'" diff --git a/pkg/rancher-desktop/backend/wsl.ts b/pkg/rancher-desktop/backend/wsl.ts index afe1b040c47..1c47bd51064 100644 --- a/pkg/rancher-desktop/backend/wsl.ts +++ b/pkg/rancher-desktop/backend/wsl.ts @@ -37,7 +37,6 @@ import SERVICE_GUEST_AGENT_INIT from '@pkg/assets/scripts/rancher-desktop-guesta import SERVICE_SCRIPT_CRI_DOCKERD from '@pkg/assets/scripts/service-cri-dockerd.initd'; import SERVICE_SCRIPT_HOST_RESOLVER from '@pkg/assets/scripts/service-host-resolver.initd'; import SERVICE_SCRIPT_K3S from '@pkg/assets/scripts/service-k3s.initd'; -import SERVICE_VTUNNEL_PEER from '@pkg/assets/scripts/service-vtunnel-peer.initd'; import SERVICE_SCRIPT_DOCKERD from '@pkg/assets/scripts/service-wsl-dockerd.initd'; import SCRIPT_DATA_WSL_CONF from '@pkg/assets/scripts/wsl-data.conf'; import WSL_EXEC from '@pkg/assets/scripts/wsl-exec'; @@ -46,7 +45,6 @@ import WSL_INIT_RD_NETWORKING_SCRIPT from '@pkg/assets/scripts/wsl-init-rd-netwo import { ContainerEngine } from '@pkg/config/settings'; import { getServerCredentialsPath, ServerState } from '@pkg/main/credentialServer/httpCredentialHelperServer'; import mainEvents from '@pkg/main/mainEvents'; -import { getVtunnelInstance, getVtunnelConfigPath } from '@pkg/main/networking/vtunnel'; import BackgroundProcess from '@pkg/utils/backgroundProcess'; import * as childProcess from '@pkg/utils/childProcess'; import clone from '@pkg/utils/clone'; @@ -147,18 +145,6 @@ export default class WSLBackend extends events.EventEmitter implements VMBackend shouldRun: () => Promise.resolve([State.STARTING, State.STARTED, State.DISABLED].includes(this.state)), }); - if (!this.cfg?.experimental.virtualMachine.networkingTunnel) { - // Register a new tunnel for RD Guest Agent - this.vtun.addTunnel({ - name: 'Rancher Desktop Privileged Service', - handshakePort: 17382, - vsockHostPort: 17381, - peerAddress: '127.0.0.1', - peerPort: 3040, - upstreamServerAddress: 'npipe:////./pipe/rancher_desktop/privileged_service', - }); - } - this.kubeBackend = kubeFactory(this); } @@ -244,9 +230,6 @@ export default class WSLBackend extends events.EventEmitter implements VMBackend this.#noModalDialogs = value; } - /** Vtunnel Proxy management singleton. */ - protected vtun = getVtunnelInstance(); - /** * The current operation underway; used to avoid responding to state changes * when we're in the process of doing a different one. @@ -807,43 +790,18 @@ export default class WSLBackend extends events.EventEmitter implements VMBackend const credsPath = getServerCredentialsPath(); try { - const vtunnelPeerServerAddr = '127.0.0.1:3030'; const credentialServerAddr = '192.168.127.254:6109'; - // When networkTunnel is enabled we talk directly to the host which is assigned - // with 192.168.127.254 static address. Otherwise, we talk to the vtunnel peer - // which is listening in the WSL VM on 127.0.0.1:3030. - const credForwarderURL = this.cfg?.experimental.virtualMachine.networkingTunnel ? credentialServerAddr : vtunnelPeerServerAddr; const stateInfo: ServerState = JSON.parse(await fs.promises.readFile(credsPath, { encoding: 'utf-8' })); const escapedPassword = stateInfo.password.replace(/\\/g, '\\\\') .replace(/'/g, "\\'"); // leading `$` is needed to escape single-quotes, as : $'abc\'xyz' const leadingDollarSign = stateInfo.password.includes("'") ? '$' : ''; const fileContents = `CREDFWD_AUTH=${ leadingDollarSign }'${ stateInfo.user }:${ escapedPassword }' - CREDFWD_URL='http://${ credForwarderURL }' + CREDFWD_URL='http://${ credentialServerAddr }' `; const defaultConfig = { credsStore: 'rancher-desktop' }; let existingConfig: Record; - const OldCredHelperService = '/etc/init.d/credhelper-vtunnel-peer'; - const OldCredHelperConfd = '/etc/conf.d/credhelper-vtunnel-peer'; - - await this.handleUpgrade([OldCredHelperService, OldCredHelperConfd]); - - await this.writeFile('/etc/init.d/vtunnel-peer', SERVICE_VTUNNEL_PEER, 0o755); - await this.writeConf('vtunnel-peer', { - VTUNNEL_PEER_BINARY: await this.getVtunnelPeerPath(), - LOG_DIR: await this.wslify(paths.logs), - CONFIG_PATH: await this.wslify(getVtunnelConfigPath()), - }); - await this.execCommand('/sbin/rc-update', 'add', 'vtunnel-peer', 'default'); - - // Stop the service if RD Networking is enabled. We need to add it - // first as rc-service del … fails if the service is not enabled, - // but rc-service add … handles an already-enabled service fine. - if (this.cfg?.experimental.virtualMachine.networkingTunnel) { - await this.execCommand('/sbin/rc-update', 'del', 'vtunnel-peer', 'default'); - } - await this.execCommand('mkdir', '-p', ETC_RANCHER_DESKTOP_DIR); await this.writeFile(CREDENTIAL_FORWARDER_SETTINGS_PATH, fileContents, 0o644); await this.writeFile(DOCKER_CREDENTIAL_PATH, DOCKER_CREDENTIAL_SCRIPT, 0o755); @@ -1333,10 +1291,6 @@ export default class WSLBackend extends events.EventEmitter implements VMBackend this.privilegedServiceEnabled = rdNetworking ? false : await this.invokePrivilegedService('start'); - if (!rdNetworking) { - await this.vtun.start(); - } - if (config.kubernetes.enabled) { prepActions.push((async() => { [kubernetesVersion] = await this.kubeBackend.download(config); @@ -1731,7 +1685,6 @@ export default class WSLBackend extends events.EventEmitter implements VMBackend } } if (!this.cfg?.experimental.virtualMachine.networkingTunnel) { - await this.vtun.stop(); await this.resolverHostProcess.stop(); await this.invokePrivilegedService('stop'); } @@ -1821,16 +1774,6 @@ export default class WSLBackend extends events.EventEmitter implements VMBackend return this.wslify(executable('wsl-helper-linux'), distro); } - /** - * Return the Linux path to the vtunnel peer executable. - */ - protected getVtunnelPeerPath(): Promise { - // We need to get the Linux path to our helper executable; it is easier to - // just get WSL to do the transformation for us. - - return this.wslify(path.join(paths.resources, 'linux', 'internal', 'vtunnel')); - } - async getFailureDetails(exception: any): Promise { const loglines = (await fs.promises.readFile(console.path, 'utf-8')).split('\n').slice(-10); diff --git a/pkg/rancher-desktop/main/commandServer/httpCommandServer.ts b/pkg/rancher-desktop/main/commandServer/httpCommandServer.ts index aa1f49f8efc..81962327b90 100644 --- a/pkg/rancher-desktop/main/commandServer/httpCommandServer.ts +++ b/pkg/rancher-desktop/main/commandServer/httpCommandServer.ts @@ -12,7 +12,6 @@ import type { TransientSettings } from '@pkg/config/transientSettings'; import type { DiagnosticsResultCollection } from '@pkg/main/diagnostics/diagnostics'; import { ExtensionMetadata } from '@pkg/main/extensions/types'; import mainEvents from '@pkg/main/mainEvents'; -import { getVtunnelInstance } from '@pkg/main/networking/vtunnel'; import * as serverHelper from '@pkg/main/serverHelper'; import { Snapshot } from '@pkg/main/snapshots/types'; import Logging from '@pkg/utils/logging'; @@ -47,7 +46,6 @@ const SERVER_FILE_BASENAME = 'rd-engine.json'; const MAX_REQUEST_BODY_LENGTH = 4194304; // 4MiB export class HttpCommandServer { - protected vtun = getVtunnelInstance(); protected server = http.createServer(); protected app = express(); protected readonly externalState: ServerState = { @@ -117,19 +115,6 @@ export class HttpCommandServer { async init() { const localHost = '127.0.0.1'; - - // The peerPort and upstreamServerAddress port will need to match - // this is crucial if we ever pick dynamic ports for upstreamServerAddress - if (process.platform === 'win32') { - this.vtun.addTunnel({ - name: 'CLI Server', - handshakePort: 17372, - vsockHostPort: 17371, - peerAddress: localHost, - peerPort: SERVER_PORT, - upstreamServerAddress: `${ localHost }:${ SERVER_PORT }`, - }); - } const statePath = path.join(paths.appHome, SERVER_FILE_BASENAME); await fs.promises.mkdir(paths.appHome, { recursive: true }); diff --git a/pkg/rancher-desktop/main/credentialServer/httpCredentialHelperServer.ts b/pkg/rancher-desktop/main/credentialServer/httpCredentialHelperServer.ts index 5a6a76ae344..a63e67cf27e 100644 --- a/pkg/rancher-desktop/main/credentialServer/httpCredentialHelperServer.ts +++ b/pkg/rancher-desktop/main/credentialServer/httpCredentialHelperServer.ts @@ -5,7 +5,6 @@ import { URL } from 'url'; import runCredentialHelper from './credentialUtils'; -import { getVtunnelInstance } from '@pkg/main/networking/vtunnel'; import * as serverHelper from '@pkg/main/serverHelper'; import Logging from '@pkg/utils/logging'; import paths from '@pkg/utils/paths'; @@ -54,7 +53,6 @@ function ensureEndsWithNewline(s: string) { } export class HttpCredentialHelperServer { - protected vtun = getVtunnelInstance(); protected server = http.createServer(); protected password = serverHelper.randomStr(); protected stateInfo: ServerState = { @@ -67,16 +65,6 @@ export class HttpCredentialHelperServer { protected listenAddr = '127.0.0.1'; async init() { - if (process.platform === 'win32') { - this.vtun.addTunnel({ - name: 'Credential Server', - handshakePort: 17362, - vsockHostPort: 17361, - peerAddress: this.listenAddr, - peerPort: 3030, - upstreamServerAddress: `${ this.listenAddr }:${ SERVER_PORT }`, - }); - } const statePath = getServerCredentialsPath(); await fs.promises.writeFile(statePath, diff --git a/pkg/rancher-desktop/main/networking/vtunnel.ts b/pkg/rancher-desktop/main/networking/vtunnel.ts deleted file mode 100644 index c8fb0d8ce04..00000000000 --- a/pkg/rancher-desktop/main/networking/vtunnel.ts +++ /dev/null @@ -1,111 +0,0 @@ -// Maintains configuration for all the processes that go over AF_VSOCK Vtunnel - -import fs from 'fs'; -import path from 'path'; - -import yaml from 'yaml'; - -import BackgroundProcess from '@pkg/utils/backgroundProcess'; -import * as childProcess from '@pkg/utils/childProcess'; -import Logging from '@pkg/utils/logging'; -import paths from '@pkg/utils/paths'; - -const vtunnelConfig = 'vtunnel-config.yaml'; - -/** - * Configuration Object for Vtunnel Proxy. - */ -export interface VtunnelConfig { - name: string; - handshakePort: number; - vsockHostPort: number; - peerAddress: string; - peerPort: number; - upstreamServerAddress: string; -} - -let instance: VTunnel | undefined; - -/** - * Vtunnel is a management and integration class for Vtunnel Proxy of Rancher Desktop. - */ -class VTunnel { - private _vtunnelConfig: VtunnelConfig[] = []; - private vsockProxy = new BackgroundProcess('Vtunnel Host Process', { - spawn: async() => { - const executable = path.join(paths.resources, 'win32', 'internal', 'vtunnel.exe'); - const stream = await Logging['vtunnel-host'].fdStream; - - return childProcess.spawn(executable, - ['host', - '--config-path', getVtunnelConfigPath()], { - stdio: ['ignore', stream, stream], - windowsHide: true, - }); - }, - }); - - private async generateConfig() { - const conf = { - tunnel: this._vtunnelConfig.map(c => ({ - name: c.name, - 'handshake-port': c.handshakePort, - 'vsock-host-port': c.vsockHostPort, - 'peer-address': c.peerAddress, - 'peer-port': c.peerPort, - 'upstream-server-address': c.upstreamServerAddress, - })), - }; - - const configYaml = yaml.stringify(conf); - - await fs.promises.writeFile(getVtunnelConfigPath(), configYaml, 'utf8'); - } - - /** - * addTunnel adds a new configuration to an existing list of configs. - */ - addTunnel(config: VtunnelConfig) { - this._vtunnelConfig.push(config); - } - - /** - * start generates the final configuration yaml file and starts the - * Vtunnel Host process. - */ - async start() { - try { - await this.generateConfig(); - } catch (error) { - console.error(`Failed to generate vtunnel configuration: ${ error }`); - - return; - } - this.vsockProxy.start(); - } - - /** - * stops the vtunnel host process. - */ - async stop() { - await this.vsockProxy.stop(); - } -} - -/** - * - * @returns an instance of Vtunnel singleton class - */ -export function getVtunnelInstance(): VTunnel { - instance ??= new VTunnel(); - - return instance; -} - -/** - * - * @returns a path to vtunnel configuration - */ -export function getVtunnelConfigPath(): string { - return path.join(paths.config, vtunnelConfig); -} diff --git a/scripts/postinstall.ts b/scripts/postinstall.ts index 380b5500bfa..8a814ed0f6f 100644 --- a/scripts/postinstall.ts +++ b/scripts/postinstall.ts @@ -50,7 +50,6 @@ const windowsDependencies = [ new HostResolverHost(), new Wix(), new HostSwitch(), - new goUtils.GoDependency('vtunnel', 'internal'), new goUtils.GoDependency('privileged-service', 'internal'), new goUtils.WSLHelper(), new goUtils.NerdctlStub(), @@ -60,7 +59,6 @@ const windowsDependencies = [ const wslDependencies = [ new HostResolverPeer(), new Moproxy(), - new goUtils.GoDependency('vtunnel', 'internal'), new goUtils.RDCtl(), new goUtils.GoDependency('guestagent', 'staging'), new goUtils.WSLHelper(), From 82f098cf4e1253ca9bb4b1360d085bdf88c0ed12 Mon Sep 17 00:00:00 2001 From: Nino Kodabande Date: Mon, 19 Aug 2024 14:07:10 -0700 Subject: [PATCH 6/7] Fix spell checker Signed-off-by: Nino Kodabande --- .github/actions/spelling/expect.txt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/actions/spelling/expect.txt b/.github/actions/spelling/expect.txt index a71b77097f4..910ad0b5d3b 100644 --- a/.github/actions/spelling/expect.txt +++ b/.github/actions/spelling/expect.txt @@ -146,7 +146,7 @@ corepack coreutils crds credfwd -credhelper +CREDHELPER cri crond crt @@ -204,7 +204,6 @@ doclink dompurify donotuse dotfile -Dowloading dport dri DSL From f78888db7253c8f141216763efb0dfa326a5e2bd Mon Sep 17 00:00:00 2001 From: Nino Kodabande Date: Tue, 20 Aug 2024 13:13:14 -0700 Subject: [PATCH 7/7] Remove existing vtunnel rc files Signed-off-by: Nino Kodabande --- .github/actions/spelling/expect.txt | 1 + pkg/rancher-desktop/backend/wsl.ts | 2 ++ 2 files changed, 3 insertions(+) diff --git a/.github/actions/spelling/expect.txt b/.github/actions/spelling/expect.txt index 910ad0b5d3b..c9a6ca35d38 100644 --- a/.github/actions/spelling/expect.txt +++ b/.github/actions/spelling/expect.txt @@ -693,6 +693,7 @@ Runas runbook runc rundir +runlevels RUnlock runtimeclass runtimeclasses diff --git a/pkg/rancher-desktop/backend/wsl.ts b/pkg/rancher-desktop/backend/wsl.ts index 1c47bd51064..e7f7818e165 100644 --- a/pkg/rancher-desktop/backend/wsl.ts +++ b/pkg/rancher-desktop/backend/wsl.ts @@ -1432,6 +1432,8 @@ export default class WSLBackend extends events.EventEmitter implements VMBackend await this.execCommand({ root: true }, 'rm', '-f', obsoleteImageAllowListConf); }), await this.progressTracker.action('Rancher Desktop guest agent', 50, this.installGuestAgent(kubernetesVersion, this.cfg)), + // Remove any residual rc artifacts from previous versions when vtunnel was installed + await this.execCommand({ root: true }, 'rm', '-f', '/etc/init.d/vtunnel-peer', '/etc/runlevels/default/vtunnel-peer'), ]); await this.writeFile('/usr/local/bin/wsl-exec', WSL_EXEC, 0o755);