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,
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);
}
};
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();
{
// 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
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
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"
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);
// 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
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));
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";
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)
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)
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)
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) {
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));
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.
// 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<
// 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.
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