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

nixos/zapret: init #347805

Merged
merged 2 commits into from
Oct 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions maintainers/maintainer-list.nix
Original file line number Diff line number Diff line change
Expand Up @@ -22608,6 +22608,13 @@
githubId = 144771550;
name = "Luca Uricariu";
};
voronind = {
email = "[email protected]";
name = "Dmitry Voronin";
github = "voronind-com";
githubId = 22127600;
keys = [ { fingerprint = "3241 FDAD 82A7 E22D 4279 F405 913F 3267 9278 2E1C"; } ];
};
votava = {
email = "[email protected]";
github = "janvotava";
Expand Down
2 changes: 2 additions & 0 deletions nixos/doc/manual/release-notes/rl-2411.section.md
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,8 @@

- [Fedimint](https://github.com/fedimint/fedimint), a module based system for building federated applications (Federated E-Cash Mint). Available as [services.fedimintd](#opt-services.fedimintd).

- [Zapret](https://github.com/bol-van/zapret), a DPI bypass tool. Available as [services.zapret](option.html#opt-services.zapret).

## Backward Incompatibilities {#sec-release-24.11-incompatibilities}

- The `sound` options have been removed or renamed, as they had a lot of unintended side effects. See [below](#sec-release-24.11-migration-sound) for details.
Expand Down
1 change: 1 addition & 0 deletions nixos/modules/module-list.nix
Original file line number Diff line number Diff line change
Expand Up @@ -1276,6 +1276,7 @@
./services/networking/xray.nix
./services/networking/xrdp.nix
./services/networking/yggdrasil.nix
./services/networking/zapret.nix
./services/networking/zerobin.nix
./services/networking/zeronet.nix
./services/networking/zerotierone.nix
Expand Down
159 changes: 159 additions & 0 deletions nixos/modules/services/networking/zapret.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
{
lib,
config,
pkgs,
...
}:
let
cfg = config.services.zapret;

whitelist = lib.optionalString (
cfg.whitelist != null
) "--hostlist ${pkgs.writeText "zapret-whitelist" (lib.concatStringsSep "\n" cfg.whitelist)}";

blacklist =
lib.optionalString (cfg.blacklist != null)
"--hostlist-exclude ${pkgs.writeText "zapret-blacklist" (lib.concatStringsSep "\n" cfg.blacklist)}";

ports = if cfg.httpSupport then "80,443" else "443";
in
{
options.services.zapret = {
enable = lib.mkEnableOption "the Zapret DPI bypass service.";
package = lib.mkPackageOption pkgs "zapret" { };
params = lib.mkOption {
default = [ ];
type = with lib.types; listOf str;
example = ''
[
"--dpi-desync=fake,disorder2"
"--dpi-desync-ttl=1"
"--dpi-desync-autottl=2"
];
'';
description = ''
Specify the bypass parameters for Zapret binary.
There are no universal parameters as they vary between different networks, so you'll have to find them yourself.

This can be done by running the `blockcheck` binary from zapret package, i.e. `nix-shell -p zapret --command blockcheck`.
It'll try different params and then tell you which params are working for your network.
'';
};
whitelist = lib.mkOption {
default = null;
type = with lib.types; nullOr (listOf str);
example = ''
[
"youtube.com"
"googlevideo.com"
"ytimg.com"
"youtu.be"
]
'';
description = ''
Specify a list of domains to bypass. All other domains will be ignored.
You can specify either whitelist or blacklist, but not both.
If neither are specified, then bypass all domains.

It is recommended to specify the whitelist. This will make sure that other resources won't be affected by this service.
'';
};
blacklist = lib.mkOption {
default = null;
type = with lib.types; nullOr (listOf str);
example = ''
[
"example.com"
]
'';
description = ''
Specify a list of domains NOT to bypass. All other domains will be bypassed.
You can specify either whitelist or blacklist, but not both.
If neither are specified, then bypass all domains.
'';
};
qnum = lib.mkOption {
default = 200;
type = lib.types.int;
description = ''
Routing queue number.
Only change this if you already use the default queue number somewhere else.
'';
};
configureFirewall = lib.mkOption {
default = true;
type = lib.types.bool;
description = ''
Whether to setup firewall routing so that system http(s) traffic is forwarded via this service.
Disable if you want to set it up manually.
'';
};
httpSupport = lib.mkOption {
default = true;
type = lib.types.bool;
description = ''
Whether to route http traffic on port 80.
Http bypass rarely works and you might want to disable it if you don't utilise http connections.
'';
};
};

config = lib.mkIf cfg.enable (
lib.mkMerge [
{
assertions = [
{
assertion = (cfg.whitelist == null) || (cfg.blacklist == null);
message = "Can't specify both whitelist and blacklist.";
}
{
assertion = (builtins.length cfg.params) != 0;
message = "You have to specify zapret parameters. See the params option's description.";
}
];

systemd.services.zapret = {
voronind-com marked this conversation as resolved.
Show resolved Hide resolved
description = "DPI bypass service";
wantedBy = [ "multi-user.target" ];
after = [ "network.target" ];
serviceConfig = {
ExecStart = "${cfg.package}/bin/nfqws --pidfile=/run/nfqws.pid ${lib.concatStringsSep " " cfg.params} ${whitelist} ${blacklist} --qnum=${toString cfg.qnum}";
Type = "simple";
PIDFile = "/run/nfqws.pid";
Restart = "always";
RuntimeMaxSec = "1h"; # This service loves to crash silently or cause network slowdowns. It also restarts instantly. In my experience restarting it hourly provided the best experience.

# 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";
};
};
}

# Route system traffic via service for specified ports.
(lib.mkIf cfg.configureFirewall {
networking.firewall.extraCommands = ''
iptables -t mangle -I POSTROUTING -p tcp -m multiport --dports ${ports} -m connbytes --connbytes-dir=original --connbytes-mode=packets --connbytes 1:6 -m mark ! --mark 0x40000000/0x40000000 -j NFQUEUE --queue-num ${toString cfg.qnum} --queue-bypass
voronind-com marked this conversation as resolved.
Show resolved Hide resolved
'';
})
]
);

meta.maintainers = with lib.maintainers; [
voronind
nishimara
];
}
Loading