diff options
| -rw-r--r-- | Cargo.lock | 96 | ||||
| -rw-r--r-- | Cargo.toml | 1 | ||||
| -rw-r--r-- | src/platform/linux.rs | 98 |
3 files changed, 78 insertions, 117 deletions
@@ -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" @@ -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)?; |
