// This file is part of masscanned. // Copyright 2021 - The IVRE project // // Masscanned is free software: you can redistribute it and/or modify it // under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Masscanned is distributed in the hope that it will be useful, but WITHOUT // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY // or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public // License for more details. // // You should have received a copy of the GNU General Public License // along with Masscanned. If not, see . use log::*; use std::net::IpAddr; use pnet::packet::{ arp::{ArpHardwareTypes, ArpOperations, ArpPacket, MutableArpPacket}, /* Import needed for traits */ Packet as _, }; use crate::Masscanned; pub fn repl<'a, 'b>( arp_req: &'a ArpPacket, masscanned: &Masscanned, ) -> Option> { masscanned.log.arp_recv(arp_req); let mut arp_repl = MutableArpPacket::owned(arp_req.packet().to_vec()).expect("error parsing ARP packet"); /* Build ARP answer depending of the type of request */ match arp_req.get_operation() { ArpOperations::Request => { masscanned.log.arp_recv(arp_req); let ip = IpAddr::V4(arp_req.get_target_proto_addr()); /* Ignore ARP requests for IP addresses not handled by masscanned */ if let Some(ip_addr_list) = masscanned.ip_addresses { if !ip_addr_list.contains(&ip) { masscanned.log.arp_drop(arp_req); return None; } } /* Fill ARP reply */ arp_repl.set_operation(ArpOperations::Reply); arp_repl.set_hardware_type(ArpHardwareTypes::Ethernet); arp_repl.set_sender_hw_addr(masscanned.mac); arp_repl.set_target_hw_addr(arp_req.get_sender_hw_addr().to_owned()); arp_repl.set_target_proto_addr(arp_req.get_sender_proto_addr().to_owned()); arp_repl.set_sender_proto_addr(arp_req.get_target_proto_addr().to_owned()); masscanned.log.arp_send(&arp_repl); } _ => { info!("ARP Operation not handled: {:?}", arp_repl.get_operation()); masscanned.log.arp_drop(arp_req); return None; } }; masscanned.log.arp_send(&arp_repl); Some(arp_repl) } #[cfg(test)] mod tests { use super::*; use std::collections::HashSet; use std::net::Ipv4Addr; use std::str::FromStr; use pnet::util::MacAddr; use crate::utils::MetaLogger; #[test] fn test_arp_reply() { let mut ips = HashSet::new(); ips.insert(IpAddr::V4(Ipv4Addr::new(0, 1, 2, 3))); /* Construct masscanned context object */ let masscanned = Masscanned { synack_key: [0, 0], mac: MacAddr::from_str("00:11:22:33:44:55").expect("error parsing MAC address"), iface: None, ip_addresses: Some(&ips), log: MetaLogger::new(), }; let mut arp_req = MutableArpPacket::owned([0; 28].to_vec()).expect("error constructing ARP request"); arp_req.set_hardware_type(ArpHardwareTypes::Ethernet); arp_req.set_operation(ArpOperations::Request); arp_req.set_sender_hw_addr( MacAddr::from_str("55:44:33:22:11:00").expect("error parsing MAC address"), ); arp_req.set_target_hw_addr( MacAddr::from_str("00:00:00:00:00:00").expect("error parsing MAC address"), ); arp_req.set_sender_proto_addr(Ipv4Addr::new(3, 2, 1, 0)); /* Test getting an ARP reply for a legitimate IP address */ arp_req.set_target_proto_addr(Ipv4Addr::new(0, 1, 2, 3)); if let Some(arp_repl) = repl(&arp_req.to_immutable(), &masscanned) { assert!(arp_repl.get_hardware_type() == ArpHardwareTypes::Ethernet); assert!(arp_repl.get_operation() == ArpOperations::Reply); assert!(arp_repl.get_sender_hw_addr() == masscanned.mac); assert!(arp_repl.get_sender_proto_addr() == Ipv4Addr::new(0, 1, 2, 3)); } else { panic!("Expected ARP reply - got None"); } /* Ensure no response is returned for an other IP address */ arp_req.set_target_proto_addr(Ipv4Addr::new(1, 1, 2, 3)); let arp_repl = repl(&arp_req.to_immutable(), &masscanned); assert!(arp_repl == None); } }