1use std::collections::HashMap;
12use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
13use std::sync::{Arc, RwLock};
14use std::time::{Duration, Instant};
15
16use crate::layer::LayerKind;
17use crate::layer::field::MacAddress;
18
19pub type ResolverFn = fn(&NeighborCache, &[u8], &[u8]) -> Option<MacAddress>;
21
22#[derive(Debug, Clone)]
24pub struct CacheEntry {
25 pub mac: MacAddress,
26 pub expires: Instant,
27}
28
29impl CacheEntry {
30 #[must_use]
31 pub fn new(mac: MacAddress, ttl: Duration) -> Self {
32 Self {
33 mac,
34 expires: Instant::now() + ttl,
35 }
36 }
37
38 #[must_use]
39 pub fn is_expired(&self) -> bool {
40 Instant::now() > self.expires
41 }
42}
43
44#[derive(Debug, Clone, Default)]
46pub struct ArpCache {
47 entries: HashMap<Ipv4Addr, CacheEntry>,
48 ttl: Duration,
49}
50
51impl ArpCache {
52 #[must_use]
53 pub fn new() -> Self {
54 Self::with_ttl(Duration::from_secs(120)) }
56
57 #[must_use]
58 pub fn with_ttl(ttl: Duration) -> Self {
59 Self {
60 entries: HashMap::new(),
61 ttl,
62 }
63 }
64
65 #[must_use]
67 pub fn get(&self, ip: &Ipv4Addr) -> Option<MacAddress> {
68 self.entries.get(ip).and_then(|entry| {
69 if entry.is_expired() {
70 None
71 } else {
72 Some(entry.mac)
73 }
74 })
75 }
76
77 pub fn put(&mut self, ip: Ipv4Addr, mac: MacAddress) {
79 self.entries.insert(ip, CacheEntry::new(mac, self.ttl));
80 }
81
82 pub fn cleanup(&mut self) {
84 self.entries.retain(|_, entry| !entry.is_expired());
85 }
86
87 pub fn clear(&mut self) {
89 self.entries.clear();
90 }
91
92 #[must_use]
94 pub fn len(&self) -> usize {
95 self.entries.len()
96 }
97
98 #[must_use]
99 pub fn is_empty(&self) -> bool {
100 self.entries.is_empty()
101 }
102}
103
104#[derive(Debug, Clone, Default)]
106pub struct NdpCache {
107 entries: HashMap<Ipv6Addr, CacheEntry>,
108 ttl: Duration,
109}
110
111impl NdpCache {
112 #[must_use]
113 pub fn new() -> Self {
114 Self::with_ttl(Duration::from_secs(120))
115 }
116
117 #[must_use]
118 pub fn with_ttl(ttl: Duration) -> Self {
119 Self {
120 entries: HashMap::new(),
121 ttl,
122 }
123 }
124
125 #[must_use]
126 pub fn get(&self, ip: &Ipv6Addr) -> Option<MacAddress> {
127 self.entries.get(ip).and_then(|entry| {
128 if entry.is_expired() {
129 None
130 } else {
131 Some(entry.mac)
132 }
133 })
134 }
135
136 pub fn put(&mut self, ip: Ipv6Addr, mac: MacAddress) {
137 self.entries.insert(ip, CacheEntry::new(mac, self.ttl));
138 }
139
140 pub fn cleanup(&mut self) {
141 self.entries.retain(|_, entry| !entry.is_expired());
142 }
143
144 pub fn clear(&mut self) {
145 self.entries.clear();
146 }
147}
148
149pub trait NeighborResolver {
151 fn resolve(&self, l2_data: &[u8], l3_data: &[u8]) -> Option<MacAddress>;
153}
154
155#[derive(Clone)]
157pub struct NeighborCache {
158 resolvers: HashMap<(LayerKind, LayerKind), ResolverFn>,
160 arp_cache: Arc<RwLock<ArpCache>>,
162 ndp_cache: Arc<RwLock<NdpCache>>,
164}
165
166impl Default for NeighborCache {
167 fn default() -> Self {
168 Self::new()
169 }
170}
171
172impl NeighborCache {
173 #[must_use]
174 pub fn new() -> Self {
175 let mut cache = Self {
176 resolvers: HashMap::new(),
177 arp_cache: Arc::new(RwLock::new(ArpCache::new())),
178 ndp_cache: Arc::new(RwLock::new(NdpCache::new())),
179 };
180 cache.register_defaults();
181 cache
182 }
183
184 fn register_defaults(&mut self) {
186 self.register_l3(LayerKind::Ethernet, LayerKind::Arp, resolve_ether_arp);
187 self.register_l3(LayerKind::Ethernet, LayerKind::Ipv4, resolve_ether_ipv4);
188 self.register_l3(LayerKind::Ethernet, LayerKind::Ipv6, resolve_ether_ipv6);
189 }
190
191 pub fn register_l3(&mut self, l2: LayerKind, l3: LayerKind, resolver: ResolverFn) {
193 self.resolvers.insert((l2, l3), resolver);
194 }
195
196 #[must_use]
198 pub fn resolve(
199 &self,
200 l2: LayerKind,
201 l3: LayerKind,
202 l2_data: &[u8],
203 l3_data: &[u8],
204 ) -> Option<MacAddress> {
205 self.resolvers
206 .get(&(l2, l3))
207 .and_then(|resolver| resolver(self, l2_data, l3_data))
208 }
209
210 #[must_use]
212 pub fn arp_cache(&self) -> &Arc<RwLock<ArpCache>> {
213 &self.arp_cache
214 }
215
216 #[must_use]
218 pub fn ndp_cache(&self) -> &Arc<RwLock<NdpCache>> {
219 &self.ndp_cache
220 }
221
222 pub fn cache_arp(&self, ip: Ipv4Addr, mac: MacAddress) {
224 if let Ok(mut cache) = self.arp_cache.write() {
225 cache.put(ip, mac);
226 }
227 }
228
229 #[must_use]
231 pub fn lookup_arp(&self, ip: &Ipv4Addr) -> Option<MacAddress> {
232 self.arp_cache.read().ok()?.get(ip)
233 }
234
235 pub fn cache_ndp(&self, ip: Ipv6Addr, mac: MacAddress) {
237 if let Ok(mut cache) = self.ndp_cache.write() {
238 cache.put(ip, mac);
239 }
240 }
241
242 #[must_use]
244 pub fn lookup_ndp(&self, ip: &Ipv6Addr) -> Option<MacAddress> {
245 self.ndp_cache.read().ok()?.get(ip)
246 }
247}
248
249impl std::fmt::Debug for NeighborCache {
250 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
251 f.debug_struct("NeighborCache")
252 .field("resolvers", &self.resolvers.keys().collect::<Vec<_>>())
253 .finish()
254 }
255}
256
257fn resolve_ether_arp(
263 _cache: &NeighborCache,
264 _l2_data: &[u8],
265 l3_data: &[u8],
266) -> Option<MacAddress> {
267 if l3_data.len() < 8 {
268 return None;
269 }
270
271 let op = u16::from_be_bytes([l3_data[6], l3_data[7]]);
273 if op == 1 {
274 Some(MacAddress::BROADCAST)
275 } else {
276 None
277 }
278}
279
280fn resolve_ether_ipv4(
282 cache: &NeighborCache,
283 _l2_data: &[u8],
284 l3_data: &[u8],
285) -> Option<MacAddress> {
286 if l3_data.len() < 20 {
287 return None;
288 }
289
290 let dst_ip = Ipv4Addr::new(l3_data[16], l3_data[17], l3_data[18], l3_data[19]);
291
292 if dst_ip.is_multicast() {
293 return Some(MacAddress::from_ipv4_multicast(dst_ip));
294 }
295 if dst_ip.is_broadcast() || dst_ip == Ipv4Addr::BROADCAST {
296 return Some(MacAddress::BROADCAST);
297 }
298
299 let interfaces = pnet_datalink::interfaces();
300 let mut next_hop = dst_ip;
301 let mut is_local = false;
302
303 for iface in &interfaces {
304 if !iface.is_up() {
305 continue;
306 }
307 for ip_net in &iface.ips {
308 if let IpAddr::V4(local_ip) = ip_net.ip()
309 && local_ip == dst_ip
310 {
311 is_local = true;
312 break;
313 }
314 if ip_net.contains(IpAddr::V4(dst_ip)) {
315 is_local = true;
316 break;
317 }
318 }
319 }
320
321 if !is_local
322 && let Ok(gw) = default_net::get_default_gateway()
323 && let IpAddr::V4(gw_ip) = gw.ip_addr
324 {
325 next_hop = gw_ip;
326 }
327
328 cache.lookup_arp(&next_hop)
329}
330
331fn resolve_ether_ipv6(
333 cache: &NeighborCache,
334 _l2_data: &[u8],
335 l3_data: &[u8],
336) -> Option<MacAddress> {
337 if l3_data.len() < 40 {
338 return None;
339 }
340
341 let mut dst_bytes = [0u8; 16];
342 dst_bytes.copy_from_slice(&l3_data[24..40]);
343 let dst_ip = Ipv6Addr::from(dst_bytes);
344
345 if dst_ip.segments()[0] >> 8 == 0xff {
346 return Some(MacAddress::from_ipv6_multicast(dst_ip));
347 }
348
349 let interfaces = pnet_datalink::interfaces();
350 let mut next_hop = dst_ip;
351 let mut is_local = false;
352
353 for iface in &interfaces {
354 if !iface.is_up() {
355 continue;
356 }
357 for ip_net in &iface.ips {
358 if ip_net.contains(IpAddr::V6(dst_ip)) {
359 is_local = true;
360 break;
361 }
362 }
363 }
364
365 if !is_local
366 && let Ok(gw) = default_net::get_default_gateway()
367 && let IpAddr::V6(gw_ip) = gw.ip_addr
368 {
369 next_hop = gw_ip;
370 }
371
372 cache.lookup_ndp(&next_hop)
373}
374
375#[must_use]
381pub fn ipv4_multicast_mac(ip: Ipv4Addr) -> MacAddress {
382 MacAddress::from_ipv4_multicast(ip)
383}
384
385#[must_use]
387pub fn ipv6_multicast_mac(ip: Ipv6Addr) -> MacAddress {
388 MacAddress::from_ipv6_multicast(ip)
389}
390
391#[must_use]
393pub fn is_ipv4_multicast(ip: Ipv4Addr) -> bool {
394 ip.is_multicast()
395}
396
397#[must_use]
399pub fn is_ipv6_multicast(ip: Ipv6Addr) -> bool {
400 ip.segments()[0] >> 8 == 0xff
401}
402
403#[must_use]
405pub fn solicited_node_multicast(ip: Ipv6Addr) -> Ipv6Addr {
406 let octets = ip.octets();
407 Ipv6Addr::new(
408 0xff02,
409 0,
410 0,
411 0,
412 0,
413 1,
414 0xff00 | u16::from(octets[13]),
415 (u16::from(octets[14]) << 8) | u16::from(octets[15]),
416 )
417}
418
419#[cfg(test)]
420mod tests {
421 use super::*;
422
423 #[test]
424 fn test_arp_cache() {
425 let mut cache = ArpCache::new();
426 let ip = Ipv4Addr::new(192, 168, 1, 1);
427 let mac = MacAddress::new([0x00, 0x11, 0x22, 0x33, 0x44, 0x55]);
428
429 cache.put(ip, mac);
430 assert_eq!(cache.get(&ip), Some(mac));
431 }
432
433 #[test]
434 fn test_arp_cache_expiration() {
435 let mut cache = ArpCache::with_ttl(Duration::from_millis(1));
436 let ip = Ipv4Addr::new(192, 168, 1, 1);
437 let mac = MacAddress::new([0x00, 0x11, 0x22, 0x33, 0x44, 0x55]);
438
439 cache.put(ip, mac);
440 std::thread::sleep(Duration::from_millis(10));
441 assert_eq!(cache.get(&ip), None);
442 }
443
444 #[test]
445 fn test_resolve_ether_arp() {
446 let cache = NeighborCache::new(); let arp_request = vec![
450 0x00, 0x01, 0x08, 0x00, 0x06, 0x04, 0x00, 0x01, ];
455
456 let result = resolve_ether_arp(&cache, &[], &arp_request);
458 assert_eq!(result, Some(MacAddress::BROADCAST));
459
460 let arp_reply = vec![
462 0x00, 0x01, 0x08, 0x00, 0x06, 0x04, 0x00, 0x02, ];
464
465 let result = resolve_ether_arp(&cache, &[], &arp_reply);
467 assert_eq!(result, None);
468 }
469
470 #[test]
471 fn test_resolve_ether_ipv4_multicast() {
472 let cache = NeighborCache::new();
473
474 let mut ipv4 = vec![0u8; 20];
476 ipv4[16] = 224;
477 ipv4[17] = 0;
478 ipv4[18] = 0;
479 ipv4[19] = 1;
480
481 let result = resolve_ether_ipv4(&cache, &[], &ipv4);
483 assert!(result.is_some());
484 let mac = result.unwrap();
485 assert!(mac.is_ipv4_multicast());
486 }
487
488 #[test]
489 fn test_resolve_ether_ipv4_broadcast() {
490 let cache = NeighborCache::new();
491
492 let mut ipv4 = vec![0u8; 20];
493 ipv4[16] = 255;
494 ipv4[17] = 255;
495 ipv4[18] = 255;
496 ipv4[19] = 255;
497
498 let result = resolve_ether_ipv4(&cache, &[], &ipv4);
500 assert_eq!(result, Some(MacAddress::BROADCAST));
501 }
502
503 #[test]
504 fn test_ipv4_multicast_mac() {
505 let ip = Ipv4Addr::new(224, 0, 0, 1);
506 let mac = ipv4_multicast_mac(ip);
507 assert_eq!(mac.0[0], 0x01);
508 assert_eq!(mac.0[1], 0x00);
509 assert_eq!(mac.0[2], 0x5e);
510 }
511
512 #[test]
513 fn test_ipv6_multicast_mac() {
514 let ip = Ipv6Addr::new(0xff02, 0, 0, 0, 0, 0, 0, 1);
515 let mac = ipv6_multicast_mac(ip);
516 assert_eq!(mac.0[0], 0x33);
517 assert_eq!(mac.0[1], 0x33);
518 }
519
520 #[test]
521 fn test_neighbor_cache() {
522 let cache = NeighborCache::new();
523
524 let ip = Ipv4Addr::new(10, 0, 0, 1);
526 let mac = MacAddress::new([0xaa; 6]);
527 cache.cache_arp(ip, mac);
528 assert_eq!(cache.lookup_arp(&ip), Some(mac));
529 }
530
531 #[test]
532 fn test_solicited_node_multicast() {
533 let ip = Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0x1234);
534 let snm = solicited_node_multicast(ip);
535
536 assert_eq!(snm.segments()[0], 0xff02);
538 assert_eq!(snm.segments()[5], 1);
539 }
540}