2024-10-11 00:03:21 +03:00
{
lib ,
config ,
pkgs ,
. . .
} :
let
cfg = config . services . zapret ;
whitelist = lib . optionalString (
2024-11-16 06:09:16 +03:00
( builtins . length cfg . whitelist ) != 0
2024-10-11 00:03:21 +03:00
) " - - h o s t l i s t ${ pkgs . writeText " z a p r e t - w h i t e l i s t " ( lib . concatStringsSep " \n " cfg . whitelist ) } " ;
blacklist =
2024-11-16 06:09:16 +03:00
lib . optionalString ( ( builtins . length cfg . blacklist ) != 0 )
2024-10-11 00:03:21 +03:00
" - - h o s t l i s t - e x c l u d e ${ pkgs . writeText " z a p r e t - b l a c k l i s t " ( lib . concatStringsSep " \n " cfg . blacklist ) } " ;
2024-11-16 06:09:16 +03:00
params = lib . concatStringsSep " " cfg . params ;
qnum = toString cfg . qnum ;
2024-10-11 00:03:21 +03:00
in
{
options . services . zapret = {
enable = lib . mkEnableOption " t h e Z a p r e t D P I b y p a s s s e r v i c e . " ;
package = lib . mkPackageOption pkgs " z a p r e t " { } ;
params = lib . mkOption {
default = [ ] ;
type = with lib . types ; listOf str ;
example = ''
[
" - - d p i - d e s y n c = f a k e , d i s o r d e r 2 "
" - - d p i - d e s y n c - t t l = 1 "
" - - d p i - d e s y n c - a u t o t t l = 2 "
2024-11-16 06:09:16 +03:00
]
2024-10-11 00:03:21 +03:00
'' ;
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 {
2024-11-16 06:09:16 +03:00
default = [ ] ;
type = with lib . types ; listOf str ;
2024-10-11 00:03:21 +03:00
example = ''
[
" y o u t u b e . c o m "
" g o o g l e v i d e o . c o m "
" y t i m g . c o m "
" y o u t u . b e "
]
'' ;
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 {
2024-11-16 06:09:16 +03:00
default = [ ] ;
type = with lib . types ; listOf str ;
2024-10-11 00:03:21 +03:00
example = ''
[
" e x a m p l e . c o m "
]
'' ;
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 .
'' ;
} ;
2024-11-16 06:09:16 +03:00
httpMode = lib . mkOption {
default = " f i r s t " ;
type = lib . types . enum [
" f i r s t "
" f u l l "
] ;
example = " f u l l " ;
description = ''
By default this service only changes the first packet sent , which is enough in most cases .
But there are DPIs that monitor the whole traffic within a session .
That requires full processing of every packet , which increases the CPU usage .
Set the mode to ` full ` if http doesn't work .
'' ;
} ;
udpSupport = lib . mkOption {
default = false ;
type = lib . types . bool ;
description = ''
Enable UDP routing .
This requires you to specify ` udpPorts ` and ` - - dpi-desync-any-protocol ` parameter .
'' ;
} ;
udpPorts = lib . mkOption {
default = [ ] ;
type = with lib . types ; listOf str ;
example = ''
[
" 5 0 0 0 0 : 5 0 0 9 9 "
" 1 2 3 4 "
]
'' ;
description = ''
List of UDP ports to route .
Port ranges are delimited with a colon like this " 5 0 0 0 0 : 5 0 0 9 9 " .
'' ;
} ;
2024-10-11 00:03:21 +03:00
} ;
config = lib . mkIf cfg . enable (
lib . mkMerge [
{
assertions = [
{
2024-11-16 06:09:16 +03:00
assertion = ( builtins . length cfg . whitelist ) = = 0 || ( builtins . length cfg . blacklist ) = = 0 ;
2024-10-11 00:03:21 +03:00
message = " C a n ' t s p e c i f y b o t h w h i t e l i s t a n d b l a c k l i s t . " ;
}
{
assertion = ( builtins . length cfg . params ) != 0 ;
message = " Y o u h a v e t o s p e c i f y z a p r e t p a r a m e t e r s . S e e t h e p a r a m s o p t i o n ' s d e s c r i p t i o n . " ;
}
2024-11-16 06:09:16 +03:00
{
assertion = cfg . udpSupport -> ( builtins . length cfg . udpPorts ) != 0 ;
message = " Y o u h a v e t o s p e c i f y U D P p o r t s o r d i s a b l e U D P s u p p o r t . " ;
}
{
assertion = ! cfg . configureFirewall || ! config . networking . nftables . enable ;
message = " Y o u n e e d t o m a n u a l l y c o n f i g u r e y o u f i r e w a l l f o r Z a p r e t s e r v i c e w h e n u s i n g n f t a b l e s . " ;
}
2024-10-11 00:03:21 +03:00
] ;
systemd . services . zapret = {
description = " D P I b y p a s s s e r v i c e " ;
wantedBy = [ " m u l t i - u s e r . t a r g e t " ] ;
after = [ " n e t w o r k . t a r g e t " ] ;
serviceConfig = {
2024-11-16 06:09:16 +03:00
ExecStart = " ${ cfg . package } / b i n / n f q w s - - p i d f i l e = / r u n / n f q w s . p i d ${ params } ${ whitelist } ${ blacklist } - - q n u m = ${ qnum } " ;
2024-10-11 00:03:21 +03:00
Type = " s i m p l e " ;
PIDFile = " / r u n / n f q w s . p i d " ;
Restart = " a l w a y s " ;
2024-11-16 06:09:16 +03:00
RuntimeMaxSec = " 1 h " ; # This service loves to crash silently or cause network slowdowns. It also restarts instantly. Restarting it at least hourly provided the best experience.
2024-10-11 00:03:21 +03:00
2024-11-16 06:09:16 +03:00
# Hardening.
2024-10-11 00:03:21 +03:00
DevicePolicy = " c l o s e d " ;
KeyringMode = " p r i v a t e " ;
PrivateTmp = true ;
PrivateMounts = true ;
ProtectHome = true ;
ProtectHostname = true ;
ProtectKernelModules = true ;
ProtectKernelTunables = true ;
ProtectSystem = " s t r i c t " ;
ProtectProc = " i n v i s i b l e " ;
RemoveIPC = true ;
RestrictNamespaces = true ;
RestrictRealtime = true ;
RestrictSUIDSGID = true ;
SystemCallArchitectures = " n a t i v e " ;
} ;
} ;
}
# Route system traffic via service for specified ports.
( lib . mkIf cfg . configureFirewall {
2024-11-16 06:09:16 +03:00
networking . firewall . extraCommands =
let
httpParams = lib . optionalString (
cfg . httpMode = = " f i r s t "
) " - m c o n n b y t e s - - c o n n b y t e s - d i r = o r i g i n a l - - c o n n b y t e s - m o d e = p a c k e t s - - c o n n b y t e s 1 : 6 " ;
udpPorts = lib . concatStringsSep " , " cfg . udpPorts ;
in
''
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
''
+ lib . optionalString ( cfg . httpSupport ) ''
ip46tables - t mangle - I POSTROUTING - p tcp - - dport 80 $ { httpParams } - m mark ! - - mark 0x40000000/0x40000000 - j NFQUEUE - - queue-num $ { qnum } - - queue-bypass
''
+ lib . optionalString ( cfg . udpSupport ) ''
ip46tables - t mangle - A POSTROUTING - p udp - m multiport - - dports $ { udpPorts } - m mark ! - - mark 0x40000000/0x40000000 - j NFQUEUE - - queue-num $ { qnum } - - queue-bypass
'' ;
2024-10-11 00:03:21 +03:00
} )
]
) ;
meta . maintainers = with lib . maintainers ; [
nishimara
] ;
}