mirror of
https://github.com/egor-white/zaprett.git
synced 2026-03-22 00:18:13 +05:00
add manifest parsing + move paths from lib to path mod
This commit is contained in:
@@ -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()
|
||||
}
|
||||
|
||||
@@ -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}"),
|
||||
)
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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");
|
||||
|
||||
@@ -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(())
|
||||
}
|
||||
|
||||
@@ -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(),
|
||||
|
||||
25
rust/crates/zaprett/src/path.rs
Normal file
25
rust/crates/zaprett/src/path.rs
Normal 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"));
|
||||
}
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user