use core::cell::RefCell; #[cfg(feature = "std")] use std::io::Write; use byteorder::{ByteOrder, NativeEndian}; use Error; use super::{DeviceLimits, Device}; enum_with_unknown! { /// Captured packet header type. pub doc enum PcapLinkType(u32) { /// Ethernet frames Ethernet = 1, /// IPv4 or IPv6 packets (depending on the version field) Ip = 101 } } /// Packet capture mode. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum PcapMode { /// Capture both received and transmitted packets. Both, /// Capture only received packets. RxOnly, /// Capture only transmitted packets. TxOnly } /// A packet capture sink. /// /// A sink is an interface to the platform functions, providing timestamping /// and streaming data output. pub trait PcapSink { /// Write data into the sink. fn write(&self, data: &[u8]); /// Write an `u16` into the sink, in native byte order. fn write_u16(&self, value: u16) { let mut bytes = [0u8; 2]; NativeEndian::write_u16(&mut bytes, value); self.write(&bytes[..]) } /// Write an `u32` into the sink, in native byte order. fn write_u32(&self, value: u32) { let mut bytes = [0u8; 4]; NativeEndian::write_u32(&mut bytes, value); self.write(&bytes[..]) } /// Write the libpcap global header into the sink. /// /// This method may be overridden e.g. if special synchronization is necessary. fn global_header(&self, link_type: PcapLinkType) { self.write_u32(0xa1b2c3d4); // magic number self.write_u16(2); // major version self.write_u16(4); // minor version self.write_u32(0); // timezone (= UTC) self.write_u32(0); // accuracy (not used) self.write_u32(65535); // maximum packet length self.write_u32(link_type.into()); // link-layer header type } /// Write the libpcap packet header into the sink. /// /// See also the note for [global_header](#method.global_header). fn packet_header(&self, timestamp: u64, length: usize) { assert!(length <= 65535); let (seconds, micros) = (timestamp / 1000, timestamp % 1000 * 1000); self.write_u32(seconds as u32); // timestamp seconds self.write_u32(micros as u32); // timestamp microseconds self.write_u32(length as u32); // captured length self.write_u32(length as u32); // original length } /// Write the libpcap packet header followed by packet data into the sink. /// /// See also the note for [global_header](#method.global_header). fn packet(&self, timestamp: u64, packet: &[u8]) { self.packet_header(timestamp, packet.len()); self.write(packet) } } impl> PcapSink for T { fn write(&self, data: &[u8]) { self.as_ref().write(data) } } #[cfg(feature = "std")] impl> PcapSink for RefCell { fn write(&self, data: &[u8]) { self.borrow_mut().as_mut().write_all(data).expect("cannot write") } fn packet(&self, timestamp: u64, packet: &[u8]) { self.packet_header(timestamp, packet.len()); PcapSink::write(self, packet); self.borrow_mut().as_mut().flush().expect("cannot flush") } } /// A packet capture writer device. /// /// Every packet transmitted or received through this device is timestamped /// and written (in the [libpcap] format) using the provided [sink]. /// Note that writes are fine-grained, and buffering is recommended. /// /// The packet sink should be cheaply cloneable, as it is cloned on every /// transmitted packet. For example, `&'a mut Vec` is cheaply cloneable /// but `&std::io::File` /// /// [libpcap]: https://wiki.wireshark.org/Development/LibpcapFileFormat /// [sink]: trait.PcapSink.html #[derive(Debug)] pub struct PcapWriter { lower: D, sink: S, mode: PcapMode } impl PcapWriter { /// Creates a packet capture writer. pub fn new(lower: D, sink: S, mode: PcapMode, link_type: PcapLinkType) -> PcapWriter { sink.global_header(link_type); PcapWriter { lower, sink, mode } } } impl Device for PcapWriter { type RxBuffer = D::RxBuffer; type TxBuffer = TxBuffer; fn limits(&self) -> DeviceLimits { self.lower.limits() } fn receive(&mut self, timestamp: u64) -> Result { let buffer = self.lower.receive(timestamp)?; match self.mode { PcapMode::Both | PcapMode::RxOnly => self.sink.packet(timestamp, buffer.as_ref()), PcapMode::TxOnly => () } Ok(buffer) } fn transmit(&mut self, timestamp: u64, length: usize) -> Result { let buffer = self.lower.transmit(timestamp, length)?; Ok(TxBuffer { buffer, timestamp, sink: self.sink.clone(), mode: self.mode }) } } #[doc(hidden)] pub struct TxBuffer + AsMut<[u8]>, S: PcapSink> { buffer: B, timestamp: u64, sink: S, mode: PcapMode } impl AsRef<[u8]> for TxBuffer where B: AsRef<[u8]> + AsMut<[u8]>, S: PcapSink { fn as_ref(&self) -> &[u8] { self.buffer.as_ref() } } impl AsMut<[u8]> for TxBuffer where B: AsRef<[u8]> + AsMut<[u8]>, S: PcapSink { fn as_mut(&mut self) -> &mut [u8] { self.buffer.as_mut() } } impl Drop for TxBuffer where B: AsRef<[u8]> + AsMut<[u8]>, S: PcapSink { fn drop(&mut self) { match self.mode { PcapMode::Both | PcapMode::TxOnly => self.sink.packet(self.timestamp, self.as_ref()), PcapMode::RxOnly => () } } }