pcap/
lib.rs

1//! pcap is a packet capture library available on Linux, Windows and Mac. This
2//! crate supports creating and configuring capture contexts, sniffing packets,
3//! sending packets to interfaces, listing devices, and recording packet captures
4//! to pcap-format dump files.
5//!
6//! # Capturing packets
7//! The easiest way to open an active capture handle and begin sniffing is to
8//! use `.open()` on a `Device`. You can obtain the "default" device using
9//! `Device::lookup()`, or you can obtain the device(s) you need via `Device::list()`.
10//!
11//! ```ignore
12//! use pcap::Device;
13//!
14//! fn main() {
15//!     let mut cap = Device::lookup().unwrap().open().unwrap();
16//!
17//!     while let Ok(packet) = cap.next() {
18//!         println!("received packet! {:?}", packet);
19//!     }
20//! }
21//! ```
22//!
23//! `Capture`'s `.next()` will produce a `Packet` which can be dereferenced to access the
24//! `&[u8]` packet contents.
25//!
26//! # Custom configuration
27//!
28//! You may want to configure the `timeout`, `snaplen` or other parameters for the capture
29//! handle. In this case, use `Capture::from_device()` to obtain a `Capture<Inactive>`, and
30//! proceed to configure the capture handle. When you're finished, run `.open()` on it to
31//! turn it into a `Capture<Active>`.
32//!
33//! ```ignore
34//! use pcap::{Device,Capture};
35//!
36//! fn main() {
37//!     let main_device = Device::lookup().unwrap();
38//!     let mut cap = Capture::from_device(main_device).unwrap()
39//!                       .promisc(true)
40//!                       .snaplen(5000)
41//!                       .open().unwrap();
42//!
43//!     while let Ok(packet) = cap.next() {
44//!         println!("received packet! {:?}", packet);
45//!     }
46//! }
47//! ```
48
49extern crate libc;
50
51use unique::Unique;
52use std::marker::PhantomData;
53use std::ptr;
54use std::ffi::{CStr,CString};
55use std::path::Path;
56use std::slice;
57use std::ops::Deref;
58use std::mem::transmute;
59use std::str;
60use std::fmt;
61use self::Error::*;
62#[cfg(not(windows))]
63use std::os::unix::io::{RawFd, AsRawFd};
64
65pub use raw::PacketHeader;
66
67mod raw;
68mod unique;
69
70const PCAP_ERROR_NOT_ACTIVATED: i32 = -3;
71const PCAP_ERRBUF_SIZE: usize = 256;
72
73/// An error received from pcap
74#[derive(Debug)]
75pub enum Error {
76    MalformedError(str::Utf8Error),
77    InvalidString,
78    PcapError(String),
79    InvalidLinktype,
80    TimeoutExpired,
81    NoMorePackets,
82    InsufficientMemory,
83}
84
85impl Error {
86    fn new<T>(ptr: *const libc::c_char) -> Result<T, Error> {
87        Err(PcapError(try!(cstr_to_string(ptr))))
88    }
89}
90
91impl fmt::Display for Error {
92    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
93        match *self {
94            MalformedError(e) => {
95                write!(f, "pcap returned a string that was not encoded properly: {}", e)
96            },
97            InvalidString => {
98                write!(f, "pcap returned an invalid (null) string")
99            },
100            PcapError(ref e) => {
101                write!(f, "pcap error: {}", e)
102            },
103            InvalidLinktype => {
104                write!(f, "invalid or unknown linktype")
105            },
106            TimeoutExpired => {
107               write!(f, "timeout expired")
108            },
109            NoMorePackets => {
110               write!(f, "no more packets to read from the file")
111            },
112            InsufficientMemory => {
113                write!(f, "insufficient memory")
114            },
115        }
116    }
117}
118
119impl std::error::Error for Error {
120    fn description(&self) -> &str {
121        match *self {
122            MalformedError(..) => "message from pcap is not encoded properly",
123            PcapError(..) => "pcap FFI error",
124            InvalidString => "pcap returned an invalid (null) string",
125            InvalidLinktype => "invalid or unknown linktype",
126            TimeoutExpired => "pcap was reading from a live capture and the timeout expired",
127            NoMorePackets => "pcap was reading from a file and there were no more packets to read",
128            InsufficientMemory => "insufficient memory",
129        }
130    }
131
132    fn cause(&self) -> Option<&std::error::Error> {
133        match *self {
134            MalformedError(ref e) => Some(e),
135            _ => None
136        }
137    }
138}
139
140impl From<str::Utf8Error> for Error {
141    fn from(obj: str::Utf8Error) -> Error {
142        MalformedError(obj)
143    }
144}
145
146#[derive(Debug)]
147/// A network device name and (potentially) pcap's description of it.
148pub struct Device {
149    pub name: String,
150    pub desc: Option<String>
151}
152
153impl Device {
154    /// Opens a `Capture<Active>` on this device.
155    pub fn open(self) -> Result<Capture<Active>, Error> {
156        Ok(try!(try!(Capture::from_device(self)).open()))
157    }
158
159    /// Returns the default Device suitable for captures according to pcap_lookupdev,
160    /// or an error from pcap.
161    pub fn lookup() -> Result<Device, Error> {
162        let mut errbuf = [0i8; PCAP_ERRBUF_SIZE];
163
164        unsafe {
165            let default_name = raw::pcap_lookupdev(errbuf.as_mut_ptr() as *mut _);
166			println!("{:?}",cstr_to_string(default_name));
167            if default_name.is_null() {
168                return Error::new(errbuf.as_ptr() as *const _);
169            }
170
171            Ok(Device {
172                name: try!(cstr_to_string(default_name)),
173                desc: None
174            })
175        }
176    }
177
178    /// Returns a vector of `Device`s known by pcap via pcap_findalldevs.
179    pub fn list() -> Result<Vec<Device>, Error> {
180        unsafe {
181            let mut errbuf = [0i8; PCAP_ERRBUF_SIZE];
182            let mut dev_buf: *mut raw::Struct_pcap_if = ptr::null_mut();
183            let mut ret = vec![];
184
185            match raw::pcap_findalldevs(&mut dev_buf, errbuf.as_mut_ptr() as *mut _) {
186                0 => {
187                    let mut cur = dev_buf;
188
189                    while !cur.is_null() {
190                        ret.push(Device {
191                            name: cstr_to_string((&*cur).name).unwrap(),
192                            desc: {
193                                if !(&*cur).description.is_null() {
194                                    Some(cstr_to_string((&*cur).description).unwrap())
195                                } else {
196                                    None
197                                }
198                            }
199                        });
200
201                        cur = (&*cur).next;
202                    }
203
204                    raw::pcap_freealldevs(dev_buf);
205
206                    Ok(ret)
207                },
208                _ => {
209                    Error::new(errbuf.as_ptr() as *mut _)
210                }
211            }
212        }
213    }
214}
215
216impl<'a> Into<Device> for &'a str {
217    fn into(self) -> Device {
218        Device {
219            name: self.into(),
220            desc: None
221        }
222    }
223}
224
225/// This is a datalink link type.
226///
227/// As an example, `Linktype(1)` is ethernet. A full list of linktypes is available
228/// [here](http://www.tcpdump.org/linktypes.html).
229#[derive(Debug, PartialEq, Eq)]
230pub struct Linktype(pub i32);
231
232impl Linktype {
233    /// Gets the name of the link type, such as EN10MB
234    pub fn get_name(&self) -> Result<String, Error> {
235        unsafe {
236            let name = raw::pcap_datalink_val_to_name(self.0);
237
238            if name.is_null() {
239                return Err(InvalidLinktype)
240            } else {
241                Ok(try!(cstr_to_string(name)))
242            }
243        }
244    }
245
246    /// Gets the description of a link type.
247    pub fn get_description(&self) -> Result<String, Error> {
248        unsafe {
249            let description = raw::pcap_datalink_val_to_description(self.0);
250
251            if description.is_null() {
252                return Err(InvalidLinktype)
253            } else {
254                Ok(try!(cstr_to_string(description)))
255            }
256        }
257    }
258}
259
260/// Represents a packet returned from pcap.
261#[derive(Debug)]
262pub struct Packet<'a> {
263    pub header: &'a PacketHeader,
264    pub data: &'a [u8]
265}
266
267impl<'b> Deref for Packet<'b> {
268   type Target = [u8];
269
270    fn deref(&self) -> &[u8] {
271        self.data
272    }
273}
274
275#[derive(Debug, Clone, Copy)]
276pub struct Stat {
277    pub received: u32,
278    pub dropped: u32,
279    pub if_dropped: u32
280}
281
282pub enum Precision {
283    Micro,
284    Nano,
285}
286
287/// Phantom type representing an inactive capture handle.
288pub enum Inactive {}
289/// Phantom type representing an active capture handle.
290pub enum Active {}
291/// Phantom type representing an offline capture handle, from a pcap dump file.
292/// Implements `Activated` because it behaves nearly the same as a live handle.
293pub enum Offline {}
294/// Phantom type representing a dead capture handle.  This can be use to create
295/// new save files that are not generated from an active capture.
296/// Implements `Activated` because it behaves nearly the same as a live handle.
297pub enum Dead {}
298
299pub unsafe trait Activated: State {}
300
301unsafe impl Activated for Active {}
302unsafe impl Activated for Offline {}
303unsafe impl Activated for Dead {}
304
305/// `Capture`s can be in different states at different times, and in these states they
306/// may or may not have particular capabilities. This trait is implemented by phantom
307/// types which allows us to punt these invariants to the type system to avoid runtime
308/// errors.
309pub unsafe trait State {}
310
311unsafe impl State for Inactive {}
312unsafe impl State for Active {}
313unsafe impl State for Offline {}
314unsafe impl State for Dead {}
315
316/// This is a pcap capture handle which is an abstraction over the `pcap_t` provided by pcap.
317/// There are many ways to instantiate and interact with a pcap handle, so phantom types are
318/// used to express these behaviors.
319///
320/// **`Capture<Inactive>`** is created via `Capture::from_device()`. This handle is inactive,
321/// so you cannot (yet) obtain packets from it. However, you can configure things like the
322/// buffer size, snaplen, timeout, and promiscuity before you activate it.
323///
324/// **`Capture<Active>`** is created by calling `.open()` on a `Capture<Inactive>`. This
325/// activates the capture handle, allowing you to get packets with `.next()` or apply filters
326/// with `.filter()`.
327///
328/// **`Capture<Offline>`** is created via `Capture::from_file()`. This allows you to read a
329/// pcap format dump file as if you were opening an interface -- very useful for testing or
330/// analysis.
331///
332/// **`Capture<Dead>`** is created via `Capture::dead()`. This allows you to create a pcap
333/// format dump file without needing an active capture.
334///
335/// # Example:
336///
337/// ```ignore
338/// let cap = Capture::from_device(Device::lookup().unwrap()) // open the "default" interface
339///               .unwrap() // assume the device exists and we are authorized to open it
340///               .open() // activate the handle
341///               .unwrap(); // assume activation worked
342///
343/// while let Ok(packet) = cap.next() {
344///     println!("received packet! {:?}", packet);
345/// }
346/// ```
347pub struct Capture<T: State + ?Sized> {
348    handle: Unique<raw::pcap_t>,
349    _marker: PhantomData<T>
350}
351
352impl Capture<Offline> {
353    /// Opens an offline capture handle from a pcap dump file, given a path.
354    pub fn from_file<P: AsRef<Path>>(path: P) -> Result<Capture<Offline>, Error> {
355        let name = CString::new(path.as_ref().to_str().unwrap()).unwrap();
356        let mut errbuf = [0i8; PCAP_ERRBUF_SIZE];
357
358        unsafe {
359            let handle = raw::pcap_open_offline(name.as_ptr(), errbuf.as_mut_ptr() as *mut _);
360            if handle.is_null() {
361                return Error::new(errbuf.as_ptr() as *mut _);
362            }
363
364            Ok(Capture {
365                handle: Unique::new(handle),
366                _marker: PhantomData
367            })
368        }
369    }
370
371    /// Opens an offline capture handle from a pcap dump file, given a path.
372    /// Takes an additional precision argument specifying the time stamp precision desired.
373    pub fn from_file_with_precision<P: AsRef<Path>>(path: P, precision: Precision) -> Result<Capture<Offline>, Error> {
374        let name = CString::new(path.as_ref().to_str().unwrap()).unwrap();
375        let mut errbuf = [0i8; PCAP_ERRBUF_SIZE];
376
377        unsafe {
378            let handle = raw::pcap_open_offline_with_tstamp_precision(name.as_ptr(), match precision {
379                Precision::Micro => 0,
380                Precision::Nano => 1,
381            }, errbuf.as_mut_ptr() as *mut _);
382            if handle.is_null() {
383                return Error::new(errbuf.as_ptr() as *const _);
384            }
385
386            Ok(Capture {
387                handle: Unique::new(handle),
388                _marker: PhantomData
389            })
390        }
391    }
392}
393
394pub enum TstampType {
395    Host,
396    HostLowPrec,
397    HostHighPrec,
398    Adapter,
399    AdapterUnsynced,
400}
401
402pub enum Direction {
403    InOut,
404    In,
405    Out,
406}
407
408impl Capture<Inactive> {
409    /// Opens a capture handle for a device. You can pass a `Device` or an `&str` device
410    /// name here. The handle is inactive, but can be activated via `.open()`.
411    pub fn from_device<D: Into<Device>>(device: D) -> Result<Capture<Inactive>, Error> {
412        let device: Device = device.into();
413        let name = CString::new(device.name).unwrap();
414        let mut errbuf = [0i8; PCAP_ERRBUF_SIZE];
415
416        unsafe {
417            let handle = raw::pcap_create(name.as_ptr(), errbuf.as_mut_ptr() as *mut _);
418            if handle.is_null() {
419                return Error::new(errbuf.as_ptr() as *const _);
420            }
421
422            Ok(Capture {
423                handle: Unique::new(handle),
424                _marker: PhantomData
425            })
426        }
427    }
428
429    /// Activates an inactive capture created from `Capture::from_device()` or returns
430    /// an error.
431    pub fn open(self) -> Result<Capture<Active>, Error> {
432        unsafe {
433            let cap = transmute::<Capture<Inactive>, Capture<Active>>(self);
434
435            if 0 != raw::pcap_activate(*cap.handle) {
436                return Error::new(raw::pcap_geterr(*cap.handle));
437            }
438
439            Ok(cap)
440        }
441    }
442
443    /// Set the read timeout for the Capture. By default, this is 0, so it will block
444    /// indefinitely.
445    pub fn timeout(self, ms: i32) -> Capture<Inactive> {
446        unsafe {
447            raw::pcap_set_timeout(*self.handle, ms);
448            self
449        }
450    }
451
452    /// Set the time stamp type to be used by a capture device.
453    #[cfg(not(windows))]
454    pub fn tstamp_type(self, t: TstampType) -> Capture<Inactive> {
455        unsafe {
456            raw::pcap_set_tstamp_type(*self.handle, match t {
457                TstampType::Host => 0,
458                TstampType::HostLowPrec => 1,
459                TstampType::HostHighPrec => 2,
460                TstampType::Adapter => 3,
461                TstampType::AdapterUnsynced => 4,
462            });
463            self
464        }
465    }
466
467    /// Set promiscuous mode on or off. By default, this is off.
468    pub fn promisc(self, to: bool) -> Capture<Inactive> {
469        unsafe {
470            raw::pcap_set_promisc(*self.handle, if to {1} else {0});
471            self
472        }
473    }
474
475    /// Set rfmon mode on or off. The default is maintained by pcap.
476    ///
477    /// **This is not available on Windows.**
478    #[cfg(not(target_os = "windows"))]
479    pub fn rfmon(self, to: bool) -> Capture<Inactive> {
480        unsafe {
481            raw::pcap_set_rfmon(*self.handle, if to {1} else {0});
482            self
483        }
484    }
485
486    /// Set the buffer size for incoming packet data.
487    ///
488    /// The default is 1000000. This should always be larger than the snaplen.
489    pub fn buffer_size(self, to: i32) -> Capture<Inactive> {
490        unsafe {
491            raw::pcap_set_buffer_size(*self.handle, to);
492            self
493        }
494    }
495
496    /// Set the time stamp precision returned in captures.
497    #[cfg(not(windows))]
498    pub fn precision(self, precision: Precision) -> Capture<Inactive> {
499        unsafe {
500            raw::pcap_set_tstamp_precision(*self.handle, match precision {
501                Precision::Micro => 0,
502                Precision::Nano => 1,
503            });
504            self
505        }
506    }
507
508    /// Set the snaplen size (the maximum length of a packet captured into the buffer).
509    /// Useful if you only want certain headers, but not the entire packet.
510    ///
511    /// The default is 65535
512    pub fn snaplen(self, to: i32) -> Capture<Inactive> {
513        unsafe {
514            raw::pcap_set_snaplen(*self.handle, to);
515            self
516        }
517    }
518}
519
520///# Activated captures include `Capture<Active>` and `Capture<Offline>`.
521impl<T: Activated + ?Sized> Capture<T> {
522    /// List the datalink types that this captured device supports.
523    pub fn list_datalinks(&self) -> Result<Vec<Linktype>, Error> {
524        unsafe {
525            let mut links: *mut i32 = ptr::null_mut();
526
527            let num = raw::pcap_list_datalinks(*self.handle, &mut links);
528
529            if num == PCAP_ERROR_NOT_ACTIVATED {
530                raw::pcap_free_datalinks(links);
531                panic!("It should not be possible to run list_datalinks on a Capture that is not activated, please report this bug!")
532            } else if num < 0 {
533                raw::pcap_free_datalinks(links);
534                Error::new(raw::pcap_geterr(*self.handle))
535            } else {
536                let slice = slice::from_raw_parts(links, num as usize).iter().map(|&a| Linktype(a)).collect();
537                raw::pcap_free_datalinks(links);
538
539                Ok(slice)
540            }
541        }
542    }
543
544    /// Set the datalink type for the current capture handle.
545    pub fn set_datalink(&mut self, linktype: Linktype) -> Result<(), Error> {
546        unsafe {
547            match raw::pcap_set_datalink(*self.handle, linktype.0) {
548                0 => {
549                    Ok(())
550                },
551                _ => {
552                    Error::new(raw::pcap_geterr(*self.handle))
553                }
554            }
555        }
556    }
557
558    /// Get the current datalink type for this capture handle.
559    pub fn get_datalink(&self) -> Linktype {
560        unsafe {
561            match raw::pcap_datalink(*self.handle) {
562                PCAP_ERROR_NOT_ACTIVATED => {
563                    panic!("It should not be possible to run get_datalink on a Capture that is not activated, please report this bug!");
564                },
565                lt => {
566                    Linktype(lt)
567                }
568            }
569        }
570    }
571
572    /// Create a `Savefile` context for recording captured packets using this `Capture`'s
573    /// configurations.
574    pub fn savefile<P: AsRef<Path>>(&self, path: P) -> Result<Savefile, Error> {
575        let name = CString::new(path.as_ref().to_str().unwrap()).unwrap();
576        unsafe {
577            let handle = raw::pcap_dump_open(*self.handle, name.as_ptr());
578
579            if handle.is_null() {
580                Error::new(raw::pcap_geterr(*self.handle))
581            } else {
582                Ok(Savefile {
583                    handle: Unique::new(handle)
584                })
585            }
586        }
587    }
588
589    /// Set the direction of the capture
590    pub fn direction(&self, direction: Direction) -> Result<(), Error> {
591        let result = unsafe {
592            raw::pcap_setdirection(*self.handle, match direction {
593                Direction::InOut => raw::PCAP_D_INOUT,
594                Direction::In => raw::PCAP_D_IN,
595                Direction::Out => raw::PCAP_D_OUT,
596            })
597        };
598        if result == 0 {
599            Ok(())
600        } else {
601            Error::new( unsafe { raw::pcap_geterr(*self.handle) })
602        }
603    }
604
605    /// Blocks until a packet is returned from the capture handle or an error occurs.
606    ///
607    /// pcap captures packets and places them into a buffer which this function reads
608    /// from. This buffer has a finite length, so if the buffer fills completely new
609    /// packets will be discarded temporarily. This means that in realtime situations,
610    /// you probably want to minimize the time between calls of this next() method.
611    pub fn next<'a>(&'a mut self) -> Result<Packet<'a>, Error> {
612        unsafe {
613            let mut header: *mut raw::Struct_pcap_pkthdr = ptr::null_mut();
614            let mut packet: *const libc::c_uchar = ptr::null();
615            match raw::pcap_next_ex(*self.handle, &mut header, &mut packet) {
616                i if i >= 1 => {
617                    // packet was read without issue
618                    Ok(Packet {
619                        header: transmute(&*header),
620                        data: slice::from_raw_parts(packet, (&*header).caplen as usize)
621                    })
622                },
623                0 => {
624                    // packets are being read from a live capture and the
625                    // timeout expired
626                    Err(TimeoutExpired)
627                },
628                -1 => {
629                    // an error occured while reading the packet
630                    Error::new(raw::pcap_geterr(*self.handle))
631                },
632                -2 => {
633                    // packets are being read from a "savefile" and there are no
634                    // more packets to read
635                    Err(NoMorePackets)
636                },
637                _ => {
638                    // libpcap only defines codes >=1, 0, -1, and -2
639                    unreachable!()
640                }
641            }
642        }
643    }
644
645    /// Adds a filter to the capture using the given BPF program string. Internally
646    /// this is compiled using `pcap_compile()`.
647    ///
648    /// See http://biot.com/capstats/bpf.html for more information about this syntax.
649    pub fn filter(&mut self, program: &str) -> Result<(), Error> {
650        let program = CString::new(program).unwrap();
651
652        unsafe {
653            let mut bpf_program: raw::Struct_bpf_program = Default::default();
654
655            if -1 == raw::pcap_compile(*self.handle, &mut bpf_program, program.as_ptr(), 0, 0) {
656                return Error::new(raw::pcap_geterr(*self.handle));
657            }
658
659            if -1 == raw::pcap_setfilter(*self.handle, &mut bpf_program) {
660                raw::pcap_freecode(&mut bpf_program);
661                return Error::new(raw::pcap_geterr(*self.handle));
662            }
663
664            raw::pcap_freecode(&mut bpf_program);
665            Ok(())
666        }
667    }
668
669    pub fn stats(&mut self) -> Result<Stat, Error> {
670        unsafe {
671            let mut stats: raw::Struct_pcap_stat =
672                raw::Struct_pcap_stat {ps_recv: 0, ps_drop: 0, ps_ifdrop: 0};
673
674            if -1 == raw::pcap_stats(*self.handle, &mut stats) {
675                return Error::new(raw::pcap_geterr(*self.handle));
676            }
677
678            Ok(Stat {
679                received: stats.ps_recv,
680                dropped: stats.ps_drop,
681                if_dropped: stats.ps_ifdrop
682            })
683        }
684    }
685}
686
687impl Capture<Active> {
688    /// Sends a packet over this capture handle's interface.
689    pub fn sendpacket<'a>(&mut self, buf: &'a [u8]) -> Result<(), Error> {
690        unsafe {
691            let result = raw::pcap_sendpacket(*self.handle, buf.as_ptr() as *const _, buf.len() as i32);
692
693            match result {
694                -1 => {
695                    return Error::new(raw::pcap_geterr(*self.handle));
696                },
697                _ => {
698                    Ok(())
699                }
700            }
701        }
702    }
703}
704
705impl Capture<Dead> {
706    /// Creates a "fake" capture handle for the given link type.
707    pub fn dead(linktype: Linktype) -> Result<Capture<Dead>, Error> {
708        unsafe {
709            let handle = raw::pcap_open_dead(linktype.0, 65535);
710            if handle.is_null() {
711                return Err(Error::InsufficientMemory);
712            }
713
714            Ok(Capture {
715                handle: Unique::new(handle),
716                _marker: PhantomData
717            })
718        }
719    }
720}
721
722#[cfg(not(windows))]
723impl AsRawFd for Capture<Active> {
724    fn as_raw_fd(&self) -> RawFd {
725        unsafe {
726            let fd = raw::pcap_fileno(*self.handle);
727
728            match fd {
729                -1 => {
730                    panic!("Unable to get file descriptor for live capture");
731                },
732                fd => {
733                    fd
734                }
735            }
736        }
737    }
738}
739
740impl<T: State + ?Sized> Drop for Capture<T> {
741    fn drop(&mut self) {
742        unsafe {
743            raw::pcap_close(*self.handle)
744        }
745    }
746}
747
748impl<T: Activated> From<Capture<T>> for Capture<Activated> {
749    fn from(cap: Capture<T>) -> Capture<Activated> {
750        unsafe { transmute(cap) }
751    }
752}
753
754/// Abstraction for writing pcap savefiles, which can be read afterwards via `Capture::from_file()`.
755pub struct Savefile {
756    handle: Unique<raw::pcap_dumper_t>
757}
758
759impl Savefile {
760    pub fn write<'a>(&mut self, packet: &'a Packet<'a>) {
761        unsafe {
762            raw::pcap_dump(*self.handle as *mut u8, transmute::<_, &raw::Struct_pcap_pkthdr>(packet.header), packet.data.as_ptr());
763        }
764    }
765}
766
767impl Drop for Savefile {
768    fn drop(&mut self) {
769        unsafe {
770            raw::pcap_dump_close(*self.handle);
771        }
772    }
773}
774
775#[inline]
776fn cstr_to_string(ptr: *const libc::c_char) -> Result<String, Error> {
777    if ptr.is_null() {
778        Err(InvalidString)
779    } else {
780        Ok(try!(str::from_utf8(unsafe{CStr::from_ptr(ptr)}.to_bytes())).into())
781    }
782}