Parcourir la source

[master] Pk6 MAC extraction code now populates HwAddr::source_

    Merges in branch 'trac4247'
Thomas Markwalder il y a 9 ans
Parent
commit
27886dadcf
3 fichiers modifiés avec 165 ajouts et 144 suppressions
  1. 37 38
      src/lib/dhcp/pkt.cc
  2. 99 99
      src/lib/dhcp/pkt6.cc
  3. 29 7
      src/lib/dhcp/tests/pkt6_unittest.cc

+ 37 - 38
src/lib/dhcp/pkt.cc

@@ -140,6 +140,7 @@ Pkt::getMAC(uint32_t hw_addr_src) {
     if (hw_addr_src & HWAddr::HWADDR_SOURCE_RAW) {
         mac = getRemoteHWAddr();
         if (mac) {
+            mac->source_ = HWAddr::HWADDR_SOURCE_RAW;
             return (mac);
         } else if (hw_addr_src == HWAddr::HWADDR_SOURCE_RAW) {
             // If we're interested only in RAW sockets as source of that info,
@@ -228,47 +229,45 @@ Pkt::getMAC(uint32_t hw_addr_src) {
 
 HWAddrPtr
 Pkt::getMACFromIPv6(const isc::asiolink::IOAddress& addr) {
+    HWAddrPtr mac;
 
-    if (!addr.isV6LinkLocal()) {
-        return (HWAddrPtr());
-    }
-
-    std::vector<uint8_t> bin = addr.toBytes();
-
-    // Double check that it's of appropriate size
-    if ((bin.size() != isc::asiolink::V6ADDRESS_LEN) ||
-
-        // Check that it's link-local (starts with fe80).
-        (bin[0] != 0xfe) || (bin[1] != 0x80) ||
-
-        // Check that u bit is set and g is clear. See Section 2.5.1 of RFC2373
-        // for details.
-        ((bin[8] & 3) != 2) ||
-
-        // And that the IID is of EUI-64 type.
-        (bin[11] != 0xff) || (bin[12] != 0xfe)) {
-        return (HWAddrPtr());
-    }
-
-    // Remove 8 most significant bytes
-    bin.erase(bin.begin(), bin.begin() + 8);
-
-    // Ok, we're down to EUI-64 only now: XX:XX:XX:ff:fe:XX:XX:XX
-    bin.erase(bin.begin() + 3, bin.begin() + 5);
-
-    // MAC-48 to EUI-64 involves inverting u bit (see explanation in Section
-    // 2.5.1 of RFC2373). We need to revert that.
-    bin[0] = bin[0] ^ 2;
-
-    // Let's get the interface this packet was received on. We need it to get
-    // hardware type
-    IfacePtr iface = IfaceMgr::instance().getIface(iface_);
-    uint16_t hwtype = 0; // not specified
-    if (iface) {
-        hwtype = iface->getHWType();
+    if (addr.isV6LinkLocal()) {
+        std::vector<uint8_t> bin = addr.toBytes();
+
+        // Double check that it's of appropriate size
+        if ((bin.size() == isc::asiolink::V6ADDRESS_LEN) &&
+            // Check that it's link-local (starts with fe80).
+            (bin[0] == 0xfe) && (bin[1] == 0x80) &&
+            // Check that u bit is set and g is clear.
+            // See Section 2.5.1 of RFC2373 for details.
+            ((bin[8] & 3) == 2) &&
+            // And that the IID is of EUI-64 type.
+            (bin[11] == 0xff) && (bin[12] == 0xfe)) {
+
+                // Remove 8 most significant bytes
+                bin.erase(bin.begin(), bin.begin() + 8);
+
+                // Ok, we're down to EUI-64 only now: XX:XX:XX:ff:fe:XX:XX:XX
+                bin.erase(bin.begin() + 3, bin.begin() + 5);
+
+                // MAC-48 to EUI-64 involves inverting u bit (see explanation
+                // in Section 2.5.1 of RFC2373). We need to revert that.
+                bin[0] = bin[0] ^ 2;
+
+                // Let's get the interface this packet was received on.
+                // We need it to get hardware type
+                IfacePtr iface = IfaceMgr::instance().getIface(iface_);
+                uint16_t hwtype = 0; // not specified
+                if (iface) {
+                    hwtype = iface->getHWType();
+                }
+
+            mac.reset(new HWAddr(bin, hwtype));
+            mac->source_ = HWAddr::HWADDR_SOURCE_IPV6_LINK_LOCAL;
+        }
     }
 
-    return (HWAddrPtr(new HWAddr(bin, hwtype)));
+    return (mac);
 }
 
 };

+ 99 - 99
src/lib/dhcp/pkt6.cc

@@ -453,9 +453,10 @@ Pkt6::unpackTCP() {
 
 HWAddrPtr
 Pkt6::getMACFromDUID() {
+    HWAddrPtr mac;
     OptionPtr opt_duid = getOption(D6O_CLIENTID);
     if (!opt_duid) {
-        return (HWAddrPtr());
+        return (mac);
     }
 
     uint8_t hlen = opt_duid->getData().size();
@@ -470,31 +471,33 @@ Pkt6::getMACFromDUID() {
     {
         // 2 bytes of duid type, 2 bytes of hardware type and at least
         // 1 byte of actual identification
-        if (duid_data.size() < 5) {
-            // This duid is truncated. We can't extract anything from it.
-            return (HWAddrPtr());
+        if (duid_data.size() >= 5) {
+            uint16_t hwtype = util::readUint16(&duid_data[2],
+                                               duid_data.size() - 2);
+            mac.reset(new HWAddr(&duid_data[4], duid_data.size() - 4, hwtype));
         }
-
-        uint16_t hwtype = util::readUint16(&duid_data[2], duid_data.size() - 2);
-        return (HWAddrPtr(new HWAddr(&duid_data[4], duid_data.size() - 4,
-                                     hwtype)));
+        break;
     }
     case DUID::DUID_LLT:
     {
         // 2 bytes of duid type, 2 bytes of hardware, 4 bytes for timestamp,
         // and at least 1 byte of actual identification
-        if (duid_data.size() < 9) {
-            // This duid is truncated. We can't extract anything from it.
-            return (HWAddrPtr());
+        if (duid_data.size() >= 9) {
+            uint16_t hwtype = util::readUint16(&duid_data[2],
+                                               duid_data.size() - 2);
+            mac.reset(new HWAddr(&duid_data[8], duid_data.size() - 8, hwtype));
         }
-
-        uint16_t hwtype = util::readUint16(&duid_data[2], duid_data.size() - 2);
-        return (HWAddrPtr(new HWAddr(&duid_data[8], duid_data.size() - 8,
-                                     hwtype)));
+        break;
     }
     default:
-        return (HWAddrPtr());
+        break;
     }
+
+    if (mac) {
+        mac->source_ = HWAddr::HWADDR_SOURCE_DUID;
+    }
+
+    return (mac);
 }
 
 std::string
@@ -705,116 +708,113 @@ Pkt6::getMACFromSrcLinkLocalAddr() {
 
 HWAddrPtr
 Pkt6::getMACFromIPv6RelayOpt() {
-    if (relay_info_.empty()) {
-        // This is a direct message
-        return (HWAddrPtr());
-    }
-    // RFC6969 Section 6: Look for the client_linklayer_addr option on the
-    // relay agent closest to the client
-    OptionPtr opt = getAnyRelayOption(D6O_CLIENT_LINKLAYER_ADDR, RELAY_GET_FIRST);
-    if (opt) {
-        const OptionBuffer data = opt->getData();
-        if (data.size() < 3) {
-            // This client link address option is truncated. It's supposed to be
+    HWAddrPtr mac;
+
+    // This is not a direct message
+    if (!relay_info_.empty()) {
+        // RFC6969 Section 6: Look for the client_linklayer_addr option on the
+        // relay agent closest to the client
+        OptionPtr opt = getAnyRelayOption(D6O_CLIENT_LINKLAYER_ADDR,
+                                          RELAY_GET_FIRST);
+        if (opt) {
+            const OptionBuffer data = opt->getData();
+            // This client link address option is supposed to be
             // 2 bytes of link-layer type followed by link-layer address.
-            return (HWAddrPtr());
-        }
+            if (data.size() >= 3) {
+                // +2, -2 means to skip the initial 2 bytes which are
+                // hwaddress type
+                mac.reset(new HWAddr(&data[0] + 2, data.size() - 2,
+                          opt->getUint16()));
 
-        // +2, -2 means to skip the initial 2 bytes which are hwaddress type
-        return (HWAddrPtr(new HWAddr(&data[0] + 2, data.size() - 2,
-                                     opt->getUint16())));
-    } else {
-        return (HWAddrPtr());
+                mac->source_ = HWAddr::HWADDR_SOURCE_CLIENT_ADDR_RELAY_OPTION;
+            }
+        }
     }
+
+    return mac;
 }
 
 HWAddrPtr
 Pkt6::getMACFromDocsisModem() {
+    HWAddrPtr mac;
     OptionVendorPtr vendor = boost::dynamic_pointer_cast<
         OptionVendor>(getOption(D6O_VENDOR_OPTS));
 
     // Check if this is indeed DOCSIS3 environment
-    if (!vendor || vendor->getVendorId() != VENDOR_ID_CABLE_LABS) {
-        return (HWAddrPtr());
-    }
-
-    // If it is, try to get device-id option
-    OptionPtr device_id = vendor->getOption(DOCSIS3_V6_DEVICE_ID);
-    if (!device_id) {
-        return (HWAddrPtr());
+    if (vendor && vendor->getVendorId() == VENDOR_ID_CABLE_LABS) {
+        // If it is, try to get device-id option
+        OptionPtr device_id = vendor->getOption(DOCSIS3_V6_DEVICE_ID);
+        if (device_id) {
+            // If the option contains any data, use it as MAC address
+            if (!device_id->getData().empty()) {
+                mac.reset(new HWAddr(device_id->getData(), HTYPE_DOCSIS));
+                mac->source_ = HWAddr::HWADDR_SOURCE_DOCSIS_MODEM;
+            }
+        }
     }
 
-    // If the option contains any data, use it as MAC address
-    if (!device_id->getData().empty()) {
-        return (HWAddrPtr(new HWAddr(device_id->getData(), HTYPE_DOCSIS)));
-    } else {
-        return (HWAddrPtr());
-    }
+    return mac;
 }
 
 HWAddrPtr
 Pkt6::getMACFromDocsisCMTS() {
-    if (relay_info_.empty()) {
-        // This message didn't pass through a CMTS, so there won't be any
-        // CMTS-specific options in it.
-        return (HWAddrPtr());
-    }
-
-    OptionVendorPtr vendor = boost::dynamic_pointer_cast<
-        OptionVendor>(getAnyRelayOption(D6O_VENDOR_OPTS,
-                                        RELAY_SEARCH_FROM_CLIENT));
-
-    // Check if this is indeed DOCSIS3 environment
-    if (!vendor || vendor->getVendorId() != VENDOR_ID_CABLE_LABS) {
-        return (HWAddrPtr());
-    }
-
-    // If it is, try to get cable modem mac
-    OptionPtr cm_mac = vendor->getOption(DOCSIS3_V6_CMTS_CM_MAC);
-    if (!cm_mac) {
-        return (HWAddrPtr());
+    HWAddrPtr mac;
+
+    // If the message passed through a CMTS, there'll
+    // CMTS-specific options in it.
+    if (!relay_info_.empty()) {
+        OptionVendorPtr vendor = boost::dynamic_pointer_cast<
+            OptionVendor>(getAnyRelayOption(D6O_VENDOR_OPTS,
+                                            RELAY_SEARCH_FROM_CLIENT));
+
+        // Check if this is indeed DOCSIS3 environment
+        if (vendor && vendor->getVendorId() == VENDOR_ID_CABLE_LABS) {
+            // Try to get cable modem mac
+            OptionPtr cm_mac = vendor->getOption(DOCSIS3_V6_CMTS_CM_MAC);
+
+            // If the option contains any data, use it as MAC address
+            if (cm_mac && !cm_mac->getData().empty()) {
+                mac.reset(new HWAddr(cm_mac->getData(), HTYPE_DOCSIS));
+                mac->source_ = HWAddr::HWADDR_SOURCE_DOCSIS_CMTS;
+            }
+        }
     }
 
-    // If the option contains any data, use it as MAC address
-    if (!cm_mac->getData().empty()) {
-        return (HWAddrPtr(new HWAddr(cm_mac->getData(), HTYPE_DOCSIS)));
-    } else {
-        return (HWAddrPtr());
-    }
+    return (mac);
 }
 
 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());
-        }
+    HWAddrPtr mac;
 
-        // Let's get the interface this packet was received on. We need it to get
-        // the hardware type.
-        IfacePtr iface = IfaceMgr::instance().getIface(iface_);
-        uint16_t hwtype = 0; // not specified
+    // If this is relayed message
+    if (!relay_info_.empty()) {
+        // 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();
+            // This remote-id option is supposed to be 4 bytes of
+            // of enterprise-number followed by remote-id.
+            if (data.size() >= 5) {
+                // Let's get the interface this packet was received on.
+                // We need it to get the hardware type.
+                IfacePtr 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();
+                }
 
-        // 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.
+                mac.reset(new HWAddr(&data[0] + 4, data.size() - 4, hwtype));
+                mac->source_ = HWAddr::HWADDR_SOURCE_REMOTE_ID;
+            }
         }
-
-        // Skip the initial 4 bytes which are enterprise-number.
-        return (HWAddrPtr(new HWAddr(&data[0] + 4, data.size() - 4, hwtype)));
-    } else {
-        return (HWAddrPtr());
     }
+
+    return (mac);
 }
 
 } // end of isc::dhcp namespace

+ 29 - 7
src/lib/dhcp/tests/pkt6_unittest.cc

@@ -406,7 +406,7 @@ TEST_F(Pkt6Test, unpackVendorMalformed) {
     orig.push_back(3);
     orig.push_back(4);
     orig.push_back(1); // suboption type=0x101
-    orig.push_back(1); 
+    orig.push_back(1);
     orig.push_back(0); // suboption length=3
     orig.push_back(3);
     orig.push_back(102); // data="foo"
@@ -428,7 +428,7 @@ TEST_F(Pkt6Test, unpackVendorMalformed) {
     shortv[len_index] = 20;
     Pkt6Ptr too_short_vendor_pkt(new Pkt6(&shortv[0], shortv.size()));
     EXPECT_NO_THROW(too_short_vendor_pkt->unpack());
-    
+
     // Truncated option header is not accepted
     vector<uint8_t> shorth = orig;
     shorth.resize(orig.size() - 4);
@@ -996,10 +996,17 @@ TEST_F(Pkt6Test, getMAC) {
     // Let's check if setting IPv6 address improves the situation.
     IOAddress linklocal_eui64("fe80::204:06ff:fe08:0a0c");
     pkt.setRemoteAddr(linklocal_eui64);
-    EXPECT_TRUE(pkt.getMAC(HWAddr::HWADDR_SOURCE_ANY));
-    EXPECT_TRUE(pkt.getMAC(HWAddr::HWADDR_SOURCE_IPV6_LINK_LOCAL));
-    EXPECT_TRUE(pkt.getMAC(HWAddr::HWADDR_SOURCE_IPV6_LINK_LOCAL |
-                           HWAddr::HWADDR_SOURCE_RAW));
+    HWAddrPtr mac;
+    ASSERT_TRUE(mac = pkt.getMAC(HWAddr::HWADDR_SOURCE_ANY));
+    EXPECT_EQ(HWAddr::HWADDR_SOURCE_IPV6_LINK_LOCAL, mac->source_);
+
+    ASSERT_TRUE(mac = pkt.getMAC(HWAddr::HWADDR_SOURCE_IPV6_LINK_LOCAL));
+    EXPECT_EQ(HWAddr::HWADDR_SOURCE_IPV6_LINK_LOCAL, mac->source_);
+
+    ASSERT_TRUE(mac = pkt.getMAC(HWAddr::HWADDR_SOURCE_IPV6_LINK_LOCAL |
+                                 HWAddr::HWADDR_SOURCE_RAW));
+    EXPECT_EQ(HWAddr::HWADDR_SOURCE_IPV6_LINK_LOCAL, mac->source_);
+
     pkt.setRemoteAddr(IOAddress("::"));
 
     // Let's invent a MAC
@@ -1011,10 +1018,15 @@ TEST_F(Pkt6Test, getMAC) {
     pkt.setRemoteHWAddr(dummy_hwaddr);
 
     // Now we should be able to get something
-    ASSERT_TRUE(pkt.getMAC(HWAddr::HWADDR_SOURCE_ANY));
+    ASSERT_TRUE(mac = pkt.getMAC(HWAddr::HWADDR_SOURCE_ANY));
+    EXPECT_EQ(HWAddr::HWADDR_SOURCE_RAW, mac->source_);
+
     ASSERT_TRUE(pkt.getMAC(HWAddr::HWADDR_SOURCE_RAW));
+    EXPECT_EQ(HWAddr::HWADDR_SOURCE_RAW, mac->source_);
+
     EXPECT_TRUE(pkt.getMAC(HWAddr::HWADDR_SOURCE_IPV6_LINK_LOCAL |
                            HWAddr::HWADDR_SOURCE_RAW));
+    EXPECT_EQ(HWAddr::HWADDR_SOURCE_RAW, mac->source_);
 
     // Check that the returned MAC is indeed the expected one
     ASSERT_TRUE(*dummy_hwaddr == *pkt.getMAC(HWAddr::HWADDR_SOURCE_ANY));
@@ -1050,6 +1062,7 @@ TEST_F(Pkt6Test, getMACFromIPv6LinkLocal_direct) {
     pkt.setRemoteAddr(linklocal_eui64);
     HWAddrPtr found = pkt.getMAC(HWAddr::HWADDR_SOURCE_IPV6_LINK_LOCAL);
     ASSERT_TRUE(found);
+    EXPECT_EQ(HWAddr::HWADDR_SOURCE_IPV6_LINK_LOCAL, found->source_);
 
     stringstream tmp;
     tmp << "hwtype=" << (int)iface->getHWType() << " f0:04:06:08:0a:0c";
@@ -1097,6 +1110,7 @@ TEST_F(Pkt6Test, getMACFromIPv6LinkLocal_singleRelay) {
     stringstream tmp;
     tmp << "hwtype=" << (int)iface->getHWType() << " f0:04:06:08:0a:0c";
     EXPECT_EQ(tmp.str(), found->toText(true));
+    EXPECT_EQ(HWAddr::HWADDR_SOURCE_IPV6_LINK_LOCAL, found->source_);
 }
 
 // Test checks whether getMACFromIPv6LinkLocal() returns the hardware (MAC)
@@ -1151,6 +1165,7 @@ TEST_F(Pkt6Test, getMACFromIPv6LinkLocal_multiRelay) {
     stringstream tmp;
     tmp << "hwtype=" << iface->getHWType() << " 00:00:00:00:00:01";
     EXPECT_EQ(tmp.str(), found->toText(true));
+    EXPECT_EQ(HWAddr::HWADDR_SOURCE_IPV6_LINK_LOCAL, found->source_);
 }
 
 // Test checks whether getMACFromIPv6RelayOpt() returns the hardware (MAC)
@@ -1184,6 +1199,7 @@ TEST_F(Pkt6Test, getMACFromIPv6RelayOpt_singleRelay) {
     stringstream tmp;
     tmp << "hwtype=1 0a:1b:0b:01:ca:fe";
     EXPECT_EQ(tmp.str(), found->toText(true));
+    EXPECT_EQ(HWAddr::HWADDR_SOURCE_CLIENT_ADDR_RELAY_OPTION, found->source_);
 }
 
 // Test checks whether getMACFromIPv6RelayOpt() returns the hardware (MAC)
@@ -1232,6 +1248,7 @@ TEST_F(Pkt6Test, getMACFromIPv6RelayOpt_multipleRelay) {
     stringstream tmp;
     tmp << "hwtype=1 fa:30:0b:fa:c0:fe";
     EXPECT_EQ(tmp.str(), found->toText(true));
+    EXPECT_EQ(HWAddr::HWADDR_SOURCE_CLIENT_ADDR_RELAY_OPTION,found->source_);
 }
 
 TEST_F(Pkt6Test, getMACFromDUID) {
@@ -1271,6 +1288,7 @@ TEST_F(Pkt6Test, getMACFromDUID) {
     HWAddrPtr mac = pkt.getMAC(HWAddr::HWADDR_SOURCE_DUID);
     ASSERT_TRUE(mac);
     EXPECT_EQ("hwtype=7 0a:0b:0c:0d:0e:0f:10", mac->toText(true));
+    EXPECT_EQ(HWAddr::HWADDR_SOURCE_DUID, mac->source_);
 
     // Let's test DUID-LL. This should work.
     ASSERT_TRUE(pkt.delOption(D6O_CLIENTID));
@@ -1278,6 +1296,7 @@ TEST_F(Pkt6Test, getMACFromDUID) {
     mac = pkt.getMAC(HWAddr::HWADDR_SOURCE_DUID);
     ASSERT_TRUE(mac);
     EXPECT_EQ("hwtype=11 0a:0b:0c:0d:0e", mac->toText(true));
+    EXPECT_EQ(HWAddr::HWADDR_SOURCE_DUID, mac->source_);
 
     // Finally, let's try DUID-EN. This should fail, as EN type does not
     // contain any MAC address information.
@@ -1303,6 +1322,7 @@ TEST_F(Pkt6Test, getMAC_DOCSIS_Modem) {
 
     // Let's check the info.
     EXPECT_EQ("hwtype=1 10:0d:7f:00:07:88", found->toText(true));
+    EXPECT_EQ(HWAddr::HWADDR_SOURCE_DOCSIS_MODEM, found->source_);
 
     // Now let's remove the option
     OptionVendorPtr vendor = boost::dynamic_pointer_cast<
@@ -1331,6 +1351,7 @@ TEST_F(Pkt6Test, getMAC_DOCSIS_CMTS) {
 
     // Let's check the info.
     EXPECT_EQ("hwtype=1 20:e5:2a:b8:15:14", found->toText(true));
+    EXPECT_EQ(HWAddr::HWADDR_SOURCE_DOCSIS_CMTS, found->source_);
 
     // Now let's remove the suboption 1026 that is inserted by the
     // relay.
@@ -1393,6 +1414,7 @@ TEST_F(Pkt6Test, getMACFromRemoteIdRelayOption) {
     tmp << "hwtype=" << (int)iface->getHWType() << " 0a:0b:0c:0d:0e:0f";
 
     EXPECT_EQ(tmp.str(), mac->toText(true));
+    EXPECT_EQ(HWAddr::HWADDR_SOURCE_REMOTE_ID, mac->source_);
 }
 
 // This test verifies that a solicit that passed through two relays is parsed