From b3611d3a5a6be590e186736985d97e9926238432 Mon Sep 17 00:00:00 2001 From: L-Nafaryus Date: Fri, 9 Aug 2024 11:35:33 +0500 Subject: [PATCH] new: nixosModules.zapret: manage service with ipset lists (incomplete) --- nixosModules/default.nix | 1 + nixosModules/services/zapret.nix | 178 +++++++++++++++++++++++++++++++ 2 files changed, 179 insertions(+) create mode 100644 nixosModules/services/zapret.nix diff --git a/nixosModules/default.nix b/nixosModules/default.nix index 6cb53e6..4ef027d 100644 --- a/nixosModules/default.nix +++ b/nixosModules/default.nix @@ -10,6 +10,7 @@ ./services/papermc.nix ./services/qbittorrent-nox.nix ./services/spoofdpi.nix + ./services/zapret.nix ]; configModule = { diff --git a/nixosModules/services/zapret.nix b/nixosModules/services/zapret.nix new file mode 100644 index 0000000..6f08b12 --- /dev/null +++ b/nixosModules/services/zapret.nix @@ -0,0 +1,178 @@ +{ + lib, + config, + pkgs, + bonPkgs, + ... +}: +with lib; let + cfg = config.services.zapret; + + createFilterList = name: str: ( + lib.concatStringsSep "\n" + (map (ip: "add ${name} ${ip}") + (lib.splitString "\n" (lib.removeSuffix "\n" str))) + ); +in { + options.services.zapret = { + enable = mkEnableOption "DPI bypass multi platform service"; + + package = mkOption { + type = types.package; + default = bonPkgs.zapret; + defaultText = literalExpression "bonPkgs.zapret"; + description = "The package to use."; + }; + + settings = mkOption { + type = types.lines; + default = ""; + + example = '' + TPWS_OPT="--hostspell=HOST --split-http-req=method --split-pos=3 --oob" + NFQWS_OPT_DESYNC="--dpi-desync-ttl=5" + ''; + + description = '' + Rules for zapret to work. Run ```nix-shell -p zapret --command blockcheck``` to get values to pass here. + + Config example can be found here https://github.com/bol-van/zapret/blob/master/config.default + ''; + }; + + firewallType = mkOption { + type = types.enum [ + "iptables" + "nftables" + ]; + default = "nftables"; + description = '' + Which firewall zapret should use. + ''; + }; + + disableIPV4 = mkOption { + type = types.bool; + default = false; + description = '' + Enable usage of IpV4. + ''; + }; + + disableIPV6 = mkOption { + type = types.bool; + default = true; + description = '' + Enable usage of IpV6. + ''; + }; + + mode = mkOption { + type = types.enum [ + "tpws" + "tpws-socks" + "nfqws" + "filter" + "custom" + ]; + default = "tpws"; + description = '' + Which mode zapret should use. + ''; + }; + + # TODO: add filter and anti filter options with optional file paths + # TODO ipset hashsize and maxelem + }; + + config = mkIf cfg.enable { + users.users.tpws = { + isSystemUser = true; + group = "tpws"; + }; + + users.groups.tpws = {}; + + systemd.services.zapret = { + after = ["network-online.target"]; + wants = ["network-online.target"]; + wantedBy = ["multi-user.target"]; + + path = with pkgs; [ + ( + if cfg.firewallType == "iptables" + then iptables + else nftables + ) + gawk + ipset + ]; + + serviceConfig = { + Type = "forking"; + Restart = "no"; + TimeoutSec = "30sec"; + IgnoreSIGPIPE = "no"; + KillMode = "none"; + GuessMainPID = "no"; + RemainAfterExit = "no"; + + ExecStart = "${cfg.package}/bin/zapret start"; + ExecStop = let + stop_script = pkgs.writeShellScriptBin "zapret-stop" '' + ${cfg.package}/bin/zapret stop + ipset destroy zapret -! + ipset destroy nozapret -! + ''; + in "${stop_script}/bin/zapret-stop"; + StandardOutput = "journal"; + StandardError = "journal"; + + EnvironmentFile = pkgs.writeText "${cfg.package.pname}-environment" (concatStrings [ + cfg.settings + '' + MODE=${cfg.mode} + FWTYPE=${cfg.firewallType} + DISABLE_IPV4=${toString cfg.disableIPV4} + DISABLE_IPV6=${toString cfg.disableIPV6} + '' + ]); + + # hardening + DevicePolicy = "closed"; + KeyringMode = "private"; + PrivateTmp = true; + PrivateMounts = true; + ProtectHome = true; + ProtectHostname = true; + ProtectKernelModules = true; + ProtectKernelTunables = true; + ProtectSystem = "strict"; + ProtectProc = "invisible"; + RemoveIPC = true; + RestrictNamespaces = true; + RestrictRealtime = true; + RestrictSUIDSGID = true; + SystemCallArchitectures = "native"; + }; + + preStart = let + zapretListFile = pkgs.writeText "zapretList" (createFilterList "zapret" (lib.readFile cfg.package.passthru.antifilter.ipsmart)); + nozapretListFile = pkgs.writeText "nozapretList" (createFilterList "nozapret" '' + 10.0.0.0/8 + 169.254.0.0/16 + 172.16.0.0/12 + 192.168.0.0/16 + ''); + in '' + ipset create zapret hash:net family inet hashsize 262144 maxelem 522288 -! + ipset flush zapret + ipset restore -! < ${zapretListFile} + + ipset create nozapret hash:net family inet hashsize 262144 maxelem 522288 -! + ipset flush nozapret + ipset restore -! < ${nozapretListFile} + ''; + }; + }; +}