ipv4.rs 17 KB

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