add manifest parsing + move paths from lib to path mod

This commit is contained in:
CherretGit
2026-03-02 22:42:59 +07:00
parent 14e0b5aa2f
commit 9b8148fc7b
7 changed files with 122 additions and 70 deletions

View File

@@ -1,6 +1,6 @@
use crate::MODULE_PATH;
use tokio::fs;
use tokio::fs::File;
use crate::path::path::MODULE_PATH;
pub async fn set_autostart() -> Result<(), anyhow::Error> {
let autostart_path = MODULE_PATH.join("autostart");
@@ -17,5 +17,5 @@ pub async fn set_autostart() -> Result<(), anyhow::Error> {
}
pub fn get_autostart() -> bool {
return MODULE_PATH.join("autostart").exists();
MODULE_PATH.join("autostart").exists()
}

View File

@@ -1,6 +1,8 @@
use crate::{MODULE_PATH, merge_files};
use std::path::{Path, PathBuf};
use crate::{check_manifest, merge_files};
use getset::Getters;
use serde::{Deserialize, Serialize};
use crate::path::path::MODULE_PATH;
#[derive(Default, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
@@ -44,11 +46,22 @@ pub struct Config {
blacklist: Vec<String>,
}
#[derive(Serialize, Deserialize, Getters)]
#[getset(get = "pub")]
pub struct Manifest {
schema: i32,
name: String,
author: String,
description: String,
dependencies: Vec<String>,
file: String
}
impl ListType {
/// # Returns
///
/// (hostlist arg, ipset arg)
pub async fn merge(&self, config: &Config) -> (String, String) {
pub async fn merge(&self, config: &Config) -> anyhow::Result<(String, String)> {
let module_path_str = MODULE_PATH.to_str().unwrap();
let (host_files, ipset_files, host_suffix, ipset_suffix, exclude_flag) = match self {
@@ -67,16 +80,28 @@ impl ListType {
"-exclude",
),
};
let host_paths: Vec<PathBuf> = host_files.iter()
.map(|path| -> anyhow::Result<PathBuf> {
let manifest = check_manifest(Path::new(path))?;
Ok(PathBuf::from(manifest.file()))
}).collect::<anyhow::Result<_>>()?;
let ipset_paths: Vec<PathBuf> = ipset_files
.iter()
.map(|path| -> anyhow::Result<PathBuf> {
let manifest = check_manifest(Path::new(path))?;
Ok(PathBuf::from(manifest.file()))
})
.collect::<anyhow::Result<_>>()?;
let host_path = MODULE_PATH.join(format!("tmp/{host_suffix}"));
let ipset_path = MODULE_PATH.join(format!("tmp/{ipset_suffix}"));
merge_files(host_files, host_path).await.unwrap();
merge_files(ipset_files, ipset_path).await.unwrap();
merge_files(&host_paths, host_path).await?;
merge_files(&ipset_paths, ipset_path).await?;
(
Ok((
format!("--hostlist{exclude_flag}={module_path_str}/tmp/{host_suffix}"),
format!("--ipset{exclude_flag}={module_path_str}/tmp/{ipset_suffix}"),
)
))
}
}
}

View File

@@ -1,7 +1,8 @@
use crate::{MODULE_PATH, run_nfqws, run_nfqws2};
use crate::{run_nfqws, run_nfqws2};
use daemonize::Daemonize;
use log::{error, info};
use std::fs::File;
use crate::path::path::MODULE_PATH;
pub async fn daemonize_nfqws(args: &str) {
info!("Starting nfqws as a daemon");

View File

@@ -1,7 +1,6 @@
use std::error;
use std::process::Command;
pub fn setup_iptables_rules() -> Result<(), Box<dyn error::Error>> {
pub fn setup_iptables_rules() -> anyhow::Result<()> {
Command::new("iptables")
.arg("-t")
.arg("mangle")
@@ -12,8 +11,7 @@ pub fn setup_iptables_rules() -> Result<(), Box<dyn error::Error>> {
.arg("--queue-num")
.arg("200")
.arg("--queue-bypass")
.status()
.expect("failed to add iptables rules");
.status()?;
Command::new("iptables")
.arg("-t")
@@ -25,8 +23,7 @@ pub fn setup_iptables_rules() -> Result<(), Box<dyn error::Error>> {
.arg("--queue-num")
.arg("200")
.arg("--queue-bypass")
.status()
.expect("failed to add iptables rules");
.status()?;
Command::new("iptables")
.arg("-t")
@@ -38,13 +35,12 @@ pub fn setup_iptables_rules() -> Result<(), Box<dyn error::Error>> {
.arg("--queue-num")
.arg("200")
.arg("--queue-bypass")
.status()
.expect("failed to add iptables rules");
.status()?;
Ok(())
}
pub fn clear_iptables_rules() -> Result<(), Box<dyn error::Error>> {
pub fn clear_iptables_rules() -> anyhow::Result<()> {
Command::new("iptables")
.arg("-t")
.arg("mangle")
@@ -55,8 +51,7 @@ pub fn clear_iptables_rules() -> Result<(), Box<dyn error::Error>> {
.arg("--queue-num")
.arg("200")
.arg("--queue-bypass")
.status()
.expect("failed to remove iptables rules");
.status()?;
Command::new("iptables")
.arg("-t")
@@ -68,8 +63,7 @@ pub fn clear_iptables_rules() -> Result<(), Box<dyn error::Error>> {
.arg("--queue-num")
.arg("200")
.arg("--queue-bypass")
.status()
.expect("failed to remove iptables rules");
.status()?;
Command::new("iptables")
.arg("-t")
@@ -81,8 +75,7 @@ pub fn clear_iptables_rules() -> Result<(), Box<dyn error::Error>> {
.arg("--queue-num")
.arg("200")
.arg("--queue-bypass")
.status()
.expect("failed to remove iptables rules");
.status()?;
Ok(())
}

View File

@@ -4,38 +4,19 @@ mod daemon;
pub mod iptables_rust;
mod service;
mod autostart;
mod path;
use crate::config::Manifest;
use anyhow::{anyhow, Context};
use libnfqws::nfqws_main;
use libnfqws2::nfqws2_main;
use std::error;
use std::ffi::CString;
use std::fs;
use std::os::raw::c_char;
use std::path::Path;
use std::sync::LazyLock;
use tokio::fs::File;
use tokio::io::{copy, AsyncWriteExt};
#[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"));
// 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
@@ -69,7 +50,7 @@ fn nfqws2_version() -> &'static str {
pub async fn merge_files(
input_paths: &[impl AsRef<Path>],
output_path: impl AsRef<Path>,
) -> Result<(), Box<dyn error::Error>> {
) -> anyhow::Result<()> {
let output_path = output_path.as_ref();
let mut output_file = File::create(output_path).await?;
@@ -78,20 +59,50 @@ pub async fn merge_files(
let mut input_file = File::open(input)
.await
.map_err(|e| format!("Failed to open {}: {e}", input.display()))?;
.map_err(|e| anyhow!("Failed to open {}: {e}", input.display()))?;
copy(&mut input_file, &mut output_file).await.map_err(|e| {
copy(&mut input_file, &mut output_file).await.map_err(|e| anyhow!(
format!(
"Failed to write contents of {}: {e}",
input.display()
)
})?;
))?;
}
output_file.flush().await?;
Ok(())
}
pub fn get_manifest(path: &Path) -> anyhow::Result<Manifest> {
let content = fs::read_to_string(path)?;
Ok(serde_json::from_str(&content)?)
}
pub fn check_dependencies(manifest: &Manifest) -> anyhow::Result<()> {
manifest.dependencies().iter().try_for_each(|dependency| {
let path = Path::new(dependency);
let manifest = get_manifest(&path).with_context(
|| format!("Failed to check dependency: {}", dependency)
)?;
check_file(&manifest)
})
}
pub fn check_file(manifest: &Manifest) -> anyhow::Result<()> {
if Path::new(manifest.file()).exists() {
Ok(())
} else {
Err(anyhow!("File not found: {}", manifest.file()))
}
}
pub fn check_manifest(path: &Path) -> anyhow::Result<Manifest> {
let manifest = get_manifest(path)?;
check_file(&manifest)?;
check_dependencies(&manifest)?;
Ok(manifest)
}
fn run_nfqws(args_str: &str) -> anyhow::Result<()> {
let mut args = vec![
"nfqws".to_string(),

View File

@@ -0,0 +1,25 @@
#[cfg(target_os = "android")]
pub mod path {
use std::path::Path;
use std::sync::LazyLock;
pub static MODULE_PATH: LazyLock<&Path> =
LazyLock::new(|| Path::new("/data/adb/modules/zaprett"));
pub static ZAPRETT_DIR_PATH: LazyLock<&Path> =
LazyLock::new(|| Path::new("/storage/emulated/0/zaprett"));
pub static ZAPRETT_LIBS_PATH: LazyLock<&Path> =
LazyLock::new(|| Path::new("/storage/emulated/0/zaprett/strategies/nfwqs2/libs"));
}
// Only for testing
#[cfg(target_os = "linux")]
pub mod path {
use std::path::Path;
use std::sync::LazyLock;
pub static MODULE_PATH: LazyLock<&Path> =
LazyLock::new(|| Path::new("zaprett_module"));
pub static ZAPRETT_DIR_PATH: LazyLock<&Path> =
LazyLock::new(|| Path::new("zaprett_dir"));
pub static ZAPRETT_LIBS_PATH: LazyLock<&Path> =
LazyLock::new(|| Path::new("zaprett_dir/strategies/nfwqs2/libs"));
}

View File

@@ -2,7 +2,7 @@ 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_STRATEGY_NFQWS, DEFAULT_STRATEGY_NFQWS2, MODULE_PATH, ZAPRETT_DIR_PATH, ZAPRETT_LIBS_PATH};
use crate::{check_manifest, DEFAULT_STRATEGY_NFQWS, DEFAULT_STRATEGY_NFQWS2};
use anyhow::bail;
use log::info;
use nix::sys::signal::{Signal, kill};
@@ -15,6 +15,7 @@ use sysctl::{Ctl, CtlValue, Sysctl};
use sysinfo::{Pid as SysPid, System};
use tokio::fs;
use tokio::io::AsyncReadExt;
use crate::path::path::{MODULE_PATH, ZAPRETT_DIR_PATH, ZAPRETT_LIBS_PATH};
pub async fn start_service() -> anyhow::Result<()> {
if !Uid::effective().is_root() {
@@ -53,30 +54,26 @@ pub async fn start_service() -> anyhow::Result<()> {
}
let config: Config = serde_json::from_str(&config_contents)?;
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 strategy = check_manifest(Path::new(config.strategy())).ok();
let default_strategy = match config.service_type() {
ServiceType::Nfqws => DEFAULT_STRATEGY_NFQWS,
ServiceType::Nfqws2 => DEFAULT_STRATEGY_NFQWS2
};
let start: Cow<str> = if let Some(manifest) = strategy {
fs::read_to_string(manifest.file())
.await
.map(Cow::Owned)
.unwrap_or(Cow::Borrowed(default_strategy))
} else {
Cow::Borrowed(default_strategy)
};
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;
let (hosts, ipsets) = config.list_type().merge(&config).await?;
strat_modified = regex_hostlist.replace_all(&start, &hosts).into_owned();
strat_modified = regex_ipsets