From: Tomek Mrugalski Date: Wed, 12 Mar 2014 14:46:22 +0000 (+0100) Subject: [3080] Support for fqdn_fwd, fqdn_rev, hostname fields + fixes X-Git-Tag: bind10-1.2.0rc1-release~23^2~12 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=71e5465e993bd11dce4ecf749f80dfcd69203595;p=thirdparty%2Fkea.git [3080] Support for fqdn_fwd, fqdn_rev, hostname fields + fixes - Added support for 3 new fields, altered schema - Fixed bug where empty HWADDR was throwing exception - Several clean-ups --- diff --git a/src/lib/dhcpsrv/dhcpdb_create.pgsql b/src/lib/dhcpsrv/dhcpdb_create.pgsql index 2bf9a47ff6..db4dc624c4 100644 --- a/src/lib/dhcpsrv/dhcpdb_create.pgsql +++ b/src/lib/dhcpsrv/dhcpdb_create.pgsql @@ -15,9 +15,9 @@ -- This is the BIND 10 DHCP schema specification for PostgreSQL. --- The schema is reasonably portable (with the exception of the engine --- specification, which is MySQL-specific). Minor changes might be needed for --- other databases. +-- The schema is reasonably portable (with the exception of some field types +-- specification, which are PostgreSQL-specific). Minor changes might be needed +-- for other databases. -- To create the schema, either type the command: @@ -36,7 +36,10 @@ CREATE TABLE lease4 ( client_id BYTEA, -- Client ID valid_lifetime BIGINT, -- Length of the lease (seconds) expire TIMESTAMP, -- Expiration time of the lease - subnet_id BIGINT -- Subnet identification + subnet_id BIGINT, -- Subnet identification + fqdn_fwd BOOLEAN, -- Has forward DNS update been performed by a server + fqdn_rev BOOLEAN, -- Has reverse DNS update been performed by a server + hostname VARCHAR(255) -- The FQDN of the client ); @@ -60,7 +63,10 @@ CREATE TABLE lease6 ( lease_type SMALLINT, -- Lease type (see lease6_types -- table for possible values) iaid INT, -- See Section 10 of RFC 3315 - prefix_len SMALLINT -- For IA_PD only + prefix_len SMALLINT, -- For IA_PD only + fqdn_fwd BOOLEAN, -- Has forward DNS update been performed by a server + fqdn_rev BOOLEAN, -- Has reverse DNS update been performed by a server + hostname VARCHAR(255) -- The FQDN of the client ); -- Create search indexes for lease4 table diff --git a/src/lib/dhcpsrv/pgsql_lease_mgr.cc b/src/lib/dhcpsrv/pgsql_lease_mgr.cc index d16310f202..a90401d9a1 100644 --- a/src/lib/dhcpsrv/pgsql_lease_mgr.cc +++ b/src/lib/dhcpsrv/pgsql_lease_mgr.cc @@ -35,12 +35,14 @@ using namespace std; namespace { const size_t ADDRESS6_TEXT_MAX_LEN = 39; +const size_t MAX_PARAMETERS_IN_QUERY = 12; + struct TaggedStatement { PgSqlLeaseMgr::StatementIndex index; - int nbparams; - const Oid types[10]; - const char * name; - const char * text; + int nbparams; + const Oid types[MAX_PARAMETERS_IN_QUERY + 1]; + const char* name; + const char* text; }; TaggedStatement tagged_statements[] = { @@ -57,7 +59,7 @@ TaggedStatement tagged_statements[] = { "get_lease4_addr", "DECLARE get_lease4_addr CURSOR FOR " "SELECT address, hwaddr, client_id, " - "valid_lifetime, extract(epoch from expire), subnet_id " + "valid_lifetime, extract(epoch from expire), subnet_id, fqdn_fwd, fqdn_rev, hostname " "FROM lease4 " "WHERE address = $1"}, {PgSqlLeaseMgr::GET_LEASE4_CLIENTID, 1, @@ -65,7 +67,7 @@ TaggedStatement tagged_statements[] = { "get_lease4_clientid", "DECLARE get_lease4_clientid CURSOR FOR " "SELECT address, hwaddr, client_id, " - "valid_lifetime, extract(epoch from expire), subnet_id " + "valid_lifetime, extract(epoch from expire), subnet_id, fqdn_fwd, fqdn_rev, hostname " "FROM lease4 " "WHERE client_id = $1"}, {PgSqlLeaseMgr::GET_LEASE4_CLIENTID_SUBID, 2, @@ -73,7 +75,7 @@ TaggedStatement tagged_statements[] = { "get_lease4_clientid_subid", "DECLARE get_lease4_clientid_subid CURSOR FOR " "SELECT address, hwaddr, client_id, " - "valid_lifetime, extract(epoch from expire)::bigint, subnet_id " + "valid_lifetime, extract(epoch from expire)::bigint, subnet_id, fqdn_fwd, fqdn_rev, hostname " "FROM lease4 " "WHERE client_id = $1 AND subnet_id = $2"}, {PgSqlLeaseMgr::GET_LEASE4_HWADDR, 1, @@ -81,7 +83,7 @@ TaggedStatement tagged_statements[] = { "get_lease4_hwaddr", "DECLARE get_lease4_hwaddr CURSOR FOR " "SELECT address, hwaddr, client_id, " - "valid_lifetime, extract(epoch from expire)::bigint, subnet_id " + "valid_lifetime, extract(epoch from expire)::bigint, subnet_id, fqdn_fwd, fqdn_rev, hostname " "FROM lease4 " "WHERE hwaddr = $1"}, {PgSqlLeaseMgr::GET_LEASE4_HWADDR_SUBID, 2, @@ -89,7 +91,7 @@ TaggedStatement tagged_statements[] = { "get_lease4_hwaddr_subid", "DECLARE get_lease4_hwaddr_subid CURSOR FOR " "SELECT address, hwaddr, client_id, " - "valid_lifetime, extract(epoch from expire)::bigint, subnet_id " + "valid_lifetime, extract(epoch from expire)::bigint, subnet_id, fqdn_fwd, fqdn_rev, hostname " "FROM lease4 " "WHERE hwaddr = $1 AND subnet_id = $2"}, {PgSqlLeaseMgr::GET_LEASE6_ADDR, 1, @@ -98,7 +100,7 @@ TaggedStatement tagged_statements[] = { "DECLARE get_lease6_addr CURSOR FOR " "SELECT address, duid, valid_lifetime, " "extract(epoch from expire)::bigint, subnet_id, pref_lifetime, " - "lease_type, iaid, prefix_len " + "lease_type, iaid, prefix_len, fqdn_fwd, fqdn_rev, hostname " "FROM lease6 " "WHERE address = $1"}, {PgSqlLeaseMgr::GET_LEASE6_DUID_IAID, 2, @@ -107,7 +109,7 @@ TaggedStatement tagged_statements[] = { "DECLARE get_lease6_duid_iaid CURSOR FOR " "SELECT address, duid, valid_lifetime, " "extract(epoch from expire)::bigint, subnet_id, pref_lifetime, " - "lease_type, iaid, prefix_len " + "lease_type, iaid, prefix_len, fqdn_fwd, fqdn_rev, hostname " "FROM lease6 " "WHERE duid = $1 AND iaid = $2"}, {PgSqlLeaseMgr::GET_LEASE6_DUID_IAID_SUBID, 3, @@ -116,7 +118,7 @@ TaggedStatement tagged_statements[] = { "DECLARE get_lease6_duid_iaid_subid CURSOR FOR " "SELECT address, duid, valid_lifetime, " "extract(epoch from expire)::bigint, subnet_id, pref_lifetime, " - "lease_type, iaid, prefix_len " + "lease_type, iaid, prefix_len, fqdn_fwd, fqdn_rev, hostname " "FROM lease6 " "WHERE duid = $1 AND iaid = $2 AND subnet_id = $3"}, {PgSqlLeaseMgr::GET_VERSION, 0, @@ -124,27 +126,26 @@ TaggedStatement tagged_statements[] = { "get_version", "DECLARE get_version CURSOR FOR " "SELECT version, minor FROM schema_version"}, - {PgSqlLeaseMgr::INSERT_LEASE4, 6, - { 20, 17, 17, 20, 1114, 20 }, + {PgSqlLeaseMgr::INSERT_LEASE4, 9, + { 20, 17, 17, 20, 1114, 20, 16, 16, 1043 }, "insert_lease4", "INSERT INTO lease4(address, hwaddr, client_id, " - "valid_lifetime, expire, subnet_id) " - "VALUES ($1, $2, $3, $4, $5, $6)"}, - {PgSqlLeaseMgr::INSERT_LEASE6, 9, - { 1043, 17, 20, 1114, 20, - 20, 21, 20, 21 }, + "valid_lifetime, expire, subnet_id, fqdn_fwd, fqdn_rev, hostname) " + "VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)"}, + {PgSqlLeaseMgr::INSERT_LEASE6, 12, + { 1043, 17, 20, 1114, 20, 20, 21, 20, 21, 16, 16, 1043 }, "insert_lease6", "INSERT INTO lease6(address, duid, valid_lifetime, " "expire, subnet_id, pref_lifetime, " - "lease_type, iaid, prefix_len) " - "VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)"}, - {PgSqlLeaseMgr::UPDATE_LEASE4, 7, - { 20, 17, 17, 20, 1114, 20, 20 }, + "lease_type, iaid, prefix_len, fqdn_fwd, fqdn_rev, hostname) " + "VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12)"}, + {PgSqlLeaseMgr::UPDATE_LEASE4, 10, + { 20, 17, 17, 20, 1114, 20, 16, 16, 1043, 20 }, "update_lease4", "UPDATE lease4 SET address = $1, hwaddr = $2, " "client_id = $3, valid_lifetime = $4, expire = $5, " - "subnet_id = $6 " - "WHERE address = $7"}, + "subnet_id = $6, fqdn_fwd = $7, fqdn_rev = $8, hostname = $9 " + "WHERE address = $10"}, {PgSqlLeaseMgr::UPDATE_LEASE6, 10, { 1043, 17, 20, 1114, 20, 20, 21, 20, 21, 1043 }, @@ -173,10 +174,25 @@ protected: localtime_r(&expire_, &tinfo); strftime(buffer_, 20, "%Y-%m-%d %H:%M:%S", &tinfo); } + + bool stringToBool(char* value) { + if (!strlen(value)) { + return (false); + } + switch (value[0]) { + case 't': + return (true); + case 'f': + return (false); + default: + isc_throw(BadValue, "Received " << value[0] << " as boolean. The " + " only accepted values are 't', 'f' or ''"); + } + } }; class PgSqlLease4Exchange : public PgSqlLeaseExchange { - static const size_t LEASE_COLUMNS = 6; + static const size_t LEASE_COLUMNS = 9; public: PgSqlLease4Exchange() : addr4_(0) { memset(hwaddr_buffer_, 0, sizeof(hwaddr_buffer_)); @@ -189,8 +205,11 @@ public: columns_[3] = "valid_lifetime"; columns_[4] = "expire"; columns_[5] = "subnet_id"; + columns_[6] = "fqdn_fwd"; + columns_[7] = "fqdn_rev"; + columns_[8] = "hostname"; - BOOST_STATIC_ASSERT(5 < LEASE_COLUMNS); + BOOST_STATIC_ASSERT(8 < LEASE_COLUMNS); params.reserve(LEASE_COLUMNS); } @@ -208,11 +227,16 @@ public: tmp.str(""); tmp.clear(); - uint8_t* data = const_cast(&(lease_->hwaddr_[0])); - PgSqlParam pdest = { .value = reinterpret_cast(data), - .isbinary = 1, - .binarylen = static_cast(lease_->hwaddr_.size()) }; - params.push_back(pdest); + // Although HWADDR object will always be there, it may be just an empty vector + if (!lease_->hwaddr_.empty()) { + uint8_t* data = const_cast(&(lease_->hwaddr_[0])); + PgSqlParam pdest = { .value = reinterpret_cast(data), + .isbinary = 1, + .binarylen = static_cast(lease_->hwaddr_.size()) }; + params.push_back(pdest); + } else { + params.push_back(PgSqlParam()); + } if(lease_->client_id_) { vector client_data = lease_->client_id_->getClientId(); @@ -240,7 +264,15 @@ public: PgSqlParam psubnet_id = { .value = tmp.str() }; params.push_back(psubnet_id); - BOOST_STATIC_ASSERT(5 < LEASE_COLUMNS); + PgSqlParam fqdn_fwd = { .value = lease_->fqdn_fwd_?"TRUE":"FALSE" }; + PgSqlParam fqdn_rev = { .value = lease_->fqdn_fwd_?"TRUE":"FALSE" }; + PgSqlParam hostname = { .value = lease_->hostname_ }; + + params.push_back(fqdn_fwd); + params.push_back(fqdn_rev); + params.push_back(hostname); + + BOOST_STATIC_ASSERT(8 < LEASE_COLUMNS); return (params); } @@ -291,9 +323,19 @@ public: time_t cltt = expire_ - valid_lifetime_; + // Extract fqdn_fwd, fqdn_rev + // boolean is represented as one of 3 possible strings: + // "" (means NULL or not set), "t" (means true), "f" (means false) + bool fwd = stringToBool(PQgetvalue(r, line, 6)); + bool rev = stringToBool(PQgetvalue(r, line, 7)); + + // Extract hostname field + string hostname(PQgetvalue(r, line, 8)); + 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_, + fwd, rev, hostname))); } private: @@ -308,10 +350,11 @@ private: uint32_t valid_lifetime_; unsigned long hwaddr_length_; unsigned long client_id_length_; + string hostname_; }; class PgSqlLease6Exchange : public PgSqlLeaseExchange { - static const size_t LEASE_COLUMNS = 9; + static const size_t LEASE_COLUMNS = 12; public: PgSqlLease6Exchange() { memset(duid_buffer_, 0, sizeof(duid_buffer_)); @@ -325,6 +368,9 @@ public: 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); params.reserve(LEASE_COLUMNS); @@ -385,7 +431,15 @@ public: PgSqlParam prefixlen = { .value = tmp.str() }; params.push_back(prefixlen); - BOOST_STATIC_ASSERT(8 < LEASE_COLUMNS); + PgSqlParam fqdn_fwd = { .value = lease_->fqdn_fwd_?"TRUE":"FALSE" }; + PgSqlParam fqdn_rev = { .value = lease_->fqdn_rev_?"TRUE":"FALSE" }; + PgSqlParam hostname = { .value = lease_->hostname_ }; + + params.push_back(fqdn_fwd); + params.push_back(fqdn_rev); + params.push_back(hostname); + + BOOST_STATIC_ASSERT(11 < LEASE_COLUMNS); return (params); } @@ -475,12 +529,21 @@ public: addr6_ << ". Only 0, 1, or 2 are allowed."); } + // Extract fqdn_fwd, fqdn_rev + // boolean is represented as one of 3 possible strings: + // "" (means NULL or not set), "t" (means true), "f" (means false) + bool fwd = stringToBool(PQgetvalue(r, line, 9)); + bool rev = stringToBool(PQgetvalue(r, line, 10)); + + // Extract hostname field + string hostname(PQgetvalue(r, line, 11)); + // Set up DUID, DuidPtr duid_ptr(new DUID(duid_buffer_, duid_length_)); Lease6Ptr result(new Lease6(type, addr, duid_ptr, iaid_, pref_lifetime_, valid_lifetime_, 0, 0, - subnet_id_, prefixlen_)); + subnet_id_, fwd, rev, hostname, prefixlen_)); time_t cltt = expire_ - valid_lifetime_; result->cltt_ = cltt; @@ -1031,7 +1094,7 @@ PgSqlLeaseMgr::updateLease4(const Lease4Ptr& lease) { bindparams params = exchange4_->createBindForSend(lease); // Set up the WHERE clause and append it to the MYSQL_BIND array - tmp << lease->addr_; + tmp << static_cast(lease->addr_); PgSqlParam addr4 = { .value = tmp.str() }; params.push_back(addr4); @@ -1084,7 +1147,7 @@ PgSqlLeaseMgr::deleteLease(const isc::asiolink::IOAddress& addr) { if (addr.isV4()) { ostringstream tmp; - tmp << addr; + tmp << static_cast(addr); PgSqlParam addr4 = { .value = tmp.str() }; inparams.push_back(addr4); diff --git a/src/lib/dhcpsrv/tests/pgsql_lease_mgr_unittest.cc b/src/lib/dhcpsrv/tests/pgsql_lease_mgr_unittest.cc index 1e4e529af0..760c30c89a 100644 --- a/src/lib/dhcpsrv/tests/pgsql_lease_mgr_unittest.cc +++ b/src/lib/dhcpsrv/tests/pgsql_lease_mgr_unittest.cc @@ -327,6 +327,11 @@ TEST_F(PgSqlLeaseMgrTest, basicLease4) { detailCompareLease(leases[2], l_returned); } +/// Checks that we are able to update an IPv4 lease in the database. +TEST_F(PgSqlLeaseMgrTest, updateLease4) { + testUpdateLease4(); +} + /// @brief Basic Lease4 Checks /// /// Checks that the addLease, getLease4(by address), getLease4(hwaddr,subnet_id), @@ -376,7 +381,6 @@ TEST_F(PgSqlLeaseMgrTest, lease4NullClientId) { ASSERT_TRUE(l_returned); detailCompareLease(leases[2], l_returned); - // Check that we can update the lease // Modify some fields in lease 1 (not the address) and update it. ++leases[1]->subnet_id_; diff --git a/src/lib/dhcpsrv/tests/schema_pgsql_copy.h b/src/lib/dhcpsrv/tests/schema_pgsql_copy.h index 6290e6bd5a..9fa0cee707 100644 --- a/src/lib/dhcpsrv/tests/schema_pgsql_copy.h +++ b/src/lib/dhcpsrv/tests/schema_pgsql_copy.h @@ -44,30 +44,36 @@ const char* destroy_statement[] = { const char* create_statement[] = { "START TRANSACTION", "CREATE TABLE lease4 (" - "address BIGINT PRIMARY KEY NOT NULL," - "hwaddr BYTEA," - "client_id BYTEA," - "valid_lifetime BIGINT," - "expire TIMESTAMP," - "subnet_id BIGINT" - ")", + "address BIGINT PRIMARY KEY NOT NULL," + "hwaddr BYTEA," + "client_id BYTEA," + "valid_lifetime BIGINT," + "expire TIMESTAMP," + "subnet_id BIGINT," + "fqdn_fwd BOOLEAN," + "fqdn_rev BOOLEAN," + "hostname VARCHAR(255)" + ")", "CREATE TABLE lease6 (" - "address VARCHAR(39) PRIMARY KEY NOT NULL," - "duid BYTEA," - "valid_lifetime BIGINT," - "expire TIMESTAMP," - "subnet_id BIGINT," - "pref_lifetime BIGINT," - "lease_type SMALLINT," - "iaid BIGINT," - "prefix_len SMALLINT" - ")", + "address VARCHAR(39) PRIMARY KEY NOT NULL," + "duid BYTEA," + "valid_lifetime BIGINT," + "expire TIMESTAMP," + "subnet_id BIGINT," + "pref_lifetime BIGINT," + "lease_type SMALLINT," + "iaid BIGINT," + "prefix_len SMALLINT," + "fqdn_fwd BOOLEAN," + "fqdn_rev BOOLEAN," + "hostname VARCHAR(255)" + ")", "CREATE TABLE lease6_types (" - "lease_type SMALLINT PRIMARY KEY NOT NULL," - "name VARCHAR(5)" - ")", + "lease_type SMALLINT PRIMARY KEY NOT NULL," + "name VARCHAR(5)" + ")", "INSERT INTO lease6_types VALUES (0, 'IA_NA')", "INSERT INTO lease6_types VALUES (1, 'IA_TA')",