ipv4.rs 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587
  1. use core::fmt;
  2. use byteorder::{ByteOrder, NetworkEndian};
  3. use Error;
  4. use super::ip::checksum;
  5. pub use super::InternetProtocolType as ProtocolType;
  6. /// A four-octet IPv4 address.
  7. #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Default)]
  8. pub struct Address(pub [u8; 4]);
  9. impl Address {
  10. pub const UNSPECIFIED: Address = Address([0x00; 4]);
  11. pub const BROADCAST: Address = Address([0xff; 4]);
  12. /// Construct an IPv4 address from a sequence of octets, in big-endian.
  13. ///
  14. /// # Panics
  15. /// The function panics if `data` is not four octets long.
  16. pub fn from_bytes(data: &[u8]) -> Address {
  17. let mut bytes = [0; 4];
  18. bytes.copy_from_slice(data);
  19. Address(bytes)
  20. }
  21. /// Return an IPv4 address as a sequence of octets, in big-endian.
  22. pub fn as_bytes(&self) -> &[u8] {
  23. &self.0
  24. }
  25. /// Query whether the address is an unicast address.
  26. pub fn is_unicast(&self) -> bool {
  27. !(self.is_broadcast() ||
  28. self.is_multicast() ||
  29. self.is_unspecified())
  30. }
  31. /// Query whether the address is the broadcast address.
  32. pub fn is_broadcast(&self) -> bool {
  33. self.0[0..4] == [255; 4]
  34. }
  35. /// Query whether the address is a multicast address.
  36. pub fn is_multicast(&self) -> bool {
  37. self.0[0] & 0xf0 == 224
  38. }
  39. /// Query whether the address falls into the "unspecified" range.
  40. pub fn is_unspecified(&self) -> bool {
  41. self.0[0] == 0
  42. }
  43. /// Query whether the address falls into the "link-local" range.
  44. pub fn is_link_local(&self) -> bool {
  45. self.0[0..2] == [169, 254]
  46. }
  47. /// Query whether the address falls into the "loopback" range.
  48. pub fn is_loopback(&self) -> bool {
  49. self.0[0] == 127
  50. }
  51. }
  52. impl fmt::Display for Address {
  53. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  54. let bytes = self.0;
  55. write!(f, "{}.{}.{}.{}", bytes[0], bytes[1], bytes[2], bytes[3])
  56. }
  57. }
  58. /// A read/write wrapper around an Internet Protocol version 4 packet buffer.
  59. #[derive(Debug)]
  60. pub struct Packet<T: AsRef<[u8]>> {
  61. buffer: T
  62. }
  63. mod field {
  64. use wire::field::*;
  65. pub const VER_IHL: usize = 0;
  66. pub const DSCP_ECN: usize = 1;
  67. pub const LENGTH: Field = 2..4;
  68. pub const IDENT: Field = 4..6;
  69. pub const FLG_OFF: Field = 6..8;
  70. pub const TTL: usize = 8;
  71. pub const PROTOCOL: usize = 9;
  72. pub const CHECKSUM: Field = 10..12;
  73. pub const SRC_ADDR: Field = 12..16;
  74. pub const DST_ADDR: Field = 16..20;
  75. }
  76. impl<T: AsRef<[u8]>> Packet<T> {
  77. /// Wrap a buffer with an IPv4 packet. Returns an error if the buffer
  78. /// is too small to contain one.
  79. pub fn new(buffer: T) -> Result<Packet<T>, Error> {
  80. let len = buffer.as_ref().len();
  81. if len < field::DST_ADDR.end {
  82. Err(Error::Truncated)
  83. } else {
  84. let packet = Packet { buffer: buffer };
  85. if len < packet.header_len() as usize {
  86. Err(Error::Truncated)
  87. } else {
  88. Ok(packet)
  89. }
  90. }
  91. }
  92. /// Consumes the packet, returning the underlying buffer.
  93. pub fn into_inner(self) -> T {
  94. self.buffer
  95. }
  96. /// Return the version field.
  97. #[inline(always)]
  98. pub fn version(&self) -> u8 {
  99. let data = self.buffer.as_ref();
  100. data[field::VER_IHL] >> 4
  101. }
  102. /// Return the header length, in octets.
  103. #[inline(always)]
  104. pub fn header_len(&self) -> u8 {
  105. let data = self.buffer.as_ref();
  106. (data[field::VER_IHL] & 0x0f) * 4
  107. }
  108. /// Return the Differential Services Code Point field.
  109. pub fn dscp(&self) -> u8 {
  110. let data = self.buffer.as_ref();
  111. data[field::DSCP_ECN] >> 2
  112. }
  113. /// Return the Explicit Congestion Notification field.
  114. pub fn ecn(&self) -> u8 {
  115. let data = self.buffer.as_ref();
  116. data[field::DSCP_ECN] & 0x03
  117. }
  118. /// Return the total length field.
  119. #[inline(always)]
  120. pub fn total_len(&self) -> u16 {
  121. let data = self.buffer.as_ref();
  122. NetworkEndian::read_u16(&data[field::LENGTH])
  123. }
  124. /// Return the fragment identification field.
  125. #[inline(always)]
  126. pub fn ident(&self) -> u16 {
  127. let data = self.buffer.as_ref();
  128. NetworkEndian::read_u16(&data[field::IDENT])
  129. }
  130. /// Return the "don't fragment" flag.
  131. #[inline(always)]
  132. pub fn dont_frag(&self) -> bool {
  133. let data = self.buffer.as_ref();
  134. NetworkEndian::read_u16(&data[field::FLG_OFF]) & 0x4000 != 0
  135. }
  136. /// Return the "more fragments" flag.
  137. #[inline(always)]
  138. pub fn more_frags(&self) -> bool {
  139. let data = self.buffer.as_ref();
  140. NetworkEndian::read_u16(&data[field::FLG_OFF]) & 0x2000 != 0
  141. }
  142. /// Return the fragment offset, in octets.
  143. #[inline(always)]
  144. pub fn frag_offset(&self) -> u16 {
  145. let data = self.buffer.as_ref();
  146. NetworkEndian::read_u16(&data[field::FLG_OFF]) << 3
  147. }
  148. /// Return the time to live field.
  149. #[inline(always)]
  150. pub fn ttl(&self) -> u8 {
  151. let data = self.buffer.as_ref();
  152. data[field::TTL]
  153. }
  154. /// Return the protocol field.
  155. #[inline(always)]
  156. pub fn protocol(&self) -> ProtocolType {
  157. let data = self.buffer.as_ref();
  158. ProtocolType::from(data[field::PROTOCOL])
  159. }
  160. /// Return the header checksum field.
  161. #[inline(always)]
  162. pub fn checksum(&self) -> u16 {
  163. let data = self.buffer.as_ref();
  164. NetworkEndian::read_u16(&data[field::CHECKSUM])
  165. }
  166. /// Return the source address field.
  167. #[inline(always)]
  168. pub fn src_addr(&self) -> Address {
  169. let data = self.buffer.as_ref();
  170. Address::from_bytes(&data[field::SRC_ADDR])
  171. }
  172. /// Return the destination address field.
  173. #[inline(always)]
  174. pub fn dst_addr(&self) -> Address {
  175. let data = self.buffer.as_ref();
  176. Address::from_bytes(&data[field::DST_ADDR])
  177. }
  178. /// Validate the header checksum.
  179. pub fn verify_checksum(&self) -> bool {
  180. let data = self.buffer.as_ref();
  181. checksum::data(&data[..self.header_len() as usize]) == !0
  182. }
  183. }
  184. impl<'a, T: AsRef<[u8]> + ?Sized> Packet<&'a T> {
  185. /// Return a pointer to the payload.
  186. #[inline(always)]
  187. pub fn payload(&self) -> &'a [u8] {
  188. let range = self.header_len() as usize;
  189. let data = self.buffer.as_ref();
  190. &data[range..]
  191. }
  192. }
  193. impl<T: AsRef<[u8]> + AsMut<[u8]>> Packet<T> {
  194. /// Set the version field.
  195. #[inline(always)]
  196. pub fn set_version(&mut self, value: u8) {
  197. let data = self.buffer.as_mut();
  198. data[field::VER_IHL] = (data[field::VER_IHL] & !0xf0) | (value << 4);
  199. }
  200. /// Set the header length, in octets.
  201. #[inline(always)]
  202. pub fn set_header_len(&mut self, value: u8) {
  203. let data = self.buffer.as_mut();
  204. data[field::VER_IHL] = (data[field::VER_IHL] & !0x0f) | ((value / 4) & 0x0f);
  205. }
  206. /// Set the Differential Services Code Point field.
  207. pub fn set_dscp(&mut self, value: u8) {
  208. let data = self.buffer.as_mut();
  209. data[field::DSCP_ECN] = (data[field::DSCP_ECN] & !0xfc) | (value << 2)
  210. }
  211. /// Set the Explicit Congestion Notification field.
  212. pub fn set_ecn(&mut self, value: u8) {
  213. let data = self.buffer.as_mut();
  214. data[field::DSCP_ECN] = (data[field::DSCP_ECN] & !0x03) | (value & 0x03)
  215. }
  216. /// Set the total length field.
  217. #[inline(always)]
  218. pub fn set_total_len(&mut self, value: u16) {
  219. let data = self.buffer.as_mut();
  220. NetworkEndian::write_u16(&mut data[field::LENGTH], value)
  221. }
  222. /// Set the fragment identification field.
  223. #[inline(always)]
  224. pub fn set_ident(&mut self, value: u16) {
  225. let data = self.buffer.as_mut();
  226. NetworkEndian::write_u16(&mut data[field::IDENT], value)
  227. }
  228. /// Clear the entire flags field.
  229. #[inline(always)]
  230. pub fn clear_flags(&mut self) {
  231. let data = self.buffer.as_mut();
  232. let raw = NetworkEndian::read_u16(&data[field::FLG_OFF]);
  233. let raw = raw & !0xe000;
  234. NetworkEndian::write_u16(&mut data[field::FLG_OFF], raw);
  235. }
  236. /// Set the "don't fragment" flag.
  237. #[inline(always)]
  238. pub fn set_dont_frag(&mut self, value: bool) {
  239. let data = self.buffer.as_mut();
  240. let raw = NetworkEndian::read_u16(&data[field::FLG_OFF]);
  241. let raw = if value { raw | 0x4000 } else { raw & !0x4000 };
  242. NetworkEndian::write_u16(&mut data[field::FLG_OFF], raw);
  243. }
  244. /// Set the "more fragments" flag.
  245. #[inline(always)]
  246. pub fn set_more_frags(&mut self, value: bool) {
  247. let data = self.buffer.as_mut();
  248. let raw = NetworkEndian::read_u16(&data[field::FLG_OFF]);
  249. let raw = if value { raw | 0x2000 } else { raw & !0x2000 };
  250. NetworkEndian::write_u16(&mut data[field::FLG_OFF], raw);
  251. }
  252. /// Set the fragment offset, in octets.
  253. #[inline(always)]
  254. pub fn set_frag_offset(&mut self, value: u16) {
  255. let data = self.buffer.as_mut();
  256. let raw = NetworkEndian::read_u16(&data[field::FLG_OFF]);
  257. let raw = (raw & 0xe000) | (value >> 3);
  258. NetworkEndian::write_u16(&mut data[field::FLG_OFF], raw);
  259. }
  260. /// Set the time to live field.
  261. #[inline(always)]
  262. pub fn set_ttl(&mut self, value: u8) {
  263. let data = self.buffer.as_mut();
  264. data[field::TTL] = value
  265. }
  266. /// Set the protocol field.
  267. #[inline(always)]
  268. pub fn set_protocol(&mut self, value: ProtocolType) {
  269. let data = self.buffer.as_mut();
  270. data[field::PROTOCOL] = value.into()
  271. }
  272. /// Set the header checksum field.
  273. #[inline(always)]
  274. pub fn set_checksum(&mut self, value: u16) {
  275. let data = self.buffer.as_mut();
  276. NetworkEndian::write_u16(&mut data[field::CHECKSUM], value)
  277. }
  278. /// Set the source address field.
  279. #[inline(always)]
  280. pub fn set_src_addr(&mut self, value: Address) {
  281. let data = self.buffer.as_mut();
  282. data[field::SRC_ADDR].copy_from_slice(value.as_bytes())
  283. }
  284. /// Set the destination address field.
  285. #[inline(always)]
  286. pub fn set_dst_addr(&mut self, value: Address) {
  287. let data = self.buffer.as_mut();
  288. data[field::DST_ADDR].copy_from_slice(value.as_bytes())
  289. }
  290. /// Compute and fill in the header checksum.
  291. pub fn fill_checksum(&mut self) {
  292. self.set_checksum(0);
  293. let checksum = {
  294. let data = self.buffer.as_ref();
  295. !checksum::data(&data[..self.header_len() as usize])
  296. };
  297. self.set_checksum(checksum)
  298. }
  299. }
  300. impl<'a, T: AsRef<[u8]> + AsMut<[u8]> + ?Sized> Packet<&'a mut T> {
  301. /// Return a mutable pointer to the payload.
  302. #[inline(always)]
  303. pub fn payload_mut(&mut self) -> &mut [u8] {
  304. let range = self.header_len() as usize..;
  305. let data = self.buffer.as_mut();
  306. &mut data[range]
  307. }
  308. }
  309. /// A high-level representation of an Internet Protocol version 4 packet header.
  310. #[derive(Debug, PartialEq, Eq, Clone, Copy)]
  311. pub struct Repr {
  312. pub src_addr: Address,
  313. pub dst_addr: Address,
  314. pub protocol: ProtocolType
  315. }
  316. impl Repr {
  317. /// Parse an Internet Protocol version 4 packet and return a high-level representation.
  318. pub fn parse<T: AsRef<[u8]> + ?Sized>(packet: &Packet<&T>) -> Result<Repr, Error> {
  319. // Version 4 is expected.
  320. if packet.version() != 4 { return Err(Error::Malformed) }
  321. // Valid checksum is expected.
  322. if !packet.verify_checksum() { return Err(Error::Checksum) }
  323. // We do not support any IP options.
  324. if packet.header_len() > 20 { return Err(Error::Unrecognized) }
  325. // We do not support fragmentation.
  326. if packet.more_frags() || packet.frag_offset() != 0 { return Err(Error::Fragmented) }
  327. // Since the packet is not fragmented, it must include the entire payload.
  328. let payload_len = packet.total_len() as usize - packet.header_len() as usize;
  329. if packet.payload().len() < payload_len { return Err(Error::Truncated) }
  330. // All DSCP values are acceptable, since they are of no concern to receiving endpoint.
  331. // All ECN values are acceptable, since ECN requires opt-in from both endpoints.
  332. // All TTL values are acceptable, since we do not perform routing.
  333. Ok(Repr {
  334. src_addr: packet.src_addr(),
  335. dst_addr: packet.dst_addr(),
  336. protocol: packet.protocol()
  337. })
  338. }
  339. /// Return the length of a header that will be emitted from this high-level representation.
  340. pub fn buffer_len(&self) -> usize {
  341. // We never emit any options.
  342. field::DST_ADDR.end
  343. }
  344. /// Emit a high-level representation into an Internet Protocol version 4 packet.
  345. pub fn emit<T: AsRef<[u8]> + AsMut<[u8]>>(&self, packet: &mut Packet<T>,
  346. payload_len: usize) {
  347. packet.set_version(4);
  348. packet.set_header_len(20);
  349. packet.set_dscp(0);
  350. packet.set_ecn(0);
  351. let total_len = packet.header_len() as u16 + payload_len as u16;
  352. packet.set_total_len(total_len);
  353. packet.set_ident(0);
  354. packet.clear_flags();
  355. packet.set_more_frags(false);
  356. packet.set_dont_frag(true);
  357. packet.set_frag_offset(0);
  358. packet.set_ttl(64);
  359. packet.set_protocol(self.protocol);
  360. packet.set_src_addr(self.src_addr);
  361. packet.set_dst_addr(self.dst_addr);
  362. packet.fill_checksum();
  363. }
  364. }
  365. impl<'a, T: AsRef<[u8]> + ?Sized> fmt::Display for Packet<&'a T> {
  366. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  367. match Repr::parse(self) {
  368. Ok(repr) => write!(f, "{}", repr),
  369. _ => {
  370. try!(write!(f, "IPv4 (unrecognized)"));
  371. try!(write!(f, " src={} dst={} proto={} ttl={}",
  372. self.src_addr(), self.dst_addr(), self.protocol(), self.ttl()));
  373. if self.version() != 4 {
  374. try!(write!(f, " ver={}", self.version()))
  375. }
  376. if self.header_len() != 20 {
  377. try!(write!(f, " hlen={}", self.header_len()))
  378. }
  379. if self.dscp() != 0 {
  380. try!(write!(f, " dscp={}", self.dscp()))
  381. }
  382. if self.ecn() != 0 {
  383. try!(write!(f, " ecn={}", self.ecn()))
  384. }
  385. try!(write!(f, " tlen={}", self.total_len()));
  386. if self.dont_frag() {
  387. try!(write!(f, " df"))
  388. }
  389. if self.more_frags() {
  390. try!(write!(f, " mf"))
  391. }
  392. if self.frag_offset() != 0 {
  393. try!(write!(f, " off={}", self.frag_offset()))
  394. }
  395. if self.more_frags() || self.frag_offset() != 0 {
  396. try!(write!(f, " id={}", self.ident()))
  397. }
  398. Ok(())
  399. }
  400. }
  401. }
  402. }
  403. impl fmt::Display for Repr {
  404. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  405. write!(f, "IPv4 src={} dst={} proto={}",
  406. self.src_addr, self.dst_addr, self.protocol)
  407. }
  408. }
  409. use super::pretty_print::{PrettyPrint, PrettyIndent};
  410. impl<T: AsRef<[u8]>> PrettyPrint for Packet<T> {
  411. fn pretty_print(buffer: &AsRef<[u8]>, f: &mut fmt::Formatter,
  412. indent: &mut PrettyIndent) -> fmt::Result {
  413. let packet = match Packet::new(buffer) {
  414. Err(err) => return write!(f, "{}({})\n", indent, err),
  415. Ok(packet) => packet
  416. };
  417. try!(write!(f, "{}{}\n", indent, packet));
  418. indent.increase();
  419. match packet.protocol() {
  420. ProtocolType::Icmp =>
  421. super::Icmpv4Packet::<&[u8]>::pretty_print(&packet.payload(), f, indent),
  422. ProtocolType::Udp =>
  423. super::UdpPacket::<&[u8]>::pretty_print(&packet.payload(), f, indent),
  424. _ => Ok(())
  425. }
  426. }
  427. }
  428. #[cfg(test)]
  429. mod test {
  430. use super::*;
  431. static PACKET_BYTES: [u8; 30] =
  432. [0x45, 0x00, 0x00, 0x1e,
  433. 0x01, 0x02, 0x62, 0x03,
  434. 0x1a, 0x01, 0xd5, 0x6e,
  435. 0x11, 0x12, 0x13, 0x14,
  436. 0x21, 0x22, 0x23, 0x24,
  437. 0xaa, 0x00, 0x00, 0x00,
  438. 0x00, 0x00, 0x00, 0x00,
  439. 0x00, 0xff];
  440. static PAYLOAD_BYTES: [u8; 10] =
  441. [0xaa, 0x00, 0x00, 0x00,
  442. 0x00, 0x00, 0x00, 0x00,
  443. 0x00, 0xff];
  444. #[test]
  445. fn test_deconstruct() {
  446. let packet = Packet::new(&PACKET_BYTES[..]).unwrap();
  447. assert_eq!(packet.version(), 4);
  448. assert_eq!(packet.header_len(), 20);
  449. assert_eq!(packet.dscp(), 0);
  450. assert_eq!(packet.ecn(), 0);
  451. assert_eq!(packet.total_len(), 30);
  452. assert_eq!(packet.ident(), 0x102);
  453. assert_eq!(packet.more_frags(), true);
  454. assert_eq!(packet.dont_frag(), true);
  455. assert_eq!(packet.frag_offset(), 0x203 * 8);
  456. assert_eq!(packet.ttl(), 0x1a);
  457. assert_eq!(packet.protocol(), ProtocolType::Icmp);
  458. assert_eq!(packet.checksum(), 0xd56e);
  459. assert_eq!(packet.src_addr(), Address([0x11, 0x12, 0x13, 0x14]));
  460. assert_eq!(packet.dst_addr(), Address([0x21, 0x22, 0x23, 0x24]));
  461. assert_eq!(packet.verify_checksum(), true);
  462. assert_eq!(packet.payload(), &PAYLOAD_BYTES[..]);
  463. }
  464. #[test]
  465. fn test_construct() {
  466. let mut bytes = vec![0; 30];
  467. let mut packet = Packet::new(&mut bytes).unwrap();
  468. packet.set_version(4);
  469. packet.set_header_len(20);
  470. packet.set_dscp(0);
  471. packet.set_ecn(0);
  472. packet.set_total_len(30);
  473. packet.set_ident(0x102);
  474. packet.set_more_frags(true);
  475. packet.set_dont_frag(true);
  476. packet.set_frag_offset(0x203 * 8);
  477. packet.set_ttl(0x1a);
  478. packet.set_protocol(ProtocolType::Icmp);
  479. packet.set_src_addr(Address([0x11, 0x12, 0x13, 0x14]));
  480. packet.set_dst_addr(Address([0x21, 0x22, 0x23, 0x24]));
  481. packet.fill_checksum();
  482. packet.payload_mut().copy_from_slice(&PAYLOAD_BYTES[..]);
  483. assert_eq!(&packet.into_inner()[..], &PACKET_BYTES[..]);
  484. }
  485. static REPR_PACKET_BYTES: [u8; 24] =
  486. [0x45, 0x00, 0x00, 0x18,
  487. 0x00, 0x00, 0x40, 0x00,
  488. 0x40, 0x01, 0xd2, 0x79,
  489. 0x11, 0x12, 0x13, 0x14,
  490. 0x21, 0x22, 0x23, 0x24,
  491. 0xaa, 0x00, 0x00, 0xff];
  492. static REPR_PAYLOAD_BYTES: [u8; 4] =
  493. [0xaa, 0x00, 0x00, 0xff];
  494. fn packet_repr() -> Repr {
  495. Repr {
  496. src_addr: Address([0x11, 0x12, 0x13, 0x14]),
  497. dst_addr: Address([0x21, 0x22, 0x23, 0x24]),
  498. protocol: ProtocolType::Icmp
  499. }
  500. }
  501. #[test]
  502. fn test_parse() {
  503. let packet = Packet::new(&REPR_PACKET_BYTES[..]).unwrap();
  504. let repr = Repr::parse(&packet).unwrap();
  505. assert_eq!(repr, packet_repr());
  506. }
  507. #[test]
  508. fn test_emit() {
  509. let repr = packet_repr();
  510. let mut bytes = vec![0; repr.buffer_len() + REPR_PAYLOAD_BYTES.len()];
  511. let mut packet = Packet::new(&mut bytes).unwrap();
  512. repr.emit(&mut packet, REPR_PAYLOAD_BYTES.len());
  513. packet.payload_mut().copy_from_slice(&REPR_PAYLOAD_BYTES);
  514. assert_eq!(&packet.into_inner()[..], &REPR_PACKET_BYTES[..]);
  515. }
  516. }