diff options
| -rw-r--r-- | Cargo.lock | 286 | ||||
| -rw-r--r-- | Cargo.toml | 2 | ||||
| -rw-r--r-- | dpibreak.1 | 21 | ||||
| -rw-r--r-- | dpibreak.1.md | 12 | ||||
| -rw-r--r-- | src/main.rs | 33 | ||||
| -rw-r--r-- | src/platform/linux.rs | 165 |
6 files changed, 439 insertions, 80 deletions
@@ -13,9 +13,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.98" +version = "1.0.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" +checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" [[package]] name = "arrayvec" @@ -37,24 +37,24 @@ checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" [[package]] name = "bitflags" -version = "2.9.1" +version = "2.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" +checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394" [[package]] name = "bytemuck" -version = "1.23.1" +version = "1.23.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c76a5792e44e4abe34d3abf15636779261d45a7450612059293d1d2cfc63422" +checksum = "3995eaeebcdf32f91f980d360f78732ddc061097ab4e39991ae7a6ace9194677" dependencies = [ "bytemuck_derive", ] [[package]] name = "bytemuck_derive" -version = "1.9.3" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ecc273b49b3205b83d648f0690daa588925572cc5063745bfe547fe7ec8e1a1" +checksum = "4f154e572231cb6ba2bd1176980827e3d5dc04cc183a75dea38109fbdd672d29" dependencies = [ "proc-macro2", "quote", @@ -69,18 +69,19 @@ checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" [[package]] name = "cc" -version = "1.2.30" +version = "1.2.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "deec109607ca693028562ed836a5f1c4b8bd77755c4e132fc5ce11b0b6211ae7" +checksum = "e1354349954c6fc9cb0deab020f27f783cf0b604e8bb754dc4658ecf0d29c35f" dependencies = [ + "find-msvc-tools", "shlex", ] [[package]] name = "cfg-if" -version = "1.0.1" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" +checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" [[package]] name = "cfg_aliases" @@ -90,30 +91,45 @@ checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" [[package]] name = "ctrlc" -version = "3.4.7" +version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46f93780a459b7d656ef7f071fe699c4d3d2cb201c4b24d085b6ddc505276e73" +checksum = "881c5d0a13b2f1498e2306e82cbada78390e152d4b1378fb28a84f4dcd0dc4f3" dependencies = [ + "dispatch", "nix 0.30.1", - "windows-sys", + "windows-sys 0.61.1", ] [[package]] +name = "dispatch" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" + +[[package]] name = "dpibreak" version = "0.0.2" dependencies = [ "anyhow", "ctrlc", - "etherparse 0.18.0", + "etherparse 0.18.2", "iptables", "nfq", + "nftables", "nix 0.27.1", + "serde_json", "socket2", "windivert", "winres", ] [[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" @@ -124,14 +140,26 @@ dependencies = [ [[package]] name = "etherparse" -version = "0.18.0" +version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ff83a5facf1a7cbfef93cfb48d6d4fb6a1f42d8ac2341a96b3255acb4d4f860" +checksum = "54a48e7bdc36cdf86876a6890c0840957029374ea07f6697c96fa15898730375" dependencies = [ "arrayvec", ] [[package]] +name = "find-msvc-tools" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ced73b1dacfc750a6db6c0a0c3a3853c8b41997e2e2c563dc90804ae6867959" + +[[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" @@ -143,6 +171,12 @@ dependencies = [ ] [[package]] +name = "itoa" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" + +[[package]] name = "lazy_static" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -150,15 +184,15 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.174" +version = "0.2.176" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776" +checksum = "58f929b4d672ea937a23a1ab494143d968337a5f47e56d0815df1e0890ddf174" [[package]] name = "memchr" -version = "2.7.5" +version = "2.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" +checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" [[package]] name = "memoffset" @@ -180,6 +214,21 @@ 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" @@ -198,7 +247,7 @@ version = "0.27.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.9.4", "cfg-if", "libc", ] @@ -209,7 +258,7 @@ version = "0.30.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.9.4", "cfg-if", "cfg_aliases", "libc", @@ -217,9 +266,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.95" +version = "1.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" +checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" dependencies = [ "unicode-ident", ] @@ -234,10 +283,30 @@ 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.1" +version = "1.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +checksum = "8b5288124840bee7b386bc413c487869b360b2b4ec421ea56425128692f2a82c" dependencies = [ "aho-corasick", "memchr", @@ -247,9 +316,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.9" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" +checksum = "833eb9ce86d40ef33cb1306d8accf7bc8ec2bfea4355cbdebb3df68b40925cad" dependencies = [ "aho-corasick", "memchr", @@ -258,24 +327,65 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.5" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "caf4aa5b0f434c91fe5c7f1ecb6a5ece2130b02ad2a590589dda5146df959001" + +[[package]] +name = "ryu" +version = "1.0.20" +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 = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" +checksum = "33d020396d1d138dc19f1165df7545479dcd58d93810dc5d646a16e55abefa80" +dependencies = [ + "proc-macro2", + "quote", + "serde_derive_internals", + "syn", +] [[package]] name = "serde" -version = "1.0.219" +version = "1.0.227" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80ece43fc6fbed4eb5392ab50c07334d3e577cbf40997ee896fe7af40bba4245" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.227" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" +checksum = "7a576275b607a2c86ea29e410193df32bc680303c82f31e275bbfcafe8b33be5" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.219" +version = "1.0.227" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" +checksum = "51e694923b8824cf0e9b382adf0f60d4e05f348f357b38833a3fa5ed7c2ede04" dependencies = [ "proc-macro2", "quote", @@ -283,6 +393,41 @@ 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" +checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", + "serde_core", +] + +[[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" @@ -295,14 +440,32 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "233504af464074f9d066d7b5416c5f9b894a5862a6506e306f7b816cdd6f1807" dependencies = [ "libc", - "windows-sys", + "windows-sys 0.59.0", +] + +[[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.104" +version = "2.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40" +checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" dependencies = [ "proc-macro2", "quote", @@ -315,7 +478,16 @@ version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" dependencies = [ - "thiserror-impl", + "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", ] [[package]] @@ -330,6 +502,17 @@ 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" @@ -340,9 +523,9 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.18" +version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" +checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" [[package]] name = "windivert" @@ -351,7 +534,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc6b6833a760d1c36b489314a5541a12a39d162dc8341d8f6f400212b96d3df1" dependencies = [ "etherparse 0.13.0", - "thiserror", + "thiserror 1.0.69", "windivert-sys", "windows", ] @@ -363,7 +546,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "832bc4af9272458a8a64395b3aabe10dc4089546486fcbd0e19b9b6d28ba6e54" dependencies = [ "cc", - "thiserror", + "thiserror 1.0.69", "windows", ] @@ -377,6 +560,12 @@ dependencies = [ ] [[package]] +name = "windows-link" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45e46c0661abb7180e7b9c281db115305d49ca1709ab8242adf09666d2173c65" + +[[package]] name = "windows-sys" version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -386,6 +575,15 @@ dependencies = [ ] [[package]] +name = "windows-sys" +version = "0.61.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f109e41dd4a3c848907eb83d5a42ea98b3769495597450cf6d153507b166f0f" +dependencies = [ + "windows-link", +] + +[[package]] name = "windows-targets" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -31,6 +31,8 @@ homepage = "https://github.com/dilluti0n/dpibreak" ctrlc = { version = "3.4", features = ["termination"] } anyhow = "1" etherparse = "0.18" +nftables = "0.6" +serde_json = "1.0.145" [target.'cfg(target_os = "linux")'.dependencies] iptables = "0.4" @@ -1,4 +1,4 @@ -.TH DPIBREAK 1 "September 2025" "DPIBreak v0.0.2" "User Commands" +.TH DPIBREAK 1 "October 2025" "DPIBreak v0.0.2" "User Commands" .nh .ad l @@ -33,15 +33,23 @@ Root privileges (or capabilities .BR CAP_NET_ADMIN and .BR CAP_NET_RAW ) -are required to install iptables rules and attach to NFQUEUE. The +are required to install rules and attach to NFQUEUE. The +.B nft +command should be available. If it is not, +.B dpibreak +try to fallback .B iptables and .B ip6tables -commands must be available. Kernel support for -.BR xt_u32 -and +. +Kernel support for .BR nfnetlink_queue -is required (these modules are typically auto\-loaded). +and +.BR xt_u32 +(when +.B nft +is not available) +is required. (these modules are typically auto\-loaded) .TP \fBWindows\fR @@ -126,6 +134,7 @@ start (for example, due to insufficient privileges, missing iptables/WinDivert, or invalid options). .SH SEE ALSO +.BR nft (8), .BR iptables (8), .BR ip6tables (8), .BR tcpdump (1), diff --git a/dpibreak.1.md b/dpibreak.1.md index def1259..03c7031 100644 --- a/dpibreak.1.md +++ b/dpibreak.1.md @@ -26,10 +26,11 @@ program enables it system-wide; stopping it disables it. **Linux** Root privileges (or capabilities **CAP_NET_ADMIN** and **CAP_NET_RAW**) -are required to install iptables rules and attach to NFQUEUE. The -**iptables** and **ip6tables** commands must be available. Kernel -support for **xt_u32** and **nfnetlink_queue** is required (these -modules are typically auto-loaded). +are required to install rules and attach to NFQUEUE. The **nft** command +should be available. If it is not, **dpibreak** try to fallback +**iptables** and **ip6tables** Kernel support for **nfnetlink_queue** +and **xt_u32** (when **nft** is not available) is required. (these +modules are typically auto-loaded) <!-- --> @@ -108,7 +109,8 @@ invalid options). ## SEE ALSO -**iptables**(8), **ip6tables**(8), **tcpdump**(1), **wireshark**(1) +**nft**(8), **iptables**(8), **ip6tables**(8), **tcpdump**(1), +**wireshark**(1) GoodByeDPI \<https://github.com/ValdikSS/GoodbyeDPI\> diff --git a/src/main.rs b/src/main.rs index 12bd303..e41888f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -83,10 +83,31 @@ fn split_packet(pkt: &pkt::PktView, start: u32, end: Option<u32>, Ok(()) } -/// Return Ok(true) if packet is handled -fn handle_packet(pkt: &[u8], buf: &mut Vec::<u8>) -> Result<bool> { +fn split_packet_1(view: &pkt::PktView, order: &[u32], buf: &mut Vec<u8>) -> Result<()> { use platform::send_to_raw; + let mut it = order.iter().copied(); + + let Some(mut first) = it.next() else { + return Err(anyhow!("split_packet_1: invalid order array")); + }; + + for next in it { + split_packet(view, first, Some(next), buf)?; + send_to_raw(buf)?; + std::thread::sleep(std::time::Duration::from_millis(delay_ms())); + first = next; + } + + split_packet(view, first, None, buf)?; + send_to_raw(buf)?; + + Ok(()) +} + + +/// Return Ok(true) if packet is handled +fn handle_packet(pkt: &[u8], buf: &mut Vec::<u8>) -> Result<bool> { #[cfg(target_os = "linux")] let is_filtered = platform::IS_U32_SUPPORTED.load(Ordering::Relaxed); @@ -102,13 +123,7 @@ fn handle_packet(pkt: &[u8], buf: &mut Vec::<u8>) -> Result<bool> { // TODO: if clienthello packet has been (unlikely) fragmented, // we should find the second part and drop, reassemble it here. - split_packet(&view, 0, Some(1), buf)?; - send_to_raw(&buf)?; - - std::thread::sleep(std::time::Duration::from_millis(delay_ms())); - - split_packet(&view, 1, None, buf)?; - send_to_raw(&buf)?; + split_packet_1(&view, &[0, 1], buf)?; #[cfg(debug_assertions)] log_println!(LogLevel::Debug, "packet is handled, len={}", pkt.len()); diff --git a/src/platform/linux.rs b/src/platform/linux.rs index 0faef31..e04a6e4 100644 --- a/src/platform/linux.rs +++ b/src/platform/linux.rs @@ -28,6 +28,7 @@ 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(); @@ -83,7 +84,7 @@ fn iptables_err(e: impl ToString) -> Error { Error::msg(format!("iptables: {}", e.to_string())) } -fn install_rules(ipt: &IPTables) -> Result<()> { +fn install_iptables_rules(ipt: &IPTables) -> Result<()> { let base = format!("-p tcp --dport 443 -j NFQUEUE --queue-num {} --queue-bypass", queue_num()); let rule = if is_u32_supported(ipt) { @@ -107,7 +108,7 @@ fn install_rules(ipt: &IPTables) -> Result<()> { Ok(()) } -fn cleanup_rules(ipt: &IPTables) -> Result<()> { +fn cleanup_iptables_rules(ipt: &IPTables) -> Result<()> { if ipt.delete("mangle", "POSTROUTING", &format!("-j {}", DPIBREAK_CHAIN)).is_ok() { log_println!(LogLevel::Info, "{}: deleted jump from POSTROUTING", ipt.cmd); } @@ -123,12 +124,151 @@ fn cleanup_rules(ipt: &IPTables) -> Result<()> { Ok(()) } -pub fn cleanup() -> Result<()> { - let ipt = iptables::new(false).map_err(iptables_err)?; - let ip6 = iptables::new(true).map_err(iptables_err)?; +const DPIBREAK_TABLE: &str = "dpibreak"; + +fn install_nft_rules() -> Result<()> { + use nftables::helper; + + let json = serde_json::json!( + { + "nftables": [ + {"add": {"table": {"family": "inet", "name": DPIBREAK_TABLE}}}, + { + "add": { + "chain": { + "family": "inet", + "table": DPIBREAK_TABLE, + "name": "OUTPUT", + "type": "filter", + "hook": "output", + "prio": 0, + "policy": "accept", + } + } + }, + { + "add": { + "chain": { + "family": "inet", + "table": DPIBREAK_TABLE, + "name": DPIBREAK_CHAIN + } + } + }, + { + "add": { + "rule": { + "family": "inet", + "table": DPIBREAK_TABLE, + "chain": "OUTPUT", + "expr": [{ "jump": { "target": DPIBREAK_CHAIN }}] + } + } + }, + { + "add": { + "rule": { + "family": "inet", + "table": DPIBREAK_TABLE, + "chain": DPIBREAK_CHAIN, + "expr": [ + { + "match": { + "left": {"payload": { "protocol": "tcp", "field": "dport" }}, + "op": "==", + "right": 443 + } + }, + // TLS ContentType == 0x16 (Handshake) + { + "match": { + "left": { "payload": { "base": "ih", "offset": 0, "len": 8 } }, + "op": "==", + "right": 0x16 + } + }, + // HandshakeType == 0x01 (ClientHello) + { + "match": { + // Note: offset and len are both "bit" unit not byte + "left": { "payload": { "base": "ih", "offset": 40, "len": 8 } }, + "op": "==", + "right": 0x01 + } + }, + { + "queue": { + "num": queue_num(), + "flags": [ "bypass" ] + } + } + ] + } + } + } + ] + } + ); + + let json_str = serde_json::to_string(&json)?; + + helper::apply_ruleset_raw(&json_str, helper::DEFAULT_NFT, + helper::DEFAULT_ARGS)?; - cleanup_rules(&ipt)?; - cleanup_rules(&ip6)?; + // clienthello filtered by nft + IS_U32_SUPPORTED.store(true, Ordering::Relaxed); + log_println!(LogLevel::Info, "nftables: create table inet {DPIBREAK_TABLE}"); + + Ok(()) +} + +fn install_rules() -> Result<()> { + match install_nft_rules() { + Ok(_) => {}, + Err(e) => { + IS_NFT_NOT_SUPPORTED.store(true, Ordering::Relaxed); + 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)?; + + install_iptables_rules(&ipt)?; + // FIXME: using xt_u32 on ipv6 is not supported; (even if it does, + // the rule should be different) + install_iptables_rules(&ip6)?; + } + } + + Ok(()) +} + +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)?; + + 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()); + } + + Ok(()) +} + +pub fn cleanup() -> Result<()> { + cleanup_rules()?; if IS_XT_U32_LOADED_BY_US.load(Ordering::Relaxed) { _ = Command::new("modprobe").args(&["-q", "-r", "xt_u32"]).status(); @@ -139,15 +279,8 @@ pub fn cleanup() -> Result<()> { } pub fn bootstrap() -> Result<()> { - let ipt = iptables::new(false).map_err(iptables_err)?; - let ip6 = iptables::new(true).map_err(iptables_err)?; - - cleanup().ok(); - install_rules(&ipt)?; - // FIXME: using xt_u32 on ipv6 is not supported; (even if it does, - // the rule should be different) - install_rules(&ip6)?; - Ok(()) + _ = cleanup(); // In case the previous execution was not cleaned properly + install_rules() } use socket2::{Domain, Protocol, Socket, Type}; |
