Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Inclusion of wsl-vpnkit #262

Open
terlar opened this issue Jun 19, 2023 · 11 comments
Open

Inclusion of wsl-vpnkit #262

terlar opened this issue Jun 19, 2023 · 11 comments
Labels
enhancement New feature or request

Comments

@terlar
Copy link
Contributor

terlar commented Jun 19, 2023

I have already implemented this and is wondering if it makes sense to include in this project.

Problem

Some VPN solutions causes problem when used together with WSL, there is wsl-vpnkit to address this issue.

Solution

wsl-vpnkit can be run within NixOS and requires the following:

Packing wsl-vpnkit:

{
  lib,
  stdenv,
  fetchFromGitHub,
  makeWrapper,
  # Runtime
  gvproxy,
  dnsutils,
  gawk,
  iproute2,
  iptables,
  iputils,
  wget,
}:

let
  gvproxyCross = gvproxy.overrideAttrs (_: {
    buildPhase = "make cross qemu-wrapper vm";
  });
in stdenv.mkDerivation rec {
  pname = "wsl-vpnkit";
  version = "0.4.1";

  src = fetchFromGitHub {
    owner = "sakai135";
    repo = "wsl-vpnkit";
    rev = "v${version}";
    sha256 = "sha256-Igbr3L2W32s4uBepllSz07bkbI3qwAKMZkBrXLqGrGA=";
  };

  nativeBuildInputs = [makeWrapper];

  postPatch = ''
    substituteInPlace wsl-vpnkit \
      --replace "/app/wsl-vm" "${gvproxyCross}/bin/vm" \
      --replace "/app/wsl-gvproxy.exe" "${gvproxyCross}/bin/gvproxy-windows.exe"
  '';

  installPhase = ''
    mkdir -p $out/bin
    cp wsl-vpnkit $out/bin
  '';

  postFixup = ''
    wrapProgram "$out/bin/wsl-vpnkit" \
      --prefix PATH : "${lib.makeBinPath [ dnsutils gawk iproute2 iptables iputils wget ]}"
  '';
}

Creating a systemd service:

{
  systemd.services.wsl-vpnkit = {
    enable = true;
    description = "wsl-vpnkit";
    after = [ "network.target" ];

    serviceConfig = {
      ExecStart = "${pkgs.wsl-vpnkit}/bin/wsl-vpnkit";
      Restart = "always";
      KillMode = "mixed";
    };
  };
}
@terlar terlar added the enhancement New feature or request label Jun 19, 2023
@nzbr
Copy link
Member

nzbr commented Jun 19, 2023

It looks like wsl-vpnkit could be useful for other distros with nix installed as well. I suggest you try to get the derivation merged into nixpkgs instead of here. Once it's in there, we could add the systemd service here

@fabianpage
Copy link

As i'm on a coporate Laptop with Windows and VPN i'm very grateful for wsl-vpnkit :) Thanks for adding it to nixpkgs.

@573
Copy link

573 commented Aug 25, 2023

Creating a systemd service:

{
  systemd.services.wsl-vpnkit = {
    enable = true;
    description = "wsl-vpnkit";
    after = [ "network.target" ];

    serviceConfig = {
      ExecStart = "${pkgs.wsl-vpnkit}/bin/wsl-vpnkit";
      Restart = "always";
      KillMode = "mixed";
    };
  };
}

adding wantedBy works:

    # see https://github.com/sakai135/wsl-vpnkit/blob/5084c6d/wsl-vpnkit.service
    systemd.services.wsl-vpnkit = {
      enable = true;
      description = "wsl-vpnkit";
      after = [ "network.target" ];
      wantedBy = [ "multi-user.target" ];

      serviceConfig = {
        ExecStart = "${pkgs.wsl-vpnkit}/bin/wsl-vpnkit";
        Restart = "always";
        KillMode = "mixed";
      };
    };

@terlar
Copy link
Contributor Author

terlar commented Aug 25, 2023

I explicitly didn't add wantedBy as I'm not always on VPN and when I'm not on VPN it breaks certain things to have this running. For example SSH access to GitHub didn't work when enabled.

@nzbr
Copy link
Member

nzbr commented Oct 2, 2023

Is this still needed? There are some experimental network options in the latest WSL which sound like they make wsl-vpnkit obsolete (I haven't used it myself, so I can't test)

@terlar
Copy link
Contributor Author

terlar commented Oct 3, 2023

Yes potentially, but there is a while until we get there. I tried to test this new feature, but it requires a bleeding edge windows version which is not under my control where needed.

Please note: You need to be on a Windows Insiders version to use the new networking settings (Any channel of Windows Insiders will do, including release preview). If you see the "These are not supported" messages it means that your current Windows version doesn't have support, and you will need to upgrade. These features will eventually be coming to Windows 11 22H2.

@573
Copy link

573 commented Nov 23, 2023

Friendly ping @terlar

As of

wsl.exe -v
WSL-Version: 2.0.9.0
Kernelversion: 5.15.133.1-1
WSLg-Version: 1.0.59
MSRDC-Version: 1.2.4677
Direct3D-Version: 1.611.1-81528511
DXCore-Version: 10.0.25131.1002-220531-1700.rs-onecore-base2-hyp
Windows-Version: 10.0.19045.3570

❯ cat /etc/wsl.conf
[automount]
enabled=true
mountFsTab=false
options=metadata,uid=1000,gid=100
root=/mnt

[boot]
command=
systemd=true

[interop]
appendWindowsPath=true
enabled=true

[network]
generateHosts=true
generateResolvConf=true
hostname=DANIELKNB1

[user]
default=nixos

wsl-vpnkit stopped working.

... wsl-vpnkit[19026]: /nix/store/ifayrgnd020y38gssz3x4y3sld0sdry5-gvproxy-0.7.1/bin/gvproxy-windows.exe is not executable due to WSL interop settings or Windows permissions

(as in https://github.com/sakai135/wsl-vpnkit#wsl-gvproxyexe-is-not-executable-due-to-wsl-interop-settings-or-windows-permissions)

Which configuration would reenable it ?
Currently I have boot.binfmt.emulatedSystems = [ "aarch64-linux" ]; in my configuration.nix

EDIT: Running directly though does seem to prove it is still executable

❯ /nix/store/ifayrgnd020y38gssz3x4y3sld0sdry5-gvproxy-0.7.1/bin/gvproxy-windows.exe
time="2023-11-23T22:21:04+01:00" level=info msg="waiting for clients..."

@terlar
Copy link
Contributor Author

terlar commented Nov 24, 2023

@573 Yes, this is an issue with the newer WSL (since 2.0.5) requires you to use WSL_INTEROP environment variable. There is a patch to fix this here:
sakai135/wsl-vpnkit#250

I am currently running this override until this gets merged:

{
  lib,
  fetchFromGitHub,
  findutils,
  pstree,
  resholve,
  wsl-vpnkit,
}:
wsl-vpnkit.override {
  resholve =
    resholve
    // {
      mkDerivation = attrs @ {solutions, ...}:
        resholve.mkDerivation (lib.recursiveUpdate attrs {
          src = fetchFromGitHub {
            owner = "sakai135";
            repo = "wsl-vpnkit";
            rev = "28992229fedfa64979faa9ec84b1b4bcf5c8f449";
            sha256 = "sha256-6VKFUoPAhVOmORTGELZu00SnGmYSbumPOZ64giWq14Q=";
          };

          solutions.wsl-vpnkit = {
            inputs =
              solutions.wsl-vpnkit.inputs
              ++ [
                findutils
                pstree
              ];

            execer =
              solutions.wsl-vpnkit.execer
              ++ ["cannot:${pstree}/bin/pstree"];
          };
        });
    };
}

@573
Copy link

573 commented Nov 24, 2023

Thank you so much, @terlar this now explains why I was able to even run

sudo -i /mnt/c/Windows/system32/wsl.exe -d wsl-vpnkit --cd /app ./wsl-vpnkit

or just plain

/mnt/c/Windows/system32/wsl.exe -d wsl-vpnkit --cd /app ./wsl-vpnkit

but not the exact same commands via systemd service. The env variable (set in NixOS-WSL correctly) was just not exported then.

Glad, you figred it out, even tried setting absolute paths and systemd.services.wsl-vpnkit.environment as suggested there and changed /etc/wsl.conf 🤣

@terlar
Copy link
Contributor Author

terlar commented Jan 17, 2024

I have tested the new options:

[wsl2]
networkingMode=mirrored
dnsTunneling=true

Unfortunately neither worked well with my company VPN and I still had to resort to wsl-vpnkit.

Since WSL 2.0.14, the mentioned issue with wsl-vpnkit has been solved. So WSL 2.0.5-2.0.13 are the problematic ones that can be used together with my mentioned patch. But for later versions it is not needed.

I have also added a custom service like this:

{
  systemd.services = {
    wsl-vpnkit-auto = {
      enable = cfg.autoVPN;
      description = "wsl-vpnkit";

      path = [pkgs.iputils];
      script = ''
        has_internet () {
          ping -q -w 1 -c 1 8.8.8.8 >/dev/null
        }

        has_company_network () {
          ping -q -w 1 -c 1 ${cfg.checkURL} >/dev/null
        }

        is_active_wsl-vpnkit () {
          systemctl is-active -q wsl-vpnkit.service
        }

        main () {
          if is_active_wsl-vpnkit; then
            if has_internet && ! has_company_network; then
              echo "Stopping wsl-vpnkit..."
              systemctl stop wsl-vpnkit.service
            fi
          else
            if ! has_internet; then
              echo "Starting wsl-vpnkit..."
              systemctl start wsl-vpnkit.service
            fi
          fi
        }

        while :
        do
          main
          sleep 5
        done
      '';

      wantedBy = ["multi-user.target"];
    };

    wsl-vpnkit = {
      enable = true;
      description = "wsl-vpnkit";

      serviceConfig = {
        ExecStart = "${pkgs.wsl-vpnkit}/bin/wsl-vpnkit";
        Type = "idle";
        Restart = "always";
        KillMode = "mixed";
      };
    };
  };
}

This way I can automatically connect to the wsl-vpnkit when needed and shut it down when off VPN. I can try to clean it up and make a PR if people think it is useful. At least for me it had made the VPN situation within WSL seemless.

@julius-boettger
Copy link

@terlar thank you so much! I would really appreciate a PR for this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

5 participants