Commit f643dc9f authored by Tomek Mrugalski's avatar Tomek Mrugalski 🛰
Browse files

[3554] Configurable MAC sources implemented.

parent 88f088fa
......@@ -422,6 +422,21 @@
} ]
}
},
{ "item_name": "mac-sources",
"item_type": "list",
"item_optional": true,
"item_default": [ "any" ],
"item_description": "Lists MAC/hardware address acquisition sources",
"list_item_spec":
{
"item_name": "source",
"item_type": "string",
"item_optional": true,
"item_default": "any"
}
} ,
{ "item_name": "dhcp-ddns",
"item_type": "map",
"item_optional": false,
......
......@@ -1253,10 +1253,18 @@ Dhcpv6Srv::assignIA_NA(const Subnet6Ptr& subnet, const DuidPtr& duid,
hostname = fqdn->getDomainName();
}
// Attempt to get MAC address using any of available mechanisms.
// It's ok if there response is NULL. Hardware address is optional in Lease6
/// @todo: Make this configurable after trac 3554 is done.
HWAddrPtr hwaddr = query->getMAC(Pkt::HWADDR_SOURCE_ANY);
// Attempt to get MAC address using configured mechanisms.
// It's ok if there response is NULL. Hardware address is optional in Lease6.
std::vector<uint32_t> mac_sources = CfgMgr::instance().getCurrentCfg()->
getMACSources();
HWAddrPtr hwaddr;
for (std::vector<uint32_t>::const_iterator it = mac_sources.begin();
it != mac_sources.end(); ++it) {
hwaddr = query->getMAC(*it);
if (hwaddr) {
break;
}
}
// Use allocation engine to pick a lease for this client. Allocation engine
// will try to honour the hint, but it is just a hint - some other address
......
......@@ -613,6 +613,9 @@ namespace dhcp {
parser = new HooksLibrariesParser(config_id);
} else if (config_id.compare("dhcp-ddns") == 0) {
parser = new D2ClientConfigParser(config_id);
} else if (config_id.compare("mac-sources") == 0) {
parser = new MACSourcesListConfigParser(config_id,
globalContext());
} else {
isc_throw(DhcpConfigError,
"unsupported global configuration parameter: "
......
......@@ -15,9 +15,6 @@
#ifndef DHCP6_CONFIG_PARSER_H
#define DHCP6_CONFIG_PARSER_H
/// @todo: This header file and its .cc counterpart are very similar between
/// DHCPv4 and DHCPv6. They should be merged. See ticket #2355.
#include <cc/data.h>
#include <dhcpsrv/parsers/dhcp_parsers.h>
#include <exceptions/exceptions.h>
......
......@@ -20,6 +20,16 @@
namespace isc {
namespace dhcp {
const uint32_t Pkt::HWADDR_SOURCE_ANY = 0xffffffff;
const uint32_t Pkt::HWADDR_SOURCE_UNKNOWN = 0x00000000;
const uint32_t Pkt::HWADDR_SOURCE_RAW = 0x00000001;
const uint32_t Pkt::HWADDR_SOURCE_DUID = 0x00000002;
const uint32_t Pkt::HWADDR_SOURCE_IPV6_LINK_LOCAL = 0x00000004;
const uint32_t Pkt::HWADDR_SOURCE_CLIENT_ADDR_RELAY_OPTION = 0x00000008;
const uint32_t Pkt::HWADDR_SOURCE_REMOTE_ID = 0x00000010;
const uint32_t Pkt::HWADDR_SOURCE_SUBSCRIBER_ID = 0x00000020;
const uint32_t Pkt::HWADDR_SOURCE_DOCSIS = 0x00000040;
Pkt::Pkt(uint32_t transid, const isc::asiolink::IOAddress& local_addr,
const isc::asiolink::IOAddress& remote_addr, uint16_t local_port,
uint16_t remote_port)
......@@ -223,6 +233,34 @@ Pkt::getMACFromIPv6(const isc::asiolink::IOAddress& addr) {
return (HWAddrPtr(new HWAddr(bin, hwtype)));
}
uint16_t Pkt::MACSourceFromText(const std::string& name) {
struct {
const char * name;
uint32_t type;
} sources[] = {
{ "any", Pkt::HWADDR_SOURCE_ANY },
{ "raw", Pkt::HWADDR_SOURCE_RAW },
{ "duid", Pkt::HWADDR_SOURCE_DUID },
{ "ipv6-link-local", Pkt::HWADDR_SOURCE_IPV6_LINK_LOCAL },
{ "client-link-addr-option", Pkt::HWADDR_SOURCE_CLIENT_ADDR_RELAY_OPTION },
{ "rfc6939", Pkt::HWADDR_SOURCE_CLIENT_ADDR_RELAY_OPTION },
{ "remote-id", Pkt::HWADDR_SOURCE_REMOTE_ID },
{ "rfc4649", Pkt::HWADDR_SOURCE_REMOTE_ID },
{ "subscriber-id", Pkt::HWADDR_SOURCE_SUBSCRIBER_ID },
{ "rfc4580", Pkt::HWADDR_SOURCE_SUBSCRIBER_ID },
{ "docsis", Pkt::HWADDR_SOURCE_DOCSIS }
};
for (int i=0; i < sizeof(sources)/sizeof(sources[0]); ++i) {
if (name.compare(sources[i].name)) {
return (sources[i].type);
}
}
isc_throw(BadValue, "Can't convert '" << name << "' to any known MAC source.");
}
};
};
......@@ -44,51 +44,63 @@ public:
///
/// @brief The list covers all possible MAC/hw address sources.
///
/// @note The uncommented ones are currently supported. When you implement
/// a new method, please uncomment appropriate line here.
///
/// @{
/// Not really a type, only used in getMAC() calls.
static const uint32_t HWADDR_SOURCE_ANY = 0xffff;
static const uint32_t HWADDR_SOURCE_ANY;
/// Used when actual origin is not known, e.g. when reading from a
/// lease database that didn't store that information.
static const uint32_t HWADDR_SOURCE_UNKNOWN = 0x0000;
static const uint32_t HWADDR_SOURCE_UNKNOWN;
/// Obtained first hand from raw socket (100% reliable).
static const uint32_t HWADDR_SOURCE_RAW = 0x0001;
static const uint32_t HWADDR_SOURCE_RAW;
/// Extracted from DUID-LL or DUID-LLT (not 100% reliable as the client
/// can send fake DUID).
//static const uint32_t HWADDR_SOURCE_DUID = 0x0002;
static const uint32_t HWADDR_SOURCE_DUID;
/// Extracted from IPv6 link-local address. Not 100% reliable, as the
/// client can use different IID other than EUI-64, e.g. Windows supports
/// RFC4941 and uses random values instead of EUI-64.
static const uint32_t HWADDR_SOURCE_IPV6_LINK_LOCAL = 0x0004;
static const uint32_t HWADDR_SOURCE_IPV6_LINK_LOCAL;
/// Get it from RFC6939 option. (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.
static const uint32_t HWADDR_SOURCE_CLIENT_ADDR_RELAY_OPTION = 0x0008;
static const uint32_t HWADDR_SOURCE_CLIENT_ADDR_RELAY_OPTION;
/// A relay can insert remote-id. In some deployments it contains a MAC
/// address (RFC4649).
//static const uint32_t HWADDR_SOURCE_REMOTE_ID = 0x0010;
static const uint32_t HWADDR_SOURCE_REMOTE_ID;
/// A relay can insert a subscriber-id option. In some deployments it
/// contains a MAC address (RFC4580).
//static const uint32_t HWADDR_SOURCE_SUBSCRIBER_ID = 0x0020;
static const uint32_t HWADDR_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.
//static const uint32_t HWADDR_SOURCE_DOCSIS_OPTIONS = 0x0040;
static const uint32_t HWADDR_SOURCE_DOCSIS;
/// @}
/// @brief Attempts to convert known hardware address sources to uint32_t
///
/// Supported strings are: any => 0xffffffff
/// raw => 0x00000001
/// duid => 0x00000002
/// ipv6-link-local 0x00000004
/// client-link-addr-option, rfc6939 => 0x00000008
/// remote-id, rfc4649 => 0x00000010
/// subscriber-id, rfc4580 => 0x00000020
/// docsis => 0x00000040
///
/// @throw BadValue if specified string is unknown
/// @return bitmask version of a given method
static uint16_t MACSourceFromText(const std::string& name);
protected:
/// @brief Constructor.
......
......@@ -187,6 +187,7 @@ InterfaceListConfigParser(const std::string& param_name,
void
InterfaceListConfigParser::build(ConstElementPtr value) {
CfgIface cfg_iface;
BOOST_FOREACH(ConstElementPtr iface, value->listValue()) {
std::string iface_name = iface->stringValue();
try {
......@@ -206,6 +207,45 @@ InterfaceListConfigParser::commit() {
// Nothing to do.
}
// ******************** MACSourcesListConfigParser *************************
MACSourcesListConfigParser::
MACSourcesListConfigParser(const std::string& param_name,
ParserContextPtr global_context)
: param_name_(param_name), global_context_(global_context) {
if (param_name_ != "mac-sources") {
isc_throw(BadValue, "Internal error. MAC sources configuration "
"parser called for the wrong parameter: " << param_name);
}
}
void
MACSourcesListConfigParser::build(ConstElementPtr value) {
CfgIface cfg_iface;
uint32_t source = 0;
// By default, there's only one source defined: ANY.
// If user specified anything, we need to get rid of that default.
CfgMgr::instance().getStagingCfg()->clearMACSources();
BOOST_FOREACH(ConstElementPtr source_elem, value->listValue()) {
std::string source_str = source_elem->stringValue();
try {
source = Pkt::MACSourceFromText(source_str);
CfgMgr::instance().getStagingCfg()->addMACSource(source);
} catch (const std::exception& ex) {
isc_throw(DhcpConfigError, "Failed to convert '"
<< source_str << "' to any recognized MAC source:"
<< ex.what() << " (" << value->getPosition() << ")");
}
}
}
void
MACSourcesListConfigParser::commit() {
// Nothing to do.
}
// ******************** HooksLibrariesParser *************************
HooksLibrariesParser::HooksLibrariesParser(const std::string& param_name)
......
......@@ -382,12 +382,10 @@ private:
/// @brief parser for interface list definition
///
/// This parser handles Dhcp4/interface entry.
/// This parser handles Dhcp4/interfaces and Dhcp6/interfaces entries.
/// It contains a list of network interfaces that the server listens on.
/// In particular, it can contain an entry called "all" or "any" that
/// designates all interfaces.
///
/// It is useful for parsing Dhcp4/interface parameter.
class InterfaceListConfigParser : public DhcpConfigParser {
public:
......@@ -422,6 +420,48 @@ private:
ParserContextPtr global_context_;
};
/// @brief parser for MAC/hardware aquisition sources
///
/// This parser handles Dhcp6/mac-sources entry.
/// It contains a list of MAC/hardware aquisition source, i.e. methods how
/// MAC address can possibly by obtained in DHCPv6. For a currently supported
/// methods, see @ref isc::dhcp::Pkt::getMAC.
class MACSourcesListConfigParser : public DhcpConfigParser {
public:
/// @brief constructor
///
/// As this is a dedicated parser, it must be used to parse
/// "mac-sources" parameter only. All other types will throw exception.
///
/// @param param_name name of the configuration parameter being parsed
/// @param global_context Global parser context.
/// @throw BadValue if supplied parameter name is not "mac-sources"
MACSourcesListConfigParser(const std::string& param_name,
ParserContextPtr global_context);
/// @brief parses parameters value
///
/// Parses configuration entry (list of sources) and adds each element
/// to the sources list.
///
/// @param value pointer to the content of parsed values
virtual void build(isc::data::ConstElementPtr value);
/// @brief Does nothing.
virtual void commit();
private:
// Parsed parameter name
std::string param_name_;
/// Global parser context.
ParserContextPtr global_context_;
};
/// @brief Parser for hooks library list
///
/// This parser handles the list of hooks libraries. This is an optional list,
......@@ -1172,4 +1212,3 @@ typedef boost::shared_ptr<Uint32Parser> Uint32ParserPtr;
}; // end of isc namespace
#endif // DHCP_PARSERS_H
......@@ -16,6 +16,7 @@
#include <dhcpsrv/srv_config.h>
#include <log/logger_manager.h>
#include <log/logger_specification.h>
#include <dhcp/pkt.h> // Needed for HWADDR_SOURCE_*
#include <list>
#include <sstream>
......@@ -28,12 +29,18 @@ SrvConfig::SrvConfig()
: sequence_(0), cfg_option_def_(new CfgOptionDef()),
cfg_option_(new CfgOption()), cfg_subnets4_(new CfgSubnets4()),
cfg_subnets6_(new CfgSubnets6()), cfg_hosts_(new CfgHosts()) {
// By default, use any hardware source that is available.
mac_sources_.push_back(Pkt::HWADDR_SOURCE_ANY);
}
SrvConfig::SrvConfig(const uint32_t sequence)
: sequence_(sequence), cfg_option_def_(new CfgOptionDef()),
cfg_option_(new CfgOption()), cfg_subnets4_(new CfgSubnets4()),
cfg_subnets6_(new CfgSubnets6()), cfg_hosts_(new CfgHosts()) {
// By default, use any hardware source that is available.
mac_sources_.push_back(Pkt::HWADDR_SOURCE_ANY);
}
std::string
......
......@@ -235,6 +235,28 @@ public:
return (cfg_hosts_);
}
/// @brief Adds additional MAC/hardware address aquisition.
///
/// @param source MAC source (see constants in Pkt::HWADDR_SOURCE_*)
///
/// Specified source is being added to the mac_sources_ array.
void addMACSource(uint32_t source) {
mac_sources_.push_back(source);
}
/// @brief Provides access to the configure MAC/Hardware address sources.
///
/// @note The const reference returned is only valid as long as the
/// object that returned it.
const std::vector<uint32_t>& getMACSources() const {
return mac_sources_;
}
/// @brief Removes any configured MAC/Hardware address sources.
void clearMACSources() {
mac_sources_.clear();
}
//@}
/// @brief Copies the currnet configuration to a new configuration.
......@@ -310,6 +332,7 @@ public:
//@}
private:
/// @brief Sequence number identifying the configuration.
......@@ -348,6 +371,8 @@ private:
/// reservations for different IPv4 and IPv6 subnets.
CfgHostsPtr cfg_hosts_;
/// @brief A list of configured MAC sources.
std::vector<uint32_t> mac_sources_;
};
/// @name Pointers to the @c SrvConfig object.
......
......@@ -120,7 +120,8 @@ if USE_CLANGPP
libdhcpsrv_unittests_CXXFLAGS += -Wno-unused-variable -Wno-unused-parameter
endif
libdhcpsrv_unittests_LDADD = $(top_builddir)/src/lib/dhcpsrv/libkea-dhcpsrv.la
libdhcpsrv_unittests_LDADD = $(top_builddir)/src/lib/dhcp/libkea-dhcp++.la
libdhcpsrv_unittests_LDADD += $(top_builddir)/src/lib/dhcpsrv/libkea-dhcpsrv.la
libdhcpsrv_unittests_LDADD += $(top_builddir)/src/lib/dhcpsrv/testutils/libdhcpsrvtest.la
libdhcpsrv_unittests_LDADD += $(top_builddir)/src/lib/dhcp/tests/libdhcptest.la
libdhcpsrv_unittests_LDADD += $(top_builddir)/src/lib/dhcp/libkea-dhcp++.la
......
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