diff options
| -rw-r--r-- | build.rs | 7 | ||||
| -rw-r--r-- | dpibreak.1 | 31 | ||||
| -rw-r--r-- | dpibreak.1.md | 20 | ||||
| -rw-r--r-- | src/main.rs | 8 | ||||
| -rw-r--r-- | src/pkt.rs | 51 | ||||
| -rw-r--r-- | src/platform/windows.rs | 6 |
6 files changed, 91 insertions, 32 deletions
@@ -1,4 +1,4 @@ -// Copyright 2025 Dillution <[email protected]>. +// Copyright 2025-2026 Dillution <[email protected]>. // // This file is part of DPIBreak. // @@ -16,6 +16,11 @@ // along with DPIBreak. If not, see <https://www.gnu.org/licenses/>. fn main() { + if std::env::var_os("DPIBREAK_SKIP_BUILD_RS").is_some() { + println!("cargo:warning=build.rs skipped (DPIBREAK_SKIP_BUILD_RS is set)"); + return; + } + let target_os = std::env::var("CARGO_CFG_TARGET_OS").unwrap_or_default(); if target_os != "windows" { eprintln!("target_os is not windows"); @@ -64,20 +64,33 @@ ClientHello. Typical values are 0–1000; larger values may increase handshake latency. (default: 0) .TP .B \-\-fake -Enable fake ClientHello packet injection before sending each -packet fragmented. The injected fake packet’s TTL / Hop Limit is -overridden with -.B \-\-fake\-ttl. -All other TCP/IP header fields follow the original packet. -Packets are transmitted in an interleaved order: -(fake 1), (orig 1), (fake 2), (orig 2), ... +Enable +.B fake +ClientHello packet injection before sending each packet +fragmented. TCP/IP header fields follow the original packet unless you +override it using the +.B \-\-fake\-* +options described below. Packets are transmitted in an interleaved +order: (fake 1), (orig 1), (fake 2), (orig 2), ... .TP .B \-\-fake\-ttl \fIu8\fR -Override ttl (IPv4) / hop_limit (IPv6) of fake ClientHello packet. -Ignored unless +Override ttl (IPv4) / hop_limit (IPv6) of +.B fake +packet. Ignored unless .B \-\-fake is enabled. (default: 8) .TP +.B \-\-fake\-badsum +Corrupts the TCP checksum of +.B fake +packets. When enabled, +.B fake +packets cannot pass through most routers and will not behave as +expected. It can be useful if your router/firewall provides an option +to disable TCP checksum verification. Ignored unless +.B \-\-fake +is enabled. +.TP .B \-\-queue\-num \fIu16\fR .Linux only. NFQUEUE number to attach to. The same queue number is diff --git a/dpibreak.1.md b/dpibreak.1.md index f303b04..a11475b 100644 --- a/dpibreak.1.md +++ b/dpibreak.1.md @@ -46,15 +46,21 @@ ClientHello. Typical values are 0–1000; larger values may increase handshake latency. (default: 0) **--fake** -Enable fake ClientHello packet injection before sending each packet -fragmented. The injected fake packet’s TTL / Hop Limit is overridden -with **--fake-ttl.** All other TCP/IP header fields follow the original -packet. Packets are transmitted in an interleaved order: (fake 1), (orig -1), (fake 2), (orig 2), ... +Enable **fake** ClientHello packet injection before sending each packet +fragmented. TCP/IP header fields follow the original packet unless you +override it using the **--fake-\*** options described below. Packets are +transmitted in an interleaved order: (fake 1), (orig 1), (fake 2), (orig +2), ... **--fake-ttl *u8*** -Override ttl (IPv4) / hop_limit (IPv6) of fake ClientHello packet. -Ignored unless **--fake** is enabled. (default: 8) +Override ttl (IPv4) / hop_limit (IPv6) of **fake** packet. Ignored +unless **--fake** is enabled. (default: 8) + +**--fake-badsum** +Corrupts the TCP checksum of **fake** packets. When enabled, **fake** +packets cannot pass through most routers and will not behave as +expected. It can be useful if your router/firewall provides an option to +disable TCP checksum verification. Ignored unless **--fake** is enabled. **--queue-num *u16*** diff --git a/src/main.rs b/src/main.rs index 498fed2..ab7becc 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,4 @@ -// Copyright 2025 Dillution <[email protected]>. +// Copyright 2025-2026 Dillution <[email protected]>. // // This file is part of DPIBreak. // @@ -54,7 +54,7 @@ fn split_packet( end: Option<u32>, out_buf: &mut Vec<u8> ) -> Result<()> { - pkt::split_packet_0(view, start, end, out_buf, None, None) + pkt::split_packet_0(view, start, end, out_buf, None, None, None) } fn send_segment( @@ -158,6 +158,7 @@ Options: --fake Enable fake clienthello injection --fake-ttl <u8> Override ttl of fake clienthello (default: 8) + --fake-badsum Modifies the TCP checksum of the fake packet to an invalid value. -h, --help Show this help"# ); @@ -183,6 +184,7 @@ fn parse_args_1() -> Result<()> { let mut no_splash: bool = false; let mut fake: bool = false; let mut fake_ttl: u8 = 8; + let mut fake_badsum: bool = false; #[cfg(debug_assertions)] let mut log_level: log::LogLevel = LogLevel::Debug; @@ -206,6 +208,7 @@ fn parse_args_1() -> Result<()> { "--fake" => { fake = true; } "--fake-ttl" => { fake_ttl = take_value(&mut args, argv)?; } + "--fake-badsum" => { fake_badsum = true } #[cfg(target_os = "linux")] "--queue-num" => { queue_num = take_value(&mut args, argv)?; } @@ -223,6 +226,7 @@ fn parse_args_1() -> Result<()> { set_opt("OPT_DELAY_MS", &OPT_DELAY_MS, delay_ms)?; set_opt("OPT_FAKE", &OPT_FAKE, fake)?; set_opt("OPT_FAKE_TTL", &pkt::OPT_FAKE_TTL, fake_ttl)?; + set_opt("OPT_FAKE_BADSUM", &pkt::OPT_FAKE_BADSUM, fake_badsum)?; #[cfg(target_os = "linux")] set_opt("OPT_QUEUE_NUM", &platform::OPT_QUEUE_NUM, queue_num)?; #[cfg(target_os = "linux")] set_opt("OPT_NFT_COMMAND", &platform::OPT_NFT_COMMAND, nft_command)?; @@ -1,4 +1,4 @@ -// Copyright 2025 Dillution <[email protected]>. +// Copyright 2025-2026 Dillution <[email protected]>. // // This file is part of DPIBreak. // @@ -83,11 +83,16 @@ const DEFAULT_FAKE_TLS_CLIENTHELLO: &'static [u8] = &[ ]; pub static OPT_FAKE_TTL: OnceLock<u8> = OnceLock::new(); +pub static OPT_FAKE_BADSUM: OnceLock<bool> = OnceLock::new(); fn fake_ttl() -> u8 { *OPT_FAKE_TTL.get().expect("OPT_FAKE_TTL not initialized") } +fn fake_badsum() -> bool { + *OPT_FAKE_BADSUM.get().expect("OPT_FAKE_BADSUM not initialized") +} + pub struct PktView<'a> { pub ip: IpSlice<'a>, pub tcp: TcpSlice<'a> @@ -106,14 +111,15 @@ impl<'a> PktView<'a> { /// Write TCP/IP packet (payload = view.tcp.payload[start..Some(end)]) /// to out_buf, explicitly clearing before. /// -/// If payload or ttl is given, override view's one. +/// If payload, ttl or tcp_checksum is given, override view's one. pub fn split_packet_0( view: &PktView, start: u32, end: Option<u32>, out_buf: &mut Vec<u8>, payload: Option<&[u8]>, - ttl: Option<u8> + ttl: Option<u8>, + tcp_checksum: Option<u16> ) -> Result<()> { use etherparse::*; @@ -131,33 +137,49 @@ pub fn split_packet_0( let mut tcp_hdr = tcp.to_header(); tcp_hdr.sequence_number += start; - let builder = match ip { + let (builder, l3_len) = match ip { IpSlice::Ipv4(hdr) => { let mut ip_hdr = hdr.header().to_header(); if let Some(t) = ttl { ip_hdr.time_to_live = t; }; - PacketBuilder::ip(IpHeaders::Ipv4( + let exts = hdr.extensions().to_header(); + let l3_len = ip_hdr.header_len() + exts.header_len(); + + (PacketBuilder::ip(IpHeaders::Ipv4( ip_hdr, hdr.extensions().to_header() - )) + )), l3_len) }, IpSlice::Ipv6(hdr) => { let mut ip6_hdr = hdr.header().to_header(); if let Some(t) = ttl { ip6_hdr.hop_limit = t; }; - PacketBuilder::ip(IpHeaders::Ipv6( + let l3_len = Ipv6Header::LEN; + + (PacketBuilder::ip(IpHeaders::Ipv6( ip6_hdr, Default::default() - )) + )), l3_len) } - }.tcp_header(tcp_hdr).options_raw(opts)?; + }; + + let builder = builder.tcp_header(tcp_hdr).options_raw(opts)?; let payload = &payload[start as usize..end as usize]; out_buf.clear(); builder.write(out_buf, payload)?; + if let Some(cs) = tcp_checksum { + let tcp_csum_off = l3_len + 16; + + if out_buf.len() < tcp_csum_off + 2 { + return Err(anyhow!("packet too short for tcp checksum patch")); + } + out_buf[tcp_csum_off..tcp_csum_off + 2].copy_from_slice(&cs.to_be_bytes()); + } + Ok(()) } @@ -167,6 +189,15 @@ pub fn fake_clienthello( end: Option<u32>, out_buf: &mut Vec<u8> ) -> Result<()> { + + let tcp_checksum = if fake_badsum() { + Some(0) + } else { + None + }; + split_packet_0(view, start, end, out_buf, - Some(DEFAULT_FAKE_TLS_CLIENTHELLO), Some(fake_ttl())) + Some(DEFAULT_FAKE_TLS_CLIENTHELLO), + Some(fake_ttl()), + tcp_checksum) } diff --git a/src/platform/windows.rs b/src/platform/windows.rs index 4d75e0e..4303a65 100644 --- a/src/platform/windows.rs +++ b/src/platform/windows.rs @@ -1,4 +1,4 @@ -// Copyright 2025 Dillution <[email protected]>. +// Copyright 2025-2026 Dillution <[email protected]>. // // This file is part of DPIBreak. // @@ -72,8 +72,8 @@ pub fn send_to_raw(pkt: &[u8]) -> Result<()> { let mut p = unsafe { packet::WinDivertPacket::<NetworkLayer>::new(pkt.to_vec()) }; p.address.set_outbound(true); - p.address.set_ip_checksum(true); - p.address.set_tcp_checksum(true); + p.address.set_ip_checksum(true); // TODO: test if this is needed + p.address.set_tcp_checksum(false); // For badsum; anyway it is already calculated p.address.set_impostor(true); // to prevent inf loop lock_handle().send(&p)?; |
