Skip to main content

pcapture/
lib.rs

1use bitcode::Decode;
2use bitcode::Encode;
3#[cfg(feature = "libpnet")]
4use pnet::datalink;
5#[cfg(feature = "libpnet")]
6use pnet::datalink::Channel::Ethernet;
7#[cfg(feature = "libpnet")]
8use pnet::datalink::ChannelType;
9#[cfg(feature = "libpnet")]
10use pnet::datalink::Config;
11#[cfg(feature = "libpnet")]
12use pnet::datalink::DataLinkReceiver;
13#[cfg(feature = "libpnet")]
14use pnet::datalink::NetworkInterface;
15use serde::Deserialize;
16use serde::Serialize;
17#[cfg(feature = "libpnet")]
18use std::io::ErrorKind;
19#[cfg(any(feature = "libpcap", feature = "libpnet"))]
20use std::result;
21#[cfg(feature = "libpnet")]
22use std::time::Duration;
23#[cfg(feature = "libpnet")]
24use std::time::SystemTime;
25#[cfg(feature = "libpnet")]
26use std::time::UNIX_EPOCH;
27
28pub mod error;
29#[cfg(any(feature = "libpcap", feature = "libpnet"))]
30pub mod filter;
31pub mod fs;
32pub mod libpcap;
33
34#[cfg(feature = "libpnet")]
35use crate::filter::Filter;
36#[cfg(any(feature = "libpcap", feature = "libpnet"))]
37use error::PcaptureError;
38#[cfg(all(unix, feature = "libpcap"))]
39use libpcap::Addresses;
40#[cfg(all(unix, feature = "libpcap"))]
41use libpcap::Libpcap;
42
43#[cfg(any(
44    all(unix, any(feature = "libpcap", feature = "libpnet")),
45    all(windows, feature = "libpnet"),
46))]
47#[cfg(feature = "pcap")]
48pub use fs::pcap::PacketRecord;
49#[cfg(any(
50    all(unix, any(feature = "libpcap", feature = "libpnet")),
51    all(windows, feature = "libpnet"),
52))]
53#[cfg(feature = "pcap")]
54pub use fs::pcap::Pcap;
55#[cfg(any(
56    all(unix, any(feature = "libpcap", feature = "libpnet")),
57    all(windows, feature = "libpnet"),
58))]
59#[cfg(feature = "pcapng")]
60pub use fs::pcapng::PcapNg;
61
62#[cfg(any(
63    all(unix, any(feature = "libpcap", feature = "libpnet")),
64    all(windows, feature = "libpnet"),
65))]
66#[cfg(feature = "pcapng")]
67use fs::pcapng::EnhancedPacketBlock;
68#[cfg(any(
69    all(unix, any(feature = "libpcap", feature = "libpnet")),
70    all(windows, feature = "libpnet"),
71))]
72#[cfg(feature = "pcapng")]
73use fs::pcapng::GeneralBlock;
74
75#[cfg(any(
76    all(unix, any(feature = "libpcap", feature = "libpnet")),
77    all(windows, feature = "libpnet"),
78))]
79const DEFAULT_BUFFER_SIZE: usize = 8 * 1024 * 1024; // 8MB
80#[cfg(feature = "libpnet")]
81const DEFAULT_TIMEOUT: f32 = 0.1;
82
83#[cfg(all(unix, feature = "libpcap"))]
84const DEFAULT_TIMEOUT_MS: i32 = 1000;
85#[cfg(any(
86    all(unix, any(feature = "libpcap", feature = "libpnet")),
87    all(windows, feature = "libpnet"),
88))]
89const DETAULT_SNAPLEN: usize = 65535;
90
91#[cfg(any(feature = "libpcap", feature = "libpnet"))]
92pub type Result<T, E = PcaptureError> = result::Result<T, E>;
93
94#[derive(Debug, Clone)]
95pub struct PacketData<'a> {
96    pub data: &'a [u8],
97    #[cfg(feature = "pcapng")]
98    pub ts_high: u32,
99    #[cfg(feature = "pcapng")]
100    pub ts_low: u32,
101    #[cfg(feature = "pcap")]
102    pub ts_sec: u32,
103    #[cfg(feature = "pcap")]
104    pub ts_usec: u32,
105}
106
107#[derive(Debug, Clone, Copy, Serialize, Deserialize, Encode, Decode)]
108pub enum PcapByteOrder {
109    BigEndian,
110    LittleEndian,
111    /// LittleEndian
112    WiresharkDefault,
113}
114
115#[cfg(feature = "libpnet")]
116#[derive(Debug, Clone)]
117pub struct Device(pub NetworkInterface);
118
119#[cfg(all(unix, feature = "libpcap"))]
120#[derive(Debug, Clone)]
121pub struct Device {
122    // Interface name.
123    pub name: String,
124    /// Interface description.
125    pub description: Option<String>,
126    // All ip address (include IPv4, IPv6 and Mac if exists).
127    pub addresses: Vec<Addresses>,
128}
129
130#[cfg(any(feature = "libpnet", feature = "libpcap"))]
131impl Device {
132    /// Returns all interfaces in the system.
133    /// ```rust
134    /// use pcapture::Device;
135    ///
136    /// fn main() {
137    ///     let devices = Device::list().unwrap();
138    ///     for device in devices {
139    ///         println!("device name: {}", device.0.name);
140    ///     }
141    /// }
142    /// ```
143    #[cfg(feature = "libpnet")]
144    pub fn list() -> Result<Vec<Device>, PcaptureError> {
145        let nis = datalink::interfaces();
146        let mut ret = Vec::new();
147        for ni in nis {
148            let device = Device(ni);
149            ret.push(device);
150        }
151        Ok(ret)
152    }
153    #[cfg(feature = "libpcap")]
154    pub fn list() -> Result<Vec<Device>, PcaptureError> {
155        Libpcap::devices()
156    }
157}
158
159#[cfg(any(
160    all(unix, any(feature = "libpcap", feature = "libpnet")),
161    all(windows, feature = "libpnet"),
162))]
163#[derive(Debug, Clone)]
164pub struct Iface {
165    pub id: u32,
166    pub device: Device,
167}
168
169#[cfg(feature = "libpnet")]
170pub struct Capture {
171    pub name: String,
172    buffer_size: usize,
173    timeout: Duration,
174    snaplen: usize,
175    promisc: bool,
176    // filter
177    filter: Option<Filter>,
178    // store the all system ifaces here
179    ifaces: Vec<Iface>,
180    // this is the current used interface
181    iface_id: u32,
182    // inner use
183    pnet_rx: Option<Box<dyn DataLinkReceiver>>,
184}
185
186#[cfg(feature = "libpnet")]
187impl Capture {
188    /// A simple example showing how to capture packets and save them in pcapng format.
189    /// ```rust
190    /// use pcapture::Capture;
191    /// use pcapture::PcapByteOrder;
192    ///
193    /// fn main() {
194    ///     let path = "test.pcapng";
195    ///     let pbo = PcapByteOrder::WiresharkDefault;
196    ///     // BPF syntax filter
197    ///     let filter_str = "icmp and host 192.168.5.2";
198    ///
199    ///     // device name 'any' is not supported due to the performance consider.
200    ///     let mut cap = Capture::new("ens33").unwrap();
201    ///     cap.filter(filter_str).unwrap();
202    ///     let mut pcapng = cap.gen_pcapng_header(pbo).unwrap();
203    ///     for _ in 0..5 {
204    ///         let block = cap.next_as_pcapng().unwrap();
205    ///         pcapng.append(block);
206    ///     }
207    ///     pcapng.write_all(path).unwrap();
208    ///     
209    /// }
210    /// ```
211    pub fn new(name: &str) -> Result<Self, PcaptureError> {
212        let interfaces = datalink::interfaces();
213        let timeout = Duration::from_secs_f32(DEFAULT_TIMEOUT);
214        let buffer_size = DEFAULT_BUFFER_SIZE;
215        let snaplen = DETAULT_SNAPLEN;
216        let promisc = true;
217
218        let mut ifaces = Vec::new();
219        let mut i = 0;
220        let mut iface_id = 0;
221        let mut interface_exists = false;
222        for interface in interfaces {
223            if interface.name == name {
224                iface_id = i;
225                interface_exists = true;
226            }
227            let iface = Iface {
228                id: i as u32,
229                device: Device(interface),
230            };
231            ifaces.push(iface);
232            i += 1;
233        }
234
235        if !interface_exists {
236            let mut v = Vec::new();
237            for iface in &ifaces {
238                let name = &iface.device.0.name;
239                let description = &iface.device.0.description;
240
241                if description.len() == 0 {
242                    v.push(format!("{}", name));
243                } else {
244                    v.push(format!("{} ({})", name, description));
245                }
246            }
247            let available_interface = v.join(", ");
248
249            return Err(PcaptureError::InterfaceNotFound {
250                name: name.to_string(),
251                available_interface,
252            });
253        }
254
255        let config = Config {
256            write_buffer_size: buffer_size, // use a bigger enough value
257            read_buffer_size: buffer_size,  // use a bigger enough value
258            read_timeout: Some(timeout),
259            write_timeout: Some(timeout),
260            channel_type: ChannelType::Layer2,
261            bpf_fd_attempts: 1000,
262            linux_fanout: None,
263            promiscuous: promisc,
264            socket_fd: None,
265        };
266
267        // find the target interface and listen
268        let iface = &ifaces[iface_id as usize];
269        // only recv and no send
270        let (_pnet_tx, pnet_rx) = match datalink::channel(&iface.device.0, config) {
271            Ok(Ethernet(tx, rx)) => (tx, rx),
272            Ok(_) => return Err(PcaptureError::UnhandledChannelType),
273            Err(e) => return Err(PcaptureError::UnableCreateChannel { e: e.to_string() }),
274        };
275
276        Ok(Capture {
277            name: name.to_string(),
278            buffer_size,
279            timeout,
280            snaplen,
281            promisc,
282            ifaces,
283            iface_id,
284            filter: None,
285            pnet_rx: Some(pnet_rx),
286        })
287    }
288    /// Generate pcap format header.
289    #[cfg(feature = "pcap")]
290    pub fn gen_pcap_header(&self, pbo: PcapByteOrder) -> Result<Pcap, PcaptureError> {
291        let pcap = Pcap::new(&self.name, pbo);
292        Ok(pcap)
293    }
294    /// Generate pcapng format header.
295    #[cfg(feature = "pcapng")]
296    pub fn gen_pcapng_header(&self, pbo: PcapByteOrder) -> Result<PcapNg, PcaptureError> {
297        let pcapng = PcapNg::new(&self.ifaces, pbo);
298        Ok(pcapng)
299    }
300    /// Set the buffer size.
301    pub fn set_buffer_size(&mut self, buffer_size: usize) {
302        self.buffer_size = buffer_size;
303        // set pnet_rx none means needs regenerate config and pnext_rx next time
304        self.pnet_rx = None;
305    }
306    /// Get the buffer size.
307    pub fn get_buffer_size(&self) -> usize {
308        self.buffer_size
309    }
310    /// Set timeout (as sec).
311    pub fn set_timeout(&mut self, timeout: f32) {
312        let timeout_fix = Duration::from_secs_f32(timeout);
313        self.timeout = timeout_fix;
314        // set pnet_rx none means needs regenerate config and pnext_rx next time
315        self.pnet_rx = None;
316    }
317    /// Get the timeout (as sec).
318    pub fn get_timeout(&self) -> f32 {
319        self.timeout.as_secs_f32()
320    }
321    /// Set promiscuous mode.
322    pub fn set_promiscuous(&mut self, promiscuous: bool) {
323        self.promisc = promiscuous;
324        // set pnet_rx none means needs regenerate config and pnext_rx next time
325        self.pnet_rx = None;
326    }
327    /// Get promiscuous mode.
328    pub fn get_promiscuous(&self) -> bool {
329        self.promisc
330    }
331    /// Set snaplen value.
332    pub fn set_snaplen(&mut self, snaplen: usize) {
333        self.snaplen = snaplen;
334        // set pnet_rx none means needs regenerate config and pnext_rx next time
335        self.pnet_rx = None;
336    }
337    /// Get snaplen value.
338    pub fn get_snaplen(&self) -> usize {
339        self.snaplen
340    }
341    /// Set filter with pcapture syntax.
342    pub fn set_filter(&mut self, filter: &str) -> Result<(), PcaptureError> {
343        let filter = Filter::parser(filter)?;
344        self.filter = filter;
345        // set pnet_rx none means needs regenerate config and pnext_rx next time
346        self.pnet_rx = None;
347        Ok(())
348    }
349    /// Get current filter.
350    pub fn get_filter(&self) -> Option<String> {
351        if let Some(filter) = &self.filter {
352            Some(filter.input_str.to_string())
353        } else {
354            None
355        }
356    }
357    /// Very low level next return call, no filter can be applied.
358    pub fn next(&'_ mut self) -> Result<PacketData<'_>, PcaptureError> {
359        if self.pnet_rx.is_none() {
360            let config = Config {
361                write_buffer_size: self.buffer_size, // use a bigger enough value
362                read_buffer_size: self.buffer_size,  // use a bigger enough value
363                read_timeout: Some(self.timeout),
364                write_timeout: Some(self.timeout),
365                channel_type: ChannelType::Layer2,
366                bpf_fd_attempts: 1000,
367                linux_fanout: None,
368                promiscuous: self.promisc,
369                socket_fd: None,
370            };
371            let iface = &self.ifaces[self.iface_id as usize];
372            let (_pnet_tx, pnet_rx) = match datalink::channel(&iface.device.0, config) {
373                Ok(Ethernet(tx, rx)) => (tx, rx),
374                Ok(_) => return Err(PcaptureError::UnhandledChannelType),
375                Err(e) => return Err(PcaptureError::UnableCreateChannel { e: e.to_string() }),
376            };
377
378            self.pnet_rx = Some(pnet_rx);
379        }
380
381        if let Some(pnet_rx) = &mut self.pnet_rx {
382            let data = pnet_rx.next()?; // sometimes here will return timeout error, and it should be ignore
383            let now = SystemTime::now().duration_since(UNIX_EPOCH)?;
384
385            #[cfg(feature = "pcap")]
386            let ts_sec = now.as_secs() as u32;
387            #[cfg(feature = "pcap")]
388            let ts_usec = now.subsec_micros();
389
390            #[cfg(feature = "pcapng")]
391            let ts64: u64 = now.as_secs() * 1_000_000 + now.subsec_micros() as u64;
392            #[cfg(feature = "pcapng")]
393            let ts_high = (ts64 >> 32) as u32;
394            #[cfg(feature = "pcapng")]
395            let ts_low = (ts64 & 0xFFFF_FFFF) as u32;
396
397            let packet_data = PacketData {
398                data,
399                #[cfg(feature = "pcap")]
400                ts_sec,
401                #[cfg(feature = "pcap")]
402                ts_usec,
403                #[cfg(feature = "pcapng")]
404                ts_high,
405                #[cfg(feature = "pcapng")]
406                ts_low,
407            };
408            Ok(packet_data)
409        } else {
410            unreachable!("pnet_rx must have value")
411        }
412    }
413    /// Capture the packets as raw format.
414    /// ```rust
415    /// use pcapture::Capture;
416    ///
417    /// fn main() {
418    ///     let mut packets = Vec::new();
419    ///     let mut cap = Capture::new("ens33").unwrap();
420    ///     for _ in 0..5 {
421    ///         let packet_raw = cap.next_as_vec().unwrap();
422    ///         packets.push(packet_raw)
423    ///     }
424    /// }
425    /// ```
426    pub fn next_as_vec(&mut self) -> Result<Vec<u8>, PcaptureError> {
427        let filter = self.filter.clone();
428        loop {
429            let packet_data = match self.next() {
430                Ok(pd) => pd,
431                Err(e) => match e {
432                    PcaptureError::IOError(e) => {
433                        if e.kind() == ErrorKind::TimedOut {
434                            continue;
435                        } else {
436                            return Err(e.into());
437                        }
438                    }
439                    _ => return Err(e.into()),
440                },
441            };
442
443            match &filter {
444                Some(fls) => {
445                    if fls.check(packet_data.data)? {
446                        return Ok(packet_data.data.to_vec());
447                    }
448                }
449                None => {
450                    return Ok(packet_data.data.to_vec());
451                }
452            }
453        }
454    }
455    /// Capture the packets as pcap format.
456    #[cfg(feature = "pcap")]
457    pub fn next_as_pcap(&mut self) -> Result<PacketRecord, PcaptureError> {
458        let filter = self.filter.clone();
459        let snaplen = self.snaplen;
460        loop {
461            let packet_data = match self.next() {
462                Ok(pd) => pd,
463                Err(e) => match e {
464                    PcaptureError::IOError(e) => {
465                        if e.kind() == ErrorKind::TimedOut {
466                            continue;
467                        } else {
468                            return Err(e.into());
469                        }
470                    }
471                    _ => return Err(e.into()),
472                },
473            };
474
475            match &filter {
476                Some(fls) => {
477                    if fls.check(packet_data.data)? {
478                        let pcap_record = PacketRecord::new(&packet_data.data, snaplen)?;
479                        return Ok(pcap_record);
480                    }
481                }
482                None => {
483                    let pcap_record = PacketRecord::new(&packet_data.data, snaplen)?;
484                    return Ok(pcap_record);
485                }
486            }
487        }
488    }
489    /// Capture the packets as pcapng format.
490    #[cfg(feature = "pcapng")]
491    pub fn next_as_pcapng(&mut self) -> Result<GeneralBlock, PcaptureError> {
492        let filter = self.filter.clone();
493        let snaplen = self.snaplen;
494        let iface_id = self.iface_id;
495
496        loop {
497            let packet_data = match self.next() {
498                Ok(pd) => pd,
499                Err(e) => match e {
500                    PcaptureError::IOError(e) => {
501                        if e.kind() == ErrorKind::TimedOut {
502                            continue;
503                        } else {
504                            return Err(e.into());
505                        }
506                    }
507                    _ => return Err(e.into()),
508                },
509            };
510
511            match &filter {
512                Some(fls) => {
513                    if fls.check(packet_data.data)? {
514                        let block = EnhancedPacketBlock::new(iface_id, &packet_data.data, snaplen)?;
515                        let ret = GeneralBlock::EnhancedPacketBlock(block);
516                        return Ok(ret);
517                    }
518                }
519                None => {
520                    let block = EnhancedPacketBlock::new(iface_id, &packet_data.data, snaplen)?;
521                    let ret = GeneralBlock::EnhancedPacketBlock(block);
522                    return Ok(ret);
523                }
524            }
525        }
526    }
527}
528
529#[cfg(all(unix, feature = "libpcap"))]
530#[derive(Debug, Clone)]
531pub struct Capture {
532    pub name: String,
533    buffer_size: usize,
534    timeout_ms: i32,
535    snaplen: usize,
536    promisc: bool,
537    immediate: bool,
538    // filter
539    filter: Option<String>,
540    // all system ifaces
541    #[cfg(feature = "pcapng")]
542    ifaces: Vec<Iface>,
543    // current used interface
544    #[cfg(feature = "pcapng")]
545    iface_id: u32,
546    // inner use
547    lp: Option<Libpcap>,
548}
549
550#[cfg(all(unix, feature = "libpcap"))]
551impl Drop for Capture {
552    fn drop(&mut self) {
553        let _ = self.stop();
554    }
555}
556
557#[cfg(all(unix, feature = "libpcap"))]
558impl<'a> Capture {
559    /// A simple example showing how to capture packets and save them in pcapng format.
560    /// ```rust
561    /// use pcapture::Capture;
562    /// use pcapture::PcapByteOrder;
563    ///
564    /// fn main() {
565    ///     let path = "test.pcapng";
566    ///     let pbo = PcapByteOrder::WiresharkDefault;
567    ///
568    ///     // suggest value
569    ///     // let buffer_size = 8 * 1024 * 1024; // 8MB
570    ///     // let snaplen = 65535;
571    ///     // let promisc = true;
572    ///     // let timeout = 0.1;
573    ///
574    ///     // [mac, srcmac, dstmac, ip, addr, srcip, srcaddr, dstip, dstaddr, port, srcport, dstport]
575    ///     // let valid_procotol = filter::valid_protocol();
576    ///     // println!("{:?}", valid_procotol);
577    ///
578    ///     // Please use the BPF filter syntax here.
579    ///     let filter = "icmp and host 192.168.5.2";
580    ///
581    ///     // when the underlying layer is libpcap, the supported interface name is any.
582    ///     let mut cap = Capture::new("ens33").unwrap();
583    ///     cap.set_filter(filter);
584    ///     let mut pcapng = cap.gen_pcapng_header(pbo).unwrap();
585    ///     for _ in 0..5 {
586    ///         let blocks = cap.fetch_as_pcapng().unwrap();
587    ///         for b in blocks {
588    ///             pcapng.append(b);
589    ///         }
590    ///     }
591    ///     pcapng.write_all(path).unwrap();
592    ///     
593    /// }
594    /// ```
595    pub fn new(name: &str) -> Result<Self, PcaptureError> {
596        let devices = Libpcap::devices()?;
597        let timeout_ms = DEFAULT_TIMEOUT_MS;
598        let buffer_size = DEFAULT_BUFFER_SIZE;
599        let snaplen = DETAULT_SNAPLEN;
600        let promisc = false;
601        let immediate = false;
602
603        let mut ifaces = Vec::new();
604        let mut i = 0;
605        #[cfg(feature = "pcapng")]
606        let mut iface_id = 0;
607        let mut interface_exists = false;
608        for device in devices {
609            if device.name == name {
610                #[cfg(feature = "pcapng")]
611                {
612                    iface_id = i;
613                }
614                interface_exists = true;
615            }
616            let iface = Iface {
617                id: i as u32,
618                device,
619            };
620            ifaces.push(iface);
621            i += 1;
622        }
623
624        if !interface_exists {
625            let available_interface = ifaces
626                .iter()
627                .map(|iface| iface.device.name.clone())
628                .collect::<Vec<String>>()
629                .join(", ");
630
631            return Err(PcaptureError::InterfaceNotFound {
632                name: name.to_string(),
633                available_interface,
634            });
635        }
636
637        let filter = None;
638        let lp = Libpcap::new(
639            name,
640            snaplen as i32,
641            promisc,
642            immediate,
643            timeout_ms,
644            buffer_size as i32,
645            filter,
646        )?;
647
648        Ok(Self {
649            name: name.to_string(),
650            buffer_size,
651            timeout_ms,
652            snaplen,
653            promisc,
654            immediate,
655            #[cfg(feature = "pcapng")]
656            ifaces,
657            #[cfg(feature = "pcapng")]
658            iface_id,
659            filter: None,
660            lp: Some(lp),
661        })
662    }
663    /// Generate pcap format header.
664    #[cfg(feature = "pcap")]
665    pub fn gen_pcap_header(&self, pbo: PcapByteOrder) -> Result<Pcap, PcaptureError> {
666        let pcap = Pcap::new(&self.name, pbo);
667        Ok(pcap)
668    }
669    /// Generate pcapng format header.
670    #[cfg(feature = "pcapng")]
671    pub fn gen_pcapng_header(&self, pbo: PcapByteOrder) -> Result<PcapNg, PcaptureError> {
672        let pcapng = PcapNg::new(&self.ifaces, pbo);
673        Ok(pcapng)
674    }
675    /// Set buffer size.
676    pub fn set_buffer_size(&mut self, buffer_size: usize) {
677        self.buffer_size = buffer_size;
678        // none means regenerate lp in fetch func
679        self.lp = None;
680    }
681    /// Get the buffer size.
682    pub fn get_buffer_size(&self) -> usize {
683        self.buffer_size
684    }
685    /// Set timeout as milliseconds.
686    pub fn set_timeout(&mut self, timeout_ms: i32) {
687        self.timeout_ms = timeout_ms;
688        // none means regenerate lp in fetch func
689        self.lp = None;
690    }
691    /// Get the timeout as milliseconds.
692    pub fn get_timeout(&self) -> i32 {
693        self.timeout_ms
694    }
695    /// Set promiscuous mode.
696    pub fn set_promiscuous_mode(&mut self, promiscuous: bool) {
697        self.promisc = promiscuous;
698        // none means regenerate lp in fetch func
699        self.lp = None;
700    }
701    /// Get promiscuous mode.
702    pub fn get_promiscuous_mode(&self) -> bool {
703        self.promisc
704    }
705    /// Set immediate mode.
706    pub fn set_immediate_mode(&mut self, immediate: bool) {
707        self.immediate = immediate;
708        // none means regenerate lp in fetch func
709        self.lp = None;
710    }
711    /// Get immediate mode.
712    pub fn get_immediate_mode(&self) -> bool {
713        self.immediate
714    }
715    /// Set snaplen value.
716    pub fn set_snaplen(&mut self, snaplen: usize) {
717        self.snaplen = snaplen;
718        // none means regenerate lp in fetch func
719        self.lp = None;
720    }
721    /// Get snaplen value.
722    pub fn get_snaplen(&self) -> usize {
723        self.snaplen
724    }
725    /// Set filter with BPF syntax.
726    pub fn set_filter(&mut self, filter: &str) {
727        self.filter = Some(filter.to_string());
728        // none means regenerate lp in fetch func
729        self.lp = None;
730    }
731    /// Get current filter.
732    pub fn get_filter(&self) -> Option<String> {
733        self.filter.clone()
734    }
735    /// Return all packets in the system cache.
736    pub fn fetch(&mut self) -> Result<Vec<PacketData<'_>>, PcaptureError> {
737        if self.lp.is_none() {
738            let lp = Libpcap::new(
739                &self.name,
740                self.snaplen as i32,
741                self.promisc,
742                self.immediate,
743                self.timeout_ms,
744                self.buffer_size as i32,
745                self.filter.clone(),
746            )?;
747            self.lp = Some(lp);
748        }
749
750        if let Some(lp) = &mut self.lp {
751            let packets = lp.fetch()?;
752            Ok(packets)
753        } else {
754            unreachable!("lp must have a value here");
755        }
756    }
757    /// Please perform this step to clear memory when exiting the program.
758    /// Note: it will automatically be called when the Capture instance is dropped.
759    pub fn stop(&mut self) -> Result<(), PcaptureError> {
760        if let Some(libpcap) = &mut self.lp {
761            let _ = libpcap.stop()?;
762        }
763        Ok(())
764    }
765    /// Capture the all packets in system cache as raw format.
766    /// ```rust
767    /// use pcapture::Capture;
768    ///
769    /// fn main() {
770    ///     let mut packets = Vec::new();
771    ///     let mut cap = Capture::new("ens33").unwrap();
772    ///     for _ in 0..5 {
773    ///         let ret = cap.fetch_as_vec().unwrap();
774    ///         for p in ret {
775    ///             packets.push(p.to_vec());
776    ///         }
777    ///     }
778    ///     
779    /// }
780    /// ```
781    pub fn fetch_as_vec(&'a mut self) -> Result<Vec<&'a [u8]>, PcaptureError> {
782        let packets = self.fetch()?;
783        let mut ret = Vec::new();
784        for p in packets {
785            ret.push(p.data)
786        }
787        return Ok(ret);
788    }
789    /// Capture the all packets in system cache as the pcap format.
790    #[cfg(feature = "pcap")]
791    pub fn fetch_as_pcap(&mut self) -> Result<Vec<PacketRecord>, PcaptureError> {
792        let snaplen = self.snaplen as usize;
793        let packets = self.fetch()?;
794
795        let mut ret = Vec::new();
796        for p in packets {
797            let data = p.data;
798            let ts_sec = p.ts_sec;
799            let ts_usec = p.ts_usec;
800            let pcap_record = PacketRecord::new(data, snaplen, ts_sec, ts_usec)?;
801            ret.push(pcap_record);
802        }
803        return Ok(ret);
804    }
805    /// Capture the all packets in system cache as the pcapng format.
806    #[cfg(feature = "pcapng")]
807    pub fn fetch_as_pcapng(&mut self) -> Result<Vec<GeneralBlock>, PcaptureError> {
808        let snaplen = self.snaplen as usize;
809        let iface_id = self.iface_id;
810        let packets = self.fetch()?;
811
812        let mut ret = Vec::new();
813        for p in packets {
814            let data = p.data;
815            let ts_high = p.ts_high;
816            let ts_low = p.ts_low;
817            let block = EnhancedPacketBlock::new(iface_id, data, snaplen, ts_high, ts_low)?;
818            let block = GeneralBlock::EnhancedPacketBlock(block);
819            ret.push(block);
820        }
821
822        return Ok(ret);
823    }
824}
825
826#[cfg(all(unix, feature = "libpcap"))]
827#[cfg(test)]
828mod tests {
829    use super::*;
830    #[test]
831    fn capture_raw() {
832        let mut cap = Capture::new("ens33").unwrap();
833        cap.set_buffer_size(4096);
834        for i in 0..5 {
835            let packet_raw = cap.fetch_as_vec().unwrap();
836            println!("fetch[{}], packets num: {}", i, packet_raw.len());
837        }
838    }
839    #[cfg(feature = "pcap")]
840    #[test]
841    fn capture_pcap() {
842        let path = "test_ens33.pcap";
843        let pbo = PcapByteOrder::WiresharkDefault;
844
845        let mut cap = Capture::new("ens33").unwrap();
846        cap.set_buffer_size(4096);
847        let mut pcap = cap.gen_pcap_header(pbo).unwrap();
848
849        let mut packet_count = 0;
850        for _ in 0..5 {
851            let record = cap.fetch_as_pcap().unwrap();
852            for r in record {
853                pcap.append(r);
854                packet_count += 1;
855            }
856        }
857        println!("packet count: {}", packet_count);
858
859        // write all capture data to test.pcap
860        pcap.write_all(path).unwrap();
861
862        let read_pcap = Pcap::read_all(path, pbo).unwrap();
863        assert_eq!(read_pcap.records.len(), packet_count);
864    }
865    #[cfg(feature = "pcap")]
866    #[test]
867    fn capture_pcap_any() {
868        let path = "test_any.pcap";
869        let pbo = PcapByteOrder::WiresharkDefault;
870
871        let mut cap = Capture::new("any").unwrap();
872        cap.set_buffer_size(4096);
873        let mut pcap = cap.gen_pcap_header(pbo).unwrap();
874
875        let mut packet_count = 0;
876        for _ in 0..5 {
877            let record = cap.fetch_as_pcap().unwrap();
878            for r in record {
879                pcap.append(r);
880                packet_count += 1;
881            }
882        }
883        println!("packet count: {}", packet_count);
884
885        // write all capture data to test.pcap
886        pcap.write_all(path).unwrap();
887
888        let read_pcap = Pcap::read_all(path, pbo).unwrap();
889        assert_eq!(read_pcap.records.len(), packet_count);
890    }
891
892    #[cfg(feature = "pcapng")]
893    #[test]
894    fn capture_pcapng() {
895        let path = "test_ens33.pcapng";
896        let pbo = PcapByteOrder::WiresharkDefault;
897
898        let mut cap = Capture::new("ens33").unwrap();
899        cap.set_buffer_size(4096);
900        cap.set_timeout(1);
901        cap.set_promiscuous_mode(true);
902        cap.set_snaplen(65535);
903
904        let mut pcapng = cap.gen_pcapng_header(pbo).unwrap();
905
906        // libpcap => 9
907        // libpnet => 3
908        println!("pcapng header len: {}", pcapng.blocks.len());
909
910        let mut packets_count = pcapng.blocks.len();
911        for _ in 0..5 {
912            let blocks = cap.fetch_as_pcapng().unwrap();
913            for b in blocks {
914                pcapng.append(b);
915                packets_count += 1;
916            }
917        }
918
919        pcapng.write_all(path).unwrap();
920
921        let read_pcapng = PcapNg::read_all(path, pbo).unwrap();
922        // interfaece info node
923        assert_eq!(read_pcapng.blocks.len(), packets_count);
924    }
925    #[cfg(feature = "pcapng")]
926    #[test]
927    fn capture_pcapng_any() {
928        let path = "test_any.pcapng";
929        let pbo = PcapByteOrder::WiresharkDefault;
930
931        let mut cap = Capture::new("any").unwrap();
932        cap.set_buffer_size(4096);
933        cap.set_timeout(1);
934        cap.set_promiscuous_mode(false);
935        cap.set_snaplen(65535);
936
937        let mut pcapng = cap.gen_pcapng_header(pbo).unwrap();
938
939        // libpcap => 9
940        // libpnet => 3
941        println!("pcapng header len: {}", pcapng.blocks.len());
942
943        let mut packets_count = pcapng.blocks.len();
944        for _ in 0..5 {
945            let blocks = cap.fetch_as_pcapng().unwrap();
946            for b in blocks {
947                pcapng.append(b);
948                packets_count += 1;
949            }
950        }
951
952        pcapng.write_all(path).unwrap();
953
954        let read_pcapng = PcapNg::read_all(path, pbo).unwrap();
955        // interfaece info node
956        assert_eq!(read_pcapng.blocks.len(), packets_count);
957    }
958    #[cfg(feature = "pcapng")]
959    #[test]
960    fn capture_pcapng_filter() {
961        let path = "test_filter.pcapng";
962        let pbo = PcapByteOrder::WiresharkDefault;
963        // let valid_procotol = filter::valid_protocol();
964        // println!("{:?}", valid_procotol);
965        let filter = "host 192.168.5.2";
966
967        let mut cap = Capture::new("ens33").unwrap();
968        cap.set_filter(filter);
969
970        let mut pcapng = cap.gen_pcapng_header(pbo).unwrap();
971        for i in 0..5 {
972            println!("i: {}", i);
973            let block = cap.fetch_as_pcapng().unwrap();
974            for b in block {
975                pcapng.append(b);
976            }
977        }
978
979        pcapng.write_all(path).unwrap();
980    }
981    #[ignore]
982    #[test]
983    fn block_read() {
984        let pbo = PcapByteOrder::WiresharkDefault;
985        let path = "1.pcapng";
986        let read_pcapng = PcapNg::read_all(path, pbo).unwrap();
987        println!("blocks num: {}", read_pcapng.blocks.len());
988        for b in read_pcapng.blocks {
989            println!("block type: {}", b.name());
990        }
991    }
992}
993
994#[cfg(feature = "libpnet")]
995#[cfg(test)]
996mod tests {
997    use super::*;
998    #[test]
999    fn capture_raw() {
1000        let mut cap = Capture::new("ens33").unwrap();
1001        cap.set_buffer_size(4096);
1002        for i in 0..5 {
1003            let packet_raw = cap.next_as_vec().unwrap();
1004            println!("fetch[{}], packets num: {}", i, packet_raw.len());
1005        }
1006    }
1007    #[cfg(feature = "pcap")]
1008    #[test]
1009    fn capture_pcap() {
1010        let path = "test_ens33.pcap";
1011        let pbo = PcapByteOrder::WiresharkDefault;
1012
1013        let mut cap = Capture::new("ens33").unwrap();
1014        cap.set_buffer_size(4096);
1015        let mut pcap = cap.gen_pcap_header(pbo).unwrap();
1016
1017        let mut packet_count = 0;
1018        for _ in 0..5 {
1019            let record = cap.next_as_pcap().unwrap();
1020            pcap.append(record);
1021            packet_count += 1;
1022        }
1023        println!("packet count: {}", packet_count);
1024
1025        // write all capture data to test.pcap
1026        pcap.write_all(path).unwrap();
1027
1028        let read_pcap = Pcap::read_all(path, pbo).unwrap();
1029        assert_eq!(read_pcap.records.len(), packet_count);
1030    }
1031    #[cfg(feature = "pcapng")]
1032    #[test]
1033    fn capture_pcapng() {
1034        let path = "test_ens33.pcapng";
1035        let pbo = PcapByteOrder::WiresharkDefault;
1036
1037        let mut cap = Capture::new("ens33").unwrap();
1038        cap.set_buffer_size(4096);
1039        cap.set_timeout(1.0);
1040        cap.set_promiscuous(true);
1041        cap.set_snaplen(65535);
1042
1043        let mut pcapng = cap.gen_pcapng_header(pbo).unwrap();
1044
1045        // libpcap => 9
1046        // libpnet => 3
1047        println!("pcapng header len: {}", pcapng.blocks.len());
1048
1049        let mut packets_count = pcapng.blocks.len();
1050        for _ in 0..5 {
1051            let block = cap.next_as_pcapng().unwrap();
1052            pcapng.append(block);
1053            packets_count += 1;
1054        }
1055
1056        pcapng.write_all(path).unwrap();
1057
1058        let read_pcapng = PcapNg::read_all(path, pbo).unwrap();
1059        // interfaece info node
1060        assert_eq!(read_pcapng.blocks.len(), packets_count);
1061    }
1062    #[cfg(feature = "pcapng")]
1063    #[test]
1064    fn capture_pcapng_filter() {
1065        let path = "test_filter.pcapng";
1066        let pbo = PcapByteOrder::WiresharkDefault;
1067        // let valid_procotol = filter::valid_protocol();
1068        // println!("{:?}", valid_procotol);
1069        let filter_str = "icmp and ip=192.168.5.2";
1070
1071        let mut cap = Capture::new("ens33").unwrap();
1072        cap.set_filter(filter_str).unwrap();
1073
1074        let mut pcapng = cap.gen_pcapng_header(pbo).unwrap();
1075        for i in 0..5 {
1076            println!("i: {}", i);
1077            let block = cap.next_as_pcapng().unwrap();
1078            pcapng.append(block);
1079        }
1080
1081        pcapng.write_all(path).unwrap();
1082    }
1083}