fix: correct ICMP diagnostic message when IP header present

The diagnostic error message was reading ICMP fields from the wrong
offset when an IP header was present. It was showing bytes from the
IP header instead of the actual ICMP identifier and sequence fields.

Now properly detects and skips IP header before extracting ICMP
fields for diagnostic output. Also added total packet length to help
distinguish between raw ICMP and IP-wrapped packets.

Example before:
  Invalid ICMP reply packet (expected id=24079, seq=12918):
  type=0 code=0 id=29 seq=12918 len=21
  (id=29 was reading from IP header, not ICMP)

Example after:
  Invalid ICMP reply packet (expected id=24079, seq=12918):
  type=0 code=0 id=24079 seq=12918 len=21 (total=41)
  (now correctly shows ICMP identifier)
This commit is contained in:
Graham McIntire 2026-01-19 15:20:10 -06:00
parent 0b3cc9121e
commit 2b5a67d26c
No known key found for this signature in database

View file

@ -131,13 +131,32 @@ fn parse_icmp_reply(packet: &[u8], expected_identifier: u16, expected_sequence:
}
// Log diagnostic information to help debug
let packet_preview = if packet.len() >= 8 {
// Determine the ICMP portion (might need to skip IP header)
let icmp_packet = if packet.len() >= 20 && (packet[0] >> 4) == 4 {
let ihl = (packet[0] & 0x0F) as usize * 4;
if ihl >= 20 && packet.len() > ihl {
&packet[ihl..]
} else {
packet
}
} else {
packet
};
let packet_preview = if icmp_packet.len() >= 8 {
format!(
"type={} code={} id={} seq={} len={}",
packet[0],
packet.get(1).unwrap_or(&0),
u16::from_be_bytes([*packet.get(4).unwrap_or(&0), *packet.get(5).unwrap_or(&0)]),
u16::from_be_bytes([*packet.get(6).unwrap_or(&0), *packet.get(7).unwrap_or(&0)]),
"type={} code={} id={} seq={} len={} (total={})",
icmp_packet[0],
icmp_packet.get(1).unwrap_or(&0),
u16::from_be_bytes([
*icmp_packet.get(4).unwrap_or(&0),
*icmp_packet.get(5).unwrap_or(&0)
]),
u16::from_be_bytes([
*icmp_packet.get(6).unwrap_or(&0),
*icmp_packet.get(7).unwrap_or(&0)
]),
icmp_packet.len(),
packet.len()
)
} else {