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}