Commit 23fca8ea authored by Tomek Mrugalski's avatar Tomek Mrugalski 🛰
Browse files

[master] Merge branch 'trac3551' (RFC6939 support)

Conflicts:
	ChangeLog
parents e292fe03 dabdf965
......@@ -70,6 +70,9 @@ We have received the following contributions:
2014-11: Export CalloutManager headers for testing statically linked
libraries.
- David Gutierrez Rueda, CERN
2014-12: Support for client link-address option in DHCPv6 (RFC6939)
Kea uses log4cplus (http://sourceforge.net/projects/log4cplus/) for logging,
Boost (http://www.boost.org/) library for almost everything, and can use Botan
(http://botan.randombit.net/) or OpenSSL (https://www.openssl.org/) for
......
862. [func] dgutier, tomek
Support for client link-layer address option (RFC6939) has
been added.
(Trac #3551, git dabdf965d92085f86d5e96c8dadce0f0a8f7c8e3)
861. [func] marcin
The configuration parameters for a DHCPv4 and DHCPv6 options are now
optional.
......
......@@ -1869,6 +1869,13 @@ should include options from the isc option space:
<ulink url="http://tools.ietf.org/html/rfc4704">RFC 4704</ulink>:
Supported option is CLIENT_FQDN.</simpara>
</listitem>
<listitem>
<simpara><emphasis>Client Link-Layer Address Option in
DHCPv6</emphasis>,
<ulink url="http://tools.ietf.org/html/rfc6939">RFC
6939</ulink>: Supported option is client link-layer
address option.</simpara>
</listitem>
</itemizedlist>
</section>
......
......@@ -65,6 +65,7 @@
#define D6O_CLT_TIME 46 /* RFC5007 */
#define D6O_LQ_RELAY_DATA 47 /* RFC5007 */
#define D6O_LQ_CLIENT_LINK 48 /* RFC5007 */
#define D6O_CLIENT_LINKLAYER_ADDR 79 /* RFC6939 */
/*
* Status Codes, from RFC 3315 section 24.4, and RFC 3633, 5007.
......
......@@ -155,6 +155,16 @@ Pkt::getMAC(uint32_t hw_addr_src) {
}
// Method 4: From client link-layer address option inserted by a relay
if (hw_addr_src & HWADDR_SOURCE_CLIENT_ADDR_RELAY_OPTION) {
mac = getMACFromIPv6RelayOpt();
if (mac) {
return (mac);
} else if (hw_addr_src == HWADDR_SOURCE_CLIENT_ADDR_RELAY_OPTION) {
// If we're interested only in RFC6939 link layer address as source
// of that info, there's no point in trying other options.
return (HWAddrPtr());
}
}
// Method 5: From remote-id option inserted by a relay
......
......@@ -68,7 +68,7 @@ public:
/// 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.
//static const uint32_t HWADDR_SOURCE_CLIENT_ADDR_RELAY_OPTION = 0x0008;
static const uint32_t HWADDR_SOURCE_CLIENT_ADDR_RELAY_OPTION = 0x0008;
/// A relay can insert remote-id. In some deployments it contains a MAC
/// address (RFC4649).
......@@ -524,6 +524,22 @@ protected:
/// @return hardware address (or NULL)
virtual HWAddrPtr getMACFromSrcLinkLocalAddr() = 0;
/// @brief Attempts to obtain MAC address from relay option
/// client-linklayer-addr
///
/// This method is called from getMAC(HWADDR_SOURCE_CLIENT_ADDR_RELAY_OPTION)
/// and should not be called directly. It will extract the client's
/// MAC/Hardware address from option client_linklayer_addr (RFC6939)
/// inserted by the 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 getMACFromIPv6RelayOpt() = 0;
/// @brief Attempts to convert IPv6 address into MAC.
///
/// Utility method that attempts to convert link-local IPv6 address to the
......
......@@ -402,6 +402,18 @@ protected:
return (HWAddrPtr());
}
/// @brief No-op
///
/// This method returns hardware address extracted from an IPv6 relay agent.
/// option. As there is no IPv4-equivalent, it always returns NULL.
/// We need this stub implementation here, to keep all the get hardware
/// address logic in the base class.
///
/// @return always NULL
virtual HWAddrPtr getMACFromIPv6RelayOpt() {
return (HWAddrPtr());
}
/// local HW address (dst if receiving packet, src if sending packet)
HWAddrPtr local_hwaddr_;
......
......@@ -16,6 +16,7 @@
#include <dhcp/libdhcp++.h>
#include <dhcp/option.h>
#include <dhcp/pkt6.h>
#include <util/io_utilities.h>
#include <exceptions/exceptions.h>
#include <iostream>
......@@ -553,6 +554,31 @@ Pkt6::getMACFromSrcLinkLocalAddr() {
return (getMACFromIPv6(relay_info_[relay_info_.size() - 1].peeraddr_));
}
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 trucnated. It's supposed to be
// 2 bytes of link-layer type followed by link-layer address.
return (HWAddrPtr());
}
// +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());
}
}
} // end of isc::dhcp namespace
} // end of isc namespace
......@@ -295,6 +295,16 @@ protected:
/// @return Hardware address (or NULL)
virtual HWAddrPtr getMACFromSrcLinkLocalAddr();
/// @brief Extract MAC/Hardware address from client link-layer address
// option inserted by a relay agent (RFC6939).
///
/// This method extracts the client's hardware address from the
// client-linklayer-addr option inserted by the relay agent closest to
// the client.
///
/// @return Hardware address (or NULL)
virtual HWAddrPtr getMACFromIPv6RelayOpt();
/// @brief Builds on wire packet for TCP transmission.
///
/// @todo This function is not implemented yet.
......
......@@ -326,7 +326,9 @@ const OptionDefParams OPTION_DEF_PARAMS6[] = {
{ "lq-relay-data", D6O_LQ_RELAY_DATA, OPT_RECORD_TYPE, false,
RECORD_DEF(LQ_RELAY_DATA_RECORDS), "" },
{ "lq-client-link", D6O_LQ_CLIENT_LINK, OPT_IPV6_ADDRESS_TYPE, true,
NO_RECORD_DEF, "" }
NO_RECORD_DEF, "" },
{ "client-linklayer-addr", D6O_CLIENT_LINKLAYER_ADDR, OPT_BINARY_TYPE, false,
NO_RECORD_DEF, "" }
// @todo There is still a bunch of options for which we have to provide
// definitions but we don't do it because they are not really
......
......@@ -1050,4 +1050,84 @@ TEST_F(Pkt6Test, getMACFromIPv6LinkLocal_multiRelay) {
EXPECT_EQ(tmp.str(), found->toText(true));
}
// Test checks whether getMACFromIPv6RelayOpt() returns the hardware (MAC)
// address properly from a single relayed message.
TEST_F(Pkt6Test, getMACFromIPv6RelayOpt_singleRelay) {
// Let's create a Solicit first...
Pkt6 pkt(DHCPV6_SOLICIT, 1234);
// Packets that are not relayed should fail
EXPECT_FALSE(pkt.getMAC(Pkt::HWADDR_SOURCE_CLIENT_ADDR_RELAY_OPTION));
// Now pretend it was relayed by a single relay.
Pkt6::RelayInfo info;
// generate options with code 79 and client link layer address
const uint8_t opt_data[] = {
0x00, 0x01, // Ethertype
0x0a, 0x1b, 0x0b, 0x01, 0xca, 0xfe // MAC
};
OptionPtr relay_opt(new Option(Option::V6, 79,
OptionBuffer(opt_data, opt_data + sizeof(opt_data))));
info.options_.insert(make_pair(relay_opt->getType(), relay_opt));
pkt.addRelayInfo(info);
ASSERT_EQ(1, pkt.relay_info_.size());
HWAddrPtr found = pkt.getMAC(Pkt::HWADDR_SOURCE_CLIENT_ADDR_RELAY_OPTION);
ASSERT_TRUE(found);
stringstream tmp;
tmp << "hwtype=1 0a:1b:0b:01:ca:fe";
EXPECT_EQ(tmp.str(), found->toText(true));
}
// Test checks whether getMACFromIPv6RelayOpt() returns the hardware (MAC)
// address properly from a message relayed by multiple servers.
TEST_F(Pkt6Test, getMACFromIPv6RelayOpt_multipleRelay) {
// Let's create a Solicit first...
Pkt6 pkt(DHCPV6_SOLICIT, 1234);
// Now pretend it was relayed two times. The relay closest to the server
// adds link-layer-address information against the RFC, the process fails.
Pkt6::RelayInfo info1;
uint8_t opt_data[] = {
0x00, 0x01, // Ethertype
0x1a, 0x30, 0x0b, 0xfa, 0xc0, 0xfe // MAC
};
OptionPtr relay_opt1(new Option(Option::V6, D6O_CLIENT_LINKLAYER_ADDR,
OptionBuffer(opt_data, opt_data + sizeof(opt_data))));
info1.options_.insert(make_pair(relay_opt1->getType(), relay_opt1));
pkt.addRelayInfo(info1);
// Second relay, closest to the client has not implemented RFC6939
Pkt6::RelayInfo info2;
pkt.addRelayInfo(info2);
ASSERT_EQ(2, pkt.relay_info_.size());
EXPECT_FALSE(pkt.getMAC(Pkt::HWADDR_SOURCE_CLIENT_ADDR_RELAY_OPTION));
// Let's envolve the packet with a third relay (now the closest to the client)
// that inserts the correct client_linklayer_addr option.
Pkt6::RelayInfo info3;
// We reuse the option and modify the MAC to be sure we get the right address
opt_data[2] = 0xfa;
OptionPtr relay_opt3(new Option(Option::V6, D6O_CLIENT_LINKLAYER_ADDR,
OptionBuffer(opt_data, opt_data + sizeof(opt_data))));
info3.options_.insert(make_pair(relay_opt3->getType(), relay_opt3));
pkt.addRelayInfo(info3);
ASSERT_EQ(3, pkt.relay_info_.size());
// Now extract the MAC address from the relayed option
HWAddrPtr found = pkt.getMAC(Pkt::HWADDR_SOURCE_CLIENT_ADDR_RELAY_OPTION);
ASSERT_TRUE(found);
stringstream tmp;
tmp << "hwtype=1 fa:30:0b:fa:c0:fe";
EXPECT_EQ(tmp.str(), found->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