Parcourir la source

[master] Merge branch 'trac3084'

Marcin Siodelski il y a 11 ans
Parent
commit
79b7d8ee01

+ 9 - 2
src/lib/dhcpsrv/dhcpdb_create.mysql

@@ -36,7 +36,10 @@ CREATE TABLE lease4 (
     client_id VARBINARY(128),                   # Client ID
     valid_lifetime INT UNSIGNED,                # Length of the lease (seconds)
     expire TIMESTAMP,                           # Expiration time of the lease
-    subnet_id INT UNSIGNED                      # Subnet identification
+    subnet_id INT UNSIGNED,                     # Subnet identification
+    fqdn_fwd BOOL,                              # Has forward DNS update been performed by a server
+    fqdn_rev BOOL,                              # Has reverse DNS update been performed by a server
+    hostname VARCHAR(255)                       # The FQDN of the client
     ) ENGINE = INNODB;
 
 
@@ -60,7 +63,11 @@ CREATE TABLE lease6 (
     lease_type TINYINT,                         # Lease type (see lease6_types
                                                 #    table for possible values)
     iaid INT UNSIGNED,                          # See Section 10 of RFC 3315
-    prefix_len TINYINT UNSIGNED                 # For IA_PD only
+    prefix_len TINYINT UNSIGNED,                # For IA_PD only
+    fqdn_fwd BOOL,                              # Has forward DNS update been performed by a server
+    fqdn_rev BOOL,                              # Has reverse DNS update been performed by a server
+    hostname VARCHAR(255)                       # The FQDN of the client
+
     ) ENGINE = INNODB;
 
 # Create search indexes for lease4 table 

+ 24 - 7
src/lib/dhcpsrv/lease_mgr.cc

@@ -33,20 +33,21 @@ namespace isc {
 namespace dhcp {
 
 Lease::Lease(const isc::asiolink::IOAddress& addr, uint32_t t1, uint32_t t2,
-             uint32_t valid_lft, SubnetID subnet_id, time_t cltt)
+             uint32_t valid_lft, SubnetID subnet_id, time_t cltt,
+             const bool fqdn_fwd, const bool fqdn_rev,
+             const std::string& hostname)
     :addr_(addr), t1_(t1), t2_(t2), valid_lft_(valid_lft), cltt_(cltt),
-     subnet_id_(subnet_id), fixed_(false), fqdn_fwd_(false), fqdn_rev_(false) {
+     subnet_id_(subnet_id), fixed_(false), hostname_(hostname),
+     fqdn_fwd_(fqdn_fwd), fqdn_rev_(fqdn_rev) {
 }
 
 Lease4::Lease4(const Lease4& other)
     : Lease(other.addr_, other.t1_, other.t2_, other.valid_lft_,
-            other.subnet_id_, other.cltt_), ext_(other.ext_),
+            other.subnet_id_, other.cltt_, other.fqdn_fwd_,
+            other.fqdn_rev_, other.hostname_), ext_(other.ext_),
       hwaddr_(other.hwaddr_) {
 
     fixed_ = other.fixed_;
-    fqdn_fwd_ = other.fqdn_fwd_;
-    fqdn_rev_ = other.fqdn_rev_;
-    hostname_ = other.hostname_;
     comments_ = other.comments_;
 
     if (other.client_id_) {
@@ -87,7 +88,23 @@ Lease4::operator=(const Lease4& other) {
 Lease6::Lease6(LeaseType type, const isc::asiolink::IOAddress& addr,
                DuidPtr duid, uint32_t iaid, uint32_t preferred, uint32_t valid,
                uint32_t t1, uint32_t t2, SubnetID subnet_id, uint8_t prefixlen)
-    : Lease(addr, t1, t2, valid, subnet_id, 0/*cltt*/),
+    : Lease(addr, t1, t2, valid, subnet_id, 0/*cltt*/, false, false, ""),
+      type_(type), prefixlen_(prefixlen), iaid_(iaid), duid_(duid),
+      preferred_lft_(preferred) {
+    if (!duid) {
+        isc_throw(InvalidOperation, "DUID must be specified for a lease");
+    }
+
+    cltt_ = time(NULL);
+}
+
+Lease6::Lease6(LeaseType type, const isc::asiolink::IOAddress& addr,
+               DuidPtr duid, uint32_t iaid, uint32_t preferred, uint32_t valid,
+               uint32_t t1, uint32_t t2, SubnetID subnet_id,
+               const bool fqdn_fwd, const bool fqdn_rev,
+               const std::string& hostname, uint8_t prefixlen)
+    : Lease(addr, t1, t2, valid, subnet_id, 0/*cltt*/,
+            fqdn_fwd, fqdn_rev, hostname),
       type_(type), prefixlen_(prefixlen), iaid_(iaid), duid_(duid),
       preferred_lft_(preferred) {
     if (!duid) {

+ 49 - 6
src/lib/dhcpsrv/lease_mgr.h

@@ -122,8 +122,13 @@ struct Lease {
     /// @param valid_lft Lifetime of the lease
     /// @param subnet_id Subnet identification
     /// @param cltt Client last transmission time
+    /// @param fqdn_fwd If true, forward DNS update is performed for a lease.
+    /// @param fqdn_rev If true, reverse DNS update is performed for a lease.
+    /// @param hostname FQDN of the client which gets the lease.
     Lease(const isc::asiolink::IOAddress& addr, uint32_t t1, uint32_t t2,
-          uint32_t valid_lft, SubnetID subnet_id, time_t cltt);
+          uint32_t valid_lft, SubnetID subnet_id, time_t cltt,
+          const bool fqdn_fwd, const bool fqdn_rev,
+          const std::string& hostname);
 
     /// @brief Destructor
     virtual ~Lease() {}
@@ -243,10 +248,16 @@ struct Lease4 : public Lease {
     /// @param t2 rebinding time
     /// @param cltt Client last transmission time
     /// @param subnet_id Subnet identification
+    /// @param fqdn_fwd If true, forward DNS update is performed for a lease.
+    /// @param fqdn_rev If true, reverse DNS update is performed for a lease.
+    /// @param hostname FQDN of the client which gets the lease.
     Lease4(const isc::asiolink::IOAddress& addr, const uint8_t* hwaddr, size_t hwaddr_len,
            const uint8_t* clientid, size_t clientid_len, uint32_t valid_lft,
-           uint32_t t1, uint32_t t2, time_t cltt, uint32_t subnet_id)
-        : Lease(addr, t1, t2, valid_lft, subnet_id, cltt),
+           uint32_t t1, uint32_t t2, time_t cltt, uint32_t subnet_id,
+           const bool fqdn_fwd = false, const bool fqdn_rev = false,
+           const std::string& hostname = "")
+        : Lease(addr, t1, t2, valid_lft, subnet_id, cltt, fqdn_fwd, fqdn_rev,
+                hostname),
         ext_(0), hwaddr_(hwaddr, hwaddr + hwaddr_len) {
         if (clientid_len) {
             client_id_.reset(new ClientId(clientid, clientid_len));
@@ -256,7 +267,7 @@ struct Lease4 : public Lease {
     /// @brief Default constructor
     ///
     /// Initialize fields that don't have a default constructor.
-    Lease4() : Lease(0, 0, 0, 0, 0, 0) {
+    Lease4() : Lease(0, 0, 0, 0, 0, 0, false, false, "") {
     }
 
     /// @brief Copy constructor
@@ -341,14 +352,46 @@ struct Lease6 : public Lease {
     /// @todo: Add DHCPv6 failover related fields here
 
     /// @brief Constructor
+    /// @param type Lease type.
+    /// @param addr Assigned address.
+    /// @param duid A pointer to an object representing DUID.
+    /// @param iaid IAID.
+    /// @param preferred Preferred lifetime.
+    /// @param valid Valid lifetime.
+    /// @param t1 A value of the T1 timer.
+    /// @param t2 A value of the T2 timer.
+    /// @param subnet_id A Subnet identifier.
+    /// @param prefixlen An address prefix length.
     Lease6(LeaseType type, const isc::asiolink::IOAddress& addr, DuidPtr duid,
            uint32_t iaid, uint32_t preferred, uint32_t valid, uint32_t t1,
-           uint32_t t2, SubnetID subnet_id, uint8_t prefixlen_ = 0);
+           uint32_t t2, SubnetID subnet_id, uint8_t prefixlen = 0);
+
+    /// @brief Constructor, including FQDN data.
+    ///
+    /// @param type Lease type.
+    /// @param addr Assigned address.
+    /// @param duid A pointer to an object representing DUID.
+    /// @param iaid IAID.
+    /// @param preferred Preferred lifetime.
+    /// @param valid Valid lifetime.
+    /// @param t1 A value of the T1 timer.
+    /// @param t2 A value of the T2 timer.
+    /// @param subnet_id A Subnet identifier.
+    /// @param fqdn_fwd If true, forward DNS update is performed for a lease.
+    /// @param fqdn_rev If true, reverse DNS update is performed for a lease.
+    /// @param hostname FQDN of the client which gets the lease.
+    /// @param prefixlen An address prefix length.
+    Lease6(LeaseType type, const isc::asiolink::IOAddress& addr, DuidPtr duid,
+           uint32_t iaid, uint32_t preferred, uint32_t valid, uint32_t t1,
+           uint32_t t2, SubnetID subnet_id, const bool fqdn_fwd,
+           const bool fqdn_rev, const std::string& hostname,
+           uint8_t prefixlen = 0);
 
     /// @brief Constructor
     ///
     /// Initialize fields that don't have a default constructor.
-    Lease6() : Lease(isc::asiolink::IOAddress("::"), 0, 0, 0, 0, 0),
+    Lease6() : Lease(isc::asiolink::IOAddress("::"), 0, 0, 0, 0, 0,
+                     false, false, ""),
         type_(LEASE_IA_NA) {
     }
 

+ 174 - 33
src/lib/dhcpsrv/mysql_lease_mgr.cc

@@ -1,4 +1,4 @@
-// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2012-2013 Internet Systems Consortium, Inc. ("ISC")
 //
 // Permission to use, copy, modify, and/or distribute this software for any
 // purpose with or without fee is hereby granted, provided that the above
@@ -104,6 +104,12 @@ const size_t ADDRESS6_TEXT_MAX_LEN = 39;
 const my_bool MLM_FALSE = 0;                ///< False value
 const my_bool MLM_TRUE = 1;                 ///< True value
 
+/// @brief Maximum length of the hostname stored in DNS.
+///
+/// This length is restricted by the length of the domain-name carried
+/// in the Client FQDN %Option (see RFC4702 and RFC4704).
+const size_t HOSTNAME_MAX_LEN = 255;
+
 ///@}
 
 /// @brief MySQL Selection Statements
@@ -123,68 +129,80 @@ TaggedStatement tagged_statements[] = {
                     "DELETE FROM lease6 WHERE address = ?"},
     {MySqlLeaseMgr::GET_LEASE4_ADDR,
                     "SELECT address, hwaddr, client_id, "
-                        "valid_lifetime, expire, subnet_id "
+                        "valid_lifetime, expire, subnet_id, "
+                        "fqdn_fwd, fqdn_rev, hostname "
                             "FROM lease4 "
                             "WHERE address = ?"},
     {MySqlLeaseMgr::GET_LEASE4_CLIENTID,
                     "SELECT address, hwaddr, client_id, "
-                        "valid_lifetime, expire, subnet_id "
+                        "valid_lifetime, expire, subnet_id, "
+                        "fqdn_fwd, fqdn_rev, hostname "
                             "FROM lease4 "
                             "WHERE client_id = ?"},
     {MySqlLeaseMgr::GET_LEASE4_CLIENTID_SUBID,
                     "SELECT address, hwaddr, client_id, "
-                        "valid_lifetime, expire, subnet_id "
+                        "valid_lifetime, expire, subnet_id, "
+                        "fqdn_fwd, fqdn_rev, hostname "
                             "FROM lease4 "
                             "WHERE client_id = ? AND subnet_id = ?"},
     {MySqlLeaseMgr::GET_LEASE4_HWADDR,
                     "SELECT address, hwaddr, client_id, "
-                        "valid_lifetime, expire, subnet_id "
+                        "valid_lifetime, expire, subnet_id, "
+                        "fqdn_fwd, fqdn_rev, hostname "
                             "FROM lease4 "
                             "WHERE hwaddr = ?"},
     {MySqlLeaseMgr::GET_LEASE4_HWADDR_SUBID,
                     "SELECT address, hwaddr, client_id, "
-                        "valid_lifetime, expire, subnet_id "
+                        "valid_lifetime, expire, subnet_id, "
+                        "fqdn_fwd, fqdn_rev, hostname "
                             "FROM lease4 "
                             "WHERE hwaddr = ? AND subnet_id = ?"},
     {MySqlLeaseMgr::GET_LEASE6_ADDR,
                     "SELECT address, duid, valid_lifetime, "
                         "expire, subnet_id, pref_lifetime, "
-                        "lease_type, iaid, prefix_len "
+                        "lease_type, iaid, prefix_len, "
+                        "fqdn_fwd, fqdn_rev, hostname "
                             "FROM lease6 "
                             "WHERE address = ?"},
     {MySqlLeaseMgr::GET_LEASE6_DUID_IAID,
                     "SELECT address, duid, valid_lifetime, "
                         "expire, subnet_id, pref_lifetime, "
-                        "lease_type, iaid, prefix_len "
+                        "lease_type, iaid, prefix_len, "
+                        "fqdn_fwd, fqdn_rev, hostname "
                             "FROM lease6 "
                             "WHERE duid = ? AND iaid = ?"},
     {MySqlLeaseMgr::GET_LEASE6_DUID_IAID_SUBID,
                     "SELECT address, duid, valid_lifetime, "
                         "expire, subnet_id, pref_lifetime, "
-                        "lease_type, iaid, prefix_len "
+                        "lease_type, iaid, prefix_len, "
+                        "fqdn_fwd, fqdn_rev, hostname "
                             "FROM lease6 "
                             "WHERE duid = ? AND iaid = ? AND subnet_id = ?"},
     {MySqlLeaseMgr::GET_VERSION,
                     "SELECT version, minor FROM schema_version"},
     {MySqlLeaseMgr::INSERT_LEASE4,
                     "INSERT INTO lease4(address, hwaddr, client_id, "
-                        "valid_lifetime, expire, subnet_id) "
-                            "VALUES (?, ?, ?, ?, ?, ?)"},
+                        "valid_lifetime, expire, subnet_id, "
+                        "fqdn_fwd, fqdn_rev, hostname) "
+                            "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)"},
     {MySqlLeaseMgr::INSERT_LEASE6,
                     "INSERT INTO lease6(address, duid, valid_lifetime, "
                         "expire, subnet_id, pref_lifetime, "
-                        "lease_type, iaid, prefix_len) "
-                            "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)"},
+                        "lease_type, iaid, prefix_len, "
+                        "fqdn_fwd, fqdn_rev, hostname) "
+                            "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"},
     {MySqlLeaseMgr::UPDATE_LEASE4,
                     "UPDATE lease4 SET address = ?, hwaddr = ?, "
                         "client_id = ?, valid_lifetime = ?, expire = ?, "
-                        "subnet_id = ? "
+                        "subnet_id = ?, fqdn_fwd = ?, fqdn_rev = ?, "
+                        "hostname = ? "
                             "WHERE address = ?"},
     {MySqlLeaseMgr::UPDATE_LEASE6,
                     "UPDATE lease6 SET address = ?, duid = ?, "
                         "valid_lifetime = ?, expire = ?, subnet_id = ?, "
                         "pref_lifetime = ?, lease_type = ?, iaid = ?, "
-                        "prefix_len = ? "
+                        "prefix_len = ?, fqdn_fwd = ?, fqdn_rev = ?, "
+                        "hostname = ? "
                             "WHERE address = ?"},
     // End of list sentinel
     {MySqlLeaseMgr::NUM_STATEMENTS, NULL}
@@ -275,7 +293,7 @@ public:
 
 class MySqlLease4Exchange : public MySqlLeaseExchange {
     /// @brief Set number of database columns for this lease structure
-    static const size_t LEASE_COLUMNS = 6;
+    static const size_t LEASE_COLUMNS = 9;
 
 public:
     /// @brief Constructor
@@ -294,7 +312,10 @@ public:
         columns_[3] = "valid_lifetime";
         columns_[4] = "expire";
         columns_[5] = "subnet_id";
-        BOOST_STATIC_ASSERT(5 < LEASE_COLUMNS);
+        columns_[6] = "fqdn_fwd";
+        columns_[7] = "fqdn_rev";
+        columns_[8] = "hostname";
+        BOOST_STATIC_ASSERT(8 < LEASE_COLUMNS);
     }
 
     /// @brief Create MYSQL_BIND objects for Lease4 Pointer
@@ -397,11 +418,32 @@ public:
         // bind_[5].is_null = &MLM_FALSE; // commented out for performance
                                           // reasons, see memset() above
 
+        // fqdn_fwd: boolean
+        bind_[6].buffer_type = MYSQL_TYPE_TINY;
+        bind_[6].buffer = reinterpret_cast<char*>(&lease_->fqdn_fwd_);
+        bind_[6].is_unsigned = MLM_TRUE;
+        // bind_[6].is_null = &MLM_FALSE; // commented out for performance
+                                          // reasons, see memset() above
+
+        // fqdn_rev: boolean
+        bind_[7].buffer_type = MYSQL_TYPE_TINY;
+        bind_[7].buffer = reinterpret_cast<char*>(&lease_->fqdn_rev_);
+        bind_[7].is_unsigned = MLM_TRUE;
+        // bind_[7].is_null = &MLM_FALSE; // commented out for performance
+                                          // reasons, see memset() above
+
+        // hostname: varchar(255)
+        bind_[8].buffer_type = MYSQL_TYPE_VARCHAR;
+        bind_[8].buffer = const_cast<char*>(lease_->hostname_.c_str());
+        bind_[8].buffer_length = lease_->hostname_.length();
+        // bind_[8].is_null = &MLM_FALSE; // commented out for performance
+                                          // reasons, see memset() above
+
         // Add the error flags
         setErrorIndicators(bind_, error_, LEASE_COLUMNS);
 
         // .. and check that we have the numbers correct at compile time.
-        BOOST_STATIC_ASSERT(5 < LEASE_COLUMNS);
+        BOOST_STATIC_ASSERT(8 < LEASE_COLUMNS);
 
         // Add the data to the vector.  Note the end element is one after the
         // end of the array.
@@ -470,11 +512,34 @@ public:
         // bind_[5].is_null = &MLM_FALSE; // commented out for performance
                                           // reasons, see memset() above
 
+        // fqdn_fwd: boolean
+        bind_[6].buffer_type = MYSQL_TYPE_TINY;
+        bind_[6].buffer = reinterpret_cast<char*>(&fqdn_fwd_);
+        bind_[6].is_unsigned = MLM_TRUE;
+        // bind_[6].is_null = &MLM_FALSE; // commented out for performance
+                                          // reasons, see memset() above
+
+        // fqdn_rev: boolean
+        bind_[7].buffer_type = MYSQL_TYPE_TINY;
+        bind_[7].buffer = reinterpret_cast<char*>(&fqdn_rev_);
+        bind_[7].is_unsigned = MLM_TRUE;
+        // bind_[7].is_null = &MLM_FALSE; // commented out for performance
+                                          // reasons, see memset() above
+
+        // hostname: varchar(255)
+        hostname_length_ = sizeof(hostname_buffer_);
+        bind_[8].buffer_type = MYSQL_TYPE_STRING;
+        bind_[8].buffer = reinterpret_cast<char*>(hostname_buffer_);
+        bind_[8].buffer_length = hostname_length_;
+        bind_[8].length = &hostname_length_;
+        // bind_[8].is_null = &MLM_FALSE; // commented out for performance
+                                          // reasons, see memset() above
+
         // Add the error flags
         setErrorIndicators(bind_, error_, LEASE_COLUMNS);
 
         // .. and check that we have the numbers correct at compile time.
-        BOOST_STATIC_ASSERT(5 < LEASE_COLUMNS);
+        BOOST_STATIC_ASSERT(8 < LEASE_COLUMNS);
 
         // Add the data to the vector.  Note the end element is one after the
         // end of the array.
@@ -500,10 +565,16 @@ public:
             client_id_length_ = 0;
         }
 
+        // Hostname is passed to Lease4 as a string object. We have to create
+        // it from the buffer holding hostname and the buffer length.
+        std::string hostname(hostname_buffer_,
+                             hostname_buffer_ + hostname_length_);
+
         // note that T1 and T2 are not stored
         return (Lease4Ptr(new Lease4(addr4_, hwaddr_buffer_, hwaddr_length_,
                                      client_id_buffer_, client_id_length_,
-                                     valid_lifetime_, 0, 0, cltt, subnet_id_)));
+                                     valid_lifetime_, 0, 0, cltt, subnet_id_,
+                                     fqdn_fwd_, fqdn_rev_, hostname)));
     }
 
     /// @brief Return columns in error
@@ -543,6 +614,15 @@ private:
     Lease4Ptr       lease_;             ///< Pointer to lease object
     uint32_t        subnet_id_;         ///< Subnet identification
     uint32_t        valid_lifetime_;    ///< Lease time
+
+    my_bool         fqdn_fwd_;          ///< Has forward DNS update been
+                                        ///< performed
+    my_bool         fqdn_rev_;          ///< Has reverse DNS update been
+                                        ///< performed
+    char            hostname_buffer_[HOSTNAME_MAX_LEN];
+                                        ///< Client hostname
+    unsigned long   hostname_length_;   ///< Client hostname length
+
 };
 
 
@@ -562,7 +642,7 @@ private:
 
 class MySqlLease6Exchange : public MySqlLeaseExchange {
     /// @brief Set number of database columns for this lease structure
-    static const size_t LEASE_COLUMNS = 9;
+    static const size_t LEASE_COLUMNS = 12;
 
 public:
     /// @brief Constructor
@@ -575,15 +655,18 @@ public:
         std::fill(&error_[0], &error_[LEASE_COLUMNS], MLM_FALSE);
 
         // Set the column names (for error messages)
-        columns_[0] = "address";
-        columns_[1] = "duid";
-        columns_[2] = "valid_lifetime";
-        columns_[3] = "expire";
-        columns_[4] = "subnet_id";
-        columns_[5] = "pref_lifetime";
-        columns_[6] = "lease_type";
-        columns_[7] = "iaid";
-        columns_[8] = "prefix_len";
+        columns_[0]  = "address";
+        columns_[1]  = "duid";
+        columns_[2]  = "valid_lifetime";
+        columns_[3]  = "expire";
+        columns_[4]  = "subnet_id";
+        columns_[5]  = "pref_lifetime";
+        columns_[6]  = "lease_type";
+        columns_[7]  = "iaid";
+        columns_[8]  = "prefix_len";
+        columns_[9]  = "fqdn_fwd";
+        columns_[10] = "fqdn_rev";
+        columns_[11] = "hostname";
         BOOST_STATIC_ASSERT(8 < LEASE_COLUMNS);
     }
 
@@ -707,11 +790,32 @@ public:
         // bind_[8].is_null = &MLM_FALSE; // commented out for performance
                                           // reasons, see memset() above
 
+        // fqdn_fwd: boolean
+        bind_[9].buffer_type = MYSQL_TYPE_TINY;
+        bind_[9].buffer = reinterpret_cast<char*>(&lease_->fqdn_fwd_);
+        bind_[9].is_unsigned = MLM_TRUE;
+        // bind_[7].is_null = &MLM_FALSE; // commented out for performance
+                                          // reasons, see memset() above
+
+        // fqdn_rev: boolean
+        bind_[10].buffer_type = MYSQL_TYPE_TINY;
+        bind_[10].buffer = reinterpret_cast<char*>(&lease_->fqdn_rev_);
+        bind_[10].is_unsigned = MLM_TRUE;
+        // bind_[10].is_null = &MLM_FALSE; // commented out for performance
+                                           // reasons, see memset() above
+
+        // hostname: varchar(255)
+        bind_[11].buffer_type = MYSQL_TYPE_VARCHAR;
+        bind_[11].buffer = const_cast<char*>(lease_->hostname_.c_str());
+        bind_[11].buffer_length = lease_->hostname_.length();
+        // bind_[11].is_null = &MLM_FALSE; // commented out for performance
+                                           // reasons, see memset() above
+
         // Add the error flags
         setErrorIndicators(bind_, error_, LEASE_COLUMNS);
 
         // .. and check that we have the numbers correct at compile time.
-        BOOST_STATIC_ASSERT(8 < LEASE_COLUMNS);
+        BOOST_STATIC_ASSERT(11 < LEASE_COLUMNS);
 
         // Add the data to the vector.  Note the end element is one after the
         // end of the array.
@@ -805,11 +909,34 @@ public:
         // bind_[8].is_null = &MLM_FALSE; // commented out for performance
                                           // reasons, see memset() above
 
+        // fqdn_fwd: boolean
+        bind_[9].buffer_type = MYSQL_TYPE_TINY;
+        bind_[9].buffer = reinterpret_cast<char*>(&fqdn_fwd_);
+        bind_[9].is_unsigned = MLM_TRUE;
+        // bind_[9].is_null = &MLM_FALSE; // commented out for performance
+                                          // reasons, see memset() above
+
+        // fqdn_rev: boolean
+        bind_[10].buffer_type = MYSQL_TYPE_TINY;
+        bind_[10].buffer = reinterpret_cast<char*>(&fqdn_rev_);
+        bind_[10].is_unsigned = MLM_TRUE;
+        // bind_[10].is_null = &MLM_FALSE; // commented out for performance
+                                           // reasons, see memset() above
+
+        // hostname: varchar(255)
+        hostname_length_ = sizeof(hostname_buffer_);
+        bind_[11].buffer_type = MYSQL_TYPE_STRING;
+        bind_[11].buffer = reinterpret_cast<char*>(hostname_buffer_);
+        bind_[11].buffer_length = hostname_length_;
+        bind_[11].length = &hostname_length_;
+        // bind_[11].is_null = &MLM_FALSE; // commented out for performance
+                                           // reasons, see memset() above
+
         // Add the error flags
         setErrorIndicators(bind_, error_, LEASE_COLUMNS);
 
         // .. and check that we have the numbers correct at compile time.
-        BOOST_STATIC_ASSERT(8 < LEASE_COLUMNS);
+        BOOST_STATIC_ASSERT(11 < LEASE_COLUMNS);
 
         // Add the data to the vector.  Note the end element is one after the
         // end of the array.
@@ -859,11 +986,17 @@ public:
         // Set up DUID,
         DuidPtr duid_ptr(new DUID(duid_buffer_, duid_length_));
 
+        // Hostname is passed to Lease6 as a string object, so we have to
+        // create it from the hostname buffer and length.
+        std::string hostname(hostname_buffer_,
+                             hostname_buffer_ + hostname_length_);
+
         // Create the lease and set the cltt (after converting from the
         // expire time retrieved from the database).
         Lease6Ptr result(new Lease6(type, addr, duid_ptr, iaid_,
                                     pref_lifetime_, valid_lifetime_, 0, 0,
-                                    subnet_id_, prefixlen_));
+                                    subnet_id_, fqdn_fwd_, fqdn_rev_,
+                                    hostname, prefixlen_));
         time_t cltt = 0;
         MySqlLeaseMgr::convertFromDatabaseTime(expire_, valid_lifetime_, cltt);
         result->cltt_ = cltt;
@@ -907,6 +1040,14 @@ private:
     uint32_t        pref_lifetime_;     ///< Preferred lifetime
     uint32_t        subnet_id_;         ///< Subnet identification
     uint32_t        valid_lifetime_;    ///< Lease time
+    my_bool         fqdn_fwd_;          ///< Has forward DNS update been
+                                        ///< performed
+    my_bool         fqdn_rev_;          ///< Has reverse DNS update been
+                                        ///< performed
+    char            hostname_buffer_[HOSTNAME_MAX_LEN];
+                                        ///< Client hostname
+    unsigned long   hostname_length_;   ///< Client hostname length
+
 };
 
 

+ 58 - 6
src/lib/dhcpsrv/tests/lease_mgr_unittest.cc

@@ -272,8 +272,9 @@ TEST(Lease4, constructor) {
 
         // Create the lease
         Lease4 lease(ADDRESS[i], HWADDR, sizeof(HWADDR),
-                     CLIENTID, sizeof(CLIENTID), VALID_LIFETIME, 0, 0, current_time,
-                     SUBNET_ID);
+                     CLIENTID, sizeof(CLIENTID), VALID_LIFETIME, 0, 0,
+                     current_time, SUBNET_ID, true, true,
+                     "hostname.example.com.");
 
         EXPECT_EQ(ADDRESS[i], static_cast<uint32_t>(lease.addr_));
         EXPECT_EQ(0, lease.ext_);
@@ -285,9 +286,9 @@ TEST(Lease4, constructor) {
         EXPECT_EQ(current_time, lease.cltt_);
         EXPECT_EQ(SUBNET_ID, lease.subnet_id_);
         EXPECT_FALSE(lease.fixed_);
-        EXPECT_TRUE(lease.hostname_.empty());
-        EXPECT_FALSE(lease.fqdn_fwd_);
-        EXPECT_FALSE(lease.fqdn_rev_);
+        EXPECT_EQ("hostname.example.com.", lease.hostname_);
+        EXPECT_TRUE(lease.fqdn_fwd_);
+        EXPECT_TRUE(lease.fqdn_rev_);
         EXPECT_TRUE(lease.comments_.empty());
     }
 }
@@ -494,7 +495,7 @@ TEST(Lease4, operatorEquals) {
 
 // Lease6 is also defined in lease_mgr.h, so is tested in this file as well.
 // This test checks if the Lease6 structure can be instantiated correctly
-TEST(Lease6, Lease6Constructor) {
+TEST(Lease6, Lease6ConstructorDefault) {
 
     // check a variety of addresses with different bits set.
     const char* ADDRESS[] = {
@@ -525,6 +526,56 @@ TEST(Lease6, Lease6Constructor) {
         EXPECT_TRUE(lease->valid_lft_ == 200);
         EXPECT_TRUE(lease->t1_ == 50);
         EXPECT_TRUE(lease->t2_ == 80);
+        EXPECT_FALSE(lease->fqdn_fwd_);
+        EXPECT_FALSE(lease->fqdn_rev_);
+        EXPECT_TRUE(lease->hostname_.empty());
+
+    }
+
+    // Lease6 must be instantiated with a DUID, not with NULL pointer
+    IOAddress addr(ADDRESS[0]);
+    Lease6Ptr lease2;
+    EXPECT_THROW(lease2.reset(new Lease6(Lease6::LEASE_IA_NA, addr,
+                                         DuidPtr(), iaid, 100, 200, 50, 80,
+                                         subnet_id)), InvalidOperation);
+}
+
+// This test verifies that the Lease6 constructor which accepts FQDN data,
+// sets the data correctly for the lease.
+TEST(Lease6, Lease6ConstructorWithFQDN) {
+
+    // check a variety of addresses with different bits set.
+    const char* ADDRESS[] = {
+        "::", "::1", "2001:db8:1::456",
+        "7fff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
+        "8000::", "8000::1",
+        "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"
+    };
+
+    // Other values
+    uint8_t llt[] = {0, 1, 2, 3, 4, 5, 6, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf};
+    DuidPtr duid(new DUID(llt, sizeof(llt)));
+    uint32_t iaid = 7;      // Just a number
+    SubnetID subnet_id = 8; // Just another number
+
+    for (int i = 0; i < sizeof(ADDRESS) / sizeof(ADDRESS[0]); ++i) {
+        IOAddress addr(ADDRESS[i]);
+        Lease6Ptr lease(new Lease6(Lease6::LEASE_IA_NA, addr,
+                               duid, iaid, 100, 200, 50, 80, subnet_id,
+                                   true, true, "host.example.com."));
+
+        EXPECT_TRUE(lease->addr_ == addr);
+        EXPECT_TRUE(*lease->duid_ == *duid);
+        EXPECT_TRUE(lease->iaid_ == iaid);
+        EXPECT_TRUE(lease->subnet_id_ == subnet_id);
+        EXPECT_TRUE(lease->type_ == Lease6::LEASE_IA_NA);
+        EXPECT_TRUE(lease->preferred_lft_ == 100);
+        EXPECT_TRUE(lease->valid_lft_ == 200);
+        EXPECT_TRUE(lease->t1_ == 50);
+        EXPECT_TRUE(lease->t2_ == 80);
+        EXPECT_TRUE(lease->fqdn_fwd_);
+        EXPECT_TRUE(lease->fqdn_rev_);
+        EXPECT_EQ("host.example.com.", lease->hostname_);
     }
 
     // Lease6 must be instantiated with a DUID, not with NULL pointer
@@ -535,6 +586,7 @@ TEST(Lease6, Lease6Constructor) {
                                          subnet_id)), InvalidOperation);
 }
 
+
 /// @brief Lease6 Equality Test
 ///
 /// Checks that the operator==() correctly compares two leases for equality.

+ 120 - 14
src/lib/dhcpsrv/tests/mysql_lease_mgr_unittest.cc

@@ -1,4 +1,4 @@
-// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2012-2013 Internet Systems Consortium, Inc. ("ISC")
 //
 // Permission to use, copy, modify, and/or distribute this software for any
 // purpose with or without fee is hereby granted, provided that the above
@@ -236,9 +236,6 @@ public:
         lease->t1_ = 0;                             // Not saved
         lease->t2_ = 0;                             // Not saved
         lease->fixed_ = false;                      // Unused
-        lease->hostname_ = std::string("");         // Unused
-        lease->fqdn_fwd_ = false;                   // Unused
-        lease->fqdn_rev_ = false;                   // Unused
         lease->comments_ = std::string("");         // Unused
 
         // Set other parameters.  For historical reasons, address 0 is not used.
@@ -249,6 +246,9 @@ public:
             lease->valid_lft_ = 8677;
             lease->cltt_ = 168256;
             lease->subnet_id_ = 23;
+            lease->fqdn_rev_ = true;
+            lease->fqdn_fwd_ = false;
+            lease->hostname_ = "myhost.example.com.";
 
         } else if (address == straddress4_[1]) {
             lease->hwaddr_ = vector<uint8_t>(6, 0x19);
@@ -257,6 +257,9 @@ public:
             lease->valid_lft_ = 3677;
             lease->cltt_ = 123456;
             lease->subnet_id_ = 73;
+            lease->fqdn_rev_ = true;
+            lease->fqdn_fwd_ = true;
+            lease->hostname_ = "myhost.example.com.";
 
         } else if (address == straddress4_[2]) {
             lease->hwaddr_ = vector<uint8_t>(6, 0x2a);
@@ -265,6 +268,9 @@ public:
             lease->valid_lft_ = 5412;
             lease->cltt_ = 234567;
             lease->subnet_id_ = 73;                         // Same as lease 1
+            lease->fqdn_rev_ = false;
+            lease->fqdn_fwd_ = false;
+            lease->hostname_ = "";
 
         } else if (address == straddress4_[3]) {
             lease->hwaddr_ = vector<uint8_t>(6, 0x19);      // Same as lease 1
@@ -278,6 +284,9 @@ public:
             lease->valid_lft_ = 7000;
             lease->cltt_ = 234567;
             lease->subnet_id_ = 37;
+            lease->fqdn_rev_ = true;
+            lease->fqdn_fwd_ = true;
+            lease->hostname_ = "otherhost.example.com.";
 
         } else if (address == straddress4_[4]) {
             lease->hwaddr_ = vector<uint8_t>(6, 0x4c);
@@ -287,6 +296,9 @@ public:
             lease->valid_lft_ = 7736;
             lease->cltt_ = 222456;
             lease->subnet_id_ = 85;
+            lease->fqdn_rev_ = true;
+            lease->fqdn_fwd_ = true;
+            lease->hostname_ = "otherhost.example.com.";
 
         } else if (address == straddress4_[5]) {
             lease->hwaddr_ = vector<uint8_t>(6, 0x19);      // Same as lease 1
@@ -296,6 +308,9 @@ public:
             lease->valid_lft_ = 7832;
             lease->cltt_ = 227476;
             lease->subnet_id_ = 175;
+            lease->fqdn_rev_ = false;
+            lease->fqdn_fwd_ = false;
+            lease->hostname_ = "otherhost.example.com.";
 
         } else if (address == straddress4_[6]) {
             lease->hwaddr_ = vector<uint8_t>(6, 0x6e);
@@ -305,6 +320,9 @@ public:
             lease->valid_lft_ = 1832;
             lease->cltt_ = 627476;
             lease->subnet_id_ = 112;
+            lease->fqdn_rev_ = false;
+            lease->fqdn_fwd_ = true;
+            lease->hostname_ = "myhost.example.com.";
 
         } else if (address == straddress4_[7]) {
             lease->hwaddr_ = vector<uint8_t>();             // Empty
@@ -312,6 +330,9 @@ public:
             lease->valid_lft_ = 7975;
             lease->cltt_ = 213876;
             lease->subnet_id_ = 19;
+            lease->fqdn_rev_ = true;
+            lease->fqdn_fwd_ = true;
+            lease->hostname_ = "myhost.example.com.";
 
         } else {
             // Unknown address, return an empty pointer.
@@ -343,9 +364,6 @@ public:
         lease->t1_ = 0;                             // Not saved
         lease->t2_ = 0;                             // Not saved
         lease->fixed_ = false;                      // Unused
-        lease->hostname_ = std::string("");         // Unused
-        lease->fqdn_fwd_ = false;                   // Unused
-        lease->fqdn_rev_ = false;                   // Unused
         lease->comments_ = std::string("");         // Unused
 
         // Set other parameters.  For historical reasons, address 0 is not used.
@@ -358,6 +376,9 @@ public:
             lease->valid_lft_ = 8677;
             lease->cltt_ = 168256;
             lease->subnet_id_ = 23;
+            lease->fqdn_fwd_ = true;
+            lease->fqdn_rev_ = true;
+            lease->hostname_ = "myhost.example.com.";
 
         } else if (address == straddress6_[1]) {
             lease->type_ = Lease6::LEASE_IA_TA;
@@ -368,6 +389,9 @@ public:
             lease->valid_lft_ = 3677;
             lease->cltt_ = 123456;
             lease->subnet_id_ = 73;
+            lease->fqdn_fwd_ = false;
+            lease->fqdn_rev_ = true;
+            lease->hostname_ = "myhost.example.com.";
 
         } else if (address == straddress6_[2]) {
             lease->type_ = Lease6::LEASE_IA_PD;
@@ -378,6 +402,9 @@ public:
             lease->valid_lft_ = 5412;
             lease->cltt_ = 234567;
             lease->subnet_id_ = 73;                     // Same as lease 1
+            lease->fqdn_fwd_ = false;
+            lease->fqdn_rev_ = false;
+            lease->hostname_ = "myhost.example.com.";
 
         } else if (address == straddress6_[3]) {
             lease->type_ = Lease6::LEASE_IA_NA;
@@ -397,6 +424,9 @@ public:
             lease->valid_lft_ = 7000;
             lease->cltt_ = 234567;
             lease->subnet_id_ = 37;
+            lease->fqdn_fwd_ = true;
+            lease->fqdn_rev_ = false;
+            lease->hostname_ = "myhost.example.com.";
 
         } else if (address == straddress6_[4]) {
             // Same DUID and IAID as straddress6_1
@@ -408,6 +438,9 @@ public:
             lease->valid_lft_ = 7736;
             lease->cltt_ = 222456;
             lease->subnet_id_ = 671;
+            lease->fqdn_fwd_ = true;
+            lease->fqdn_rev_ = true;
+            lease->hostname_ = "otherhost.example.com.";
 
         } else if (address == straddress6_[5]) {
             // Same DUID and IAID as straddress6_1
@@ -420,6 +453,9 @@ public:
             lease->valid_lft_ = 7832;
             lease->cltt_ = 227476;
             lease->subnet_id_ = 175;
+            lease->fqdn_fwd_ = false;
+            lease->fqdn_rev_ = true;
+            lease->hostname_ = "hostname.example.com.";
 
         } else if (address == straddress6_[6]) {
             // Same DUID as straddress6_1
@@ -432,6 +468,9 @@ public:
             lease->valid_lft_ = 1832;
             lease->cltt_ = 627476;
             lease->subnet_id_ = 112;
+            lease->fqdn_fwd_ = false;
+            lease->fqdn_rev_ = true;
+            lease->hostname_ = "hostname.example.com.";
 
         } else if (address == straddress6_[7]) {
             // Same IAID as straddress6_1
@@ -443,6 +482,9 @@ public:
             lease->valid_lft_ = 7975;
             lease->cltt_ = 213876;
             lease->subnet_id_ = 19;
+            lease->fqdn_fwd_ = false;
+            lease->fqdn_rev_ = true;
+            lease->hostname_ = "hostname.example.com.";
 
         } else {
             // Unknown address, return an empty pointer.
@@ -779,6 +821,31 @@ TEST_F(MySqlLeaseMgrTest, lease4NullClientId) {
 
 }
 
+/// @brief Verify that too long hostname for Lease4 is not accepted.
+///
+/// Checks that the it is not possible to create a lease when the hostname
+/// length exceeds 255 characters.
+TEST_F(MySqlLeaseMgrTest, lease4InvalidHostname) {
+    // Get the leases to be used for the test.
+    vector<Lease4Ptr> leases = createLeases4();
+
+    // Create a dummy hostname, consisting of 255 characters.
+    leases[1]->hostname_.assign(255, 'a');
+    ASSERT_TRUE(lmptr_->addLease(leases[1]));
+
+    // The new lease must be in the database.
+    Lease4Ptr l_returned = lmptr_->getLease4(ioaddress4_[1]);
+    detailCompareLease(leases[1], l_returned);
+
+    // Let's delete the lease, so as we can try to add it again with
+    // invalid hostname.
+    EXPECT_TRUE(lmptr_->deleteLease(ioaddress4_[1]));
+
+    // Create a hostname with 256 characters. It should not be accepted.
+    leases[1]->hostname_.assign(256, 'a');
+    EXPECT_THROW(lmptr_->addLease(leases[1]), DbOperationError);
+}
+
 /// @brief Basic Lease6 Checks
 ///
 /// Checks that the addLease, getLease6 (by address) and deleteLease (with an
@@ -825,6 +892,31 @@ TEST_F(MySqlLeaseMgrTest, basicLease6) {
     detailCompareLease(leases[2], l_returned);
 }
 
+/// @brief Verify that too long hostname for Lease6 is not accepted.
+///
+/// Checks that the it is not possible to create a lease when the hostname
+/// length exceeds 255 characters.
+TEST_F(MySqlLeaseMgrTest, lease6InvalidHostname) {
+    // Get the leases to be used for the test.
+    vector<Lease6Ptr> leases = createLeases6();
+
+    // Create a dummy hostname, consisting of 255 characters.
+    leases[1]->hostname_.assign(255, 'a');
+    ASSERT_TRUE(lmptr_->addLease(leases[1]));
+
+    // The new lease must be in the database.
+    Lease6Ptr l_returned = lmptr_->getLease6(ioaddress6_[1]);
+    detailCompareLease(leases[1], l_returned);
+
+    // Let's delete the lease, so as we can try to add it again with
+    // invalid hostname.
+    EXPECT_TRUE(lmptr_->deleteLease(ioaddress6_[1]));
+
+    // Create a hostname with 256 characters. It should not be accepted.
+    leases[1]->hostname_.assign(256, 'a');
+    EXPECT_THROW(lmptr_->addLease(leases[1]), DbOperationError);
+}
+
 /// @brief Check GetLease4 methods - access by Hardware Address
 ///
 /// Adds leases to the database and checks that they can be accessed via
@@ -888,7 +980,7 @@ TEST_F(MySqlLeaseMgrTest, getLease4HwaddrSize) {
         leases[1]->hwaddr_.resize(i, i);
         EXPECT_TRUE(lmptr_->addLease(leases[1]));
         // @todo: Simply use HWAddr directly once 2589 is implemented
-        Lease4Collection returned = 
+        Lease4Collection returned =
             lmptr_->getLease4(HWAddr(leases[1]->hwaddr_, HTYPE_ETHER));
 
         ASSERT_EQ(1, returned.size());
@@ -917,7 +1009,7 @@ TEST_F(MySqlLeaseMgrTest, getLease4HwaddrSubnetId) {
     // Get the leases matching the hardware address of lease 1 and
     // subnet ID of lease 1.  Result should be a single lease - lease 1.
     // @todo: Simply use HWAddr directly once 2589 is implemented
-    Lease4Ptr returned = lmptr_->getLease4(HWAddr(leases[1]->hwaddr_, 
+    Lease4Ptr returned = lmptr_->getLease4(HWAddr(leases[1]->hwaddr_,
         HTYPE_ETHER), leases[1]->subnet_id_);
 
     ASSERT_TRUE(returned);
@@ -954,9 +1046,9 @@ TEST_F(MySqlLeaseMgrTest, getLease4HwaddrSubnetId) {
     leases[1]->addr_ = leases[2]->addr_;
     EXPECT_TRUE(lmptr_->addLease(leases[1]));
     // @todo: Simply use HWAddr directly once 2589 is implemented
-    EXPECT_THROW(returned = lmptr_->getLease4(HWAddr(leases[1]->hwaddr_, 
-                                                    HTYPE_ETHER), 
-                                             leases[1]->subnet_id_), 
+    EXPECT_THROW(returned = lmptr_->getLease4(HWAddr(leases[1]->hwaddr_,
+                                                    HTYPE_ETHER),
+                                             leases[1]->subnet_id_),
                  isc::dhcp::MultipleRecords);
 
     // Delete all leases in the database
@@ -981,8 +1073,8 @@ TEST_F(MySqlLeaseMgrTest, getLease4HwaddrSubnetIdSize) {
         leases[1]->hwaddr_.resize(i, i);
         EXPECT_TRUE(lmptr_->addLease(leases[1]));
         // @todo: Simply use HWAddr directly once 2589 is implemented
-        Lease4Ptr returned = lmptr_->getLease4(HWAddr(leases[1]->hwaddr_, 
-                                                      HTYPE_ETHER), 
+        Lease4Ptr returned = lmptr_->getLease4(HWAddr(leases[1]->hwaddr_,
+                                                      HTYPE_ETHER),
                                                leases[1]->subnet_id_);
         ASSERT_TRUE(returned);
         detailCompareLease(leases[1], returned);
@@ -1273,6 +1365,9 @@ TEST_F(MySqlLeaseMgrTest, updateLease4) {
     // Modify some fields in lease 1 (not the address) and update it.
     ++leases[1]->subnet_id_;
     leases[1]->valid_lft_ *= 2;
+    leases[1]->hostname_ = "modified.hostname.";
+    leases[1]->fqdn_fwd_ = !leases[1]->fqdn_fwd_;
+    leases[1]->fqdn_rev_ = !leases[1]->fqdn_rev_;;
     lmptr_->updateLease4(leases[1]);
 
     // ... and check what is returned is what is expected.
@@ -1299,6 +1394,10 @@ TEST_F(MySqlLeaseMgrTest, updateLease4) {
     ASSERT_TRUE(l_returned);
     detailCompareLease(leases[1], l_returned);
 
+    // Try to update the lease with the too long hostname.
+    leases[1]->hostname_.assign(256, 'a');
+    EXPECT_THROW(lmptr_->updateLease4(leases[1]), isc::dhcp::DbOperationError);
+
     // Try updating a lease not in the database.
     lmptr_->deleteLease(ioaddress4_[2]);
     EXPECT_THROW(lmptr_->updateLease4(leases[2]), isc::dhcp::NoSuchLease);
@@ -1324,6 +1423,9 @@ TEST_F(MySqlLeaseMgrTest, updateLease6) {
     ++leases[1]->iaid_;
     leases[1]->type_ = Lease6::LEASE_IA_PD;
     leases[1]->valid_lft_ *= 2;
+    leases[1]->hostname_ = "modified.hostname.v6.";
+    leases[1]->fqdn_fwd_ = !leases[1]->fqdn_fwd_;
+    leases[1]->fqdn_rev_ = !leases[1]->fqdn_rev_;;
     lmptr_->updateLease6(leases[1]);
     lmptr_->commit();
 
@@ -1352,6 +1454,10 @@ TEST_F(MySqlLeaseMgrTest, updateLease6) {
     ASSERT_TRUE(l_returned);
     detailCompareLease(leases[1], l_returned);
 
+    // Try to update the lease with the too long hostname.
+    leases[1]->hostname_.assign(256, 'a');
+    EXPECT_THROW(lmptr_->updateLease6(leases[1]), isc::dhcp::DbOperationError);
+
     // Try updating a lease not in the database.
     EXPECT_THROW(lmptr_->updateLease6(leases[2]), isc::dhcp::NoSuchLease);
 }

+ 9 - 3
src/lib/dhcpsrv/tests/schema_copy.h

@@ -1,4 +1,4 @@
-// Copyright (C) 2012  Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2012-2013 Internet Systems Consortium, Inc. ("ISC")
 //
 // Permission to use, copy, modify, and/or distribute this software for any
 // purpose with or without fee is hereby granted, provided that the above
@@ -49,7 +49,10 @@ const char* create_statement[] = {
         "client_id VARBINARY(128),"
         "valid_lifetime INT UNSIGNED,"
         "expire TIMESTAMP,"
-        "subnet_id INT UNSIGNED"
+        "subnet_id INT UNSIGNED,"
+        "fqdn_fwd BOOL,"
+        "fqdn_rev BOOL,"
+        "hostname VARCHAR(255)"
         ") ENGINE = INNODB",
 
     "CREATE INDEX lease4_by_hwaddr_subnet_id ON lease4 (hwaddr, subnet_id)",
@@ -65,7 +68,10 @@ const char* create_statement[] = {
         "pref_lifetime INT UNSIGNED,"
         "lease_type TINYINT,"
         "iaid INT UNSIGNED,"
-        "prefix_len TINYINT UNSIGNED"
+        "prefix_len TINYINT UNSIGNED,"
+        "fqdn_fwd BOOL,"
+        "fqdn_rev BOOL,"
+        "hostname VARCHAR(255)"
         ") ENGINE = INNODB",
 
     "CREATE INDEX lease6_by_iaid_subnet_id_duid ON lease6 (iaid, subnet_id, duid)",