extern crate pnet;
extern crate pnet_datalink;
use crate::net;
use std::{thread, time};
use std::time::Instant;
use std::net::Ipv4Addr;
use anyhow::{anyhow, Result};
use pnet::packet::ethernet::EtherTypes;
use pnet::packet::ethernet::MutableEthernetPacket;
use pnet::packet::{MutablePacket, Packet};
use pnet_datalink::{Channel, MacAddr, NetworkInterface};
use pnet::packet::arp::{ArpHardwareTypes, ArpOperations, ArpPacket, MutableArpPacket};
const ETH_HEADER_SIZE: usize = 42;
const ARP_HEADER_SIZE: usize = 28;
#[derive(Debug, Clone, Copy)]
pub struct ArpHost {
pub ip: Ipv4Addr,
pub mac: MacAddr
}
macro_rules! eth {
( $buffer:expr, $src:expr, $dst:expr, $ether_type:expr, $payload:expr ) => {
{
let mut ethernet_packet = MutableEthernetPacket::new($buffer).unwrap();
ethernet_packet.set_source($src);
ethernet_packet.set_destination($dst);
ethernet_packet.set_ethertype($ether_type);
ethernet_packet.set_payload($payload);
ethernet_packet
}
};
}
macro_rules! arp {
( $buffer:expr, $arp_type:expr, $source:expr, $target:expr ) => {
{
let mut arp_packet = MutableArpPacket::new($buffer).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($arp_type);
arp_packet.set_sender_hw_addr($source.mac);
arp_packet.set_sender_proto_addr($source.ip);
arp_packet.set_target_hw_addr($target.mac);
arp_packet.set_target_proto_addr($target.ip);
arp_packet
}
};
}
pub fn send_arp_reply(
interface: &NetworkInterface,
source: ArpHost,
target: ArpHost
) -> Option<std::io::Result<()>> {
let (mut tx, mut _rx) = match pnet_datalink::channel(interface, Default::default()) {
Ok(Channel::Ethernet(tx, rx)) => (tx, rx),
Ok(_) => return None,
Err(_e) => return None
};
let mut eth_buffer = [0u8; ETH_HEADER_SIZE];
let mut arp_buffer = [0u8; ARP_HEADER_SIZE];
let mut arp_packet = arp!(
&mut arp_buffer,
ArpOperations::Reply,
source,
target
);
let eth_packet = eth!(
&mut eth_buffer,
interface.mac.unwrap(),
target.mac,
EtherTypes::Arp,
arp_packet.packet_mut()
);
tx.send_to(eth_packet.packet(), None)
}
pub fn resolve_arp_host(
interface: &NetworkInterface,
target_ip: Ipv4Addr
) -> Result<ArpHost> {
let source_ip: Ipv4Addr = net::get_ipv4_addr_of(interface).unwrap();
let (mut sender, mut rx) = match pnet_datalink::channel(interface, Default::default()) {
Ok(Channel::Ethernet(tx, rx)) => (tx, rx),
Ok(_) => return Err(anyhow!("Unknown channel type")),
Err(e) => return Err(anyhow!(e))
};
let mut eth_buffer = [0u8; ETH_HEADER_SIZE];
let mut arp_buffer = [0u8; ARP_HEADER_SIZE];
let source_mac = interface.mac.unwrap();
let mut arp_packet = arp!(
&mut arp_buffer,
ArpOperations::Request,
ArpHost { ip: source_ip, mac: source_mac },
ArpHost { ip: target_ip, mac: MacAddr::zero() }
);
let eth_packet = eth!(
&mut eth_buffer,
source_mac,
MacAddr::broadcast(),
EtherTypes::Arp,
arp_packet.packet_mut()
);
let start = Instant::now();
loop {
sender
.send_to(eth_packet.packet(), None)
.unwrap()
.unwrap();
let buf = rx.next().unwrap();
let arp = ArpPacket::new(&buf[MutableEthernetPacket::minimum_packet_size()..]).unwrap();
if arp.get_operation() == ArpOperations::Reply
&& arp.get_target_hw_addr() == source_mac
&& arp.get_sender_proto_addr() == target_ip {
return Ok(
ArpHost { ip: target_ip, mac: arp.get_sender_hw_addr() }
);
}
if start.elapsed().as_secs() >= 10 {
return Err(
anyhow!("Could not resolve the MAC address of IP {}", target_ip)
);
}
thread::sleep(time::Duration::from_secs(1));
}
}