From: Marcin Siodelski Date: Tue, 27 Sep 2016 15:59:55 +0000 (+0200) Subject: [github24] Specify excluded prefix for a PD pool. X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=6a0c11038a46c7502805977eb7802a8a4ca18dc1;p=thirdparty%2Fkea.git [github24] Specify excluded prefix for a PD pool. --- diff --git a/src/lib/dhcpsrv/pool.cc b/src/lib/dhcpsrv/pool.cc index fa89aac580..96d9b5db9d 100644 --- a/src/lib/dhcpsrv/pool.cc +++ b/src/lib/dhcpsrv/pool.cc @@ -1,4 +1,4 @@ -// Copyright (C) 2012-2015 Internet Systems Consortium, Inc. ("ISC") +// Copyright (C) 2012-2016 Internet Systems Consortium, Inc. ("ISC") // // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this @@ -76,7 +76,9 @@ Pool4::Pool4( const isc::asiolink::IOAddress& prefix, uint8_t prefix_len) Pool6::Pool6(Lease::Type type, const isc::asiolink::IOAddress& first, const isc::asiolink::IOAddress& last) - :Pool(type, first, last), prefix_len_(128) { + : Pool(type, first, last), prefix_len_(128), + excluded_prefix_(IOAddress::IPV6_ZERO_ADDRESS()), + excluded_prefix_len_(0) { // check if specified address boundaries are sane if (!first.isV6() || !last.isV6()) { @@ -117,21 +119,91 @@ Pool6::Pool6(Lease::Type type, const isc::asiolink::IOAddress& first, } Pool6::Pool6(Lease::Type type, const isc::asiolink::IOAddress& prefix, - uint8_t prefix_len, uint8_t delegated_len /* = 128 */) - :Pool(type, prefix, IOAddress("::")), prefix_len_(delegated_len) { + const uint8_t prefix_len, const uint8_t delegated_len /* = 128 */) + : Pool(type, prefix, IOAddress::IPV6_ZERO_ADDRESS()), + prefix_len_(delegated_len), + excluded_prefix_(IOAddress::IPV6_ZERO_ADDRESS()), + excluded_prefix_len_(0) { + + init(type, prefix, prefix_len, delegated_len, + IOAddress::IPV6_ZERO_ADDRESS(), 0); +} - // check if the prefix is sane +Pool6::Pool6(const asiolink::IOAddress& prefix, const uint8_t prefix_len, + const uint8_t delegated_len, + const asiolink::IOAddress& excluded_prefix, + const uint8_t excluded_prefix_len) + : Pool(Lease::TYPE_PD, prefix, IOAddress::IPV6_ZERO_ADDRESS()), + prefix_len_(delegated_len), + excluded_prefix_(excluded_prefix), + excluded_prefix_len_(excluded_prefix_len) { + + init(Lease::TYPE_PD, prefix, prefix_len, delegated_len, excluded_prefix, + excluded_prefix_len); + + // The excluded prefix can only be specified using this constructor. + // Therefore, the initialization of the excluded prefix is takes place + // here, rather than in the init(...) function. + if (!excluded_prefix_.isV6()) { + isc_throw(BadValue, "excluded prefix must be an IPv6 prefix"); + } + + // An "unspecified" prefix should have both value and length equal to 0. + if ((excluded_prefix_.isV6Zero() && (excluded_prefix_len_ != 0)) || + (!excluded_prefix_.isV6Zero() && (excluded_prefix_len_ == 0))) { + isc_throw(BadValue, "invalid excluded prefix " + << excluded_prefix_ << "/" + << static_cast(excluded_prefix_len_)); + } + + // If excluded prefix has been specified. + if (!excluded_prefix_.isV6Zero() && (excluded_prefix_len_ != 0)) { + + // Excluded prefix length must not be greater than 128. + if (excluded_prefix_len_ > 128) { + isc_throw(BadValue, "excluded prefix length " + << static_cast(excluded_prefix_len_) + << " must not be greater than 128"); + } + + // Excluded prefix must be a sub-prefix of a delegated prefix. First + // check the prefix length as it is less involved. + if (excluded_prefix_len_ <= prefix_len_) { + isc_throw(BadValue, "excluded prefix length " + << static_cast(excluded_prefix_len_) + << " must be lower than the delegated prefix length " + << static_cast(prefix_len_)); + } + + /// @todo Check that the prefixes actually match. Theoretically, a + /// user could specify a prefix which sets insgnificant bits. We should + /// clear insignificant bits based on the prefix length but this + /// should be considered a part of the IOAddress class, perhaps and + /// requires a bit of work (mainly in terms of testing). + } +} + +void +Pool6::init(const Lease::Type& type, + const asiolink::IOAddress& prefix, + const uint8_t prefix_len, + const uint8_t delegated_len, + const asiolink::IOAddress& excluded_prefix, + const uint8_t excluded_prefix_len) { + // Check if the prefix is sane if (!prefix.isV6()) { isc_throw(BadValue, "Invalid Pool6 address boundaries: not IPv6"); } - // check if the prefix length is sane + // Check if the prefix length is sane if (prefix_len == 0 || prefix_len > 128) { - isc_throw(BadValue, "Invalid prefix length: " << static_cast(prefix_len)); + isc_throw(BadValue, "Invalid prefix length: " + << static_cast(prefix_len)); } if (prefix_len > delegated_len) { - isc_throw(BadValue, "Delegated length (" << static_cast(delegated_len) + isc_throw(BadValue, "Delegated length (" + << static_cast(delegated_len) << ") must be longer than or equal to prefix length (" << static_cast(prefix_len) << ")"); } @@ -156,11 +228,17 @@ Pool6::Pool6(Lease::Type type, const isc::asiolink::IOAddress& prefix, std::string Pool6::toText() const { - std::stringstream tmp; - tmp << "type=" << Lease::typeToText(type_) << ", " << first_ - << "-" << last_ << ", delegated_len=" - << static_cast(prefix_len_); - return (tmp.str()); + std::ostringstream s; + s << "type=" << Lease::typeToText(type_) << ", " << first_ + << "-" << last_ << ", delegated_len=" + << static_cast(prefix_len_); + + if (excluded_prefix_len_ > 0) { + s << ", excluded_prefix=" << excluded_prefix_ + << ", excluded_prefix_len=" + << static_cast(excluded_prefix_len_); + } + return (s.str()); } }; // end of isc::dhcp namespace diff --git a/src/lib/dhcpsrv/pool.h b/src/lib/dhcpsrv/pool.h index d5b26aa28f..fdf252e452 100644 --- a/src/lib/dhcpsrv/pool.h +++ b/src/lib/dhcpsrv/pool.h @@ -1,4 +1,4 @@ -// Copyright (C) 2012-2015 Internet Systems Consortium, Inc. ("ISC") +// Copyright (C) 2012-2016 Internet Systems Consortium, Inc. ("ISC") // // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this @@ -197,10 +197,27 @@ public: /// @param type type of the pool (IA, TA or PD) /// @param prefix specifies prefix of the pool /// @param prefix_len specifies prefix length of the pool - /// @param delegated_len specifies lenght of the delegated prefixes + /// @param delegated_len specifies length of the delegated prefixes Pool6(Lease::Type type, const isc::asiolink::IOAddress& prefix, uint8_t prefix_len, uint8_t delegated_len = 128); + /// @brief Constructor for DHCPv6 prefix pool with an excluded prefix. + /// + /// If @c excluded_prefix is equal to '::' and the @c excluded_prefix_len + /// is equal to 0, the excluded prefix is assumed to be unspecified for + /// the pool. In this case, the server will not send the Prefix Exclude + /// option to a client. + /// + /// @param prefix specified a prefix of the pool. + /// @param prefix_Leb specifies prefix length of the pool. + /// @param delegated_len specifies length of the delegated prefixes. + /// @param excluded_prefix specifies an excluded prefix as per RFC6603. + /// @param excluded_prefix_len specifies length of an excluded prefix. + Pool6(const asiolink::IOAddress& prefix, const uint8_t prefix_len, + const uint8_t delegated_len, + const asiolink::IOAddress& excluded_prefix, + const uint8_t excluded_prefix_len); + /// @brief returns pool type /// /// @return pool type @@ -217,14 +234,75 @@ public: return (prefix_len_); } + /// @brief Returns an excluded prefix. + /// + /// An excluded prefix can be specified for a prefix pool as specified + /// in RFC6603. + /// + /// @return Reference to an IOAddress object representing an excluded + /// prefix pool. A value of '::' if the excluded prefix is not specified. + const isc::asiolink::IOAddress& getExcludedPrefix() const{ + return (excluded_prefix_); + } + + /// @brief Returns an excluded prefix length. + /// + /// An excluded prefix can be specified for a prefix pool as specified + /// in RFC6603. + /// + /// @return Excluded prefix length in the range of 2 to 128, if the + /// excluded prefix is specified. A value of 0 if the excluded prefix + /// is not specified. + uint8_t getExcludedPrefixLength() const{ + return (excluded_prefix_len_); + } + /// @brief returns textual representation of the pool /// /// @return textual representation virtual std::string toText() const; private: + + /// @brief Generic method initializing a DHCPv6 pool. + /// + /// This method should be called by the constructors to initialize + /// DHCPv6 pools. + /// + /// @param Lease/pool type. + /// @param prefix An address or delegated prefix (depending on the + /// pool type specified as @c type). + /// @param prefix_len Prefix length. If a pool is an address pool, + /// this value should be set to 128. + /// @param delegated_len Length of the delegated prefixes. If a pool + /// is an address pool, this value should be set to 128. + /// @param excluded_prefix An excluded prefix as per RFC6603. This + /// value should only be specified for prefix pools. The value of + /// '::' means "unspecified". + /// @param excluded_prefix_len Length of the excluded prefix. This + /// is only specified for prefix pools. The value of 0 should be + /// used when @c excluded_prefix is not specified. + void init(const Lease::Type& type, + const asiolink::IOAddress& prefix, + const uint8_t prefix_len, + const uint8_t delegated_len, + const asiolink::IOAddress& excluded_prefix, + const uint8_t excluded_prefix_len); + /// @brief Defines prefix length (for TYPE_PD only) uint8_t prefix_len_; + + /// @brief The excluded prefix (RFC6603). + /// + /// This prefix can only be specified for DHCPv6 prefix pools. + /// An "unspecified" prefix has a value of '::'. + isc::asiolink::IOAddress excluded_prefix_; + + /// @brief The excluded prefix length (RFC6603). + /// + /// This value can only be specified for DHCPv6 prefix pool. + /// An "unspecified" prefix has a length of 0. + uint8_t excluded_prefix_len_; }; /// @brief a pointer an IPv6 Pool diff --git a/src/lib/dhcpsrv/tests/pool_unittest.cc b/src/lib/dhcpsrv/tests/pool_unittest.cc index 3c61ecd236..8c3cf12466 100644 --- a/src/lib/dhcpsrv/tests/pool_unittest.cc +++ b/src/lib/dhcpsrv/tests/pool_unittest.cc @@ -1,4 +1,4 @@ -// Copyright (C) 2012-2015 Internet Systems Consortium, Inc. ("ISC") +// Copyright (C) 2012-2016 Internet Systems Consortium, Inc. ("ISC") // // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this @@ -206,6 +206,68 @@ TEST(Pool6Test, PD) { 77, 77)); } +// Checks that prefix pools with excluded prefixes are handlded properly. +TEST(Pool6Test, PDExclude) { + Pool6Ptr pool; + + // Create a pool with a good excluded prefix. The good excluded prefix + // is the one for which is a sub-prefix of the main prefix. + ASSERT_NO_THROW(pool.reset(new Pool6(IOAddress("2001:db8:1::"), 96, 112, + IOAddress("2001:db8:1:2::"), 120))); + + // Verify pool properties. + EXPECT_EQ(Lease::TYPE_PD, pool->getType()); + EXPECT_EQ(112, pool->getLength()); + EXPECT_EQ("2001:db8:1::", pool->getFirstAddress().toText()); + EXPECT_EQ("2001:db8:1::ffff:ffff", pool->getLastAddress().toText()); + EXPECT_EQ("2001:db8:1:2::", pool->getExcludedPrefix().toText()); + EXPECT_EQ(120, static_cast(pool->getExcludedPrefixLength())); + + // Create another pool instance, but with the excluded prefix being + // "unspecified". + ASSERT_NO_THROW(pool.reset(new Pool6(IOAddress("2001:db8:1::"), 96, 112, + IOAddress::IPV6_ZERO_ADDRESS(), 0))); + + EXPECT_EQ(Lease::TYPE_PD, pool->getType()); + EXPECT_EQ(112, pool->getLength()); + EXPECT_EQ("2001:db8:1::", pool->getFirstAddress().toText()); + EXPECT_EQ("2001:db8:1::ffff:ffff", pool->getLastAddress().toText()); + EXPECT_TRUE(pool->getExcludedPrefix().isV6Zero()); + EXPECT_EQ(0, static_cast(pool->getExcludedPrefixLength())); + + // Excluded prefix length must be greater than the main prefix length. + EXPECT_THROW(Pool6(IOAddress("2001:db8:1::"), 96, 112, + IOAddress("2001:db8:1::"), 112), + BadValue); + + // Again, the excluded prefix length must be greater than main prefix + // length. + EXPECT_THROW(Pool6(IOAddress("2001:db8:1::"), 96, 112, + IOAddress("2001:db8:1::"), 104), + BadValue); + + // The "unspecified" excluded prefix must have both values set to 0. + EXPECT_THROW(Pool6(IOAddress("2001:db8:1::"), 48, 64, + IOAddress("2001:db8:1::"), 0), + BadValue); + + // Similar case as above, but the prefix value is 0 and the length + // is non zero. + EXPECT_THROW(Pool6(IOAddress("2001:db8:1::"), 48, 64, + IOAddress::IPV6_ZERO_ADDRESS(), 72), + BadValue); + + // Excluded prefix must be an IPv6 prefix. + EXPECT_THROW(Pool6(IOAddress("10::"), 8, 16, + IOAddress("10.0.0.0"), 24), + BadValue); + + // Excluded prefix length must not be greater than 128. + EXPECT_THROW(Pool6(IOAddress("2001:db8:1::"), 48, 64, + IOAddress("2001:db8:1::"), 129), + BadValue); +} + // Checks that temporary address pools are handled properly TEST(Pool6Test, TA) { // Note: since we defined TA pool types during PD work, we can test it @@ -261,7 +323,7 @@ TEST(Pool6Test, unique_id) { } // Simple check if toText returns reasonable values -TEST(Poo6Test,toText) { +TEST(Pool6Test,toText) { Pool6 pool1(Lease::TYPE_NA, IOAddress("2001:db8::1"), IOAddress("2001:db8::2")); EXPECT_EQ("type=IA_NA, 2001:db8::1-2001:db8::2, delegated_len=128", @@ -270,6 +332,13 @@ TEST(Poo6Test,toText) { Pool6 pool2(Lease::TYPE_PD, IOAddress("2001:db8:1::"), 96, 112); EXPECT_EQ("type=IA_PD, 2001:db8:1::-2001:db8:1::ffff:ffff, delegated_len=112", pool2.toText()); + + Pool6 pool3(IOAddress("2001:db8:1::"), 96, 112, + IOAddress("2001:db8:1::1000"), 120); + EXPECT_EQ("type=IA_PD, 2001:db8:1::-2001:db8:1::ffff:ffff, delegated_len=112," + " excluded_prefix=2001:db8:1::1000, excluded_prefix_len=120", + pool3.toText()); + } // Checks if the number of possible leases in range is reported correctly.