use crate::config::Config; use crate::worker::WorkerState; use iced::{Color, Element}; use iced::widget::{button, column, container, pick_list, row, text}; use pnet::packet::{MutablePacket, Packet}; use pnet::util::MacAddr; use pnet_packet::arp::{ArpHardwareTypes, ArpOperations, MutableArpPacket}; use pnet_packet::ethernet::{EtherTypes, MutableEthernetPacket}; use std::fmt::Display; use std::net::{IpAddr, Ipv4Addr}; pub const WINDOW_WIDTH: u32 = 750; pub const WINDOW_HEIGHT: u32 = 500; pub struct LANToolkit { pub state: WorkerState, pub cfg: Config, pub ifaces: Vec, pub selected_iface: Option, pub selected_iface_idx: Option, pub raw_packet_available: bool, pub test_message: TestState, pub spoof_state: SpoofState, pub spoof_btn_text: String, pub mode: Mode, } #[derive(Copy, Clone, Debug)] pub enum Messages { RefreshIfaces, IfaceSelected(Option), TestIface, // Running, Random StartSpoof(bool, bool), ModeSwitch, } #[derive(Copy, Clone, Debug)] pub enum TestState { NotTested, Unavailable, Available, InvalidSelection, ListUpdated, NotSelected, } #[derive(Copy, Clone, Debug)] pub enum SpoofState { Unchecked, NotReady, Ready, 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 { SpoofState::Unchecked => write!(f, "点击启动按钮表示您愿意承担相应责任"), SpoofState::NotReady => write!(f, "网卡未检测或不可用"), SpoofState::Ready => write!(f, "准备就绪"), SpoofState::Online => write!(f, "运行中"), } } } impl SpoofState { fn get_color(self) -> Color { match self { SpoofState::Unchecked => Color::from_rgb(1.0f32, 0.0f32, 0.0f32), SpoofState::NotReady => Color::from_rgb(0.0f32, 1.0f32, 1.0f32), SpoofState::Ready => Color::from_rgb(0.0f32, 0.0f32, 1.0f32), SpoofState::Online => Color::from_rgb(0.0f32, 1.0f32, 0.0f32), } } fn get_btn_text(self) -> String { match self { SpoofState::Unchecked => "确认".to_string(), SpoofState::NotReady => "启动".to_string(), SpoofState::Ready => "启动".to_string(), SpoofState::Online => "停止".to_string(), } } } impl Display for TestState { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { TestState::NotTested => write!(f, "尚未测试"), TestState::Unavailable => write!(f, "不可用"), TestState::Available => write!(f, "可用"), TestState::InvalidSelection => write!(f, "无效选项"), TestState::ListUpdated => write!(f, "网卡列表已更新,需要刷新"), TestState::NotSelected => write!(f, "请选择接口"), } } } impl LANToolkit { pub fn boot(state: WorkerState, config: Config) -> impl Fn() -> Self { move || { LANToolkit { state: state.clone(), cfg: config.clone(), ifaces: vec![], selected_iface: None, selected_iface_idx: None, raw_packet_available: false, test_message: TestState::NotSelected, spoof_state: SpoofState::Unchecked, spoof_btn_text: SpoofState::Unchecked.get_btn_text(), mode: Mode::Standard, } } } pub fn view(&self) -> Element<'_, Messages> { container( column![ // 第一行 row![ text("可用的网络接口: ").width(130), pick_list( self.ifaces.clone(), self.selected_iface.clone(), |string: String| { Messages::IfaceSelected( self.ifaces.iter().position(|x| x == string.as_str()) ) } ).placeholder("Select a network interface") .width(300), button("重新加载").on_press(Messages::RefreshIfaces), ].padding(10), // 第二行 row![ text("接口状态: ").width(130), text(self.test_message.to_string()).width(300), button("重新检测").on_press(Messages::TestIface), ].padding(10), // 第三行 row![ button(self.spoof_btn_text.as_str()) .width(515) .on_press(Messages::StartSpoof(false, false)), ].padding(10), column![ text("警告: 在未经过配置的设备上使用该程序可能导致连接的网络瘫痪") .color(Color::from_rgb(1.0f32,0.0f32,0.0f32)), text("使用者需自行承担责任"), ].padding(10), row![ text("当前状态: "), 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) .height(WINDOW_HEIGHT) .into() } fn test_iface(self: &LANToolkit) -> TestState { // Test if the interface is available to send raw packets // First We get the selected interface let ifaces = pnet::datalink::interfaces(); if self.selected_iface_idx.is_none() { return TestState::NotSelected; } if self.selected_iface_idx.unwrap() >= ifaces.len() { return TestState::InvalidSelection; } let iface = ifaces[self.selected_iface_idx.unwrap()].clone(); if iface.name != self.selected_iface.clone().unwrap() { return TestState::ListUpdated; } if iface.mac.is_none() { println!("Test failed because selected interface has no mac address"); return TestState::Unavailable; } if iface.ips.len() == 0 { println!("Test failed because selected interface has no IP address"); return TestState::Unavailable; } // Then we get its v4 address let v4addr = iface.ips.iter().map(|x| -> Option { if x.is_ipv4() { let IpAddr::V4(v4) = x.ip() else { return None }; return Some(v4); } None }).filter(|x| { if x.is_some() { return true; } false }).nth(0); if v4addr.is_none() { println!("Test failed because selected interface has no IPv4 address"); return TestState::Unavailable; } let v4addr = v4addr.unwrap().unwrap(); // Now try to send an arp packet let channel = pnet::datalink::channel(&iface, pnet::datalink::Config::default()); if channel.is_err() { println!("Channel creation failed: {}", channel.err().unwrap()); return TestState::Unavailable; } let channel = channel.unwrap(); let pnet::datalink::Channel::Ethernet(mut tx, _rx) = channel else { // This should not happen return TestState::Unavailable; }; let mut buf = [0u8; 42]; let epacket = MutableEthernetPacket::new(&mut buf); if epacket.is_none() { println!("Ethernet packet couldn't be constructed"); return TestState::Unavailable; } let mut epacket = epacket.unwrap(); epacket.set_destination(MacAddr::broadcast()); epacket.set_source(iface.mac.unwrap()); epacket.set_ethertype(EtherTypes::Arp); let packet = MutableArpPacket::new(epacket.payload_mut()); if packet.is_none() { println!("Test failed because error occurred while constructing ArpPacket"); return TestState::Unavailable; } let mut packet = packet.unwrap(); packet.set_hardware_type(ArpHardwareTypes::Ethernet); packet.set_hw_addr_len(6); packet.set_proto_addr_len(4); packet.set_protocol_type(EtherTypes::Ipv4); packet.set_operation(ArpOperations::Request); packet.set_sender_hw_addr(iface.mac.unwrap()); packet.set_sender_proto_addr(v4addr); packet.set_target_hw_addr(MacAddr::zero()); packet.set_target_proto_addr(Ipv4Addr::new(1,2,3,4)); // After construction we send it let res = tx.send_to(epacket.packet(), None); if res.is_none() { // That means theres no sufficient capacity in the buffer println!("Test failed because send_to() returns None"); return TestState::Unavailable; } if let Err(e) = res.unwrap() { println!("Send arp packet failed because {}", e); return TestState::Unavailable; } TestState::Available } fn reset(&mut self) { self.selected_iface = None; self.selected_iface_idx = None; self.raw_packet_available = false; if !matches!(self.spoof_state, SpoofState::Unchecked) { self.spoof_state = SpoofState::NotReady; } self.state.tx.send(Messages::StartSpoof(false, false)).unwrap(); } pub fn update(&mut self, message: Messages) { let mut messages = message; if let Messages::IfaceSelected(Some(index)) = messages { self.reset(); self.selected_iface_idx = Some(index); self.selected_iface = self.ifaces.get(index).cloned(); self.test_message = TestState::NotTested; } if matches!(messages, Messages::RefreshIfaces) { // Refresh Interfaces let ifaces = pnet::datalink::interfaces(); self.ifaces = ifaces.iter().map(|x| x.name.clone()).collect(); self.reset(); self.test_message = TestState::NotSelected; } if matches!(messages, Messages::TestIface) { self.test_message = self.test_iface(); if matches!(self.test_message, TestState::Available) { self.raw_packet_available = true; if matches!(self.spoof_state, SpoofState::NotReady) { self.spoof_state = SpoofState::Ready; } } } 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 { SpoofState::Ready }else { SpoofState::NotReady } }, SpoofState::NotReady => {}, SpoofState::Ready => { messages = Messages::StartSpoof(true, self.mode == Mode::Random); self.spoof_state = SpoofState::Online }, SpoofState::Online => { messages = Messages::StartSpoof(false, false); self.spoof_state = SpoofState::Ready } } } self.spoof_btn_text = self.spoof_state.get_btn_text(); self.state.tx.send(messages).unwrap(); } }