ndisc.rs 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531
  1. use byteorder::{ByteOrder, NetworkEndian};
  2. use {Error, Result};
  3. use super::icmpv6::{field, Message, Packet};
  4. use wire::{EthernetAddress, Ipv6Repr, Ipv6Packet};
  5. use wire::{NdiscOption, NdiscOptionRepr, NdiscOptionType};
  6. use wire::{NdiscPrefixInformation, NdiscRedirectedHeader};
  7. use time::Duration;
  8. use super::Ipv6Address;
  9. bitflags! {
  10. pub struct RouterFlags: u8 {
  11. const MANAGED = 0b10000000;
  12. const OTHER = 0b01000000;
  13. }
  14. }
  15. bitflags! {
  16. pub struct NeighborFlags: u8 {
  17. const ROUTER = 0b10000000;
  18. const SOLICITED = 0b01000000;
  19. const OVERRIDE = 0b00100000;
  20. }
  21. }
  22. /// Getters for the Router Advertisement message header.
  23. /// See [RFC 4861 § 4.2].
  24. ///
  25. /// [RFC 4861 § 4.2]: https://tools.ietf.org/html/rfc4861#section-4.2
  26. impl<T: AsRef<[u8]>> Packet<T> {
  27. /// Return the current hop limit field.
  28. #[inline]
  29. pub fn current_hop_limit(&self) -> u8 {
  30. let data = self.buffer.as_ref();
  31. data[field::CUR_HOP_LIMIT]
  32. }
  33. /// Return the Router Advertisement flags.
  34. #[inline]
  35. pub fn router_flags(&self) -> RouterFlags {
  36. let data = self.buffer.as_ref();
  37. RouterFlags::from_bits_truncate(data[field::ROUTER_FLAGS])
  38. }
  39. /// Return the router lifetime field.
  40. #[inline]
  41. pub fn router_lifetime(&self) -> Duration {
  42. let data = self.buffer.as_ref();
  43. Duration::from_secs(NetworkEndian::read_u16(&data[field::ROUTER_LT]) as u64)
  44. }
  45. /// Return the reachable time field.
  46. #[inline]
  47. pub fn reachable_time(&self) -> Duration {
  48. let data = self.buffer.as_ref();
  49. Duration::from_millis(NetworkEndian::read_u32(&data[field::REACHABLE_TM]) as u64)
  50. }
  51. /// Return the retransmit time field.
  52. #[inline]
  53. pub fn retrans_time(&self) -> Duration {
  54. let data = self.buffer.as_ref();
  55. Duration::from_millis(NetworkEndian::read_u32(&data[field::RETRANS_TM]) as u64)
  56. }
  57. }
  58. /// Common getters for the [Neighbor Solicitation], [Neighbor Advertisement], and
  59. /// [Redirect] message types.
  60. ///
  61. /// [Neighbor Solicitation]: https://tools.ietf.org/html/rfc4861#section-4.3
  62. /// [Neighbor Advertisement]: https://tools.ietf.org/html/rfc4861#section-4.4
  63. /// [Redirect]: https://tools.ietf.org/html/rfc4861#section-4.5
  64. impl<T: AsRef<[u8]>> Packet<T> {
  65. /// Return the target address field.
  66. #[inline]
  67. pub fn target_addr(&self) -> Ipv6Address {
  68. let data = self.buffer.as_ref();
  69. Ipv6Address::from_bytes(&data[field::TARGET_ADDR])
  70. }
  71. }
  72. /// Getters for the Neighbor Solicitation message header.
  73. /// See [RFC 4861 § 4.3].
  74. ///
  75. /// [RFC 4861 § 4.3]: https://tools.ietf.org/html/rfc4861#section-4.3
  76. impl<T: AsRef<[u8]>> Packet<T> {
  77. /// Return the Neighbor Solicitation flags.
  78. #[inline]
  79. pub fn neighbor_flags(&self) -> NeighborFlags {
  80. let data = self.buffer.as_ref();
  81. NeighborFlags::from_bits_truncate(data[field::NEIGH_FLAGS])
  82. }
  83. }
  84. /// Getters for the Redirect message header.
  85. /// See [RFC 4861 § 4.5].
  86. ///
  87. /// [RFC 4861 § 4.5]: https://tools.ietf.org/html/rfc4861#section-4.5
  88. impl<T: AsRef<[u8]>> Packet<T> {
  89. /// Return the destination address field.
  90. #[inline]
  91. pub fn dest_addr(&self) -> Ipv6Address {
  92. let data = self.buffer.as_ref();
  93. Ipv6Address::from_bytes(&data[field::DEST_ADDR])
  94. }
  95. }
  96. /// Setters for the Router Advertisement message header.
  97. /// See [RFC 4861 § 4.2].
  98. ///
  99. /// [RFC 4861 § 4.2]: https://tools.ietf.org/html/rfc4861#section-4.2
  100. impl<T: AsRef<[u8]> + AsMut<[u8]>> Packet<T> {
  101. /// Set the current hop limit field.
  102. #[inline]
  103. pub fn set_current_hop_limit(&mut self, value: u8) {
  104. let data = self.buffer.as_mut();
  105. data[field::CUR_HOP_LIMIT] = value;
  106. }
  107. /// Set the Router Advertisement flags.
  108. #[inline]
  109. pub fn set_router_flags(&mut self, flags: RouterFlags) {
  110. self.buffer.as_mut()[field::ROUTER_FLAGS] = flags.bits();
  111. }
  112. /// Set the router lifetime field.
  113. #[inline]
  114. pub fn set_router_lifetime(&mut self, value: Duration) {
  115. let data = self.buffer.as_mut();
  116. NetworkEndian::write_u16(&mut data[field::ROUTER_LT], value.secs() as u16);
  117. }
  118. /// Set the reachable time field.
  119. #[inline]
  120. pub fn set_reachable_time(&mut self, value: Duration) {
  121. let data = self.buffer.as_mut();
  122. NetworkEndian::write_u32(&mut data[field::REACHABLE_TM], value.total_millis() as u32);
  123. }
  124. /// Set the retransmit time field.
  125. #[inline]
  126. pub fn set_retrans_time(&mut self, value: Duration) {
  127. let data = self.buffer.as_mut();
  128. NetworkEndian::write_u32(&mut data[field::RETRANS_TM], value.total_millis() as u32);
  129. }
  130. }
  131. /// Common setters for the [Neighbor Solicitation], [Neighbor Advertisement], and
  132. /// [Redirect] message types.
  133. ///
  134. /// [Neighbor Solicitation]: https://tools.ietf.org/html/rfc4861#section-4.3
  135. /// [Neighbor Advertisement]: https://tools.ietf.org/html/rfc4861#section-4.4
  136. /// [Redirect]: https://tools.ietf.org/html/rfc4861#section-4.5
  137. impl<T: AsRef<[u8]> + AsMut<[u8]>> Packet<T> {
  138. /// Set the target address field.
  139. #[inline]
  140. pub fn set_target_addr(&mut self, value: Ipv6Address) {
  141. let data = self.buffer.as_mut();
  142. data[field::TARGET_ADDR].copy_from_slice(value.as_bytes());
  143. }
  144. }
  145. /// Setters for the Neighbor Solicitation message header.
  146. /// See [RFC 4861 § 4.3].
  147. ///
  148. /// [RFC 4861 § 4.3]: https://tools.ietf.org/html/rfc4861#section-4.3
  149. impl<T: AsRef<[u8]> + AsMut<[u8]>> Packet<T> {
  150. /// Set the Neighbor Solicitation flags.
  151. #[inline]
  152. pub fn set_neighbor_flags(&mut self, flags: NeighborFlags) {
  153. self.buffer.as_mut()[field::NEIGH_FLAGS] = flags.bits();
  154. }
  155. }
  156. /// Setters for the Redirect message header.
  157. /// See [RFC 4861 § 4.5].
  158. ///
  159. /// [RFC 4861 § 4.5]: https://tools.ietf.org/html/rfc4861#section-4.5
  160. impl<T: AsRef<[u8]> + AsMut<[u8]>> Packet<T> {
  161. /// Set the destination address field.
  162. #[inline]
  163. pub fn set_dest_addr(&mut self, value: Ipv6Address) {
  164. let data = self.buffer.as_mut();
  165. data[field::DEST_ADDR].copy_from_slice(value.as_bytes());
  166. }
  167. }
  168. /// A high-level representation of an Neighbor Discovery packet header.
  169. #[derive(Debug, PartialEq, Eq, Clone, Copy)]
  170. pub enum Repr<'a> {
  171. RouterSolicit {
  172. lladdr: Option<EthernetAddress>
  173. },
  174. RouterAdvert {
  175. hop_limit: u8,
  176. flags: RouterFlags,
  177. router_lifetime: Duration,
  178. reachable_time: Duration,
  179. retrans_time: Duration,
  180. lladdr: Option<EthernetAddress>,
  181. mtu: Option<u32>,
  182. prefix_info: Option<NdiscPrefixInformation>
  183. },
  184. NeighborSolicit {
  185. target_addr: Ipv6Address,
  186. lladdr: Option<EthernetAddress>
  187. },
  188. NeighborAdvert {
  189. flags: NeighborFlags,
  190. target_addr: Ipv6Address,
  191. lladdr: Option<EthernetAddress>
  192. },
  193. Redirect {
  194. target_addr: Ipv6Address,
  195. dest_addr: Ipv6Address,
  196. lladdr: Option<EthernetAddress>,
  197. redirected_hdr: Option<NdiscRedirectedHeader<'a>>
  198. }
  199. }
  200. impl<'a> Repr<'a> {
  201. /// Parse an NDISC packet and return a high-level representation of the
  202. /// packet.
  203. pub fn parse<T>(packet: &Packet<&'a T>)
  204. -> Result<Repr<'a>>
  205. where T: AsRef<[u8]> + ?Sized {
  206. match packet.msg_type() {
  207. Message::RouterSolicit => {
  208. let lladdr = if packet.payload().len() > 0 {
  209. let opt = NdiscOption::new_checked(packet.payload())?;
  210. match opt.option_type() {
  211. NdiscOptionType::SourceLinkLayerAddr => Some(opt.link_layer_addr()),
  212. _ => { return Err(Error::Unrecognized); }
  213. }
  214. } else {
  215. None
  216. };
  217. Ok(Repr::RouterSolicit { lladdr })
  218. },
  219. Message::RouterAdvert => {
  220. let mut offset = 0;
  221. let (mut lladdr, mut mtu, mut prefix_info) = (None, None, None);
  222. while packet.payload().len() - offset > 0 {
  223. let pkt = NdiscOption::new_checked(&packet.payload()[offset..])?;
  224. let opt = NdiscOptionRepr::parse(&pkt)?;
  225. match opt {
  226. NdiscOptionRepr::SourceLinkLayerAddr(addr) => lladdr = Some(addr),
  227. NdiscOptionRepr::Mtu(val) => mtu = Some(val),
  228. NdiscOptionRepr::PrefixInformation(info) => prefix_info = Some(info),
  229. _ => { return Err(Error::Unrecognized); }
  230. }
  231. offset += opt.buffer_len();
  232. }
  233. Ok(Repr::RouterAdvert {
  234. hop_limit: packet.current_hop_limit(),
  235. flags: packet.router_flags(),
  236. router_lifetime: packet.router_lifetime(),
  237. reachable_time: packet.reachable_time(),
  238. retrans_time: packet.retrans_time(),
  239. lladdr, mtu, prefix_info
  240. })
  241. },
  242. Message::NeighborSolicit => {
  243. let lladdr = if packet.payload().len() > 0 {
  244. let opt = NdiscOption::new_checked(packet.payload())?;
  245. match opt.option_type() {
  246. NdiscOptionType::SourceLinkLayerAddr => Some(opt.link_layer_addr()),
  247. _ => { return Err(Error::Unrecognized); }
  248. }
  249. } else {
  250. None
  251. };
  252. Ok(Repr::NeighborSolicit {
  253. target_addr: packet.target_addr(), lladdr
  254. })
  255. },
  256. Message::NeighborAdvert => {
  257. let lladdr = if packet.payload().len() > 0 {
  258. let opt = NdiscOption::new_checked(packet.payload())?;
  259. match opt.option_type() {
  260. NdiscOptionType::TargetLinkLayerAddr => Some(opt.link_layer_addr()),
  261. _ => { return Err(Error::Unrecognized); }
  262. }
  263. } else {
  264. None
  265. };
  266. Ok(Repr::NeighborAdvert {
  267. flags: packet.neighbor_flags(),
  268. target_addr: packet.target_addr(),
  269. lladdr
  270. })
  271. },
  272. Message::Redirect => {
  273. let mut offset = 0;
  274. let (mut lladdr, mut redirected_hdr) = (None, None);
  275. while packet.payload().len() - offset > 0 {
  276. let opt = NdiscOption::new_checked(&packet.payload()[offset..])?;
  277. match opt.option_type() {
  278. NdiscOptionType::SourceLinkLayerAddr => {
  279. lladdr = Some(opt.link_layer_addr());
  280. offset += 8;
  281. },
  282. NdiscOptionType::RedirectedHeader => {
  283. if opt.data_len() < 6 {
  284. return Err(Error::Truncated)
  285. } else {
  286. let ip_packet = Ipv6Packet::new(&opt.data()[offset + 8..]);
  287. let ip_repr = Ipv6Repr::parse(&ip_packet)?;
  288. let data = &opt.data()[offset + 8 + ip_repr.buffer_len()..];
  289. redirected_hdr = Some(NdiscRedirectedHeader {
  290. header: ip_repr, data
  291. });
  292. offset += 8 + ip_repr.buffer_len() + data.len();
  293. }
  294. }
  295. _ => { return Err(Error::Unrecognized); }
  296. }
  297. }
  298. Ok(Repr::Redirect {
  299. target_addr: packet.target_addr(),
  300. dest_addr: packet.dest_addr(),
  301. lladdr, redirected_hdr
  302. })
  303. },
  304. _ => Err(Error::Unrecognized)
  305. }
  306. }
  307. pub fn buffer_len(&self) -> usize {
  308. match self {
  309. &Repr::RouterSolicit { lladdr } => {
  310. match lladdr {
  311. Some(_) => field::UNUSED.end + 8,
  312. None => field::UNUSED.end,
  313. }
  314. },
  315. &Repr::RouterAdvert { lladdr, mtu, prefix_info, .. } => {
  316. let mut offset = 0;
  317. if lladdr.is_some() {
  318. offset += 8;
  319. }
  320. if mtu.is_some() {
  321. offset += 8;
  322. }
  323. if prefix_info.is_some() {
  324. offset += 32;
  325. }
  326. field::RETRANS_TM.end + offset
  327. },
  328. &Repr::NeighborSolicit { lladdr, .. } | &Repr::NeighborAdvert { lladdr, .. } => {
  329. match lladdr {
  330. Some(_) => field::TARGET_ADDR.end + 8,
  331. None => field::TARGET_ADDR.end,
  332. }
  333. },
  334. &Repr::Redirect { lladdr, redirected_hdr, .. } => {
  335. let mut offset = 0;
  336. if lladdr.is_some() {
  337. offset += 8;
  338. }
  339. if let Some(NdiscRedirectedHeader { header, data }) = redirected_hdr {
  340. offset += 8 + header.buffer_len() + data.len();
  341. }
  342. field::DEST_ADDR.end + offset
  343. }
  344. }
  345. }
  346. pub fn emit<T>(&self, packet: &mut Packet<&mut T>)
  347. where T: AsRef<[u8]> + AsMut<[u8]> + ?Sized {
  348. match self {
  349. &Repr::RouterSolicit { lladdr } => {
  350. packet.set_msg_type(Message::RouterSolicit);
  351. packet.set_msg_code(0);
  352. packet.clear_reserved();
  353. if let Some(lladdr) = lladdr {
  354. let mut opt_pkt = NdiscOption::new(packet.payload_mut());
  355. NdiscOptionRepr::SourceLinkLayerAddr(lladdr).emit(&mut opt_pkt);
  356. }
  357. },
  358. &Repr::RouterAdvert { hop_limit, flags, router_lifetime, reachable_time,
  359. retrans_time, lladdr, mtu, prefix_info } => {
  360. packet.set_msg_type(Message::RouterAdvert);
  361. packet.set_msg_code(0);
  362. packet.set_current_hop_limit(hop_limit);
  363. packet.set_router_flags(flags);
  364. packet.set_router_lifetime(router_lifetime);
  365. packet.set_reachable_time(reachable_time);
  366. packet.set_retrans_time(retrans_time);
  367. let mut offset = 0;
  368. if let Some(lladdr) = lladdr {
  369. let mut opt_pkt = NdiscOption::new(packet.payload_mut());
  370. NdiscOptionRepr::SourceLinkLayerAddr(lladdr).emit(&mut opt_pkt);
  371. offset += 8;
  372. }
  373. if let Some(mtu) = mtu {
  374. let mut opt_pkt = NdiscOption::new(&mut packet.payload_mut()[offset..]);
  375. NdiscOptionRepr::Mtu(mtu).emit(&mut opt_pkt);
  376. offset += 8;
  377. }
  378. if let Some(prefix_info) = prefix_info {
  379. let mut opt_pkt = NdiscOption::new(&mut packet.payload_mut()[offset..]);
  380. NdiscOptionRepr::PrefixInformation(prefix_info).emit(&mut opt_pkt)
  381. }
  382. },
  383. &Repr::NeighborSolicit { target_addr, lladdr } => {
  384. packet.set_msg_type(Message::NeighborSolicit);
  385. packet.set_msg_code(0);
  386. packet.clear_reserved();
  387. packet.set_target_addr(target_addr);
  388. if let Some(lladdr) = lladdr {
  389. let mut opt_pkt = NdiscOption::new(packet.payload_mut());
  390. NdiscOptionRepr::SourceLinkLayerAddr(lladdr).emit(&mut opt_pkt);
  391. }
  392. },
  393. &Repr::NeighborAdvert { flags, target_addr, lladdr } => {
  394. packet.set_msg_type(Message::NeighborAdvert);
  395. packet.set_msg_code(0);
  396. packet.clear_reserved();
  397. packet.set_neighbor_flags(flags);
  398. packet.set_target_addr(target_addr);
  399. if let Some(lladdr) = lladdr {
  400. let mut opt_pkt = NdiscOption::new(packet.payload_mut());
  401. NdiscOptionRepr::TargetLinkLayerAddr(lladdr).emit(&mut opt_pkt);
  402. }
  403. },
  404. &Repr::Redirect { target_addr, dest_addr, lladdr, redirected_hdr } => {
  405. packet.set_msg_type(Message::Redirect);
  406. packet.set_msg_code(0);
  407. packet.clear_reserved();
  408. packet.set_target_addr(target_addr);
  409. packet.set_dest_addr(dest_addr);
  410. let offset = match lladdr {
  411. Some(lladdr) => {
  412. let mut opt_pkt = NdiscOption::new(packet.payload_mut());
  413. NdiscOptionRepr::TargetLinkLayerAddr(lladdr).emit(&mut opt_pkt);
  414. 8
  415. },
  416. None => 0,
  417. };
  418. if let Some(redirected_hdr) = redirected_hdr {
  419. let mut opt_pkt = NdiscOption::new(&mut packet.payload_mut()[offset..]);
  420. NdiscOptionRepr::RedirectedHeader(redirected_hdr).emit(&mut opt_pkt);
  421. }
  422. },
  423. }
  424. }
  425. }
  426. #[cfg(test)]
  427. mod test {
  428. use phy::ChecksumCapabilities;
  429. use super::*;
  430. use wire::Icmpv6Repr;
  431. use wire::ip::test::{MOCK_IP_ADDR_1, MOCK_IP_ADDR_2};
  432. static ROUTER_ADVERT_BYTES: [u8; 24] =
  433. [0x86, 0x00, 0xa9, 0xde,
  434. 0x40, 0x80, 0x03, 0x84,
  435. 0x00, 0x00, 0x03, 0x84,
  436. 0x00, 0x00, 0x03, 0x84,
  437. 0x01, 0x01, 0x52, 0x54,
  438. 0x00, 0x12, 0x34, 0x56];
  439. static SOURCE_LINK_LAYER_OPT: [u8; 8] =
  440. [0x01, 0x01, 0x52, 0x54,
  441. 0x00, 0x12, 0x34, 0x56];
  442. fn create_repr<'a>() -> Icmpv6Repr<'a> {
  443. Icmpv6Repr::Ndisc(Repr::RouterAdvert {
  444. hop_limit: 64,
  445. flags: RouterFlags::MANAGED,
  446. router_lifetime: Duration::from_secs(900),
  447. reachable_time: Duration::from_millis(900),
  448. retrans_time: Duration::from_millis(900),
  449. lladdr: Some(EthernetAddress([0x52, 0x54, 0x00, 0x12, 0x34, 0x56])),
  450. mtu: None,
  451. prefix_info: None
  452. })
  453. }
  454. #[test]
  455. fn test_router_advert_deconstruct() {
  456. let packet = Packet::new(&ROUTER_ADVERT_BYTES[..]);
  457. assert_eq!(packet.msg_type(), Message::RouterAdvert);
  458. assert_eq!(packet.msg_code(), 0);
  459. assert_eq!(packet.current_hop_limit(), 64);
  460. assert_eq!(packet.router_flags(), RouterFlags::MANAGED);
  461. assert_eq!(packet.router_lifetime(), Duration::from_secs(900));
  462. assert_eq!(packet.reachable_time(), Duration::from_millis(900));
  463. assert_eq!(packet.retrans_time(), Duration::from_millis(900));
  464. assert_eq!(packet.payload(), &SOURCE_LINK_LAYER_OPT[..]);
  465. }
  466. #[test]
  467. fn test_router_advert_construct() {
  468. let mut bytes = vec![0x0; 24];
  469. let mut packet = Packet::new(&mut bytes);
  470. packet.set_msg_type(Message::RouterAdvert);
  471. packet.set_msg_code(0);
  472. packet.set_current_hop_limit(64);
  473. packet.set_router_flags(RouterFlags::MANAGED);
  474. packet.set_router_lifetime(Duration::from_secs(900));
  475. packet.set_reachable_time(Duration::from_millis(900));
  476. packet.set_retrans_time(Duration::from_millis(900));
  477. packet.payload_mut().copy_from_slice(&SOURCE_LINK_LAYER_OPT[..]);
  478. packet.fill_checksum(&MOCK_IP_ADDR_1, &MOCK_IP_ADDR_2);
  479. assert_eq!(&packet.into_inner()[..], &ROUTER_ADVERT_BYTES[..]);
  480. }
  481. #[test]
  482. fn test_router_advert_repr_parse() {
  483. let packet = Packet::new(&ROUTER_ADVERT_BYTES[..]);
  484. assert_eq!(Icmpv6Repr::parse(&MOCK_IP_ADDR_1, &MOCK_IP_ADDR_2,
  485. &packet, &ChecksumCapabilities::default()).unwrap(),
  486. create_repr());
  487. }
  488. #[test]
  489. fn test_router_advert_repr_emit() {
  490. let mut bytes = vec![0x2a; 24];
  491. let mut packet = Packet::new(&mut bytes[..]);
  492. create_repr().emit(&MOCK_IP_ADDR_1, &MOCK_IP_ADDR_2,
  493. &mut packet, &ChecksumCapabilities::default());
  494. assert_eq!(&packet.into_inner()[..], &ROUTER_ADVERT_BYTES[..]);
  495. }
  496. }