mirror of
https://github.com/egor-white/zaprett.git
synced 2025-12-10 13:30:23 +05:00
refaktor
This commit is contained in:
@@ -1,7 +1,8 @@
|
||||
pub mod commands;
|
||||
|
||||
use clap::Parser;
|
||||
use getset::Getters;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use crate::commands::Command;
|
||||
use commands::Command;
|
||||
|
||||
#[derive(Parser, Getters)]
|
||||
#[command(version)]
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
use crate::{bin_version, get_autostart, module_version, restart_service, service_status, set_autostart, start_service, stop_service};
|
||||
use crate::{bin_version, get_autostart, module_version, set_autostart};
|
||||
use clap::Subcommand;
|
||||
use log::error;
|
||||
use crate::service::{restart_service, service_status, start_service, stop_service};
|
||||
|
||||
#[derive(Subcommand)]
|
||||
pub enum Command {
|
||||
@@ -30,18 +30,20 @@ impl ListType {
|
||||
pub async fn merge(&self, config: &Config) -> (String, String) {
|
||||
let module_path_str = MODULE_PATH.to_str().unwrap();
|
||||
|
||||
let (host_files, ipset_files, host_suffix, ipset_suffix) = match self {
|
||||
let (host_files, ipset_files, host_suffix, ipset_suffix, exclude_flag) = match self {
|
||||
ListType::Whitelist => (
|
||||
&config.active_lists,
|
||||
&config.active_ipsets,
|
||||
"hostlist",
|
||||
"ipset",
|
||||
""
|
||||
),
|
||||
ListType::Blacklist => (
|
||||
&config.active_exclude_lists,
|
||||
&config.active_exclude_ipsets,
|
||||
"hostlist-exclude",
|
||||
"ipset-exclude",
|
||||
"-exclude"
|
||||
),
|
||||
};
|
||||
|
||||
@@ -50,16 +52,10 @@ impl ListType {
|
||||
|
||||
merge_files(host_files, host_path).await.unwrap();
|
||||
merge_files(ipset_files, ipset_path).await.unwrap();
|
||||
|
||||
let exclude = if matches!(self, ListType::Blacklist) {
|
||||
"-exclude"
|
||||
} else {
|
||||
""
|
||||
};
|
||||
|
||||
|
||||
(
|
||||
format!("--hostlist{exclude}={module_path_str}/tmp/{host_suffix}"),
|
||||
format!("--ipset{exclude}={module_path_str}/tmp/{ipset_suffix}"),
|
||||
format!("--hostlist{exclude_flag}={module_path_str}/tmp/{host_suffix}"),
|
||||
format!("--ipset{exclude_flag}={module_path_str}/tmp/{ipset_suffix}"),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
20
rust/crates/zaprett/src/daemon.rs
Normal file
20
rust/crates/zaprett/src/daemon.rs
Normal file
@@ -0,0 +1,20 @@
|
||||
use log::{error, info};
|
||||
use daemonize::Daemonize;
|
||||
use crate::{run_nfqws, MODULE_PATH};
|
||||
|
||||
pub async fn daemonize_nfqws(args: &str) {
|
||||
info!("Starting nfqws as a daemon");
|
||||
let daemonize = Daemonize::new()
|
||||
.pid_file(MODULE_PATH.join("tmp/pid.lock").as_path())
|
||||
.working_directory("/tmp")
|
||||
.group("daemon")
|
||||
.privileged_action(|| "Executed before drop privileges");
|
||||
|
||||
match daemonize.start() {
|
||||
Ok(_) => {
|
||||
info!("Success, daemonized");
|
||||
run_nfqws(args).await.unwrap()
|
||||
}
|
||||
Err(e) => error!("Error while starting nfqws daemon: {e}"),
|
||||
}
|
||||
}
|
||||
51
rust/crates/zaprett/src/iptables_rust.rs
Normal file
51
rust/crates/zaprett/src/iptables_rust.rs
Normal file
@@ -0,0 +1,51 @@
|
||||
use std::error;
|
||||
|
||||
pub fn setup_iptables_rules() -> Result<(), Box<dyn error::Error>> {
|
||||
let ipt = iptables::new(false)?;
|
||||
|
||||
ipt.insert(
|
||||
"mangle",
|
||||
"POSTROUTING",
|
||||
"-j NFQUEUE --queue-num 200 --queue-bypass",
|
||||
1,
|
||||
)?;
|
||||
|
||||
ipt.insert(
|
||||
"mangle",
|
||||
"PREROUTING",
|
||||
"-j NFQUEUE --queue-num 200 --queue-bypass",
|
||||
1,
|
||||
)?;
|
||||
|
||||
ipt.append(
|
||||
"filter",
|
||||
"FORWARD",
|
||||
"-j NFQUEUE --queue-num 200 --queue-bypass",
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn clear_iptables_rules() -> Result<(), Box<dyn error::Error>> {
|
||||
let ipt = iptables::new(false)?;
|
||||
|
||||
ipt.delete(
|
||||
"mangle",
|
||||
"POSTROUTING",
|
||||
"-j NFQUEUE --queue-num 200 --queue-bypass",
|
||||
)?;
|
||||
|
||||
ipt.delete(
|
||||
"mangle",
|
||||
"PREROUTING",
|
||||
"-j NFQUEUE --queue-num 200 --queue-bypass",
|
||||
)?;
|
||||
|
||||
ipt.delete(
|
||||
"filter",
|
||||
"FORWARD",
|
||||
"-j NFQUEUE --queue-num 200 --queue-bypass",
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -1,6 +1,8 @@
|
||||
pub mod commands;
|
||||
pub mod cli;
|
||||
pub mod config;
|
||||
pub mod iptables_rust;
|
||||
mod service;
|
||||
mod daemon;
|
||||
|
||||
use std::error;
|
||||
use std::ffi::CString;
|
||||
@@ -8,126 +10,32 @@ use std::os::raw::c_char;
|
||||
use std::path::Path;
|
||||
use std::sync::LazyLock;
|
||||
use anyhow::bail;
|
||||
use daemonize::Daemonize;
|
||||
use ini::Ini;
|
||||
use log::{error, info};
|
||||
use nix::sys::signal::{kill, Signal};
|
||||
use nix::unistd::{Pid, Uid};
|
||||
use regex::Regex;
|
||||
use sysctl::Sysctl;
|
||||
use tokio::{fs, task};
|
||||
use tokio::fs::File;
|
||||
use tokio::io::{copy, AsyncReadExt, AsyncWriteExt};
|
||||
use tokio::io::{copy, AsyncWriteExt};
|
||||
use libnfqws::nfqws_main;
|
||||
use crate::config::Config;
|
||||
|
||||
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"));
|
||||
|
||||
async fn daemonize_nfqws(args: &str) {
|
||||
info!("Starting nfqws as a daemon");
|
||||
let daemonize = Daemonize::new()
|
||||
.pid_file(MODULE_PATH.join("tmp/pid.lock").as_path())
|
||||
.working_directory("/tmp")
|
||||
.group("daemon")
|
||||
.privileged_action(|| "Executed before drop privileges");
|
||||
|
||||
match daemonize.start() {
|
||||
Ok(_) => {
|
||||
info!("Success, daemonized");
|
||||
run_nfqws(args).await.unwrap()
|
||||
}
|
||||
Err(e) => error!("Error while starting nfqws daemon: {e}"),
|
||||
}
|
||||
}
|
||||
|
||||
async fn start_service() -> anyhow::Result<()> {
|
||||
if !Uid::effective().is_root() {
|
||||
bail!("Running not from root, exiting");
|
||||
};
|
||||
|
||||
info!("Starting zaprett service...");
|
||||
|
||||
let tmp_dir = MODULE_PATH.join("/tmp");
|
||||
if tmp_dir.exists() {
|
||||
fs::remove_dir_all(&tmp_dir).await?;
|
||||
fs::create_dir_all(&tmp_dir).await?;
|
||||
}
|
||||
|
||||
let mut config_contents = String::new();
|
||||
File::open(ZAPRETT_DIR_PATH.join("config.json"))
|
||||
.await
|
||||
.expect("cannot open config.json")
|
||||
.read_to_string(&mut config_contents).await?;
|
||||
|
||||
let config: Config = serde_json::from_str(&config_contents).expect("invalid json");
|
||||
|
||||
let def_strat = String::from("
|
||||
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
|
||||
--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
|
||||
");
|
||||
|
||||
let start = fs::read_to_string(config.strategy())
|
||||
.await
|
||||
.unwrap_or(def_strat);
|
||||
|
||||
let regex_hostlist = Regex::new(r"\$hostlist")?;
|
||||
let regex_ipsets = Regex::new(r"\$ipset")?;
|
||||
let regex_zaprettdir = Regex::new(r"\$\{?zaprettdir}?")?;
|
||||
|
||||
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();
|
||||
|
||||
let ctl = sysctl::Ctl::new("net.netfilter.nf_conntrack_tcp_be_liberal")?;
|
||||
ctl.set_value(sysctl::CtlValue::String("1".into()))?;
|
||||
|
||||
setup_iptables_rules().expect("setup iptables rules");
|
||||
|
||||
daemonize_nfqws(&strat_modified).await;
|
||||
info!("zaprett service started!");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn stop_service() -> anyhow::Result<()> {
|
||||
if !Uid::effective().is_root() {
|
||||
bail!("Running not from root, exiting");
|
||||
};
|
||||
|
||||
clear_iptables_rules().expect("clear iptables rules");
|
||||
|
||||
let pid_str = fs::read_to_string(MODULE_PATH.join("tmp/pid.lock")).await?;
|
||||
let pid = pid_str.trim().parse::<i32>()?;
|
||||
|
||||
kill(Pid::from_raw(pid), Signal::SIGKILL)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn restart_service() -> anyhow::Result<()> {
|
||||
stop_service().await?;
|
||||
start_service().await?;
|
||||
info!("zaprett service restarted!");
|
||||
Ok(())
|
||||
}
|
||||
";
|
||||
|
||||
async fn set_autostart(autostart: &bool) -> Result<(), anyhow::Error> {
|
||||
let autostart_path = MODULE_PATH.join("autostart");
|
||||
|
||||
if *autostart {
|
||||
File::create(MODULE_PATH.join("autostart")).await?;
|
||||
File::create(autostart_path).await?;
|
||||
} else {
|
||||
fs::remove_file(MODULE_PATH.join("autostart")).await?;
|
||||
fs::remove_file(autostart_path).await?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@@ -138,14 +46,6 @@ fn get_autostart() {
|
||||
println!("{}", file.exists());
|
||||
}
|
||||
|
||||
async fn service_status() -> bool {
|
||||
fs::read_to_string(MODULE_PATH.join("tmp/pid.lock"))
|
||||
.await
|
||||
.ok()
|
||||
.and_then(|pid_str| pid_str.trim().parse::<i32>().ok())
|
||||
.is_some()
|
||||
}
|
||||
|
||||
fn module_version() {
|
||||
if let Ok(prop) = Ini::load_from_file(MODULE_PATH.join("module.prop"))
|
||||
&& let Some(props) = prop.section::<String>(None)
|
||||
@@ -187,58 +87,8 @@ pub async fn merge_files(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn setup_iptables_rules() -> Result<(), Box<dyn error::Error>> {
|
||||
let ipt = iptables::new(false)?;
|
||||
|
||||
ipt.insert(
|
||||
"mangle",
|
||||
"POSTROUTING",
|
||||
"-j NFQUEUE --queue-num 200 --queue-bypass",
|
||||
1,
|
||||
)?;
|
||||
|
||||
ipt.insert(
|
||||
"mangle",
|
||||
"PREROUTING",
|
||||
"-j NFQUEUE --queue-num 200 --queue-bypass",
|
||||
1,
|
||||
)?;
|
||||
|
||||
ipt.append(
|
||||
"filter",
|
||||
"FORWARD",
|
||||
"-j NFQUEUE --queue-num 200 --queue-bypass",
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn clear_iptables_rules() -> Result<(), Box<dyn error::Error>> {
|
||||
let ipt = iptables::new(false)?;
|
||||
|
||||
ipt.delete(
|
||||
"mangle",
|
||||
"POSTROUTING",
|
||||
"-j NFQUEUE --queue-num 200 --queue-bypass",
|
||||
)?;
|
||||
|
||||
ipt.delete(
|
||||
"mangle",
|
||||
"PREROUTING",
|
||||
"-j NFQUEUE --queue-num 200 --queue-bypass",
|
||||
)?;
|
||||
|
||||
ipt.delete(
|
||||
"filter",
|
||||
"FORWARD",
|
||||
"-j NFQUEUE --queue-num 200 --queue-bypass",
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn run_nfqws(args_str: &str) -> anyhow::Result<()> {
|
||||
if service_status().await {
|
||||
if service::service_status().await {
|
||||
bail!("nfqws already started!");
|
||||
}
|
||||
|
||||
|
||||
96
rust/crates/zaprett/src/service.rs
Normal file
96
rust/crates/zaprett/src/service.rs
Normal file
@@ -0,0 +1,96 @@
|
||||
use std::borrow::Cow;
|
||||
use nix::unistd::{Pid, Uid};
|
||||
use anyhow::bail;
|
||||
use tokio::fs;
|
||||
use nix::sys::signal::{kill, Signal};
|
||||
use log::info;
|
||||
use tokio::fs::File;
|
||||
use regex::Regex;
|
||||
use tokio::io::AsyncReadExt;
|
||||
use sysctl::Sysctl;
|
||||
use crate::iptables_rust::{clear_iptables_rules, setup_iptables_rules};
|
||||
use crate::{DEFAULT_START, MODULE_PATH, ZAPRETT_DIR_PATH};
|
||||
use crate::config::Config;
|
||||
use crate::daemon::daemonize_nfqws;
|
||||
|
||||
pub async fn start_service() -> anyhow::Result<()> {
|
||||
if !Uid::effective().is_root() {
|
||||
bail!("Running not from root, exiting");
|
||||
};
|
||||
|
||||
info!("Starting zaprett service...");
|
||||
|
||||
let tmp_dir = MODULE_PATH.join("/tmp");
|
||||
if tmp_dir.exists() {
|
||||
fs::remove_dir_all(&tmp_dir).await?;
|
||||
fs::create_dir_all(&tmp_dir).await?;
|
||||
}
|
||||
|
||||
let mut config_contents = String::new();
|
||||
File::open(ZAPRETT_DIR_PATH.join("config.json"))
|
||||
.await
|
||||
.expect("cannot open config.json")
|
||||
.read_to_string(&mut config_contents).await?;
|
||||
|
||||
let config: Config = serde_json::from_str(&config_contents).expect("invalid json");
|
||||
|
||||
let start = fs::read_to_string(config.strategy())
|
||||
.await
|
||||
.map(Cow::Owned)
|
||||
.unwrap_or(Cow::Borrowed(DEFAULT_START));
|
||||
|
||||
let regex_hostlist = Regex::new(r"\$hostlist")?;
|
||||
let regex_ipsets = Regex::new(r"\$ipset")?;
|
||||
let regex_zaprettdir = Regex::new(r"\$\{?zaprettdir}?")?;
|
||||
|
||||
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();
|
||||
|
||||
let ctl = sysctl::Ctl::new("net.netfilter.nf_conntrack_tcp_be_liberal")?;
|
||||
ctl.set_value(sysctl::CtlValue::String("1".into()))?;
|
||||
|
||||
setup_iptables_rules().expect("setup iptables rules");
|
||||
|
||||
daemonize_nfqws(&strat_modified).await;
|
||||
info!("zaprett service started!");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn stop_service() -> anyhow::Result<()> {
|
||||
if !Uid::effective().is_root() {
|
||||
bail!("Running not from root, exiting");
|
||||
};
|
||||
|
||||
clear_iptables_rules().expect("clear iptables rules");
|
||||
|
||||
let pid_str = fs::read_to_string(MODULE_PATH.join("tmp/pid.lock")).await?;
|
||||
let pid = pid_str.trim().parse::<i32>()?;
|
||||
|
||||
kill(Pid::from_raw(pid), Signal::SIGKILL)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn restart_service() -> anyhow::Result<()> {
|
||||
stop_service().await?;
|
||||
start_service().await?;
|
||||
info!("zaprett service restarted!");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn service_status() -> bool {
|
||||
fs::read_to_string(MODULE_PATH.join("tmp/pid.lock"))
|
||||
.await
|
||||
.ok()
|
||||
.and_then(|pid_str| pid_str.trim().parse::<i32>().ok())
|
||||
.is_some()
|
||||
}
|
||||
Reference in New Issue
Block a user