Skip to content

Commit

Permalink
Continue work on MAC address based deauth
Browse files Browse the repository at this point in the history
  • Loading branch information
josephrhobbs committed Jul 26, 2024
1 parent 6628b89 commit caba9fd
Show file tree
Hide file tree
Showing 9 changed files with 185 additions and 21 deletions.
3 changes: 3 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

37 changes: 37 additions & 0 deletions examples/deauth.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
//! Example code to deauthenticate a wireless device.

use std::net::Ipv4Addr;

use proton::{
ap::AccessPoint,
cidr::Ipv4Cidr,
device::Device,
error::ProtonResult,
};

#[tokio::main]
async fn main() -> ProtonResult<()> {
let ifname = "wlp4s0";

let mut ap = AccessPoint::new(
Ipv4Cidr::new( // Internal network range
Ipv4Addr::new(192, 168, 0, 0), // Network address
24, // Network length
).unwrap(),
ifname, // Network interface name
)?;

println!("Scanning network interface: {}...", ifname);

let devices: Vec<Device> = ap.scan().await?;

println!("Found: {:#?}", devices);

let deauth_mac = devices[0].mac;

println!("Deauthenticating {}", deauth_mac);

ap.deauth(deauth_mac)?;

Ok (())
}
5 changes: 2 additions & 3 deletions examples/list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,9 @@

use std::net::Ipv4Addr;

use cidr::Ipv4Cidr;

use proton::{
ap::AccessPoint,
cidr::Ipv4Cidr,
device::Device,
error::ProtonResult,
};
Expand All @@ -19,7 +18,7 @@ async fn main() -> ProtonResult<()> {
Ipv4Addr::new(192, 168, 0, 0), // Network address
24, // Network length
).unwrap(),
ifname,
ifname, // Network interface name
)?;

println!("Scanning network interface: {}...", ifname);
Expand Down
15 changes: 15 additions & 0 deletions proton_dev/src/manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ use proton_err::{
ProtonResult,
};

use proton_mac::MacAddr;

use crate::{
Device,
NetworkSocket,
Expand Down Expand Up @@ -86,4 +88,17 @@ impl DeviceManager {

Ok (devices)
}

/// Deauthenticate a device by its MAC address.
///
/// # Parameters
/// - `mac` (`MacAddr`): the MAC address of the device to be
/// deauthenticated
///
/// # Returns
/// A `ProtonResult<()>` indicating whether or not the device was
/// successfully deauthenticated.
pub fn deauthenticate(&mut self, mac: MacAddr) -> ProtonResult<()> {
self.socket.deauthenticate_by_mac(mac)
}
}
90 changes: 84 additions & 6 deletions proton_dev/src/socket.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ use proton_err::{
ProtonResult,
};

use proton_mac::MacAddr;

/// A wireless AP with a number of connected stations.
pub trait NetworkSocket {
/// Get all stations connected to this AP.
Expand All @@ -32,17 +34,17 @@ pub trait NetworkSocket {
/// - `nlif_index` (`&[u8]`): a Netlink network interface index
///
/// # Returns
/// `NetlinkResult<Vec<Station>>` containing a list of network stations.
/// `ProtonResult<Vec<Station>>` containing a list of network stations.
fn get_all_stations(&mut self, nlif_index: &[u8]) -> ProtonResult<Vec<Station>>;

/// Deauthenticate a device from this AP by MAC address.
///
/// # Parameters
/// TODO
/// - `mac` (`MacAddr`): the MAC address to deauthenticate
///
/// # Returns
/// TODO
fn deauthenticate_by_mac(&mut self) -> ();
/// `ProtonResult<()>` indicating the status of the disconnection.
fn deauthenticate_by_mac(&mut self, mac: MacAddr) -> ProtonResult<()>;
}

impl NetworkSocket for Socket {
Expand Down Expand Up @@ -113,7 +115,83 @@ impl NetworkSocket for Socket {

fn deauthenticate_by_mac(
&mut self,
) -> () {
todo!()
mac: MacAddr,
) -> ProtonResult<()> {
// Get the Netlink socket
let nl80211sock = &mut self.sock;

// Convert the MAC address into a vector of octets
let mac_vec: Vec<u8> = vec![
mac.0,
mac.1,
mac.2,
mac.3,
mac.4,
mac.5,
];

// Set Generic Netlink attributes
let mut attrs: Vec<Nlattr<Nl80211Attr, Vec<u8>>> = vec![];

// Set MAC attribute (MAC address)
let mac_attr = Nlattr::new(
None,
Nl80211Attr::AttrMac,
mac_vec,
)?;
attrs.push(mac_attr);

// Set Reason Code attribute (reason for deauthentication)
let rc_attr = Nlattr::new(
None,
Nl80211Attr::AttrReasonCode,
vec![1, 0], // unspecified reason
)?;
attrs.push(rc_attr);

// Construct the Generic Netlink header
let genlhdr = Genlmsghdr::new(
Nl80211Cmd::CmdDeauthenticate,
NL_80211_GENL_VERSION,
attrs,
)?;

// Set the Netlink header length
let len = None;

// Set the Generic Netlink Family ID
let nl_type = self.family_id;

// Set the Netlink flags
let flags = vec![NlmF::Request, NlmF::Dump];

// Set the sequence number
let seq = None;

// Set the Netlink port ID
let pid = None;

// Set the Netlink header payload (contains Generic Netlink header)
let payload = genlhdr;

// Construct the Netlink header
let nlhdr = Nlmsghdr::new(len, nl_type, flags, seq, pid, payload);

// Send header to the Netlink socket
nl80211sock.send_nl(nlhdr)?;

// Read results back from the Netlink socket
let mut iter = nl80211sock.iter::<Nlmsg, Genlmsghdr<Nl80211Cmd, Nl80211Attr>>();

if let Some (Ok (response)) = iter.next() {
dbg!(&response.nl_payload);

match response.nl_type {
Nlmsg::Done => Ok (()),
_ => Err (ProtonError::CouldNotDeauthenticateDevice (mac)),
}
} else {
Err (ProtonError::NoResponseFromNetlink)
}
}
}
3 changes: 2 additions & 1 deletion proton_err/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@ edition = "2021"
name = "proton_err"
path = "src/lib.rs"

[dependencies]
[dependencies.proton_mac]
path = "../proton_mac"
12 changes: 11 additions & 1 deletion proton_err/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ use std::{
},
};

use proton_mac::MacAddr;

#[derive(Debug)]
/// An error that occurred within the Proton library.
pub enum ProtonError {
Expand All @@ -19,9 +21,15 @@ pub enum ProtonError {
/// The program could not find any wireless network interfaces.
CouldNotFindWirelessInterface,

/// Could not get device information
/// Could not get device information.
CouldNotGetDeviceInformation,

/// Netlink gave no response.
NoResponseFromNetlink,

/// Could not deauthenticate device by MAC address.
CouldNotDeauthenticateDevice (MacAddr),

/// An error that could not be converted to a native error.
Other (String),
}
Expand All @@ -33,6 +41,8 @@ impl Display for ProtonError {
MustBeEthernetInterface => "must be Ethernet interface",
CouldNotFindWirelessInterface => "could not find wireless interface",
CouldNotGetDeviceInformation => "could not get wireless device information",
NoResponseFromNetlink => "no response from Netlink",
CouldNotDeauthenticateDevice (mac) => &format!("could not deauthenticate device with MAC address {}", mac),
Other (t) => t.as_str(),
};

Expand Down
27 changes: 17 additions & 10 deletions proton_mac/src/mac.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,19 @@ use serde::Serialize;

#[derive(Serialize, PartialEq, Eq, Clone, Copy)]
/// A hardware (MAC) address consisting of six octets.
pub struct MacAddr ([u8; 6]);
pub struct MacAddr (pub u8, pub u8, pub u8, pub u8, pub u8, pub u8);

impl Display for MacAddr {
fn fmt(&self, f: &mut Formatter<'_>) -> 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],
self.0,
self.1,
self.2,
self.3,
self.4,
self.5,
)
}
}
Expand All @@ -36,19 +36,26 @@ impl Debug for MacAddr {

impl From<[u8; 6]> for MacAddr {
fn from(octets: [u8; 6]) -> Self {
Self (octets)
Self (
octets[0],
octets[1],
octets[2],
octets[3],
octets[4],
octets[5],
)
}
}

impl From<pnet::datalink::MacAddr> for MacAddr {
fn from(mac: pnet::datalink::MacAddr) -> Self {
Self ([
Self (
mac.0,
mac.1,
mac.2,
mac.3,
mac.4,
mac.5,
])
)
}
}
14 changes: 14 additions & 0 deletions proton_wap/src/ap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ use proton_dev::{

use proton_err::ProtonResult;

use proton_mac::MacAddr;

/// A wireless access point.
pub struct AccessPoint {
#[allow(dead_code)]
Expand Down Expand Up @@ -53,6 +55,18 @@ impl AccessPoint {
Ok (self.manager.scan().await?)
}

/// Deauthenticate a device by its MAC address.
///
/// # Parameters
/// - `mac` (`MacAddr`): the MAC address of the device to be
/// deauthenticated
///
/// # Returns
/// A `ProtonResult<()>` indicating the status of the response.
pub fn deauth(&mut self, mac: MacAddr) -> ProtonResult<()> {
self.manager.deauthenticate(mac)
}

/// Continuously route packets, monitoring both the Data Link Layer and
/// the Transport Layer to ensure both proper NAT and MAC policy enforcement.
///
Expand Down

0 comments on commit caba9fd

Please sign in to comment.