libkea_dhcp___la_SOURCES += classify.cc classify.h
libkea_dhcp___la_SOURCES += dhcp6.h dhcp4.h
libkea_dhcp___la_SOURCES += duid.cc duid.h
+libkea_dhcp___la_SOURCES += duid_factory.cc duid_factory.h
libkea_dhcp___la_SOURCES += hwaddr.cc hwaddr.h
libkea_dhcp___la_SOURCES += iface_mgr.cc iface_mgr.h
libkea_dhcp___la_SOURCES += iface_mgr_bsd.cc
--- /dev/null
+// Copyright (C) 2015 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// 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 <dhcp/duid_factory.h>
+#include <dhcp/iface_mgr.h>
+#include <util/io_utilities.h>
+#include <util/range_utilities.h>
+#include <util/strutil.h>
+#include <boost/foreach.hpp>
+#include <ctime>
+#include <string>
+#include <vector>
+
+using namespace isc::util;
+using namespace isc::util::str;
+
+namespace {
+
+const size_t MIN_MAC_LEN = 6;
+
+}
+
+namespace isc {
+namespace dhcp {
+
+DUIDFactory::DUIDFactory(const std::string& storage_location)
+ : storage_location_(trim(storage_location)), duid_() {
+}
+
+bool
+DUIDFactory::isPersisted() const {
+ return (!storage_location_.empty());
+}
+
+void
+DUIDFactory::createLLT(const uint16_t htype, const uint32_t time_in,
+ const std::vector<uint8_t>& ll_identifier) {
+ uint32_t time_out = time_in;
+ if (time_out == 0) {
+ time_out = static_cast<uint32_t>(time(NULL) - DUID_TIME_EPOCH);
+ }
+
+ uint16_t htype_out = htype;
+ if (htype_out == 0) {
+ htype_out = HTYPE_ETHER;
+ }
+
+ std::vector<uint8_t> ll_identifier_out = ll_identifier;
+ if (ll_identifier_out.empty()) {
+ createLinkLayerId(ll_identifier_out);
+ }
+
+ std::vector<uint8_t> duid_out(2 + sizeof(time_out) + sizeof(htype_out));
+ writeUint16(DUID::DUID_LLT, &duid_out[0], 2);
+ writeUint16(htype_out, &duid_out[2], 2);
+ writeUint32(time_out, &duid_out[4], 4);
+ duid_out.insert(duid_out.end(), ll_identifier_out.begin(),
+ ll_identifier_out.end());
+
+ duid_.reset(new DUID(duid_out));
+}
+
+/*void
+DUIDFactory::createEN(const uint32_t enterprise_id,
+ const std::vector<uint8_t>& identifier) {
+}*/
+
+/*void
+DUIDFactory::createLL(const uint16_t htype, const std::vector<uint8_t>& ll_identifier) {
+} */
+
+void
+DUIDFactory::createLinkLayerId(std::vector<uint8_t>& identifier) const {
+ const IfaceMgr::IfaceCollection& ifaces = IfaceMgr::instance().getIfaces();
+
+ // Let's find suitable interface.
+ BOOST_FOREACH(IfacePtr iface, ifaces) {
+ // All the following checks could be merged into one multi-condition
+ // statement, but let's keep them separated as perhaps one day
+ // we will grow knobs to selectively turn them on or off. Also,
+ // this code is used only *once* during first start on a new machine
+ // and then server-id is stored. (or at least it will be once
+ // DUID storage is implemented)
+
+ // I wish there was a this_is_a_real_physical_interface flag...
+
+ // MAC address should be at least 6 bytes. Although there is no such
+ // requirement in any RFC, all decent physical interfaces (Ethernet,
+ // WiFi, InfiniBand, etc.) have 6 bytes long MAC address. We want to
+ // base our DUID on real hardware address, rather than virtual
+ // interface that pretends that underlying IP address is its MAC.
+ if (iface->getMacLen() < MIN_MAC_LEN) {
+ continue;
+ }
+
+ // Let's don't use loopback.
+ if (iface->flag_loopback_) {
+ continue;
+ }
+
+ // Let's skip downed interfaces. It is better to use working ones.
+ if (!iface->flag_up_) {
+ continue;
+ }
+
+ // Some interfaces (like lo on Linux) report 6-bytes long
+ // MAC address 00:00:00:00:00:00. Let's not use such weird interfaces
+ // to generate DUID.
+ if (isRangeZero(iface->getMac(), iface->getMac() + iface->getMacLen())) {
+ continue;
+ }
+
+ identifier.assign(iface->getMac(), iface->getMac() + iface->getMacLen());
+ }
+}
+
+DuidPtr
+DUIDFactory::get() {
+ return (duid_);
+}
+
+}; // end of isc::dhcp namespace
+}; // end of isc namespace
--- /dev/null
+// Copyright (C) 2015 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// 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 DUID_FACTORY_H
+#define DUID_FACTORY_H
+
+#include <dhcp/duid.h>
+#include <stdint.h>
+#include <string>
+#include <vector>
+
+namespace isc {
+namespace dhcp {
+
+class DUIDFactory {
+public:
+
+ DUIDFactory(const std::string& storage_location = "");
+
+ bool isPersisted() const;
+
+ void createLLT(const uint16_t htype, const uint32_t time_in,
+ const std::vector<uint8_t>& ll_identifier);
+
+ void createEN(const uint32_t enterprise_id, const std::vector<uint8_t>& identifier);
+
+ void createLL(const uint16_t htype, const std::vector<uint8_t>& ll_identifier);
+
+ DuidPtr get();
+
+private:
+
+ void createLinkLayerId(std::vector<uint8_t>& identifier) const;
+
+ std::string storage_location_;
+
+ DuidPtr duid_;
+
+};
+
+}; // end of isc::dhcp namespace
+}; // end of isc namespace
+
+#endif /* DUID_FACTORY_H */
libdhcp___unittests_SOURCES = run_unittests.cc
libdhcp___unittests_SOURCES += classify_unittest.cc
+libdhcp___unittests_SOURCES += duid_factory_unittest.cc
libdhcp___unittests_SOURCES += hwaddr_unittest.cc
libdhcp___unittests_SOURCES += iface_mgr_unittest.cc
libdhcp___unittests_SOURCES += iface_mgr_test_config.cc iface_mgr_test_config.h
--- /dev/null
+// Copyright (C) 2015 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// 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 <config.h>
+#include <dhcp/dhcp4.h>
+#include <dhcp/duid_factory.h>
+#include <dhcp/tests/iface_mgr_test_config.h>
+#include <util/encode/hex.h>
+#include <boost/algorithm/string.hpp>
+#include <gtest/gtest.h>
+#include <ctime>
+#include <iomanip>
+#include <sstream>
+#include <stdio.h>
+#include <string>
+#include <vector>
+
+using namespace isc;
+using namespace isc::dhcp;
+using namespace isc::dhcp::test;
+
+namespace {
+
+const std::string DEFAULT_DUID_FILE = "duid-factory-test.duid";
+
+class DUIDFactoryTest : public ::testing::Test {
+public:
+
+ DUIDFactoryTest();
+
+ virtual ~DUIDFactoryTest();
+
+ std::string absolutePath(const std::string& duid_file_path) const;
+
+ void removeDefaultFile() const;
+
+ std::vector<uint8_t> toVector(const std::string& hex) const;
+
+ std::string toString(const std::vector<uint8_t>& vec) const;
+
+ std::string timeAsHexString() const;
+
+ void testLLT(const std::string& expected_htype,
+ const std::string& expected_time,
+ const bool time_equal,
+ const std::string& expected_hwaddr);
+
+ DUIDFactory& factory() {
+ return (factory_);
+ }
+
+private:
+
+ IfaceMgrTestConfig iface_mgr_test_config_;
+
+ DUIDFactory factory_;
+
+};
+
+DUIDFactoryTest::DUIDFactoryTest()
+ : iface_mgr_test_config_(true),
+ factory_(absolutePath(DEFAULT_DUID_FILE)) {
+ removeDefaultFile();
+}
+
+DUIDFactoryTest::~DUIDFactoryTest() {
+ removeDefaultFile();
+}
+
+std::string
+DUIDFactoryTest::absolutePath(const std::string& duid_file_path) const {
+ std::ostringstream s;
+ s << TEST_DATA_BUILDDIR << "/" << duid_file_path;
+ return (s.str());
+}
+
+void
+DUIDFactoryTest::removeDefaultFile() const {
+ static_cast<void>(remove(absolutePath(DEFAULT_DUID_FILE).c_str()));
+}
+
+std::vector<uint8_t>
+DUIDFactoryTest::toVector(const std::string& hex) const {
+ std::vector<uint8_t> vec;
+ try {
+ util::encode::decodeHex(hex, vec);
+ } catch (...) {
+ ADD_FAILURE() << "toVector: the following string " << hex
+ << " is not a valid hex string";
+ }
+
+ return (vec);
+}
+
+std::string
+DUIDFactoryTest::toString(const std::vector<uint8_t>& vec) const {
+ try {
+ return (util::encode::encodeHex(vec));
+ } catch (...) {
+ ADD_FAILURE() << "toString: unable to encode vector to"
+ " hexadecimal string";
+ }
+ return ("");
+}
+
+std::string
+DUIDFactoryTest::timeAsHexString() const {
+ time_t current_time = time(NULL) - DUID_TIME_EPOCH;
+ std::ostringstream s;
+ s << std::hex << std::setw(8) << std::setfill('0') << current_time;
+ return (boost::to_upper_copy<std::string>(s.str()));
+}
+
+void
+DUIDFactoryTest::testLLT(const std::string& expected_htype,
+ const std::string& expected_time,
+ const bool time_equal,
+ const std::string& expected_hwaddr) {
+ DuidPtr duid = factory().get();
+ ASSERT_TRUE(duid);
+ ASSERT_GE(duid->getDuid().size(), 14);
+ std::string duid_text = toString(duid->getDuid());
+
+ // DUID type LLT
+ EXPECT_EQ("0001", duid_text.substr(0, 4));
+ // Link layer type HTYPE_ETHER
+ EXPECT_EQ(expected_htype, duid_text.substr(4, 4));
+
+ // Verify if time is correct.
+ if (time_equal) {
+ // Strict time check.
+ EXPECT_EQ(expected_time, duid_text.substr(8, 8));
+ } else {
+ // Timestamp equal or less current time.
+ EXPECT_LE(duid_text.substr(8, 8), expected_time);
+ }
+
+ // MAC address of the interface.
+ EXPECT_EQ(expected_hwaddr, duid_text.substr(16));
+}
+
+
+// This test verifies that the factory class will generate the entire
+// DUID-LLT if there are no explicit values specified for the
+// time, link layer type and link layer address.
+TEST_F(DUIDFactoryTest, createLLT) {
+ // Use 0 values for time and link layer type and empty vector for
+ // the link layer address. The createLLT function will need to
+ // use current time, HTYPE_ETHER and MAC address of one of the
+ // interfaces.
+ ASSERT_NO_THROW(factory().createLLT(0, 0, std::vector<uint8_t>()));
+ testLLT("0001", timeAsHexString(), false, "010101010101");
+}
+
+// This test verifies that the factory class creates a DUID-LLT from
+// the explicitly specified time, when link layer type and address are
+// generated.
+TEST_F(DUIDFactoryTest, createLLTExplicitTime) {
+ ASSERT_NO_THROW(factory().createLLT(0, 0xABCDEF, std::vector<uint8_t>()));
+ testLLT("0001", "00ABCDEF", true, "010101010101");
+}
+
+// This test verifies that the factory class creates DUID-LLT from
+// the explcitly specified link layer type, when the time and link
+// layer address are generated.
+TEST_F(DUIDFactoryTest, createLLTExplicitHtype) {
+ ASSERT_NO_THROW(factory().createLLT(HTYPE_FDDI, 0, std::vector<uint8_t>()));
+ testLLT("0008", timeAsHexString(), false, "010101010101");
+}
+
+// This test verifies that the factory class creates DUID-LLT from
+// explcitly specified link layer address, when other parameters
+// are generated.
+TEST_F(DUIDFactoryTest, createLLTExplicitLinkLayerAddress) {
+ ASSERT_NO_THROW(factory().createLLT(0, 0, toVector("121212121212")));
+ testLLT("0001", timeAsHexString(), false, "121212121212");
+}
+
+// This test verifies that the factory function creates DUID-LLT from
+// all values explicitly specified.
+TEST_F(DUIDFactoryTest, createLLTAllExplcitParameters) {
+ ASSERT_NO_THROW(factory().createLLT(HTYPE_FDDI, 0xFAFAFAFA,
+ toVector("24242424242424242424")));
+ testLLT("0008", "FAFAFAFA", true, "24242424242424242424");
+}
+
+} // End anonymous namespace
iface->flag_broadcast_ = false;
iface->flag_up_ = true;
iface->flag_running_ = true;
+
+ // Set MAC address to 01:01:01:01:01:01.
+ std::vector<uint8_t> mac_vec(6, 1);
+ iface->setMac(&mac_vec[0], mac_vec.size());
+
return (iface);
}