diff --git a/gunpowder/services/mullvad.nix b/gunpowder/services/mullvad.nix index c3699a7b3e7dc861eb365c995dbd15ebec2abe60..2c755b2941a0eb17ba233f32a032ad33e4923079 100644 --- a/gunpowder/services/mullvad.nix +++ b/gunpowder/services/mullvad.nix @@ -1,14 +1,54 @@ -{ lib, config, ... }: +{ + lib, + pkgs, + config, + ... +}: let enable = true; + + metaMark = "0x6d6f6c65"; + ctMark = "0x00000f41"; + + bypassRuleset = pkgs.writeText "mullvad-tailscale-bypass.nft" '' + table inet mullvad_tailscale_bypass { + chain output { + type route hook output priority 0; policy accept; + ip daddr 100.64.0.0/10 meta mark set ${metaMark} ct mark set ${ctMark} + ip6 daddr fd7a:115c:a1e0::/48 meta mark set ${metaMark} ct mark set ${ctMark} + oifname "tailscale0" meta mark set ${metaMark} ct mark set ${ctMark} + } + chain input { + type filter hook input priority -100; policy accept; + ip saddr 100.64.0.0/10 meta mark set ${metaMark} ct mark set ${ctMark} + ip6 saddr fd7a:115c:a1e0::/48 meta mark set ${metaMark} ct mark set ${ctMark} + iifname "tailscale0" meta mark set ${metaMark} ct mark set ${ctMark} + } + } + ''; in lib.mkIf enable { age.secrets.mullvad.file = ../../secrets/mullvad.age; services.mullvad-vpn.enable = true; + systemd.services.mullvad-tailscale-bypass = { + description = "Exempt tailnet traffic from the Mullvad tunnel and kill switch"; + wantedBy = [ "multi-user.target" ]; + after = [ "network-pre.target" ]; + before = [ "mullvad-daemon.service" ]; + serviceConfig = { + Type = "oneshot"; + RemainAfterExit = true; + ExecStart = pkgs.writeShellScript "mullvad-tailscale-bypass-start" '' + ${pkgs.nftables}/bin/nft delete table inet mullvad_tailscale_bypass 2>/dev/null || true + ${pkgs.nftables}/bin/nft -f ${bypassRuleset} + ''; + }; + }; + systemd.services.mullvad-provision = { - description = "Log in to Mullvad and keep it connected"; + description = "Log in to Mullvad and lock networking to the tunnel"; wantedBy = [ "multi-user.target" ]; after = [ "mullvad-daemon.service" ]; requires = [ "mullvad-daemon.service" ]; @@ -20,6 +60,8 @@ }; script = '' until mullvad status >/dev/null 2>&1; do sleep 1; done mullvad account login "$(cat ${config.age.secrets.mullvad.path})" + mullvad lan set block + mullvad lockdown-mode set on mullvad auto-connect set on mullvad connect ''; diff --git a/gunpowder/services/qbittorrent.nix b/gunpowder/services/qbittorrent.nix index e4b74bfbb2615624cadcc1d8995227c01d7cd2b1..a14e7f0610b088286e9500010ce44ed9b162cc8a 100644 --- a/gunpowder/services/qbittorrent.nix +++ b/gunpowder/services/qbittorrent.nix @@ -3,14 +3,10 @@ let enable = true; port = 7248; - mullvadBypassMark = "0x6d6f6c65"; - mullvadBypassCtMark = "0x00000f41"; - - ruleset = pkgs.writeText "qbittorrent-mullvad-scope.nft" '' - table inet qbittorrent_mullvad_scope { + killSwitchRuleset = pkgs.writeText "qbittorrent-mullvad-only.nft" '' + table inet qbittorrent_mullvad_only { chain output { - type route hook output priority 0; policy accept; - meta skuid != "qbittorrent" meta mark set ${mullvadBypassMark} ct mark set ${mullvadBypassCtMark} + type filter hook output priority -50; policy accept; meta skuid "qbittorrent" oifname != "wg-mullvad" oifname != "lo" drop } } @@ -31,20 +27,17 @@ authKey = "tskey-auth-kV7j5FHHHh11CNTRL-wPSNdNQqza8kXxzpnZXha8B7JCvdwCAy"; # One-time key }; }; - systemd.services.qbittorrent-mullvad-scope = { - description = "Scope the Mullvad tunnel to qBittorrent only"; + systemd.services.qbittorrent-mullvad-only = { + description = "Restrict qBittorrent's egress to the Mullvad tunnel only"; wantedBy = [ "multi-user.target" ]; after = [ "network-pre.target" ]; - before = [ - "qbittorrent.service" - "mullvad-daemon.service" - ]; + before = [ "qbittorrent.service" ]; serviceConfig = { Type = "oneshot"; RemainAfterExit = true; - ExecStart = pkgs.writeShellScript "qbittorrent-mullvad-scope-start" '' - ${pkgs.nftables}/bin/nft delete table inet qbittorrent_mullvad_scope 2>/dev/null || true - ${pkgs.nftables}/bin/nft -f ${ruleset} + ExecStart = pkgs.writeShellScript "qbittorrent-mullvad-only-start" '' + ${pkgs.nftables}/bin/nft delete table inet qbittorrent_mullvad_only 2>/dev/null || true + ${pkgs.nftables}/bin/nft -f ${killSwitchRuleset} ''; }; };