Skip to content

Commit 5a5c04d

Browse files
committed
nixos/zapret: init
1 parent 3b34229 commit 5a5c04d

File tree

3 files changed

+162
-0
lines changed

3 files changed

+162
-0
lines changed

nixos/doc/manual/release-notes/rl-2411.section.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,8 @@
181181

182182
- [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).
183183

184+
- [Zapret](https://github.com/bol-van/zapret), a DPI bypass tool. Available as [services.zapret](option.html#opt-services.zapret).
185+
184186
## Backward Incompatibilities {#sec-release-24.11-incompatibilities}
185187

186188
- 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.

nixos/modules/module-list.nix

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1276,6 +1276,7 @@
12761276
./services/networking/xray.nix
12771277
./services/networking/xrdp.nix
12781278
./services/networking/yggdrasil.nix
1279+
./services/networking/zapret.nix
12791280
./services/networking/zerobin.nix
12801281
./services/networking/zeronet.nix
12811282
./services/networking/zerotierone.nix
Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
{
2+
lib,
3+
config,
4+
pkgs,
5+
...
6+
}:
7+
let
8+
cfg = config.services.zapret;
9+
10+
whitelist = lib.optionalString (
11+
cfg.whitelist != null
12+
) "--hostlist ${pkgs.writeText "zapret-whitelist" (lib.concatStringsSep "\n" cfg.whitelist)}";
13+
14+
blacklist =
15+
lib.optionalString (cfg.blacklist != null)
16+
"--hostlist-exclude ${pkgs.writeText "zapret-blacklist" (lib.concatStringsSep "\n" cfg.blacklist)}";
17+
18+
ports = if cfg.httpSupport then "80,443" else "443";
19+
in
20+
{
21+
options.services.zapret = {
22+
enable = lib.mkEnableOption "the Zapret DPI bypass service.";
23+
package = lib.mkPackageOption pkgs "zapret" { };
24+
params = lib.mkOption {
25+
default = [ ];
26+
type = with lib.types; listOf str;
27+
example = ''
28+
[
29+
"--dpi-desync=fake,disorder2"
30+
"--dpi-desync-ttl=1"
31+
"--dpi-desync-autottl=2"
32+
];
33+
'';
34+
description = ''
35+
Specify the bypass parameters for Zapret binary.
36+
There are no universal parameters as they vary between different networks, so you'll have to find them yourself.
37+
38+
This can be done by running the `blockcheck` binary from zapret package, i.e. `nix-shell -p zapret --command blockcheck`.
39+
It'll try different params and then tell you which params are working for your network.
40+
'';
41+
};
42+
whitelist = lib.mkOption {
43+
default = null;
44+
type = with lib.types; nullOr (listOf str);
45+
example = ''
46+
[
47+
"youtube.com"
48+
"googlevideo.com"
49+
"ytimg.com"
50+
"youtu.be"
51+
]
52+
'';
53+
description = ''
54+
Specify a list of domains to bypass. All other domains will be ignored.
55+
You can specify either whitelist or blacklist, but not both.
56+
If neither are specified, then bypass all domains.
57+
58+
It is recommended to specify the whitelist. This will make sure that other resources won't be affected by this service.
59+
'';
60+
};
61+
blacklist = lib.mkOption {
62+
default = null;
63+
type = with lib.types; nullOr (listOf str);
64+
example = ''
65+
[
66+
"example.com"
67+
]
68+
'';
69+
description = ''
70+
Specify a list of domains NOT to bypass. All other domains will be bypassed.
71+
You can specify either whitelist or blacklist, but not both.
72+
If neither are specified, then bypass all domains.
73+
'';
74+
};
75+
qnum = lib.mkOption {
76+
default = 200;
77+
type = lib.types.int;
78+
description = ''
79+
Routing queue number.
80+
Only change this if you already use the default queue number somewhere else.
81+
'';
82+
};
83+
configureFirewall = lib.mkOption {
84+
default = true;
85+
type = lib.types.bool;
86+
description = ''
87+
Whether to setup firewall routing so that system http(s) traffic is forwarded via this service.
88+
Disable if you want to set it up manually.
89+
'';
90+
};
91+
httpSupport = lib.mkOption {
92+
default = true;
93+
type = lib.types.bool;
94+
description = ''
95+
Whether to route http traffic on port 80.
96+
Http bypass rarely works and you might want to disable it if you don't utilise http connections.
97+
'';
98+
};
99+
};
100+
101+
config = lib.mkIf cfg.enable (
102+
lib.mkMerge [
103+
{
104+
assertions = [
105+
{
106+
assertion = (cfg.whitelist == null) || (cfg.blacklist == null);
107+
message = "Can't specify both whitelist and blacklist.";
108+
}
109+
{
110+
assertion = (builtins.length cfg.params) != 0;
111+
message = "You have to specify zapret parameters. See the params option's description.";
112+
}
113+
];
114+
115+
systemd.services.zapret = {
116+
description = "DPI bypass service";
117+
wantedBy = [ "multi-user.target" ];
118+
after = [ "network.target" ];
119+
serviceConfig = {
120+
ExecStart = "${cfg.package}/bin/nfqws --pidfile=/run/nfqws.pid ${lib.concatStringsSep " " cfg.params} ${whitelist} ${blacklist} --qnum=${toString cfg.qnum}";
121+
Type = "simple";
122+
PIDFile = "/run/nfqws.pid";
123+
Restart = "always";
124+
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.
125+
126+
# hardening
127+
DevicePolicy = "closed";
128+
KeyringMode = "private";
129+
PrivateTmp = true;
130+
PrivateMounts = true;
131+
ProtectHome = true;
132+
ProtectHostname = true;
133+
ProtectKernelModules = true;
134+
ProtectKernelTunables = true;
135+
ProtectSystem = "strict";
136+
ProtectProc = "invisible";
137+
RemoveIPC = true;
138+
RestrictNamespaces = true;
139+
RestrictRealtime = true;
140+
RestrictSUIDSGID = true;
141+
SystemCallArchitectures = "native";
142+
};
143+
};
144+
}
145+
146+
# Route system traffic via service for specified ports.
147+
(lib.mkIf cfg.configureFirewall {
148+
networking.firewall.extraCommands = ''
149+
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
150+
'';
151+
})
152+
]
153+
);
154+
155+
meta.maintainers = with lib.maintainers; [
156+
voronind
157+
nishimara
158+
];
159+
}

0 commit comments

Comments
 (0)