async_icmp/message/
mod.rs1use crate::IcmpVersion;
4
5#[cfg(test)]
6mod tests;
7
8pub mod decode;
9pub mod echo;
10
11pub trait EncodeIcmpMessage<V: IcmpVersion> {
13 fn encode(&mut self) -> &mut IcmpMessageBuffer;
15}
16
17#[derive(Clone, Debug)]
19pub struct IcmpMessageBuffer {
20 buf: Vec<u8>,
29}
30
31impl IcmpMessageBuffer {
32 const ICMP_HDR_LEN: usize = 4;
33
34 pub fn new(typ: u8, code: u8, body: &[u8]) -> Self {
36 let mut buf = vec![typ, code, 0, 0];
37 buf.extend_from_slice(body);
38 Self { buf }
39 }
40
41 pub fn set_type(&mut self, typ: u8) {
43 self.buf[0] = typ;
44 }
45
46 pub fn set_code(&mut self, code: u8) {
48 self.buf[1] = code;
49 }
50
51 pub fn body(&self) -> &[u8] {
53 &self.buf[Self::ICMP_HDR_LEN..]
54 }
55
56 pub fn body_mut(&mut self) -> &mut [u8] {
58 &mut self.buf[Self::ICMP_HDR_LEN..]
59 }
60
61 pub fn set_body(&mut self, body: impl IntoIterator<Item = u8>) {
63 self.truncate_body(0);
64 self.extend_body(body);
65 }
66
67 pub fn extend_body(&mut self, body_suffix: impl IntoIterator<Item = u8>) {
69 self.buf.extend(body_suffix);
70 }
71
72 pub fn truncate_body(&mut self, body_len: usize) {
74 self.buf.truncate(Self::ICMP_HDR_LEN + body_len);
75 }
76
77 pub(crate) fn calculate_icmpv4_checksum(&mut self) {
79 self.buf[2..4].fill(0);
81 let checksum = ones_complement_checksum(&self.buf);
82 self.buf[2..4].copy_from_slice(&checksum.to_be_bytes());
83 }
84
85 pub fn as_slice(&self) -> &[u8] {
87 &self.buf
88 }
89}
90
91#[repr(u8)]
95#[allow(missing_docs)]
96pub enum IcmpV4MsgType {
97 EchoReply = 0,
98 DestinationUnreachable = 3,
99 SourceQuench = 4,
100 Redirect = 5,
101 EchoRequest = 8,
102 TimeExceeded = 11,
103 ParameterProblem = 12,
104 Timestamp = 13,
105 TimestampReply = 14,
106 InfoRequest = 15,
107 InfoReply = 16,
108}
109
110#[repr(u8)]
114#[allow(missing_docs)]
115pub enum IcmpV6MsgType {
116 DestinationUnreachable = 1,
117 PacketTooBig = 2,
118 TimeExceeded = 3,
119 ParameterProblem = 4,
120 PrivateExperimentationError1 = 100,
121 PrivateExperimentationError2 = 101,
122 ReservedForExpansionError = 127,
123 EchoRequest = 128,
124 EchoReply = 129,
125 PrivateExperimentationInfo1 = 200,
126 PrivateExperimentationInfo2 = 201,
127 ReservedForExpansionInfo = 255,
128}
129
130fn ones_complement_checksum(data: &[u8]) -> u16 {
132 let last = if data.len() % 2 == 1 {
133 u16::from(data.last().copied().unwrap()) << 8
134 } else {
135 0_u16
136 };
137
138 let mut sum = data
139 .chunks_exact(2)
140 .map(|chunk| u16::from_be_bytes(chunk.try_into().unwrap()))
141 .fold(0_u32, |accum, num| accum.wrapping_add(num.into()))
142 .wrapping_add(last.into());
143
144 while (sum >> 16) > 0 {
145 sum = (sum & 0xffff) + (sum >> 16);
146 }
147
148 !(sum as u16)
149}