diff --git a/src/iface/ethernet.rs b/src/iface/ethernet.rs index 5bdf2ebf0..2b98d79d4 100644 --- a/src/iface/ethernet.rs +++ b/src/iface/ethernet.rs @@ -876,13 +876,12 @@ 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 @@ -890,7 +889,7 @@ impl<'b, 'c, 'e> InterfaceInner<'b, 'c, 'e> { #[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> { match nxt_hdr { @@ -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. @@ -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() && @@ -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), @@ -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, @@ -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> + ipv6_repr: Ipv6Repr, handled_by_raw_socket: bool, + ip_payload: &'frame [u8]) -> Result> { let hbh_pkt = Ipv6HopByHopHeader::new_checked(ip_payload)?; let hbh_repr = Ipv6HopByHopRepr::parse(&hbh_pkt)?; @@ -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")] @@ -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> { let (src_addr, dst_addr) = (ip_repr.src_addr(), ip_repr.dst_addr()); @@ -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()); @@ -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 { @@ -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] @@ -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)); { @@ -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)))); } @@ -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::(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::(udp_socket_handle); + assert!(socket.can_recv()); + assert_eq!(socket.recv(), Ok((&UDP_PAYLOAD[..], IpEndpoint::new(src_addr.into(), 67)))); + } + } }