Skip to main content

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}