icmpv6.rs 27 KB

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