#include <asiodns/dns_service.h>
-#include <datasrc/query.h>
#include <datasrc/data_source.h>
#include <datasrc/client_list.h>
CLEANFILES += static.zone
lib_LTLIBRARIES = libb10-datasrc.la
-libb10_datasrc_la_SOURCES = data_source.h data_source.cc
-libb10_datasrc_la_SOURCES += query.h query.cc
-libb10_datasrc_la_SOURCES += cache.h cache.cc
+libb10_datasrc_la_SOURCES = data_source.h
libb10_datasrc_la_SOURCES += rbnode_rrset.h
libb10_datasrc_la_SOURCES += rbtree.h
libb10_datasrc_la_SOURCES += zonetable.h zonetable.cc
+++ /dev/null
-// 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 <stdint.h>
-
-#include <map>
-
-#include <dns/question.h>
-#include <dns/rrclass.h>
-#include <dns/rrset.h>
-#include <dns/rrtype.h>
-
-#include <list>
-
-#include <datasrc/cache.h>
-#include <datasrc/logger.h>
-
-using namespace std;
-using namespace isc::dns;
-
-namespace isc {
-namespace datasrc {
-
-/// \brief A \c CacheEntry object contains the data stored with
-/// each \c CacheNode: a pointer to the cached RRset (empty in
-/// the case of a negative cache entry), and a copy of the
-/// query-response flags that were returned when the RRset
-/// was originally looked up in the low-level data source.
-class CacheEntry {
-private:
- /// The copy constructor and the assignment operator are intentionally
- /// defined as private.
- CacheEntry(const CacheEntry& source);
- CacheEntry& operator=(const CacheEntry& source);
-
-public:
- CacheEntry(RRsetPtr r, uint32_t f) : rrset(r), flags(f) {};
-
- RRsetPtr rrset;
- uint32_t flags;
-};
-
-typedef boost::shared_ptr<CacheEntry> CacheEntryPtr;
-
-/// \brief A \c CacheNode is a node in the \c HotCache LRU queue. It
-/// contains a pointer to a \c CacheEntry, a reference to the \c Question
-/// that we are answering, a lifespan during which this entry remains
-/// valid, and pointers to the next and previous entries in the list.
-class CacheNode {
-private:
- /// \name Constructors and Assignment Operator
- ///
- /// Note: The copy constructor and the assignment operator are intentionally
- /// defined as private.
- //@{
- CacheNode(const CacheNode& source);
- CacheNode& operator=(const CacheNode& source);
-
-public:
- /// \brief Constructor for positive cache entry.
- ///
- /// \param rrset The \c RRset to cache.
- /// \param flags The query response flags returned from the low-level
- /// data source when this \c RRset was looked up.
- /// \param lifespan How long the cache node is to be considered valid.
- CacheNode(const RRsetPtr rrset, uint32_t flags, time_t lifespan);
-
- /// \brief Constructor for negative cache entry.
- ///
- /// \param name Query name
- /// \param rrclass Query class
- /// \param rrtype Query type
- /// \param flags Query response flags returned from the low-level
- /// data source, indicating why this lookup failed (name not found,
- /// type not found, etc).
- /// \param lifespan How long the cache node is to be considered valid.
- CacheNode(const Name& name,
- const RRClass& rrclass,
- const RRType& rrtype,
- uint32_t flags,
- time_t lifespan);
- //@}
-
- /// \name Getter and Setter Methods
- //@{
- /// \brief Returns a pointer to the cached RRset (or an empty
- /// RRsetPtr for negative cache entries).
-
- /// \return \c RRsetPtr
- RRsetPtr getRRset() const { return (entry->rrset); }
-
- /// \brief Returns name associated with cached node
- ///
- /// This is the name associated with the RRset if it is a positive
- /// entry, and the associated question name if the RRSet is NULL
- /// and this is a negative entry (together with an indication that
- /// this is a negative entry).
- string getNodeName() const {
- if (getRRset()) {
- return (getRRset()->getName().toText());
- }
- return (std::string("negative entry for ") + question.toText());
- }
-
- /// \brief Returns the query response flags associated with the data.
- ///
- /// \return \c uint32_t
- uint32_t getFlags() const { return (entry->flags); }
-
- /// \brief Is this record still valid?
- ///
- /// \return True if the expiration time has not yet passed,
- /// or false if it has.
- bool isValid() const;
- //@}
-
- // An iterator referencing this entry in the LRU list. This
- // permits unit-time removal using list::erase().
- list<CacheNodePtr>::iterator lru_entry_;
-
- /// The \c Question (name/rrclass/rrtype) answered by this cache node
- const isc::dns::Question question;
-
-private:
- // The cached RRset data
- CacheEntryPtr entry;
-
- // When this record should be discarded
- time_t expiry;
-};
-
-// CacheNode constructor for a positive cache entry
-CacheNode::CacheNode(const RRsetPtr rrset, const uint32_t flags,
- const time_t lifespan) :
- question(Question(rrset->getName(), rrset->getClass(), rrset->getType()))
-{
- const time_t now = time(NULL);
- expiry = now + lifespan;
-
- entry = CacheEntryPtr(new CacheEntry(rrset, flags));
-}
-
-// CacheNode constructor for a negative cache entry
-CacheNode::CacheNode(const Name& name,
- const RRClass& rrclass,
- const RRType& rrtype,
- const uint32_t flags,
- const time_t lifespan) :
- question(Question(name, rrclass, rrtype))
-{
- const time_t now = time(NULL);
- expiry = now + lifespan;
-
- entry = CacheEntryPtr(new CacheEntry(RRsetPtr(), flags));
-}
-// Returns true if the node has not yet expired.
-bool
-CacheNode::isValid() const {
- const time_t now = time(NULL);
- return (now < expiry);
-}
-
-/// This class abstracts the implementation details for \c HotCache.
-///
-/// Each node inserted into the cache is placed at the head of a
-/// doubly-linked list. Whenever that node is retrieved from the cache,
-/// it is again moved to the head of the list. When the configured
-/// number of slots in the cache has been exceeded, the least recently
-/// used nodes will be removed from the tail of the list.
-///
-/// A pointer to each cache node is also placed in a \c std::map object,
-/// keyed by \c isc::dns::Question. This allows retrieval of data in
-/// (usually) logarithmic time. (Possible TODO item: replace this with a
-/// hash table instead.)
-class HotCacheImpl {
-public:
- HotCacheImpl(int slots, bool enabled);
-
- // The LRU list
- list<CacheNodePtr> lru_;
-
- // Flag to indicate whether the cache is enabled
- bool enabled_;
-
- // The number of available slots in the LRU list. (If zero,
- // then the list is unbounded; otherwise, items are removed
- // from the tail of the list whenever it grows past slots_.)
- int slots_;
-
- // The number of items currently in the list.
- int count_;
-
- // Map from query tuple to cache node pointer, allowing fast retrieval
- // of data without a linear search of the LRU list
- std::map<Question, CacheNodePtr> map_;
-
- // Move a node to the front of the LRU list.
- void promote(CacheNodePtr node);
-
- // Remove a node from the cache.
- void remove(ConstCacheNodePtr node);
-
- // Insert a node into the cache (called by both cache() and ncache())
- void insert(CacheNodePtr node);
-};
-
-// HotCacheImpl constructor
-HotCacheImpl::HotCacheImpl(int slots, bool enabled) :
- enabled_(enabled), slots_(slots), count_(0)
-{
- LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_CACHE_CREATE);
-}
-
-// Insert a cache node into the cache
-inline void
-HotCacheImpl::insert(const CacheNodePtr node) {
- LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_CACHE_INSERT).
- arg(node->getNodeName());
- std::map<Question, CacheNodePtr>::const_iterator iter;
- iter = map_.find(node->question);
- if (iter != map_.end()) {
- CacheNodePtr old = iter->second;
- if (old && old->isValid()) {
- LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_CACHE_OLD_FOUND)
- .arg(node->getNodeName());
- remove(old);
- }
- }
-
- lru_.push_front(node);
- node->lru_entry_ = lru_.begin();
-
- map_[node->question] = node;
- ++count_;
-
- if (slots_ != 0 && count_ > slots_) {
- LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_CACHE_FULL);
- remove(lru_.back());
- }
-}
-
-// Promote a node to the head of the LRU list
-void
-HotCacheImpl::promote(CacheNodePtr node) {
- if (!node) {
- return;
- }
- if (node->lru_entry_ == lru_.begin()) {
- return;
- }
- lru_.splice(lru_.begin(), lru_, node->lru_entry_); // move node to front
- node->lru_entry_ = lru_.begin();
-}
-
-// Remove a node from the LRU list and the map
-void
-HotCacheImpl::remove(ConstCacheNodePtr node) {
- LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_CACHE_REMOVE).
- arg(node->getNodeName());
- lru_.erase(node->lru_entry_);
- map_.erase(node->question);
- --count_;
-}
-
-// HotCache constructor
-HotCache::HotCache(const int slots) {
- impl_ = new HotCacheImpl(slots, true);
-}
-
-// HotCache destructor
-HotCache::~HotCache() {
- LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_CACHE_DESTROY);
- delete impl_;
-}
-
-// Add a positive entry to the cache
-void
-HotCache::addPositive(RRsetPtr rrset, const uint32_t flags,
- const time_t lifespan)
-{
- if (!impl_->enabled_) {
- return;
- }
-
- impl_->insert(CacheNodePtr(new CacheNode(rrset, flags, lifespan)));
-}
-
-// Add a negative entry to the cache
-void
-HotCache::addNegative(const Name& name, const RRClass &rrclass,
- const RRType& rrtype, const uint32_t flags,
- const time_t lifespan)
-{
- if (!impl_->enabled_) {
- return;
- }
-
- if (rrtype == RRType::ANY() || rrclass == RRClass::ANY()) {
- return;
- }
-
- impl_->insert(CacheNodePtr(new CacheNode(name, rrclass, rrtype,
- flags, lifespan)));
-}
-
-// Try to retrieve an entry from the cache, returning true if
-// it was found and valid.
-bool
-HotCache::retrieve(const Name& n, const RRClass& c, const RRType& t,
- RRsetPtr& rrset, uint32_t& flags)
-{
- if (!impl_->enabled_) {
- return (false);
- }
-
- std::map<Question, CacheNodePtr>::const_iterator iter;
- iter = impl_->map_.find(Question(n, c, t));
- if (iter == impl_->map_.end()) {
- LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_CACHE_NOT_FOUND).arg(n);
- return (false);
- }
-
- CacheNodePtr node = iter->second;
-
- if (node->isValid()) {
- LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_CACHE_FOUND).arg(n);
- impl_->promote(node);
- rrset = node->getRRset();
- flags = node->getFlags();
- return (true);
- }
-
- LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_CACHE_EXPIRED).arg(n);
- impl_->remove(node);
- return (false);
-}
-
-// Set the number of slots in the cache.
-void
-HotCache::setSlots(const int slots) {
- impl_->slots_ = slots;
-
- if (!impl_->enabled_) {
- return;
- }
-
- logger.info(DATASRC_CACHE_SLOTS).arg(slots).arg(max(0, impl_->count_ -
- slots));
-
- while (impl_->slots_ != 0 && impl_->count_ > impl_->slots_) {
- impl_->remove(impl_->lru_.back());
- }
-}
-
-// Return the number of slots in the cache
-int
-HotCache::getSlots() const {
- return (impl_->slots_);
-}
-
-/// Enable or disable the cache
-void
-HotCache::setEnabled(const bool e) {
- impl_->enabled_ = e;
- if (e) {
- logger.info(DATASRC_CACHE_ENABLE);
- } else {
- logger.info(DATASRC_CACHE_DISABLE);
- }
-}
-
-/// Indicate whether the cache is enabled
-bool
-HotCache::getEnabled() const {
- return (impl_->enabled_);
-}
-
-// Return the number of entries in the cache
-int
-HotCache::getCount() const {
- return (impl_->count_);
-}
-
-}
-}
+++ /dev/null
-// 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.
-
-#ifndef __CACHE_H
-#define __CACHE_H
-
-#include <time.h>
-
-#include <boost/shared_ptr.hpp>
-
-#include <dns/rrset.h>
-
-namespace isc {
-namespace dns {
-class Name;
-class RRClass;
-class RRType;
-}
-
-namespace datasrc {
-
-class CacheNode;
-typedef boost::shared_ptr<CacheNode> CacheNodePtr;
-typedef boost::shared_ptr<const CacheNode> ConstCacheNodePtr;
-
-class HotCacheImpl;
-
-/// \brief A \c HotCache is a hot-spot cache for one or more data sources.
-///
-/// A \c HotCache must be instantiated prior to creating a \c Query.
-/// The same instance should be passed to the constructor for all queries,
-/// so that all of them will be using the same cache.
-///
-/// The cache may contain positive or negative entries, indicating
-/// whether the data does or does not exist in the underlying data
-/// source. Entries have a fixed and limited lifespan (currently
-/// set to 30 seconds, see LIFESPAN_ below). If a cache entry is
-/// found which has exceeded its lifespan, it will not be returned
-/// to the caller--exactly as if it had not been found.
-///
-/// The current 30 second cache entry lifespan is experimental. A longer
-/// lifespan would improve performance somewhat; however, longer-lived
-/// cache entries are more likely to be incorrect in the event that
-/// the underlying data source had been updated. Depending on the
-/// frequency of queries and the frequency of updates, longer or
-/// shorter lifespans may be desirable -- it's even possible
-/// we may want the lifespan to be set differently depending on
-/// the zone or the data source (i.e., with an infinite lifespan
-/// for cached data from a static data source). Additional benchmarking
-/// and analysis will be needed for this.
-///
-/// The cache may be configured with a number of available slots for
-/// for entries. When set to a nonzero value, no more than that number
-/// of entries can exist in the cache. If more entries are inserted,
-/// old entries will be dropped in "least recently used" order. If
-/// set to zero, the cache size is unlimited. The current default is
-/// based on one thousand queries per second, times the number of seconds
-/// in the cache lifespan: 30,000 slots.
-///
-/// Notes to developers: The current implementation of HotCache uses
-/// a std::map (keyed by isc::dns::Question) to locate nodes, so access
-/// will generally be in O(log n) time. (XXX: This might be faster if a
-/// hash table were used instead.)
-///
-/// A linked list is also maintained to keep track of recent accesses
-/// to cache entries; each time an entry is accessed, it is moved to the
-/// head of the list; when entries need to be removed, they are taken
-/// from the tail of the list. This operation is not locked. BIND 10
-/// does not currently use threads, but if it ever does (or if libdatasrc
-/// is ever used by a threaded application), this will need to be
-/// revisited.
-class HotCache {
-private:
- /// \name Static definitions
- //@{
- /// \brief Default validity period for cache entries
- static const int LIFESPAN_ = 30;
-
- /// \brief Default number of slots in cache
- static const int SLOTS_ = 1000 * LIFESPAN_;
- //@}
-
- /// \name Constructors, Assignment Operator and Destructor.
- ///
- /// Note: The copy constructor and the assignment operator are intentionally
- /// defined as private.
- //@{
- HotCache(const HotCache& source);
- HotCache& operator=(const HotCache& source);
-
-public:
- /// \brief Constructor for HotCache
- ///
- /// \param slots The number of slots available in the cache.
- HotCache(const int slots = SLOTS_);
-
- /// \brief Destructor for HotCache
- ~HotCache();
- //@}
-
- /// \name Cache Manipulation Methods
- //@{
- /// \brief Enter a positive cache entry.
- ///
- /// If an entry already exists in the cache which matches the
- /// name/class/type of the RRset being cached, then the old entry
- /// is removed before the the new one is inserted. (XXX: This is
- /// currently slightly inefficient; it would be quicker to keep the
- /// existing node and simply update the rrset, flags, and lifespan.)
- ///
- /// \param rrset The \c RRset to cache.
- /// \param flags The query response flags returned from the low-level
- /// data source when this \c RRset was looked up.
- /// \param lifespan How long the cache node is to be considered valid;
- /// defaulting to 30 seconds.
- void addPositive(isc::dns::RRsetPtr rrset,
- uint32_t flags,
- time_t lifespan = LIFESPAN_);
-
- /// \brief Enter a negative cache entry.
- ///
- /// In the case of a negative cache entry there is no \c RRset to
- /// cache, so instead a null \c RRsetPtr will be stored. Since the
- /// name, class, and type cannot be retrieved from an \c RRset, they
- /// must be specified in the parameters.
- ///
- /// If an entry already exists in the cache which matches the
- /// specified name/class/type, then the old entry is removed
- /// before the the new one is inserted. (XXX: As noted in the comments
- /// for addPositive(), this is currently slightly inefficient.)
- ///
- /// \param name Query name
- /// \param rrclass Query class
- /// \param rrtype Query type
- /// \param flags Query response flags returned from the low-level
- /// data source, indicating why this lookup failed (name not found,
- /// type not found, etc).
- /// \param lifespan How long the cache node is to be considered valid;
- /// defaulting to 30 seconds.
- ///
- /// Note: 'rrclass' and 'rrtype' must refer to a specific class and
- /// type; it is not meaningful to cache type or class ANY. Currently,
- /// this condition is silently ignored.
- void addNegative(const isc::dns::Name& name,
- const isc::dns::RRClass& rrclass,
- const isc::dns::RRType& rrtype,
- uint32_t flags,
- time_t lifespan = LIFESPAN_);
-
- /// \brief Retrieve (and promote) a record from the cache
- ///
- /// Retrieves a record from the cache matching the given
- /// query-tuple. Returns true if one is found. If it is a
- /// positive cache entry, then 'rrset' is set to the cached
- /// RRset. For both positive and negative cache entries, 'flags'
- /// is set to the query response flags. The cache entry is
- /// then promoted to the head of the LRU queue. (NOTE: Because
- /// of this, "retrieve" cannot be implemented as a const method.)
- ///
- /// \param qname The query name
- /// \param qclass The query class
- /// \param qtype The query type
- /// \param rrset Returns the RRset found, if any, to the caller
- /// \param flags Returns the flags, if any, to the caller
- ///
- /// \return \c bool, true if data was found in the cache, false if not.
- bool retrieve(const isc::dns::Name& qname,
- const isc::dns::RRClass& qclass,
- const isc::dns::RRType& qtype,
- isc::dns::RRsetPtr& rrset,
- uint32_t& flags);
- //@}
-
- /// \name Getter and Setter Methods
- //@{
- /// \brief Sets the number of slots in the cache.
- ///
- /// If slots is set to zero, the cache can grow without any imposed
- /// limit. If slots is to set a lower number than the cache currently
- /// contains, then the least recently used records will be purged from
- /// the cache until the total number of items in the cache equals slots.
- void setSlots(int slots);
-
- /// \brief Returns the number of slots in the cache.
- int getSlots() const;
-
- /// \brief Enable or disable the cache
- void setEnabled(bool e);
-
- /// \brief Indicate whether the cache is enabled
- bool getEnabled() const;
-
- /// \brief Returns the number of nodes currently stored in the cache.
- ///
- /// Note that this doesn't indicate how many nodes are still valid;
- /// some may have expired.
- int getCount() const;
- //@}
-
-private:
- /// \brief Hidden implementation details
- HotCacheImpl* impl_;
-};
-
-}
-}
-
-#endif
-
-// Local Variables:
-// mode: c++
-// End:
+++ /dev/null
-// 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 <cassert>
-#include <iomanip>
-#include <iostream>
-#include <vector>
-
-#include <boost/shared_ptr.hpp>
-#include <boost/foreach.hpp>
-
-#include <datasrc/cache.h>
-#include <datasrc/data_source.h>
-#include <datasrc/query.h>
-#include <datasrc/logger.h>
-
-#include <util/encode/base32hex.h>
-#include <util/hash/sha1.h>
-#include <util/buffer.h>
-
-#include <dns/message.h>
-#include <dns/name.h>
-#include <dns/rcode.h>
-#include <dns/rdataclass.h>
-#include <dns/rrset.h>
-#include <dns/rrsetlist.h>
-
-#include <cc/data.h>
-
-#define RETERR(x) do { \
- DataSrc::Result r = (x); \
- if (r != DataSrc::SUCCESS) \
- return (r); \
- } while (0)
-
-using namespace std;
-using namespace isc::util;
-using namespace isc::util::encode;
-using namespace isc::util::hash;
-using namespace isc::dns;
-using namespace isc::dns::rdata;
-
-namespace {
-
-struct MatchRRsetForType {
- MatchRRsetForType(const RRType rrtype) : rrtype_(rrtype) {}
- bool operator()(RRsetPtr rrset) {
- return (rrset->getType() == rrtype_);
- }
- const RRType rrtype_;
-};
-
-// This is a helper to retrieve a specified RR type of RRset from RRsetList.
-// In our case the data source search logic should ensure that the class is
-// valid. We use this find logic of our own so that we can support both
-// specific RR class queries (normal case) and class ANY queries.
-RRsetPtr
-findRRsetFromList(RRsetList& list, const RRType rrtype) {
- RRsetList::iterator it(find_if(list.begin(), list.end(),
- MatchRRsetForType(rrtype)));
- return (it != list.end() ? *it : RRsetPtr());
-}
-}
-
-namespace isc {
-namespace datasrc {
-
-typedef boost::shared_ptr<const Nsec3Param> ConstNsec3ParamPtr;
-
-class ZoneInfo {
-public:
- ZoneInfo(DataSrc* ts,
- const isc::dns::Name& n,
- const isc::dns::RRClass& c,
- const isc::dns::RRType& t = isc::dns::RRType::ANY()) :
- top_source_(ts),
- dsm_(((t == RRType::DS() && n.getLabelCount() != 1)
- ? n.split(1, n.getLabelCount() - 1) : n),
- c)
- {}
-
- const Name* getEnclosingZone() {
- if (dsm_.getEnclosingZone() == NULL) {
- top_source_->findClosestEnclosure(dsm_);
- }
- return (dsm_.getEnclosingZone());
- }
-
- const DataSrc* getDataSource() {
- if (dsm_.getDataSource() == NULL) {
- top_source_->findClosestEnclosure(dsm_);
- }
- return (dsm_.getDataSource());
- }
-
-private:
- const DataSrc* top_source_;
- DataSrcMatch dsm_;
-};
-
-// Add a task to the query task queue to look up additional data
-// (i.e., address records for the names included in NS or MX records)
-void
-getAdditional(Query& q, ConstRRsetPtr rrset) {
- if (!q.wantAdditional()) {
- return;
- }
-
- RdataIteratorPtr it = rrset->getRdataIterator();
- for (; !it->isLast(); it->next()) {
- const Rdata& rd(it->getCurrent());
- if (rrset->getType() == RRType::NS()) {
- const generic::NS& ns = dynamic_cast<const generic::NS&>(rd);
- LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_QUERY_GET_NS_ADDITIONAL).
- arg(ns.getNSName()).arg(rrset->getName());
- q.tasks().push(QueryTaskPtr(
- new QueryTask(q, ns.getNSName(),
- Message::SECTION_ADDITIONAL,
- QueryTask::GLUE_QUERY,
- QueryTask::GETADDITIONAL)));
- } else if (rrset->getType() == RRType::MX()) {
- const generic::MX& mx = dynamic_cast<const generic::MX&>(rd);
- LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_QUERY_GET_MX_ADDITIONAL).
- arg(mx.getMXName()).arg(rrset->getName());
- q.tasks().push(QueryTaskPtr(
- new QueryTask(q, mx.getMXName(),
- Message::SECTION_ADDITIONAL,
- QueryTask::NOGLUE_QUERY,
- QueryTask::GETADDITIONAL)));
- }
- }
-}
-
-// Synthesize a CNAME answer, for the benefit of clients that don't
-// understand DNAME
-void
-synthesizeCname(QueryTaskPtr task, RRsetPtr rrset, RRsetList& target) {
- LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_QUERY_SYNTH_CNAME).
- arg(rrset->getName());
- RdataIteratorPtr it = rrset->getRdataIterator();
-
- // More than one DNAME RR in the RRset is illegal, so we only have
- // to process the first one.
- if (it->isLast()) {
- logger.error(DATASRC_QUERY_EMPTY_DNAME).arg(rrset->getName());
- return;
- }
-
- const Rdata& rd(it->getCurrent());
- const generic::DNAME& dname = dynamic_cast<const generic::DNAME&>(rd);
- const Name& dname_target(dname.getDname());
-
- RRsetPtr cname(new RRset(task->qname, rrset->getClass(), RRType::CNAME(),
- rrset->getTTL()));
-
- const int qnlen = task->qname.getLabelCount();
- const int dnlen = rrset->getName().getLabelCount();
- assert(qnlen > dnlen);
- const Name& prefix(task->qname.split(0, qnlen - dnlen));
- cname->addRdata(generic::CNAME(prefix.concatenate(dname_target)));
-
- target.addRRset(cname);
-}
-
-// Add a task to the query task queue to look up the data pointed
-// to by a CNAME record
-void
-chaseCname(Query& q, QueryTaskPtr task, RRsetPtr rrset) {
- LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_QUERY_FOLLOW_CNAME).
- arg(rrset->getName());
- RdataIteratorPtr it = rrset->getRdataIterator();
-
- // More than one CNAME RR in the RRset is illegal, so we only have
- // to process the first one.
- if (it->isLast()) {
- logger.error(DATASRC_QUERY_EMPTY_CNAME).arg(rrset->getName());
- return;
- }
-
- // Stop chasing CNAMES after 16 lookups, to prevent loops
- if (q.tooMany()) {
- logger.error(DATASRC_QUERY_TOO_MANY_CNAMES).arg(rrset->getName());
- return;
- }
-
- q.tasks().push(QueryTaskPtr(
- new QueryTask(q, dynamic_cast<const generic::CNAME&>
- (it->getCurrent()).getCname(),
- task->qtype, Message::SECTION_ANSWER,
- QueryTask::FOLLOWCNAME)));
-}
-
-// Check the cache for data which can answer the current query task.
-bool
-checkCache(QueryTask& task, RRsetList& target) {
- LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_QUERY_CHECK_CACHE).
- arg(task.qname).arg(task.qtype);
- HotCache& cache = task.q.getCache();
- RRsetList rrsets;
- RRsetPtr rrset;
- int count = 0;
- uint32_t flags = 0, cflags = 0;
- bool hit = false, found = false;
-
- switch (task.op) {
- case QueryTask::SIMPLE_QUERY: // Find exact RRset
- // ANY queries must be handled by the low-level data source,
- // or the results won't be guaranteed to be complete
- if (task.qtype == RRType::ANY() || task.qclass == RRClass::ANY()) {
- LOG_DEBUG(logger, DBG_TRACE_DATA,
- DATASRC_QUERY_NO_CACHE_ANY_SIMPLE).arg(task.qname).
- arg(task.qtype).arg(task.qclass);
- break;
- }
-
- hit = cache.retrieve(task.qname, task.qclass, task.qtype, rrset, flags);
- if (hit) {
- if (rrset) {
- rrsets.addRRset(rrset);
- target.append(rrsets);
- }
-
- // Reset the referral flag and treat CNAME as "not found".
- // This emulates the behavior of the sqlite3 data source.
- // XXX: this is not ideal in that the responsibility for handling
- // operation specific cases is spread over various classes at
- // different abstraction levels. For longer terms we should
- // revisit the whole datasource/query design, and clarify this
- // point better.
- flags &= ~DataSrc::REFERRAL;
- if ((flags & DataSrc::CNAME_FOUND) != 0) {
- flags &= ~DataSrc::CNAME_FOUND;
- flags |= DataSrc::TYPE_NOT_FOUND;
- }
- task.flags = flags;
- return (true);
- }
- break;
-
- case QueryTask::AUTH_QUERY: // Find exact RRset or CNAME
- if (task.qtype == RRType::ANY() || task.qclass == RRClass::ANY()) {
- LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_QUERY_NO_CACHE_ANY_AUTH).
- arg(task.qname).arg(task.qtype).arg(task.qclass);
- break;
- }
-
- hit = cache.retrieve(task.qname, task.qclass, task.qtype, rrset, flags);
- if (!hit || !rrset || (flags & DataSrc::CNAME_FOUND) != 0) {
- hit = cache.retrieve(task.qname, task.qclass, RRType::CNAME(),
- rrset, flags);
- if (!rrset) {
- // If we don't have a positive cache, forget it; otherwise the
- // intermediate result may confuse the subsequent processing.
- hit = false;
- }
- }
-
- if (hit) {
- if (rrset) {
- rrsets.addRRset(rrset);
- target.append(rrsets);
- }
- task.flags = flags;
- return (true);
- }
- break;
-
- case QueryTask::GLUE_QUERY: // Find addresses
- case QueryTask::NOGLUE_QUERY:
- // (XXX: need to figure out how to deal with noglue case)
- flags = 0;
-
- hit = cache.retrieve(task.qname, task.qclass, RRType::A(),
- rrset, cflags);
- if (hit) {
- flags |= cflags;
- ++count;
- if (rrset) {
- rrsets.addRRset(rrset);
- found = true;
- }
- }
-
- hit = cache.retrieve(task.qname, task.qclass, RRType::AAAA(),
- rrset, flags);
- if (hit) {
- flags |= cflags;
- ++count;
- if (rrset) {
- rrsets.addRRset(rrset);
- found = true;
- }
- }
-
- if (count == 2) {
- if (found) {
- flags &= ~DataSrc::TYPE_NOT_FOUND;
- target.append(rrsets);
- }
- task.flags = flags;
- return (true);
- }
- break;
-
-
- case QueryTask::REF_QUERY: // Find NS, DS and/or DNAME
- flags = count = 0;
-
- hit = cache.retrieve(task.qname, task.qclass, RRType::NS(),
- rrset, cflags);
- if (hit) {
- flags |= cflags;
- ++count;
- if (rrset) {
- rrsets.addRRset(rrset);
- found = true;
- }
- }
-
- hit = cache.retrieve(task.qname, task.qclass, RRType::DS(),
- rrset, flags);
- if (hit) {
- flags |= cflags;
- ++count;
- if (rrset) {
- rrsets.addRRset(rrset);
- found = true;
- }
- }
-
- hit = cache.retrieve(task.qname, task.qclass, RRType::DNAME(),
- rrset, flags);
- if (hit) {
- flags |= cflags;
- ++count;
- if (rrset) {
- rrsets.addRRset(rrset);
- found = true;
- }
- }
-
- if (count == 3) {
- if (found) {
- flags &= ~DataSrc::TYPE_NOT_FOUND;
- flags &= DataSrc::REFERRAL;
- target.append(rrsets);
- }
- task.flags = flags;
- return (true);
- }
- break;
- }
-
- return (false);
-}
-
-// Carry out the query specified in a QueryTask object
-DataSrc::Result
-doQueryTask(QueryTask& task, ZoneInfo& zoneinfo, RRsetList& target) {
- HotCache& cache = task.q.getCache();
- RRsetPtr rrset;
- LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_DO_QUERY).arg(task.qname).
- arg(task.qtype);
-
- // First off, make sure at least we have a matching zone in some data
- // source. We must do this before checking the cache, because it can
- // happen that the matching zone has been removed after an RRset of that
- // zone is cached. Such inconsistency will cause various problems,
- // including a crash.
- const DataSrc* ds = zoneinfo.getDataSource();
- const Name* const zonename = zoneinfo.getEnclosingZone();
- if (ds == NULL) {
- task.flags |= DataSrc::NO_SUCH_ZONE;
- LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_QUERY_NO_ZONE).
- arg(task.qname).arg(task.qclass);
- return (DataSrc::SUCCESS);
- }
-
- // Then check the cache for matching data
- if (checkCache(task, target)) {
- LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_QUERY_CACHED).
- arg(task.qname).arg(task.qtype);
- return (DataSrc::SUCCESS);
- }
-
- // Requested data weren't in the cache (or were, but had expired),
- // so now we proceed with the low-level data source lookup, and cache
- // whatever we find.
-
- DataSrc::Result result;
- switch (task.op) {
- case QueryTask::SIMPLE_QUERY:
- LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_QUERY_IS_SIMPLE).
- arg(task.qname).arg(task.qtype);
- result = ds->findExactRRset(task.qname, task.qclass, task.qtype,
- target, task.flags, zonename);
-
- if (result != DataSrc::SUCCESS) {
- logger.error(DATASRC_QUERY_SIMPLE_FAIL).arg(result);
- return (result);
- }
-
- if (task.qclass == RRClass::ANY()) {
- // XXX: Currently, RRsetList::findRRset() doesn't handle
- // ANY queries, and without that we can't cache the results,
- // so we just return in that case.
- return (result);
- }
-
- if (task.flags == 0) {
- rrset = target.findRRset(task.qtype, task.qclass);
- assert(rrset);
- cache.addPositive(rrset, task.flags);
- } else {
- cache.addNegative(task.qname, task.qclass, task.qtype, task.flags);
- }
-
- return (result);
-
- case QueryTask::AUTH_QUERY:
- LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_QUERY_IS_AUTH).
- arg(task.qname).arg(task.qtype);
- result = ds->findRRset(task.qname, task.qclass, task.qtype,
- target, task.flags, zonename);
-
- if (result != DataSrc::SUCCESS) {
- logger.error(DATASRC_QUERY_AUTH_FAIL).arg(result);
- return (result);
- }
-
- if (task.qclass == RRClass::ANY()) {
- return (result);
- }
-
- if (task.qtype == RRType::ANY()) {
- BOOST_FOREACH(RRsetPtr rr, target) {
- cache.addPositive(rr, task.flags);
- }
- } else if ((task.flags & DataSrc::CNAME_FOUND) != 0) {
- cache.addNegative(task.qname, task.qclass, task.qtype, task.flags);
- rrset = target.findRRset(RRType::CNAME(), task.qclass);
- assert(rrset);
- cache.addPositive(rrset, task.flags);
- } else if ((task.flags & DataSrc::DATA_NOT_FOUND) == 0) {
- if (task.qtype != RRType::CNAME()) {
- cache.addNegative(task.qname, task.qclass, RRType::CNAME(),
- task.flags);
- }
- rrset = target.findRRset(task.qtype, task.qclass);
- assert(rrset);
- cache.addPositive(rrset, task.flags);
- } else {
- cache.addNegative(task.qname, task.qclass, task.qtype, task.flags);
- }
-
- return (result);
-
- case QueryTask::GLUE_QUERY:
- case QueryTask::NOGLUE_QUERY:
- LOG_DEBUG(logger, DBG_TRACE_DATA, task.op == QueryTask::GLUE_QUERY ?
- DATASRC_QUERY_IS_GLUE : DATASRC_QUERY_IS_NOGLUE).
- arg(task.qname).arg(task.qtype);
- result = ds->findAddrs(task.qname, task.qclass, target,
- task.flags, zonename);
-
- if (result != DataSrc::SUCCESS) {
- logger.error(task.op == QueryTask::GLUE_QUERY ?
- DATASRC_QUERY_GLUE_FAIL : DATASRC_QUERY_NOGLUE_FAIL).
- arg(result);
- return (result);
- }
-
- if (task.qclass == RRClass::ANY()) {
- return (result);
- }
-
- rrset = target.findRRset(RRType::A(), task.qclass);
- if (rrset) {
- cache.addPositive(rrset, task.flags);
- } else {
- cache.addNegative(task.qname, task.qclass, RRType::A(), task.flags);
- }
-
- rrset = target.findRRset(RRType::AAAA(), task.qclass);
- if (rrset) {
- cache.addPositive(rrset, task.flags);
- } else {
- cache.addNegative(task.qname, task.qclass, RRType::AAAA(),
- task.flags);
- }
-
- return (result);
-
- case QueryTask::REF_QUERY:
- LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_QUERY_IS_REF).
- arg(task.qname).arg(task.qtype);
- result = ds->findReferral(task.qname, task.qclass, target,
- task.flags, zonename);
-
- if (result != DataSrc::SUCCESS) {
- logger.error(DATASRC_QUERY_REF_FAIL).arg(result);
- return (result);
- }
-
- if (task.qclass == RRClass::ANY()) {
- return (result);
- }
-
- rrset = target.findRRset(RRType::NS(), task.qclass);
- if (rrset) {
- cache.addPositive(rrset, task.flags);
- } else {
- cache.addNegative(task.qname, task.qclass, RRType::NS(),
- task.flags);
- }
- rrset = target.findRRset(RRType::DS(), task.qclass);
- if (rrset) {
- cache.addPositive(rrset, task.flags);
- } else {
- cache.addNegative(task.qname, task.qclass, RRType::DS(),
- task.flags);
- }
- rrset = target.findRRset(RRType::DNAME(), task.qclass);
- if (rrset) {
- cache.addPositive(rrset, task.flags);
- } else {
- cache.addNegative(task.qname, task.qclass, RRType::DNAME(),
- task.flags);
- }
-
- return (result);
- }
-
- // Not reached
- logger.error(DATASRC_QUERY_INVALID_OP);
- return (DataSrc::ERROR);
-}
-
-
-// Add an RRset (and its associated RRSIG) to a message section,
-// checking first to ensure that there isn't already an RRset with
-// the same name and type.
-inline void
-addToMessage(Query& q, const Message::Section sect, RRsetPtr rrset,
- bool no_dnssec = false)
-{
- LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_QUERY_ADD_RRSET).
- arg(rrset->getName()).arg(rrset->getType());
- Message& m = q.message();
- if (no_dnssec) {
- if (rrset->getType() == RRType::RRSIG() ||
- !m.hasRRset(sect, rrset->getName(), rrset->getClass(),
- rrset->getType())) {
- m.addRRset(sect, rrset);
- }
- } else {
- if (!m.hasRRset(sect, rrset->getName(), rrset->getClass(),
- rrset->getType())) {
- m.addRRset(sect, rrset);
- }
- }
-}
-
-// Copy referral information into the authority section of a message
-inline void
-copyAuth(Query& q, RRsetList& auth) {
- LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_QUERY_COPY_AUTH);
- BOOST_FOREACH(RRsetPtr rrset, auth) {
- if (rrset->getType() == RRType::DNAME()) {
- continue;
- }
- if (rrset->getType() == RRType::DS() && !q.wantDnssec()) {
- continue;
- }
- addToMessage(q, Message::SECTION_AUTHORITY, rrset);
- getAdditional(q, rrset);
- }
-}
-
-// Query for referrals (i.e., NS/DS or DNAME) at a given name
-inline bool
-refQuery(const Query& q, const Name& name, ZoneInfo& zoneinfo,
- RRsetList& target)
-{
- QueryTask newtask(q, name, QueryTask::REF_QUERY);
-
- if (doQueryTask(newtask, zoneinfo, target) != DataSrc::SUCCESS) {
- // Lookup failed
- return (false);
- }
-
- // Referral bit is expected, so clear it when checking flags
- if ((newtask.flags & ~DataSrc::REFERRAL) != 0) {
- return (false);
- }
-
- return (true);
-}
-
-// Match downward, from the zone apex to the query name, looking for
-// referrals. Note that we exclude the apex name and query name themselves;
-// they'll be handled in a normal lookup in the zone.
-inline bool
-hasDelegation(Query& q, QueryTaskPtr task, ZoneInfo& zoneinfo) {
- LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_QUERY_DELEGATION).
- arg(task->qname);
-
- const Name* const zonename = zoneinfo.getEnclosingZone();
- if (zonename == NULL) {
- if (task->state == QueryTask::GETANSWER) {
- q.message().setRcode(Rcode::REFUSED());
- }
- return (false);
- }
-
- const int diff = task->qname.getLabelCount() - zonename->getLabelCount();
- if (diff > 1) {
- bool found = false;
- RRsetList ref;
- for (int i = diff - 1; i > 0; --i) {
- const Name sub(task->qname.split(i));
- if (refQuery(q, sub, zoneinfo, ref)) {
- found = true;
- break;
- }
- }
-
- // Found a referral while getting additional data
- // for something other than NS; we skip it.
- if (found && task->op == QueryTask::NOGLUE_QUERY) {
- return (true);
- }
-
- // Found a referral while getting answer data;
- // send a delegation.
- if (found) {
- RRsetPtr r = findRRsetFromList(ref, RRType::DNAME());
- if (r != NULL) {
- RRsetList syn;
- addToMessage(q, Message::SECTION_ANSWER, r);
- q.message().setHeaderFlag(Message::HEADERFLAG_AA);
- synthesizeCname(task, r, syn);
- if (syn.size() == 1) {
- RRsetPtr cname_rrset = findRRsetFromList(syn,
- RRType::CNAME());
- addToMessage(q, Message::SECTION_ANSWER, cname_rrset);
- chaseCname(q, task, cname_rrset);
- return (true);
- }
- }
-
- copyAuth(q, ref);
- return (true);
- }
- }
-
- // We appear to have authoritative data; set the header
- // flag. (We may clear it later if we find a referral
- // at the actual qname node.)
- if (task->op == QueryTask::AUTH_QUERY &&
- task->state == QueryTask::GETANSWER) {
- q.message().setHeaderFlag(Message::HEADERFLAG_AA);
- }
-
- return (false);
-}
-
-inline DataSrc::Result
-addSOA(Query& q, ZoneInfo& zoneinfo) {
- RRsetList soa;
-
- const Name* const zonename = zoneinfo.getEnclosingZone();
- LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_QUERY_ADD_SOA).arg(*zonename);
- QueryTask newtask(q, *zonename, RRType::SOA(), QueryTask::SIMPLE_QUERY);
- RETERR(doQueryTask(newtask, zoneinfo, soa));
- if (newtask.flags != 0) {
- return (DataSrc::ERROR);
- }
-
- addToMessage(q, Message::SECTION_AUTHORITY,
- findRRsetFromList(soa, RRType::SOA()));
- return (DataSrc::SUCCESS);
-}
-
-inline DataSrc::Result
-addNSEC(Query& q, const Name& name, ZoneInfo& zoneinfo) {
- LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_QUERY_ADD_NSEC).arg(name);
- RRsetList nsec;
-
- QueryTask newtask(q, name, RRType::NSEC(), QueryTask::SIMPLE_QUERY);
- RETERR(doQueryTask(newtask, zoneinfo, nsec));
- if (newtask.flags == 0) {
- addToMessage(q, Message::SECTION_AUTHORITY,
- findRRsetFromList(nsec, RRType::NSEC()));
- }
-
- return (DataSrc::SUCCESS);
-}
-
-inline DataSrc::Result
-getNsec3(Query& q, ZoneInfo& zoneinfo, string& hash, RRsetPtr& target) {
- const DataSrc* ds = zoneinfo.getDataSource();
- const Name* const zonename = zoneinfo.getEnclosingZone();
- LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_QUERY_ADD_NSEC3).arg(*zonename);
-
- if (ds == NULL) {
- q.message().setRcode(Rcode::SERVFAIL());
- logger.error(DATASRC_QUERY_NO_DS_NSEC3).arg(*zonename);
- return (DataSrc::ERROR);
- }
-
- RRsetList rl;
- RETERR(ds->findCoveringNSEC3(*zonename, hash, rl));
- target = rl.findRRset(RRType::NSEC3(), q.qclass());
-
- return (DataSrc::SUCCESS);
-}
-
-ConstNsec3ParamPtr
-getNsec3Param(Query& q, ZoneInfo& zoneinfo) {
- DataSrc::Result result;
- RRsetList nsec3param;
-
- const Name* const zonename = zoneinfo.getEnclosingZone();
- QueryTask newtask(q, *zonename, RRType::NSEC3PARAM(),
- QueryTask::SIMPLE_QUERY);
- result = doQueryTask(newtask, zoneinfo, nsec3param);
- newtask.flags &= ~DataSrc::REFERRAL;
- if (result != DataSrc::SUCCESS || newtask.flags != 0) {
- return (ConstNsec3ParamPtr());
- }
-
- RRsetPtr rrset = nsec3param.findRRset(RRType::NSEC3PARAM(), q.qclass());
- if (!rrset) {
- return (ConstNsec3ParamPtr());
- }
-
- // XXX: currently only one NSEC3 chain per zone is supported;
- // we will need to revisit this.
- RdataIteratorPtr it = rrset->getRdataIterator();
- if (it->isLast()) {
- return (ConstNsec3ParamPtr());
- }
-
- const generic::NSEC3PARAM& np =
- dynamic_cast<const generic::NSEC3PARAM&>(it->getCurrent());
- return (ConstNsec3ParamPtr(new Nsec3Param(np.getHashalg(), np.getFlags(),
- np.getIterations(),
- np.getSalt())));
-}
-
-inline DataSrc::Result
-proveNX(Query& q, QueryTaskPtr task, ZoneInfo& zoneinfo, const bool wildcard) {
- Message& m = q.message();
- const Name* const zonename = zoneinfo.getEnclosingZone();
- ConstNsec3ParamPtr nsec3 = getNsec3Param(q, zoneinfo);
-
- if (nsec3 != NULL) {
- // Attach the NSEC3 record covering the QNAME
- RRsetPtr rrset;
- string hash1(nsec3->getHash(task->qname));
- RETERR(getNsec3(q, zoneinfo, hash1, rrset));
- addToMessage(q, Message::SECTION_AUTHORITY, rrset);
-
- // If this is an NXRRSET or NOERROR/NODATA, we're done
- if ((task->flags & DataSrc::TYPE_NOT_FOUND) != 0) {
- return (DataSrc::SUCCESS);
- }
-
- // Find the closest provable enclosing name for QNAME
- Name enclosure(*zonename);
- const int diff = task->qname.getLabelCount() -
- enclosure.getLabelCount();
- string hash2;
- for (int i = 1; i <= diff; ++i) {
- enclosure = task->qname.split(i);
- string nodehash(nsec3->getHash(enclosure));
- if (nodehash == hash1) {
- break;
- }
- hash2 = nodehash;
- RRsetList rl;
-
- // hash2 will be overwritten with the actual hash found;
- // we don't want to use one until we find an exact match
- RETERR(getNsec3(q, zoneinfo, hash2, rrset));
- if (hash2 == nodehash) {
- addToMessage(q, Message::SECTION_AUTHORITY, rrset);
- break;
- }
- }
-
- // If we are processing a wildcard answer, we're done.
- if (wildcard) {
- return (DataSrc::SUCCESS);
- }
-
- // Otherwise, there is no wildcard record, so we must add a
- // covering NSEC3 to prove that it doesn't exist.
- string hash3(nsec3->getHash(Name("*").concatenate(enclosure)));
- RETERR(getNsec3(q, zoneinfo, hash3, rrset));
- if (hash3 != hash1 && hash3 != hash2) {
- addToMessage(q, Message::SECTION_AUTHORITY, rrset);
- }
- } else {
- Name nsecname(task->qname);
- if ((task->flags & DataSrc::NAME_NOT_FOUND) != 0 || wildcard) {
- const DataSrc* ds = zoneinfo.getDataSource();
- if (ds == NULL) {
- m.setRcode(Rcode::SERVFAIL());
- logger.error(DATASRC_QUERY_NO_DS_NSEC).arg(*zonename);
- return (DataSrc::ERROR);
- }
- ds->findPreviousName(task->qname, nsecname, zonename);
- }
-
- RETERR(addNSEC(q, nsecname, zoneinfo));
- if ((task->flags & DataSrc::TYPE_NOT_FOUND) != 0 ||
- nsecname == *zonename)
- {
- return (DataSrc::SUCCESS);
- }
-
- // If we are processing a wildcard answer, we're done.
- if (wildcard) {
- return (DataSrc::SUCCESS);
- }
-
- // Otherwise, there is no wildcard record, so we must add an
- // NSEC for the zone to prove the wildcard doesn't exist.
- RETERR(addNSEC(q, *zonename, zoneinfo));
- }
-
- return (DataSrc::SUCCESS);
-}
-
-// Attempt a wildcard lookup
-inline DataSrc::Result
-tryWildcard(Query& q, QueryTaskPtr task, ZoneInfo& zoneinfo, bool& found) {
- LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_QUERY_WILDCARD).arg(task->qname);
- Message& m = q.message();
- DataSrc::Result result;
- found = false;
-
- if ((task->flags & DataSrc::NAME_NOT_FOUND) == 0 ||
- (task->state != QueryTask::GETANSWER &&
- task->state != QueryTask::FOLLOWCNAME)) {
- return (DataSrc::SUCCESS);
- }
-
- const Name* const zonename = zoneinfo.getEnclosingZone();
- const int diff = task->qname.getLabelCount() - zonename->getLabelCount();
- if (diff < 1) {
- return (DataSrc::SUCCESS);
- }
-
- RRsetList wild;
- const Name star("*");
- bool cname = false;
-
- for (int i = 1; i <= diff; ++i) {
- const Name& wname(star.concatenate(task->qname.split(i)));
- QueryTask newtask(q, wname, task->qtype, Message::SECTION_ANSWER,
- QueryTask::AUTH_QUERY);
- result = doQueryTask(newtask, zoneinfo, wild);
- if (result == DataSrc::SUCCESS) {
- if (newtask.flags == 0) {
- task->flags &= ~DataSrc::NAME_NOT_FOUND;
- task->flags &= ~DataSrc::TYPE_NOT_FOUND;
- found = true;
- break;
- } else if ((newtask.flags & DataSrc::CNAME_FOUND) != 0) {
- task->flags &= ~DataSrc::NAME_NOT_FOUND;
- task->flags &= ~DataSrc::TYPE_NOT_FOUND;
- task->flags |= DataSrc::CNAME_FOUND;
- found = true;
- cname = true;
- break;
- } else if ((newtask.flags & DataSrc::TYPE_NOT_FOUND) != 0) {
- task->flags &= ~DataSrc::NAME_NOT_FOUND;
- task->flags |= DataSrc::TYPE_NOT_FOUND;
- break;
- }
- }
- }
-
- // A wildcard was found.
- if (found) {
- // Prove the nonexistence of the name we were looking for
- if (q.wantDnssec()) {
- result = proveNX(q, task, zoneinfo, true);
- if (result != DataSrc::SUCCESS) {
- m.setRcode(Rcode::SERVFAIL());
- logger.error(DATASRC_QUERY_WILDCARD_PROVE_NX_FAIL).
- arg(task->qname).arg(result);
- return (DataSrc::ERROR);
- }
- }
-
- // Add the data to the answer section (but with the name changed to
- // match the qname), and then continue as if this were a normal
- // answer: if a CNAME, chase the target, otherwise add authority.
- if (cname) {
- RRsetPtr rrset = findRRsetFromList(wild, RRType::CNAME());
- if (rrset != NULL) {
- rrset->setName(task->qname);
- addToMessage(q, Message::SECTION_ANSWER, rrset);
- chaseCname(q, task, rrset);
- }
- } else {
- BOOST_FOREACH (RRsetPtr rrset, wild) {
- rrset->setName(task->qname);
- addToMessage(q, Message::SECTION_ANSWER, rrset);
- }
-
- RRsetList auth;
- if (!refQuery(q, *zonename, zoneinfo, auth)) {
- logger.error(DATASRC_QUERY_WILDCARD_REFERRAL).arg(task->qname).
- arg(result);
- return (DataSrc::ERROR);
- }
-
- copyAuth(q, auth);
- }
- }
-
- return (DataSrc::SUCCESS);
-}
-
-//
-// doQuery: Processes a query.
-//
-void
-DataSrc::doQuery(Query& q) {
- LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_QUERY_PROCESS).arg(q.qname()).
- arg(q.qtype()).arg(q.qclass());
- Message& m = q.message();
- vector<RRsetPtr> additional;
-
- // Record the fact that the query is being processed by the
- // current data source.
- q.setDatasrc(this);
-
- // Process the query task queue. (The queue is initialized
- // and the first task placed on it by the Query constructor.)
- m.setHeaderFlag(Message::HEADERFLAG_AA, false);
- while (!q.tasks().empty()) {
- QueryTaskPtr task = q.tasks().front();
- q.tasks().pop();
-
- // Can't query directly for RRSIG.
- if (task->qtype == RRType::RRSIG()) {
- m.setRcode(Rcode::REFUSED());
- logger.warn(DATASRC_QUERY_RRSIG).arg(task->qname);
- return;
- }
-
- // These task types should never be on the task queue.
- if (task->op == QueryTask::SIMPLE_QUERY ||
- task->op == QueryTask::REF_QUERY) {
- m.setRcode(Rcode::SERVFAIL());
- logger.error(DATASRC_QUERY_MISPLACED_TASK);
- return;
- }
-
- ZoneInfo zoneinfo(this, task->qname, task->qclass, task->qtype);
- RRsetList data;
- Result result = SUCCESS;
-
- // For these query task types, if there is more than
- // one level between the zone name and qname, we need to
- // check the intermediate nodes for referrals.
- if ((task->op == QueryTask::AUTH_QUERY ||
- task->op == QueryTask::NOGLUE_QUERY) &&
- hasDelegation(q, task, zoneinfo)) {
- continue;
- }
-
- result = doQueryTask(*task, zoneinfo, data);
- if (result != SUCCESS) {
- m.setRcode(Rcode::SERVFAIL());
- logger.error(DATASRC_QUERY_TASK_FAIL).arg(result);
- return;
- }
-
- // No such zone. If we're chasing cnames or adding additional
- // data, that's okay, but if doing an original query, return
- // REFUSED.
- if (task->flags == NO_SUCH_ZONE) {
- if (task->state == QueryTask::GETANSWER) {
- m.setRcode(Rcode::REFUSED());
- // No need to log it here, it was already logged in doQueryTask
- return;
- }
- continue;
- }
-
- // Query found a referral; let's find out if that was expected--
- // i.e., if an NS was at the zone apex, or if we were querying
- // specifically for, and found, a DS, NSEC, or DNAME record.
- const Name* const zonename = zoneinfo.getEnclosingZone();
- if ((task->flags & REFERRAL) != 0 &&
- (zonename->getLabelCount() == task->qname.getLabelCount() ||
- ((task->qtype == RRType::NSEC() ||
- task->qtype == RRType::DS() ||
- task->qtype == RRType::DNAME()) &&
- findRRsetFromList(data, task->qtype)))) {
- task->flags &= ~REFERRAL;
- }
-
- if (result == SUCCESS && task->flags == 0) {
- bool have_ns = false, need_auth = false;
- switch (task->state) {
- case QueryTask::GETANSWER:
- case QueryTask::FOLLOWCNAME:
- BOOST_FOREACH(RRsetPtr rrset, data) {
- addToMessage(q, task->section, rrset);
- if (q.tasks().empty()) {
- need_auth = true;
- }
- getAdditional(q, rrset);
- if (rrset->getType() == RRType::NS()) {
- have_ns = true;
- }
- }
- q.setStatus(Query::ANSWERED);
- if (need_auth && !have_ns) {
- // Data found, no additional processing needed.
- // Add the NS records for the enclosing zone to
- // the authority section.
- RRsetList auth;
- if (!refQuery(q, Name(*zonename), zoneinfo, auth) ||
- !findRRsetFromList(auth, RRType::NS())) {
- logger.error(DATASRC_QUERY_MISSING_NS).arg(*zonename);
- isc_throw(DataSourceError,
- "NS RR not found in " << *zonename << "/" <<
- q.qclass());
- }
-
- copyAuth(q, auth);
- }
- continue;
-
- case QueryTask::GETADDITIONAL:
- // Got additional data. Do not add it to the message
- // yet; instead store it and copy it in at the end
- // (this allow RRSIGs to be omitted if necessary).
- BOOST_FOREACH(RRsetPtr rrset, data) {
- if (q.status() == Query::ANSWERED &&
- rrset->getName() == q.qname() &&
- rrset->getType() == q.qtype()) {
- continue;
- }
- additional.push_back(rrset);
- }
- continue;
-
- default:
- logger.error(DATASRC_UNEXPECTED_QUERY_STATE);
- isc_throw (Unexpected, "unexpected query state");
- }
- } else if (result == ERROR || result == NOT_IMPLEMENTED) {
- m.setRcode(Rcode::SERVFAIL());
- logger.error(DATASRC_QUERY_FAIL);
- return;
- } else if ((task->flags & CNAME_FOUND) != 0) {
- // The qname node contains a CNAME. Add a new task to the
- // queue to look up its target.
- RRsetPtr rrset = findRRsetFromList(data, RRType::CNAME());
- if (rrset != NULL) {
- addToMessage(q, task->section, rrset);
- chaseCname(q, task, rrset);
- }
- continue;
- } else if ((task->flags & REFERRAL) != 0) {
- // The qname node contains an out-of-zone referral.
- if (task->state == QueryTask::GETANSWER) {
- RRsetList auth;
- m.setHeaderFlag(Message::HEADERFLAG_AA, false);
- if (!refQuery(q, task->qname, zoneinfo, auth)) {
- m.setRcode(Rcode::SERVFAIL());
- logger.error(DATASRC_QUERY_BAD_REFERRAL).arg(task->qname);
- return;
- }
- BOOST_FOREACH (RRsetPtr rrset, auth) {
- if (rrset->getType() == RRType::NS()) {
- addToMessage(q, Message::SECTION_AUTHORITY, rrset);
- } else if (rrset->getType() == task->qtype) {
- addToMessage(q, Message::SECTION_ANSWER, rrset);
- } else if (rrset->getType() == RRType::DS() &&
- q.wantDnssec()) {
- addToMessage(q, Message::SECTION_AUTHORITY, rrset);
- }
- getAdditional(q, rrset);
- }
- }
- continue;
- } else if ((task->flags & (NAME_NOT_FOUND|TYPE_NOT_FOUND)) != 0) {
- // No data found at this qname/qtype.
-
- // If we were looking for additional data, we should simply
- // ignore this result.
- if (task->state == QueryTask::GETADDITIONAL) {
- continue;
- }
-
- // If we were looking for answer data, not additional,
- // and the name was not found, we need to find out whether
- // there are any relevant wildcards.
- bool wildcard_found = false;
- result = tryWildcard(q, task, zoneinfo, wildcard_found);
- if (result != SUCCESS) {
- m.setRcode(Rcode::SERVFAIL());
- logger.error(DATASRC_QUERY_WILDCARD_FAIL).arg(task->qname);
- return;
- }
-
- if (wildcard_found) {
- continue;
- }
-
- // If we've reached this point, there is definitely no answer.
- // If we were chasing cnames or adding additional data, that's
- // okay, but if we were doing an original query, reply with the
- // SOA in the authority section. For NAME_NOT_FOUND, set
- // NXDOMAIN, and also add the previous NSEC to the authority
- // section. For TYPE_NOT_FOUND, do not set an error rcode,
- // and send the current NSEC in the authority section.
- if (task->state == QueryTask::GETANSWER) {
- if ((task->flags & NAME_NOT_FOUND) != 0) {
- m.setRcode(Rcode::NXDOMAIN());
- }
-
- result = addSOA(q, zoneinfo);
- if (result != SUCCESS) {
- logger.error(DATASRC_QUERY_MISSING_SOA).arg(*zonename);
- isc_throw(DataSourceError,
- "SOA RR not found in " << *zonename <<
- "/" << q.qclass());
- }
- }
-
- Name nsecname(task->qname);
- if ((task->flags & NAME_NOT_FOUND) != 0) {
- const DataSrc* ds = zoneinfo.getDataSource();
- ds->findPreviousName(task->qname, nsecname, zonename);
- }
-
- if (q.wantDnssec()) {
- result = proveNX(q, task, zoneinfo, false);
- if (result != DataSrc::SUCCESS) {
- m.setRcode(Rcode::SERVFAIL());
- logger.error(DATASRC_QUERY_PROVE_NX_FAIL).arg(task->qname);
- return;
- }
- }
-
- return;
- } else {
- // Should never be reached!
- m.setRcode(Rcode::SERVFAIL());
- logger.error(DATASRC_QUERY_UNKNOWN_RESULT);
- return;
- }
- }
-
- // We're done, so now copy in the additional data:
- // data first, then signatures. (If we run out of
- // space, signatures in additional section are
- // optional.)
- BOOST_FOREACH(RRsetPtr rrset, additional) {
- addToMessage(q, Message::SECTION_ADDITIONAL, rrset, true);
- }
-
- if (q.wantDnssec()) {
- BOOST_FOREACH(RRsetPtr rrset, additional) {
- if (rrset->getRRsig()) {
- addToMessage(q, Message::SECTION_ADDITIONAL, rrset->getRRsig(),
- true);
- }
- }
- }
-}
-
-DataSrc::Result
-DataSrc::findAddrs(const Name& qname, const RRClass& qclass,
- RRsetList& target, uint32_t& flags,
- const Name* zonename) const
-{
- Result r;
- bool a = false, aaaa = false;
-
- flags = 0;
- r = findExactRRset(qname, qclass, RRType::A(), target, flags, zonename);
- if (r == SUCCESS && flags == 0) {
- a = true;
- }
-
- flags = 0;
- r = findExactRRset(qname, qclass, RRType::AAAA(), target, flags,
- zonename);
- if (r == SUCCESS && flags == 0) {
- aaaa = true;
- }
-
- if (!a && !aaaa) {
- flags = TYPE_NOT_FOUND;
- } else {
- flags = 0;
- }
-
- return (SUCCESS);
-}
-
-DataSrc::Result
-DataSrc::findReferral(const Name& qname, const RRClass& qclass,
- RRsetList& target, uint32_t& flags,
- const Name* zonename) const
-{
- Result r;
- bool ns = false, ds = false, dname = false;
-
- flags = 0;
- r = findExactRRset(qname, qclass, RRType::NS(), target, flags, zonename);
- if (r == SUCCESS && flags == 0) {
- ns = true;
- } else if ((flags & (NO_SUCH_ZONE|NAME_NOT_FOUND))) {
- return (SUCCESS);
- }
-
- flags = 0;
- r = findExactRRset(qname, qclass, RRType::DS(), target, flags, zonename);
- if (r == SUCCESS && flags == 0) {
- ds = true;
- } else if ((flags & (NO_SUCH_ZONE|NAME_NOT_FOUND))) {
- return (SUCCESS);
- }
-
- flags = 0;
- r = findExactRRset(qname, qclass, RRType::DNAME(), target, flags, zonename);
- if (r == SUCCESS && flags == 0) {
- dname = true;
- } else if ((flags & (NO_SUCH_ZONE|NAME_NOT_FOUND))) {
- return (SUCCESS);
- }
-
- if (!ns && !dname && !ds) {
- flags = TYPE_NOT_FOUND;
- } else {
- flags = 0;
- }
-
- return (SUCCESS);
-}
-
-void
-MetaDataSrc::addDataSrc(ConstDataSrcPtr data_src) {
- LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_META_ADD);
- if (getClass() != RRClass::ANY() && data_src->getClass() != getClass()) {
- logger.error(DATASRC_META_ADD_CLASS_MISMATCH).
- arg(data_src->getClass()).arg(getClass());
- isc_throw(Unexpected, "class mismatch");
- }
-
- data_sources.push_back(data_src);
-}
-
-void
-MetaDataSrc::removeDataSrc(ConstDataSrcPtr data_src) {
- LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_META_REMOVE);
- std::vector<ConstDataSrcPtr>::iterator it, itr;
- for (it = data_sources.begin(); it != data_sources.end(); ++it) {
- if (*it == data_src) {
- itr = it;
- }
- }
-
- data_sources.erase(itr);
-}
-
-void
-MetaDataSrc::findClosestEnclosure(DataSrcMatch& match) const {
- if (getClass() != match.getClass() &&
- getClass() != RRClass::ANY() && match.getClass() != RRClass::ANY()) {
- return;
- }
-
- BOOST_FOREACH (ConstDataSrcPtr data_src, data_sources) {
- data_src->findClosestEnclosure(match);
- }
-}
-
-DataSrcMatch::~DataSrcMatch() {
- delete closest_name_;
-}
-
-void
-DataSrcMatch::update(const DataSrc& new_source, const Name& container) {
- if (getClass() != new_source.getClass() && getClass() != RRClass::ANY() &&
- new_source.getClass() != RRClass::ANY())
- {
- return;
- }
-
- if (closest_name_ == NULL) {
- const NameComparisonResult::NameRelation cmp =
- getName().compare(container).getRelation();
- if (cmp != NameComparisonResult::EQUAL &&
- cmp != NameComparisonResult::SUBDOMAIN)
- {
- return;
- }
-
- closest_name_ = new Name(container);
- best_source_ = &new_source;
- return;
- }
-
- if (container.compare(*closest_name_).getRelation() ==
- NameComparisonResult::SUBDOMAIN) {
- Name* newname = new Name(container);
- delete closest_name_;
- closest_name_ = newname;
- best_source_ = &new_source;
- }
-}
-
-Nsec3Param::Nsec3Param(const uint8_t a, const uint8_t f, const uint16_t i,
- const std::vector<uint8_t>& s) :
- algorithm_(a), flags_(f), iterations_(i), salt_(s)
-{}
-
-string
-Nsec3Param::getHash(const Name& name) const {
- OutputBuffer buf(0);
- name.toWire(buf);
-
- uint8_t digest[SHA1_HASHSIZE];
- const uint8_t* input = static_cast<const uint8_t*>(buf.getData());
- size_t inlength = buf.getLength();
- const uint8_t saltlen = salt_.size();
-
- int n = 0;
- SHA1Context sha;
- do {
- SHA1Reset(&sha);
- SHA1Input(&sha, input, inlength);
- SHA1Input(&sha, &salt_[0], saltlen);
- SHA1Result(&sha, digest);
- input = digest;
- inlength = SHA1_HASHSIZE;
- } while (n++ < iterations_);
-
- return (encodeBase32Hex(vector<uint8_t>(digest, digest + SHA1_HASHSIZE)));
-}
-
-DataSrc::Result
-DataSrc::init(isc::data::ConstElementPtr) {
- return (NOT_IMPLEMENTED);
-}
-
-DataSrc::Result
-MetaDataSrc::findRRset(const isc::dns::Name&,
- const isc::dns::RRClass&,
- const isc::dns::RRType&,
- isc::dns::RRsetList&,
- uint32_t&,
- const isc::dns::Name*) const
-{
- return (NOT_IMPLEMENTED);
-}
-
-DataSrc::Result
-MetaDataSrc::findExactRRset(const isc::dns::Name&,
- const isc::dns::RRClass&,
- const isc::dns::RRType&,
- isc::dns::RRsetList&,
- uint32_t&,
- const isc::dns::Name*) const
-{
- return (NOT_IMPLEMENTED);
-}
-
-DataSrc::Result
-MetaDataSrc::findAddrs(const isc::dns::Name&,
- const isc::dns::RRClass&,
- isc::dns::RRsetList&,
- uint32_t&,
- const isc::dns::Name*) const
-{
- return (NOT_IMPLEMENTED);
-}
-
-DataSrc::Result
-MetaDataSrc::findReferral(const isc::dns::Name&,
- const isc::dns::RRClass&,
- isc::dns::RRsetList&,
- uint32_t&,
- const isc::dns::Name*) const
-{
- return (NOT_IMPLEMENTED);
-}
-
-DataSrc::Result
-MetaDataSrc::findPreviousName(const isc::dns::Name&,
- isc::dns::Name&,
- const isc::dns::Name*) const
-{
- return (NOT_IMPLEMENTED);
-}
-
-DataSrc::Result
-MetaDataSrc::findCoveringNSEC3(const isc::dns::Name&,
- std::string&,
- isc::dns::RRsetList&) const
-{
- return (NOT_IMPLEMENTED);
-}
-
-}
-}
DataSourceError(file, line, what) {}
};
-
-class AbstractDataSrc {
- ///
- /// \name Constructors, Assignment Operator and Destructor.
- ///
- /// Note: The copy constructor and the assignment operator are intentionally
- /// defined as private to make it explicit that this is a pure base class.
-private:
- AbstractDataSrc(const AbstractDataSrc& source);
- AbstractDataSrc& operator=(const AbstractDataSrc& source);
-protected:
- /// \brief The default constructor.
- ///
- /// This is intentionally defined as \c protected as this base class should
- /// never be instantiated (except as part of a derived class).
- AbstractDataSrc() {}
-public:
- /// \brief The destructor.
- virtual ~AbstractDataSrc() {};
- //@}
-
- enum Result {
- SUCCESS,
- ERROR,
- NOT_IMPLEMENTED
- };
-
- // These flags indicate conditions encountered while processing a query.
- //
- // REFERRAL: The node contains an NS record
- // CNAME_FOUND: The node contains a CNAME record
- // NAME_NOT_FOUND: The node does not exist in the data source.
- // TYPE_NOT_FOUND: The node does not contain the requested RRType
- // NO_SUCH_ZONE: The zone does not exist in this data source.
- //
- // DATA_NOT_FOUND: A combination of the last three, for coding convenience
- enum QueryResponseFlags {
- REFERRAL = 0x01,
- CNAME_FOUND = 0x02,
- NAME_NOT_FOUND = 0x04,
- TYPE_NOT_FOUND = 0x08,
- NO_SUCH_ZONE = 0x10,
- DATA_NOT_FOUND = (NAME_NOT_FOUND|TYPE_NOT_FOUND|NO_SUCH_ZONE)
- };
-
- // 'High-level' methods. These will be implemented by the
- // general DataSrc class, and SHOULD NOT be overwritten by subclasses.
- virtual void doQuery(Query& query) = 0;
-
- // XXX: High-level methods to be implemented later:
- // virtual void doUpdate(Update update) = 0;
- // virtual void doXfr(Query query) = 0;
-
- // 'Medium-level' methods. This will be implemented by the general
- // DataSrc class but MAY be overwritten by subclasses.
- virtual void findClosestEnclosure(DataSrcMatch& match) const = 0;
-
- // Optional 'low-level' methods. These will have stub implementations
- // in the general DataSrc class but MAY be overwritten by subclasses
- virtual Result init() = 0;
- virtual Result init(isc::data::ConstElementPtr config) = 0;
- virtual Result close() = 0;
-
- // Mandatory 'low-level' methods: These will NOT be implemented by
- // the general DataSrc class; subclasses MUST implement them.
- virtual Result findRRset(const isc::dns::Name& qname,
- const isc::dns::RRClass& qclass,
- const isc::dns::RRType& qtype,
- isc::dns::RRsetList& target,
- uint32_t& flags,
- const isc::dns::Name* zonename) const = 0;
-
- virtual Result findExactRRset(const isc::dns::Name& qname,
- const isc::dns::RRClass& qclass,
- const isc::dns::RRType& qtype,
- isc::dns::RRsetList& target,
- uint32_t& flags,
- const isc::dns::Name* zonename) const = 0;
-
- // These will have dumb implementations in the general DataSrc
- // class, and SHOULD be overwritten by subclasses.
- virtual Result findAddrs(const isc::dns::Name& qname,
- const isc::dns::RRClass& qclass,
- isc::dns::RRsetList& target,
- uint32_t& flags,
- const isc::dns::Name* zonename) const = 0;
-
- virtual Result findReferral(const isc::dns::Name& qname,
- const isc::dns::RRClass& qclass,
- isc::dns::RRsetList& target,
- uint32_t& flags,
- const isc::dns::Name* zonename) const = 0;
-
- // This MUST be implemented by concrete data sources which support
- // DNSSEC, but is optional for others (e.g., the static data source).
- virtual Result findPreviousName(const isc::dns::Name& qname,
- isc::dns::Name& target,
- const isc::dns::Name* zonename) const = 0;
-
- // This MUST be implemented by concrete data sources which support
- // NSEC3, but is optional for others
- virtual Result findCoveringNSEC3(const isc::dns::Name& zonename,
- std::string& hash,
- isc::dns::RRsetList& target) const = 0;
-};
-
-// Base class for a DNS Data Source
-class DataSrc : public AbstractDataSrc {
- ///
- /// \name Constructors, Assignment Operator and Destructor.
- ///
- /// Note: The copy constructor and the assignment operator are intentionally
- /// defined as private.
-private:
- DataSrc(const DataSrc& source);
- DataSrc& operator=(const DataSrc& source);
-public:
- DataSrc() : rrclass(isc::dns::RRClass::IN()) {}
- DataSrc(const isc::dns::RRClass& c) : rrclass(c) {}
- /// \brief The destructor.
- virtual ~DataSrc() {};
- //@}
-
- virtual void doQuery(Query& q);
-
- virtual void findClosestEnclosure(DataSrcMatch& match) const = 0;
-
- const isc::dns::RRClass& getClass() const { return (rrclass); }
- void setClass(isc::dns::RRClass& c) { rrclass = c; }
- void setClass(const isc::dns::RRClass& c) { rrclass = c; }
-
- virtual Result init() { return (NOT_IMPLEMENTED); }
- virtual Result init(isc::data::ConstElementPtr config);
- virtual Result close() { return (NOT_IMPLEMENTED); }
-
- virtual Result findRRset(const isc::dns::Name& qname,
- const isc::dns::RRClass& qclass,
- const isc::dns::RRType& qtype,
- isc::dns::RRsetList& target,
- uint32_t& flags,
- const isc::dns::Name* zonename) const = 0;
-
- virtual Result findExactRRset(const isc::dns::Name& qname,
- const isc::dns::RRClass& qclass,
- const isc::dns::RRType& qtype,
- isc::dns::RRsetList& target,
- uint32_t& flags,
- const isc::dns::Name* zonename) const = 0;
-
- virtual Result findAddrs(const isc::dns::Name& qname,
- const isc::dns::RRClass& qclass,
- isc::dns::RRsetList& target,
- uint32_t& flags,
- const isc::dns::Name* zonename) const;
-
- virtual Result findReferral(const isc::dns::Name& qname,
- const isc::dns::RRClass& qclass,
- isc::dns::RRsetList& target,
- uint32_t& flags,
- const isc::dns::Name* zonename) const;
-
- virtual Result findPreviousName(const isc::dns::Name& qname,
- isc::dns::Name& target,
- const isc::dns::Name* zonename) const = 0;
-
- virtual Result findCoveringNSEC3(const isc::dns::Name& zonename,
- std::string& hash,
- isc::dns::RRsetList& target) const = 0;
-
-private:
- isc::dns::RRClass rrclass;
-};
-
-class MetaDataSrc : public DataSrc {
- ///
- /// \name Constructors, Assignment Operator and Destructor.
- ///
- /// Note: The copy constructor and the assignment operator are intentionally
- /// defined as private.
- //@{
-private:
- MetaDataSrc(const MetaDataSrc& source);
- MetaDataSrc& operator=(const MetaDataSrc& source);
-public:
- MetaDataSrc() : DataSrc(isc::dns::RRClass::ANY()) {}
- MetaDataSrc(const isc::dns::RRClass& c) : DataSrc(c) {}
- /// \brief The destructor.
- virtual ~MetaDataSrc() {}
- //@}
-
- void addDataSrc(ConstDataSrcPtr data_src);
- void removeDataSrc(ConstDataSrcPtr data_src);
- size_t dataSrcCount() { return (data_sources.size()); }
-
- void findClosestEnclosure(DataSrcMatch& match) const;
-
- // Actual queries for data should not be sent to a MetaDataSrc object,
- // so we return NOT_IMPLEMENTED if we receive any.
- //
- // The proper way to use the MetaDataSrc is to run findClosestEnclosure()
- // to get a pointer to the best concrete data source for the specified
- // zone, then send all queries directly to that data source.
-
- Result findRRset(const isc::dns::Name& qname,
- const isc::dns::RRClass& qclass,
- const isc::dns::RRType& qtype,
- isc::dns::RRsetList& target,
- uint32_t& flags,
- const isc::dns::Name* zonename) const;
-
- Result findExactRRset(const isc::dns::Name& qname,
- const isc::dns::RRClass& qclass,
- const isc::dns::RRType& qtype,
- isc::dns::RRsetList& target,
- uint32_t& flags,
- const isc::dns::Name* zonename) const;
-
- Result findAddrs(const isc::dns::Name& qname,
- const isc::dns::RRClass& qclass,
- isc::dns::RRsetList& target,
- uint32_t& flags,
- const isc::dns::Name* zonename) const;
-
- Result findReferral(const isc::dns::Name& qname,
- const isc::dns::RRClass& qclass,
- isc::dns::RRsetList& target,
- uint32_t& flags,
- const isc::dns::Name* zonename) const;
-
- virtual Result findPreviousName(const isc::dns::Name& qname,
- isc::dns::Name& target,
- const isc::dns::Name* zonename) const;
-
- virtual Result findCoveringNSEC3(const isc::dns::Name& zonename,
- std::string& hash,
- isc::dns::RRsetList& target) const;
-
-private:
- std::vector<ConstDataSrcPtr> data_sources;
-};
-
-/// \brief Information about the zone along with the %data source that best
-/// matches a give name and RR class.
-///
-/// A \c DataSrcMatch object is created with a domain name and RR class to
-/// hold the search state of looking for the zone and the %data source that
-/// stores the zone that best match the given name and RR class.
-/// The application of this class passes an object of \c DataSrcMatch to
-/// one or more ^data sources via their \c findClosestEnclosure() method.
-/// The %data source searches its content for the given key, and update
-/// the state if it finds a better zone than the currently recorded one.
-///
-/// The state of a \c DataSrcMatch object should be updated if and only if:
-/// - The specified RR class and the RR class of the %data source are the
-// same, or the specified RR class is ANY; and
-/// - There is no matching %data source and name found (which is probably
-/// wrong, see below), or the given enclosing name gives a longer match
-/// than the currently stored enclosing name against the specified name.
-class DataSrcMatch {
- ///
- /// \name Constructors, Assignment Operator and Destructor.
- ///
- /// Note: The copy constructor and the assignment operator are
- /// intentionally defined as private.
- //@{
-private:
- DataSrcMatch(const DataSrcMatch& source);
- DataSrcMatch& operator=(const DataSrcMatch& source);
-public:
- /// \brief The constructor.
- ///
- /// This constructor normally doesn't throw an exception. However,
- /// it creates a copy of the given name object, which may require memory
- /// allocation, and if it fails the corresponding standard exception will
- /// be thrown.
- ///
- /// \param name The domain name to be matched.
- /// \param rrclass The RR class to be matched
- DataSrcMatch(const isc::dns::Name& name,
- const isc::dns::RRClass& rrclass) :
- closest_name_(NULL), best_source_(NULL),
- name_(name), rrclass_(rrclass)
- {}
- ~DataSrcMatch();
- //@}
-
- /// \name Getter and Setter Methods
- //@{
- /// \brief Returns the name to be matched.
- const isc::dns::Name& getName() const { return (name_); }
-
- /// \brief Returns the RR class to be matched.
- ///
- /// This method never throws an exception.
- const isc::dns::RRClass& getClass() const { return (rrclass_); }
-
- /// \brief Returns the best enclosing zone name found for the given
- // name and RR class so far.
- ///
- /// \return A pointer to the zone apex \c Name, NULL if none found yet.
- ///
- /// This method never throws an exception.
- const isc::dns::Name* getEnclosingZone() const { return (closest_name_); }
-
- /// \brief Returns the best %data source found for the given name and
- /// RR class so far.
- ///
- /// This method never throws an exception.
- ///
- /// \return A pointer to a concrete %data source, NULL if none found yet.
- const DataSrc* getDataSource() const { return (best_source_); }
- //@}
-
- /// \brief Update the object state with better information if possible.
- ///
- /// This method is intended to be called by a concrete %data source's
- /// \c findClosestEnclosure() method to store the best match for
- /// the given name and class that has been found so far.
- ///
- /// It compares the best name (if found) and \c container, and if the
- /// latter gives a longer match, it will install the given %data source
- /// and the enclosing name as the best match;
- /// if there is no known pair of %data source and enclosing name,
- /// this method will install the given pair unconditionally.
- /// (which is probably BAD);
- /// otherwise this method does nothing.
- ///
- /// In any case, if a new pair of %data source and enclosing name are
- /// installed, a new name object will be internally allocated.
- /// And, if memory allocation fails the corresponding standard exception
- /// will be thrown.
- ///
- /// \param new_source A candidate %data source that gives a better match.
- /// \param container The enclosing name of the matching zone in
- /// \c new_source.
- void update(const DataSrc& new_source, const isc::dns::Name& container);
-
-private:
- isc::dns::Name* closest_name_;
- const DataSrc* best_source_;
- const isc::dns::Name name_;
- const isc::dns::RRClass& rrclass_;
-};
-
-class Nsec3Param {
-public:
- Nsec3Param(uint8_t a, uint8_t f, uint16_t i, const std::vector<uint8_t>& s);
- std::string getHash(const isc::dns::Name& name) const;
-private:
- const uint8_t algorithm_;
- const uint8_t flags_;
- const uint16_t iterations_;
- const std::vector<uint8_t> salt_;
-};
-
}
}
+++ /dev/null
-// 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 <util/buffer.h>
-#include <dns/name.h>
-#include <dns/rrset.h>
-#include <dns/message.h>
-
-#include <cc/data.h>
-
-#include <datasrc/query.h>
-
-using namespace isc::dns;
-
-namespace isc {
-namespace datasrc {
-
-QueryTask::QueryTask(const Query& qry, const isc::dns::Name& n,
- const isc::dns::RRType& t,
- const isc::dns::Message::Section sect) :
- q(qry), qname(n), qclass(qry.qclass()), qtype(t), section(sect),
- op(AUTH_QUERY), state(GETANSWER), flags(0)
-{}
-
-QueryTask::QueryTask(const Query& qry, const isc::dns::Name& n,
- const isc::dns::RRType& t,
- const isc::dns::Message::Section sect,
- const Op o) :
- q(qry), qname(n), qclass(qry.qclass()), qtype(t), section(sect), op(o),
- state(GETANSWER), flags(0)
-{}
-
-QueryTask::QueryTask(const Query& qry, const isc::dns::Name& n,
- const isc::dns::RRType& t,
- const isc::dns::Message::Section sect,
- const State st) :
- q(qry), qname(n), qclass(qry.qclass()), qtype(t), section(sect),
- op(AUTH_QUERY), state(st), flags(0)
-{}
-
-QueryTask::QueryTask(const Query& qry, const isc::dns::Name& n,
- const isc::dns::RRType& t,
- const isc::dns::Message::Section sect,
- const Op o, const State st) :
- q(qry), qname(n), qclass(qry.qclass()), qtype(t), section(sect), op(o),
- state(st), flags(0)
-{}
-
-QueryTask::QueryTask(const Query& qry, const isc::dns::Name& n,
- const isc::dns::RRType& t, const Op o) :
- q(qry), qname(n), qclass(qry.qclass()), qtype(t),
- section(Message::SECTION_ANSWER), op(o), state(GETANSWER), flags(0)
-{
- if (op != SIMPLE_QUERY) {
- isc_throw(Unexpected, "invalid constructor for this task operation");
- }
-}
-
-// A referral query doesn't need to specify section, state, or type.
-QueryTask::QueryTask(const Query& qry, const isc::dns::Name& n, const Op o) :
- q(qry), qname(n), qclass(qry.qclass()), qtype(RRType::ANY()),
- section(Message::SECTION_ANSWER), op(o), state(GETANSWER), flags(0)
-{
- if (op != REF_QUERY) {
- isc_throw(Unexpected, "invalid constructor for this task operation");
- }
-}
-
-QueryTask::QueryTask(const Query& qry, const isc::dns::Name& n,
- const isc::dns::Message::Section sect, const Op o,
- const State st) :
- q(qry), qname(n), qclass(qry.qclass()), qtype(RRType::ANY()),
- section(sect), op(o), state(st), flags(0)
-{
- if (op != GLUE_QUERY && op != NOGLUE_QUERY) {
- isc_throw(Unexpected, "invalid constructor for this task operation");
- }
-}
-
-QueryTask::~QueryTask() {}
-
-Query::Query(Message& m, HotCache& c, bool dnssec) :
- status_(PENDING), qname_(NULL), qclass_(NULL), qtype_(NULL),
- cache_(&c), message_(&m), want_additional_(true), want_dnssec_(dnssec)
-{
- // Check message formatting
- if (message_->getRRCount(Message::SECTION_QUESTION) != 1) {
- isc_throw(Unexpected, "malformed message: too many questions");
- }
-
- // Populate the query task queue with the initial question
- QuestionPtr question = *message_->beginQuestion();
- qname_ = &question->getName();
- qclass_ = &question->getClass();
- qtype_ = &question->getType();
- restarts_ = 0;
-
- querytasks_.push(QueryTaskPtr(new QueryTask(*this, *qname_, *qtype_,
- Message::SECTION_ANSWER)));
-}
-
-Query::~Query() {}
-
-}
-}
+++ /dev/null
-// 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.
-
-#ifndef __QUERY_H
-#define __QUERY_H
-
-#include <boost/shared_ptr.hpp>
-
-#include <datasrc/cache.h>
-#include <datasrc/data_source.h>
-
-#include <dns/name.h>
-#include <dns/message.h>
-#include <dns/rrtype.h>
-#include <dns/rrclass.h>
-
-#include <queue>
-
-namespace isc {
-namespace datasrc {
-
-class Query;
-typedef boost::shared_ptr<Query> QueryPtr;
-
-// An individual task to be carried out by the query logic
-class QueryTask {
-private:
- /// Note: The copy constructor and the assignment operator are intentionally
- /// defined as private.
- QueryTask(const QueryTask& source);
- QueryTask& operator=(const QueryTask& source);
-public:
- // XXX: Members are currently public, but should probably be
- // moved to private and wrapped in get() functions later.
-
- // The \c Query that this \c QueryTask was created to service.
- const Query& q;
-
- // The standard query tuple: qname/qclass/qtype.
- // Note that qtype is ignored in the GLUE_QUERY/NOGLUE_QUERY case.
- const isc::dns::Name qname;
- const isc::dns::RRClass qclass;
- const isc::dns::RRType qtype;
-
- // The section of the reply into which the data should be
- // written after it has been fetched from the data source.
- const isc::dns::Message::Section section;
-
- // The op field indicates the operation to be carried out by
- // this query task:
- //
- // - SIMPLE_QUERY: look for a match for qname/qclass/qtype
- // in local data (regardless of whether it is above or below
- // a zone cut).
- //
- // - AUTH_QUERY: look for a match for qname/qclass/qtype, or
- // for qname/qclass/CNAME, or for a referral.
- //
- // - GLUE_QUERY: look for matches with qname/qclass/A
- // OR qname/class/AAAA in local data, regardless of
- // authority, for use in glue. (This can be implemented
- // as two successive SIMPLE_QUERY tasks, but might be
- // optimized by the concrete data source implementation
- // by turning it into a single database lookup.)
- //
- // - NOGLUE_QUERY: same as GLUE_QUERY except that answers
- // are rejected if they are below a zone cut.
- //
- // - REF_QUERY: look for matches for qname/qclass/NS,
- // qname/qclass/DS, and qname/qclass/DNAME. Used
- // to search for a zone cut.
-
- const enum Op {
- SIMPLE_QUERY,
- AUTH_QUERY,
- GLUE_QUERY,
- NOGLUE_QUERY,
- REF_QUERY
- } op;
-
- // The state field indicates the state of the query; it controls
- // the next step after processing each query task.
- //
- // - GETANSWER: We are looking for the answer to a primary query.
- // (The qname of the task should exactly match the qname of the
- // query.) If we have no match, the query has failed.
- //
- // - GETADDITIONAL: We are filling in additional data, either
- // as a result of finding NS or MX records via a GETANSWER
- // query task, or as a result of finding NS records when
- // getting authority-section data.
- //
- // - FOLLOWCNAME: We are looking for the target of a CNAME RR that
- // was found via a previous GETANSWER query task. If we have no
- // match, the query is still successful.
- //
- // (NOTE: It is only necessary to set a task state when pushing
- // tasks onto the query task queue, which in turn is only necessary
- // when it's uncertain which data source will be authoritative for the
- // data. That's why there is no GETAUTHORITY task state; when
- // processing an answer, either positive or negative, the authoritative
- // data source will already have been discovered, and can be queried
- // directly.)
-
- enum State {
- GETANSWER,
- GETADDITIONAL,
- FOLLOWCNAME
- } state;
-
- // Response flags to indicate conditions encountered while
- // processing this task.
- uint32_t flags;
-
- // Constructors
- QueryTask(const Query& q, const isc::dns::Name& n,
- const isc::dns::RRType& t,
- const isc::dns::Message::Section sect);
- QueryTask(const Query& q, const isc::dns::Name& n,
- const isc::dns::RRType& t,
- const isc::dns::Message::Section sect, Op o);
- QueryTask(const Query& q, const isc::dns::Name& n,
- const isc::dns::RRType& t,
- const isc::dns::Message::Section sect,
- const State st);
- QueryTask(const Query& q, const isc::dns::Name& n,
- const isc::dns::RRType& t,
- const isc::dns::Message::Section sect,
- Op o, State st);
-
- // These are special constructors for particular query task types,
- // to simplify the code.
- //
- // A simple query doesn't need to specify section or state.
- QueryTask(const Query& q, const isc::dns::Name& n,
- const isc::dns::RRType& t, Op o);
- // A referral query doesn't need to specify section, state, or type.
- QueryTask(const Query& q, const isc::dns::Name& n, Op o);
- // A glue (or noglue) query doesn't need to specify type.
- QueryTask(const Query& q, const isc::dns::Name& n,
- const isc::dns::Message::Section sect, Op o, State st);
-
- ~QueryTask();
-};
-
-typedef boost::shared_ptr<QueryTask> QueryTaskPtr;
-typedef std::queue<QueryTaskPtr> QueryTaskQueue;
-
-// Data Source query
-class Query {
-public:
- // The state of a query: pending or answered.
- enum Status {
- PENDING,
- ANSWERED
- };
-
- ///
- /// \name Constructors, Assignment Operator and Destructor.
- ///
- /// Note: The copy constructor and the assignment operator are intentionally
- /// defined as private.
- //@{
-private:
- Query(const Query& source);
- Query& operator=(const Query& source);
-public:
- // Query constructor
- Query(isc::dns::Message& m, HotCache& c, bool dnssec);
- /// \brief The destructor.
- virtual ~Query();
- //@}
-
- // wantAdditional() == true indicates that additional-section data
- // should be looked up while processing this query. false indicates
- // that we're only interested in answer-section data
- bool wantAdditional() { return (want_additional_); }
- void setWantAdditional(bool d) { want_additional_ = d; }
-
- // wantDnssec() == true indicates that DNSSEC data should be retrieved
- // from the data source when this query is being processed
- bool wantDnssec() const { return (want_dnssec_); }
- void setWantDnssec(bool d) { want_dnssec_ = d; }
-
- const isc::dns::Name& qname() const { return (*qname_); }
- const isc::dns::RRClass& qclass() const { return (*qclass_); }
- const isc::dns::RRType& qtype() const { return (*qtype_); }
-
- // Note: these can't be constant member functions because they expose
- // writable 'handles' of internal member variables. It's questionable
- // whether we need these accessors in the first place because the
- // corresponding members are public (which itself is not a good practice
- // but it's a different topic), but at the moment we keep them.
- // We should definitely revisit the design later.
- isc::dns::Message& message() { return (*message_); }
- QueryTaskQueue& tasks() { return (querytasks_); }
-
- Status status() const { return (status_); }
- void setStatus(Status s) { status_ = s; }
-
- // Limit CNAME chains to 16 per query, to avoid loops
- inline bool tooMany() {
- if (++restarts_ > MAX_RESTARTS) {
- return (true);
- }
- return (false);
- }
-
- void setDatasrc(DataSrc* ds) { datasrc_ = ds; }
- DataSrc* datasrc() const { return (datasrc_); }
-
- // \brief The query cache. This is a static member of class \c Query;
- // the same cache will be used by all instances.
- HotCache& getCache() const { return (*cache_); }
-
-private:
- Status status_;
-
- const isc::dns::Name* qname_;
- const isc::dns::RRClass* qclass_;
- const isc::dns::RRType* qtype_;
-
- HotCache* cache_;
- DataSrc* datasrc_;
-
- isc::dns::Message* message_;
- QueryTaskQueue querytasks_;
-
- bool want_additional_;
- bool want_dnssec_;
-
- static const int MAX_RESTARTS = 16;
- int restarts_;
-};
-
-}
-}
-
-
-#endif
-
-// Local Variables:
-// mode: c++
-// End:
# The general tests
run_unittests_SOURCES = $(common_sources)
-# Commented out by ticket #2165. If you re-enable these, please modify
-# EXTRA_DIST at the bottom of this file.
-#run_unittests_SOURCES += datasrc_unittest.cc
-#run_unittests_SOURCES += query_unittest.cc
-#run_unittests_SOURCES += cache_unittest.cc
-#run_unittests_SOURCES += test_datasrc.h test_datasrc.cc
-
run_unittests_SOURCES += test_client.h test_client.cc
run_unittests_SOURCES += rbtree_unittest.cc
run_unittests_SOURCES += logger_unittest.cc
EXTRA_DIST += testdata/newschema.sqlite3
EXTRA_DIST += testdata/oldschema.sqlite3
EXTRA_DIST += testdata/static.zone
-
-# Added by ticket #2165
-EXTRA_DIST += datasrc_unittest.cc
-EXTRA_DIST += query_unittest.cc
-EXTRA_DIST += cache_unittest.cc
-EXTRA_DIST += test_datasrc.h test_datasrc.cc
+++ /dev/null
-// 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 <stdexcept>
-
-#include <dns/name.h>
-#include <dns/rdata.h>
-#include <dns/rdataclass.h>
-#include <dns/rrclass.h>
-#include <dns/rrtype.h>
-#include <dns/rrttl.h>
-#include <dns/rrset.h>
-
-#include <datasrc/cache.h>
-#include <datasrc/data_source.h>
-
-#include <gtest/gtest.h>
-
-using namespace std;
-using namespace isc::dns;
-using namespace isc::dns::rdata;
-using namespace isc::datasrc;
-
-namespace {
-class CacheTest : public ::testing::Test {
-protected:
- CacheTest() : test_name("test.example.com"),
- test_nsname("ns.example.com"),
- test_ch("example.com")
- {
- RRsetPtr a(new RRset(test_name, RRClass::IN(), RRType::A(),
- RRTTL(3600)));
- a->addRdata(in::A("192.0.2.1"));
- a->addRdata(in::A("192.0.2.2"));
-
- RRsetPtr b(new RRset(test_nsname, RRClass::IN(), RRType::NS(),
- RRTTL(86400)));
- RRsetPtr c(new RRset(test_ch, RRClass::CH(), RRType::TXT(),
- RRTTL(0)));
- c->addRdata(generic::TXT("Text record"));
-
- cache.setSlots(5);
-
- cache.addPositive(a, 1, 30);
- cache.addPositive(b, 2, 30);
- cache.addPositive(c, 4, 30);
- }
-
- Name test_name;
- Name test_nsname;
- Name test_ch;
-
- HotCache cache;
-};
-
-class TestRRset : public RRset {
-public:
- TestRRset(const Name& name, int& counter) :
- RRset(name, RRClass::IN(), RRType::A(), RRTTL(3600)),
- counter_(counter)
- {
- ++counter_;
- }
- ~TestRRset() {
- --counter_;
- }
- int& counter_;
-};
-
-// make sure any remaining cache entries are purged on destruction of the
-// cache.
-TEST_F(CacheTest, cleanup) {
- HotCache* local_cache(new HotCache);
- int num_rrsets = 0;
-
- local_cache->addPositive(RRsetPtr(new TestRRset(Name("example.com"),
- num_rrsets)), 0, 10);
- local_cache->addPositive(RRsetPtr(new TestRRset(Name("example.org"),
- num_rrsets)), 0, 10);
-
- EXPECT_EQ(2, num_rrsets);
- delete local_cache;
- EXPECT_EQ(0, num_rrsets);
-}
-
-TEST_F(CacheTest, slots) {
- EXPECT_EQ(5, cache.getSlots());
- EXPECT_EQ(3, cache.getCount());
-}
-
-TEST_F(CacheTest, insert) {
- RRsetPtr aaaa(new RRset(Name("foo"), RRClass::IN(), RRType::AAAA(),
- RRTTL(0)));
- aaaa->addRdata(in::AAAA("2001:db8:3:bb::5"));
- cache.addPositive(aaaa, 0, 4);
-
- EXPECT_EQ(4, cache.getCount());
-
- RRsetPtr r;
- uint32_t f;
- bool hit = cache.retrieve(Name("foo"), RRClass::IN(),
- RRType::AAAA(), r, f);
- EXPECT_TRUE(hit);
- EXPECT_EQ(aaaa, r);
-}
-
-TEST_F(CacheTest, retrieveOK) {
- bool hit;
- RRsetPtr r;
- uint32_t f;
-
- // Test repeatedly to ensure that all records remain accessible
- // even after being promoted to the top of the cache
- hit = cache.retrieve(test_name, RRClass::IN(), RRType::A(), r, f);
- EXPECT_TRUE(hit);
- EXPECT_EQ(test_name, r->getName());
- EXPECT_EQ(RRClass::IN(), r->getClass());
- EXPECT_EQ(RRType::A(), r->getType());
-
- hit = cache.retrieve(test_nsname, RRClass::IN(), RRType::NS(), r, f);
- EXPECT_TRUE(hit);
- EXPECT_EQ(test_nsname, r->getName());
- EXPECT_EQ(RRClass::IN(), r->getClass());
- EXPECT_EQ(RRType::NS(), r->getType());
-
- hit = cache.retrieve(test_ch, RRClass::CH(), RRType::TXT(), r, f);
- EXPECT_TRUE(hit);
- EXPECT_EQ(test_ch, r->getName());
- EXPECT_EQ(RRClass::CH(), r->getClass());
- EXPECT_EQ(RRType::TXT(), r->getType());
-
- hit = cache.retrieve(test_nsname, RRClass::IN(), RRType::NS(), r, f);
- EXPECT_TRUE(hit);
- EXPECT_EQ(test_nsname, r->getName());
- EXPECT_EQ(RRClass::IN(), r->getClass());
- EXPECT_EQ(RRType::NS(), r->getType());
-
- hit = cache.retrieve(test_ch, RRClass::CH(), RRType::TXT(), r, f);
- EXPECT_TRUE(hit);
- EXPECT_EQ(test_ch, r->getName());
- EXPECT_EQ(RRClass::CH(), r->getClass());
- EXPECT_EQ(RRType::TXT(), r->getType());
-
- hit = cache.retrieve(test_name, RRClass::IN(), RRType::A(), r, f);
- EXPECT_TRUE(hit);
- EXPECT_EQ(test_name, r->getName());
- EXPECT_EQ(RRClass::IN(), r->getClass());
- EXPECT_EQ(RRType::A(), r->getType());
-
- hit = cache.retrieve(test_name, RRClass::IN(), RRType::A(), r, f);
- EXPECT_TRUE(hit);
- EXPECT_EQ(test_name, r->getName());
- EXPECT_EQ(RRClass::IN(), r->getClass());
- EXPECT_EQ(RRType::A(), r->getType());
-};
-
-TEST_F(CacheTest, flags) {
- bool hit;
- RRsetPtr r;
- uint32_t f;
-
- hit = cache.retrieve(test_name, RRClass::IN(), RRType::A(), r, f);
- EXPECT_TRUE(hit);
- EXPECT_TRUE(r);
- EXPECT_EQ(DataSrc::REFERRAL, f);
-
- hit = cache.retrieve(test_nsname, RRClass::IN(), RRType::NS(), r, f);
- EXPECT_TRUE(hit);
- EXPECT_TRUE(r);
- EXPECT_EQ(DataSrc::CNAME_FOUND, f);
-
- hit = cache.retrieve(test_ch, RRClass::CH(), RRType::TXT(), r, f);
- EXPECT_TRUE(hit);
- EXPECT_TRUE(r);
- EXPECT_EQ(DataSrc::NAME_NOT_FOUND, f);
-}
-
-TEST_F(CacheTest, retrieveFail) {
- bool hit;
- RRsetPtr r;
- uint32_t f;
-
- hit = cache.retrieve(Name("fake"), RRClass::IN(), RRType::A(), r, f);
- EXPECT_FALSE(hit);
-
- hit = cache.retrieve(test_name, RRClass::CH(), RRType::A(), r, f);
- EXPECT_FALSE(hit);
-
- hit = cache.retrieve(test_name, RRClass::IN(), RRType::DNSKEY(), r, f);
- EXPECT_FALSE(hit);
-}
-
-TEST_F(CacheTest, expire) {
- // Insert "foo" with a duration of 1 seconds; sleep 2. The
- // record should not be returned from the cache even though it's
- // at the top of the cache.
- RRsetPtr aaaa(new RRset(Name("foo"), RRClass::IN(), RRType::AAAA(),
- RRTTL(0)));
- aaaa->addRdata(in::AAAA("2001:db8:3:bb::5"));
- cache.addPositive(aaaa, 0, 1);
-
- sleep(2);
-
- RRsetPtr r;
- uint32_t f;
- bool hit = cache.retrieve(Name("foo"), RRClass::IN(), RRType::AAAA(), r, f);
- EXPECT_FALSE(hit);
-};
-
-TEST_F(CacheTest, LRU) {
- // Retrieve a record, cache four new records; with five slots
- // in the LRU queue this should remove all the previous records
- // except the last one retreived.
- bool hit;
- RRsetPtr r;
- uint32_t f;
-
- hit = cache.retrieve(test_nsname, RRClass::IN(), RRType::NS(), r, f);
- EXPECT_TRUE(hit);
- EXPECT_EQ(3, cache.getCount());
-
- RRsetPtr one(new RRset(Name("one"), RRClass::IN(), RRType::TXT(),
- RRTTL(0)));
- one->addRdata(generic::TXT("one"));
- cache.addPositive(one, 0, 30);
- EXPECT_EQ(4, cache.getCount());
-
- RRsetPtr two(new RRset(Name("two"), RRClass::IN(), RRType::TXT(),
- RRTTL(0)));
- two->addRdata(generic::TXT("two"));
- cache.addPositive(two, 0, 30);
- EXPECT_EQ(5, cache.getCount());
-
- RRsetPtr three(new RRset(Name("three"), RRClass::IN(), RRType::TXT(),
- RRTTL(0)));
- three->addRdata(generic::TXT("three"));
- cache.addPositive(three, 0, 30);
- EXPECT_EQ(5, cache.getCount());
-
- RRsetPtr four(new RRset(Name("four"), RRClass::IN(), RRType::TXT(),
- RRTTL(0)));
- four->addRdata(generic::TXT("four"));
- cache.addPositive(four, 0, 30);
- EXPECT_EQ(5, cache.getCount());
-
- hit = cache.retrieve(test_name, RRClass::IN(), RRType::A(), r, f);
- EXPECT_FALSE(hit);
-
- hit = cache.retrieve(test_nsname, RRClass::IN(), RRType::NS(), r, f);
- EXPECT_TRUE(hit);
-
- hit = cache.retrieve(test_ch, RRClass::CH(), RRType::TXT(), r, f);
- EXPECT_FALSE(hit);
-}
-
-TEST_F(CacheTest, ncache) {
- Name missing("missing.example.com");
- cache.addNegative(missing, RRClass::IN(), RRType::DNSKEY(), 8, 30);
-
- RRsetPtr r;
- uint32_t f;
- bool hit = cache.retrieve(missing, RRClass::IN(), RRType::DNSKEY(), r, f);
-
- EXPECT_TRUE(hit);
- EXPECT_FALSE(r);
- EXPECT_EQ(DataSrc::TYPE_NOT_FOUND, f);
-}
-
-TEST_F(CacheTest, overwrite) {
- EXPECT_EQ(3, cache.getCount());
-
- RRsetPtr a(new RRset(test_name, RRClass::IN(), RRType::A(), RRTTL(300)));
- a->addRdata(in::A("192.0.2.100"));
-
- EXPECT_NO_THROW(cache.addPositive(a, 16, 30));
- EXPECT_EQ(3, cache.getCount());
-
- RRsetPtr r;
- uint32_t f;
- bool hit = cache.retrieve(test_name, RRClass::IN(), RRType::A(), r, f);
- EXPECT_TRUE(hit);
- EXPECT_TRUE(r);
- EXPECT_EQ(16, f);
-
- EXPECT_NO_THROW(cache.addNegative(test_name, RRClass::IN(), RRType::A(), 1, 30));
- EXPECT_EQ(3, cache.getCount());
-
- hit = cache.retrieve(test_name, RRClass::IN(), RRType::A(), r, f);
- EXPECT_TRUE(hit);
- EXPECT_FALSE(r);
- EXPECT_EQ(DataSrc::REFERRAL, f);
-}
-
-TEST_F(CacheTest, reduceSlots) {
- EXPECT_EQ(3, cache.getCount());
- cache.setSlots(2);
- EXPECT_EQ(2, cache.getCount());
- cache.setSlots(1);
- EXPECT_EQ(1, cache.getCount());
- cache.setSlots(0);
- EXPECT_EQ(1, cache.getCount());
-}
-
-TEST_F(CacheTest, setEnabled) {
- cache.setEnabled(false);
- EXPECT_FALSE(cache.getEnabled());
- cache.setEnabled(true);
- EXPECT_TRUE(cache.getEnabled());
-}
-
-TEST_F(CacheTest, disabled) {
- bool hit;
- RRsetPtr r;
- uint32_t f;
-
- cache.setEnabled(false);
- hit = cache.retrieve(test_name, RRClass::IN(), RRType::A(), r, f);
- EXPECT_FALSE(hit);
-
- cache.setEnabled(true);
- hit = cache.retrieve(test_name, RRClass::IN(), RRType::A(), r, f);
- EXPECT_TRUE(hit);
-
- EXPECT_EQ(test_name, r->getName());
- EXPECT_EQ(RRClass::IN(), r->getClass());
- EXPECT_EQ(RRType::A(), r->getType());
-}
-
-}
+++ /dev/null
-// 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 <gtest/gtest.h>
-
-#include <util/buffer.h>
-#include <dns/message.h>
-#include <dns/name.h>
-#include <dns/opcode.h>
-#include <dns/rrtype.h>
-#include <dns/rrclass.h>
-
-#include <datasrc/query.h>
-
-#include <dns/tests/unittest_util.h>
-
-using isc::UnitTestUtil;
-using namespace isc::dns;
-using namespace isc::datasrc;
-
-namespace {
-
-void
-createQuery(Message& m, const Name& qname, const RRClass& qclass,
- const RRType& qtype)
-{
- m.setOpcode(Opcode::QUERY());
- m.setHeaderFlag(Message::HEADERFLAG_RD);
- m.addQuestion(Question(qname, qclass, qtype));
-}
-
-QueryTaskPtr
-createTask(Message& m, const Name& name, const RRType& rrtype0, HotCache& c) {
- RRType rrtype(rrtype0);
- Query q(m, c, true);
- return (QueryTaskPtr(new QueryTask(q, name, rrtype,
- QueryTask::SIMPLE_QUERY)));
-}
-
-// Check the QueryTask created using a temporary RRType object will remain
-// valid.
-TEST(QueryTest, constructWithTemporary) {
- HotCache cache;
-
- Message m1(Message::RENDER);
- createQuery(m1, Name("www.wild.example.com"), RRClass::IN(), RRType::A());
- QueryTaskPtr task_a = createTask(m1, Name("www.wild.example.com"),
- RRType::A(), cache);
- EXPECT_EQ(RRType::A(), task_a->qtype);
-
- Message m2(Message::RENDER);
- createQuery(m2, Name("www.wild.example.com"), RRClass::IN(),
- RRType::AAAA());
- QueryTaskPtr task_aaaa = createTask(m2, Name("www.wild.example.com"),
- RRType::AAAA(), cache);
- EXPECT_EQ(RRType::AAAA(), task_aaaa->qtype);
-
-}
-
-}
+++ /dev/null
-// 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 <cassert>
-
-#include <algorithm>
-
-#include <dns/tests/unittest_util.h>
-#include <datasrc/tests/test_datasrc.h>
-
-#include <datasrc/data_source.h>
-
-#include <util/buffer.h>
-#include <dns/messagerenderer.h>
-#include <dns/name.h>
-#include <dns/rdata.h>
-#include <dns/rdataclass.h>
-#include <dns/rrclass.h>
-#include <dns/rrset.h>
-#include <dns/rrsetlist.h>
-#include <dns/rrtype.h>
-#include <dns/rrttl.h>
-
-#include <iostream>
-
-using isc::UnitTestUtil;
-using namespace std;
-using namespace isc::dns;
-using namespace isc::dns::rdata;
-
-namespace isc {
-namespace datasrc {
-
-namespace {
-
-// This is a mock data source for testing. It can contain multiple zones.
-// The content of each zone should be configured in the form of RRData{}.
-// Each RRData element is a tuple of char strings, representing
-// "name, RRtype, RDATA". For simplicity we use the same single TTL for
-// RRs (TEST_TTL) defined below.
-// Multiple RRs of the same pair of (name, RRtype) can be defined, but
-// they must not be interleaved with other types of pair. For example,
-// This is okay:
-// {"example.com", "AAAA", "2001:db8::1"},
-// {"example.com", "AAAA", "2001:db8::2"},
-// ...
-// but this is invalid:
-// {"example.com", "AAAA", "2001:db8::1"},
-// {"example.com", "A", "192.0.2.1"},
-// {"example.com", "AAAA", "2001:db8::2"},
-// ...
-// If an RRset is associated with an RRSIG, the RRSIG must immediately follow
-// the RRset to be signed. Multiple RRSIGs can follow the RRset. RRSIG
-// records will always be attached to the most recent non-RRSIG RRset;
-// consequently, the first RR listed must not be an RRSIG record.
-//
-// Names are sorted internally, and don't have to be sorted in the data.
-//
-// A zone is defined in the form of ZoneData{}, which contains:
-// zone name (character string)
-// RRclass (character string)
-// A pointer to in-zone RRs in the form of RRData{}
-// A pointer to glue RRs in the form of RRData{}
-// Glues can be omitted, in which case a convenient constant "empty_records"
-// can be specified.
-
-// For simplicity we use the same single TTL for all test RRs.
-const uint32_t TEST_TTL = 3600;
-
-struct RRData {
- const char* const name;
- const char* const rrtype;
- const char* const rdata;
-};
-
-struct ZoneData {
- const char* const zone_name;
- const char* const rrclass;
- const struct RRData* records;
- const struct RRData* glue_records;
-};
-
-//
-// zone data for example.com
-//
-const struct RRData example_com_records[] = {
- // example.com
- {"example.com", "NS", "dns01.example.com"},
- {"example.com", "NS", "dns02.example.com"},
- {"example.com", "NS", "dns03.example.com"},
- {"example.com", "RRSIG", "NS 5 2 3600 20100322084538 20100220084538 33495 example.com. ClcrfjkQZUY5L6ZlCkU3cJHzcrEGrofKSVeeoeZ+w6yeEowFNVXs2YBo3tom53DiCrdD9rs3feVSLGW5rjsz/O6lDuomgQG+EVSnWa7GTIPBXj1BmDXXp3XxeldYmhf4UzaN5BA+RUA5E8NChNKuNNof76j2S9tilfN/kvpy4fw="},
- {"example.com", "SOA", "master.example.com. admin.example.com. 1234 3600 1800 2419200 7200"},
- {"example.com", "RRSIG", "SOA 5 2 3600 20100322084538 20100220084538 33495 example.com. KUun66Qaw36osk2BJS6U1fAy3PPDkNo2QK4meGNbDBY8q8b+f2o+IXJ14YCvssGl1ORW0CcLnDRxssnk8V/Svmj5iFhO+8HC2hnVBdi2zewvdVtwRb+lWwKN7pkXXwuy6g1t9WCd/j5FCc/wgxqtZUTPb6XgZcnHrORDMOTqLs4="},
- {"example.com", "NSEC", "cname-ext.example.com. NS SOA MX RRSIG NSEC DNSKEY"},
- {"example.com", "RRSIG", "NSEC 5 2 7200 20100322084538 20100220084538 33495 example.com. KxuVaPPKNPJzr/q+cJPiNlkHVTQK0LVsgTbSqruXQc25lAd0wn5oKUtxL1bEAchHkfA8eLzcYCj2ZqqAv9OJubw53mfskTad7UHs4Uj2RTrIsNGMCiZGgOpvNb9JcWpQtoyXVT1uNse+Qsbeir0eyeYIufUynFU041jtNrlJMio="},
- {"example.com", "DNSKEY", "257 3 5 AwEAAe5WFbxdCPq2jZrZhlMj7oJdff3W7syJtbvzg62tRx0gkoCDoBI9DPjlOQG0UAbj+xUV4HQZJStJaZ+fHU5AwVNT+bBZdtV+NujSikhdTHb4FYLg2b3Cx9NyJvAVukHp/91HnWuG4T36CzAFrfPwsHIrBz9BsaIQ21VRkcmj7DswfI/iDGd8j6bqiODyNZYQ+ZrLmF0KIJ2yPN3iO6Zq23TaOrVTjB7d1a/h31ODfiHAxFHrkY3t3D5JR9Nsl/7fdRmSznwtcSDgLXBoFEYmw6p86AcvRyoYNcL1SXjaKVLG5jyU3UR+LcGZT5t/0xGfoIK/aKwENrsjcKZZj660b1M="},
- {"example.com", "DNSKEY", "256 3 5 AwEAAcOUBllYc1hf7ND9uDy+Yz1BF3sI0m4qNGV7WcTD0WEiuV7IjXgHE36fCmS9QsUxSSOVo1I/FMxI2PJVqTYHkXFBS7AzLGsQYMU7UjBZSotBJ6Imt5pXMu+lEDNy8TOUzG3xm7g0qcbWYF6qCEfvZoBtAqi5Rk7Mlrqs8agxYyMx"},
- {"example.com", "RRSIG", "DNSKEY 5 2 3600 20100416210049 20100317210049 4456 example.com. 37FC0rcwOZVarTMjft0BMbvv8hbJU7OHNsvO7R1q6OgsLTj7QGMX3sC42JGbwUrYI/OwnZblNcv1eim0g0jX5k+sVr2OJsEubngRjVqLo54qV8rBC14tLk9PGKxxjQG0IBJU866uHxzXYBO2a1r2g93/qyTtrT7iPLu/2Ce1WRKMBPK0yf4nW2usFU/PXesXFWpZ7HLGZL73/NWv8wcezBDuU0B2PlHLjSu7k6poq6JWDC02o5SYnEBwsJ5Chi+3/NZmzKTiNP7g0H4t6QhunkEXxL3z0617mwwQt00ypXsNunnPy4Ub5Kllk1SKJl8ZkEDKkJtSvuXJhcAZsLyMQw=="},
- {"example.com", "RRSIG", "DNSKEY 5 2 3600 20100416210049 20100317210049 33495 example.com. h3OM5r3roBsgnEQk9fcjTg5L7p3yDptDpVzDN/lgjqpaWxtlz5LsulBH3YzwYyXzT7pG7L0/qT6dcuRECc/rniECviWvmJMJZzEAMry0Of/pk/8ekuGTxABpqwAoCwM5as30sc0cfMJTS7umpJVDA4lRB2zoKGefWnJ3+pREDiY="},
-
- // dns01.example.com
- {"dns01.example.com", "A", "192.0.2.1"},
- {"dns01.example.com", "RRSIG", "A 5 3 3600 20100322084538 20100220084538 33495 example.com. NIawlZLk8WZAjNux7oQM2mslfW52OZFFkWt++7FHu2SU98XqEeKfCMnpgtWe5T8Nr9cS8df901iEOJoWQzGTEaHYUBtEhsSjBVn7mKp3fz6473a2xxy75SUKZ0rxjNXSZ8Q5rnFmkX0HTH2Sg51mtjH6aC2pfheQnA2t193BnSg="},
- {"dns01.example.com", "NSEC", "dns02.example.com. A RRSIG NSEC"},
- {"dns01.example.com", "RRSIG", "NSEC 5 3 7200 20100322084538 20100220084538 33495 example.com. EkyeshmMNP9xiAz6mDFDIwksTdmkF9zsFzLuVKAgK6eUk7St6tp5PSvjA8nWol0vdvvz4LK85a4ffTFEiNRyvWeYP2vOhEkyDcrwuCd8Vc3jh/8Sm1Js+nX7hJStrZGFvp2TWPpt9nKH5p3MxXvTb/YVurnue0xSeFAE17O3+I0="},
-
- // dns02.example.com
- {"dns02.example.com", "A", "192.0.2.2"},
- {"dns02.example.com", "RRSIG", "A 5 3 3600 20100322084538 20100220084538 33495 example.com. XJtVMbUIRE0mk6Hn/Nx6k36jaxaBDPK2/IYB6vCQjJETz6gW4T6q/H/eY9/Lsw5iYPFhoBRDxT4XFj575t98kELXnJe1WhuMbRPlOhyOjxkLECaUne/sbFPOtbGFx9ohuojI0RgxxZiCFaO8wJuv6nfPuzmlLajWS6z9NZeOMIk="},
- {"dns02.example.com", "NSEC", "dns03.example.com. A RRSIG NSEC"},
- {"dns02.example.com", "RRSIG", "NSEC 5 3 7200 20100322084538 20100220084538 33495 example.com. imBNTMB3sPU4kblcaAH6V7lCVt5xgtAybi3DA/SbLEulLaV2NE6vcoEn/AieaM4mOJicQnUDj/H+1hSEhzxU2tRM8zfVlvztxQWn6eh7ZR4mKfNDSvRUGU9ykhpwMyC7wjOt1j5bcSA/OTnLRAilslnJyOM4bSaxVEFo8YPjncY="},
-
- // dns03.example.com
- {"dns03.example.com", "A", "192.0.2.3"},
- {"dns03.example.com", "RRSIG", "A 5 3 3600 20100322084538 20100220084538 33495 example.com. Ubrcm1H+F6m8khle7P9zU8eO+Jtuj+1Vx1MM5KAkmZPJwQe9uTcoCpQa6DXOGG9kajDTnNN1Be1gkZuJDTZJG4SmJLXLbNY3RDnxpGmWta3qs/VgDq78/YM8ropt1/s7YKyrCfGE2ff+FUB0mLObiG01ZV2gu5HJzgE7SEWLEiI="},
- {"dns03.example.com", "NSEC", "foo.example.com. A RRSIG NSEC"},
- {"dns03.example.com", "RRSIG", "NSEC 5 3 7200 20100322084538 20100220084538 33495 example.com. nn829Xw5CJFnPHwI9WHeT5epQv+odtCkHnjlPFGoPTLOyiks+041UmMqtq3uiSp4d2meMSe9UuDvoROT0L6NTtQQvVqiDhTn0irTFw1uw7fO8ZTG7eyu6Ypfz0+HvfbNvd4kMoD2OTgADRXPVsCTwK+PBOIIG9YTEQfl8pCqW5g="},
-
- // www.example.com
- {"www.example.com", "A", "192.0.2.1"},
- {"www.example.com", "RRSIG", "A 5 3 3600 20100322084538 20100220084538 33495 example.com. qyFyyV/mE8x4pdhudr5iycwhDsva31MzwO1kBR+bDKvzJg8mN8KxlPZrOlNNUhd3YRXQVwieMyxOTWRPXoxrNEDkNwimXkfe3rrHY7ibV9eNS4OIBUjb44VjCNr9CmQSzfuQ2yxO2r+YIuPYHRCjieD4xh6t9ay4IaCN/tDAJ+Q="},
- {"www.example.com", "NSEC", "example.com. A RRSIG NSEC"},
- {"www.example.com", "RRSIG", "NSEC 5 3 7200 20100322084538 20100220084538 33495 example.com. ZLZlSVBa2oe4U+7SZASnypP2VkI5gg1/1cVGqYUvfYNIUkcVMWDgn7DZCfpmo+2vdlV/4VhAc+sjDd+X+e57XGnW8+lqZHvG6NMMhmSGmeATD3D+8lEJJGo0dxoN4rHJQyp/eT2S4nChz+D/ze+YRagYxGF7pXm9zcrw3kKZGTs="},
-
- // *.wild.example.com
- {"*.wild.example.com", "A", "192.0.2.2"},
- {"*.wild.example.com", "RRSIG", "A 5 3 3600 20100322084538 20100220084538 33495 example.com. FdO+UWONgtLKFxUzzygGunw67F9y8SzsP7yOLEYVJclRR8X3Ii62L0gtQHq2y0TcKsXttRsD6XY+tM5P/pgXlTNi7Bk4Fgb0PIDPjOsfT4DrS80kWn0YbinM/4/FA1j5ru5sTTboOY5UGhvDnoA9ogNuQQYb2/3wkoH0PrA2Q/0="},
- {"*.wild.example.com", "NSEC", "*.wild2.example.com. A RRSIG NSEC"},
- {"*.wild.example.com", "RRSIG", "NSEC 5 3 7200 20100322084538 20100220084538 33495 example.com. OoGYslRj4xjZnBuzgOqsrvkDAHWycmQzbUxCRmgWnCbXiobJK7/ynONH3jm8G3vGlU0lwpHkhNs6cUK+6Nu8W49X3MT0Xksl/brroLcXYLi3vfxnYUNMMpXdeFl6WNNfoJRo90F/f/TWXAClRrDS29qiG3G1PEJZikIxZsZ0tyM="},
-
- // *.wild2.example.com
- {"*.wild2.example.com", "CNAME", "www.example.com"},
- {"*.wild2.example.com", "RRSIG", "CNAME 5 3 3600 20100410212307 20100311212307 33495 example.com. pGHtGdRBi4GKFSKszi6SsKvuBLDX8dFhZubU0tMojQ9SJuiFNF+WtxvdAYuUaoWP/9VLUaYmiw5u7JnzmR84DiXZPEs6DtD+UJdOZhaS7V7RTpE+tMOfVQBLpUnRWYtlTTmiBpFquzf3DdIxgUFhEPEuJJyp3LFRxJObCaq9 nvI="},
- {"*.wild2.example.com", "NSEC", "*.wild3.example.com. CNAME RRSIG NSEC"},
- {"*.wild2.example.com", "RRSIG", "NSEC 5 3 7200 20100410212307 20100311212307 33495 example.com. EuSzh6or8mbvwru2H7fyYeMpW6J8YZ528rabU38V/lMN0TdamghIuCneAvSNaZgwk2MSN1bWpZqB2kAipaM/ZI9/piLlTvVjjOQ8pjk0auwCEqT7Z7Qng3E92O9yVzO+WHT9QZn/fR6t60392In4IvcBGjZyjzQk8njIwbui xGA="},
-
- // *.wild3.example.com -- a wildcard record with a lame CNAME
- {"*.wild3.example.com", "CNAME", "spork.example.com"},
- {"*.wild3.example.com", "RRSIG", "CNAME 5 3 3600 20100410212307 20100311212307 33495 example.com. pGHtGdRBi4GKFSKszi6SsKvuBLDX8dFhZubU0tMojQ9SJuiFNF+WtxvdAYuUaoWP/9VLUaYmiw5u7JnzmR84DiXZPEs6DtD+UJdOZhaS7V7RTpE+tMOfVQBLpUnRWYtlTTmiBpFquzf3DdIxgUFhEPEuJJyp3LFRxJObCaq9 nvI="},
- {"*.wild3.example.com", "NSEC", "www.example.com. CNAME RRSIG NSEC"},
- {"*.wild3.example.com", "RRSIG", "NSEC 5 3 7200 20100410212307 20100311212307 33495 example.com. EuSzh6or8mbvwru2H7fyYeMpW6J8YZ528rabU38V/lMN0TdamghIuCneAvSNaZgwk2MSN1bWpZqB2kAipaM/ZI9/piLlTvVjjOQ8pjk0auwCEqT7Z7Qng3E92O9yVzO+WHT9QZn/fR6t60392In4IvcBGjZyjzQk8njIwbui xGA="},
-
- // foo.example.com
- {"foo.example.com", "CNAME", "cnametest.example.net"},
- {"foo.example.com", "RRSIG", "CNAME 5 3 3600 20100322084538 20100220084538 33495 example.com. DSqkLnsh0gCeCPVW/Q8viy9GNP+KHmFGfWqyVG1S6koBtGN/VQQ16M4PHZ9Zssmf/JcDVJNIhAChHPE2WJiaPCNGTprsaUshf1Q2vMPVnkrJKgDY8SVRYMptmT8eaT0gGri4KhqRoFpMT5OYfesybwDgfhFSQQAh6ps3bIUsy4o="},
- {"foo.example.com", "NSEC", "mail.example.com. CNAME RRSIG NSEC"},
- {"foo.example.com", "RRSIG", "NSEC 5 3 7200 20100322084538 20100220084538 33495 example.com. RTQwlSqui6StUYye1KCSOEr1d3irndWFqHBpwP7g7n+w8EDXJ8I7lYgwzHvlQt6BLAxe5fUDi7ct8M5hXvsm7FoWPZ5wXH+2/eJUCYxIw4vezKMkMwBP6M/YkJ2CMqY8DppYf60QaLDONQAr7AcK/naSyioeI5h6eaoVitUDMso="},
-
- // cname-int.example.com
- {"cname-int.example.com", "CNAME", "www.example.com."},
- {"cname-int.example.com", "RRSIG", "CNAME 5 3 3600 20100322084538 20100220084538 33495 example.com. U1wjt0XY9xjTwvUmWSUcfLGMhCjfX2ylWfHrycy50x2oxcK9z94E1ejen9wDTIEBSGYgi6wpZ8RK0+02N1DWTGpDqNXd7aFRfDrWQJ/q/XJHDx0vlcmhkWhrT82LBfKxkrptOzchuSo/c0mpK+mpiIMc1VOwY+yuQ2ALfcD6EHw="},
- {"cname-int.example.com", "NSEC", "dname.example.com. CNAME RRSIG NSEC"},
- {"cname-int.example.com", "RRSIG", "NSEC 5 3 7200 20100322084538 20100220084538 33495 example.com. rbV+gaxfrsoha59NOLF4EFyWQ+GuFCVK/8D77x1atan3HNlXBlZ1smgudKTaJ3CtlobIDt0MEdPxY1yn2Tskw/5mlP1PWf8oaP3BwGSQdn4gLI8+sMpNOPFEdXpxqxngm2F6/7fqniL1QuSAQBEdO+5UiCAgnncPmAsSJg3u1zg="},
-
- // cname-ext.example.com
- {"cname-ext.example.com", "CNAME", "www.sql1.example.com"},
- {"cname-ext.example.com", "RRSIG", "CNAME 5 3 3600 20100322084538 20100220084538 33495 example.com. bGPIuZilyygvTThK4BrdECuaBcnZUgW/0d09iN2CrNjckchQl3dtbnMNirFsVs9hShDSldRNlQpiAVMpnPgXHhReNum7jmX6yqIH6s8GKIo91zr3VL/ramlezie5w4MilDHrxXLK2pb8IHmP+ZHivQ2EtdYQZgETWBWxr5FDfwk="},
- {"cname-ext.example.com", "NSEC", "cname-int.example.com. CNAME RRSIG NSEC"},
- {"cname-ext.example.com", "RRSIG", "NSEC 5 3 7200 20100322084538 20100220084538 33495 example.com. inWsFwSDWG7TakjwbUTzTRpXz0WifelA5Kn3ABk6BVirIPmd+yQoNj2QZBDFAQwhnLPlNws2Oo4vgMsBMyx1Fv5eHgMUuCN3DUDaLlzlPtUb42CjOUa+jZBeTV/Hd7WZrirluASE1QFDprLdSSqoPPfAKvN3pORtW7y580dMOIM="},
-
- // dname.example.com
- {"dname.example.com", "DNAME", "sql1.example.com."},
- {"dname.example.com", "RRSIG", "DNAME 5 3 3600 20100322084538 20100220084538 33495 example.com. ae8U47oaiwWdurkSyzcsCAF6DxBqjukizwF7K7U6lQVMtfoUE14oiAqfj1fjH8YLDOO/Hd1twrd/u0vgjnI1Gg32YTi7cYOzwE912SV1u2B/y0awaQKWPBwOW0aI7vxelt1vMUF81xosiQD04gOIdDBTqbHKcDxum87iWbhk4Ug="},
- {"dname.example.com", "NSEC", "dns01.example.com. DNAME RRSIG NSEC"},
- {"dname.example.com", "RRSIG", "NSEC 5 3 7200 20100322084538 20100220084538 33495 example.com. c21Fff2D8vBrLzohBnUeflkaRdUAnUxAFGp+UQ0miACDCMOFBlCS9v9g/2+orOnKfd3l4vyz55C310t8JXgXb119ofaZWj2zkdUe+X8Bax+sMS0Y5K/sUhSNvbJbozr9UYPdvjSVBiWgh3s9fsb+etKq9uFukAzGU/FuGYpO0r0="},
-
- // subzone.example.com
- {"subzone.example.com", "NS", "ns1.subzone.example.com"},
- {"subzone.example.com", "NS", "ns2.subzone.example.com"},
- {"subzone.example.com", "NSEC", "*.wild.example.com. NS DS RRSIG NSEC"},
- {"subzone.example.com", "RRSIG", "NSEC 5 3 7200 20100322084538 20100220084538 33495 example.com. Oe2kgIhsLtPJ4+lDZDxznV8/vEVoXKOBFN9lwWyebaKa19BaSXlQ+YVejmulmKDDjEucMvEfuItfn6w7bnU+DzOLk5D1lJCjwDlKz8u3xOAx16TiuQn4bgQAOiFtBQygmGGqO3BVpX+jxsmw7eH3emofy8uUqr/C4aopnwuf28g="},
- {"subzone.example.com", "DS", "33313 5 1 0FDD7A2C11AA7F55D50FBF9B7EDDA2322C541A8D"},
- {"subzone.example.com", "DS", "33313 5 2 00B99B7006F496D135B01AB17EDB469B4BE9E1973884DEA757BC4E3015A8C3AB"},
- {"subzone.example.com", "RRSIG", "DS 5 3 3600 20100322084538 20100220084538 33495 example.com. dIqZKvpkJN1l92SOiWgJh3KbjErIN+EfojMsm4pEdV5xQdZwj6DNNEu6Kw4rRwdvrZIu0TyqPr3jSJb7o6R7vZgZzmLfVV/ojQah7rwuYHCFcfyZ4JyK2311fMhRR1QAvMsdcjdyA1XC140Cm6AnL3cH5rh/KUks/0ec3Ca7GNQ="},
-
- // subset of child zone: sql1
- {"sql1.example.com", "NS", "dns01.example.com"},
- {"sql1.example.com", "NS", "dns02.example.com"},
- {"sql1.example.com", "NS", "dns03.example.com"},
-
- {"sql1.example.com", "DS", "33313 5 1 0FDD7A2C11AA7F55D50FBF9B7EDDA2322C541A8D"},
- {"sql1.example.com", "DS", "33313 5 2 00B99B7006F496D135B01AB17EDB469B4BE9E1973884DEA757BC4E3015A8C3AB"},
- {"sql1.example.com", "RRSIG", "DS 5 3 3600 20100322084538 20100220084538 33495 example.com. dIqZKvpkJN1l92SOiWgJh3KbjErIN+EfojMsm4pEdV5xQdZwj6DNNEu6Kw4rRwdvrZIu0TyqPr3jSJb7o6R7vZgZzmLfVV/ojQah7rwuYHCFcfyZ4JyK2311fMhRR1QAvMsdcjdyA1XC140Cm6AnL3cH5rh/KUks/0ec3Ca7GNQ="},
- {"sql1.example.com", "NSEC", "subzone.example.com. NS DS RRSIG NSEC"},
- {"sql1.example.com", "RRSIG", "NSEC 5 3 7200 20100322084538 20100220084538 33495 example.com. k9FRdFyk/cPdkmmaoZbGZPpzIzfbFWQ3QCHd2qhJa0xAXaEOT/GBL6aFqx9SlunDu2wgES+To5fWPZGi4NzWpp6c5t27rnATN/oCEQ/UYIJKmWbqrXdst0Ps5boznk7suK2Y+km31KxaIf3fDd/T3kZCVsR0aWKRRRatPb7GfLw="},
-
- {NULL, NULL, NULL}
-};
-
-const struct RRData example_com_glue_records[] = {
- {"ns1.subzone.example.com", "A", "192.0.2.1"},
- {"ns2.subzone.example.com", "A", "192.0.2.2"},
- {NULL, NULL, NULL}
-};
-
-//
-// zone data for sql1.example.com
-//
-const struct RRData sql1_example_com_records[] = {
- {"sql1.example.com", "NS", "dns01.example.com"},
- {"sql1.example.com", "NS", "dns02.example.com"},
- {"sql1.example.com", "NS", "dns03.example.com"},
- {"sql1.example.com", "RRSIG", "NS 5 3 3600 20100322084536 20100220084536 12447 sql1.example.com. 0CL8noy0NSgoWwuKd+Dc6vyIIw2BrAEBx0IJzcSB6GlB25x/zjEd6AJG0be13HN6jOaTX8iWTuCVrEYuXg76V+M4EvTZHjEScj0az74TrDv4Vdo459paGKCX9B8NLJW1mW4fzZrrXQ8jmBEZeS91Q5rJrO+UKJEuUz3LYdTPvao="},
- {"sql1.example.com", "SOA", "master.example.com. admin.example.com. 678 3600 1800 2419200 7200"},
- {"sql1.example.com", "RRSIG", "SOA 5 3 3600 20100322084536 20100220084536 12447 sql1.example.com. oakulfyljL/RAKgCKXEZ3KsG8BJj5WG4JK4moWFB6c9OKem6jIk8hKP2XlUVXFuOYJlRdIM4KicmR2GAK+5jJp6z5ShssstYTXo3QosVm6oCKumuFeLFHzcjfqP1D+F9NsvHldJIBnS/4ebPkmR5OENyCZXQF5HmN2awIj4CLjE="},
- {"sql1.example.com", "NSEC", "www.sql1.example.com. NS SOA RRSIG NSEC DNSKEY"},
- {"sql1.example.com", "RRSIG", "NSEC 5 3 7200 20100322084536 20100220084536 12447 sql1.example.com. v71CgdTYccCiTqfRcn6HsvISQa8ruvUfCKtpwym0RW/G27xlZn8otj2IMtWwkLxti8Rqqu+PTViLaOIbeVfHBcqzAd7U59cAOYoq3ODZx6auiE3C23HAKqUavKcP7Esaajm1cbcWy6Kyie4CAZc8M7EeKxgkXMKJGqBQzF+/FOo="},
-
- // www.sql1.example.com
- {"www.sql1.example.com", "A", "192.0.2.2"},
- {"www.sql1.example.com", "RRSIG", "A 5 4 3600 20100322084536 20100220084536 12447 sql1.example.com. DNdVKxB3oBsB14NPoV9WG14Y/g4zMcIXLYnFjj9vRZRZJpAvbTEipiXlayuhOxnqU827OipETQyeULZmLsqIQ1wK4Fgf+9b5aJ8D85/o4wBka00X4hZ3MwDPRb4mjuogwBTBg5NRpNSzUfbkPGiav08BFwgg+Efm9veSB05arS0="},
- {"www.sql1.example.com", "NSEC", "sql1.example.com. A RRSIG NSEC"},
- {"www.sql1.example.com", "RRSIG", "NSEC 5 4 7200 20100322084536 20100220084536 12447 sql1.example.com. cJMJhDx/ND7/9j3zhyXe+6eaSsU7ByYpXhJzbe+OhjFgH0VasQXq7o1QB3I293UZ+yhkjgXap+9QtPlraaNaYyTyOMQ42OoxSefJpYz9CME/FI2tsUfyrCnLFxYRNet7sMS0q+hLqxRayuEHDFDp72hHPGLJQ8a7jq4SrIonT50="},
-
- {NULL, NULL, NULL}
-};
-
-//
-// zone data for loop.example
-//
-const struct RRData loop_example_records[] = {
- {"loop.example", "SOA", "master.loop.example admin.loop.example. "
- "1234 3600 1800 2419200 7200"},
- {"loop.example", "NS", "ns.loop.example"},
- {"one.loop.example", "CNAME", "two.loop.example"},
- {"two.loop.example", "CNAME", "one.loop.example"},
- {NULL, NULL, NULL}
-};
-
-//
-// zone data for nons.example
-//
-const struct RRData nons_example_records[] = {
- {"nons.example", "SOA", "master.nons.example admin.nons.example. "
- "1234 3600 1800 2419200 7200"},
- {"www.nons.example", "A", "192.0.2.1"},
- {"ns.nons.example", "A", "192.0.2.2"},
-
- // One of the NS names is intentionally non existent in the zone it belongs
- // to. This delegation is used to see if we still return the NS and the
- // existent glue.
- // (These are not relevant to test the case for the "no NS" case. We use
- // this zone to minimize the number of test zones)
- {"incompletechild.nons.example", "NS", "ns.incompletechild.nons.example"},
- {"incompletechild.nons.example", "NS", "nx.nosoa.example"},
-
- {NULL, NULL, NULL}
-};
-
-const struct RRData nons_example_glue_records[] = {
- {"ns.incompletechild.nons.example", "A", "192.0.2.1"},
- {NULL, NULL, NULL}
-};
-
-//
-// zone data for nons-dname.example
-//
-const struct RRData nonsdname_example_records[] = {
- {"nons-dname.example", "SOA", "master.nons-dname.example "
- "admin.nons-dname.example. 1234 3600 1800 2419200 7200"},
- {"nons-dname.example", "DNAME", "example.org"},
- {"www.nons-dname.example", "A", "192.0.2.1"},
- {"ns.nons-dname.example", "A", "192.0.2.2"},
- {NULL, NULL, NULL}
-};
-
-//
-// zone data for nosoa.example
-//
-const struct RRData nosoa_example_records[] = {
- {"nosoa.example", "NS", "ns.nosoa.example"},
- {"www.nosoa.example", "A", "192.0.2.1"},
- {"ns.nosoa.example", "A", "192.0.2.2"},
- {NULL, NULL, NULL}
-};
-
-//
-// zone data for apexcname.example.
-//
-const struct RRData apexcname_example_records[] = {
- {"apexcname.example", "CNAME", "canonical.apexcname.example"},
- {"canonical.apexcname.example", "SOA",
- "master.apexcname.example "
- "admin.apexcname.example. 1234 3600 1800 2419200 7200"},
- {NULL, NULL, NULL}
-};
-
-
-//
-// empty data set, for convenience.
-//
-const struct RRData empty_records[] = {
- {NULL, NULL, NULL}
-};
-
-//
-// test zones
-//
-const struct ZoneData zone_data[] = {
- { "example.com", "IN", example_com_records, example_com_glue_records },
- { "sql1.example.com", "IN", sql1_example_com_records, empty_records },
- { "loop.example", "IN", loop_example_records, empty_records },
- { "nons.example", "IN", nons_example_records, nons_example_glue_records },
- { "nons-dname.example", "IN", nonsdname_example_records, empty_records },
- { "nosoa.example", "IN", nosoa_example_records, empty_records },
- { "apexcname.example", "IN", nosoa_example_records, empty_records }
-};
-const size_t NUM_ZONES = sizeof(zone_data) / sizeof(zone_data[0]);
-
-struct Zone {
- Zone(const char* const name, const char* const class_txt) :
- zone_name(Name(name)), rrclass(class_txt)
- {}
- Name zone_name;
- RRClass rrclass;
- vector<Name> names;
- vector<RRsetPtr> rrsets;
-};
-vector<Zone> zones;
-}
-
-DataSrc::Result
-TestDataSrc::init(isc::data::ConstElementPtr) {
- return (init());
-}
-
-void
-buildZone(Zone& zone, const RRData* records, const bool is_glue) {
- RRsetPtr prev_rrset;
- for (int i = 0; records[i].name != NULL; ++i) {
- Name name(records[i].name);
- RRType rrtype(records[i].rrtype);
- RRsetPtr rrset;
- bool new_name = false;
-
- if (!prev_rrset || prev_rrset->getName() != name) {
- if (!is_glue) {
- zone.names.push_back(name);
- }
- new_name = true;
- }
-
- if (new_name || prev_rrset->getType() != rrtype) {
- rrset = RRsetPtr(new RRset(name, zone.rrclass, rrtype,
- RRTTL(TEST_TTL)));
- if (rrtype != RRType::RRSIG()) {
- zone.rrsets.push_back(rrset);
- }
- } else {
- rrset = prev_rrset;
- }
- rrset->addRdata(createRdata(rrtype, zone.rrclass, records[i].rdata));
- if (rrtype == RRType::RRSIG()) {
- prev_rrset->addRRsig(rrset);
- } else {
- prev_rrset = rrset;
- }
- }
-}
-
-DataSrc::Result
-TestDataSrc::init() {
- if (initialized) {
- return (SUCCESS);
- }
-
- if (zones.empty()) {
- for (int i = 0; i < NUM_ZONES; ++i) {
- Zone zone(zone_data[i].zone_name, zone_data[i].rrclass);
- buildZone(zone, zone_data[i].records, false);
- buildZone(zone, zone_data[i].glue_records, true);
- sort(zone.names.begin(), zone.names.end());
- zones.push_back(zone);
- }
- }
-
- initialized = true;
- return (SUCCESS);
-}
-
-void
-TestDataSrc::findClosestEnclosure(DataSrcMatch& match) const {
- const Name& qname = match.getName();
-
- if (match.getClass() != getClass() && match.getClass() != RRClass::ANY()) {
- return;
- }
-
- vector<Zone>::const_iterator it;
- vector<Zone>::const_iterator best_it = zones.end();
- unsigned int best_common_labels = 0;
- for (it = zones.begin(); it != zones.end(); ++it) {
- const NameComparisonResult cmp = qname.compare(it->zone_name);
- const NameComparisonResult::NameRelation reln = cmp.getRelation();
-
- if ((reln == NameComparisonResult::EQUAL ||
- reln == NameComparisonResult::SUBDOMAIN) &&
- cmp.getCommonLabels() > best_common_labels) {
- best_it = it;
- best_common_labels = cmp.getCommonLabels();
- }
- }
-
- if (best_it != zones.end()) {
- match.update(*this, best_it->zone_name);
- }
-}
-
-struct ZoneNameMatch : public unary_function<Name, bool> {
- ZoneNameMatch(const Name& name) : name_(name) {}
- bool operator()(const Zone& zone) const {
- return (zone.zone_name == name_);
- }
- const Name& name_;
-};
-
-// XXX: the main data source module can override the returned RRset.
-// That's bad and should be fixed (Trac #254), but for now we work around it.
-RRsetPtr
-copyRRset(RRsetPtr const source) {
- RRsetPtr rrset = RRsetPtr(new RRset(source->getName(), source->getClass(),
- source->getType(), source->getTTL()));
- RdataIteratorPtr it = source->getRdataIterator();
- for (; !it->isLast(); it->next()) {
- rrset->addRdata(it->getCurrent());
- }
- if (source->getRRsig()) {
- rrset->addRRsig(copyRRset(source->getRRsig()));
- }
-
- return (rrset);
-}
-
-class TestDataSrc::RRsetMatch {
-public:
- struct MatchResult {
- MatchResult(const bool name_found, const bool has_delegation) :
- name_found_(name_found), has_delegation_(has_delegation)
- {}
- bool name_found_;
- bool has_delegation_;
- };
- RRsetMatch(const Name& name, const RRType& rrtype, const Mode mode,
- RRsetList& target, uint32_t& flags) :
- name_(name), rrtype_(rrtype), mode_(mode), target_(target),
- flags_(flags), name_found_(false), has_delegation_(false)
- {}
- void operator()(const RRsetPtr& rrset) {
- if (rrset->getName() != name_) {
- return;
- }
- name_found_ = true;
-
- if (rrset->getType() == RRType::NS() ||
- rrset->getType() == RRType::DNAME()) {
- has_delegation_ = true;
- }
-
- if (mode_ == DELEGATION) {
- if (rrset->getType() == RRType::NS() ||
- rrset->getType() == RRType::DNAME() ||
- rrset->getType() == RRType::DS()) {
- target_.addRRset(copyRRset(rrset));
- }
- } else if (mode_ == ADDRESS) {
- if (rrset->getType() == RRType::A() ||
- rrset->getType() == RRType::AAAA()) {
- target_.addRRset(copyRRset(rrset));
- }
- } else {
- if (rrtype_ == RRType::NSEC() &&
- rrset->getType() == RRType::CNAME()) {
- // XXX: ignore CNAME if the qtype is NSEC.
- // tricky, but necessary.
- return;
- }
- if (rrtype_ == RRType::ANY() || rrtype_ == rrset->getType() ||
- rrset->getType() == RRType::CNAME() ||
- rrset->getType() == RRType::DNAME()) {
- target_.addRRset(copyRRset(rrset));
- if (rrset->getType() == RRType::CNAME()) {
- flags_ |= CNAME_FOUND;
- }
- if (rrset->getType() == RRType::DNAME()) {
- flags_ |= REFERRAL;
- }
- }
- }
-
- }
- MatchResult getResult() { return (MatchResult(name_found_,
- has_delegation_)); }
- const Name& name_;
- const RRType& rrtype_;
- const Mode mode_;
- RRsetList& target_;
- uint32_t& flags_;
- bool name_found_;
- bool has_delegation_;
-};
-
-void
-TestDataSrc::findRecords(const Name& name, const RRType& rdtype,
- RRsetList& target, const Name* zonename,
- const Mode mode, uint32_t& flags) const
-{
- flags = 0;
-
- assert(zonename != NULL);
-
- vector<Zone>::const_iterator zone = find_if(zones.begin(), zones.end(),
- ZoneNameMatch(*zonename));
- if (zone == zones.end()) {
- return;
- }
-
- const RRsetMatch::MatchResult match_result =
- for_each(zone->rrsets.begin(), zone->rrsets.end(),
- RRsetMatch(name, rdtype, mode, target, flags)).getResult();
- if (match_result.has_delegation_) {
- flags |= REFERRAL;
- }
- if (target.size() == 0) {
- if (match_result.name_found_) {
- flags |= TYPE_NOT_FOUND;
- } else {
- flags |= NAME_NOT_FOUND;
- }
- }
-}
-
-DataSrc::Result
-TestDataSrc::findRRset(const Name& qname,
- const RRClass& qclass,
- const RRType& qtype,
- RRsetList& target,
- uint32_t& flags,
- const Name* zonename) const
-{
- if (qclass != getClass() && qclass != RRClass::ANY()) {
- return (ERROR);
- }
-
- findRecords(qname, qtype, target, zonename, NORMAL, flags);
- return (SUCCESS);
-}
-
-DataSrc::Result
-TestDataSrc::findExactRRset(const Name& qname,
- const RRClass& qclass,
- const RRType& qtype,
- RRsetList& target,
- uint32_t& flags,
- const Name* zonename) const
-{
- if (qclass != getClass() && qclass != RRClass::ANY()) {
- return (ERROR);
- }
-
- findRecords(qname, qtype, target, zonename, NORMAL, flags);
- // Ignore referrals in this case
- flags &= ~REFERRAL;
-
- // CNAMEs don't count in this case
- if ((flags & CNAME_FOUND) != 0) {
- flags &= ~CNAME_FOUND;
- flags |= TYPE_NOT_FOUND;
- }
-
- return (SUCCESS);
-}
-
-DataSrc::Result
-TestDataSrc::findAddrs(const Name& qname,
- const RRClass& qclass,
- RRsetList& target,
- uint32_t& flags,
- const Name* zonename) const
-{
- if (qclass != getClass() && qclass != RRClass::ANY()) {
- return (ERROR);
- }
-
- findRecords(qname, RRType::ANY(), target, zonename, ADDRESS, flags);
- return (SUCCESS);
-}
-
-DataSrc::Result
-TestDataSrc::findReferral(const Name& qname,
- const RRClass& qclass,
- RRsetList& target,
- uint32_t& flags,
- const Name* zonename) const
-{
- if (qclass != getClass() && qclass != RRClass::ANY()) {
- return (ERROR);
- }
-
- findRecords(qname, RRType::ANY(), target, zonename, DELEGATION, flags);
- return (SUCCESS);
-}
-
-DataSrc::Result
-TestDataSrc::findPreviousName(const Name& qname,
- Name& target,
- const Name* zonename) const
-{
- assert(zonename != NULL);
-
- vector<Zone>::const_iterator zone = find_if(zones.begin(), zones.end(),
- ZoneNameMatch(*zonename));
- if (zone == zones.end()) {
- return (ERROR);
- }
-
- if (zone->names.empty()) {
- return (ERROR);
- }
-
- // if found, next_name >= qname.
- vector<Name>::const_iterator next_name =
- lower_bound(zone->names.begin(), zone->names.end(), qname);
- if (next_name == zone->names.end()) {
- // if no such name was found, the previous name is the last name.
- target = zone->names.back();
- } else if (*next_name == qname) {
- target = *next_name;
- } else if (next_name == zone->names.begin()) {
- // if qname < first_name, the "previous name" is the last name.
- target = zone->names.back();
- } else {
- // otherwise, qname and next_name share the same previous name.
- target = *(next_name - 1);
- }
- return (SUCCESS);
-}
-
-DataSrc::Result
-TestDataSrc::findCoveringNSEC3(const Name&, string&, RRsetList&) const {
- return (NOT_IMPLEMENTED);
-}
-
-}
-}
+++ /dev/null
-// 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.
-
-#ifndef __TEST_DATA_SOURCE_H
-#define __TEST_DATA_SOURCE_H
-
-#include <gtest/gtest.h>
-
-#include <datasrc/data_source.h>
-
-namespace isc {
-
-namespace dns {
-class Name;
-class RRClass;
-class RRType;
-class RRsetList;
-}
-
-namespace datasrc {
-class Query;
-
-class TestDataSrc : public DataSrc {
- ///
- /// \name Constructors, Assignment Operator and Destructor.
- ///
- /// Note: The copy constructor and the assignment operator are intentionally
- /// defined as private.
- //@{
-private:
- TestDataSrc(const TestDataSrc& source);
- TestDataSrc operator=(const TestDataSrc& source);
-public:
- TestDataSrc() : initialized(false) {}
- ~TestDataSrc() {}
- //@}
-
- void findClosestEnclosure(DataSrcMatch& match) const;
-
- Result findRRset(const isc::dns::Name& qname,
- const isc::dns::RRClass& qclass,
- const isc::dns::RRType& qtype,
- isc::dns::RRsetList& target,
- uint32_t& flags,
- const isc::dns::Name* zonename) const;
-
- Result findExactRRset(const isc::dns::Name& qname,
- const isc::dns::RRClass& qclass,
- const isc::dns::RRType& qtype,
- isc::dns::RRsetList& target,
- uint32_t& flags,
- const isc::dns::Name* zonename) const;
-
- Result findAddrs(const isc::dns::Name& qname,
- const isc::dns::RRClass& qclass,
- isc::dns::RRsetList& target,
- uint32_t& flags,
- const isc::dns::Name* zonename) const;
-
- Result findReferral(const isc::dns::Name& qname,
- const isc::dns::RRClass& qclass,
- isc::dns::RRsetList& target,
- uint32_t& flags,
- const isc::dns::Name* zonename) const;
-
- Result findPreviousName(const isc::dns::Name& qname,
- isc::dns::Name& target,
- const isc::dns::Name* zonename) const;
-
- Result findCoveringNSEC3(const isc::dns::Name& zonename,
- std::string& hash,
- isc::dns::RRsetList& target) const;
-
- Result init();
- Result init(isc::data::ConstElementPtr config);
- Result close() { return (SUCCESS); }
-
-private:
- bool initialized;
- enum Mode {
- NORMAL,
- ADDRESS,
- DELEGATION
- };
- class RRsetMatch;
-
- void findRecords(const isc::dns::Name& name, const isc::dns::RRType& rdtype,
- isc::dns::RRsetList& target,
- const isc::dns::Name* zonename, const Mode mode,
- uint32_t& flags) const;
-};
-
-}
-}
-
-#endif
-
-// Local Variables:
-// mode: c++
-// End: