2013-01-03 13:54:50 +01:00
|
|
|
// Copyright (C) 2012-2013 Internet Systems Consortium, Inc. ("ISC")
|
2012-09-21 19:01:14 +02:00
|
|
|
//
|
|
|
|
// Permission to use, copy, modify, and/or distribute this software for any
|
|
|
|
// purpose with or without fee is hereby granted, provided that the above
|
|
|
|
// copyright notice and this permission notice appear in all copies.
|
|
|
|
//
|
|
|
|
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
|
|
|
|
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
|
|
|
// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
|
|
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
|
|
|
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
|
|
|
|
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
|
|
// PERFORMANCE OF THIS SOFTWARE.
|
|
|
|
|
|
|
|
#include <asiolink/io_address.h>
|
2013-01-23 12:00:26 +01:00
|
|
|
#include <dhcp/option_space.h>
|
2012-11-16 11:19:19 +00:00
|
|
|
#include <dhcpsrv/addr_utilities.h>
|
|
|
|
#include <dhcpsrv/subnet.h>
|
|
|
|
|
2012-10-30 18:07:53 +01:00
|
|
|
#include <sstream>
|
2012-09-21 19:01:14 +02:00
|
|
|
|
|
|
|
using namespace isc::asiolink;
|
|
|
|
|
|
|
|
namespace isc {
|
|
|
|
namespace dhcp {
|
|
|
|
|
|
|
|
Subnet::Subnet(const isc::asiolink::IOAddress& prefix, uint8_t len,
|
|
|
|
const Triplet<uint32_t>& t1,
|
|
|
|
const Triplet<uint32_t>& t2,
|
|
|
|
const Triplet<uint32_t>& valid_lifetime)
|
|
|
|
:id_(getNextID()), prefix_(prefix), prefix_len_(len), t1_(t1),
|
2012-10-17 18:05:25 +02:00
|
|
|
t2_(t2), valid_(valid_lifetime),
|
2013-09-10 20:39:04 +02:00
|
|
|
last_allocated_ia_(lastAddrInPrefix(prefix, len)),
|
|
|
|
last_allocated_ta_(lastAddrInPrefix(prefix, len)),
|
|
|
|
last_allocated_pd_(lastAddrInPrefix(prefix, len)) {
|
2012-12-13 19:33:12 +01:00
|
|
|
if ((prefix.isV6() && len > 128) ||
|
|
|
|
(prefix.isV4() && len > 32)) {
|
2013-09-16 12:46:12 +02:00
|
|
|
isc_throw(BadValue,
|
2013-05-06 11:45:27 -04:00
|
|
|
"Invalid prefix length specified for subnet: " << len);
|
2012-09-21 19:01:14 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-09-16 12:46:12 +02:00
|
|
|
bool
|
2013-05-06 11:45:27 -04:00
|
|
|
Subnet::inRange(const isc::asiolink::IOAddress& addr) const {
|
2012-09-21 19:01:14 +02:00
|
|
|
IOAddress first = firstAddrInPrefix(prefix_, prefix_len_);
|
|
|
|
IOAddress last = lastAddrInPrefix(prefix_, prefix_len_);
|
|
|
|
|
|
|
|
return ((first <= addr) && (addr <= last));
|
|
|
|
}
|
|
|
|
|
2012-10-16 17:09:47 +02:00
|
|
|
void
|
2013-01-16 11:38:25 +01:00
|
|
|
Subnet::addOption(const OptionPtr& option, bool persistent,
|
2013-01-03 13:54:50 +01:00
|
|
|
const std::string& option_space) {
|
2013-01-22 18:40:55 +01:00
|
|
|
// Check that the option space name is valid.
|
|
|
|
if (!OptionSpace::validateName(option_space)) {
|
|
|
|
isc_throw(isc::BadValue, "invalid option space name: '"
|
|
|
|
<< option_space << "'");
|
2013-01-03 13:54:50 +01:00
|
|
|
}
|
2012-10-16 17:09:47 +02:00
|
|
|
validateOption(option);
|
2013-01-07 22:58:42 +01:00
|
|
|
|
2013-01-09 13:18:15 +01:00
|
|
|
// Actually add new option descriptor.
|
|
|
|
option_spaces_.addItem(OptionDescriptor(option, persistent), option_space);
|
2012-10-16 17:09:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Subnet::delOptions() {
|
2013-01-09 13:18:15 +01:00
|
|
|
option_spaces_.clearItems();
|
2013-01-03 13:54:50 +01:00
|
|
|
}
|
|
|
|
|
2013-01-07 22:58:42 +01:00
|
|
|
Subnet::OptionContainerPtr
|
|
|
|
Subnet::getOptionDescriptors(const std::string& option_space) const {
|
2013-01-09 13:18:15 +01:00
|
|
|
return (option_spaces_.getItems(option_space));
|
2012-10-16 17:09:47 +02:00
|
|
|
}
|
|
|
|
|
2013-01-03 14:54:00 +01:00
|
|
|
Subnet::OptionDescriptor
|
2013-01-07 19:51:06 +01:00
|
|
|
Subnet::getOptionDescriptor(const std::string& option_space,
|
|
|
|
const uint16_t option_code) {
|
2013-01-07 22:58:42 +01:00
|
|
|
OptionContainerPtr options = getOptionDescriptors(option_space);
|
|
|
|
if (!options || options->empty()) {
|
2013-01-03 14:54:00 +01:00
|
|
|
return (OptionDescriptor(false));
|
|
|
|
}
|
2013-01-07 22:58:42 +01:00
|
|
|
const OptionContainerTypeIndex& idx = options->get<1>();
|
2013-01-03 14:54:00 +01:00
|
|
|
const OptionContainerTypeRange& range = idx.equal_range(option_code);
|
|
|
|
if (std::distance(range.first, range.second) == 0) {
|
|
|
|
return (OptionDescriptor(false));
|
|
|
|
}
|
|
|
|
|
|
|
|
return (*range.first);
|
2012-10-16 17:09:47 +02:00
|
|
|
}
|
|
|
|
|
2013-10-22 12:27:07 +02:00
|
|
|
void Subnet::addVendorOption(const OptionPtr& option, bool persistent,
|
|
|
|
uint32_t vendor_id){
|
|
|
|
|
|
|
|
validateOption(option);
|
|
|
|
|
|
|
|
vendor_option_spaces_.addItem(OptionDescriptor(option, persistent), vendor_id);
|
|
|
|
}
|
|
|
|
|
|
|
|
Subnet::OptionContainerPtr
|
|
|
|
Subnet::getVendorOptionDescriptors(uint32_t vendor_id) const {
|
|
|
|
return (vendor_option_spaces_.getItems(vendor_id));
|
|
|
|
}
|
|
|
|
|
|
|
|
Subnet::OptionDescriptor
|
|
|
|
Subnet::getVendorOptionDescriptor(uint32_t vendor_id, uint16_t option_code) {
|
|
|
|
OptionContainerPtr options = getVendorOptionDescriptors(vendor_id);
|
|
|
|
if (!options || options->empty()) {
|
|
|
|
return (OptionDescriptor(false));
|
|
|
|
}
|
|
|
|
const OptionContainerTypeIndex& idx = options->get<1>();
|
|
|
|
const OptionContainerTypeRange& range = idx.equal_range(option_code);
|
|
|
|
if (std::distance(range.first, range.second) == 0) {
|
|
|
|
return (OptionDescriptor(false));
|
|
|
|
}
|
|
|
|
|
|
|
|
return (*range.first);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Subnet::delVendorOptions() {
|
|
|
|
vendor_option_spaces_.clearItems();
|
|
|
|
}
|
|
|
|
|
2013-09-18 15:44:48 +02:00
|
|
|
isc::asiolink::IOAddress Subnet::getLastAllocated(Lease::Type type) const {
|
2013-09-16 14:35:46 +02:00
|
|
|
// check if the type is valid (and throw if it isn't)
|
|
|
|
checkType(type);
|
|
|
|
|
2013-09-10 20:39:04 +02:00
|
|
|
switch (type) {
|
2013-09-18 15:44:48 +02:00
|
|
|
case Lease::TYPE_V4:
|
|
|
|
case Lease::TYPE_NA:
|
2013-09-10 20:39:04 +02:00
|
|
|
return last_allocated_ia_;
|
2013-09-18 15:44:48 +02:00
|
|
|
case Lease::TYPE_TA:
|
2013-09-10 20:39:04 +02:00
|
|
|
return last_allocated_ta_;
|
2013-09-18 15:44:48 +02:00
|
|
|
case Lease::TYPE_PD:
|
2013-09-10 20:39:04 +02:00
|
|
|
return last_allocated_pd_;
|
|
|
|
default:
|
|
|
|
isc_throw(BadValue, "Pool type " << type << " not supported");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-09-18 15:44:48 +02:00
|
|
|
void Subnet::setLastAllocated(Lease::Type type,
|
2013-09-16 13:55:18 +02:00
|
|
|
const isc::asiolink::IOAddress& addr) {
|
|
|
|
|
|
|
|
// check if the type is valid (and throw if it isn't)
|
|
|
|
checkType(type);
|
|
|
|
|
2013-09-10 20:39:04 +02:00
|
|
|
switch (type) {
|
2013-09-18 15:44:48 +02:00
|
|
|
case Lease::TYPE_V4:
|
|
|
|
case Lease::TYPE_NA:
|
2013-09-10 20:39:04 +02:00
|
|
|
last_allocated_ia_ = addr;
|
|
|
|
return;
|
2013-09-18 15:44:48 +02:00
|
|
|
case Lease::TYPE_TA:
|
2013-09-10 20:39:04 +02:00
|
|
|
last_allocated_ta_ = addr;
|
|
|
|
return;
|
2013-09-18 15:44:48 +02:00
|
|
|
case Lease::TYPE_PD:
|
2013-09-10 20:39:04 +02:00
|
|
|
last_allocated_pd_ = addr;
|
|
|
|
return;
|
|
|
|
default:
|
|
|
|
isc_throw(BadValue, "Pool type " << type << " not supported");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-09-16 12:46:12 +02:00
|
|
|
std::string
|
2013-05-06 11:45:27 -04:00
|
|
|
Subnet::toText() const {
|
2012-10-30 18:07:53 +01:00
|
|
|
std::stringstream tmp;
|
|
|
|
tmp << prefix_.toText() << "/" << static_cast<unsigned int>(prefix_len_);
|
|
|
|
return (tmp.str());
|
|
|
|
}
|
|
|
|
|
2013-09-18 15:44:48 +02:00
|
|
|
void Subnet4::checkType(Lease::Type type) const {
|
|
|
|
if (type != Lease::TYPE_V4) {
|
2013-09-16 13:55:18 +02:00
|
|
|
isc_throw(BadValue, "Only TYPE_V4 is allowed for Subnet4");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-10-04 14:43:43 +02:00
|
|
|
Subnet4::Subnet4(const isc::asiolink::IOAddress& prefix, uint8_t length,
|
|
|
|
const Triplet<uint32_t>& t1,
|
|
|
|
const Triplet<uint32_t>& t2,
|
|
|
|
const Triplet<uint32_t>& valid_lifetime)
|
2013-10-11 20:02:57 +02:00
|
|
|
:Subnet(prefix, length, t1, t2, valid_lifetime),
|
|
|
|
siaddr_(IOAddress("0.0.0.0")) {
|
2012-12-13 19:33:12 +01:00
|
|
|
if (!prefix.isV4()) {
|
2012-10-04 14:43:43 +02:00
|
|
|
isc_throw(BadValue, "Non IPv4 prefix " << prefix.toText()
|
|
|
|
<< " specified in subnet4");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-10-11 20:02:57 +02:00
|
|
|
void Subnet4::setSiaddr(const isc::asiolink::IOAddress& siaddr) {
|
|
|
|
if (!siaddr.isV4()) {
|
2013-10-17 19:10:50 +02:00
|
|
|
isc_throw(BadValue, "Can't set siaddr to non-IPv4 address "
|
2013-10-11 20:02:57 +02:00
|
|
|
<< siaddr.toText());
|
|
|
|
}
|
|
|
|
siaddr_ = siaddr;
|
|
|
|
}
|
|
|
|
|
|
|
|
isc::asiolink::IOAddress Subnet4::getSiaddr() const {
|
|
|
|
return (siaddr_);
|
|
|
|
}
|
|
|
|
|
2013-09-18 15:44:48 +02:00
|
|
|
const PoolCollection& Subnet::getPools(Lease::Type type) const {
|
2013-09-16 14:35:46 +02:00
|
|
|
// check if the type is valid (and throw if it isn't)
|
|
|
|
checkType(type);
|
|
|
|
|
2013-09-16 12:46:12 +02:00
|
|
|
switch (type) {
|
2013-09-18 15:44:48 +02:00
|
|
|
case Lease::TYPE_V4:
|
|
|
|
case Lease::TYPE_NA:
|
2013-09-16 12:46:12 +02:00
|
|
|
return (pools_);
|
2013-09-18 15:44:48 +02:00
|
|
|
case Lease::TYPE_TA:
|
2013-09-16 12:46:12 +02:00
|
|
|
return (pools_ta_);
|
2013-09-18 15:44:48 +02:00
|
|
|
case Lease::TYPE_PD:
|
2013-09-16 12:46:12 +02:00
|
|
|
return (pools_pd_);
|
|
|
|
default:
|
2013-10-02 20:31:23 +02:00
|
|
|
isc_throw(BadValue, "Unsupported pool type: "
|
|
|
|
<< static_cast<int>(type));
|
2012-10-04 14:43:43 +02:00
|
|
|
}
|
2013-09-16 12:46:12 +02:00
|
|
|
}
|
2012-10-04 14:43:43 +02:00
|
|
|
|
2013-10-03 16:14:36 +02:00
|
|
|
PoolCollection& Subnet::getPoolsWritable(Lease::Type type) {
|
2013-09-20 15:08:22 +02:00
|
|
|
// check if the type is valid (and throw if it isn't)
|
|
|
|
checkType(type);
|
2012-10-04 14:43:43 +02:00
|
|
|
|
2013-09-16 12:46:12 +02:00
|
|
|
switch (type) {
|
2013-09-18 15:44:48 +02:00
|
|
|
case Lease::TYPE_V4:
|
|
|
|
case Lease::TYPE_NA:
|
2013-09-19 19:38:05 +02:00
|
|
|
return (pools_);
|
2013-09-18 15:44:48 +02:00
|
|
|
case Lease::TYPE_TA:
|
2013-09-20 15:08:22 +02:00
|
|
|
return (pools_ta_);
|
2013-09-18 15:44:48 +02:00
|
|
|
case Lease::TYPE_PD:
|
2013-09-19 19:38:05 +02:00
|
|
|
return (pools_pd_);
|
2013-09-16 12:46:12 +02:00
|
|
|
default:
|
2013-09-19 19:38:05 +02:00
|
|
|
isc_throw(BadValue, "Invalid pool type specified: "
|
|
|
|
<< static_cast<int>(type));
|
2013-09-16 12:46:12 +02:00
|
|
|
}
|
2013-09-19 19:38:05 +02:00
|
|
|
}
|
|
|
|
|
2013-10-02 20:31:23 +02:00
|
|
|
const PoolPtr Subnet::getPool(Lease::Type type, const isc::asiolink::IOAddress& hint,
|
|
|
|
bool anypool /* true */) const {
|
2013-09-19 19:38:05 +02:00
|
|
|
// check if the type is valid (and throw if it isn't)
|
|
|
|
checkType(type);
|
|
|
|
|
|
|
|
const PoolCollection& pools = getPools(type);
|
2012-12-20 21:57:55 +01:00
|
|
|
|
|
|
|
PoolPtr candidate;
|
2013-09-19 19:38:05 +02:00
|
|
|
for (PoolCollection::const_iterator pool = pools.begin();
|
|
|
|
pool != pools.end(); ++pool) {
|
2012-10-04 14:43:43 +02:00
|
|
|
|
2013-09-16 12:46:12 +02:00
|
|
|
// if we won't find anything better, then let's just use the first pool
|
2013-09-19 17:06:03 +02:00
|
|
|
if (anypool && !candidate) {
|
2012-10-04 14:43:43 +02:00
|
|
|
candidate = *pool;
|
|
|
|
}
|
|
|
|
|
2013-09-16 12:46:12 +02:00
|
|
|
// if the client provided a pool and there's a pool that hint is valid
|
2013-05-06 11:45:27 -04:00
|
|
|
// in, then let's use that pool
|
2012-10-04 14:43:43 +02:00
|
|
|
if ((*pool)->inRange(hint)) {
|
|
|
|
return (*pool);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return (candidate);
|
|
|
|
}
|
|
|
|
|
2013-09-16 12:46:12 +02:00
|
|
|
void
|
|
|
|
Subnet::addPool(const PoolPtr& pool) {
|
|
|
|
IOAddress first_addr = pool->getFirstAddress();
|
|
|
|
IOAddress last_addr = pool->getLastAddress();
|
|
|
|
|
|
|
|
if (!inRange(first_addr) || !inRange(last_addr)) {
|
|
|
|
isc_throw(BadValue, "Pool (" << first_addr.toText() << "-"
|
|
|
|
<< last_addr.toText()
|
|
|
|
<< " does not belong in this (" << prefix_.toText() << "/"
|
|
|
|
<< static_cast<int>(prefix_len_) << ") subnet");
|
|
|
|
}
|
|
|
|
|
|
|
|
/// @todo: Check that pools do not overlap
|
|
|
|
|
2013-09-16 14:35:46 +02:00
|
|
|
// check if the type is valid (and throw if it isn't)
|
|
|
|
checkType(pool->getType());
|
|
|
|
|
2013-09-19 19:38:05 +02:00
|
|
|
// Add the pool to the appropriate pools collection
|
2013-10-03 16:14:36 +02:00
|
|
|
getPoolsWritable(pool->getType()).push_back(pool);
|
2013-09-16 12:46:12 +02:00
|
|
|
}
|
|
|
|
|
2013-09-19 18:35:32 +02:00
|
|
|
void
|
|
|
|
Subnet::delPools(Lease::Type type) {
|
2013-10-03 16:14:36 +02:00
|
|
|
getPoolsWritable(type).clear();
|
2013-09-19 18:35:32 +02:00
|
|
|
}
|
|
|
|
|
2013-09-16 12:46:12 +02:00
|
|
|
void
|
2013-05-06 11:45:27 -04:00
|
|
|
Subnet::setIface(const std::string& iface_name) {
|
2013-05-01 07:39:08 -04:00
|
|
|
iface_ = iface_name;
|
|
|
|
}
|
|
|
|
|
2013-09-16 12:46:12 +02:00
|
|
|
std::string
|
2013-05-06 11:45:27 -04:00
|
|
|
Subnet::getIface() const {
|
2013-05-01 07:39:08 -04:00
|
|
|
return (iface_);
|
|
|
|
}
|
|
|
|
|
2012-10-16 17:09:47 +02:00
|
|
|
void
|
2012-10-24 10:57:39 +02:00
|
|
|
Subnet4::validateOption(const OptionPtr& option) const {
|
2012-10-16 17:09:47 +02:00
|
|
|
if (!option) {
|
2013-09-16 12:46:12 +02:00
|
|
|
isc_throw(isc::BadValue,
|
2013-05-06 11:45:27 -04:00
|
|
|
"option configured for subnet must not be NULL");
|
2012-10-16 17:09:47 +02:00
|
|
|
} else if (option->getUniverse() != Option::V4) {
|
2013-09-16 12:46:12 +02:00
|
|
|
isc_throw(isc::BadValue,
|
2013-05-06 11:45:27 -04:00
|
|
|
"expected V4 option to be added to the subnet");
|
2012-10-16 17:09:47 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-09-16 12:46:12 +02:00
|
|
|
bool
|
2013-09-19 19:38:05 +02:00
|
|
|
Subnet::inPool(Lease::Type type, const isc::asiolink::IOAddress& addr) const {
|
2012-10-24 15:05:09 +02:00
|
|
|
|
|
|
|
// Let's start with checking if it even belongs to that subnet.
|
|
|
|
if (!inRange(addr)) {
|
|
|
|
return (false);
|
|
|
|
}
|
|
|
|
|
2013-09-19 19:38:05 +02:00
|
|
|
const PoolCollection& pools = getPools(type);
|
|
|
|
|
|
|
|
for (PoolCollection::const_iterator pool = pools.begin();
|
|
|
|
pool != pools.end(); ++pool) {
|
2012-10-24 15:05:09 +02:00
|
|
|
if ((*pool)->inRange(addr)) {
|
|
|
|
return (true);
|
|
|
|
}
|
|
|
|
}
|
2013-05-06 11:45:27 -04:00
|
|
|
// There's no pool that address belongs to
|
2012-10-24 15:05:09 +02:00
|
|
|
return (false);
|
|
|
|
}
|
|
|
|
|
2012-09-21 19:01:14 +02:00
|
|
|
Subnet6::Subnet6(const isc::asiolink::IOAddress& prefix, uint8_t length,
|
|
|
|
const Triplet<uint32_t>& t1,
|
|
|
|
const Triplet<uint32_t>& t2,
|
|
|
|
const Triplet<uint32_t>& preferred_lifetime,
|
|
|
|
const Triplet<uint32_t>& valid_lifetime)
|
|
|
|
:Subnet(prefix, length, t1, t2, valid_lifetime),
|
|
|
|
preferred_(preferred_lifetime){
|
2012-12-13 19:33:12 +01:00
|
|
|
if (!prefix.isV6()) {
|
2012-09-21 19:01:14 +02:00
|
|
|
isc_throw(BadValue, "Non IPv6 prefix " << prefix.toText()
|
|
|
|
<< " specified in subnet6");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-09-18 15:44:48 +02:00
|
|
|
void Subnet6::checkType(Lease::Type type) const {
|
|
|
|
if ( (type != Lease::TYPE_NA) && (type != Lease::TYPE_TA) &&
|
|
|
|
(type != Lease::TYPE_PD)) {
|
|
|
|
isc_throw(BadValue, "Invalid Pool type: " << Lease::typeToText(type)
|
|
|
|
<< "(" << static_cast<int>(type)
|
|
|
|
<< "), must be TYPE_NA, TYPE_TA or TYPE_PD for Subnet6");
|
2013-09-16 13:55:18 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-10-16 17:09:47 +02:00
|
|
|
void
|
2012-10-24 10:57:39 +02:00
|
|
|
Subnet6::validateOption(const OptionPtr& option) const {
|
2012-10-16 17:09:47 +02:00
|
|
|
if (!option) {
|
2013-09-16 12:46:12 +02:00
|
|
|
isc_throw(isc::BadValue,
|
2013-05-06 11:45:27 -04:00
|
|
|
"option configured for subnet must not be NULL");
|
2012-10-16 17:09:47 +02:00
|
|
|
} else if (option->getUniverse() != Option::V6) {
|
2013-09-16 12:46:12 +02:00
|
|
|
isc_throw(isc::BadValue,
|
2013-05-06 11:45:27 -04:00
|
|
|
"expected V6 option to be added to the subnet");
|
2012-10-16 17:09:47 +02:00
|
|
|
}
|
|
|
|
}
|
2012-10-29 13:18:27 +01:00
|
|
|
|
2012-09-21 19:01:14 +02:00
|
|
|
} // end of isc::dhcp namespace
|
|
|
|
} // end of isc namespace
|