Browse Source

Don't put non-unicast (IP or Ethernet) addresses into ARP cache.

Thanks @little-dude for pointing this out--it's probably a DoS bug.
whitequark 8 years ago
parent
commit
15cf0cc56e
3 changed files with 21 additions and 3 deletions
  1. 3 0
      src/iface/arp_cache.rs
  2. 12 3
      src/iface/ethernet.rs
  3. 6 0
      src/wire/ethernet.rs

+ 3 - 0
src/iface/arp_cache.rs

@@ -95,6 +95,9 @@ impl<'a> SliceCache<'a> {
 
 impl<'a> Cache for SliceCache<'a> {
     fn fill(&mut self, protocol_addr: &IpAddress, hardware_addr: &EthernetAddress) {
+        debug_assert!(protocol_addr.is_unicast());
+        debug_assert!(hardware_addr.is_unicast());
+
         if let None = self.find(protocol_addr) {
             let lru_index = self.lru();
 

+ 12 - 3
src/iface/ethernet.rs

@@ -137,7 +137,10 @@ impl<'a, 'b, 'c, DeviceT: Device + 'a> Interface<'a, 'b, 'c, DeviceT> {
                         source_hardware_addr, source_protocol_addr,
                         target_protocol_addr, ..
                     } => {
-                        self.arp_cache.fill(&source_protocol_addr.into(), &source_hardware_addr);
+                        if source_protocol_addr.is_unicast() && source_hardware_addr.is_unicast() {
+                            self.arp_cache.fill(&source_protocol_addr.into(),
+                                                &source_hardware_addr);
+                        }
 
                         if self.has_protocol_addr(target_protocol_addr) {
                             response = Response::Arp(ArpRepr::EthernetIpv4 {
@@ -155,7 +158,10 @@ impl<'a, 'b, 'c, DeviceT: Device + 'a> Interface<'a, 'b, 'c, DeviceT> {
                         operation: ArpOperation::Reply,
                         source_hardware_addr, source_protocol_addr, ..
                     } => {
-                         self.arp_cache.fill(&source_protocol_addr.into(), &source_hardware_addr)
+                        if source_protocol_addr.is_unicast() && source_hardware_addr.is_unicast() {
+                            self.arp_cache.fill(&source_protocol_addr.into(),
+                                                &source_hardware_addr);
+                        }
                     },
 
                     _ => return Err(Error::Unrecognized)
@@ -168,7 +174,10 @@ impl<'a, 'b, 'c, DeviceT: Device + 'a> Interface<'a, 'b, 'c, DeviceT> {
                 let ipv4_repr = try!(Ipv4Repr::parse(&ipv4_packet));
 
                 // Fill the ARP cache from IP header.
-                self.arp_cache.fill(&IpAddress::Ipv4(ipv4_repr.src_addr), &eth_frame.src_addr());
+                if ipv4_repr.src_addr.is_unicast() && eth_frame.src_addr().is_unicast() {
+                    self.arp_cache.fill(&IpAddress::Ipv4(ipv4_repr.src_addr),
+                                        &eth_frame.src_addr());
+                }
 
                 match ipv4_repr {
                     // Ignore IP packets not directed at us.

+ 6 - 0
src/wire/ethernet.rs

@@ -45,6 +45,12 @@ impl Address {
         &self.0
     }
 
+    /// Query whether the address is an unicast address.
+    pub fn is_unicast(&self) -> bool {
+        !(self.is_broadcast() ||
+          self.is_multicast())
+    }
+
     /// Query whether this address is the broadcast address.
     pub fn is_broadcast(&self) -> bool {
         self.0 == [0xff; 6]