-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement network interfacing and scanning utilities
- Loading branch information
1 parent
7b3d149
commit 4f5bac0
Showing
14 changed files
with
459 additions
and
68 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -16,3 +16,6 @@ features = ["full"] | |
|
||
[dependencies.pnet] | ||
version = "0.35.0" | ||
|
||
[dependencies.proton_nif] | ||
path = "../proton_nif" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
//! Network scanning utility for the ARP manager. | ||
|
||
mod reply; | ||
mod request; | ||
|
||
use std::{ | ||
net::Ipv4Addr, | ||
time::Duration, | ||
}; | ||
|
||
use tokio::{ | ||
sync::mpsc, | ||
task, | ||
}; | ||
|
||
use proton_nif::{ | ||
ifnames::DEFAULT_WIRELESS_INTERFACE, | ||
NetworkInterface, | ||
}; | ||
|
||
use crate::{ | ||
ArpCacheEntry, | ||
ArpError, | ||
ScanResult, | ||
}; | ||
|
||
use reply::listen; | ||
use request::request; | ||
|
||
/// Buffer size for the asynchronous communication channel for ARP replies. | ||
pub const ARP_CHANNEL_BUFFER_SIZE: usize = 256; | ||
|
||
/// Default delay to wait before closing the ARP reply listener. | ||
pub static ARP_LISTENER_DELAY: Duration = Duration::from_millis(2_500); | ||
|
||
/// Scan the provided list of IPv4 addresses and return all ARP replies. | ||
/// | ||
/// # Parameters | ||
/// - `ips` (`Vec<Ipv4Addr>`): the IPv4 addresses to scan | ||
/// | ||
/// # Returns | ||
/// A `ScanResult` containing the ARP responses | ||
/// received, if the scan was successful. | ||
pub async fn scan(ips: Vec<Ipv4Addr>) -> ScanResult { | ||
// Get the wireless network interface | ||
let interface = NetworkInterface::new(DEFAULT_WIRELESS_INTERFACE) | ||
.ok_or(ArpError::CouldNotFindWirelessInterface)?; | ||
|
||
// Create an asynchronous communication channel for received replies | ||
let (reply_tx, reply_rx) = mpsc::channel::<ArpCacheEntry>(ARP_CHANNEL_BUFFER_SIZE); | ||
|
||
// Begin listening for ARP replies | ||
let rx_task = task::spawn(listen(interface.clone(), reply_tx)); | ||
|
||
// Begin making ARP requests | ||
let tx_task = task::spawn(request(interface, ips, reply_rx)); | ||
|
||
// Await the transmitter | ||
// After completing it will pass back the async channel receiver | ||
let mut reply_rx = tx_task.await?; | ||
|
||
// Await the listener | ||
let _ = rx_task.await?; | ||
|
||
// Construct a list of entries | ||
let mut entries = Vec::new(); | ||
|
||
// Extract each entry | ||
while let Some (entry) = reply_rx.recv().await { | ||
entries.push(entry) | ||
} | ||
|
||
Ok (entries) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
//! ARP Reply functionality. | ||
|
||
use pnet::{ | ||
packet::{ | ||
arp::ArpPacket, | ||
ethernet::{ | ||
EtherTypes, | ||
EthernetPacket, | ||
}, | ||
Packet, | ||
}, | ||
}; | ||
|
||
use tokio::sync::mpsc; | ||
|
||
use proton_nif::NetworkInterface; | ||
|
||
use crate::ArpCacheEntry; | ||
|
||
/// Receive a series of ARP replies. | ||
/// | ||
/// # Parameters | ||
/// - `interface` (`NetworkInterface`): the network interface to use | ||
/// - `tx` (`Sender<ArpCacheEntry>`): the cache entry transmitter | ||
/// | ||
/// # Returns | ||
/// None. | ||
pub async fn listen( | ||
mut interface: NetworkInterface, | ||
tx: mpsc::Sender<ArpCacheEntry>, | ||
) { | ||
// Get interface MAC address | ||
let mac = interface.mac.unwrap(); | ||
|
||
while let Some (packet) = interface.recv().await { | ||
// Check if the MPSC channel has closed | ||
// There's no point in continuing if it is because | ||
// all future packets will be dropped anyways | ||
if tx.is_closed() { | ||
break; | ||
} | ||
|
||
// Convert to ETH Frame | ||
let eth_frame = if let Some (f) = EthernetPacket::new(&packet) { | ||
f | ||
} else { | ||
continue; | ||
}; | ||
|
||
// Check ETH Frame Type | ||
let frame_type = eth_frame.get_ethertype(); | ||
if frame_type != EtherTypes::Arp { | ||
continue; | ||
} | ||
|
||
// Convert to ARP Packet | ||
let arp_packet = if let Some (a) = ArpPacket::new(eth_frame.payload()) { | ||
a | ||
} else { | ||
continue; | ||
}; | ||
|
||
// Drop the frame if it was sent from our own computer | ||
if arp_packet.get_sender_hw_addr() == mac { | ||
continue; | ||
} | ||
|
||
// Construct cache entry | ||
let entry = ArpCacheEntry::new( | ||
arp_packet.get_sender_proto_addr(), | ||
arp_packet.get_sender_hw_addr(), | ||
); | ||
|
||
// Send the reply | ||
let send = tx.send(entry); | ||
|
||
// When the receiver side of the channel is closed, | ||
// this will return, because `tx::send` will return an error | ||
if send.await.is_err() { | ||
break; | ||
} | ||
|
||
// If there are no packets left, the function returns | ||
} | ||
} |
Oops, something went wrong.