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