pub fn build_icmp_echo_request(ident: u16, seq: u16) -> Vec<u8> {
let mut packet = vec![0u8; 8 + 32];
packet[0] = 8; packet[1] = 0; packet[4] = (ident >> 8) as u8;
packet[5] = (ident & 0xFF) as u8;
packet[6] = (seq >> 8) as u8;
packet[7] = (seq & 0xFF) as u8;
for i in 0..32 {
packet[8 + i] = i as u8;
}
let checksum = icmp_checksum(&packet);
packet[2] = (checksum >> 8) as u8;
packet[3] = (checksum & 0xFF) as u8;
packet
}
pub fn icmp_checksum(data: &[u8]) -> u16 {
let mut sum: u32 = 0;
let mut i = 0;
while i + 1 < data.len() {
sum += ((data[i] as u32) << 8) | (data[i + 1] as u32);
i += 2;
}
if i < data.len() {
sum += (data[i] as u32) << 8;
}
while (sum >> 16) != 0 {
sum = (sum & 0xFFFF) + (sum >> 16);
}
!(sum as u16)
}
pub fn parse_icmp_response(buf: &[u8], ident: u16, seq: u16) -> Option<()> {
if buf.len() < 20 {
return None;
}
let ihl = ((buf[0] & 0x0F) * 4) as usize;
if buf.len() < ihl + 8 {
return None;
}
let icmp_type = buf[ihl];
match icmp_type {
0 => {
let recv_ident = u16::from_be_bytes([buf[ihl + 4], buf[ihl + 5]]);
let recv_seq = u16::from_be_bytes([buf[ihl + 6], buf[ihl + 7]]);
if recv_ident == ident && recv_seq == seq {
Some(())
} else {
None
}
}
11 => {
let inner_start = ihl + 8;
if buf.len() < inner_start + 20 + 8 {
return Some(()); }
let inner_ihl = ((buf[inner_start] & 0x0F) * 4) as usize;
let icmp_offset = inner_start + inner_ihl;
if buf.len() < icmp_offset + 8 {
return Some(());
}
if buf[icmp_offset] != 8 {
return None; }
let orig_ident = u16::from_be_bytes([buf[icmp_offset + 4], buf[icmp_offset + 5]]);
let orig_seq = u16::from_be_bytes([buf[icmp_offset + 6], buf[icmp_offset + 7]]);
if orig_ident == ident && orig_seq == seq {
Some(())
} else {
None
}
}
_ => None,
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_build_icmp_echo_request() {
let packet = build_icmp_echo_request(0x1234, 0x0001);
assert_eq!(packet[0], 8); assert_eq!(packet[4], 0x12); assert_eq!(packet[5], 0x34); assert_eq!(packet[6], 0x00); assert_eq!(packet[7], 0x01); }
#[test]
fn test_icmp_checksum() {
let packet = build_icmp_echo_request(0x1234, 0x0001);
let mut sum: u32 = 0;
let mut i = 0;
while i + 1 < packet.len() {
sum += ((packet[i] as u32) << 8) | (packet[i + 1] as u32);
i += 2;
}
if i < packet.len() {
sum += (packet[i] as u32) << 8;
}
while (sum >> 16) != 0 {
sum = (sum & 0xFFFF) + (sum >> 16);
}
assert_eq!(sum, 0xFFFF); }
}