Fix IPv4 broadcast handling
A regression meant broadcast IPv4 packets were ignored. Restore handling those packets and also reply to broadcast ICMPv4 echo requests. Closes #287. Closes: #288 Approved by: whitequark
This commit is contained in:
parent
d9e0c8246c
commit
59f5cbbe64
|
@ -941,8 +941,10 @@ 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);
|
||||
|
||||
if !self.has_ip_addr(ipv4_repr.dst_addr) && !self.has_multicast_group(ipv4_repr.dst_addr) {
|
||||
// Ignore IP packets not directed at us or any of the multicast groups
|
||||
if !self.has_ip_addr(ipv4_repr.dst_addr) &&
|
||||
!ipv4_repr.dst_addr.is_broadcast() &&
|
||||
!self.has_multicast_group(ipv4_repr.dst_addr) {
|
||||
// Ignore IP packets not directed at us, or broadcast, or any of the multicast groups.
|
||||
// If AnyIP is enabled, also check if the packet is routed locally.
|
||||
if !self.any_ip {
|
||||
return Ok(Packet::None);
|
||||
|
@ -1242,7 +1244,11 @@ impl<'b, 'c, 'e> InterfaceInner<'b, 'c, 'e> {
|
|||
(&self, ipv4_repr: Ipv4Repr, icmp_repr: Icmpv4Repr<'icmp>) ->
|
||||
Packet<'frame>
|
||||
{
|
||||
if ipv4_repr.dst_addr.is_unicast() {
|
||||
if !ipv4_repr.src_addr.is_unicast() {
|
||||
// Do not send ICMP replies to non-unicast sources
|
||||
Packet::None
|
||||
} else if ipv4_repr.dst_addr.is_unicast() {
|
||||
// Reply as normal when src_addr and dst_addr are both unicast
|
||||
let ipv4_reply_repr = Ipv4Repr {
|
||||
src_addr: ipv4_repr.dst_addr,
|
||||
dst_addr: ipv4_repr.src_addr,
|
||||
|
@ -1251,8 +1257,25 @@ impl<'b, 'c, 'e> InterfaceInner<'b, 'c, 'e> {
|
|||
hop_limit: 64
|
||||
};
|
||||
Packet::Icmpv4((ipv4_reply_repr, icmp_repr))
|
||||
} else if ipv4_repr.dst_addr.is_broadcast() {
|
||||
// Only reply to broadcasts for echo replies and not other ICMP messages
|
||||
match icmp_repr {
|
||||
Icmpv4Repr::EchoReply {..} => match self.ipv4_address() {
|
||||
Some(src_addr) => {
|
||||
let ipv4_reply_repr = Ipv4Repr {
|
||||
src_addr: src_addr,
|
||||
dst_addr: ipv4_repr.src_addr,
|
||||
protocol: IpProtocol::Icmp,
|
||||
payload_len: icmp_repr.buffer_len(),
|
||||
hop_limit: 64
|
||||
};
|
||||
Packet::Icmpv4((ipv4_reply_repr, icmp_repr))
|
||||
},
|
||||
None => Packet::None,
|
||||
},
|
||||
_ => Packet::None,
|
||||
}
|
||||
} else {
|
||||
// Do not send any ICMP replies to a broadcast destination address.
|
||||
Packet::None
|
||||
}
|
||||
}
|
||||
|
@ -2017,6 +2040,64 @@ mod test {
|
|||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "proto-ipv4")]
|
||||
fn test_handle_ipv4_broadcast() {
|
||||
use wire::{Ipv4Packet, Icmpv4Repr, Icmpv4Packet};
|
||||
|
||||
let (mut iface, mut socket_set) = create_loopback();
|
||||
|
||||
let our_ipv4_addr = iface.ipv4_address().unwrap();
|
||||
let src_ipv4_addr = Ipv4Address([127, 0, 0, 2]);
|
||||
|
||||
// ICMPv4 echo request
|
||||
let icmpv4_data: [u8; 4] = [0xaa, 0x00, 0x00, 0xff];
|
||||
let icmpv4_repr = Icmpv4Repr::EchoRequest {
|
||||
ident: 0x1234, seq_no: 0xabcd, data: &icmpv4_data
|
||||
};
|
||||
|
||||
// Send to IPv4 broadcast address
|
||||
let ipv4_repr = Ipv4Repr {
|
||||
src_addr: src_ipv4_addr,
|
||||
dst_addr: Ipv4Address::BROADCAST,
|
||||
protocol: IpProtocol::Icmp,
|
||||
hop_limit: 64,
|
||||
payload_len: icmpv4_repr.buffer_len(),
|
||||
};
|
||||
|
||||
// Emit to ethernet frame
|
||||
let mut eth_bytes = vec![0u8;
|
||||
EthernetFrame::<&[u8]>::header_len() +
|
||||
ipv4_repr.buffer_len() + icmpv4_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());
|
||||
icmpv4_repr.emit(
|
||||
&mut Icmpv4Packet::new_unchecked(
|
||||
&mut frame.payload_mut()[ipv4_repr.buffer_len()..]),
|
||||
&ChecksumCapabilities::default());
|
||||
EthernetFrame::new_unchecked(&*frame.into_inner())
|
||||
};
|
||||
|
||||
// Expected ICMPv4 echo reply
|
||||
let expected_icmpv4_repr = Icmpv4Repr::EchoReply {
|
||||
ident: 0x1234, seq_no: 0xabcd, data: &icmpv4_data };
|
||||
let expected_ipv4_repr = Ipv4Repr {
|
||||
src_addr: our_ipv4_addr,
|
||||
dst_addr: src_ipv4_addr,
|
||||
protocol: IpProtocol::Icmp,
|
||||
hop_limit: 64,
|
||||
payload_len: expected_icmpv4_repr.buffer_len(),
|
||||
};
|
||||
let expected_packet = Packet::Icmpv4((expected_ipv4_repr, expected_icmpv4_repr));
|
||||
|
||||
assert_eq!(iface.inner.process_ipv4(&mut socket_set, Instant::from_millis(0), &frame),
|
||||
Ok(expected_packet));
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "socket-udp")]
|
||||
fn test_icmp_reply_size() {
|
||||
|
|
Loading…
Reference in New Issue