浏览代码

iface: add support for sending to subnet-local broadcast addrs (like 192.168.1.255).

Dario Nieuwenhuis 1 年之前
父节点
当前提交
7d78370ded
共有 3 个文件被更改,包括 45 次插入24 次删除
  1. 22 11
      src/iface/interface/mod.rs
  2. 21 11
      src/iface/interface/tests.rs
  3. 2 2
      src/socket/udp.rs

+ 22 - 11
src/iface/interface/mod.rs

@@ -1312,10 +1312,25 @@ impl InterfaceInner {
         handled_by_raw_socket
     }
 
-    /// Checks if an incoming packet has a broadcast address for the interfaces
-    /// associated ipv4 addresses.
+    /// Checks if an address is broadcast, taking into account ipv4 subnet-local
+    /// broadcast addresses.
+    pub(crate) fn is_broadcast(&self, address: &IpAddress) -> bool {
+        match address {
+            #[cfg(feature = "proto-ipv4")]
+            IpAddress::Ipv4(address) => self.is_broadcast_v4(*address),
+            #[cfg(feature = "proto-ipv6")]
+            IpAddress::Ipv6(_) => false,
+        }
+    }
+
+    /// Checks if an address is broadcast, taking into account ipv4 subnet-local
+    /// broadcast addresses.
     #[cfg(feature = "proto-ipv4")]
-    fn is_subnet_broadcast(&self, address: Ipv4Address) -> bool {
+    pub(crate) fn is_broadcast_v4(&self, address: Ipv4Address) -> bool {
+        if address.is_broadcast() {
+            return true;
+        }
+
         self.ip_addrs
             .iter()
             .filter_map(|own_cidr| match own_cidr {
@@ -1326,16 +1341,10 @@ impl InterfaceInner {
             .any(|broadcast_address| address == broadcast_address)
     }
 
-    /// Checks if an ipv4 address is broadcast, taking into account subnet broadcast addresses
-    #[cfg(feature = "proto-ipv4")]
-    fn is_broadcast_v4(&self, address: Ipv4Address) -> bool {
-        address.is_broadcast() || self.is_subnet_broadcast(address)
-    }
-
     /// Checks if an ipv4 address is unicast, taking into account subnet broadcast addresses
     #[cfg(feature = "proto-ipv4")]
     fn is_unicast_v4(&self, address: Ipv4Address) -> bool {
-        address.is_unicast() && !self.is_subnet_broadcast(address)
+        address.is_unicast() && !self.is_broadcast_v4(address)
     }
 
     #[cfg(any(feature = "socket-udp", feature = "socket-dns"))]
@@ -1475,6 +1484,8 @@ impl InterfaceInner {
 
     fn route(&self, addr: &IpAddress, timestamp: Instant) -> Option<IpAddress> {
         // Send directly.
+        // note: no need to use `self.is_broadcast()` to check for subnet-local broadcast addrs
+        //       here because `in_same_network` will already return true.
         if self.in_same_network(addr) || addr.is_broadcast() {
             return Some(*addr);
         }
@@ -1508,7 +1519,7 @@ impl InterfaceInner {
     where
         Tx: TxToken,
     {
-        if dst_addr.is_broadcast() {
+        if self.is_broadcast(dst_addr) {
             let hardware_addr = match self.caps.medium {
                 #[cfg(feature = "medium-ethernet")]
                 Medium::Ethernet => HardwareAddress::Ethernet(EthernetAddress::BROADCAST),

+ 21 - 11
src/iface/interface/tests.rs

@@ -268,46 +268,56 @@ fn test_local_subnet_broadcasts() {
 
     assert!(iface
         .inner
-        .is_subnet_broadcast(Ipv4Address([192, 168, 1, 255])),);
+        .is_broadcast_v4(Ipv4Address([255, 255, 255, 255])));
     assert!(!iface
         .inner
-        .is_subnet_broadcast(Ipv4Address([192, 168, 1, 254])),);
+        .is_broadcast_v4(Ipv4Address([255, 255, 255, 254])));
+    assert!(iface.inner.is_broadcast_v4(Ipv4Address([192, 168, 1, 255])));
+    assert!(!iface.inner.is_broadcast_v4(Ipv4Address([192, 168, 1, 254])));
 
     iface.update_ip_addrs(|addrs| {
         addrs.iter_mut().next().map(|addr| {
             *addr = IpCidr::Ipv4(Ipv4Cidr::new(Ipv4Address([192, 168, 23, 24]), 16));
         });
     });
+    assert!(iface
+        .inner
+        .is_broadcast_v4(Ipv4Address([255, 255, 255, 255])));
+    assert!(!iface
+        .inner
+        .is_broadcast_v4(Ipv4Address([255, 255, 255, 254])));
     assert!(!iface
         .inner
-        .is_subnet_broadcast(Ipv4Address([192, 168, 23, 255])),);
+        .is_broadcast_v4(Ipv4Address([192, 168, 23, 255])));
     assert!(!iface
         .inner
-        .is_subnet_broadcast(Ipv4Address([192, 168, 23, 254])),);
+        .is_broadcast_v4(Ipv4Address([192, 168, 23, 254])));
     assert!(!iface
         .inner
-        .is_subnet_broadcast(Ipv4Address([192, 168, 255, 254])),);
+        .is_broadcast_v4(Ipv4Address([192, 168, 255, 254])));
     assert!(iface
         .inner
-        .is_subnet_broadcast(Ipv4Address([192, 168, 255, 255])),);
+        .is_broadcast_v4(Ipv4Address([192, 168, 255, 255])));
 
     iface.update_ip_addrs(|addrs| {
         addrs.iter_mut().next().map(|addr| {
             *addr = IpCidr::Ipv4(Ipv4Cidr::new(Ipv4Address([192, 168, 23, 24]), 8));
         });
     });
-    assert!(!iface
+    assert!(iface
         .inner
-        .is_subnet_broadcast(Ipv4Address([192, 23, 1, 255])),);
+        .is_broadcast_v4(Ipv4Address([255, 255, 255, 255])));
     assert!(!iface
         .inner
-        .is_subnet_broadcast(Ipv4Address([192, 23, 1, 254])),);
+        .is_broadcast_v4(Ipv4Address([255, 255, 255, 254])));
+    assert!(!iface.inner.is_broadcast_v4(Ipv4Address([192, 23, 1, 255])));
+    assert!(!iface.inner.is_broadcast_v4(Ipv4Address([192, 23, 1, 254])));
     assert!(!iface
         .inner
-        .is_subnet_broadcast(Ipv4Address([192, 255, 255, 254])),);
+        .is_broadcast_v4(Ipv4Address([192, 255, 255, 254])));
     assert!(iface
         .inner
-        .is_subnet_broadcast(Ipv4Address([192, 255, 255, 255])),);
+        .is_broadcast_v4(Ipv4Address([192, 255, 255, 255])));
 }
 
 #[test]

+ 2 - 2
src/socket/udp.rs

@@ -405,13 +405,13 @@ impl<'a> Socket<'a> {
         Ok((length, endpoint))
     }
 
-    pub(crate) fn accepts(&self, _cx: &mut Context, ip_repr: &IpRepr, repr: &UdpRepr) -> bool {
+    pub(crate) fn accepts(&self, cx: &mut Context, ip_repr: &IpRepr, repr: &UdpRepr) -> bool {
         if self.endpoint.port != repr.dst_port {
             return false;
         }
         if self.endpoint.addr.is_some()
             && self.endpoint.addr != Some(ip_repr.dst_addr())
-            && !ip_repr.dst_addr().is_broadcast()
+            && !cx.is_broadcast(&ip_repr.dst_addr())
             && !ip_repr.dst_addr().is_multicast()
         {
             return false;