85 lines
2.8 KiB
Rust
85 lines
2.8 KiB
Rust
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<FrameControl> {
|
|
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(())
|
|
}
|