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
This commit is contained in:
osmarks 2021-04-18 21:09:12 +01:00
parent b027bde26f
commit 3d946ce89f

View File

@ -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<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()?),
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<MacAddress> {
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);
},
_ => {}
}