Skip to content

Commit

Permalink
add: All the changes from AngryOxide
Browse files Browse the repository at this point in the history
  • Loading branch information
Nukesor committed Jan 11, 2025
1 parent a70168e commit b85be02
Show file tree
Hide file tree
Showing 33 changed files with 3,255 additions and 138 deletions.
22 changes: 22 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,28 @@ All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [0.4.0] - unreleased

This release encompasses a huge amount of backports from @Ragnt, which vendored `libwifi` in [AngryOxide](https://github.com/Ragnt/AngryOxide) and continued development over there.

@Ragnt added a vast amount of additional features and parsers for data structures.
They allowed the backport of their changes and republished their vendored library under a permissable license [over here](https://github.com/Ragnt/libwifi).

The most prominent features being:

- Frame encoding. Parsed or constructed frames can now be brought back into byte representation.
- CRC Frame validation.
- More `MacAddress` helper functions and parsed formats.
- `MacAddressGlob` to match certain MacAddress spaces.
- Many more parsed `StationInfo` fields.
- Various parsers for new control and data frames, including
- `CTS` and `Ack` frames for the `RTS -> CTS -> Data -> ACK` flow.
- Complete `Data` frame parsing.
- `DataCfAck` `DataCfPoll`, `DataCfAckCfPoll`, `CfPoll` `CfAckCfPoll`
- `QosDataCfAck`, `QosDataCfPoll`, `QosDataCfAckCfPoll`, `QosCfPoll`, `QosCfAckCfPoll`
- Deauthentication reason parsing
- `ReassociationRequest`, `ReassociationResponse`

## [0.3.1] - unreleased

### Changes
Expand Down
6 changes: 3 additions & 3 deletions examples/capture_example/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
[package]
name = "capture_example"
version = "0.1.0"
authors = ["Arne Beer <[email protected]>"]
edition = "2021"
name = "capture_example"
version = "0.1.0"

[dependencies]
anyhow = "1"
better-panic = "0.3"
clap = { version = "4", features = ["derive", "cargo"] }
clap = { version = "4", features = ["cargo", "derive"] }
libwifi = { path = "../../libwifi" }
pcap = { version = "2", features = ['capture-stream'] }
radiotap = "1.3"
22 changes: 12 additions & 10 deletions libwifi/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,31 +1,33 @@
[package]
name = "libwifi"
description = "A library for parsing IEEE 802.11 frames and handling wifi interfaces."
version = "0.3.1"
keywords = ["wifi", "802_11", "parser", "frame"]
readme = "README.md"
description = "A library for parsing IEEE 802.11 frames and handling wifi interfaces."
keywords = ["802_11", "frame", "parser", "wifi"]
authors.workspace = true
edition.workspace = true
homepage.workspace = true
repository.workspace = true
license.workspace = true
edition.workspace = true
repository.workspace = true
rust-version.workspace = true

[[bench]]
name = "parse_beacon"
harness = false
name = "parse_beacon"

[[bench]]
name = "parse_data"
harness = false
name = "parse_data"

[dependencies]
byteorder = "1.5.0"
crc = "3.0.1"
enum_dispatch = "0.3"
libwifi_macros = { version = "0.0.2", path = "../libwifi_macros" }
log = "0.4"
nom = "7"
thiserror = "2.0"
rand = "0.8"
strum_macros = "0.26"
enum_dispatch = "0.3"
libwifi_macros = { version = "0.0.2", path = "../libwifi_macros" }
thiserror = "2.0"

[dev-dependencies]
criterion = "0.5"
Expand Down
4 changes: 2 additions & 2 deletions libwifi/benches/parse_beacon.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ const BEACON_PAYLOAD: [u8; 272] = [
pub fn parse_beacon(crit: &mut Criterion) {
let mut rng = thread_rng();
let random: u8 = rng.gen();
let mut payload = BEACON_PAYLOAD.clone();
let mut payload = BEACON_PAYLOAD;

// Log raw byte throughput
let mut group = crit.benchmark_group("parsers");
Expand All @@ -49,7 +49,7 @@ pub fn parse_beacon(crit: &mut Criterion) {
group.bench_function("Parse beacon", |bencher| {
bencher.iter(|| {
payload[270] = random;
assert!(parse_frame(&BEACON_PAYLOAD).is_ok())
assert!(parse_frame(&BEACON_PAYLOAD, false).is_ok())
})
});
group.finish()
Expand Down
4 changes: 2 additions & 2 deletions libwifi/benches/parse_data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ pub fn parse_data(crit: &mut Criterion) {
// Add some random variable to prevent aggressive compiler optimizations;
let mut rng = thread_rng();
let random: u8 = rng.gen();
let mut payload = DATA_PAYLOAD.clone();
let mut payload = DATA_PAYLOAD;

// Log raw byte throughput
let mut group = crit.benchmark_group("parsers");
Expand All @@ -30,7 +30,7 @@ pub fn parse_data(crit: &mut Criterion) {
group.bench_function("Parse data", |bencher| {
bencher.iter(|| {
payload[111] = random;
assert!(parse_frame(&payload).is_ok());
assert!(parse_frame(&payload, false).is_ok());
})
});
group.finish()
Expand Down
13 changes: 12 additions & 1 deletion libwifi/src/frame/components/frame_control.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ pub struct FrameControl {
pub frame_subtype: FrameSubType,
pub flags: u8,
}

//
impl FrameControl {
pub fn to_ds(&self) -> bool {
flag_is_set(self.flags, 0)
Expand Down Expand Up @@ -72,6 +72,17 @@ impl FrameControl {
pub fn order(&self) -> bool {
flag_is_set(self.flags, 7)
}

pub fn encode(&self) -> [u8; 2] {
let protocol_version_bits = self.protocol_version & 0b11; // 2 bits
let frame_type_bits = (self.frame_type as u8 & 0b11) << 2; // 2 bits
let frame_subtype_bits = (self.frame_subtype.to_bytes() & 0b1111) << 4; // 4 bits

let first_byte = frame_subtype_bits | frame_type_bits | protocol_version_bits;
let second_byte = self.flags; // Assuming flags fit into one byte

[first_byte, second_byte]
}
}

#[cfg(test)]
Expand Down
56 changes: 55 additions & 1 deletion libwifi/src/frame/components/header.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,28 @@ pub struct ManagementHeader {
pub sequence_control: SequenceControl,
}

impl ManagementHeader {
pub fn encode(&self) -> Vec<u8> {
let mut bytes = Vec::new();

// Serialize frame control
bytes.extend_from_slice(&self.frame_control.encode());

// Serialize duration (2 bytes, big-endian)
bytes.extend_from_slice(&self.duration);

// Serialize MAC addresses
bytes.extend_from_slice(&self.address_1.encode());
bytes.extend_from_slice(&self.address_2.encode());
bytes.extend_from_slice(&self.address_3.encode());

// Serialize sequence control
bytes.extend_from_slice(&self.sequence_control.encode());

bytes
}
}

/// Which address is used in which way, depends on a combination of
/// - two flags in the FrameControl header.
/// - the Type/Subtype constellation.
Expand Down Expand Up @@ -104,7 +126,7 @@ impl Addresses for ManagementHeader {
/// Representation of a data frame header. This format is used by all data frames!
///
/// It's very similar to the format of the management header, but there are some slight
/// differences, since they allow a forth address and Quality of Service (QoS) data.
/// differences, since they allow a fourth address and Quality of Service (QoS) data.
///
/// Structure:
///
Expand Down Expand Up @@ -137,6 +159,38 @@ pub struct DataHeader {
pub qos: Option<[u8; 2]>,
}

impl DataHeader {
pub fn encode(&self) -> Vec<u8> {
let mut bytes = Vec::new();

// Serialize frame control
bytes.extend_from_slice(&self.frame_control.encode());

// Serialize duration (2 bytes)
bytes.extend_from_slice(&self.duration);

// Serialize MAC addresses
bytes.extend_from_slice(&self.address_1.encode());
bytes.extend_from_slice(&self.address_2.encode());
bytes.extend_from_slice(&self.address_3.encode());

// Serialize sequence control
bytes.extend_from_slice(&self.sequence_control.encode());

// Serialize address 4 if present
if let Some(addr) = &self.address_4 {
bytes.extend_from_slice(&addr.encode());
}

// Serialize QoS if present
if let Some(qos) = &self.qos {
bytes.extend_from_slice(qos);
}

bytes
}
}

impl Addresses for DataHeader {
/// Return the mac address of the sender
fn src(&self) -> Option<&MacAddress> {
Expand Down
Loading

0 comments on commit b85be02

Please sign in to comment.