raw_socket: gracefully handle packet truncation errors

This commit is contained in:
Scott Mabin 2019-10-09 00:55:48 +01:00 committed by whitequark
parent eebd8e431a
commit 287e4f2814
1 changed files with 63 additions and 2 deletions

View File

@ -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() {