Browse Source

[3546] Initial version of Pkt::getMAC() method implemented.

Tomek Mrugalski 10 years ago
parent
commit
dd1ecaaa20
4 changed files with 123 additions and 1 deletions
  1. 17 0
      src/lib/dhcp/pkt.cc
  2. 53 1
      src/lib/dhcp/pkt.h
  3. 26 0
      src/lib/dhcp/tests/pkt4_unittest.cc
  4. 27 0
      src/lib/dhcp/tests/pkt6_unittest.cc

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

@@ -86,5 +86,22 @@ Pkt::setHWAddrMember(const uint8_t htype, const uint8_t,
     hw_addr.reset(new HWAddr(mac_addr, htype));
 }
 
+HWAddrPtr
+Pkt::getMAC(MACSource from) {
+    HWAddrPtr mac;
+    if (from == MAC_SOURCE_RAW || from == MAC_SOURCE_ANY) {
+        mac = getRemoteHWAddr();
+        if (mac) {
+            return (mac);
+        }
+    }
+
+    /// @todo: add other MAC acquisition methods here
+
+
+    // Ok, none of the methods were suitable. Return NULL.
+    return (HWAddrPtr());
+}
+
 };
 };

+ 53 - 1
src/lib/dhcp/pkt.h

@@ -34,6 +34,49 @@ namespace dhcp {
 /// This class is purely virtual. Please instantiate Pkt4, Pkt6 or any
 /// other derived classes.
 class Pkt {
+public:
+
+    /// @brief specified where did we get this MAC address from?
+    ///
+    /// The list covers all possible MAC sources. The uncommented ones
+    /// are currently supported. When you implement a new method, please
+    /// uncomment appropriate line here.
+    enum MACSource {
+
+        /// Not really a type, only used in getMAC() calls
+        MAC_SOURCE_ANY,
+
+        /// obtained first hand from raw socket (100% reliable)
+        MAC_SOURCE_RAW,
+
+        /// extracted from DUID-LL or DUID-LLT (not reliable as the client
+        /// can send fake DUID)
+        // MAC_SOURCE_DUID,
+
+        /// extracted from IPv6 link-local address. Client can use different
+        /// IID other than EUI-64, e.g. Windows supports RFC4941 and uses
+        /// random values instead of EUI-64.
+        // MAC_SOURCE_IPV6_LINK_LOCAL,
+
+        /// RFC6939 (a relay agent can insert client link layer address option)
+        /// Note that a skilled attacker can fake that by sending his request
+        /// relayed, so the legitimate relay will think it's a second relay.
+        // MAC_SOURCE_CLIENT_ADDR_RELAY_OPTION,
+
+        /// A relay can insert remote-id. In some deployments it contains a MAC
+        /// address.
+        // MAC_SOURCE_REMOTE_ID,
+
+        /// A relay can insert a subscriber-id option. In some deployments it
+        /// contains a MAC address.
+        // MAC_SOURCE_SUBSCRIBER_ID,
+
+        /// A CMTS (acting as DHCP relay agent) that supports DOCSIS standard
+        /// can insert DOCSIS options that contain client's MAC address.
+        /// Client in this context would be a cable modem.
+        // MAC_SOURCE_DOCSIS_OPTIONS
+    };
+
 protected:
 Pkt(uint32_t transid, const isc::asiolink::IOAddress& local_addr,
     const isc::asiolink::IOAddress& remote_addr, uint16_t local_port,
@@ -381,13 +424,22 @@ public:
     void setRemoteHWAddr(const uint8_t htype, const uint8_t hlen,
                          const std::vector<uint8_t>& mac_addr);
 
-    /// @brief Returns the remote HW address.
+    /// @brief Returns the remote HW address obtained from raw sockets.
     ///
     /// @return remote HW address.
     HWAddrPtr getRemoteHWAddr() const {
         return (remote_hwaddr_);
     }
 
+    /// @brief Returns MAC address.
+    ///
+    /// The difference between this method and getRemoteHWAddr() is that
+    /// getRemoteHWAddr() returns only what was obtained from raw sockets.
+    /// This method is more generic and can attempt to obtain MAC from
+    /// varied sources: raw sockets, client-id, link-local IPv6 address,
+    /// and various relay options.
+    HWAddrPtr getMAC(MACSource from);
+
     /// @brief virtual desctructor
     ///
     /// There is nothing to clean up here, but since there are virtual methods,

+ 26 - 0
src/lib/dhcp/tests/pkt4_unittest.cc

@@ -851,4 +851,30 @@ TEST_F(Pkt4Test, clientClasses) {
     EXPECT_TRUE(pkt.inClass("foo"));
 }
 
+// Tests whether MAC can be obtained and that MAC sources are not
+// confused.
+TEST_F(Pkt4Test, getMAC) {
+    Pkt4 pkt(DHCPOFFER, 1234);
+
+    // DHCPv6 packet by default doens't have MAC address specified.
+    EXPECT_FALSE(pkt.getMAC(Pkt::MAC_SOURCE_ANY));
+    EXPECT_FALSE(pkt.getMAC(Pkt::MAC_SOURCE_RAW));
+
+    // Let's invent a MAC
+    const uint8_t hw[] = { 2, 4, 6, 8, 10, 12 }; // MAC
+    const uint8_t hw_type = 123; // hardware type
+    HWAddrPtr dummy_hwaddr(new HWAddr(hw, sizeof(hw), hw_type));
+
+    // Now let's pretend that we obtained it from raw sockets
+    pkt.setRemoteHWAddr(dummy_hwaddr);
+
+    // Now we should be able to get something
+    ASSERT_TRUE(pkt.getMAC(Pkt::MAC_SOURCE_ANY));
+    ASSERT_TRUE(pkt.getMAC(Pkt::MAC_SOURCE_RAW));
+
+    // Check that the returned MAC is indeed the expected one
+    ASSERT_TRUE(*dummy_hwaddr == *pkt.getMAC(Pkt::MAC_SOURCE_ANY));
+    ASSERT_TRUE(*dummy_hwaddr == *pkt.getMAC(Pkt::MAC_SOURCE_RAW));
+}
+
 } // end of anonymous namespace

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

@@ -22,6 +22,7 @@
 #include <dhcp/option_int.h>
 #include <dhcp/option_int_array.h>
 #include <dhcp/pkt6.h>
+#include <dhcp/hwaddr.h>
 #include <dhcp/docsis3_option_defs.h>
 #include <util/range_utilities.h>
 
@@ -810,4 +811,30 @@ TEST_F(Pkt6Test, clientClasses) {
     EXPECT_TRUE(pkt.inClass("foo"));
 }
 
+// Tests whether MAC can be obtained and that MAC sources are not
+// confused.
+TEST_F(Pkt6Test, getMAC) {
+    Pkt6 pkt(DHCPV6_ADVERTISE, 1234);
+
+    // DHCPv6 packet by default doens't have MAC address specified.
+    EXPECT_FALSE(pkt.getMAC(Pkt::MAC_SOURCE_ANY));
+    EXPECT_FALSE(pkt.getMAC(Pkt::MAC_SOURCE_RAW));
+
+    // Let's invent a MAC
+    const uint8_t hw[] = { 2, 4, 6, 8, 10, 12 }; // MAC
+    const uint8_t hw_type = 123; // hardware type
+    HWAddrPtr dummy_hwaddr(new HWAddr(hw, sizeof(hw), hw_type));
+
+    // Now let's pretend that we obtained it from raw sockets
+    pkt.setRemoteHWAddr(dummy_hwaddr);
+
+    // Now we should be able to get something
+    ASSERT_TRUE(pkt.getMAC(Pkt::MAC_SOURCE_ANY));
+    ASSERT_TRUE(pkt.getMAC(Pkt::MAC_SOURCE_RAW));
+
+    // Check that the returned MAC is indeed the expected one
+    ASSERT_TRUE(*dummy_hwaddr == *pkt.getMAC(Pkt::MAC_SOURCE_ANY));
+    ASSERT_TRUE(*dummy_hwaddr == *pkt.getMAC(Pkt::MAC_SOURCE_RAW));
+}
+
 }