icmpv6.rs 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904
  1. use core::{cmp, fmt};
  2. use byteorder::{ByteOrder, NetworkEndian};
  3. use {Error, Result};
  4. use phy::ChecksumCapabilities;
  5. use super::ip::checksum;
  6. use super::{IpAddress, IpProtocol, Ipv6Packet, Ipv6Repr};
  7. use super::MldRepr;
  8. #[cfg(feature = "ethernet")]
  9. use super::NdiscRepr;
  10. enum_with_unknown! {
  11. /// Internet protocol control message type.
  12. pub doc enum Message(u8) {
  13. /// Destination Unreachable.
  14. DstUnreachable = 0x01,
  15. /// Packet Too Big.
  16. PktTooBig = 0x02,
  17. /// Time Exceeded.
  18. TimeExceeded = 0x03,
  19. /// Parameter Problem.
  20. ParamProblem = 0x04,
  21. /// Echo Request
  22. EchoRequest = 0x80,
  23. /// Echo Reply
  24. EchoReply = 0x81,
  25. /// Multicast Listener Query
  26. MldQuery = 0x82,
  27. /// Router Solicitation
  28. RouterSolicit = 0x85,
  29. /// Router Advertisement
  30. RouterAdvert = 0x86,
  31. /// Neighbor Solicitation
  32. NeighborSolicit = 0x87,
  33. /// Neighbor Advertisement
  34. NeighborAdvert = 0x88,
  35. /// Redirect
  36. Redirect = 0x89,
  37. /// Multicast Listener Report
  38. MldReport = 0x8f
  39. }
  40. }
  41. impl Message {
  42. /// Per [RFC 4443 § 2.1] ICMPv6 message types with the highest order
  43. /// bit set are informational messages while message types without
  44. /// the highest order bit set are error messages.
  45. ///
  46. /// [RFC 4443 § 2.1]: https://tools.ietf.org/html/rfc4443#section-2.1
  47. pub fn is_error(&self) -> bool {
  48. (u8::from(*self) & 0x80) != 0x80
  49. }
  50. /// Return a boolean value indicating if the given message type
  51. /// is an [NDISC] message type.
  52. ///
  53. /// [NDISC]: https://tools.ietf.org/html/rfc4861
  54. pub fn is_ndisc(&self) -> bool {
  55. match *self {
  56. Message::RouterSolicit | Message::RouterAdvert | Message::NeighborSolicit |
  57. Message::NeighborAdvert | Message::Redirect => true,
  58. _ => false,
  59. }
  60. }
  61. /// Return a boolean value indicating if the given message type
  62. /// is an [MLD] message type.
  63. ///
  64. /// [MLD]: https://tools.ietf.org/html/rfc3810
  65. pub fn is_mld(&self) -> bool {
  66. match *self {
  67. Message::MldQuery | Message::MldReport => true,
  68. _ => false,
  69. }
  70. }
  71. }
  72. impl fmt::Display for Message {
  73. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  74. match self {
  75. &Message::DstUnreachable => write!(f, "destination unreachable"),
  76. &Message::PktTooBig => write!(f, "packet too big"),
  77. &Message::TimeExceeded => write!(f, "time exceeded"),
  78. &Message::ParamProblem => write!(f, "parameter problem"),
  79. &Message::EchoReply => write!(f, "echo reply"),
  80. &Message::EchoRequest => write!(f, "echo request"),
  81. &Message::RouterSolicit => write!(f, "router solicitation"),
  82. &Message::RouterAdvert => write!(f, "router advertisement"),
  83. &Message::NeighborSolicit => write!(f, "neighbor solicitation"),
  84. &Message::NeighborAdvert => write!(f, "neighbor advert"),
  85. &Message::Redirect => write!(f, "redirect"),
  86. &Message::MldQuery => write!(f, "multicast listener query"),
  87. &Message::MldReport => write!(f, "multicast listener report"),
  88. &Message::Unknown(id) => write!(f, "{}", id)
  89. }
  90. }
  91. }
  92. enum_with_unknown! {
  93. /// Internet protocol control message subtype for type "Destination Unreachable".
  94. pub doc enum DstUnreachable(u8) {
  95. /// No Route to destination.
  96. NoRoute = 0,
  97. /// Communication with destination administratively prohibited.
  98. AdminProhibit = 1,
  99. /// Beyond scope of source address.
  100. BeyondScope = 2,
  101. /// Address unreachable.
  102. AddrUnreachable = 3,
  103. /// Port unreachable.
  104. PortUnreachable = 4,
  105. /// Source address failed ingress/egress policy.
  106. FailedPolicy = 5,
  107. /// Reject route to destination.
  108. RejectRoute = 6
  109. }
  110. }
  111. impl fmt::Display for DstUnreachable {
  112. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  113. match self {
  114. &DstUnreachable::NoRoute =>
  115. write!(f, "no route to destination"),
  116. &DstUnreachable::AdminProhibit =>
  117. write!(f, "communication with destination administratively prohibited"),
  118. &DstUnreachable::BeyondScope =>
  119. write!(f, "beyond scope of source address"),
  120. &DstUnreachable::AddrUnreachable =>
  121. write!(f, "address unreachable"),
  122. &DstUnreachable::PortUnreachable =>
  123. write!(f, "port unreachable"),
  124. &DstUnreachable::FailedPolicy =>
  125. write!(f, "source address failed ingress/egress policy"),
  126. &DstUnreachable::RejectRoute =>
  127. write!(f, "reject route to destination"),
  128. &DstUnreachable::Unknown(id) =>
  129. write!(f, "{}", id)
  130. }
  131. }
  132. }
  133. enum_with_unknown! {
  134. /// Internet protocol control message subtype for the type "Parameter Problem".
  135. pub doc enum ParamProblem(u8) {
  136. /// Erroneous header field encountered.
  137. ErroneousHdrField = 0,
  138. /// Unrecognized Next Header type encountered.
  139. UnrecognizedNxtHdr = 1,
  140. /// Unrecognized IPv6 option encountered.
  141. UnrecognizedOption = 2
  142. }
  143. }
  144. impl fmt::Display for ParamProblem {
  145. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  146. match self {
  147. &ParamProblem::ErroneousHdrField =>
  148. write!(f, "erroneous header field."),
  149. &ParamProblem::UnrecognizedNxtHdr =>
  150. write!(f, "unrecognized next header type."),
  151. &ParamProblem::UnrecognizedOption =>
  152. write!(f, "unrecognized IPv6 option."),
  153. &ParamProblem::Unknown(id) =>
  154. write!(f, "{}", id)
  155. }
  156. }
  157. }
  158. enum_with_unknown! {
  159. /// Internet protocol control message subtype for the type "Time Exceeded".
  160. pub doc enum TimeExceeded(u8) {
  161. /// Hop limit exceeded in transit.
  162. HopLimitExceeded = 0,
  163. /// Fragment reassembly time exceeded.
  164. FragReassemExceeded = 1
  165. }
  166. }
  167. impl fmt::Display for TimeExceeded {
  168. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  169. match self {
  170. &TimeExceeded::HopLimitExceeded =>
  171. write!(f, "hop limit exceeded in transit"),
  172. &TimeExceeded::FragReassemExceeded =>
  173. write!(f, "fragment reassembly time exceeded"),
  174. &TimeExceeded::Unknown(id) =>
  175. write!(f, "{}", id)
  176. }
  177. }
  178. }
  179. /// A read/write wrapper around an Internet Control Message Protocol version 6 packet buffer.
  180. #[derive(Debug, PartialEq, Clone)]
  181. pub struct Packet<T: AsRef<[u8]>> {
  182. pub(super) buffer: T
  183. }
  184. // Ranges and constants describing key boundaries in the ICMPv6 header.
  185. pub(super) mod field {
  186. use wire::field::*;
  187. // ICMPv6: See https://tools.ietf.org/html/rfc4443
  188. pub const TYPE: usize = 0;
  189. pub const CODE: usize = 1;
  190. pub const CHECKSUM: Field = 2..4;
  191. pub const UNUSED: Field = 4..8;
  192. pub const MTU: Field = 4..8;
  193. pub const POINTER: Field = 4..8;
  194. pub const ECHO_IDENT: Field = 4..6;
  195. pub const ECHO_SEQNO: Field = 6..8;
  196. pub const HEADER_END: usize = 8;
  197. // NDISC: See https://tools.ietf.org/html/rfc4861
  198. // Router Advertisement message offsets
  199. pub const CUR_HOP_LIMIT: usize = 4;
  200. pub const ROUTER_FLAGS: usize = 5;
  201. pub const ROUTER_LT: Field = 6..8;
  202. pub const REACHABLE_TM: Field = 8..12;
  203. pub const RETRANS_TM: Field = 12..16;
  204. // Neighbor Solicitation message offsets
  205. pub const TARGET_ADDR: Field = 8..24;
  206. // Neighbor Advertisement message offsets
  207. pub const NEIGH_FLAGS: usize = 4;
  208. // Redirected Header message offsets
  209. pub const DEST_ADDR: Field = 24..40;
  210. // MLD:
  211. // - https://tools.ietf.org/html/rfc3810
  212. // - https://tools.ietf.org/html/rfc3810
  213. // Multicast Listener Query message
  214. pub const MAX_RESP_CODE: Field = 4..6;
  215. pub const QUERY_RESV: Field = 6..8;
  216. pub const QUERY_MCAST_ADDR: Field = 8..24;
  217. pub const SQRV: usize = 24;
  218. pub const QQIC: usize = 25;
  219. pub const QUERY_NUM_SRCS: Field = 26..28;
  220. // Multicast Listener Report Message
  221. pub const RECORD_RESV: Field = 4..6;
  222. pub const NR_MCAST_RCRDS: Field = 6..8;
  223. // Multicast Address Record Offsets
  224. pub const RECORD_TYPE: usize = 0;
  225. pub const AUX_DATA_LEN: usize = 1;
  226. pub const RECORD_NUM_SRCS: Field = 2..4;
  227. pub const RECORD_MCAST_ADDR: Field = 4..20;
  228. }
  229. impl<T: AsRef<[u8]>> Packet<T> {
  230. /// Imbue a raw octet buffer with ICMPv6 packet structure.
  231. pub fn new_unchecked(buffer: T) -> Packet<T> {
  232. Packet { buffer }
  233. }
  234. /// Shorthand for a combination of [new_unchecked] and [check_len].
  235. ///
  236. /// [new_unchecked]: #method.new_unchecked
  237. /// [check_len]: #method.check_len
  238. pub fn new_checked(buffer: T) -> Result<Packet<T>> {
  239. let packet = Self::new_unchecked(buffer);
  240. packet.check_len()?;
  241. Ok(packet)
  242. }
  243. /// Ensure that no accessor method will panic if called.
  244. /// Returns `Err(Error::Truncated)` if the buffer is too short.
  245. pub fn check_len(&self) -> Result<()> {
  246. let len = self.buffer.as_ref().len();
  247. if len < field::HEADER_END {
  248. Err(Error::Truncated)
  249. } else {
  250. if len < self.header_len() {
  251. Err(Error::Truncated)
  252. } else {
  253. Ok(())
  254. }
  255. }
  256. }
  257. /// Consume the packet, returning the underlying buffer.
  258. pub fn into_inner(self) -> T {
  259. self.buffer
  260. }
  261. /// Return the message type field.
  262. #[inline]
  263. pub fn msg_type(&self) -> Message {
  264. let data = self.buffer.as_ref();
  265. Message::from(data[field::TYPE])
  266. }
  267. /// Return the message code field.
  268. #[inline]
  269. pub fn msg_code(&self) -> u8 {
  270. let data = self.buffer.as_ref();
  271. data[field::CODE]
  272. }
  273. /// Return the checksum field.
  274. #[inline]
  275. pub fn checksum(&self) -> u16 {
  276. let data = self.buffer.as_ref();
  277. NetworkEndian::read_u16(&data[field::CHECKSUM])
  278. }
  279. /// Return the identifier field (for echo request and reply packets).
  280. #[inline]
  281. pub fn echo_ident(&self) -> u16 {
  282. let data = self.buffer.as_ref();
  283. NetworkEndian::read_u16(&data[field::ECHO_IDENT])
  284. }
  285. /// Return the sequence number field (for echo request and reply packets).
  286. #[inline]
  287. pub fn echo_seq_no(&self) -> u16 {
  288. let data = self.buffer.as_ref();
  289. NetworkEndian::read_u16(&data[field::ECHO_SEQNO])
  290. }
  291. /// Return the MTU field (for packet too big messages).
  292. #[inline]
  293. pub fn pkt_too_big_mtu(&self) -> u32 {
  294. let data = self.buffer.as_ref();
  295. NetworkEndian::read_u32(&data[field::MTU])
  296. }
  297. /// Return the pointer field (for parameter problem messages).
  298. #[inline]
  299. pub fn param_problem_ptr(&self) -> u32 {
  300. let data = self.buffer.as_ref();
  301. NetworkEndian::read_u32(&data[field::POINTER])
  302. }
  303. /// Return the header length. The result depends on the value of
  304. /// the message type field.
  305. pub fn header_len(&self) -> usize {
  306. match self.msg_type() {
  307. Message::DstUnreachable => field::UNUSED.end,
  308. Message::PktTooBig => field::MTU.end,
  309. Message::TimeExceeded => field::UNUSED.end,
  310. Message::ParamProblem => field::POINTER.end,
  311. Message::EchoRequest => field::ECHO_SEQNO.end,
  312. Message::EchoReply => field::ECHO_SEQNO.end,
  313. Message::RouterSolicit => field::UNUSED.end,
  314. Message::RouterAdvert => field::RETRANS_TM.end,
  315. Message::NeighborSolicit => field::TARGET_ADDR.end,
  316. Message::NeighborAdvert => field::TARGET_ADDR.end,
  317. Message::Redirect => field::DEST_ADDR.end,
  318. Message::MldQuery => field::QUERY_NUM_SRCS.end,
  319. Message::MldReport => field::NR_MCAST_RCRDS.end,
  320. // For packets that are not included in RFC 4443, do not
  321. // include the last 32 bits of the ICMPv6 header in
  322. // `header_bytes`. This must be done so that these bytes
  323. // can be accessed in the `payload`.
  324. _ => field::CHECKSUM.end
  325. }
  326. }
  327. /// Validate the header checksum.
  328. ///
  329. /// # Fuzzing
  330. /// This function always returns `true` when fuzzing.
  331. pub fn verify_checksum(&self, src_addr: &IpAddress, dst_addr: &IpAddress) -> bool {
  332. if cfg!(fuzzing) { return true }
  333. let data = self.buffer.as_ref();
  334. checksum::combine(&[
  335. checksum::pseudo_header(src_addr, dst_addr, IpProtocol::Icmpv6,
  336. data.len() as u32),
  337. checksum::data(data)
  338. ]) == !0
  339. }
  340. }
  341. impl<'a, T: AsRef<[u8]> + ?Sized> Packet<&'a T> {
  342. /// Return a pointer to the type-specific data.
  343. #[inline]
  344. pub fn payload(&self) -> &'a [u8] {
  345. let data = self.buffer.as_ref();
  346. &data[self.header_len()..]
  347. }
  348. }
  349. impl<T: AsRef<[u8]> + AsMut<[u8]>> Packet<T> {
  350. /// Set the message type field.
  351. #[inline]
  352. pub fn set_msg_type(&mut self, value: Message) {
  353. let data = self.buffer.as_mut();
  354. data[field::TYPE] = value.into()
  355. }
  356. /// Set the message code field.
  357. #[inline]
  358. pub fn set_msg_code(&mut self, value: u8) {
  359. let data = self.buffer.as_mut();
  360. data[field::CODE] = value
  361. }
  362. /// Clear any reserved fields in the message header.
  363. ///
  364. /// # Panics
  365. /// This function panics if the message type has not been set.
  366. /// See [set_msg_type].
  367. ///
  368. /// [set_msg_type]: #method.set_msg_type
  369. #[inline]
  370. pub fn clear_reserved(&mut self) {
  371. match self.msg_type() {
  372. Message::RouterSolicit | Message::NeighborSolicit |
  373. Message::NeighborAdvert | Message::Redirect => {
  374. let data = self.buffer.as_mut();
  375. NetworkEndian::write_u32(&mut data[field::UNUSED], 0);
  376. },
  377. Message::MldQuery => {
  378. let data = self.buffer.as_mut();
  379. NetworkEndian::write_u16(&mut data[field::QUERY_RESV], 0);
  380. data[field::SQRV] = data[field::SQRV] & 0xf;
  381. },
  382. Message::MldReport => {
  383. let data = self.buffer.as_mut();
  384. NetworkEndian::write_u16(&mut data[field::RECORD_RESV], 0);
  385. }
  386. ty => panic!("Message type `{}` does not have any reserved fields.", ty),
  387. }
  388. }
  389. #[inline]
  390. pub fn set_checksum(&mut self, value: u16) {
  391. let data = self.buffer.as_mut();
  392. NetworkEndian::write_u16(&mut data[field::CHECKSUM], value)
  393. }
  394. /// Set the identifier field (for echo request and reply packets).
  395. ///
  396. /// # Panics
  397. /// This function may panic if this packet is not an echo request or reply packet.
  398. #[inline]
  399. pub fn set_echo_ident(&mut self, value: u16) {
  400. let data = self.buffer.as_mut();
  401. NetworkEndian::write_u16(&mut data[field::ECHO_IDENT], value)
  402. }
  403. /// Set the sequence number field (for echo request and reply packets).
  404. ///
  405. /// # Panics
  406. /// This function may panic if this packet is not an echo request or reply packet.
  407. #[inline]
  408. pub fn set_echo_seq_no(&mut self, value: u16) {
  409. let data = self.buffer.as_mut();
  410. NetworkEndian::write_u16(&mut data[field::ECHO_SEQNO], value)
  411. }
  412. /// Set the MTU field (for packet too big messages).
  413. ///
  414. /// # Panics
  415. /// This function may panic if this packet is not an packet too big packet.
  416. #[inline]
  417. pub fn set_pkt_too_big_mtu(&mut self, value: u32) {
  418. let data = self.buffer.as_mut();
  419. NetworkEndian::write_u32(&mut data[field::MTU], value)
  420. }
  421. /// Set the pointer field (for parameter problem messages).
  422. ///
  423. /// # Panics
  424. /// This function may panic if this packet is not a parameter problem message.
  425. #[inline]
  426. pub fn set_param_problem_ptr(&mut self, value: u32) {
  427. let data = self.buffer.as_mut();
  428. NetworkEndian::write_u32(&mut data[field::POINTER], value)
  429. }
  430. /// Compute and fill in the header checksum.
  431. pub fn fill_checksum(&mut self, src_addr: &IpAddress, dst_addr: &IpAddress) {
  432. self.set_checksum(0);
  433. let checksum = {
  434. let data = self.buffer.as_ref();
  435. !checksum::combine(&[
  436. checksum::pseudo_header(src_addr, dst_addr, IpProtocol::Icmpv6,
  437. data.len() as u32),
  438. checksum::data(data)
  439. ])
  440. };
  441. self.set_checksum(checksum)
  442. }
  443. /// Return a mutable pointer to the type-specific data.
  444. #[inline]
  445. pub fn payload_mut(&mut self) -> &mut [u8] {
  446. let range = self.header_len()..;
  447. let data = self.buffer.as_mut();
  448. &mut data[range]
  449. }
  450. }
  451. impl<T: AsRef<[u8]>> AsRef<[u8]> for Packet<T> {
  452. fn as_ref(&self) -> &[u8] {
  453. self.buffer.as_ref()
  454. }
  455. }
  456. /// A high-level representation of an Internet Control Message Protocol version 6 packet header.
  457. #[derive(Debug, PartialEq, Eq, Clone, Copy)]
  458. pub enum Repr<'a> {
  459. DstUnreachable {
  460. reason: DstUnreachable,
  461. header: Ipv6Repr,
  462. data: &'a [u8]
  463. },
  464. PktTooBig {
  465. mtu: u32,
  466. header: Ipv6Repr,
  467. data: &'a [u8]
  468. },
  469. TimeExceeded {
  470. reason: TimeExceeded,
  471. header: Ipv6Repr,
  472. data: &'a [u8]
  473. },
  474. ParamProblem {
  475. reason: ParamProblem,
  476. pointer: u32,
  477. header: Ipv6Repr,
  478. data: &'a [u8]
  479. },
  480. EchoRequest {
  481. ident: u16,
  482. seq_no: u16,
  483. data: &'a [u8]
  484. },
  485. EchoReply {
  486. ident: u16,
  487. seq_no: u16,
  488. data: &'a [u8]
  489. },
  490. #[cfg(feature = "ethernet")]
  491. Ndisc(NdiscRepr<'a>),
  492. Mld(MldRepr<'a>),
  493. #[doc(hidden)]
  494. __Nonexhaustive
  495. }
  496. impl<'a> Repr<'a> {
  497. /// Parse an Internet Control Message Protocol version 6 packet and return
  498. /// a high-level representation.
  499. pub fn parse<T>(src_addr: &IpAddress, dst_addr: &IpAddress,
  500. packet: &Packet<&'a T>, checksum_caps: &ChecksumCapabilities)
  501. -> Result<Repr<'a>>
  502. where T: AsRef<[u8]> + ?Sized {
  503. fn create_packet_from_payload<'a, T>(packet: &Packet<&'a T>)
  504. -> Result<(&'a [u8], Ipv6Repr)>
  505. where T: AsRef<[u8]> + ?Sized {
  506. let ip_packet = Ipv6Packet::new_checked(packet.payload())?;
  507. let payload = &packet.payload()[ip_packet.header_len() as usize..];
  508. if payload.len() < 8 { return Err(Error::Truncated) }
  509. let repr = Ipv6Repr {
  510. src_addr: ip_packet.src_addr(),
  511. dst_addr: ip_packet.dst_addr(),
  512. next_header: ip_packet.next_header(),
  513. payload_len: payload.len(),
  514. hop_limit: ip_packet.hop_limit()
  515. };
  516. Ok((payload, repr))
  517. }
  518. // Valid checksum is expected.
  519. if checksum_caps.icmpv6.rx() && !packet.verify_checksum(src_addr, dst_addr) {
  520. return Err(Error::Checksum)
  521. }
  522. match (packet.msg_type(), packet.msg_code()) {
  523. (Message::DstUnreachable, code) => {
  524. let (payload, repr) = create_packet_from_payload(packet)?;
  525. Ok(Repr::DstUnreachable {
  526. reason: DstUnreachable::from(code),
  527. header: repr,
  528. data: payload
  529. })
  530. },
  531. (Message::PktTooBig, 0) => {
  532. let (payload, repr) = create_packet_from_payload(packet)?;
  533. Ok(Repr::PktTooBig {
  534. mtu: packet.pkt_too_big_mtu(),
  535. header: repr,
  536. data: payload
  537. })
  538. },
  539. (Message::TimeExceeded, code) => {
  540. let (payload, repr) = create_packet_from_payload(packet)?;
  541. Ok(Repr::TimeExceeded {
  542. reason: TimeExceeded::from(code),
  543. header: repr,
  544. data: payload
  545. })
  546. },
  547. (Message::ParamProblem, code) => {
  548. let (payload, repr) = create_packet_from_payload(packet)?;
  549. Ok(Repr::ParamProblem {
  550. reason: ParamProblem::from(code),
  551. pointer: packet.param_problem_ptr(),
  552. header: repr,
  553. data: payload
  554. })
  555. },
  556. (Message::EchoRequest, 0) => {
  557. Ok(Repr::EchoRequest {
  558. ident: packet.echo_ident(),
  559. seq_no: packet.echo_seq_no(),
  560. data: packet.payload()
  561. })
  562. },
  563. (Message::EchoReply, 0) => {
  564. Ok(Repr::EchoReply {
  565. ident: packet.echo_ident(),
  566. seq_no: packet.echo_seq_no(),
  567. data: packet.payload()
  568. })
  569. },
  570. #[cfg(feature = "ethernet")]
  571. (msg_type, 0) if msg_type.is_ndisc() => {
  572. NdiscRepr::parse(packet).map(|repr| Repr::Ndisc(repr))
  573. },
  574. (msg_type, 0) if msg_type.is_mld() => {
  575. MldRepr::parse(packet).map(|repr| Repr::Mld(repr))
  576. },
  577. _ => Err(Error::Unrecognized)
  578. }
  579. }
  580. /// Return the length of a packet that will be emitted from this high-level representation.
  581. pub fn buffer_len(&self) -> usize {
  582. match self {
  583. &Repr::DstUnreachable { header, data, .. } | &Repr::PktTooBig { header, data, .. } |
  584. &Repr::TimeExceeded { header, data, .. } | &Repr::ParamProblem { header, data, .. } => {
  585. field::UNUSED.end + header.buffer_len() + data.len()
  586. }
  587. &Repr::EchoRequest { data, .. } |
  588. &Repr::EchoReply { data, .. } => {
  589. field::ECHO_SEQNO.end + data.len()
  590. },
  591. #[cfg(feature = "ethernet")]
  592. &Repr::Ndisc(ndisc) => {
  593. ndisc.buffer_len()
  594. },
  595. &Repr::Mld(mld) => {
  596. mld.buffer_len()
  597. },
  598. &Repr::__Nonexhaustive => unreachable!()
  599. }
  600. }
  601. /// Emit a high-level representation into an Internet Control Message Protocol version 6
  602. /// packet.
  603. pub fn emit<T>(&self, src_addr: &IpAddress, dst_addr: &IpAddress,
  604. packet: &mut Packet<&mut T>, checksum_caps: &ChecksumCapabilities)
  605. where T: AsRef<[u8]> + AsMut<[u8]> + ?Sized {
  606. fn emit_contained_packet(buffer: &mut [u8], header: Ipv6Repr, data: &[u8]) {
  607. let mut ip_packet = Ipv6Packet::new_unchecked(buffer);
  608. header.emit(&mut ip_packet);
  609. let payload = &mut ip_packet.into_inner()[header.buffer_len()..];
  610. payload.copy_from_slice(&data[..]);
  611. }
  612. match self {
  613. &Repr::DstUnreachable { reason, header, data } => {
  614. packet.set_msg_type(Message::DstUnreachable);
  615. packet.set_msg_code(reason.into());
  616. emit_contained_packet(packet.payload_mut(), header, &data);
  617. },
  618. &Repr::PktTooBig { mtu, header, data } => {
  619. packet.set_msg_type(Message::PktTooBig);
  620. packet.set_msg_code(0);
  621. packet.set_pkt_too_big_mtu(mtu);
  622. emit_contained_packet(packet.payload_mut(), header, &data);
  623. },
  624. &Repr::TimeExceeded { reason, header, data } => {
  625. packet.set_msg_type(Message::TimeExceeded);
  626. packet.set_msg_code(reason.into());
  627. emit_contained_packet(packet.payload_mut(), header, &data);
  628. },
  629. &Repr::ParamProblem { reason, pointer, header, data } => {
  630. packet.set_msg_type(Message::ParamProblem);
  631. packet.set_msg_code(reason.into());
  632. packet.set_param_problem_ptr(pointer);
  633. emit_contained_packet(packet.payload_mut(), header, &data);
  634. },
  635. &Repr::EchoRequest { ident, seq_no, data } => {
  636. packet.set_msg_type(Message::EchoRequest);
  637. packet.set_msg_code(0);
  638. packet.set_echo_ident(ident);
  639. packet.set_echo_seq_no(seq_no);
  640. let data_len = cmp::min(packet.payload_mut().len(), data.len());
  641. packet.payload_mut()[..data_len].copy_from_slice(&data[..data_len])
  642. },
  643. &Repr::EchoReply { ident, seq_no, data } => {
  644. packet.set_msg_type(Message::EchoReply);
  645. packet.set_msg_code(0);
  646. packet.set_echo_ident(ident);
  647. packet.set_echo_seq_no(seq_no);
  648. let data_len = cmp::min(packet.payload_mut().len(), data.len());
  649. packet.payload_mut()[..data_len].copy_from_slice(&data[..data_len])
  650. },
  651. #[cfg(feature = "ethernet")]
  652. &Repr::Ndisc(ndisc) => {
  653. ndisc.emit(packet)
  654. },
  655. &Repr::Mld(mld) => {
  656. mld.emit(packet)
  657. },
  658. &Repr::__Nonexhaustive => unreachable!(),
  659. }
  660. if checksum_caps.icmpv6.tx() {
  661. packet.fill_checksum(src_addr, dst_addr);
  662. } else {
  663. // make sure we get a consistently zeroed checksum, since implementations might rely on it
  664. packet.set_checksum(0);
  665. }
  666. }
  667. }
  668. #[cfg(test)]
  669. mod test {
  670. use wire::{Ipv6Address, Ipv6Repr, IpProtocol};
  671. use wire::ip::test::{MOCK_IP_ADDR_1, MOCK_IP_ADDR_2};
  672. use super::*;
  673. static ECHO_PACKET_BYTES: [u8; 12] =
  674. [0x80, 0x00, 0x19, 0xb3,
  675. 0x12, 0x34, 0xab, 0xcd,
  676. 0xaa, 0x00, 0x00, 0xff];
  677. static ECHO_PACKET_PAYLOAD: [u8; 4] =
  678. [0xaa, 0x00, 0x00, 0xff];
  679. static PKT_TOO_BIG_BYTES: [u8; 60] =
  680. [0x02, 0x00, 0x0f, 0xc9,
  681. 0x00, 0x00, 0x05, 0xdc,
  682. 0x60, 0x00, 0x00, 0x00,
  683. 0x00, 0x0c, 0x11, 0x40,
  684. 0xfe, 0x80, 0x00, 0x00,
  685. 0x00, 0x00, 0x00, 0x00,
  686. 0x00, 0x00, 0x00, 0x00,
  687. 0x00, 0x00, 0x00, 0x01,
  688. 0xfe, 0x80, 0x00, 0x00,
  689. 0x00, 0x00, 0x00, 0x00,
  690. 0x00, 0x00, 0x00, 0x00,
  691. 0x00, 0x00, 0x00, 0x02,
  692. 0xbf, 0x00, 0x00, 0x35,
  693. 0x00, 0x0c, 0x12, 0x4d,
  694. 0xaa, 0x00, 0x00, 0xff];
  695. static PKT_TOO_BIG_IP_PAYLOAD: [u8; 52] =
  696. [0x60, 0x00, 0x00, 0x00,
  697. 0x00, 0x0c, 0x11, 0x40,
  698. 0xfe, 0x80, 0x00, 0x00,
  699. 0x00, 0x00, 0x00, 0x00,
  700. 0x00, 0x00, 0x00, 0x00,
  701. 0x00, 0x00, 0x00, 0x01,
  702. 0xfe, 0x80, 0x00, 0x00,
  703. 0x00, 0x00, 0x00, 0x00,
  704. 0x00, 0x00, 0x00, 0x00,
  705. 0x00, 0x00, 0x00, 0x02,
  706. 0xbf, 0x00, 0x00, 0x35,
  707. 0x00, 0x0c, 0x12, 0x4d,
  708. 0xaa, 0x00, 0x00, 0xff];
  709. static PKT_TOO_BIG_UDP_PAYLOAD: [u8; 12] =
  710. [0xbf, 0x00, 0x00, 0x35,
  711. 0x00, 0x0c, 0x12, 0x4d,
  712. 0xaa, 0x00, 0x00, 0xff];
  713. fn echo_packet_repr() -> Repr<'static> {
  714. Repr::EchoRequest {
  715. ident: 0x1234,
  716. seq_no: 0xabcd,
  717. data: &ECHO_PACKET_PAYLOAD
  718. }
  719. }
  720. fn too_big_packet_repr() -> Repr<'static> {
  721. Repr::PktTooBig {
  722. mtu: 1500,
  723. header: Ipv6Repr {
  724. src_addr: Ipv6Address([0xfe, 0x80, 0x00, 0x00,
  725. 0x00, 0x00, 0x00, 0x00,
  726. 0x00, 0x00, 0x00, 0x00,
  727. 0x00, 0x00, 0x00, 0x01]),
  728. dst_addr: Ipv6Address([0xfe, 0x80, 0x00, 0x00,
  729. 0x00, 0x00, 0x00, 0x00,
  730. 0x00, 0x00, 0x00, 0x00,
  731. 0x00, 0x00, 0x00, 0x02]),
  732. next_header: IpProtocol::Udp,
  733. payload_len: 12,
  734. hop_limit: 0x40
  735. },
  736. data: &PKT_TOO_BIG_UDP_PAYLOAD,
  737. }
  738. }
  739. #[test]
  740. fn test_echo_deconstruct() {
  741. let packet = Packet::new_unchecked(&ECHO_PACKET_BYTES[..]);
  742. assert_eq!(packet.msg_type(), Message::EchoRequest);
  743. assert_eq!(packet.msg_code(), 0);
  744. assert_eq!(packet.checksum(), 0x19b3);
  745. assert_eq!(packet.echo_ident(), 0x1234);
  746. assert_eq!(packet.echo_seq_no(), 0xabcd);
  747. assert_eq!(packet.payload(), &ECHO_PACKET_PAYLOAD[..]);
  748. assert_eq!(packet.verify_checksum(&MOCK_IP_ADDR_1, &MOCK_IP_ADDR_2), true);
  749. assert!(!packet.msg_type().is_error());
  750. }
  751. #[test]
  752. fn test_echo_construct() {
  753. let mut bytes = vec![0xa5; 12];
  754. let mut packet = Packet::new_unchecked(&mut bytes);
  755. packet.set_msg_type(Message::EchoRequest);
  756. packet.set_msg_code(0);
  757. packet.set_echo_ident(0x1234);
  758. packet.set_echo_seq_no(0xabcd);
  759. packet.payload_mut().copy_from_slice(&ECHO_PACKET_PAYLOAD[..]);
  760. packet.fill_checksum(&MOCK_IP_ADDR_1, &MOCK_IP_ADDR_2);
  761. assert_eq!(&packet.into_inner()[..], &ECHO_PACKET_BYTES[..]);
  762. }
  763. #[test]
  764. fn test_echo_repr_parse() {
  765. let packet = Packet::new_unchecked(&ECHO_PACKET_BYTES[..]);
  766. let repr = Repr::parse(&MOCK_IP_ADDR_1, &MOCK_IP_ADDR_2,
  767. &packet, &ChecksumCapabilities::default()).unwrap();
  768. assert_eq!(repr, echo_packet_repr());
  769. }
  770. #[test]
  771. fn test_echo_emit() {
  772. let repr = echo_packet_repr();
  773. let mut bytes = vec![0xa5; repr.buffer_len()];
  774. let mut packet = Packet::new_unchecked(&mut bytes);
  775. repr.emit(&MOCK_IP_ADDR_1, &MOCK_IP_ADDR_2,
  776. &mut packet, &ChecksumCapabilities::default());
  777. assert_eq!(&packet.into_inner()[..], &ECHO_PACKET_BYTES[..]);
  778. }
  779. #[test]
  780. fn test_too_big_deconstruct() {
  781. let packet = Packet::new_unchecked(&PKT_TOO_BIG_BYTES[..]);
  782. assert_eq!(packet.msg_type(), Message::PktTooBig);
  783. assert_eq!(packet.msg_code(), 0);
  784. assert_eq!(packet.checksum(), 0x0fc9);
  785. assert_eq!(packet.pkt_too_big_mtu(), 1500);
  786. assert_eq!(packet.payload(), &PKT_TOO_BIG_IP_PAYLOAD[..]);
  787. assert_eq!(packet.verify_checksum(&MOCK_IP_ADDR_1, &MOCK_IP_ADDR_2), true);
  788. assert!(packet.msg_type().is_error());
  789. }
  790. #[test]
  791. fn test_too_big_construct() {
  792. let mut bytes = vec![0xa5; 60];
  793. let mut packet = Packet::new_unchecked(&mut bytes);
  794. packet.set_msg_type(Message::PktTooBig);
  795. packet.set_msg_code(0);
  796. packet.set_pkt_too_big_mtu(1500);
  797. packet.payload_mut().copy_from_slice(&PKT_TOO_BIG_IP_PAYLOAD[..]);
  798. packet.fill_checksum(&MOCK_IP_ADDR_1, &MOCK_IP_ADDR_2);
  799. assert_eq!(&packet.into_inner()[..], &PKT_TOO_BIG_BYTES[..]);
  800. }
  801. #[test]
  802. fn test_too_big_repr_parse() {
  803. let packet = Packet::new_unchecked(&PKT_TOO_BIG_BYTES[..]);
  804. let repr = Repr::parse(&MOCK_IP_ADDR_1, &MOCK_IP_ADDR_2,
  805. &packet, &ChecksumCapabilities::default()).unwrap();
  806. assert_eq!(repr, too_big_packet_repr());
  807. }
  808. #[test]
  809. fn test_too_big_emit() {
  810. let repr = too_big_packet_repr();
  811. let mut bytes = vec![0xa5; repr.buffer_len()];
  812. let mut packet = Packet::new_unchecked(&mut bytes);
  813. repr.emit(&MOCK_IP_ADDR_1, &MOCK_IP_ADDR_2,
  814. &mut packet, &ChecksumCapabilities::default());
  815. assert_eq!(&packet.into_inner()[..], &PKT_TOO_BIG_BYTES[..]);
  816. }
  817. }