Skip to main content

packet/icmp/previous/
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;
16
17use crate::error::*;
18use crate::packet::{Packet as P, PacketMut as PM, AsPacket, AsPacketMut};
19use crate::size;
20use crate::ip;
21use crate::icmp::Kind;
22
23/// Source Quench, Destination Unreachable and Time Exceeded packet parser.
24pub struct Packet<B> {
25	buffer: B,
26}
27
28sized!(Packet,
29	header {
30		min:  8,
31		max:  8,
32		size: 8,
33	}
34
35	payload {
36		min:  <ip::v4::Packet<()> as size::header::Min>::min(),
37		max:  <ip::v4::Packet<()> as size::header::Max>::max(),
38		size: p => {
39			if let Ok(ip) = p.packet() {
40				size::header::Size::size(&ip)
41			}
42			else {
43				p.buffer.as_ref().len() - 8
44			}
45		},
46	});
47
48impl<B: AsRef<[u8]>> fmt::Debug for Packet<B> {
49	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
50		f.debug_struct("icmp::previous::Packet")
51			.field("packet", &self.packet())
52			.finish()
53	}
54}
55
56impl<B: AsRef<[u8]>> Packet<B> {
57	/// Create a Source Quench, Destination Unreachable and Time Exceeded packet
58	/// without checking the buffer.
59	pub fn unchecked(buffer: B) -> Packet<B> {
60		Packet { buffer }
61	}
62
63	/// Parse a Source Quench, Destination Unreachable and Time Exceeded
64	/// packet, checking the bufffer contents are correct.
65	pub fn new(buffer: B) -> Result<Packet<B>> {
66		use crate::size::header::Min;
67
68		let packet = Packet::unchecked(buffer);
69
70		if packet.buffer.as_ref().len() < Self::min() {
71			Err(Error::SmallBuffer)?
72		}
73
74		match Kind::from(packet.buffer.as_ref()[0]) {
75			Kind::SourceQuench |
76			Kind::DestinationUnreachable |
77			Kind::TimeExceeded =>
78				(),
79
80			_ =>
81				Err(Error::InvalidPacket)?
82		}
83
84		Ok(packet)
85	}
86}
87
88impl<B: AsRef<[u8]>> Packet<B> {
89	/// Convert the packet to its owned version.
90	///
91	/// # Notes
92	///
93	/// It would be nice if `ToOwned` could be implemented, but `Packet` already
94	/// implements `Clone` and the impl would conflict.
95	pub fn to_owned(&self) -> Packet<Vec<u8>> {
96		Packet::unchecked(self.buffer.as_ref().to_vec())
97	}
98}
99
100impl<B: AsRef<[u8]>> AsRef<[u8]> for Packet<B> {
101	fn as_ref(&self) -> &[u8] {
102		use crate::size::Size;
103
104		&self.buffer.as_ref()[.. self.size()]
105	}
106}
107
108impl<B: AsRef<[u8]> + AsMut<[u8]>> AsMut<[u8]> for Packet<B> {
109	fn as_mut(&mut self) -> &mut [u8] {
110		use crate::size::Size;
111
112		let size = self.size();
113		&mut self.buffer.as_mut()[.. size]
114	}
115}
116
117impl<'a, B: AsRef<[u8]>> AsPacket<'a, Packet<&'a [u8]>> for B {
118	fn as_packet(&self) -> Result<Packet<&[u8]>> {
119		Packet::new(self.as_ref())
120	}
121}
122
123impl<'a, B: AsRef<[u8]> + AsMut<[u8]>> AsPacketMut<'a, Packet<&'a mut [u8]>> for B {
124	fn as_packet_mut(&mut self) -> Result<Packet<&mut [u8]>> {
125		Packet::new(self.as_mut())
126	}
127}
128
129impl<B: AsRef<[u8]>> P for Packet<B> {
130	fn split(&self) -> (&[u8], &[u8]) {
131		let (header, payload) = self.buffer.as_ref().split_at(8);
132		(&header[.. 4], payload)
133	}
134}
135
136impl<B: AsRef<[u8]> + AsMut<[u8]>> PM for Packet<B> {
137	fn split_mut(&mut self) -> (&mut [u8], &mut [u8]) {
138		let (header, payload) = self.buffer.as_mut().split_at_mut(8);
139		(&mut header[.. 4], payload)
140	}
141}
142
143impl<B: AsRef<[u8]>> Packet<B> {
144	/// Packet to cause the message.
145	pub fn packet(&self) -> Result<ip::v4::Packet<&[u8]>> {
146		ip::v4::Packet::new(&self.buffer.as_ref()[8 ..])
147	}
148}