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