ipv6.rs 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466
  1. use super::*;
  2. /// Enum used for the process_hopbyhop function. In some cases, when discarding a packet, an ICMMP
  3. /// parameter problem message needs to be transmitted to the source of the address. In other cases,
  4. /// the processing of the IP packet can continue.
  5. #[allow(clippy::large_enum_variant)]
  6. enum HopByHopResponse<'frame> {
  7. /// Continue processing the IPv6 packet.
  8. Continue((IpProtocol, &'frame [u8])),
  9. /// Discard the packet and maybe send back an ICMPv6 packet.
  10. Discard(Option<Packet<'frame>>),
  11. }
  12. // We implement `Default` such that we can use the check! macro.
  13. impl Default for HopByHopResponse<'_> {
  14. fn default() -> Self {
  15. Self::Discard(None)
  16. }
  17. }
  18. impl InterfaceInner {
  19. /// Return the IPv6 address that is a candidate source address for the given destination
  20. /// address, based on RFC 6724.
  21. #[allow(unused)]
  22. pub(crate) fn get_source_address_ipv6(&self, dst_addr: &Ipv6Address) -> Option<Ipv6Address> {
  23. // See RFC 6724 Section 4: Candidate source address
  24. fn is_candidate_source_address(dst_addr: &Ipv6Address, src_addr: &Ipv6Address) -> bool {
  25. // For all multicast and link-local destination addresses, the candidate address MUST
  26. // only be an address from the same link.
  27. if dst_addr.is_link_local() && !src_addr.is_link_local() {
  28. return false;
  29. }
  30. if dst_addr.is_multicast()
  31. && matches!(dst_addr.scope(), Ipv6AddressScope::LinkLocal)
  32. && src_addr.is_multicast()
  33. && !matches!(src_addr.scope(), Ipv6AddressScope::LinkLocal)
  34. {
  35. return false;
  36. }
  37. // Loopback addresses and multicast address can not be in the candidate source address
  38. // list. Except when the destination multicast address has a link-local scope, then the
  39. // source address can also be link-local multicast.
  40. if src_addr.is_loopback() || src_addr.is_multicast() {
  41. return false;
  42. }
  43. true
  44. }
  45. // See RFC 6724 Section 2.2: Common Prefix Length
  46. fn common_prefix_length(dst_addr: &Ipv6Cidr, src_addr: &Ipv6Address) -> usize {
  47. let addr = dst_addr.address();
  48. let mut bits = 0;
  49. for (l, r) in addr.as_bytes().iter().zip(src_addr.as_bytes().iter()) {
  50. if l == r {
  51. bits += 8;
  52. } else {
  53. bits += (l ^ r).leading_zeros();
  54. break;
  55. }
  56. }
  57. bits = bits.min(dst_addr.prefix_len() as u32);
  58. bits as usize
  59. }
  60. // Get the first address that is a candidate address.
  61. let mut candidate = self
  62. .ip_addrs
  63. .iter()
  64. .filter_map(|a| match a {
  65. #[cfg(feature = "proto-ipv4")]
  66. IpCidr::Ipv4(_) => None,
  67. #[cfg(feature = "proto-ipv6")]
  68. IpCidr::Ipv6(a) => Some(a),
  69. })
  70. .find(|a| is_candidate_source_address(dst_addr, &a.address()))
  71. .unwrap();
  72. for addr in self.ip_addrs.iter().filter_map(|a| match a {
  73. #[cfg(feature = "proto-ipv4")]
  74. IpCidr::Ipv4(_) => None,
  75. #[cfg(feature = "proto-ipv6")]
  76. IpCidr::Ipv6(a) => Some(a),
  77. }) {
  78. if !is_candidate_source_address(dst_addr, &addr.address()) {
  79. continue;
  80. }
  81. // Rule 1: prefer the address that is the same as the output destination address.
  82. if candidate.address() != *dst_addr && addr.address() == *dst_addr {
  83. candidate = addr;
  84. }
  85. // Rule 2: prefer appropriate scope.
  86. if (candidate.address().scope() as u8) < (addr.address().scope() as u8) {
  87. if (candidate.address().scope() as u8) < (dst_addr.scope() as u8) {
  88. candidate = addr;
  89. }
  90. } else if (addr.address().scope() as u8) > (dst_addr.scope() as u8) {
  91. candidate = addr;
  92. }
  93. // Rule 3: avoid deprecated addresses (TODO)
  94. // Rule 4: prefer home addresses (TODO)
  95. // Rule 5: prefer outgoing interfaces (TODO)
  96. // Rule 5.5: prefer addresses in a prefix advertises by the next-hop (TODO).
  97. // Rule 6: prefer matching label (TODO)
  98. // Rule 7: prefer temporary addresses (TODO)
  99. // Rule 8: use longest matching prefix
  100. if common_prefix_length(candidate, dst_addr) < common_prefix_length(addr, dst_addr) {
  101. candidate = addr;
  102. }
  103. }
  104. Some(candidate.address())
  105. }
  106. /// Determine if the given `Ipv6Address` is the solicited node
  107. /// multicast address for a IPv6 addresses assigned to the interface.
  108. /// See [RFC 4291 § 2.7.1] for more details.
  109. ///
  110. /// [RFC 4291 § 2.7.1]: https://tools.ietf.org/html/rfc4291#section-2.7.1
  111. pub fn has_solicited_node(&self, addr: Ipv6Address) -> bool {
  112. self.ip_addrs.iter().any(|cidr| {
  113. match *cidr {
  114. IpCidr::Ipv6(cidr) if cidr.address() != Ipv6Address::LOOPBACK => {
  115. // Take the lower order 24 bits of the IPv6 address and
  116. // append those bits to FF02:0:0:0:0:1:FF00::/104.
  117. addr.as_bytes()[14..] == cidr.address().as_bytes()[14..]
  118. }
  119. _ => false,
  120. }
  121. })
  122. }
  123. /// Get the first IPv6 address if present.
  124. pub fn ipv6_addr(&self) -> Option<Ipv6Address> {
  125. self.ip_addrs.iter().find_map(|addr| match *addr {
  126. IpCidr::Ipv6(cidr) => Some(cidr.address()),
  127. #[allow(unreachable_patterns)]
  128. _ => None,
  129. })
  130. }
  131. pub(super) fn process_ipv6<'frame>(
  132. &mut self,
  133. sockets: &mut SocketSet,
  134. meta: PacketMeta,
  135. ipv6_packet: &Ipv6Packet<&'frame [u8]>,
  136. ) -> Option<Packet<'frame>> {
  137. let ipv6_repr = check!(Ipv6Repr::parse(ipv6_packet));
  138. if !ipv6_repr.src_addr.is_unicast() {
  139. // Discard packets with non-unicast source addresses.
  140. net_debug!("non-unicast source address");
  141. return None;
  142. }
  143. let (next_header, ip_payload) = if ipv6_repr.next_header == IpProtocol::HopByHop {
  144. match self.process_hopbyhop(ipv6_repr, ipv6_packet.payload()) {
  145. HopByHopResponse::Discard(e) => return e,
  146. HopByHopResponse::Continue(next) => next,
  147. }
  148. } else {
  149. (ipv6_repr.next_header, ipv6_packet.payload())
  150. };
  151. if !self.has_ip_addr(ipv6_repr.dst_addr)
  152. && !self.has_multicast_group(ipv6_repr.dst_addr)
  153. && !ipv6_repr.dst_addr.is_loopback()
  154. {
  155. net_trace!("packet IP address not for this interface");
  156. return None;
  157. }
  158. #[cfg(feature = "socket-raw")]
  159. let handled_by_raw_socket = self.raw_socket_filter(sockets, &ipv6_repr.into(), ip_payload);
  160. #[cfg(not(feature = "socket-raw"))]
  161. let handled_by_raw_socket = false;
  162. self.process_nxt_hdr(
  163. sockets,
  164. meta,
  165. ipv6_repr,
  166. next_header,
  167. handled_by_raw_socket,
  168. ip_payload,
  169. )
  170. }
  171. fn process_hopbyhop<'frame>(
  172. &mut self,
  173. ipv6_repr: Ipv6Repr,
  174. ip_payload: &'frame [u8],
  175. ) -> HopByHopResponse<'frame> {
  176. let param_problem = || {
  177. let payload_len =
  178. icmp_reply_payload_len(ip_payload.len(), IPV6_MIN_MTU, ipv6_repr.buffer_len());
  179. self.icmpv6_reply(
  180. ipv6_repr,
  181. Icmpv6Repr::ParamProblem {
  182. reason: Icmpv6ParamProblem::UnrecognizedOption,
  183. pointer: ipv6_repr.buffer_len() as u32,
  184. header: ipv6_repr,
  185. data: &ip_payload[0..payload_len],
  186. },
  187. )
  188. };
  189. let ext_hdr = check!(Ipv6ExtHeader::new_checked(ip_payload));
  190. let ext_repr = check!(Ipv6ExtHeaderRepr::parse(&ext_hdr));
  191. let hbh_hdr = check!(Ipv6HopByHopHeader::new_checked(ext_repr.data));
  192. let hbh_repr = check!(Ipv6HopByHopRepr::parse(&hbh_hdr));
  193. for opt_repr in &hbh_repr.options {
  194. match opt_repr {
  195. Ipv6OptionRepr::Pad1 | Ipv6OptionRepr::PadN(_) => (),
  196. #[cfg(feature = "proto-rpl")]
  197. Ipv6OptionRepr::Rpl(_) => {}
  198. Ipv6OptionRepr::Unknown { type_, .. } => {
  199. match Ipv6OptionFailureType::from(*type_) {
  200. Ipv6OptionFailureType::Skip => (),
  201. Ipv6OptionFailureType::Discard => {
  202. return HopByHopResponse::Discard(None);
  203. }
  204. Ipv6OptionFailureType::DiscardSendAll => {
  205. return HopByHopResponse::Discard(param_problem());
  206. }
  207. Ipv6OptionFailureType::DiscardSendUnicast
  208. if !ipv6_repr.dst_addr.is_multicast() =>
  209. {
  210. return HopByHopResponse::Discard(param_problem());
  211. }
  212. _ => unreachable!(),
  213. }
  214. }
  215. }
  216. }
  217. HopByHopResponse::Continue((
  218. ext_repr.next_header,
  219. &ip_payload[ext_repr.header_len() + ext_repr.data.len()..],
  220. ))
  221. }
  222. /// Given the next header value forward the payload onto the correct process
  223. /// function.
  224. fn process_nxt_hdr<'frame>(
  225. &mut self,
  226. sockets: &mut SocketSet,
  227. meta: PacketMeta,
  228. ipv6_repr: Ipv6Repr,
  229. nxt_hdr: IpProtocol,
  230. handled_by_raw_socket: bool,
  231. ip_payload: &'frame [u8],
  232. ) -> Option<Packet<'frame>> {
  233. match nxt_hdr {
  234. IpProtocol::Icmpv6 => self.process_icmpv6(sockets, ipv6_repr.into(), ip_payload),
  235. #[cfg(any(feature = "socket-udp", feature = "socket-dns"))]
  236. IpProtocol::Udp => self.process_udp(
  237. sockets,
  238. meta,
  239. handled_by_raw_socket,
  240. ipv6_repr.into(),
  241. ip_payload,
  242. ),
  243. #[cfg(feature = "socket-tcp")]
  244. IpProtocol::Tcp => self.process_tcp(sockets, ipv6_repr.into(), ip_payload),
  245. #[cfg(feature = "socket-raw")]
  246. _ if handled_by_raw_socket => None,
  247. _ => {
  248. // Send back as much of the original payload as we can.
  249. let payload_len =
  250. icmp_reply_payload_len(ip_payload.len(), IPV6_MIN_MTU, ipv6_repr.buffer_len());
  251. let icmp_reply_repr = Icmpv6Repr::ParamProblem {
  252. reason: Icmpv6ParamProblem::UnrecognizedNxtHdr,
  253. // The offending packet is after the IPv6 header.
  254. pointer: ipv6_repr.buffer_len() as u32,
  255. header: ipv6_repr,
  256. data: &ip_payload[0..payload_len],
  257. };
  258. self.icmpv6_reply(ipv6_repr, icmp_reply_repr)
  259. }
  260. }
  261. }
  262. pub(super) fn process_icmpv6<'frame>(
  263. &mut self,
  264. _sockets: &mut SocketSet,
  265. ip_repr: IpRepr,
  266. ip_payload: &'frame [u8],
  267. ) -> Option<Packet<'frame>> {
  268. let icmp_packet = check!(Icmpv6Packet::new_checked(ip_payload));
  269. let icmp_repr = check!(Icmpv6Repr::parse(
  270. &ip_repr.src_addr(),
  271. &ip_repr.dst_addr(),
  272. &icmp_packet,
  273. &self.caps.checksum,
  274. ));
  275. #[cfg(feature = "socket-icmp")]
  276. let mut handled_by_icmp_socket = false;
  277. #[cfg(feature = "socket-icmp")]
  278. {
  279. use crate::socket::icmp::Socket as IcmpSocket;
  280. for icmp_socket in _sockets
  281. .items_mut()
  282. .filter_map(|i| IcmpSocket::downcast_mut(&mut i.socket))
  283. {
  284. if icmp_socket.accepts(self, &ip_repr, &icmp_repr.into()) {
  285. icmp_socket.process(self, &ip_repr, &icmp_repr.into());
  286. handled_by_icmp_socket = true;
  287. }
  288. }
  289. }
  290. match icmp_repr {
  291. // Respond to echo requests.
  292. Icmpv6Repr::EchoRequest {
  293. ident,
  294. seq_no,
  295. data,
  296. } => match ip_repr {
  297. IpRepr::Ipv6(ipv6_repr) => {
  298. let icmp_reply_repr = Icmpv6Repr::EchoReply {
  299. ident,
  300. seq_no,
  301. data,
  302. };
  303. self.icmpv6_reply(ipv6_repr, icmp_reply_repr)
  304. }
  305. #[allow(unreachable_patterns)]
  306. _ => unreachable!(),
  307. },
  308. // Ignore any echo replies.
  309. Icmpv6Repr::EchoReply { .. } => None,
  310. // Forward any NDISC packets to the ndisc packet handler
  311. #[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))]
  312. Icmpv6Repr::Ndisc(repr) if ip_repr.hop_limit() == 0xff => match ip_repr {
  313. IpRepr::Ipv6(ipv6_repr) => match self.caps.medium {
  314. #[cfg(feature = "medium-ethernet")]
  315. Medium::Ethernet => self.process_ndisc(ipv6_repr, repr),
  316. #[cfg(feature = "medium-ieee802154")]
  317. Medium::Ieee802154 => self.process_ndisc(ipv6_repr, repr),
  318. #[cfg(feature = "medium-ip")]
  319. Medium::Ip => None,
  320. },
  321. #[allow(unreachable_patterns)]
  322. _ => unreachable!(),
  323. },
  324. // Don't report an error if a packet with unknown type
  325. // has been handled by an ICMP socket
  326. #[cfg(feature = "socket-icmp")]
  327. _ if handled_by_icmp_socket => None,
  328. // FIXME: do something correct here?
  329. _ => None,
  330. }
  331. }
  332. #[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))]
  333. pub(super) fn process_ndisc<'frame>(
  334. &mut self,
  335. ip_repr: Ipv6Repr,
  336. repr: NdiscRepr<'frame>,
  337. ) -> Option<Packet<'frame>> {
  338. match repr {
  339. NdiscRepr::NeighborAdvert {
  340. lladdr,
  341. target_addr,
  342. flags,
  343. } => {
  344. let ip_addr = ip_repr.src_addr.into();
  345. if let Some(lladdr) = lladdr {
  346. let lladdr = check!(lladdr.parse(self.caps.medium));
  347. if !lladdr.is_unicast() || !target_addr.is_unicast() {
  348. return None;
  349. }
  350. if flags.contains(NdiscNeighborFlags::OVERRIDE)
  351. || !self.neighbor_cache.lookup(&ip_addr, self.now).found()
  352. {
  353. self.neighbor_cache.fill(ip_addr, lladdr, self.now)
  354. }
  355. }
  356. None
  357. }
  358. NdiscRepr::NeighborSolicit {
  359. target_addr,
  360. lladdr,
  361. ..
  362. } => {
  363. if let Some(lladdr) = lladdr {
  364. let lladdr = check!(lladdr.parse(self.caps.medium));
  365. if !lladdr.is_unicast() || !target_addr.is_unicast() {
  366. return None;
  367. }
  368. self.neighbor_cache
  369. .fill(ip_repr.src_addr.into(), lladdr, self.now);
  370. }
  371. if self.has_solicited_node(ip_repr.dst_addr) && self.has_ip_addr(target_addr) {
  372. let advert = Icmpv6Repr::Ndisc(NdiscRepr::NeighborAdvert {
  373. flags: NdiscNeighborFlags::SOLICITED,
  374. target_addr,
  375. #[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))]
  376. lladdr: Some(self.hardware_addr.into()),
  377. });
  378. let ip_repr = Ipv6Repr {
  379. src_addr: target_addr,
  380. dst_addr: ip_repr.src_addr,
  381. next_header: IpProtocol::Icmpv6,
  382. hop_limit: 0xff,
  383. payload_len: advert.buffer_len(),
  384. };
  385. Some(Packet::new_ipv6(ip_repr, IpPayload::Icmpv6(advert)))
  386. } else {
  387. None
  388. }
  389. }
  390. _ => None,
  391. }
  392. }
  393. pub(super) fn icmpv6_reply<'frame, 'icmp: 'frame>(
  394. &self,
  395. ipv6_repr: Ipv6Repr,
  396. icmp_repr: Icmpv6Repr<'icmp>,
  397. ) -> Option<Packet<'frame>> {
  398. let src_addr = ipv6_repr.dst_addr;
  399. let dst_addr = ipv6_repr.src_addr;
  400. let src_addr = if src_addr.is_unicast() {
  401. src_addr
  402. } else if let Some(addr) = self.get_source_address_ipv6(&dst_addr) {
  403. addr
  404. } else {
  405. net_debug!("no suitable source address found");
  406. return None;
  407. };
  408. let ipv6_reply_repr = Ipv6Repr {
  409. src_addr,
  410. dst_addr,
  411. next_header: IpProtocol::Icmpv6,
  412. payload_len: icmp_repr.buffer_len(),
  413. hop_limit: 64,
  414. };
  415. Some(Packet::new_ipv6(
  416. ipv6_reply_repr,
  417. IpPayload::Icmpv6(icmp_repr),
  418. ))
  419. }
  420. }