Skip to main content

nullsec_carfuzz/protocols/
mod.rs

1use rand::Rng;
2use rand::seq::SliceRandom;
3use super::{CanFrame, mutate};
4
5// ──────────────────────────────────────────────
6// CAN raw frame generation
7// ──────────────────────────────────────────────
8
9/// Generate a random raw CAN 2.0A frame (11-bit ID).
10pub fn can_random(rng: &mut impl Rng) -> CanFrame {
11    CanFrame::random(rng)
12}
13
14/// Generate a CAN-FD frame (29-bit extended ID, up to 64 bytes).
15pub fn canfd_random(rng: &mut impl Rng) -> CanFrame {
16    let arb_id: u32 = rng.gen_range(0..0x1FFF_FFFF);
17    let len: usize = rng.gen_range(1..=64);
18    let data: Vec<u8> = (0..len).map(|_| rng.gen()).collect();
19    CanFrame { arb_id, extended: true, data }
20}
21
22// ──────────────────────────────────────────────
23// UDS (ISO 14229) frame builders
24// ──────────────────────────────────────────────
25
26pub const UDS_SERVICES: &[u8] = &[
27    0x10, // DiagnosticSessionControl
28    0x11, // ECUReset
29    0x14, // ClearDiagnosticInformation
30    0x19, // ReadDTCInformation
31    0x22, // ReadDataByIdentifier
32    0x23, // ReadMemoryByAddress
33    0x27, // SecurityAccess
34    0x28, // CommunicationControl
35    0x2A, // ReadDataByPeriodicIdentifier
36    0x2C, // DynamicallyDefineDataIdentifier
37    0x2E, // WriteDataByIdentifier
38    0x2F, // InputOutputControlByIdentifier
39    0x31, // RoutineControl
40    0x34, // RequestDownload
41    0x35, // RequestUpload
42    0x36, // TransferData
43    0x37, // RequestTransferExit
44    0x3D, // WriteMemoryByAddress
45    0x3E, // TesterPresent
46    0x85, // ControlDTCSetting
47    0x86, // ResponseOnEvent
48    0x87, // LinkControl
49];
50
51/// Build a UDS request frame for the given target ECU arbitration ID.
52pub fn uds_request(target: u32, rng: &mut impl Rng) -> CanFrame {
53    let service = *UDS_SERVICES.choose(rng).unwrap();
54    let mut data = vec![service];
55    // Add sub-function / DID / address bytes
56    let extra = rng.gen_range(0..=6usize);
57    for _ in 0..extra {
58        data.push(rng.gen());
59    }
60    // ISO TP single frame: first byte = length
61    let len = data.len() as u8;
62    let mut frame_data = vec![len];
63    frame_data.extend_from_slice(&data);
64    frame_data.truncate(8);
65    CanFrame::new(target, frame_data)
66}
67
68/// Security access level 1 seed request (service 0x27 subfunction 0x01).
69pub fn uds_security_access_seed(target: u32) -> CanFrame {
70    CanFrame::new(target, vec![0x02, 0x27, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00])
71}
72
73/// Mutate an existing UDS frame.
74pub fn uds_mutate(frame: &CanFrame, rng: &mut impl Rng) -> CanFrame {
75    CanFrame::new(frame.arb_id, mutate(&frame.data, rng))
76}
77
78// ──────────────────────────────────────────────
79// OBD-II (ISO 15031) frame builders
80// ──────────────────────────────────────────────
81
82pub const OBD_MODES: &[u8] = &[
83    0x01, // Current data
84    0x02, // Freeze frame
85    0x03, // Stored DTCs
86    0x04, // Clear DTCs
87    0x05, // O2 sensor monitoring (legacy)
88    0x06, // On-board monitoring results
89    0x07, // Pending DTCs
90    0x08, // Control on-board system
91    0x09, // Vehicle info
92    0x0A, // Permanent DTCs
93];
94
95/// Generate a random OBD-II request on the functional address 0x7DF.
96pub fn obd_request(rng: &mut impl Rng) -> CanFrame {
97    let mode = *OBD_MODES.choose(rng).unwrap();
98    let pid: u8 = rng.gen();
99    CanFrame::new(0x7DF, vec![0x02, mode, pid, 0x00, 0x00, 0x00, 0x00, 0x00])
100}
101
102// ──────────────────────────────────────────────
103// DoIP (ISO 13400) payload builders (UDP/TCP)
104// ──────────────────────────────────────────────
105
106pub const DOIP_PAYLOAD_TYPES: &[u16] = &[
107    0x0001, // Vehicle identification request
108    0x0002, // Vehicle identification request with EID
109    0x0003, // Vehicle identification request with VIN
110    0x0004, // Vehicle announcement
111    0x0005, // Routing activation request
112    0x0006, // Routing activation response
113    0x0007, // Alive check request
114    0x0008, // Alive check response
115    0x4001, // Diagnostic message
116    0x4002, // Diagnostic message positive ack
117    0x4003, // Diagnostic message negative ack
118    0x0501, // Entity status request
119    0x0502, // Entity status response
120];
121
122/// Build a raw DoIP frame as bytes (generic header + fuzzed payload).
123pub fn doip_frame(rng: &mut impl Rng) -> Vec<u8> {
124    let payload_type = *DOIP_PAYLOAD_TYPES.choose(rng).unwrap();
125    let payload_len = rng.gen_range(0u32..=64);
126    let payload: Vec<u8> = (0..payload_len).map(|_| rng.gen()).collect();
127    let mut frame = vec![
128        0x02, // Protocol version
129        0xFD, // Inverse protocol version
130        ((payload_type >> 8) & 0xFF) as u8,
131        (payload_type & 0xFF) as u8,
132        ((payload_len >> 24) & 0xFF) as u8,
133        ((payload_len >> 16) & 0xFF) as u8,
134        ((payload_len >> 8) & 0xFF) as u8,
135        (payload_len & 0xFF) as u8,
136    ];
137    frame.extend_from_slice(&payload);
138    frame
139}
140
141// ──────────────────────────────────────────────
142// J1939 (SAE heavy-duty) frame builders
143// ──────────────────────────────────────────────
144
145/// Generate a random J1939 frame (29-bit PGN-based ID).
146pub fn j1939_random(rng: &mut impl Rng) -> CanFrame {
147    let priority: u32 = rng.gen_range(0u32..8) << 26;
148    let pgn: u32 = rng.gen_range(0u32..0xFFFF) << 8;
149    let sa: u32 = rng.gen_range(0u32..0xFF);
150    let arb_id = priority | pgn | sa;
151    let len = rng.gen_range(1..=8);
152    let data: Vec<u8> = (0..len).map(|_| rng.gen()).collect();
153    CanFrame { arb_id, extended: true, data }
154}
155
156