ipv4.rs 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448
  1. use super::*;
  2. #[cfg(feature = "socket-dhcpv4")]
  3. use crate::socket::dhcpv4;
  4. #[cfg(feature = "socket-icmp")]
  5. use crate::socket::icmp;
  6. use crate::socket::AnySocket;
  7. use crate::phy::{Medium, TxToken};
  8. use crate::time::Instant;
  9. use crate::wire::{Ipv4Packet as Ipv4PacketWire, *};
  10. impl InterfaceInner {
  11. pub(super) fn process_ipv4<'a>(
  12. &mut self,
  13. sockets: &mut SocketSet,
  14. meta: PacketMeta,
  15. ipv4_packet: &Ipv4PacketWire<&'a [u8]>,
  16. frag: &'a mut FragmentsBuffer,
  17. ) -> Option<IpPacket<'a>> {
  18. let ipv4_repr = check!(Ipv4Repr::parse(ipv4_packet, &self.caps.checksum));
  19. if !self.is_unicast_v4(ipv4_repr.src_addr) && !ipv4_repr.src_addr.is_unspecified() {
  20. // Discard packets with non-unicast source addresses but allow unspecified
  21. net_debug!("non-unicast or unspecified source address");
  22. return None;
  23. }
  24. #[cfg(feature = "proto-ipv4-fragmentation")]
  25. let ip_payload = {
  26. if ipv4_packet.more_frags() || ipv4_packet.frag_offset() != 0 {
  27. let key = FragKey::Ipv4(ipv4_packet.get_key());
  28. let f = match frag.assembler.get(&key, self.now + frag.reassembly_timeout) {
  29. Ok(f) => f,
  30. Err(_) => {
  31. net_debug!("No available packet assembler for fragmented packet");
  32. return None;
  33. }
  34. };
  35. if !ipv4_packet.more_frags() {
  36. // This is the last fragment, so we know the total size
  37. check!(f.set_total_size(
  38. ipv4_packet.total_len() as usize - ipv4_packet.header_len() as usize
  39. + ipv4_packet.frag_offset() as usize,
  40. ));
  41. }
  42. if let Err(e) = f.add(ipv4_packet.payload(), ipv4_packet.frag_offset() as usize) {
  43. net_debug!("fragmentation error: {:?}", e);
  44. return None;
  45. }
  46. // NOTE: according to the standard, the total length needs to be
  47. // recomputed, as well as the checksum. However, we don't really use
  48. // the IPv4 header after the packet is reassembled.
  49. match f.assemble() {
  50. Some(payload) => payload,
  51. None => return None,
  52. }
  53. } else {
  54. ipv4_packet.payload()
  55. }
  56. };
  57. #[cfg(not(feature = "proto-ipv4-fragmentation"))]
  58. let ip_payload = ipv4_packet.payload();
  59. let ip_repr = IpRepr::Ipv4(ipv4_repr);
  60. #[cfg(feature = "socket-raw")]
  61. let handled_by_raw_socket = self.raw_socket_filter(sockets, &ip_repr, ip_payload);
  62. #[cfg(not(feature = "socket-raw"))]
  63. let handled_by_raw_socket = false;
  64. #[cfg(feature = "socket-dhcpv4")]
  65. {
  66. if ipv4_repr.next_header == IpProtocol::Udp
  67. && matches!(self.caps.medium, Medium::Ethernet)
  68. {
  69. let udp_packet = check!(UdpPacket::new_checked(ip_payload));
  70. if let Some(dhcp_socket) = sockets
  71. .items_mut()
  72. .find_map(|i| dhcpv4::Socket::downcast_mut(&mut i.socket))
  73. {
  74. // First check for source and dest ports, then do `UdpRepr::parse` if they match.
  75. // This way we avoid validating the UDP checksum twice for all non-DHCP UDP packets (one here, one in `process_udp`)
  76. if udp_packet.src_port() == dhcp_socket.server_port
  77. && udp_packet.dst_port() == dhcp_socket.client_port
  78. {
  79. let (src_addr, dst_addr) = (ip_repr.src_addr(), ip_repr.dst_addr());
  80. let udp_repr = check!(UdpRepr::parse(
  81. &udp_packet,
  82. &src_addr,
  83. &dst_addr,
  84. &self.caps.checksum
  85. ));
  86. let udp_payload = udp_packet.payload();
  87. dhcp_socket.process(self, &ipv4_repr, &udp_repr, udp_payload);
  88. return None;
  89. }
  90. }
  91. }
  92. }
  93. if !self.has_ip_addr(ipv4_repr.dst_addr)
  94. && !self.has_multicast_group(ipv4_repr.dst_addr)
  95. && !self.is_broadcast_v4(ipv4_repr.dst_addr)
  96. {
  97. // Ignore IP packets not directed at us, or broadcast, or any of the multicast groups.
  98. // If AnyIP is enabled, also check if the packet is routed locally.
  99. if !self.any_ip
  100. || !ipv4_repr.dst_addr.is_unicast()
  101. || self
  102. .routes
  103. .lookup(&IpAddress::Ipv4(ipv4_repr.dst_addr), self.now)
  104. .map_or(true, |router_addr| !self.has_ip_addr(router_addr))
  105. {
  106. return None;
  107. }
  108. }
  109. match ipv4_repr.next_header {
  110. IpProtocol::Icmp => self.process_icmpv4(sockets, ip_repr, ip_payload),
  111. #[cfg(feature = "proto-igmp")]
  112. IpProtocol::Igmp => self.process_igmp(ipv4_repr, ip_payload),
  113. #[cfg(any(feature = "socket-udp", feature = "socket-dns"))]
  114. IpProtocol::Udp => {
  115. let udp_packet = check!(UdpPacket::new_checked(ip_payload));
  116. let udp_repr = check!(UdpRepr::parse(
  117. &udp_packet,
  118. &ipv4_repr.src_addr.into(),
  119. &ipv4_repr.dst_addr.into(),
  120. &self.checksum_caps(),
  121. ));
  122. self.process_udp(
  123. sockets,
  124. meta,
  125. ip_repr,
  126. udp_repr,
  127. handled_by_raw_socket,
  128. udp_packet.payload(),
  129. ip_payload,
  130. )
  131. }
  132. #[cfg(feature = "socket-tcp")]
  133. IpProtocol::Tcp => self.process_tcp(sockets, ip_repr, ip_payload),
  134. _ if handled_by_raw_socket => None,
  135. _ => {
  136. // Send back as much of the original payload as we can.
  137. let payload_len =
  138. icmp_reply_payload_len(ip_payload.len(), IPV4_MIN_MTU, ipv4_repr.buffer_len());
  139. let icmp_reply_repr = Icmpv4Repr::DstUnreachable {
  140. reason: Icmpv4DstUnreachable::ProtoUnreachable,
  141. header: ipv4_repr,
  142. data: &ip_payload[0..payload_len],
  143. };
  144. self.icmpv4_reply(ipv4_repr, icmp_reply_repr)
  145. }
  146. }
  147. }
  148. #[cfg(feature = "medium-ethernet")]
  149. pub(super) fn process_arp<'frame>(
  150. &mut self,
  151. timestamp: Instant,
  152. eth_frame: &EthernetFrame<&'frame [u8]>,
  153. ) -> Option<EthernetPacket<'frame>> {
  154. let arp_packet = check!(ArpPacket::new_checked(eth_frame.payload()));
  155. let arp_repr = check!(ArpRepr::parse(&arp_packet));
  156. match arp_repr {
  157. ArpRepr::EthernetIpv4 {
  158. operation,
  159. source_hardware_addr,
  160. source_protocol_addr,
  161. target_protocol_addr,
  162. ..
  163. } => {
  164. // Only process ARP packets for us.
  165. if !self.has_ip_addr(target_protocol_addr) {
  166. return None;
  167. }
  168. // Only process REQUEST and RESPONSE.
  169. if let ArpOperation::Unknown(_) = operation {
  170. net_debug!("arp: unknown operation code");
  171. return None;
  172. }
  173. // Discard packets with non-unicast source addresses.
  174. if !source_protocol_addr.is_unicast() || !source_hardware_addr.is_unicast() {
  175. net_debug!("arp: non-unicast source address");
  176. return None;
  177. }
  178. if !self.in_same_network(&IpAddress::Ipv4(source_protocol_addr)) {
  179. net_debug!("arp: source IP address not in same network as us");
  180. return None;
  181. }
  182. // Fill the ARP cache from any ARP packet aimed at us (both request or response).
  183. // We fill from requests too because if someone is requesting our address they
  184. // are probably going to talk to us, so we avoid having to request their address
  185. // when we later reply to them.
  186. self.neighbor_cache.fill(
  187. source_protocol_addr.into(),
  188. source_hardware_addr.into(),
  189. timestamp,
  190. );
  191. if operation == ArpOperation::Request {
  192. let src_hardware_addr = self.hardware_addr.ethernet_or_panic();
  193. Some(EthernetPacket::Arp(ArpRepr::EthernetIpv4 {
  194. operation: ArpOperation::Reply,
  195. source_hardware_addr: src_hardware_addr,
  196. source_protocol_addr: target_protocol_addr,
  197. target_hardware_addr: source_hardware_addr,
  198. target_protocol_addr: source_protocol_addr,
  199. }))
  200. } else {
  201. None
  202. }
  203. }
  204. }
  205. }
  206. pub(super) fn process_icmpv4<'frame>(
  207. &mut self,
  208. _sockets: &mut SocketSet,
  209. ip_repr: IpRepr,
  210. ip_payload: &'frame [u8],
  211. ) -> Option<IpPacket<'frame>> {
  212. let icmp_packet = check!(Icmpv4Packet::new_checked(ip_payload));
  213. let icmp_repr = check!(Icmpv4Repr::parse(&icmp_packet, &self.caps.checksum));
  214. #[cfg(feature = "socket-icmp")]
  215. let mut handled_by_icmp_socket = false;
  216. #[cfg(all(feature = "socket-icmp", feature = "proto-ipv4"))]
  217. for icmp_socket in _sockets
  218. .items_mut()
  219. .filter_map(|i| icmp::Socket::downcast_mut(&mut i.socket))
  220. {
  221. if icmp_socket.accepts(self, &ip_repr, &icmp_repr.into()) {
  222. icmp_socket.process(self, &ip_repr, &icmp_repr.into());
  223. handled_by_icmp_socket = true;
  224. }
  225. }
  226. match icmp_repr {
  227. // Respond to echo requests.
  228. #[cfg(feature = "proto-ipv4")]
  229. Icmpv4Repr::EchoRequest {
  230. ident,
  231. seq_no,
  232. data,
  233. } => {
  234. let icmp_reply_repr = Icmpv4Repr::EchoReply {
  235. ident,
  236. seq_no,
  237. data,
  238. };
  239. match ip_repr {
  240. IpRepr::Ipv4(ipv4_repr) => self.icmpv4_reply(ipv4_repr, icmp_reply_repr),
  241. #[allow(unreachable_patterns)]
  242. _ => unreachable!(),
  243. }
  244. }
  245. // Ignore any echo replies.
  246. Icmpv4Repr::EchoReply { .. } => None,
  247. // Don't report an error if a packet with unknown type
  248. // has been handled by an ICMP socket
  249. #[cfg(feature = "socket-icmp")]
  250. _ if handled_by_icmp_socket => None,
  251. // FIXME: do something correct here?
  252. _ => None,
  253. }
  254. }
  255. pub(super) fn icmpv4_reply<'frame, 'icmp: 'frame>(
  256. &self,
  257. ipv4_repr: Ipv4Repr,
  258. icmp_repr: Icmpv4Repr<'icmp>,
  259. ) -> Option<IpPacket<'frame>> {
  260. if !self.is_unicast_v4(ipv4_repr.src_addr) {
  261. // Do not send ICMP replies to non-unicast sources
  262. None
  263. } else if self.is_unicast_v4(ipv4_repr.dst_addr) {
  264. // Reply as normal when src_addr and dst_addr are both unicast
  265. let ipv4_reply_repr = Ipv4Repr {
  266. src_addr: ipv4_repr.dst_addr,
  267. dst_addr: ipv4_repr.src_addr,
  268. next_header: IpProtocol::Icmp,
  269. payload_len: icmp_repr.buffer_len(),
  270. hop_limit: 64,
  271. };
  272. Some(IpPacket::new_ipv4(
  273. ipv4_reply_repr,
  274. IpPayload::Icmpv4(icmp_repr),
  275. ))
  276. } else if self.is_broadcast_v4(ipv4_repr.dst_addr) {
  277. // Only reply to broadcasts for echo replies and not other ICMP messages
  278. match icmp_repr {
  279. Icmpv4Repr::EchoReply { .. } => match self.ipv4_addr() {
  280. Some(src_addr) => {
  281. let ipv4_reply_repr = Ipv4Repr {
  282. src_addr,
  283. dst_addr: ipv4_repr.src_addr,
  284. next_header: IpProtocol::Icmp,
  285. payload_len: icmp_repr.buffer_len(),
  286. hop_limit: 64,
  287. };
  288. Some(IpPacket::new_ipv4(
  289. ipv4_reply_repr,
  290. IpPayload::Icmpv4(icmp_repr),
  291. ))
  292. }
  293. None => None,
  294. },
  295. _ => None,
  296. }
  297. } else {
  298. None
  299. }
  300. }
  301. #[cfg(feature = "proto-ipv4-fragmentation")]
  302. pub(super) fn dispatch_ipv4_frag<Tx: TxToken>(&mut self, tx_token: Tx, frag: &mut Fragmenter) {
  303. let caps = self.caps.clone();
  304. let mtu_max = self.ip_mtu();
  305. let ip_len = (frag.packet_len - frag.sent_bytes + frag.ipv4.repr.buffer_len()).min(mtu_max);
  306. let payload_len = ip_len - frag.ipv4.repr.buffer_len();
  307. let more_frags = (frag.packet_len - frag.sent_bytes) != payload_len;
  308. frag.ipv4.repr.payload_len = payload_len;
  309. frag.sent_bytes += payload_len;
  310. let mut tx_len = ip_len;
  311. #[cfg(feature = "medium-ethernet")]
  312. if matches!(caps.medium, Medium::Ethernet) {
  313. tx_len += EthernetFrame::<&[u8]>::header_len();
  314. }
  315. // Emit function for the Ethernet header.
  316. #[cfg(feature = "medium-ethernet")]
  317. let emit_ethernet = |repr: &IpRepr, tx_buffer: &mut [u8]| {
  318. let mut frame = EthernetFrame::new_unchecked(tx_buffer);
  319. let src_addr = self.hardware_addr.ethernet_or_panic();
  320. frame.set_src_addr(src_addr);
  321. frame.set_dst_addr(frag.ipv4.dst_hardware_addr);
  322. match repr.version() {
  323. #[cfg(feature = "proto-ipv4")]
  324. IpVersion::Ipv4 => frame.set_ethertype(EthernetProtocol::Ipv4),
  325. #[cfg(feature = "proto-ipv6")]
  326. IpVersion::Ipv6 => frame.set_ethertype(EthernetProtocol::Ipv6),
  327. }
  328. };
  329. tx_token.consume(tx_len, |mut tx_buffer| {
  330. #[cfg(feature = "medium-ethernet")]
  331. if matches!(self.caps.medium, Medium::Ethernet) {
  332. emit_ethernet(&IpRepr::Ipv4(frag.ipv4.repr), tx_buffer);
  333. tx_buffer = &mut tx_buffer[EthernetFrame::<&[u8]>::header_len()..];
  334. }
  335. let mut packet =
  336. Ipv4PacketWire::new_unchecked(&mut tx_buffer[..frag.ipv4.repr.buffer_len()]);
  337. frag.ipv4.repr.emit(&mut packet, &caps.checksum);
  338. packet.set_ident(frag.ipv4.ident);
  339. packet.set_more_frags(more_frags);
  340. packet.set_dont_frag(false);
  341. packet.set_frag_offset(frag.ipv4.frag_offset);
  342. if caps.checksum.ipv4.tx() {
  343. packet.fill_checksum();
  344. }
  345. tx_buffer[frag.ipv4.repr.buffer_len()..][..payload_len].copy_from_slice(
  346. &frag.buffer[frag.ipv4.frag_offset as usize + frag.ipv4.repr.buffer_len()..]
  347. [..payload_len],
  348. );
  349. // Update the frag offset for the next fragment.
  350. frag.ipv4.frag_offset += payload_len as u16;
  351. })
  352. }
  353. #[cfg(feature = "proto-igmp")]
  354. pub(super) fn igmp_report_packet<'any>(
  355. &self,
  356. version: IgmpVersion,
  357. group_addr: Ipv4Address,
  358. ) -> Option<IpPacket<'any>> {
  359. let iface_addr = self.ipv4_addr()?;
  360. let igmp_repr = IgmpRepr::MembershipReport {
  361. group_addr,
  362. version,
  363. };
  364. let pkt = IpPacket::new_ipv4(
  365. Ipv4Repr {
  366. src_addr: iface_addr,
  367. // Send to the group being reported
  368. dst_addr: group_addr,
  369. next_header: IpProtocol::Igmp,
  370. payload_len: igmp_repr.buffer_len(),
  371. hop_limit: 1,
  372. // [#183](https://github.com/m-labs/smoltcp/issues/183).
  373. },
  374. IpPayload::Igmp(igmp_repr),
  375. );
  376. Some(pkt)
  377. }
  378. #[cfg(feature = "proto-igmp")]
  379. pub(super) fn igmp_leave_packet<'any>(
  380. &self,
  381. group_addr: Ipv4Address,
  382. ) -> Option<IpPacket<'any>> {
  383. self.ipv4_addr().map(|iface_addr| {
  384. let igmp_repr = IgmpRepr::LeaveGroup { group_addr };
  385. IpPacket::new_ipv4(
  386. Ipv4Repr {
  387. src_addr: iface_addr,
  388. dst_addr: Ipv4Address::MULTICAST_ALL_ROUTERS,
  389. next_header: IpProtocol::Igmp,
  390. payload_len: igmp_repr.buffer_len(),
  391. hop_limit: 1,
  392. },
  393. IpPayload::Igmp(igmp_repr),
  394. )
  395. })
  396. }
  397. }