From 5a7d504905d7329a46ac54f8ea12279bfd4229b8 Mon Sep 17 00:00:00 2001 From: Ricardo Zuasti Date: Thu, 15 Jan 2026 11:19:33 -0500 Subject: [PATCH] Parallel execution and timeouts working. Receiver returning found devices properly. --- .cargo/config.toml | 6 +- src/device_finders/arp.rs | 73 +++++++------------ src/device_finders/arp/packet_send_receive.rs | 38 ++++++++-- src/main.rs | 5 +- 4 files changed, 65 insertions(+), 57 deletions(-) diff --git a/.cargo/config.toml b/.cargo/config.toml index 9c1a223..200f37f 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -1,4 +1,4 @@ [env] -RUST_LOG="info" -OOTT_ARP_SENDER_TIMEOUT="180" -OOTT_ARP_RECEIVER_TIMEOUT="300" +RUST_LOG="debug" +OOTT_ARP_SENDER_TIMEOUT="30" +OOTT_ARP_SCAN_DURATION="60" diff --git a/src/device_finders/arp.rs b/src/device_finders/arp.rs index ad2b218..d319bcd 100644 --- a/src/device_finders/arp.rs +++ b/src/device_finders/arp.rs @@ -10,7 +10,7 @@ use pnet::{ 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_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 { debug!("Looking up devices via ARP using interface {}", interface); @@ -57,55 +57,36 @@ pub async fn find(interface: &str) -> Vec { let send_interface = network_interface.clone(); - // Spawn sender thread - info!("Starting ARP sender"); - let sender_start = Instant::now(); + // Get timeouts let sender_timeout = config::parse_env("OOTT_ARP_SENDER_TIMEOUT").unwrap_or(DEFAULT_SENDER_TIMEOUT); - debug!("Sender timeout set to {} seconds", sender_timeout); - let sender_thread = timeout( - Duration::from_secs(sender_timeout), - send_packet(sender, send_interface, ipv4_net, mac), + info!("Sender timeout set to {} seconds", sender_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), + send_packet(sender, send_interface, ipv4_net, mac), + ), + timeout( + Duration::from_secs(receiver_timeout), + listen_for_packets(receiver, ipv4_net, scan_duration), + ) ); - // 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), - listen_for_packets(receiver, ipv4_net), - ); - - // Now we wait - // Joining sender thread - It should have a shorter timeout than the receiver thread - let sender_result = sender_thread.await; - match sender_result { - Ok(_) => info!("ARP sender done"), - Err(_) => warn!("ARP sender timed out"), + match result { + (Ok(_), Ok(_)) => info!("ARP sender and receiver done"), + (Err(_), _) => warn!("ARP sender timed out"), + (_, Err(_)) => info!("ARP receiver timed out"), }; - info!( - "ARP sender took {} secs", - (Instant::now() - sender_start).as_secs() - ); - // Joining receiver thread - 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 + result.1.unwrap_or(Vec::new()) } diff --git a/src/device_finders/arp/packet_send_receive.rs b/src/device_finders/arp/packet_send_receive.rs index 15b5165..3437370 100644 --- a/src/device_finders/arp/packet_send_receive.rs +++ b/src/device_finders/arp/packet_send_receive.rs @@ -1,3 +1,4 @@ +use crate::device_finders::Device; use log::{debug, info, warn}; use pnet::datalink::{DataLinkReceiver, DataLinkSender, NetworkInterface}; 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::{MutablePacket, Packet}; use pnet::util::MacAddr; -use tokio::time::{Duration, sleep, timeout}; +use tokio::time::{Duration, Instant, sleep}; pub async fn send_packet( mut tx: Box, @@ -13,7 +14,9 @@ pub async fn send_packet( sender_ip: Ipv4Network, sender_macaddr: MacAddr, ) { - info!("Starting ARP sender loop"); + info!("Starting ARP sender"); + let sender_start = Instant::now(); + for target_ip in sender_ip.iter() { if target_ip == sender_ip.ip() { continue; @@ -51,11 +54,24 @@ pub async fn send_packet( // Sleep 1 millisecond between IPs 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, ipv4_net: Ipv4Network) { - info!("Starting ARP receiver loop"); - loop { +pub async fn listen_for_packets( + mut rx: Box, + ipv4_net: Ipv4Network, + run_for_secs: u64, +) -> Vec { + 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() { Ok(buffer) => buffer, Err(_) => continue, @@ -68,15 +84,25 @@ pub async fn listen_for_packets(mut rx: Box, ipv4_net: Ipv if arp_packet.get_operation() == ArpOperations::Reply { debug!("It is an ARP reply packet"); if arp_packet.get_target_proto_addr() == ipv4_net.ip() { - info!( + debug!( "Found online device - IP addr={} - MAC addr={}", arp_packet.get_sender_proto_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(Duration::from_millis(1)).await; } + info!( + "ARP receiver run for {} secs", + (Instant::now() - start_time).as_secs() + ); + + devices } diff --git a/src/main.rs b/src/main.rs index 8d691db..9af82ba 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,11 +7,12 @@ async fn main() { env_logger::init(); 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!("Found {} online devices", devices.iter().count()); for device in devices.iter() { - debug!("Device found {}", device); + info!("Device found {}", device); } info!("Exiting"); }