fix(icmp): handle RFC 792 timestamp rollover
Build / build (pull_request) Failing after 4s
DevSkim / DevSkim (pull_request) Failing after 1m21s
rust-clippy analyze / Run rust-clippy analyzing (pull_request) Failing after 1m36s

This commit is contained in:
Nils Andreas Svee committed 2026-09-25 17:12:01 +07:00
1 parent 8fb051d48f
commit 11f6d33fa9
1 file changed
+48 -5
+48 -5
View File
@@ -19,6 +19,19 @@ pub struct PingerICMPTimestampListener {}
pub struct PingerICMPTimestampSender {} pub struct PingerICMPTimestampSender {}
const MS_PER_DAY: i64 = 86_400_000;
fn timestamp_delta(later: i64, earlier: i64) -> i64 {
let delta = later - earlier;
if delta < -MS_PER_DAY / 2 {
delta + MS_PER_DAY
} else if delta > MS_PER_DAY / 2 {
delta - MS_PER_DAY
} else {
delta
}
}
impl PingListener for PingerICMPTimestampListener { impl PingListener for PingerICMPTimestampListener {
// Result: RTT, down time, up time // Result: RTT, down time, up time
fn parse_packet( fn parse_packet(
@@ -46,12 +59,18 @@ impl PingListener for PingerICMPTimestampListener {
}); });
} }
let time_now = Time::new(ClockId::Realtime); if receive & 0x8000_0000 != 0 || transmit & 0x8000_0000 != 0 {
let time_since_midnight = time_now.get_time_since_midnight(); return Err(PingError::InvalidPacket(
"non-standard RFC 792 timestamp".into(),
));
}
let rtt = (time_since_midnight - originate as i64) as f64; let time_since_midnight =
let dl_time = (time_since_midnight - transmit as i64) as f64; Time::new(ClockId::Realtime).get_time_since_midnight();
let ul_time = (receive as i64 - originate as i64) as f64;
let rtt = timestamp_delta(time_since_midnight, originate as i64) as f64;
let dl_time = timestamp_delta(time_since_midnight, transmit as i64) as f64;
let ul_time = timestamp_delta(receive as i64, originate as i64) as f64;
Ok(PingReply { Ok(PingReply {
reflector, reflector,
@@ -88,3 +107,27 @@ impl PingSender for PingerICMPTimestampSender {
) )
} }
} }
#[cfg(test)]
mod tests {
use super::*;
use icmp_socket2::packet::WithTimestampReply;
#[test]
fn timestamps_wrap_at_midnight_in_both_directions() {
assert_eq!(timestamp_delta(20, 86_399_900), 120);
assert_eq!(timestamp_delta(86_399_900, 20), -120);
}
#[test]
fn non_standard_rfc_792_timestamps_are_rejected() {
let packet = Icmpv4Packet::with_timestamp_reply(7, 1, 10, 0x8000_0001, 20).unwrap();
let result = PingerICMPTimestampListener {}.parse_packet(
7,
"192.0.2.1".parse().unwrap(),
MeasurementType::IcmpTimestamps,
packet,
);
assert!(matches!(result, Err(PingError::InvalidPacket(_))));
}
}