async_icmp/message/
mod.rsuse crate::IcmpVersion;
#[cfg(test)]
mod tests;
pub mod decode;
pub mod echo;
pub trait EncodeIcmpMessage<V: IcmpVersion> {
fn encode(&mut self) -> &mut IcmpMessageBuffer;
}
#[derive(Clone, Debug)]
pub struct IcmpMessageBuffer {
buf: Vec<u8>,
}
impl IcmpMessageBuffer {
const ICMP_HDR_LEN: usize = 4;
pub fn new(typ: u8, code: u8, body: &[u8]) -> Self {
let mut buf = vec![typ, code, 0, 0];
buf.extend_from_slice(body);
Self { buf }
}
pub fn set_type(&mut self, typ: u8) {
self.buf[0] = typ;
}
pub fn set_code(&mut self, code: u8) {
self.buf[1] = code;
}
pub fn body(&self) -> &[u8] {
&self.buf[Self::ICMP_HDR_LEN..]
}
pub fn body_mut(&mut self) -> &mut [u8] {
&mut self.buf[Self::ICMP_HDR_LEN..]
}
pub fn set_body(&mut self, body: impl IntoIterator<Item = u8>) {
self.truncate_body(0);
self.extend_body(body);
}
pub fn extend_body(&mut self, body_suffix: impl IntoIterator<Item = u8>) {
self.buf.extend(body_suffix);
}
pub fn truncate_body(&mut self, body_len: usize) {
self.buf.truncate(Self::ICMP_HDR_LEN + body_len);
}
pub(crate) fn calculate_icmpv4_checksum(&mut self) {
self.buf[2..4].fill(0);
let checksum = ones_complement_checksum(&self.buf);
self.buf[2..4].copy_from_slice(&checksum.to_be_bytes());
}
pub fn as_slice(&self) -> &[u8] {
&self.buf
}
}
#[repr(u8)]
#[allow(missing_docs)]
pub enum IcmpV4MsgType {
EchoReply = 0,
DestinationUnreachable = 3,
SourceQuench = 4,
Redirect = 5,
EchoRequest = 8,
TimeExceeded = 11,
ParameterProblem = 12,
Timestamp = 13,
TimestampReply = 14,
InfoRequest = 15,
InfoReply = 16,
}
#[repr(u8)]
#[allow(missing_docs)]
pub enum IcmpV6MsgType {
DestinationUnreachable = 1,
PacketTooBig = 2,
TimeExceeded = 3,
ParameterProblem = 4,
PrivateExperimentationError1 = 100,
PrivateExperimentationError2 = 101,
ReservedForExpansionError = 127,
EchoRequest = 128,
EchoReply = 129,
PrivateExperimentationInfo1 = 200,
PrivateExperimentationInfo2 = 201,
ReservedForExpansionInfo = 255,
}
fn ones_complement_checksum(data: &[u8]) -> u16 {
let last = if data.len() % 2 == 1 {
u16::from(data.last().copied().unwrap()) << 8
} else {
0_u16
};
let mut sum = data
.chunks_exact(2)
.map(|chunk| u16::from_be_bytes(chunk.try_into().unwrap()))
.fold(0_u32, |accum, num| accum.wrapping_add(num.into()))
.wrapping_add(last.into());
while (sum >> 16) > 0 {
sum = (sum & 0xffff) + (sum >> 16);
}
!(sum as u16)
}