icmpv6.rs 38 KB

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