summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock140
-rw-r--r--Cargo.toml1
-rw-r--r--dpibreak.14
-rw-r--r--dpibreak.1.md4
-rw-r--r--src/main.rs15
-rw-r--r--src/platform/linux.rs71
6 files changed, 73 insertions, 162 deletions
diff --git a/Cargo.lock b/Cargo.lock
index f0e3e6e..e9ba31d 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -115,7 +115,6 @@ dependencies = [
"etherparse 0.18.2",
"iptables",
"nfq",
- "nftables",
"nix 0.27.1",
"serde_json",
"socket2",
@@ -124,12 +123,6 @@ dependencies = [
]
[[package]]
-name = "dyn-clone"
-version = "1.0.20"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555"
-
-[[package]]
name = "etherparse"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -154,12 +147,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0399f9d26e5191ce32c498bebd31e7a3ceabc2745f0ac54af3f335126c3f24b3"
[[package]]
-name = "heck"
-version = "0.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
-
-[[package]]
name = "iptables"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -214,21 +201,6 @@ dependencies = [
]
[[package]]
-name = "nftables"
-version = "0.6.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3c57e7343eed9e9330e084eef12651b15be3c8ed7825915a0ffa33736b852bed"
-dependencies = [
- "schemars",
- "serde",
- "serde_json",
- "serde_path_to_error",
- "strum",
- "strum_macros",
- "thiserror 2.0.17",
-]
-
-[[package]]
name = "nix"
version = "0.20.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -283,26 +255,6 @@ dependencies = [
]
[[package]]
-name = "ref-cast"
-version = "1.0.25"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f354300ae66f76f1c85c5f84693f0ce81d747e2c3f21a45fef496d89c960bf7d"
-dependencies = [
- "ref-cast-impl",
-]
-
-[[package]]
-name = "ref-cast-impl"
-version = "1.0.25"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn",
-]
-
-[[package]]
name = "regex"
version = "1.11.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -338,38 +290,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f"
[[package]]
-name = "schemars"
-version = "1.0.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "82d20c4491bc164fa2f6c5d44565947a52ad80b9505d8e36f8d54c27c739fcd0"
-dependencies = [
- "dyn-clone",
- "ref-cast",
- "schemars_derive",
- "serde",
- "serde_json",
-]
-
-[[package]]
-name = "schemars_derive"
-version = "1.0.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "33d020396d1d138dc19f1165df7545479dcd58d93810dc5d646a16e55abefa80"
-dependencies = [
- "proc-macro2",
- "quote",
- "serde_derive_internals",
- "syn",
-]
-
-[[package]]
name = "serde"
version = "1.0.228"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
dependencies = [
"serde_core",
- "serde_derive",
]
[[package]]
@@ -393,17 +319,6 @@ dependencies = [
]
[[package]]
-name = "serde_derive_internals"
-version = "0.29.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn",
-]
-
-[[package]]
name = "serde_json"
version = "1.0.145"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -417,17 +332,6 @@ dependencies = [
]
[[package]]
-name = "serde_path_to_error"
-version = "0.1.20"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "10a9ff822e371bb5403e391ecd83e182e0e77ba7f6fe0160b795797109d1b457"
-dependencies = [
- "itoa",
- "serde",
- "serde_core",
-]
-
-[[package]]
name = "shlex"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -444,24 +348,6 @@ dependencies = [
]
[[package]]
-name = "strum"
-version = "0.27.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "af23d6f6c1a224baef9d3f61e287d2761385a5b88fdab4eb4c6f11aeb54c4bcf"
-
-[[package]]
-name = "strum_macros"
-version = "0.27.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7695ce3845ea4b33927c055a39dc438a45b059f7c1b3d91d38d10355fb8cbca7"
-dependencies = [
- "heck",
- "proc-macro2",
- "quote",
- "syn",
-]
-
-[[package]]
name = "syn"
version = "2.0.106"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -478,16 +364,7 @@ version = "1.0.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
dependencies = [
- "thiserror-impl 1.0.69",
-]
-
-[[package]]
-name = "thiserror"
-version = "2.0.17"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8"
-dependencies = [
- "thiserror-impl 2.0.17",
+ "thiserror-impl",
]
[[package]]
@@ -502,17 +379,6 @@ dependencies = [
]
[[package]]
-name = "thiserror-impl"
-version = "2.0.17"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn",
-]
-
-[[package]]
name = "toml"
version = "0.5.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -534,7 +400,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc6b6833a760d1c36b489314a5541a12a39d162dc8341d8f6f400212b96d3df1"
dependencies = [
"etherparse 0.13.0",
- "thiserror 1.0.69",
+ "thiserror",
"windivert-sys",
"windows",
]
@@ -546,7 +412,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "832bc4af9272458a8a64395b3aabe10dc4089546486fcbd0e19b9b6d28ba6e54"
dependencies = [
"cc",
- "thiserror 1.0.69",
+ "thiserror",
"windows",
]
diff --git a/Cargo.toml b/Cargo.toml
index c901930..fbca391 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -37,7 +37,6 @@ iptables = "0.4"
nfq = { git = "https://github.com/nbdd0121/nfq-rs.git", rev = "4efbaa3" } # to use as_raw_fd
socket2 = { version = "0.6", features = ["all"] }
nix = { version = "0.27.1", features = ["fs", "poll"] }
-nftables = "0.6"
serde_json = "1.0.145"
[target.'cfg(windows)'.dependencies]
diff --git a/dpibreak.1 b/dpibreak.1
index 75a6fac..6365c9f 100644
--- a/dpibreak.1
+++ b/dpibreak.1
@@ -68,6 +68,10 @@ handshake latency. (default: 0)
NFQUEUE number to attach to. The same queue number is
used for IPv4 and IPv6. (default: 1)
.TP
+.B \-\-nft\-command \fI<string>\fR
+.Linux only.
+Custom nftables command to be executed. (default: nft)
+.TP
.B \-\-loglevel \fIdebug|info|warning|error\fR
Set the logging level (default:
.BR warning ).
diff --git a/dpibreak.1.md b/dpibreak.1.md
index 189eae7..d43a70d 100644
--- a/dpibreak.1.md
+++ b/dpibreak.1.md
@@ -50,6 +50,10 @@ handshake latency. (default: 0)
NFQUEUE number to attach to. The same queue number is used for IPv4 and
IPv6. (default: 1)
+**--nft-command *\<string\>***
+
+Custom nftables command to be executed. (default: nft)
+
**--loglevel *debug\|info\|warning\|error***
Set the logging level (default: **warning**). Aliases: **warn** -\>
**warning**, **err** -\> **error**.
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(())