1pub mod active;
2pub mod dead;
3pub mod iterator;
4pub mod offline;
5
6use std::{
7 any::Any,
8 convert::TryInto,
9 ffi::CString,
10 fmt, mem,
11 panic::{catch_unwind, resume_unwind, AssertUnwindSafe},
12 path::Path,
13 ptr::{self, NonNull},
14 slice,
15 sync::{Arc, Weak},
16};
17
18#[cfg(not(windows))]
19use std::os::unix::io::RawFd;
20
21use crate::{
22 capture::{Activated, Capture, PcapHandle},
23 codec::PacketCodec,
24 linktype::Linktype,
25 packet::{Packet, PacketHeader},
26 raw, Error,
27};
28
29use iterator::PacketIter;
30
31#[derive(Debug, Clone, Copy, PartialEq, Eq)]
32pub struct Stat {
34 pub received: u32,
36 pub dropped: u32,
39 pub if_dropped: u32,
41}
42
43impl Stat {
44 fn new(received: u32, dropped: u32, if_dropped: u32) -> Stat {
45 Stat {
46 received,
47 dropped,
48 if_dropped,
49 }
50 }
51}
52
53#[repr(u32)]
54#[derive(Debug, PartialEq, Eq, Clone, Copy)]
55pub enum Direction {
57 InOut = raw::PCAP_D_INOUT,
59 In = raw::PCAP_D_IN,
61 Out = raw::PCAP_D_OUT,
63}
64
65impl<T: Activated + ?Sized> Capture<T> {
67 pub fn list_datalinks(&self) -> Result<Vec<Linktype>, Error> {
69 unsafe {
70 let mut links: *mut i32 = ptr::null_mut();
71 let num = raw::pcap_list_datalinks(self.handle.as_ptr(), &mut links);
72 let mut vec = vec![];
73 if num > 0 {
74 vec.extend(
75 slice::from_raw_parts(links, num as _)
76 .iter()
77 .cloned()
78 .map(Linktype),
79 )
80 }
81 raw::pcap_free_datalinks(links);
82 self.check_err(num > 0).and(Ok(vec))
83 }
84 }
85
86 pub fn set_datalink(&mut self, linktype: Linktype) -> Result<(), Error> {
88 self.check_err(unsafe { raw::pcap_set_datalink(self.handle.as_ptr(), linktype.0) == 0 })
89 }
90
91 pub fn get_datalink(&self) -> Linktype {
93 unsafe { Linktype(raw::pcap_datalink(self.handle.as_ptr())) }
94 }
95
96 pub fn savefile<P: AsRef<Path>>(&self, path: P) -> Result<Savefile, Error> {
99 let name = CString::new(path.as_ref().to_str().unwrap())?;
100 let handle_opt = NonNull::<raw::pcap_dumper_t>::new(unsafe {
101 raw::pcap_dump_open(self.handle.as_ptr(), name.as_ptr())
102 });
103 let handle = self
104 .check_err(handle_opt.is_some())
105 .map(|_| handle_opt.unwrap())?;
106 Ok(Savefile::from(handle))
107 }
108
109 #[cfg(not(windows))]
117 pub unsafe fn savefile_raw_fd(&self, fd: RawFd) -> Result<Savefile, Error> {
118 open_raw_fd(fd, b'w').and_then(|file| {
119 let handle_opt = NonNull::<raw::pcap_dumper_t>::new(raw::pcap_dump_fopen(
120 self.handle.as_ptr(),
121 file,
122 ));
123 let handle = self
124 .check_err(handle_opt.is_some())
125 .map(|_| handle_opt.unwrap())?;
126 Ok(Savefile::from(handle))
127 })
128 }
129
130 #[cfg(libpcap_1_7_2)]
137 pub fn savefile_append<P: AsRef<Path>>(&self, path: P) -> Result<Savefile, Error> {
138 let name = CString::new(path.as_ref().to_str().unwrap())?;
139 let handle_opt = NonNull::<raw::pcap_dumper_t>::new(unsafe {
140 raw::pcap_dump_open_append(self.handle.as_ptr(), name.as_ptr())
141 });
142 let handle = self
143 .check_err(handle_opt.is_some())
144 .map(|_| handle_opt.unwrap())?;
145 Ok(Savefile::from(handle))
146 }
147
148 pub fn direction(&self, direction: Direction) -> Result<(), Error> {
150 self.check_err(unsafe {
151 raw::pcap_setdirection(self.handle.as_ptr(), direction as u32 as _) == 0
152 })
153 }
154
155 pub fn next_packet(&mut self) -> Result<Packet<'_>, Error> {
166 unsafe {
167 let mut header: *mut raw::pcap_pkthdr = ptr::null_mut();
168 let mut packet: *const libc::c_uchar = ptr::null();
169 let retcode = raw::pcap_next_ex(self.handle.as_ptr(), &mut header, &mut packet);
170 match retcode {
171 i if i >= 1 => {
172 Ok(Packet::new(
174 &*(&*header as *const raw::pcap_pkthdr as *const PacketHeader),
175 slice::from_raw_parts(packet, (*header).caplen as _),
176 ))
177 }
178 0 => {
179 Err(Error::TimeoutExpired)
182 }
183 -1 => {
184 Err(self.get_err())
186 }
187 -2 => {
188 Err(Error::NoMorePackets)
191 }
192 _ => {
194 unreachable!()
196 } }
198 }
199 }
200
201 pub fn iter<C: PacketCodec>(self, codec: C) -> PacketIter<T, C> {
203 PacketIter::new(self, codec)
204 }
205
206 pub fn for_each<F>(&mut self, count: Option<usize>, handler: F) -> Result<(), Error>
207 where
208 F: FnMut(Packet),
209 {
210 let cnt = match count {
211 Some(0) => return Ok(()),
214 Some(cnt) => cnt
215 .try_into()
216 .expect("count of packets to read cannot exceed c_int::MAX"),
217 None => -1,
218 };
219
220 let mut handler = HandlerFn {
221 func: AssertUnwindSafe(handler),
222 panic_payload: None,
223 handle: self.handle.clone(),
224 };
225 let return_code = unsafe {
226 raw::pcap_loop(
227 self.handle.as_ptr(),
228 cnt,
229 HandlerFn::<F>::callback,
230 &mut handler as *mut HandlerFn<AssertUnwindSafe<F>> as *mut u8,
231 )
232 };
233 if let Some(e) = handler.panic_payload {
234 resume_unwind(e);
235 }
236 self.check_err(return_code == 0)
237 }
238
239 pub fn breakloop_handle(&mut self) -> BreakLoop {
266 BreakLoop {
267 handle: Arc::<PcapHandle>::downgrade(&self.handle),
268 }
269 }
270
271 pub fn compile(&self, program: &str, optimize: bool) -> Result<BpfProgram, Error> {
273 let program = CString::new(program)?;
274
275 unsafe {
276 let mut bpf_program: raw::bpf_program = mem::zeroed();
277 let ret = raw::pcap_compile(
278 self.handle.as_ptr(),
279 &mut bpf_program,
280 program.as_ptr(),
281 optimize as libc::c_int,
282 0,
283 );
284 self.check_err(ret != -1).and(Ok(BpfProgram(bpf_program)))
285 }
286 }
287
288 pub fn filter(&mut self, program: &str, optimize: bool) -> Result<(), Error> {
294 let mut bpf_program = self.compile(program, optimize)?;
295 let ret = unsafe { raw::pcap_setfilter(self.handle.as_ptr(), &mut bpf_program.0) };
296 self.check_err(ret != -1)
297 }
298
299 pub fn stats(&mut self) -> Result<Stat, Error> {
305 unsafe {
306 let mut stats: raw::pcap_stat = mem::zeroed();
307 self.check_err(raw::pcap_stats(self.handle.as_ptr(), &mut stats) != -1)
308 .map(|_| Stat::new(stats.ps_recv, stats.ps_drop, stats.ps_ifdrop))
309 }
310 }
311}
312
313struct HandlerFn<F> {
318 func: F,
319 panic_payload: Option<Box<dyn Any + Send>>,
320 handle: Arc<PcapHandle>,
321}
322
323impl<F> HandlerFn<F>
324where
325 F: FnMut(Packet),
326{
327 extern "C" fn callback(
328 slf: *mut libc::c_uchar,
329 header: *const raw::pcap_pkthdr,
330 packet: *const libc::c_uchar,
331 ) {
332 unsafe {
333 let packet = Packet::new(
334 &*(header as *const PacketHeader),
335 slice::from_raw_parts(packet, (*header).caplen as _),
336 );
337
338 let slf = slf as *mut Self;
339 let func = &mut (*slf).func;
340 let mut func = AssertUnwindSafe(func);
341 if let Err(e) = catch_unwind(move || func(packet)) {
345 (*slf).panic_payload = Some(e);
346 raw::pcap_breakloop((*slf).handle.as_ptr());
347 }
348 }
349 }
350}
351
352impl<T: Activated> From<Capture<T>> for Capture<dyn Activated> {
353 fn from(cap: Capture<T>) -> Capture<dyn Activated> {
354 unsafe { mem::transmute(cap) }
355 }
356}
357
358pub struct BreakLoop {
364 handle: Weak<PcapHandle>,
365}
366
367unsafe impl Send for BreakLoop {}
368unsafe impl Sync for BreakLoop {}
369
370impl BreakLoop {
371 pub fn breakloop(&self) {
383 if let Some(handle) = self.handle.upgrade() {
384 unsafe { raw::pcap_breakloop(handle.as_ptr()) };
385 }
386 }
387}
388
389pub struct Savefile {
391 handle: NonNull<raw::pcap_dumper_t>,
392}
393
394unsafe impl Send for Savefile {}
398
399impl Savefile {
400 pub fn write(&mut self, packet: &Packet<'_>) {
402 unsafe {
403 raw::pcap_dump(
404 self.handle.as_ptr() as _,
405 &*(packet.header as *const PacketHeader as *const raw::pcap_pkthdr),
406 packet.data.as_ptr(),
407 );
408 }
409 }
410
411 pub fn flush(&mut self) -> Result<(), Error> {
413 if unsafe { raw::pcap_dump_flush(self.handle.as_ptr() as _) } != 0 {
414 return Err(Error::ErrnoError(errno::errno()));
415 }
416
417 Ok(())
418 }
419}
420
421impl From<NonNull<raw::pcap_dumper_t>> for Savefile {
422 fn from(handle: NonNull<raw::pcap_dumper_t>) -> Self {
423 Savefile { handle }
424 }
425}
426
427impl Drop for Savefile {
428 fn drop(&mut self) {
429 unsafe { raw::pcap_dump_close(self.handle.as_ptr()) }
430 }
431}
432
433#[repr(transparent)]
434pub struct BpfInstruction(raw::bpf_insn);
435#[repr(transparent)]
436pub struct BpfProgram(raw::bpf_program);
437
438impl BpfProgram {
439 pub fn filter(&self, buf: &[u8]) -> bool {
441 let header: raw::pcap_pkthdr = raw::pcap_pkthdr {
442 ts: libc::timeval {
443 tv_sec: 0,
444 tv_usec: 0,
445 },
446 caplen: buf.len() as u32,
447 len: buf.len() as u32,
448 };
449 unsafe { raw::pcap_offline_filter(&self.0, &header, buf.as_ptr()) > 0 }
450 }
451
452 pub fn get_instructions(&self) -> &[BpfInstruction] {
453 unsafe {
454 slice::from_raw_parts(
455 self.0.bf_insns as *const BpfInstruction,
456 self.0.bf_len as usize,
457 )
458 }
459 }
460}
461
462impl Drop for BpfProgram {
463 fn drop(&mut self) {
464 unsafe { raw::pcap_freecode(&mut self.0) }
465 }
466}
467
468impl fmt::Display for BpfInstruction {
469 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
470 write!(
471 f,
472 "{} {} {} {}",
473 self.0.code, self.0.jt, self.0.jf, self.0.k
474 )
475 }
476}
477
478unsafe impl Send for BpfProgram {}
479
480#[cfg(not(windows))]
481pub unsafe fn open_raw_fd(fd: RawFd, mode: u8) -> Result<*mut libc::FILE, Error> {
487 let mode = [mode, 0];
488 libc::fdopen(fd, mode.as_ptr() as _)
489 .as_mut()
490 .map(|f| f as _)
491 .ok_or(Error::InvalidRawFd)
492}
493
494#[cfg(test)]
496mod testmod {
497 use super::*;
498
499 pub static TS: libc::timeval = libc::timeval {
500 tv_sec: 5,
501 tv_usec: 50,
502 };
503 pub static LEN: u32 = DATA.len() as u32;
504 pub static CAPLEN: u32 = LEN;
505
506 pub static mut PKTHDR: raw::pcap_pkthdr = raw::pcap_pkthdr {
507 ts: TS,
508 caplen: CAPLEN,
509 len: LEN,
510 };
511 pub static PACKET_HEADER: PacketHeader = PacketHeader {
512 ts: TS,
513 caplen: CAPLEN,
514 len: LEN,
515 };
516
517 pub static DATA: [u8; 4] = [4, 5, 6, 7];
518 pub static PACKET: Packet = Packet {
519 header: &PACKET_HEADER,
520 data: &DATA,
521 };
522
523 pub struct NextExContext(raw::__pcap_next_ex::Context);
524 pub fn next_ex_expect(pcap: *mut raw::pcap_t) -> NextExContext {
525 let data_ptr: *const libc::c_uchar = DATA.as_ptr();
526 #[allow(unused_unsafe)] let pkthdr_ptr: *mut raw::pcap_pkthdr = unsafe { std::ptr::addr_of_mut!(PKTHDR) };
528
529 let ctx = raw::pcap_next_ex_context();
530 ctx.checkpoint();
531 ctx.expect()
532 .withf_st(move |arg1, _, _| *arg1 == pcap)
533 .return_once_st(move |_, arg2, arg3| {
534 unsafe {
535 *arg2 = pkthdr_ptr;
536 *arg3 = data_ptr;
537 }
538 CAPLEN as i32
539 });
540
541 NextExContext(ctx)
542 }
543}
544#[cfg(test)]
547mod tests {
548 use crate::{
549 capture::{
550 activated::testmod::{next_ex_expect, PACKET},
551 testmod::test_capture,
552 Active, Capture, Offline,
553 },
554 raw::testmod::{as_pcap_dumper_t, as_pcap_t, geterr_expect, RAWMTX},
555 };
556
557 use super::*;
558
559 #[test]
560 fn test_list_datalinks() {
561 let _m = RAWMTX.lock();
562
563 let mut value: isize = 777;
564 let pcap = as_pcap_t(&mut value);
565
566 let test_capture = test_capture::<Active>(pcap);
567 let capture: Capture<dyn Activated> = test_capture.capture.into();
568
569 let ctx = raw::pcap_list_datalinks_context();
570 ctx.expect()
571 .withf_st(move |arg1, _| *arg1 == pcap)
572 .return_once_st(|_, _| 0);
573
574 let ctx = raw::pcap_free_datalinks_context();
575 ctx.expect().return_once(|_| {});
576
577 let _err = geterr_expect(pcap);
578
579 let result = capture.list_datalinks();
580 assert!(result.is_err());
581
582 let mut datalinks: [i32; 4] = [0, 1, 2, 3];
583 let links: *mut i32 = datalinks.as_mut_ptr();
584 let len = datalinks.len();
585
586 let ctx = raw::pcap_list_datalinks_context();
587 ctx.checkpoint();
588 ctx.expect()
589 .withf_st(move |arg1, _| *arg1 == pcap)
590 .return_once_st(move |_, arg2| {
591 unsafe { *arg2 = links };
592 len as i32
593 });
594
595 let ctx = raw::pcap_free_datalinks_context();
596 ctx.checkpoint();
597 ctx.expect().return_once(|_| {});
598
599 let pcap_datalinks = capture.list_datalinks().unwrap();
600 assert_eq!(
601 pcap_datalinks,
602 datalinks.iter().cloned().map(Linktype).collect::<Vec<_>>()
603 );
604 }
605
606 #[test]
607 fn test_set_datalink() {
608 let _m = RAWMTX.lock();
609
610 let mut value: isize = 777;
611 let pcap = as_pcap_t(&mut value);
612
613 let test_capture = test_capture::<Active>(pcap);
614 let mut capture: Capture<dyn Activated> = test_capture.capture.into();
615
616 let ctx = raw::pcap_set_datalink_context();
617 ctx.expect()
618 .withf_st(move |arg1, _| *arg1 == pcap)
619 .return_once(|_, _| 0);
620
621 let result = capture.set_datalink(Linktype::ETHERNET);
622 assert!(result.is_ok());
623
624 let ctx = raw::pcap_set_datalink_context();
625 ctx.checkpoint();
626 ctx.expect()
627 .withf_st(move |arg1, _| *arg1 == pcap)
628 .return_once(|_, _| -1);
629
630 let _err = geterr_expect(pcap);
631
632 let result = capture.set_datalink(Linktype::ETHERNET);
633 assert!(result.is_err());
634 }
635
636 #[test]
637 fn test_get_datalink() {
638 let _m = RAWMTX.lock();
639
640 let mut value: isize = 777;
641 let pcap = as_pcap_t(&mut value);
642
643 let test_capture = test_capture::<Active>(pcap);
644 let capture: Capture<dyn Activated> = test_capture.capture.into();
645
646 let ctx = raw::pcap_datalink_context();
647 ctx.expect()
648 .withf_st(move |arg1| *arg1 == pcap)
649 .return_once(|_| 1);
650
651 let linktype = capture.get_datalink();
652 assert_eq!(linktype, Linktype::ETHERNET);
653 }
654
655 #[test]
656 fn unify_activated() {
657 #![allow(dead_code)]
658 fn test1() -> Capture<Active> {
659 panic!();
660 }
661
662 fn test2() -> Capture<Offline> {
663 panic!();
664 }
665
666 fn maybe(a: bool) -> Capture<dyn Activated> {
667 if a {
668 test1().into()
669 } else {
670 test2().into()
671 }
672 }
673
674 fn also_maybe(a: &mut Capture<dyn Activated>) {
675 a.filter("whatever filter string, this won't be run anyway", false)
676 .unwrap();
677 }
678 }
679
680 #[test]
681 fn test_breakloop_capture_dropped() {
682 let _m = RAWMTX.lock();
683
684 let mut value: isize = 1234;
685 let pcap = as_pcap_t(&mut value);
686
687 let test_capture = test_capture::<Active>(pcap);
688 let mut capture: Capture<dyn Activated> = test_capture.capture.into();
689
690 let ctx = raw::pcap_breakloop_context();
691 ctx.expect()
692 .withf_st(move |h| *h == pcap)
693 .return_const(())
694 .times(1);
695
696 let break_handle = capture.breakloop_handle();
697
698 break_handle.breakloop();
699
700 drop(capture);
701
702 break_handle.breakloop(); }
704
705 #[test]
706 fn test_savefile() {
707 let _m = RAWMTX.lock();
708
709 let mut value: isize = 777;
710 let pcap = as_pcap_t(&mut value);
711
712 let mut value: isize = 888;
713 let pcap_dumper = as_pcap_dumper_t(&mut value);
714
715 let test_capture = test_capture::<Offline>(pcap);
716 let capture = test_capture.capture;
717
718 let ctx = raw::pcap_dump_open_context();
719 ctx.expect()
720 .withf_st(move |arg1, _| *arg1 == pcap)
721 .return_once_st(move |_, _| pcap_dumper);
722
723 let ctx = raw::pcap_dump_close_context();
724 ctx.expect()
725 .withf_st(move |arg1| *arg1 == pcap_dumper)
726 .return_once(|_| {});
727
728 let result = capture.savefile("path/to/nowhere");
729 assert!(result.is_ok());
730 }
731
732 #[test]
733 #[cfg(libpcap_1_7_2)]
734 fn test_savefile_append() {
735 let _m = RAWMTX.lock();
736
737 let mut value: isize = 777;
738 let pcap = as_pcap_t(&mut value);
739
740 let mut value: isize = 888;
741 let pcap_dumper = as_pcap_dumper_t(&mut value);
742
743 let test_capture = test_capture::<Offline>(pcap);
744 let capture = test_capture.capture;
745
746 let ctx = raw::pcap_dump_open_append_context();
747 ctx.expect()
748 .withf_st(move |arg1, _| *arg1 == pcap)
749 .return_once_st(move |_, _| pcap_dumper);
750
751 let ctx = raw::pcap_dump_close_context();
752 ctx.expect()
753 .withf_st(move |arg1| *arg1 == pcap_dumper)
754 .return_once(|_| {});
755
756 let result = capture.savefile_append("path/to/nowhere");
757 assert!(result.is_ok());
758 }
759
760 #[test]
761 fn test_savefile_error() {
762 let _m = RAWMTX.lock();
763
764 let mut value: isize = 777;
765 let pcap = as_pcap_t(&mut value);
766
767 let test_capture = test_capture::<Offline>(pcap);
768 let capture = test_capture.capture;
769
770 let ctx = raw::pcap_dump_open_context();
771 ctx.expect()
772 .withf_st(move |arg1, _| *arg1 == pcap)
773 .return_once(|_, _| std::ptr::null_mut());
774
775 let _err = geterr_expect(pcap);
776
777 let result = capture.savefile("path/to/nowhere");
778 assert!(result.is_err());
779 }
780
781 #[test]
782 #[cfg(libpcap_1_7_2)]
783 fn test_savefile_append_error() {
784 let _m = RAWMTX.lock();
785
786 let mut value: isize = 777;
787 let pcap = as_pcap_t(&mut value);
788
789 let test_capture = test_capture::<Offline>(pcap);
790 let capture = test_capture.capture;
791
792 let ctx = raw::pcap_dump_open_append_context();
793 ctx.expect()
794 .withf_st(move |arg1, _| *arg1 == pcap)
795 .return_once(|_, _| std::ptr::null_mut());
796
797 let _err = geterr_expect(pcap);
798
799 let result = capture.savefile_append("path/to/nowhere");
800 assert!(result.is_err());
801 }
802
803 #[test]
804 fn test_savefile_ops() {
805 let _m = RAWMTX.lock();
806
807 let mut value: isize = 888;
808 let pcap_dumper = as_pcap_dumper_t(&mut value);
809
810 let ctx = raw::pcap_dump_close_context();
811 ctx.expect()
812 .withf_st(move |arg1| *arg1 == pcap_dumper)
813 .return_once(|_| {});
814
815 let mut savefile = Savefile {
816 handle: NonNull::new(pcap_dumper).unwrap(),
817 };
818
819 let ctx = raw::pcap_dump_context();
820 ctx.expect()
821 .withf_st(move |arg1, _, _| *arg1 == pcap_dumper as _)
822 .return_once(|_, _, _| {});
823
824 savefile.write(&PACKET);
825
826 let ctx = raw::pcap_dump_flush_context();
827 ctx.expect()
828 .withf_st(move |arg1| *arg1 == pcap_dumper)
829 .return_once(|_| 0);
830
831 let result = savefile.flush();
832 assert!(result.is_ok());
833
834 let ctx = raw::pcap_dump_flush_context();
835 ctx.checkpoint();
836 ctx.expect()
837 .withf_st(move |arg1| *arg1 == pcap_dumper)
838 .return_once(|_| -1);
839
840 let result = savefile.flush();
841 assert!(result.is_err());
842 }
843
844 #[test]
845 fn test_direction() {
846 let _m = RAWMTX.lock();
847
848 let mut value: isize = 777;
849 let pcap = as_pcap_t(&mut value);
850
851 let test_capture = test_capture::<Active>(pcap);
852 let capture = test_capture.capture;
853
854 let ctx = raw::pcap_setdirection_context();
855 ctx.expect()
856 .withf_st(move |arg1, arg2| (*arg1 == pcap) && (*arg2 == raw::PCAP_D_OUT))
857 .return_once(|_, _| 0);
858
859 let result = capture.direction(Direction::Out);
860 assert!(result.is_ok());
861
862 let ctx = raw::pcap_setdirection_context();
863 ctx.checkpoint();
864 ctx.expect()
865 .withf_st(move |arg1, arg2| (*arg1 == pcap) && (*arg2 == raw::PCAP_D_OUT))
866 .return_once(|_, _| -1);
867
868 let _err = geterr_expect(pcap);
869
870 let result = capture.direction(Direction::Out);
871 assert!(result.is_err());
872
873 assert_ne!(Direction::In, Direction::InOut);
875 assert_ne!(Direction::In, Direction::Out);
876 assert_ne!(Direction::InOut, Direction::Out);
877 }
878
879 #[test]
880 fn test_next_packet() {
881 let _m = RAWMTX.lock();
882
883 let mut value: isize = 777;
884 let pcap = as_pcap_t(&mut value);
885
886 let test_capture = test_capture::<Active>(pcap);
887 let mut capture = test_capture.capture;
888
889 let _nxt = next_ex_expect(pcap);
890
891 let next_packet = capture.next_packet().unwrap();
892 assert_eq!(next_packet, PACKET);
893 }
894
895 #[test]
896 fn test_next_packet_timeout() {
897 let _m = RAWMTX.lock();
898
899 let mut value: isize = 777;
900 let pcap = as_pcap_t(&mut value);
901
902 let test_capture = test_capture::<Active>(pcap);
903 let mut capture = test_capture.capture;
904
905 let ctx = raw::pcap_next_ex_context();
906 ctx.expect()
907 .withf_st(move |arg1, _, _| *arg1 == pcap)
908 .return_once_st(move |_, _, _| 0);
909
910 let err = capture.next_packet().unwrap_err();
911 assert_eq!(err, Error::TimeoutExpired);
912 }
913
914 #[test]
915 fn test_next_packet_read_error() {
916 let _m = RAWMTX.lock();
917
918 let mut value: isize = 777;
919 let pcap = as_pcap_t(&mut value);
920
921 let test_capture = test_capture::<Active>(pcap);
922 let mut capture = test_capture.capture;
923
924 let ctx = raw::pcap_next_ex_context();
925 ctx.expect()
926 .withf_st(move |arg1, _, _| *arg1 == pcap)
927 .return_once_st(move |_, _, _| -1);
928
929 let _err = geterr_expect(pcap);
930
931 let result = capture.next_packet();
932 assert!(result.is_err());
933 }
934
935 #[test]
936 fn test_next_packet_no_more_packets() {
937 let _m = RAWMTX.lock();
938
939 let mut value: isize = 777;
940 let pcap = as_pcap_t(&mut value);
941
942 let test_capture = test_capture::<Offline>(pcap);
943 let mut capture = test_capture.capture;
944
945 let ctx = raw::pcap_next_ex_context();
946 ctx.expect()
947 .withf_st(move |arg1, _, _| *arg1 == pcap)
948 .return_once_st(move |_, _, _| -2);
949
950 let err = capture.next_packet().unwrap_err();
951 assert_eq!(err, Error::NoMorePackets);
952 }
953
954 #[test]
955 fn test_compile() {
956 let _m = RAWMTX.lock();
957
958 let mut value: isize = 777;
959 let pcap = as_pcap_t(&mut value);
960
961 let test_capture = test_capture::<Active>(pcap);
962 let capture = test_capture.capture;
963
964 let ctx = raw::pcap_compile_context();
965 ctx.expect()
966 .withf_st(move |arg1, _, _, _, _| *arg1 == pcap)
967 .return_once(|_, _, _, _, _| -1);
968
969 let _err = geterr_expect(pcap);
970
971 let ctx = raw::pcap_freecode_context();
972 ctx.expect().return_once(|_| {});
973
974 let result = capture.compile("some bpf program", false);
975 assert!(result.is_err());
976
977 let ctx = raw::pcap_compile_context();
978 ctx.checkpoint();
979 ctx.expect()
980 .withf_st(move |arg1, _, _, _, _| *arg1 == pcap)
981 .return_once(|_, _, _, _, _| 0);
982
983 let ctx = raw::pcap_freecode_context();
984 ctx.checkpoint();
985 ctx.expect().return_once(|_| {});
986
987 let result = capture.compile("some bpf program", false);
988 assert!(result.is_ok());
989 }
990
991 #[test]
992 fn test_filter() {
993 let _m = RAWMTX.lock();
994
995 let mut value: isize = 777;
996 let pcap = as_pcap_t(&mut value);
997
998 let test_capture = test_capture::<Active>(pcap);
999 let mut capture = test_capture.capture;
1000
1001 let ctx = raw::pcap_compile_context();
1002 ctx.expect()
1003 .withf_st(move |arg1, _, _, _, _| *arg1 == pcap)
1004 .return_once(|_, _, _, _, _| 0);
1005
1006 let ctx = raw::pcap_setfilter_context();
1007 ctx.expect()
1008 .withf_st(move |arg1, _| *arg1 == pcap)
1009 .return_once(|_, _| -1);
1010
1011 let _err = geterr_expect(pcap);
1012
1013 let ctx = raw::pcap_freecode_context();
1014 ctx.expect().return_once(|_| {});
1015
1016 let result = capture.filter("some bpf program", false);
1017 assert!(result.is_err());
1018
1019 let ctx = raw::pcap_compile_context();
1020 ctx.checkpoint();
1021 ctx.expect()
1022 .withf_st(move |arg1, _, _, _, _| *arg1 == pcap)
1023 .return_once(|_, _, _, _, _| 0);
1024
1025 let ctx = raw::pcap_setfilter_context();
1026 ctx.checkpoint();
1027 ctx.expect()
1028 .withf_st(move |arg1, _| *arg1 == pcap)
1029 .return_once(|_, _| 0);
1030
1031 let ctx = raw::pcap_freecode_context();
1032 ctx.checkpoint();
1033 ctx.expect().return_once(|_| {});
1034
1035 let result = capture.compile("some bpf program", false);
1036 assert!(result.is_ok());
1037 }
1038
1039 #[test]
1040 fn test_stats() {
1041 let _m = RAWMTX.lock();
1042
1043 let mut value: isize = 777;
1044 let pcap = as_pcap_t(&mut value);
1045
1046 let test_capture = test_capture::<Active>(pcap);
1047 let mut capture = test_capture.capture;
1048
1049 let stat = raw::pcap_stat {
1050 ps_recv: 1,
1051 ps_drop: 2,
1052 ps_ifdrop: 3,
1053 };
1054
1055 let ctx = raw::pcap_stats_context();
1056 ctx.expect()
1057 .withf_st(move |arg1, _| *arg1 == pcap)
1058 .return_once_st(move |_, arg2| {
1059 unsafe { *arg2 = stat };
1060 0
1061 });
1062
1063 let stats = capture.stats().unwrap();
1064 assert_eq!(stats, Stat::new(stat.ps_recv, stat.ps_drop, stat.ps_ifdrop));
1065
1066 let ctx = raw::pcap_stats_context();
1067 ctx.checkpoint();
1068 ctx.expect()
1069 .withf_st(move |arg1, _| *arg1 == pcap)
1070 .return_once_st(move |_, _| -1);
1071
1072 let _err = geterr_expect(pcap);
1073
1074 let result = capture.stats();
1075 assert!(result.is_err());
1076 }
1077
1078 #[test]
1079 fn test_bpf_instruction_display() {
1080 let instr = BpfInstruction(raw::bpf_insn {
1081 code: 1,
1082 jt: 2,
1083 jf: 3,
1084 k: 4,
1085 });
1086 assert_eq!(format!("{instr}"), "1 2 3 4");
1087 }
1088
1089 #[test]
1090 fn read_packet_via_pcap_loop() {
1091 let _m = RAWMTX.lock();
1092
1093 let mut value: isize = 777;
1094 let pcap = as_pcap_t(&mut value);
1095
1096 let test_capture = test_capture::<Active>(pcap);
1097 let mut capture: Capture<dyn Activated> = test_capture.capture.into();
1098
1099 let ctx = raw::pcap_loop_context();
1100 ctx.expect()
1101 .withf_st(move |arg1, cnt, _, _| *arg1 == pcap && *cnt == -1)
1102 .return_once_st(move |_, _, func, data| {
1103 let header = raw::pcap_pkthdr {
1104 ts: libc::timeval {
1105 tv_sec: 0,
1106 tv_usec: 0,
1107 },
1108 caplen: 0,
1109 len: 0,
1110 };
1111 let packet_data = &[];
1112 func(data, &header, packet_data.as_ptr());
1113 0
1114 });
1115
1116 let mut packets = 0;
1117 capture
1118 .for_each(None, |_| {
1119 packets += 1;
1120 })
1121 .unwrap();
1122 assert_eq!(packets, 1);
1123 }
1124
1125 #[test]
1126 #[should_panic = "panic in callback"]
1127 fn panic_in_pcap_loop() {
1128 let _m = RAWMTX.lock();
1129
1130 let mut value: isize = 777;
1131 let pcap = as_pcap_t(&mut value);
1132
1133 let test_capture = test_capture::<Active>(pcap);
1134 let mut capture: Capture<dyn Activated> = test_capture.capture.into();
1135
1136 let ctx = raw::pcap_loop_context();
1137 ctx.expect()
1138 .withf_st(move |arg1, cnt, _, _| *arg1 == pcap && *cnt == -1)
1139 .return_once_st(move |_, _, func, data| {
1140 let header = raw::pcap_pkthdr {
1141 ts: libc::timeval {
1142 tv_sec: 0,
1143 tv_usec: 0,
1144 },
1145 caplen: 0,
1146 len: 0,
1147 };
1148 let packet_data = &[];
1149 func(data, &header, packet_data.as_ptr());
1150 0
1151 });
1152
1153 let ctx = raw::pcap_breakloop_context();
1154 ctx.expect()
1155 .withf_st(move |arg1| *arg1 == pcap)
1156 .return_once_st(move |_| {});
1157
1158 capture
1159 .for_each(None, |_| panic!("panic in callback"))
1160 .unwrap();
1161 }
1162
1163 #[test]
1164 fn for_each_with_count() {
1165 let _m = RAWMTX.lock();
1166
1167 let mut value: isize = 777;
1168 let pcap = as_pcap_t(&mut value);
1169
1170 let test_capture = test_capture::<Active>(pcap);
1171 let mut capture: Capture<dyn Activated> = test_capture.capture.into();
1172
1173 let ctx = raw::pcap_loop_context();
1174 ctx.expect()
1175 .withf_st(move |arg1, cnt, _, _| *arg1 == pcap && *cnt == 2)
1176 .return_once_st(move |_, _, func, data| {
1177 let header = raw::pcap_pkthdr {
1178 ts: libc::timeval {
1179 tv_sec: 0,
1180 tv_usec: 0,
1181 },
1182 caplen: 0,
1183 len: 0,
1184 };
1185 let packet_data = &[];
1186 func(data, &header, packet_data.as_ptr());
1187 func(data, &header, packet_data.as_ptr());
1188 0
1189 });
1190
1191 let mut packets = 0;
1192 capture
1193 .for_each(Some(2), |_| {
1194 packets += 1;
1195 })
1196 .unwrap();
1197 assert_eq!(packets, 2);
1198 }
1199
1200 #[test]
1201 fn for_each_with_count_0() {
1202 let _m = RAWMTX.lock();
1203
1204 let mut value: isize = 777;
1205 let pcap = as_pcap_t(&mut value);
1206
1207 let test_capture = test_capture::<Active>(pcap);
1208 let mut capture: Capture<dyn Activated> = test_capture.capture.into();
1209
1210 let mut packets = 0;
1211 capture
1212 .for_each(Some(0), |_| {
1213 packets += 1;
1214 })
1215 .unwrap();
1216 assert_eq!(packets, 0);
1217 }
1218}