Merge pull request #17 from egor-white/hybrid

Hybrid
This commit is contained in:
CherretGit
2026-02-17 22:20:44 +07:00
committed by GitHub
21 changed files with 759 additions and 231 deletions

View File

@@ -11,8 +11,12 @@ on:
description: "Tag for the release (x.x.x)"
required: true
type: string
zapret-version:
description: "Zapret version (x.x)"
nfqws-version:
description: "Nfqws version (x.x)"
required: true
type: string
nfqws2-version:
description: "Nfqws2 version (x.x)"
required: true
type: string
version:
@@ -36,7 +40,10 @@ jobs:
build:
runs-on: ubuntu-latest
env:
ZAPRET_VERSION: ${{ inputs.zapret-version }}
NFQWS_VERSION: ${{ inputs.nfqws-version }}
NFQWS2_VERSION: ${{ inputs.nfqws2-version }}
MODULE_VERSION: ${{ inputs.version }}
MODULE_VERSION_CODE: ${{ inputs.version_code }}
steps:
- uses: actions/checkout@v4
@@ -84,33 +91,15 @@ jobs:
- name: Create module.prop
run: |
cat > zaprett/module.prop <<EOF
id=zaprett
name=zaprett
version=${{ inputs.version }}
versionCode=${{ inputs.version_code }}
author=egor-white, Cherret
description=Ускорение CDN серверов Google. ТГК: https://t.me/zaprett_module
updateJson=https://raw.githubusercontent.com/egor-white/zaprett/refs/heads/main/update.json
EOF
sudo dpkg --add-architecture i386
sudo apt update
sudo apt install -y build-essential pkg-config just unzip libc6-dev-i386 gcc-multilib
cat > zaprett-hosts/module.prop <<EOF
id=zaprett
name=zaprett-hosts
version=${{ inputs.version }}
versionCode=${{ inputs.version_code }}
author=egor-white, Cherret
description=Ускорение CDN серверов Google. ТГК: https://t.me/zaprett_module
updateJson=https://raw.githubusercontent.com/egor-white/zaprett/refs/heads/main/update-hosts.json
EOF
- name: Make executable
run: chmod +x build-module.sh
- name: Create archives
run: |
cd zaprett && zip -r ../zaprett.zip ./* && cd ..
cd zaprett-hosts && zip -r ../zaprett-hosts.zip ./* && cd ..
mv zaprett.zip out/
mv zaprett-hosts.zip out/
- name: Build module
run: ./build-module.sh
- name: Create release
if: ${{ inputs.create_release == 'true' }}

View File

@@ -11,8 +11,12 @@ on:
description: "Tag for the release (x.x.x)"
required: true
type: string
zapret-version:
description: "Zapret version (x.x)"
nfqws-version:
description: "Nfqws version (x.x)"
required: true
type: string
nfqws2-version:
description: "Nfqws2 version (x.x)"
required: true
type: string
version:
@@ -36,7 +40,10 @@ jobs:
build:
runs-on: ubuntu-latest
env:
ZAPRET_VERSION: ${{ inputs.zapret-version }}
NFQWS_VERSION: ${{ inputs.nfqws-version }}
NFQWS2_VERSION: ${{ inputs.nfqws2-version }}
MODULE_VERSION: ${{ inputs.version }}
MODULE_VERSION_CODE: ${{ inputs.version_code }}
steps:
- uses: actions/checkout@v4
@@ -74,45 +81,15 @@ jobs:
- name: Download and copy actual lists
run: |
wget https://raw.githubusercontent.com/CherretGit/zaprett-repo/refs/heads/main/lists/include/list-youtube.txt -O lists/list-youtube.txt
wget https://raw.githubusercontent.com/CherretGit/zaprett-repo/refs/heads/main/lists/include/list-discord.txt -O lists/list-discord.txt
sudo dpkg --add-architecture i386
sudo apt update
sudo apt install -y build-essential pkg-config just unzip libc6-dev-i386 gcc-multilib
cp lists/* zaprett/zaprett/lists/include/
- name: Make executable
run: chmod +x build-module.sh
cp lists/* zaprett-hosts/zaprett/lists/include/
cp hosts/hosts zaprett-hosts/system/etc
- name: Create module.prop
run: |
cat > zaprett/module.prop <<EOF
id=zaprett
name=zaprett
version=${{ inputs.version }}
versionCode=${{ inputs.version_code }}
author=egor-white, Cherret
description=Ускорение CDN серверов Google. ТГК: https://t.me/zaprett_module
updateJson=https://raw.githubusercontent.com/egor-white/zaprett/refs/heads/main/update.json
EOF
cat > zaprett-hosts/module.prop <<EOF
id=zaprett
name=zaprett-hosts
version=${{ inputs.version }}
versionCode=${{ inputs.version_code }}
author=egor-white, Cherret
description=Ускорение CDN серверов Google. ТГК: https://t.me/zaprett_module
updateJson=https://raw.githubusercontent.com/egor-white/zaprett/refs/heads/main/update-hosts.json
EOF
- name: Create archives
run: |
cd zaprett && zip -r ../zaprett.zip ./* && cd ..
cd zaprett-hosts && zip -r ../zaprett-hosts.zip ./* && cd ..
mv zaprett.zip out/
mv zaprett-hosts.zip out/
- name: Build module
run: ./build-module.sh
- name: Create release
if: ${{ inputs.create_release == 'true' }}

3
.gitignore vendored
View File

@@ -1 +1,4 @@
.gitignore
target
deps
out

3
.gitmodules vendored
View File

@@ -1,3 +1,6 @@
[submodule "rust/crates/libnfqws/zapret"]
path = rust/crates/libnfqws/zapret
url = https://github.com/bol-van/zapret.git
[submodule "rust/crates/libnfqws2/zapret2"]
path = rust/crates/libnfqws2/zapret2
url = https://github.com/bol-van/zapret2

65
build-module.sh Normal file
View File

@@ -0,0 +1,65 @@
#!/usr/bin/env bash
set -euo pipefail
: "${MODULE_VERSION:?MODULE_VERSION is not set}"
: "${MODULE_VERSION_CODE:?MODULE_VERSION_CODE is not set}"
echo "Build zaprett binaries"
just -f rust/justfile build-android --release
echo "Make build dirs"
mkdir -p zaprett/system/bin
mkdir -p zaprett/zaprett/bin
mkdir -p zaprett/zaprett/lists/include
mkdir -p zaprett/zaprett/lists/exclude
mkdir -p zaprett/zaprett/strategies/nfqws2/libs
mkdir -p zaprett-hosts/system/bin
mkdir -p zaprett-hosts/system/etc
mkdir -p zaprett-hosts/zaprett/bin
mkdir -p zaprett-hosts/zaprett/lists/include
mkdir -p zaprett-hosts/zaprett/lists/exclude
mkdir -p zaprett/zaprett/strategies/nfqws2/libs
mkdir -p out lists
echo "Copy files to dirs"
cp rust/target/armv7-linux-androideabi/release/zaprett zaprett/system/bin/zaprett-armv7
cp rust/target/aarch64-linux-android/release/zaprett zaprett/system/bin/zaprett-aarch64
cp rust/target/x86_64-linux-android/release/zaprett zaprett/system/bin/zaprett-x86_64
cp -a src/* zaprett/
cp -r zaprett/* zaprett-hosts/
echo "Download and copy actual lists"
wget https://raw.githubusercontent.com/CherretGit/zaprett-repo/refs/heads/main/lists/include/list-youtube.txt -O lists/list-youtube.txt
wget https://raw.githubusercontent.com/CherretGit/zaprett-repo/refs/heads/main/lists/include/list-discord.txt -O lists/list-discord.txt
cp lists/* zaprett/zaprett/lists/include/
cp lists/* zaprett-hosts/zaprett/lists/include/
cp hosts/hosts zaprett-hosts/system/etc
echo "Create module.prop"
cat > zaprett/module.prop <<EOF
id=zaprett
name=zaprett
version=$MODULE_VERSION
versionCode=$MODULE_VERSION_CODE
author=egor-white, Cherret
description=Ускорение CDN серверов Google. ТГК: https://t.me/zaprett_module
updateJson=https://raw.githubusercontent.com/egor-white/zaprett/refs/heads/main/update.json
EOF
cat > zaprett-hosts/module.prop <<EOF
id=zaprett
name=zaprett-hosts
version=$MODULE_VERSION
versionCode=$MODULE_VERSION_CODE
author=egor-white, Cherret
description=Ускорение CDN серверов Google. ТГК: https://t.me/zaprett_module
updateJson=https://raw.githubusercontent.com/egor-white/zaprett/refs/heads/main/update-hosts.json
EOF
echo "Create archives"
cd zaprett && zip -r ../zaprett.zip ./* && cd ..
cd zaprett-hosts && zip -r ../zaprett-hosts.zip ./* && cd ..
mv zaprett.zip out/
mv zaprett-hosts.zip out/
echo "Clean temp files"
rm -rf zaprett zaprett-hosts lists

93
rust/Cargo.lock generated
View File

@@ -193,32 +193,6 @@ version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75"
[[package]]
name = "const-random"
version = "0.1.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87e00182fe74b066627d63b85fd550ac2998d4b0bd86bfed477a0ae4c7c71359"
dependencies = [
"const-random-macro",
]
[[package]]
name = "const-random-macro"
version = "0.1.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e"
dependencies = [
"getrandom",
"once_cell",
"tiny-keccak",
]
[[package]]
name = "crunchy"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5"
[[package]]
name = "daemonize"
version = "0.5.0"
@@ -228,15 +202,6 @@ dependencies = [
"libc",
]
[[package]]
name = "dlv-list"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "442039f5147480ba31067cb00ada1adae6892028e40e45fc5de7b7df6dcc1b5f"
dependencies = [
"const-random",
]
[[package]]
name = "either"
version = "1.15.0"
@@ -274,17 +239,6 @@ version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "52051878f80a721bb68ebfbc930e07b65ba72f2da88968ea5c06fd6ca3d3a127"
[[package]]
name = "getrandom"
version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592"
dependencies = [
"cfg-if",
"libc",
"wasi",
]
[[package]]
name = "getset"
version = "0.1.6"
@@ -303,12 +257,6 @@ version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280"
[[package]]
name = "hashbrown"
version = "0.14.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
[[package]]
name = "heck"
version = "0.5.0"
@@ -385,6 +333,16 @@ dependencies = [
"once_cell",
]
[[package]]
name = "libnfqws2"
version = "0.0.1"
dependencies = [
"bindgen",
"cc",
"glob",
"once_cell",
]
[[package]]
name = "lock_api"
version = "0.4.14"
@@ -485,16 +443,6 @@ version = "1.70.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe"
[[package]]
name = "ordered-multimap"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49203cdcae0030493bad186b28da2fa25645fa276a51b6fec8010d281e02ef79"
dependencies = [
"dlv-list",
"hashbrown",
]
[[package]]
name = "parking_lot"
version = "0.12.5"
@@ -622,16 +570,6 @@ version = "0.8.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58"
[[package]]
name = "rust-ini"
version = "0.21.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "796e8d2b6696392a43bea58116b667fb4c29727dc5abd27d6acf338bb4f688c7"
dependencies = [
"cfg-if",
"ordered-multimap",
]
[[package]]
name = "rustc-hash"
version = "2.1.1"
@@ -807,15 +745,6 @@ dependencies = [
"syn",
]
[[package]]
name = "tiny-keccak"
version = "2.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237"
dependencies = [
"crunchy",
]
[[package]]
name = "tokio"
version = "1.48.0"
@@ -1113,11 +1042,11 @@ dependencies = [
"getset",
"libc",
"libnfqws",
"libnfqws2",
"log",
"nix",
"pretty_env_logger",
"regex",
"rust-ini",
"serde",
"serde_json",
"sysctl",

View File

@@ -15,22 +15,171 @@ rel_manifest_path!(NFQ, "zapret/nfq");
rel_manifest_path!(NFQ_CRYPTO, "zapret/nfq/crypto");
fn main() {
cc::Build::new()
.files(
glob::glob(&format!("{}/*.c", NFQ.display()))
.unwrap()
.filter_map(Result::ok),
)
.files(
glob::glob(&format!("{}/*.c", NFQ_CRYPTO.display()))
.unwrap()
.filter_map(Result::ok),
)
.include(&*NFQ)
.include(&*NFQ_CRYPTO)
.flag("-w")
.define("main", "nfqws_main")
.compile("libnfqws.a");
const SYMBOLS: &[&str] = &[
"DLOG",
"net32_add",
"net16_add",
"tcp_find_option",
"tcp_find_scale_factor",
"tcp_find_mss",
"proto_skip_ipv6",
"proto_check_ipv4",
"proto_check_ipv6",
"extract_ports",
"extract_endpoints",
"proto_name",
"family_from_proto",
"str_ip",
"print_ip",
"str_srcdst_ip6",
"str_ip6hdr",
"print_ip6hdr",
"str_tcphdr",
"print_tcphdr",
"l7proto_str",
"l7_proto_match",
"posmarker_name",
"AnyProtoPos",
"ResolvePos",
"HttpPos",
"TLSPos",
"TLSFindExt",
"TLSAdvanceToHostInSNI",
"ResolveMultiPos",
"IsHttp",
"HttpFindHost",
"IsHttpReply",
"HttpReplyCode",
"HttpExtractHeader",
"HttpExtractHost",
"HttpReplyLooksLikeDPIRedirect",
"TLSVersionStr",
"TLSRecordDataLen",
"TLSRecordLen",
"DLOG_CONDUP",
"IsTLSRecordFull",
"DLOG_ERR",
"IsTLSClientHello",
"DLOG_PERROR",
"LOG_APPEND",
"HOSTLIST_DEBUGLOG_APPEND",
"hexdump_limited_dlog",
"TLSHandshakeLen",
"IsTLSHandshakeClientHello",
"IsTLSHandshakeFull",
"TLSFindExtLenOffsetInHandshake",
"TLSFindExtLen",
"TLSFindExtInHandshake",
"TLSHelloExtractHost",
"TLSHelloExtractHostFromHandshake",
"IsQUICCryptoHello",
"QUICDraftVersion",
"str_udphdr",
"QUICIsLongHeader",
"dp_init",
"dp_list_add",
"dp_clear",
"dp_entry_destroy",
"dp_list_destroy",
"dp_list_have_autohostlist",
"cleanup_params",
"progname",
"tld",
"QUICExtractVersion",
"QUICExtractDCID",
"QUICDecryptInitial",
"print_udphdr",
"QUICDefragCrypto",
"IsQUICInitial",
"IsWireguardHandshakeInitiation",
"proto_skip_ipv4",
"IsDiscordIpDiscoveryRequest",
"IsStunMessage",
"proto_check_tcp",
"proto_skip_tcp",
"proto_check_udp",
"proto_skip_udp",
"proto_dissect_l3l4",
"tcp_synack_segment",
"tcp_syn_segment",
"rawsend_cleanup",
"rawsend_preinit",
"rawsend",
"rawsend_rp",
"rawsend_queue",
"wlan_info_deinit",
"wlan_info_init",
"wlan_info_get_rate_limited",
"wlans",
"wlan_ifname2ssid",
"wlan_ifidx2ssid",
"wlan_ssid_search_ifname",
"wlan_ssid_search_ifidx",
"verdict_tcp_csum_fix",
"dpi_desync_packet",
"verdict_udp_csum_fix",
"unique_size_t",
"qsort_size_t",
"dbgprint_socket_buffers",
"fake_http_request_default",
"rtrim",
"replace_char",
"fake_tls_clienthello_default",
"params",
"strncasestr",
"load_file",
"append_to_list_file",
"expand_bits",
"strip_host_to_ip",
"ntop46",
"ntop46_port",
"print_sockaddr",
"saport",
"pntoh64",
"set_socket_buffers",
"phton64",
"seq_within",
"ipv6_addr_is_zero",
"parse_hex_str",
"fprint_localtime",
"file_mod_time",
"file_mod_signature",
"file_open_test",
"pf_in_range",
"pf_parse",
"pf_is_empty",
"fill_random_bytes",
"fill_random_az",
"fill_random_az09",
"set_console_io_buffering",
"set_env_exedir",
"str_cidr4",
"print_cidr4",
"str_cidr6",
"print_cidr6",
"parse_cidr4",
"parse_cidr6",
];
let mut cc_builder = cc::Build::new();
cc_builder.files(
glob::glob(&format!("{}/*.c", NFQ.display()))
.unwrap()
.filter_map(Result::ok),
);
cc_builder.files(
glob::glob(&format!("{}/*.c", NFQ_CRYPTO.display()))
.unwrap()
.filter_map(Result::ok),
);
cc_builder.include(&*NFQ);
cc_builder.include(&*NFQ_CRYPTO);
cc_builder.flag("-w");
for &symbol in SYMBOLS {
let val = format!("nfq_{}", symbol);
cc_builder.define(symbol, Some(&val[..]));
}
cc_builder.define("main", "nfqws_main");
cc_builder.compile("libnfqws.a");
println!("cargo:rustc-link-lib=z");
println!("cargo:rustc-link-lib=netfilter_queue");

View File

@@ -0,0 +1,11 @@
[package]
name = "libnfqws2"
version.workspace = true
edition.workspace = true
repository.workspace = true
[build-dependencies]
cc = "1.2.43"
once_cell = "1.21.3"
glob = "0.3.3"
bindgen = "0.72.1"

View File

@@ -0,0 +1,248 @@
use once_cell::sync::Lazy;
use std::env;
use std::path::{Path, PathBuf};
macro_rules! rel_manifest_path {
($name:ident, $path:expr) => {
static $name: Lazy<PathBuf> = Lazy::new(|| {
let manifest_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
Path::new(&manifest_dir).join($path)
});
};
}
rel_manifest_path!(NFQ, "zapret2/nfq2");
rel_manifest_path!(NFQ_CRYPTO, "zapret2/nfq2/crypto");
fn main() {
const SYMBOLS: &[&str] = &[
"DLOG",
"net32_add",
"net16_add",
"tcp_find_option",
"tcp_find_scale_factor",
"tcp_find_mss",
"proto_skip_ipv6",
"proto_check_ipv4",
"proto_check_ipv6",
"extract_ports",
"extract_endpoints",
"proto_name",
"family_from_proto",
"str_ip",
"print_ip",
"str_srcdst_ip6",
"str_ip6hdr",
"print_ip6hdr",
"str_tcphdr",
"print_tcphdr",
"l7proto_str",
"l7_proto_match",
"posmarker_name",
"AnyProtoPos",
"ResolvePos",
"HttpPos",
"TLSPos",
"TLSFindExt",
"TLSAdvanceToHostInSNI",
"ResolveMultiPos",
"IsHttp",
"HttpFindHost",
"IsHttpReply",
"HttpReplyCode",
"HttpExtractHeader",
"HttpExtractHost",
"HttpReplyLooksLikeDPIRedirect",
"TLSVersionStr",
"TLSRecordDataLen",
"TLSRecordLen",
"DLOG_CONDUP",
"IsTLSRecordFull",
"DLOG_ERR",
"IsTLSClientHello",
"DLOG_PERROR",
"LOG_APPEND",
"HOSTLIST_DEBUGLOG_APPEND",
"hexdump_limited_dlog",
"TLSHandshakeLen",
"IsTLSHandshakeClientHello",
"IsTLSHandshakeFull",
"TLSFindExtLenOffsetInHandshake",
"TLSFindExtLen",
"TLSFindExtInHandshake",
"TLSHelloExtractHost",
"TLSHelloExtractHostFromHandshake",
"IsQUICCryptoHello",
"QUICDraftVersion",
"str_udphdr",
"QUICIsLongHeader",
"dp_init",
"dp_list_add",
"dp_clear",
"dp_entry_destroy",
"dp_list_destroy",
"dp_list_have_autohostlist",
"cleanup_params",
"progname",
"tld",
"QUICExtractVersion",
"QUICExtractDCID",
"QUICDecryptInitial",
"print_udphdr",
"QUICDefragCrypto",
"IsQUICInitial",
"IsWireguardHandshakeInitiation",
"proto_skip_ipv4",
"IsDiscordIpDiscoveryRequest",
"IsStunMessage",
"proto_check_tcp",
"proto_skip_tcp",
"proto_check_udp",
"proto_skip_udp",
"proto_dissect_l3l4",
"tcp_synack_segment",
"tcp_syn_segment",
"rawsend_cleanup",
"rawsend_preinit",
"rawsend",
"rawsend_rp",
"rawsend_queue",
"wlan_info_deinit",
"wlan_info_init",
"wlan_info_get_rate_limited",
"wlans",
"wlan_ifname2ssid",
"wlan_ifidx2ssid",
"wlan_ssid_search_ifname",
"wlan_ssid_search_ifidx",
"verdict_tcp_csum_fix",
"dpi_desync_packet",
"verdict_udp_csum_fix",
"unique_size_t",
"qsort_size_t",
"dbgprint_socket_buffers",
"fake_http_request_default",
"rtrim",
"replace_char",
"fake_tls_clienthello_default",
"params",
"strncasestr",
"load_file",
"append_to_list_file",
"expand_bits",
"strip_host_to_ip",
"ntop46",
"ntop46_port",
"print_sockaddr",
"saport",
"pntoh64",
"set_socket_buffers",
"phton64",
"seq_within",
"ipv6_addr_is_zero",
"parse_hex_str",
"fprint_localtime",
"file_mod_time",
"file_mod_signature",
"file_open_test",
"pf_in_range",
"pf_parse",
"pf_is_empty",
"fill_random_bytes",
"fill_random_az",
"fill_random_az09",
"set_console_io_buffering",
"set_env_exedir",
"str_cidr4",
"print_cidr4",
"str_cidr6",
"print_cidr6",
"parse_cidr4",
"parse_cidr6",
];
let mut cc_builder = cc::Build::new();
cc_builder.files(
glob::glob(&format!("{}/*.c", NFQ.display()))
.unwrap()
.filter_map(Result::ok),
);
cc_builder.files(
glob::glob(&format!("{}/*.c", NFQ_CRYPTO.display()))
.unwrap()
.filter_map(Result::ok),
);
cc_builder.include(&*NFQ);
cc_builder.include(&*NFQ_CRYPTO);
cc_builder.flag("-w");
for &symbol in SYMBOLS {
let val = format!("nfq2_{}", symbol);
cc_builder.define(symbol, Some(&val[..]));
}
cc_builder.define("main", "nfqws2_main");
cc_builder.compile("libnfqws2.a");
let compiler = cc_builder.get_compiler();
let output = compiler.to_command()
.arg("-print-libgcc-file-name")
.output()
.expect("Failed to query compiler for libgcc path");
let path_str = String::from_utf8(output.stdout).unwrap();
let lib_path = Path::new(path_str.trim());
if lib_path.exists() {
if let Some(parent) = lib_path.parent() {
println!("cargo:rustc-link-search=native={}", parent.display());
}
if let Some(stem) = lib_path.file_stem() {
let lib_name = stem.to_string_lossy();
let lib_name = lib_name.strip_prefix("lib").unwrap_or(&lib_name);
println!("cargo:rustc-link-lib=static={}", lib_name);
}
} else {
println!("cargo:warning=Could not find compiler builtins library at {:?}", lib_path);
println!("cargo:rustc-link-lib=gcc");
}
println!("cargo:rustc-link-lib=z");
println!("cargo:rustc-link-lib=netfilter_queue");
println!("cargo:rustc-link-lib=nfnetlink");
println!("cargo:rustc-link-lib=mnl");
println!("cargo:rustc-link-lib=static=luajit");
println!("cargo:rustc-link-lib=unwind"); // for shitass luajit
let _ = env::var("NETFILTER_LIBS")
.map(|libs| println!("cargo:rustc-link-search=native={libs}/lib"));
let _ = env::var("LUAJIT_LIBS")
.map(|libs| println!("cargo:rustc-link-search=native={libs}/lib"));
println!("cargo:rustc-link-lib=static=nfqws2");
println!("cargo:rerun-if-changed={}", NFQ.display());
println!("cargo:rerun-if-changed={}", NFQ_CRYPTO.display());
println!("cargo:rerun-if-changed=build.rs");
let mut builder = bindgen::Builder::default();
for header in glob::glob(&format!("{}/*.h", NFQ.display()))
.unwrap()
.filter_map(Result::ok)
{
builder = builder.header(header.to_string_lossy());
}
builder = builder.clang_arg("-Dmain=nfqws2_main");
if let Ok(luajit) = env::var("LUAJIT") {
builder = builder.clang_arg(format!("-I{}", luajit));
}
let bindings = builder
.parse_callbacks(Box::new(bindgen::CargoCallbacks::new()))
.generate()
.expect("Unable to generate libnfqws2");
let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
bindings
.write_to_file(out_path.join("libnfqws2.rs"))
.expect("Couldn't write libnfqws2");
}

View File

@@ -0,0 +1,2 @@
#![allow(warnings)]
include!(concat!(env!("OUT_DIR"), "/libnfqws2.rs"));

View File

@@ -9,12 +9,12 @@ anyhow = { workspace = true }
clap = { workspace = true }
libc = { workspace = true }
regex = { workspace = true }
rust-ini = { workspace = true }
serde = { workspace = true }
serde_json = { workspace = true }
sysctl ={ workspace = true }
tokio = { workspace = true }
libnfqws = { path = "../libnfqws" }
libnfqws2 = { path = "../libnfqws2" }
daemonize = { workspace = true }
pretty_env_logger = { workspace = true }
log = { workspace = true }

View File

@@ -1,5 +1,7 @@
use std::env;
fn main() {
let zapret_version = env::var("ZAPRET_VERSION").unwrap_or("unknown".to_string());
println!("cargo:rustc-env=ZAPRET_VERSION={}", zapret_version);
let nfqws_version = env::var("NFQWS_VERSION").unwrap_or("unknown".to_string());
let nfqws2_version = env::var("NFQWS2_VERSION").unwrap_or("unknown".to_string());
println!("cargo:rustc-env=NFQWS_VERSION={}", nfqws_version);
println!("cargo:rustc-env=NFQWS2_VERSION={}", nfqws2_version)
}

View File

@@ -5,7 +5,7 @@ use commands::Command;
use getset::Getters;
#[derive(Parser, Getters)]
// #[command(version)]
#[command(version = option_env!("MODULE_VERSION").unwrap_or("unknown"))]
#[getset(get = "pub")]
pub struct CliApp {
#[command(subcommand)]

View File

@@ -1,8 +1,7 @@
use crate::autostart::{get_autostart, set_autostart};
use crate::service::{restart_service, service_status, start_service, stop_service};
use crate::{bin_version, module_version, run_nfqws};
use crate::{nfqws_version, nfqws2_version, run_nfqws};
use clap::Subcommand;
use log::error;
#[derive(Subcommand)]
pub enum Command {
@@ -24,14 +23,14 @@ pub enum Command {
/// Show whether autostart is enabled
GetAutostart,
/// Show the module version
ModuleVersion,
/// Show the nfqws version
NfqwsVersion,
/// Show the nfqws binary version
BinaryVersion,
/// Show the nfqws2 version
Nfqws2Version,
/// Run nfqws
Args {
Run {
#[arg(allow_hyphen_values=true, trailing_var_arg = true, num_args = 0..)]
args: Vec<String>,
},
@@ -40,11 +39,9 @@ pub enum Command {
impl Command {
pub async fn exec(&self) -> anyhow::Result<()> {
match self {
Command::Start => return start_service().await,
Command::Stop => {
let _ = stop_service().await;
}
Command::Restart => return restart_service().await,
Command::Start => start_service().await?,
Command::Stop => stop_service().await?,
Command::Restart => restart_service().await?,
Command::Status => {
println!(
"zaprett is {}",
@@ -55,15 +52,11 @@ impl Command {
}
);
}
Command::SetAutostart => {
if let Err(err) = set_autostart().await {
error!("Failed to set auto start: {err}")
}
}
Command::SetAutostart => set_autostart().await?,
Command::GetAutostart => println!("{}", get_autostart()),
Command::ModuleVersion => println!("{}", module_version().await?),
Command::BinaryVersion => println!("{}", bin_version()),
Command::Args { args } => run_nfqws(&args.join(" "))?,
Command::NfqwsVersion => println!("{}", nfqws_version()),
Command::Nfqws2Version => println!("{}", nfqws2_version()),
Command::Run { args } => run_nfqws(&args.join(" "))?,
}
Ok(())

View File

@@ -10,17 +10,36 @@ pub enum ListType {
Blacklist,
}
#[derive(Default, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "lowercase")]
pub enum ServiceType {
#[default]
Nfqws,
Nfqws2,
}
#[derive(Default, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "lowercase")]
pub enum ApplistType {
#[default]
None,
Blacklist,
Whitelist,
}
#[derive(Default, Serialize, Deserialize, Getters)]
#[getset(get = "pub")]
#[serde(default)]
pub struct Config {
service_type: ServiceType,
active_lists: Vec<String>,
active_ipsets: Vec<String>,
active_exclude_lists: Vec<String>,
active_exclude_ipsets: Vec<String>,
list_type: ListType,
strategy: String,
app_list: String,
strategy_nfqws2: String,
app_list: ApplistType,
whitelist: Vec<String>,
blacklist: Vec<String>,
}

View File

@@ -1,4 +1,4 @@
use crate::{MODULE_PATH, run_nfqws};
use crate::{MODULE_PATH, run_nfqws, run_nfqws2};
use daemonize::Daemonize;
use log::{error, info};
use std::fs::File;
@@ -24,3 +24,25 @@ pub async fn daemonize_nfqws(args: &str) {
Err(e) => error!("Error while starting nfqws daemon: {e}"),
}
}
pub async fn daemonize_nfqws2(args: &str) {
info!("Starting nfqws2 as a daemon");
let stdout = File::create(MODULE_PATH.join("tmp/nfqws2.out")).unwrap();
let stderr = File::create(MODULE_PATH.join("tmp/nfqws2.err")).unwrap();
let daemonize = Daemonize::new()
.pid_file(MODULE_PATH.join("tmp/pid.lock").as_path())
.working_directory(MODULE_PATH.join("tmp"))
.stdout(stdout)
.stderr(stderr)
.privileged_action(|| "Executed before drop privileges");
match daemonize.start() {
Ok(_) => {
info!("Success, nfqws2 daemonized");
run_nfqws2(args).unwrap()
}
Err(e) => error!("Error while starting nfqws2 daemon: {e}"),
}
}

View File

@@ -5,48 +5,65 @@ pub mod iptables_rust;
mod service;
mod autostart;
use ini::Ini;
use libnfqws::nfqws_main;
use libnfqws2::nfqws2_main;
use std::error;
use std::ffi::CString;
use std::os::raw::c_char;
use std::path::Path;
use std::sync::LazyLock;
use anyhow::bail;
use tokio::fs::File;
use tokio::io::{copy, AsyncWriteExt};
use tokio::task::spawn_blocking;
#[cfg(target_os = "android")]
pub static MODULE_PATH: LazyLock<&Path> =
LazyLock::new(|| Path::new("/data/adb/modules/zaprett"));
#[cfg(target_os = "android")]
pub static ZAPRETT_DIR_PATH: LazyLock<&Path> =
LazyLock::new(|| Path::new("/storage/emulated/0/zaprett"));
#[cfg(target_os = "android")]
pub static ZAPRETT_LIBS_PATH: LazyLock<&Path> =
LazyLock::new(|| Path::new("/storage/emulated/0/zaprett/strategies/nfwqs2/libs"));
pub static DEFAULT_START: &str = "
--filter-tcp=80 --dpi-desync=fake,split2 --dpi-desync-autottl=2 --dpi-desync-fooling=md5sig,badsum $hostlist --new
--filter-tcp=443 $hostlist --dpi-desync=fake,split2 --dpi-desync-repeats=6 --dpi-desync-fooling=md5sig,badsum --dpi-desync-fake-tls=${zaprettdir}/bin/tls_clienthello_www_google_com.bin --new
--filter-tcp=80,443 --dpi-desync=fake,disorder2 --dpi-desync-repeats=6 --dpi-desync-autottl=2 --dpi-desync-fooling=md5sig,badsum $hostlist --new
// Only for testing
#[cfg(target_os = "linux")]
pub static MODULE_PATH: LazyLock<&Path> =
LazyLock::new(|| Path::new("zaprett_module"));
#[cfg(target_os = "linux")]
pub static ZAPRETT_DIR_PATH: LazyLock<&Path> =
LazyLock::new(|| Path::new("zaprett"));
#[cfg(target_os = "linux")]
pub static ZAPRETT_LIBS_PATH: LazyLock<&Path> =
LazyLock::new(|| Path::new("zaprett/strategies/nfwqs2/libs"));
pub static DEFAULT_STRATEGY_NFQWS: &str = "
--filter-tcp=80 --dpi-desync=fake,split2 --dpi-desync-autottl=2 --dpi-desync-fooling=md5sig,badsum ${hostlist} --new
--filter-tcp=443 ${hostlist} --dpi-desync=fake,split2 --dpi-desync-repeats=6 --dpi-desync-fooling=md5sig,badsum --dpi-desync-fake-tls=${zaprettdir}/bin/tls_clienthello_www_google_com.bin --new
--filter-tcp=80,443 --dpi-desync=fake,disorder2 --dpi-desync-repeats=6 --dpi-desync-autottl=2 --dpi-desync-fooling=md5sig,badsum ${hostlist} --new
--filter-udp=50000-50100 --dpi-desync=fake --dpi-desync-any-protocol --dpi-desync-fake-quic=0xC30000000108 --new
--filter-udp=443 $hostlist --dpi-desync=fake --dpi-desync-repeats=6 --dpi-desync-fake-quic=${zaprettdir}/bin/quic_initial_www_google_com.bin --new
--filter-udp=443 --dpi-desync=fake --dpi-desync-repeats=6 $hostlist
--filter-udp=443 ${hostlist} --dpi-desync=fake --dpi-desync-repeats=6 --dpi-desync-fake-quic=${zaprettdir}/bin/quic_initial_www_google_com.bin --new
--filter-udp=443 --dpi-desync=fake --dpi-desync-repeats=6 ${hostlist}
";
// тестовая стратегия, заменить на нормальную потом
pub static DEFAULT_STRATEGY_NFQWS2: &str = "
--lua-init=@${libsdir}/zapret-lib.lua --lua-init=@${libsdir}/zapret-antidpi.lua
--blob=quic_google:@${zaprettdir}/bin/quic_initial_www_google_com.bin
--blob=tls_google:${zaprettdir}/bin/tls_clienthello_www_google_com.bin
--blob=tls_4pda:@${zaprettdir}/bin/tls_clienthello_4pda_to.bin
--blob=tls_max:@${zaprettdir}/bin/tls_clienthello_max_ru.bin
--blob=zero4:0x00000000
--filter-udp=443 --hostlist=${zaprettdir}/lists/include/list-general.txt --lua-desync=fake:blob=quic_google:repeats=6 --new
--filter-tcp=443 --hostlist=${zaprettdir}/lists/include/list-google.txt --lua-desync=fake:blob=tls_google:repeats=6:tcp_seq=2:tls_mod=none:ip_id=zero --new
--filter-tcp=80,443 --hostlist=${zaprettdir}/lists/include/list-general.txt --lua-desync=fake:blob=tls_google:repeats=6:tcp_seq=2:tls_mod=none
";
async fn module_version() -> anyhow::Result<String> {
let prop = spawn_blocking(|| Ini::load_from_file(MODULE_PATH.join("module.prop")))
.await??;
if let Some(props) = prop.section::<String>(None)
&& let Some(version) = props.get("version")
{
return Ok(version.into());
}
bail!("Failed to get version, prop not found")
fn nfqws_version() -> &'static str {
env!("NFQWS_VERSION")
}
fn bin_version() -> &'static str {
env!("ZAPRET_VERSION")
fn nfqws2_version() -> &'static str {
env!("NFQWS2_VERSION")
}
pub async fn merge_files(
@@ -101,3 +118,31 @@ fn run_nfqws(args_str: &str) -> anyhow::Result<()> {
Ok(())
}
fn run_nfqws2(args_str: &str) -> anyhow::Result<()> {
let mut args = vec![
"nfqws2".to_string(),
"--uid=0:0".to_string(),
"--qnum=200".to_string(),
];
if args_str.trim().is_empty() {
args.push("-v".to_string());
} else {
args.extend(args_str.split_whitespace().map(String::from));
}
let c_args: Vec<CString> = args
.into_iter()
.map(|arg| CString::new(arg).unwrap())
.collect();
let mut ptrs: Vec<*const c_char> = c_args.iter().map(|arg| arg.as_ptr()).collect();
unsafe {
nfqws2_main(c_args.len() as libc::c_int, ptrs.as_mut_ptr() as *mut _);
}
Ok(())
}

View File

@@ -8,7 +8,7 @@ async fn main() -> anyhow::Result<()> {
let cli = CliApp::parse();
match cli.cmd() {
Some(cmd) => cmd.exec().await?,
None => println!("zaprett installed. Join us: t.me/zaprett_module"),
None => println!("zaprett installed. Join us in Telegram: t.me/zaprett_module"),
}
Ok(())

View File

@@ -1,7 +1,8 @@
use crate::config::Config;
use crate::config::{Config, ServiceType};
use crate::daemon::daemonize_nfqws;
use crate::daemon::daemonize_nfqws2;
use crate::iptables_rust::{clear_iptables_rules, setup_iptables_rules};
use crate::{DEFAULT_START, MODULE_PATH, ZAPRETT_DIR_PATH};
use crate::{DEFAULT_STRATEGY_NFQWS, DEFAULT_STRATEGY_NFQWS2, MODULE_PATH, ZAPRETT_DIR_PATH, ZAPRETT_LIBS_PATH};
use anyhow::bail;
use log::info;
use nix::sys::signal::{Signal, kill};
@@ -53,14 +54,26 @@ pub async fn start_service() -> anyhow::Result<()> {
let config: Config = serde_json::from_str(&config_contents)?;
let start = fs::read_to_string(config.strategy())
.await
.map(Cow::Owned)
.unwrap_or(Cow::Borrowed(DEFAULT_START));
let start: Cow<str> = if config.service_type() == &ServiceType::Nfqws {
fs::read_to_string(config.strategy())
.await
.map(Cow::Owned)
.unwrap_or(Cow::Borrowed(DEFAULT_STRATEGY_NFQWS))
}
else if config.service_type() == &ServiceType::Nfqws2 {
fs::read_to_string(config.strategy_nfqws2())
.await
.map(Cow::Owned)
.unwrap_or(Cow::Borrowed(DEFAULT_STRATEGY_NFQWS2))
}
else {
bail!("Broken config file!");
};
let regex_hostlist = Regex::new(r"\$hostlist")?;
let regex_ipsets = Regex::new(r"\$ipset")?;
let regex_zaprettdir = Regex::new(r"\$\{?zaprettdir}?")?;
let regex_hostlist = Regex::new(r"\$(?:hostlist|\{hostlist})")?;
let regex_ipsets = Regex::new(r"\$(?:ipset|\{ipset})")?;
let regex_zaprettdir = Regex::new(r"\$(?:zaprettdir|\{zaprettdir})")?;
let regex_libsdir = Regex::new(r"\$(?:libsdir|\{libsdir})")?;
let mut strat_modified;
let (hosts, ipsets) = config.list_type().merge(&config).await;
@@ -74,12 +87,25 @@ pub async fn start_service() -> anyhow::Result<()> {
.replace_all(&strat_modified, ZAPRETT_DIR_PATH.to_str().unwrap())
.into_owned();
strat_modified = regex_libsdir
.replace_all(&strat_modified, ZAPRETT_LIBS_PATH.to_str().unwrap())
.into_owned();
let ctl = Ctl::new("net.netfilter.nf_conntrack_tcp_be_liberal")?;
ctl.set_value(CtlValue::String("1".into()))?;
setup_iptables_rules().expect("setup iptables rules");
daemonize_nfqws(&strat_modified).await;
if config.service_type() == &ServiceType::Nfqws {
daemonize_nfqws(&strat_modified).await;
}
else if config.service_type() == &ServiceType::Nfqws2 {
daemonize_nfqws2(&strat_modified).await;
}
else {
bail!("Broken config file!");
}
println!("zaprett service started!");
Ok(())
}

View File

@@ -6,6 +6,7 @@ export ANDROID_NDK_VERSION := "r27d-linux"
TARGET := `pwd` + "/target"
export NETFILTER_LIBS := TARGET + "/netfilter"
export LUAJIT_LIBS := TARGET + "/luajit"
export NDK_HOME := TARGET + "/android-ndk-" + ANDROID_NDK_VERSION
@@ -76,7 +77,44 @@ _build_netfilter_libs target_arch:
echo "Netfilter libs for {{target_arch}} already built"
fi
_instal_rust_target target:
_build_luajit target_arch:
#!/usr/bin/env bash
if [ ! -d "{{LUAJIT_LIBS}}-{{target_arch}}" ]; then
cd "{{TARGET}}"
if [ ! -d "luajit2-*" ]; then
wget -qO- https://github.com/openresty/luajit2/archive/refs/tags/v2.1-20250826.tar.gz | tar -xz
fi
export TOOLCHAIN=$NDK_HOME/toolchains/llvm/prebuilt/linux-x86_64
export CC="$TOOLCHAIN/bin/clang --target={{target_arch}}$ANDROID_API"
export AR=$TOOLCHAIN/bin/llvm-ar
export STRIP=$TOOLCHAIN/bin/llvm-strip
case "{{target_arch}}" in
*64*) HOSTCC="cc" ;;
*) HOSTCC="cc -m32" ;;
esac
(
cd luajit2-*
make clean
make BUILDMODE=static XCFLAGS=-DLUAJIT_DISABLE_FFI \
HOST_CC="$HOSTCC" CROSS= CC="$CC" \
TARGET_AR="$AR rcus" TARGET_STRIP=$STRIP \
CFLAGS="-Os -flto=auto" -j$(nproc)
make install PREFIX= DESTDIR="{{LUAJIT_LIBS}}-{{target_arch}}"
mv "{{LUAJIT_LIBS}}-{{target_arch}}/lib/libluajit-5.1.a" \
"{{LUAJIT_LIBS}}-{{target_arch}}/lib/libluajit.a"
)
else
echo "LuaJIT for {{target_arch}} already built"
fi
_install_rust_target target:
#!/usr/bin/env bash
if ! rustup target list --installed | grep -q "{{target}}"; then
echo "Installing missing target: {{target}}"
@@ -98,12 +136,18 @@ build-android *args: prepare-android
t=${targets[$i]}
(
echo "Building target $t"
export CFLAGS="-I$NETFILTER_LIBS-$t/include"
export LDFLAGS="-L$NETFILTER_LIBS-$t/lib"
export CFLAGS="-I$NETFILTER_LIBS-$t/include -I$LUAJIT_LIBS-$t/include/luajit-2.1"
export LDFLAGS="-L$NETFILTER_LIBS-$t/lib -L$LUAJIT_LIBS-$t/lib"
export CXXFLAGS="$CFLAGS"
export LUAJIT="$LUAJIT_LIBS-$t/include/luajit-2.1"
export LJIT=1
export LCFLAGS="-I$LUAJIT_LIBS-$t/include/luajit-2.1"
export LLIB="-L$LUAJIT_LIBS-$t/lib -lluajit-2.1"
just _build_netfilter_libs $t
just _instal_rust_target $t
NETFILTER_LIBS=$NETFILTER_LIBS-$t cargo ndk -t $t --platform $ANDROID_API build {{args}}
just _build_luajit $t
just _install_rust_target $t
NETFILTER_LIBS=$NETFILTER_LIBS-$t LUAJIT_LIBS=$LUAJIT_LIBS-$t cargo ndk -t $t --platform $ANDROID_API build {{args}}
)
done