summaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/main.rs15
-rw-r--r--src/platform/linux.rs71
2 files changed, 62 insertions, 24 deletions
diff --git a/src/main.rs b/src/main.rs
index 75806b4..e8d2f78 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -163,9 +163,10 @@ fn usage() {
r#"Usage: dpibreak [OPTIONS]
Options:
- --delay-ms <u64> (default: 0)
- --queue-num <u16> (linux only, default: 1)
- --loglevel <debug|info|warning|error> (default: warning)
+ --delay-ms <u64> (default: 0)
+ --queue-num <u16> (linux only, default: 1)
+ --nft-command <string> (linux only, default: nft)
+ --loglevel <debug|info|warning|error> (default: warning)
--no-splash Do not print splash messages
-h, --help Show this help"#
);
@@ -181,6 +182,8 @@ fn parse_args_1() -> Result<()> {
let mut log_level: log::LogLevel = LogLevel::Warning;
#[cfg(target_os = "linux")]
let mut queue_num: u16 = 1;
+ #[cfg(target_os = "linux")]
+ let mut nft_command = String::from("nft");
let mut args = std::env::args().skip(1); // program name
@@ -196,6 +199,9 @@ fn parse_args_1() -> Result<()> {
#[cfg(target_os = "linux")]
"--queue-num" => { queue_num = take_value(&mut args, argv)?; }
+ #[cfg(target_os = "linux")]
+ "--nft-command" => { nft_command = take_value(&mut args, argv)?; }
+
_ => { return Err(anyhow!("argument: unknown: {}", arg)); }
}
}
@@ -207,6 +213,9 @@ fn parse_args_1() -> Result<()> {
#[cfg(target_os = "linux")]
platform::QUEUE_NUM.set(queue_num).map_err(|_| anyhow!("QUEUE_NUM already initialized"))?;
+ #[cfg(target_os = "linux")]
+ platform::NFT_COMMAND.set(nft_command).map_err(|_| anyhow!("NFT_COMMAND already initialized"))?;
+
Ok(())
}
diff --git a/src/platform/linux.rs b/src/platform/linux.rs
index e04a6e4..259643e 100644
--- a/src/platform/linux.rs
+++ b/src/platform/linux.rs
@@ -22,22 +22,55 @@ use std::sync::{
OnceLock,
LazyLock
};
-use std::process::Command;
-use anyhow::{Result, Error, anyhow};
+use std::process::{Command, Stdio};
+use std::io::Write;
+use anyhow::{Result, Error, Context, anyhow};
use crate::{log::LogLevel, log_println, splash, MESSAGE_AT_RUN};
pub static IS_U32_SUPPORTED: AtomicBool = AtomicBool::new(false);
pub static IS_XT_U32_LOADED_BY_US: AtomicBool = AtomicBool::new(false);
static IS_NFT_NOT_SUPPORTED: AtomicBool = AtomicBool::new(false);
-pub static QUEUE_NUM: OnceLock<u16> = OnceLock::new();
-
const DPIBREAK_CHAIN: &str = "DPIBREAK";
+pub static QUEUE_NUM: OnceLock<u16> = OnceLock::new();
+pub static NFT_COMMAND: OnceLock<String> = OnceLock::new();
+
fn queue_num() -> u16 {
*QUEUE_NUM.get().expect("QUEUE_NUM not initialized")
}
+fn nft_command() -> &'static str {
+ NFT_COMMAND.get().expect("NFT_COMMAND not initialized").as_str()
+}
+
+/// Apply json format nft rules with `nft_command() -j -f -`.
+fn apply_nft_rules(rule: &str) -> Result<()> {
+ let mut child = Command::new(nft_command())
+ .args(&["-j", "-f", "-"])
+ .stdin(Stdio::piped())
+ .stdout(Stdio::null())
+ .stderr(Stdio::piped())
+ .spawn()
+ .context("failed to spawn nft process")?;
+
+ {
+ let mut stdin = child.stdin.take().context("failed to take stdin")?;
+ stdin.write_all(rule.as_bytes()).context("failed to write rule to nft")?;
+ } // Close the pipe
+
+ let output = child.wait_with_output().context("failed to wait for nft")?;
+
+ match output.status.code() {
+ Some(0) => Ok(()),
+ Some(code) =>
+ Err(anyhow!("{} exited with status {}: {}", nft_command(), code,
+ String::from_utf8_lossy(&output.stderr))),
+ None =>
+ Err(anyhow!("{} terminated by signal", nft_command()))
+ }
+}
+
fn is_xt_u32_loaded() -> bool {
std::fs::read_to_string("/proc/modules")
.map(|s| s.lines().any(|l| l.starts_with("xt_u32 ")))
@@ -127,9 +160,7 @@ fn cleanup_iptables_rules(ipt: &IPTables) -> Result<()> {
const DPIBREAK_TABLE: &str = "dpibreak";
fn install_nft_rules() -> Result<()> {
- use nftables::helper;
-
- let json = serde_json::json!(
+ let rule = serde_json::json!(
{
"nftables": [
{"add": {"table": {"family": "inet", "name": DPIBREAK_TABLE}}},
@@ -210,10 +241,7 @@ fn install_nft_rules() -> Result<()> {
}
);
- let json_str = serde_json::to_string(&json)?;
-
- helper::apply_ruleset_raw(&json_str, helper::DEFAULT_NFT,
- helper::DEFAULT_ARGS)?;
+ apply_nft_rules(&serde_json::to_string(&rule)?)?;
// clienthello filtered by nft
IS_U32_SUPPORTED.store(true, Ordering::Relaxed);
@@ -251,17 +279,18 @@ fn cleanup_rules() -> Result<()> {
cleanup_iptables_rules(&ipt)?;
cleanup_iptables_rules(&ip6)?;
} else {
- use nftables::*;
-
- let mut nft = batch::Batch::new();
-
// nft delete table inet dpibreak
- nft.delete(schema::NfListObject::Table(schema::Table {
- family: types::NfFamily::INet,
- name: DPIBREAK_TABLE.into(),
- ..Default::default()
- }));
- _ = helper::apply_ruleset(&nft.to_nftables());
+ let rule = serde_json::json!({
+ "nftables": [
+ {"delete": {"table": {"family": "inet", "name": DPIBREAK_TABLE}}}
+ ]
+ });
+ match apply_nft_rules(&serde_json::to_string(&rule)?) {
+ Ok(_) =>
+ log_println!(LogLevel::Info, "cleanup: nftables: delete table inet {}", DPIBREAK_TABLE),
+ Err(e) =>
+ log_println!(LogLevel::Warning, "cleanup: nftables: {}", e.to_string().trim()),
+ }
}
Ok(())