From 3d946ce89fda99e16d3552e9f8349c8b11da808e Mon Sep 17 00:00:00 2001 From: osmarks Date: Sun, 18 Apr 2021 21:09:12 +0100 Subject: [PATCH] slightly improve things There appear to be issues with data frames containing tons of unique MAC addresses for no apparent reason (specifically QoS ones?) so there may be misparsing --- src/main.rs | 91 ++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 80 insertions(+), 11 deletions(-) diff --git a/src/main.rs b/src/main.rs index 3268f84..ac0a149 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,9 +1,13 @@ use pcap::Capture; use stable_eyre::eyre::{eyre, Result}; +use std::collections::HashSet; +use std::convert::TryInto; mod ieee80211 { use int_enum::IntEnum; use std::convert::TryFrom; + use std::convert::TryInto; + use std::fmt; // data/extension frames are irrelevant so just ignore their subtype #[derive(Clone, Copy, Debug, Eq, PartialEq)] @@ -17,10 +21,17 @@ mod ieee80211 { #[repr(u8)] #[derive(Clone, Copy, Debug, Eq, PartialEq, IntEnum)] pub enum ManagementSubtype { + AssociationRequest = 0b0000, + AssociationResponse = 0b0001, + ReassociationRequest = 0b0010, + ReassociationResponse = 0b0011, ProbeRequest = 0b0100, ProbeResponse = 0b0101, - TimingAdvertisement = 0b0110, - Beacon = 0b1000 + Beacon = 0b1000, + Disassociation = 0b1010, + Authentication = 0b1011, + Deauthentication = 0b1100, + Other = 0b1111 } #[repr(u8)] @@ -28,31 +39,75 @@ mod ieee80211 { pub enum ControlSubtype { Rts = 0b1011, Cts = 0b1100, - Ack = 0b1101 + Ack = 0b1101, + Other = 0b1111 } #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub struct FrameControl { pub version: u8, - pub ftype: FrameType + pub ftype: FrameType, + pub to_ds: bool, + pub from_ds: bool, + pub more_fragments: bool, + pub retry: bool, + pub more_data: bool, + pub protected: bool, + pub htc_order: bool, + subtype: u8 + } + + // read a bit out of a number (0 = LSB) + fn read_bit(x: u8, bit: u8) -> bool { + x >> bit & 0b1 == 1 } 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()?), + 0b00 => FrameType::Management(ManagementSubtype::try_from(subtype).unwrap_or(ManagementSubtype::Other)), + 0b01 => FrameType::Control(ControlSubtype::try_from(subtype).unwrap_or(ControlSubtype::Other)), 0b10 => FrameType::Data, 0b11 => FrameType::Extension, _ => unreachable!() }; + //println!("{:?} {:08b}", ftype, flags); Some(FrameControl { version: version_type_subtype & 0b11, - ftype: ftype + ftype: ftype, + to_ds: read_bit(flags, 0), + from_ds: read_bit(flags, 1), + more_fragments: read_bit(flags, 2), + retry: read_bit(flags, 3), + more_data: read_bit(flags, 5), + protected: read_bit(flags, 6), + htc_order: read_bit(flags, 7), + subtype: subtype }) } + #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] pub struct MacAddress([u8; 6]); + + impl fmt::Display for MacAddress { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}", self.0[0], self.0[1], self.0[2], self.0[3], self.0[4], self.0[5]) + } + } + + impl MacAddress { + pub fn is_local(&self) -> bool { read_bit(self.0[0], 1) } + pub fn is_group(&self) -> bool { read_bit(self.0[0], 0) } + } + + pub fn read_addresses(frame: &[u8]) -> Vec { + let mut out = Vec::with_capacity(4); + if frame.len() >= 10 { out.push(MacAddress(frame[4..10].try_into().unwrap())); } + if frame.len() >= 16 { out.push(MacAddress(frame[10..16].try_into().unwrap())); } + if frame.len() >= 22 { out.push(MacAddress(frame[16..22].try_into().unwrap())); } + //if frame.len() >= 30 { out.push(MacAddress(frame[24..30].try_into().unwrap())); } + out + } } fn main() -> Result<()> { @@ -60,16 +115,30 @@ fn main() -> Result<()> { let mut cap = cap.open()?; if cap.get_datalink() != pcap::Linktype::IEEE802_11_RADIOTAP { return Err(eyre!("device link type wrong")) } + let mut seen = HashSet::new(); + 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]); } + Some(ieee80211::FrameControl { ftype: ieee80211::FrameType::Control(ieee80211::ControlSubtype::Other), .. }) => {}, + Some(x) => { + let sequence = if data.len() >= 24 { + let sn_fst = data[22] as u16; + let sn_snd = data[23] as u16; + let seq = (sn_snd << 4) + (sn_fst >> 4); + Some((seq, sn_fst & 0b1111)) + } else { None }; + let addrs = ieee80211::read_addresses(data); + for addr in &addrs { + if !seen.contains(addr) && !addr.is_group() && !addr.is_local() { + println!("attained new MAC {} from {:?} {:?} {:?} local={} group={}", addr, x, addrs, sequence, addr.is_local(), addr.is_group()); + seen.insert(addr.clone()); + } + } + //println!("{:?} {:?}\nADDR={:?} SEQ={:?}\n", header.antenna_signal.unwrap().into_inner(), x, addrs, sequence); }, _ => {} }