Commit 7b920501 authored by Tomek Mrugalski's avatar Tomek Mrugalski 🛰
Browse files

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

parent 82847177
......@@ -180,6 +180,16 @@ Pkt::getMAC(uint32_t hw_addr_src) {
}
// 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
......
......@@ -492,8 +492,7 @@ protected:
/// @return hardware address (or NULL)
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
/// called directly. It will attempt to extract MAC address information
......@@ -507,6 +506,20 @@ protected:
/// @return hardware address (or NULL)
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.
///
/// Utility method that attempts to convert link-local IPv6 address to the
......
// 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
// purpose with or without fee is hereby granted, provided that the above
......@@ -447,6 +447,16 @@ protected:
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)
HWAddrPtr local_hwaddr_;
......
......@@ -22,6 +22,7 @@
#include <util/io_utilities.h>
#include <exceptions/exceptions.h>
#include <dhcp/duid.h>
#include <dhcp/iface_mgr.h>
#include <iostream>
#include <sstream>
......@@ -615,7 +616,7 @@ Pkt6::getMACFromIPv6RelayOpt() {
if (opt) {
const OptionBuffer data = opt->getData();
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.
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 namespace
......@@ -342,6 +342,16 @@ protected:
/// @return hardware address (if DOCSIS suboption 1026 is present)
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.
///
/// @todo This function is not implemented yet.
......
......@@ -1242,4 +1242,56 @@ TEST_F(Pkt6Test, getMAC_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));
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment