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