ipv6hopbyhop.rs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371
  1. use super::{Error, Result};
  2. use core::fmt;
  3. pub use super::IpProtocol as Protocol;
  4. use crate::wire::ipv6option::Ipv6OptionsIterator;
  5. /// A read/write wrapper around an IPv6 Hop-by-Hop Options Header.
  6. #[derive(Debug, PartialEq, Eq)]
  7. #[cfg_attr(feature = "defmt", derive(defmt::Format))]
  8. pub struct Header<T: AsRef<[u8]>> {
  9. buffer: T,
  10. }
  11. // Format of the Hop-by-Hop Options Header
  12. //
  13. // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  14. // | Next Header | Hdr Ext Len | |
  15. // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +
  16. // | |
  17. // . .
  18. // . Options .
  19. // . .
  20. // | |
  21. // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  22. //
  23. //
  24. // See https://tools.ietf.org/html/rfc8200#section-4.3 for details.
  25. mod field {
  26. #![allow(non_snake_case)]
  27. use crate::wire::field::*;
  28. // Minimum size of the header.
  29. pub const MIN_HEADER_SIZE: usize = 8;
  30. // 8-bit identifier of the header immediately following this header.
  31. pub const NXT_HDR: usize = 0;
  32. // 8-bit unsigned integer. Length of the OPTIONS field in 8-octet units,
  33. // not including the first 8 octets.
  34. pub const LENGTH: usize = 1;
  35. // Variable-length field. Option-Type-specific data.
  36. //
  37. // Length of the header is in 8-octet units, not including the first 8 octets. The first two
  38. // octets are the next header type and the header length.
  39. pub const fn OPTIONS(length_field: u8) -> Field {
  40. let bytes = length_field as usize * 8 + 8;
  41. 2..bytes
  42. }
  43. }
  44. impl<T: AsRef<[u8]>> Header<T> {
  45. /// Create a raw octet buffer with an IPv6 Hop-by-Hop Options Header structure.
  46. pub const fn new_unchecked(buffer: T) -> Header<T> {
  47. Header { buffer }
  48. }
  49. /// Shorthand for a combination of [new_unchecked] and [check_len].
  50. ///
  51. /// [new_unchecked]: #method.new_unchecked
  52. /// [check_len]: #method.check_len
  53. pub fn new_checked(buffer: T) -> Result<Header<T>> {
  54. let header = Self::new_unchecked(buffer);
  55. header.check_len()?;
  56. Ok(header)
  57. }
  58. /// Ensure that no accessor method will panic if called.
  59. /// Returns `Err(Error)` if the buffer is too short.
  60. ///
  61. /// The result of this check is invalidated by calling [set_header_len].
  62. ///
  63. /// [set_header_len]: #method.set_header_len
  64. pub fn check_len(&self) -> Result<()> {
  65. let data = self.buffer.as_ref();
  66. let len = data.len();
  67. if len < field::MIN_HEADER_SIZE {
  68. return Err(Error);
  69. }
  70. let of = field::OPTIONS(data[field::LENGTH]);
  71. if len < of.end {
  72. return Err(Error);
  73. }
  74. Ok(())
  75. }
  76. /// Consume the header, returning the underlying buffer.
  77. pub fn into_inner(self) -> T {
  78. self.buffer
  79. }
  80. /// Return the next header field.
  81. #[inline]
  82. pub fn next_header(&self) -> Protocol {
  83. let data = self.buffer.as_ref();
  84. Protocol::from(data[field::NXT_HDR])
  85. }
  86. /// Return length of the Hop-by-Hop Options header in 8-octet units, not including the first
  87. /// 8 octets.
  88. #[inline]
  89. pub fn header_len(&self) -> u8 {
  90. let data = self.buffer.as_ref();
  91. data[field::LENGTH]
  92. }
  93. }
  94. impl<'a, T: AsRef<[u8]> + ?Sized> Header<&'a T> {
  95. /// Return the option data.
  96. #[inline]
  97. pub fn options(&self) -> &'a [u8] {
  98. let data = self.buffer.as_ref();
  99. &data[field::OPTIONS(data[field::LENGTH])]
  100. }
  101. }
  102. impl<T: AsRef<[u8]> + AsMut<[u8]>> Header<T> {
  103. /// Set the next header field.
  104. #[inline]
  105. pub fn set_next_header(&mut self, value: Protocol) {
  106. let data = self.buffer.as_mut();
  107. data[field::NXT_HDR] = value.into();
  108. }
  109. /// Set the option data length. Length of the Hop-by-Hop Options header in 8-octet units,
  110. /// not including the first 8 octets.
  111. #[inline]
  112. pub fn set_header_len(&mut self, value: u8) {
  113. let data = self.buffer.as_mut();
  114. data[field::LENGTH] = value;
  115. }
  116. }
  117. impl<'a, T: AsRef<[u8]> + AsMut<[u8]> + ?Sized> Header<&'a mut T> {
  118. /// Return a mutable pointer to the option data.
  119. #[inline]
  120. pub fn options_mut(&mut self) -> &mut [u8] {
  121. let data = self.buffer.as_mut();
  122. let len = data[field::LENGTH];
  123. &mut data[field::OPTIONS(len)]
  124. }
  125. }
  126. impl<'a, T: AsRef<[u8]> + ?Sized> fmt::Display for Header<&'a T> {
  127. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  128. match Repr::parse(self) {
  129. Ok(repr) => write!(f, "{}", repr),
  130. Err(err) => {
  131. write!(f, "IPv6 Hop-by-Hop Options ({})", err)?;
  132. Ok(())
  133. }
  134. }
  135. }
  136. }
  137. /// A high-level representation of an IPv6 Hop-by-Hop Options header.
  138. #[derive(Debug, PartialEq, Eq, Clone, Copy)]
  139. #[cfg_attr(feature = "defmt", derive(defmt::Format))]
  140. pub struct Repr<'a> {
  141. /// The type of header immediately following the Hop-by-Hop Options header.
  142. pub next_header: Protocol,
  143. /// Length of the Hop-by-Hop Options header in 8-octet units, not including the first 8 octets.
  144. pub length: u8,
  145. /// The options contained in the Hop-by-Hop Options header.
  146. pub options: &'a [u8],
  147. }
  148. impl<'a> Repr<'a> {
  149. /// Parse an IPv6 Hop-by-Hop Options Header and return a high-level representation.
  150. pub fn parse<T>(header: &Header<&'a T>) -> Result<Repr<'a>>
  151. where
  152. T: AsRef<[u8]> + ?Sized,
  153. {
  154. Ok(Repr {
  155. next_header: header.next_header(),
  156. length: header.header_len(),
  157. options: header.options(),
  158. })
  159. }
  160. /// Return the length, in bytes, of a header that will be emitted from this high-level
  161. /// representation.
  162. pub const fn buffer_len(&self) -> usize {
  163. field::OPTIONS(self.length).end
  164. }
  165. /// Emit a high-level representation into an IPv6 Hop-by-Hop Options Header.
  166. pub fn emit<T: AsRef<[u8]> + AsMut<[u8]> + ?Sized>(&self, header: &mut Header<&mut T>) {
  167. header.set_next_header(self.next_header);
  168. header.set_header_len(self.length);
  169. header.options_mut().copy_from_slice(self.options);
  170. }
  171. /// Return an `Iterator` for the contained options.
  172. pub fn options(&self) -> Ipv6OptionsIterator {
  173. Ipv6OptionsIterator::new(self.options, self.buffer_len() - 2)
  174. }
  175. }
  176. impl<'a> fmt::Display for Repr<'a> {
  177. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  178. write!(
  179. f,
  180. "IPv6 Hop-by-Hop Options next_hdr={} length={} ",
  181. self.next_header, self.length
  182. )
  183. }
  184. }
  185. #[cfg(test)]
  186. mod test {
  187. use super::*;
  188. // A Hop-by-Hop Option header with a PadN option of option data length 4.
  189. static REPR_PACKET_PAD4: [u8; 8] = [0x6, 0x0, 0x1, 0x4, 0x0, 0x0, 0x0, 0x0];
  190. // A Hop-by-Hop Option header with a PadN option of option data length 12.
  191. static REPR_PACKET_PAD12: [u8; 16] = [
  192. 0x06, 0x1, 0x1, 0x12, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
  193. ];
  194. #[test]
  195. fn test_check_len() {
  196. // zero byte buffer
  197. assert_eq!(
  198. Err(Error),
  199. Header::new_unchecked(&REPR_PACKET_PAD4[..0]).check_len()
  200. );
  201. // no length field
  202. assert_eq!(
  203. Err(Error),
  204. Header::new_unchecked(&REPR_PACKET_PAD4[..1]).check_len()
  205. );
  206. // less than 8 bytes
  207. assert_eq!(
  208. Err(Error),
  209. Header::new_unchecked(&REPR_PACKET_PAD4[..7]).check_len()
  210. );
  211. // valid
  212. assert_eq!(Ok(()), Header::new_unchecked(&REPR_PACKET_PAD4).check_len());
  213. // valid
  214. assert_eq!(
  215. Ok(()),
  216. Header::new_unchecked(&REPR_PACKET_PAD12).check_len()
  217. );
  218. // length field value greater than number of bytes
  219. let header: [u8; 8] = [0x06, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0];
  220. assert_eq!(Err(Error), Header::new_unchecked(&header).check_len());
  221. }
  222. #[test]
  223. fn test_header_deconstruct() {
  224. let header = Header::new_unchecked(&REPR_PACKET_PAD4);
  225. assert_eq!(header.next_header(), Protocol::Tcp);
  226. assert_eq!(header.header_len(), 0);
  227. assert_eq!(header.options(), &REPR_PACKET_PAD4[2..]);
  228. let header = Header::new_unchecked(&REPR_PACKET_PAD12);
  229. assert_eq!(header.next_header(), Protocol::Tcp);
  230. assert_eq!(header.header_len(), 1);
  231. assert_eq!(header.options(), &REPR_PACKET_PAD12[2..]);
  232. }
  233. #[test]
  234. fn test_overlong() {
  235. let mut bytes = vec![];
  236. bytes.extend(&REPR_PACKET_PAD4[..]);
  237. bytes.push(0);
  238. assert_eq!(
  239. Header::new_unchecked(&bytes).options().len(),
  240. REPR_PACKET_PAD4[2..].len()
  241. );
  242. assert_eq!(
  243. Header::new_unchecked(&mut bytes).options_mut().len(),
  244. REPR_PACKET_PAD4[2..].len()
  245. );
  246. let mut bytes = vec![];
  247. bytes.extend(&REPR_PACKET_PAD12[..]);
  248. bytes.push(0);
  249. assert_eq!(
  250. Header::new_unchecked(&bytes).options().len(),
  251. REPR_PACKET_PAD12[2..].len()
  252. );
  253. assert_eq!(
  254. Header::new_unchecked(&mut bytes).options_mut().len(),
  255. REPR_PACKET_PAD12[2..].len()
  256. );
  257. }
  258. #[test]
  259. fn test_header_len_overflow() {
  260. let mut bytes = vec![];
  261. bytes.extend(&REPR_PACKET_PAD4);
  262. let len = bytes.len() as u8;
  263. Header::new_unchecked(&mut bytes).set_header_len(len + 1);
  264. assert_eq!(Header::new_checked(&bytes).unwrap_err(), Error);
  265. let mut bytes = vec![];
  266. bytes.extend(&REPR_PACKET_PAD12);
  267. let len = bytes.len() as u8;
  268. Header::new_unchecked(&mut bytes).set_header_len(len + 1);
  269. assert_eq!(Header::new_checked(&bytes).unwrap_err(), Error);
  270. }
  271. #[test]
  272. fn test_repr_parse_valid() {
  273. let header = Header::new_unchecked(&REPR_PACKET_PAD4);
  274. let repr = Repr::parse(&header).unwrap();
  275. assert_eq!(
  276. repr,
  277. Repr {
  278. next_header: Protocol::Tcp,
  279. length: 0,
  280. options: &REPR_PACKET_PAD4[2..]
  281. }
  282. );
  283. let header = Header::new_unchecked(&REPR_PACKET_PAD12);
  284. let repr = Repr::parse(&header).unwrap();
  285. assert_eq!(
  286. repr,
  287. Repr {
  288. next_header: Protocol::Tcp,
  289. length: 1,
  290. options: &REPR_PACKET_PAD12[2..]
  291. }
  292. );
  293. }
  294. #[test]
  295. fn test_repr_emit() {
  296. let repr = Repr {
  297. next_header: Protocol::Tcp,
  298. length: 0,
  299. options: &REPR_PACKET_PAD4[2..],
  300. };
  301. let mut bytes = [0u8; 8];
  302. let mut header = Header::new_unchecked(&mut bytes);
  303. repr.emit(&mut header);
  304. assert_eq!(header.into_inner(), &REPR_PACKET_PAD4[..]);
  305. let repr = Repr {
  306. next_header: Protocol::Tcp,
  307. length: 1,
  308. options: &REPR_PACKET_PAD12[2..],
  309. };
  310. let mut bytes = [0u8; 16];
  311. let mut header = Header::new_unchecked(&mut bytes);
  312. repr.emit(&mut header);
  313. assert_eq!(header.into_inner(), &REPR_PACKET_PAD12[..]);
  314. }
  315. #[test]
  316. fn test_buffer_len() {
  317. let header = Header::new_unchecked(&REPR_PACKET_PAD4);
  318. let repr = Repr::parse(&header).unwrap();
  319. assert_eq!(repr.buffer_len(), REPR_PACKET_PAD4.len());
  320. let header = Header::new_unchecked(&REPR_PACKET_PAD12);
  321. let repr = Repr::parse(&header).unwrap();
  322. assert_eq!(repr.buffer_len(), REPR_PACKET_PAD12.len());
  323. }
  324. }