BIND 10 master, updated. 6167f31e01864656cf1a26a0d6bea75f08783a01 [master] Merge branch 'trac2597' (server-id is now stored by dhcpv{4, 6})
BIND 10 source code commits
bind10-changes at lists.isc.org
Mon Jan 21 12:57:11 UTC 2013
The branch, master has been updated
via 6167f31e01864656cf1a26a0d6bea75f08783a01 (commit)
via fa342a994de5dbefe32996be7eebe58f6304cff7 (commit)
via 32a5e02895ad3faf098172a08c11ce4df535521e (commit)
via 695d9fc3bc135de080369b0b7213aca3c264216c (commit)
via 5f6ae1f6c5c0f484c1e2f3073d713784cf3c5373 (commit)
via 4c2bed018107dea2091ac26f51e81d2f14f33582 (commit)
from 0a89b374d57877e3b1ea1f379276d74a34ea7d8f (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commit 6167f31e01864656cf1a26a0d6bea75f08783a01
Merge: 0a89b37 fa342a9
Author: Tomek Mrugalski <tomasz at isc.org>
Date: Mon Jan 21 13:56:57 2013 +0100
[master] Merge branch 'trac2597' (server-id is now stored by dhcpv{4,6})
Conflicts:
ChangeLog
src/bin/dhcp6/tests/dhcp6_srv_unittest.cc
-----------------------------------------------------------------------
Summary of changes:
ChangeLog | 8 ++
doc/guide/bind10-guide.xml | 51 ++++++++++--
src/bin/dhcp4/dhcp4_messages.mes | 20 +++++
src/bin/dhcp4/dhcp4_srv.cc | 126 ++++++++++++++++++++++++++---
src/bin/dhcp4/dhcp4_srv.h | 36 ++++++++-
src/bin/dhcp4/tests/dhcp4_srv_unittest.cc | 44 +++++++++-
src/bin/dhcp6/ctrl_dhcp6_srv.cc | 1 -
src/bin/dhcp6/dhcp6_messages.mes | 28 +++++++
src/bin/dhcp6/dhcp6_srv.cc | 85 ++++++++++++++++++-
src/bin/dhcp6/dhcp6_srv.h | 44 ++++++++--
src/bin/dhcp6/tests/dhcp6_srv_unittest.cc | 45 ++++++++++-
src/lib/dhcpsrv/Makefile.am | 2 +-
src/lib/dhcpsrv/cfgmgr.cc | 11 ++-
src/lib/dhcpsrv/cfgmgr.h | 10 +++
14 files changed, 482 insertions(+), 29 deletions(-)
-----------------------------------------------------------------------
diff --git a/ChangeLog b/ChangeLog
index ce45dbc..86eaa0e 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+5XX. [func] tomek
+ b10-dhcp4: The DHCPv4 server now generates a server identifier
+ the first time it is run. The identifier is preserved in a file
+ across server restarts.
+ b10-dhcp6: The server identifier is now preserved in a file across
+ server restarts.
+ (Trac #2597, git fa342a994de5dbefe32996be7eebe58f6304cff7)
+
549. [func] tomek
b10-dhcp6: It is now possible to specify that a configured subnet
is reachable locally over specified interface (see "interface"
diff --git a/doc/guide/bind10-guide.xml b/doc/guide/bind10-guide.xml
index f1f5859..5384d14 100644
--- a/doc/guide/bind10-guide.xml
+++ b/doc/guide/bind10-guide.xml
@@ -3485,18 +3485,34 @@ Dhcp4/subnet4 [] list (default)</screen>
src/bin/dhcp6/dhcp4_srv.cc file, modify the following parameters and
recompile:
<screen>
-const std::string HARDCODED_LEASE = "192.0.2.222"; // assigned lease
-const std::string HARDCODED_NETMASK = "255.255.255.0";
-const uint32_t HARDCODED_LEASE_TIME = 60; // in seconds
const std::string HARDCODED_GATEWAY = "192.0.2.1";
const std::string HARDCODED_DNS_SERVER = "192.0.2.2";
-const std::string HARDCODED_DOMAIN_NAME = "isc.example.com";
-const std::string HARDCODED_SERVER_ID = "192.0.2.1";</screen>
+const std::string HARDCODED_DOMAIN_NAME = "isc.example.com";</screen>
Lease database and configuration support is planned for end of 2012.
</para>
</section>
+ <section id="dhcp4-serverid">
+ <title>Server Identifier in DHCPv4</title>
+ <para>The DHCPv4 protocol uses a "server identifier" for clients to be able
+ to discriminate between several servers present on the same link: this
+ value is an IPv4 address of the server. When started for the first time,
+ the DHCPv4 server will choose one of its IPv4 addresses as its server-id,
+ and store the chosen value to a file. (The file is named b10-dhcp4-serverid and is
+ stored in the "local state directory". This is set during installation
+ when "configure" is run, and can be changed by using "--localstatedir"
+ on the "configure" command line.) That file will be read by the server
+ and the contained value used whenever the server is subsequently started.
+ </para>
+ <para>
+ It is unlikely that this parameter needs to be changed. If such a need
+ arises, please stop the server, edit the file and restart the server.
+ It is a text file that should contain an IPv4 address. Spaces are
+ ignored. No extra characters are allowed in this file.
+ </para>
+ </section>
+
<section id="dhcp4-std">
<title>Supported standards</title>
<para>The following standards and draft standards are currently
@@ -3841,6 +3857,31 @@ Dhcp6/subnet6 [] list (default)</screen>
</note>
</section>
+ <section id="dhcp6-serverid">
+ <title>Server Identifier in DHCPv6</title>
+ <para>The DHCPv6 protocol uses a "server identifier" (also known
+ as a DUID) for clients to be able to discriminate between several
+ servers present on the same link. There are several types of
+ DUIDs defined, but RFC 3315 instructs servers to use DUID-LLT if
+ possible. This format consists of a link-layer (MAC) address and a
+ timestamp. When started for the first time, the DHCPv6 server will
+ automatically generate such a DUID and store the chosen value to
+ a file (The file is named b10-dhcp6-serverid and is stored in the
+ "local state directory". This is set during installation when
+ "configure" is run, and can be changed by using "--localstatedir"
+ on the "configure" command line.) That file will be read by the server
+ and the contained value used whenever the server is subsequently started.
+ </para>
+ <para>
+ It is unlikely that this parameter needs to be changed. If such a need
+ arises, please stop the server, edit the file and start the server
+ again. It is a text file that contains double digit hexadecimal values
+ separated by colons. This format is similar to typical MAC address
+ format. Spaces are ignored. No extra characters are allowed in this
+ file.
+ </para>
+ </section>
+
<section id="dhcp6-std">
<title>Supported DHCPv6 Standards</title>
<para>The following standards and draft standards are currently
diff --git a/src/bin/dhcp4/dhcp4_messages.mes b/src/bin/dhcp4/dhcp4_messages.mes
index fc47823..02ad0a0 100644
--- a/src/bin/dhcp4/dhcp4_messages.mes
+++ b/src/bin/dhcp4/dhcp4_messages.mes
@@ -162,6 +162,26 @@ A debug message listing the data returned to the client.
The IPv4 DHCP server has encountered a fatal error and is terminating.
The reason for the failure is included in the message.
+% DHCP4_SERVERID_GENERATED server-id %1 has been generated and will be stored in %2
+This informational messages indicates that the server was not able to
+read its server identifier and has generated a new one. This server-id
+will be stored in a file and will be read (and used) whenever the server
+is restarted. This is normal behavior when the server is started for the
+first time. If this message is printed every time the server is started,
+please check that the server has sufficient permission to write its
+server-id file and that the file is not corrupt.
+
+% DHCP4_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.
+
+% DHCP4_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 to a file. The most likely cause is is that the server
+does not have permissions to write the server id file.
+
% DHCP4_SESSION_FAIL failed to establish BIND 10 session (%1), running stand-alone
The server has failed to establish communication with the rest of BIND
10 and is running in stand-alone mode. (This behavior will change once
diff --git a/src/bin/dhcp4/dhcp4_srv.cc b/src/bin/dhcp4/dhcp4_srv.cc
index 88ccfea..20d8597 100644
--- a/src/bin/dhcp4/dhcp4_srv.cc
+++ b/src/bin/dhcp4/dhcp4_srv.cc
@@ -30,6 +30,11 @@
#include <dhcpsrv/utils.h>
#include <dhcpsrv/addr_utilities.h>
+#include <boost/algorithm/string/erase.hpp>
+
+#include <iomanip>
+#include <fstream>
+
using namespace isc;
using namespace isc::asiolink;
using namespace isc::dhcp;
@@ -41,7 +46,6 @@ using namespace std;
const std::string HARDCODED_GATEWAY = "192.0.2.1";
const std::string HARDCODED_DNS_SERVER = "192.0.2.2";
const std::string HARDCODED_DOMAIN_NAME = "isc.example.com";
-const std::string HARDCODED_SERVER_ID = "192.0.2.1";
Dhcpv4Srv::Dhcpv4Srv(uint16_t port, const char* dbconfig) {
LOG_DEBUG(dhcp4_logger, DBG_DHCP4_START, DHCP4_OPEN_SOCKET).arg(port);
@@ -56,7 +60,22 @@ Dhcpv4Srv::Dhcpv4Srv(uint16_t port, const char* dbconfig) {
IfaceMgr::instance().openSockets4(port);
}
- setServerID();
+ string srvid_file = CfgMgr::instance().getDataDir() + "/" + string(SERVER_ID_FILE);
+ if (loadServerID(srvid_file)) {
+ LOG_DEBUG(dhcp4_logger, DBG_DHCP4_START, DHCP4_SERVERID_LOADED)
+ .arg(srvid_file);
+ } else {
+ generateServerID();
+ LOG_INFO(dhcp4_logger, DHCP4_SERVERID_GENERATED)
+ .arg(srvidToString(getServerID()))
+ .arg(srvid_file);
+
+ if (!writeServerID(srvid_file)) {
+ LOG_WARN(dhcp4_logger, DHCP4_SERVERID_WRITE_FAIL)
+ .arg(srvid_file);
+ }
+
+ }
// Instantiate LeaseMgr
LeaseMgrFactory::create(dbconfig);
@@ -176,19 +195,108 @@ Dhcpv4Srv::run() {
}
}
}
+ }
+
+ return (true);
+}
+
+bool Dhcpv4Srv::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, " ");
+
+ try {
+ IOAddress addr(hex_string);
+
+ if (!addr.isV4()) {
+ return (false);
+ }
+
+ // Now create server-id option
+ serverid_.reset(new Option4AddrLst(DHO_DHCP_SERVER_IDENTIFIER, addr));
- // TODO add support for config session (see src/bin/auth/main.cc)
- // so this daemon can be controlled from bob
+ } catch(...) {
+ // any kind of malformed input (empty string, IPv6 address, complete
+ // garbate etc.)
+ return (false);
}
return (true);
}
-void
-Dhcpv4Srv::setServerID() {
- /// @todo: implement this for real (see ticket #2588)
- serverid_ = OptionPtr(new Option4AddrLst(DHO_DHCP_SERVER_IDENTIFIER,
- IOAddress(HARDCODED_SERVER_ID)));
+void Dhcpv4Srv::generateServerID() {
+
+ const IfaceMgr::IfaceCollection& ifaces = IfaceMgr::instance().getIfaces();
+
+ // Let's find suitable interface.
+ for (IfaceMgr::IfaceCollection::const_iterator iface = ifaces.begin();
+ iface != ifaces.end(); ++iface) {
+
+ // 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;
+ }
+
+ const IfaceMgr::AddressCollection addrs = iface->getAddresses();
+
+ for (IfaceMgr::AddressCollection::const_iterator addr = addrs.begin();
+ addr != addrs.end(); ++addr) {
+ if (addr->getFamily() != AF_INET) {
+ continue;
+ }
+
+ serverid_ = OptionPtr(new Option4AddrLst(DHO_DHCP_SERVER_IDENTIFIER,
+ *addr));
+ return;
+ }
+
+
+ }
+
+ isc_throw(BadValue, "No suitable interfaces for server-identifier found");
+}
+
+bool Dhcpv4Srv::writeServerID(const std::string& file_name) {
+ fstream f(file_name.c_str(), ios::out | ios::trunc);
+ if (!f.good()) {
+ return (false);
+ }
+ f << srvidToString(getServerID());
+ f.close();
+}
+
+string Dhcpv4Srv::srvidToString(const OptionPtr& srvid) {
+ if (!srvid) {
+ isc_throw(BadValue, "NULL pointer passed to srvidToString()");
+ }
+ boost::shared_ptr<Option4AddrLst> generated =
+ boost::dynamic_pointer_cast<Option4AddrLst>(srvid);
+ if (!srvid) {
+ isc_throw(BadValue, "Pointer to invalid option passed to srvidToString()");
+ }
+
+ Option4AddrLst::AddressContainer addrs = generated->getAddresses();
+ if (addrs.size() != 1) {
+ isc_throw(BadValue, "Malformed option passed to srvidToString(). "
+ << "Expected to contain a single IPv4 address.");
+ }
+
+ return (addrs[0].toText());
}
void Dhcpv4Srv::copyDefaultFields(const Pkt4Ptr& question, Pkt4Ptr& answer) {
diff --git a/src/bin/dhcp4/dhcp4_srv.h b/src/bin/dhcp4/dhcp4_srv.h
index 53401c5..8d26e05 100644
--- a/src/bin/dhcp4/dhcp4_srv.h
+++ b/src/bin/dhcp4/dhcp4_srv.h
@@ -28,6 +28,15 @@
namespace isc {
namespace dhcp {
+/// @brief file name of a server-id file
+///
+/// Server must store its server identifier in persistent storage that must not
+/// change between restarts. This is name of the file that is created in dataDir
+/// (see isc::dhcp::CfgMgr::getDataDir()). It is a text file that uses
+/// regular IPv4 address, e.g. 192.0.2.1. Server will create it during
+/// first run and then use it afterwards.
+static const char* SERVER_ID_FILE = "b10-dhcp4-serverid";
+
/// @brief DHCPv4 server service.
///
/// This singleton class represents DHCPv4 server. It contains all
@@ -216,7 +225,32 @@ protected:
///
/// @throws isc::Unexpected Failed to obtain server identifier (i.e. no
// previously stored configuration and no network interfaces available)
- void setServerID();
+ void generateServerID();
+
+ /// @brief attempts to load server-id 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 server-id file to load
+ /// @return true if load was successful, false otherwise
+ bool loadServerID(const std::string& file_name);
+
+ /// @brief attempts to write server-id to a file
+ /// Tries to write server-id content (stored in serverid_) to a text file.
+ ///
+ /// @param file_name name of the server-id file to write
+ /// @return true if write was successful, false otherwise
+ bool writeServerID(const std::string& file_name);
+
+ /// @brief converts server-id to text
+ /// Converts content of server-id option to a text representation, e.g.
+ /// "192.0.2.1"
+ ///
+ /// @param opt option that contains server-id
+ /// @return string representation
+ static std::string srvidToString(const OptionPtr& opt);
/// @brief Selects a subnet for a given client's packet.
///
diff --git a/src/bin/dhcp4/tests/dhcp4_srv_unittest.cc b/src/bin/dhcp4/tests/dhcp4_srv_unittest.cc
index bc2246f..a2331ff 100644
--- a/src/bin/dhcp4/tests/dhcp4_srv_unittest.cc
+++ b/src/bin/dhcp4/tests/dhcp4_srv_unittest.cc
@@ -49,9 +49,15 @@ public:
using Dhcpv4Srv::processDecline;
using Dhcpv4Srv::processInform;
using Dhcpv4Srv::getServerID;
+ using Dhcpv4Srv::loadServerID;
+ using Dhcpv4Srv::generateServerID;
+ using Dhcpv4Srv::writeServerID;
using Dhcpv4Srv::sanityCheck;
+ using Dhcpv4Srv::srvidToString;
};
+static const char* SRVID_FILE = "server-id-test.txt";
+
class Dhcpv4SrvTest : public ::testing::Test {
public:
@@ -67,6 +73,9 @@ public:
CfgMgr::instance().deleteSubnets4();
CfgMgr::instance().addSubnet4(subnet_);
+
+ // it's ok if that fails. There should not be such a file anyway
+ unlink(SRVID_FILE);
}
/// @brief checks that the response matches request
@@ -245,6 +254,9 @@ public:
~Dhcpv4SrvTest() {
CfgMgr::instance().deleteSubnets4();
+
+ // Let's clean up if there is such a file.
+ unlink(SRVID_FILE);
};
/// @brief A subnet used in most tests
@@ -691,7 +703,7 @@ TEST_F(Dhcpv4SrvTest, ManyDiscovers) {
checkAddressParams(offer2, subnet_);
checkAddressParams(offer3, subnet_);
- // Check DUIDs
+ // Check server-ids
checkServerId(offer1, srv->getServerID());
checkServerId(offer2, srv->getServerID());
checkServerId(offer3, srv->getServerID());
@@ -1126,4 +1138,34 @@ TEST_F(Dhcpv4SrvTest, ReleaseReject) {
EXPECT_FALSE(l);
}
+// This test verifies if the server-id disk operations (read, write) are
+// working properly.
+TEST_F(Dhcpv4SrvTest, ServerID) {
+ NakedDhcpv4Srv srv(0);
+
+ string srvid_text = "192.0.2.100";
+ IOAddress srvid(srvid_text);
+
+ fstream file1(SRVID_FILE, ios::out | ios::trunc);
+ file1 << srvid_text;
+ file1.close();
+
+ // Test reading from a file
+ EXPECT_TRUE(srv.loadServerID(SRVID_FILE));
+ ASSERT_TRUE(srv.getServerID());
+ EXPECT_EQ(srvid_text, srv.srvidToString(srv.getServerID()));
+
+ // Now test writing to a file
+ EXPECT_EQ(0, unlink(SRVID_FILE));
+ EXPECT_NO_THROW(srv.writeServerID(SRVID_FILE));
+
+ fstream file2(SRVID_FILE, ios::in);
+ ASSERT_TRUE(file2.good());
+ string text;
+ file2 >> text;
+ file2.close();
+
+ EXPECT_EQ(srvid_text, text);
+}
+
} // end of anonymous namespace
diff --git a/src/bin/dhcp6/ctrl_dhcp6_srv.cc b/src/bin/dhcp6/ctrl_dhcp6_srv.cc
index ba3e2c2..5505a36 100644
--- a/src/bin/dhcp6/ctrl_dhcp6_srv.cc
+++ b/src/bin/dhcp6/ctrl_dhcp6_srv.cc
@@ -42,7 +42,6 @@ using namespace std;
namespace isc {
namespace dhcp {
-
ControlledDhcpv6Srv* ControlledDhcpv6Srv::server_ = NULL;
ConstElementPtr
diff --git a/src/bin/dhcp6/dhcp6_messages.mes b/src/bin/dhcp6/dhcp6_messages.mes
index 83f75d9..c38776c 100644
--- a/src/bin/dhcp6/dhcp6_messages.mes
+++ b/src/bin/dhcp6/dhcp6_messages.mes
@@ -194,6 +194,34 @@ A debug message listing the data returned to the client.
The IPv6 DHCP server has encountered a fatal error and is terminating.
The reason for the failure is included in the message.
+% DHCP6_SERVERID_GENERATED server-id %1 has been generated and will be stored in %2
+This informational messages indicates that the server was not able to read
+its server identifier (DUID) and has generated a new one. This server-id
+will be stored in a file and will be read and used during next restart. It
+is normal behavior when the server is started for the first time. If
+this message is printed every start, please check that the server have
+sufficient permission to write its server-id file and that the file is not
+corrupt.
+
+Changing the server identifier in a production environment is not
+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 cricital 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_SESSION_FAIL failed to establish BIND 10 session (%1), running stand-alone
The server has failed to establish communication with the rest of BIND
10 and is running in stand-alone mode. (This behavior will change once
diff --git a/src/bin/dhcp6/dhcp6_srv.cc b/src/bin/dhcp6/dhcp6_srv.cc
index 8fb55ec..e50950f 100644
--- a/src/bin/dhcp6/dhcp6_srv.cc
+++ b/src/bin/dhcp6/dhcp6_srv.cc
@@ -36,11 +36,16 @@
#include <exceptions/exceptions.h>
#include <util/io_utilities.h>
#include <util/range_utilities.h>
+#include <util/encode/hex.h>
#include <boost/foreach.hpp>
+#include <boost/tokenizer.hpp>
+#include <boost/algorithm/string/erase.hpp>
#include <stdlib.h>
#include <time.h>
+#include <iomanip>
+#include <fstream>
using namespace isc;
using namespace isc::asiolink;
@@ -70,7 +75,22 @@ Dhcpv6Srv::Dhcpv6Srv(uint16_t port, const char* dbconfig)
IfaceMgr::instance().openSockets6(port);
}
- setServerID();
+ 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(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);
+ }
+
+ }
// Instantiate LeaseMgr
LeaseMgrFactory::create(dbconfig);
@@ -209,10 +229,67 @@ bool Dhcpv6Srv::run() {
return (true);
}
-void Dhcpv6Srv::setServerID() {
+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<uint8_t> 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;
+
+ OptionBuffer data = opt->getData();
+
+ bool colon = false;
+ for (OptionBufferConstIter it = data.begin(); it != data.end(); ++it) {
+ if (colon) {
+ tmp << ":";
+ }
+ tmp << hex << setw(2) << setfill('0') << static_cast<uint16_t>(*it);
+ if (!colon) {
+ colon = true;
+ }
+ }
+
+ 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();
+}
- /// @todo: DUID should be generated once and then stored, rather
- /// than generated each time
+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
diff --git a/src/bin/dhcp6/dhcp6_srv.h b/src/bin/dhcp6/dhcp6_srv.h
index 30abb50..6515543 100644
--- a/src/bin/dhcp6/dhcp6_srv.h
+++ b/src/bin/dhcp6/dhcp6_srv.h
@@ -31,6 +31,16 @@
namespace isc {
namespace dhcp {
+/// @brief file name of a server-id file
+///
+/// Server must store its duid in persistent storage that must not change
+/// between restarts. This is name of the file that is created in dataDir
+/// (see isc::dhcp::CfgMgr::getDataDir()). It is a text file that uses
+/// double digit hex values separated by colons format, e.g.
+/// 01:ff:02:03:06:80:90:ab:cd:ef. Server will create it during first
+/// run and then use it afterwards.
+static const char* SERVER_DUID_FILE = "b10-dhcp6-serverid";
+
/// @brief DHCPv6 server service.
///
/// This class represents DHCPv6 server. It contains all
@@ -290,15 +300,39 @@ protected:
/// @brief Sets server-identifier.
///
- /// This method attempts to set server-identifier DUID. It loads it
- /// from a file. If file load fails, it generates new DUID using
- /// interface link-layer addresses (EUI-64) + timestamp (DUID type
- /// duid-llt, see RFC3315, section 9.2). If there are no suitable
+ /// 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 setServerID();
+ 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
+ ///
+ /// @param opt option that contains DUID
+ /// @return string representation
+ static std::string duidToString(const OptionPtr& opt);
private:
/// @brief Allocation Engine.
diff --git a/src/bin/dhcp6/tests/dhcp6_srv_unittest.cc b/src/bin/dhcp6/tests/dhcp6_srv_unittest.cc
index 0ed4e85..1df143f 100644
--- a/src/bin/dhcp6/tests/dhcp6_srv_unittest.cc
+++ b/src/bin/dhcp6/tests/dhcp6_srv_unittest.cc
@@ -35,7 +35,7 @@
#include <boost/scoped_ptr.hpp>
#include <gtest/gtest.h>
-
+#include <unistd.h>
#include <fstream>
#include <iostream>
#include <sstream>
@@ -64,10 +64,16 @@ public:
using Dhcpv6Srv::createStatusCode;
using Dhcpv6Srv::selectSubnet;
using Dhcpv6Srv::sanityCheck;
+ using Dhcpv6Srv::loadServerID;
+ using Dhcpv6Srv::writeServerID;
};
+static const char* DUID_FILE = "server-id-test.txt";
+
class Dhcpv6SrvTest : public ::testing::Test {
public:
+ /// Name of the server-id file (used in server-id tests)
+
// these are empty for now, but let's keep them around
Dhcpv6SrvTest() : rcode_(-1) {
subnet_ = Subnet6Ptr(new Subnet6(IOAddress("2001:db8:1::"), 48, 1000,
@@ -77,6 +83,9 @@ public:
CfgMgr::instance().deleteSubnets6();
CfgMgr::instance().addSubnet6(subnet_);
+
+ // it's ok if that fails. There should not be such a file anyway
+ unlink(DUID_FILE);
}
// Generate IA_NA option with specified parameters
@@ -246,6 +255,9 @@ public:
~Dhcpv6SrvTest() {
CfgMgr::instance().deleteSubnets6();
+
+ // Let's clean up if there is such a file.
+ unlink(DUID_FILE);
};
// A subnet used in most tests
@@ -1407,7 +1419,38 @@ TEST_F(Dhcpv6SrvTest, selectSubnetIface) {
pkt->setIface("wifi1");
EXPECT_EQ(subnet3, 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, unlink(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);
}
/// @todo: Add more negative tests for processX(), e.g. extend sanityCheck() test
diff --git a/src/lib/dhcpsrv/Makefile.am b/src/lib/dhcpsrv/Makefile.am
index cc5daec..ce066e7 100644
--- a/src/lib/dhcpsrv/Makefile.am
+++ b/src/lib/dhcpsrv/Makefile.am
@@ -1,6 +1,6 @@
SUBDIRS = . tests
-AM_CPPFLAGS = -I$(top_builddir)/src/lib -I$(top_srcdir)/src/lib
+AM_CPPFLAGS = -I$(top_builddir)/src/lib -I$(top_srcdir)/src/lib -DDHCP_DATA_DIR="\"$(localstatedir)\""
AM_CPPFLAGS += $(BOOST_INCLUDES)
if HAVE_MYSQL
AM_CPPFLAGS += $(MYSQL_CPPFLAGS)
diff --git a/src/lib/dhcpsrv/cfgmgr.cc b/src/lib/dhcpsrv/cfgmgr.cc
index c6a190f..b5e83e3 100644
--- a/src/lib/dhcpsrv/cfgmgr.cc
+++ b/src/lib/dhcpsrv/cfgmgr.cc
@@ -248,7 +248,16 @@ void CfgMgr::deleteSubnets6() {
subnets6_.clear();
}
-CfgMgr::CfgMgr() {
+std::string CfgMgr::getDataDir() {
+ return (datadir_);
+}
+
+
+CfgMgr::CfgMgr()
+ :datadir_(DHCP_DATA_DIR) {
+ // DHCP_DATA_DIR must be set set with -DDHCP_DATA_DIR="..." in Makefile.am
+ // Note: the definition of DHCP_DATA_DIR needs to include quotation marks
+ // See AM_CPPFLAGS definition in Makefile.am
}
CfgMgr::~CfgMgr() {
diff --git a/src/lib/dhcpsrv/cfgmgr.h b/src/lib/dhcpsrv/cfgmgr.h
index bc4ffde..0e56869 100644
--- a/src/lib/dhcpsrv/cfgmgr.h
+++ b/src/lib/dhcpsrv/cfgmgr.h
@@ -230,6 +230,14 @@ public:
/// completely new?
void deleteSubnets4();
+
+ /// @brief returns path do the data directory
+ ///
+ /// This method returns a path to writeable directory that DHCP servers
+ /// can store data in.
+ /// @return data directory
+ std::string getDataDir();
+
protected:
/// @brief Protected constructor.
@@ -274,6 +282,8 @@ private:
/// @brief Container for defined DHCPv4 option spaces.
OptionSpaceCollection spaces4_;
+ /// @brief directory where data files (e.g. server-id) are stored
+ std::string datadir_;
};
} // namespace isc::dhcp
More information about the bind10-changes
mailing list