1use std::fmt::{self, Formatter};
50use std::mem;
51
52use zerocopy::byteorder::{BigEndian, U16, U32};
53use zerocopy::{FromBytes, IntoBytes, Unaligned};
54
55use crate::packet::{HeaderParser, PacketHeader};
56
57#[repr(C, packed)]
68#[derive(
69 FromBytes, IntoBytes, Unaligned, Debug, Clone, Copy, zerocopy::KnownLayout, zerocopy::Immutable,
70)]
71pub struct SctpHeader {
72 src_port: U16<BigEndian>,
73 dst_port: U16<BigEndian>,
74 verification_tag: U32<BigEndian>,
75 checksum: U32<BigEndian>,
76}
77
78impl SctpHeader {
79 #[inline]
81 pub fn src_port(&self) -> u16 {
82 self.src_port.get()
83 }
84
85 #[inline]
87 pub fn dst_port(&self) -> u16 {
88 self.dst_port.get()
89 }
90
91 #[inline]
96 pub fn verification_tag(&self) -> u32 {
97 self.verification_tag.get()
98 }
99
100 #[inline]
102 pub fn checksum(&self) -> u32 {
103 self.checksum.get()
104 }
105
106 #[inline]
108 pub fn header_len(&self) -> usize {
109 mem::size_of::<SctpHeader>()
110 }
111
112 #[inline]
117 pub fn is_valid(&self) -> bool {
118 true
121 }
122
123 pub fn compute_checksum(sctp_data: &[u8]) -> u32 {
128 const CRC32C_POLYNOMIAL: u32 = 0x1EDC6F41;
129 const CRC32C_INITIAL: u32 = 0xFFFFFFFF;
130
131 let mut crc = CRC32C_INITIAL;
132
133 let mut data = sctp_data.to_vec();
135 if data.len() >= 12 {
136 data[8..12].copy_from_slice(&[0, 0, 0, 0]);
138 }
139
140 for &byte in &data {
141 crc ^= byte as u32;
142 for _ in 0..8 {
143 if crc & 1 != 0 {
144 crc = (crc >> 1) ^ CRC32C_POLYNOMIAL;
145 } else {
146 crc >>= 1;
147 }
148 }
149 }
150
151 !crc
152 }
153
154 pub fn verify_checksum(&self, sctp_data: &[u8]) -> bool {
158 let stored_checksum = self.checksum();
159 let computed = Self::compute_checksum(sctp_data);
160 computed == stored_checksum
161 }
162}
163
164impl PacketHeader for SctpHeader {
165 const NAME: &'static str = "SctpHeader";
166
167 #[inline]
168 fn is_valid(&self) -> bool {
169 self.is_valid()
170 }
171
172 type InnerType = ();
173
174 #[inline]
175 fn inner_type(&self) -> Self::InnerType {}
176}
177
178impl HeaderParser for SctpHeader {
179 type Output<'a> = &'a SctpHeader;
180
181 #[inline]
182 fn into_view<'a>(header: &'a Self, _: &'a [u8]) -> Self::Output<'a> {
183 header
184 }
185}
186
187impl fmt::Display for SctpHeader {
188 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
189 write!(
190 f,
191 "SCTP {} -> {} vtag=0x{:08x}",
192 self.src_port(),
193 self.dst_port(),
194 self.verification_tag()
195 )
196 }
197}
198
199#[cfg(test)]
200mod tests {
201 use super::*;
202
203 #[test]
204 fn test_sctp_header_basic() {
205 let header = SctpHeader {
206 src_port: U16::new(3868),
207 dst_port: U16::new(3868),
208 verification_tag: U32::new(0x12345678),
209 checksum: U32::new(0),
210 };
211
212 assert_eq!(header.src_port(), 3868);
213 assert_eq!(header.dst_port(), 3868);
214 assert_eq!(header.verification_tag(), 0x12345678);
215 assert_eq!(header.checksum(), 0);
216 assert_eq!(header.header_len(), 12);
217 assert!(header.is_valid());
218 }
219
220 #[test]
221 fn test_sctp_header_size() {
222 assert_eq!(mem::size_of::<SctpHeader>(), 12);
223 assert_eq!(SctpHeader::FIXED_LEN, 12);
224 }
225
226 #[test]
227 fn test_sctp_parsing_basic() {
228 let packet = create_test_packet();
229
230 let result = SctpHeader::from_bytes(&packet);
231 assert!(result.is_ok());
232
233 let (header, payload) = result.unwrap();
234 assert_eq!(header.src_port(), 2905);
235 assert_eq!(header.dst_port(), 2905);
236 assert_eq!(header.verification_tag(), 0xABCDEF01);
237 assert!(header.is_valid());
238 assert_eq!(payload.len(), 8); }
240
241 #[test]
242 fn test_sctp_parsing_too_small() {
243 let packet = vec![0u8; 11]; let result = SctpHeader::from_bytes(&packet);
246 assert!(result.is_err());
247 }
248
249 #[test]
250 fn test_sctp_total_len() {
251 let packet = create_test_packet();
252 let (header, _) = SctpHeader::from_bytes(&packet).unwrap();
253
254 assert_eq!(header.total_len(&packet), 12);
256 }
257
258 #[test]
259 fn test_sctp_from_bytes_with_payload() {
260 let mut packet = Vec::new();
261
262 packet.extend_from_slice(&9899u16.to_be_bytes()); packet.extend_from_slice(&9899u16.to_be_bytes()); packet.extend_from_slice(&0x11223344u32.to_be_bytes()); packet.extend_from_slice(&0u32.to_be_bytes()); let chunk_data = b"SCTP CHUNK DATA";
270 packet.extend_from_slice(chunk_data);
271
272 let result = SctpHeader::from_bytes(&packet);
273 assert!(result.is_ok());
274
275 let (header, payload) = result.unwrap();
276
277 assert_eq!(header.src_port(), 9899);
279 assert_eq!(header.dst_port(), 9899);
280 assert_eq!(header.verification_tag(), 0x11223344);
281
282 assert_eq!(payload.len(), chunk_data.len());
284 assert_eq!(payload, chunk_data);
285 }
286
287 #[test]
288 fn test_sctp_init_chunk() {
289 let mut packet = Vec::new();
290
291 packet.extend_from_slice(&5000u16.to_be_bytes()); packet.extend_from_slice(&5000u16.to_be_bytes()); packet.extend_from_slice(&0u32.to_be_bytes()); packet.extend_from_slice(&0x12345678u32.to_be_bytes()); let chunk_data = vec![
299 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x0A, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x02, ];
308 packet.extend_from_slice(&chunk_data);
309
310 let (header, payload) = SctpHeader::from_bytes(&packet).unwrap();
311
312 assert_eq!(header.src_port(), 5000);
313 assert_eq!(header.dst_port(), 5000);
314 assert_eq!(header.verification_tag(), 0); assert_eq!(payload.len(), chunk_data.len());
316 }
317
318 #[test]
319 fn test_sctp_multiple_ports() {
320 let test_cases: Vec<(u16, u16)> = vec![
322 (2905, 2905), (3868, 3868), (9899, 9899), (36412, 36412), (38412, 38412), ];
328
329 for (src, dst) in test_cases {
330 let mut packet = Vec::new();
331 packet.extend_from_slice(&src.to_be_bytes());
332 packet.extend_from_slice(&dst.to_be_bytes());
333 packet.extend_from_slice(&0x11111111u32.to_be_bytes());
334 packet.extend_from_slice(&0x22222222u32.to_be_bytes());
335
336 let (header, _) = SctpHeader::from_bytes(&packet).unwrap();
337 assert_eq!(header.src_port(), src);
338 assert_eq!(header.dst_port(), dst);
339 }
340 }
341
342 #[test]
343 fn test_sctp_checksum_computation() {
344 let mut packet = Vec::new();
345
346 packet.extend_from_slice(&2905u16.to_be_bytes()); packet.extend_from_slice(&2905u16.to_be_bytes()); packet.extend_from_slice(&0x12345678u32.to_be_bytes()); packet.extend_from_slice(&0u32.to_be_bytes()); packet.extend_from_slice(&[0x01, 0x00, 0x00, 0x04]); let checksum = SctpHeader::compute_checksum(&packet);
356
357 assert_ne!(checksum, 0);
360 }
361
362 #[test]
363 fn test_sctp_verification_tag_values() {
364 let tags = vec![0x00000000, 0xFFFFFFFF, 0x12345678, 0xABCDEF01];
366
367 for tag in tags {
368 let header = SctpHeader {
369 src_port: U16::new(2905),
370 dst_port: U16::new(2905),
371 verification_tag: U32::new(tag),
372 checksum: U32::new(0),
373 };
374
375 assert_eq!(header.verification_tag(), tag);
376 }
377 }
378
379 #[test]
380 fn test_sctp_wellknown_ports() {
381 let header_diameter = SctpHeader {
383 src_port: U16::new(3868),
384 dst_port: U16::new(3868),
385 verification_tag: U32::new(0),
386 checksum: U32::new(0),
387 };
388 assert_eq!(header_diameter.src_port(), 3868); let header_s1ap = SctpHeader {
391 src_port: U16::new(36412),
392 dst_port: U16::new(36412),
393 verification_tag: U32::new(0),
394 checksum: U32::new(0),
395 };
396 assert_eq!(header_s1ap.src_port(), 36412); }
398
399 fn create_test_packet() -> Vec<u8> {
401 let mut packet = Vec::new();
402
403 packet.extend_from_slice(&2905u16.to_be_bytes());
405
406 packet.extend_from_slice(&2905u16.to_be_bytes());
408
409 packet.extend_from_slice(&0xABCDEF01u32.to_be_bytes());
411
412 packet.extend_from_slice(&0u32.to_be_bytes());
414
415 packet.extend_from_slice(b"SCTP_TST");
417
418 packet
419 }
420}