1 use byteorder::{ByteOrder, NativeEndian}; 2 use core::cell::RefCell; 3 use phy::Medium; 4 #[cfg(feature = "std")] 5 use std::io::Write; 6 7 use crate::phy::{self, Device, DeviceCapabilities}; 8 use crate::time::Instant; 9 10 enum_with_unknown! { 11 /// Captured packet header type. 12 pub enum PcapLinkType(u32) { 13 /// Ethernet frames 14 Ethernet = 1, 15 /// IPv4 or IPv6 packets (depending on the version field) 16 Ip = 101, 17 /// IEEE 802.15.4 packets with FCS included. 18 Ieee802154WithFcs = 195, 19 } 20 } 21 22 /// Packet capture mode. 23 #[derive(Debug, Clone, Copy, PartialEq, Eq)] 24 #[cfg_attr(feature = "defmt", derive(defmt::Format))] 25 pub enum PcapMode { 26 /// Capture both received and transmitted packets. 27 Both, 28 /// Capture only received packets. 29 RxOnly, 30 /// Capture only transmitted packets. 31 TxOnly, 32 } 33 34 /// A packet capture sink. 35 pub trait PcapSink { 36 /// Write data into the sink. write(&mut self, data: &[u8])37 fn write(&mut self, data: &[u8]); 38 39 /// Flush data written into the sync. flush(&mut self)40 fn flush(&mut self) {} 41 42 /// Write an `u16` into the sink, in native byte order. write_u16(&mut self, value: u16)43 fn write_u16(&mut self, value: u16) { 44 let mut bytes = [0u8; 2]; 45 NativeEndian::write_u16(&mut bytes, value); 46 self.write(&bytes[..]) 47 } 48 49 /// Write an `u32` into the sink, in native byte order. write_u32(&mut self, value: u32)50 fn write_u32(&mut self, value: u32) { 51 let mut bytes = [0u8; 4]; 52 NativeEndian::write_u32(&mut bytes, value); 53 self.write(&bytes[..]) 54 } 55 56 /// Write the libpcap global header into the sink. 57 /// 58 /// This method may be overridden e.g. if special synchronization is necessary. global_header(&mut self, link_type: PcapLinkType)59 fn global_header(&mut self, link_type: PcapLinkType) { 60 self.write_u32(0xa1b2c3d4); // magic number 61 self.write_u16(2); // major version 62 self.write_u16(4); // minor version 63 self.write_u32(0); // timezone (= UTC) 64 self.write_u32(0); // accuracy (not used) 65 self.write_u32(65535); // maximum packet length 66 self.write_u32(link_type.into()); // link-layer header type 67 } 68 69 /// Write the libpcap packet header into the sink. 70 /// 71 /// See also the note for [global_header](#method.global_header). 72 /// 73 /// # Panics 74 /// This function panics if `length` is greater than 65535. packet_header(&mut self, timestamp: Instant, length: usize)75 fn packet_header(&mut self, timestamp: Instant, length: usize) { 76 assert!(length <= 65535); 77 78 self.write_u32(timestamp.secs() as u32); // timestamp seconds 79 self.write_u32(timestamp.micros() as u32); // timestamp microseconds 80 self.write_u32(length as u32); // captured length 81 self.write_u32(length as u32); // original length 82 } 83 84 /// Write the libpcap packet header followed by packet data into the sink. 85 /// 86 /// See also the note for [global_header](#method.global_header). packet(&mut self, timestamp: Instant, packet: &[u8])87 fn packet(&mut self, timestamp: Instant, packet: &[u8]) { 88 self.packet_header(timestamp, packet.len()); 89 self.write(packet); 90 self.flush(); 91 } 92 } 93 94 #[cfg(feature = "std")] 95 impl<T: Write> PcapSink for T { write(&mut self, data: &[u8])96 fn write(&mut self, data: &[u8]) { 97 T::write_all(self, data).expect("cannot write") 98 } 99 flush(&mut self)100 fn flush(&mut self) { 101 T::flush(self).expect("cannot flush") 102 } 103 } 104 105 /// A packet capture writer device. 106 /// 107 /// Every packet transmitted or received through this device is timestamped 108 /// and written (in the [libpcap] format) using the provided [sink]. 109 /// Note that writes are fine-grained, and buffering is recommended. 110 /// 111 /// The packet sink should be cheaply cloneable, as it is cloned on every 112 /// transmitted packet. For example, `&'a mut Vec<u8>` is cheaply cloneable 113 /// but `&std::io::File` 114 /// 115 /// [libpcap]: https://wiki.wireshark.org/Development/LibpcapFileFormat 116 /// [sink]: trait.PcapSink.html 117 #[derive(Debug)] 118 pub struct PcapWriter<D, S> 119 where 120 D: Device, 121 S: PcapSink, 122 { 123 lower: D, 124 sink: RefCell<S>, 125 mode: PcapMode, 126 } 127 128 impl<D: Device, S: PcapSink> PcapWriter<D, S> { 129 /// Creates a packet capture writer. new(lower: D, mut sink: S, mode: PcapMode) -> PcapWriter<D, S>130 pub fn new(lower: D, mut sink: S, mode: PcapMode) -> PcapWriter<D, S> { 131 let medium = lower.capabilities().medium; 132 let link_type = match medium { 133 #[cfg(feature = "medium-ip")] 134 Medium::Ip => PcapLinkType::Ip, 135 #[cfg(feature = "medium-ethernet")] 136 Medium::Ethernet => PcapLinkType::Ethernet, 137 #[cfg(feature = "medium-ieee802154")] 138 Medium::Ieee802154 => PcapLinkType::Ieee802154WithFcs, 139 }; 140 sink.global_header(link_type); 141 PcapWriter { 142 lower, 143 sink: RefCell::new(sink), 144 mode, 145 } 146 } 147 148 /// Get a reference to the underlying device. 149 /// 150 /// Even if the device offers reading through a standard reference, it is inadvisable to 151 /// directly read from the device as doing so will circumvent the packet capture. get_ref(&self) -> &D152 pub fn get_ref(&self) -> &D { 153 &self.lower 154 } 155 156 /// Get a mutable reference to the underlying device. 157 /// 158 /// It is inadvisable to directly read from the device as doing so will circumvent the packet capture. get_mut(&mut self) -> &mut D159 pub fn get_mut(&mut self) -> &mut D { 160 &mut self.lower 161 } 162 } 163 164 impl<D: Device, S> Device for PcapWriter<D, S> 165 where 166 S: PcapSink, 167 { 168 type RxToken<'a> = RxToken<'a, D::RxToken<'a>, S> 169 where 170 Self: 'a; 171 type TxToken<'a> = TxToken<'a, D::TxToken<'a>, S> 172 where 173 Self: 'a; 174 capabilities(&self) -> DeviceCapabilities175 fn capabilities(&self) -> DeviceCapabilities { 176 self.lower.capabilities() 177 } 178 receive(&mut self, timestamp: Instant) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)>179 fn receive(&mut self, timestamp: Instant) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> { 180 let sink = &self.sink; 181 let mode = self.mode; 182 self.lower 183 .receive(timestamp) 184 .map(move |(rx_token, tx_token)| { 185 let rx = RxToken { 186 token: rx_token, 187 sink, 188 mode, 189 timestamp, 190 }; 191 let tx = TxToken { 192 token: tx_token, 193 sink, 194 mode, 195 timestamp, 196 }; 197 (rx, tx) 198 }) 199 } 200 transmit(&mut self, timestamp: Instant) -> Option<Self::TxToken<'_>>201 fn transmit(&mut self, timestamp: Instant) -> Option<Self::TxToken<'_>> { 202 let sink = &self.sink; 203 let mode = self.mode; 204 self.lower.transmit(timestamp).map(move |token| TxToken { 205 token, 206 sink, 207 mode, 208 timestamp, 209 }) 210 } 211 } 212 213 #[doc(hidden)] 214 pub struct RxToken<'a, Rx: phy::RxToken, S: PcapSink> { 215 token: Rx, 216 sink: &'a RefCell<S>, 217 mode: PcapMode, 218 timestamp: Instant, 219 } 220 221 impl<'a, Rx: phy::RxToken, S: PcapSink> phy::RxToken for RxToken<'a, Rx, S> { consume<R, F: FnOnce(&mut [u8]) -> R>(self, f: F) -> R222 fn consume<R, F: FnOnce(&mut [u8]) -> R>(self, f: F) -> R { 223 self.token.consume(|buffer| { 224 match self.mode { 225 PcapMode::Both | PcapMode::RxOnly => self 226 .sink 227 .borrow_mut() 228 .packet(self.timestamp, buffer.as_ref()), 229 PcapMode::TxOnly => (), 230 } 231 f(buffer) 232 }) 233 } 234 } 235 236 #[doc(hidden)] 237 pub struct TxToken<'a, Tx: phy::TxToken, S: PcapSink> { 238 token: Tx, 239 sink: &'a RefCell<S>, 240 mode: PcapMode, 241 timestamp: Instant, 242 } 243 244 impl<'a, Tx: phy::TxToken, S: PcapSink> phy::TxToken for TxToken<'a, Tx, S> { consume<R, F>(self, len: usize, f: F) -> R where F: FnOnce(&mut [u8]) -> R,245 fn consume<R, F>(self, len: usize, f: F) -> R 246 where 247 F: FnOnce(&mut [u8]) -> R, 248 { 249 self.token.consume(len, |buffer| { 250 let result = f(buffer); 251 match self.mode { 252 PcapMode::Both | PcapMode::TxOnly => { 253 self.sink.borrow_mut().packet(self.timestamp, buffer) 254 } 255 PcapMode::RxOnly => (), 256 }; 257 result 258 }) 259 } 260 } 261