2
0
mirror of https://gitlab.isc.org/isc-projects/kea synced 2025-08-31 05:55:28 +00:00

Merge branch 'master' into trac2276

This commit is contained in:
Mukund Sivaraman
2012-10-02 19:06:11 +05:30
22 changed files with 1591 additions and 27 deletions

View File

@@ -1,3 +1,10 @@
484. [func] tomek
A new library (libb10-dhcpsrv) has been created. At present, it
only holds the code for the DHCP Configuration Manager. Currently
this object only supports basic configuration storage for the DHCPv6
server, but that capability will be expanded.
(Trac #2238, git 6f29861b92742da34be9ae76968e82222b5bfd7d)
bind10-devel-20120927 released on September 27, 2012
483. [func] marcin

View File

@@ -131,7 +131,7 @@ public:
return equals(other);
}
// \brief Compare addresses for inequality
/// \brief Compare addresses for inequality
///
/// \param other Address to compare against.
///
@@ -140,7 +140,58 @@ public:
return (!equals(other));
}
// \brief Compare addresses for inequality
/// \brief Checks if one address is smaller than the other
///
/// \param other Address to compare against.
///
/// \return true if this address is smaller than the other address.
///
/// It is useful for comparing which address is bigger.
/// Operations within one protocol family are obvious.
/// Comparisons between v4 and v6 will allways return v4
/// being smaller. This follows boost::asio::ip implementation
bool lessThan(const IOAddress& other) const {
if (this->getFamily() == other.getFamily()) {
if (this->getFamily() == AF_INET6) {
return (this->asio_address_.to_v6() < other.asio_address_.to_v6());
} else {
return (this->asio_address_.to_v4() < other.asio_address_.to_v4());
}
}
return (this->getFamily() < other.getFamily());
}
/// \brief Checks if one address is smaller or equal than the other
///
/// \param other Address to compare against.
///
/// \return true if this address is smaller than the other address.
bool smallerEqual(const IOAddress& other) const {
if (equals(other)) {
return (true);
}
return (lessThan(other));
}
/// \brief Checks if one address is smaller than the other
///
/// \param other Address to compare against.
///
/// See \ref smaller_than method for details.
bool operator<(const IOAddress& other) const {
return (lessThan(other));
}
/// \brief Checks if one address is smaller or equal than the other
///
/// \param other Address to compare against.
///
/// See \ref smaller_equal method for details.
bool operator<=(const IOAddress& other) const {
return (smallerEqual(other));
}
/// \brief Compare addresses for inequality
///
/// \param other Address to compare against.
///

View File

@@ -99,3 +99,35 @@ TEST(IOAddressTest, uint32) {
EXPECT_EQ(addr3.toText(), "192.0.2.5");
}
TEST(IOAddressTest, lessThanEqual) {
IOAddress addr1("192.0.2.5");
IOAddress addr2("192.0.2.6");
IOAddress addr3("0.0.0.0");
IOAddress addr4("::");
IOAddress addr5("2001:db8::1");
IOAddress addr6("2001:db8::1:0");
IOAddress addr7("2001:db8::1:0"); // the same as 6
// v4 comparisons
EXPECT_TRUE(addr1 < addr2);
EXPECT_FALSE(addr2 < addr1);
EXPECT_FALSE(addr2 <= addr1);
EXPECT_TRUE(addr3 < addr1);
EXPECT_TRUE(addr3 < addr2);
EXPECT_TRUE(addr3 <= addr2);
// v6 comparisons
EXPECT_TRUE(addr4 < addr5);
EXPECT_TRUE(addr5 < addr6);
EXPECT_FALSE(addr6 < addr5);
EXPECT_FALSE(addr6 <= addr5);
// v4 to v6 - v4 should always be smaller
EXPECT_TRUE(addr1 < addr4);
EXPECT_TRUE(addr3 < addr4);
EXPECT_TRUE(addr2 < addr5);
EXPECT_TRUE(addr6 <= addr7);
}

View File

@@ -20,6 +20,8 @@
#include <exceptions/exceptions.h>
#include <dns/name.h>
#include <datasrc/sqlite3_accessor.h>
#include <datasrc/logger.h>
#include <datasrc/data_source.h>
@@ -84,8 +86,13 @@ const char* const text_statements[NUM_STATEMENTS] = {
"SELECT id FROM zones WHERE name=?1 AND rdclass = ?2", // ZONE
"SELECT rdtype, ttl, sigtype, rdata FROM records " // ANY
"WHERE zone_id=?1 AND name=?2",
"SELECT rdtype, ttl, sigtype, rdata " // ANY_SUB
"FROM records WHERE zone_id=?1 AND name LIKE (\"%.\" || ?2)",
// ANY_SUB:
// This query returns records in the specified zone for the domain
// matching the passed name, and its sub-domains.
"SELECT rdtype, ttl, sigtype, rdata "
"FROM records WHERE zone_id=?1 AND rname LIKE ?2",
"BEGIN", // BEGIN
"COMMIT", // COMMIT
"ROLLBACK", // ROLLBACK
@@ -660,17 +667,27 @@ public:
statement_(NULL),
name_(name)
{
// Choose the statement text depending on the query type
const char* statement(NULL);
// Choose the statement text depending on the query type, and
// prepare a statement to get data from it.
switch (qtype) {
case QT_ANY:
statement = text_statements[ANY];
statement_ = prepare(accessor->dbparameters_->db_,
text_statements[ANY]);
bindZoneId(id);
bindName(name_);
break;
case QT_SUBDOMAINS:
statement = text_statements[ANY_SUB];
statement_ = prepare(accessor->dbparameters_->db_,
text_statements[ANY_SUB]);
bindZoneId(id);
// Done once, this should not be very inefficient.
bindName(isc::dns::Name(name_).reverse().toText() + "%");
break;
case QT_NSEC3:
statement = text_statements[NSEC3];
statement_ = prepare(accessor->dbparameters_->db_,
text_statements[NSEC3]);
bindZoneId(id);
bindName(name_);
break;
default:
// Can Not Happen - there isn't any other type of query
@@ -680,11 +697,6 @@ public:
"Invalid qtype passed - unreachable code branch "
"reached");
}
// We create the statement now and then just keep getting data from it
statement_ = prepare(accessor->dbparameters_->db_, statement);
bindZoneId(id);
bindName(name_);
}
bool getNext(std::string (&data)[COLUMN_COUNT]) {

View File

@@ -13,7 +13,7 @@ AM_CXXFLAGS += $(WARNING_NO_MISSING_FIELD_INITIALIZERS_CFLAG)
CLEANFILES = *.gcno *.gcda
lib_LTLIBRARIES = libb10-dhcp++.la
lib_LTLIBRARIES = libb10-dhcp++.la libb10-dhcpsrv.la
libb10_dhcp___la_SOURCES =
libb10_dhcp___la_SOURCES += libdhcp++.cc libdhcp++.h
libb10_dhcp___la_SOURCES += iface_mgr.cc iface_mgr.h
@@ -29,8 +29,18 @@ libb10_dhcp___la_SOURCES += dhcp6.h dhcp4.h
libb10_dhcp___la_SOURCES += pkt6.cc pkt6.h
libb10_dhcp___la_SOURCES += pkt4.cc pkt4.h
libb10_dhcpsrv_la_SOURCES = cfgmgr.cc cfgmgr.h
libb10_dhcpsrv_la_SOURCES += pool.cc pool.h
libb10_dhcpsrv_la_SOURCES += subnet.cc subnet.h
libb10_dhcpsrv_la_SOURCES += triplet.h
libb10_dhcpsrv_la_SOURCES += addr_utilities.cc addr_utilities.h
libb10_dhcpsrv_la_CXXFLAGS = $(AM_CXXFLAGS)
libb10_dhcpsrv_la_CPPFLAGS = $(AM_CPPFLAGS) $(LOG4CPLUS_INCLUDES)
libb10_dhcpsrv_la_LIBADD = $(top_builddir)/src/lib/asiolink/libb10-asiolink.la
libb10_dhcpsrv_la_LIBADD += $(top_builddir)/src/lib/util/libb10-util.la
libb10_dhcpsrv_la_LDFLAGS = -no-undefined -version-info 2:0:0
EXTRA_DIST = README
#EXTRA_DIST += log_messages.mes
libb10_dhcp___la_CXXFLAGS = $(AM_CXXFLAGS)
libb10_dhcp___la_CPPFLAGS = $(AM_CPPFLAGS) $(LOG4CPLUS_INCLUDES)

View File

@@ -1,11 +1,9 @@
This directory holds implementation for libdhcp++.
This directory holds implementation for DHCP libraries:
libdhcp++ - this is a generic purpose DHCP library. Please be careful
what is put here. It is going to be shared by various servers (the "regular"
one and the embedded as well), clients, relays and performance tools.
Basic Ideas
===========
libdhcpsrv - Server specific code goes in here. It will be used by
dhcp4 and dhcp6 server.
Notes
=====
This work just begun. Don't expect to see much useful code here.
We are working on it.

View File

@@ -0,0 +1,96 @@
// Copyright (C) 2012 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
// 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 <string.h>
#include <dhcp/addr_utilities.h>
using namespace isc::asiolink;
namespace isc {
namespace dhcp {
isc::asiolink::IOAddress firstAddrInPrefix(const isc::asiolink::IOAddress& prefix,
uint8_t len) {
const static uint8_t bitMask[]= { 0, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff };
uint8_t packed[V6ADDRESS_LEN];
// First we copy the whole address as 16 bytes.
memcpy(packed, prefix.getAddress().to_v6().to_bytes().data(), 16);
// If the length is divisible by 8, it is simple. We just zero out the host
// part. Otherwise we need to handle the byte that has to be partially
// zeroed.
if (len % 8 != 0) {
// Get the appropriate mask. It has relevant bits (those that should
// stay) set and irrelevant (those that should be wiped) cleared.
uint8_t mask = bitMask[len % 8];
// Let's leave only whatever the mask says should not be cleared.
packed[len / 8] = packed[len / 8] & mask;
// Since we have just dealt with this byte, let's move the prefix length
// to the beginning of the next byte (len is expressed in bits).
len = (len / 8 + 1) * 8;
}
// Clear out the remaining bits.
for (int i = len / 8; i < sizeof(packed); ++i) {
packed[i] = 0x0;
}
// Finally, let's wrap this into nice and easy IOAddress object.
return (isc::asiolink::IOAddress::from_bytes(AF_INET6, packed));
}
isc::asiolink::IOAddress lastAddrInPrefix(const isc::asiolink::IOAddress& prefix,
uint8_t len) {
const static uint8_t bitMask[]= { 0, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff };
uint8_t packed[V6ADDRESS_LEN];
// First we copy the whole address as 16 bytes.
memcpy(packed, prefix.getAddress().to_v6().to_bytes().data(), 16);
// if the length is divisible by 8, it is simple. We just fill the host part
// with ones. Otherwise we need to handle the byte that has to be partially
// zeroed.
if (len % 8 != 0) {
// Get the appropriate mask. It has relevant bits (those that should
// stay) set and irrelevant (those that should be set to 1) cleared.
uint8_t mask = bitMask[len % 8];
// Let's set those irrelevant bits with 1. It would be perhaps
// easier to not use negation here and invert bitMask content. However,
// with this approach, we can use the same mask in first and last
// address calculations.
packed[len / 8] = packed[len / 8] | ~mask;
// Since we have just dealt with this byte, let's move the prefix length
// to the beginning of the next byte (len is expressed in bits).
len = (len / 8 + 1) * 8;
}
// Finally set remaining bits to 1.
for (int i = len / 8; i < sizeof(packed); ++i) {
packed[i] = 0xff;
}
// Finally, let's wrap this into nice and easy IOAddress object.
return (isc::asiolink::IOAddress::from_bytes(AF_INET6, packed));
}
};
};

View File

@@ -0,0 +1,53 @@
// Copyright (C) 2012 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
// 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>
namespace isc {
namespace dhcp {
/// This code is based on similar code from the Dibbler project. I, Tomasz Mrugalski,
/// as a sole creator of that code hereby release it under BSD license for the benefit
/// of the BIND10 project.
/// @brief returns a first address in a given prefix
///
/// Example: For 2001:db8:1::deaf:beef and length /120 the function will return
/// 2001:db8:1::dead:be00. See also @ref lastAddrInPrefix.
///
/// @todo It currently works for v6 only and will throw if v4 address is passed.
///
/// @param prefix and address that belongs to a prefix
/// @param len prefix length
///
/// @return first address from a prefix
isc::asiolink::IOAddress firstAddrInPrefix(const isc::asiolink::IOAddress& prefix,
uint8_t len);
/// @brief returns a last address in a given prefix
///
/// Example: For 2001:db8:1::deaf:beef and length /112 the function will return
/// 2001:db8:1::dead:ffff. See also @ref firstAddrInPrefix.
///
/// @todo It currently works for v6 only and will throw if v4 address is passed.
///
/// @param prefix and address that belongs to a prefix
/// @param len prefix length
///
/// @return first address from a prefix
isc::asiolink::IOAddress lastAddrInPrefix(const isc::asiolink::IOAddress& prefix,
uint8_t len);
};
};

78
src/lib/dhcp/cfgmgr.cc Normal file
View File

@@ -0,0 +1,78 @@
// Copyright (C) 2012 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
// 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>
#include <dhcp/cfgmgr.h>
using namespace isc::asiolink;
using namespace isc::util;
namespace isc {
namespace dhcp {
CfgMgr&
CfgMgr::instance() {
static CfgMgr cfg_mgr;
return (cfg_mgr);
}
Subnet6Ptr
CfgMgr::getSubnet6(const isc::asiolink::IOAddress& hint) {
// If there's only one subnet configured, let's just use it
// The idea is to keep small deployments easy. In a small network - one
// router that also runs DHCPv6 server. Users specifies a single pool and
// expects it to just work. Without this, the server would complain that it
// doesn't have IP address on its interfaces that matches that
// configuration. Such requirement makes sense in IPv4, but not in IPv6.
// The server does not need to have a global address (using just link-local
// is ok for DHCPv6 server) from the pool it serves.
if (subnets6_.size() == 1) {
return (subnets6_[0]);
}
// If there is more than one, we need to choose the proper one
for (Subnet6Collection::iterator subnet = subnets6_.begin();
subnet != subnets6_.end(); ++subnet) {
if ((*subnet)->inRange(hint)) {
return (*subnet);
}
}
// sorry, we don't support that subnet
return (Subnet6Ptr());
}
Subnet6Ptr CfgMgr::getSubnet6(OptionPtr /*interfaceId*/) {
/// @todo: Implement get subnet6 by interface-id (for relayed traffic)
isc_throw(NotImplemented, "Relayed DHCPv6 traffic is not supported yet.");
}
void CfgMgr::addSubnet6(const Subnet6Ptr& subnet) {
/// @todo: Check that this new subnet does not cross boundaries of any
/// other already defined subnet.
subnets6_.push_back(subnet);
}
CfgMgr::CfgMgr() {
}
CfgMgr::~CfgMgr() {
}
}; // end of isc::dhcp namespace
}; // end of isc namespace

126
src/lib/dhcp/cfgmgr.h Normal file
View File

@@ -0,0 +1,126 @@
// Copyright (C) 2012 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
// 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.
#ifndef CFGMGR_H
#define CFGMGR_H
#include <string>
#include <map>
#include <vector>
#include <boost/shared_ptr.hpp>
#include <boost/noncopyable.hpp>
#include <asiolink/io_address.h>
#include <util/buffer.h>
#include <dhcp/option.h>
#include <dhcp/pool.h>
#include <dhcp/subnet.h>
namespace isc {
namespace dhcp {
/// @brief Configuration Manager
///
/// This singleton class holds the whole configuration for DHCPv4 and DHCPv6
/// servers. It currently holds information about zero or more subnets6.
/// Each subnet may contain zero or more pools. Pool4 and Pool6 is the most
/// basic "chunk" of configuration. It contains a range of assigneable
/// addresses.
///
/// Below is a sketch of configuration inheritance (not implemented yet).
/// Let's investigate the following configuration:
///
/// preferred-lifetime 500;
/// valid-lifetime 1000;
/// subnet6 2001:db8:1::/48 {
/// pool6 2001::db8:1::1 - 2001::db8:1::ff;
/// };
/// subnet6 2001:db8:2::/48 {
/// valid-lifetime 2000;
/// pool6 2001::db8:2::1 - 2001::db8:2::ff;
/// };
/// Parameters defined in a global scope are applicable to everything until
/// they are overwritten in a smaller scope, in this case subnet6.
/// In the example above, the first subnet6 has preferred lifetime of 500s
/// and a valid lifetime of 1000s. The second subnet has preferred lifetime
/// of 500s, but valid lifetime of 2000s.
///
/// Parameter inheritance is likely to be implemented in configuration handling
/// routines, so there is no storage capability in a global scope for
/// subnet-specific parameters.
///
/// @todo: Implement Subnet4 support (ticket #2237)
/// @todo: Implement option definition support
/// @todo: Implement parameter inheritance
class CfgMgr : public boost::noncopyable {
public:
/// @brief returns a single instance of Configuration Manager
///
/// CfgMgr is a singleton and this method is the only way of
/// accessing it.
static CfgMgr& instance();
/// @brief get subnet by address
///
/// Finds a matching subnet, based on an address. This can be used
/// in two cases: when trying to find an appropriate lease based on
/// a) relay link address (that must be the address that is on link)
/// b) our global address on the interface the message was received on
/// (for directly connected clients)
///
/// @param hint an address that belongs to a searched subnet
Subnet6Ptr getSubnet6(const isc::asiolink::IOAddress& hint);
/// @brief get subnet by interface-id
///
/// Another possibility to find a subnet is based on interface-id.
///
/// @param interface_id content of interface-id option returned by a relay
/// @todo This method is not currently supported.
Subnet6Ptr getSubnet6(OptionPtr interface_id);
/// @brief adds a subnet6
void addSubnet6(const Subnet6Ptr& subnet);
/// @todo: Add subnet6 removal routines. Currently it is not possible
/// to remove subnets. The only case where subnet6 removal would be
/// needed is a dynamic server reconfiguration - a use case that is not
/// planned to be supported any time soon.
protected:
/// @brief Protected constructor.
///
/// This constructor is protected for 2 reasons. First, it forbids any
/// instantiations of this class (CfgMgr is a singleton). Second, it
/// allows derived class to instantiate it. That is useful for testing
/// purposes.
CfgMgr();
/// @brief virtual desctructor
virtual ~CfgMgr();
/// @brief a container for Subnet6
///
/// That is a simple vector of pointers. It does not make much sense to
/// optimize access time (e.g. using a map), because typical search
/// pattern will use calling inRange() method on each subnet until
/// a match is found.
Subnet6Collection subnets6_;
};
} // namespace isc::dhcp
} // namespace isc
#endif

87
src/lib/dhcp/pool.cc Normal file
View File

@@ -0,0 +1,87 @@
// Copyright (C) 2012 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
// 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>
#include <dhcp/addr_utilities.h>
#include <dhcp/pool.h>
using namespace isc::asiolink;
namespace isc {
namespace dhcp {
Pool::Pool(const isc::asiolink::IOAddress& first,
const isc::asiolink::IOAddress& last)
:id_(getNextID()), first_(first), last_(last) {
}
bool Pool::inRange(const isc::asiolink::IOAddress& addr) const {
return (first_.smallerEqual(addr) && addr.smallerEqual(last_));
}
Pool6::Pool6(Pool6Type type, const isc::asiolink::IOAddress& first,
const isc::asiolink::IOAddress& last)
:Pool(first, last), type_(type), prefix_len_(0) {
// check if specified address boundaries are sane
if (first.getFamily() != AF_INET6 || last.getFamily() != AF_INET6) {
isc_throw(BadValue, "Invalid Pool6 address boundaries: not IPv6");
}
if (last < first) {
isc_throw(BadValue, "Upper boundary is smaller than lower boundary.");
// This check is a bit strict. If we decide that it is too strict,
// we need to comment it and uncomment lines below.
// On one hand, letting the user specify 2001::f - 2001::1 is nice, but
// on the other hand, 2001::1 may be a typo and the user really meant
// 2001::1:0 (or 1 followed by some hex digit), so a at least a warning
// would be useful.
// first_ = last;
// last_ = first;
}
// TYPE_PD is not supported by this constructor. first-last style
// parameters are for IA and TA only. There is another dedicated
// constructor for that (it uses prefix/length)
if ((type != TYPE_IA) && (type != TYPE_TA)) {
isc_throw(BadValue, "Invalid Pool6 type specified");
}
}
Pool6::Pool6(Pool6Type type, const isc::asiolink::IOAddress& prefix,
uint8_t prefix_len)
:Pool(prefix, IOAddress("::")),
type_(type), prefix_len_(prefix_len) {
// check if the prefix is sane
if (prefix.getFamily() != AF_INET6) {
isc_throw(BadValue, "Invalid Pool6 address boundaries: not IPv6");
}
// check if the prefix length is sane
if (prefix_len == 0 || prefix_len > 128) {
isc_throw(BadValue, "Invalid prefix length");
}
/// @todo: We should probably implement checks against weird addresses
/// here, like ::, starting with fe80, starting with ff etc. .
// Let's now calculate the last address in defined pool
last_ = lastAddrInPrefix(prefix, prefix_len);
}
}; // end of isc::dhcp namespace
}; // end of isc namespace

155
src/lib/dhcp/pool.h Normal file
View File

@@ -0,0 +1,155 @@
// Copyright (C) 2012 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
// 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.
#ifndef POOL_H
#define POOL_H
#include <vector>
#include <asiolink/io_address.h>
#include <boost/shared_ptr.hpp>
namespace isc {
namespace dhcp {
/// @brief base class for Pool4 and Pool6
///
/// Stores information about pool of IPv4 or IPv6 addresses.
/// That is a basic component of a configuration.
class Pool {
public:
/// @brief returns Pool-id
///
/// @return pool-id value
/// Pool-id is an unique value that can be used to identify a pool.
uint32_t getId() const {
return (id_);
}
/// @brief Returns the first address in a pool.
///
/// @return first address in a pool
const isc::asiolink::IOAddress& getFirstAddress() const {
return (first_);
}
/// @brief Returns the last address in a pool.
/// @return last address in a pool
const isc::asiolink::IOAddress& getLastAddress() const {
return (last_);
}
/// @brief Checks if a given address is in the range.
///
/// @return true, if the address is in pool
bool inRange(const isc::asiolink::IOAddress& addr) const;
protected:
/// @brief protected constructor
///
/// This constructor is protected to prevent anyone from instantiating
/// Pool class directly. Instances of Pool4 and Pool6 should be created
/// instead.
Pool(const isc::asiolink::IOAddress& first,
const isc::asiolink::IOAddress& last);
/// @brief returns the next unique Pool-ID
///
/// @return the next unique Pool-ID
static uint32_t getNextID() {
static uint32_t id = 0;
return (id++);
}
/// @brief pool-id
///
/// This ID is used to identify this specific pool.
uint32_t id_;
/// @brief The first address in a pool
isc::asiolink::IOAddress first_;
/// @brief The last address in a pool
isc::asiolink::IOAddress last_;
/// @brief Comments field
///
/// @todo: This field is currently not used.
std::string comments_;
};
/// @brief Pool information for IPv6 addresses and prefixes
///
/// It holds information about pool6, i.e. a range of IPv6 address space that
/// is configured for DHCP allocation.
class Pool6 : public Pool {
public:
/// @brief specifies Pool type
///
/// Currently there are 3 pool types defined in DHCPv6:
/// - Non-temporary addresses (conveyed in IA_NA)
/// - Temporary addresses (conveyed in IA_TA)
/// - Delegated Prefixes (conveyed in IA_PD)
/// There is a new one being worked on (IA_PA, see draft-ietf-dhc-host-gen-id), but
/// support for it is not planned for now.
typedef enum {
TYPE_IA,
TYPE_TA,
TYPE_PD
} Pool6Type;
/// @brief the constructor for Pool6 "min-max" style definition
///
/// @param first the first address in a pool
/// @param last the last address in a pool
Pool6(Pool6Type type, const isc::asiolink::IOAddress& first,
const isc::asiolink::IOAddress& last);
/// @brief the constructor for Pool6 "prefix/len" style definition
///
/// @param prefix specifies prefix of the pool
/// @param prefix_len specifies length of the prefix of the pool
Pool6(Pool6Type type, const isc::asiolink::IOAddress& prefix,
uint8_t prefix_len);
/// @brief returns pool type
///
/// @return pool type
Pool6Type getType() const {
return (type_);
}
private:
/// @brief defines a pool type
Pool6Type type_;
/// @brief prefix length
/// used by TYPE_PD only (zeroed for other types)
uint8_t prefix_len_;
};
/// @brief a pointer an IPv6 Pool
typedef boost::shared_ptr<Pool6> Pool6Ptr;
/// @brief a container for IPv6 Pools
typedef std::vector<Pool6Ptr> Pool6Collection;
} // end of isc::dhcp namespace
} // end of isc namespace
#endif // POOL_H

91
src/lib/dhcp/subnet.cc Normal file
View File

@@ -0,0 +1,91 @@
// Copyright (C) 2012 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
// 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 <dhcp/addr_utilities.h>
#include <asiolink/io_address.h>
#include <dhcp/subnet.h>
#include <dhcp/pool.h>
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),
t2_(t2), valid_(valid_lifetime) {
if ( (prefix.getFamily() == AF_INET6 && len > 128) ||
(prefix.getFamily() == AF_INET && len > 32) ) {
isc_throw(BadValue, "Invalid prefix length specified for subnet: " << len);
}
}
bool Subnet::inRange(const isc::asiolink::IOAddress& addr) const {
IOAddress first = firstAddrInPrefix(prefix_, prefix_len_);
IOAddress last = lastAddrInPrefix(prefix_, prefix_len_);
return ((first <= addr) && (addr <= last));
}
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){
if (prefix.getFamily() != AF_INET6) {
isc_throw(BadValue, "Non IPv6 prefix " << prefix.toText()
<< " specified in subnet6");
}
}
void Subnet6::addPool6(const Pool6Ptr& pool) {
IOAddress first_addr = pool->getFirstAddress();
IOAddress last_addr = pool->getLastAddress();
if (!inRange(first_addr) || !inRange(last_addr)) {
isc_throw(BadValue, "Pool6 (" << first_addr.toText() << "-" << last_addr.toText()
<< " does not belong in this (" << prefix_ << "/" << prefix_len_
<< ") subnet6");
}
/// @todo: Check that pools do not overlap
pools_.push_back(pool);
}
Pool6Ptr Subnet6::getPool6(const isc::asiolink::IOAddress& hint /* = IOAddress("::")*/ ) {
Pool6Ptr candidate;
for (Pool6Collection::iterator pool = pools_.begin(); pool != pools_.end(); ++pool) {
// if we won't find anything better, then let's just use the first pool
if (!candidate) {
candidate = *pool;
}
// if the client provided a pool and there's a pool that hint is valid in,
// then let's use that pool
if ((*pool)->inRange(hint)) {
return (*pool);
}
}
return (candidate);
}
} // end of isc::dhcp namespace
} // end of isc namespace

161
src/lib/dhcp/subnet.h Normal file
View File

@@ -0,0 +1,161 @@
// Copyright (C) 2012 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
// 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.
#ifndef SUBNET_H
#define SUBNET_H
#include <boost/shared_ptr.hpp>
#include <asiolink/io_address.h>
#include <dhcp/pool.h>
#include <dhcp/triplet.h>
namespace isc {
namespace dhcp {
/// @brief a base class for Subnet4 and Subnet6
///
/// This class presents a common base for IPv4 and IPv6 subnets.
/// In a physical sense, a subnet defines a single network link with all devices
/// attached to it. In most cases all devices attached to a single link can
/// share the same parameters. Therefore Subnet holds several values that are
/// typically shared by all hosts: renew timer (T1), rebind timer (T2) and
/// leased addresses lifetime (valid-lifetime).
///
/// @todo: Implement support for options here
class Subnet {
public:
/// @brief checks if specified address is in range
bool inRange(const isc::asiolink::IOAddress& addr) const;
/// @brief return valid-lifetime for addresses in that prefix
Triplet<uint32_t> getValid() const {
return (valid_);
}
/// @brief returns T1 (renew timer), expressed in seconds
Triplet<uint32_t> getT1() const {
return (t1_);
}
/// @brief returns T2 (rebind timer), expressed in seconds
Triplet<uint32_t> getT2() const {
return (t2_);
}
protected:
/// @brief protected constructor
//
/// By making the constructor protected, we make sure that noone will
/// ever instantiate that class. Pool4 and Pool6 should be used instead.
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);
/// @brief returns the next unique Subnet-ID
///
/// @return the next unique Subnet-ID
static uint32_t getNextID() {
static uint32_t id = 0;
return (id++);
}
/// @brief subnet-id
///
/// Subnet-id is a unique value that can be used to find or identify
/// a Subnet4 or Subnet6.
uint32_t id_;
/// @brief a prefix of the subnet
isc::asiolink::IOAddress prefix_;
/// @brief a prefix length of the subnet
uint8_t prefix_len_;
/// @brief a tripet (min/default/max) holding allowed renew timer values
Triplet<uint32_t> t1_;
/// @brief a tripet (min/default/max) holding allowed rebind timer values
Triplet<uint32_t> t2_;
/// @brief a tripet (min/default/max) holding allowed valid lifetime values
Triplet<uint32_t> valid_;
};
/// @brief A configuration holder for IPv6 subnet.
///
/// This class represents an IPv6 subnet.
class Subnet6 : public Subnet {
public:
/// @brief Constructor with all parameters
///
/// @param prefix Subnet6 prefix
/// @param length prefix length
/// @param t1 renewal timer (in seconds)
/// @param t2 rebind timer (in seconds)
/// @param preferred_lifetime preferred lifetime of leases (in seconds)
/// @param valid_lifetime preferred lifetime of leases (in seconds)
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);
/// @brief Returns preverred lifetime (in seconds)
///
/// @return a triplet with preferred lifetime
Triplet<uint32_t> getPreferred() const {
return (preferred_);
}
/// @brief Returns a pool that specified address belongs to
///
/// @param hint address that the returned pool should cover (optional)
/// @return Pointer to found pool6 (or NULL)
Pool6Ptr getPool6(const isc::asiolink::IOAddress& hint =
isc::asiolink::IOAddress("::"));
/// @brief Adds a new pool.
/// @param pool pool to be added
void addPool6(const Pool6Ptr& pool);
/// @brief returns all pools
///
/// The reference is only valid as long as the object that
/// returned it.
///
/// @return a collection of all pools
const Pool6Collection& getPools() const {
return pools_;
}
protected:
/// @brief collection of pools in that list
Pool6Collection pools_;
/// @brief a triplet with preferred lifetime (in seconds)
Triplet<uint32_t> preferred_;
};
/// @brief A pointer to a Subnet6 object
typedef boost::shared_ptr<Subnet6> Subnet6Ptr;
/// @brief A collection of Subnet6 objects
typedef std::vector<Subnet6Ptr> Subnet6Collection;
} // end of isc::dhcp namespace
} // end of isc namespace
#endif // SUBNET_T

View File

@@ -24,7 +24,7 @@ TESTS_ENVIRONMENT = \
TESTS =
if HAVE_GTEST
TESTS += libdhcp++_unittests
TESTS += libdhcp++_unittests libdhcpsrv_unittests
libdhcp___unittests_SOURCES = run_unittests.cc
libdhcp___unittests_SOURCES += libdhcp++_unittest.cc
libdhcp___unittests_SOURCES += iface_mgr_unittest.cc
@@ -38,20 +38,37 @@ libdhcp___unittests_SOURCES += pkt4_unittest.cc
libdhcp___unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES) $(LOG4CPLUS_INCLUDES)
libdhcp___unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
libdhcp___unittests_CXXFLAGS = $(AM_CXXFLAGS)
libdhcpsrv_unittests_SOURCES = run_unittests.cc
libdhcpsrv_unittests_SOURCES += cfgmgr_unittest.cc triplet_unittest.cc
libdhcpsrv_unittests_SOURCES += pool_unittest.cc subnet_unittest.cc
libdhcpsrv_unittests_SOURCES += addr_utilities_unittest.cc
libdhcpsrv_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES) $(LOG4CPLUS_INCLUDES)
libdhcpsrv_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
libdhcpsrv_unittests_CXXFLAGS = $(AM_CXXFLAGS)
libdhcpsrv_unittests_LDADD = $(GTEST_LDADD)
libdhcpsrv_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libb10-exceptions.la
libdhcpsrv_unittests_LDADD += $(top_builddir)/src/lib/asiolink/libb10-asiolink.la
libdhcpsrv_unittests_LDADD += $(top_builddir)/src/lib/dhcp/libb10-dhcpsrv.la
libdhcpsrv_unittests_LDADD += $(top_builddir)/src/lib/log/libb10-log.la
if USE_CLANGPP
# This is to workaround unused variables tcout and tcerr in
# log4cplus's streams.h and unused parameters from some of the
# Boost headers.
libdhcp___unittests_CXXFLAGS += -Wno-unused-variable -Wno-unused-parameter
libdhcpsrv_unittests_CXXFLAGS += -Wno-unused-variable -Wno-unused-parameter
endif
libdhcp___unittests_LDADD = $(top_builddir)/src/lib/dhcp/libb10-dhcp++.la
libdhcp___unittests_LDADD += $(top_builddir)/src/lib/log/libb10-log.la
libdhcp___unittests_LDADD += $(top_builddir)/src/lib/util/libb10-util.la
libdhcp___unittests_LDADD += $(top_builddir)/src/lib/asiolink/libb10-asiolink.la
libdhcp___unittests_LDADD += $(top_builddir)/src/lib/exceptions/libb10-exceptions.la
libdhcp___unittests_LDADD += $(top_builddir)/src/lib/log/libb10-log.la
libdhcp___unittests_LDADD += $(GTEST_LDADD)
endif

View File

@@ -0,0 +1,93 @@
// Copyright (C) 2010 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
// 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 <config.h>
#include <stdint.h>
#include <stdlib.h>
#include <gtest/gtest.h>
#include <vector>
#include <dhcp/addr_utilities.h>
using namespace std;
using namespace isc::dhcp;
using namespace isc::asiolink;
TEST(Pool6Test, lastAddrInPrefix) {
IOAddress addr1("2001:db8:1:1234:5678:abcd:1234:beef");
// Prefixes rounded to nibbles are easy...
EXPECT_EQ("2001:db8:1:1234:5678:abcd:1234:ffff",
lastAddrInPrefix(addr1, 112).toText());
EXPECT_EQ("2001:db8:1:1234:5678:abcd:123f:ffff",
lastAddrInPrefix(addr1, 108).toText());
EXPECT_EQ("2001:db8:1:1234:5678:abcd:12ff:ffff",
lastAddrInPrefix(addr1, 104).toText());
EXPECT_EQ("2001:db8:1:1234:ffff:ffff:ffff:ffff",
lastAddrInPrefix(addr1, 64).toText());
IOAddress addr2("2001::");
// These are tricker, though, as they are done in 1 bit increments
// the last address in 2001::/127 pool should be 2001::1
EXPECT_EQ("2001::1", lastAddrInPrefix(addr2, 127).toText());
EXPECT_EQ("2001::3", lastAddrInPrefix(addr2, 126).toText());
EXPECT_EQ("2001::7", lastAddrInPrefix(addr2, 125).toText());
EXPECT_EQ("2001::f", lastAddrInPrefix(addr2, 124).toText());
EXPECT_EQ("2001::1f", lastAddrInPrefix(addr2, 123).toText());
EXPECT_EQ("2001::3f", lastAddrInPrefix(addr2, 122).toText());
EXPECT_EQ("2001::7f", lastAddrInPrefix(addr2, 121).toText());
EXPECT_EQ("2001::ff", lastAddrInPrefix(addr2, 120).toText());
// Let's check extreme cases
IOAddress anyAddr("::");
EXPECT_EQ("7fff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
lastAddrInPrefix(anyAddr, 1).toText());
EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
lastAddrInPrefix(anyAddr, 0).toText());
EXPECT_EQ("::", lastAddrInPrefix(anyAddr, 128).toText());
}
TEST(Pool6Test, firstAddrInPrefix) {
IOAddress addr1("2001:db8:1:1234:5678:1234:abcd:beef");
// Prefixes rounded to nibbles are easy...
EXPECT_EQ("2001:db8:1:1234:5678:1234::",
firstAddrInPrefix(addr1, 96).toText());
EXPECT_EQ("2001:db8:1:1234:5678:1230::",
firstAddrInPrefix(addr1, 92).toText());
EXPECT_EQ("2001:db8:1:1234:5678:1200::",
firstAddrInPrefix(addr1, 88).toText());
EXPECT_EQ("2001:db8:1:1234::",
firstAddrInPrefix(addr1, 64).toText());
IOAddress addr2("2001::ffff");
// These are tricker, though, as they are done in 1 bit increments
// the first address in 2001::/127 pool should be 2001::1
EXPECT_EQ("2001::fffe", firstAddrInPrefix(addr2, 127).toText());
EXPECT_EQ("2001::fffc", firstAddrInPrefix(addr2, 126).toText());
EXPECT_EQ("2001::fff8", firstAddrInPrefix(addr2, 125).toText());
EXPECT_EQ("2001::fff0", firstAddrInPrefix(addr2, 124).toText());
EXPECT_EQ("2001::ffe0", firstAddrInPrefix(addr2, 123).toText());
EXPECT_EQ("2001::ffc0", firstAddrInPrefix(addr2, 122).toText());
EXPECT_EQ("2001::ff80", firstAddrInPrefix(addr2, 121).toText());
EXPECT_EQ("2001::ff00", firstAddrInPrefix(addr2, 120).toText());
}

View File

@@ -0,0 +1,63 @@
// Copyright (C) 2012 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
// 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 <config.h>
#include <iostream>
#include <sstream>
#include <arpa/inet.h>
#include <gtest/gtest.h>
#include <dhcp/cfgmgr.h>
#include <exceptions/exceptions.h>
using namespace std;
using namespace isc::asiolink;
using namespace isc::dhcp;
using namespace isc::util;
using namespace isc;
// don't import the entire boost namespace. It will unexpectedly hide uint8_t
// for some systems.
using boost::scoped_ptr;
namespace {
// This test verifies if the configuration manager is able to hold and return
// valid leases
TEST(CfgMgrTest, subnet6) {
CfgMgr& cfg_mgr = CfgMgr::instance();
ASSERT_TRUE(&cfg_mgr != 0);
Subnet6Ptr subnet1(new Subnet6(IOAddress("2000::"), 48, 1, 2, 3, 4));
Subnet6Ptr subnet2(new Subnet6(IOAddress("3000::"), 48, 1, 2, 3, 4));
Subnet6Ptr subnet3(new Subnet6(IOAddress("4000::"), 48, 1, 2, 3, 4));
// there shouldn't be any subnet configured at this stage
EXPECT_EQ( Subnet6Ptr(), cfg_mgr.getSubnet6(IOAddress("2000::1")));
cfg_mgr.addSubnet6(subnet1);
// Now we have only one subnet, any request will be served from it
EXPECT_EQ(subnet1, cfg_mgr.getSubnet6(IOAddress("2001:db8::1")));
cfg_mgr.addSubnet6(subnet2);
cfg_mgr.addSubnet6(subnet3);
EXPECT_EQ(subnet3, cfg_mgr.getSubnet6(IOAddress("4000::123")));
EXPECT_EQ(subnet2, cfg_mgr.getSubnet6(IOAddress("3000::dead:beef")));
EXPECT_EQ(Subnet6Ptr(), cfg_mgr.getSubnet6(IOAddress("5000::1")));
}
} // end of anonymous namespace

View File

@@ -0,0 +1,109 @@
// Copyright (C) 2012 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
// 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 <config.h>
#include <iostream>
#include <vector>
#include <sstream>
#include <gtest/gtest.h>
#include <dhcp/pool.h>
#include <asiolink/io_address.h>
using boost::scoped_ptr;
using namespace isc;
using namespace isc::dhcp;
using namespace isc::asiolink;
namespace {
TEST(Pool6Test, constructor_first_last) {
// let's construct 2001:db8:1:: - 2001:db8:1::ffff:ffff:ffff:ffff pool
Pool6 pool1(Pool6::TYPE_IA, IOAddress("2001:db8:1::"),
IOAddress("2001:db8:1::ffff:ffff:ffff:ffff"));
EXPECT_EQ(Pool6::TYPE_IA, pool1.getType());
EXPECT_EQ(IOAddress("2001:db8:1::"), pool1.getFirstAddress());
EXPECT_EQ(IOAddress("2001:db8:1::ffff:ffff:ffff:ffff"),
pool1.getLastAddress());
// This is Pool6, IPv4 addresses do not belong here
EXPECT_THROW(Pool6(Pool6::TYPE_IA, IOAddress("2001:db8::1"),
IOAddress("192.168.0.5")), BadValue);
EXPECT_THROW(Pool6(Pool6::TYPE_IA, IOAddress("192.168.0.2"),
IOAddress("2001:db8::1")), BadValue);
// Should throw. Range should be 2001:db8::1 - 2001:db8::2, not
// the other way around.
EXPECT_THROW(Pool6(Pool6::TYPE_IA, IOAddress("2001:db8::2"),
IOAddress("2001:db8::1")), BadValue);
}
TEST(Pool6Test, constructor_prefix_len) {
// let's construct 2001:db8:1::/96 pool
Pool6 pool1(Pool6::TYPE_IA, IOAddress("2001:db8:1::"), 96);
EXPECT_EQ(Pool6::TYPE_IA, pool1.getType());
EXPECT_EQ("2001:db8:1::", pool1.getFirstAddress().toText());
EXPECT_EQ("2001:db8:1::ffff:ffff", pool1.getLastAddress().toText());
// No such thing as /130 prefix
EXPECT_THROW(Pool6(Pool6::TYPE_IA, IOAddress("2001:db8::"), 130),
BadValue);
// /0 prefix does not make sense
EXPECT_THROW(Pool6(Pool6::TYPE_IA, IOAddress("2001:db8::"), 0),
BadValue);
// This is Pool6, IPv4 addresses do not belong here
EXPECT_THROW(Pool6(Pool6::TYPE_IA, IOAddress("192.168.0.2"), 96),
BadValue);
}
TEST(Pool6Test, in_range) {
Pool6 pool1(Pool6::TYPE_IA, IOAddress("2001:db8:1::1"),
IOAddress("2001:db8:1::f"));
EXPECT_FALSE(pool1.inRange(IOAddress("2001:db8:1::")));
EXPECT_TRUE(pool1.inRange(IOAddress("2001:db8:1::1")));
EXPECT_TRUE(pool1.inRange(IOAddress("2001:db8:1::7")));
EXPECT_TRUE(pool1.inRange(IOAddress("2001:db8:1::f")));
EXPECT_FALSE(pool1.inRange(IOAddress("2001:db8:1::10")));
EXPECT_FALSE(pool1.inRange(IOAddress("::")));
}
// This test creates 100 pools and verifies that their IDs are unique.
TEST(Pool6Test, unique_id) {
const int num_pools = 100;
std::vector<Pool6Ptr> pools;
for (int i = 0; i < num_pools; ++i) {
pools.push_back(Pool6Ptr(new Pool6(Pool6::TYPE_IA, IOAddress("2001:db8:1::"),
IOAddress("2001:db8:1::ffff:ffff:ffff:ffff"))));
}
for (int i = 0; i < num_pools; ++i) {
for (int j = i + 1; j < num_pools; ++j) {
if (pools[i]->getId() == pools[j]->getId()) {
FAIL() << "Pool-ids must be unique";
}
}
}
}
}; // end of anonymous namespace

View File

@@ -13,7 +13,6 @@
// PERFORMANCE OF THIS SOFTWARE.
#include <gtest/gtest.h>
#include <log/logger_support.h>
int

View File

@@ -0,0 +1,112 @@
// Copyright (C) 2012 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
// 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 <config.h>
#include <dhcp/subnet.h>
#include <exceptions/exceptions.h>
#include <boost/scoped_ptr.hpp>
#include <gtest/gtest.h>
#include <asiolink/io_address.h>
// don't import the entire boost namespace. It will unexpectedly hide uint8_t
// for some systems.
using boost::scoped_ptr;
using namespace isc;
using namespace isc::dhcp;
using namespace isc::asiolink;
namespace {
TEST(Subnet6Test, constructor) {
EXPECT_NO_THROW(Subnet6 subnet1(IOAddress("2001:db8:1::"), 64,
1, 2, 3, 4));
EXPECT_THROW(Subnet6 subnet2(IOAddress("2001:db8:1::"), 129, 1, 2, 3, 4),
BadValue); // invalid prefix length
EXPECT_THROW(Subnet6 subnet3(IOAddress("192.168.0.0"), 32, 1, 2, 3, 4),
BadValue); // IPv4 addresses are not allowed in Subnet6
}
TEST(Subnet6Test, in_range) {
Subnet6 subnet(IOAddress("2001:db8:1::"), 64, 1000, 2000, 3000, 4000);
EXPECT_EQ(1000, subnet.getT1());
EXPECT_EQ(2000, subnet.getT2());
EXPECT_EQ(3000, subnet.getPreferred());
EXPECT_EQ(4000, subnet.getValid());
EXPECT_FALSE(subnet.inRange(IOAddress("2001:db8:0:ffff:ffff:ffff:ffff:ffff")));
EXPECT_TRUE(subnet.inRange(IOAddress("2001:db8:1::0")));
EXPECT_TRUE(subnet.inRange(IOAddress("2001:db8:1::1")));
EXPECT_TRUE(subnet.inRange(IOAddress("2001:db8:1::ffff:ffff:ffff:ffff")));
EXPECT_FALSE(subnet.inRange(IOAddress("2001:db8:1:1::")));
EXPECT_FALSE(subnet.inRange(IOAddress("::")));
}
TEST(Subnet6Test, Pool6InSubnet6) {
Subnet6Ptr subnet(new Subnet6(IOAddress("2001:db8:1::"), 56, 1, 2, 3, 4));
Pool6Ptr pool1(new Pool6(Pool6::TYPE_IA, IOAddress("2001:db8:1:1::"), 64));
Pool6Ptr pool2(new Pool6(Pool6::TYPE_IA, IOAddress("2001:db8:1:2::"), 64));
Pool6Ptr pool3(new Pool6(Pool6::TYPE_IA, IOAddress("2001:db8:1:3::"), 64));
subnet->addPool6(pool1);
// If there's only one pool, get that pool
Pool6Ptr mypool = subnet->getPool6();
EXPECT_EQ(mypool, pool1);
subnet->addPool6(pool2);
subnet->addPool6(pool3);
// If there are more than one pool and we didn't provide hint, we
// should get the first pool
mypool = subnet->getPool6();
EXPECT_EQ(mypool, pool1);
// If we provide a hint, we should get a pool that this hint belongs to
mypool = subnet->getPool6(IOAddress("2001:db8:1:3::dead:beef"));
EXPECT_EQ(mypool, pool3);
}
TEST(Subnet6Test, Subnet6_Pool6_checks) {
Subnet6Ptr subnet(new Subnet6(IOAddress("2001:db8:1::"), 56, 1, 2, 3, 4));
// this one is in subnet
Pool6Ptr pool1(new Pool6(Pool6::TYPE_IA, IOAddress("2001:db8:1:1::"), 64));
subnet->addPool6(pool1);
// this one is larger than the subnet!
Pool6Ptr pool2(new Pool6(Pool6::TYPE_IA, IOAddress("2001:db8::"), 48));
EXPECT_THROW(subnet->addPool6(pool2), BadValue);
// this one is totally out of blue
Pool6Ptr pool3(new Pool6(Pool6::TYPE_IA, IOAddress("3000::"), 16));
EXPECT_THROW(subnet->addPool6(pool3), BadValue);
}
};

View File

@@ -0,0 +1,104 @@
// Copyright (C) 2012 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
// 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 <config.h>
#include <stdint.h>
#include <gtest/gtest.h>
#include <dhcp/triplet.h>
#include <exceptions/exceptions.h>
using namespace isc::dhcp;
using namespace isc;
namespace {
// constructor validation
TEST(TripletTest, constructor) {
const uint32_t min = 10;
const uint32_t value = 20;
const uint32_t max = 30;
Triplet<uint32_t> x(min, value, max);
EXPECT_EQ(min, x.getMin());
EXPECT_EQ(value, x.get());
EXPECT_EQ(max, x.getMax());
// requested values below min should return allowed min value
EXPECT_EQ(min, x.get(min - 5));
EXPECT_EQ(min, x.get(min));
// requesting a value from within the range (min < x < max) should
// return the requested value
EXPECT_EQ(17, x.get(17));
EXPECT_EQ(max, x.get(max));
EXPECT_EQ(max, x.get(max + 5));
// this will be boring. It is expected to return 42 no matter what
Triplet<uint32_t> y(42);
EXPECT_EQ(42, y.getMin()); // min, default and max are equal to 42
EXPECT_EQ(42, y.get()); // it returns ...
EXPECT_EQ(42, y.getMax()); // the exact value...
// requested values below or above are ignore
EXPECT_EQ(42, y.get(5)); // all...
EXPECT_EQ(42, y.get(42)); // the...
EXPECT_EQ(42, y.get(80)); // time!
}
// Triplets must be easy to use.
// Simple to/from int conversions must be done on the fly.
TEST(TripletTest, operator) {
uint32_t x = 47;
Triplet<uint32_t> foo(1,2,3);
Triplet<uint32_t> bar(4,5,6);
foo = bar;
EXPECT_EQ(4, foo.getMin());
EXPECT_EQ(5, foo.get());
EXPECT_EQ(6, foo.getMax());
// assignment operator: uint32_t => triplet
Triplet<uint32_t> y(0);
y = x;
EXPECT_EQ(x, y.get());
// let's try the other way around: triplet => uint32_t
uint32_t z = 0;
z = y;
EXPECT_EQ(x, z);
}
// check if specified values are sane
TEST(TripletTest, sanity_check) {
// min is larger than default
EXPECT_THROW(Triplet<uint32_t>(6,5,5), BadValue);
// max is smaller than default
EXPECT_THROW(Triplet<uint32_t>(5,5,4), BadValue);
}
}; // end of anonymous namespace

110
src/lib/dhcp/triplet.h Normal file
View File

@@ -0,0 +1,110 @@
// Copyright (C) 2012 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
// 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 <exceptions/exceptions.h>
namespace isc {
namespace dhcp {
/// @brief this template specifies a parameter value
///
/// This template class is used to store configuration parameters, like lifetime or T1.
/// It defines 3 parameters: min, default, and max value. There are 2 constructors:
/// - simple (just one value that sets all parameters)
/// - extended (that sets default value and two thresholds)
/// It will be used with integer types. It provides necessary operators, so
/// it can be assigned to a plain integer or integer assigned to a Triplet.
/// See TripletTest.operator test for details on an easy Triplet usage.
template <class T>
class Triplet {
public:
/// @brief base type to Triple conversion
///
/// Typically: uint32_t to Triplet assignment. It is very convenient
/// to be able to simply write Triplet<uint32_t> x = 7;
Triplet<T> operator=(T other) {
min_ = other;
default_ = other;
max_ = other;
return *this;
}
/// @brief triplet to base type conversion
///
/// Typically: Triplet to uint32_t assignment. It is very convenient
/// to be able to simply write uint32_t z = x; (where x is a Triplet)
operator T() const {
return (default_);
}
/// @brief sets a fixed value
///
/// This constructor assigns a fixed (i.e. no range, just a single value)
/// value.
Triplet(T value)
:min_(value), default_(value), max_(value) {
}
/// @brief sets the default value and thresholds
///
/// @throw BadValue if min <= def <= max rule is violated
Triplet(T min, T def, T max)
:min_(min), default_(def), max_(max) {
if ( (min_ > def) || (def > max_) ) {
isc_throw(BadValue, "Invalid triplet values.");
}
}
/// @brief returns a minimum allowed value
T getMin() const { return min_;}
/// @brief returns the default value
T get() const { return default_;}
/// @brief returns value with a hint
///
/// DHCP protocol treats any values sent by a client as hints.
/// This is a method that implements that. We can assign any value
/// from configured range that client asks.
T get(T hint) const {
if (hint <= min_) {
return (min_);
}
if (hint >= max_) {
return (max_);
}
return (hint);
}
/// @brief returns a maximum allowed value
T getMax() const { return max_; }
protected:
/// @brief the minimum value
T min_;
/// @brief the default value
T default_;
/// @brief the maximum value
T max_;
};
} // namespace isc::dhcp
} // namespace isc