diff options
Diffstat (limited to 'src/platform')
| -rw-r--r-- | src/platform/linux/iptables.rs | 19 | ||||
| -rw-r--r-- | src/platform/linux/nftables.rs | 59 | ||||
| -rw-r--r-- | src/platform/windows.rs | 24 |
3 files changed, 96 insertions, 6 deletions
diff --git a/src/platform/linux/iptables.rs b/src/platform/linux/iptables.rs index 91fa1da..4264967 100644 --- a/src/platform/linux/iptables.rs +++ b/src/platform/linux/iptables.rs @@ -138,6 +138,21 @@ pub fn install_iptables_rules(ipt: &IPTables) -> Result<()> { 1 ).map_err(iptables_err)?; + if opt::fake_autottl() { + let synack_rule = vec![ + "-p", "tcp", + "--sport", "443", + "-m", "tcp", "--tcp-flags", "SYN,ACK", "SYN,ACK", + "-j", "NFQUEUE", "--queue-num", &q_num, "--queue-bypass", + ]; + + ipt.append("mangle", DPIBREAK_CHAIN, &synack_rule).map_err(iptables_err)?; + log_println!(LogLevel::Info, "{}: add SYN/ACK learning rule on mangle/{}", ipt.cmd, DPIBREAK_CHAIN); + + ipt.insert("mangle", "INPUT", &["-j", DPIBREAK_CHAIN], 1).map_err(iptables_err)?; + log_println!(LogLevel::Info, "{}: add jump to {} chain on INPUT", ipt.cmd, DPIBREAK_CHAIN); + } + ipt.append("mangle", DPIBREAK_CHAIN, &rule).map_err(iptables_err)?; log_println!(LogLevel::Info, "{}: new chain {} on table mangle", ipt.cmd, DPIBREAK_CHAIN); @@ -152,6 +167,10 @@ pub fn cleanup_iptables_rules(ipt: &IPTables) -> Result<()> { log_println!(LogLevel::Info, "{}: delete jump to {} from mangle/POSTROUTING", ipt.cmd, DPIBREAK_CHAIN); } + if opt::fake_autottl() && ipt.delete("mangle", "INPUT", &["-j", DPIBREAK_CHAIN]).is_ok() { + log_println!(LogLevel::Info, "{}: delete jump to {} from mangle/INPUT", ipt.cmd, DPIBREAK_CHAIN); + } + if ipt.flush_chain("mangle", DPIBREAK_CHAIN).is_ok() { log_println!(LogLevel::Info, "{}: flush chain {}", ipt.cmd, DPIBREAK_CHAIN); } diff --git a/src/platform/linux/nftables.rs b/src/platform/linux/nftables.rs index ccb918e..27e1830 100644 --- a/src/platform/linux/nftables.rs +++ b/src/platform/linux/nftables.rs @@ -103,6 +103,65 @@ pub fn install_nft_rules() -> Result<()> { opt::queue_num()); log_println!(LogLevel::Debug, "nftables: rule json={}", rule); + if opt::fake_autottl() { + let synack_rule = serde_json::json!( + { + "nftables": [ + // SYN,ACK (for --fake-autottl) + { + "add": { + "chain": { + "family": "inet", + "table": DPIBREAK_TABLE, + "name": "INPUT", + "type": "filter", + "hook": "input", + "prio": 0, + "policy": "accept", + } + } + }, + { + "add" : { + "rule": { + "family": "inet", + "table": DPIBREAK_TABLE, + "chain": "INPUT", + "expr": [ + { + "match": { + "left": { "payload": { "protocol": "tcp", "field": "sport" }}, + "op": "==", "right": 443 + } + }, + { + "match": { + "left": { "payload": { "protocol": "tcp", "field": "flags" }}, + "op": "==", "right": 18 // 18 = SYN(2) | ACK(16) + } + }, + { + "queue": { + "num": crate::opt::queue_num(), + "flags": [ "bypass" ] + } + } + ] + }, + } + } + ] + } + ); + + apply_nft_rules(&serde_json::to_string(&synack_rule)?)?; + + log_println!(LogLevel::Info, + "nftables: add chain INPUT, match tcp sport 443 & SYN|ACK -> queue {})", + opt::queue_num()); + log_println!(LogLevel::Debug, "nftables: synack rule json={}", synack_rule); + } + // clienthello filtered by nft IS_U32_SUPPORTED.store(true, Ordering::Relaxed); log_println!(LogLevel::Info, "nftables: create table inet {DPIBREAK_TABLE}"); diff --git a/src/platform/windows.rs b/src/platform/windows.rs index 4303a65..37a6654 100644 --- a/src/platform/windows.rs +++ b/src/platform/windows.rs @@ -23,17 +23,29 @@ use windivert::{ use std::sync::{atomic::Ordering, LazyLock, Mutex, MutexGuard}; use crate::{log::LogLevel, log_println, splash}; +fn windivert_filter() -> String { + let base = "(outbound and tcp and tcp.DstPort == 443 \ + and tcp.Payload[0] == 22 \ + and tcp.Payload[5] == 1)"; + + if crate::opt::fake_autottl() { + let synack = "(!outbound and tcp and tcp.SrcPort == 443 \ + and tcp.Syn and tcp.Ack)"; + format!("({base} or {synack}) and !impostor") + } else { + format!("{base} and !impostor") + } +} + + pub static WINDIVERT_HANDLE: LazyLock<Mutex<WinDivert<NetworkLayer>>> = LazyLock::new(|| { use windivert::*; - const FILTER: &str = "outbound and tcp and tcp.DstPort == 443 \ - and tcp.Payload[0] == 22 \ - and tcp.Payload[5] == 1 \ - and !impostor"; // to prevent inf loop + let filter = windivert_filter(); - let h = match WinDivert::network(FILTER, 0, prelude::WinDivertFlags::new()) { + let h = match WinDivert::network(&filter, 0, prelude::WinDivertFlags::new()) { Ok(h) => { - log_println!(LogLevel::Info, "windivert: HANDLE constructed for {}", FILTER); + log_println!(LogLevel::Info, "windivert: HANDLE constructed for {}", filter); h }, Err(e) => { |
