packet/icmp/information/
packet.rs

1//            DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
2//                    Version 2, December 2004
3//
4// Copyleft (ↄ) meh. <meh@schizofreni.co> | http://meh.schizofreni.co
5//
6// Everyone is permitted to copy and distribute verbatim or modified
7// copies of this license document, and changing it is allowed as long
8// as the name is changed.
9//
10//            DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
11//   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
12//
13//  0. You just DO WHAT THE FUCK YOU WANT TO.
14
15use std::fmt;
16use std::io::Cursor;
17use byteorder::{ReadBytesExt, WriteBytesExt, BigEndian};
18
19use crate::error::*;
20use crate::packet::{Packet as P, PacketMut as PM, AsPacket, AsPacketMut};
21use crate::icmp::Kind;
22use crate::icmp::packet::Checked;
23
24/// Information Request/Reply packet parser.
25pub struct Packet<B> {
26	buffer: B,
27}
28
29sized!(Packet,
30	header {
31		min:  8,
32		max:  8,
33		size: 8,
34	}
35
36	payload {
37		min:  0,
38		max:  0,
39		size: 0,
40	});
41
42impl<B: AsRef<[u8]>> fmt::Debug for Packet<B> {
43	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
44		f.debug_struct("icmp::information::Packet")
45			.field("request", &self.is_request())
46			.field("identifier", &self.identifier())
47			.field("sequence", &self.sequence())
48			.finish()
49	}
50}
51
52impl<B: AsRef<[u8]>> Packet<B> {
53	pub fn unchecked(buffer: B) -> Packet<B> {
54		Packet { buffer }
55	}
56
57	/// Parse an Information Request/Reply packet, checking the buffer contents
58	/// are correct.
59	pub fn new(buffer: B) -> Result<Packet<B>> {
60		use crate::size::header::Min;
61
62		let packet = Packet::unchecked(buffer);
63
64		if packet.buffer.as_ref().len() < Self::min() {
65			Err(Error::SmallBuffer)?
66		}
67
68		match Kind::from(packet.buffer.as_ref()[0]) {
69			Kind::InformationRequest |
70			Kind::InformationReply =>
71				(),
72
73			_ =>
74				Err(Error::InvalidPacket)?
75		}
76
77		Ok(packet)
78	}
79}
80
81impl<B: AsRef<[u8]>> Packet<B> {
82	/// Convert the packet to its owned version.
83	///
84	/// # Notes
85	///
86	/// It would be nice if `ToOwned` could be implemented, but `Packet` already
87	/// implements `Clone` and the impl would conflict.
88	pub fn to_owned(&self) -> Packet<Vec<u8>> {
89		Packet::unchecked(self.buffer.as_ref().to_vec())
90	}
91}
92
93impl<B: AsRef<[u8]>> AsRef<[u8]> for Packet<B> {
94	fn as_ref(&self) -> &[u8] {
95		use crate::size::Size;
96
97		&self.buffer.as_ref()[.. self.size()]
98	}
99}
100
101impl<B: AsRef<[u8]> + AsMut<[u8]>> AsMut<[u8]> for Packet<B> {
102	fn as_mut(&mut self) -> &mut [u8] {
103		use crate::size::Size;
104
105		let size = self.size();
106		&mut self.buffer.as_mut()[.. size]
107	}
108}
109
110impl<'a, B: AsRef<[u8]>> AsPacket<'a, Packet<&'a [u8]>> for B {
111	fn as_packet(&self) -> Result<Packet<&[u8]>> {
112		Packet::new(self.as_ref())
113	}
114}
115
116impl<'a, B: AsRef<[u8]> + AsMut<[u8]>> AsPacketMut<'a, Packet<&'a mut [u8]>> for B {
117	fn as_packet_mut(&mut self) -> Result<Packet<&mut [u8]>> {
118		Packet::new(self.as_mut())
119	}
120}
121
122impl<B: AsRef<[u8]>> P for Packet<B> {
123	fn split(&self) -> (&[u8], &[u8]) {
124		self.buffer.as_ref().split_at(8)
125	}
126}
127
128impl<B: AsRef<[u8]> + AsMut<[u8]>> PM for Packet<B> {
129	fn split_mut(&mut self) -> (&mut [u8], &mut [u8]) {
130		self.buffer.as_mut().split_at_mut(8)
131	}
132}
133
134impl<B: AsRef<[u8]>> Packet<B> {
135	/// Check if it's a Request packet.
136	pub fn is_request(&self) -> bool {
137		Kind::from(self.buffer.as_ref()[0]) == Kind::InformationRequest
138	}
139
140	/// Check if it's a Reply packet.
141	pub fn is_reply(&self) -> bool {
142		Kind::from(self.buffer.as_ref()[0]) == Kind::InformationReply
143	}
144
145	/// Packet identifier.
146	pub fn identifier(&self) -> u16 {
147		(&self.buffer.as_ref()[4 ..]).read_u16::<BigEndian>().unwrap()
148	}
149
150	/// Packet sequence.
151	pub fn sequence(&self) -> u16 {
152		(&self.buffer.as_ref()[6 ..]).read_u16::<BigEndian>().unwrap()
153	}
154}
155
156impl<B: AsRef<[u8]> + AsMut<[u8]>> Packet<B> {
157	/// Make the packet an Echo Request.
158	pub fn make_request(&mut self) -> Result<&mut Self> {
159		self.buffer.as_mut()[0] = Kind::EchoRequest.into();
160
161		Ok(self)
162	}
163
164	/// Make the packet an Echo Reply.
165	pub fn make_reply(&mut self) -> Result<&mut Self> {
166		self.buffer.as_mut()[0] = Kind::EchoReply.into();
167
168		Ok(self)
169	}
170
171	/// Packet identifier.
172	pub fn set_identifier(&mut self, value: u16) -> Result<&mut Self> {
173		Cursor::new(&mut self.buffer.as_mut()[4 ..])
174			.write_u16::<BigEndian>(value)?;
175
176		Ok(self)
177	}
178
179	/// Packet sequence.
180	pub fn set_sequence(&mut self, value: u16) -> Result<&mut Self> {
181		Cursor::new(&mut self.buffer.as_mut()[6 ..])
182			.write_u16::<BigEndian>(value)?;
183
184		Ok(self)
185	}
186
187	/// Create a checksumed setter.
188	pub fn checked(&mut self) -> Checked<'_, Self> {
189		Checked {
190			packet: self
191		}
192	}
193}
194
195impl<'a, B: AsRef<[u8]> + AsMut<[u8]> + 'a> Checked<'a, Packet<B>> {
196	/// Make the packet an Echo Request.
197	pub fn make_request(&mut self) -> Result<&mut Self> {
198		self.packet.make_request()?;
199		Ok(self)
200	}
201
202	/// Make the packet an Echo Reply.
203	pub fn make_reply(&mut self) -> Result<&mut Self> {
204		self.packet.make_reply()?;
205		Ok(self)
206	}
207
208	/// Packet identifier.
209	pub fn set_identifier(&mut self, value: u16) -> Result<&mut Self> {
210		self.packet.set_identifier(value)?;
211		Ok(self)
212	}
213
214	/// Packet sequence.
215	pub fn set_sequence(&mut self, value: u16) -> Result<&mut Self> {
216		self.packet.set_sequence(value)?;
217		Ok(self)
218	}
219}