diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml deleted file mode 100644 index f6bc674..0000000 --- a/.github/workflows/codeql-analysis.yml +++ /dev/null @@ -1,71 +0,0 @@ -# For most projects, this workflow file will not need changing; you simply need -# to commit it to your repository. -# -# You may wish to alter this file to override the set of languages analyzed, -# or to provide custom queries or build logic. -# -# ******** NOTE ******** -# We have attempted to detect the languages in your repository. Please check -# the `language` matrix defined below to confirm you have the correct set of -# supported CodeQL languages. -# -name: "CodeQL" - -on: - workflow_dispatch: - push: - branches: [ main ] - pull_request: - # The branches below must be a subset of the branches above - branches: [ main ] - schedule: - - cron: '22 10 * * 0' - -jobs: - analyze: - name: Analyze - runs-on: ubuntu-latest - permissions: - actions: read - contents: read - security-events: write - - strategy: - fail-fast: false - matrix: - language: [ 'go' ] - # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] - # Learn more about CodeQL language support at https://git.io/codeql-language-support - - steps: - - name: Checkout repository - uses: actions/checkout@v3 - - # Initializes the CodeQL tools for scanning. - - name: Initialize CodeQL - uses: github/codeql-action/init@v2 - with: - languages: ${{ matrix.language }} - # If you wish to specify custom queries, you can do so here or in a config file. - # By default, queries listed here will override any specified in a config file. - # Prefix the list here with "+" to use these queries and those in the config file. - # queries: ./path/to/local/query, your-org/your-repo/queries@main - - # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). - # If this step fails, then you should remove it and run the build manually (see below) - - name: Autobuild - uses: github/codeql-action/autobuild@v2 - - # ℹī¸ Command-line programs to run using the OS shell. - # 📚 https://git.io/JvXDl - - # ✏ī¸ If the Autobuild fails above, remove it and uncomment the following three lines - # and modify them (or add more) to build your code if your project - # uses a compiled language - - #- run: | - # make bootstrap - # make release - - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v2 diff --git a/.github/workflows/distro.yml b/.github/workflows/distro.yml index d434fff..41f794e 100644 --- a/.github/workflows/distro.yml +++ b/.github/workflows/distro.yml @@ -19,7 +19,7 @@ jobs: - name: Build run: | - docker build -t $TAG_NAME -f ./distro/Dockerfile --build-arg REF=$RUN_URL --build-arg VERSION=${GITHUB_REF#refs/tags/} . + docker build -t $TAG_NAME -f ./distro/alpine.dockerfile --build-arg REF=$RUN_URL --build-arg VERSION=${GITHUB_REF#refs/tags/} . - uses: anchore/scan-action@v3 with: diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml deleted file mode 100644 index 1346566..0000000 --- a/.github/workflows/go.yml +++ /dev/null @@ -1,28 +0,0 @@ -name: Go - -on: - workflow_dispatch: - push: - -jobs: - - build: - runs-on: ubuntu-20.04 - steps: - - uses: actions/checkout@v3 - - - name: Set up Go - uses: actions/setup-go@v3 - with: - go-version: 1.18.5 - - - name: Build - run: go build -v ./... - - - name: Test - run: go test -v ./... - - - name: Lint - uses: golangci/golangci-lint-action@v3 - with: - version: latest diff --git a/.gitignore b/.gitignore index 34a4a3f..15fa919 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ wsl-vpnkit.tar.gz +wsl-gvproxy.exe +wsl-vm diff --git a/README.md b/README.md index c3b0ba2..8653723 100644 --- a/README.md +++ b/README.md @@ -1,41 +1,37 @@ # wsl-vpnkit -The `wsl-vpnkit` v0.3 script uses [gvisor-tap-vsock](https://github.com/containers/gvisor-tap-vsock) to provide network connectivity to the WSL 2 VM while connected to VPNs on the Windows host. This requires no settings changes or admin privileges on the Windows host. +The `wsl-vpnkit` v0.4 script uses [gvisor-tap-vsock](https://github.com/containers/gvisor-tap-vsock) to provide network connectivity to the WSL 2 VM while connected to VPNs on the Windows host. This requires no settings changes or admin privileges on the Windows host. -The releases bundle the script together with the binaries in an [Alpine](https://alpinelinux.org/) distro. - -For v0.2, please see the [v0.2.x branch](https://github.com/sakai135/wsl-vpnkit/tree/v0.2.x). +For previous versions, see [v0.3](https://github.com/sakai135/wsl-vpnkit/tree/v0.3.x) and [v0.2](https://github.com/sakai135/wsl-vpnkit/tree/v0.2.x). ## Setup -Download the prebuilt file `wsl-vpnkit.tar.gz` from the [latest release](https://github.com/sakai135/wsl-vpnkit/releases/latest) and import the distro into WSL 2. Running the distro will show a short intro and exit. +Try the following troubleshooting steps from Microsoft first. + +* [WSL has no network connection on my work machine or in an Enterpise environment](https://learn.microsoft.com/en-us/windows/wsl/troubleshooting#wsl-has-no-network-connection-on-my-work-machine-or-in-an-enterpise-environment) +* [WSL has no network connectivity once connected to a VPN](https://learn.microsoft.com/en-us/windows/wsl/troubleshooting#wsl-has-no-network-connectivity-once-connected-to-a-vpn) + +If those steps do not resolve the issue, `wsl-vpnkit` should be able to provide network connectivity. + +### Setup as a distro + +#### Install + +Download the prebuilt file `wsl-vpnkit.tar.gz` from the [latest release](https://github.com/sakai135/wsl-vpnkit/releases/latest) and import the distro into WSL 2. ```pwsh # PowerShell wsl --import wsl-vpnkit --version 2 $env:USERPROFILE\wsl-vpnkit wsl-vpnkit.tar.gz -wsl -d wsl-vpnkit ``` -Start `wsl-vpnkit` from your other WSL 2 distros. Add the command to your `.profile` or `.bashrc` to start `wsl-vpnkit` when you open your WSL terminal. +Run `wsl-vpnkit`. This will run `wsl-vpnkit` in the foreground. ```sh -wsl.exe -d wsl-vpnkit --cd /app service wsl-vpnkit start -``` - -You can also check service status to start service only if needed. - -```sh -wsl.exe -d wsl-vpnkit --cd /app service wsl-vpnkit status >/dev/null || \ -wsl.exe -d wsl-vpnkit --cd /app service wsl-vpnkit start +wsl.exe -d wsl-vpnkit --cd /app wsl-vpnkit ``` -### Notes - -* Ports on the WSL 2 VM are accessible from the Windows host using `localhost`. -* Ports on the Windows host are accessible from WSL 2 using `host.internal`, `192.168.67.2` or [the IP address of the host machine](https://docs.microsoft.com/en-us/windows/wsl/networking#accessing-windows-networking-apps-from-linux-host-ip). - -### Update +#### Update To update, unregister the existing distro and import the new version. @@ -46,7 +42,7 @@ wsl --unregister wsl-vpnkit wsl --import wsl-vpnkit --version 2 $env:USERPROFILE\wsl-vpnkit wsl-vpnkit.tar.gz ``` -### Uninstall +#### Uninstall To uninstall, unregister the distro. @@ -54,84 +50,115 @@ To uninstall, unregister the distro. # PowerShell wsl --unregister wsl-vpnkit -rm -r $env:USERPROFILE\wsl-vpnkit ``` -### Build +### Setup as a standalone script -This will build and import the distro. +The `wsl-vpnkit` script can be used as a normal script in your existing distro. This is an example setup script for Ubuntu. ```sh -git clone https://github.com/sakai135/wsl-vpnkit.git -cd wsl-vpnkit/ -./build.sh -./import.sh -./test.sh +# install dependencies +sudo apt-get install iproute2 iptables iputils-ping dnsutils wget + +# download wsl-vpnkit and unpack +VERSION=v0.4.x +wget https://github.com/sakai135/wsl-vpnkit/releases/download/$VERSION/wsl-vpnkit.tar.gz +tar --strip-components=1 -xf wsl-vpnkit.tar.gz \ + app/wsl-vpnkit \ + app/wsl-gvproxy.exe \ + app/wsl-vm \ + app/wsl-vpnkit.service +rm wsl-vpnkit.tar.gz + +# run the wsl-vpnkit script in the foreground +sudo VMEXEC_PATH=$(pwd)/wsl-vm GVPROXY_PATH=$(pwd)/wsl-gvproxy.exe ./wsl-vpnkit ``` -Optionally you may build with `podman` instead of `docker` (default) by overriding environment variable `DOCKER`: +### Setup systemd + +WSL versions 0.67.6 and later [support systemd](https://learn.microsoft.com/en-us/windows/wsl/wsl-config#systemd-support). Follow the instructions in the link to enable systemd support for your distro. + +Create the service file and enable the service. Now `wsl-vpnkit.service` should start with your distro next time. + ```sh -DOCKER=podman ./build.sh +# wsl-vpnkit setup as a distro +wsl.exe -d wsl-vpnkit --cd /app cat /app/wsl-vpnkit.service | sudo tee /etc/systemd/system/wsl-vpnkit.service + +# copy and edit for wsl-vpnkit setup as a standalone script +sudo cp ./wsl-vpnkit.service /etc/systemd/system/ +sudo nano /etc/systemd/system/wsl-vpnkit.service + +# enable the service +sudo systemctl enable wsl-vpnkit + +# start and check the status of the service +sudo systemctl start wsl-vpnkit +systemctl status wsl-vpnkit ``` -## Using `wsl-vpnkit` as a standalone script +## Build -The `wsl-vpnkit` script can be used as a normal script in your existing distro. This is an example setup script for Ubuntu. ```sh -# download wsl-vpnkit -VERSION=v0.3.x -wget https://github.com/sakai135/wsl-vpnkit/releases/download/$VERSION/wsl-vpnkit.tar.gz -tar --strip-components=1 -xf wsl-vpnkit.tar.gz app/wsl-vpnkit files/wsl-gvproxy.exe files/wsl-vm -rm wsl-vpnkit.tar.gz +# build with alpine image to ./wsl-vpnkit.tar.gz +./build.sh alpine -# place Windows exe -USERPROFILE=$(wslpath "$(powershell.exe -c 'Write-Host -NoNewline $env:USERPROFILE')") -mkdir -p "$USERPROFILE/wsl-vpnkit" -mv wsl-gvproxy.exe "$USERPROFILE/wsl-vpnkit/wsl-gvproxy.exe" +# build with fedora using Podman +DOCKER=podman ./build.sh fedora -# place Linux bin -chmod +x wsl-vm -sudo chown root:root wsl-vm -sudo mv wsl-vm /usr/local/sbin/wsl-vm +# import the built distro from ./wsl-vpnkit.tar.gz +./import.sh -# run the wsl-vpnkit script -chmod +x wsl-vpnkit -sudo ./wsl-vpnkit +# run using the imported distro +wsl.exe -d wsl-vpnkit --cd /app wsl-vpnkit ``` ## Troubleshooting -### Configure VS Code Remote WSL Extension +### Notes -If VS Code takes a long time to open your folder in WSL, [enable the setting "Connect Through Localhost"](https://github.com/microsoft/vscode-docs/blob/main/remote-release-notes/v1_54.md#fix-for-wsl-2-connection-issues-when-behind-a-proxy). +* Ports on the WSL 2 VM are [accessible from the Windows host using `localhost`](https://learn.microsoft.com/en-us/windows/wsl/networking#accessing-linux-networking-apps-from-windows-localhost). +* Ports on the Windows host are accessible from WSL 2 using `host.containers.internal`, `192.168.127.254` or [the IP address of the host machine](https://docs.microsoft.com/en-us/windows/wsl/networking#accessing-windows-networking-apps-from-linux-host-ip). -### Cannot connect to WSL 2 VM IP while connected to VPN +### Error messages from `wsl-vpnkit` -This is due to the VPN blocking connections to the WSL 2 VM network interface. Ports on the WSL 2 VM are accessible from the Windows host using `localhost`. +#### resolv.conf has been modified without setting generateResolvConf -For this and other networking considerations when using WSL 2, see [Accessing network applications with WSL](https://docs.microsoft.com/en-us/windows/wsl/networking). +`wsl-vpnkit` uses `/mnt/wsl/resolv.conf` to get the WSL 2 gateway IP. If modifying `/etc/resolv.conf` to set a custom DNS configuration, set [`generateResolvConf=false` in `wsl.conf`](https://learn.microsoft.com/en-us/windows/wsl/wsl-config#network-settings). -### Run in foreground +#### wsl-gvproxy.exe is not executable due to WSL interop settings or Windows permissions + +`wsl-vpnkit` requires that the WSL 2 distro be able to run Windows executables. This [`interop` setting](https://learn.microsoft.com/en-us/windows/wsl/wsl-config#interop-settings) is enabled by default in WSL 2 and in the `wsl-vpnkit` distro. + +Security configurations on the Windows host may prevent executables from running. You can copy `wsl-gvproxy.exe` to an appropriate location and use the `GVPROXY_PATH` environment variable to specify the location. ```sh -wsl.exe -d wsl-vpnkit --cd /app wsl-vpnkit +wsl.exe -d wsl-vpnkit --cd /app GVPROXY_PATH=/mnt/c/path/wsl-gvproxy.exe wsl-vpnkit ``` +### Configuring proxies and certificates + +`wsl-vpnkit` currently only handles creating a network connection. Proxies and certificates must be configured separately in your distro. + +### Configure VS Code Remote WSL Extension + +If VS Code takes a long time to open your folder in WSL, [enable the setting "Connect Through Localhost"](https://github.com/microsoft/vscode-docs/blob/main/remote-release-notes/v1_54.md#fix-for-wsl-2-connection-issues-when-behind-a-proxy). + ### Try shutting down WSL 2 VM to reset ```pwsh # PowerShell +# shutdown WSL to reset networking state wsl --shutdown + +# kill any straggler wsl-gvproxy processes kill -Name wsl-gvproxy ``` ### Run service with debug -If you set DEBUG variable before calling service you can see more debug information - -Example: ```sh -wsl.exe -d wsl-vpnkit --cd /app DEBUG=1 service wsl-vpnkit restart +# set the DEBUG environment variable +wsl.exe -d wsl-vpnkit --cd /app DEBUG=1 wsl-vpnkit ``` diff --git a/build.sh b/build.sh index 5fbc8e6..cc51087 100755 --- a/build.sh +++ b/build.sh @@ -6,13 +6,14 @@ : "${DOCKER:=docker}" # docker/podman command (default: docker) DUMP=wsl-vpnkit.tar.gz # exported rootfs file TAG_NAME=wslvpnkit # build tag +BASE_DISTRO=$1 # build build_args=() [ -z "${http_proxy}" ] || build_args+=( --build-arg http_proxy="${http_proxy}" ) [ -z "${https_proxy}" ] || build_args+=( --build-arg https_proxy="${https_proxy}" ) [ -z "${no_proxy}" ] || build_args+=( --build-arg no_proxy="${no_proxy}" ) -${DOCKER} build --network host "${build_args[@]}" --tag ${TAG_NAME} --file ./distro/Dockerfile . +${DOCKER} build --network host "${build_args[@]}" --tag ${TAG_NAME} --file ./distro/$BASE_DISTRO.dockerfile . CONTAINER_ID=$(${DOCKER} create ${TAG_NAME}) ${DOCKER} export "${CONTAINER_ID}" | gzip > ${DUMP} ${DOCKER} container rm "${CONTAINER_ID}" diff --git a/cmd/gvproxy/flags.go b/cmd/gvproxy/flags.go deleted file mode 100644 index b81b170..0000000 --- a/cmd/gvproxy/flags.go +++ /dev/null @@ -1,94 +0,0 @@ -package main - -import ( - "flag" - "net" - - "github.com/containers/gvisor-tap-vsock/pkg/types" - "github.com/pkg/errors" -) - -const ( - gatewayMacAddress = "5a:94:ef:e4:0c:dd" - vmMacAddress = "5a:94:ef:e4:0c:ee" -) - -type proxyFlags struct { - debug bool - mtu int - subnet string - gatewayIP string - hostIP string - vmIP string - gatewayMacAddress string - vmMacAddress string -} - -func parseProxyFlags() (*types.Configuration, error) { - f := &proxyFlags{} - - flag.BoolVar(&f.debug, "debug", false, "Print debug info") - flag.IntVar(&f.mtu, "mtu", 1500, "Set the MTU") - - flag.StringVar(&f.subnet, "subnet", "192.168.127.0/24", "Set the subnet") - flag.StringVar(&f.gatewayIP, "gateway-ip", "192.168.127.1", "Set the IP for the gateway") - flag.StringVar(&f.hostIP, "host-ip", "192.168.127.254", "Set the IP for accessing the host from the WSL 2 VM") - flag.StringVar(&f.vmIP, "vm-ip", "192.168.127.2", "Set the IP for the WSL 2 VM") - - flag.Parse() - - if net.ParseIP(f.gatewayIP) == nil { - return nil, errors.New("invalid gateway-ip") - } - if net.ParseIP(f.hostIP) == nil { - return nil, errors.New("invalid host-ip") - } - if net.ParseIP(f.vmIP) == nil { - return nil, errors.New("invalid vm-ip") - } - if _, _, err := net.ParseCIDR(f.subnet); err != nil { - return nil, errors.Wrap(err, "invalid subnet") - } - - f.gatewayMacAddress = gatewayMacAddress - f.vmMacAddress = vmMacAddress - - return configuration(f), nil -} - -func configuration(c *proxyFlags) *types.Configuration { - return &types.Configuration{ - Debug: c.debug, - CaptureFile: "", - MTU: c.mtu, - Subnet: c.subnet, - GatewayIP: c.gatewayIP, - GatewayMacAddress: gatewayMacAddress, - DHCPStaticLeases: map[string]string{ - c.vmIP: c.vmMacAddress, - }, - DNS: []types.Zone{ - { - Name: "internal.", - Records: []types.Record{ - { - Name: "gateway", - IP: net.ParseIP(c.gatewayIP), - }, - { - Name: "host", - IP: net.ParseIP(c.hostIP), - }, - }, - }, - }, - DNSSearchDomains: nil, - Forwards: map[string]string{}, - NAT: map[string]string{ - c.hostIP: "127.0.0.1", - }, - GatewayVirtualIPs: []string{c.hostIP}, - VpnKitUUIDMacAddresses: map[string]string{}, - Protocol: types.HyperKitProtocol, - } -} diff --git a/cmd/gvproxy/main.go b/cmd/gvproxy/main.go deleted file mode 100644 index 4039aa5..0000000 --- a/cmd/gvproxy/main.go +++ /dev/null @@ -1,79 +0,0 @@ -package main - -import ( - "context" - "os" - "os/signal" - "syscall" - - "github.com/containers/gvisor-tap-vsock/pkg/types" - "github.com/containers/gvisor-tap-vsock/pkg/virtualnetwork" - "github.com/pkg/errors" - "github.com/sakai135/wsl-vpnkit/pkg/transport" - log "github.com/sirupsen/logrus" - "golang.org/x/sync/errgroup" -) - -var ( - exitCode int -) - -func main() { - log.SetOutput(os.Stderr) - - config, err := parseProxyFlags() - if err != nil { - log.Error(err) - exitCode = 1 - return - } - - if config.Debug { - log.SetLevel(log.DebugLevel) - } - - ctx, cancel := context.WithCancel(context.Background()) - // Make this the last defer statement in the stack - defer os.Exit(exitCode) - - groupErrs, ctx := errgroup.WithContext(ctx) - // Setup signal channel for catching user signals - sigChan := make(chan os.Signal, 1) - signal.Notify(sigChan, os.Interrupt, syscall.SIGTERM, syscall.SIGINT) - - groupErrs.Go(func() error { - return run(ctx, groupErrs, config) - }) - - // Wait for something to happen - groupErrs.Go(func() error { - select { - // Catch signals so exits are graceful and defers can run - case <-sigChan: - cancel() - return errors.New("signal caught") - case <-ctx.Done(): - return nil - } - }) - // Wait for all of the go funcs to finish up - if err := groupErrs.Wait(); err != nil { - log.Error(err) - exitCode = 1 - } -} - -func run(ctx context.Context, g *errgroup.Group, configuration *types.Configuration) error { - vn, err := virtualnetwork.New(configuration) - if err != nil { - return err - } - - conn := transport.GetStdioConn() - err = vn.AcceptQemu(ctx, conn) - if err != nil { - return err - } - - return nil -} diff --git a/cmd/vm/flags.go b/cmd/vm/flags.go deleted file mode 100644 index 80ce914..0000000 --- a/cmd/vm/flags.go +++ /dev/null @@ -1,76 +0,0 @@ -package main - -import ( - "flag" - "fmt" - "net" - "os" - - "github.com/pkg/errors" - "github.com/vishvananda/netlink" -) - -const ( - vmMacAddress = "5a:94:ef:e4:0c:ee" -) - -type VMFlags struct { - Endpoint string - Iface string - Debug bool - MTU int - - Subnet string - GatewayIP string - HostIP string - VMIP string - ProxyMTU int - MAC string -} - -func parseVMFlags() (*VMFlags, error) { - f := &VMFlags{} - - flag.StringVar(&f.Endpoint, "path", "gvproxy.exe", "path to gvproxy.exe") - flag.StringVar(&f.Iface, "iface", "tap0", "tap interface name") - flag.BoolVar(&f.Debug, "debug", false, "debug") - flag.IntVar(&f.MTU, "mtu", 4000, "mtu") - - flag.StringVar(&f.Subnet, "subnet", "192.168.127.0/24", "Set the subnet") - flag.StringVar(&f.GatewayIP, "gateway-ip", "192.168.127.1", "Set the IP for the gateway") - flag.StringVar(&f.HostIP, "host-ip", "192.168.127.254", "Set the IP for accessing the host from the WSL 2 VM") - flag.StringVar(&f.VMIP, "vm-ip", "192.168.127.2", "Set the IP for the WSL 2 VM") - flag.IntVar(&f.ProxyMTU, "proxy-mtu", 1500, "Set the MTU for the proxy") - - flag.Parse() - - if _, err := os.Stat(f.Endpoint); err != nil { - return nil, errors.Wrapf(err, "error verifying path %s", f.Endpoint) - } - if net.ParseIP(f.GatewayIP) == nil { - return nil, errors.New("invalid gateway-ip") - } - if net.ParseIP(f.HostIP) == nil { - return nil, errors.New("invalid host-ip") - } - if net.ParseIP(f.VMIP) == nil { - return nil, errors.New("invalid vm-ip") - } - if _, _, err := net.ParseCIDR(f.Subnet); err != nil { - return nil, errors.Wrap(err, "invalid subnet") - } - - links, err := netlink.LinkList() - if err != nil { - return nil, err - } - for _, link := range links { - if f.Iface == link.Attrs().Name { - return nil, errors.New(fmt.Sprintf("interface %s already exists", link.Attrs().Name)) - } - } - - f.MAC = vmMacAddress - - return f, nil -} diff --git a/cmd/vm/main.go b/cmd/vm/main.go deleted file mode 100644 index acad3b0..0000000 --- a/cmd/vm/main.go +++ /dev/null @@ -1,182 +0,0 @@ -package main - -import ( - "encoding/binary" - "fmt" - "io" - "net" - "os" - "os/exec" - "strconv" - - "github.com/google/gopacket" - "github.com/google/gopacket/layers" - "github.com/pkg/errors" - "github.com/sakai135/wsl-vpnkit/pkg/transport" - log "github.com/sirupsen/logrus" - "github.com/songgao/packets/ethernet" - "github.com/songgao/water" - "github.com/vishvananda/netlink" - "gvisor.dev/gvisor/pkg/tcpip/header" -) - -func main() { - f, err := parseVMFlags() - if err != nil { - log.Fatal(err) - } - - if err := run(f); err != nil { - log.Fatal(err) - if err == io.EOF { - os.Exit(1) - } - } -} - -func parseProxyOptions(f *VMFlags) []string { - options := []string{ - "-subnet", f.Subnet, - "-gateway-ip", f.GatewayIP, - "-host-ip", f.HostIP, - "-vm-ip", f.VMIP, - "-mtu", strconv.Itoa(f.ProxyMTU), - } - if f.Debug { - options = append(options, "-debug") - } - return options -} - -func run(f *VMFlags) error { - conn, err := transport.Dial(f.Endpoint, parseProxyOptions(f)[:]...) - if err != nil { - return errors.Wrap(err, "cannot connect to host") - } - defer conn.Close() - - tap, err := water.New(water.Config{ - DeviceType: water.TAP, - PlatformSpecificParams: water.PlatformSpecificParams{ - Name: f.Iface, - }, - }) - if err != nil { - return errors.Wrap(err, "cannot create tap device") - } - defer tap.Close() - - if err := linkUp(f.Iface, f.MAC); err != nil { - return errors.Wrap(err, "cannot set mac address") - } - - errCh := make(chan error, 1) - go tx(conn, tap, errCh, f.MTU, f.Debug) - go rx(conn, tap, errCh, f.MTU, f.Debug) - go func() { - if err := dhcp(f.Iface); err != nil { - errCh <- errors.Wrap(err, "dhcp error") - } - }() - return <-errCh -} - -func linkUp(iface string, mac string) error { - link, err := netlink.LinkByName(iface) - if err != nil { - return err - } - if mac == "" { - return netlink.LinkSetUp(link) - } - hw, err := net.ParseMAC(mac) - if err != nil { - return err - } - if err := netlink.LinkSetHardwareAddr(link, hw); err != nil { - return err - } - return netlink.LinkSetUp(link) -} - -func dhcp(iface string) error { - if _, err := exec.LookPath("udhcpc"); err == nil { // busybox dhcp client - cmd := exec.Command("udhcpc", "-f", "-q", "-i", iface, "-v") - cmd.Stderr = os.Stderr - cmd.Stdout = os.Stderr - return cmd.Run() - } - cmd := exec.Command("dhclient", "-4", "-d", "-v", iface) - cmd.Stderr = os.Stderr - cmd.Stdout = os.Stderr - return cmd.Run() -} - -func rx(conn net.Conn, tap *water.Interface, errCh chan error, mtu int, debug bool) { - log.Info("waiting for packets...") - var frame ethernet.Frame - for { - frame.Resize(mtu) - n, err := tap.Read([]byte(frame)) - if err != nil { - errCh <- errors.Wrap(err, "cannot read packet from tap") - return - } - frame = frame[:n] - - if debug { - packet := gopacket.NewPacket(frame, layers.LayerTypeEthernet, gopacket.Default) - log.Info(packet.String()) - } - - size := make([]byte, 2) - binary.LittleEndian.PutUint16(size, uint16(n)) - - if _, err := conn.Write(size); err != nil { - errCh <- errors.Wrap(err, "cannot write size to socket") - return - } - if _, err := conn.Write(frame); err != nil { - errCh <- errors.Wrap(err, "cannot write packet to socket") - return - } - } -} - -func tx(conn net.Conn, tap *water.Interface, errCh chan error, mtu int, debug bool) { - sizeBuf := make([]byte, 2) - buf := make([]byte, mtu+header.EthernetMinimumSize) - - for { - n, err := io.ReadFull(conn, sizeBuf) - if err != nil { - errCh <- errors.Wrap(err, "cannot read size from socket") - return - } - if n != 2 { - errCh <- fmt.Errorf("unexpected size %d", n) - return - } - size := int(binary.LittleEndian.Uint16(sizeBuf[0:2])) - - n, err = io.ReadFull(conn, buf[:size]) - if err != nil { - errCh <- errors.Wrap(err, "cannot read payload from socket") - return - } - if n == 0 || n != size { - errCh <- fmt.Errorf("unexpected size %d != %d", n, size) - return - } - - if debug { - packet := gopacket.NewPacket(buf[:size], layers.LayerTypeEthernet, gopacket.Default) - log.Info(packet.String()) - } - - if _, err := tap.Write(buf[:size]); err != nil { - errCh <- errors.Wrap(err, "cannot write packet to tap") - return - } - } -} diff --git a/distro/Dockerfile b/distro/Dockerfile deleted file mode 100644 index a6af442..0000000 --- a/distro/Dockerfile +++ /dev/null @@ -1,38 +0,0 @@ -FROM docker.io/library/golang:1.18.10-alpine3.17 as build -WORKDIR /app -COPY go.mod go.sum ./ -RUN go mod download -COPY cmd ./cmd -COPY pkg ./pkg -# wsl-gvproxy.exe is compiled as a windows GUI to support backgrounding -RUN GOOS=windows go build -ldflags '-H=windowsgui' -o bin/wsl-gvproxy.exe ./cmd/gvproxy && \ - GOOS=linux CGO_ENABLED=0 go build -ldflags '-s -w' -o bin/wsl-vm ./cmd/vm && \ - find ./bin -type f -exec sha256sum {} \; - -FROM docker.io/library/golang:1.18.10-alpine3.17 as licenses -RUN apk add --no-cache git && \ - apk list --installed && \ - go install github.com/google/go-licenses@v1.0.0 -WORKDIR /app -COPY go.mod go.sum LICENSE ./ -COPY cmd ./cmd -COPY pkg ./pkg -RUN go-licenses save ./cmd/gvproxy --save_path ./licenses/gvproxy && \ - go-licenses save ./cmd/vm --save_path ./licenses/vm - -FROM docker.io/library/alpine:3.17.2 -RUN apk add --no-cache openrc iptables && \ - apk list --installed -ARG REF=https://example.com/ -ARG VERSION=v0.0.0 -WORKDIR /app -COPY --from=build /app/bin /files/ -COPY --from=licenses /app/licenses/gvproxy /app/licenses/vm /licenses/ -COPY ./distro/conf/udhcpc.conf /etc/udhcpc/udhcpc.conf -COPY ./distro/scripts/ ./wsl-vpnkit ./LICENSE ./ -RUN echo "$REF" > /app/ref && \ - echo "$VERSION" > /app/version && \ - find /files -type f -exec sha256sum {} \; && \ - ln -s /files/wsl-vm /app/wsl-vpnkit /usr/sbin/ && \ - ln -s /app/wsl-vpnkit.service /etc/init.d/wsl-vpnkit && \ - ln -s /app/startup.sh /etc/profile.d/ diff --git a/distro/alpine.dockerfile b/distro/alpine.dockerfile new file mode 100644 index 0000000..2c5ba7f --- /dev/null +++ b/distro/alpine.dockerfile @@ -0,0 +1,24 @@ +FROM docker.io/library/alpine:3.17.2 as gvisor-tap-vsock +WORKDIR /app/bin +RUN wget https://github.com/containers/gvisor-tap-vsock/releases/download/v0.6.1/gvproxy-windows.exe && \ + wget https://github.com/containers/gvisor-tap-vsock/releases/download/v0.6.1/vm && \ + chmod +x ./gvproxy-windows.exe ./vm +RUN find . -type f -exec sha256sum {} \; + +FROM docker.io/library/alpine:3.17.2 +RUN apk update && \ + apk upgrade && \ + apk add iproute2 iptables && \ + apk list --installed && \ + rm -rf /var/cache/apk/* +WORKDIR /app +COPY --from=gvisor-tap-vsock /app/bin/vm ./wsl-vm +COPY --from=gvisor-tap-vsock /app/bin/gvproxy-windows.exe ./wsl-gvproxy.exe +COPY ./wsl-vpnkit ./wsl-vpnkit.service ./ +COPY ./distro/wsl.conf /etc/wsl.conf +ARG REF=https://example.com/ +ARG VERSION=v0.0.0 +RUN find ./ -type f -exec sha256sum {} \; && \ + ln -s /app/wsl-vpnkit /usr/bin/ && \ + echo "$REF" > ./ref && \ + echo "$VERSION" > ./version diff --git a/distro/conf/udhcpc.conf b/distro/conf/udhcpc.conf deleted file mode 100644 index 354c80c..0000000 --- a/distro/conf/udhcpc.conf +++ /dev/null @@ -1 +0,0 @@ -RESOLV_CONF=no diff --git a/distro/fedora.dockerfile b/distro/fedora.dockerfile new file mode 100644 index 0000000..03e1fb9 --- /dev/null +++ b/distro/fedora.dockerfile @@ -0,0 +1,17 @@ +FROM docker.io/library/alpine:3.17.2 as gvisor-tap-vsock +WORKDIR /app/bin +RUN wget https://github.com/containers/gvisor-tap-vsock/releases/download/v0.6.1/gvproxy-windows.exe && \ + wget https://github.com/containers/gvisor-tap-vsock/releases/download/v0.6.1/vm && \ + chmod +x ./gvproxy-windows.exe ./vm +RUN find . -type f -exec sha256sum {} \; + +FROM docker.io/library/fedora:37 +RUN dnf upgrade -y && \ + dnf install -y iproute iptables-legacy iputils bind-utils wget && \ + dnf clean all +WORKDIR /app +COPY --from=gvisor-tap-vsock /app/bin/vm ./wsl-vm +COPY --from=gvisor-tap-vsock /app/bin/gvproxy-windows.exe ./wsl-gvproxy.exe +COPY ./wsl-vpnkit ./wsl-vpnkit.service ./ +COPY ./distro/wsl.conf /etc/wsl.conf +RUN ln -s /app/wsl-vpnkit /usr/bin/ diff --git a/distro/scripts/defaults.conf b/distro/scripts/defaults.conf deleted file mode 100644 index d0f505e..0000000 --- a/distro/scripts/defaults.conf +++ /dev/null @@ -1,16 +0,0 @@ -# Virtual interface name -TAP_NAME=eth1 - -# Network configuration -VPNKIT_SUBNET=192.168.67.0/24 -VPNKIT_GATEWAY_IP=192.168.67.1 -VPNKIT_HOST_IP=192.168.67.2 -VPNKIT_LOWEST_IP=192.168.67.3 -DNS_IP=192.168.67.1 - -# Debug logging for gvisor-tap-vsock -VPNKIT_DEBUG=false - -# Connectivity test endpoints -CHECK_DNS=1.1.1.1 -CHECK_HOST=example.com diff --git a/distro/scripts/startup.sh b/distro/scripts/startup.sh deleted file mode 100755 index 830bfca..0000000 --- a/distro/scripts/startup.sh +++ /dev/null @@ -1,41 +0,0 @@ -#! /bin/sh - -LOG_PATH="/var/log/wsl-vpnkit.log" -USERPROFILE=$(wslpath "$(powershell.exe -NoLogo -NoProfile -c 'Write-Host -NoNewline $env:USERPROFILE')") -VERSION="$(cat /app/version)" - -touch $LOG_PATH - -echo " -wsl-vpnkit $VERSION -This distro is only intended for running wsl-vpnkit. - -Run the following commands from Windows or other WSL 2 distros to use. - - wsl.exe -d $WSL_DISTRO_NAME --cd /app service wsl-vpnkit stop - wsl.exe -d $WSL_DISTRO_NAME --cd /app service wsl-vpnkit start - -The following file will be copied if it does not already exist. - - $USERPROFILE/wsl-vpnkit/wsl-gvproxy.exe - -Logs for wsl-vpnkit can be viewed here. - - wsl.exe -d $WSL_DISTRO_NAME --cd /app tail -f $LOG_PATH - -To see only the most recent logs - - wsl.exe -d $WSL_DISTRO_NAME --cd /app sh -c \"tac $LOG_PATH | awk '{print}; /starting wsl-vpnkit/{exit}' | tac\" - -Config for wsl-vpnkit can be edited here. - - $USERPROFILE/wsl-vpnkit/wsl-vpnkit.conf - -Run the following command to see the default values. - - wsl.exe -d $WSL_DISTRO_NAME --cd /app cat /app/defaults.conf - -Press [enter] key to continue... -" -read _ -exit 0 diff --git a/distro/scripts/wsl-vpnkit.service b/distro/scripts/wsl-vpnkit.service deleted file mode 100755 index b8e54bf..0000000 --- a/distro/scripts/wsl-vpnkit.service +++ /dev/null @@ -1,88 +0,0 @@ -#! /bin/sh - -EXECUTABLE="wsl-vpnkit" # starting point -PID_PATH="/var/run/$EXECUTABLE.pid" -LOG_PATH="/var/log/$EXECUTABLE.log" -ret=0 - -_debug_check() { - if [ -n "$DEBUG" ]; then - set -x - ps - fi -} - -start() { - start-stop-daemon \ - --pidfile $PID_PATH \ - --make-pidfile \ - --background \ - --stdout $LOG_PATH \ - --stderr $LOG_PATH \ - --exec $EXECUTABLE \ - --wait 1 --progress \ - ${DEBUG+--verbose} \ - --start - status >/dev/null # sets ret var -} - -stop() { - start-stop-daemon \ - --pidfile $PID_PATH \ - ${DEBUG+--verbose} \ - --stop - if status >/dev/null; then - pid=$(cat $PID_PATH) - kill -INT "$pid" - sleep 3 - fi - if status >/dev/null; then - kill -TERM "$pid" - fi - rm -f $PID_PATH - # kill sub processes if still running - for subp in wget udhcpc wsl-gvproxy wsl-vm; do - while pgrep $subp >/dev/null; do - pkill -TERM $subp - sleep 1 - done - done - if status >/dev/null; then - ret=1 - else - ret=0 - fi -} - -status() { - _debug_check >&2 - if test -f $PID_PATH && pgrep -P "$(cat $PID_PATH)" >/dev/null; then - echo Service $EXECUTABLE is running - ret=0 - else - echo Service $EXECUTABLE is not running - ret=1 - fi - return $ret -} - -case "$1" in - start) - start - ;; - stop) - stop - ;; - restart) - stop - start - ;; - status) - status - ;; - *) - echo "Usage: $EXECUTABLE {start|stop|restart|status}" - exit 1 -esac - -exit $ret \ No newline at end of file diff --git a/distro/ubuntu.dockerfile b/distro/ubuntu.dockerfile new file mode 100644 index 0000000..00066a7 --- /dev/null +++ b/distro/ubuntu.dockerfile @@ -0,0 +1,18 @@ +FROM docker.io/library/alpine:3.17.2 as gvisor-tap-vsock +WORKDIR /app/bin +RUN wget https://github.com/containers/gvisor-tap-vsock/releases/download/v0.6.1/gvproxy-windows.exe && \ + wget https://github.com/containers/gvisor-tap-vsock/releases/download/v0.6.1/vm && \ + chmod +x ./gvproxy-windows.exe ./vm +RUN find . -type f -exec sha256sum {} \; + +FROM docker.io/library/ubuntu:22.04 +RUN apt-get update && \ + apt-get upgrade -y && \ + apt-get install -y iproute2 iptables iputils-ping dnsutils wget && \ + apt-get clean +WORKDIR /app +COPY --from=gvisor-tap-vsock /app/bin/vm ./wsl-vm +COPY --from=gvisor-tap-vsock /app/bin/gvproxy-windows.exe ./wsl-gvproxy.exe +COPY ./wsl-vpnkit ./wsl-vpnkit.service ./ +COPY ./distro/wsl.conf /etc/wsl.conf +RUN ln -s /app/wsl-vpnkit /usr/bin/ diff --git a/distro/wsl.conf b/distro/wsl.conf new file mode 100644 index 0000000..7c889e1 --- /dev/null +++ b/distro/wsl.conf @@ -0,0 +1,13 @@ +[boot] +systemd=false + +[automount] +enabled=false + +[network] +generateHosts=false +generateResolvConf=true + +[interop] +enabled=true +appendWindowsPath=false diff --git a/go.mod b/go.mod deleted file mode 100644 index 851f603..0000000 --- a/go.mod +++ /dev/null @@ -1,36 +0,0 @@ -module github.com/sakai135/wsl-vpnkit - -go 1.18 - -require ( - github.com/pkg/errors v0.9.1 - github.com/vishvananda/netlink v1.1.1-0.20201029203352-d40f9887b852 -) - -require ( - github.com/Microsoft/go-winio v0.6.0 // indirect - github.com/apparentlymart/go-cidr v1.1.0 // indirect - github.com/google/btree v1.0.1 // indirect - github.com/insomniacslk/dhcp v0.0.0-20220504074936-1ca156eafb9f // indirect - github.com/miekg/dns v1.1.50 // indirect - github.com/u-root/uio v0.0.0-20210528114334-82958018845c // indirect - golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa // indirect - golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect - golang.org/x/net v0.4.0 // indirect - golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e // indirect - golang.org/x/tools v0.1.12 // indirect - inet.af/tcpproxy v0.0.0-20220326234310-be3ee21c9fa0 // indirect -) - -require ( - github.com/containers/gvisor-tap-vsock v0.5.0 - github.com/google/go-cmp v0.5.9 - github.com/google/gopacket v1.1.19 - github.com/sirupsen/logrus v1.9.0 - github.com/songgao/packets v0.0.0-20160404182456-549a10cd4091 - github.com/songgao/water v0.0.0-20200317203138-2b4b6d7c09d8 - github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 // indirect - golang.org/x/sync v0.1.0 - golang.org/x/sys v0.3.0 // indirect - gvisor.dev/gvisor v0.0.0-20221216231429-a78e892a26d2 -) diff --git a/go.sum b/go.sum deleted file mode 100644 index 4aba806..0000000 --- a/go.sum +++ /dev/null @@ -1,142 +0,0 @@ -github.com/Microsoft/go-winio v0.6.0 h1:slsWYD/zyx7lCXoZVlvQrj0hPTM1HI4+v1sIda2yDvg= -github.com/Microsoft/go-winio v0.6.0/go.mod h1:cTAf44im0RAYeL23bpB+fzCyDH2MJiz2BO69KH/soAE= -github.com/apparentlymart/go-cidr v1.1.0 h1:2mAhrMoF+nhXqxTzSZMUzDHkLjmIHC+Zzn4tdgBZjnU= -github.com/apparentlymart/go-cidr v1.1.0/go.mod h1:EBcsNrHc3zQeuaeCeCtQruQm+n9/YjEn/vI25Lg7Gwc= -github.com/armon/go-proxyproto v0.0.0-20210323213023-7e956b284f0a/go.mod h1:QmP9hvJ91BbJmGVGSbutW19IC0Q9phDCLGaomwTJbgU= -github.com/containers/gvisor-tap-vsock v0.5.0 h1:hoCkrfQ96tjek2BtiW1BHy50zAQCzkqeiAQY96y6NLk= -github.com/containers/gvisor-tap-vsock v0.5.0/go.mod h1:jrnI5plQtmys5LEKpXcCCrLqZlrHsozQg0V2Jw1UG74= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/fanliao/go-promise v0.0.0-20141029170127-1890db352a72/go.mod h1:PjfxuH4FZdUyfMdtBio2lsRr1AKEaVPwelzuHuh8Lqc= -github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4= -github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= -github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= -github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= -github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8= -github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo= -github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/hugelgupf/socketpair v0.0.0-20190730060125-05d35a94e714/go.mod h1:2Goc3h8EklBH5mspfHFxBnEoURQCGzQQH1ga9Myjvis= -github.com/insomniacslk/dhcp v0.0.0-20220504074936-1ca156eafb9f h1:l1QCwn715k8nYkj4Ql50rzEog3WnMdrd4YYMMwemxEo= -github.com/insomniacslk/dhcp v0.0.0-20220504074936-1ca156eafb9f/go.mod h1:h+MxyHxRg9NH3terB1nfRIUaQEcI0XOVkdR9LNBlp8E= -github.com/jsimonetti/rtnetlink v0.0.0-20190606172950-9527aa82566a/go.mod h1:Oz+70psSo5OFh8DBl0Zv2ACw7Esh6pPUphlvZG9x7uw= -github.com/jsimonetti/rtnetlink v0.0.0-20200117123717-f846d4f6c1f4/go.mod h1:WGuG/smIU4J/54PblvSbh+xvCZmpJnFgr3ds6Z55XMQ= -github.com/jsimonetti/rtnetlink v0.0.0-20201009170750-9c6f07d100c1/go.mod h1:hqoO/u39cqLeBLebZ8fWdE96O7FxrAsRYhnVOdgHxok= -github.com/jsimonetti/rtnetlink v0.0.0-20201110080708-d2c240429e6c/go.mod h1:huN4d1phzjhlOsNIjFsw2SVRbwIHj3fJDMEU2SDPTmg= -github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= -github.com/mdlayher/ethernet v0.0.0-20190606142754-0394541c37b7 h1:lez6TS6aAau+8wXUP3G9I3TGlmPFEq2CTxBaRqY6AGE= -github.com/mdlayher/ethernet v0.0.0-20190606142754-0394541c37b7/go.mod h1:U6ZQobyTjI/tJyq2HG+i/dfSoFUt8/aZCM+GKtmFk/Y= -github.com/mdlayher/netlink v0.0.0-20190409211403-11939a169225/go.mod h1:eQB3mZE4aiYnlUsyGGCOpPETfdQq4Jhsgf1fk3cwQaA= -github.com/mdlayher/netlink v1.0.0/go.mod h1:KxeJAFOFLG6AjpyDkQ/iIhxygIUKD+vcwqcnu43w/+M= -github.com/mdlayher/netlink v1.1.0/go.mod h1:H4WCitaheIsdF9yOYu8CFmCgQthAPIWZmcKp9uZHgmY= -github.com/mdlayher/netlink v1.1.1/go.mod h1:WTYpFb/WTvlRJAyKhZL5/uy69TDDpHHu2VZmb2XgV7o= -github.com/mdlayher/raw v0.0.0-20190606142536-fef19f00fc18/go.mod h1:7EpbotpCmVZcu+KCX4g9WaRNuu11uyhiW7+Le1dKawg= -github.com/mdlayher/raw v0.0.0-20191009151244-50f2db8cc065 h1:aFkJ6lx4FPip+S+Uw4aTegFMct9shDvP+79PsSxpm3w= -github.com/mdlayher/raw v0.0.0-20191009151244-50f2db8cc065/go.mod h1:7EpbotpCmVZcu+KCX4g9WaRNuu11uyhiW7+Le1dKawg= -github.com/miekg/dns v1.1.50 h1:DQUfb9uc6smULcREF09Uc+/Gd46YWqJd5DbpPE9xkcA= -github.com/miekg/dns v1.1.50/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME= -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 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= -github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= -github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= -github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= -github.com/songgao/packets v0.0.0-20160404182456-549a10cd4091 h1:1zN6ImoqhSJhN8hGXFaJlSC8msLmIbX8bFqOfWLKw0w= -github.com/songgao/packets v0.0.0-20160404182456-549a10cd4091/go.mod h1:N20Z5Y8oye9a7HmytmZ+tr8Q2vlP0tAHP13kTHzwvQY= -github.com/songgao/water v0.0.0-20200317203138-2b4b6d7c09d8 h1:TG/diQgUe0pntT/2D9tmUCz4VNwm9MfrtPr0SU2qSX8= -github.com/songgao/water v0.0.0-20200317203138-2b4b6d7c09d8/go.mod h1:P5HUIBuIWKbyjl083/loAegFkfbFNx5i2qEP4CNbm7E= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= -github.com/u-root/uio v0.0.0-20210528114334-82958018845c h1:BFvcl34IGnw8yvJi8hlqLFo9EshRInwWBs2M5fGWzQA= -github.com/u-root/uio v0.0.0-20210528114334-82958018845c/go.mod h1:LpEX5FO/cB+WF4TYGY1V5qktpaZLkKkSegbr0V4eYXA= -github.com/vishvananda/netlink v1.1.1-0.20201029203352-d40f9887b852 h1:cPXZWzzG0NllBLdjWoD1nDfaqu98YMv+OneaKc8sPOA= -github.com/vishvananda/netlink v1.1.1-0.20201029203352-d40f9887b852/go.mod h1:twkDnbuQxJYemMlGd4JFIcuhgX83tXhKS2B/PRMpOho= -github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= -github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 h1:gga7acRE695APm9hlsSMoOoE65U4/TcqNj90mc69Rlg= -github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= -github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa h1:zuSxTR4o9y82ebqCUJYNGJbGPo6sKVl54f/TVDObg1c= -golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s= -golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190419010253-1f3472d942ba/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191007182048-72f939374954/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.4.0 h1:Q5QPcMlvfxFTAPV0+07Xz/MpK9NTXu2VDUuy0FeMfaU= -golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= -golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190411185658-b44545bcd369/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190418153312-f0ce4c0180be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190606122018-79a91cf218c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200728102440-3e129f6d46b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201009025420-dfb3f7c4e634/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201101102859-da207088b7d1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210525143221-35b2ab0089ea/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ= -golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.3.0 h1:qoo4akIqOcDME5bhc/NgxUdovd6BSS2uMsVjB56q1xI= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e h1:EHBhcS0mlXEAVwNyO2dLfjToGsyY4j24pTs2ScHnX7s= -golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU= -golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -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= -gvisor.dev/gvisor v0.0.0-20221216231429-a78e892a26d2 h1:QN+Xh63jThYFN4CrcD4KXj+rUhevlb0LXEAlZ4m+qXQ= -gvisor.dev/gvisor v0.0.0-20221216231429-a78e892a26d2/go.mod h1:Dn5idtptoW1dIos9U6A2rpebLs/MtTwFacjKb8jLdQA= -inet.af/tcpproxy v0.0.0-20220326234310-be3ee21c9fa0 h1:PqdHrvQRVK1zapJkd0qf6+tevvSIcWdfenVqJd3PHWU= -inet.af/tcpproxy v0.0.0-20220326234310-be3ee21c9fa0/go.mod h1:Tojt5kmHpDIR2jMojxzZK2w2ZR7OILODmUo2gaSwjrk= diff --git a/pkg/transport/dial.go b/pkg/transport/dial.go deleted file mode 100644 index a68951b..0000000 --- a/pkg/transport/dial.go +++ /dev/null @@ -1,53 +0,0 @@ -package transport - -import ( - "net" - "os" - "os/exec" - "strconv" -) - -var execCommand = exec.Command - -func Dial(endpoint string, arg ...string) (net.Conn, error) { - cmd := execCommand(endpoint, arg[:]...) - cmd.Stderr = os.Stderr - - stdin, err := cmd.StdinPipe() - if err != nil { - return nil, err - } - - stdout, err := cmd.StdoutPipe() - if err != nil { - return nil, err - } - - err = cmd.Start() - if err != nil { - return nil, err - } - - local := IoAddr{path: strconv.Itoa(os.Getpid())} - remote := IoAddr{path: strconv.Itoa(cmd.Process.Pid)} - conn := IoConn{ - reader: stdout, - writer: stdin, - local: local, - remote: remote, - close: cmd.Process.Kill, - } - return conn, nil -} - -func GetStdioConn() net.Conn { - local := IoAddr{path: strconv.Itoa(os.Getpid())} - remote := IoAddr{path: "remote"} - conn := IoConn{ - writer: os.Stdout, - reader: os.Stdin, - local: local, - remote: remote, - } - return conn -} diff --git a/pkg/transport/dial_test.go b/pkg/transport/dial_test.go deleted file mode 100644 index f38559d..0000000 --- a/pkg/transport/dial_test.go +++ /dev/null @@ -1,126 +0,0 @@ -package transport - -import ( - "bufio" - "fmt" - "io" - "os" - "os/exec" - "testing" -) - -func helperCommand(name string, arg ...string) (cmd *exec.Cmd) { - cs := []string{"-test.run=TestHelperProcess", "--"} - cs = append(cs, name) - cs = append(cs, arg...) - cmd = exec.Command(os.Args[0], cs...) - cmd.Env = append(os.Environ(), "GO_WANT_HELPER_PROCESS=1") - return cmd -} - -func TestHelperProcess(*testing.T) { - if os.Getenv("GO_WANT_HELPER_PROCESS") != "1" { - return - } - defer os.Exit(0) - - args := os.Args - for len(args) > 0 { - if args[0] == "--" { - args = args[1:] - break - } - args = args[1:] - } - - iargs := []any{} - for _, s := range args { - iargs = append(iargs, s) - } - fmt.Println(iargs...) - - conn := GetStdioConn() - buf := make([]byte, 512) - for { - i, err := conn.Read(buf) - if err != nil { - break - } - read := buf[:i] - if string(read) == "error" { - os.Exit(1) - } - _, _ = conn.Write(read) - } -} - -func TestDial(t *testing.T) { - execCommand = helperCommand - defer func() { execCommand = exec.Command }() - - conn, err := Dial("executable", "arg1", "arg2") - if err != nil { - t.Error(err) - } - - reader := bufio.NewReader(conn) - line, _, err := reader.ReadLine() - if err != nil { - t.Error(err) - } - str := string(line) - if str != "executable arg1 arg2" { - t.Errorf("unexpected string %s", str) - } - - _, _ = conn.Write([]byte("hi there\n")) - line, _, err = reader.ReadLine() - if err != nil { - t.Error(err) - } - str = string(line) - if str != "hi there" { - t.Errorf("unexpected string %s", str) - } - - err = conn.Close() - if err != nil { - t.Error(err) - } -} - -func TestDial_Error(t *testing.T) { - execCommand = helperCommand - defer func() { execCommand = exec.Command }() - - conn, err := Dial("executable", "arg1", "arg2") - if err != nil { - t.Error(err) - } - - reader := bufio.NewReader(conn) - _, _, err = reader.ReadLine() - if err != nil { - t.Error(err) - } - - _, _ = conn.Write([]byte("error")) - _, _, err = reader.ReadLine() - if err == nil { - t.Error("expected error") - } - if err != io.EOF { - t.Errorf("unexpected error %s", err) - } -} - -func TestGetStdioConn(t *testing.T) { - conn := GetStdioConn() - if conn.RemoteAddr().String() != "remote" { - t.Errorf("unexpected remote address %s", conn.RemoteAddr().String()) - } - err := conn.Close() - if err != nil { - t.Error(err) - } -} diff --git a/pkg/transport/ioaddr.go b/pkg/transport/ioaddr.go deleted file mode 100644 index 267a76c..0000000 --- a/pkg/transport/ioaddr.go +++ /dev/null @@ -1,12 +0,0 @@ -package transport - -type IoAddr struct { - path string -} - -func (a IoAddr) Network() string { - return "stdio" -} -func (a IoAddr) String() string { - return a.path -} diff --git a/pkg/transport/ioaddr_test.go b/pkg/transport/ioaddr_test.go deleted file mode 100644 index 30f87c4..0000000 --- a/pkg/transport/ioaddr_test.go +++ /dev/null @@ -1,21 +0,0 @@ -package transport - -import "testing" - -func TestNetwork(t *testing.T) { - addr := &IoAddr{path: "path"} - result := addr.Network() - - if "stdio" != result { - t.Errorf("unexpected result %s", result) - } -} - -func TestString(t *testing.T) { - addr := &IoAddr{path: "path"} - result := addr.String() - - if "path" != result { - t.Errorf("unexpected result %s", result) - } -} diff --git a/pkg/transport/ioconn.go b/pkg/transport/ioconn.go deleted file mode 100644 index e492b46..0000000 --- a/pkg/transport/ioconn.go +++ /dev/null @@ -1,50 +0,0 @@ -package transport - -import ( - "io" - "net" - "time" -) - -type IoConn struct { - writer io.Writer - reader io.Reader - local net.Addr - remote net.Addr - close func() error -} - -func (c IoConn) Read(b []byte) (n int, err error) { - return c.reader.Read(b) -} - -func (c IoConn) Write(b []byte) (n int, err error) { - return c.writer.Write(b) -} - -func (c IoConn) Close() error { - if c.close != nil { - return c.close() - } - return nil -} - -func (c IoConn) LocalAddr() net.Addr { - return c.local -} - -func (c IoConn) RemoteAddr() net.Addr { - return c.remote -} - -func (c IoConn) SetDeadline(t time.Time) error { - return nil -} - -func (c IoConn) SetReadDeadline(t time.Time) error { - return nil -} - -func (c IoConn) SetWriteDeadline(t time.Time) error { - return nil -} diff --git a/pkg/transport/ioconn_test.go b/pkg/transport/ioconn_test.go deleted file mode 100644 index e2cb46b..0000000 --- a/pkg/transport/ioconn_test.go +++ /dev/null @@ -1,115 +0,0 @@ -package transport - -import ( - "bytes" - "strings" - "testing" - "time" - - "github.com/google/go-cmp/cmp" -) - -func TestRead(t *testing.T) { - buf := make([]byte, 10) - conn := &IoConn{reader: strings.NewReader("aaaaa")} - i, err := conn.Read(buf) - - if 5 != i { - t.Errorf("unexpected bytes read %d", i) - } - if err != nil { - t.Error("unexpected error") - } - expected := make([]byte, 10) - copy(expected, []byte("aaaaa")) - if !cmp.Equal(expected, buf) { - t.Error(cmp.Diff(expected, buf)) - } -} - -func TestWrite(t *testing.T) { - writer := &bytes.Buffer{} - conn := &IoConn{writer: writer} - i, err := conn.Write([]byte("aaaaa")) - - if err != nil { - t.Error(err) - } - if i != 5 { - t.Errorf("unexpected bytes written %d", i) - } - expected := []byte("aaaaa") - if !cmp.Equal(expected, writer.Bytes()) { - t.Error(cmp.Diff(expected, writer.Bytes())) - } -} - -func TestClose_Nil(t *testing.T) { - conn := &IoConn{} - err := conn.Close() - - if err != nil { - t.Error(err) - } -} - -func TestClose_FuncSuccess(t *testing.T) { - called := false - conn := &IoConn{ - close: func() error { - called = true - return nil - }, - } - err := conn.Close() - - if err != nil { - t.Error(err) - } - if !called { - t.Error("called should be true") - } -} - -func TestLocalAddr(t *testing.T) { - conn := &IoConn{local: &IoAddr{path: "local"}} - - if "local" != conn.LocalAddr().String() { - t.Error("unexpected local") - } -} - -func TestRemoteAddr(t *testing.T) { - conn := &IoConn{remote: &IoAddr{path: "remote"}} - - if "remote" != conn.RemoteAddr().String() { - t.Error("unexpected local") - } -} - -func TestSetDeadline(t *testing.T) { - conn := &IoConn{} - err := conn.SetDeadline(time.Now()) - - if err != nil { - t.Error(err) - } -} - -func TestSetReadDeadline(t *testing.T) { - conn := &IoConn{} - err := conn.SetReadDeadline(time.Now()) - - if err != nil { - t.Error(err) - } -} - -func TestSetWriteDeadline(t *testing.T) { - conn := &IoConn{} - err := conn.SetWriteDeadline(time.Now()) - - if err != nil { - t.Error(err) - } -} diff --git a/test.sh b/test.sh deleted file mode 100755 index c9a8fed..0000000 --- a/test.sh +++ /dev/null @@ -1,55 +0,0 @@ -#!/bin/sh -xe - -# ensuring distro is stopped before running tests -wsl.exe -d wsl-vpnkit --cd /app service wsl-vpnkit stop -if wsl.exe -d wsl-vpnkit --cd /app service wsl-vpnkit status; then - wsl.exe -t wsl-vpnkit -fi - -# tests -for debug_value in '1' '2' ''; do - if [ -n "${debug_value}" ]; then - debug_str="DEBUG=${debug_value}" - else - debug_str="" - fi - echo "####### Test Round with debug_str [${debug_str}] #######" | grep --colour=always . - - # inital status should be stopped - output=$(wsl.exe -d wsl-vpnkit --cd /app ${debug_str} service wsl-vpnkit status)||echo "ignoring exit code" - echo "$output" | grep --colour=always "Service wsl-vpnkit is not running" - - # start service - wsl.exe -d wsl-vpnkit --cd /app ${debug_str} service wsl-vpnkit start - sleep 2 - output=$(wsl.exe -d wsl-vpnkit --cd /app ${debug_str} service wsl-vpnkit status) - echo "$output" | grep --colour=always "Service wsl-vpnkit is running" - - # check latest log - sleep 5 - output=$(wsl.exe -d wsl-vpnkit --cd /app sh -c "tac /var/log/wsl-vpnkit.log | awk '{print}; /starting wsl-vpnkit/{exit}' | tac") - - ( set +x # avoid clutter during output checks - # check for working ping - echo "$output" | grep --colour=always "ping success" - - # check for working dns - echo "$output" | grep --colour=always "nslookup success" - ) - - # restart service - wsl.exe -d wsl-vpnkit --cd /app ${debug_str} service wsl-vpnkit restart - sleep 2 - output=$(wsl.exe -d wsl-vpnkit --cd /app ${debug_str} service wsl-vpnkit status) - echo "$output" | grep --colour=always "Service wsl-vpnkit is running" - - # stop service - wsl.exe -d wsl-vpnkit --cd /app ${debug_str} service wsl-vpnkit stop - output=$(wsl.exe -d wsl-vpnkit --cd /app ${debug_str} service wsl-vpnkit status)||echo "ignoring exit code" - echo "$output" | grep --colour=always "Service wsl-vpnkit is not running" - - # check welcome screen - wsl.exe -d wsl-vpnkit --cd /app sh -c 'echo 1 | source /etc/profile' -done - -echo "$0 Finished" | grep --colour=always . \ No newline at end of file diff --git a/wsl-vpnkit b/wsl-vpnkit index 7338f7b..0de675c 100755 --- a/wsl-vpnkit +++ b/wsl-vpnkit @@ -1,115 +1,82 @@ #!/bin/sh -CMDSHELL="$(command -v cmd.exe || echo '/mnt/c/Windows/system32/cmd.exe')" -USERPROFILE=$(wslpath "$($CMDSHELL /d /v:off /c 'echo | set /p t=%USERPROFILE%' 2>/dev/null)") -WSL2_GATEWAY_IP="$(cat /etc/resolv.conf | awk '/^nameserver/ {print $2}')" -WSL2_VM_IP="$(ifconfig eth0 | awk '/inet /{print substr($2, 6)}')" -WSL2_TAP_NAME=eth0 -WIN_STORE="/files" -WIN_PATH="$USERPROFILE/wsl-vpnkit" -CONF_PATH="$WIN_PATH/wsl-vpnkit.conf" -GVPROXY_PATH="$WIN_PATH/wsl-gvproxy.exe" -VM_PID= - -echo "starting wsl-vpnkit" - -# Load defaults -if [ -f "/app/defaults.conf" ]; then - . /app/defaults.conf -fi -# Load user config if needed -if [ -f "$CONF_PATH" ]; then - . "$CONF_PATH" - echo "loaded config: $CONF_PATH" +set -x + +# hardcoded in gvisor-tap-vsock +VPNKIT_GATEWAY_IP="192.168.127.1" +VPNKIT_HOST_IP="192.168.127.254" +VPNKIT_LOCAL_IP="192.168.127.2" +TAP_MAC_ADDR="5a:94:ef:e4:0c:ee" + +# overrideable with env +VMEXEC_PATH=${VMEXEC_PATH:-/app/wsl-vm} +GVPROXY_PATH=${GVPROXY_PATH:-/app/wsl-gvproxy.exe} +TAP_NAME=${TAP_NAME:-wsltap} +CHECK_HOST=${CHECK_HOST:-example.com} +CHECK_DNS=${CHECK_DNS:-1.1.1.1} +DEBUG=${DEBUG:-0} + +set +x + +# WSL2 default values +WSL2_TAP_NAME="eth0" +WSL2_RESOLVCONF="/mnt/wsl/resolv.conf" +WSL2_GATEWAY_IP="$(cat $WSL2_RESOLVCONF | awk '/^nameserver/ {print $2}')" + +set -x + +# show values +WSL2_TAP_NAME=$WSL2_TAP_NAME +WSL2_GATEWAY_IP=$WSL2_GATEWAY_IP + +if [ "$DEBUG" -eq 0 ]; then + set +x fi -# Failsafe configuration to run as a standalone script -TAP_NAME=${TAP_NAME:-eth1} -VPNKIT_SUBNET=${VPNKIT_SUBNET:-192.168.67.0/24} -VPNKIT_GATEWAY_IP=${VPNKIT_GATEWAY_IP:-192.168.67.1} -VPNKIT_HOST_IP=${VPNKIT_HOST_IP:-192.168.67.2} -VPNKIT_LOWEST_IP=${VPNKIT_LOWEST_IP:-192.168.67.3} -DNS_IP=${DNS_IP:-192.168.67.1} -VPNKIT_DEBUG=${VPNKIT_DEBUG:-false} -CHECK_DNS=${CHECK_DNS:-1.1.1.1} -CHECK_HOST=${CHECK_HOST:-example.com} +# replace calls to iptables if iptables-legacy exists +command -v iptables-legacy >/dev/null && alias iptables=iptables-legacy -hash () { - md5sum "$1" | awk '{ print $1 }' +run () { + echo "starting vm and gvproxy..." + $VMEXEC_PATH \ + -url="stdio:$GVPROXY_PATH?listen-stdio=accept&debug=$DEBUG" \ + -iface="$TAP_NAME" \ + -stop-if-exist="" \ + -preexisting=1 \ + -debug=$DEBUG & + sleep 1 # wait to establish connection + echo "started vm and gvproxy" } -install_file () { - FILE_STORE="$WIN_STORE/$1" - FILE_PATH="$2" - if [ -f "$FILE_STORE" ]; then - if [ ! -f "$FILE_PATH" ]; then - mkdir -p "$(dirname "$FILE_PATH")" - cp "$FILE_STORE" "$FILE_PATH" - echo "copied $1 to $FILE_PATH" - else - echo "$1 exists at $FILE_PATH" - if [ `hash "$FILE_STORE"` != `hash "$FILE_PATH"` ]; then - cp -f "$FILE_STORE" "$FILE_PATH" - echo "updated $1 at $FILE_PATH" - fi - fi - fi - if [ ! -f "$FILE_PATH" ]; then - echo "$1 not found at $FILE_PATH" - exit 1 - fi -} +wsl2tap_down () { + # remove WSL2 default route + ip route del default -install () { - install_file wsl-gvproxy.exe "$GVPROXY_PATH" + # setup wsl-vpnkit tap + ip tuntap add $TAP_NAME mode tap + ip link set dev $TAP_NAME address $TAP_MAC_ADDR + ip link set dev $TAP_NAME up + ip addr add $VPNKIT_LOCAL_IP/255.255.255.0 dev $TAP_NAME + ip route add default via $VPNKIT_GATEWAY_IP dev $TAP_NAME } -run () { - echo "starting gvproxy at $GVPROXY_PATH..." - wsl-vm \ - -path "$GVPROXY_PATH" \ - -iface "$TAP_NAME" \ - -subnet "$VPNKIT_SUBNET" \ - -gateway-ip "$VPNKIT_GATEWAY_IP" \ - -host-ip "$VPNKIT_HOST_IP" \ - -vm-ip "$VPNKIT_LOWEST_IP" \ - -debug="$VPNKIT_DEBUG" & - VM_PID=$! - echo "started gvproxy" -} +wsl2tap_up () { + # take down wsl-vpnkit tap + ip link set dev $TAP_NAME down 2>/dev/null + ip tuntap del $TAP_NAME mode tap -tap_wait () { - echo "waiting for dhcp..." - c=1 - d=0 - while [ "$c" -eq 1 ] && [ "$d" -eq 0 ]; do - sleep 0.1 - ip route | grep "default via .* dev $TAP_NAME" - c=$? - kill -0 $VM_PID - d=$? - done - if [ "$d" -eq 1 ]; then - echo "wsl-vm exited" - exit 1 - fi - echo "dhcp completed" + # add WSL2 default route + ip route add default via $WSL2_GATEWAY_IP dev $WSL2_TAP_NAME 2>/dev/null } -ipconfig () { - echo "removing WSL 2 ip route..." - ip route | grep -e "$WSL2_GATEWAY_IP" | tr '\n' '\0' | xargs -0 -n 1 sh -c 'ip route del $1' argv0 - echo "removed WSL 2 ip route" - - echo "adding rules to iptables..." - iptables -t nat -A PREROUTING -d $WSL2_GATEWAY_IP/32 -p udp -m udp --dport 53 -j DNAT --to-destination $DNS_IP:53 - iptables -t nat -A PREROUTING -d $WSL2_GATEWAY_IP/32 -p tcp -m tcp --dport 53 -j DNAT --to-destination $DNS_IP:53 - iptables -t nat -A PREROUTING -d $WSL2_GATEWAY_IP/32 -j DNAT --to-destination $VPNKIT_HOST_IP - iptables -t nat -A OUTPUT -d $WSL2_GATEWAY_IP/32 -p udp -m udp --dport 53 -j DNAT --to-destination $DNS_IP:53 - iptables -t nat -A OUTPUT -d $WSL2_GATEWAY_IP/32 -p tcp -m tcp --dport 53 -j DNAT --to-destination $DNS_IP:53 - iptables -t nat -A OUTPUT -d $WSL2_GATEWAY_IP/32 -j DNAT --to-destination $VPNKIT_HOST_IP - iptables -t nat -A POSTROUTING -o $TAP_NAME -j MASQUERADE - echo "iptables done" +iptables_set () { + iptables -t nat -$1 PREROUTING -d $WSL2_GATEWAY_IP/32 -p udp -m udp --dport 53 -j DNAT --to-destination $VPNKIT_GATEWAY_IP:53 + iptables -t nat -$1 PREROUTING -d $WSL2_GATEWAY_IP/32 -p tcp -m tcp --dport 53 -j DNAT --to-destination $VPNKIT_GATEWAY_IP:53 + iptables -t nat -$1 PREROUTING -d $WSL2_GATEWAY_IP/32 -j DNAT --to-destination $VPNKIT_HOST_IP + iptables -t nat -$1 OUTPUT -d $WSL2_GATEWAY_IP/32 -p udp -m udp --dport 53 -j DNAT --to-destination $VPNKIT_GATEWAY_IP:53 + iptables -t nat -$1 OUTPUT -d $WSL2_GATEWAY_IP/32 -p tcp -m tcp --dport 53 -j DNAT --to-destination $VPNKIT_GATEWAY_IP:53 + iptables -t nat -$1 OUTPUT -d $WSL2_GATEWAY_IP/32 -j DNAT --to-destination $VPNKIT_HOST_IP + iptables -t nat -$1 POSTROUTING -o $TAP_NAME -j MASQUERADE } check_ping () { @@ -135,34 +102,26 @@ check () { check_ping 4 'WSL 2 gateway / Windows host' $WSL2_GATEWAY_IP check_ping 4 'Windows host' $VPNKIT_HOST_IP check_ping 4 'gateway' $VPNKIT_GATEWAY_IP - check_dns 4 $CHECK_HOST $DNS_IP check_dns 4 $CHECK_HOST $VPNKIT_GATEWAY_IP check_dns 4 $CHECK_HOST $WSL2_GATEWAY_IP check_dns 4 $CHECK_HOST $CHECK_DNS - check_ping 4 'external host' $CHECK_HOST - check_dns 6 $CHECK_HOST $DNS_IP + check_ping 4 'external host domain' $CHECK_HOST + check_ping 4 'external host IP' $CHECK_DNS check_dns 6 $CHECK_HOST $VPNKIT_GATEWAY_IP check_dns 6 $CHECK_HOST $WSL2_GATEWAY_IP check_dns 6 $CHECK_HOST $CHECK_DNS check_ping 6 'external host' $CHECK_HOST + check_https "http://$CHECK_HOST" check_https "https://$CHECK_HOST" } cleanup () { - echo "cleaning up iptables..." - iptables -t nat -S | grep $VPNKIT_GATEWAY_IP | cut -d " " -f 2- | tr '\n' '\0' | xargs -0 -r -n 1 sh -c 'iptables -t nat -D $1' argv0 - iptables -t nat -S | grep $VPNKIT_HOST_IP | cut -d " " -f 2- | tr '\n' '\0' | xargs -0 -r -n 1 sh -c 'iptables -t nat -D $1' argv0 - iptables -t nat -S | grep $TAP_NAME | cut -d " " -f 2- | tr '\n' '\0' | xargs -0 -r -n 1 sh -c 'iptables -t nat -D $1' argv0 - iptables -t nat -S | grep $DNS_IP | cut -d " " -f 2- | tr '\n' '\0' | xargs -0 -r -n 1 sh -c 'iptables -t nat -D $1' argv0 - echo "iptables cleanup done" - - echo "restoring WSL 2 ip route..." - ip addr add $WSL2_VM_IP/255.255.255.0 dev $WSL2_TAP_NAME - ip route add default via $WSL2_GATEWAY_IP dev $WSL2_TAP_NAME - echo "restored WSL 2 ip route" + iptables_set D 2>/dev/null + wsl2tap_up } close () { + echo "cleaning up..." cleanup echo "stopped wsl-vpnkit" kill 0 @@ -172,13 +131,34 @@ if [ ${EUID:-$(id -u)} -ne 0 ]; then echo "Please run this script as root" exit 1 fi +if [ ! -f "$VMEXEC_PATH" ]; then + echo "VMEXEC_PATH [$VMEXEC_PATH] does not exist" + exit 1 +fi +if [ ! -f "$GVPROXY_PATH" ]; then + echo "GVPROXY_PATH [$GVPROXY_PATH] does not exist" + exit 1 +fi +cat $WSL2_RESOLVCONF | grep "automatically generated by WSL" >/dev/null +if [ $? -eq 1 ]; then + echo "resolv.conf has been modified without setting generateResolvConf" + exit 1 +fi +$GVPROXY_PATH -help 2>/dev/null +if [ $? -eq 1 ]; then + echo "$GVPROXY_PATH is not executable due to WSL interop settings or Windows permissions" + exit 1 +fi + +# trap first so close runs even if the rest of the commands fail +trap close exit +trap exit int term +# run cleanup to restore any leftover configuration changes cleanup -install + +wsl2tap_down run -tap_wait -ipconfig +iptables_set A check -trap close exit -trap exit int term wait diff --git a/wsl-vpnkit.service b/wsl-vpnkit.service new file mode 100644 index 0000000..dee9019 --- /dev/null +++ b/wsl-vpnkit.service @@ -0,0 +1,17 @@ +[Unit] +Description=wsl-vpnkit +After=network.target + +[Service] +# for wsl-vpnkit setup as a distro +ExecStart=/mnt/c/Windows/system32/wsl.exe -d wsl-vpnkit --cd /app wsl-vpnkit + +# for wsl-vpnkit setup as a standalone script +#ExecStart=/full/path/to/wsl-vpnkit +#Environment=VMEXEC_PATH=/full/path/to/wsl-vm GVPROXY_PATH=/full/path/to/wsl-gvproxy.exe + +Restart=always +KillMode=mixed + +[Install] +WantedBy=multi-user.target