Browse Source

[3552] Patch by Adam Kalmus (with minor clean-ups)

Tomek Mrugalski 10 years ago
parent
commit
7b920501d2
6 changed files with 134 additions and 4 deletions
  1. 10 0
      src/lib/dhcp/pkt.cc
  2. 15 2
      src/lib/dhcp/pkt.h
  3. 11 1
      src/lib/dhcp/pkt4.h
  4. 36 1
      src/lib/dhcp/pkt6.cc
  5. 10 0
      src/lib/dhcp/pkt6.h
  6. 52 0
      src/lib/dhcp/tests/pkt6_unittest.cc

+ 10 - 0
src/lib/dhcp/pkt.cc

@@ -180,6 +180,16 @@ Pkt::getMAC(uint32_t hw_addr_src) {
     }
     }
 
 
     // Method 5: From remote-id option inserted by a relay
     // Method 5: From remote-id option inserted by a relay
+    if(hw_addr_src & HWAddr::HWADDR_SOURCE_REMOTE_ID) {
+        mac = getMACFromRemoteIdRelayOption();
+        if (mac) {
+            return (mac);
+        } else if (hw_addr_src == HWAddr::HWADDR_SOURCE_REMOTE_ID) {
+            // If the only source allowed is remote-id option then we can skip
+            // the other methods.
+            return (HWAddrPtr());
+        }
+    }
 
 
     // Method 6: From subscriber-id option inserted by a relay
     // Method 6: From subscriber-id option inserted by a relay
 
 

+ 15 - 2
src/lib/dhcp/pkt.h

@@ -492,8 +492,7 @@ protected:
     /// @return hardware address (or NULL)
     /// @return hardware address (or NULL)
     virtual HWAddrPtr getMACFromIPv6RelayOpt() = 0;
     virtual HWAddrPtr getMACFromIPv6RelayOpt() = 0;
 
 
-
-    /// @brief Attempts to obtain MAC address from DUID-LL or DUID-LLT
+    /// @brief Attempts to obtain MAC address from DUID-LL or DUID-LLT.
     ///
     ///
     /// This method is called from getMAC(HWADDR_SOURCE_DUID) and should not be
     /// This method is called from getMAC(HWADDR_SOURCE_DUID) and should not be
     /// called directly. It will attempt to extract MAC address information
     /// called directly. It will attempt to extract MAC address information
@@ -507,6 +506,20 @@ protected:
     /// @return hardware address (or NULL)
     /// @return hardware address (or NULL)
     virtual HWAddrPtr getMACFromDUID() = 0;
     virtual HWAddrPtr getMACFromDUID() = 0;
 
 
+    /// @brief Attempts to obtain MAC address from remote-id relay option.
+    ///
+    /// This method is called from getMAC(HWADDR_SOURCE_REMOTE_ID) and should not be
+    /// called directly. It will attempt to extract MAC address information
+    /// from remote-id option inserted by a relay agent closest to the client.
+    /// If this method fails, it will return NULL.
+    ///
+    /// @note This is a pure virtual method and must be implemented in
+    /// the derived classes. The @c Pkt6 class have respective implementation.
+    /// This method is not applicable to DHCPv4.
+    ///
+    /// @return hardware address (or NULL)
+    virtual HWAddrPtr getMACFromRemoteIdRelayOption() = 0;
+
     /// @brief Attempts to convert IPv6 address into MAC.
     /// @brief Attempts to convert IPv6 address into MAC.
     ///
     ///
     /// Utility method that attempts to convert link-local IPv6 address to the
     /// Utility method that attempts to convert link-local IPv6 address to the

+ 11 - 1
src/lib/dhcp/pkt4.h

@@ -1,4 +1,4 @@
-// Copyright (C) 2011-2014 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2011-2015 Internet Systems Consortium, Inc. ("ISC")
 //
 //
 // Permission to use, copy, modify, and/or distribute this software for any
 // Permission to use, copy, modify, and/or distribute this software for any
 // purpose with or without fee is hereby granted, provided that the above
 // purpose with or without fee is hereby granted, provided that the above
@@ -447,6 +447,16 @@ protected:
         return (HWAddrPtr());
         return (HWAddrPtr());
     }
     }
 
 
+    /// @brief No-op
+    ///
+    /// This method returns hardware address extracted from remote-id relay option.
+    /// Currently it is a no-op, it always returns NULL.
+    ///
+    /// @return always NULL
+    virtual HWAddrPtr getMACFromRemoteIdRelayOption(){
+        return(HWAddrPtr());
+    }
+
     /// local HW address (dst if receiving packet, src if sending packet)
     /// local HW address (dst if receiving packet, src if sending packet)
     HWAddrPtr local_hwaddr_;
     HWAddrPtr local_hwaddr_;
 
 

+ 36 - 1
src/lib/dhcp/pkt6.cc

@@ -22,6 +22,7 @@
 #include <util/io_utilities.h>
 #include <util/io_utilities.h>
 #include <exceptions/exceptions.h>
 #include <exceptions/exceptions.h>
 #include <dhcp/duid.h>
 #include <dhcp/duid.h>
+#include <dhcp/iface_mgr.h>
 
 
 #include <iostream>
 #include <iostream>
 #include <sstream>
 #include <sstream>
@@ -615,7 +616,7 @@ Pkt6::getMACFromIPv6RelayOpt() {
     if (opt) {
     if (opt) {
         const OptionBuffer data = opt->getData();
         const OptionBuffer data = opt->getData();
         if (data.size() < 3) {
         if (data.size() < 3) {
-            // This client link address option is trucnated. It's supposed to be
+            // This client link address option is truncated. It's supposed to be
             // 2 bytes of link-layer type followed by link-layer address.
             // 2 bytes of link-layer type followed by link-layer address.
             return (HWAddrPtr());
             return (HWAddrPtr());
         }
         }
@@ -683,5 +684,39 @@ Pkt6::getMACFromDocsisCMTS() {
     }
     }
 }
 }
 
 
+HWAddrPtr
+Pkt6::getMACFromRemoteIdRelayOption() {
+    if (relay_info_.empty()) {
+        // This is a direct message
+        return (HWAddrPtr());
+    }
+
+    // Get remote-id option from a relay agent closest to the client
+    OptionPtr opt = getAnyRelayOption(D6O_REMOTE_ID, RELAY_GET_FIRST);
+    if (opt) {
+        const OptionBuffer data = opt->getData();
+        if (data.size() < 5) {
+            // This remote-id option is truncated. It's supposed to be
+            // 4 bytes of enterprise-number followed by remote-id.
+            return (HWAddrPtr());
+        }
+
+        // Let's get the interface this packet was received on. We need it to get
+        // the hardware type.
+        Iface* iface = IfaceMgr::instance().getIface(iface_);
+        uint16_t hwtype = 0; // not specified
+
+        // If we get the interface HW type, great! If not, let's not panic.
+        if (iface) {
+            hwtype = iface->getHWType();
+        }
+
+        // Skip the initial 4 bytes which are enterprise-number.
+        return (HWAddrPtr(new HWAddr(&data[0] + 4, data.size() - 4, hwtype)));
+    } else {
+        return (HWAddrPtr());
+    }
+}
+
 } // end of isc::dhcp namespace
 } // end of isc::dhcp namespace
 } // end of isc namespace
 } // end of isc namespace

+ 10 - 0
src/lib/dhcp/pkt6.h

@@ -342,6 +342,16 @@ protected:
     /// @return hardware address (if DOCSIS suboption 1026 is present)
     /// @return hardware address (if DOCSIS suboption 1026 is present)
     virtual HWAddrPtr getMACFromDocsisCMTS();
     virtual HWAddrPtr getMACFromDocsisCMTS();
 
 
+    /// @brief Attempts to obtain MAC address from remote-id relay option.
+    ///
+    /// This method is called from getMAC(HWADDR_SOURCE_REMOTE_ID) and should not be
+    /// called directly. It will attempt to extract MAC address information
+    /// from remote-id option inserted by a relay agent closest to the client.
+    /// If this method fails, it will return NULL.
+    ///
+    /// @return hardware address (or NULL)
+    virtual HWAddrPtr getMACFromRemoteIdRelayOption();
+
     /// @brief Builds on wire packet for TCP transmission.
     /// @brief Builds on wire packet for TCP transmission.
     ///
     ///
     /// @todo This function is not implemented yet.
     /// @todo This function is not implemented yet.

+ 52 - 0
src/lib/dhcp/tests/pkt6_unittest.cc

@@ -1242,4 +1242,56 @@ TEST_F(Pkt6Test, getMAC_DOCSIS_CMTS) {
     EXPECT_FALSE(pkt->getMAC(HWAddr::HWADDR_SOURCE_DOCSIS_CMTS));
     EXPECT_FALSE(pkt->getMAC(HWAddr::HWADDR_SOURCE_DOCSIS_CMTS));
 }
 }
 
 
+// Test checks whether getMACFromRemoteIdRelayOption() returns the hardware (MAC)
+// address properly from a relayed message.
+TEST_F(Pkt6Test, getMACFromRemoteIdRelayOption) {
+
+    // Create a solicit message.
+    Pkt6 pkt(DHCPV6_SOLICIT, 1234);
+
+    // This should fail as the message is't relayed yet.
+    EXPECT_FALSE(pkt.getMAC(HWAddr::HWADDR_SOURCE_REMOTE_ID));
+
+    // Let's get the first interface
+    Iface* iface = IfaceMgr::instance().getIface(1);
+    ASSERT_TRUE(iface);
+
+    // and set source interface data properly. getMACFromIPv6LinkLocal attempts
+    // to use source interface to obtain hardware type
+    pkt.setIface(iface->getName());
+    pkt.setIndex(iface->getIndex());
+
+    // Generate option data with randomly picked enterprise number and MAC address
+    const uint8_t opt_data[] = {
+        1, 2, 3, 4,  // enterprise-number
+        0xa, 0xb, 0xc, 0xd, 0xe, 0xf // MAC
+    };
+
+    // Create option with number 37 (remote-id relay agent option)
+    OptionPtr relay_opt(new Option(Option::V6, D6O_REMOTE_ID,
+                        OptionBuffer(opt_data, opt_data + sizeof(opt_data))));
+
+    // First simulate relaying message without adding remote-id option
+    Pkt6::RelayInfo info;
+    pkt.addRelayInfo(info);
+    ASSERT_EQ(1, pkt.relay_info_.size());
+
+    // This should fail as the remote-id option isn't there
+    EXPECT_FALSE(pkt.getMAC(HWAddr::HWADDR_SOURCE_REMOTE_ID));
+
+    // Now add this option to the relayed message
+    info.options_.insert(make_pair(relay_opt->getType(), relay_opt));
+    pkt.addRelayInfo(info);
+    ASSERT_EQ(2, pkt.relay_info_.size());
+
+    // This should work now
+    HWAddrPtr mac = pkt.getMAC(HWAddr::HWADDR_SOURCE_REMOTE_ID);
+    ASSERT_TRUE(mac);
+
+    stringstream tmp;
+    tmp << "hwtype=" << (int)iface->getHWType() << " 0a:0b:0c:0d:0e:0f";
+
+    EXPECT_EQ(tmp.str(), mac->toText(true));
+}
+
 }
 }