summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock96
-rw-r--r--Cargo.toml1
-rw-r--r--src/platform/linux.rs98
3 files changed, 78 insertions, 117 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 8e44fc8..5e90b72 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -3,15 +3,6 @@
version = 4
[[package]]
-name = "aho-corasick"
-version = "1.1.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301"
-dependencies = [
- "memchr",
-]
-
-[[package]]
name = "anyhow"
version = "1.0.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -24,18 +15,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50"
[[package]]
-name = "autocfg"
-version = "1.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
-
-[[package]]
-name = "bitflags"
-version = "1.2.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
-
-[[package]]
name = "bitflags"
version = "2.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -95,7 +74,7 @@ version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89a09f22a6c6069a18470eb92d2298acf25463f14256d24778e1230d789a2aec"
dependencies = [
- "bitflags 2.10.0",
+ "bitflags",
"block2",
"libc",
"objc2",
@@ -108,7 +87,6 @@ dependencies = [
"anyhow",
"ctrlc",
"etherparse 0.18.2",
- "iptables",
"nfq-updated",
"nix 0.27.1",
"serde_json",
@@ -142,29 +120,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f449e6c6c08c865631d4890cfacf252b3d396c9bcc83adb6623cdb02a8336c41"
[[package]]
-name = "iptables"
-version = "0.4.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5451d970ceaf1d94b287f060eda6c553b0bd93412986765e3274c28a89b50830"
-dependencies = [
- "lazy_static",
- "nix 0.20.2",
- "regex",
-]
-
-[[package]]
name = "itoa"
version = "1.0.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2"
[[package]]
-name = "lazy_static"
-version = "1.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
-
-[[package]]
name = "libc"
version = "0.2.180"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -177,15 +138,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273"
[[package]]
-name = "memoffset"
-version = "0.6.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce"
-dependencies = [
- "autocfg",
-]
-
-[[package]]
name = "nfq-updated"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -198,24 +150,11 @@ dependencies = [
[[package]]
name = "nix"
-version = "0.20.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f5e06129fb611568ef4e868c14b326274959aa70ff7776e9d55323531c374945"
-dependencies = [
- "bitflags 1.2.1",
- "cc",
- "cfg-if",
- "libc",
- "memoffset",
-]
-
-[[package]]
-name = "nix"
version = "0.27.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053"
dependencies = [
- "bitflags 2.10.0",
+ "bitflags",
"cfg-if",
"libc",
]
@@ -226,7 +165,7 @@ version = "0.30.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6"
dependencies = [
- "bitflags 2.10.0",
+ "bitflags",
"cfg-if",
"cfg_aliases",
"libc",
@@ -266,35 +205,6 @@ dependencies = [
]
[[package]]
-name = "regex"
-version = "1.12.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "843bc0191f75f3e22651ae5f1e72939ab2f72a4bc30fa80a066bd66edefc24d4"
-dependencies = [
- "aho-corasick",
- "memchr",
- "regex-automata",
- "regex-syntax",
-]
-
-[[package]]
-name = "regex-automata"
-version = "0.4.13"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c"
-dependencies = [
- "aho-corasick",
- "memchr",
- "regex-syntax",
-]
-
-[[package]]
-name = "regex-syntax"
-version = "0.8.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58"
-
-[[package]]
name = "serde"
version = "1.0.228"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/Cargo.toml b/Cargo.toml
index 2d85d64..3dae72b 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -34,7 +34,6 @@ anyhow = "1"
etherparse = "0.18"
[target.'cfg(target_os = "linux")'.dependencies]
-iptables = "0.4"
nfq = { package = "nfq-updated", version = "0.2.6" } # nfq-updated: to us as_raw_fd
socket2 = { version = "0.6", features = ["all"] }
nix = { version = "0.27.1", features = ["fs", "poll"] }
diff --git a/src/platform/linux.rs b/src/platform/linux.rs
index 5b413b4..2571cb1 100644
--- a/src/platform/linux.rs
+++ b/src/platform/linux.rs
@@ -15,7 +15,6 @@
// You should have received a copy of the GNU General Public License
// along with DPIBreak. If not, see <https://www.gnu.org/licenses/>.
-use iptables::IPTables;
use std::sync::{
atomic::{AtomicBool, Ordering},
Mutex,
@@ -67,6 +66,58 @@ fn exec_process(args: &[&str], input: Option<&str>) -> Result<()> {
}
}
+pub struct IPTables {
+ cmd: &'static str,
+}
+
+impl IPTables {
+ pub fn new(is_ipv6: bool) -> Result<Self> {
+ Ok(Self {
+ cmd: if is_ipv6 { "ip6tables" } else { "iptables" },
+ })
+ }
+
+ fn run(&self, args: &[&str]) -> Result<()> {
+ let mut full_args = Vec::with_capacity(args.len() + 1);
+
+ full_args.push(self.cmd);
+ full_args.extend_from_slice(args);
+
+ exec_process(&full_args, None)
+ }
+
+ pub fn new_chain(&self, table: &str, chain: &str) -> Result<()> {
+ self.run(&["-t", table, "-N", chain])
+ }
+
+ pub fn flush_chain(&self, table: &str, chain: &str) -> Result<()> {
+ self.run(&["-t", table, "-F", chain])
+ }
+
+ pub fn delete_chain(&self, table: &str, chain: &str) -> Result<()> {
+ self.run(&["-t", table, "-X", chain])
+ }
+
+ pub fn insert(&self, table: &str, chain: &str, rule: &[&str], pos: i32) -> Result<()> {
+ let pos_str = pos.to_string();
+ let mut args = vec!["-t", table, "-I", chain, &pos_str];
+ args.extend_from_slice(rule);
+ self.run(&args)
+ }
+
+ pub fn append(&self, table: &str, chain: &str, rule: &[&str]) -> Result<()> {
+ let mut args = vec!["-t", table, "-A", chain];
+ args.extend_from_slice(rule);
+ self.run(&args)
+ }
+
+ pub fn delete(&self, table: &str, chain: &str, rule: &[&str]) -> Result<()> {
+ let mut args = vec!["-t", table, "-D", chain];
+ args.extend_from_slice(rule);
+ self.run(&args)
+ }
+}
+
/// Apply json format nft rules with `nft_command() -j -f -`.
fn apply_nft_rules(rule: &str) -> Result<()> {
exec_process(&[crate::opt::nft_command(), "-j", "-f", "-"], Some(rule))
@@ -79,7 +130,6 @@ fn is_xt_u32_loaded() -> bool {
}
fn ensure_xt_u32() -> Result<()> {
-
let before = is_xt_u32_loaded();
Command::new("modprobe").args(&["-q", "xt_u32"]).status()?;
let after = is_xt_u32_loaded();
@@ -102,10 +152,11 @@ fn is_u32_supported(ipt: &IPTables) -> bool {
log_println!(LogLevel::Info, "xt_u32 loaded");
- let rule = "-m u32 --u32 \'0x0=0x0\' -j RETURN";
- match ipt.insert("raw", "PREROUTING", rule, 1) {
+ let rule = ["-m", "u32", "--u32", "0x0=0x0", "-j", "RETURN"];
+
+ match ipt.insert("raw", "PREROUTING", &rule, 1) {
Ok(_) => {
- _ = ipt.delete("raw", "PREROUTING", rule);
+ _ = ipt.delete("raw", "PREROUTING", &rule);
IS_U32_SUPPORTED.store(true, Ordering::Relaxed);
true
}
@@ -119,41 +170,42 @@ fn iptables_err(e: impl ToString) -> Error {
}
fn install_iptables_rules(ipt: &IPTables) -> Result<()> {
- let base = format!("-p tcp --dport 443 -j NFQUEUE --queue-num {} --queue-bypass",
- crate::opt::queue_num());
+ let q_num = crate::opt::queue_num().to_string();
- let rule = if is_u32_supported(ipt) {
- const U32: &str = "-m u32 --u32 \
- \'0>>22&0x3C @ 12>>26&0x3C @ 0>>24&0xFF=0x16 && \
- 0>>22&0x3C @ 12>>26&0x3C @ 2>>24&0xFF=0x01\'";
+ let mut rule = vec![
+ "-p", "tcp", "--dport", "443",
+ "-j", "NFQUEUE", "--queue-num", &q_num, "--queue-bypass"
+ ];
- format!("{} {}", base, U32)
- } else {
- base
- };
+ if is_u32_supported(ipt) {
+ const U32: &str = "0>>22&0x3C @ 12>>26&0x3C @ 0>>24&0xFF=0x16 && \
+ 0>>22&0x3C @ 12>>26&0x3C @ 2>>24&0xFF=0x01";
+
+ rule.extend_from_slice(&["-m", "u32", "--u32", U32]);
+ }
ipt.new_chain("mangle", DPIBREAK_CHAIN).map_err(iptables_err)?;
// prevent inf loop
+ let mark = format!("{:#x}", INJECT_MARK);
ipt.insert(
"mangle",
DPIBREAK_CHAIN,
- &format!("-m mark --mark {:#x} -j RETURN", INJECT_MARK),
+ &["-m", "mark", "--mark", &mark, "-j", "RETURN"],
1
).map_err(iptables_err)?;
ipt.append("mangle", DPIBREAK_CHAIN, &rule).map_err(iptables_err)?;
log_println!(LogLevel::Info, "{}: new chain {} on table mangle", ipt.cmd, DPIBREAK_CHAIN);
- ipt.insert("mangle", "POSTROUTING",
- &format!("-j {}", DPIBREAK_CHAIN), 1).map_err(iptables_err)?;
+ ipt.insert("mangle", "POSTROUTING", &["-j", DPIBREAK_CHAIN], 1).map_err(iptables_err)?;
log_println!(LogLevel::Info, "{}: add jump to {} chain on POSTROUTING", ipt.cmd, DPIBREAK_CHAIN);
Ok(())
}
fn cleanup_iptables_rules(ipt: &IPTables) -> Result<()> {
- if ipt.delete("mangle", "POSTROUTING", &format!("-j {}", DPIBREAK_CHAIN)).is_ok() {
+ if ipt.delete("mangle", "POSTROUTING", &["-j", DPIBREAK_CHAIN]).is_ok() {
log_println!(LogLevel::Info, "{}: deleted jump from POSTROUTING", ipt.cmd);
}
@@ -289,8 +341,8 @@ fn install_rules() -> Result<()> {
log_println!(LogLevel::Warning, "nftables: {}", e.to_string());
log_println!(LogLevel::Warning, "fallback to iptables");
- let ipt = iptables::new(false).map_err(iptables_err)?;
- let ip6 = iptables::new(true).map_err(iptables_err)?;
+ let ipt = IPTables::new(false).map_err(iptables_err)?;
+ let ip6 = IPTables::new(true).map_err(iptables_err)?;
install_iptables_rules(&ipt)?;
// FIXME: using xt_u32 on ipv6 is not supported; (even if it does,
@@ -304,8 +356,8 @@ fn install_rules() -> Result<()> {
fn cleanup_rules() -> Result<()> {
if IS_NFT_NOT_SUPPORTED.load(Ordering::Relaxed) {
- let ipt = iptables::new(false).map_err(iptables_err)?;
- let ip6 = iptables::new(true).map_err(iptables_err)?;
+ let ipt = IPTables::new(false).map_err(iptables_err)?;
+ let ip6 = IPTables::new(true).map_err(iptables_err)?;
cleanup_iptables_rules(&ipt)?;
cleanup_iptables_rules(&ip6)?;