use super::*;
use pnet::{
packet::{arp, ethernet, ipv4, tcp},
util::{self, MacAddr},
};
use std::sync::mpsc::channel;
use std::sync::{Arc, Mutex};
use std::time::Duration;
use std::{net::Ipv4Addr, str::FromStr};
use crate::{
network,
packet::{arp_packet::create_arp_reply, syn_packet::create_syn_reply},
wire::{
PacketMetadata, Reader, Sender,
mocks::{MockPacketReader, MockPacketSender},
},
};
const PKT_ETH_SIZE: usize = ethernet::EthernetPacket::minimum_packet_size();
const PKT_ARP_SIZE: usize = arp::ArpPacket::minimum_packet_size();
const PKT_TOTAL_ARP_SIZE: usize = PKT_ETH_SIZE + PKT_ARP_SIZE;
const PKT_IP4_SIZE: usize = ipv4::Ipv4Packet::minimum_packet_size();
const PKT_TCP_SIZE: usize = tcp::TcpPacket::minimum_packet_size();
const PKT_TOTAL_SYN_SIZE: usize = PKT_ETH_SIZE + PKT_IP4_SIZE + PKT_TCP_SIZE;
#[test]
fn new() {
let interface = Arc::new(network::get_default_interface().unwrap());
let sender: Arc<Mutex<dyn Sender>> =
Arc::new(Mutex::new(MockPacketSender::new()));
let receiver: Arc<Mutex<dyn Reader>> =
Arc::new(Mutex::new(MockPacketReader::new()));
let wire = Wire(sender, receiver);
let idle_timeout = Duration::from_secs(2);
let targets = IPTargets::new(vec!["192.168.1.0/24".to_string()]).unwrap();
let (tx, _) = channel();
let scanner = ARPScanner::builder()
.interface(interface)
.wire(wire)
.targets(targets)
.source_port(54321_u16)
.include_vendor(true)
.include_host_names(true)
.idle_timeout(idle_timeout)
.notifier(tx)
.build()
.unwrap();
assert!(scanner.include_host_names);
assert!(scanner.include_vendor);
assert_eq!(scanner.idle_timeout, idle_timeout);
assert_eq!(scanner.source_port, 54321);
}
#[test]
#[allow(static_mut_refs)]
fn sends_and_reads_packets() {
static mut PACKET: [u8; PKT_TOTAL_ARP_SIZE] = [0u8; PKT_TOTAL_ARP_SIZE];
let interface = Arc::new(network::get_default_interface().unwrap());
let device_ip = Ipv4Addr::from_str("192.168.1.2").unwrap();
let device_mac = util::MacAddr::default();
create_arp_reply(
device_mac,
device_ip,
interface.mac,
interface.ipv4,
#[allow(static_mut_refs)]
unsafe {
&mut PACKET
},
);
let mut receiver = MockPacketReader::new();
let mut sender = MockPacketSender::new();
#[allow(static_mut_refs)]
receiver.expect_next_packet_with_metadata().returning(|| {
Ok((unsafe { &PACKET }, PacketMetadata { timestamp: None }))
});
sender.expect_send().returning(|_| Ok(()));
let idle_timeout = Duration::from_secs(2);
let targets = IPTargets::new(vec![device_ip.to_string()]).unwrap();
let (tx, rx) = channel();
let sender: Arc<Mutex<dyn Sender>> = Arc::new(Mutex::new(sender));
let receiver: Arc<Mutex<dyn Reader>> = Arc::new(Mutex::new(receiver));
let wire = Wire(sender, receiver);
let scanner = ARPScanner::builder()
.interface(interface)
.wire(wire)
.targets(targets)
.source_port(54321_u16)
.include_vendor(true)
.include_host_names(true)
.idle_timeout(idle_timeout)
.notifier(tx)
.build()
.unwrap();
let handle = scanner.scan().unwrap();
let mut detected_device = Device {
hostname: "".to_string(),
ip: Ipv4Addr::new(10, 10, 10, 10),
is_current_host: false,
is_gateway: false,
mac: MacAddr::default(),
vendor: "".to_string(),
open_ports: PortSet::new(),
latency_ms: None,
response_ttl: None,
};
loop {
if let Ok(msg) = rx.recv() {
match msg {
ScanMessage::Done => {
break;
}
ScanMessage::ARPScanDevice(device) => {
detected_device = device;
}
_ => {}
}
}
}
let result = handle.join().unwrap();
assert!(result.is_ok());
assert_eq!(detected_device.mac.to_string(), device_mac.to_string());
assert_eq!(detected_device.ip.to_string(), device_ip.to_string());
}
#[test]
#[allow(static_mut_refs)]
fn marks_gateway_device() {
static mut PACKET: [u8; PKT_TOTAL_ARP_SIZE] = [0u8; PKT_TOTAL_ARP_SIZE];
let interface = Arc::new(network::get_default_interface().unwrap());
let device_ip = Ipv4Addr::from_str("192.168.1.2").unwrap();
let device_mac = util::MacAddr::default();
create_arp_reply(
device_mac,
device_ip,
interface.mac,
interface.ipv4,
#[allow(static_mut_refs)]
unsafe {
&mut PACKET
},
);
let mut receiver = MockPacketReader::new();
let mut sender = MockPacketSender::new();
#[allow(static_mut_refs)]
receiver.expect_next_packet_with_metadata().returning(|| {
Ok((unsafe { &PACKET }, PacketMetadata { timestamp: None }))
});
sender.expect_send().returning(|_| Ok(()));
let idle_timeout = Duration::from_secs(2);
let targets = IPTargets::new(vec![device_ip.to_string()]).unwrap();
let (tx, rx) = channel();
let sender: Arc<Mutex<dyn Sender>> = Arc::new(Mutex::new(sender));
let receiver: Arc<Mutex<dyn Reader>> = Arc::new(Mutex::new(receiver));
let wire = Wire(sender, receiver);
let scanner = ARPScanner::builder()
.interface(interface)
.wire(wire)
.targets(targets)
.source_port(54321_u16)
.include_vendor(false)
.include_host_names(false)
.idle_timeout(idle_timeout)
.gateway(Some(device_ip))
.notifier(tx)
.build()
.unwrap();
let handle = scanner.scan().unwrap();
let mut detected_device = Device::default();
loop {
if let Ok(msg) = rx.recv() {
match msg {
ScanMessage::Done => {
break;
}
ScanMessage::ARPScanDevice(device) => {
detected_device = device;
}
_ => {}
}
}
}
let result = handle.join().unwrap();
assert!(result.is_ok());
assert_eq!(detected_device.ip, device_ip);
assert!(detected_device.is_gateway);
}
#[test]
#[allow(warnings)]
fn ignores_unrelated_packets() {
static mut PACKET: [u8; PKT_TOTAL_SYN_SIZE] = [0u8; PKT_TOTAL_SYN_SIZE];
let interface = Arc::new(network::get_default_interface().unwrap());
let mut receiver = MockPacketReader::new();
let mut sender = MockPacketSender::new();
for i in 0..5 {
let mac = util::MacAddr::default();
let ip = Ipv4Addr::from_str(format!("192.168.0.{}", 1 + i).as_str())
.unwrap();
create_syn_reply(
mac,
ip,
8080,
interface.mac,
interface.ipv4,
54321,
#[allow(static_mut_refs)]
unsafe {
&mut PACKET
},
);
#[allow(static_mut_refs)]
receiver.expect_next_packet_with_metadata().returning(|| {
Ok((unsafe { &PACKET }, PacketMetadata { timestamp: None }))
});
}
sender.expect_send().returning(|_| Ok(()));
let idle_timeout = Duration::from_secs(2);
let targets = IPTargets::new(vec!["192.168.1.2".to_string()]).unwrap();
let (tx, rx) = channel();
let sender: Arc<Mutex<dyn Sender>> = Arc::new(Mutex::new(sender));
let receiver: Arc<Mutex<dyn Reader>> = Arc::new(Mutex::new(receiver));
let wire = Wire(sender, receiver);
let scanner = ARPScanner::builder()
.interface(interface)
.wire(wire)
.targets(targets)
.source_port(54321_u16)
.include_vendor(true)
.include_host_names(true)
.idle_timeout(idle_timeout)
.notifier(tx)
.build()
.unwrap();
let (done_tx, done_rx) = channel();
scanner.read_packets(done_rx);
let mut detected_devices: Vec<Device> = Vec::new();
let mut count = 0;
loop {
if count >= 8 {
done_tx.send(()).unwrap();
break;
}
if let Ok(msg) = rx.try_recv() {
match msg {
ScanMessage::Done => {
break;
}
ScanMessage::ARPScanDevice(device) => {
detected_devices.push(device);
}
_ => {}
}
} else {
count += 1;
thread::sleep(Duration::from_secs(1));
}
}
assert_eq!(detected_devices.len(), 0);
}
#[test]
fn reports_error_on_packet_reader_lock() {
let interface = Arc::new(network::get_default_interface().unwrap());
let receiver = MockPacketReader::new();
let mut sender = MockPacketSender::new();
sender.expect_send().returning(|_| Ok(()));
let idle_timeout = Duration::from_secs(2);
let targets = IPTargets::new(vec!["192.168.1.2".to_string()]).unwrap();
let (tx, _rx) = channel();
let arc_sender: Arc<Mutex<dyn Sender>> = Arc::new(Mutex::new(sender));
let arc_receiver: Arc<Mutex<dyn Reader>> = Arc::new(Mutex::new(receiver));
let receiver_clone = Arc::clone(&arc_receiver);
let handle = thread::spawn(move || {
let _guard = receiver_clone.lock().unwrap(); panic!("Simulated panic"); });
let _ = handle.join();
let wire = Wire(arc_sender, arc_receiver);
let scanner = ARPScanner::builder()
.interface(interface)
.wire(wire)
.targets(targets)
.source_port(54321_u16)
.include_vendor(true)
.include_host_names(true)
.idle_timeout(idle_timeout)
.notifier(tx)
.build()
.unwrap();
let (_done_tx, done_rx) = channel();
let handle = scanner.read_packets(done_rx).unwrap();
let result = handle.join().unwrap();
assert!(result.is_err());
}
#[test]
fn reports_error_on_packet_read_error() {
let interface = Arc::new(network::get_default_interface().unwrap());
let mut receiver = MockPacketReader::new();
let mut sender = MockPacketSender::new();
receiver
.expect_next_packet_with_metadata()
.returning(|| Err(RLanLibError::Wire("oh no an error".into())));
sender.expect_send().returning(|_| Ok(()));
let sender: Arc<Mutex<dyn Sender>> = Arc::new(Mutex::new(sender));
let receiver: Arc<Mutex<dyn Reader>> = Arc::new(Mutex::new(receiver));
let wire = Wire(sender, receiver);
let idle_timeout = Duration::from_secs(2);
let targets = IPTargets::new(vec!["192.168.1.2".to_string()]).unwrap();
let (tx, _rx) = channel();
let scanner = ARPScanner::builder()
.interface(interface)
.wire(wire)
.targets(targets)
.source_port(54321_u16)
.include_vendor(true)
.include_host_names(true)
.idle_timeout(idle_timeout)
.notifier(tx)
.build()
.unwrap();
let (_done_tx, done_rx) = channel();
let handle = scanner.read_packets(done_rx).unwrap();
let result = handle.join().unwrap();
assert!(result.is_err());
}
#[test]
fn reports_error_on_notifier_send_errors() {
let interface = Arc::new(network::get_default_interface().unwrap());
let mut receiver = MockPacketReader::new();
let mut sender = MockPacketSender::new();
receiver
.expect_next_packet_with_metadata()
.returning(|| Ok((&[1], PacketMetadata { timestamp: None })));
sender.expect_send().returning(|_| Ok(()));
let sender: Arc<Mutex<dyn Sender>> = Arc::new(Mutex::new(sender));
let receiver: Arc<Mutex<dyn Reader>> = Arc::new(Mutex::new(receiver));
let wire = Wire(sender, receiver);
let idle_timeout = Duration::from_secs(2);
let targets = IPTargets::new(vec!["192.168.1.2".to_string()]).unwrap();
let (tx, rx) = channel();
drop(rx);
let scanner = ARPScanner::builder()
.interface(interface)
.wire(wire)
.targets(targets)
.source_port(54321_u16)
.include_vendor(true)
.include_host_names(true)
.idle_timeout(idle_timeout)
.notifier(tx)
.build()
.unwrap();
let handle = scanner.scan().unwrap();
let result = handle.join().unwrap();
assert!(result.is_err());
}
#[test]
fn reports_error_on_packet_sender_lock_errors() {
let interface = Arc::new(network::get_default_interface().unwrap());
let mut receiver = MockPacketReader::new();
let sender = MockPacketSender::new();
receiver
.expect_next_packet_with_metadata()
.returning(|| Ok((&[1], PacketMetadata { timestamp: None })));
let sender: Arc<Mutex<dyn Sender>> = Arc::new(Mutex::new(sender));
let receiver: Arc<Mutex<dyn Reader>> = Arc::new(Mutex::new(receiver));
let sender_clone = Arc::clone(&sender);
let wire = Wire(sender, receiver);
let idle_timeout = Duration::from_secs(2);
let targets = IPTargets::new(vec!["192.168.1.2".to_string()]).unwrap();
let (tx, rx) = channel();
let handle = thread::spawn(move || {
let _guard = sender_clone.lock().unwrap(); panic!("Simulated panic"); });
let _ = handle.join();
let scanner = ARPScanner::builder()
.interface(interface)
.wire(wire)
.targets(targets)
.source_port(54321_u16)
.include_vendor(true)
.include_host_names(true)
.idle_timeout(idle_timeout)
.notifier(tx)
.build()
.unwrap();
let handle = scanner.scan().unwrap();
loop {
if let Ok(ScanMessage::Done) = rx.recv() {
break;
}
}
let result = handle.join().unwrap();
assert!(result.is_err());
}
#[test]
fn reports_error_on_packet_send_errors() {
let interface = Arc::new(network::get_default_interface().unwrap());
let mut receiver = MockPacketReader::new();
let mut sender = MockPacketSender::new();
receiver
.expect_next_packet_with_metadata()
.returning(|| Ok((&[1], PacketMetadata { timestamp: None })));
sender
.expect_send()
.returning(|_| Err(RLanLibError::Wire("oh no a send error".into())));
let receiver: Arc<Mutex<dyn Reader>> = Arc::new(Mutex::new(receiver));
let sender: Arc<Mutex<dyn Sender>> = Arc::new(Mutex::new(sender));
let wire = Wire(sender, receiver);
let idle_timeout = Duration::from_secs(2);
let targets = IPTargets::new(vec!["192.168.1.2".to_string()]).unwrap();
let (tx, rx) = channel();
let scanner = ARPScanner::builder()
.interface(interface)
.wire(wire)
.targets(targets)
.source_port(54321_u16)
.include_vendor(true)
.include_host_names(true)
.idle_timeout(idle_timeout)
.notifier(tx)
.build()
.unwrap();
let handle = scanner.scan().unwrap();
loop {
if let Ok(ScanMessage::Done) = rx.recv() {
break;
}
}
let result = handle.join().unwrap();
assert!(result.is_err());
}
#[test]
fn emits_current_host_immediately_without_arp() {
let interface = Arc::new(network::get_default_interface().unwrap());
let host_ip = interface.ipv4;
let host_mac = interface.mac;
let mut receiver = MockPacketReader::new();
let mut sender = MockPacketSender::new();
sender.expect_send().returning(|_| Ok(()));
receiver
.expect_next_packet_with_metadata()
.returning(|| Ok((&[1], PacketMetadata { timestamp: None })));
let idle_timeout = Duration::from_secs(2);
let targets = IPTargets::new(vec![host_ip.to_string()]).unwrap();
let (tx, rx) = channel();
let sender: Arc<Mutex<dyn Sender>> = Arc::new(Mutex::new(sender));
let receiver: Arc<Mutex<dyn Reader>> = Arc::new(Mutex::new(receiver));
let wire = Wire(sender, receiver);
let scanner = ARPScanner::builder()
.interface(interface)
.wire(wire)
.targets(targets)
.source_port(54321_u16)
.include_vendor(false)
.include_host_names(false)
.idle_timeout(idle_timeout)
.notifier(tx)
.build()
.unwrap();
let handle = scanner.scan().unwrap();
let mut detected_device: Option<Device> = None;
loop {
if let Ok(msg) = rx.recv() {
match msg {
ScanMessage::Done => break,
ScanMessage::ARPScanDevice(device) => {
detected_device = Some(device);
}
_ => {}
}
}
}
let result = handle.join().unwrap();
assert!(result.is_ok());
let device = detected_device.expect("host device should be emitted");
assert_eq!(device.ip, host_ip);
assert_eq!(device.mac.to_string(), host_mac.to_string());
assert!(device.is_current_host);
assert_eq!(device.latency_ms, Some(0));
}
#[test]
fn reports_errors_from_read_handle() {
let interface = Arc::new(network::get_default_interface().unwrap());
let mut receiver = MockPacketReader::new();
let mut sender = MockPacketSender::new();
receiver
.expect_next_packet_with_metadata()
.returning(|| Err(RLanLibError::Wire("oh no a read error".into())));
sender.expect_send().returning(|_| Ok(()));
let receiver: Arc<Mutex<dyn Reader>> = Arc::new(Mutex::new(receiver));
let sender: Arc<Mutex<dyn Sender>> = Arc::new(Mutex::new(sender));
let wire = Wire(sender, receiver);
let idle_timeout = Duration::from_secs(2);
let targets = IPTargets::new(vec!["192.168.1.2".to_string()]).unwrap();
let (tx, rx) = channel();
let scanner = ARPScanner::builder()
.interface(interface)
.wire(wire)
.targets(targets)
.source_port(54321_u16)
.include_vendor(true)
.include_host_names(true)
.idle_timeout(idle_timeout)
.notifier(tx)
.build()
.unwrap();
let handle = scanner.scan().unwrap();
loop {
if let Ok(ScanMessage::Done) = rx.recv() {
break;
}
}
let result = handle.join().unwrap();
assert!(result.is_err());
}