Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
133 changes: 111 additions & 22 deletions src/iface/ethernet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -876,21 +876,20 @@ impl<'b, 'c, 'e> InterfaceInner<'b, 'c, 'e> {
let ip_payload = ipv6_packet.payload();

#[cfg(feature = "socket-raw")]
{
if self.raw_socket_filter(sockets, &ipv6_repr.into(), ip_payload) {
return Ok(Packet::None);
}
}
let handled_by_raw_socket = self.raw_socket_filter(sockets, &ipv6_repr.into(), ip_payload);
#[cfg(not(feature = "socket-raw"))]
let handled_by_raw_socket = false;

self.process_nxt_hdr(sockets, timestamp, ipv6_repr, ipv6_repr.next_header, ip_payload)
self.process_nxt_hdr(sockets, timestamp, ipv6_repr, ipv6_repr.next_header,
handled_by_raw_socket, ip_payload)
}

/// Given the next header value forward the payload onto the correct process
/// function.
#[cfg(feature = "proto-ipv6")]
fn process_nxt_hdr<'frame>
(&mut self, sockets: &mut SocketSet, timestamp: Instant, ipv6_repr: Ipv6Repr,
nxt_hdr: IpProtocol, ip_payload: &'frame [u8])
nxt_hdr: IpProtocol, handled_by_raw_socket: bool, ip_payload: &'frame [u8])
-> Result<Packet<'frame>>
{
match nxt_hdr {
Expand All @@ -899,14 +898,18 @@ impl<'b, 'c, 'e> InterfaceInner<'b, 'c, 'e> {

#[cfg(feature = "socket-udp")]
IpProtocol::Udp =>
self.process_udp(sockets, ipv6_repr.into(), ip_payload),
self.process_udp(sockets, ipv6_repr.into(), handled_by_raw_socket, ip_payload),

#[cfg(feature = "socket-tcp")]
IpProtocol::Tcp =>
self.process_tcp(sockets, timestamp, ipv6_repr.into(), ip_payload),

IpProtocol::HopByHop =>
self.process_hopbyhop(sockets, timestamp, ipv6_repr, ip_payload),
self.process_hopbyhop(sockets, timestamp, ipv6_repr, handled_by_raw_socket, ip_payload),

#[cfg(feature = "socket-raw")]
_ if handled_by_raw_socket =>
Ok(Packet::None),

_ => {
// Send back as much of the original payload as we can.
Expand Down Expand Up @@ -953,6 +956,8 @@ impl<'b, 'c, 'e> InterfaceInner<'b, 'c, 'e> {

#[cfg(feature = "socket-raw")]
let handled_by_raw_socket = self.raw_socket_filter(sockets, &ip_repr, ip_payload);
#[cfg(not(feature = "socket-raw"))]
let handled_by_raw_socket = false;

if !self.has_ip_addr(ipv4_repr.dst_addr) &&
!ipv4_repr.dst_addr.is_broadcast() &&
Expand All @@ -970,10 +975,6 @@ impl<'b, 'c, 'e> InterfaceInner<'b, 'c, 'e> {
}

match ipv4_repr.protocol {
#[cfg(feature = "socket-raw")]
_ if handled_by_raw_socket =>
Ok(Packet::None),

IpProtocol::Icmp =>
self.process_icmpv4(sockets, ip_repr, ip_payload),

Expand All @@ -983,12 +984,15 @@ impl<'b, 'c, 'e> InterfaceInner<'b, 'c, 'e> {

#[cfg(feature = "socket-udp")]
IpProtocol::Udp =>
self.process_udp(sockets, ip_repr, ip_payload),
self.process_udp(sockets, ip_repr, handled_by_raw_socket, ip_payload),

#[cfg(feature = "socket-tcp")]
IpProtocol::Tcp =>
self.process_tcp(sockets, timestamp, ip_repr, ip_payload),

_ if handled_by_raw_socket =>
Ok(Packet::None),

_ => {
// Send back as much of the original payload as we can.
let payload_len = icmp_reply_payload_len(ip_payload.len(), IPV4_MIN_MTU,
Expand Down Expand Up @@ -1170,7 +1174,8 @@ impl<'b, 'c, 'e> InterfaceInner<'b, 'c, 'e> {

#[cfg(feature = "proto-ipv6")]
fn process_hopbyhop<'frame>(&mut self, sockets: &mut SocketSet, timestamp: Instant,
ipv6_repr: Ipv6Repr, ip_payload: &'frame [u8]) -> Result<Packet<'frame>>
ipv6_repr: Ipv6Repr, handled_by_raw_socket: bool,
ip_payload: &'frame [u8]) -> Result<Packet<'frame>>
{
let hbh_pkt = Ipv6HopByHopHeader::new_checked(ip_payload)?;
let hbh_repr = Ipv6HopByHopRepr::parse(&hbh_pkt)?;
Expand All @@ -1195,7 +1200,7 @@ impl<'b, 'c, 'e> InterfaceInner<'b, 'c, 'e> {
}
}
self.process_nxt_hdr(sockets, timestamp, ipv6_repr, hbh_repr.next_header,
&ip_payload[hbh_repr.buffer_len()..])
handled_by_raw_socket, &ip_payload[hbh_repr.buffer_len()..])
}

#[cfg(feature = "proto-ipv4")]
Expand Down Expand Up @@ -1314,7 +1319,7 @@ impl<'b, 'c, 'e> InterfaceInner<'b, 'c, 'e> {

#[cfg(feature = "socket-udp")]
fn process_udp<'frame>(&self, sockets: &mut SocketSet,
ip_repr: IpRepr, ip_payload: &'frame [u8]) ->
ip_repr: IpRepr, handled_by_raw_socket: bool, ip_payload: &'frame [u8]) ->
Result<Packet<'frame>>
{
let (src_addr, dst_addr) = (ip_repr.src_addr(), ip_repr.dst_addr());
Expand All @@ -1336,6 +1341,12 @@ impl<'b, 'c, 'e> InterfaceInner<'b, 'c, 'e> {
// The packet wasn't handled by a socket, send an ICMP port unreachable packet.
match ip_repr {
#[cfg(feature = "proto-ipv4")]
IpRepr::Ipv4(_) if handled_by_raw_socket =>
Ok(Packet::None),
#[cfg(feature = "proto-ipv6")]
IpRepr::Ipv6(_) if handled_by_raw_socket =>
Ok(Packet::None),
#[cfg(feature = "proto-ipv4")]
IpRepr::Ipv4(ipv4_repr) => {
let payload_len = icmp_reply_payload_len(ip_payload.len(), IPV4_MIN_MTU,
ipv4_repr.buffer_len());
Expand Down Expand Up @@ -1957,7 +1968,7 @@ mod test {

// Ensure that the unknown protocol triggers an error response.
// And we correctly handle no payload.
assert_eq!(iface.inner.process_udp(&mut socket_set, ip_repr, data),
assert_eq!(iface.inner.process_udp(&mut socket_set, ip_repr, false, data),
Ok(expected_repr));

let ip_repr = IpRepr::Ipv4(Ipv4Repr {
Expand All @@ -1977,7 +1988,7 @@ mod test {
// ICMP error response when the destination address is a
// broadcast address and no socket is bound to the port.
assert_eq!(iface.inner.process_udp(&mut socket_set, ip_repr,
packet_broadcast.into_inner()), Ok(Packet::None));
false, packet_broadcast.into_inner()), Ok(Packet::None));
}

#[test]
Expand Down Expand Up @@ -2040,7 +2051,7 @@ mod test {
&ChecksumCapabilities::default());

// Packet should be handled by bound UDP socket
assert_eq!(iface.inner.process_udp(&mut socket_set, ip_repr, packet.into_inner()),
assert_eq!(iface.inner.process_udp(&mut socket_set, ip_repr, false, packet.into_inner()),
Ok(Packet::None));

{
Expand Down Expand Up @@ -2198,10 +2209,10 @@ mod test {
assert_eq!(expected_ip_repr.buffer_len() + expected_icmp_repr.buffer_len(), MIN_MTU);
// The expected packet and the generated packet are equal
#[cfg(all(feature = "proto-ipv4", not(feature = "proto-ipv6")))]
assert_eq!(iface.inner.process_udp(&mut socket_set, ip_repr.into(), payload),
assert_eq!(iface.inner.process_udp(&mut socket_set, ip_repr.into(), false, payload),
Ok(Packet::Icmpv4((expected_ip_repr, expected_icmp_repr))));
#[cfg(feature = "proto-ipv6")]
assert_eq!(iface.inner.process_udp(&mut socket_set, ip_repr.into(), payload),
assert_eq!(iface.inner.process_udp(&mut socket_set, ip_repr.into(), false, payload),
Ok(Packet::Icmpv6((expected_ip_repr, expected_icmp_repr))));
}

Expand Down Expand Up @@ -2645,4 +2656,82 @@ mod test {
assert_eq!(iface.inner.process_ipv4(&mut socket_set, Instant::from_millis(0), &frame),
Ok(Packet::None));
}

#[test]
#[cfg(all(feature = "proto-ipv4", feature = "socket-raw", feature = "socket-udp"))]
fn test_raw_socket_with_udp_socket() {
use socket::{UdpSocket, UdpSocketBuffer, UdpPacketMetadata,
RawSocket, RawSocketBuffer, RawPacketMetadata};
use wire::{IpVersion, IpEndpoint, Ipv4Packet, UdpPacket, UdpRepr};

static UDP_PAYLOAD: [u8; 5] = [0x48, 0x65, 0x6c, 0x6c, 0x6f];

let (mut iface, mut socket_set) = create_loopback();

let udp_rx_buffer = UdpSocketBuffer::new(vec![UdpPacketMetadata::EMPTY], vec![0; 15]);
let udp_tx_buffer = UdpSocketBuffer::new(vec![UdpPacketMetadata::EMPTY], vec![0; 15]);
let udp_socket = UdpSocket::new(udp_rx_buffer, udp_tx_buffer);
let udp_socket_handle = socket_set.add(udp_socket);
{
// Bind the socket to port 68
let mut socket = socket_set.get::<UdpSocket>(udp_socket_handle);
assert_eq!(socket.bind(68), Ok(()));
assert!(!socket.can_recv());
assert!(socket.can_send());
}

let packets = 1;
let raw_rx_buffer = RawSocketBuffer::new(vec![RawPacketMetadata::EMPTY; packets], vec![0; 48 * 1]);
let raw_tx_buffer = RawSocketBuffer::new(vec![RawPacketMetadata::EMPTY; packets], vec![0; 48 * packets]);
let raw_socket = RawSocket::new(IpVersion::Ipv4, IpProtocol::Udp, raw_rx_buffer, raw_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: &UDP_PAYLOAD
};
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())
};

assert_eq!(iface.inner.process_ipv4(&mut socket_set, Instant::from_millis(0), &frame),
Ok(Packet::None));

{
// Make sure the UDP socket can still receive in presence of a Raw socket that handles UDP
let mut socket = socket_set.get::<UdpSocket>(udp_socket_handle);
assert!(socket.can_recv());
assert_eq!(socket.recv(), Ok((&UDP_PAYLOAD[..], IpEndpoint::new(src_addr.into(), 67))));
}
}
}