ipv6option.rs 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525
  1. use core::fmt;
  2. use {Error, Result};
  3. enum_with_unknown! {
  4. /// IPv6 Extension Header Option Type
  5. pub doc enum Type(u8) {
  6. /// 1 byte of padding
  7. Pad1 = 0,
  8. /// Multiple bytes of padding
  9. PadN = 1
  10. }
  11. }
  12. impl fmt::Display for Type {
  13. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  14. match self {
  15. &Type::Pad1 => write!(f, "Pad1"),
  16. &Type::PadN => write!(f, "PadN"),
  17. &Type::Unknown(id) => write!(f, "{}", id)
  18. }
  19. }
  20. }
  21. enum_with_unknown! {
  22. /// Action required when parsing the given IPv6 Extension
  23. /// Header Option Type fails
  24. pub doc enum FailureType(u8) {
  25. /// Skip this option and continue processing the packet
  26. Skip = 0b00000000,
  27. /// Discard the containing packet
  28. Discard = 0b01000000,
  29. /// Discard the containing packet and notify the sender
  30. DiscardSendAll = 0b10000000,
  31. /// Discard the containing packet and only notify the sender
  32. /// if the sender is a unicast address
  33. DiscardSendUnicast = 0b11000000,
  34. }
  35. }
  36. impl fmt::Display for FailureType {
  37. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  38. match self {
  39. &FailureType::Skip => write!(f, "skip"),
  40. &FailureType::Discard => write!(f, "discard"),
  41. &FailureType::DiscardSendAll => write!(f, "discard and send error"),
  42. &FailureType::DiscardSendUnicast => write!(f, "discard and send error if unicast"),
  43. &FailureType::Unknown(id) => write!(f, "Unknown({})", id),
  44. }
  45. }
  46. }
  47. impl From<Type> for FailureType {
  48. fn from(other: Type) -> FailureType {
  49. let raw: u8 = other.into();
  50. Self::from(raw & 0b11000000u8)
  51. }
  52. }
  53. /// A read/write wrapper around an IPv6 Extension Header Option.
  54. #[derive(Debug, PartialEq)]
  55. pub struct Ipv6Option<T: AsRef<[u8]>> {
  56. buffer: T
  57. }
  58. // Format of Option
  59. //
  60. // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- - - - - - - - -
  61. // | Option Type | Opt Data Len | Option Data
  62. // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- - - - - - - - -
  63. //
  64. //
  65. // See https://tools.ietf.org/html/rfc8200#section-4.2 for details.
  66. mod field {
  67. #![allow(non_snake_case)]
  68. use wire::field::*;
  69. // 8-bit identifier of the type of option.
  70. pub const TYPE: usize = 0;
  71. // 8-bit unsigned integer. Length of the DATA field of this option, in octets.
  72. pub const LENGTH: usize = 1;
  73. // Variable-length field. Option-Type-specific data.
  74. pub fn DATA(length: u8) -> Field {
  75. 2..length as usize + 2
  76. }
  77. }
  78. impl<T: AsRef<[u8]>> Ipv6Option<T> {
  79. /// Create a raw octet buffer with an IPv6 Extension Header Option structure.
  80. pub fn new(buffer: T) -> Ipv6Option<T> {
  81. Ipv6Option { buffer }
  82. }
  83. /// Shorthand for a combination of [new] and [check_len].
  84. ///
  85. /// [new]: #method.new
  86. /// [check_len]: #method.check_len
  87. pub fn new_checked(buffer: T) -> Result<Ipv6Option<T>> {
  88. let opt = Self::new(buffer);
  89. opt.check_len()?;
  90. Ok(opt)
  91. }
  92. /// Ensure that no accessor method will panic if called.
  93. /// Returns `Err(Error::Truncated)` if the buffer is too short.
  94. ///
  95. /// The result of this check is invalidated by calling [set_data_len].
  96. ///
  97. /// [set_data_len]: #method.set_data_len
  98. pub fn check_len(&self) -> Result<()> {
  99. let data = self.buffer.as_ref();
  100. let len = data.len();
  101. if len < field::LENGTH {
  102. return Err(Error::Truncated);
  103. }
  104. if self.option_type() == Type::Pad1 {
  105. return Ok(());
  106. }
  107. if len == field::LENGTH {
  108. return Err(Error::Truncated);
  109. }
  110. let df = field::DATA(data[field::LENGTH]);
  111. if len < df.end {
  112. return Err(Error::Truncated);
  113. }
  114. Ok(())
  115. }
  116. /// Consume the ipv6 option, returning the underlying buffer.
  117. pub fn into_inner(self) -> T {
  118. self.buffer
  119. }
  120. /// Return the option type.
  121. #[inline]
  122. pub fn option_type(&self) -> Type {
  123. let data = self.buffer.as_ref();
  124. Type::from(data[field::TYPE])
  125. }
  126. /// Return the length of the data.
  127. ///
  128. /// # Panics
  129. /// This function panics if this is an 1-byte padding option.
  130. #[inline]
  131. pub fn data_len(&self) -> u8 {
  132. let data = self.buffer.as_ref();
  133. data[field::LENGTH]
  134. }
  135. }
  136. impl<'a, T: AsRef<[u8]> + ?Sized> Ipv6Option<&'a T> {
  137. /// Return the option data.
  138. ///
  139. /// # Panics
  140. /// This function panics if this is an 1-byte padding option.
  141. #[inline]
  142. pub fn data(&self) -> &'a [u8] {
  143. let len = self.data_len();
  144. let data = self.buffer.as_ref();
  145. &data[field::DATA(len)]
  146. }
  147. }
  148. impl<T: AsRef<[u8]> + AsMut<[u8]>> Ipv6Option<T> {
  149. /// Set the option type.
  150. #[inline]
  151. pub fn set_option_type(&mut self, value: Type) {
  152. let data = self.buffer.as_mut();
  153. data[field::TYPE] = value.into();
  154. }
  155. /// Set the option data length.
  156. ///
  157. /// # Panics
  158. /// This function panics if this is an 1-byte padding option.
  159. #[inline]
  160. pub fn set_data_len(&mut self, value: u8) {
  161. let data = self.buffer.as_mut();
  162. data[field::LENGTH] = value;
  163. }
  164. }
  165. impl<'a, T: AsRef<[u8]> + AsMut<[u8]> + ?Sized> Ipv6Option<&'a mut T> {
  166. /// Return a mutable pointer to the option data.
  167. ///
  168. /// # Panics
  169. /// This function panics if this is an 1-byte padding option.
  170. #[inline]
  171. pub fn data_mut(&mut self) -> &mut [u8] {
  172. let len = self.data_len();
  173. let data = self.buffer.as_mut();
  174. &mut data[field::DATA(len)]
  175. }
  176. }
  177. impl<'a, T: AsRef<[u8]> + ?Sized> fmt::Display for Ipv6Option<&'a T> {
  178. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  179. match Repr::parse(self) {
  180. Ok(repr) => write!(f, "{}", repr),
  181. Err(err) => {
  182. write!(f, "IPv6 Extension Option ({})", err)?;
  183. Ok(())
  184. }
  185. }
  186. }
  187. }
  188. /// A high-level representation of an IPv6 Extension Header Option.
  189. #[derive(Debug, PartialEq, Eq, Clone, Copy)]
  190. pub enum Repr<'a> {
  191. Pad1,
  192. PadN(u8),
  193. Unknown {
  194. type_: Type,
  195. length: u8,
  196. data: &'a [u8]
  197. },
  198. #[doc(hidden)]
  199. __Nonexhaustive
  200. }
  201. impl<'a> Repr<'a> {
  202. /// Parse an IPv6 Extension Header Option and return a high-level representation.
  203. pub fn parse<T>(opt: &Ipv6Option<&'a T>) -> Result<Repr<'a>> where T: AsRef<[u8]> + ?Sized {
  204. match opt.option_type() {
  205. Type::Pad1 =>
  206. Ok(Repr::Pad1),
  207. Type::PadN =>
  208. Ok(Repr::PadN(opt.data_len())),
  209. unknown_type @ Type::Unknown(_) => {
  210. Ok(Repr::Unknown {
  211. type_: unknown_type,
  212. length: opt.data_len(),
  213. data: opt.data(),
  214. })
  215. }
  216. }
  217. }
  218. /// Return the length of a header that will be emitted from this high-level representation.
  219. pub fn buffer_len(&self) -> usize {
  220. match self {
  221. &Repr::Pad1 => 1,
  222. &Repr::PadN(length) =>
  223. field::DATA(length).end,
  224. &Repr::Unknown{ length, .. } =>
  225. field::DATA(length).end,
  226. &Repr::__Nonexhaustive => unreachable!()
  227. }
  228. }
  229. /// Emit a high-level representation into an IPv6 Extension Header Option.
  230. pub fn emit<T: AsRef<[u8]> + AsMut<[u8]> + ?Sized>(&self, opt: &mut Ipv6Option<&'a mut T>) {
  231. match self {
  232. &Repr::Pad1 =>
  233. opt.set_option_type(Type::Pad1),
  234. &Repr::PadN(len) => {
  235. opt.set_option_type(Type::PadN);
  236. opt.set_data_len(len);
  237. // Ensure all padding bytes are set to zero.
  238. for x in opt.data_mut().iter_mut() {
  239. *x = 0
  240. }
  241. }
  242. &Repr::Unknown{ type_, length, data } => {
  243. opt.set_option_type(type_);
  244. opt.set_data_len(length);
  245. opt.data_mut().copy_from_slice(&data[..length as usize]);
  246. }
  247. &Repr::__Nonexhaustive => unreachable!()
  248. }
  249. }
  250. }
  251. /// A iterator for IPv6 options.
  252. #[derive(Debug)]
  253. pub struct Ipv6OptionsIterator<'a> {
  254. pos: usize,
  255. length: usize,
  256. data: &'a [u8],
  257. hit_error: bool
  258. }
  259. impl<'a> Ipv6OptionsIterator<'a> {
  260. /// Create a new `Ipv6OptionsIterator`, used to iterate over the
  261. /// options contained in a IPv6 Extension Header (e.g. the Hop-by-Hop
  262. /// header).
  263. ///
  264. /// # Panics
  265. /// This function panics if the `length` provided is larger than the
  266. /// length of the `data` buffer.
  267. pub fn new(data: &'a [u8], length: usize) -> Ipv6OptionsIterator<'a> {
  268. assert!(length <= data.len());
  269. Ipv6OptionsIterator {
  270. pos: 0,
  271. hit_error: false,
  272. length, data
  273. }
  274. }
  275. /// Helper function to return an error in the implementation
  276. /// of `Iterator`.
  277. #[inline]
  278. fn return_err(&mut self, err: Error) -> Option<Result<Repr<'a>>> {
  279. self.hit_error = true;
  280. Some(Err(err))
  281. }
  282. }
  283. impl<'a> Iterator for Ipv6OptionsIterator<'a> {
  284. type Item = Result<Repr<'a>>;
  285. fn next(&mut self) -> Option<Self::Item> {
  286. if self.pos < self.length && !self.hit_error {
  287. // If we still have data to parse and we have not previously
  288. // hit an error, attempt to parse the next option.
  289. match Ipv6Option::new_checked(&self.data[self.pos..]) {
  290. Ok(hdr) => {
  291. match Repr::parse(&hdr) {
  292. Ok(repr) => {
  293. self.pos += repr.buffer_len();
  294. Some(Ok(repr))
  295. }
  296. Err(e) => {
  297. self.return_err(e)
  298. }
  299. }
  300. }
  301. Err(e) => {
  302. self.return_err(e)
  303. }
  304. }
  305. } else {
  306. // If we failed to parse a previous option or hit the end of the
  307. // buffer, we do not continue to iterate.
  308. None
  309. }
  310. }
  311. }
  312. impl<'a> fmt::Display for Repr<'a> {
  313. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  314. write!(f, "IPv6 Option ")?;
  315. match self {
  316. &Repr::Pad1 =>
  317. write!(f, "{} ", Type::Pad1),
  318. &Repr::PadN(len) =>
  319. write!(f, "{} length={} ", Type::PadN, len),
  320. &Repr::Unknown{ type_, length, .. } =>
  321. write!(f, "{} length={} ", type_, length),
  322. &Repr::__Nonexhaustive => unreachable!()
  323. }
  324. }
  325. }
  326. #[cfg(test)]
  327. mod test {
  328. use super::*;
  329. static IPV6OPTION_BYTES_PAD1: [u8; 1] = [0x0];
  330. static IPV6OPTION_BYTES_PADN: [u8; 3] = [0x1, 0x1, 0x0];
  331. static IPV6OPTION_BYTES_UNKNOWN: [u8; 5] = [0xff, 0x3, 0x0, 0x0, 0x0];
  332. #[test]
  333. fn test_check_len() {
  334. let bytes = [0u8];
  335. // zero byte buffer
  336. assert_eq!(Err(Error::Truncated), Ipv6Option::new(&bytes[..0]).check_len());
  337. // pad1
  338. assert_eq!(Ok(()), Ipv6Option::new(&IPV6OPTION_BYTES_PAD1).check_len());
  339. // padn with truncated data
  340. assert_eq!(Err(Error::Truncated), Ipv6Option::new(&IPV6OPTION_BYTES_PADN[..2]).check_len());
  341. // padn
  342. assert_eq!(Ok(()), Ipv6Option::new(&IPV6OPTION_BYTES_PADN).check_len());
  343. // unknown option type with truncated data
  344. assert_eq!(Err(Error::Truncated), Ipv6Option::new(&IPV6OPTION_BYTES_UNKNOWN[..4]).check_len());
  345. assert_eq!(Err(Error::Truncated), Ipv6Option::new(&IPV6OPTION_BYTES_UNKNOWN[..1]).check_len());
  346. // unknown type
  347. assert_eq!(Ok(()), Ipv6Option::new(&IPV6OPTION_BYTES_UNKNOWN).check_len());
  348. }
  349. #[test]
  350. #[should_panic(expected = "index out of bounds")]
  351. fn test_data_len() {
  352. let opt = Ipv6Option::new(&IPV6OPTION_BYTES_PAD1);
  353. opt.data_len();
  354. }
  355. #[test]
  356. fn test_option_deconstruct() {
  357. // one octet of padding
  358. let opt = Ipv6Option::new(&IPV6OPTION_BYTES_PAD1);
  359. assert_eq!(opt.option_type(), Type::Pad1);
  360. // two octets of padding
  361. let bytes: [u8; 2] = [0x1, 0x0];
  362. let opt = Ipv6Option::new(&bytes);
  363. assert_eq!(opt.option_type(), Type::PadN);
  364. assert_eq!(opt.data_len(), 0);
  365. // three octets of padding
  366. let opt = Ipv6Option::new(&IPV6OPTION_BYTES_PADN);
  367. assert_eq!(opt.option_type(), Type::PadN);
  368. assert_eq!(opt.data_len(), 1);
  369. assert_eq!(opt.data(), &[0]);
  370. // extra bytes in buffer
  371. let bytes: [u8; 10] = [0x1, 0x7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff];
  372. let opt = Ipv6Option::new(&bytes);
  373. assert_eq!(opt.option_type(), Type::PadN);
  374. assert_eq!(opt.data_len(), 7);
  375. assert_eq!(opt.data(), &[0, 0, 0, 0, 0, 0, 0]);
  376. // unrecognized option
  377. let bytes: [u8; 1] = [0xff];
  378. let opt = Ipv6Option::new(&bytes);
  379. assert_eq!(opt.option_type(), Type::Unknown(255));
  380. // unrecognized option without length and data
  381. assert_eq!(Ipv6Option::new_checked(&bytes), Err(Error::Truncated));
  382. }
  383. #[test]
  384. fn test_option_parse() {
  385. // one octet of padding
  386. let opt = Ipv6Option::new(&IPV6OPTION_BYTES_PAD1);
  387. let pad1 = Repr::parse(&opt).unwrap();
  388. assert_eq!(pad1, Repr::Pad1);
  389. assert_eq!(pad1.buffer_len(), 1);
  390. // two or more octets of padding
  391. let opt = Ipv6Option::new(&IPV6OPTION_BYTES_PADN);
  392. let padn = Repr::parse(&opt).unwrap();
  393. assert_eq!(padn, Repr::PadN(1));
  394. assert_eq!(padn.buffer_len(), 3);
  395. // unrecognized option type
  396. let data = [0u8; 3];
  397. let opt = Ipv6Option::new(&IPV6OPTION_BYTES_UNKNOWN);
  398. let unknown = Repr::parse(&opt).unwrap();
  399. assert_eq!(unknown, Repr::Unknown { type_: Type::Unknown(255), length: 3, data: &data});
  400. }
  401. #[test]
  402. fn test_option_emit() {
  403. let repr = Repr::Pad1;
  404. let mut bytes = [255u8; 1]; // don't assume bytes are initialized to zero
  405. let mut opt = Ipv6Option::new(&mut bytes);
  406. repr.emit(&mut opt);
  407. assert_eq!(opt.into_inner(), &IPV6OPTION_BYTES_PAD1);
  408. let repr = Repr::PadN(1);
  409. let mut bytes = [255u8; 3]; // don't assume bytes are initialized to zero
  410. let mut opt = Ipv6Option::new(&mut bytes);
  411. repr.emit(&mut opt);
  412. assert_eq!(opt.into_inner(), &IPV6OPTION_BYTES_PADN);
  413. let data = [0u8; 3];
  414. let repr = Repr::Unknown { type_: Type::Unknown(255), length: 3, data: &data };
  415. let mut bytes = [254u8; 5]; // don't assume bytes are initialized to zero
  416. let mut opt = Ipv6Option::new(&mut bytes);
  417. repr.emit(&mut opt);
  418. assert_eq!(opt.into_inner(), &IPV6OPTION_BYTES_UNKNOWN);
  419. }
  420. #[test]
  421. fn test_failure_type() {
  422. let mut failure_type: FailureType = Type::Pad1.into();
  423. assert_eq!(failure_type, FailureType::Skip);
  424. failure_type = Type::PadN.into();
  425. assert_eq!(failure_type, FailureType::Skip);
  426. failure_type = Type::Unknown(0b01000001).into();
  427. assert_eq!(failure_type, FailureType::Discard);
  428. failure_type = Type::Unknown(0b10100000).into();
  429. assert_eq!(failure_type, FailureType::DiscardSendAll);
  430. failure_type = Type::Unknown(0b11000100).into();
  431. assert_eq!(failure_type, FailureType::DiscardSendUnicast);
  432. }
  433. #[test]
  434. fn test_options_iter() {
  435. let options = [0x00, 0x01, 0x01, 0x00,
  436. 0x01, 0x02, 0x00, 0x00,
  437. 0x01, 0x00, 0x00, 0x11,
  438. 0x00, 0x01, 0x08, 0x00];
  439. let mut iterator = Ipv6OptionsIterator::new(&options, 0);
  440. assert_eq!(iterator.next(), None);
  441. iterator = Ipv6OptionsIterator::new(&options, 16);
  442. for (i, opt) in iterator.enumerate() {
  443. match (i, opt) {
  444. (0, Ok(Repr::Pad1)) => continue,
  445. (1, Ok(Repr::PadN(1))) => continue,
  446. (2, Ok(Repr::PadN(2))) => continue,
  447. (3, Ok(Repr::PadN(0))) => continue,
  448. (4, Ok(Repr::Pad1)) => continue,
  449. (5, Ok(Repr::Unknown { type_: Type::Unknown(0x11), length: 0, .. })) =>
  450. continue,
  451. (6, Err(Error::Truncated)) => continue,
  452. (i, res) => panic!("Unexpected option `{:?}` at index {}", res, i),
  453. }
  454. }
  455. }
  456. #[test]
  457. #[should_panic(expected = "length <= data.len()")]
  458. fn test_options_iter_truncated() {
  459. let options = [0x01, 0x02, 0x00, 0x00];
  460. let _ = Ipv6OptionsIterator::new(&options, 5);
  461. }
  462. }