Commit 92280f3d authored by Tomek Mrugalski's avatar Tomek Mrugalski 🛰
Browse files

[5272] lease4-add, lease6-add implemented

parent 592492ea
/lease_cmds_messages.cc
/lease_cmds_messages.h
/s-messages
/html
......@@ -57,7 +57,7 @@ public:
TYPE_HWADDR, ///< query by hardware address (v4 only)
TYPE_DUID ///< query by DUID (v6 only)
} Type;
/// @brief Specifies subnet-id (always used)
SubnetID subnet_id;
......@@ -71,13 +71,31 @@ public:
/// @brief Specifies identifier value (used when query_by_addr is false)
isc::dhcp::DuidPtr duid;
static Type txtToType(const std::string& txt) {
if (txt == "address") {
return (Parameters::TYPE_ADDR);
} else if (txt == "hw-address") {
return (Parameters::TYPE_HWADDR);
} else if (txt == "duid") {
return (Parameters::TYPE_DUID);
} else {
isc_throw(BadValue, "Incorrect identifier type: "
<< txt << ", the only supported values are: "
"address, hw-address, duid");
}
}
/// @brief specifies parameter types (true = query by address, false =
/// query by indetifier-type,identifier)
Type query_type;
Lease::Type lease_type;
uint32_t iaid;
/// @brief Default contstructor.
Parameters()
:addr("::"), query_type(TYPE_ADDR) {
:addr("::"), query_type(TYPE_ADDR), lease_type(Lease::TYPE_NA), iaid(0) {
}
};
......@@ -135,8 +153,8 @@ private:
/// "valid-lft": 3600,
/// "expire": 1499282530,
/// "subnet-id": 1,
/// "fdqn_fwd": true,
/// "fqdn_rev": true,
/// "fdqn-fwd": true,
/// "fqdn-rev": true,
/// "hostname": "myhost.example.org",
/// "state": 0
/// }
......@@ -236,6 +254,7 @@ private:
};
LeaseCmdsImpl::LeaseCmdsImpl() {
/// @todo: Remove family_
family_ = CfgMgr::instance().getFamily();
registerCommands();
......@@ -311,32 +330,34 @@ LeaseCmdsImpl::leaseAddHandler(const std::string& name,
isc_throw(isc::BadValue, "'lease' parameters must be specified");
}
ConstSrvConfigPtr config = CfgMgr::instance().getCurrentCfg();
Lease4Ptr lease4;
Lease6Ptr lease6;
if (v4) {
LeaseDataParser4 parser;
lease4 = parser.parse(lease_data);
Lease4Parser parser;
lease4 = parser.parse(config, lease_data);
checkLeaseIntegrity(lease4);
// checkLeaseIntegrity(config, lease4);
if (lease4) {
LeaseMgrFactory::instance().add(lease4);
LeaseMgrFactory::instance().addLease(lease4);
}
} else {
LeaseDataParser6 parser;
lease6 = parser.parse(lease_data);
Lease6Parser parser;
lease6 = parser.parse(config, lease_data);
checkLeaseIntegrity(lease6);
// checkLeaseIntegrity(config, lease6);
if (lease6) {
LeaseMgrFactory::instance().add(lease6);
LeaseMgrFactory::instance().addLease(lease6);
}
}
} catch (const std::exception& ex) {
LOG_ERROR(lease_cmds_logger, LEASE_CMDS_RESERV_ADD_FAILED)
LOG_ERROR(lease_cmds_logger, v4 ? LEASE_CMDS_ADD4_FAILED : LEASE_CMDS_ADD6_FAILED)
.arg(txt)
.arg(ex.what());
return (createAnswer(CONTROL_RESULT_ERROR, ex.what()));
......@@ -366,15 +387,14 @@ LeaseCmdsImpl::getParameters(const ConstElementPtr& params) {
}
x.subnet_id = tmp->intValue();
tmp = params->get("ip-address");
ConstLeasePtr host;
tmp = params->get("address");
if (tmp) {
if (tmp->getType() != Element::string) {
isc_throw(BadValue, "'ip-address' is not a string.");
isc_throw(BadValue, "'address' is not a string.");
}
x.addr = IOAddress(tmp->stringValue());
x.query_by_addr = true;
x.query_type = Parameters::TYPE_ADDR;
return (x);
}
......@@ -394,32 +414,29 @@ LeaseCmdsImpl::getParameters(const ConstElementPtr& params) {
}
// Got the parameters. Let's see if their values make sense.
// Try to parse the identifier value first.
try {
x.ident = util::str::quotedStringToBinary(ident->stringValue());
if (x.ident.empty()) {
util::str::decodeFormattedHexString(ident->stringValue(),
x.ident);
}
} catch (...) {
// The string doesn't match any known pattern, so we have to
// report an error at this point.
isc_throw(BadValue, "Unable to parse 'identifier' value.");
// Try to convert identifier-type
x.query_type = Parameters::txtToType(type->stringValue());
switch (x.query_type) {
case Parameters::TYPE_HWADDR: {
HWAddr hw = HWAddr::fromText(ident->stringValue());
x.hwaddr = HWAddrPtr(new HWAddr(hw));
break;
}
if (x.ident.empty()) {
isc_throw(BadValue, "Unable to query for empty 'identifier'.");
case Parameters::TYPE_DUID: {
DUID duid = DUID::fromText(ident->stringValue());
x.duid = DuidPtr(new DUID(duid));
}
case Parameters::TYPE_ADDR: {
// We should never get here. The address clause should have been caught
// earlier.
return (x);
}
default: {
isc_throw(BadValue, "Identifier type " << type->stringValue() <<
" is not supported.");
}
// Next, try to convert identifier-type
try {
x.type = Lease::getIdentifierType(type->stringValue());
} catch (const std::exception& ex) {
isc_throw(BadValue, "Value of 'identifier-type' was not recognized.");
}
x.query_by_addr = false;
return (x);
}
......@@ -433,77 +450,93 @@ LeaseCmdsImpl::leaseGetHandler(const std::string& name, ConstElementPtr params)
p = getParameters(params);
switch (p.query_type) {
case TYPE_ADDR: {
case Parameters::TYPE_ADDR: {
// Query by address
if (v4) {
lease4 = LeaseMgr::instance().getLease4(p.subnet_id, p.addr);
lease4 = LeaseMgrFactory::instance().getLease4(p.addr);
} else {
lease6 = LeaseMgr::instance().getLease6(p.subnet_id, p.addr);
lease6 = LeaseMgrFactory::instance().getLease6(p.lease_type, p.addr);
}
break;
}
case TYPE_HWADDR:
case Parameters::TYPE_HWADDR:
if (v4) {
lease4 = LeaseMgr::instance().getLease4(p.subnet_id, p.hwaddr);
if (!p.hwaddr) {
return (createAnswer(CONTROL_RESULT_ERROR,
"Program error: Query by hw-address "
"requires hwaddr to be specified"));
}
lease4 = LeaseMgrFactory::instance().getLease4(*p.hwaddr, p.subnet_id);
} else {
return (createAnswer(CONTROL_RESULT_ERROR,
"Query by hw-address is not allowed in v6."));
}
case TYPE_DUID:
if (v6) {
lease6 = LeaseMgr::instance().getLease6(p.subnet_id, p.duid);
case Parameters::TYPE_DUID:
if (!v4) {
if (!p.duid) {
return (createAnswer(CONTROL_RESULT_ERROR,
"Program error: Query by duid "
"requires duid to be specified"));
}
lease6 = LeaseMgrFactory::instance().getLease6(p.lease_type, *p.duid,
p.iaid, p.subnet_id);
} else {
return (createAnswer(CONTROL_RESULT_ERROR,
"Query by duid is not allowed in v4."));
}
default:
return (createAnswer(CONTROL_RESULT_ERROR,
"Unknown query type: " << static_cast<int>(p.query_type)));
default: {
stringstream tmp;
tmp << "Unknown query type: " << static_cast<int>(p.query_type);
return (createAnswer(CONTROL_RESULT_ERROR, tmp.str()));
}
}
} catch (const std::exception& ex) {
return (createAnswer(CONTROL_RESULT_ERROR,
"Failure during leaseX-get: " << ex.what()));
stringstream tmp;
tmp << "Failure during leaseX-get: " << ex.what();
return (createAnswer(CONTROL_RESULT_ERROR, tmp.str()));
}
ElementPtr lease_json;
if (v4 && lease4) {
lease_json = lease4->toElement4();
lease_json = lease4->toElement();
return (createAnswer(CONTROL_RESULT_SUCCESS, "DHCPv4 lease found.", lease_json));
}
if (!v4 && lease6) {
lease_json = lease6->toElement6();
lease_json = lease6->toElement();
return (createAnswer(CONTROL_RESULT_SUCCESS, "DHCPv6 lease found.", lease_json));
}
if (lease) {
return (createAnswer(CONTROL_RESULT_SUCCESS, "Lease found.", lease_json));
} else {
return (createAnswer(CONTROL_RESULT_SUCCESS, "Lease not found."));
}
// If we got here, the lease has not been found.
return (createAnswer(CONTROL_RESULT_EMPTY, "Lease not found."));
}
ConstElementPtr
LeaseCmdsImpl::reservationDelHandler(const std::string& /*name*/,
ConstElementPtr params) {
LeaseCmdsImpl::leaseDelHandler(const std::string& name,
ConstElementPtr params) {
Parameters p;
bool deleted;
bool deleted = false;
#if 0
try {
p = getParameters(params);
if (p.query_by_addr) {
// try to delete by address
deleted = LeaseMgr::instance().del(p.subnet_id, p.addr);
deleted = LeaseMgrFactory::instance().del(p.subnet_id, p.addr);
} else {
// try to delete by identifier
if (family_ == AF_INET) {
deleted = LeaseMgr::instance().del4(p.subnet_id, p.type,
&p.ident[0], p.ident.size());
deleted = LeaseMgrFactory::instance().del4(p.subnet_id, p.type,
&p.ident[0], p.ident.size());
} else {
deleted = LeaseMgr::instance().del6(p.subnet_id, p.type,
&p.ident[0], p.ident.size());
deleted = LeaseMgrFactory::instance().del6(p.subnet_id, p.type,
&p.ident[0], p.ident.size());
}
}
} catch (const std::exception& ex) {
return (createAnswer(CONTROL_RESULT_ERROR, ex.what()));
}
#endif
if (deleted) {
return (createAnswer(CONTROL_RESULT_SUCCESS, "Lease deleted."));
......@@ -513,8 +546,18 @@ LeaseCmdsImpl::reservationDelHandler(const std::string& /*name*/,
}
}
ConstElementPtr
LeaseCmdsImpl::leaseUpdateHandler(const string& command, ConstElementPtr args) {
return (createAnswer(CONTROL_RESULT_ERROR, "not implemented yet."));
}
ConstElementPtr
LeaseCmdsImpl::leaseWipeHandler(const string& command, ConstElementPtr args) {
return (createAnswer(CONTROL_RESULT_ERROR, "not implemented yet."));
}
uint16_t LeaseCmdsImpl::family_ = AF_INET;
LeaseDataSourcePtr LeaseCmdsImpl::db_storage_;
LeaseCmds::LeaseCmds()
:impl_(new LeaseCmdsImpl()) {
......
......@@ -18,11 +18,11 @@ the log message.
This info message indicates that the Lease Commands hooks library has been
removed successfully.
% LEASE_CMDS_ADD4_FAILED Lease4-add command failed (parameters: %1, reason: %2)
% LEASE_CMDS_ADD4_FAILED lease4-add command failed (parameters: %1, reason: %2)
The lease4-add command has failed. Both the reason as well as the
parameters passed are logged.
% LEASE_CMDS_ADD6_FAILED Lease4-add command failed (parameters: %1, reason: %2)
% LEASE_CMDS_ADD6_FAILED Lease6-add command failed (parameters: %1, reason: %2)
The lease6-add command has failed. Both the reason as well as the
parameters passed are logged.
......
......@@ -4,14 +4,242 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include <cc/data.h>
#include <dhcp/hwaddr.h>
#include <asiolink/io_address.h>
#include <dhcpsrv/lease.h>
#include <lease_parser.h>
// V4:
// address,hwaddr,client_id,valid_lifetime,expire,subnet_id,fqdn_fwd,fqdn_rev,hostname,state
#include <config.h>
// V6:
// address,duid,valid_lifetime,expire,subnet_id,pref_lifetime,lease_type,iaid,prefix_len,fqdn_fwd,fqdn_rev,hostname,hwaddr,state
using namespace std;
using namespace isc::dhcp;
using namespace isc::data;
using namespace isc::asiolink;
#include <config.h>
// Can't use a constructor as a function
namespace {
IOAddress buildIOAddress(const std::string& str) { return (IOAddress(str)); }
};
namespace isc {
namespace lease_cmds {
IOAddress
LeaseParser::getIOAddress(const ConstElementPtr& scope,
const std::string& name) {
return (getAndConvert<IOAddress,
buildIOAddress>(scope, name, "address"));
}
Lease4Ptr
Lease4Parser::parse(ConstSrvConfigPtr& cfg,
const ConstElementPtr& lease_info) {
if (!lease_info) {
isc_throw(BadValue, "lease information missing");
}
// These are mandatory parameters.
IOAddress addr = getIOAddress(lease_info, "ip-address");
SubnetID subnet_id = getUint32(lease_info, "subnet-id");
if (!addr.isV4()) {
isc_throw(BadValue, "Non-IPv4 address specified: " << addr);
}
// Not a most straightforward conversion, but it works.
string hwaddr_txt = getString(lease_info, "hw-address");
HWAddr hwaddr = HWAddr::fromText(hwaddr_txt);
HWAddrPtr hwaddr_ptr = HWAddrPtr(new HWAddr(hwaddr));
Subnet4Ptr subnet = cfg->getCfgSubnets4()->getSubnet(subnet_id);
if (!subnet) {
isc_throw(BadValue, "Invalid subnet-id: No IPv4 subnet with subnet-id="
<< subnet_id << " currently configured.");
}
// Client-id is optional.
ClientIdPtr client_id;
if (lease_info->contains("client-id")) {
string txt = getString(lease_info, "client-id");
client_id = ClientId::fromText(txt);
}
// These parameters are optional. If not specified, we'll derive them from
// the current subnet configuration, if possible.
uint32_t valid_lft = 0;
if (lease_info->contains("valid-lft")) {
valid_lft = getUint32(lease_info, "valid-lft");
} else {
valid_lft = subnet->getValid();
}
/// Let's calculate client last transmission time (cltt). If expiration
/// timestamp is specified explicitly, we will use that. Note there are no
/// checks whether this is in the past. There may be valid cases when user
/// wants to insert expired leases, e.g. when migrating from one DHCP server
/// to another and wants to migrate the database as is, without disarding
/// any leases.
time_t cltt;
if (lease_info->contains("expire")) {
int64_t tmp = getUint32(lease_info, "expire");
cltt = static_cast<time_t>(tmp - valid_lft);
} else {
cltt = time(NULL);
}
bool fqdn_fwd = false;
if (lease_info->contains("fqdn-fwd")) {
fqdn_fwd = getBoolean(lease_info, "fqdn-fwd");
}
bool fqdn_rev = false;
if (lease_info->contains("fqdn-rev")) {
fqdn_rev = getBoolean(lease_info, "fqdn-rev");
}
string hostname;
if (lease_info->contains("hostname")) {
hostname = getString(lease_info, "hostname");
}
if (hostname.empty() && (fqdn_fwd || fqdn_rev)) {
isc_throw(BadValue, "No hostname specified and either forward or reverse"
" fqdn was set to true.");
}
uint32_t state = 0;
if (lease_info->contains("state")) {
state = getUint8(lease_info, "state");
}
// Let's fabricate some data and we're ready to go.
uint32_t t1 = subnet->getT1();
uint32_t t2 = subnet->getT2();
Lease4Ptr l(new Lease4(addr, hwaddr_ptr, client_id, valid_lft, t1, t2,
cltt, subnet_id,
fqdn_fwd, fqdn_rev, hostname));
l->state_ = state;
return (l);
}
Lease6Ptr
Lease6Parser::parse(ConstSrvConfigPtr& cfg,
const ConstElementPtr& lease_info) {
if (!lease_info) {
isc_throw(BadValue, "lease information missing");
}
// These are mandatory parameters.
IOAddress addr = getIOAddress(lease_info, "ip-address");
SubnetID subnet_id = getUint32(lease_info, "subnet-id");
if (addr.isV4()) {
isc_throw(BadValue, "Non-IPv6 address specified: " << addr);
}
// Not a most straightforward conversion, but it works.
string duid_txt = getString(lease_info, "duid");
DUID duid = DUID::fromText(duid_txt);
DuidPtr duid_ptr = DuidPtr(new DUID(duid));
Subnet6Ptr subnet = cfg->getCfgSubnets6()->getSubnet(subnet_id);
if (!subnet) {
isc_throw(BadValue, "Invalid subnet-id: No IPv6 subnet with subnet-id="
<< subnet_id << " currently configured.");
}
Lease::Type type = Lease::TYPE_NA;
uint8_t prefix_len = 128;
if (lease_info->contains("type")) {
string txt = getString(lease_info, "type");
if (txt == "IA_NA") {
type = Lease::TYPE_NA;
} else if (txt == "IA_TA") {
type = Lease::TYPE_TA;
} else if (txt == "IA_PD") {
type = Lease::TYPE_PD;
prefix_len = getUint8(lease_info, "prefix-len");
} else {
isc_throw(BadValue, "Incorrect lease type: " << txt << ", the only "
"supported values are: na, ta and pd");
}
}
uint32_t iaid = getUint32(lease_info, "iaid");
// Hw-address is optional in v6 leases.
HWAddrPtr hwaddr_ptr;
if (lease_info->contains("hw-address")) {
string hwaddr_txt = getString(lease_info, "hw-address");
HWAddr hwaddr = HWAddr::fromText(hwaddr_txt);
hwaddr_ptr = HWAddrPtr(new HWAddr(hwaddr));
}
// These parameters are optional. If not specified, we'll derive them
// from the current subnet configuration, if possible.
uint32_t valid_lft = 0;
if (lease_info->contains("valid-lft")) {
valid_lft = getUint32(lease_info, "valid-lft");
} else {
valid_lft = subnet->getValid();
}
// These parameters are optional. If not specified, we'll derive them
// from the current subnet configuration, if possible.
uint32_t pref_lft = 0;
if (lease_info->contains("preferred-lft")) {
pref_lft = getUint32(lease_info, "preferred-lft");
} else {
pref_lft = subnet->getValid();
}
/// Let's calculate client last transmission time (cltt). If expiration
/// timestamp is specified explicitly, we will use that. Note there are
/// no checks whether this is in the past. There may be valid cases when
/// user wants to insert expired leases, e.g. when migrating from one
/// DHCP server to another and wants to migrate the database as is, without
/// disarding any leases.
time_t cltt;
if (lease_info->contains("expire")) {
int64_t tmp = getUint32(lease_info, "expire");
cltt = static_cast<time_t>(tmp - valid_lft);
} else {
cltt = time(NULL);
}
bool fqdn_fwd = false;
if (lease_info->contains("fqdn-fwd")) {
fqdn_fwd = getBoolean(lease_info, "fqdn-fwd");
}
bool fqdn_rev = false;
if (lease_info->contains("fqdn-rev")) {
fqdn_rev = getBoolean(lease_info, "fqdn-rev");
}
string hostname;
if (lease_info->contains("hostname")) {
hostname = getString(lease_info, "hostname");
}
if (hostname.empty() && (fqdn_fwd || fqdn_rev)) {
isc_throw(BadValue, "No hostname specified and either forward or reverse"
" fqdn was set to true.");
}
uint32_t state = 0;
if (lease_info->contains("state")) {
state = getUint8(lease_info, "state");
}
// Let's fabricate some data and we're ready to go.
uint32_t t1 = subnet->getT1();
uint32_t t2 = subnet->getT2();
Lease6Ptr l(new Lease6(type, addr, duid_ptr, iaid, pref_lft, valid_lft, t1, t2,
subnet_id, fqdn_fwd, fqdn_rev, hostname,
hwaddr_ptr, prefix_len));
l->cltt_ = cltt;
l->state_ = state;
return (l);
}
};
};
// Copyright (C) 2014-2017 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2017 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
......@@ -10,28 +10,96 @@
#include <cc/data.h>
#include <cc/simple_parser.h>
#include <dhcpsrv/lease.h>
#include <dhcpsrv/srv_config.h>
namespace isc {
namespace lease_cmds {
/// @brief Parser for a single Lease information.
/// @brief Base class for Lease4 and Lease6 parsers
class LeaseParser : public isc::data::SimpleParser {
protected:
/// @brief Returns an address from JSON structure
///
/// @param scope a map the element will be searched at