summaryrefslogtreecommitdiffhomepage
path: root/src/main.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/main.rs')
-rw-r--r--src/main.rs217
1 files changed, 9 insertions, 208 deletions
diff --git a/src/main.rs b/src/main.rs
index ab7becc..a36bd48 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -15,16 +15,16 @@
// You should have received a copy of the GNU General Public License
// along with DPIBreak. If not, see <https://www.gnu.org/licenses/>.
-use anyhow::{Result, anyhow, Context};
+use anyhow::{Result, Context};
use std::sync::{
atomic::{Ordering, AtomicBool},
- OnceLock,
};
mod platform;
mod pkt;
mod tls;
mod log;
+mod opt;
use log::LogLevel;
@@ -36,211 +36,6 @@ const MESSAGE_AT_RUN: &str = r#"DPIBreak is now running.
Press Ctrl+C or close this window to stop.
"#;
static RUNNING: AtomicBool = AtomicBool::new(true);
-static OPT_DELAY_MS: OnceLock<u64> = OnceLock::new();
-
-static OPT_FAKE: OnceLock<bool> = OnceLock::new();
-
-fn opt_fake() -> bool {
- *crate::OPT_FAKE.get().expect("OPT_FAKE not initialized")
-}
-
-fn delay_ms() -> u64 {
- *OPT_DELAY_MS.get().expect("OPT_DELAY_MS not initialized")
-}
-
-fn split_packet(
- view: &pkt::PktView,
- start: u32,
- end: Option<u32>,
- out_buf: &mut Vec<u8>
-) -> Result<()> {
- pkt::split_packet_0(view, start, end, out_buf, None, None, None)
-}
-
-fn send_segment(
- view: &pkt::PktView,
- start: u32,
- end: Option<u32>,
- buf: &mut Vec<u8>
-) -> Result<()> {
- use platform::send_to_raw;
-
- if opt_fake() {
- pkt::fake_clienthello(view, start, end, buf)?;
- send_to_raw(buf)?;
- }
- split_packet(view, start, end, buf)?;
- send_to_raw(buf)?;
-
- Ok(())
-}
-
-fn split_packet_1(view: &pkt::PktView, order: &[u32], buf: &mut Vec<u8>) -> Result<()> {
- 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 {
- send_segment(view, first, Some(next), buf)?;
- std::thread::sleep(std::time::Duration::from_millis(delay_ms()));
- first = next;
- }
-
- send_segment(view, first, None, 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);
-
- #[cfg(windows)]
- let is_filtered = true;
-
- let view = pkt::PktView::from_raw(pkt)?;
-
- if !is_filtered && !tls::is_client_hello(view.tcp.payload()) {
- return Ok(false);
- }
-
- // TODO: if clienthello packet has been (unlikely) fragmented,
- // we should find the second part and drop, reassemble it here.
-
- split_packet_1(&view, &[0, 1], buf)?;
-
- #[cfg(debug_assertions)]
- log_println!(LogLevel::Debug, "packet is handled, len={}", pkt.len());
-
- Ok(true)
-}
-
-#[macro_export]
-macro_rules! handle_packet {
- ($bytes:expr, $buf:expr, handled => $on_handled:expr, rejected => $on_rejected:expr $(,)?) => {{
- match handle_packet($bytes, $buf) {
- Ok(true) => { $on_handled }
- Ok(false) => { $on_rejected }
- Err(e) => {
- log_println!(LogLevel::Warning, "handle_packet: {e}");
- $on_rejected
- }
- }
- }};
-}
-
-fn take_value<T, I>(args: &mut I, arg_name: &str) -> Result<T>
-where
- T: std::str::FromStr,
- T::Err: std::error::Error + Send + Sync + 'static,
- I: Iterator<Item = String>,
-{
- let raw = args
- .next()
- .ok_or_else(|| anyhow!("argument: missing value after {}", arg_name))?;
- raw.parse::<T>()
- .with_context(|| format!("argument {}: invalid value '{}'", arg_name, raw))
-}
-
-fn usage() {
- println!(
- r#"Usage: dpibreak [OPTIONS]
-
-Options:
- --delay-ms <u64> (default: 0)
- --queue-num <u16> (linux only, default: 1)
- --nft-command <string> (linux only, default: nft)
- --loglevel <debug|info|warning|error> (default: warning)
- --no-splash Do not print splash messages
-
- --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"#
- );
-}
-
-fn set_opt<T: std::fmt::Display>(
- name: &str,
- cell: &OnceLock<T>,
- value: T,
-) -> Result<()> {
- log_println!(LogLevel::Info, "{name}: {value}");
- cell.set(value).map_err(|_| anyhow!("{name} already initialized"))
-}
-
-fn splash_banner() {
- splash!("{PROJECT_NAME} v{PKG_VERSION} - {PKG_DESCRIPTION}");
- splash!("{PKG_HOMEPAGE}");
- splash!("");
-}
-
-fn parse_args_1() -> Result<()> {
- let mut delay_ms: u64 = 0;
- 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;
- #[cfg(not(debug_assertions))]
- let mut log_level: log::LogLevel = LogLevel::Warning;
- #[cfg(target_os = "linux")]
- let mut queue_num: u16 = 1;
- #[cfg(target_os = "linux")]
- let mut nft_command = String::from("nft");
-
- let mut args = std::env::args().skip(1); // program name
-
- while let Some(arg) = args.next() {
- let argv = arg.as_str();
-
- match argv {
- "-h" | "--help" => { usage(); std::process::exit(0); }
- "--delay-ms" => { delay_ms = take_value(&mut args, argv)?; }
- "--loglevel" => { log_level = take_value(&mut args, argv)?; }
- "--no-splash" => { no_splash = true; }
-
- "--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)?; }
-
- #[cfg(target_os = "linux")]
- "--nft-command" => { nft_command = take_value(&mut args, argv)?; }
-
- _ => { return Err(anyhow!("argument: unknown: {}", arg)); }
- }
- }
-
- log::set_no_splash(no_splash).map_err(|e| anyhow!("{e}"))?;
- log::set_log_level(log_level).map_err(|e| anyhow!("{e}"))?;
-
- 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)?;
-
- Ok(())
-}
-
-fn parse_args() {
- if let Err(e) = parse_args_1() {
- log_println!(LogLevel::Error, "{e}");
- usage();
- std::process::exit(1);
- }
-}
fn trap_exit() -> Result<()> {
ctrlc::set_handler(|| {
@@ -261,9 +56,15 @@ impl Drop for EnsureCleanup {
}
}
+fn splash_banner() {
+ splash!("{PROJECT_NAME} v{PKG_VERSION} - {PKG_DESCRIPTION}");
+ splash!("{PKG_HOMEPAGE}");
+ splash!("");
+}
+
fn main_0() -> Result<()> {
trap_exit()?;
- parse_args();
+ opt::parse_args();
splash_banner();
let _guard = EnsureCleanup;