mirror of
https://github.com/egor-white/zaprett.git
synced 2026-03-22 00:18:13 +05:00
add support for new variables in strategies
This commit is contained in:
@@ -5,7 +5,7 @@ use commands::Command;
|
||||
use getset::Getters;
|
||||
|
||||
#[derive(Parser, Getters)]
|
||||
#[command(version = option_env!("MODULE_VERSION").unwrap_or("unknown"))]
|
||||
#[command(version = option_env!("MODULE_VERSION").unwrap_or(env!("CARGO_PKG_VERSION")))]
|
||||
#[getset(get = "pub")]
|
||||
pub struct CliApp {
|
||||
#[command(subcommand)]
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use std::path::{Path, PathBuf};
|
||||
use crate::{check_manifest, merge_files};
|
||||
use crate::{get_manifest, merge_files};
|
||||
use getset::Getters;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use crate::path::path::MODULE_PATH;
|
||||
@@ -82,13 +82,13 @@ impl ListType {
|
||||
};
|
||||
let host_paths: Vec<PathBuf> = host_files.iter()
|
||||
.map(|path| -> anyhow::Result<PathBuf> {
|
||||
let manifest = check_manifest(Path::new(path))?;
|
||||
let manifest = get_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))?;
|
||||
let manifest = get_manifest(Path::new(path))?;
|
||||
Ok(PathBuf::from(manifest.file()))
|
||||
})
|
||||
.collect::<anyhow::Result<_>>()?;
|
||||
|
||||
@@ -5,6 +5,7 @@ pub mod iptables_rust;
|
||||
mod service;
|
||||
mod autostart;
|
||||
mod path;
|
||||
mod strategy;
|
||||
|
||||
use crate::config::Manifest;
|
||||
use anyhow::{anyhow, Context};
|
||||
@@ -19,12 +20,12 @@ use tokio::io::{copy, AsyncWriteExt};
|
||||
|
||||
|
||||
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-tcp=80 --dpi-desync=fake,split2 --dpi-desync-autottl=2 --dpi-desync-fooling=md5sig,badsum ${hostlists} --new
|
||||
--filter-tcp=443 ${hostlists} --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 ${hostlists} --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 ${hostlists} --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 ${hostlists}
|
||||
";
|
||||
// тестовая стратегия, заменить на нормальную потом
|
||||
pub static DEFAULT_STRATEGY_NFQWS2: &str = "
|
||||
@@ -73,7 +74,7 @@ pub async fn merge_files(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn get_manifest(path: &Path) -> anyhow::Result<Manifest> {
|
||||
pub fn read_manifest(path: &Path) -> anyhow::Result<Manifest> {
|
||||
let content = fs::read_to_string(path)?;
|
||||
Ok(serde_json::from_str(&content)?)
|
||||
}
|
||||
@@ -81,7 +82,7 @@ pub fn get_manifest(path: &Path) -> anyhow::Result<Manifest> {
|
||||
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(
|
||||
let manifest = read_manifest(&path).with_context(
|
||||
|| format!("Failed to check dependency: {}", dependency)
|
||||
)?;
|
||||
check_file(&manifest)
|
||||
@@ -96,13 +97,20 @@ pub fn check_file(manifest: &Manifest) -> anyhow::Result<()> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn check_manifest(path: &Path) -> anyhow::Result<Manifest> {
|
||||
let manifest = get_manifest(path)?;
|
||||
pub fn get_manifest(path: &Path) -> anyhow::Result<Manifest> {
|
||||
let manifest = read_manifest(path)?;
|
||||
check_file(&manifest)?;
|
||||
check_dependencies(&manifest)?;
|
||||
Ok(manifest)
|
||||
}
|
||||
|
||||
pub fn get_all_manifests(path: &Path) -> anyhow::Result<Vec<Manifest>> {
|
||||
path.read_dir()?.map(
|
||||
|manifest_path| {
|
||||
get_manifest(&manifest_path?.path())
|
||||
}
|
||||
).collect()
|
||||
}
|
||||
fn run_nfqws(args_str: &str) -> anyhow::Result<()> {
|
||||
let mut args = vec![
|
||||
"nfqws".to_string(),
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
use crate::config::{Config, ServiceType};
|
||||
use crate::config::{Config, Manifest, ServiceType};
|
||||
use crate::daemon::daemonize_nfqws;
|
||||
use crate::daemon::daemonize_nfqws2;
|
||||
use crate::iptables_rust::{clear_iptables_rules, setup_iptables_rules};
|
||||
use crate::{check_manifest, DEFAULT_STRATEGY_NFQWS, DEFAULT_STRATEGY_NFQWS2};
|
||||
use crate::{get_manifest, get_all_manifests, DEFAULT_STRATEGY_NFQWS, DEFAULT_STRATEGY_NFQWS2};
|
||||
use anyhow::bail;
|
||||
use log::info;
|
||||
use nix::sys::signal::{Signal, kill};
|
||||
use nix::unistd::{Pid, Uid};
|
||||
use regex::Regex;
|
||||
use std::borrow::Cow;
|
||||
use std::collections::{HashMap};
|
||||
use std::io::ErrorKind;
|
||||
use std::path::Path;
|
||||
use sysctl::{Ctl, CtlValue, Sysctl};
|
||||
@@ -16,6 +17,7 @@ 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};
|
||||
use crate::strategy::prepare_manifests;
|
||||
|
||||
pub async fn start_service() -> anyhow::Result<()> {
|
||||
if !Uid::effective().is_root() {
|
||||
@@ -54,7 +56,7 @@ pub async fn start_service() -> anyhow::Result<()> {
|
||||
}
|
||||
|
||||
let config: Config = serde_json::from_str(&config_contents)?;
|
||||
let strategy = check_manifest(Path::new(config.strategy())).ok();
|
||||
let strategy = get_manifest(Path::new(config.strategy())).ok();
|
||||
let default_strategy = match config.service_type() {
|
||||
ServiceType::Nfqws => DEFAULT_STRATEGY_NFQWS,
|
||||
ServiceType::Nfqws2 => DEFAULT_STRATEGY_NFQWS2
|
||||
@@ -67,26 +69,50 @@ pub async fn start_service() -> anyhow::Result<()> {
|
||||
} else {
|
||||
Cow::Borrowed(default_strategy)
|
||||
};
|
||||
let regex_hostlist = Regex::new(r"\$(?:hostlist|\{hostlist})")?;
|
||||
let regex_ipsets = Regex::new(r"\$(?:ipset|\{ipset})")?;
|
||||
let regex_hostlists = Regex::new(r"\$(?:hostlists|\{hostlists})")?;
|
||||
let regex_hostlist = Regex::new(r"\$\{hostlist:([^}]+)\}")?;
|
||||
let regex_hostlist_exclude = Regex::new(r"\$\{hostlist_exclude:([^}]+)\}")?;
|
||||
let regex_ipset = Regex::new(r"\$\{ipset:([^}]+)\}")?;
|
||||
let regex_ipset_exclude = Regex::new(r"\$\{ipset_exclude:([^}]+)\}")?;
|
||||
let regex_ipsets = Regex::new(r"\$(?:ipsets|\{ipsets})")?;
|
||||
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?;
|
||||
|
||||
strat_modified = regex_hostlist.replace_all(&start, &hosts).into_owned();
|
||||
strat_modified = regex_ipsets
|
||||
.replace_all(&strat_modified, &ipsets)
|
||||
.into_owned();
|
||||
|
||||
strat_modified = regex_zaprettdir
|
||||
.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 hostlists: HashMap<String, Manifest> =
|
||||
get_all_manifests(&ZAPRETT_DIR_PATH.join("manifests/lists/include"))
|
||||
.unwrap_or_default()
|
||||
.into_iter()
|
||||
.map(|m| (m.name().clone(), m))
|
||||
.collect();
|
||||
let hostlists_exclude: HashMap<String, Manifest> =
|
||||
get_all_manifests(&ZAPRETT_DIR_PATH.join("manifests/lists/exclude"))
|
||||
.unwrap_or_default()
|
||||
.into_iter()
|
||||
.map(|m| (m.name().clone(), m))
|
||||
.collect();
|
||||
let ipset: HashMap<String, Manifest> =
|
||||
get_all_manifests(&ZAPRETT_DIR_PATH.join("manifests/ipset/include"))
|
||||
.unwrap_or_default()
|
||||
.into_iter()
|
||||
.map(|m| (m.name().clone(), m))
|
||||
.collect();
|
||||
let ipset_exclude: HashMap<String, Manifest> =
|
||||
get_all_manifests(&ZAPRETT_DIR_PATH.join("manifests/ipset/exclude"))
|
||||
.unwrap_or_default()
|
||||
.into_iter()
|
||||
.map(|m| (m.name().clone(), m))
|
||||
.collect();
|
||||
let strat_modified = prepare_manifests(&start, ®ex_hostlist, &hostlists, &tmp_dir)?;
|
||||
let strat_modified = prepare_manifests(&strat_modified, ®ex_hostlist_exclude, &hostlists_exclude, &tmp_dir)?;
|
||||
let strat_modified = prepare_manifests(&strat_modified, ®ex_ipset, &ipset, &tmp_dir)?;
|
||||
let strat_modified = prepare_manifests(&strat_modified, ®ex_ipset_exclude, &ipset_exclude, &tmp_dir)?;
|
||||
let strat_modified = regex_hostlists.replace_all(&strat_modified, &hosts);
|
||||
let strat_modified = regex_ipsets.replace_all(&strat_modified, &ipsets);
|
||||
let strat_modified =
|
||||
regex_zaprettdir.replace_all(&strat_modified, ZAPRETT_DIR_PATH.to_str().unwrap());
|
||||
let strat_modified =
|
||||
regex_libsdir.replace_all(&strat_modified, ZAPRETT_LIBS_PATH.to_str().unwrap());
|
||||
let strat_modified = strat_modified.into_owned();
|
||||
|
||||
let ctl = Ctl::new("net.netfilter.nf_conntrack_tcp_be_liberal")?;
|
||||
ctl.set_value(CtlValue::String("1".into()))?;
|
||||
|
||||
26
rust/crates/zaprett/src/strategy.rs
Normal file
26
rust/crates/zaprett/src/strategy.rs
Normal file
@@ -0,0 +1,26 @@
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::path::{Path, PathBuf};
|
||||
use anyhow::bail;
|
||||
use regex::Regex;
|
||||
use crate::config::Manifest;
|
||||
|
||||
pub fn prepare_manifests(input: &str, regex: &Regex, manifests: &HashMap<String, Manifest>, tmp_dir: &Path) -> anyhow::Result<String> {
|
||||
let required: HashSet<String> = regex.captures_iter(input).map(|c| c[1].to_string()).collect();
|
||||
for name in &required {
|
||||
if !manifests.contains_key(name) {
|
||||
bail!("Manifest not found: {}", name)
|
||||
}
|
||||
}
|
||||
let mut paths: HashMap<String, PathBuf> = HashMap::new();
|
||||
for name in &required {
|
||||
let manifest = &manifests[name];
|
||||
let path = Path::new(manifest.file());
|
||||
let dst = tmp_dir.join(format!("{}.txt", name));
|
||||
std::fs::copy(path, &dst)?;
|
||||
paths.insert(name.clone(), dst);
|
||||
}
|
||||
let result = regex.replace_all(input, |caps: ®ex::Captures| {
|
||||
paths[&caps[1]].to_string_lossy().into_owned()
|
||||
});
|
||||
Ok(result.into_owned())
|
||||
}
|
||||
Reference in New Issue
Block a user