Files
sqm-autorate-rust/src/pinger_icmp_ts.rs
T

103 lines
4.2 KiB
Rust

use std::net::IpAddr;
use crate::endian::ToNativeEndian;
use crate::pinger::{PingError, PingListener, PingReply, PingSender};
use crate::utils::Utils;
use etherparse::icmpv4::TimestampMessage;
use etherparse::TransportSlice::{Icmpv4, Icmpv6};
use etherparse::{Icmpv4Header, Icmpv4Type, SlicedPacket};
use nix::time::{clock_gettime, ClockId};
pub struct PingerICMPTimestampListener {}
pub struct PingerICMPTimestampSender {}
impl PingListener for PingerICMPTimestampListener {
// Result: RTT, down time, up time
fn parse_packet(&self, id: u16, reflector: IpAddr, buf: &[u8]) -> Result<PingReply, PingError> {
match SlicedPacket::from_ip(buf) {
Err(err) => return Err(PingError::InvalidPacket(err)),
Ok(value) => match value.transport {
Some(Icmpv4(icmp)) => match icmp.icmp_type() {
Icmpv4Type::TimestampReply(reply) => {
if reply.id != id {
return Err(PingError::WrongID {
expected: id,
found: reply.id,
});
}
let time_now = clock_gettime(ClockId::CLOCK_REALTIME).unwrap();
let time_since_midnight: i64 = (time_now.tv_sec() as i64 % 86400 * 1000)
+ (time_now.tv_nsec() as i64 / 1000000);
let originate_timestamp = reply.originate_timestamp.to_ne();
let receive_timestamp = reply.receive_timestamp.to_ne();
let transmit_timestamp = reply.transmit_timestamp.to_ne();
let rtt: i64 = time_since_midnight - originate_timestamp as i64;
let dl_time: i64 = time_since_midnight - transmit_timestamp as i64;
let ul_time: i64 = receive_timestamp as i64 - originate_timestamp as i64;
return Ok(PingReply {
reflector,
seq: reply.seq,
rtt,
current_time: time_since_midnight,
down_time: dl_time as f64,
up_time: ul_time as f64,
originate_timestamp: originate_timestamp as i64,
receive_timestamp: receive_timestamp as i64,
transmit_timestamp: transmit_timestamp as i64,
last_receive_time_s: time_now.tv_sec() as f64
+ (time_now.tv_nsec() as f64 / 1e9),
});
}
type_ => {
return Err(PingError::InvalidType(format!("{:?}", type_)));
}
},
Some(Icmpv6(slice)) => {
return Err(PingError::InvalidType(format!("{:?}", slice)));
}
Some(type_) => {
return Err(PingError::InvalidType(format!("{:?}", type_)));
}
None => {
return Err(PingError::NoTransport);
}
},
}
}
}
impl PingSender for PingerICMPTimestampSender {
fn craft_packet(&self, id: u16, seq: u16) -> Vec<u8> {
let time = clock_gettime(ClockId::CLOCK_REALTIME).unwrap();
let time_since_midnight: u32 =
((time.tv_sec() % 86400 * 1000) + (time.tv_nsec() / 1000000)) as u32;
let payload: [u8; 0] = [];
// Construct a header with checksum based on the payload
let hdr = Icmpv4Header::with_checksum(
Icmpv4Type::TimestampRequest(TimestampMessage {
id,
seq,
originate_timestamp: time_since_midnight,
receive_timestamp: 0,
transmit_timestamp: 0,
}),
&payload,
);
// Create a buffer to hold the result of header + payload
let mut result = Vec::<u8>::with_capacity(hdr.header_len());
// Write the header to the buffer
hdr.write(&mut result).expect("Error writing packet");
result
}
}