1 use crate::phy::{self, Device, DeviceCapabilities}; 2 use crate::time::Instant; 3 4 // This could be fixed once associated consts are stable. 5 const MTU: usize = 1536; 6 7 /// Represents a fuzzer. It is expected to replace bytes in the packet with fuzzed data. 8 pub trait Fuzzer { 9 /// Modify a single packet with fuzzed data. fuzz_packet(&self, packet_data: &mut [u8])10 fn fuzz_packet(&self, packet_data: &mut [u8]); 11 } 12 13 /// A fuzz injector device. 14 /// 15 /// A fuzz injector is a device that alters packets traversing through it according to the 16 /// directions of a guided fuzzer. It is designed to support fuzzing internal state machines inside 17 /// smoltcp, and is not for production use. 18 #[allow(unused)] 19 #[derive(Debug)] 20 #[cfg_attr(feature = "defmt", derive(defmt::Format))] 21 pub struct FuzzInjector<D: Device, FTx: Fuzzer, FRx: Fuzzer> { 22 inner: D, 23 fuzz_tx: FTx, 24 fuzz_rx: FRx, 25 } 26 27 #[allow(unused)] 28 impl<D: Device, FTx: Fuzzer, FRx: Fuzzer> FuzzInjector<D, FTx, FRx> { 29 /// Create a fuzz injector device. new(inner: D, fuzz_tx: FTx, fuzz_rx: FRx) -> FuzzInjector<D, FTx, FRx>30 pub fn new(inner: D, fuzz_tx: FTx, fuzz_rx: FRx) -> FuzzInjector<D, FTx, FRx> { 31 FuzzInjector { 32 inner, 33 fuzz_tx, 34 fuzz_rx, 35 } 36 } 37 38 /// Return the underlying device, consuming the fuzz injector. into_inner(self) -> D39 pub fn into_inner(self) -> D { 40 self.inner 41 } 42 } 43 44 impl<D: Device, FTx, FRx> Device for FuzzInjector<D, FTx, FRx> 45 where 46 FTx: Fuzzer, 47 FRx: Fuzzer, 48 { 49 type RxToken<'a> = RxToken<'a, D::RxToken<'a>, FRx> 50 where 51 Self: 'a; 52 type TxToken<'a> = TxToken<'a, D::TxToken<'a>, FTx> 53 where 54 Self: 'a; 55 capabilities(&self) -> DeviceCapabilities56 fn capabilities(&self) -> DeviceCapabilities { 57 let mut caps = self.inner.capabilities(); 58 if caps.max_transmission_unit > MTU { 59 caps.max_transmission_unit = MTU; 60 } 61 caps 62 } 63 receive(&mut self, timestamp: Instant) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)>64 fn receive(&mut self, timestamp: Instant) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> { 65 self.inner.receive(timestamp).map(|(rx_token, tx_token)| { 66 let rx = RxToken { 67 fuzzer: &mut self.fuzz_rx, 68 token: rx_token, 69 }; 70 let tx = TxToken { 71 fuzzer: &mut self.fuzz_tx, 72 token: tx_token, 73 }; 74 (rx, tx) 75 }) 76 } 77 transmit(&mut self, timestamp: Instant) -> Option<Self::TxToken<'_>>78 fn transmit(&mut self, timestamp: Instant) -> Option<Self::TxToken<'_>> { 79 self.inner.transmit(timestamp).map(|token| TxToken { 80 fuzzer: &mut self.fuzz_tx, 81 token: token, 82 }) 83 } 84 } 85 86 #[doc(hidden)] 87 pub struct RxToken<'a, Rx: phy::RxToken, F: Fuzzer + 'a> { 88 fuzzer: &'a F, 89 token: Rx, 90 } 91 92 impl<'a, Rx: phy::RxToken, FRx: Fuzzer> phy::RxToken for RxToken<'a, Rx, FRx> { consume<R, F>(self, f: F) -> R where F: FnOnce(&mut [u8]) -> R,93 fn consume<R, F>(self, f: F) -> R 94 where 95 F: FnOnce(&mut [u8]) -> R, 96 { 97 self.token.consume(|buffer| { 98 self.fuzzer.fuzz_packet(buffer); 99 f(buffer) 100 }) 101 } 102 } 103 104 #[doc(hidden)] 105 pub struct TxToken<'a, Tx: phy::TxToken, F: Fuzzer + 'a> { 106 fuzzer: &'a F, 107 token: Tx, 108 } 109 110 impl<'a, Tx: phy::TxToken, FTx: Fuzzer> phy::TxToken for TxToken<'a, Tx, FTx> { consume<R, F>(self, len: usize, f: F) -> R where F: FnOnce(&mut [u8]) -> R,111 fn consume<R, F>(self, len: usize, f: F) -> R 112 where 113 F: FnOnce(&mut [u8]) -> R, 114 { 115 self.token.consume(len, |buf| { 116 let result = f(buf); 117 self.fuzzer.fuzz_packet(buf); 118 result 119 }) 120 } 121 } 122