Compare commits

...

5 commits

14 changed files with 362 additions and 113 deletions

View file

@ -113,11 +113,11 @@
"nixpkgs-lib": "nixpkgs-lib" "nixpkgs-lib": "nixpkgs-lib"
}, },
"locked": { "locked": {
"lastModified": 1712014858, "lastModified": 1717285511,
"narHash": "sha256-sB4SWl2lX95bExY2gMFG5HIzvva5AVMJd4Igm+GpZNw=", "narHash": "sha256-iKzJcpdXih14qYVcZ9QC9XuZYnPc6T8YImb6dX166kw=",
"owner": "hercules-ci", "owner": "hercules-ci",
"repo": "flake-parts", "repo": "flake-parts",
"rev": "9126214d0a59633752a136528f5f3b9aa8565b7d", "rev": "2a55567fcf15b1b1c7ed712a2c6fadaec7412ea8",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -205,11 +205,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1712452624, "lastModified": 1717550333,
"narHash": "sha256-R35K+4krhK5B2fcV6W2HFe/uhXmP8YGTb35uZ+nDAxw=", "narHash": "sha256-QebVpP3Z0zVBTSqExNQRg3FLOi2h0bPML6urBbUPzLY=",
"owner": "fufexan", "owner": "fufexan",
"repo": "nix-gaming", "repo": "nix-gaming",
"rev": "06314bbf8fedd83c7253442994a2f0c81d47988e", "rev": "de70cdf224bd40928fe2af7fa558e1bdb7d8d619",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -225,11 +225,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1712459390, "lastModified": 1717297675,
"narHash": "sha256-e12bNDottaGoBgd0AdH/bQvk854xunlWAdZwr/oHO1c=", "narHash": "sha256-43UmlS1Ifx17y93/Vc258U7bOlAAIZbu8dsGDHOIIr0=",
"owner": "nix-community", "owner": "nix-community",
"repo": "nix-index-database", "repo": "nix-index-database",
"rev": "4676d72d872459e1e3a248d049609f110c570e9a", "rev": "972a52bee3991ae1f1899e6452e0d7c01ee566d9",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -240,11 +240,11 @@
}, },
"nixos-hardware": { "nixos-hardware": {
"locked": { "locked": {
"lastModified": 1712760404, "lastModified": 1717574423,
"narHash": "sha256-4zhaEW1nB+nGbCNMjOggWeY5nXs/H0Y71q0+h+jdxoU=", "narHash": "sha256-cz3P5MZffAHwL2IQaNzsqUBsJS+u0J/AAwArHMAcCa0=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixos-hardware", "repo": "nixos-hardware",
"rev": "e1c4bac14beb8c409d0534382cf967171706b9d9", "rev": "d6c6cf6f5fead4057d8fb2d5f30aa8ac1727f177",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -263,11 +263,11 @@
"utils": "utils" "utils": "utils"
}, },
"locked": { "locked": {
"lastModified": 1710449465, "lastModified": 1717515088,
"narHash": "sha256-2orO8nfplp6uQJBFqKkj1iyNMC6TysmwbWwbb4osTag=", "narHash": "sha256-nWOLpPA7+k7V1OjXTuxdsVd5jeeI0b13Di57wvnqkic=",
"owner": "simple-nixos-mailserver", "owner": "simple-nixos-mailserver",
"repo": "nixos-mailserver", "repo": "nixos-mailserver",
"rev": "79c8cfcd5873a85559da6201b116fb38b490d030", "rev": "0d51a32e4799d081f260eb4db37145f5f4ee7456",
"type": "gitlab" "type": "gitlab"
}, },
"original": { "original": {
@ -298,35 +298,30 @@
}, },
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1712769857, "lastModified": 1715947901,
"narHash": "sha256-YUyh+yfB15+2gvvvTvWBQbAUrD1x391QF1PRZUSt87k=", "narHash": "sha256-nAcmnm4/PBA+E3kjtLZJy7aKmzu4Ou5dzVFAC0j9ORM=",
"owner": "chayleaf", "owner": "chayleaf",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "058c6a3724a1cc5ef010ce6f2163d959666e8a86", "rev": "8620504340e055daa4f81b43117e55952c8b7a87",
"type": "github" "type": "github"
}, },
"original": { "original": {
"owner": "chayleaf", "owner": "chayleaf",
"ref": "ci",
"repo": "nixpkgs", "repo": "nixpkgs",
"type": "github" "type": "github"
} }
}, },
"nixpkgs-lib": { "nixpkgs-lib": {
"locked": { "locked": {
"dir": "lib", "lastModified": 1717284937,
"lastModified": 1711703276, "narHash": "sha256-lIbdfCsf8LMFloheeE6N31+BMIeixqyQWbSr2vk79EQ=",
"narHash": "sha256-iMUFArF0WCatKK6RzfUJknjem0H9m4KgorO/p3Dopkk=", "type": "tarball",
"owner": "NixOS", "url": "https://github.com/NixOS/nixpkgs/archive/eb9ceca17df2ea50a250b6b27f7bf6ab0186f198.tar.gz"
"repo": "nixpkgs",
"rev": "d8fe5e6c92d0d190646fb9f1056741a229980089",
"type": "github"
}, },
"original": { "original": {
"dir": "lib", "type": "tarball",
"owner": "NixOS", "url": "https://github.com/NixOS/nixpkgs/archive/eb9ceca17df2ea50a250b6b27f7bf6ab0186f198.tar.gz"
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
} }
}, },
"notlua": { "notlua": {
@ -371,11 +366,11 @@
}, },
"nur": { "nur": {
"locked": { "locked": {
"lastModified": 1712785619, "lastModified": 1717590062,
"narHash": "sha256-1RCStMZUGqus3DAl7jivw7XM5jpbecfqWtA1r45Ts90=", "narHash": "sha256-Xw9yQ3KttiV/t9ClwC2Eo6EX1IEEONw4jCe9s794zhg=",
"owner": "nix-community", "owner": "nix-community",
"repo": "NUR", "repo": "NUR",
"rev": "a0471f14e0499a66898fc1c7d5aff259a9fa58b9", "rev": "a364b6de0f2bd5ed5614ee3827f2ad135c69c73d",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -411,11 +406,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1712715149, "lastModified": 1717553884,
"narHash": "sha256-uOx7GaLV+5hekAYtm/CBr627Pi7+d1Yh70hwKmVjYYo=", "narHash": "sha256-+t3XaYEvlMo5BUJ/6C6RZcEfBTWFVUdMHpNoqUU+pSE=",
"owner": "oxalica", "owner": "oxalica",
"repo": "rust-overlay", "repo": "rust-overlay",
"rev": "9ef1eca23bee5fb8080863909af3802130b2ee57", "rev": "8795c817dfab19243a33387a16c98d2df4075bb3",
"type": "github" "type": "github"
}, },
"original": { "original": {

View file

@ -4,7 +4,7 @@
inputs = { inputs = {
#nixpkgs.url = "github:NixOS/nixpkgs/3dc2b4f8166f744c3b3e9ff8224e7c5d74a5424f"; #nixpkgs.url = "github:NixOS/nixpkgs/3dc2b4f8166f744c3b3e9ff8224e7c5d74a5424f";
# nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; # nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
nixpkgs.url = "github:chayleaf/nixpkgs"; nixpkgs.url = "github:chayleaf/nixpkgs/ci";
nixos-hardware.url = "github:NixOS/nixos-hardware"; nixos-hardware.url = "github:NixOS/nixos-hardware";
nix-index-database = { nix-index-database = {
url = "github:nix-community/nix-index-database"; url = "github:nix-community/nix-index-database";

View file

@ -42,7 +42,7 @@
home.stateVersion = "22.11"; home.stateVersion = "22.11";
home.username = "user"; home.username = "user";
home.homeDirectory = "/home/user"; home.homeDirectory = "/home/user";
terminals = [ "kitty" ]; terminals = [ "alacritty" "foot" "kitty" ];
# xsession.windowManager.i3.enable = true; # xsession.windowManager.i3.enable = true;
wayland.windowManager.sway.enable = true; wayland.windowManager.sway.enable = true;
services.kdeconnect.enable = true; services.kdeconnect.enable = true;
@ -58,13 +58,13 @@
anki-bin anki-bin
(gimp.overrideAttrs (old: { doCheck = false; })) krita blender-hip (gimp.overrideAttrs (old: { doCheck = false; })) krita blender-hip
kdenlive glaxnimate mediainfo kdenlive glaxnimate mediainfo
ghidra (cutter.withPlugins (p: with p; [ sigdb rz-ghidra ])) ghidra # (cutter.withPlugins (p: with p; [ sigdb rz-ghidra ]))
openrgb piper openrgb piper
steam-run steam steam-run steam
# faf-client # faf-client
(osu-lazer-bin.override { #(osu-lazer-bin.override {
command_prefix = "env SDL_VIDEODRIVER=wayland ${obs-studio-plugins.obs-vkcapture}/bin/obs-gamecapture"; #command_prefix = "env SDL_VIDEODRIVER=wayland ${obs-studio-plugins.obs-vkcapture}/bin/obs-gamecapture";
}) #})
taisei taisei
techmino techmino
(wrapOBS { (wrapOBS {

View file

@ -80,6 +80,7 @@
ripgrep ripgrep
(python3.withPackages (p: with p; [ (python3.withPackages (p: with p; [
python-lsp-server python-lsp-server
python-lsp-black
pylsp-mypy pylsp-mypy
python-lsp-server.optional-dependencies.pyflakes python-lsp-server.optional-dependencies.pyflakes
python-lsp-server.optional-dependencies.mccabe python-lsp-server.optional-dependencies.mccabe
@ -433,6 +434,7 @@
pylsp = { pylsp = {
settings = { settings = {
pylsp.plugins.pylsp_mypy.enabled = true; pylsp.plugins.pylsp_mypy.enabled = true;
pylsp.plugins.black.enabled = true;
}; };
}; };
svelte = { }; svelte = { };

View file

@ -22,24 +22,24 @@
"pinned": false, "pinned": false,
"src": { "src": {
"name": null, "name": null,
"sha256": "sha256-wCIffeayOy3kEwmIKB7e+NrliuSpKXoVYC334fxVB3U=", "sha256": "sha256-gHNrozbSBlTFY5VzRyhdiv3YkS+rXTekRJWSXlMalLY=",
"type": "url", "type": "url",
"url": "https://github.com/GloriousEggroll/proton-ge-custom/releases/download/GE-Proton9-1/GE-Proton9-1.tar.gz" "url": "https://github.com/GloriousEggroll/proton-ge-custom/releases/download/GE-Proton9-6/GE-Proton9-6.tar.gz"
}, },
"version": "GE-Proton9-1" "version": "GE-Proton9-6"
}, },
"searxng": { "searxng": {
"cargoLocks": null, "cargoLocks": null,
"date": "2024-03-15", "date": "2024-05-31",
"extract": null, "extract": null,
"name": "searxng", "name": "searxng",
"passthru": null, "passthru": null,
"pinned": false, "pinned": false,
"src": { "src": {
"sha256": "sha256-BqVnp/lByAMr/LOCGkuXCYsomu9hRBGXK3DbBQX10TA=", "sha256": "sha256-okE/Uxl7YqcM99kLJ4KAlMQi50x5m0bPfYp5bv62WEw=",
"type": "tarball", "type": "tarball",
"url": "https://github.com/searxng/searxng/archive/e2af3e49702f6fb40e1614f826544dc3b03bca2f.tar.gz" "url": "https://github.com/searxng/searxng/archive/18fb701be225560b3fb1011cc533f785823f26a4.tar.gz"
}, },
"version": "e2af3e49702f6fb40e1614f826544dc3b03bca2f" "version": "18fb701be225560b3fb1011cc533f785823f26a4"
} }
} }

View file

@ -12,19 +12,19 @@
}; };
proton-ge = { proton-ge = {
pname = "proton-ge"; pname = "proton-ge";
version = "GE-Proton9-1"; version = "GE-Proton9-6";
src = fetchurl { src = fetchurl {
url = "https://github.com/GloriousEggroll/proton-ge-custom/releases/download/GE-Proton9-1/GE-Proton9-1.tar.gz"; url = "https://github.com/GloriousEggroll/proton-ge-custom/releases/download/GE-Proton9-6/GE-Proton9-6.tar.gz";
sha256 = "sha256-wCIffeayOy3kEwmIKB7e+NrliuSpKXoVYC334fxVB3U="; sha256 = "sha256-gHNrozbSBlTFY5VzRyhdiv3YkS+rXTekRJWSXlMalLY=";
}; };
}; };
searxng = { searxng = {
pname = "searxng"; pname = "searxng";
version = "e2af3e49702f6fb40e1614f826544dc3b03bca2f"; version = "18fb701be225560b3fb1011cc533f785823f26a4";
src = fetchTarball { src = fetchTarball {
url = "https://github.com/searxng/searxng/archive/e2af3e49702f6fb40e1614f826544dc3b03bca2f.tar.gz"; url = "https://github.com/searxng/searxng/archive/18fb701be225560b3fb1011cc533f785823f26a4.tar.gz";
sha256 = "sha256-BqVnp/lByAMr/LOCGkuXCYsomu9hRBGXK3DbBQX10TA="; sha256 = "sha256-okE/Uxl7YqcM99kLJ4KAlMQi50x5m0bPfYp5bv62WEw=";
}; };
date = "2024-03-15"; date = "2024-05-31";
}; };
} }

View file

@ -79,9 +79,11 @@ in
sha256 = "sha256-6vYbNmNJBCoU23nVculac24tHqH7F4AZVftIjL93WJU="; sha256 = "sha256-6vYbNmNJBCoU23nVculac24tHqH7F4AZVftIjL93WJU=";
fetchSubmodules = true; fetchSubmodules = true;
}; };
patches = [ ];
}); });
kvmfrOverlay = kvmfr: kvmfr.overrideAttrs (old: { kvmfrOverlay = kvmfr: kvmfr.overrideAttrs (old: {
inherit (pkgs'.looking-glass-client) version src; inherit (pkgs'.looking-glass-client) version src;
patches = [ ./looking-glass.patch ];
}); });
mobile-config-firefox = callPackage ./mobile-config-firefox { }; mobile-config-firefox = callPackage ./mobile-config-firefox { };
osu-wine = callPackage ./osu-wine { }; osu-wine = callPackage ./osu-wine { };

View file

@ -2,10 +2,10 @@
{ {
"fastforwardteam" = buildFirefoxXpiAddon { "fastforwardteam" = buildFirefoxXpiAddon {
pname = "fastforwardteam"; pname = "fastforwardteam";
version = "0.2334"; version = "0.2383";
addonId = "addon@fastforward.team"; addonId = "addon@fastforward.team";
url = "https://addons.mozilla.org/firefox/downloads/file/4177101/fastforwardteam-0.2334.xpi"; url = "https://addons.mozilla.org/firefox/downloads/file/4258067/fastforwardteam-0.2383.xpi";
sha256 = "d790219622469f08316b41c0d01abf2b584a37fa87b45666a74bd30cffb95ed0"; sha256 = "eec6328df3df1afe2cb6a331f6907669d804235551ea766d48655f8f831caf28";
meta = with lib; meta = with lib;
{ {
homepage = "https://fastforward.team"; homepage = "https://fastforward.team";
@ -23,10 +23,10 @@
}; };
"rikaitan" = buildFirefoxXpiAddon { "rikaitan" = buildFirefoxXpiAddon {
pname = "rikaitan"; pname = "rikaitan";
version = "24.3.7.1"; version = "24.5.21.0";
addonId = "tatsu@autistici.org"; addonId = "tatsu@autistici.org";
url = "https://addons.mozilla.org/firefox/downloads/file/4246908/rikaitan-24.3.7.1.xpi"; url = "https://addons.mozilla.org/firefox/downloads/file/4291845/rikaitan-24.5.21.0.xpi";
sha256 = "db849343b029b2f1b510cc66032157502e3fe9e6168072d27e8aad9867b6ec17"; sha256 = "a2a94d88af04023f14daaafda1f6ca7a7197f2ab92ada08ee2e9e4292d57a391";
meta = with lib; meta = with lib;
{ {
homepage = "https://github.com/Ajatt-Tools/rikaitan"; homepage = "https://github.com/Ajatt-Tools/rikaitan";

16
pkgs/looking-glass.patch Normal file
View file

@ -0,0 +1,16 @@
diff --git a/kvmfr.c b/kvmfr.c
index 121aae5b..2f4c9e1a 100644
--- a/kvmfr.c
+++ b/kvmfr.c
@@ -539,7 +539,11 @@ static int __init kvmfr_module_init(void)
if (kvmfr->major < 0)
goto out_free;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 4, 0)
kvmfr->pClass = class_create(THIS_MODULE, KVMFR_DEV_NAME);
+#else
+ kvmfr->pClass = class_create(KVMFR_DEV_NAME);
+#endif
if (IS_ERR(kvmfr->pClass))
goto out_unreg;

View file

@ -49,7 +49,12 @@ let
# vpn table, assign an id but don't actually add a rule for it, so it is the default # vpn table, assign an id but don't actually add a rule for it, so it is the default
vpn_table = 2; vpn_table = 2;
vpn_mtu = config.networking.wireguard.interfaces.wg0.mtu; vpn_iface =
if cfg.vpn.openvpn.enable && !cfg.vpn.wireguard.enable then "tun0"
else if cfg.vpn.wireguard.enable && !cfg.vpn.openvpn.enable then "wg0"
else throw "Exactly one of OpenVPN/Wireguard must be used";
vpn_mtu = config.networking.wireguard.interfaces.${vpn_iface}.mtu or 1320;
vpn_ipv4_mss = vpn_mtu - 40; vpn_ipv4_mss = vpn_mtu - 40;
vpn_ipv6_mss = vpn_mtu - 60; vpn_ipv6_mss = vpn_mtu - 60;
@ -411,7 +416,8 @@ in {
# ethernet wan # ethernet wan
router.interfaces.wan = { router.interfaces.wan = {
dependentServices = [ dependentServices = [
{ service = "wireguard-wg0"; inNetns = false; } (lib.mkIf cfg.vpn.wireguard.enable { service = "wireguard-${vpn_iface}"; inNetns = false; })
(lib.mkIf cfg.vpn.openvpn.enable { service = "openvpn-client"; inNetns = false; })
{ service = "wireguard-wg1"; inNetns = false; } { service = "wireguard-wg1"; inNetns = false; }
]; ];
systemdLink.linkConfig.MACAddressPolicy = "none"; systemdLink.linkConfig.MACAddressPolicy = "none";
@ -503,12 +509,12 @@ in {
selfIp4 = netAddresses.lan4; selfIp4 = netAddresses.lan4;
selfIp6 = netAddresses.lan6; selfIp6 = netAddresses.lan6;
lans = [ "br0" "wg1" ]; lans = [ "br0" "wg1" ];
wans = [ "wg0" "veth-wan-a" ]; wans = [ vpn_iface "veth-wan-a" ];
logPrefix = "lan "; logPrefix = "lan ";
netdevIngressWanRules = with notnft.dsl; with payload; [ netdevIngressWanRules = with notnft.dsl; with payload; [
# check oif only from vpn # check oif only from vpn
# dont check it from veth-wan-a because of dnat fuckery and because we already check packets coming from wan there # dont check it from veth-wan-a because of dnat fuckery and because we already check packets coming from wan there
[(is.eq meta.iifname (set [ "wg0" "wg1" ])) (is.eq (fib (f: with f; [ saddr mark iif ]) (f: f.oif)) missing) (log "lan oif missing ") drop] [(is.eq meta.iifname (set [ vpn_iface "wg1" ])) (is.eq (fib (f: with f; [ saddr mark iif ]) (f: f.oif)) missing) (log "lan oif missing ") drop]
]; ];
inetDnatRules = inetDnatRules =
builtins.concatLists (map builtins.concatLists (map
@ -517,10 +523,10 @@ in {
rule4 = rule.target4; rule6 = rule.target6; rule4 = rule.target4; rule6 = rule.target6;
in with notnft.dsl; with payload; in with notnft.dsl; with payload;
lib.optional (rule4 != null) lib.optional (rule4 != null)
[ (is.eq meta.iifname "wg0") (is.eq ip.protocol protocols) (is.eq th.dport rule.port) [ (is.eq meta.iifname vpn_iface) (is.eq ip.protocol protocols) (is.eq th.dport rule.port)
(if rule4.port == null then dnat.ip rule4.address else dnat.ip rule4.address rule4.port) ] (if rule4.port == null then dnat.ip rule4.address else dnat.ip rule4.address rule4.port) ]
++ lib.optional (rule6 != null) ++ lib.optional (rule6 != null)
[ (is.eq meta.iifname "wg0") (is.eq ip6.nexthdr protocols) (is.eq th.dport rule.port) [ (is.eq meta.iifname vpn_iface) (is.eq ip6.nexthdr protocols) (is.eq th.dport rule.port)
(if rule6.port == null then dnat.ip6 rule6.address else dnat.ip6 rule6.address rule6.port) ] (if rule6.port == null then dnat.ip6 rule6.address else dnat.ip6 rule6.address rule6.port) ]
) )
(builtins.filter (x: x.inVpn && (x.tcp || x.udp)) cfg.dnatRules)) (builtins.filter (x: x.inVpn && (x.tcp || x.udp)) cfg.dnatRules))
@ -574,13 +580,14 @@ in {
[(is.eq ip6.daddr "@block6") (log "block6 ") drop] [(is.eq ip6.daddr "@block6") (log "block6 ") drop]
[(is.eq ip.saddr "@block4") (log "block4/s ") drop] [(is.eq ip.saddr "@block4") (log "block4/s ") drop]
[(is.eq ip6.saddr "@block6") (log "block6/s ") drop] [(is.eq ip6.saddr "@block6") (log "block6/s ") drop]
[(mangle meta.mark wan_table)]
# default to vpn... # default to vpn...
[(mangle meta.mark vpn_table)] # [(mangle meta.mark vpn_table)]
# ...but unvpn traffic to/from force_unvpn4/force_unvpn6 # ...but unvpn traffic to/from force_unvpn4/force_unvpn6
[(is.eq ip.daddr "@force_unvpn4") (mangle meta.mark wan_table)] # [(is.eq ip.daddr "@force_unvpn4") (mangle meta.mark wan_table)]
[(is.eq ip6.daddr "@force_unvpn6") (mangle meta.mark wan_table)] # [(is.eq ip6.daddr "@force_unvpn6") (mangle meta.mark wan_table)]
[(is.eq ip.saddr "@force_unvpn4") (mangle meta.mark wan_table)] # [(is.eq ip.saddr "@force_unvpn4") (mangle meta.mark wan_table)]
[(is.eq ip6.saddr "@force_unvpn6") (mangle meta.mark wan_table)] # [(is.eq ip6.saddr "@force_unvpn6") (mangle meta.mark wan_table)]
# ...force vpn to/from force_vpn4/force_vpn6 # ...force vpn to/from force_vpn4/force_vpn6
# (disable this if it breaks some sites) # (disable this if it breaks some sites)
[(is.eq ip.daddr "@force_vpn4") (mangle meta.mark vpn_table)] [(is.eq ip.daddr "@force_vpn4") (mangle meta.mark vpn_table)]
@ -619,12 +626,12 @@ in {
lib.optionals (rule4 != null) [ lib.optionals (rule4 != null) [
[ (is.eq meta.iifname lanSet) (is.eq ip.protocol protocols) (is.eq ip.saddr rule4.address) [ (is.eq meta.iifname lanSet) (is.eq ip.protocol protocols) (is.eq ip.saddr rule4.address)
(is.eq th.sport (if rule4.port != null then rule4.port else rule.port)) (mangle meta.mark vpn_table) ] (is.eq th.sport (if rule4.port != null then rule4.port else rule.port)) (mangle meta.mark vpn_table) ]
[ (is.eq meta.iifname "wg0") (is.eq ip.protocol protocols) (is.eq ip.daddr rule4.address) [ (is.eq meta.iifname vpn_iface) (is.eq ip.protocol protocols) (is.eq ip.daddr rule4.address)
(is.eq th.dport (if rule4.port != null then rule4.port else rule.port)) (mangle meta.mark vpn_table) ] (is.eq th.dport (if rule4.port != null then rule4.port else rule.port)) (mangle meta.mark vpn_table) ]
] ++ lib.optionals (rule6 != null) [ ] ++ lib.optionals (rule6 != null) [
[ (is.eq meta.iifname lanSet) (is.eq ip6.nexthdr protocols) (is.eq ip6.saddr rule6.address) [ (is.eq meta.iifname lanSet) (is.eq ip6.nexthdr protocols) (is.eq ip6.saddr rule6.address)
(is.eq th.sport (if rule6.port != null then rule6.port else rule.port)) (mangle meta.mark vpn_table) ] (is.eq th.sport (if rule6.port != null then rule6.port else rule.port)) (mangle meta.mark vpn_table) ]
[ (is.eq meta.iifname "wg0") (is.eq ip6.nexthdr protocols) (is.eq ip6.daddr rule6.address) [ (is.eq meta.iifname vpn_iface) (is.eq ip6.nexthdr protocols) (is.eq ip6.daddr rule6.address)
(is.eq th.dport (if rule6.port != null then rule6.port else rule.port)) (mangle meta.mark vpn_table) ] (is.eq th.dport (if rule6.port != null then rule6.port else rule.port)) (mangle meta.mark vpn_table) ]
]) ])
(builtins.filter (x: x.inVpn && (x.tcp || x.udp) && dnatRuleMode x == "mark") cfg.dnatRules)) (builtins.filter (x: x.inVpn && (x.tcp || x.udp) && dnatRuleMode x == "mark") cfg.dnatRules))
@ -756,9 +763,43 @@ in {
# vpn socket is in wan namespace, meaning traffic gets sent through the wan namespace # vpn socket is in wan namespace, meaning traffic gets sent through the wan namespace
# vpn interface is in default namespace, meaning it can be used in the default namespace # vpn interface is in default namespace, meaning it can be used in the default namespace
networking.wireguard.interfaces.wg0 = cfg.wireguard // { # networking.wireguard.interfaces.${vpn_iface} = cfg.vpn.wireguard.config // {
socketNamespace = "wan"; # socketNamespace = "wan";
interfaceNamespace = "init"; # interfaceNamespace = "init";
# };
systemd.services.vpn-tunnel = {
description = "VPN Tunnel";
wantedBy = [
"multi-user.target"
(lib.mkIf cfg.vpn.openvpn.enable "openvpn-client.service")
(lib.mkIf cfg.vpn.wireguard.enable "wireguard-${vpn_iface}.service")
];
after = [ "network.target" "netns-wan.service" ];
bindsTo = [ "netns-wan.service" ];
stopIfChanged = false;
path = [ config.programs.ssh.package ];
script = ''
while true; do
${config.programs.ssh.package}/bin/ssh \
-i /secrets/vpn/sshtunnel.key \
-L ${netAddresses.netnsWan4}:${toString cfg.vpn.tunnel.localPort}:127.0.0.1:${toString cfg.vpn.tunnel.remotePort} \
-p ${toString cfg.vpn.tunnel.port} \
-N -T -v \
sshtunnel@${cfg.vpn.tunnel.ip}
echo "Restarting..."
sleep 10
done
'';
serviceConfig = {
Restart = "always";
Type = "simple";
NetworkNamespacePath = "/var/run/netns/wan";
};
};
services.openvpn.servers = lib.mkIf cfg.vpn.openvpn.enable {
client.config = cfg.vpn.openvpn.config;
}; };
# use main netns's address instead of 127.0.0.1 # use main netns's address instead of 127.0.0.1
@ -847,6 +888,7 @@ in {
wants = [ "nftables-default.service" "avahi-daemon.service" ]; wants = [ "nftables-default.service" "avahi-daemon.service" ];
# allow it to call nft # allow it to call nft
serviceConfig.AmbientCapabilities = [ "CAP_NET_ADMIN" ]; serviceConfig.AmbientCapabilities = [ "CAP_NET_ADMIN" ];
serviceConfig.CapabilityBoundingSet = [ "CAP_NET_ADMIN" ];
}; };
systemd.services.update-rkn-blacklist = { systemd.services.update-rkn-blacklist = {
# fetch vpn_ips.json and vpn_domains.json for unbound # fetch vpn_ips.json and vpn_domains.json for unbound
@ -864,7 +906,6 @@ in {
systemd.timers.update-rkn-blacklist = { systemd.timers.update-rkn-blacklist = {
wantedBy = [ "timers.target" ]; wantedBy = [ "timers.target" ];
partOf = [ "update-rkn-blacklist.service" ]; partOf = [ "update-rkn-blacklist.service" ];
# slightly unusual time to reduce server load
timerConfig.OnCalendar = [ "*-*-* 00:00:00" ]; # every day timerConfig.OnCalendar = [ "*-*-* 00:00:00" ]; # every day
timerConfig.RandomizedDelaySec = 43200; # execute at random time in the first 12 hours timerConfig.RandomizedDelaySec = 43200; # execute at random time in the first 12 hours
}; };

View file

@ -5,6 +5,38 @@
{ {
options.router-settings = { options.router-settings = {
vpn = {
tunnel = {
enable = lib.mkEnableOption "VPN tunnel";
localPort = lib.mkOption {
description = "local port";
type = lib.types.port;
};
remotePort = lib.mkOption {
description = "remote port";
type = lib.types.port;
};
ip = lib.mkOption {
description = "remote ip";
type = router-lib.types.ipv4;
};
port = lib.mkOption {
description = "SSH port";
type = lib.types.port;
default = 22;
};
};
openvpn.enable = lib.mkEnableOption "OpenVPN";
openvpn.config = lib.mkOption {
description = "OpenVPN config";
type = lib.types.lines;
};
wireguard.enable = lib.mkEnableOption "Wireguard";
wireguard.config = lib.mkOption {
description = "wireguard config";
type = lib.types.attrs;
};
};
routerMac = lib.mkOption { routerMac = lib.mkOption {
description = "router's mac address"; description = "router's mac address";
type = lib.types.str; type = lib.types.str;
@ -82,10 +114,6 @@
description = "wlan passphrase"; description = "wlan passphrase";
type = lib.types.str; type = lib.types.str;
}; };
wireguard = lib.mkOption {
description = "wireguard config";
type = lib.types.attrs;
};
dhcpReservations = lib.mkOption { dhcpReservations = lib.mkOption {
description = "dhcp reservations (ipv4)"; description = "dhcp reservations (ipv4)";
default = [ ]; default = [ ];

View file

@ -5,33 +5,19 @@
let let
cfg = config.server; cfg = config.server;
in { python = pkgs.python3.withPackages (p: with p; [ cryptography pyasn1 pyasn1-modules requests ]);
security.acme.certs = lib.flip builtins.mapAttrs (lib.filterAttrs (k: v: v.enableACME) config.services.nginx.virtualHosts) (k: v: { tool = pkgs.writeScript "certspotter.py" ''
postRun = let
python = pkgs.python3.withPackages (p: with p; [ cryptography pyasn1 pyasn1-modules ]);
tbs-hash = pkgs.writeScript "tbs-hash.py" ''
#!${python}/bin/python3 #!${python}/bin/python3
import hashlib ${builtins.readFile ./certspotter.py}
from pyasn1.codec.der.decoder import decode
from pyasn1.codec.der.encoder import encode
from pyasn1_modules import rfc5280
from cryptography import x509
with open('full.pem', 'rb') as f:
cert = x509.load_pem_x509_certificate(f.read())
tbs, _leftover = decode(cert.tbs_certificate_bytes, asn1Spec=rfc5280.TBSCertificate())
precert_exts = [v.dotted_string for k, v in x509.ExtensionOID.__dict__.items() if k.startswith('PRECERT_')]
exts = [ext for ext in tbs["extensions"] if str(ext["extnID"]) not in precert_exts]
tbs["extensions"].clear()
tbs["extensions"].extend(exts)
print(hashlib.sha256(encode(tbs)).hexdigest())
''; '';
in '' in {
${tbs-hash} > "/var/lib/certspotter/tbs-hashes/${k}" security.acme.certs = lib.mkIf config.services.certspotter.enable (lib.flip builtins.mapAttrs (lib.filterAttrs (k: v: v.enableACME) config.services.nginx.virtualHosts) (k: v: {
postRun = ''
${tool} tbs full.pem > "/var/lib/certspotter/tbs-hashes/${k}"
''; '';
}); }));
services.certspotter = { services.certspotter = {
enable = true; enable = false;
extraFlags = [ ]; extraFlags = [ ];
watchlist = [ ".${cfg.domainName}" ]; watchlist = [ ".${cfg.domainName}" ];
hooks = lib.toList (pkgs.writeShellScript "certspotter-hook" '' hooks = lib.toList (pkgs.writeShellScript "certspotter-hook" ''
@ -41,4 +27,25 @@ in {
(echo "Subject: $SUMMARY" && echo && cat "$TEXT_FILENAME") | /run/wrappers/bin/sendmail -i webmaster-certspotter@${cfg.domainName} (echo "Subject: $SUMMARY" && echo && cat "$TEXT_FILENAME") | /run/wrappers/bin/sendmail -i webmaster-certspotter@${cfg.domainName}
''); '');
}; };
systemd.services.certspotter-lite = {
script = ''
exec ${tool} spot \
-c /var/lib/acme/certspotter-lite.txt \
-d ${cfg.domainName} \
-t webmaster-certspotter@${cfg.domainName} \
-s /run/wrappers/bin/sendmail \
/var/lib/acme/*/full.pem
'';
serviceConfig = {
User = "acme";
Group = "acme";
Type = "oneshot";
};
};
systemd.timers.certspotter-lite = {
wantedBy = [ "timers.target" ];
partOf = [ "certspotter-lite.service" ];
timerConfig.OnCalendar = [ "*-*-* 00:00:00" ]; # every day
timerConfig.RandomizedDelaySec = 43200; # execute at random time in the first 12 hours
};
} }

View file

@ -0,0 +1,158 @@
import argparse
import hashlib
import requests
import subprocess
import traceback
from datetime import date
from pyasn1.codec.der.decoder import decode
from pyasn1.codec.der.encoder import encode
from pyasn1_modules import rfc5280
from cryptography import x509
def calc_tbs(pem: bytes) -> str:
cert = x509.load_pem_x509_certificate(pem)
tbs, _leftover = decode(
cert.tbs_certificate_bytes, asn1Spec=rfc5280.TBSCertificate()
)
precert_exts = [
v.dotted_string
for k, v in x509.ExtensionOID.__dict__.items()
if k.startswith("PRECERT_")
]
exts = [ext for ext in tbs["extensions"] if str(ext["extnID"]) not in precert_exts]
tbs["extensions"].clear()
tbs["extensions"].extend(exts)
return hashlib.sha256(encode(tbs)).hexdigest()
def main() -> None:
parser = argparse.ArgumentParser()
subparsers = parser.add_subparsers(required=True)
spot = subparsers.add_parser("spot")
spot.set_defaults(func=spotter)
spot.add_argument("--sendmail", "-s", type=str, required=True)
spot.add_argument("--from", "-f", type=str, required=False, default="Certificate Monitoring")
spot.add_argument("--to", "-t", type=str, required=False)
spot.add_argument("--domain", "-d", type=str, required=True)
spot.add_argument("--cache_file", "-c", type=str, required=True)
spot.add_argument("certs", type=str, nargs="*")
hash = subparsers.add_parser("hash")
hash.set_defaults(func=print_hash)
hash.add_argument("path", type=str)
args = parser.parse_args()
args.func(args)
def print_hash(args) -> None:
with open(args.path, "rb") as f:
print(calc_tbs(f.read()))
def send_mail(
sendmail: str, from_: str | None, to: str | None, subject: str, text: str
):
proc = subprocess.Popen(
[sendmail, "-i"] + (["-F", from_] if from_ else []) + (['--', to] if to else []),
stdin=subprocess.PIPE,
)
assert proc.stdin is not None
proc.stdin.write(f"Subject: {subject}\n\n".encode("utf-8"))
proc.stdin.write((text + "\n").encode("utf-8"))
proc.stdin.close()
proc.wait()
assert proc.returncode == 0
def spotter(args) -> None:
try:
spotter1(args)
except Exception:
subject = "Certificate monitoring failure"
text = traceback.format_exc()
send_mail(args.sendmail, args.__dict__["from"], args.to, subject, text)
def spotter1(args) -> None:
url = f"https://crt.sh/?CN={args.domain}&dir=^&sort=1&group=none"
try:
with open(args.cache_file, "rt") as f:
lastid = int(f.read())
except FileNotFoundError:
lastid = 0
body = requests.get(url).text
def parse_row(row: str, tag: str) -> list[str]:
ret = []
for col in row.split(f"</{tag}>")[:-1]:
if "</A>" in col:
col = col.split("</A>")[-2].split(">")[-1]
else:
col = col.split(">")[-1]
ret.append(col)
return ret
cols: list[str] = []
rows: list[dict[str, str]] = []
for s_row in body.split("<TR>")[2:]:
s_row = s_row.split("</TR>")[0]
if "<TH" in s_row:
cols = parse_row(s_row, "TH")
elif cols:
rows.append({k: v for k, v in zip(cols, parse_row(s_row, "TD"))})
today = date.today()
pem_urls = {}
issuers = {}
cns = {}
if not rows:
raise Exception("No rows found!")
for row in rows:
crtid = int(row["crt.sh ID"])
if crtid <= lastid:
continue
d = date.fromisoformat(row["Logged At"])
if (today - d).days > 30:
continue
pem_urls[crtid] = f"https://crt.sh/?d={crtid}"
issuers[crtid] = row.get("Issuer Name", "")
cns[crtid] = row.get("Matching Identities", "")
if not pem_urls:
return
valid_hashes: set[str] = set()
for path in args.certs:
with open(path, "rb") as f1:
valid_hashes.add(calc_tbs(f1.read()))
pems: dict[int, bytes] = {}
for id, pem_url in pem_urls.items():
lastid = max(id, lastid)
pems[id] = requests.get(pem_url).content
invalid_ids: set[int] = set()
for id, pem in pems.items():
if calc_tbs(pem) not in valid_hashes:
invalid_ids.add(id)
if invalid_ids:
subject = f"{len(invalid_ids)} invalid certs discovered!"
text = "\n".join(
f"https://crt.sh/?id={id} ({cns[id]}, {issuers[id]})"
for id in sorted(invalid_ids)
)
send_mail(args.sendmail, args.__dict__["from"], args.to, subject, text)
with open(args.cache_file, "wt") as f:
f.write(str(lastid))
if __name__ == "__main__":
main()

View file

@ -7,9 +7,9 @@ mozilla-addons-to-nix \
./pkgs/firefox-addons/addons.json \ ./pkgs/firefox-addons/addons.json \
./pkgs/firefox-addons/generated.nix || echo "failed to update firefox addons" ./pkgs/firefox-addons/generated.nix || echo "failed to update firefox addons"
nix flake update nix flake update
if [ -z ${SUDO_ASKPASS+x} ]; then #if [ -z ${SUDO_ASKPASS+x} ]; then
sudo nixos-rebuild switch --flake . --option extra-builtins-file "$(pwd)/extra-builtins.nix" # sudo nixos-rebuild switch --flake . --option extra-builtins-file "$(pwd)/extra-builtins.nix"
else #else
sudo -A nixos-rebuild switch --flake . --option extra-builtins-file "$(pwd)/extra-builtins.nix" # sudo -A nixos-rebuild switch --flake . --option extra-builtins-file "$(pwd)/extra-builtins.nix"
fi #fi
home-manager switch --flake . --option extra-builtins-file "$(pwd)/extra-builtins.nix" #home-manager switch --flake . --option extra-builtins-file "$(pwd)/extra-builtins.nix"