From f643dc9f47d3b80ad9406f775412a61f0ac78f4f Mon Sep 17 00:00:00 2001 From: Tomek Mrugalski Date: Tue, 16 Dec 2014 14:53:57 +0100 Subject: [PATCH 01/12] [3554] Configurable MAC sources implemented. --- src/bin/dhcp6/dhcp6.spec | 15 ++++++++ src/bin/dhcp6/dhcp6_srv.cc | 16 ++++++--- src/bin/dhcp6/json_config_parser.cc | 3 ++ src/bin/dhcp6/json_config_parser.h | 3 -- src/lib/dhcp/pkt.cc | 38 ++++++++++++++++++++ src/lib/dhcp/pkt.h | 36 ++++++++++++------- src/lib/dhcpsrv/parsers/dhcp_parsers.cc | 40 +++++++++++++++++++++ src/lib/dhcpsrv/parsers/dhcp_parsers.h | 47 ++++++++++++++++++++++--- src/lib/dhcpsrv/srv_config.cc | 7 ++++ src/lib/dhcpsrv/srv_config.h | 25 +++++++++++++ src/lib/dhcpsrv/tests/Makefile.am | 3 +- 11 files changed, 209 insertions(+), 24 deletions(-) diff --git a/src/bin/dhcp6/dhcp6.spec b/src/bin/dhcp6/dhcp6.spec index f0fe861b90..ff2b308b42 100644 --- a/src/bin/dhcp6/dhcp6.spec +++ b/src/bin/dhcp6/dhcp6.spec @@ -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, diff --git a/src/bin/dhcp6/dhcp6_srv.cc b/src/bin/dhcp6/dhcp6_srv.cc index 8b5336cde5..1d56f7da3c 100644 --- a/src/bin/dhcp6/dhcp6_srv.cc +++ b/src/bin/dhcp6/dhcp6_srv.cc @@ -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 mac_sources = CfgMgr::instance().getCurrentCfg()-> + getMACSources(); + HWAddrPtr hwaddr; + for (std::vector::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 diff --git a/src/bin/dhcp6/json_config_parser.cc b/src/bin/dhcp6/json_config_parser.cc index eaf278a199..1ea45bacd9 100644 --- a/src/bin/dhcp6/json_config_parser.cc +++ b/src/bin/dhcp6/json_config_parser.cc @@ -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: " diff --git a/src/bin/dhcp6/json_config_parser.h b/src/bin/dhcp6/json_config_parser.h index d3c1b27f3f..3970d68e94 100644 --- a/src/bin/dhcp6/json_config_parser.h +++ b/src/bin/dhcp6/json_config_parser.h @@ -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 #include #include diff --git a/src/lib/dhcp/pkt.cc b/src/lib/dhcp/pkt.cc index 6bb0c8e386..9428c131e7 100644 --- a/src/lib/dhcp/pkt.cc +++ b/src/lib/dhcp/pkt.cc @@ -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."); +} + }; }; diff --git a/src/lib/dhcp/pkt.h b/src/lib/dhcp/pkt.h index 21626b0d35..9917ac03cf 100644 --- a/src/lib/dhcp/pkt.h +++ b/src/lib/dhcp/pkt.h @@ -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. diff --git a/src/lib/dhcpsrv/parsers/dhcp_parsers.cc b/src/lib/dhcpsrv/parsers/dhcp_parsers.cc index 18043635c1..11f96dcc28 100644 --- a/src/lib/dhcpsrv/parsers/dhcp_parsers.cc +++ b/src/lib/dhcpsrv/parsers/dhcp_parsers.cc @@ -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) diff --git a/src/lib/dhcpsrv/parsers/dhcp_parsers.h b/src/lib/dhcpsrv/parsers/dhcp_parsers.h index 984633f20b..46e1f7f865 100644 --- a/src/lib/dhcpsrv/parsers/dhcp_parsers.h +++ b/src/lib/dhcpsrv/parsers/dhcp_parsers.h @@ -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 Uint32ParserPtr; }; // end of isc namespace #endif // DHCP_PARSERS_H - diff --git a/src/lib/dhcpsrv/srv_config.cc b/src/lib/dhcpsrv/srv_config.cc index a48268e927..a33a79cc66 100644 --- a/src/lib/dhcpsrv/srv_config.cc +++ b/src/lib/dhcpsrv/srv_config.cc @@ -16,6 +16,7 @@ #include #include #include +#include // Needed for HWADDR_SOURCE_* #include #include @@ -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 diff --git a/src/lib/dhcpsrv/srv_config.h b/src/lib/dhcpsrv/srv_config.h index 8ffe29de87..4f1fc57f78 100644 --- a/src/lib/dhcpsrv/srv_config.h +++ b/src/lib/dhcpsrv/srv_config.h @@ -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& 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 mac_sources_; }; /// @name Pointers to the @c SrvConfig object. diff --git a/src/lib/dhcpsrv/tests/Makefile.am b/src/lib/dhcpsrv/tests/Makefile.am index a57545791c..09b95fc455 100644 --- a/src/lib/dhcpsrv/tests/Makefile.am +++ b/src/lib/dhcpsrv/tests/Makefile.am @@ -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 From 4119b60cf923ef1f6bc4894b7a64edf775950fec Mon Sep 17 00:00:00 2001 From: Tomek Mrugalski Date: Tue, 16 Dec 2014 16:18:21 +0100 Subject: [PATCH 02/12] [3554] Unit-tests implemented. --- src/bin/dhcp6/tests/config_parser_unittest.cc | 25 +++++++++++ src/lib/dhcp/tests/pkt6_unittest.cc | 30 +++++++++++++ .../dhcpsrv/tests/dhcp_parsers_unittest.cc | 45 ++++++++++++++++++- 3 files changed, 99 insertions(+), 1 deletion(-) diff --git a/src/bin/dhcp6/tests/config_parser_unittest.cc b/src/bin/dhcp6/tests/config_parser_unittest.cc index c3bf74ece6..8d6863777b 100644 --- a/src/bin/dhcp6/tests/config_parser_unittest.cc +++ b/src/bin/dhcp6/tests/config_parser_unittest.cc @@ -3627,4 +3627,29 @@ TEST_F(Dhcp6ParserTest, reservationBogus) { } +/// The goal of this test is to verify that configuration can include +/// MAC/Hardware sources. +TEST_F(Dhcp6ParserTest, macSources) { + + ConstElementPtr status; + + EXPECT_NO_THROW(status = configureDhcp6Server(srv_, + Element::fromJSON("{ \"interfaces\": [ \"*\" ]," + "\"mac-sources\": [ \"rfc6939\", \"rfc4649\", \"rfc4580\" ]," + "\"preferred-lifetime\": 3000," + "\"rebind-timer\": 2000, " + "\"renew-timer\": 1000, " + "\"subnet6\": [ ], " + "\"valid-lifetime\": 4000 }"))); + + // returned value should be 0 (success) + checkResult(status, 0); + + vector mac_sources = CfgMgr::instance().getStagingCfg()->getMACSources(); + ASSERT_EQ(3, mac_sources.size()); + EXPECT_EQ(Pkt::HWADDR_SOURCE_CLIENT_ADDR_RELAY_OPTION, mac_sources[0]); + EXPECT_EQ(Pkt::HWADDR_SOURCE_REMOTE_ID, mac_sources[1]); + EXPECT_EQ(Pkt::HWADDR_SOURCE_SUBSCRIBER_ID, mac_sources[2]); +} + }; diff --git a/src/lib/dhcp/tests/pkt6_unittest.cc b/src/lib/dhcp/tests/pkt6_unittest.cc index a2c3615184..1827f9d219 100644 --- a/src/lib/dhcp/tests/pkt6_unittest.cc +++ b/src/lib/dhcp/tests/pkt6_unittest.cc @@ -1130,4 +1130,34 @@ TEST_F(Pkt6Test, getMACFromIPv6RelayOpt_multipleRelay) { tmp << "hwtype=1 fa:30:0b:fa:c0:fe"; EXPECT_EQ(tmp.str(), found->toText(true)); } + +// Checks whether Pkt::MACSourceFromText is working correctly. +// Technically, this is a Pkt, not Pkt6 test, but since there is no separate +// unit-tests for Pkt and it is abstract, so it would be tricky to test it +// directly. Hence test is being run in Pkt6. +TEST_F(Pkt6Test, MACSourceFromText) { + EXPECT_THROW(Pkt::MACSourceFromText("unknown"), BadValue); + + EXPECT_EQ(Pkt::HWADDR_SOURCE_ANY, Pkt::MACSourceFromText("any")); + EXPECT_EQ(Pkt::HWADDR_SOURCE_RAW, Pkt::MACSourceFromText("raw")); + EXPECT_EQ(Pkt::HWADDR_SOURCE_DUID, Pkt::MACSourceFromText("duid")); + EXPECT_EQ(Pkt::HWADDR_SOURCE_IPV6_LINK_LOCAL, + Pkt::MACSourceFromText("ipv6-link-local")); + EXPECT_EQ(Pkt::HWADDR_SOURCE_CLIENT_ADDR_RELAY_OPTION, + Pkt::MACSourceFromText("client-link-addr-option")); + EXPECT_EQ(Pkt::HWADDR_SOURCE_CLIENT_ADDR_RELAY_OPTION, + Pkt::MACSourceFromText("rfc6939")); + EXPECT_EQ(Pkt::HWADDR_SOURCE_REMOTE_ID, + Pkt::MACSourceFromText("remote-id")); + EXPECT_EQ(Pkt::HWADDR_SOURCE_REMOTE_ID, + Pkt::MACSourceFromText("rfc4649")); + EXPECT_EQ(Pkt::HWADDR_SOURCE_SUBSCRIBER_ID, + Pkt::MACSourceFromText("subscriber-id")); + EXPECT_EQ(Pkt::HWADDR_SOURCE_SUBSCRIBER_ID, + Pkt::MACSourceFromText("rfc4580")); + EXPECT_EQ(Pkt::HWADDR_SOURCE_DOCSIS, + Pkt::MACSourceFromText("docsis")); + +} + } diff --git a/src/lib/dhcpsrv/tests/dhcp_parsers_unittest.cc b/src/lib/dhcpsrv/tests/dhcp_parsers_unittest.cc index a16e8f8c22..4eea46e4da 100644 --- a/src/lib/dhcpsrv/tests/dhcp_parsers_unittest.cc +++ b/src/lib/dhcpsrv/tests/dhcp_parsers_unittest.cc @@ -212,7 +212,7 @@ TEST_F(DhcpParserTest, uint32ParserTest) { EXPECT_EQ(test_value, actual_value); } -/// @brief Check InterfaceListParser basic functionality +/// @brief Check InterfaceListConfigParser basic functionality /// /// Verifies that the parser: /// 1. Does not allow empty for storage. @@ -270,6 +270,49 @@ TEST_F(DhcpParserTest, interfaceListParserTest) { EXPECT_TRUE(test_config.socketOpen("eth1", AF_INET)); } + +/// @brief Check MACSourcesListConfigParser basic functionality +/// +/// Verifies that the parser: +/// 1. Does not allow empty for storage. +/// 2. Does not allow name other than "mac-sources" +/// 3. Parses list of mac sources and adds them to CfgMgr +TEST_F(DhcpParserTest, MacSourcesListConfigParserTest) { + + const std::string valid_name = "mac-sources"; + const std::string bogus_name = "bogus-name"; + + ParserContextPtr parser_context(new ParserContext(Option::V6)); + + // Verify that parser constructor fails if parameter name isn't "mac-sources" + EXPECT_THROW(MACSourcesListConfigParser(bogus_name, parser_context), + isc::BadValue); + + // That's an equivalent of the following snippet: + // "mac-sources: [ \"duid\", \"ipv6\" ]"; + ElementPtr config = Element::createList(); + config->add(Element::create("duid")); + config->add(Element::create("ipv6-link-local")); + + boost::scoped_ptr + parser(new MACSourcesListConfigParser(valid_name, parser_context)); + + // This should parse the configuration and add eth0 and eth1 to the list + // of interfaces that server should listen on. + EXPECT_NO_THROW(parser->build(config)); + EXPECT_NO_THROW(parser->commit()); + + // Use CfgMgr instance to check if eth0 and eth1 was added, and that + // eth2 was not added. + SrvConfigPtr cfg = CfgMgr::instance().getStagingCfg(); + ASSERT_TRUE(cfg); + vector configured_sources = cfg->getMACSources(); + + ASSERT_EQ(2, configured_sources.size()); + EXPECT_EQ(Pkt::HWADDR_SOURCE_DUID, configured_sources[0]); + EXPECT_EQ(Pkt::HWADDR_SOURCE_IPV6_LINK_LOCAL, configured_sources[1]); +} + /// @brief Test Fixture class which provides basic structure for testing /// configuration parsing. This is essentially the same structure provided /// by dhcp servers. From 417c41301a953be3e8f09518740d1d37240d88cc Mon Sep 17 00:00:00 2001 From: Tomek Mrugalski Date: Tue, 16 Dec 2014 16:18:44 +0100 Subject: [PATCH 03/12] [3554] Fix in Pkt::MACSourceFromText() --- src/lib/dhcp/pkt.cc | 4 ++-- src/lib/dhcp/pkt.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/lib/dhcp/pkt.cc b/src/lib/dhcp/pkt.cc index 9428c131e7..c5abdcc0e7 100644 --- a/src/lib/dhcp/pkt.cc +++ b/src/lib/dhcp/pkt.cc @@ -233,7 +233,7 @@ Pkt::getMACFromIPv6(const isc::asiolink::IOAddress& addr) { return (HWAddrPtr(new HWAddr(bin, hwtype))); } -uint16_t Pkt::MACSourceFromText(const std::string& name) { +uint32_t Pkt::MACSourceFromText(const std::string& name) { struct { const char * name; @@ -253,7 +253,7 @@ uint16_t Pkt::MACSourceFromText(const std::string& name) { }; for (int i=0; i < sizeof(sources)/sizeof(sources[0]); ++i) { - if (name.compare(sources[i].name)) { + if (name.compare(sources[i].name) == 0) { return (sources[i].type); } } diff --git a/src/lib/dhcp/pkt.h b/src/lib/dhcp/pkt.h index 9917ac03cf..24bb1ee690 100644 --- a/src/lib/dhcp/pkt.h +++ b/src/lib/dhcp/pkt.h @@ -99,7 +99,7 @@ public: /// /// @throw BadValue if specified string is unknown /// @return bitmask version of a given method - static uint16_t MACSourceFromText(const std::string& name); + static uint32_t MACSourceFromText(const std::string& name); protected: From 72f999e31a9009a991177f7e338d08f3da913fbc Mon Sep 17 00:00:00 2001 From: Tomek Mrugalski Date: Tue, 16 Dec 2014 20:20:57 +0100 Subject: [PATCH 04/12] [3554] User's Guide updated. --- doc/guide/dhcp6-srv.xml | 103 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 103 insertions(+) diff --git a/doc/guide/dhcp6-srv.xml b/doc/guide/dhcp6-srv.xml index 8abb16c373..1230886f6e 100644 --- a/doc/guide/dhcp6-srv.xml +++ b/doc/guide/dhcp6-srv.xml @@ -1838,6 +1838,109 @@ should include options from the isc option space: +
+ MAC/Hardware addresses in DHCPv6 + MAC or hardware addesses are available in DHCPv4 and administrators + frequently use that information to perform certain tasks, like per host + configuration, address reserveration for specific MAC addresses and other. + Unfortunately, DHCPv6 protocol does not provide any completely reliable way + to access that information. To mitigate that issue a number of mechanisms + has been implemented in Kea that attempts to gather that information. Each + of those mechanisms works in certain cases, but may fail in others. There + is no single best mechanism as they are somewhat dependent on the network + topology and the technologies used. + + Kea allows configuration which of the supported methods should be + used and in which order. This configuration may be considered a fine tuning + of the DHCP deployment. The format of this parameter is as follows: + +"Dhcp6": { + "mac-sources: [ "method1", "method2", "method3", ... ], + + "subnet6": [ ... ], + + ... +} + + + When not specified, a special value of any is used, which + instructs the server to attempt to use all the methods in sequence and use + value returned by the first one that succeeds. + + Supported methods are: + + + any - not an actual method, just a keyword that + instructs Kea to try all other methods and use the first one that succeeds. + This is the default operation if no mac-sources are defined. + + + + raw In principle, a DHCPv6 server could use raw + sockets to receive incoming traffic and extract MAC/hardware address + information. This is currently not implemented and this value has no effect. + + + + duid - DHCPv6 uses DUID identifiers instead of + MAC addresses. There are currently four DUID types defined, with two of them + (DUID-LLT, which is the default one and DUID-LL) convey MAC address information. + Although RFC3315 forbids it, it is possible to parse those DUIDs and extract + necessary information from them. This method is not completely reliable, as + clients may use other DUID types, namely DUID-EN or DUID-UUID. + + + + ipv6-link-local - Another possible aquisition + method comes from the source IPv6 address. In typical usage, clients are + sending their packets from IPv6 link-local addresses. There's a good chance + that those addresses are based on EUI-64, which contains MAC address. This + method is not completely reliable, as clients may use other link-local address + types. In particular, privacy extensions, defined in RFC4941, do not use + MAC addresses. + + + + client-link-addr-option - One extension defined + to alleviate missing MAC issues is client link-layer address option, defined + in RFC 6939. This is + an option that is inserted by a relay and contains information about client's + MAC address. This method requires a relay agent that supports the option and + is configured to insert it. This method is useless for directly connected + clients. This parameter can also be specified as rfc6939, + which is an alias for client-link-addr-option. + + + + remote-id RFC 4649 + defines remote-id option that is inserted by a relay agent. Depending + on the relay agent configuration, the inserted option may convey client's + MAC address information. This parameter can also be specified as + rfc4649, which is an alias for remote-id. + + + + subscriber-id - Another option + that is somewhat similar to the previous one is subscriber-id, + defined in RFC + 4580. It is, too, inserted by a relay agent that is + configured to insert it. This parameter can also be specified + as rfc4580, which is an alias for + subscriber-id. This method is currently not + implemented. + + + + docsis - Yet another possible source of MAC + address information are DOCSIS options inserted by a CMTS that acts + as a DHCPv6 relay agent in cable networks. This method is + currently not implemented. + + + + +
Supported DHCPv6 Standards From 7f70083c522e4dba237c028e0c29923d973f9926 Mon Sep 17 00:00:00 2001 From: Tomek Mrugalski Date: Tue, 16 Dec 2014 20:23:24 +0100 Subject: [PATCH 05/12] [3554] Example config added. --- doc/Makefile.am | 1 + doc/examples/kea6/advanced.json | 72 +++++++++++++++++++++++++++++++++ doc/examples/kea6/simple.json | 2 +- 3 files changed, 74 insertions(+), 1 deletion(-) create mode 100644 doc/examples/kea6/advanced.json diff --git a/doc/Makefile.am b/doc/Makefile.am index dbaabbb35a..bdff6ba4c1 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -8,6 +8,7 @@ nobase_dist_doc_DATA += examples/kea4/multiple-options.json nobase_dist_doc_DATA += examples/kea6/simple.json nobase_dist_doc_DATA += examples/kea6/several-subnets.json nobase_dist_doc_DATA += examples/kea6/multiple-options.json +nobase_dist_doc_DATA += examples/kea6/advanced.json nobase_dist_doc_DATA += examples/ddns/sample1.json nobase_dist_doc_DATA += examples/ddns/template.json diff --git a/doc/examples/kea6/advanced.json b/doc/examples/kea6/advanced.json new file mode 100644 index 0000000000..0cee002050 --- /dev/null +++ b/doc/examples/kea6/advanced.json @@ -0,0 +1,72 @@ +# This is an example configuration file for DHCPv6 server in Kea. +# It attempts to showcase some of the more advanced features. +# Topology wise, it's a basic scenario with one IPv6 subnet configured. +# It is assumed that one subnet (2001:db8:1::/64) is available directly +# over eth0 interface. + +{ "Dhcp6": + +{ +# Kea is told to listen on eth0 interface only. + "interfaces": [ "eth0" ], + +# We need to specify lease type. As of May 2014, three backends are supported: +# memfile, mysql and pgsql. We'll just use memfile, because it doesn't require +# any prior set up. + "lease-database": { + "type": "memfile" + }, + +# Kea 0.9.1 introduced MAC/hardware addresses support in DHCPv6. There is +# no single reliable method of getting MAC address information in DHCPv6. +# Kea supports several methods. Depending on your network set up, some +# methods may be more preferable than others, hence the configuration +# parameter. 'mac-sources' is a list of methods. Allowed parameters are: +# any, raw, duid, ipv6-link-local, client-link-addr-option, rfc6939 (which +# is an alias for client-link-addr-option), remote-id, rfc4649 (which is an +# alias for remote-id, subscriber-id, rfc4580 (which is an alias for +# subscriber-id) and docsis. +# +# If mac-sources are not specified, a default value of 'any' is used. + "mac-sources": [ "client-link-addr-option", "duid", "ipv6-link-local" ], + +# Addresses will be assigned with preferred and valid lifetimes +# being 3000 and 4000, respectively. Client is told to start +# renewing after 1000 seconds. If the server does not repond +# after 2000 seconds since the lease was granted, client is supposed +# to start REBIND procedure (emergency renewal that allows switching +# to a different server). + "preferred-lifetime": 3000, + "valid-lifetime": 4000, + "renew-timer": 1000, + "rebind-timer": 2000, + +# The following list defines subnets. Each subnet consists of at +# least subnet and pool entries. + "subnet6": [ + { + "pools": [ { "pool": "2001:db8:1::/80" } ], + "subnet": "2001:db8:1::/64", + "interface": "eth0" + } + ] +}, + +# The following configures logging. Kea will log all debug messages +# to /var/log/kea-debug.log file. +"Logging": { + "loggers": [ + { + "name": "kea-dhcp6", + "output_options": [ + { + "output": "/var/log/kea-debug.log" + } + ], + "debuglevel": 99, + "severity": "DEBUG" + } + ] +} + +} diff --git a/doc/examples/kea6/simple.json b/doc/examples/kea6/simple.json index e266d0ba10..dec58f42b8 100644 --- a/doc/examples/kea6/simple.json +++ b/doc/examples/kea6/simple.json @@ -1,5 +1,5 @@ # This is an example configuration file for DHCPv6 server in Kea. -# It's a basic scenario with four IPv6 subnets configured. It is +# It's a basic scenario with one IPv6 subnet configured. It is # assumed that one subnet (2001:db8:1::/64 is available directly # over eth0 interface. From a98bfd3927c5f2d5d78ec5c60b420aafb1c5c48e Mon Sep 17 00:00:00 2001 From: Tomek Mrugalski Date: Tue, 23 Dec 2014 11:41:43 +0100 Subject: [PATCH 06/12] [3554] Config examples updated - clarified that order in mac-sources is important - tweaked all examples to use eth9 rather than more common eth0 --- doc/examples/kea4/multiple-options.json | 4 ++-- doc/examples/kea4/several-subnets.json | 4 ++-- doc/examples/kea4/single-subnet.json | 4 ++-- doc/examples/kea6/advanced.json | 11 +++++++++-- doc/examples/kea6/multiple-options.json | 4 ++-- doc/examples/kea6/several-subnets.json | 4 ++-- doc/examples/kea6/simple.json | 4 ++-- 7 files changed, 21 insertions(+), 14 deletions(-) diff --git a/doc/examples/kea4/multiple-options.json b/doc/examples/kea4/multiple-options.json index 9b125dc1b9..9b66c01501 100644 --- a/doc/examples/kea4/multiple-options.json +++ b/doc/examples/kea4/multiple-options.json @@ -4,8 +4,8 @@ { "Dhcp4": { -# Kea is told to listen on eth0 interface only. - "interfaces": [ "eth0" ], +# Kea is told to listen on eth9 interface only. + "interfaces": [ "eth9" ], # We need to specify lease type. As of May 2014, three backends are supported: # memfile, mysql and pgsql. We'll just use memfile, because it doesn't require diff --git a/doc/examples/kea4/several-subnets.json b/doc/examples/kea4/several-subnets.json index aff824b640..006ae51d77 100644 --- a/doc/examples/kea4/several-subnets.json +++ b/doc/examples/kea4/several-subnets.json @@ -5,8 +5,8 @@ { "Dhcp4": { -# Kea is told to listen on eth0 interface only. - "interfaces": [ "eth0" ], +# Kea is told to listen on eth9 interface only. + "interfaces": [ "eth9" ], # We need to specify lease type. As of May 2014, three backends are supported: # memfile, mysql and pgsql. We'll just use memfile, because it doesn't require diff --git a/doc/examples/kea4/single-subnet.json b/doc/examples/kea4/single-subnet.json index 0c2e10ca07..9edb61905b 100644 --- a/doc/examples/kea4/single-subnet.json +++ b/doc/examples/kea4/single-subnet.json @@ -5,8 +5,8 @@ { "Dhcp4": { -# Kea is told to listen on eth0 interface only. - "interfaces": [ "eth0" ], +# Kea is told to listen on eth9 interface only. + "interfaces": [ "eth9" ], # We need to specify lease type. As of May 2014, three backends are supported: # memfile, mysql and pgsql. We'll just use memfile, because it doesn't require diff --git a/doc/examples/kea6/advanced.json b/doc/examples/kea6/advanced.json index 0cee002050..426f902f56 100644 --- a/doc/examples/kea6/advanced.json +++ b/doc/examples/kea6/advanced.json @@ -3,12 +3,15 @@ # Topology wise, it's a basic scenario with one IPv6 subnet configured. # It is assumed that one subnet (2001:db8:1::/64) is available directly # over eth0 interface. +# +# The following features are currently showcased here: +# 1. Configuration of MAC/hardware address sources in DHCPv6 { "Dhcp6": { -# Kea is told to listen on eth0 interface only. - "interfaces": [ "eth0" ], +# Kea is told to listen on eth9 interface only. + "interfaces": [ "eth9" ], # We need to specify lease type. As of May 2014, three backends are supported: # memfile, mysql and pgsql. We'll just use memfile, because it doesn't require @@ -27,6 +30,10 @@ # alias for remote-id, subscriber-id, rfc4580 (which is an alias for # subscriber-id) and docsis. # +# Note that the order matters. Methods are attempted one by one in the order +# specified until hardware address is obtained. If you don't care which method +# is used, using 'any' is marginally faster than enumerating them all. +# # If mac-sources are not specified, a default value of 'any' is used. "mac-sources": [ "client-link-addr-option", "duid", "ipv6-link-local" ], diff --git a/doc/examples/kea6/multiple-options.json b/doc/examples/kea6/multiple-options.json index 682b3b5102..333192e714 100644 --- a/doc/examples/kea6/multiple-options.json +++ b/doc/examples/kea6/multiple-options.json @@ -4,8 +4,8 @@ { "Dhcp6": { -# Kea is told to listen on eth0 interface only. - "interfaces": [ "eth0" ], +# Kea is told to listen on eth9 interface only. + "interfaces": [ "eth9" ], # We need to specify lease type. As of May 2014, three backends are supported: # memfile, mysql and pgsql. We'll just use memfile, because it doesn't require diff --git a/doc/examples/kea6/several-subnets.json b/doc/examples/kea6/several-subnets.json index f138c059ea..78a090bea0 100644 --- a/doc/examples/kea6/several-subnets.json +++ b/doc/examples/kea6/several-subnets.json @@ -5,8 +5,8 @@ { "Dhcp6": { -# Kea is told to listen on eth0 interface only. - "interfaces": [ "eth0" ], +# Kea is told to listen on eth9 interface only. + "interfaces": [ "eth9" ], # We need to specify lease type. As of May 2014, three backends are supported: # memfile, mysql and pgsql. We'll just use memfile, because it doesn't require diff --git a/doc/examples/kea6/simple.json b/doc/examples/kea6/simple.json index dec58f42b8..3ac9fc1f10 100644 --- a/doc/examples/kea6/simple.json +++ b/doc/examples/kea6/simple.json @@ -6,8 +6,8 @@ { "Dhcp6": { -# Kea is told to listen on eth0 interface only. - "interfaces": [ "eth0" ], +# Kea is told to listen on eth9 interface only. + "interfaces": [ "eth9" ], # We need to specify lease type. As of May 2014, three backends are supported: # memfile, mysql and pgsql. We'll just use memfile, because it doesn't require From be7879090910513f1dffa740e4a84438a7236032 Mon Sep 17 00:00:00 2001 From: Tomek Mrugalski Date: Tue, 23 Dec 2014 13:17:59 +0100 Subject: [PATCH 07/12] [3554] config examples updated: eth9 -> ethX --- doc/examples/kea4/multiple-options.json | 4 ++-- doc/examples/kea4/several-subnets.json | 4 ++-- doc/examples/kea4/single-subnet.json | 4 ++-- doc/examples/kea6/advanced.json | 4 ++-- doc/examples/kea6/multiple-options.json | 4 ++-- doc/examples/kea6/several-subnets.json | 4 ++-- doc/examples/kea6/simple.json | 4 ++-- 7 files changed, 14 insertions(+), 14 deletions(-) diff --git a/doc/examples/kea4/multiple-options.json b/doc/examples/kea4/multiple-options.json index 9b66c01501..ba8045e29c 100644 --- a/doc/examples/kea4/multiple-options.json +++ b/doc/examples/kea4/multiple-options.json @@ -4,8 +4,8 @@ { "Dhcp4": { -# Kea is told to listen on eth9 interface only. - "interfaces": [ "eth9" ], +# Kea is told to listen on ethX interface only. + "interfaces": [ "ethX" ], # We need to specify lease type. As of May 2014, three backends are supported: # memfile, mysql and pgsql. We'll just use memfile, because it doesn't require diff --git a/doc/examples/kea4/several-subnets.json b/doc/examples/kea4/several-subnets.json index 006ae51d77..b8576a9f23 100644 --- a/doc/examples/kea4/several-subnets.json +++ b/doc/examples/kea4/several-subnets.json @@ -5,8 +5,8 @@ { "Dhcp4": { -# Kea is told to listen on eth9 interface only. - "interfaces": [ "eth9" ], +# Kea is told to listen on ethX interface only. + "interfaces": [ "ethX" ], # We need to specify lease type. As of May 2014, three backends are supported: # memfile, mysql and pgsql. We'll just use memfile, because it doesn't require diff --git a/doc/examples/kea4/single-subnet.json b/doc/examples/kea4/single-subnet.json index 9edb61905b..169d41c986 100644 --- a/doc/examples/kea4/single-subnet.json +++ b/doc/examples/kea4/single-subnet.json @@ -5,8 +5,8 @@ { "Dhcp4": { -# Kea is told to listen on eth9 interface only. - "interfaces": [ "eth9" ], +# Kea is told to listen on ethX interface only. + "interfaces": [ "ethX" ], # We need to specify lease type. As of May 2014, three backends are supported: # memfile, mysql and pgsql. We'll just use memfile, because it doesn't require diff --git a/doc/examples/kea6/advanced.json b/doc/examples/kea6/advanced.json index 426f902f56..8b1f340fdd 100644 --- a/doc/examples/kea6/advanced.json +++ b/doc/examples/kea6/advanced.json @@ -10,8 +10,8 @@ { "Dhcp6": { -# Kea is told to listen on eth9 interface only. - "interfaces": [ "eth9" ], +# Kea is told to listen on ethX network interface only. + "interfaces": [ "ethX" ], # We need to specify lease type. As of May 2014, three backends are supported: # memfile, mysql and pgsql. We'll just use memfile, because it doesn't require diff --git a/doc/examples/kea6/multiple-options.json b/doc/examples/kea6/multiple-options.json index 333192e714..70f2794a73 100644 --- a/doc/examples/kea6/multiple-options.json +++ b/doc/examples/kea6/multiple-options.json @@ -4,8 +4,8 @@ { "Dhcp6": { -# Kea is told to listen on eth9 interface only. - "interfaces": [ "eth9" ], +# Kea is told to listen on ethX interface only. + "interfaces": [ "ethX" ], # We need to specify lease type. As of May 2014, three backends are supported: # memfile, mysql and pgsql. We'll just use memfile, because it doesn't require diff --git a/doc/examples/kea6/several-subnets.json b/doc/examples/kea6/several-subnets.json index 78a090bea0..d9744053fe 100644 --- a/doc/examples/kea6/several-subnets.json +++ b/doc/examples/kea6/several-subnets.json @@ -5,8 +5,8 @@ { "Dhcp6": { -# Kea is told to listen on eth9 interface only. - "interfaces": [ "eth9" ], +# Kea is told to listen on ethX interface only. + "interfaces": [ "ethX" ], # We need to specify lease type. As of May 2014, three backends are supported: # memfile, mysql and pgsql. We'll just use memfile, because it doesn't require diff --git a/doc/examples/kea6/simple.json b/doc/examples/kea6/simple.json index 3ac9fc1f10..7d8e80fea9 100644 --- a/doc/examples/kea6/simple.json +++ b/doc/examples/kea6/simple.json @@ -6,8 +6,8 @@ { "Dhcp6": { -# Kea is told to listen on eth9 interface only. - "interfaces": [ "eth9" ], +# Kea is told to listen on ethX interface only. + "interfaces": [ "ethX" ], # We need to specify lease type. As of May 2014, three backends are supported: # memfile, mysql and pgsql. We'll just use memfile, because it doesn't require From 33a90f024176075eb20020298004ab67dc7dcf2c Mon Sep 17 00:00:00 2001 From: Tomek Mrugalski Date: Tue, 23 Dec 2014 13:18:29 +0100 Subject: [PATCH 08/12] [3554] MAC Sources description in the User's Guide clarified --- doc/guide/dhcp6-srv.xml | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/doc/guide/dhcp6-srv.xml b/doc/guide/dhcp6-srv.xml index 1230886f6e..b59f09209b 100644 --- a/doc/guide/dhcp6-srv.xml +++ b/doc/guide/dhcp6-srv.xml @@ -1840,11 +1840,12 @@ should include options from the isc option space:
MAC/Hardware addresses in DHCPv6 - MAC or hardware addesses are available in DHCPv4 and administrators + MAC/hardware addesses are available in DHCPv4 messages + from the client and administrators frequently use that information to perform certain tasks, like per host configuration, address reserveration for specific MAC addresses and other. Unfortunately, DHCPv6 protocol does not provide any completely reliable way - to access that information. To mitigate that issue a number of mechanisms + to retrieve that information. To mitigate that issue a number of mechanisms has been implemented in Kea that attempts to gather that information. Each of those mechanisms works in certain cases, but may fail in others. There is no single best mechanism as they are somewhat dependent on the network @@ -1852,10 +1853,17 @@ should include options from the isc option space: Kea allows configuration which of the supported methods should be used and in which order. This configuration may be considered a fine tuning - of the DHCP deployment. The format of this parameter is as follows: + of the DHCP deployment. In a typical deployment the default + value of "any" is reasonable and there's no + need to change it. This paramter is the most useful in cases + when an administrator wants to disable certain method, e.g. if you + trust the network infrastructure more than the information + provided by the clients clients themselves, you may prefer + information provided by the relays over that provided by the + clients. The format of this parameter is as follows: "Dhcp6": { - "mac-sources: [ "method1", "method2", "method3", ... ], + "mac-sources": [ "method1", "method2", "method3", ... ], "subnet6": [ ... ], From 2662ac5f02d36a236c796ecb1174876c0d0cee5c Mon Sep 17 00:00:00 2001 From: Tomek Mrugalski Date: Tue, 23 Dec 2014 13:50:20 +0100 Subject: [PATCH 09/12] [3554] Changes after review: - Moved MAC operations to a new CfgMACSource class - Moved macros to HWaddr class - Added several unit-tests for MAC sources - MAC extraction code moved to separate function in Dhcpv6Srv --- src/bin/dhcp6/dhcp6_srv.cc | 32 ++++--- src/bin/dhcp6/dhcp6_srv.h | 9 ++ src/bin/dhcp6/tests/config_parser_unittest.cc | 64 ++++++++++++-- src/bin/dhcp6/tests/dhcp6_client.cc | 2 +- src/lib/dhcp/hwaddr.cc | 10 +++ src/lib/dhcp/hwaddr.h | 47 ++++++++++ src/lib/dhcp/pkt.cc | 52 ++---------- src/lib/dhcp/pkt.h | 64 -------------- src/lib/dhcp/tests/pkt4_unittest.cc | 12 +-- src/lib/dhcp/tests/pkt6_unittest.cc | 75 +++++----------- src/lib/dhcpsrv/Makefile.am | 1 + src/lib/dhcpsrv/cfg_mac_source.cc | 59 +++++++++++++ src/lib/dhcpsrv/cfg_mac_source.h | 85 +++++++++++++++++++ src/lib/dhcpsrv/parsers/dhcp_parsers.cc | 7 +- src/lib/dhcpsrv/srv_config.cc | 6 -- src/lib/dhcpsrv/srv_config.h | 41 ++++----- src/lib/dhcpsrv/tests/Makefile.am | 1 + .../dhcpsrv/tests/cfg_mac_source_unittest.cc | 54 ++++++++++++ .../dhcpsrv/tests/dhcp_parsers_unittest.cc | 7 +- 19 files changed, 406 insertions(+), 222 deletions(-) create mode 100644 src/lib/dhcpsrv/cfg_mac_source.cc create mode 100644 src/lib/dhcpsrv/cfg_mac_source.h create mode 100644 src/lib/dhcpsrv/tests/cfg_mac_source_unittest.cc diff --git a/src/bin/dhcp6/dhcp6_srv.cc b/src/bin/dhcp6/dhcp6_srv.cc index 1d56f7da3c..fc44347866 100644 --- a/src/bin/dhcp6/dhcp6_srv.cc +++ b/src/bin/dhcp6/dhcp6_srv.cc @@ -1184,6 +1184,21 @@ Dhcpv6Srv::createRemovalNameChangeRequest(const Lease6Ptr& lease) { CfgMgr::instance().getD2ClientMgr().sendRequest(ncr); } +HWAddrPtr +Dhcpv6Srv::getMAC(const Pkt6Ptr& pkt) { + CfgMACSources mac_sources = CfgMgr::instance().getCurrentCfg()-> + getMACSources().get(); + HWAddrPtr hwaddr; + for (CfgMACSources::const_iterator it = mac_sources.begin(); + it != mac_sources.end(); ++it) { + hwaddr = pkt->getMAC(*it); + if (hwaddr) { + return (hwaddr); + } + } + return (hwaddr); +} + OptionPtr Dhcpv6Srv::assignIA_NA(const Subnet6Ptr& subnet, const DuidPtr& duid, const Pkt6Ptr& query, const Pkt6Ptr& answer, @@ -1255,16 +1270,7 @@ Dhcpv6Srv::assignIA_NA(const Subnet6Ptr& subnet, const DuidPtr& duid, // Attempt to get MAC address using configured mechanisms. // It's ok if there response is NULL. Hardware address is optional in Lease6. - std::vector mac_sources = CfgMgr::instance().getCurrentCfg()-> - getMACSources(); - HWAddrPtr hwaddr; - for (std::vector::const_iterator it = mac_sources.begin(); - it != mac_sources.end(); ++it) { - hwaddr = query->getMAC(*it); - if (hwaddr) { - break; - } - } + HWAddrPtr hwaddr = getMAC(query); // 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 @@ -1384,8 +1390,7 @@ Dhcpv6Srv::assignIA_PD(const Subnet6Ptr& subnet, const DuidPtr& duid, // 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); + HWAddrPtr hwaddr = getMAC(query); LOG_DEBUG(dhcp6_logger, DBG_DHCP6_DETAIL, DHCP6_PROCESS_IA_PD_REQUEST) .arg(duid ? duid->toText() : "(no-duid)").arg(ia->getIAID()) @@ -1577,6 +1582,9 @@ Dhcpv6Srv::extendIA_NA(const Subnet6Ptr& subnet, const DuidPtr& duid, lease->fqdn_fwd_ = do_fwd; lease->fqdn_rev_ = do_rev; + /// @todo: check if hardware address has changed since last update. + /// And modify lease->hwaddr_ if it did. + ia_rsp->setT1(subnet->getT1()); ia_rsp->setT2(subnet->getT2()); diff --git a/src/bin/dhcp6/dhcp6_srv.h b/src/bin/dhcp6/dhcp6_srv.h index af355c0d7a..f974cc0320 100644 --- a/src/bin/dhcp6/dhcp6_srv.h +++ b/src/bin/dhcp6/dhcp6_srv.h @@ -597,6 +597,15 @@ protected: void classifyPacket(const Pkt6Ptr& pkt); + /// @brief Attempts to get a MAC/hardware address using configred sources + /// + /// Tries to extract MAC/hardware address information from the packet + /// using MAC sources configured in 'mac-sources' directive. + /// + /// @param pkt will try to exact MAC address from this packet + /// @return HWaddr pointer (or NULL if configured methods fail) + HWAddrPtr getMAC(const Pkt6Ptr& pkt); + /// @brief this is a prefix added to the contend of vendor-class option /// /// If incoming packet has a vendor class option, its content is diff --git a/src/bin/dhcp6/tests/config_parser_unittest.cc b/src/bin/dhcp6/tests/config_parser_unittest.cc index 8d6863777b..8682d0b57c 100644 --- a/src/bin/dhcp6/tests/config_parser_unittest.cc +++ b/src/bin/dhcp6/tests/config_parser_unittest.cc @@ -3628,14 +3628,48 @@ TEST_F(Dhcp6ParserTest, reservationBogus) { } /// The goal of this test is to verify that configuration can include -/// MAC/Hardware sources. +/// MAC/Hardware sources. This test also checks if the aliases are +/// handled properly (rfc6939 = client-addr-relay, rfc4649 = remote-id, +/// rfc4580 = subscriber-id). TEST_F(Dhcp6ParserTest, macSources) { ConstElementPtr status; + EXPECT_NO_THROW(status = configureDhcp6Server(srv_, + Element::fromJSON("{ \"interfaces\": [ \"*\" ]," + "\"mac-sources\": [ \"rfc6939\", \"rfc4649\", \"rfc4580\"," + "\"client-link-addr-option\", \"remote-id\", \"subscriber-id\"]," + "\"preferred-lifetime\": 3000," + "\"rebind-timer\": 2000, " + "\"renew-timer\": 1000, " + "\"subnet6\": [ ], " + "\"valid-lifetime\": 4000 }"))); + + // returned value should be 0 (success) + checkResult(status, 0); + + CfgMACSources mac_sources = CfgMgr::instance().getStagingCfg()->getMACSources().get(); + ASSERT_EQ(6, mac_sources.size()); + // Let's check the aliases. They should be recognized to their base methods. + EXPECT_EQ(HWAddr::HWADDR_SOURCE_CLIENT_ADDR_RELAY_OPTION, mac_sources[0]); + EXPECT_EQ(HWAddr::HWADDR_SOURCE_REMOTE_ID, mac_sources[1]); + EXPECT_EQ(HWAddr::HWADDR_SOURCE_SUBSCRIBER_ID, mac_sources[2]); + + // Let's check if the actual methods are recognized properly. + EXPECT_EQ(HWAddr::HWADDR_SOURCE_CLIENT_ADDR_RELAY_OPTION, mac_sources[3]); + EXPECT_EQ(HWAddr::HWADDR_SOURCE_REMOTE_ID, mac_sources[4]); + EXPECT_EQ(HWAddr::HWADDR_SOURCE_SUBSCRIBER_ID, mac_sources[5]); +} + +/// The goal of this test is to verify that MAC sources configuration can be +/// empty. +TEST_F(Dhcp6ParserTest, macSourcesEmpty) { + + ConstElementPtr status; + EXPECT_NO_THROW(status = configureDhcp6Server(srv_, Element::fromJSON("{ \"interfaces\": [ \"*\" ]," - "\"mac-sources\": [ \"rfc6939\", \"rfc4649\", \"rfc4580\" ]," + "\"mac-sources\": [ ]," "\"preferred-lifetime\": 3000," "\"rebind-timer\": 2000, " "\"renew-timer\": 1000, " @@ -3645,11 +3679,27 @@ TEST_F(Dhcp6ParserTest, macSources) { // returned value should be 0 (success) checkResult(status, 0); - vector mac_sources = CfgMgr::instance().getStagingCfg()->getMACSources(); - ASSERT_EQ(3, mac_sources.size()); - EXPECT_EQ(Pkt::HWADDR_SOURCE_CLIENT_ADDR_RELAY_OPTION, mac_sources[0]); - EXPECT_EQ(Pkt::HWADDR_SOURCE_REMOTE_ID, mac_sources[1]); - EXPECT_EQ(Pkt::HWADDR_SOURCE_SUBSCRIBER_ID, mac_sources[2]); + CfgMACSources mac_sources = CfgMgr::instance().getStagingCfg()->getMACSources().get(); + EXPECT_EQ(0, mac_sources.size()); +} + +/// The goal of this test is to verify that MAC sources configuration can +/// only use valid parameters. +TEST_F(Dhcp6ParserTest, macSourcesBogus) { + + ConstElementPtr status; + + EXPECT_NO_THROW(status = configureDhcp6Server(srv_, + Element::fromJSON("{ \"interfaces\": [ \"*\" ]," + "\"mac-sources\": [ \"from-wire\" ]," + "\"preferred-lifetime\": 3000," + "\"rebind-timer\": 2000, " + "\"renew-timer\": 1000, " + "\"subnet6\": [ ], " + "\"valid-lifetime\": 4000 }"))); + + // returned value should be 1 (failure) + checkResult(status, 1); } }; diff --git a/src/bin/dhcp6/tests/dhcp6_client.cc b/src/bin/dhcp6/tests/dhcp6_client.cc index b4feb3c199..4e5a9108a8 100644 --- a/src/bin/dhcp6/tests/dhcp6_client.cc +++ b/src/bin/dhcp6/tests/dhcp6_client.cc @@ -63,7 +63,7 @@ Dhcp6Client::applyRcvdConfiguration(const Pkt6Ptr& reply) { Opts opts = reply->options_; // Let's try to get a MAC - HWAddrPtr hwaddr = reply->getMAC(Pkt::HWADDR_SOURCE_ANY); + HWAddrPtr hwaddr = reply->getMAC(HWAddr::HWADDR_SOURCE_ANY); // Set the global status code to default: success and not received. config_.resetGlobalStatusCode(); diff --git a/src/lib/dhcp/hwaddr.cc b/src/lib/dhcp/hwaddr.cc index 6be98a6770..5d76ec723d 100644 --- a/src/lib/dhcp/hwaddr.cc +++ b/src/lib/dhcp/hwaddr.cc @@ -27,6 +27,16 @@ namespace isc { namespace dhcp { +const uint32_t HWAddr::HWADDR_SOURCE_ANY = 0xffffffff; +const uint32_t HWAddr::HWADDR_SOURCE_UNKNOWN = 0x00000000; +const uint32_t HWAddr::HWADDR_SOURCE_RAW = 0x00000001; +const uint32_t HWAddr::HWADDR_SOURCE_DUID = 0x00000002; +const uint32_t HWAddr::HWADDR_SOURCE_IPV6_LINK_LOCAL = 0x00000004; +const uint32_t HWAddr::HWADDR_SOURCE_CLIENT_ADDR_RELAY_OPTION = 0x00000008; +const uint32_t HWAddr::HWADDR_SOURCE_REMOTE_ID = 0x00000010; +const uint32_t HWAddr::HWADDR_SOURCE_SUBSCRIBER_ID = 0x00000020; +const uint32_t HWAddr::HWADDR_SOURCE_DOCSIS = 0x00000040; + HWAddr::HWAddr() :htype_(HTYPE_ETHER), source_(0) { } diff --git a/src/lib/dhcp/hwaddr.h b/src/lib/dhcp/hwaddr.h index 0c7f21675a..3aa2046a1c 100644 --- a/src/lib/dhcp/hwaddr.h +++ b/src/lib/dhcp/hwaddr.h @@ -34,6 +34,53 @@ public: /// @brief Maximum size of a hardware address. static const size_t MAX_HWADDR_LEN = 20; + /// @defgroup hw_sources Specifies where a given MAC/hardware address was + /// obtained. + /// + /// @brief The list covers all possible MAC/hw address sources. + /// + /// @{ + + /// Not really a type, only used in getMAC() calls. + 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; + + /// Obtained first hand from raw socket (100% reliable). + 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; + + /// 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; + + /// 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; + + /// A relay can insert remote-id. In some deployments it contains a MAC + /// address (RFC4649). + 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; + + /// 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; + + /// @} + /// @brief default constructor HWAddr(); diff --git a/src/lib/dhcp/pkt.cc b/src/lib/dhcp/pkt.cc index c5abdcc0e7..72e0f86742 100644 --- a/src/lib/dhcp/pkt.cc +++ b/src/lib/dhcp/pkt.cc @@ -15,21 +15,12 @@ #include #include #include +#include #include 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) @@ -139,11 +130,11 @@ Pkt::getMAC(uint32_t hw_addr_src) { HWAddrPtr mac; // Method 1: from raw sockets. - if (hw_addr_src & HWADDR_SOURCE_RAW) { + if (hw_addr_src & HWAddr::HWADDR_SOURCE_RAW) { mac = getRemoteHWAddr(); if (mac) { return (mac); - } else if (hw_addr_src == HWADDR_SOURCE_RAW) { + } else if (hw_addr_src == HWAddr::HWADDR_SOURCE_RAW) { // If we're interested only in RAW sockets as source of that info, // there's no point in trying other options. return (HWAddrPtr()); @@ -153,11 +144,11 @@ Pkt::getMAC(uint32_t hw_addr_src) { // Method 2: Extracted from DUID-LLT or DUID-LL // Method 3: Extracted from source IPv6 link-local address - if (hw_addr_src & HWADDR_SOURCE_IPV6_LINK_LOCAL) { + if (hw_addr_src & HWAddr::HWADDR_SOURCE_IPV6_LINK_LOCAL) { mac = getMACFromSrcLinkLocalAddr(); if (mac) { return (mac); - } else if (hw_addr_src == HWADDR_SOURCE_IPV6_LINK_LOCAL) { + } else if (hw_addr_src == HWAddr::HWADDR_SOURCE_IPV6_LINK_LOCAL) { // If we're interested only in link-local addr as source of that // info, there's no point in trying other options. return (HWAddrPtr()); @@ -165,11 +156,11 @@ 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) { + if (hw_addr_src & HWAddr::HWADDR_SOURCE_CLIENT_ADDR_RELAY_OPTION) { mac = getMACFromIPv6RelayOpt(); if (mac) { return (mac); - } else if (hw_addr_src == HWADDR_SOURCE_CLIENT_ADDR_RELAY_OPTION) { + } else if (hw_addr_src == HWAddr::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()); @@ -233,34 +224,5 @@ Pkt::getMACFromIPv6(const isc::asiolink::IOAddress& addr) { return (HWAddrPtr(new HWAddr(bin, hwtype))); } -uint32_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) == 0) { - return (sources[i].type); - } - } - - isc_throw(BadValue, "Can't convert '" << name << "' to any known MAC source."); -} - - }; }; diff --git a/src/lib/dhcp/pkt.h b/src/lib/dhcp/pkt.h index 24bb1ee690..2b5e73f4bf 100644 --- a/src/lib/dhcp/pkt.h +++ b/src/lib/dhcp/pkt.h @@ -37,70 +37,6 @@ namespace dhcp { /// @note This is abstract class. Please instantiate derived classes /// such as @c Pkt4 or @c Pkt6. class Pkt { -public: - - /// @defgroup hw_sources Specifies where a given MAC/hardware address was - /// obtained. - /// - /// @brief The list covers all possible MAC/hw address sources. - /// - /// @{ - - /// Not really a type, only used in getMAC() calls. - 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; - - /// Obtained first hand from raw socket (100% reliable). - 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; - - /// 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; - - /// 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; - - /// A relay can insert remote-id. In some deployments it contains a MAC - /// address (RFC4649). - 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; - - /// 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; - - /// @} - - /// @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 uint32_t MACSourceFromText(const std::string& name); - protected: /// @brief Constructor. diff --git a/src/lib/dhcp/tests/pkt4_unittest.cc b/src/lib/dhcp/tests/pkt4_unittest.cc index ae39d8906b..1ebf77125a 100644 --- a/src/lib/dhcp/tests/pkt4_unittest.cc +++ b/src/lib/dhcp/tests/pkt4_unittest.cc @@ -857,8 +857,8 @@ TEST_F(Pkt4Test, getMAC) { Pkt4 pkt(DHCPOFFER, 1234); // DHCPv4 packet by default doens't have MAC address specified. - EXPECT_FALSE(pkt.getMAC(Pkt::HWADDR_SOURCE_ANY)); - EXPECT_FALSE(pkt.getMAC(Pkt::HWADDR_SOURCE_RAW)); + EXPECT_FALSE(pkt.getMAC(HWAddr::HWADDR_SOURCE_ANY)); + EXPECT_FALSE(pkt.getMAC(HWAddr::HWADDR_SOURCE_RAW)); // Let's invent a MAC const uint8_t hw[] = { 2, 4, 6, 8, 10, 12 }; // MAC @@ -869,12 +869,12 @@ TEST_F(Pkt4Test, getMAC) { pkt.setRemoteHWAddr(dummy_hwaddr); // Now we should be able to get something - ASSERT_TRUE(pkt.getMAC(Pkt::HWADDR_SOURCE_ANY)); - ASSERT_TRUE(pkt.getMAC(Pkt::HWADDR_SOURCE_RAW)); + ASSERT_TRUE(pkt.getMAC(HWAddr::HWADDR_SOURCE_ANY)); + ASSERT_TRUE(pkt.getMAC(HWAddr::HWADDR_SOURCE_RAW)); // Check that the returned MAC is indeed the expected one - ASSERT_TRUE(*dummy_hwaddr == *pkt.getMAC(Pkt::HWADDR_SOURCE_ANY)); - ASSERT_TRUE(*dummy_hwaddr == *pkt.getMAC(Pkt::HWADDR_SOURCE_RAW)); + ASSERT_TRUE(*dummy_hwaddr == *pkt.getMAC(HWAddr::HWADDR_SOURCE_ANY)); + ASSERT_TRUE(*dummy_hwaddr == *pkt.getMAC(HWAddr::HWADDR_SOURCE_RAW)); } } // end of anonymous namespace diff --git a/src/lib/dhcp/tests/pkt6_unittest.cc b/src/lib/dhcp/tests/pkt6_unittest.cc index 1827f9d219..a015c04f3b 100644 --- a/src/lib/dhcp/tests/pkt6_unittest.cc +++ b/src/lib/dhcp/tests/pkt6_unittest.cc @@ -883,20 +883,20 @@ TEST_F(Pkt6Test, getMAC) { Pkt6 pkt(DHCPV6_ADVERTISE, 1234); // DHCPv6 packet by default doens't have MAC address specified. - EXPECT_FALSE(pkt.getMAC(Pkt::HWADDR_SOURCE_ANY)); - EXPECT_FALSE(pkt.getMAC(Pkt::HWADDR_SOURCE_RAW)); + EXPECT_FALSE(pkt.getMAC(HWAddr::HWADDR_SOURCE_ANY)); + EXPECT_FALSE(pkt.getMAC(HWAddr::HWADDR_SOURCE_RAW)); // We haven't specified source IPv6 address, so this method should // fail, too - EXPECT_FALSE(pkt.getMAC(Pkt::HWADDR_SOURCE_IPV6_LINK_LOCAL)); + EXPECT_FALSE(pkt.getMAC(HWAddr::HWADDR_SOURCE_IPV6_LINK_LOCAL)); // 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(Pkt::HWADDR_SOURCE_ANY)); - EXPECT_TRUE(pkt.getMAC(Pkt::HWADDR_SOURCE_IPV6_LINK_LOCAL)); - EXPECT_TRUE(pkt.getMAC(Pkt::HWADDR_SOURCE_IPV6_LINK_LOCAL | - Pkt::HWADDR_SOURCE_RAW)); + 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)); pkt.setRemoteAddr(IOAddress("::")); // Let's invent a MAC @@ -908,14 +908,14 @@ TEST_F(Pkt6Test, getMAC) { pkt.setRemoteHWAddr(dummy_hwaddr); // Now we should be able to get something - ASSERT_TRUE(pkt.getMAC(Pkt::HWADDR_SOURCE_ANY)); - ASSERT_TRUE(pkt.getMAC(Pkt::HWADDR_SOURCE_RAW)); - EXPECT_TRUE(pkt.getMAC(Pkt::HWADDR_SOURCE_IPV6_LINK_LOCAL | - Pkt::HWADDR_SOURCE_RAW)); + ASSERT_TRUE(pkt.getMAC(HWAddr::HWADDR_SOURCE_ANY)); + ASSERT_TRUE(pkt.getMAC(HWAddr::HWADDR_SOURCE_RAW)); + EXPECT_TRUE(pkt.getMAC(HWAddr::HWADDR_SOURCE_IPV6_LINK_LOCAL | + HWAddr::HWADDR_SOURCE_RAW)); // Check that the returned MAC is indeed the expected one - ASSERT_TRUE(*dummy_hwaddr == *pkt.getMAC(Pkt::HWADDR_SOURCE_ANY)); - ASSERT_TRUE(*dummy_hwaddr == *pkt.getMAC(Pkt::HWADDR_SOURCE_RAW)); + ASSERT_TRUE(*dummy_hwaddr == *pkt.getMAC(HWAddr::HWADDR_SOURCE_ANY)); + ASSERT_TRUE(*dummy_hwaddr == *pkt.getMAC(HWAddr::HWADDR_SOURCE_RAW)); } // Test checks whether getMACFromIPv6LinkLocal() returns the hardware (MAC) @@ -941,11 +941,11 @@ TEST_F(Pkt6Test, getMACFromIPv6LinkLocal_direct) { // If received from a global address, this method should fail pkt.setRemoteAddr(global); - EXPECT_FALSE(pkt.getMAC(Pkt::HWADDR_SOURCE_IPV6_LINK_LOCAL)); + EXPECT_FALSE(pkt.getMAC(HWAddr::HWADDR_SOURCE_IPV6_LINK_LOCAL)); // If received from link-local that is EUI-64 based, it should succeed pkt.setRemoteAddr(linklocal_eui64); - HWAddrPtr found = pkt.getMAC(Pkt::HWADDR_SOURCE_IPV6_LINK_LOCAL); + HWAddrPtr found = pkt.getMAC(HWAddr::HWADDR_SOURCE_IPV6_LINK_LOCAL); ASSERT_TRUE(found); stringstream tmp; @@ -980,15 +980,15 @@ TEST_F(Pkt6Test, getMACFromIPv6LinkLocal_singleRelay) { // If received from a global address, this method should fail pkt.relay_info_[0].peeraddr_ = global; - EXPECT_FALSE(pkt.getMAC(Pkt::HWADDR_SOURCE_IPV6_LINK_LOCAL)); + EXPECT_FALSE(pkt.getMAC(HWAddr::HWADDR_SOURCE_IPV6_LINK_LOCAL)); // If received from a link-local that does not use EUI-64, it should fail pkt.relay_info_[0].peeraddr_ = linklocal_noneui64; - EXPECT_FALSE(pkt.getMAC(Pkt::HWADDR_SOURCE_IPV6_LINK_LOCAL)); + EXPECT_FALSE(pkt.getMAC(HWAddr::HWADDR_SOURCE_IPV6_LINK_LOCAL)); // If received from link-local that is EUI-64 based, it should succeed pkt.relay_info_[0].peeraddr_ = linklocal_eui64; - HWAddrPtr found = pkt.getMAC(Pkt::HWADDR_SOURCE_IPV6_LINK_LOCAL); + HWAddrPtr found = pkt.getMAC(HWAddr::HWADDR_SOURCE_IPV6_LINK_LOCAL); ASSERT_TRUE(found); stringstream tmp; @@ -1041,7 +1041,7 @@ TEST_F(Pkt6Test, getMACFromIPv6LinkLocal_multiRelay) { pkt.setIndex(iface->getIndex()); // The method should return MAC based on the first relay that was closest - HWAddrPtr found = pkt.getMAC(Pkt::HWADDR_SOURCE_IPV6_LINK_LOCAL); + HWAddrPtr found = pkt.getMAC(HWAddr::HWADDR_SOURCE_IPV6_LINK_LOCAL); ASSERT_TRUE(found); // Let's check the info now. @@ -1058,7 +1058,7 @@ TEST_F(Pkt6Test, getMACFromIPv6RelayOpt_singleRelay) { Pkt6 pkt(DHCPV6_SOLICIT, 1234); // Packets that are not relayed should fail - EXPECT_FALSE(pkt.getMAC(Pkt::HWADDR_SOURCE_CLIENT_ADDR_RELAY_OPTION)); + EXPECT_FALSE(pkt.getMAC(HWAddr::HWADDR_SOURCE_CLIENT_ADDR_RELAY_OPTION)); // Now pretend it was relayed by a single relay. Pkt6::RelayInfo info; @@ -1075,7 +1075,7 @@ TEST_F(Pkt6Test, getMACFromIPv6RelayOpt_singleRelay) { pkt.addRelayInfo(info); ASSERT_EQ(1, pkt.relay_info_.size()); - HWAddrPtr found = pkt.getMAC(Pkt::HWADDR_SOURCE_CLIENT_ADDR_RELAY_OPTION); + HWAddrPtr found = pkt.getMAC(HWAddr::HWADDR_SOURCE_CLIENT_ADDR_RELAY_OPTION); ASSERT_TRUE(found); stringstream tmp; @@ -1108,7 +1108,7 @@ TEST_F(Pkt6Test, getMACFromIPv6RelayOpt_multipleRelay) { pkt.addRelayInfo(info2); ASSERT_EQ(2, pkt.relay_info_.size()); - EXPECT_FALSE(pkt.getMAC(Pkt::HWADDR_SOURCE_CLIENT_ADDR_RELAY_OPTION)); + EXPECT_FALSE(pkt.getMAC(HWAddr::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. @@ -1123,7 +1123,7 @@ TEST_F(Pkt6Test, getMACFromIPv6RelayOpt_multipleRelay) { 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); + HWAddrPtr found = pkt.getMAC(HWAddr::HWADDR_SOURCE_CLIENT_ADDR_RELAY_OPTION); ASSERT_TRUE(found); stringstream tmp; @@ -1131,33 +1131,4 @@ TEST_F(Pkt6Test, getMACFromIPv6RelayOpt_multipleRelay) { EXPECT_EQ(tmp.str(), found->toText(true)); } -// Checks whether Pkt::MACSourceFromText is working correctly. -// Technically, this is a Pkt, not Pkt6 test, but since there is no separate -// unit-tests for Pkt and it is abstract, so it would be tricky to test it -// directly. Hence test is being run in Pkt6. -TEST_F(Pkt6Test, MACSourceFromText) { - EXPECT_THROW(Pkt::MACSourceFromText("unknown"), BadValue); - - EXPECT_EQ(Pkt::HWADDR_SOURCE_ANY, Pkt::MACSourceFromText("any")); - EXPECT_EQ(Pkt::HWADDR_SOURCE_RAW, Pkt::MACSourceFromText("raw")); - EXPECT_EQ(Pkt::HWADDR_SOURCE_DUID, Pkt::MACSourceFromText("duid")); - EXPECT_EQ(Pkt::HWADDR_SOURCE_IPV6_LINK_LOCAL, - Pkt::MACSourceFromText("ipv6-link-local")); - EXPECT_EQ(Pkt::HWADDR_SOURCE_CLIENT_ADDR_RELAY_OPTION, - Pkt::MACSourceFromText("client-link-addr-option")); - EXPECT_EQ(Pkt::HWADDR_SOURCE_CLIENT_ADDR_RELAY_OPTION, - Pkt::MACSourceFromText("rfc6939")); - EXPECT_EQ(Pkt::HWADDR_SOURCE_REMOTE_ID, - Pkt::MACSourceFromText("remote-id")); - EXPECT_EQ(Pkt::HWADDR_SOURCE_REMOTE_ID, - Pkt::MACSourceFromText("rfc4649")); - EXPECT_EQ(Pkt::HWADDR_SOURCE_SUBSCRIBER_ID, - Pkt::MACSourceFromText("subscriber-id")); - EXPECT_EQ(Pkt::HWADDR_SOURCE_SUBSCRIBER_ID, - Pkt::MACSourceFromText("rfc4580")); - EXPECT_EQ(Pkt::HWADDR_SOURCE_DOCSIS, - Pkt::MACSourceFromText("docsis")); - -} - } diff --git a/src/lib/dhcpsrv/Makefile.am b/src/lib/dhcpsrv/Makefile.am index 062ef8ef57..7e1cb28120 100644 --- a/src/lib/dhcpsrv/Makefile.am +++ b/src/lib/dhcpsrv/Makefile.am @@ -69,6 +69,7 @@ libkea_dhcpsrv_la_SOURCES += cfg_option.cc cfg_option.h libkea_dhcpsrv_la_SOURCES += cfg_option_def.cc cfg_option_def.h libkea_dhcpsrv_la_SOURCES += cfg_subnets4.cc cfg_subnets4.h libkea_dhcpsrv_la_SOURCES += cfg_subnets6.cc cfg_subnets6.h +libkea_dhcpsrv_la_SOURCES += cfg_mac_source.cc cfg_mac_source.h libkea_dhcpsrv_la_SOURCES += cfgmgr.cc cfgmgr.h libkea_dhcpsrv_la_SOURCES += csv_lease_file4.cc csv_lease_file4.h libkea_dhcpsrv_la_SOURCES += csv_lease_file6.cc csv_lease_file6.h diff --git a/src/lib/dhcpsrv/cfg_mac_source.cc b/src/lib/dhcpsrv/cfg_mac_source.cc new file mode 100644 index 0000000000..715820bd07 --- /dev/null +++ b/src/lib/dhcpsrv/cfg_mac_source.cc @@ -0,0 +1,59 @@ +// Copyright (C) 2014 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 +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH +// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, +// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE +// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +// PERFORMANCE OF THIS SOFTWARE. + +#include +#include +#include +#include + +namespace isc { +namespace dhcp { + +CfgMACSource::CfgMACSource() { + + // By default, use any hardware source that is available. + mac_sources_.push_back(HWAddr::HWADDR_SOURCE_ANY); +} + +uint32_t CfgMACSource::MACSourceFromText(const std::string& name) { + + struct { + const char * name; + uint32_t type; + } sources[] = { + { "any", HWAddr::HWADDR_SOURCE_ANY }, + { "raw", HWAddr::HWADDR_SOURCE_RAW }, + { "duid", HWAddr::HWADDR_SOURCE_DUID }, + { "ipv6-link-local", HWAddr::HWADDR_SOURCE_IPV6_LINK_LOCAL }, + { "client-link-addr-option", HWAddr::HWADDR_SOURCE_CLIENT_ADDR_RELAY_OPTION }, + { "rfc6939", HWAddr::HWADDR_SOURCE_CLIENT_ADDR_RELAY_OPTION }, + { "remote-id", HWAddr::HWADDR_SOURCE_REMOTE_ID }, + { "rfc4649", HWAddr::HWADDR_SOURCE_REMOTE_ID }, + { "subscriber-id", HWAddr::HWADDR_SOURCE_SUBSCRIBER_ID }, + { "rfc4580", HWAddr::HWADDR_SOURCE_SUBSCRIBER_ID }, + { "docsis", HWAddr::HWADDR_SOURCE_DOCSIS } + }; + + for (int i=0; i < sizeof(sources)/sizeof(sources[0]); ++i) { + if (name.compare(sources[i].name) == 0) { + return (sources[i].type); + } + } + + isc_throw(BadValue, "Can't convert '" << name << "' to any known MAC source."); +} + + +}; +}; diff --git a/src/lib/dhcpsrv/cfg_mac_source.h b/src/lib/dhcpsrv/cfg_mac_source.h new file mode 100644 index 0000000000..f919a5a8bd --- /dev/null +++ b/src/lib/dhcpsrv/cfg_mac_source.h @@ -0,0 +1,85 @@ +// Copyright (C) 2014 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 +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH +// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, +// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE +// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +// PERFORMANCE OF THIS SOFTWARE. + +#ifndef CFG_MAC_SOURCE_H +#define CFG_MAC_SOURCE_H + +#include + +namespace isc { +namespace dhcp { + +/// @brief Container for defined MAC/hardware address sources +typedef std::vector CfgMACSources; + +/// @brief Wrapper class that holds MAC/hardware address sources +/// +/// It's a simple wrapper around a vector of uint32_t, with each entry +/// holding one MAC source. +class CfgMACSource { + + public: + /// @brief Default constructor. + /// + /// Sets source to 'any'. + CfgMACSource(); + + /// @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 uint32_t MACSourceFromText(const std::string& name); + + + /// @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 add(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 CfgMACSources& get() const { + return mac_sources_; + } + + /// @brief Removes any configured MAC/Hardware address sources. + void clear() { + mac_sources_.clear(); + } + + protected: + /// @brief Actual MAC sources storage + CfgMACSources mac_sources_; + +}; + +}; +}; + +#endif diff --git a/src/lib/dhcpsrv/parsers/dhcp_parsers.cc b/src/lib/dhcpsrv/parsers/dhcp_parsers.cc index 11f96dcc28..bf9a47731f 100644 --- a/src/lib/dhcpsrv/parsers/dhcp_parsers.cc +++ b/src/lib/dhcpsrv/parsers/dhcp_parsers.cc @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -226,13 +227,13 @@ MACSourcesListConfigParser::build(ConstElementPtr value) { // 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(); + CfgMgr::instance().getStagingCfg()->getMACSources().clear(); 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); + source = CfgMACSource::MACSourceFromText(source_str); + CfgMgr::instance().getStagingCfg()->getMACSources().add(source); } catch (const std::exception& ex) { isc_throw(DhcpConfigError, "Failed to convert '" << source_str << "' to any recognized MAC source:" diff --git a/src/lib/dhcpsrv/srv_config.cc b/src/lib/dhcpsrv/srv_config.cc index a33a79cc66..ba2384db0f 100644 --- a/src/lib/dhcpsrv/srv_config.cc +++ b/src/lib/dhcpsrv/srv_config.cc @@ -29,18 +29,12 @@ 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 diff --git a/src/lib/dhcpsrv/srv_config.h b/src/lib/dhcpsrv/srv_config.h index 4f1fc57f78..b7403f4590 100644 --- a/src/lib/dhcpsrv/srv_config.h +++ b/src/lib/dhcpsrv/srv_config.h @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -235,30 +236,24 @@ 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& getMACSources() const { - return mac_sources_; - } - - /// @brief Removes any configured MAC/Hardware address sources. - void clearMACSources() { - mac_sources_.clear(); - } - //@} + /// @brief Returns non-const reference to an array that stores + /// MAC/hardware address sources. + /// + /// @return non-const reference to MAC/hardware address sources + CfgMACSource& getMACSources() { + return (cfg_mac_source_); + } + + /// @brief Returns const reference to an array that stores + /// MAC/hardware address sources. + /// + /// @return const reference to MAC/hardware address sources + const CfgMACSource& getMACSources() const { + return (cfg_mac_source_); + } + /// @brief Copies the currnet configuration to a new configuration. /// /// This method copies the parameters stored in the configuration to @@ -372,7 +367,7 @@ private: CfgHostsPtr cfg_hosts_; /// @brief A list of configured MAC sources. - std::vector mac_sources_; + CfgMACSource cfg_mac_source_; }; /// @name Pointers to the @c SrvConfig object. diff --git a/src/lib/dhcpsrv/tests/Makefile.am b/src/lib/dhcpsrv/tests/Makefile.am index 09b95fc455..8b7d5e212c 100644 --- a/src/lib/dhcpsrv/tests/Makefile.am +++ b/src/lib/dhcpsrv/tests/Makefile.am @@ -57,6 +57,7 @@ libdhcpsrv_unittests_SOURCES += alloc_engine_unittest.cc libdhcpsrv_unittests_SOURCES += callout_handle_store_unittest.cc libdhcpsrv_unittests_SOURCES += cfg_hosts_unittest.cc libdhcpsrv_unittests_SOURCES += cfg_iface_unittest.cc +libdhcpsrv_unittests_SOURCES += cfg_mac_source_unittest.cc libdhcpsrv_unittests_SOURCES += cfg_option_unittest.cc libdhcpsrv_unittests_SOURCES += cfg_option_def_unittest.cc libdhcpsrv_unittests_SOURCES += cfg_subnets4_unittest.cc diff --git a/src/lib/dhcpsrv/tests/cfg_mac_source_unittest.cc b/src/lib/dhcpsrv/tests/cfg_mac_source_unittest.cc new file mode 100644 index 0000000000..ad684aff13 --- /dev/null +++ b/src/lib/dhcpsrv/tests/cfg_mac_source_unittest.cc @@ -0,0 +1,54 @@ +// Copyright (C) 2014 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 +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH +// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, +// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE +// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +// PERFORMANCE OF THIS SOFTWARE. + +#include +#include +#include +#include + +namespace { + +using namespace isc; +using namespace isc::dhcp; + +// Checks whether CfgMACSource::MACSourceFromText is working correctly. +// Technically, this is a Pkt, not Pkt6 test, but since there is no separate +// unit-tests for Pkt and it is abstract, so it would be tricky to test it +// directly. Hence test is being run in Pkt6. +TEST(CfgMACSourceTest, MACSourceFromText) { + EXPECT_THROW(CfgMACSource::MACSourceFromText("unknown"), BadValue); + + EXPECT_EQ(HWAddr::HWADDR_SOURCE_ANY, CfgMACSource::MACSourceFromText("any")); + EXPECT_EQ(HWAddr::HWADDR_SOURCE_RAW, CfgMACSource::MACSourceFromText("raw")); + EXPECT_EQ(HWAddr::HWADDR_SOURCE_DUID, CfgMACSource::MACSourceFromText("duid")); + EXPECT_EQ(HWAddr::HWADDR_SOURCE_IPV6_LINK_LOCAL, + CfgMACSource::MACSourceFromText("ipv6-link-local")); + EXPECT_EQ(HWAddr::HWADDR_SOURCE_CLIENT_ADDR_RELAY_OPTION, + CfgMACSource::MACSourceFromText("client-link-addr-option")); + EXPECT_EQ(HWAddr::HWADDR_SOURCE_CLIENT_ADDR_RELAY_OPTION, + CfgMACSource::MACSourceFromText("rfc6939")); + EXPECT_EQ(HWAddr::HWADDR_SOURCE_REMOTE_ID, + CfgMACSource::MACSourceFromText("remote-id")); + EXPECT_EQ(HWAddr::HWADDR_SOURCE_REMOTE_ID, + CfgMACSource::MACSourceFromText("rfc4649")); + EXPECT_EQ(HWAddr::HWADDR_SOURCE_SUBSCRIBER_ID, + CfgMACSource::MACSourceFromText("subscriber-id")); + EXPECT_EQ(HWAddr::HWADDR_SOURCE_SUBSCRIBER_ID, + CfgMACSource::MACSourceFromText("rfc4580")); + EXPECT_EQ(HWAddr::HWADDR_SOURCE_DOCSIS, + CfgMACSource::MACSourceFromText("docsis")); + +} + +}; diff --git a/src/lib/dhcpsrv/tests/dhcp_parsers_unittest.cc b/src/lib/dhcpsrv/tests/dhcp_parsers_unittest.cc index 4eea46e4da..61b8e9d080 100644 --- a/src/lib/dhcpsrv/tests/dhcp_parsers_unittest.cc +++ b/src/lib/dhcpsrv/tests/dhcp_parsers_unittest.cc @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -306,11 +307,11 @@ TEST_F(DhcpParserTest, MacSourcesListConfigParserTest) { // eth2 was not added. SrvConfigPtr cfg = CfgMgr::instance().getStagingCfg(); ASSERT_TRUE(cfg); - vector configured_sources = cfg->getMACSources(); + CfgMACSources configured_sources = cfg->getMACSources().get(); ASSERT_EQ(2, configured_sources.size()); - EXPECT_EQ(Pkt::HWADDR_SOURCE_DUID, configured_sources[0]); - EXPECT_EQ(Pkt::HWADDR_SOURCE_IPV6_LINK_LOCAL, configured_sources[1]); + EXPECT_EQ(HWAddr::HWADDR_SOURCE_DUID, configured_sources[0]); + EXPECT_EQ(HWAddr::HWADDR_SOURCE_IPV6_LINK_LOCAL, configured_sources[1]); } /// @brief Test Fixture class which provides basic structure for testing From 591cbdb68647a579d41a1a4d14e1bd4e4d9e52ac Mon Sep 17 00:00:00 2001 From: Tomek Mrugalski Date: Tue, 23 Dec 2014 14:07:16 +0100 Subject: [PATCH 10/12] [3554] Doxygen clean-up. --- src/lib/dhcpsrv/cfg_mac_source.h | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/lib/dhcpsrv/cfg_mac_source.h b/src/lib/dhcpsrv/cfg_mac_source.h index f919a5a8bd..a2681254c3 100644 --- a/src/lib/dhcpsrv/cfg_mac_source.h +++ b/src/lib/dhcpsrv/cfg_mac_source.h @@ -37,14 +37,16 @@ class CfgMACSource { /// @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
+ /// Supported strings are: \li any => 0xffffffff + /// \li raw => 0x00000001 + /// \li duid => 0x00000002 + /// \li ipv6-link-local 0x00000004 + /// \li client-link-addr-option, rfc6939 => 0x00000008 + /// \li remote-id, rfc4649 => 0x00000010 + /// \li subscriber-id, rfc4580 => 0x00000020 + /// \li docsis => 0x00000040 + /// + /// For specific constants, see @ref isc::dhcp::HWAddr class. /// /// @throw BadValue if specified string is unknown /// @return bitmask version of a given method From 80b5b1b6dfe0bcbc22f9cf19af32aafe80aa5d6b Mon Sep 17 00:00:00 2001 From: Marcin Siodelski Date: Tue, 23 Dec 2014 15:54:45 +0100 Subject: [PATCH 11/12] [3554] Updated the MAC/HW addresses in DHCPv6 section in the kea-guide. --- doc/guide/dhcp6-srv.xml | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/doc/guide/dhcp6-srv.xml b/doc/guide/dhcp6-srv.xml index b59f09209b..e1974a06c2 100644 --- a/doc/guide/dhcp6-srv.xml +++ b/doc/guide/dhcp6-srv.xml @@ -1841,26 +1841,26 @@ should include options from the isc option space:
MAC/Hardware addresses in DHCPv6 MAC/hardware addesses are available in DHCPv4 messages - from the client and administrators + from the clients and administrators frequently use that information to perform certain tasks, like per host configuration, address reserveration for specific MAC addresses and other. Unfortunately, DHCPv6 protocol does not provide any completely reliable way to retrieve that information. To mitigate that issue a number of mechanisms - has been implemented in Kea that attempts to gather that information. Each - of those mechanisms works in certain cases, but may fail in others. There - is no single best mechanism as they are somewhat dependent on the network - topology and the technologies used. + have been implemented in Kea that attempt to gather that information. Each + of those mechanisms works in certain cases, but may fail in other cases. + Whether the mechanism works or not in the particular deployment is + somewhat dependent on the network topology and the technologies used. - Kea allows configuration which of the supported methods should be + Kea allows for configuration which of the supported methods should be used and in which order. This configuration may be considered a fine tuning of the DHCP deployment. In a typical deployment the default - value of "any" is reasonable and there's no - need to change it. This paramter is the most useful in cases - when an administrator wants to disable certain method, e.g. if you - trust the network infrastructure more than the information - provided by the clients clients themselves, you may prefer - information provided by the relays over that provided by the - clients. The format of this parameter is as follows: + value of "any" is sufficient and there is no + need to select specific methods. Changing the value of this parameter + is the most useful in cases when an administrator wants to disable + certain method, e.g. if the administrator trusts the network infrastructure + more than the information provided by the clients themselves, the + administrator may prefer information provided by the relays over that + provided by the clients. The format of this parameter is as follows: "Dhcp6": { "mac-sources": [ "method1", "method2", "method3", ... ], From c12560be7264a6a80622d219b7385a619e934370 Mon Sep 17 00:00:00 2001 From: Tomek Mrugalski Date: Tue, 23 Dec 2014 16:41:29 +0100 Subject: [PATCH 12/12] [3554] Changes after review: - eth0 => ethX in several examples - added @todo in Dhcp6Srv, getMAC() is now static - added @todo in CfgMACSource --- doc/examples/kea4/multiple-options.json | 2 +- doc/examples/kea4/single-subnet.json | 4 ++-- doc/examples/kea6/advanced.json | 4 ++-- doc/examples/kea6/multiple-options.json | 2 +- doc/examples/kea6/simple.json | 4 ++-- src/bin/dhcp6/dhcp6_srv.h | 5 ++--- src/lib/dhcpsrv/cfg_mac_source.h | 1 + 7 files changed, 11 insertions(+), 11 deletions(-) diff --git a/doc/examples/kea4/multiple-options.json b/doc/examples/kea4/multiple-options.json index ba8045e29c..4130e4c5e6 100644 --- a/doc/examples/kea4/multiple-options.json +++ b/doc/examples/kea4/multiple-options.json @@ -36,7 +36,7 @@ { "pools": [ { "pool": "192.0.2.10 - 192.0.2.200" } ], "subnet": "192.0.2.0/24", - "interface": "eth0", + "interface": "ethX", "option-data": [ { "name": "domain-name-servers", diff --git a/doc/examples/kea4/single-subnet.json b/doc/examples/kea4/single-subnet.json index 169d41c986..28368939d1 100644 --- a/doc/examples/kea4/single-subnet.json +++ b/doc/examples/kea4/single-subnet.json @@ -35,8 +35,8 @@ { "pools": [ { "pool": "192.0.2.1 - 192.0.2.200" } ], "subnet": "192.0.2.0/24", - "interface": "eth0" - } + "interface": "ethX" + } ] }, diff --git a/doc/examples/kea6/advanced.json b/doc/examples/kea6/advanced.json index 8b1f340fdd..1923064657 100644 --- a/doc/examples/kea6/advanced.json +++ b/doc/examples/kea6/advanced.json @@ -2,7 +2,7 @@ # It attempts to showcase some of the more advanced features. # Topology wise, it's a basic scenario with one IPv6 subnet configured. # It is assumed that one subnet (2001:db8:1::/64) is available directly -# over eth0 interface. +# over ethX interface. # # The following features are currently showcased here: # 1. Configuration of MAC/hardware address sources in DHCPv6 @@ -54,7 +54,7 @@ { "pools": [ { "pool": "2001:db8:1::/80" } ], "subnet": "2001:db8:1::/64", - "interface": "eth0" + "interface": "ethX" } ] }, diff --git a/doc/examples/kea6/multiple-options.json b/doc/examples/kea6/multiple-options.json index 70f2794a73..e30cf9d303 100644 --- a/doc/examples/kea6/multiple-options.json +++ b/doc/examples/kea6/multiple-options.json @@ -32,7 +32,7 @@ { "pools": [ { "pool": "2001:db8:1::/80" } ], "subnet": "2001:db8:1::/64", - "interface": "eth0", + "interface": "ethX", "option-data": [ { "name": "dns-servers", diff --git a/doc/examples/kea6/simple.json b/doc/examples/kea6/simple.json index 7d8e80fea9..cffec39f02 100644 --- a/doc/examples/kea6/simple.json +++ b/doc/examples/kea6/simple.json @@ -1,7 +1,7 @@ # This is an example configuration file for DHCPv6 server in Kea. # It's a basic scenario with one IPv6 subnet configured. It is # assumed that one subnet (2001:db8:1::/64 is available directly -# over eth0 interface. +# over ethX interface. { "Dhcp6": @@ -33,7 +33,7 @@ { "pools": [ { "pool": "2001:db8:1::/80" } ], "subnet": "2001:db8:1::/64", - "interface": "eth0" + "interface": "ethX" } ] }, diff --git a/src/bin/dhcp6/dhcp6_srv.h b/src/bin/dhcp6/dhcp6_srv.h index f974cc0320..ff3ff69581 100644 --- a/src/bin/dhcp6/dhcp6_srv.h +++ b/src/bin/dhcp6/dhcp6_srv.h @@ -596,15 +596,14 @@ protected: /// @param pkt packet to be classified void classifyPacket(const Pkt6Ptr& pkt); - /// @brief Attempts to get a MAC/hardware address using configred sources /// /// Tries to extract MAC/hardware address information from the packet - /// using MAC sources configured in 'mac-sources' directive. + /// using MAC sources configured in 'mac-sources' configuration parameter. /// /// @param pkt will try to exact MAC address from this packet /// @return HWaddr pointer (or NULL if configured methods fail) - HWAddrPtr getMAC(const Pkt6Ptr& pkt); + static HWAddrPtr getMAC(const Pkt6Ptr& pkt); /// @brief this is a prefix added to the contend of vendor-class option /// diff --git a/src/lib/dhcpsrv/cfg_mac_source.h b/src/lib/dhcpsrv/cfg_mac_source.h index a2681254c3..3b3a098a86 100644 --- a/src/lib/dhcpsrv/cfg_mac_source.h +++ b/src/lib/dhcpsrv/cfg_mac_source.h @@ -58,6 +58,7 @@ class CfgMACSource { /// @param source MAC source (see constants in Pkt::HWADDR_SOURCE_*) /// /// Specified source is being added to the mac_sources_ array. + /// @todo implement add(string) version of this method. void add(uint32_t source) { mac_sources_.push_back(source); }