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