From: Marcin Siodelski Date: Tue, 28 Oct 2014 10:05:48 +0000 (+0100) Subject: [3562] Added negative test scenarios for ipv6 host reservations. X-Git-Tag: kea-eng-20141219~28^2~1 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=0ed7f6f05eba31b127b307fb0ae1e94b7ab2d16d;p=thirdparty%2Fkea.git [3562] Added negative test scenarios for ipv6 host reservations. --- diff --git a/src/lib/dhcpsrv/host.cc b/src/lib/dhcpsrv/host.cc index 7fff0d6cfa..a47b59d404 100644 --- a/src/lib/dhcpsrv/host.cc +++ b/src/lib/dhcpsrv/host.cc @@ -15,6 +15,7 @@ #include #include #include +#include namespace isc { namespace dhcp { @@ -42,6 +43,17 @@ IPv6Resrv::set(const asiolink::IOAddress& prefix, const uint8_t prefix_len) { prefix_len_ = prefix_len; } +std::string +IPv6Resrv::toText() const { + std::ostringstream s; + s << prefix_; + // For PD, append prefix length. + if (getType() == TYPE_PD) { + s << "/" << static_cast(prefix_len_); + } + return (s.str()); +} + bool IPv6Resrv::operator==(const IPv6Resrv& other) const { return (prefix_ == other.prefix_ && @@ -158,6 +170,12 @@ Host::setIPv4Reservation(const asiolink::IOAddress& address) { void Host::addReservation(const IPv6Resrv& reservation) { + // Check if it is not duplicating existing reservation. + if (hasReservation(reservation)) { + isc_throw(isc::InvalidOperation, "failed on attempt to add a duplicated" + " host reservation for " << reservation.toText()); + } + // Add it. ipv6_reservations_.insert(IPv6ResrvTuple(reservation.getType(), reservation)); } @@ -167,6 +185,22 @@ Host::getIPv6Reservations(const IPv6Resrv::Type& type) const { return (ipv6_reservations_.equal_range(type)); } +bool +Host::hasReservation(const IPv6Resrv& reservation) const { + IPv6ResrvRange reservations = getIPv6Reservations(reservation.getType()); + if (std::distance(reservations.first, reservations.second) > 0) { + for (IPv6ResrvIterator it = reservations.first; + it != reservations.second; ++it) { + if (it->second == reservation) { + return (true); + } + } + } + + // No matching reservations found. + return (false); +} + void Host::addClientClassInternal(ClientClasses& classes, const std::string& class_name) { diff --git a/src/lib/dhcpsrv/host.h b/src/lib/dhcpsrv/host.h index ee6bb75427..30f04b3cd8 100644 --- a/src/lib/dhcpsrv/host.h +++ b/src/lib/dhcpsrv/host.h @@ -91,6 +91,9 @@ public: /// multicast address or the prefix length is greater than 128. void set(const asiolink::IOAddress& prefix, const uint8_t prefix_len); + /// @brief Returns information about the reservation in the textual format. + std::string toText() const; + /// @brief Equality operator. /// /// @param other Reservation to compare to. @@ -340,6 +343,14 @@ public: /// the specified type. IPv6ResrvRange getIPv6Reservations(const IPv6Resrv::Type& type) const; + /// @brief Checks if specified IPv6 reservation exists for the host. + /// + /// @param reservation A reservation to be checked for the host. + /// + /// @return true if the reservation already exists for the host, false + /// otherwise. + bool hasReservation(const IPv6Resrv& reservation) const; + /// @brief Sets new hostname. /// /// @param hostname New hostname. diff --git a/src/lib/dhcpsrv/tests/host_reservation_parser_unittest.cc b/src/lib/dhcpsrv/tests/host_reservation_parser_unittest.cc index b06889bc2c..343ce5c624 100644 --- a/src/lib/dhcpsrv/tests/host_reservation_parser_unittest.cc +++ b/src/lib/dhcpsrv/tests/host_reservation_parser_unittest.cc @@ -271,5 +271,78 @@ TEST_F(HostReservationParserTest, dhcp6IPv4Address) { EXPECT_THROW(parser.build(config_element), DhcpConfigError); } +// This test verifies that the configuration parser throws an exception +// when empty address has been specified. +TEST_F(HostReservationParserTest, dhcp6NullAddress) { + std::string config = "{ \"duid\": \"01:02:03:04:05:06:07:08:09:0A\"," + "\"ip-addresses\": [ \"\" ]," + "\"prefixes\": [ ] }"; + + ElementPtr config_element = Element::fromJSON(config); + + HostReservationParser6 parser(SubnetID(12)); + EXPECT_THROW(parser.build(config_element), DhcpConfigError); +} + +// This test verifies that the configuration parser throws an exception +// when invalid prefix length is specified. +TEST_F(HostReservationParserTest, dhcp6InvalidPrefixLength) { + std::string config = "{ \"duid\": \"01:02:03:04:05:06:07:08:09:0A\"," + "\"prefixes\": [ \"2001:db8:1::/abc\" ] }"; + + ElementPtr config_element = Element::fromJSON(config); + + HostReservationParser6 parser(SubnetID(12)); + EXPECT_THROW(parser.build(config_element), DhcpConfigError); +} + +// This test verifies that the configuration parser throws an exception +// when empty prefix is specified. +TEST_F(HostReservationParserTest, dhcp6NullPrefix) { + std::string config = "{ \"duid\": \"01:02:03:04:05:06:07:08:09:0A\"," + "\"prefixes\": [ \"/64\" ] }"; + + ElementPtr config_element = Element::fromJSON(config); + + HostReservationParser6 parser(SubnetID(12)); + EXPECT_THROW(parser.build(config_element), DhcpConfigError); +} + +// This test verifies that the configuration parser throws an exception +// when only slash is specified for the prefix.. +TEST_F(HostReservationParserTest, dhcp6NullPrefix2) { + std::string config = "{ \"duid\": \"01:02:03:04:05:06:07:08:09:0A\"," + "\"prefixes\": [ \"/\" ] }"; + + ElementPtr config_element = Element::fromJSON(config); + + HostReservationParser6 parser(SubnetID(12)); + EXPECT_THROW(parser.build(config_element), DhcpConfigError); +} + +// This test verifies that the configuration parser throws an exception +// when the same address is reserved twice. +TEST_F(HostReservationParserTest, dhcp6DuplicatedAddress) { + std::string config = "{ \"duid\": \"01:02:03:04:05:06:07:08:09:0A\"," + "\"ip-addresses\": [ \"2001:db8:1::1\", \"2001:db8:1::1\" ] }"; + + ElementPtr config_element = Element::fromJSON(config); + + HostReservationParser6 parser(SubnetID(12)); + EXPECT_THROW(parser.build(config_element), DhcpConfigError); +} + +// This test verifies that the configuration parser throws an exception +// when the same prefix is reserved twice. +TEST_F(HostReservationParserTest, dhcp6DuplicatedPrefix) { + std::string config = "{ \"duid\": \"01:02:03:04:05:06:07:08:09:0A\"," + "\"prefixes\": [ \"2001:db8:0101::/64\", \"2001:db8:0101::/64\" ] }"; + + ElementPtr config_element = Element::fromJSON(config); + + HostReservationParser6 parser(SubnetID(12)); + EXPECT_THROW(parser.build(config_element), DhcpConfigError); +} + } // end of anonymous namespace diff --git a/src/lib/dhcpsrv/tests/host_unittest.cc b/src/lib/dhcpsrv/tests/host_unittest.cc index 0849210895..8564cb09cb 100644 --- a/src/lib/dhcpsrv/tests/host_unittest.cc +++ b/src/lib/dhcpsrv/tests/host_unittest.cc @@ -42,6 +42,15 @@ TEST(IPv6ResrvTest, constructorPrefix) { EXPECT_EQ(IPv6Resrv::TYPE_PD, resrv.getType()); } +// This test verifies that the toText() function prints correctly. +TEST(IPv6ResrvTest, toText) { + IPv6Resrv resrv_prefix(IOAddress("2001:db8:1::"), 64); + EXPECT_EQ("2001:db8:1::/64", resrv_prefix.toText()); + + IPv6Resrv resrv_address(IOAddress("2001:db8:111::23")); + EXPECT_EQ("2001:db8:111::23", resrv_address.toText()); +} + // This test verifies that invalid prefix is rejected. TEST(IPv6ResrvTest, constructorInvalidPrefix) { // IPv4 address is invalid for IPv6 reservation. @@ -339,6 +348,14 @@ TEST(HostTest, addReservations) { host->addReservation(IPv6Resrv(IOAddress("2001:db8:1::1"))); ); + // Check that reservations exist. + EXPECT_TRUE(host->hasReservation(IPv6Resrv(IOAddress("2001:db8:1::cafe")))); + EXPECT_TRUE(host->hasReservation(IPv6Resrv(IOAddress("2001:db8:1:1::"), + 64))); + EXPECT_TRUE(host->hasReservation(IPv6Resrv(IOAddress("2001:db8:1:2::"), + 64))); + EXPECT_TRUE(host->hasReservation(IPv6Resrv(IOAddress("2001:db8:1::1")))); + // Get only NA reservations. IPv6ResrvRange addresses = host->getIPv6Reservations(IPv6Resrv::TYPE_NA); ASSERT_EQ(2, std::distance(addresses.first, addresses.second));