Commit 26e55ce1 authored by Mukund Sivaraman's avatar Mukund Sivaraman
Browse files

Merge branch 'master' into trac2276

parents ae20aca3 b9b89934
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
......
......@@ -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.
///
......
......@@ -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);
}
......@@ -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]) {
......
......@@ -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)
......
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.
// 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));
}
};
};
// 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);
};
};
// 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
// 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
// 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_));
}