summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--doc/guide/dhcp4-srv.xml4
-rw-r--r--src/bin/dhcp4/tests/dora_unittest.cc8
-rw-r--r--src/bin/dhcp4/tests/inform_unittest.cc57
-rw-r--r--src/lib/dhcpsrv/host.cc21
-rw-r--r--src/lib/dhcpsrv/host.h14
-rw-r--r--src/lib/dhcpsrv/tests/host_reservation_parser_unittest.cc38
-rw-r--r--src/lib/dhcpsrv/tests/host_unittest.cc6
7 files changed, 130 insertions, 18 deletions
diff --git a/doc/guide/dhcp4-srv.xml b/doc/guide/dhcp4-srv.xml
index 61355e9bb0..cbad5ab517 100644
--- a/doc/guide/dhcp4-srv.xml
+++ b/doc/guide/dhcp4-srv.xml
@@ -2837,8 +2837,8 @@ It is merely echoed by the server
"subnet4": [ {
"reservations": [
{
- <userinput>"hw-address": "aa:bb:cc:dd:ee:ff",
- "next-server": "10.1.1.2",
+ "hw-address": "aa:bb:cc:dd:ee:ff",
+ <userinput>"next-server": "10.1.1.2",
"server-hostname": "server-hostname.example.org",
"boot-file-name": "/tmp/bootfile.efi"</userinput>
} ]
diff --git a/src/bin/dhcp4/tests/dora_unittest.cc b/src/bin/dhcp4/tests/dora_unittest.cc
index 9b0cdb99f2..4c6f8f50a7 100644
--- a/src/bin/dhcp4/tests/dora_unittest.cc
+++ b/src/bin/dhcp4/tests/dora_unittest.cc
@@ -77,7 +77,7 @@ namespace {
/// - 1 subnet: 10.0.0.0/24
/// - 1 reservation for this subnet:
/// - Client's HW address: aa:bb:cc:dd:ee:ff
-/// - next-server = 192.0.0.2
+/// - next-server = 10.0.0.7
/// - server name = "some-name.example.org"
/// - boot-file-name = "bootfile.efi"
const char* DORA_CONFIGS[] = {
@@ -262,7 +262,7 @@ const char* DORA_CONFIGS[] = {
" }"
" ]"
"} ]"
- "}",
+ "}"
};
/// @brief Test fixture class for testing 4-way (DORA) exchanges.
@@ -1028,8 +1028,8 @@ TEST_F(DORATest, messageFieldsReservations) {
client.setHWAddress("aa:bb:cc:dd:ee:ff");
// Configure DHCP server.
configure(DORA_CONFIGS[6], *client.getServer());
- // Client A performs 4-way exchange and should obtain a reserved
- // address.
+ // Client performs 4-way exchange and should obtain a reserved
+ // address and fixed fields.
ASSERT_NO_THROW(client.doDORA(boost::shared_ptr<
IOAddress>(new IOAddress("0.0.0.0"))));
// Make sure that the server responded.
diff --git a/src/bin/dhcp4/tests/inform_unittest.cc b/src/bin/dhcp4/tests/inform_unittest.cc
index 5ed038b4dc..7a45b7e0a1 100644
--- a/src/bin/dhcp4/tests/inform_unittest.cc
+++ b/src/bin/dhcp4/tests/inform_unittest.cc
@@ -39,6 +39,16 @@ namespace {
/// - Domain Name Server option present: 192.0.2.202, 192.0.2.203.
/// - Log Servers option present: 192.0.2.200 and 192.0.2.201
/// - Quotes Servers option present: 192.0.2.202, 192.0.2.203.
+///
+/// - Configuration 2:
+/// - This configuration provides reservations for next-server,
+/// server-hostname and boot-file-name value.
+/// - 1 subnet: 192.0.2.0/24
+/// - 1 reservation for this subnet:
+/// - Client's HW address: aa:bb:cc:dd:ee:ff
+/// - next-server = 10.0.0.7
+/// - server name = "some-name.example.org"
+/// - boot-file-name = "bootfile.efi"
const char* INFORM_CONFIGS[] = {
// Configuration 0
"{ \"interfaces-config\": {"
@@ -91,7 +101,26 @@ const char* INFORM_CONFIGS[] = {
" \"data\": \"10.0.0.202,10.0.0.203\""
" } ]"
" } ]"
- "}"
+ "}",
+
+// Configuration 2
+ "{ \"interfaces-config\": {"
+ " \"interfaces\": [ \"*\" ]"
+ "},"
+ "\"valid-lifetime\": 600,"
+ "\"next-server\": \"10.0.0.1\","
+ "\"subnet4\": [ { "
+ " \"subnet\": \"192.0.2.0/24\", "
+ " \"reservations\": [ "
+ " {"
+ " \"hw-address\": \"aa:bb:cc:dd:ee:ff\","
+ " \"next-server\": \"10.0.0.7\","
+ " \"server-hostname\": \"some-name.example.org\","
+ " \"boot-file-name\": \"bootfile.efi\""
+ " }"
+ " ]"
+ "} ]"
+ "}",
};
/// @brief Test fixture class for testing DHCPINFORM.
@@ -364,6 +393,32 @@ TEST_F(InformTest, relayedClientNoCiaddr) {
EXPECT_EQ("192.0.2.203", client.config_.dns_servers_[1].toText());
}
+// This test verifies that the server assigns reserved values for the
+// siaddr, sname and file fields carried within DHCPv4 message.
+TEST_F(InformTest, messageFieldsReservations) {
+ // Client has a reservation.
+ Dhcp4Client client(Dhcp4Client::SELECTING);
+ // Message is relayed.
+ client.useRelay();
+ // Set explicit HW address so as it matches the reservation in the
+ // configuration used below.
+ client.setHWAddress("aa:bb:cc:dd:ee:ff");
+ // Configure DHCP server.
+ configure(INFORM_CONFIGS[2], *client.getServer());
+ // Client sends DHCPINFORM and should receive reserved fields.
+ ASSERT_NO_THROW(client.doInform());
+ // Make sure that the server responded.
+ ASSERT_TRUE(client.getContext().response_);
+ Pkt4Ptr resp = client.getContext().response_;
+ // Make sure that the server has responded with DHCPACK.
+ ASSERT_EQ(DHCPACK, static_cast<int>(resp->getType()));
+
+ // Check that the reserved values have been assigned.
+ EXPECT_EQ("10.0.0.7", client.config_.siaddr_.toText());
+ EXPECT_EQ("some-name.example.org", client.config_.sname_);
+ EXPECT_EQ("bootfile.efi", client.config_.boot_file_name_);
+}
+
/// This test verifies that after a client completes its INFORM exchange,
/// appropriate statistics are updated.
TEST_F(InformTest, statisticsInform) {
diff --git a/src/lib/dhcpsrv/host.cc b/src/lib/dhcpsrv/host.cc
index 70211e903b..8b3bbb3e1e 100644
--- a/src/lib/dhcpsrv/host.cc
+++ b/src/lib/dhcpsrv/host.cc
@@ -5,6 +5,7 @@
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include <config.h>
+#include <dhcp/pkt4.h>
#include <dhcpsrv/host.h>
#include <util/encode/hex.h>
#include <util/strutil.h>
@@ -365,7 +366,7 @@ Host::setNextServer(const asiolink::IOAddress& next_server) {
if (!next_server.isV4()) {
isc_throw(isc::BadValue, "next server address '" << next_server
<< "' is not a valid IPv4 address");
- } else if (next_server.isV4Zero() || next_server.isV4Bcast()) {
+ } else if (next_server.isV4Bcast()) {
isc_throw(isc::BadValue, "invalid next server address '"
<< next_server << "'");
}
@@ -373,6 +374,24 @@ Host::setNextServer(const asiolink::IOAddress& next_server) {
next_server_ = next_server;
}
+void
+Host::setServerHostname(const std::string& server_host_name) {
+ if (server_host_name.size() > Pkt4::MAX_SNAME_LEN - 1) {
+ isc_throw(isc::BadValue, "server hostname length must not exceed "
+ << (Pkt4::MAX_SNAME_LEN - 1));
+ }
+ server_host_name_ = server_host_name;
+}
+
+void
+Host::setBootFileName(const std::string& boot_file_name) {
+ if (boot_file_name.size() > Pkt4::MAX_FILE_LEN - 1) {
+ isc_throw(isc::BadValue, "boot file length must not exceed "
+ << (Pkt4::MAX_FILE_LEN - 1));
+ }
+ boot_file_name_ = boot_file_name;
+}
+
std::string
Host::toText() const {
std::ostringstream s;
diff --git a/src/lib/dhcpsrv/host.h b/src/lib/dhcpsrv/host.h
index 5a912346d1..fa080e67ce 100644
--- a/src/lib/dhcpsrv/host.h
+++ b/src/lib/dhcpsrv/host.h
@@ -466,7 +466,7 @@ public:
/// @param next_server New address of a next server.
///
/// @throw isc::BadValue if the provided address is not an IPv4 address,
- /// is a 0 address or broadcast address.
+ /// is broadcast address.
void setNextServer(const asiolink::IOAddress& next_server);
/// @brief Returns value of next server field (siaddr).
@@ -477,9 +477,9 @@ public:
/// @brief Sets new value for server hostname (sname).
///
/// @param server_host_name New value for server hostname.
- void setServerHostname(const std::string& server_host_name) {
- server_host_name_ = server_host_name;
- }
+ ///
+ /// @throw BadValue if hostname is longer than 63 bytes.
+ void setServerHostname(const std::string& server_host_name);
/// @brief Returns value of server hostname (sname).
const std::string& getServerHostname() const {
@@ -489,9 +489,9 @@ public:
/// @brief Sets new value for boot file name (file).
///
/// @param boot_file_name New value of boot file name.
- void setBootFileName(const std::string& boot_file_name) {
- boot_file_name_ = boot_file_name;
- }
+ ///
+ /// @throw BadValue if boot file name is longer than 128 bytes.
+ void setBootFileName(const std::string& boot_file_name);
/// @brief Returns value of boot file name (file).
const std::string& getBootFileName() const {
diff --git a/src/lib/dhcpsrv/tests/host_reservation_parser_unittest.cc b/src/lib/dhcpsrv/tests/host_reservation_parser_unittest.cc
index c90e309912..f083299927 100644
--- a/src/lib/dhcpsrv/tests/host_reservation_parser_unittest.cc
+++ b/src/lib/dhcpsrv/tests/host_reservation_parser_unittest.cc
@@ -20,6 +20,7 @@
#include <boost/pointer_cast.hpp>
#include <gtest/gtest.h>
#include <iterator>
+#include <sstream>
#include <string>
#include <vector>
@@ -327,6 +328,43 @@ TEST_F(HostReservationParserTest, dhcp4MessageFields) {
EXPECT_EQ("/tmp/some-file.efi", hosts[0]->getBootFileName());
}
+// This test verifies that the invalid value of the next server is rejected.
+TEST_F(HostReservationParserTest, invalidNextServer) {
+ // Invalid IPv4 address.
+ std::string config = "{ \"hw-address\": \"1:2:3:4:5:6\","
+ "\"next-server\": \"192.0.2.foo\" }";
+ testInvalidConfig<HostReservationParser4>(config);
+
+ // Broadcast address.
+ config = "{ \"hw-address\": \"1:2:3:4:5:6\","
+ "\"next-server\": \"255.255.255.255\" }";
+ testInvalidConfig<HostReservationParser4>(config);
+
+ // IPv6 address.
+ config = "{ \"hw-address\": \"1:2:3:4:5:6\","
+ "\"next-server\": \"2001:db8:1::1\" }";
+ testInvalidConfig<HostReservationParser4>(config);
+}
+
+// This test verifies that the invalid server hostname is rejected.
+TEST_F(HostReservationParserTest, invalidServerHostname) {
+ std::ostringstream config;
+ config << "{ \"hw-address\": \"1:2:3:4:5:6\","
+ "\"server-hostname\": \"";
+ config << std::string(64, 'a');
+ config << "\" }";
+ testInvalidConfig<HostReservationParser4>(config.str());
+}
+
+// This test verifies that the invalid boot file name is rejected.
+TEST_F(HostReservationParserTest, invalidBootFileName) {
+ std::ostringstream config;
+ config << "{ \"hw-address\": \"1:2:3:4:5:6\","
+ "\"boot-file-name\": \"";
+ config << std::string(128, 'a');
+ config << "\" }";
+ testInvalidConfig<HostReservationParser4>(config.str());
+}
// This test verifies that the configuration parser for host reservations
// throws an exception when IPv6 address is specified for IPv4 address
diff --git a/src/lib/dhcpsrv/tests/host_unittest.cc b/src/lib/dhcpsrv/tests/host_unittest.cc
index 195b7766cd..e51733bbb1 100644
--- a/src/lib/dhcpsrv/tests/host_unittest.cc
+++ b/src/lib/dhcpsrv/tests/host_unittest.cc
@@ -686,11 +686,11 @@ TEST_F(HostTest, setValues) {
EXPECT_THROW(host->setIPv4Reservation(IOAddress::IPV4_BCAST_ADDRESS()),
isc::BadValue);
- // Zero or broadcast are invalid addresses for next server.
- EXPECT_THROW(host->setNextServer(asiolink::IOAddress::IPV4_ZERO_ADDRESS()),
- isc::BadValue);
+ // Broadcast and IPv6 are invalid addresses for next server.
EXPECT_THROW(host->setNextServer(asiolink::IOAddress::IPV4_BCAST_ADDRESS()),
isc::BadValue);
+ EXPECT_THROW(host->setNextServer(IOAddress("2001:db8:1::1")),
+ isc::BadValue);
}
// Test that Host constructors initialize client classes from string.