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