Browse Source

raw_socket: gracefully handle packet truncation errors

Scott Mabin 5 years ago
parent
commit
0fedb1db9a
1 changed files with 63 additions and 2 deletions
  1. 63 2
      src/iface/ethernet.rs

+ 63 - 2
src/iface/ethernet.rs

@@ -850,8 +850,8 @@ impl<'b, 'c, 'e> InterfaceInner<'b, 'c, 'e> {
             match raw_socket.process(&ip_repr, ip_payload, &checksum_caps) {
                 // The packet is valid and handled by socket.
                 Ok(()) => handled_by_raw_socket = true,
-                // The socket buffer is full.
-                Err(Error::Exhausted) => (),
+                // The socket buffer is full or the packet was truncated
+                Err(Error::Exhausted) | Err(Error::Truncated) => (),
                 // Raw sockets don't validate the packets in any way.
                 Err(_) => unreachable!(),
             }
@@ -2667,6 +2667,67 @@ mod test {
                    Ok(Packet::None));
     }
 
+    #[test]
+    #[cfg(all(feature = "proto-ipv4", feature = "socket-raw"))]
+    fn test_raw_socket_truncated_packet() {
+        use socket::{RawSocket, RawSocketBuffer, RawPacketMetadata};
+        use wire::{IpVersion, Ipv4Packet, UdpPacket, UdpRepr};
+
+        let (mut iface, mut socket_set) = create_loopback();
+
+        let packets = 1;
+        let rx_buffer = RawSocketBuffer::new(vec![RawPacketMetadata::EMPTY; packets], vec![0; 48 * 1]);
+        let tx_buffer = RawSocketBuffer::new(vec![RawPacketMetadata::EMPTY; packets], vec![0; 48 * packets]);
+        let raw_socket = RawSocket::new(IpVersion::Ipv4, IpProtocol::Udp, rx_buffer, tx_buffer);
+        socket_set.add(raw_socket);
+
+        let src_addr = Ipv4Address([127, 0, 0, 2]);
+        let dst_addr = Ipv4Address([127, 0, 0, 1]);
+
+        let udp_repr = UdpRepr {
+            src_port: 67,
+            dst_port: 68,
+            payload: &[0x2a; 49] // 49 > 48, hence packet will be truncated
+        };
+        let mut bytes = vec![0xff; udp_repr.buffer_len()];
+        let mut packet = UdpPacket::new_unchecked(&mut bytes[..]);
+        udp_repr.emit(&mut packet, &src_addr.into(), &dst_addr.into(), &ChecksumCapabilities::default());
+        let ipv4_repr = Ipv4Repr {
+            src_addr: src_addr,
+            dst_addr: dst_addr,
+            protocol: IpProtocol::Udp,
+            hop_limit: 64,
+            payload_len: udp_repr.buffer_len()
+        };
+
+        // Emit to ethernet frame
+        let mut eth_bytes = vec![0u8;
+            EthernetFrame::<&[u8]>::header_len() +
+            ipv4_repr.buffer_len() + udp_repr.buffer_len()
+        ];
+        let frame = {
+            let mut frame = EthernetFrame::new_unchecked(&mut eth_bytes);
+            ipv4_repr.emit(
+                &mut Ipv4Packet::new_unchecked(frame.payload_mut()),
+                &ChecksumCapabilities::default());
+            udp_repr.emit(
+                &mut UdpPacket::new_unchecked(
+                    &mut frame.payload_mut()[ipv4_repr.buffer_len()..]),
+                &src_addr.into(),
+                &dst_addr.into(),
+                &ChecksumCapabilities::default());
+            EthernetFrame::new_unchecked(&*frame.into_inner())
+        };
+
+        let frame = iface.inner.process_ipv4(&mut socket_set, Instant::from_millis(0), &frame);
+
+        // because the packet could not be handled we should send an Icmp message
+        assert!(match frame {  
+            Ok(Packet::Icmpv4(_)) => true,
+            _ => false,
+        });
+    }
+
     #[test]
     #[cfg(all(feature = "proto-ipv4", feature = "socket-raw", feature = "socket-udp"))]
     fn test_raw_socket_with_udp_socket() {