Przeglądaj źródła

ICMP sockets don't end ICMP packets processing.

Egor Karavaev 7 lat temu
rodzic
commit
752ae033db
1 zmienionych plików z 34 dodań i 14 usunięć
  1. 34 14
      src/iface/ethernet.rs

+ 34 - 14
src/iface/ethernet.rs

@@ -431,15 +431,20 @@ impl<'b, 'c> InterfaceInner<'b, 'c> {
         let checksum_caps = self.device_capabilities.checksum.clone();
         let icmp_repr = Icmpv4Repr::parse(&icmp_packet, &checksum_caps)?;
 
+        #[cfg(feature = "socket-icmp")]
+        let mut handled_by_icmp_socket = false;
+
         #[cfg(feature = "socket-icmp")]
         for mut icmp_socket in _sockets.iter_mut().filter_map(IcmpSocket::downcast) {
             if !icmp_socket.accepts(&ip_repr, &icmp_repr, &checksum_caps) { continue }
 
             match icmp_socket.process(&ip_repr, ip_payload) {
                 // The packet is valid and handled by socket.
-                Ok(()) => return Ok(Packet::None),
-                // The packet is malformed, or the socket buffer is full.
-                Err(e) => return Err(e)
+                Ok(()) => handled_by_icmp_socket = true,
+                // The socket buffer is full.
+                Err(Error::Exhausted) => (),
+                // ICMP sockets don't validate the packets in any way.
+                Err(_) => unreachable!(),
             }
         }
 
@@ -460,6 +465,11 @@ impl<'b, 'c> InterfaceInner<'b, 'c> {
             // Ignore any echo replies.
             Icmpv4Repr::EchoReply { .. } => Ok(Packet::None),
 
+            // Don't report an error if a packet with unknown type
+            // has been handled by an ICMP socket
+            #[cfg(feature = "socket-icmp")]
+            _ if handled_by_icmp_socket => Ok(Packet::None),
+
             // FIXME: do something correct here?
             _ => Err(Error::Unrecognized),
         }
@@ -1040,6 +1050,9 @@ mod test {
         let socket_handle = socket_set.add(icmpv4_socket);
 
         let ident = 0x1234;
+        let seq_no = 0x5432;
+        let echo_data = &[0xff; 16];
+
         {
             let mut socket = socket_set.get::<IcmpSocket>(socket_handle);
             // Bind to the ID 0x1234
@@ -1049,34 +1062,41 @@ mod test {
         // Ensure the ident we bound to and the ident of the packet are the same.
         let mut bytes = [0xff; 24];
         let mut packet = Icmpv4Packet::new(&mut bytes);
-        let echo_repr = Icmpv4Repr::EchoReply {
-            ident:  ident,
-            seq_no: 0x5432,
-            data:   &[0xff; 16],
-        };
+        let echo_repr = Icmpv4Repr::EchoRequest{ ident, seq_no, data: echo_data };
         echo_repr.emit(&mut packet, &ChecksumCapabilities::default());
-        let data = &packet.into_inner()[..];
+        let icmp_data = &packet.into_inner()[..];
 
-        let ip_repr = IpRepr::Ipv4(Ipv4Repr {
+        let ipv4_repr = Ipv4Repr {
             src_addr:    Ipv4Address::new(0x7f, 0x00, 0x00, 0x02),
             dst_addr:    Ipv4Address::new(0x7f, 0x00, 0x00, 0x01),
             protocol:    IpProtocol::Icmp,
             payload_len: 24,
             ttl:         64
-        });
+        };
+        let ip_repr = IpRepr::Ipv4(ipv4_repr);
 
         // Open a socket and ensure the packet is handled due to the listening
         // socket.
         {
             assert!(!socket_set.get::<IcmpSocket>(socket_handle).can_recv());
         }
-        assert_eq!(iface.inner.process_icmpv4(&mut socket_set, ip_repr, data),
-                   Ok(Packet::None));
+
+        // Confirm we still get EchoReply from `smoltcp` even with the ICMP socket listening
+        let echo_reply = Icmpv4Repr::EchoReply{ ident, seq_no, data: echo_data };
+        let ipv4_reply = Ipv4Repr {
+            src_addr: ipv4_repr.dst_addr,
+            dst_addr: ipv4_repr.src_addr,
+            ..ipv4_repr
+        };
+        assert_eq!(iface.inner.process_icmpv4(&mut socket_set, ip_repr, icmp_data),
+                   Ok(Packet::Icmpv4((ipv4_reply, echo_reply))));
+
         {
             let mut socket = socket_set.get::<IcmpSocket>(socket_handle);
             assert!(socket.can_recv());
             assert_eq!(socket.recv(),
-                       Ok((&data[..], IpAddress::Ipv4(Ipv4Address::new(0x7f, 0x00, 0x00, 0x02)))));
+                       Ok((&icmp_data[..],
+                           IpAddress::Ipv4(Ipv4Address::new(0x7f, 0x00, 0x00, 0x02)))));
         }
     }
 }