icmpv4.rs 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610
  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::{Ipv4Packet, Ipv4Repr};
  7. enum_with_unknown! {
  8. /// Internet protocol control message type.
  9. pub doc enum Message(u8) {
  10. /// Echo reply
  11. EchoReply = 0,
  12. /// Destination unreachable
  13. DstUnreachable = 3,
  14. /// Message redirect
  15. Redirect = 5,
  16. /// Echo request
  17. EchoRequest = 8,
  18. /// Router advertisement
  19. RouterAdvert = 9,
  20. /// Router solicitation
  21. RouterSolicit = 10,
  22. /// Time exceeded
  23. TimeExceeded = 11,
  24. /// Parameter problem
  25. ParamProblem = 12,
  26. /// Timestamp
  27. Timestamp = 13,
  28. /// Timestamp reply
  29. TimestampReply = 14
  30. }
  31. }
  32. impl fmt::Display for Message {
  33. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  34. match self {
  35. &Message::EchoReply => write!(f, "echo reply"),
  36. &Message::DstUnreachable => write!(f, "destination unreachable"),
  37. &Message::Redirect => write!(f, "message redirect"),
  38. &Message::EchoRequest => write!(f, "echo request"),
  39. &Message::RouterAdvert => write!(f, "router advertisement"),
  40. &Message::RouterSolicit => write!(f, "router solicitation"),
  41. &Message::TimeExceeded => write!(f, "time exceeded"),
  42. &Message::ParamProblem => write!(f, "parameter problem"),
  43. &Message::Timestamp => write!(f, "timestamp"),
  44. &Message::TimestampReply => write!(f, "timestamp reply"),
  45. &Message::Unknown(id) => write!(f, "{}", id)
  46. }
  47. }
  48. }
  49. enum_with_unknown! {
  50. /// Internet protocol control message subtype for type "Destination Unreachable".
  51. pub doc enum DstUnreachable(u8) {
  52. /// Destination network unreachable
  53. NetUnreachable = 0,
  54. /// Destination host unreachable
  55. HostUnreachable = 1,
  56. /// Destination protocol unreachable
  57. ProtoUnreachable = 2,
  58. /// Destination port unreachable
  59. PortUnreachable = 3,
  60. /// Fragmentation required, and DF flag set
  61. FragRequired = 4,
  62. /// Source route failed
  63. SrcRouteFailed = 5,
  64. /// Destination network unknown
  65. DstNetUnknown = 6,
  66. /// Destination host unknown
  67. DstHostUnknown = 7,
  68. /// Source host isolated
  69. SrcHostIsolated = 8,
  70. /// Network administratively prohibited
  71. NetProhibited = 9,
  72. /// Host administratively prohibited
  73. HostProhibited = 10,
  74. /// Network unreachable for ToS
  75. NetUnreachToS = 11,
  76. /// Host unreachable for ToS
  77. HostUnreachToS = 12,
  78. /// Communication administratively prohibited
  79. CommProhibited = 13,
  80. /// Host precedence violation
  81. HostPrecedViol = 14,
  82. /// Precedence cutoff in effect
  83. PrecedCutoff = 15
  84. }
  85. }
  86. impl fmt::Display for DstUnreachable {
  87. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  88. match self {
  89. &DstUnreachable::NetUnreachable =>
  90. write!(f, "destination network unreachable"),
  91. &DstUnreachable::HostUnreachable =>
  92. write!(f, "destination host unreachable"),
  93. &DstUnreachable::ProtoUnreachable =>
  94. write!(f, "destination protocol unreachable"),
  95. &DstUnreachable::PortUnreachable =>
  96. write!(f, "destination port unreachable"),
  97. &DstUnreachable::FragRequired =>
  98. write!(f, "fragmentation required, and DF flag set"),
  99. &DstUnreachable::SrcRouteFailed =>
  100. write!(f, "source route failed"),
  101. &DstUnreachable::DstNetUnknown =>
  102. write!(f, "destination network unknown"),
  103. &DstUnreachable::DstHostUnknown =>
  104. write!(f, "destination host unknown"),
  105. &DstUnreachable::SrcHostIsolated =>
  106. write!(f, "source host isolated"),
  107. &DstUnreachable::NetProhibited =>
  108. write!(f, "network administratively prohibited"),
  109. &DstUnreachable::HostProhibited =>
  110. write!(f, "host administratively prohibited"),
  111. &DstUnreachable::NetUnreachToS =>
  112. write!(f, "network unreachable for ToS"),
  113. &DstUnreachable::HostUnreachToS =>
  114. write!(f, "host unreachable for ToS"),
  115. &DstUnreachable::CommProhibited =>
  116. write!(f, "communication administratively prohibited"),
  117. &DstUnreachable::HostPrecedViol =>
  118. write!(f, "host precedence violation"),
  119. &DstUnreachable::PrecedCutoff =>
  120. write!(f, "precedence cutoff in effect"),
  121. &DstUnreachable::Unknown(id) =>
  122. write!(f, "{}", id)
  123. }
  124. }
  125. }
  126. enum_with_unknown! {
  127. /// Internet protocol control message subtype for type "Redirect Message".
  128. pub doc enum Redirect(u8) {
  129. /// Redirect Datagram for the Network
  130. Net = 0,
  131. /// Redirect Datagram for the Host
  132. Host = 1,
  133. /// Redirect Datagram for the ToS & network
  134. NetToS = 2,
  135. /// Redirect Datagram for the ToS & host
  136. HostToS = 3
  137. }
  138. }
  139. enum_with_unknown! {
  140. /// Internet protocol control message subtype for type "Time Exceeded".
  141. pub doc enum TimeExceeded(u8) {
  142. /// TTL expired in transit
  143. TtlExpired = 0,
  144. /// Fragment reassembly time exceeded
  145. FragExpired = 1
  146. }
  147. }
  148. enum_with_unknown! {
  149. /// Internet protocol control message subtype for type "Parameter Problem".
  150. pub doc enum ParamProblem(u8) {
  151. /// Pointer indicates the error
  152. AtPointer = 0,
  153. /// Missing a required option
  154. MissingOption = 1,
  155. /// Bad length
  156. BadLength = 2
  157. }
  158. }
  159. /// A read/write wrapper around an Internet Control Message Protocol version 4 packet buffer.
  160. #[derive(Debug, PartialEq)]
  161. pub struct Packet<T: AsRef<[u8]>> {
  162. buffer: T
  163. }
  164. mod field {
  165. use wire::field::*;
  166. pub const TYPE: usize = 0;
  167. pub const CODE: usize = 1;
  168. pub const CHECKSUM: Field = 2..4;
  169. pub const UNUSED: Field = 4..8;
  170. pub const ECHO_IDENT: Field = 4..6;
  171. pub const ECHO_SEQNO: Field = 6..8;
  172. }
  173. impl<T: AsRef<[u8]>> Packet<T> {
  174. /// Imbue a raw octet buffer with ICMPv4 packet structure.
  175. pub fn new(buffer: T) -> Packet<T> {
  176. Packet { buffer }
  177. }
  178. /// Shorthand for a combination of [new] and [check_len].
  179. ///
  180. /// [new]: #method.new
  181. /// [check_len]: #method.check_len
  182. pub fn new_checked(buffer: T) -> Result<Packet<T>> {
  183. let packet = Self::new(buffer);
  184. packet.check_len()?;
  185. Ok(packet)
  186. }
  187. /// Ensure that no accessor method will panic if called.
  188. /// Returns `Err(Error::Truncated)` if the buffer is too short.
  189. ///
  190. /// The result of this check is invalidated by calling [set_header_len].
  191. ///
  192. /// [set_header_len]: #method.set_header_len
  193. pub fn check_len(&self) -> Result<()> {
  194. let len = self.buffer.as_ref().len();
  195. if len < field::CHECKSUM.end {
  196. Err(Error::Truncated)
  197. } else {
  198. if len < self.header_len() as usize {
  199. Err(Error::Truncated)
  200. } else {
  201. Ok(())
  202. }
  203. }
  204. }
  205. /// Consume the packet, returning the underlying buffer.
  206. pub fn into_inner(self) -> T {
  207. self.buffer
  208. }
  209. /// Return the message type field.
  210. #[inline]
  211. pub fn msg_type(&self) -> Message {
  212. let data = self.buffer.as_ref();
  213. Message::from(data[field::TYPE])
  214. }
  215. /// Return the message code field.
  216. #[inline]
  217. pub fn msg_code(&self) -> u8 {
  218. let data = self.buffer.as_ref();
  219. data[field::CODE]
  220. }
  221. /// Return the checksum field.
  222. #[inline]
  223. pub fn checksum(&self) -> u16 {
  224. let data = self.buffer.as_ref();
  225. NetworkEndian::read_u16(&data[field::CHECKSUM])
  226. }
  227. /// Return the identifier field (for echo request and reply packets).
  228. ///
  229. /// # Panics
  230. /// This function may panic if this packet is not an echo request or reply packet.
  231. #[inline]
  232. pub fn echo_ident(&self) -> u16 {
  233. let data = self.buffer.as_ref();
  234. NetworkEndian::read_u16(&data[field::ECHO_IDENT])
  235. }
  236. /// Return the sequence number field (for echo request and reply packets).
  237. ///
  238. /// # Panics
  239. /// This function may panic if this packet is not an echo request or reply packet.
  240. #[inline]
  241. pub fn echo_seq_no(&self) -> u16 {
  242. let data = self.buffer.as_ref();
  243. NetworkEndian::read_u16(&data[field::ECHO_SEQNO])
  244. }
  245. /// Return the header length.
  246. /// The result depends on the value of the message type field.
  247. pub fn header_len(&self) -> usize {
  248. match self.msg_type() {
  249. Message::EchoRequest => field::ECHO_SEQNO.end,
  250. Message::EchoReply => field::ECHO_SEQNO.end,
  251. Message::DstUnreachable => field::UNUSED.end,
  252. _ => field::CHECKSUM.end // make a conservative assumption
  253. }
  254. }
  255. /// Validate the header checksum.
  256. ///
  257. /// # Fuzzing
  258. /// This function always returns `true` when fuzzing.
  259. pub fn verify_checksum(&self) -> bool {
  260. if cfg!(fuzzing) { return true }
  261. let data = self.buffer.as_ref();
  262. checksum::data(data) == !0
  263. }
  264. }
  265. impl<'a, T: AsRef<[u8]> + ?Sized> Packet<&'a T> {
  266. /// Return a pointer to the type-specific data.
  267. #[inline]
  268. pub fn data(&self) -> &'a [u8] {
  269. let data = self.buffer.as_ref();
  270. &data[self.header_len()..]
  271. }
  272. }
  273. impl<T: AsRef<[u8]> + AsMut<[u8]>> Packet<T> {
  274. /// Set the message type field.
  275. #[inline]
  276. pub fn set_msg_type(&mut self, value: Message) {
  277. let data = self.buffer.as_mut();
  278. data[field::TYPE] = value.into()
  279. }
  280. /// Set the message code field.
  281. #[inline]
  282. pub fn set_msg_code(&mut self, value: u8) {
  283. let data = self.buffer.as_mut();
  284. data[field::CODE] = value
  285. }
  286. /// Set the checksum field.
  287. #[inline]
  288. pub fn set_checksum(&mut self, value: u16) {
  289. let data = self.buffer.as_mut();
  290. NetworkEndian::write_u16(&mut data[field::CHECKSUM], value)
  291. }
  292. /// Set the identifier field (for echo request and reply packets).
  293. ///
  294. /// # Panics
  295. /// This function may panic if this packet is not an echo request or reply packet.
  296. #[inline]
  297. pub fn set_echo_ident(&mut self, value: u16) {
  298. let data = self.buffer.as_mut();
  299. NetworkEndian::write_u16(&mut data[field::ECHO_IDENT], value)
  300. }
  301. /// Set the sequence number field (for echo request and reply packets).
  302. ///
  303. /// # Panics
  304. /// This function may panic if this packet is not an echo request or reply packet.
  305. #[inline]
  306. pub fn set_echo_seq_no(&mut self, value: u16) {
  307. let data = self.buffer.as_mut();
  308. NetworkEndian::write_u16(&mut data[field::ECHO_SEQNO], value)
  309. }
  310. /// Compute and fill in the header checksum.
  311. pub fn fill_checksum(&mut self) {
  312. self.set_checksum(0);
  313. let checksum = {
  314. let data = self.buffer.as_ref();
  315. !checksum::data(data)
  316. };
  317. self.set_checksum(checksum)
  318. }
  319. }
  320. impl<'a, T: AsRef<[u8]> + AsMut<[u8]> + ?Sized> Packet<&'a mut T> {
  321. /// Return a mutable pointer to the type-specific data.
  322. #[inline]
  323. pub fn data_mut(&mut self) -> &mut [u8] {
  324. let range = self.header_len()..;
  325. let data = self.buffer.as_mut();
  326. &mut data[range]
  327. }
  328. }
  329. /// A high-level representation of an Internet Control Message Protocol version 4 packet header.
  330. #[derive(Debug, PartialEq, Eq, Clone, Copy)]
  331. pub enum Repr<'a> {
  332. EchoRequest {
  333. ident: u16,
  334. seq_no: u16,
  335. data: &'a [u8]
  336. },
  337. EchoReply {
  338. ident: u16,
  339. seq_no: u16,
  340. data: &'a [u8]
  341. },
  342. DstUnreachable {
  343. reason: DstUnreachable,
  344. header: Ipv4Repr,
  345. data: &'a [u8]
  346. },
  347. #[doc(hidden)]
  348. __Nonexhaustive
  349. }
  350. impl<'a> Repr<'a> {
  351. /// Parse an Internet Control Message Protocol version 4 packet and return
  352. /// a high-level representation.
  353. pub fn parse<T>(packet: &Packet<&'a T>, checksum_caps: &ChecksumCapabilities)
  354. -> Result<Repr<'a>>
  355. where T: AsRef<[u8]> + ?Sized {
  356. // Valid checksum is expected.
  357. if checksum_caps.icmpv4.rx() && !packet.verify_checksum() { return Err(Error::Checksum) }
  358. match (packet.msg_type(), packet.msg_code()) {
  359. (Message::EchoRequest, 0) => {
  360. Ok(Repr::EchoRequest {
  361. ident: packet.echo_ident(),
  362. seq_no: packet.echo_seq_no(),
  363. data: packet.data()
  364. })
  365. },
  366. (Message::EchoReply, 0) => {
  367. Ok(Repr::EchoReply {
  368. ident: packet.echo_ident(),
  369. seq_no: packet.echo_seq_no(),
  370. data: packet.data()
  371. })
  372. },
  373. (Message::DstUnreachable, code) => {
  374. let ip_packet = Ipv4Packet::new_checked(packet.data())?;
  375. let payload = &packet.data()[ip_packet.header_len() as usize..];
  376. // RFC 792 requires exactly eight bytes to be returned.
  377. // We allow more, since there isn't a reason not to, but require at least eight.
  378. if payload.len() < 8 { return Err(Error::Truncated) }
  379. Ok(Repr::DstUnreachable {
  380. reason: DstUnreachable::from(code),
  381. header: Ipv4Repr {
  382. src_addr: ip_packet.src_addr(),
  383. dst_addr: ip_packet.dst_addr(),
  384. protocol: ip_packet.protocol(),
  385. payload_len: payload.len(),
  386. hop_limit: ip_packet.hop_limit()
  387. },
  388. data: payload
  389. })
  390. }
  391. _ => Err(Error::Unrecognized)
  392. }
  393. }
  394. /// Return the length of a packet that will be emitted from this high-level representation.
  395. pub fn buffer_len(&self) -> usize {
  396. match self {
  397. &Repr::EchoRequest { data, .. } |
  398. &Repr::EchoReply { data, .. } => {
  399. field::ECHO_SEQNO.end + data.len()
  400. },
  401. &Repr::DstUnreachable { header, data, .. } => {
  402. field::UNUSED.end + header.buffer_len() + data.len()
  403. }
  404. &Repr::__Nonexhaustive => unreachable!()
  405. }
  406. }
  407. /// Emit a high-level representation into an Internet Control Message Protocol version 4
  408. /// packet.
  409. pub fn emit<T>(&self, packet: &mut Packet<&mut T>, checksum_caps: &ChecksumCapabilities)
  410. where T: AsRef<[u8]> + AsMut<[u8]> + ?Sized {
  411. packet.set_msg_code(0);
  412. match self {
  413. &Repr::EchoRequest { ident, seq_no, data } => {
  414. packet.set_msg_type(Message::EchoRequest);
  415. packet.set_msg_code(0);
  416. packet.set_echo_ident(ident);
  417. packet.set_echo_seq_no(seq_no);
  418. let data_len = cmp::min(packet.data_mut().len(), data.len());
  419. packet.data_mut()[..data_len].copy_from_slice(&data[..data_len])
  420. },
  421. &Repr::EchoReply { ident, seq_no, data } => {
  422. packet.set_msg_type(Message::EchoReply);
  423. packet.set_msg_code(0);
  424. packet.set_echo_ident(ident);
  425. packet.set_echo_seq_no(seq_no);
  426. let data_len = cmp::min(packet.data_mut().len(), data.len());
  427. packet.data_mut()[..data_len].copy_from_slice(&data[..data_len])
  428. },
  429. &Repr::DstUnreachable { reason, header, data } => {
  430. packet.set_msg_type(Message::DstUnreachable);
  431. packet.set_msg_code(reason.into());
  432. let mut ip_packet = Ipv4Packet::new(packet.data_mut());
  433. header.emit(&mut ip_packet, checksum_caps);
  434. let payload = &mut ip_packet.into_inner()[header.buffer_len()..];
  435. payload.copy_from_slice(&data[..])
  436. }
  437. &Repr::__Nonexhaustive => unreachable!()
  438. }
  439. if checksum_caps.icmpv4.tx() {
  440. packet.fill_checksum()
  441. } else {
  442. // make sure we get a consistently zeroed checksum, since implementations might rely on it
  443. packet.set_checksum(0);
  444. }
  445. }
  446. }
  447. impl<'a, T: AsRef<[u8]> + ?Sized> fmt::Display for Packet<&'a T> {
  448. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  449. match Repr::parse(self, &ChecksumCapabilities::default()) {
  450. Ok(repr) => write!(f, "{}", repr),
  451. Err(err) => {
  452. write!(f, "ICMPv4 ({})", err)?;
  453. write!(f, " type={:?}", self.msg_type())?;
  454. match self.msg_type() {
  455. Message::DstUnreachable =>
  456. write!(f, " code={:?}", DstUnreachable::from(self.msg_code())),
  457. _ => write!(f, " code={}", self.msg_code())
  458. }
  459. }
  460. }
  461. }
  462. }
  463. impl<'a> fmt::Display for Repr<'a> {
  464. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  465. match self {
  466. &Repr::EchoRequest { ident, seq_no, data } =>
  467. write!(f, "ICMPv4 echo request id={} seq={} len={}",
  468. ident, seq_no, data.len()),
  469. &Repr::EchoReply { ident, seq_no, data } =>
  470. write!(f, "ICMPv4 echo reply id={} seq={} len={}",
  471. ident, seq_no, data.len()),
  472. &Repr::DstUnreachable { reason, .. } =>
  473. write!(f, "ICMPv4 destination unreachable ({})",
  474. reason),
  475. &Repr::__Nonexhaustive => unreachable!()
  476. }
  477. }
  478. }
  479. use super::pretty_print::{PrettyPrint, PrettyIndent};
  480. impl<T: AsRef<[u8]>> PrettyPrint for Packet<T> {
  481. fn pretty_print(buffer: &AsRef<[u8]>, f: &mut fmt::Formatter,
  482. indent: &mut PrettyIndent) -> fmt::Result {
  483. let packet = match Packet::new_checked(buffer) {
  484. Err(err) => return write!(f, "{}({})", indent, err),
  485. Ok(packet) => packet
  486. };
  487. write!(f, "{}{}", indent, packet)?;
  488. match packet.msg_type() {
  489. Message::DstUnreachable => {
  490. indent.increase(f)?;
  491. super::Ipv4Packet::<&[u8]>::pretty_print(&packet.data(), f, indent)
  492. }
  493. _ => Ok(())
  494. }
  495. }
  496. }
  497. #[cfg(test)]
  498. mod test {
  499. use super::*;
  500. static ECHO_PACKET_BYTES: [u8; 12] =
  501. [0x08, 0x00, 0x8e, 0xfe,
  502. 0x12, 0x34, 0xab, 0xcd,
  503. 0xaa, 0x00, 0x00, 0xff];
  504. static ECHO_DATA_BYTES: [u8; 4] =
  505. [0xaa, 0x00, 0x00, 0xff];
  506. #[test]
  507. fn test_echo_deconstruct() {
  508. let packet = Packet::new(&ECHO_PACKET_BYTES[..]);
  509. assert_eq!(packet.msg_type(), Message::EchoRequest);
  510. assert_eq!(packet.msg_code(), 0);
  511. assert_eq!(packet.checksum(), 0x8efe);
  512. assert_eq!(packet.echo_ident(), 0x1234);
  513. assert_eq!(packet.echo_seq_no(), 0xabcd);
  514. assert_eq!(packet.data(), &ECHO_DATA_BYTES[..]);
  515. assert_eq!(packet.verify_checksum(), true);
  516. }
  517. #[test]
  518. fn test_echo_construct() {
  519. let mut bytes = vec![0xa5; 12];
  520. let mut packet = Packet::new(&mut bytes);
  521. packet.set_msg_type(Message::EchoRequest);
  522. packet.set_msg_code(0);
  523. packet.set_echo_ident(0x1234);
  524. packet.set_echo_seq_no(0xabcd);
  525. packet.data_mut().copy_from_slice(&ECHO_DATA_BYTES[..]);
  526. packet.fill_checksum();
  527. assert_eq!(&packet.into_inner()[..], &ECHO_PACKET_BYTES[..]);
  528. }
  529. fn echo_packet_repr() -> Repr<'static> {
  530. Repr::EchoRequest {
  531. ident: 0x1234,
  532. seq_no: 0xabcd,
  533. data: &ECHO_DATA_BYTES
  534. }
  535. }
  536. #[test]
  537. fn test_echo_parse() {
  538. let packet = Packet::new(&ECHO_PACKET_BYTES[..]);
  539. let repr = Repr::parse(&packet, &ChecksumCapabilities::default()).unwrap();
  540. assert_eq!(repr, echo_packet_repr());
  541. }
  542. #[test]
  543. fn test_echo_emit() {
  544. let repr = echo_packet_repr();
  545. let mut bytes = vec![0xa5; repr.buffer_len()];
  546. let mut packet = Packet::new(&mut bytes);
  547. repr.emit(&mut packet, &ChecksumCapabilities::default());
  548. assert_eq!(&packet.into_inner()[..], &ECHO_PACKET_BYTES[..]);
  549. }
  550. }