1use std::{convert::TryFrom, net::IpAddr, ptr};
2
3use bitflags::bitflags;
4
5#[cfg(target_os = "windows")]
6use windows_sys::Win32::Networking::WinSock;
7
8use crate::{
9 capture::{Active, Capture},
10 cstr_to_string, raw, Error,
11};
12
13bitflags! {
14 pub struct IfFlags: u32 {
16 const LOOPBACK = raw::PCAP_IF_LOOPBACK;
18 const UP = raw::PCAP_IF_UP;
20 const RUNNING = raw::PCAP_IF_RUNNING;
22 const WIRELESS = raw::PCAP_IF_WIRELESS;
25 }
26}
27
28impl From<u32> for IfFlags {
29 fn from(flags: u32) -> Self {
30 IfFlags::from_bits_truncate(flags)
31 }
32}
33
34#[derive(Debug, Clone, PartialEq, Eq)]
35pub enum ConnectionStatus {
38 Unknown,
40 Connected,
42 Disconnected,
44 NotApplicable,
47}
48
49impl From<u32> for ConnectionStatus {
50 fn from(flags: u32) -> Self {
51 match flags & raw::PCAP_IF_CONNECTION_STATUS {
52 raw::PCAP_IF_CONNECTION_STATUS_UNKNOWN => ConnectionStatus::Unknown,
53 raw::PCAP_IF_CONNECTION_STATUS_CONNECTED => ConnectionStatus::Connected,
54 raw::PCAP_IF_CONNECTION_STATUS_DISCONNECTED => ConnectionStatus::Disconnected,
55 raw::PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE => ConnectionStatus::NotApplicable,
56 _ => unreachable!(),
60 }
62 }
63}
64
65#[derive(Debug, Clone)]
66pub struct DeviceFlags {
67 pub if_flags: IfFlags,
68 pub connection_status: ConnectionStatus,
69}
70
71impl From<u32> for DeviceFlags {
72 fn from(flags: u32) -> Self {
73 DeviceFlags {
74 if_flags: flags.into(),
75 connection_status: flags.into(),
76 }
77 }
78}
79
80impl DeviceFlags {
81 pub fn empty() -> Self {
82 DeviceFlags {
83 if_flags: IfFlags::empty(),
84 connection_status: ConnectionStatus::Unknown,
85 }
86 }
87
88 pub fn contains(&self, if_flags: IfFlags) -> bool {
89 self.if_flags.contains(if_flags)
90 }
91
92 pub fn is_loopback(&self) -> bool {
93 self.contains(IfFlags::LOOPBACK)
94 }
95
96 pub fn is_up(&self) -> bool {
97 self.contains(IfFlags::UP)
98 }
99
100 pub fn is_running(&self) -> bool {
101 self.contains(IfFlags::RUNNING)
102 }
103
104 pub fn is_wireless(&self) -> bool {
105 self.contains(IfFlags::WIRELESS)
106 }
107}
108
109#[derive(Debug, Clone)]
110pub struct Device {
112 pub name: String,
114 pub desc: Option<String>,
116 pub addresses: Vec<Address>,
118 pub flags: DeviceFlags,
120}
121
122impl Device {
123 fn new(
124 name: String,
125 desc: Option<String>,
126 addresses: Vec<Address>,
127 flags: DeviceFlags,
128 ) -> Device {
129 Device {
130 name,
131 desc,
132 addresses,
133 flags,
134 }
135 }
136
137 pub fn open(self) -> Result<Capture<Active>, Error> {
139 Capture::from_device(self)?.open()
140 }
141
142 pub fn lookup() -> Result<Option<Device>, Error> {
145 unsafe {
146 Device::with_all_devs(|all_devs| {
147 let dev = all_devs;
148 Ok(if !dev.is_null() {
149 Some(Device::try_from(&*dev)?)
150 } else {
151 None
152 })
153 })
154 }
155 }
156
157 pub fn list() -> Result<Vec<Device>, Error> {
159 unsafe {
160 Device::with_all_devs(|all_devs| {
161 let mut devices = vec![];
162 let mut dev = all_devs;
163 while !dev.is_null() {
164 devices.push(Device::try_from(&*dev)?);
165 dev = (*dev).next;
166 }
167 Ok(devices)
168 })
169 }
170 }
171
172 unsafe fn with_all_devs<T, F>(func: F) -> Result<T, Error>
173 where
174 F: FnOnce(*mut raw::pcap_if_t) -> Result<T, Error>,
175 {
176 let all_devs = Error::with_errbuf(|err| {
177 let mut all_devs: *mut raw::pcap_if_t = ptr::null_mut();
178 if raw::pcap_findalldevs(&mut all_devs, err) != 0 {
179 return Err(Error::new(err));
180 }
181 Ok(all_devs)
182 })?;
183 let result = func(all_devs);
184 raw::pcap_freealldevs(all_devs);
185 result
186 }
187}
188
189impl From<&str> for Device {
190 fn from(name: &str) -> Self {
191 Device::new(name.into(), None, Vec::new(), DeviceFlags::empty())
192 }
193}
194
195impl TryFrom<&raw::pcap_if_t> for Device {
196 type Error = Error;
197
198 fn try_from(dev: &raw::pcap_if_t) -> Result<Self, Error> {
199 Ok(Device::new(
200 unsafe { cstr_to_string(dev.name)?.ok_or(Error::InvalidString)? },
201 unsafe { cstr_to_string(dev.description)? },
202 unsafe { Address::new_vec(dev.addresses) },
203 DeviceFlags::from(dev.flags),
204 ))
205 }
206}
207
208#[derive(Debug, Clone)]
209pub struct Address {
211 pub addr: IpAddr,
213 pub netmask: Option<IpAddr>,
215 pub broadcast_addr: Option<IpAddr>,
217 pub dst_addr: Option<IpAddr>,
219}
220
221impl Address {
222 unsafe fn new_vec(mut ptr: *const raw::pcap_addr_t) -> Vec<Address> {
223 let mut vec = Vec::new();
224 while !ptr.is_null() {
225 if let Some(addr) = Address::new(ptr) {
226 vec.push(addr);
227 }
228 ptr = (*ptr).next;
229 }
230 vec
231 }
232
233 unsafe fn new(ptr: *const raw::pcap_addr_t) -> Option<Address> {
234 Self::convert_sockaddr((*ptr).addr).map(|addr| Address {
235 addr,
236 netmask: Self::convert_sockaddr((*ptr).netmask),
237 broadcast_addr: Self::convert_sockaddr((*ptr).broadaddr),
238 dst_addr: Self::convert_sockaddr((*ptr).dstaddr),
239 })
240 }
241
242 #[cfg(not(windows))]
243 unsafe fn convert_sockaddr(ptr: *const libc::sockaddr) -> Option<IpAddr> {
244 if ptr.is_null() {
245 return None;
246 }
247
248 match (*ptr).sa_family as i32 {
249 libc::AF_INET => {
250 let ptr: *const libc::sockaddr_in = std::mem::transmute(ptr);
251 Some(IpAddr::V4(u32::from_be((*ptr).sin_addr.s_addr).into()))
252 }
253
254 libc::AF_INET6 => {
255 let ptr: *const libc::sockaddr_in6 = std::mem::transmute(ptr);
256 Some(IpAddr::V6((*ptr).sin6_addr.s6_addr.into()))
257 }
258
259 _ => None,
260 }
261 }
262
263 #[cfg(windows)]
264 unsafe fn convert_sockaddr(ptr: *const libc::sockaddr) -> Option<IpAddr> {
265 if ptr.is_null() {
266 return None;
267 }
268
269 match (*ptr).sa_family as u32 {
270 WinSock::AF_INET => {
271 let ptr: *const WinSock::SOCKADDR_IN = std::mem::transmute(ptr);
272 let addr: [u8; 4] = ((*ptr).sin_addr.S_un.S_addr).to_ne_bytes();
273 Some(IpAddr::from(addr))
274 }
275 WinSock::AF_INET6 => {
276 let ptr: *const WinSock::SOCKADDR_IN6 = std::mem::transmute(ptr);
277 let addr = (*ptr).sin6_addr.u.Byte;
278 Some(IpAddr::from(addr))
279 }
280
281 _ => None,
282 }
283 }
284}
285
286#[cfg(test)]
287mod tests {
288 use std::ffi::CString;
289
290 use crate::raw::testmod::{as_pcap_t, RAWMTX};
291
292 use super::*;
293
294 #[cfg(not(windows))]
295 enum Sockaddr {
296 SockaddrIn(libc::sockaddr_in),
297 SockaddrIn6(libc::sockaddr_in6),
298 }
299
300 #[cfg(windows)]
301 enum Sockaddr {
302 SockaddrIn(WinSock::SOCKADDR_IN),
303 SockaddrIn6(WinSock::SOCKADDR_IN6),
304 }
305
306 impl Sockaddr {
307 fn as_mut_ptr(&mut self) -> *mut libc::sockaddr {
308 match self {
309 Sockaddr::SockaddrIn(ref mut sin) => sin as *mut _ as _,
310 Sockaddr::SockaddrIn6(ref mut sin6) => sin6 as *mut _ as _,
311 }
312 }
313
314 fn set_family(&mut self, family: u16) {
315 #[cfg(not(windows))]
317 let family = family as libc::sa_family_t;
318
319 match self {
320 Sockaddr::SockaddrIn(ref mut sin) => sin.sin_family = family,
321 Sockaddr::SockaddrIn6(ref mut sin6) => sin6.sin6_family = family,
322 }
323 }
324 }
325
326 static IF1_NAME: &str = "if1";
327 static IF2_NAME: &str = "if2";
328 static IF1_DESC: &str = "if1 desc";
329 static IF2_DESC: &str = "if2 desc";
330
331 fn devs() -> Vec<raw::pcap_if_t> {
332 let mut devs = vec![
333 raw::pcap_if_t {
334 next: std::ptr::null_mut(),
335 name: CString::new(IF1_NAME).unwrap().into_raw(),
336 description: CString::new(IF1_DESC).unwrap().into_raw(),
337 addresses: std::ptr::null_mut(),
338 flags: (raw::PCAP_IF_LOOPBACK | raw::PCAP_IF_UP),
339 },
340 raw::pcap_if_t {
341 next: std::ptr::null_mut(),
342 name: CString::new(IF2_NAME).unwrap().into_raw(),
343 description: CString::new(IF2_DESC).unwrap().into_raw(),
344 addresses: std::ptr::null_mut(),
345 flags: 0,
346 },
347 ];
348 devs[0].next = &mut devs[1];
349 devs
350 }
351
352 trait InetAddressV4 {
353 fn new() -> Self;
354 fn set_addr(&mut self, addr: u32);
355 }
356
357 #[cfg(not(windows))]
358 impl InetAddressV4 for libc::sockaddr_in {
359 fn new() -> Self {
360 let mut addr: Self = unsafe { std::mem::zeroed() };
361 addr.sin_family = libc::AF_INET as libc::sa_family_t;
362 addr
363 }
364
365 fn set_addr(&mut self, addr: u32) {
366 self.sin_addr.s_addr = addr;
367 }
368 }
369
370 #[cfg(windows)]
371 impl InetAddressV4 for WinSock::SOCKADDR_IN {
372 fn new() -> Self {
373 let mut addr: Self = unsafe { std::mem::zeroed() };
374 addr.sin_family = WinSock::AF_INET as u16;
376 addr
377 }
378
379 fn set_addr(&mut self, addr: u32) {
380 self.sin_addr.S_un.S_addr = addr;
381 }
382 }
383
384 fn sockaddr_ipv4() -> Sockaddr {
385 #[cfg(not(windows))]
386 let mut addr: libc::sockaddr_in = InetAddressV4::new();
387 #[cfg(windows)]
388 let mut addr: WinSock::SOCKADDR_IN = InetAddressV4::new();
389
390 addr.sin_port = 1075;
391 addr.set_addr(0x0A000042_u32.to_be());
392
393 Sockaddr::SockaddrIn(addr)
394 }
395
396 trait InetAddressV6 {
397 fn new() -> Self;
398 fn set_octet(&mut self, index: usize, octet: u8);
399 }
400
401 #[cfg(not(windows))]
402 impl InetAddressV6 for libc::sockaddr_in6 {
403 fn new() -> Self {
404 let mut addr: Self = unsafe { std::mem::zeroed() };
405 addr.sin6_family = libc::AF_INET6 as libc::sa_family_t;
406 addr.sin6_addr.s6_addr[0] = 0xFE;
407 addr.sin6_addr.s6_addr[1] = 0x80;
408 addr
409 }
410
411 fn set_octet(&mut self, index: usize, octet: u8) {
412 self.sin6_addr.s6_addr[index] = octet;
413 }
414 }
415
416 #[cfg(windows)]
417 impl InetAddressV6 for WinSock::SOCKADDR_IN6 {
418 fn new() -> Self {
419 let mut addr: Self = unsafe { std::mem::zeroed() };
420 addr.sin6_family = WinSock::AF_INET6 as u16;
422 unsafe {
423 addr.sin6_addr.u.Byte[0] = 0xFE;
424 addr.sin6_addr.u.Byte[1] = 0x80;
425 }
426 addr
427 }
428
429 fn set_octet(&mut self, index: usize, octet: u8) {
430 unsafe { self.sin6_addr.u.Byte[index] = octet };
431 }
432 }
433
434 fn sockaddr_ipv6() -> Sockaddr {
435 #[cfg(not(windows))]
436 let mut addr: libc::sockaddr_in6 = InetAddressV6::new();
437 #[cfg(windows)]
438 let mut addr: WinSock::SOCKADDR_IN6 = InetAddressV6::new();
439
440 addr.sin6_port = 1075;
441 addr.set_octet(15, 0x42);
442
443 Sockaddr::SockaddrIn6(addr)
444 }
445
446 impl From<&mut Sockaddr> for raw::pcap_addr_t {
447 fn from(value: &mut Sockaddr) -> Self {
448 raw::pcap_addr_t {
449 next: std::ptr::null_mut(),
450 addr: value.as_mut_ptr(),
451 netmask: std::ptr::null_mut(),
452 broadaddr: std::ptr::null_mut(),
453 dstaddr: std::ptr::null_mut(),
454 }
455 }
456 }
457
458 #[test]
459 fn test_device_flags() {
460 let flags = DeviceFlags::from(
461 raw::PCAP_IF_LOOPBACK | raw::PCAP_IF_UP | raw::PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE,
462 );
463
464 assert!(flags.is_loopback());
465 assert!(flags.is_up());
466 assert!(flags.contains(IfFlags::LOOPBACK | IfFlags::UP));
467
468 assert!(!flags.is_running());
469 assert!(!flags.is_wireless());
470
471 assert_ne!(flags.connection_status, ConnectionStatus::Unknown);
472 assert_ne!(flags.connection_status, ConnectionStatus::Connected);
473 assert_ne!(flags.connection_status, ConnectionStatus::Disconnected);
474 assert_eq!(flags.connection_status, ConnectionStatus::NotApplicable);
475
476 assert!(!format!("{flags:?}").is_empty());
477 }
478
479 #[test]
480 fn test_connection_status() {
481 let flags = raw::PCAP_IF_CONNECTION_STATUS_UNKNOWN;
482 assert_eq!(ConnectionStatus::from(flags), ConnectionStatus::Unknown);
483
484 let flags = raw::PCAP_IF_CONNECTION_STATUS_CONNECTED;
485 assert_eq!(ConnectionStatus::from(flags), ConnectionStatus::Connected);
486
487 let flags = raw::PCAP_IF_CONNECTION_STATUS_DISCONNECTED;
488 assert_eq!(
489 ConnectionStatus::from(flags),
490 ConnectionStatus::Disconnected
491 );
492
493 let flags = raw::PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE;
494 assert_eq!(
495 ConnectionStatus::from(flags),
496 ConnectionStatus::NotApplicable
497 );
498 }
499
500 #[test]
501 fn test_into_capture() {
502 let _m = RAWMTX.lock();
503
504 let mut dummy: isize = 777;
505 let pcap = as_pcap_t(&mut dummy);
506
507 let ctx = raw::pcap_create_context();
508 ctx.expect().return_once_st(move |_, _| pcap);
509
510 let ctx = raw::pcap_activate_context();
511 ctx.expect()
512 .withf_st(move |arg1| *arg1 == pcap)
513 .return_once(|_| 0);
514
515 let ctx = raw::pcap_close_context();
516 ctx.expect()
517 .withf_st(move |ptr| *ptr == pcap)
518 .return_once(|_| {});
519
520 let device: Device = "device".into();
521 let _capture: Capture<Active> = device.clone().open().unwrap();
522
523 assert!(!format!("{device:?}").is_empty());
524 }
525
526 #[test]
527 fn test_lookup() {
528 let _m = RAWMTX.lock();
529
530 let ctx = raw::pcap_findalldevs_context();
531 ctx.expect().return_once_st(move |arg1, _| {
532 unsafe { *arg1 = std::ptr::null_mut() };
533 0
534 });
535
536 let ctx = raw::pcap_freealldevs_context();
537 ctx.expect().return_once(move |_| {});
538
539 let device = Device::lookup().unwrap();
540 assert!(device.is_none());
541
542 let mut devs = devs();
543 let mut addrs = sockaddr_ipv4();
544 let mut pcap_addr = (&mut addrs).into();
545 devs[0].addresses = &mut pcap_addr;
546 let devs_ptr = devs.as_mut_ptr();
547
548 let ctx = raw::pcap_findalldevs_context();
549 ctx.checkpoint();
550 ctx.expect().return_once_st(move |arg1, _| {
551 unsafe { *arg1 = devs_ptr };
552 0
553 });
554
555 let ctx = raw::pcap_freealldevs_context();
556 ctx.checkpoint();
557 ctx.expect().return_once(move |_| {});
558
559 let device = Device::lookup().unwrap().unwrap();
560 assert_eq!(&device.name, IF1_NAME);
561 assert_eq!(&device.desc.unwrap(), IF1_DESC);
562 assert_eq!(device.addresses.len(), 1);
563 assert!(device.addresses[0].addr.is_ipv4());
564
565 let ctx = raw::pcap_findalldevs_context();
566 ctx.checkpoint();
567 ctx.expect().return_once_st(move |_, _| -1);
568
569 let ctx = raw::pcap_freealldevs_context();
570 ctx.checkpoint();
571
572 let result = Device::lookup();
573 assert!(result.is_err());
574 }
575
576 #[test]
577 fn test_list() {
578 let _m = RAWMTX.lock();
579
580 let ctx = raw::pcap_findalldevs_context();
581 ctx.expect().return_once_st(move |arg1, _| {
582 unsafe { *arg1 = std::ptr::null_mut() };
583 0
584 });
585
586 let ctx = raw::pcap_freealldevs_context();
587 ctx.expect().return_once(move |_| {});
588
589 let devices = Device::list().unwrap();
590 assert!(devices.is_empty());
591
592 let mut devs = devs();
593 let mut ipv4s = sockaddr_ipv4();
594 let mut ipv6s = sockaddr_ipv6();
595 let mut pcap_addr: raw::pcap_addr_t = (&mut ipv4s).into();
596 let mut pcap_addr6: raw::pcap_addr_t = (&mut ipv6s).into();
597 pcap_addr.next = &mut pcap_addr6;
598 devs[1].addresses = &mut pcap_addr;
599 let devs_ptr = devs.as_mut_ptr();
600
601 let ctx = raw::pcap_findalldevs_context();
602 ctx.checkpoint();
603 ctx.expect().return_once_st(move |arg1, _| {
604 unsafe { *arg1 = devs_ptr };
605 0
606 });
607
608 let ctx = raw::pcap_freealldevs_context();
609 ctx.checkpoint();
610 ctx.expect().return_once(move |_| {});
611
612 let devices = Device::list().unwrap();
613 assert_eq!(devices.len(), devs.len());
614
615 assert_eq!(&devices[0].name, IF1_NAME);
616 assert_eq!(devices[0].desc.as_ref().unwrap(), IF1_DESC);
617 assert_eq!(devices[0].addresses.len(), 0);
618
619 assert_eq!(&devices[1].name, IF2_NAME);
620 assert_eq!(devices[1].desc.as_ref().unwrap(), IF2_DESC);
621 assert_eq!(devices[1].addresses.len(), 2);
622 assert!(devices[1].addresses[0].addr.is_ipv4());
623 assert!(devices[1].addresses[1].addr.is_ipv6());
624
625 let ctx = raw::pcap_findalldevs_context();
626 ctx.checkpoint();
627 ctx.expect().return_once_st(move |_, _| -1);
628
629 let ctx = raw::pcap_freealldevs_context();
630 ctx.checkpoint();
631
632 let result = Device::list();
633 assert!(result.is_err());
634 }
635
636 #[test]
637 fn test_address_ipv4() {
638 let mut addr = sockaddr_ipv4();
639 let pcap_addr: raw::pcap_addr_t = (&mut addr).into();
640
641 let address = unsafe { Address::new(&pcap_addr) }.unwrap();
642
643 assert!(address.addr.is_ipv4());
644 assert_eq!(address.addr.to_string(), "10.0.0.66");
645
646 assert!(address.netmask.is_none());
647 assert!(address.broadcast_addr.is_none());
648 assert!(address.dst_addr.is_none());
649
650 assert!(!format!("{address:?}").is_empty());
651 }
652
653 #[test]
654 fn test_address_family() {
655 let mut addr = sockaddr_ipv4();
656
657 #[cfg(not(windows))]
658 addr.set_family(libc::AF_IPX as u16);
659 #[cfg(windows)]
660 addr.set_family(WinSock::AF_IPX);
661
662 let pcap_addr: raw::pcap_addr_t = (&mut addr).into();
663
664 let address = unsafe { Address::new(&pcap_addr) };
665 assert!(address.is_none());
666 }
667
668 #[test]
669 fn test_address_ipv6() {
670 let mut addr = sockaddr_ipv6();
671 let pcap_addr: raw::pcap_addr_t = (&mut addr).into();
672
673 let address = unsafe { Address::new(&pcap_addr) }.unwrap();
674
675 assert!(address.addr.is_ipv6());
676 assert_eq!(address.addr.to_string(), "fe80::42");
677
678 assert!(address.netmask.is_none());
679 assert!(address.broadcast_addr.is_none());
680 assert!(address.dst_addr.is_none());
681
682 assert!(!format!("{address:?}").is_empty());
683 }
684}