subnet_broadcasts

Adds `is_subnet_broadcast` to the ethernet interface which checks for
subnet broadcasts, which are discussed on page 8 in
https://tools.ietf.org/html/rfc917. The subnet broadcast addresses are
derived from the interfaces ipv4 addresses.
This commit is contained in:
Scott Mabin 2021-01-16 01:22:16 +00:00
parent db39ffd2ad
commit 47d27472b9
1 changed files with 51 additions and 2 deletions

View File

@ -1023,7 +1023,9 @@ impl<'b, 'c, 'e> InterfaceInner<'b, 'c, 'e> {
if !self.has_ip_addr(ipv4_repr.dst_addr) &&
!ipv4_repr.dst_addr.is_broadcast() &&
!self.has_multicast_group(ipv4_repr.dst_addr) {
!self.has_multicast_group(ipv4_repr.dst_addr) &&
!self.is_subnet_broadcast(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 ||
@ -1066,6 +1068,19 @@ impl<'b, 'c, 'e> InterfaceInner<'b, 'c, 'e> {
}
}
/// Checks if an incoming packet has a broadcast address for the interfaces
/// associated ipv4 addresses.
#[cfg(feature = "proto-ipv4")]
fn is_subnet_broadcast(&self, address: Ipv4Address) -> bool {
self.ip_addrs.iter()
.filter_map(|own_cidr| match own_cidr {
IpCidr::Ipv4(own_ip) => Some(own_ip.broadcast()?),
#[cfg(feature = "proto-ipv6")]
IpCidr::Ipv6(_) => None
})
.any(|broadcast_address| address == broadcast_address)
}
/// Host duties of the **IGMPv2** protocol.
///
/// Sets up `igmp_report_state` for responding to IGMP general/specific membership queries.
@ -1695,7 +1710,7 @@ mod test {
use crate::wire::{EthernetAddress, EthernetFrame, EthernetProtocol};
use crate::wire::{IpAddress, IpCidr, IpProtocol, IpRepr};
#[cfg(feature = "proto-ipv4")]
use crate::wire::{Ipv4Address, Ipv4Repr};
use crate::wire::{Ipv4Address, Ipv4Repr, Ipv4Cidr};
#[cfg(feature = "proto-igmp")]
use crate::wire::Ipv4Packet;
#[cfg(feature = "proto-ipv4")]
@ -1875,6 +1890,40 @@ mod test {
Ok(Some(expected_repr)));
}
#[test]
#[cfg(feature = "proto-ipv4")]
fn test_local_subnet_broadcasts() {
let (mut iface, _) = create_loopback();
iface.update_ip_addrs(|addrs| {
addrs.iter_mut().next().map(|addr| {
*addr = IpCidr::Ipv4(Ipv4Cidr::new(Ipv4Address([192, 168, 1, 23]), 24));
});
});
assert_eq!(iface.inner.is_subnet_broadcast(Ipv4Address([192, 168, 1, 255])), true);
assert_eq!(iface.inner.is_subnet_broadcast(Ipv4Address([192, 168, 1, 254])), false);
iface.update_ip_addrs(|addrs| {
addrs.iter_mut().next().map(|addr| {
*addr = IpCidr::Ipv4(Ipv4Cidr::new(Ipv4Address([192, 168, 23, 24]), 16));
});
});
assert_eq!(iface.inner.is_subnet_broadcast(Ipv4Address([192, 168, 23, 255])), false);
assert_eq!(iface.inner.is_subnet_broadcast(Ipv4Address([192, 168, 23, 254])), false);
assert_eq!(iface.inner.is_subnet_broadcast(Ipv4Address([192, 168, 255, 254])), false);
assert_eq!(iface.inner.is_subnet_broadcast(Ipv4Address([192, 168, 255, 255])), true);
iface.update_ip_addrs(|addrs| {
addrs.iter_mut().next().map(|addr| {
*addr = IpCidr::Ipv4(Ipv4Cidr::new(Ipv4Address([192, 168, 23, 24]), 8));
});
});
assert_eq!(iface.inner.is_subnet_broadcast(Ipv4Address([192, 23, 1, 255])), false);
assert_eq!(iface.inner.is_subnet_broadcast(Ipv4Address([192, 23, 1, 254])), false);
assert_eq!(iface.inner.is_subnet_broadcast(Ipv4Address([192, 255, 255, 254])), false);
assert_eq!(iface.inner.is_subnet_broadcast(Ipv4Address([192, 255, 255, 255])), true);
}
#[test]
#[cfg(all(feature = "socket-udp", feature = "proto-ipv4"))]
fn test_icmp_error_port_unreachable() {