Parallel execution and timeouts working. Receiver returning found

devices properly.
This commit is contained in:
Ricardo Zuasti
2026-01-15 11:19:33 -05:00
parent dda430556b
commit 5a7d504905
4 changed files with 65 additions and 57 deletions
+3 -3
View File
@@ -1,4 +1,4 @@
[env] [env]
RUST_LOG="info" RUST_LOG="debug"
OOTT_ARP_SENDER_TIMEOUT="180" OOTT_ARP_SENDER_TIMEOUT="30"
OOTT_ARP_RECEIVER_TIMEOUT="300" OOTT_ARP_SCAN_DURATION="60"
+24 -43
View File
@@ -10,7 +10,7 @@ use pnet::{
use tokio::time::{Duration, Instant, timeout}; use tokio::time::{Duration, Instant, timeout};
const DEFAULT_SENDER_TIMEOUT: u64 = 60; // 1 minute to send all packets - good for a class C network const DEFAULT_SENDER_TIMEOUT: u64 = 60; // 1 minute to send all packets - good for a class C network
const DEFAULT_RECEIVER_TIMEOUT: u64 = 300; // 5 minutes to wait per round to receive responses const DEFAULT_SCAN_DURATION: u64 = 300; // 5 minutes to wait per round to receive responses
pub async fn find(interface: &str) -> Vec<Device> { pub async fn find(interface: &str) -> Vec<Device> {
debug!("Looking up devices via ARP using interface {}", interface); debug!("Looking up devices via ARP using interface {}", interface);
@@ -57,55 +57,36 @@ pub async fn find(interface: &str) -> Vec<Device> {
let send_interface = network_interface.clone(); let send_interface = network_interface.clone();
// Spawn sender thread // Get timeouts
info!("Starting ARP sender");
let sender_start = Instant::now();
let sender_timeout = let sender_timeout =
config::parse_env("OOTT_ARP_SENDER_TIMEOUT").unwrap_or(DEFAULT_SENDER_TIMEOUT); config::parse_env("OOTT_ARP_SENDER_TIMEOUT").unwrap_or(DEFAULT_SENDER_TIMEOUT);
debug!("Sender timeout set to {} seconds", sender_timeout); info!("Sender timeout set to {} seconds", sender_timeout);
let sender_thread = timeout( let scan_duration =
config::parse_env("OOTT_ARP_SCAN_DURATION").unwrap_or(DEFAULT_SCAN_DURATION);
let receiver_timeout = scan_duration * 2;
info!("Scan duration set to {} seconds", scan_duration);
info!("Receiver timeout set to {} seconds", receiver_timeout);
if sender_timeout >= scan_duration {
panic!("OOTT_ARP_SENDER_TIMEOUT needs to be smaller than OOTT_ARP_SCAN_DURATION");
}
let result = tokio::join!(
timeout(
Duration::from_secs(sender_timeout), Duration::from_secs(sender_timeout),
send_packet(sender, send_interface, ipv4_net, mac), send_packet(sender, send_interface, ipv4_net, mac),
); ),
timeout(
// Spawn receiver thread
info!("Starting ARP receiver");
let receiver_start = Instant::now();
let receiver_timeout =
config::parse_env("OOTT_ARP_RECEIVER_TIMEOUT").unwrap_or(DEFAULT_RECEIVER_TIMEOUT);
debug!("Receiver timeout set to {} seconds", receiver_timeout);
let receiver_thread = timeout(
Duration::from_secs(receiver_timeout), Duration::from_secs(receiver_timeout),
listen_for_packets(receiver, ipv4_net), listen_for_packets(receiver, ipv4_net, scan_duration),
)
); );
// Now we wait match result {
// Joining sender thread - It should have a shorter timeout than the receiver thread (Ok(_), Ok(_)) => info!("ARP sender and receiver done"),
let sender_result = sender_thread.await; (Err(_), _) => warn!("ARP sender timed out"),
match sender_result { (_, Err(_)) => info!("ARP receiver timed out"),
Ok(_) => info!("ARP sender done"),
Err(_) => warn!("ARP sender timed out"),
}; };
info!(
"ARP sender took {} secs",
(Instant::now() - sender_start).as_secs()
);
// Joining receiver thread result.1.unwrap_or(Vec::new())
let receiver_result = receiver_thread.await;
match receiver_result {
Ok(_) => info!("ARP receiver done"),
Err(_) => warn!("ARP receiver timed out"),
};
info!(
"ARP receiver took {} secs",
(Instant::now() - receiver_start).as_secs()
);
let mut devices = Vec::new();
devices.push(Device {
mac_address: String::from("mac"),
ipv4_address: String::from("ip"),
});
devices
} }
+32 -6
View File
@@ -1,3 +1,4 @@
use crate::device_finders::Device;
use log::{debug, info, warn}; use log::{debug, info, warn};
use pnet::datalink::{DataLinkReceiver, DataLinkSender, NetworkInterface}; use pnet::datalink::{DataLinkReceiver, DataLinkSender, NetworkInterface};
use pnet::ipnetwork::Ipv4Network; use pnet::ipnetwork::Ipv4Network;
@@ -5,7 +6,7 @@ use pnet::packet::arp::{ArpHardwareTypes, ArpOperations, ArpPacket, MutableArpPa
use pnet::packet::ethernet::{EtherTypes, EthernetPacket, MutableEthernetPacket}; use pnet::packet::ethernet::{EtherTypes, EthernetPacket, MutableEthernetPacket};
use pnet::packet::{MutablePacket, Packet}; use pnet::packet::{MutablePacket, Packet};
use pnet::util::MacAddr; use pnet::util::MacAddr;
use tokio::time::{Duration, sleep, timeout}; use tokio::time::{Duration, Instant, sleep};
pub async fn send_packet( pub async fn send_packet(
mut tx: Box<dyn DataLinkSender>, mut tx: Box<dyn DataLinkSender>,
@@ -13,7 +14,9 @@ pub async fn send_packet(
sender_ip: Ipv4Network, sender_ip: Ipv4Network,
sender_macaddr: MacAddr, sender_macaddr: MacAddr,
) { ) {
info!("Starting ARP sender loop"); info!("Starting ARP sender");
let sender_start = Instant::now();
for target_ip in sender_ip.iter() { for target_ip in sender_ip.iter() {
if target_ip == sender_ip.ip() { if target_ip == sender_ip.ip() {
continue; continue;
@@ -51,11 +54,24 @@ pub async fn send_packet(
// Sleep 1 millisecond between IPs // Sleep 1 millisecond between IPs
sleep(Duration::from_millis(1)).await; sleep(Duration::from_millis(1)).await;
} }
info!(
"ARP sender took {} secs",
(Instant::now() - sender_start).as_secs()
);
} }
pub async fn listen_for_packets(mut rx: Box<dyn DataLinkReceiver>, ipv4_net: Ipv4Network) { pub async fn listen_for_packets(
info!("Starting ARP receiver loop"); mut rx: Box<dyn DataLinkReceiver>,
loop { ipv4_net: Ipv4Network,
run_for_secs: u64,
) -> Vec<Device> {
info!("Starting ARP receiver for {} secs", run_for_secs);
let start_time = Instant::now();
let mut devices = Vec::new();
// Run while still under the time window
while (Instant::now() - start_time).as_secs() <= run_for_secs {
let arp_buffer = match rx.next() { let arp_buffer = match rx.next() {
Ok(buffer) => buffer, Ok(buffer) => buffer,
Err(_) => continue, Err(_) => continue,
@@ -68,15 +84,25 @@ pub async fn listen_for_packets(mut rx: Box<dyn DataLinkReceiver>, ipv4_net: Ipv
if arp_packet.get_operation() == ArpOperations::Reply { if arp_packet.get_operation() == ArpOperations::Reply {
debug!("It is an ARP reply packet"); debug!("It is an ARP reply packet");
if arp_packet.get_target_proto_addr() == ipv4_net.ip() { if arp_packet.get_target_proto_addr() == ipv4_net.ip() {
info!( debug!(
"Found online device - IP addr={} - MAC addr={}", "Found online device - IP addr={} - MAC addr={}",
arp_packet.get_sender_proto_addr(), arp_packet.get_sender_proto_addr(),
arp_packet.get_sender_hw_addr() arp_packet.get_sender_hw_addr()
); );
devices.push(Device {
mac_address: arp_packet.get_sender_hw_addr().to_string(),
ipv4_address: arp_packet.get_sender_proto_addr().to_string(),
});
} }
} }
} }
// Sleep 1 millisecond between IPs // Sleep 1 millisecond between IPs
sleep(Duration::from_millis(1)).await; sleep(Duration::from_millis(1)).await;
} }
info!(
"ARP receiver run for {} secs",
(Instant::now() - start_time).as_secs()
);
devices
} }
+3 -2
View File
@@ -7,11 +7,12 @@ async fn main() {
env_logger::init(); env_logger::init();
info!("Starting up oott"); info!("Starting up oott");
let devices = device_finders::arp::find("eno1").await; let devices = device_finders::arp::find("wlp1s0").await;
info!("Done with ARP probes"); info!("Done with ARP probes");
info!("Found {} online devices", devices.iter().count());
for device in devices.iter() { for device in devices.iter() {
debug!("Device found {}", device); info!("Device found {}", device);
} }
info!("Exiting"); info!("Exiting");
} }