stackforge_core/layer/icmp/checksum.rs
1//! ICMP checksum calculation and verification.
2//!
3//! ICMP uses the Internet checksum (RFC 1071) over the entire ICMP message
4//! (header + data), without a pseudo-header like TCP/UDP.
5
6use crate::utils::internet_checksum;
7
8/// Calculate ICMP checksum.
9///
10/// # Arguments
11/// * `icmp_data` - Complete ICMP packet (header + payload)
12///
13/// # Returns
14/// The calculated checksum.
15///
16/// # Note
17/// Unlike TCP/UDP, ICMP does not use a pseudo-header. The checksum is
18/// calculated over the entire ICMP message only.
19#[must_use]
20pub fn icmp_checksum(icmp_data: &[u8]) -> u16 {
21 internet_checksum(icmp_data)
22}
23
24/// Verify ICMP checksum.
25///
26/// # Arguments
27/// * `icmp_data` - Complete ICMP packet (header + payload) with checksum field
28///
29/// # Returns
30/// `true` if the checksum is valid, `false` otherwise.
31///
32/// # Note
33/// A valid checksum should result in 0 or 0xFFFF when the checksum is
34/// computed over the entire message including the checksum field.
35#[must_use]
36pub fn verify_icmp_checksum(icmp_data: &[u8]) -> bool {
37 if icmp_data.len() < 8 {
38 return false;
39 }
40
41 let checksum = icmp_checksum(icmp_data);
42 checksum == 0 || checksum == 0xFFFF
43}
44
45#[cfg(test)]
46mod tests {
47 use super::*;
48
49 #[test]
50 fn test_icmp_checksum() {
51 // ICMP echo request: type=8, code=0, checksum=0, id=1, seq=1
52 let mut icmp_data = vec![
53 0x08, // type = 8 (echo request)
54 0x00, // code = 0
55 0x00, 0x00, // checksum = 0 (to be calculated)
56 0x00, 0x01, // id = 1
57 0x00, 0x01, // seq = 1
58 ];
59
60 let checksum = icmp_checksum(&icmp_data);
61 assert_ne!(checksum, 0);
62
63 // Set the checksum
64 icmp_data[2] = (checksum >> 8) as u8;
65 icmp_data[3] = (checksum & 0xFF) as u8;
66
67 // Verify the checksum
68 assert!(verify_icmp_checksum(&icmp_data));
69 }
70
71 #[test]
72 fn test_icmp_checksum_with_payload() {
73 // ICMP echo request with payload
74 let mut icmp_data = vec![
75 0x08, // type = 8
76 0x00, // code = 0
77 0x00, 0x00, // checksum = 0
78 0x12, 0x34, // id
79 0x00, 0x01, // seq
80 // Payload
81 0x48, 0x65, 0x6c, 0x6c, 0x6f, // "Hello"
82 ];
83
84 let checksum = icmp_checksum(&icmp_data);
85 icmp_data[2] = (checksum >> 8) as u8;
86 icmp_data[3] = (checksum & 0xFF) as u8;
87
88 assert!(verify_icmp_checksum(&icmp_data));
89 }
90
91 #[test]
92 fn test_verify_icmp_checksum_invalid() {
93 // ICMP with wrong checksum
94 let icmp_data = vec![
95 0x08, 0x00, // type, code
96 0xFF, 0xFF, // wrong checksum
97 0x00, 0x01, // id
98 0x00, 0x01, // seq
99 ];
100
101 assert!(!verify_icmp_checksum(&icmp_data));
102 }
103
104 #[test]
105 fn test_verify_icmp_checksum_too_short() {
106 let icmp_data = vec![0x08, 0x00, 0x00]; // Too short
107 assert!(!verify_icmp_checksum(&icmp_data));
108 }
109}