1use crate::interfaces::{Interface, MacAddr};
2use std::{
3 convert::TryFrom,
4 io::{Error, ErrorKind},
5 net::Ipv4Addr,
6 u16,
7};
8
9use num_derive::FromPrimitive;
10use num_traits::FromPrimitive;
11
12use pnet::packet::{
13 arp::{ArpHardwareTypes, ArpOperation, ArpPacket, MutableArpPacket},
14 ethernet::{
15 EtherType,
16 EtherTypes::{self},
17 MutableEthernetPacket,
18 },
19 MutablePacket, Packet,
20};
21
22pub struct ArpMessage {
23 pub source_hardware_address: MacAddr,
24 pub source_protocol_address: Ipv4Addr,
25
26 pub target_hardware_address: MacAddr,
27 pub target_protocol_address: Ipv4Addr,
28
29 pub ethertype: EtherType,
30 pub operation: Operation,
31}
32
33#[derive(Copy, Clone, FromPrimitive, PartialEq)]
34pub enum Operation {
35 ArpRequest = 0x1,
36 ArpResponse = 0x2,
37 RarpRequest = 0x3,
38 RarpResponse = 0x4,
39}
40
41impl ArpMessage {
42 pub fn new(
44 ethertype: EtherType,
45 source_hardware_address: MacAddr,
46 source_protocol_address: Ipv4Addr,
47 target_hardware_address: MacAddr,
48 target_protocol_address: Ipv4Addr,
49 operation: Operation,
50 ) -> Self {
51 ArpMessage {
52 source_hardware_address: source_hardware_address,
53 source_protocol_address: source_protocol_address,
54 target_hardware_address: target_hardware_address,
55 target_protocol_address: target_protocol_address,
56 ethertype: ethertype,
57 operation: operation,
58 }
59 }
60
61 pub fn new_arp_request(
63 source_hardware_address: MacAddr,
64 source_protocol_address: Ipv4Addr,
65 target_protocol_address: Ipv4Addr,
66 ) -> Self {
67 Self::new(
68 EtherTypes::Arp,
69 source_hardware_address,
70 source_protocol_address,
71 MacAddr(0, 0, 0, 0, 0, 0),
72 target_protocol_address,
73 Operation::ArpRequest,
74 )
75 }
76
77 pub fn new_arp_response(
79 source_hardware_address: MacAddr,
80 source_protocol_address: Ipv4Addr,
81 target_hardware_address: MacAddr,
82 target_protocol_address: Ipv4Addr,
83 ) -> Self {
84 Self::new(
85 EtherTypes::Arp,
86 source_hardware_address,
87 source_protocol_address,
88 target_hardware_address,
89 target_protocol_address,
90 Operation::ArpResponse,
91 )
92 }
93
94 pub fn new_rarp_request(
96 source_hardware_address: MacAddr,
97 target_hardware_address: MacAddr,
98 ) -> Self {
99 Self::new(
100 EtherTypes::Rarp,
101 source_hardware_address,
102 Ipv4Addr::new(0, 0, 0, 0),
103 target_hardware_address,
104 Ipv4Addr::new(0, 0, 0, 0),
105 Operation::RarpRequest,
106 )
107 }
108
109 pub fn new_rarp_response(
111 source_hardware_address: MacAddr,
112 source_protocol_address: Ipv4Addr,
113 target_hardware_address: MacAddr,
114 target_protocol_address: Ipv4Addr,
115 ) -> Self {
116 Self::new(
117 EtherTypes::Rarp,
118 source_hardware_address,
119 source_protocol_address,
120 target_hardware_address,
121 target_protocol_address,
122 Operation::RarpResponse,
123 )
124 }
125
126 pub fn send(&self, interface: &Interface) -> Result<(), Error> {
130 let mut tx = match interface.create_tx_rx_channels() {
131 Ok((tx, _)) => tx,
132 Err(err) => return Err(err),
133 };
134
135 let mut eth_buf = vec![0; 42];
136 let mut eth_packet = MutableEthernetPacket::new(&mut eth_buf).unwrap();
137
138 eth_packet.set_destination(MacAddr::new(0xff, 0xff, 0xff, 0xff, 0xff, 0xff).into());
139 eth_packet.set_source(interface.get_mac()?.into());
140 eth_packet.set_ethertype(self.ethertype);
141
142 let mut arp_buf = vec![0; 28];
143 let mut arp_packet = MutableArpPacket::new(&mut arp_buf).unwrap();
144
145 arp_packet.set_hardware_type(ArpHardwareTypes::Ethernet);
146 arp_packet.set_protocol_type(EtherTypes::Ipv4);
147 arp_packet.set_hw_addr_len(0x06);
148 arp_packet.set_proto_addr_len(0x04);
149 arp_packet.set_operation(ArpOperation::new(self.operation as u16));
150 arp_packet.set_sender_hw_addr(self.source_hardware_address.into());
151 arp_packet.set_sender_proto_addr(self.source_protocol_address);
152 arp_packet.set_target_hw_addr(self.target_hardware_address.into());
153 arp_packet.set_target_proto_addr(self.target_protocol_address);
154
155 eth_packet.set_payload(arp_packet.packet_mut());
156
157 tx.send_to(eth_packet.packet(), None).unwrap()
158 }
159}
160
161impl TryFrom<ArpPacket<'_>> for ArpMessage {
162 type Error = Error;
163
164 fn try_from(arp_packet: ArpPacket<'_>) -> Result<Self, Self::Error> {
165 let operation_raw = arp_packet.get_operation().0;
166 let operation = match FromPrimitive::from_u16(operation_raw) {
167 Some(op) => op,
168 None => {
169 return Err(Error::new(
170 ErrorKind::InvalidData,
171 format!(
172 "Could not cast operation raw value {} to enum.",
173 operation_raw
174 ),
175 ))
176 }
177 };
178
179 Ok(ArpMessage::new(
180 arp_packet.get_protocol_type(),
181 arp_packet.get_sender_hw_addr().into(),
182 arp_packet.get_sender_proto_addr(),
183 arp_packet.get_target_hw_addr().into(),
184 arp_packet.get_target_proto_addr(),
185 operation,
186 ))
187 }
188}