]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[lib] Extend host structure to support auth keys for reconfiguration.
authormayya <mayya@itwm.fraunhofer.de>
Sun, 10 Jun 2018 16:45:34 +0000 (18:45 +0200)
committerTomek Mrugalski <tomasz@isc.org>
Mon, 23 Jul 2018 11:31:03 +0000 (13:31 +0200)
 See issue #83

25 files changed:
src/lib/dhcpsrv/cql_host_data_source.cc
src/lib/dhcpsrv/cql_lease_mgr.cc
src/lib/dhcpsrv/cql_lease_mgr.h
src/lib/dhcpsrv/dhcpsrv_messages.mes
src/lib/dhcpsrv/host.cc
src/lib/dhcpsrv/host.h
src/lib/dhcpsrv/lease_mgr.h
src/lib/dhcpsrv/memfile_lease_mgr.cc
src/lib/dhcpsrv/memfile_lease_mgr.h
src/lib/dhcpsrv/mysql_host_data_source.cc
src/lib/dhcpsrv/mysql_lease_mgr.cc
src/lib/dhcpsrv/mysql_lease_mgr.h
src/lib/dhcpsrv/pgsql_host_data_source.cc
src/lib/dhcpsrv/pgsql_lease_mgr.cc
src/lib/dhcpsrv/pgsql_lease_mgr.h
src/lib/dhcpsrv/tests/cql_host_data_source_unittest.cc
src/lib/dhcpsrv/tests/host_unittest.cc
src/lib/dhcpsrv/tests/lease_mgr_unittest.cc
src/lib/dhcpsrv/tests/pgsql_host_data_source_unittest.cc
src/lib/dhcpsrv/testutils/generic_host_data_source_unittest.cc
src/lib/dhcpsrv/testutils/host_data_source_utils.cc
src/lib/dhcpsrv/testutils/host_data_source_utils.h
src/share/database/scripts/mysql/dhcpdb_create.mysql
src/share/database/scripts/mysql/upgrade_5.2_to_6.0.sh.in
src/share/database/scripts/pgsql/dhcpdb_create.pgsql

index ae8787359c1288f9a070135b08a57576d2691909..0c0609cb11c4ec457ffaf6747a1be46c04d96d54 100644 (file)
@@ -116,6 +116,7 @@ static constexpr char NULL_USER_CONTEXT[] = "";
 static constexpr char NULL_RESERVED_IPV6_PREFIX_ADDRESS[] = "::";
 static constexpr cass_int32_t NULL_RESERVED_IPV6_PREFIX_LENGTH = 0;
 static constexpr cass_int32_t NULL_RESERVED_IPV6_PREFIX_ADDRESS_TYPE = -1;
+static constexpr char NULL_RESERVED_KEY[] = "";
 static constexpr cass_int32_t NULL_IAID = -1;
 static constexpr cass_int32_t NULL_OPTION_UNIVERSE = -1;
 static constexpr cass_int32_t NULL_OPTION_CODE = -1;
@@ -372,6 +373,9 @@ private:
     /// This value corresponds to the @ref Host::IdentifierType value.
     cass_int32_t reserved_ipv6_prefix_address_type_;
 
+    /// @brief Key for authentication
+    std::string reserved_key_;
+
     /// @brief The reservation's IAID
     cass_int32_t iaid_;
 
@@ -438,6 +442,7 @@ StatementMap CqlHostExchange::tagged_statements_ = {
       "reserved_ipv6_prefix_address, "
       "reserved_ipv6_prefix_length, "
       "reserved_ipv6_prefix_address_type, "
+      "reserved_key, "
       "iaid, "
       "option_universe, "
       "option_code, "
@@ -455,7 +460,7 @@ StatementMap CqlHostExchange::tagged_statements_ = {
       // host
       "?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, "
       // denormalized reservation, option
-      "?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? "
+      "?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? "
       ") "
       "IF NOT EXISTS "
      }},
@@ -479,6 +484,7 @@ StatementMap CqlHostExchange::tagged_statements_ = {
       "reserved_ipv6_prefix_address, "
       "reserved_ipv6_prefix_length, "
       "reserved_ipv6_prefix_address_type, "
+      "reserved_key, "
       "iaid, "
       "option_universe, "
       "option_code, "
@@ -512,6 +518,7 @@ StatementMap CqlHostExchange::tagged_statements_ = {
       "reserved_ipv6_prefix_address, "
       "reserved_ipv6_prefix_length, "
       "reserved_ipv6_prefix_address_type, "
+      "reserved_key, "
       "iaid, "
       "option_universe, "
       "option_code, "
@@ -548,6 +555,7 @@ StatementMap CqlHostExchange::tagged_statements_ = {
       "reserved_ipv6_prefix_address, "
       "reserved_ipv6_prefix_length, "
       "reserved_ipv6_prefix_address_type, "
+      "reserved_key, "
       "iaid, "
       "option_universe, "
       "option_code, "
@@ -583,6 +591,7 @@ StatementMap CqlHostExchange::tagged_statements_ = {
       "reserved_ipv6_prefix_address, "
       "reserved_ipv6_prefix_length, "
       "reserved_ipv6_prefix_address_type, "
+      "reserved_key, "
       "iaid, "
       "option_universe, "
       "option_code, "
@@ -620,6 +629,7 @@ StatementMap CqlHostExchange::tagged_statements_ = {
       "reserved_ipv6_prefix_address, "
       "reserved_ipv6_prefix_length, "
       "reserved_ipv6_prefix_address_type, "
+      "reserved_key, "
       "iaid, "
       "option_universe, "
       "option_code, "
@@ -657,6 +667,7 @@ StatementMap CqlHostExchange::tagged_statements_ = {
       "reserved_ipv6_prefix_address, "
       "reserved_ipv6_prefix_length, "
       "reserved_ipv6_prefix_address_type, "
+      "reserved_key, "
       "iaid, "
       "option_universe, "
       "option_code, "
@@ -693,6 +704,7 @@ StatementMap CqlHostExchange::tagged_statements_ = {
       "reserved_ipv6_prefix_address, "
       "reserved_ipv6_prefix_length, "
       "reserved_ipv6_prefix_address_type, "
+      "reserved_key, "
       "iaid, "
       "option_universe, "
       "option_code, "
@@ -729,6 +741,7 @@ StatementMap CqlHostExchange::tagged_statements_ = {
       "reserved_ipv6_prefix_address, "
       "reserved_ipv6_prefix_length, "
       "reserved_ipv6_prefix_address_type, "
+      "reserved_key, "
       "iaid, "
       "option_universe, "
       "option_code, "
@@ -811,6 +824,8 @@ CqlHostExchange::createBindForSelect(AnyArray& data, StatementTag /* not used */
     data.add(&reserved_ipv6_prefix_length_);
     // reserved_ipv6_prefix_address_type: int
     data.add(&reserved_ipv6_prefix_address_type_);
+    // reserved_key: text
+    data.add(&reserved_key_);
     // iaid: int
     data.add(&iaid_);
     /// @}
@@ -929,6 +944,8 @@ CqlHostExchange::prepareExchange(const HostPtr& host,
             reserved_ipv6_prefix_length_ = NULL_RESERVED_IPV6_PREFIX_LENGTH;
             // reserved_ipv6_prefix_address_type: int
             reserved_ipv6_prefix_address_type_ = NULL_RESERVED_IPV6_PREFIX_ADDRESS_TYPE;
+            // reserved_key: text
+            key_ = NULL_RESERVED_KEY;
             iaid_ = NULL_IAID;
         } else {
             // reserved_ipv6_prefix_address: text
@@ -941,6 +958,9 @@ CqlHostExchange::prepareExchange(const HostPtr& host,
             reserved_ipv6_prefix_address_type_ =
                 reservation->getType() == IPv6Resrv::TYPE_NA ? 0 : 2;
 
+            // reserved_key: text
+            reserved_key_ = reservation->getKeys();
+            
             // iaid: int
             /// @todo: We don't support iaid in the IPv6Resrv yet.
             iaid_ = 0;
@@ -1060,6 +1080,7 @@ CqlHostExchange::createBindForMutation(const HostPtr& host,
         data.add(&reserved_ipv6_prefix_address_);
         data.add(&reserved_ipv6_prefix_length_);
         data.add(&reserved_ipv6_prefix_address_type_);
+        data.add(&reserved_key_);
         data.add(&iaid_);
 
         // Option
@@ -1227,7 +1248,7 @@ CqlHostExchange::retrieveReservation() const {
     }
 
     return (IPv6Resrv(type, IOAddress(reserved_ipv6_prefix_address_),
-                      reserved_ipv6_prefix_length_));
+                      reserved_ipv6_prefix_length_, reserved_key_));
 }
 
 const OptionWrapper
index 9825aab193da72c6e87bec4f79f0ec6832bce2d3..a99955b15b3c623d490537053f9f6d0db4f07262 100644 (file)
@@ -901,6 +901,7 @@ public:
     static constexpr StatementTag DELETE_LEASE6 = "DELETE_LEASE6";
     static constexpr StatementTag GET_LEASE6_EXPIRE = "GET_LEASE6_EXPIRE";
     static constexpr StatementTag GET_LEASE6_ADDR = "GET_LEASE6_ADDR";
+    static constexpr StatementTag GET_LEASE6_DUID = "GET_LEASE6_DUID";
     static constexpr StatementTag GET_LEASE6_DUID_IAID = "GET_LEASE6_DUID_IAID";
     static constexpr StatementTag GET_LEASE6_DUID_IAID_SUBID = "GET_LEASE6_DUID_IAID_SUBID";
     static constexpr StatementTag GET_LEASE6_LIMIT = "GET_LEASE6_LIMIT";
@@ -1003,7 +1004,7 @@ StatementMap CqlLease6Exchange::tagged_statements_ = {
       "LIMIT ? "
       "ALLOW FILTERING "}},
 
-    // Gets an IPv6 lease with specified IPv4 address
+    // Gets an IPv6 lease with specified IPv6 address
     {GET_LEASE6_ADDR,
      {GET_LEASE6_ADDR,
       "SELECT "
@@ -1015,6 +1016,17 @@ StatementMap CqlLease6Exchange::tagged_statements_ = {
       "AND lease_type = ? "
       "ALLOW FILTERING "}},
 
+    // Gets an IPv6 lease with specified duid
+    {GET_LEASE6_DUID,
+     {GET_LEASE6_DUID,
+      "SELECT "
+      "address, valid_lifetime, expire, subnet_id, pref_lifetime, duid, iaid, "
+      "lease_type, prefix_len, fqdn_fwd, fqdn_rev, hostname, hwaddr, hwtype, "
+      "hwaddr_source, state "
+      "FROM lease6 "
+      "WHERE duid = ? "
+      "ALLOW FILTERING "}},
+
     // Gets an IPv6 lease(s) with specified duid and iaid
     {GET_LEASE6_DUID_IAID,
      {GET_LEASE6_DUID_IAID,
@@ -2280,6 +2292,27 @@ CqlLeaseMgr::getLease6(Lease::Type lease_type, const IOAddress &addr) const {
     return (result);
 }
 
+Lease6Ptr
+CqlLeaseMgr::getLease6(const DUID& duid) const {
+    std::string duid_data = duid.toText();
+    LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_CQL_GET_DUID)
+        .arg(duid_data);
+
+    // Set up the WHERE clause value
+    AnyArray data;
+    
+    CassBlob duid_data(duid.getDuid());
+
+    data.add(&duid_data);
+
+    // Get the data.
+    Lease6Collection result;
+    std::unique_ptr<CqlLease6Exchange> exchange6(new CqlLease6Exchange(dbconn_));
+    exchange6->getLeaseCollection(CqlLease6Exchange::GET_LEASE6_DUID, data, result);
+
+    return (result);
+}
+
 Lease6Collection
 CqlLeaseMgr::getLeases6(Lease::Type lease_type, const DUID &duid, uint32_t iaid) const {
     LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_CQL_GET_IAID_DUID)
index 39382b2f4efaaced27a8ada18270916d4413b55b..f67add57a3d6519d736f5cb654d67dc92e8a86d9 100644 (file)
@@ -353,6 +353,11 @@ public:
     getLeases6(const asiolink::IOAddress& lower_bound_address,
                const LeasePageSize& page_size) const override;
 
+    /// @brief Returns all IPv6 leases.
+    ///
+    /// @return Lease collection (may be empty if no IPv6 lease found).
+    virtual Lease6Collection getLeases6(const DUID& duid) const;
+
     /// @brief Returns a collection of expired DHCPv4 leases.
     ///
     /// This method returns at most @c max_leases expired leases. The leases
index 1361e2266ff59c0bb14c0579cee93d9f3b670a08..5801d9825f0b4ee28544c4c3fb6a5f3bbcb24b81 100644 (file)
@@ -757,6 +757,10 @@ of leases beginning with the specified address.
 A debug message issued when the server is attempting to obtain an IPv6
 lease from the MySQL database for the specified address.
 
+% DHCPSRV_MYSQL_GET_DUID obtaining IPv6 lease for duid %1,
+A debug message issued when the server is attempting to obtain an IPv6
+lease from the MySQL database for the specified duid.
+
 % DHCPSRV_MYSQL_GET_CLIENTID obtaining IPv4 leases for client ID %1
 A debug message issued when the server is attempting to obtain a set
 of IPv4 leases from the MySQL database for a client with the specified
@@ -954,6 +958,10 @@ A debug message issued when the server is attempting to obtain a set of IPv6
 leases from the PostgreSQL database for a client with the specified IAID
 (Identity Association ID) and DUID (DHCP Unique Identifier).
 
+% DHCPSRV_PGSQL_GET_DUID obtaining IPv6 leases for DUID %1,
+A debug message issued when the server is attempting to obtain a set of IPv6
+leases from the PostgreSQL database for a client with the specified DUID (DHCP Unique Identifier).
+
 % DHCPSRV_PGSQL_GET_IAID_SUBID_DUID obtaining IPv4 leases for IAID %1, Subnet ID %2, DUID %3, and lease type %4
 A debug message issued when the server is attempting to obtain an IPv6
 lease from the PostgreSQL database for a client with the specified IAID
index 38b29c13f070534343e890c248887de22077d176..12897280dac95be985ef5bcedf7cc4e739508480 100644 (file)
@@ -10,6 +10,8 @@
 #include <util/encode/hex.h>
 #include <util/strutil.h>
 #include <asiolink/io_address.h>
+#include <boost/random/uniform_int_distribution.hpp>
+#include <boost/random/mersenne_twister.hpp>
 #include <exceptions/exceptions.h>
 #include <sstream>
 
@@ -22,14 +24,26 @@ namespace dhcp {
 IPv6Resrv::IPv6Resrv(const Type& type,
                      const asiolink::IOAddress& prefix,
                      const uint8_t prefix_len)
-    : type_(type), prefix_(asiolink::IOAddress("::")), prefix_len_(128) {
+    : type_(type), prefix_(asiolink::IOAddress("::")), 
+      prefix_len_(128), keys_("") {
     // Validate and set the actual values.
     set(type, prefix, prefix_len);
 }
 
+
+IPv6Resrv::IPv6Resrv(const Type& type,
+                     const asiolink::IOAddress& prefix,
+                     const std::string& keys,
+                     const uint8_t prefix_len)
+    : type_(type), prefix_(asiolink::IOAddress("::")), 
+      prefix_len_(128), keys_("") {
+    // Validate and set the actual values.
+    set(type, prefix, prefix_len, keys);
+}
+
 void
 IPv6Resrv::set(const Type& type, const asiolink::IOAddress& prefix,
-               const uint8_t prefix_len) {
+               const uint8_t prefix_len, const std::string& keys) {
     if (!prefix.isV6() || prefix.isV6Multicast()) {
         isc_throw(isc::BadValue, "invalid prefix '" << prefix
                   << "' for new IPv6 reservation");
@@ -43,6 +57,9 @@ IPv6Resrv::set(const Type& type, const asiolink::IOAddress& prefix,
         isc_throw(isc::BadValue, "invalid prefix length '"
                   << static_cast<int>(prefix_len)
                   << "' for reserved IPv6 address, expected 128");
+    } else if (!keys.empty()) {
+    //Don't overwrite with an empty string
+        keys_ = keys;
     }
 
     type_ = type;
@@ -50,11 +67,27 @@ IPv6Resrv::set(const Type& type, const asiolink::IOAddress& prefix,
     prefix_len_ = prefix_len;
 }
 
+std::string
+IPv6Resrv::getRandomKeyString() 
+{
+    std::array <char, 128> randomString;
+    
+    std::random_device rd;
+    boost::random::mt19937 gen(rd());
+
+    std::for_each(randomString.begin(), randomString.end() - 1,
+        [&gen](char& a){ boost::random::uniform_int_distribution<char> dist('!', '~');
+        a = dist(gen); } );
+
+    return std::string(randomString.begin(), randomString.end());
+}
+
 std::string
 IPv6Resrv::toText() const {
     std::ostringstream s;
     s << prefix_;
     // For PD, append prefix length.
+    // @todo: add to text for keys
     if (getType() == TYPE_PD) {
         s << "/" << static_cast<int>(prefix_len_);
     }
@@ -65,7 +98,8 @@ bool
 IPv6Resrv::operator==(const IPv6Resrv& other) const {
     return (type_ == other.type_ &&
             prefix_ == other.prefix_ &&
-            prefix_len_ == other.prefix_len_);
+            prefix_len_ == other.prefix_len_ &&
+            keys_ == other.keys_ );
 }
 
 bool
index 544172700600ed5778939062a906429c7555666b..444c17b07db8f9f83db9924a43b8af537d8b6955 100644 (file)
@@ -63,6 +63,25 @@ public:
               const asiolink::IOAddress& prefix,
               const uint8_t prefix_len = 128);
 
+    /// @brief Constructor.
+    ///
+    /// Creates a reservation from the IPv6 address ,prefix length and
+    /// key value. If the prefix length is not specified, the default value
+    /// of 128 is used. This value indicates that the reservation is made
+    /// for an IPv6 address for a client which supports reconfiguration.
+    ///
+    /// @param type Reservation type: NA or PD.
+    /// @param prefix Address or prefix to be reserved.
+    /// @param keys to be reserved.
+    /// @param prefix_len Prefix length.
+    ///
+    /// @throw isc::BadValue if prefix is not IPv6 prefix, is a
+    /// multicast address or the prefix length is greater than 128.
+    IPv6Resrv(const Type& type,
+              const asiolink::IOAddress& prefix,
+              const std::string& keys,
+              const uint8_t prefix_len = 128);
+
     /// @brief Returns prefix for the reservation.
     const asiolink::IOAddress& getPrefix() const {
         return (prefix_);
@@ -82,6 +101,14 @@ public:
         return (type_);
     }
 
+    /// @brief Returns the keys.
+    ///
+    /// Keys are used for signing the Reconfigure Message.
+    /// The accessor should ensure 128 characters
+    std::string getKeys() const {
+        return (keys_);
+    }
+    
     /// @brief Sets a new prefix and prefix length.
     ///
     /// @param type Reservation type: NA or PD.
@@ -91,11 +118,18 @@ public:
     /// @throw isc::BadValue if prefix is not IPv6 prefix, is a
     /// multicast address or the prefix length is greater than 128.
     void set(const Type& type, const asiolink::IOAddress& prefix,
-             const uint8_t prefix_len);
+             const uint8_t prefix_len, const std::string& keys = "");
 
     /// @brief Returns information about the reservation in the textual format.
     std::string toText() const;
 
+    /// @brief Generates random 128 bit string
+    ///
+    /// Random string is generated by default will be used for  
+    /// the keys to be used for signing Reconfigure Message.
+
+    static  std::string getRandomKeyString(); 
+
     /// @brief Equality operator.
     ///
     /// @param other Reservation to compare to.
@@ -111,6 +145,7 @@ private:
     Type type_;                  ///< Reservation type.
     asiolink::IOAddress prefix_; ///< Prefix
     uint8_t prefix_len_;         ///< Prefix length.
+    std::string keys_;         ///< keys for  authentication.
 
 };
 
index 852e5b2da8cd6d9b1fcb528b1e11ef035e36b697..152039dd257e2b6f306d02690fc61a38539a7ca6 100644 (file)
@@ -500,6 +500,11 @@ public:
     getLeases6(const asiolink::IOAddress& lower_bound_address,
                const LeasePageSize& page_size) const = 0;
 
+    /// @brief Returns collection of lease for matching DUID
+    ///
+    /// @return Lease collection (may be empty if no IPv6 lease found for the DUID).
+    virtual Lease6Collection getLeases6(const DUID& duid) const = 0; 
+    
     /// @brief Returns a collection of expired DHCPv4 leases.
     ///
     /// This method returns at most @c max_leases expired leases. The leases
index a4b4a1114c3417029aeb8cdbf263416332073ad7..c1c84b8aeae5a53db4e734215574d59991b28938 100644 (file)
@@ -1048,6 +1048,19 @@ Memfile_LeaseMgr::getLeases6(const asiolink::IOAddress& lower_bound_address,
     return (collection);
 }
 
+Lease6Collection
+Memfile_LeaseMgr::getLeases6(const DUID& duid) const {
+   LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_MEMFILE_GET6);
+
+   Lease6Collection collection;
+   for (auto lease = storage6_.begin(); lease != storage6_.end(); ++lease ) {
+       if ( (**lease).duid_->getDuid() == duid.getDuid() )
+            collection.push_back(Lease6Ptr(new Lease6(**lease)));
+   }
+
+   return (collection);
+}
+
 void
 Memfile_LeaseMgr::getExpiredLeases4(Lease4Collection& expired_leases,
                                     const size_t max_leases) const {
index 5e227a1d7860e9eb86545ebd15a6a7e581b58c8c..6a1008b4e806d2015b7dff70575f4d55f45424f0 100644 (file)
@@ -340,6 +340,11 @@ public:
     getLeases6(const asiolink::IOAddress& lower_bound_address,
                const LeasePageSize& page_size) const;
 
+    /// @brief Returns all IPv6 leases.
+    ///
+    /// @return Lease collection (may be empty if no IPv6 lease found).
+    virtual Lease6Collection getLeases6(const DUID& duid) const;
+
     /// @brief Returns a collection of expired DHCPv4 leases.
     ///
     /// This method returns at most @c max_leases expired leases. The leases
index 37eb903b5d672b1f65758f20c39453d8721d8f6d..a6cd094abbb8d12abb65e490e8b4a036de52d22f 100644 (file)
@@ -73,6 +73,10 @@ const size_t SERVER_HOSTNAME_MAX_LEN = 64;
 /// @brief Maximum length of the boot file name.
 const size_t BOOT_FILE_NAME_MAX_LEN = 128;
 
+/// @brief Maximum length of keys.
+const size_t KEY_MAX_LEN = 128;
+
+/// @brief Numeric value representing last supported identifier.
 /// @brief Numeric value representing last supported identifier.
 ///
 /// This value is used to validate whether the identifier type stored in
@@ -1325,7 +1329,7 @@ class MySqlHostIPv6Exchange : public MySqlHostWithOptionsExchange {
 private:
 
     /// @brief Number of columns holding IPv6 reservation information.
-    static const size_t RESERVATION_COLUMNS = 5;
+    static const size_t RESERVATION_COLUMNS = 6;
 
 public:
 
@@ -1338,11 +1342,12 @@ public:
           reservation_id_(0),
           reserv_type_(0), reserv_type_null_(MLM_FALSE),
           ipv6_address_buffer_len_(0), prefix_len_(0), iaid_(0),
-          reservation_id_index_(findAvailColumn()),
+          key_len_(0),reservation_id_index_(findAvailColumn()),
           address_index_(reservation_id_index_ + 1),
           prefix_len_index_(reservation_id_index_ + 2),
           type_index_(reservation_id_index_ + 3),
           iaid_index_(reservation_id_index_ + 4),
+          key_index_(reservation_id_index_ + 5),
           most_recent_reservation_id_(0) {
 
         memset(ipv6_address_buffer_, 0, sizeof(ipv6_address_buffer_));
@@ -1353,6 +1358,7 @@ public:
         columns_[prefix_len_index_] = "prefix_len";
         columns_[type_index_] = "type";
         columns_[iaid_index_] = "dhcp6_iaid";
+        columns_[key_index_] = "auth_key";
     }
 
     /// @brief Returns last fetched reservation id.
@@ -1393,7 +1399,11 @@ public:
 
         ipv6_address_buffer_[ipv6_address_buffer_len_] = '\0';
         std::string address = ipv6_address_buffer_;
-        IPv6Resrv r(type, IOAddress(address), prefix_len_);
+
+        key_buffer_[key_len_] = '\0';          
+        std::string key = key_buffer_;
+
+        IPv6Resrv r(type, IOAddress(address), key, prefix_len_);
         return (r);
     };
 
@@ -1487,6 +1497,13 @@ public:
         bind_[iaid_index_].buffer = reinterpret_cast<char*>(&iaid_);
         bind_[iaid_index_].is_unsigned = MLM_TRUE;
 
+        // key for auth VARCHAR(128)
+        key_len_ = sizeof(key_buffer_) - 1;
+        bind_[key_index_].buffer_type = MYSQL_TYPE_STRING;
+        bind_[key_index_].buffer = key_buffer_;
+        bind_[key_index_].buffer_length = key_len_;
+        bind_[key_index_].length = &key_len_;
+
         // Add the error flags
         setErrorIndicators(bind_, error_);
 
@@ -1519,6 +1536,12 @@ private:
     /// @brief IAID.
     uint32_t iaid_;
 
+    /// @brief Buffer length for holding keys in textual format.
+    char key_buffer_[KEY_MAX_LEN + 1];
+
+    /// @brief Length of the keys
+    unsigned long key_len_;
+
     /// @name Indexes of columns holding information about IPv6 reservations.
     //@{
     /// @brief Index of reservation_id column.
@@ -1536,6 +1559,9 @@ private:
     /// @brief Index of IAID column.
     size_t iaid_index_;
 
+    /// @brief Index of keys column.
+    size_t key_index_;
+
     //@}
 
     /// @brief Reservation id for last processed row.
@@ -1546,7 +1572,7 @@ private:
 ///
 /// This class is only used to insert IPv6 reservations into the
 /// ipv6_reservations table. It is not used to retrieve IPv6 reservations. To
-/// retrieve IPv6 reservation the @ref MySqlIPv6HostExchange class should be
+/// retrieve IPv6 reservation the @ref MySqlHostIPv6Exchange class should be
 /// used instead.
 ///
 /// When a new IPv6 reservation is inserted into the database, an appropriate
@@ -1556,7 +1582,7 @@ class MySqlIPv6ReservationExchange {
 private:
 
     /// @brief Set number of columns for ipv6_reservation table.
-    static const size_t RESRV_COLUMNS = 6;
+    static const size_t RESRV_COLUMNS = 7;
 
 public:
 
@@ -1576,6 +1602,7 @@ public:
         columns_[2] = "prefix_len";
         columns_[3] = "type";
         columns_[4] = "dhcp6_iaid";
+        columns_[5] = "auth_key";
         BOOST_STATIC_ASSERT(4 < RESRV_COLUMNS);
     }
 
@@ -1642,6 +1669,16 @@ public:
             bind_[4].buffer = reinterpret_cast<char*>(&host_id_);
             bind_[4].is_unsigned = MLM_TRUE;
 
+            // key VARCHAR(128)
+            // why we need member for len
+            key_ = resv.getKeys();
+            key_len_ = key_.length();
+            bind_[5].buffer_type = MYSQL_TYPE_BLOB;
+            bind_[5].buffer = reinterpret_cast<char*>
+                (const_cast<char*>(key_.c_str()));
+            bind_[5].buffer_length = key_len_;
+            bind_[5].length = &key_len_;
+
         } catch (const std::exception& ex) {
             isc_throw(DbOperationError,
                       "Could not create bind array from IPv6 Reservation: "
@@ -1662,6 +1699,12 @@ private:
     /// @brief Address (or prefix).
     std::string address_;
 
+    /// @brief Keys for Authentication
+    std::string key_;
+
+    /// @brief length of keys for Authentication
+    unsigned long key_len_;
+
     /// @brief Length of the textual address representation.
     unsigned long address_len_;
 
@@ -2112,7 +2155,7 @@ TaggedStatementArray tagged_statements = { {
                 "o6.option_id, o6.code, o6.value, o6.formatted_value, o6.space, "
                 "o6.persistent, o6.user_context, "
                 "r.reservation_id, r.address, r.prefix_len, r.type, "
-                "r.dhcp6_iaid "
+                "r.dhcp6_iaid, r.auth_key "
             "FROM hosts AS h "
             "LEFT JOIN dhcp4_options AS o4 "
                 "ON h.host_id = o4.host_id "
@@ -2168,7 +2211,7 @@ TaggedStatementArray tagged_statements = { {
                 "o.option_id, o.code, o.value, o.formatted_value, o.space, "
                 "o.persistent, o.user_context, "
                 "r.reservation_id, r.address, r.prefix_len, r.type, "
-                "r.dhcp6_iaid "
+                "r.dhcp6_iaid, r.auth_key "
             "FROM hosts AS h "
             "LEFT JOIN dhcp6_options AS o "
                 "ON h.host_id = o.host_id "
@@ -2210,7 +2253,7 @@ TaggedStatementArray tagged_statements = { {
                 "o.option_id, o.code, o.value, o.formatted_value, o.space, "
                 "o.persistent, o.user_context,"
                 "r.reservation_id, r.address, r.prefix_len, r.type, "
-                "r.dhcp6_iaid "
+                "r.dhcp6_iaid, r.auth_key "
             "FROM hosts AS h "
             "LEFT JOIN dhcp6_options AS o "
                 "ON h.host_id = o.host_id "
@@ -2237,7 +2280,7 @@ TaggedStatementArray tagged_statements = { {
                 "o.option_id, o.code, o.value, o.formatted_value, o.space, "
                 "o.persistent, o.user_context, "
                 "r.reservation_id, r.address, r.prefix_len, r.type, "
-                "r.dhcp6_iaid "
+                "r.dhcp6_iaid, r.auth_key "
             "FROM hosts AS h "
             "LEFT JOIN dhcp6_options AS o "
                 "ON h.host_id = o.host_id "
@@ -2258,8 +2301,8 @@ TaggedStatementArray tagged_statements = { {
     // Inserts a single IPv6 reservation into 'reservations' table.
     {MySqlHostDataSourceImpl::INSERT_V6_RESRV,
          "INSERT INTO ipv6_reservations(address, prefix_len, type, "
-            "dhcp6_iaid, host_id) "
-         "VALUES (?,?,?,?,?)"},
+            "dhcp6_iaid, host_id, auth_key) "
+         "VALUES (?,?,?,?,?,?)"},
 
     // Inserts a single DHCPv4 option into 'dhcp4_options' table.
     // Using fixed scope_id = 3, which associates an option with host.
index 16c3327ce42aaa2f3684d8ca432be3832a597521..663bc0c8c9ea848bbc97337707c737a653588dee 100644 (file)
@@ -184,7 +184,7 @@ tagged_statements = { {
                         "state, user_context "
                             "FROM lease6 "
                             "WHERE address = ? AND lease_type = ?"},
-    {MySqlLeaseMgr::GET_LEASE6_DUID_IAID,
+       {MySqlLeaseMgr::GET_LEASE6_DUID_IAID,
                     "SELECT address, duid, valid_lifetime, "
                         "expire, subnet_id, pref_lifetime, "
                         "lease_type, iaid, prefix_len, "
@@ -2266,6 +2266,23 @@ MySqlLeaseMgr::getLeases6(const asiolink::IOAddress& lower_bound_address,
     return (result);
 }
 
+Lease6Collection
+MySqlLeaseMgr::getLeases6(const DUID& duid) const {
+   LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_MYSQL_GET_DUID);
+   
+    Lease6Collection result =  getLeases6();
+    
+    //erase the ones not containing the matching DUID
+    for (auto iter = result.begin(); iter != result.end();
+            iter++) {
+        if ((*iter)->duid_->getDuid() != duid.getDuid()) {
+            result.erase(iter);
+        }
+    }
+
+    return (result);
+}
+
 void
 MySqlLeaseMgr::getExpiredLeases4(Lease4Collection& expired_leases,
                                  const size_t max_leases) const {
index ede95dcecfb91d247e70740784661f48de28dc6c..f9d9286c05dcfd0f369d1b9e45c065077b341d3f 100644 (file)
@@ -337,6 +337,11 @@ public:
     getLeases6(const asiolink::IOAddress& lower_bound_address,
                const LeasePageSize& page_size) const;
 
+    /// @brief Returns all IPv6 leases.
+    ///
+    /// @return Lease collection (may be empty if no IPv6 lease found).
+    virtual Lease6Collection getLeases6(const DUID& duid) const;
+
     /// @brief Returns a collection of expired DHCPv4 leases.
     ///
     /// This method returns at most @c max_leases expired leases. The leases
index f11ab16c9e7418ef34fa3886eb23a0ad17263038..bcbddd88af1c1ba7e132c2a4cf8cb7a4e7ead6ac 100644 (file)
@@ -851,7 +851,7 @@ class PgSqlHostIPv6Exchange : public PgSqlHostWithOptionsExchange {
 private:
 
     /// @brief Number of columns holding IPv6 reservation information.
-    static const size_t RESERVATION_COLUMNS = 5;
+    static const size_t RESERVATION_COLUMNS = 6;
 
 public:
 
@@ -866,6 +866,7 @@ public:
           prefix_len_index_(reservation_id_index_ + 2),
           type_index_(reservation_id_index_ + 3),
           iaid_index_(reservation_id_index_ + 4),
+          key_index_(reservation_id_index_ + 5),
           most_recent_reservation_id_(0) {
 
         // Provide names of additional columns returned by the queries.
@@ -874,6 +875,7 @@ public:
         columns_[prefix_len_index_] = "prefix_len";
         columns_[type_index_] = "type";
         columns_[iaid_index_] = "dhcp6_iaid";
+        columns_[key_index_] = "auth_key";
 
         BOOST_STATIC_ASSERT(4 < RESERVATION_COLUMNS);
     }
@@ -934,13 +936,17 @@ public:
         uint16_t prefix_len;
         getColumnValue(r, row, prefix_len_index_, prefix_len);
 
+        // key_: string
+        string key;
+        getColumnValue(r, row, key_index_, key);
+
         // @todo once we support populating iaid
         // iaid: INT
         // int iaid;
         // getColumnValue(r, row, iaid_index_, iaid);
 
         // Create the reservation.
-        IPv6Resrv reservation(resv_type, IOAddress(address), prefix_len);
+        IPv6Resrv reservation(resv_type, IOAddress(address), key, prefix_len);
         return (reservation);
     };
 
@@ -1004,6 +1010,9 @@ private:
     /// @brief Index of IAID column.
     size_t iaid_index_;
 
+    /// @brief Index of IAID column.
+    size_t key_index_;
+
     //@}
 
     /// @brief Reservation id for last processed row.
@@ -1024,7 +1033,7 @@ class PgSqlIPv6ReservationExchange : public PgSqlExchange {
 private:
 
     /// @brief Set number of columns for ipv6_reservation table.
-    static const size_t RESRV_COLUMNS = 6;
+    static const size_t RESRV_COLUMNS = 7;
 
 public:
 
@@ -1040,7 +1049,8 @@ public:
         columns_[2] = "prefix_len";
         columns_[3] = "type";
         columns_[4] = "dhcp6_iaid";
-        BOOST_STATIC_ASSERT(5 < RESRV_COLUMNS);
+        columns_[5] = "auth_key";
+        BOOST_STATIC_ASSERT(6 < RESRV_COLUMNS);
     }
 
     /// @brief Populate a bind array representing an IPv6 reservation
@@ -1082,6 +1092,10 @@ public:
 
             // host_id: BIGINT NOT NULL
             bind_array->add(host_id);
+
+            // type: VARCHAR(128) NOT NULL
+            bind_array->add(resv.getKeys());
+
         } catch (const std::exception& ex) {
             isc_throw(DbOperationError,
                       "Could not create bind array from IPv6 Reservation: "
@@ -1461,7 +1475,7 @@ TaggedStatementArray tagged_statements = { {
      "  o4.persistent, o4.user_context, "
      "  o6.option_id, o6.code, o6.value, o6.formatted_value, o6.space, "
      "  o6.persistent, o6.user_context, "
-     "  r.reservation_id, r.address, r.prefix_len, r.type, r.dhcp6_iaid "
+     "  r.reservation_id, r.address, r.prefix_len, r.type, r.dhcp6_iaid, r.auth_key "
      "FROM hosts AS h "
      "LEFT JOIN dhcp4_options AS o4 ON h.host_id = o4.host_id "
      "LEFT JOIN dhcp6_options AS o6 ON h.host_id = o6.host_id "
@@ -1522,7 +1536,7 @@ TaggedStatementArray tagged_statements = { {
      "  h.dhcp4_next_server, h.dhcp4_server_hostname, h.dhcp4_boot_file_name, "
      "  o.option_id, o.code, o.value, o.formatted_value, o.space, "
      "  o.persistent, o.user_context, "
-     "  r.reservation_id, r.address, r.prefix_len, r.type, r.dhcp6_iaid "
+     "  r.reservation_id, r.address, r.prefix_len, r.type, r.dhcp6_iaid, r.auth_key "
      "FROM hosts AS h "
      "LEFT JOIN dhcp6_options AS o ON h.host_id = o.host_id "
      "LEFT JOIN ipv6_reservations AS r ON h.host_id = r.host_id "
@@ -1569,7 +1583,7 @@ TaggedStatementArray tagged_statements = { {
      "  o.option_id, o.code, o.value, o.formatted_value, o.space, "
      "  o.persistent, o.user_context, "
      "  r.reservation_id, r.address, r.prefix_len, r.type, "
-     "  r.dhcp6_iaid "
+     "  r.dhcp6_iaid, r.auth_key "
      "FROM hosts AS h "
      "LEFT JOIN dhcp6_options AS o ON h.host_id = o.host_id "
      "LEFT JOIN ipv6_reservations AS r ON h.host_id = r.host_id "
@@ -1597,7 +1611,7 @@ TaggedStatementArray tagged_statements = { {
      "  o.option_id, o.code, o.value, o.formatted_value, o.space, "
      "  o.persistent, o.user_context, "
      "  r.reservation_id, r.address, r.prefix_len, r.type, "
-     "  r.dhcp6_iaid "
+     "  r.dhcp6_iaid, r.auth_key "
      "FROM hosts AS h "
      "LEFT JOIN dhcp6_options AS o ON h.host_id = o.host_id "
      "LEFT JOIN ipv6_reservations AS r ON h.host_id = r.host_id "
@@ -1622,12 +1636,12 @@ TaggedStatementArray tagged_statements = { {
 
     //PgSqlHostDataSourceImpl::INSERT_V6_RESRV
     // Inserts a single IPv6 reservation into 'reservations' table.
-    {5,
+    {6,
      { OID_VARCHAR, OID_INT2, OID_INT4, OID_INT4, OID_INT4 },
      "insert_v6_resrv",
      "INSERT INTO ipv6_reservations(address, prefix_len, type, "
-     "  dhcp6_iaid, host_id) "
-     "VALUES ($1, $2, $3, $4, $5)"
+     "  dhcp6_iaid, host_id, auth_key) "
+     "VALUES ($1, $2, $3, $4, $5, $6)"
     },
 
     // PgSqlHostDataSourceImpl::INSERT_V4_HOST_OPTION
index fc3bc0dfd0c4dc108faeeecd7acc3c621995165f..a2ac2b746564e13698314e1356a63d1bc2936edb 100644 (file)
@@ -1506,6 +1506,25 @@ PgSqlLeaseMgr::getLeases6(SubnetID subnet_id) const {
     return (result);
 }
 
+Lease6Collection
+PgSqlLeaseMgr::getLeases6( const DUID& duid ) const {
+    LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
+              DHCPSRV_PGSQL_GET_DUID)
+              .arg(duid.toText());
+
+    Lease6Collection result = getLeases6();
+
+    //erase the ones not containing the matching DUID
+    for (auto iter = result.begin(); iter != result.end();
+            iter++) {
+        if ((*iter)->duid_->getDuid() != duid.getDuid()) {
+            result.erase(iter);
+        }
+    }
+
+    return (result);
+}
+
 Lease6Collection
 PgSqlLeaseMgr::getLeases6() const {
     LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_PGSQL_GET6);
index e80a20f2b2f704f3bfc18d9dce7529529c99b3e5..423f820bcf89421cf9c8be30589594d788e09387 100644 (file)
@@ -309,6 +309,11 @@ public:
     getLeases6(const asiolink::IOAddress& lower_bound_address,
                const LeasePageSize& page_size) const;
 
+    /// @brief Returns all IPv6 leases.
+    ///
+    /// @return Lease collection (may be empty if no IPv6 lease found).
+    virtual Lease6Collection getLeases6(const DUID& duid) const;
+
     /// @brief Returns a collection of expired DHCPv4 leases.
     ///
     /// This method returns at most @c max_leases expired leases. The leases
index 46c21e53375131d1949cb93350cbe4c7e861bd95..2c657f0ccf3798bb320c7db697dd067e902226d1 100644 (file)
@@ -585,7 +585,7 @@ TEST_F(CqlHostDataSourceTest, testAddRollback) {
     destroyCqlSchema(false, true);
 
     // Create a host with a reservation.
-    HostPtr host = HostDataSourceUtils::initializeHost6("2001:db8:1::1", Host::IDENT_HWADDR, false);
+    HostPtr host = HostDataSourceUtils::initializeHost6("2001:db8:1::1", Host::IDENT_HWADDR, false, "key##1");
     // Let's assign some DHCPv4 subnet to the host, because we will use the
     // DHCPv4 subnet to try to retrieve the host after failed insertion.
     host->setIPv4SubnetID(SubnetID(4));
index 674bca8009429f8c5210fca91565afe1a2826dd2..983e94a9e73f476b490b25d98a28b9600b85f6e6 100644 (file)
@@ -13,6 +13,7 @@
 #include <boost/scoped_ptr.hpp>
 #include <gtest/gtest.h>
 #include <cstdlib>
+#include <unordered_map>
 #include <sstream>
 
 using namespace isc;
@@ -34,6 +35,14 @@ TEST(IPv6ResrvTest, constructorAddress) {
     EXPECT_EQ("2001:db8:1::cafe", resrv.getPrefix().toText());
     EXPECT_EQ(128, resrv.getPrefixLen());
     EXPECT_EQ(IPv6Resrv::TYPE_NA, resrv.getType());
+    EXPECT_EQ("", resrv.getKeys());
+
+    //create reservation with keys
+    IPv6Resrv resrv_keys(IPv6Resrv::TYPE_NA, IOAddress("2001:db8:1::cafe"), "#ssd@@dce3");
+    EXPECT_EQ("2001:db8:1::cafe", resrv_keys.getPrefix().toText());
+    EXPECT_EQ(128, resrv_keys.getPrefixLen());
+    EXPECT_EQ(IPv6Resrv::TYPE_NA, resrv_keys.getType());
+    EXPECT_EQ("#ssd@@dce3", resrv_keys.getKeys());
 }
 
 // This test verifies that it is possible to create IPv6 prefix
@@ -43,9 +52,18 @@ TEST(IPv6ResrvTest, constructorPrefix) {
     EXPECT_EQ("2001:db8:1::", resrv.getPrefix().toText());
     EXPECT_EQ(64, resrv.getPrefixLen());
     EXPECT_EQ(IPv6Resrv::TYPE_PD, resrv.getType());
+    EXPECT_EQ("", resrv.getKeys());
+    
+    //create reservation with keys
+    IPv6Resrv resrv_keys(IPv6Resrv::TYPE_PD, IOAddress("2001:db8:1::"), "#ssd@@dce3", 64);
+    EXPECT_EQ("2001:db8:1::", resrv_keys.getPrefix().toText());
+    EXPECT_EQ(64, resrv_keys.getPrefixLen());
+    EXPECT_EQ(IPv6Resrv::TYPE_PD, resrv_keys.getType());
+    EXPECT_EQ("#ssd@@dce3", resrv_keys.getKeys());
 }
 
 // This test verifies that the toText() function prints correctly.
+// @todo: Add test to keys once toText() for keys is implemented.
 TEST(IPv6ResrvTest, toText) {
     IPv6Resrv resrv_prefix(IPv6Resrv::TYPE_PD, IOAddress("2001:db8:1::"), 64);
     EXPECT_EQ("2001:db8:1::/64", resrv_prefix.toText());
@@ -102,6 +120,39 @@ TEST(IPv6ResrvTest, setPrefix) {
                  isc::BadValue);
 }
 
+// This test verifies that it is possible to modify the keys  
+// 
+TEST(IPv6ResrvTest, setKeys) {
+    // Create an address reservation without assigning keys.
+    IPv6Resrv resrv(IPv6Resrv::TYPE_NA, IOAddress("2001:db8:1::1"));
+    ASSERT_EQ("2001:db8:1::1", resrv.getPrefix().toText());
+    ASSERT_EQ(128, resrv.getPrefixLen());
+    ASSERT_EQ(IPv6Resrv::TYPE_NA, resrv.getType());
+    ASSERT_EQ("", resrv.getKeys());
+
+    // Replace default keys with new value. 
+    resrv.set(IPv6Resrv::TYPE_NA, IOAddress("2001:db8:1::1"), 128, "first_set_keys_#");
+    ASSERT_EQ("2001:db8:1::1", resrv.getPrefix().toText());
+    ASSERT_EQ(128, resrv.getPrefixLen());
+    ASSERT_EQ(IPv6Resrv::TYPE_NA, resrv.getType());
+    ASSERT_EQ("first_set_keys_#", resrv.getKeys());
+
+    // Modify an existing key for the reservation 
+    resrv.set(IPv6Resrv::TYPE_NA, IOAddress("2001:db8:1::1"), 128, "second_set_keys_#");
+    ASSERT_EQ("2001:db8:1::1", resrv.getPrefix().toText());
+    ASSERT_EQ(128, resrv.getPrefixLen());
+    ASSERT_EQ(IPv6Resrv::TYPE_NA, resrv.getType());
+    ASSERT_EQ("second_set_keys_#", resrv.getKeys());
+
+    // Enusre not including the key parameter won't affect
+    // the current configured keys
+    resrv.set(IPv6Resrv::TYPE_NA, IOAddress("2001:db8:1::1"), 128);
+    ASSERT_EQ("2001:db8:1::1", resrv.getPrefix().toText());
+    ASSERT_EQ(128, resrv.getPrefixLen());
+    ASSERT_EQ(IPv6Resrv::TYPE_NA, resrv.getType());
+    ASSERT_EQ("second_set_keys_#", resrv.getKeys());
+}
+
 // This test checks that the equality operators work fine.
 TEST(IPv6ResrvTest, equal) {
     EXPECT_TRUE(IPv6Resrv(IPv6Resrv::TYPE_PD, IOAddress("2001:db8::"), 64) ==
@@ -130,6 +181,23 @@ TEST(IPv6ResrvTest, equal) {
     EXPECT_TRUE(IPv6Resrv(IPv6Resrv::TYPE_NA, IOAddress("2001:db8::1"), 128) !=
                 IPv6Resrv(IPv6Resrv::TYPE_PD, IOAddress("2001:db8::1"), 128));
 
+    EXPECT_TRUE(IPv6Resrv(IPv6Resrv::TYPE_NA, IOAddress("2001:db8::1"),
+                "key##1", 128) ==
+                IPv6Resrv(IPv6Resrv::TYPE_NA, IOAddress("2001:db8::1"),
+                "key##1", 128));
+    EXPECT_FALSE(IPv6Resrv(IPv6Resrv::TYPE_PD, IOAddress("2001:db8::1"),
+                "key##1", 128) !=
+                IPv6Resrv(IPv6Resrv::TYPE_PD, IOAddress("2001:db8::1"),
+                "key##1", 128));
+
+    EXPECT_FALSE(IPv6Resrv(IPv6Resrv::TYPE_NA, IOAddress("2001:db8::1"),
+                "key##1", 128) ==
+                IPv6Resrv(IPv6Resrv::TYPE_NA, IOAddress("2001:db8::1"),
+                "key##2", 128));
+    EXPECT_TRUE(IPv6Resrv(IPv6Resrv::TYPE_PD, IOAddress("2001:db8::1"),
+                "key##1", 128) !=
+                IPv6Resrv(IPv6Resrv::TYPE_PD, IOAddress("2001:db8::1"),
+                "key##2", 128));
 }
 
 /// @brief Test fixture class for @c Host.
@@ -607,12 +675,12 @@ TEST_F(HostTest, addReservations) {
 
     EXPECT_FALSE(host->hasIPv6Reservation());
 
-    // Add 4 reservations: 2 for NAs, 2 for PDs.
+    // Add 4 reservations: 2 for NAs, 2 for PDs
     ASSERT_NO_THROW(
         host->addReservation(IPv6Resrv(IPv6Resrv::TYPE_NA,
-                                       IOAddress("2001:db8:1::cafe")));
+                                       IOAddress("2001:db8:1::cafe"), "key##1"));
         host->addReservation(IPv6Resrv(IPv6Resrv::TYPE_PD,
-                                       IOAddress("2001:db8:1:1::"), 64));
+                                       IOAddress("2001:db8:1:1::"), "key##2", 64));
         host->addReservation(IPv6Resrv(IPv6Resrv::TYPE_PD,
                                        IOAddress("2001:db8:1:2::"), 64));
         host->addReservation(IPv6Resrv(IPv6Resrv::TYPE_NA,
@@ -623,9 +691,9 @@ TEST_F(HostTest, addReservations) {
 
     // Check that reservations exist.
     EXPECT_TRUE(host->hasReservation(IPv6Resrv(IPv6Resrv::TYPE_NA,
-                                               IOAddress("2001:db8:1::cafe"))));
+                                               IOAddress("2001:db8:1::cafe"), "key##1")));
     EXPECT_TRUE(host->hasReservation(IPv6Resrv(IPv6Resrv::TYPE_PD,
-                                               IOAddress("2001:db8:1:1::"),
+                                               IOAddress("2001:db8:1:1::"), "key##2",
                                                64)));
     EXPECT_TRUE(host->hasReservation(IPv6Resrv(IPv6Resrv::TYPE_PD,
                                                IOAddress("2001:db8:1:2::"),
@@ -637,7 +705,7 @@ TEST_F(HostTest, addReservations) {
     IPv6ResrvRange addresses = host->getIPv6Reservations(IPv6Resrv::TYPE_NA);
     ASSERT_EQ(2, std::distance(addresses.first, addresses.second));
     EXPECT_TRUE(reservationExists(IPv6Resrv(IPv6Resrv::TYPE_NA,
-                                            IOAddress("2001:db8:1::cafe")),
+                                            IOAddress("2001:db8:1::cafe"), "key##1"),
                                   addresses));
     EXPECT_TRUE(reservationExists(IPv6Resrv(IPv6Resrv::TYPE_NA,
                                             IOAddress("2001:db8:1::1")),
@@ -648,7 +716,7 @@ TEST_F(HostTest, addReservations) {
     IPv6ResrvRange prefixes = host->getIPv6Reservations(IPv6Resrv::TYPE_PD);
     ASSERT_EQ(2, std::distance(prefixes.first, prefixes.second));
     EXPECT_TRUE(reservationExists(IPv6Resrv(IPv6Resrv::TYPE_PD,
-                                            IOAddress("2001:db8:1:1::"), 64),
+                                            IOAddress("2001:db8:1:1::"),"key##2", 64),
                                   prefixes));
     EXPECT_TRUE(reservationExists(IPv6Resrv(IPv6Resrv::TYPE_PD,
                                             IOAddress("2001:db8:1:2::"), 64),
@@ -1038,6 +1106,7 @@ TEST_F(HostTest, toText) {
 }
 
 // This test checks that Host object is correctly unparsed,
+// @todo: add support for keys
 TEST_F(HostTest, unparse) {
     boost::scoped_ptr<Host> host;
     ASSERT_NO_THROW(host.reset(new Host("01:02:03:04:05:06", "hw-address",
@@ -1209,4 +1278,32 @@ TEST_F(HostTest, hostId) {
     EXPECT_EQ(12345, host->getHostId());
 }
 
+// Test verifies if getRandomKeyString can generate  1000 keys which are random
+TEST_F(HostTest, randomKeys) {
+    //use hashtable and set size to 1000
+    std::unordered_map<std::string, int> key_map;
+    
+    int dup_element = 0;
+    const uint16_t max_iter = 1000;
+    uint16_t iter_num = 0;
+    size_t max_hash_size = 1000;
+
+    key_map.reserve(max_hash_size);
+
+    for (iter_num = 0; iter_num < max_iter; iter_num++) {
+        std::string key = IPv6Resrv::getRandomKeyString();
+        if (key_map[key]) {
+            dup_element++;
+            break;
+        }
+
+        key_map[key] = 1;
+    }
+
+    EXPECT_EQ(0, dup_element);
+}
+
+
 } // end of anonymous namespace
+
+// Test verifies if 
index d32379fe8dd2e0a3c538ed8788ce723ef5b65075..40e262741a0b73f854d199f52a9c2d8a4c157314 100644 (file)
@@ -208,6 +208,14 @@ public:
         return (leases6_);
     }
 
+    /// @brief Returns collection of lease for matching DUID
+    ///
+    /// @param duid ignored
+    /// @return whatever is set in leases6_ field
+    virtual Lease6Collection getLeases6(const DUID& duid) const {
+        return (leases6_);
+    }
+
     /// @brief Returns all IPv6 leases for the particular subnet identifier.
     ///
     /// @param subnet_id subnet identifier.
index df2122d475c5d781477ea16f892312d3beed2d1c..6d787f9a08a0af154a2b978371335fcfbd44f410 100644 (file)
@@ -571,7 +571,7 @@ TEST_F(PgSqlHostDataSourceTest, testAddRollback) {
                  << " drop command failed :" << PQerrorMessage(conn);
 
     // Create a host with a reservation.
-    HostPtr host = HostDataSourceUtils::initializeHost6("2001:db8:1::1", Host::IDENT_HWADDR, false);
+    HostPtr host = HostDataSourceUtils::initializeHost6("2001:db8:1::1", Host::IDENT_HWADDR, false, "randomKey");
     // Let's assign some DHCPv4 subnet to the host, because we will use the
     // DHCPv4 subnet to try to retrieve the host after failed insertion.
     host->setIPv4SubnetID(SubnetID(4));
index 2e7ef08ad8f353c48f7c28c8bda332835e4bb6d5..3d7324db82e74b0951e2d03163c861a521b1b8e3 100644 (file)
@@ -706,7 +706,7 @@ GenericHostDataSourceTest::testSubnetId6(int subnets, Host::IdentifierType id) {
     for (int i = 0; i < subnets; ++i) {
         // Last boolean value set to false indicates that the same identifier
         // must be used for each generated host.
-        host = HostDataSourceUtils::initializeHost6(current_address.toText(), id, true, false);
+        host = HostDataSourceUtils::initializeHost6(current_address.toText(), id, true, "", false);
 
         host->setIPv4SubnetID(i + 1000);
         host->setIPv6SubnetID(i + 1000);
@@ -754,10 +754,14 @@ GenericHostDataSourceTest::testGetByIPv6(Host::IdentifierType id, bool prefix) {
     ASSERT_TRUE(hdsptr_);
 
     // Let's create a couple of hosts...
-    HostPtr host1 = HostDataSourceUtils::initializeHost6("2001:db8::1", id, prefix);
-    HostPtr host2 = HostDataSourceUtils::initializeHost6("2001:db8::2", id, prefix);
-    HostPtr host3 = HostDataSourceUtils::initializeHost6("2001:db8::3", id, prefix);
-    HostPtr host4 = HostDataSourceUtils::initializeHost6("2001:db8::4", id, prefix);
+    HostPtr host1 = HostDataSourceUtils::initializeHost6("2001:db8::1",
+                                                        id, prefix, "key##1");
+    HostPtr host2 = HostDataSourceUtils::initializeHost6("2001:db8::2",
+                                                        id, prefix, "key##2");
+    HostPtr host3 = HostDataSourceUtils::initializeHost6("2001:db8::3",
+                                                        id, prefix, "key##3");
+    HostPtr host4 = HostDataSourceUtils::initializeHost6("2001:db8::4",
+                                                        id, prefix, "key##4");
 
     // ... and add them to the data source.
     ASSERT_NO_THROW(hdsptr_->add(host1));
@@ -797,10 +801,10 @@ GenericHostDataSourceTest::testGetBySubnetIPv6() {
     ASSERT_TRUE(hdsptr_);
 
     // Let's create a couple of hosts...
-    HostPtr host1 = HostDataSourceUtils::initializeHost6("2001:db8:1::", Host::IDENT_DUID, true);
-    HostPtr host2 = HostDataSourceUtils::initializeHost6("2001:db8:2::", Host::IDENT_DUID, true);
-    HostPtr host3 = HostDataSourceUtils::initializeHost6("2001:db8:3::", Host::IDENT_DUID, true);
-    HostPtr host4 = HostDataSourceUtils::initializeHost6("2001:db8:4::", Host::IDENT_DUID, true);
+    HostPtr host1 = HostDataSourceUtils::initializeHost6("2001:db8:1::", Host::IDENT_DUID, true, "key##1");
+    HostPtr host2 = HostDataSourceUtils::initializeHost6("2001:db8:2::", Host::IDENT_DUID, true, "key##2");
+    HostPtr host3 = HostDataSourceUtils::initializeHost6("2001:db8:3::", Host::IDENT_DUID, true, "key##3");
+    HostPtr host4 = HostDataSourceUtils::initializeHost6("2001:db8:4::", Host::IDENT_DUID, true, "key##4");
 
     // ... and add them to the data source.
     ASSERT_NO_THROW(hdsptr_->add(host1));
@@ -889,10 +893,11 @@ GenericHostDataSourceTest::testAddr6AndPrefix() {
     ASSERT_TRUE(hdsptr_);
 
     // Create a host reservations with prefix reservation (prefix = true)
-    HostPtr host = HostDataSourceUtils::initializeHost6("2001:db8::1", Host::IDENT_DUID, true);
+    HostPtr host = HostDataSourceUtils::initializeHost6("2001:db8::1", Host::IDENT_DUID,
+                                                        true, "key##1", true);
 
     // Create IPv6 reservation (for an address) and add it to the host
-    IPv6Resrv resv(IPv6Resrv::TYPE_NA, IOAddress("2001:db8::2"), 128);
+    IPv6Resrv resv(IPv6Resrv::TYPE_NA, IOAddress("2001:db8::2"), "key##2", 128);
     host->addReservation(resv);
 
     // Add this reservation
@@ -920,10 +925,10 @@ GenericHostDataSourceTest::testMultipleReservations() {
     HostPtr host = HostDataSourceUtils::initializeHost6("2001:db8::1", Host::IDENT_DUID, false);
 
     // Add some reservations
-    IPv6Resrv resv1(IPv6Resrv::TYPE_NA, IOAddress("2001:db8::6"), len);
-    IPv6Resrv resv2(IPv6Resrv::TYPE_NA, IOAddress("2001:db8::7"), len);
-    IPv6Resrv resv3(IPv6Resrv::TYPE_NA, IOAddress("2001:db8::8"), len);
-    IPv6Resrv resv4(IPv6Resrv::TYPE_NA, IOAddress("2001:db8::9"), len);
+    IPv6Resrv resv1(IPv6Resrv::TYPE_NA, IOAddress("2001:db8::6"), "key##1", len);
+    IPv6Resrv resv2(IPv6Resrv::TYPE_NA, IOAddress("2001:db8::7"), "key##2", len);
+    IPv6Resrv resv3(IPv6Resrv::TYPE_NA, IOAddress("2001:db8::8"), "key##3", len);
+    IPv6Resrv resv4(IPv6Resrv::TYPE_NA, IOAddress("2001:db8::9"), "key##4", len);
 
     host->addReservation(resv1);
     host->addReservation(resv2);
@@ -951,10 +956,10 @@ GenericHostDataSourceTest::testMultipleReservationsDifferentOrder() {
     HostPtr host2 = HostDataSourceUtils::initializeHost6("2001:db8::1", Host::IDENT_DUID, false);
 
     // Add some reservations
-    IPv6Resrv resv1(IPv6Resrv::TYPE_NA, IOAddress("2001:db8::6"), len);
-    IPv6Resrv resv2(IPv6Resrv::TYPE_NA, IOAddress("2001:db8::7"), len);
-    IPv6Resrv resv3(IPv6Resrv::TYPE_NA, IOAddress("2001:db8::8"), len);
-    IPv6Resrv resv4(IPv6Resrv::TYPE_NA, IOAddress("2001:db8::9"), len);
+    IPv6Resrv resv1(IPv6Resrv::TYPE_NA, IOAddress("2001:db8::6"), "key##1", len);
+    IPv6Resrv resv2(IPv6Resrv::TYPE_NA, IOAddress("2001:db8::7"), "key##2", len);
+    IPv6Resrv resv3(IPv6Resrv::TYPE_NA, IOAddress("2001:db8::8"), "key##3", len);
+    IPv6Resrv resv4(IPv6Resrv::TYPE_NA, IOAddress("2001:db8::9"), "key##4", len);
 
     host1->addReservation(resv1);
     host1->addReservation(resv2);
@@ -1246,7 +1251,11 @@ GenericHostDataSourceTest::stressTest(unsigned int nOfHosts /* = 0xfffdU */) {
         ss >> n_host;
 
         const std::string prefix = std::string("2001:db8::") + n_host;
-        hosts.push_back(HostDataSourceUtils::initializeHost6(prefix, Host::IDENT_HWADDR, false));
+        const std::string keys = 
+            std::string("arbitary_long_enough_for_stress_test"
+                        "but_less_than_128_characters");
+        hosts.push_back(HostDataSourceUtils::initializeHost6(prefix, Host::IDENT_HWADDR, false, keys));
+        
         IPv6ResrvRange range = hosts.back()->getIPv6Reservations();
         ASSERT_EQ(1, std::distance(range.first, range.second));
         EXPECT_TRUE(HostDataSourceUtils::reservationExists
@@ -1410,7 +1419,7 @@ void GenericHostDataSourceTest::testDeleteById6() {
     ASSERT_TRUE(hdsptr_);
 
     // Let's create a v6 host...
-    HostPtr host1 = HostDataSourceUtils::initializeHost6("2001:db8::1", Host::IDENT_DUID, false);
+    HostPtr host1 = HostDataSourceUtils::initializeHost6("2001:db8::1", Host::IDENT_DUID, false, "key##1");
     SubnetID subnet1 = host1->getIPv6SubnetID();
 
     // ... and add it to the data source.
index 09239970e09131d2485a154d08fbb93570ba0972..364f26ecb9453b2a99ce605e4433888b3cecdf89 100644 (file)
@@ -81,9 +81,10 @@ HostDataSourceUtils::initializeHost4(const std::string& address,
 }
 
 HostPtr
-HostDataSourceUtils::initializeHost6(std::string address,
+HostDataSourceUtils::initializeHost6(const std::string address,
                                      Host::IdentifierType identifier,
                                      bool prefix,
+                                     const std::string& key,
                                      bool new_identifier) {
     std::vector<uint8_t> ident;
     switch (identifier) {
@@ -111,11 +112,11 @@ HostDataSourceUtils::initializeHost6(std::string address,
 
     if (!prefix) {
         // Create IPv6 reservation (for an address)
-        IPv6Resrv resv(IPv6Resrv::TYPE_NA, IOAddress(address), 128);
+        IPv6Resrv resv(IPv6Resrv::TYPE_NA, IOAddress(address), key, 128);
         host->addReservation(resv);
     } else {
         // Create IPv6 reservation for a /64 prefix
-        IPv6Resrv resv(IPv6Resrv::TYPE_PD, IOAddress(address), 64);
+        IPv6Resrv resv(IPv6Resrv::TYPE_PD, IOAddress(address), key, 64);
         host->addReservation(resv);
     }
     return (host);
index f46906f02ea2b28d4e1c54d044e38e75bba9ca21..1b5251c75123173e6fac01876296323368492c5e 100644 (file)
@@ -38,8 +38,8 @@ public:
     /// identifier should be generated or the same as previously.
     ///
     /// @return generated Host object
-    static HostPtr initializeHost6(std::string address, Host::IdentifierType id,
-                                   bool prefix, bool new_identifier = true);
+    static HostPtr initializeHost6(const std::string address, Host::IdentifierType id,
+                                   bool prefix, const std::string& key = "", bool new_identifier = true);
 
     /// @brief Generates a hardware address in text version.
     ///
index 2b166a0c9b42e938875bd08448ae861a59404ea9..99d7659f03c281c6080096e189dec253daabf71c 100644 (file)
@@ -176,6 +176,7 @@ CREATE TABLE IF NOT EXISTS ipv6_reservations (
     prefix_len TINYINT(3) UNSIGNED NOT NULL DEFAULT 128,
     type TINYINT(4) UNSIGNED NOT NULL DEFAULT 0,
     dhcp6_iaid INT UNSIGNED NULL,
+    auth_key VARCHAR(128) NOT NULL,
     host_id INT UNSIGNED NOT NULL,
     PRIMARY KEY (reservation_id),
     INDEX fk_ipv6_reservations_host_idx (host_id ASC),
index 3bf129cce432a58813604a254687713ca553a055..41736c9b6ecbabd9de5197facb81c716088da96d 100644 (file)
@@ -23,6 +23,7 @@ ALTER TABLE hosts ADD COLUMN user_context TEXT NULL;
 # Add user contexts into tables holding DHCP options
 ALTER TABLE dhcp4_options ADD COLUMN user_context TEXT NULL;
 ALTER TABLE dhcp6_options ADD COLUMN user_context TEXT NULL;
+ALTER TABLE  ipv6_reservations ADD COLUMN auth_key VARCHAR(128) NOT NULL;
 
 # Create index for searching leases by subnet identifier.
 CREATE INDEX lease4_by_subnet_id ON lease4 (subnet_id);
index 5e8fd059cfdca531df1c19a9cbfad52ca210cf89..e5c7e30c3defd9d7de2bc5b7948c949ab15b165b 100644 (file)
@@ -335,6 +335,7 @@ CREATE TABLE ipv6_reservations (
   prefix_len SMALLINT NOT NULL DEFAULT '128',
   type SMALLINT NOT NULL DEFAULT '0',
   dhcp6_iaid INT DEFAULT NULL,
+  auth_key VARCHAR(128) NOT NULL,
   host_id INT NOT NULL,
   CONSTRAINT key_dhcp6_address_prefix_len UNIQUE (address, prefix_len),
   CONSTRAINT fk_ipv6_reservations_host FOREIGN KEY (host_id) REFERENCES hosts (host_id) ON DELETE CASCADE