1#![deny(missing_docs)]
10
11use packet_dissector_core::dissector::{DispatchHint, DissectResult, Dissector};
12use packet_dissector_core::error::PacketError;
13use packet_dissector_core::field::{FieldDescriptor, FieldType, FieldValue};
14use packet_dissector_core::lookup::ip_protocol_name;
15use packet_dissector_core::packet::DissectBuffer;
16use packet_dissector_core::util::read_be_u16;
17
18const MIN_HEADER_SIZE: usize = 20;
20
21const FD_VERSION: usize = 0;
23const FD_IHL: usize = 1;
24const FD_DSCP: usize = 2;
25const FD_ECN: usize = 3;
26const FD_TOTAL_LENGTH: usize = 4;
27const FD_IDENTIFICATION: usize = 5;
28const FD_FLAGS: usize = 6;
29const FD_FRAGMENT_OFFSET: usize = 7;
30const FD_TTL: usize = 8;
31const FD_PROTOCOL: usize = 9;
32const FD_CHECKSUM: usize = 10;
33const FD_SRC: usize = 11;
34const FD_DST: usize = 12;
35const FD_OPTIONS: usize = 13;
36
37static FIELD_DESCRIPTORS: &[FieldDescriptor] = &[
38 FieldDescriptor::new("version", "Version", FieldType::U8),
39 FieldDescriptor::new("ihl", "Internet Header Length", FieldType::U8),
40 FieldDescriptor::new("dscp", "Differentiated Services Code Point", FieldType::U8),
41 FieldDescriptor::new("ecn", "Explicit Congestion Notification", FieldType::U8),
42 FieldDescriptor::new("total_length", "Total Length", FieldType::U16),
43 FieldDescriptor::new("identification", "Identification", FieldType::U16),
44 FieldDescriptor::new("flags", "Flags", FieldType::U8),
45 FieldDescriptor::new("fragment_offset", "Fragment Offset", FieldType::U16),
46 FieldDescriptor::new("ttl", "Time to Live", FieldType::U8),
47 FieldDescriptor {
48 name: "protocol",
49 display_name: "Protocol",
50 field_type: FieldType::U8,
51 optional: false,
52 children: None,
53 display_fn: Some(|v, _siblings| match v {
54 FieldValue::U8(p) => ip_protocol_name(*p),
55 _ => None,
56 }),
57 format_fn: None,
58 },
59 FieldDescriptor::new("checksum", "Header Checksum", FieldType::U16),
60 FieldDescriptor::new("src", "Source Address", FieldType::Ipv4Addr),
61 FieldDescriptor::new("dst", "Destination Address", FieldType::Ipv4Addr),
62 FieldDescriptor::new("options", "Options", FieldType::Bytes).optional(),
63];
64
65pub struct Ipv4Dissector;
67
68impl Dissector for Ipv4Dissector {
69 fn name(&self) -> &'static str {
70 "Internet Protocol version 4"
71 }
72
73 fn short_name(&self) -> &'static str {
74 "IPv4"
75 }
76
77 fn field_descriptors(&self) -> &'static [FieldDescriptor] {
78 FIELD_DESCRIPTORS
79 }
80
81 fn dissect<'pkt>(
82 &self,
83 data: &'pkt [u8],
84 buf: &mut DissectBuffer<'pkt>,
85 offset: usize,
86 ) -> Result<DissectResult, PacketError> {
87 if data.len() < MIN_HEADER_SIZE {
88 return Err(PacketError::Truncated {
89 expected: MIN_HEADER_SIZE,
90 actual: data.len(),
91 });
92 }
93
94 let version = (data[0] >> 4) & 0x0F;
97 let ihl = (data[0] & 0x0F) as usize;
98
99 if version != 4 {
103 return Err(PacketError::InvalidFieldValue {
104 field: "version",
105 value: version as u32,
106 });
107 }
108
109 if ihl < 5 {
112 return Err(PacketError::InvalidFieldValue {
113 field: "ihl",
114 value: ihl as u32,
115 });
116 }
117
118 let header_len = ihl * 4;
119 if data.len() < header_len {
120 return Err(PacketError::Truncated {
121 expected: header_len,
122 actual: data.len(),
123 });
124 }
125
126 let total_length = read_be_u16(data, 2)?;
131 if (total_length as usize) < header_len {
132 return Err(PacketError::InvalidFieldValue {
133 field: "total_length",
134 value: total_length as u32,
135 });
136 }
137
138 if data.len() < total_length as usize {
142 return Err(PacketError::Truncated {
143 expected: total_length as usize,
144 actual: data.len(),
145 });
146 }
147
148 let dscp = data[1] >> 2;
153 let ecn = data[1] & 0x03;
154
155 let identification = read_be_u16(data, 4)?;
160
161 let flags_frag = read_be_u16(data, 6)?;
165 let flags = ((flags_frag >> 13) & 0x07) as u8;
166 let fragment_offset = flags_frag & 0x1FFF;
167
168 let ttl = data[8];
169 let protocol = data[9];
170 let checksum = read_be_u16(data, 10)?;
171 let src = [data[12], data[13], data[14], data[15]];
172 let dst = [data[16], data[17], data[18], data[19]];
173
174 buf.begin_layer(
175 self.short_name(),
176 None,
177 FIELD_DESCRIPTORS,
178 offset..offset + header_len,
179 );
180 buf.push_field(
181 &FIELD_DESCRIPTORS[FD_VERSION],
182 FieldValue::U8(version),
183 offset..offset + 1,
184 );
185 buf.push_field(
186 &FIELD_DESCRIPTORS[FD_IHL],
187 FieldValue::U8(ihl as u8),
188 offset..offset + 1,
189 );
190 buf.push_field(
191 &FIELD_DESCRIPTORS[FD_DSCP],
192 FieldValue::U8(dscp),
193 offset + 1..offset + 2,
194 );
195 buf.push_field(
196 &FIELD_DESCRIPTORS[FD_ECN],
197 FieldValue::U8(ecn),
198 offset + 1..offset + 2,
199 );
200 buf.push_field(
201 &FIELD_DESCRIPTORS[FD_TOTAL_LENGTH],
202 FieldValue::U16(total_length),
203 offset + 2..offset + 4,
204 );
205 buf.push_field(
206 &FIELD_DESCRIPTORS[FD_IDENTIFICATION],
207 FieldValue::U16(identification),
208 offset + 4..offset + 6,
209 );
210 buf.push_field(
215 &FIELD_DESCRIPTORS[FD_FLAGS],
216 FieldValue::U8(flags),
217 offset + 6..offset + 7,
218 );
219 buf.push_field(
220 &FIELD_DESCRIPTORS[FD_FRAGMENT_OFFSET],
221 FieldValue::U16(fragment_offset),
222 offset + 6..offset + 8,
223 );
224 buf.push_field(
225 &FIELD_DESCRIPTORS[FD_TTL],
226 FieldValue::U8(ttl),
227 offset + 8..offset + 9,
228 );
229 buf.push_field(
230 &FIELD_DESCRIPTORS[FD_PROTOCOL],
231 FieldValue::U8(protocol),
232 offset + 9..offset + 10,
233 );
234 buf.push_field(
235 &FIELD_DESCRIPTORS[FD_CHECKSUM],
236 FieldValue::U16(checksum),
237 offset + 10..offset + 12,
238 );
239 buf.push_field(
240 &FIELD_DESCRIPTORS[FD_SRC],
241 FieldValue::Ipv4Addr(src),
242 offset + 12..offset + 16,
243 );
244 buf.push_field(
245 &FIELD_DESCRIPTORS[FD_DST],
246 FieldValue::Ipv4Addr(dst),
247 offset + 16..offset + 20,
248 );
249
250 if header_len > MIN_HEADER_SIZE {
253 buf.push_field(
254 &FIELD_DESCRIPTORS[FD_OPTIONS],
255 FieldValue::Bytes(&data[MIN_HEADER_SIZE..header_len]),
256 offset + MIN_HEADER_SIZE..offset + header_len,
257 );
258 }
259
260 buf.end_layer();
261
262 Ok(DissectResult::new(
263 header_len,
264 DispatchHint::ByIpProtocol(protocol),
265 ))
266 }
267}