]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[github24] Specify excluded prefix for a PD pool.
authorMarcin Siodelski <marcin@isc.org>
Tue, 27 Sep 2016 15:59:55 +0000 (17:59 +0200)
committerMarcin Siodelski <marcin@isc.org>
Tue, 27 Sep 2016 15:59:55 +0000 (17:59 +0200)
src/lib/dhcpsrv/pool.cc
src/lib/dhcpsrv/pool.h
src/lib/dhcpsrv/tests/pool_unittest.cc

index fa89aac580d6ae4e1e1283b37446878bc4e0b1b1..96d9b5db9dc3d70f6968c746a2943f92a0ed3cf9 100644 (file)
@@ -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<unsigned>(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<unsigned>(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<unsigned>(excluded_prefix_len_)
+                      << " must be lower than the delegated prefix length "
+                      << static_cast<unsigned>(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<unsigned>(prefix_len));
+        isc_throw(BadValue, "Invalid prefix length: "
+                  << static_cast<unsigned>(prefix_len));
     }
 
     if (prefix_len > delegated_len) {
-        isc_throw(BadValue, "Delegated length (" << static_cast<int>(delegated_len)
+        isc_throw(BadValue, "Delegated length ("
+                  << static_cast<int>(delegated_len)
                   << ") must be longer than or equal to prefix length ("
                   << static_cast<int>(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<int>(prefix_len_);
-    return (tmp.str());
+    std::ostringstream s;
+    s << "type=" << Lease::typeToText(type_) << ", " << first_
+      << "-" << last_ << ", delegated_len="
+      << static_cast<int>(prefix_len_);
+
+    if (excluded_prefix_len_ > 0) {
+       s << ", excluded_prefix=" << excluded_prefix_
+         << ", excluded_prefix_len="
+         << static_cast<unsigned>(excluded_prefix_len_);
+    }
+    return (s.str());
 }
 
 }; // end of isc::dhcp namespace
index d5b26aa28fbfc5bc1e370fef0680fda093ae1dc7..fdf252e45208a8b1dbab7118f70f7283a655c382 100644 (file)
@@ -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
index 3c61ecd2369915aae1a959d8019451611bfa5e50..8c3cf124667d3527f1386ab1a8761f8cea5ce0cd 100644 (file)
@@ -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<unsigned>(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<unsigned>(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.