icmpv6.rs 25 KB

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