From: Marcin Siodelski Date: Mon, 16 Nov 2015 11:29:38 +0000 (+0100) Subject: [3874] Use DUIDFactory class in the DHCPV6 server code. X-Git-Tag: trac4231_base~39^2~12 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=3c5e3548bdfcdddf96646f0efdeafb73880bdb47;p=thirdparty%2Fkea.git [3874] Use DUIDFactory class in the DHCPV6 server code. --- diff --git a/src/bin/dhcp6/dhcp6_messages.mes b/src/bin/dhcp6/dhcp6_messages.mes index cda6ad0828..756c590476 100644 --- a/src/bin/dhcp6/dhcp6_messages.mes +++ b/src/bin/dhcp6/dhcp6_messages.mes @@ -649,19 +649,16 @@ recommended as existing clients will not recognize the server and may go through a rebind phase. However, they should be able to recover without losing their leases. -% DHCP6_SERVERID_LOADED server-id %1 has been loaded from file %2 -This debug message indicates that the server loaded its server identifier. -That value is sent in all server responses and clients use it to -discriminate between servers. This is a part of normal startup or -reconfiguration procedure. - -% DHCP6_SERVERID_WRITE_FAIL server was not able to write its ID to file %1 -This warning message indicates that server was not able to write its -server identifier (DUID) to a file. This likely indicates lack of write -permission to a given file or directory. This is not critical and the -server will continue to operate, but server will generate different DUID -during every start and clients will need to go through a rebind phase -to recover. +% DHCP6_USING_SERVERID server is using server-id %1 and stores in the the file %2 +This info message is logged when the server reads its server-id from a +file or generates it. This message is a notification to the administrator +what server-id will be used and where it is persisted. Typically, there is +no need to modify the server id. However, it is possible to do it in the +Kea configuration file. It is important to understand the implications of +such modification. The clients will remember previous server-id, and will +use it to extend their leases. As a result, they will have to go through +a rebinding phase to re-acquire their leases and associate them with a +new server id. % DHCP6_SERVER_FAILED server failed: %1 The IPv6 DHCP server has encountered a fatal error and is terminating. diff --git a/src/bin/dhcp6/dhcp6_srv.cc b/src/bin/dhcp6/dhcp6_srv.cc index 2f0687b60f..ace7821b17 100644 --- a/src/bin/dhcp6/dhcp6_srv.cc +++ b/src/bin/dhcp6/dhcp6_srv.cc @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -199,21 +200,12 @@ Dhcpv6Srv::Dhcpv6Srv(uint16_t port) } string duid_file = CfgMgr::instance().getDataDir() + "/" + string(SERVER_DUID_FILE); - if (loadServerID(duid_file)) { - LOG_DEBUG(dhcp6_logger, DBG_DHCP6_START, DHCP6_SERVERID_LOADED) - .arg(duidToString(getServerID())) - .arg(duid_file); - } else { - generateServerID(); - LOG_INFO(dhcp6_logger, DHCP6_SERVERID_GENERATED) - .arg(duidToString(getServerID())) - .arg(duid_file); - - if (!writeServerID(duid_file)) { - LOG_WARN(dhcp6_logger, DHCP6_SERVERID_WRITE_FAIL) - .arg(duid_file); - } - } + DUIDFactory duid_factory(duid_file); + DuidPtr duid = duid_factory.get(); + serverid_.reset(new Option(Option::V6, D6O_SERVERID, duid->getDuid())); + LOG_INFO(dhcp6_logger, DHCP6_USING_SERVERID) + .arg(duidToString(getServerID())) + .arg(duid_file); // Instantiate allocation engine. The number of allocation attempts equal // to zero indicates that the allocation engine will use the number of @@ -717,38 +709,6 @@ bool Dhcpv6Srv::run() { return (true); } -bool Dhcpv6Srv::loadServerID(const std::string& file_name) { - - // load content of the file into a string - fstream f(file_name.c_str(), ios::in); - if (!f.is_open()) { - return (false); - } - - string hex_string; - f >> hex_string; - f.close(); - - // remove any spaces - boost::algorithm::erase_all(hex_string, " "); - - // now remove : - /// @todo: We should check first if the format is sane. - /// Otherwise 1:2:3:4 will be converted to 0x12, 0x34 - boost::algorithm::erase_all(hex_string, ":"); - - std::vector bin; - - // Decode the hex string and store it in bin (which happens - // to be OptionBuffer format) - isc::util::encode::decodeHex(hex_string, bin); - - // Now create server-id option - serverid_.reset(new Option(Option::V6, D6O_SERVERID, bin)); - - return (true); -} - std::string Dhcpv6Srv::duidToString(const OptionPtr& opt) { stringstream tmp; @@ -769,102 +729,6 @@ Dhcpv6Srv::duidToString(const OptionPtr& opt) { return tmp.str(); } -bool -Dhcpv6Srv::writeServerID(const std::string& file_name) { - fstream f(file_name.c_str(), ios::out | ios::trunc); - if (!f.good()) { - return (false); - } - f << duidToString(getServerID()); - f.close(); - return (true); -} - -void -Dhcpv6Srv::generateServerID() { - - /// @todo: This code implements support for DUID-LLT (the recommended one). - /// We should eventually add support for other DUID types: DUID-LL, DUID-EN - /// and DUID-UUID - - 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; - } - - // Ok, we have useful MAC. Let's generate DUID-LLT based on - // it. See RFC3315, Section 9.2 for details. - - // DUID uses seconds since midnight of 01-01-2000, time() returns - // seconds since 01-01-1970. DUID_TIME_EPOCH substitution corrects - // that. - time_t seconds = time(NULL); - seconds -= DUID_TIME_EPOCH; - - OptionBuffer srvid(8 + iface->getMacLen()); - // We know that the buffer is more than 8 bytes long at this point. - writeUint16(DUID::DUID_LLT, &srvid[0], 2); - writeUint16(HWTYPE_ETHERNET, &srvid[2], 2); - writeUint32(static_cast(seconds), &srvid[4], 4); - memcpy(&srvid[8], iface->getMac(), iface->getMacLen()); - - serverid_ = OptionPtr(new Option(Option::V6, D6O_SERVERID, - srvid.begin(), srvid.end())); - return; - } - - // If we reached here, there are no suitable interfaces found. - // Either interface detection is not supported on this platform or - // this is really weird box. Let's use DUID-EN instead. - // See Section 9.3 of RFC3315 for details. - - OptionBuffer srvid(12); - writeUint16(DUID::DUID_EN, &srvid[0], srvid.size()); - writeUint32(ENTERPRISE_ID_ISC, &srvid[2], srvid.size() - 2); - - // Length of the identifier is company specific. I hereby declare - // ISC "standard" of 6 bytes long pseudo-random numbers. - srandom(time(NULL)); - fillRandom(&srvid[6], &srvid[12]); - - serverid_ = OptionPtr(new Option(Option::V6, D6O_SERVERID, - srvid.begin(), srvid.end())); -} - void Dhcpv6Srv::copyClientOptions(const Pkt6Ptr& question, Pkt6Ptr& answer) { // Add client-id. diff --git a/src/bin/dhcp6/dhcp6_srv.h b/src/bin/dhcp6/dhcp6_srv.h index 1609af068c..b744f757ef 100644 --- a/src/bin/dhcp6/dhcp6_srv.h +++ b/src/bin/dhcp6/dhcp6_srv.h @@ -564,34 +564,6 @@ protected: void releaseLeases(const Pkt6Ptr& release, Pkt6Ptr& reply, AllocEngine::ClientContext6& ctx); - /// @brief Sets server-identifier. - /// - /// This method attempts to generate server-identifier DUID. It generates a - /// new DUID using interface link-layer addresses (EUI-64) + timestamp (DUID - /// type duid-llt, see RFC3315, section 9.2). If there are no suitable - /// interfaces present, exception it thrown - /// - /// @throws isc::Unexpected Failed to read DUID file and no suitable - /// interfaces for new DUID generation are detected. - void generateServerID(); - - /// @brief attempts to load DUID from a file - /// - /// Tries to load duid from a text file. If the load is successful, - /// it creates server-id option and stores it in serverid_ (to be used - /// later by getServerID()). - /// - /// @param file_name name of the DUID file to load - /// @return true if load was successful, false otherwise - bool loadServerID(const std::string& file_name); - - /// @brief attempts to write DUID to a file - /// Tries to write duid content (stored in serverid_) to a text file. - /// - /// @param file_name name of the DUID file to write - /// @return true if write was successful, false otherwise - bool writeServerID(const std::string& file_name); - /// @brief converts DUID to text /// Converts content of DUID option to a text representation, e.g. /// 01:ff:02:03:06:80:90:ab:cd:ef @@ -600,7 +572,6 @@ protected: /// @return string representation static std::string duidToString(const OptionPtr& opt); - /// @brief dummy wrapper around IfaceMgr::receive6 /// /// This method is useful for testing purposes, where its replacement diff --git a/src/bin/dhcp6/tests/dhcp6_srv_unittest.cc b/src/bin/dhcp6/tests/dhcp6_srv_unittest.cc index a5d1c1519c..19cd8309a6 100644 --- a/src/bin/dhcp6/tests/dhcp6_srv_unittest.cc +++ b/src/bin/dhcp6/tests/dhcp6_srv_unittest.cc @@ -1432,38 +1432,6 @@ TEST_F(Dhcpv6SrvTest, selectSubnetRelayInterfaceId) { EXPECT_EQ(subnet2, srv.selectSubnet(pkt)); } -// This test verifies if the server-id disk operations (read, write) are -// working properly. -TEST_F(Dhcpv6SrvTest, ServerID) { - NakedDhcpv6Srv srv(0); - - string duid1_text = "01:ff:02:03:06:80:90:ab:cd:ef"; - uint8_t duid1[] = { 0x01, 0xff, 2, 3, 6, 0x80, 0x90, 0xab, 0xcd, 0xef }; - OptionBuffer expected_duid1(duid1, duid1 + sizeof(duid1)); - - fstream file1(DUID_FILE, ios::out | ios::trunc); - file1 << duid1_text; - file1.close(); - - // Test reading from a file - EXPECT_TRUE(srv.loadServerID(DUID_FILE)); - ASSERT_TRUE(srv.getServerID()); - ASSERT_EQ(sizeof(duid1) + Option::OPTION6_HDR_LEN, srv.getServerID()->len()); - ASSERT_TRUE(expected_duid1 == srv.getServerID()->getData()); - - // Now test writing to a file - EXPECT_EQ(0, remove(DUID_FILE)); - EXPECT_NO_THROW(srv.writeServerID(DUID_FILE)); - - fstream file2(DUID_FILE, ios::in); - ASSERT_TRUE(file2.good()); - string text; - file2 >> text; - file2.close(); - - EXPECT_EQ(duid1_text, text); -} - // Checks if server responses are sent to the proper port. TEST_F(Dhcpv6SrvTest, portsDirectTraffic) { diff --git a/src/bin/dhcp6/tests/dhcp6_test_utils.h b/src/bin/dhcp6/tests/dhcp6_test_utils.h index 85397aacb8..454a309245 100644 --- a/src/bin/dhcp6/tests/dhcp6_test_utils.h +++ b/src/bin/dhcp6/tests/dhcp6_test_utils.h @@ -111,8 +111,6 @@ public: using Dhcpv6Srv::testUnicast; using Dhcpv6Srv::sanityCheck; using Dhcpv6Srv::classifyPacket; - using Dhcpv6Srv::loadServerID; - using Dhcpv6Srv::writeServerID; using Dhcpv6Srv::unpackOptions; using Dhcpv6Srv::shutdown_; using Dhcpv6Srv::name_change_reqs_;