use pcap::Capture; use stable_eyre::eyre::{eyre, Result}; mod ieee80211 { use int_enum::IntEnum; use std::convert::TryFrom; // data/extension frames are irrelevant so just ignore their subtype #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub enum FrameType { Management(ManagementSubtype), Control(ControlSubtype), Data, Extension } #[repr(u8)] #[derive(Clone, Copy, Debug, Eq, PartialEq, IntEnum)] pub enum ManagementSubtype { ProbeRequest = 0b0100, ProbeResponse = 0b0101, TimingAdvertisement = 0b0110, Beacon = 0b1000 } #[repr(u8)] #[derive(Clone, Copy, Debug, Eq, PartialEq, IntEnum)] pub enum ControlSubtype { Rts = 0b1011, Cts = 0b1100, Ack = 0b1101 } #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub struct FrameControl { pub version: u8, pub ftype: FrameType } pub fn parse_frame_control(version_type_subtype: u8, flags: u8) -> Option { let subtype = version_type_subtype >> 4 & 0b1111; let ftype = match version_type_subtype >> 2 & 0b11 { 0b00 => FrameType::Management(ManagementSubtype::try_from(subtype).ok()?), 0b01 => FrameType::Control(ControlSubtype::try_from(subtype).ok()?), 0b10 => FrameType::Data, 0b11 => FrameType::Extension, _ => unreachable!() }; Some(FrameControl { version: version_type_subtype & 0b11, ftype: ftype }) } pub struct MacAddress([u8; 12]); } fn main() -> Result<()> { let cap = Capture::from_device("mon0")?.immediate_mode(true); let mut cap = cap.open()?; if cap.get_datalink() != pcap::Linktype::IEEE802_11_RADIOTAP { return Err(eyre!("device link type wrong")) } while let Ok(packet) = cap.next() { //println!("{:?}", packet); match radiotap::parse(packet.data) { Ok(header) => { let data = &packet.data[header.length()..]; match ieee80211::parse_frame_control(data[0], data[1]) { Some(x) if x.ftype != ieee80211::FrameType::Data => { println!("RTH={:?} FH={:?} MAC1={:?}", header, x, &data[4..10]); if data.len() >= 16 { println!("MAC2={:?}", &data[10..16]); } if data.len() >= 22 { println!("MAC3={:?}", &data[16..22]); } }, _ => {} } }, // This happens sometimes. I don't know why, since it really shouldn't (the radiotap headers are applied by the kernel). Thusly, just ignore it and hope it goes away. Err(e) => { eprintln!("header decoding failed: {:?}", e); } } } Ok(()) }