Sfoglia il codice sorgente

Merge pull request #900 from thvdveld/ipv6-any-ip

fix: accept any ip for IPv6
Thibaut Vandervelden 10 mesi fa
parent
commit
ef67e7b46c
3 ha cambiato i file con 86 aggiunte e 12 eliminazioni
  1. 11 2
      src/iface/interface/ipv6.rs
  2. 1 10
      src/iface/interface/mod.rs
  3. 74 0
      src/iface/interface/tests/ipv6.rs

+ 11 - 2
src/iface/interface/ipv6.rs

@@ -210,8 +210,17 @@ impl InterfaceInner {
             && !self.has_multicast_group(ipv6_repr.dst_addr)
             && !ipv6_repr.dst_addr.is_loopback()
         {
-            net_trace!("packet IP address not for this interface");
-            return None;
+            // If AnyIP is enabled, also check if the packet is routed locally.
+            if !self.any_ip
+                || !ipv6_repr.dst_addr.is_unicast()
+                || self
+                    .routes
+                    .lookup(&IpAddress::Ipv6(ipv6_repr.dst_addr), self.now)
+                    .map_or(true, |router_addr| !self.has_ip_addr(router_addr))
+            {
+                net_trace!("packet IP address not for this interface");
+                return None;
+            }
         }
 
         #[cfg(feature = "socket-raw")]

+ 1 - 10
src/iface/interface/mod.rs

@@ -109,7 +109,6 @@ pub struct InterfaceInner {
     #[cfg(feature = "proto-sixlowpan-fragmentation")]
     tag: u16,
     ip_addrs: Vec<IpCidr, IFACE_MAX_ADDR_COUNT>,
-    #[cfg(feature = "proto-ipv4")]
     any_ip: bool,
     routes: Routes,
     #[cfg(feature = "proto-igmp")]
@@ -223,7 +222,6 @@ impl Interface {
                 caps,
                 hardware_addr: config.hardware_addr,
                 ip_addrs: Vec::new(),
-                #[cfg(feature = "proto-ipv4")]
                 any_ip: false,
                 routes: Routes::new(),
                 #[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))]
@@ -362,16 +360,10 @@ impl Interface {
     /// Enable or disable the AnyIP capability.
     ///
     /// AnyIP allowins packets to be received
-    /// locally on IPv4 addresses other than the interface's configured [ip_addrs].
+    /// locally on IP addresses other than the interface's configured [ip_addrs].
     /// When AnyIP is enabled and a route prefix in [`routes`](Self::routes) specifies one of
     /// the interface's [`ip_addrs`](Self::ip_addrs) as its gateway, the interface will accept
     /// packets addressed to that prefix.
-    ///
-    /// # IPv6
-    ///
-    /// This option is not available or required for IPv6 as packets sent to
-    /// the interface are not filtered by IPv6 address.
-    #[cfg(feature = "proto-ipv4")]
     pub fn set_any_ip(&mut self, any_ip: bool) {
         self.inner.any_ip = any_ip;
     }
@@ -379,7 +371,6 @@ impl Interface {
     /// Get whether AnyIP is enabled.
     ///
     /// See [`set_any_ip`](Self::set_any_ip) for details on AnyIP
-    #[cfg(feature = "proto-ipv4")]
     pub fn any_ip(&self) -> bool {
         self.inner.any_ip
     }

+ 74 - 0
src/iface/interface/tests/ipv6.rs

@@ -29,6 +29,80 @@ fn parse_ipv6(data: &[u8]) -> crate::wire::Result<Packet<'_>> {
     }
 }
 
+#[rstest]
+#[case::ip(Medium::Ip)]
+#[cfg(feature = "medium-ip")]
+#[case::ethernet(Medium::Ethernet)]
+#[cfg(feature = "medium-ethernet")]
+#[case::ieee802154(Medium::Ieee802154)]
+#[cfg(feature = "medium-ieee802154")]
+fn any_ip(#[case] medium: Medium) {
+    // An empty echo request with destination address fdbe::3, which is not part of the interface
+    // address list.
+    let data = [
+        0x60, 0x0, 0x0, 0x0, 0x0, 0x8, 0x3a, 0x40, 0xfd, 0xbe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+        0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0xfd, 0xbe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+        0x0, 0x0, 0x0, 0x0, 0x3, 0x80, 0x0, 0x84, 0x3a, 0x0, 0x0, 0x0, 0x0,
+    ];
+
+    assert_eq!(
+        parse_ipv6(&data),
+        Ok(Packet::new_ipv6(
+            Ipv6Repr {
+                src_addr: Ipv6Address::from_parts(&[0xfdbe, 0, 0, 0, 0, 0, 0, 0x0002]),
+                dst_addr: Ipv6Address::from_parts(&[0xfdbe, 0, 0, 0, 0, 0, 0, 0x0003]),
+                hop_limit: 64,
+                next_header: IpProtocol::Icmpv6,
+                payload_len: 8,
+            },
+            IpPayload::Icmpv6(Icmpv6Repr::EchoRequest {
+                ident: 0,
+                seq_no: 0,
+                data: b"",
+            })
+        ))
+    );
+
+    let (mut iface, mut sockets, _device) = setup(medium);
+
+    // Add a route to the interface, otherwise, we don't know if the packet is routed localy.
+    iface.routes_mut().update(|routes| {
+        routes
+            .push(crate::iface::Route {
+                cidr: IpCidr::Ipv6(Ipv6Cidr::new(
+                    Ipv6Address::new(0xfdbe, 0, 0, 0, 0, 0, 0, 0),
+                    64,
+                )),
+                via_router: IpAddress::Ipv6(Ipv6Address::from_parts(&[
+                    0xfdbe, 0, 0, 0, 0, 0, 0, 0x0001,
+                ])),
+                preferred_until: None,
+                expires_at: None,
+            })
+            .unwrap();
+    });
+
+    assert_eq!(
+        iface.inner.process_ipv6(
+            &mut sockets,
+            PacketMeta::default(),
+            &Ipv6Packet::new_checked(&data[..]).unwrap()
+        ),
+        None
+    );
+
+    // Accept any IP:
+    iface.set_any_ip(true);
+    assert!(iface
+        .inner
+        .process_ipv6(
+            &mut sockets,
+            PacketMeta::default(),
+            &Ipv6Packet::new_checked(&data[..]).unwrap()
+        )
+        .is_some());
+}
+
 #[rstest]
 #[case::ip(Medium::Ip)]
 #[cfg(feature = "medium-ip")]