Skip to content

Commit 130bb06

Browse files
authored
nixos/zapret: extra features (#356339)
2 parents 046e35b + 3890e02 commit 130bb06

File tree

1 file changed

+76
-15
lines changed

1 file changed

+76
-15
lines changed

nixos/modules/services/networking/zapret.nix

Lines changed: 76 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,16 @@ let
88
cfg = config.services.zapret;
99

1010
whitelist = lib.optionalString (
11-
cfg.whitelist != null
11+
(builtins.length cfg.whitelist) != 0
1212
) "--hostlist ${pkgs.writeText "zapret-whitelist" (lib.concatStringsSep "\n" cfg.whitelist)}";
1313

1414
blacklist =
15-
lib.optionalString (cfg.blacklist != null)
15+
lib.optionalString ((builtins.length cfg.blacklist) != 0)
1616
"--hostlist-exclude ${pkgs.writeText "zapret-blacklist" (lib.concatStringsSep "\n" cfg.blacklist)}";
1717

18-
ports = if cfg.httpSupport then "80,443" else "443";
18+
params = lib.concatStringsSep " " cfg.params;
19+
20+
qnum = toString cfg.qnum;
1921
in
2022
{
2123
options.services.zapret = {
@@ -29,7 +31,7 @@ in
2931
"--dpi-desync=fake,disorder2"
3032
"--dpi-desync-ttl=1"
3133
"--dpi-desync-autottl=2"
32-
];
34+
]
3335
'';
3436
description = ''
3537
Specify the bypass parameters for Zapret binary.
@@ -40,8 +42,8 @@ in
4042
'';
4143
};
4244
whitelist = lib.mkOption {
43-
default = null;
44-
type = with lib.types; nullOr (listOf str);
45+
default = [ ];
46+
type = with lib.types; listOf str;
4547
example = ''
4648
[
4749
"youtube.com"
@@ -59,8 +61,8 @@ in
5961
'';
6062
};
6163
blacklist = lib.mkOption {
62-
default = null;
63-
type = with lib.types; nullOr (listOf str);
64+
default = [ ];
65+
type = with lib.types; listOf str;
6466
example = ''
6567
[
6668
"example.com"
@@ -96,34 +98,79 @@ in
9698
Http bypass rarely works and you might want to disable it if you don't utilise http connections.
9799
'';
98100
};
101+
httpMode = lib.mkOption {
102+
default = "first";
103+
type = lib.types.enum [
104+
"first"
105+
"full"
106+
];
107+
example = "full";
108+
description = ''
109+
By default this service only changes the first packet sent, which is enough in most cases.
110+
But there are DPIs that monitor the whole traffic within a session.
111+
That requires full processing of every packet, which increases the CPU usage.
112+
113+
Set the mode to `full` if http doesn't work.
114+
'';
115+
};
116+
udpSupport = lib.mkOption {
117+
default = false;
118+
type = lib.types.bool;
119+
description = ''
120+
Enable UDP routing.
121+
This requires you to specify `udpPorts` and `--dpi-desync-any-protocol` parameter.
122+
'';
123+
};
124+
udpPorts = lib.mkOption {
125+
default = [ ];
126+
type = with lib.types; listOf str;
127+
example = ''
128+
[
129+
"50000:50099"
130+
"1234"
131+
]
132+
'';
133+
description = ''
134+
List of UDP ports to route.
135+
Port ranges are delimited with a colon like this "50000:50099".
136+
'';
137+
};
99138
};
100139

101140
config = lib.mkIf cfg.enable (
102141
lib.mkMerge [
103142
{
104143
assertions = [
105144
{
106-
assertion = (cfg.whitelist == null) || (cfg.blacklist == null);
145+
assertion = (builtins.length cfg.whitelist) == 0 || (builtins.length cfg.blacklist) == 0;
107146
message = "Can't specify both whitelist and blacklist.";
108147
}
109148
{
110149
assertion = (builtins.length cfg.params) != 0;
111150
message = "You have to specify zapret parameters. See the params option's description.";
112151
}
152+
{
153+
assertion = cfg.udpSupport -> (builtins.length cfg.udpPorts) != 0;
154+
message = "You have to specify UDP ports or disable UDP support.";
155+
}
156+
{
157+
assertion = !cfg.configureFirewall || !config.networking.nftables.enable;
158+
message = "You need to manually configure you firewall for Zapret service when using nftables.";
159+
}
113160
];
114161

115162
systemd.services.zapret = {
116163
description = "DPI bypass service";
117164
wantedBy = [ "multi-user.target" ];
118165
after = [ "network.target" ];
119166
serviceConfig = {
120-
ExecStart = "${cfg.package}/bin/nfqws --pidfile=/run/nfqws.pid ${lib.concatStringsSep " " cfg.params} ${whitelist} ${blacklist} --qnum=${toString cfg.qnum}";
167+
ExecStart = "${cfg.package}/bin/nfqws --pidfile=/run/nfqws.pid ${params} ${whitelist} ${blacklist} --qnum=${qnum}";
121168
Type = "simple";
122169
PIDFile = "/run/nfqws.pid";
123170
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.
171+
RuntimeMaxSec = "1h"; # This service loves to crash silently or cause network slowdowns. It also restarts instantly. Restarting it at least hourly provided the best experience.
125172

126-
# hardening
173+
# Hardening.
127174
DevicePolicy = "closed";
128175
KeyringMode = "private";
129176
PrivateTmp = true;
@@ -145,9 +192,23 @@ in
145192

146193
# Route system traffic via service for specified ports.
147194
(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-
'';
195+
networking.firewall.extraCommands =
196+
let
197+
httpParams = lib.optionalString (
198+
cfg.httpMode == "first"
199+
) "-m connbytes --connbytes-dir=original --connbytes-mode=packets --connbytes 1:6";
200+
201+
udpPorts = lib.concatStringsSep "," cfg.udpPorts;
202+
in
203+
''
204+
ip46tables -t mangle -I POSTROUTING -p tcp --dport 443 -m connbytes --connbytes-dir=original --connbytes-mode=packets --connbytes 1:6 -m mark ! --mark 0x40000000/0x40000000 -j NFQUEUE --queue-num ${qnum} --queue-bypass
205+
''
206+
+ lib.optionalString (cfg.httpSupport) ''
207+
ip46tables -t mangle -I POSTROUTING -p tcp --dport 80 ${httpParams} -m mark ! --mark 0x40000000/0x40000000 -j NFQUEUE --queue-num ${qnum} --queue-bypass
208+
''
209+
+ lib.optionalString (cfg.udpSupport) ''
210+
ip46tables -t mangle -A POSTROUTING -p udp -m multiport --dports ${udpPorts} -m mark ! --mark 0x40000000/0x40000000 -j NFQUEUE --queue-num ${qnum} --queue-bypass
211+
'';
151212
})
152213
]
153214
);

0 commit comments

Comments
 (0)