LCOV - code coverage report
Current view: top level - datasrc - data_source.cc (source / functions) Hit Total Coverage
Test: report.info Lines: 535 648 82.6 %
Date: 2012-05-15 Functions: 26 34 76.5 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 732 1479 49.5 %

           Branch data     Line data    Source code
       1                 :            : // Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
       2                 :            : //
       3                 :            : // Permission to use, copy, modify, and/or distribute this software for any
       4                 :            : // purpose with or without fee is hereby granted, provided that the above
       5                 :            : // copyright notice and this permission notice appear in all copies.
       6                 :            : //
       7                 :            : // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
       8                 :            : // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
       9                 :            : // AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
      10                 :            : // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
      11                 :            : // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
      12                 :            : // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
      13                 :            : // PERFORMANCE OF THIS SOFTWARE.
      14                 :            : 
      15                 :            : #include <config.h>
      16                 :            : 
      17                 :            : #include <cassert>
      18                 :            : #include <iomanip>
      19                 :            : #include <iostream>
      20                 :            : #include <vector>
      21                 :            : 
      22                 :            : #include <boost/shared_ptr.hpp>
      23                 :            : #include <boost/foreach.hpp>
      24                 :            : 
      25                 :            : #include <datasrc/cache.h>
      26                 :            : #include <datasrc/data_source.h>
      27                 :            : #include <datasrc/query.h>
      28                 :            : #include <datasrc/logger.h>
      29                 :            : 
      30                 :            : #include <util/encode/base32hex.h>
      31                 :            : #include <util/hash/sha1.h>
      32                 :            : #include <util/buffer.h>
      33                 :            : 
      34                 :            : #include <dns/message.h>
      35                 :            : #include <dns/name.h>
      36                 :            : #include <dns/rcode.h>
      37                 :            : #include <dns/rdataclass.h>
      38                 :            : #include <dns/rrset.h>
      39                 :            : #include <dns/rrsetlist.h>
      40                 :            : 
      41                 :            : #include <cc/data.h>
      42                 :            : 
      43                 :            : #define RETERR(x) do { \
      44                 :            :                       DataSrc::Result r = (x); \
      45                 :            :                       if (r != DataSrc::SUCCESS) \
      46                 :            :                           return (r); \
      47                 :            :                       } while (0)
      48                 :            : 
      49                 :            : using namespace std;
      50                 :            : using namespace isc::util;
      51                 :            : using namespace isc::util::encode;
      52                 :            : using namespace isc::util::hash;
      53                 :            : using namespace isc::dns;
      54                 :            : using namespace isc::dns::rdata;
      55                 :            : 
      56                 :            : namespace {
      57                 :            : 
      58                 :            : struct MatchRRsetForType {
      59                 :            :     MatchRRsetForType(const RRType rrtype) : rrtype_(rrtype) {}
      60                 :            :     bool operator()(RRsetPtr rrset) {
      61 [ #  # ][ +  - ]:         86 :         return (rrset->getType() == rrtype_);
      62                 :            :     }
      63                 :            :     const RRType rrtype_;
      64                 :            : };
      65                 :            : 
      66                 :            : // This is a helper to retrieve a specified RR type of RRset from RRsetList.
      67                 :            : // In our case the data source search logic should ensure that the class is
      68                 :            : // valid.  We use this find logic of our own so that we can support both
      69                 :            : // specific RR class queries (normal case) and class ANY queries.
      70                 :            : RRsetPtr
      71                 :         87 : findRRsetFromList(RRsetList& list, const RRType rrtype) {
      72                 :            :     RRsetList::iterator it(find_if(list.begin(), list.end(),
      73                 :         87 :                                    MatchRRsetForType(rrtype)));
      74         [ +  + ]:        174 :     return (it != list.end() ? *it : RRsetPtr());
      75                 :            : }
      76                 :            : }
      77                 :            : 
      78                 :            : namespace isc {
      79                 :            : namespace datasrc {
      80                 :            : 
      81                 :            : typedef boost::shared_ptr<const Nsec3Param> ConstNsec3ParamPtr;
      82                 :            : 
      83 [ +  - ][ +  - ]:        173 : class ZoneInfo {
      84                 :            : public:
      85                 :            :     ZoneInfo(DataSrc* ts,
      86                 :            :              const isc::dns::Name& n,
      87                 :            :              const isc::dns::RRClass& c,
      88                 :            :              const isc::dns::RRType& t = isc::dns::RRType::ANY()) :
      89                 :            :         top_source_(ts),
      90                 :        173 :         dsm_(((t == RRType::DS() && n.getLabelCount() != 1)
      91                 :        173 :               ? n.split(1, n.getLabelCount() - 1) : n),
      92 [ +  + ][ +  + ]:        173 :              c)
         [ +  - ][ +  - ]
      93                 :            :     {}
      94                 :            : 
      95                 :            :     const Name* getEnclosingZone() {
      96 [ -  + ][ -  + ]:        581 :         if (dsm_.getEnclosingZone() == NULL) {
         [ -  + ][ -  + ]
         [ #  # ][ -  + ]
         [ +  - ][ +  + ]
      97 [ #  # ][ #  # ]:        102 :             top_source_->findClosestEnclosure(dsm_);
         [ #  # ][ +  - ]
      98                 :            :         }
      99                 :            :         return (dsm_.getEnclosingZone());
     100                 :            :     }
     101                 :            : 
     102                 :            :     const DataSrc* getDataSource() {
     103 [ -  + ][ -  + ]:        294 :         if (dsm_.getDataSource() == NULL) {
         [ #  # ][ +  + ]
     104 [ #  # ][ #  # ]:         95 :             top_source_->findClosestEnclosure(dsm_);
                 [ +  - ]
     105                 :            :         }
     106                 :            :         return (dsm_.getDataSource());
     107                 :            :     }
     108                 :            : 
     109                 :            : private:
     110                 :            :     const DataSrc* top_source_;
     111                 :            :     DataSrcMatch dsm_;
     112                 :            : };
     113                 :            : 
     114                 :            : // Add a task to the query task queue to look up additional data
     115                 :            : // (i.e., address records for the names included in NS or MX records)
     116                 :            : void
     117                 :         64 : getAdditional(Query& q, ConstRRsetPtr rrset) {
     118         [ +  - ]:         64 :     if (!q.wantAdditional()) {
     119                 :         64 :         return;
     120                 :            :     }
     121                 :            : 
     122                 :         64 :     RdataIteratorPtr it = rrset->getRdataIterator();
     123 [ +  - ][ +  - ]:        185 :     for (; !it->isLast(); it->next()) {
                 [ +  + ]
     124         [ +  - ]:        121 :         const Rdata& rd(it->getCurrent());
     125 [ +  - ][ +  + ]:        121 :         if (rrset->getType() == RRType::NS()) {
     126         [ +  - ]:         83 :             const generic::NS& ns = dynamic_cast<const generic::NS&>(rd);
     127 [ +  - ][ +  - ]:        166 :             LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_QUERY_GET_NS_ADDITIONAL).
                 [ +  - ]
     128 [ +  - ][ +  - ]:         83 :                 arg(ns.getNSName()).arg(rrset->getName());
         [ +  - ][ +  - ]
                 [ +  - ]
     129                 :         83 :             q.tasks().push(QueryTaskPtr(
     130                 :            :                                new QueryTask(q, ns.getNSName(),
     131                 :            :                                              Message::SECTION_ADDITIONAL,
     132                 :            :                                              QueryTask::GLUE_QUERY,
     133 [ +  - ][ +  - ]:         83 :                                              QueryTask::GETADDITIONAL)));
         [ +  - ][ +  - ]
                 [ +  - ]
     134 [ +  - ][ -  + ]:         38 :         } else if (rrset->getType() == RRType::MX()) {
     135         [ #  # ]:          0 :             const generic::MX& mx = dynamic_cast<const generic::MX&>(rd);
     136 [ #  # ][ #  # ]:          0 :             LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_QUERY_GET_MX_ADDITIONAL).
                 [ #  # ]
     137 [ #  # ][ #  # ]:          0 :                 arg(mx.getMXName()).arg(rrset->getName());
         [ #  # ][ #  # ]
                 [ #  # ]
     138                 :          0 :             q.tasks().push(QueryTaskPtr(
     139                 :            :                                new QueryTask(q, mx.getMXName(),
     140                 :            :                                              Message::SECTION_ADDITIONAL,
     141                 :            :                                              QueryTask::NOGLUE_QUERY,
     142 [ #  # ][ #  # ]:          0 :                                              QueryTask::GETADDITIONAL)));
         [ #  # ][ #  # ]
                 [ #  # ]
     143                 :            :         }
     144                 :            :     }
     145                 :            : }
     146                 :            : 
     147                 :            : // Synthesize a CNAME answer, for the benefit of clients that don't
     148                 :            : // understand DNAME
     149                 :            : void
     150                 :          2 : synthesizeCname(QueryTaskPtr task, RRsetPtr rrset, RRsetList& target) {
     151         [ +  - ]:          4 :     LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_QUERY_SYNTH_CNAME).
     152         [ +  - ]:          2 :         arg(rrset->getName());
     153                 :          2 :     RdataIteratorPtr it = rrset->getRdataIterator();
     154                 :            : 
     155                 :            :     // More than one DNAME RR in the RRset is illegal, so we only have
     156                 :            :     // to process the first one.
     157 [ +  - ][ -  + ]:          2 :     if (it->isLast()) {
     158 [ #  # ][ #  # ]:          0 :         logger.error(DATASRC_QUERY_EMPTY_DNAME).arg(rrset->getName());
         [ #  # ][ #  # ]
     159                 :          2 :         return;
     160                 :            :     }
     161                 :            : 
     162         [ +  - ]:          2 :     const Rdata& rd(it->getCurrent());
     163         [ +  - ]:          2 :     const generic::DNAME& dname = dynamic_cast<const generic::DNAME&>(rd);
     164         [ +  - ]:          2 :     const Name& dname_target(dname.getDname());
     165                 :            : 
     166                 :          2 :     RRsetPtr cname(new RRset(task->qname, rrset->getClass(), RRType::CNAME(),
     167 [ +  - ][ +  - ]:          2 :                              rrset->getTTL()));
         [ +  - ][ +  - ]
                 [ +  - ]
     168                 :            : 
     169                 :          2 :     const int qnlen = task->qname.getLabelCount();
     170         [ +  - ]:          2 :     const int dnlen = rrset->getName().getLabelCount();
     171         [ -  + ]:          2 :     assert(qnlen > dnlen);
     172         [ +  - ]:          4 :     const Name& prefix(task->qname.split(0, qnlen - dnlen));
     173 [ +  - ][ +  - ]:          4 :     cname->addRdata(generic::CNAME(prefix.concatenate(dname_target)));
                 [ +  - ]
     174                 :            : 
     175         [ +  - ]:          2 :     target.addRRset(cname);
     176                 :            : }
     177                 :            : 
     178                 :            : // Add a task to the query task queue to look up the data pointed
     179                 :            : // to by a CNAME record
     180                 :            : void
     181                 :         27 : chaseCname(Query& q, QueryTaskPtr task, RRsetPtr rrset) {
     182         [ +  - ]:         54 :     LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_QUERY_FOLLOW_CNAME).
     183         [ +  - ]:         27 :         arg(rrset->getName());
     184                 :         27 :     RdataIteratorPtr it = rrset->getRdataIterator();
     185                 :            : 
     186                 :            :     // More than one CNAME RR in the RRset is illegal, so we only have
     187                 :            :     // to process the first one.
     188 [ +  - ][ -  + ]:         27 :     if (it->isLast()) {
     189 [ #  # ][ #  # ]:          0 :         logger.error(DATASRC_QUERY_EMPTY_CNAME).arg(rrset->getName());
         [ #  # ][ #  # ]
     190                 :            :         return;
     191                 :            :     }
     192                 :            : 
     193                 :            :     // Stop chasing CNAMES after 16 lookups, to prevent loops
     194         [ +  + ]:         27 :     if (q.tooMany()) {
     195 [ +  - ][ +  - ]:          1 :         logger.error(DATASRC_QUERY_TOO_MANY_CNAMES).arg(rrset->getName());
         [ +  - ][ +  - ]
     196                 :            :         return;
     197                 :            :     }
     198                 :            : 
     199                 :         26 :     q.tasks().push(QueryTaskPtr(
     200                 :            :                        new QueryTask(q, dynamic_cast<const generic::CNAME&>
     201 [ +  - ][ +  - ]:         26 :                                      (it->getCurrent()).getCname(),
     202                 :         26 :                                      task->qtype, Message::SECTION_ANSWER,
     203   [ +  -  +  - ]:         52 :                                      QueryTask::FOLLOWCNAME)));
         [ +  - ][ +  - ]
                 [ +  - ]
     204                 :            : }
     205                 :            : 
     206                 :            : // Check the cache for data which can answer the current query task.
     207                 :            : bool
     208                 :        267 : checkCache(QueryTask& task, RRsetList& target) {
     209         [ +  - ]:        534 :     LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_QUERY_CHECK_CACHE).
     210 [ +  - ][ +  - ]:        267 :         arg(task.qname).arg(task.qtype);
     211                 :        534 :     HotCache& cache = task.q.getCache();
     212                 :            :     RRsetList rrsets;
     213                 :            :     RRsetPtr rrset;
     214                 :        267 :     int count = 0;
     215                 :        267 :     uint32_t flags = 0, cflags = 0;
     216                 :        267 :     bool hit = false, found = false;
     217                 :            : 
     218   [ +  +  +  +  :        267 :     switch (task.op) {
                      - ]
     219                 :            :     case QueryTask::SIMPLE_QUERY:       // Find exact RRset
     220                 :            :         // ANY queries must be handled by the low-level data source,
     221                 :            :         // or the results won't be guaranteed to be complete
     222 [ +  - ][ +  + ]:         48 :         if (task.qtype == RRType::ANY() || task.qclass == RRClass::ANY()) {
                 [ +  + ]
     223 [ +  - ][ +  - ]:         14 :             LOG_DEBUG(logger, DBG_TRACE_DATA,
                 [ +  - ]
     224 [ +  - ][ +  - ]:          7 :                       DATASRC_QUERY_NO_CACHE_ANY_SIMPLE).arg(task.qname).
     225 [ +  - ][ +  - ]:          7 :                 arg(task.qtype).arg(task.qclass);
     226                 :            :             break;
     227                 :            :         }
     228                 :            : 
     229         [ +  - ]:         41 :         hit = cache.retrieve(task.qname, task.qclass, task.qtype, rrset, flags);
     230         [ +  + ]:         41 :         if (hit) {
     231         [ +  + ]:          3 :             if (rrset) {
     232         [ +  - ]:          1 :                 rrsets.addRRset(rrset);
     233         [ +  - ]:          1 :                 target.append(rrsets);
     234                 :            :             }
     235                 :            : 
     236                 :            :             // Reset the referral flag and treat CNAME as "not found".
     237                 :            :             // This emulates the behavior of the sqlite3 data source.
     238                 :            :             // XXX: this is not ideal in that the responsibility for handling
     239                 :            :             // operation specific cases is spread over various classes at
     240                 :            :             // different abstraction levels.  For longer terms we should
     241                 :            :             // revisit the whole datasource/query design, and clarify this
     242                 :            :             // point better.
     243                 :          3 :             flags &= ~DataSrc::REFERRAL;
     244         [ -  + ]:          3 :             if ((flags & DataSrc::CNAME_FOUND) != 0) {
     245                 :          0 :                 flags &= ~DataSrc::CNAME_FOUND;
     246                 :          0 :                 flags |= DataSrc::TYPE_NOT_FOUND;
     247                 :            :             }
     248                 :          3 :             task.flags = flags;
     249                 :            :             return (true);
     250                 :            :         }
     251                 :            :         break;
     252                 :            : 
     253                 :            :     case QueryTask::AUTH_QUERY:         // Find exact RRset or CNAME
     254 [ +  + ][ +  + ]:         88 :         if (task.qtype == RRType::ANY() || task.qclass == RRClass::ANY()) {
                 [ +  + ]
     255 [ +  - ][ +  - ]:         22 :             LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_QUERY_NO_CACHE_ANY_AUTH).
                 [ +  - ]
     256 [ +  - ][ +  - ]:         11 :                 arg(task.qname).arg(task.qtype).arg(task.qclass);
         [ +  - ][ +  - ]
     257                 :            :             break;
     258                 :            :         }
     259                 :            : 
     260         [ +  - ]:         77 :         hit = cache.retrieve(task.qname, task.qclass, task.qtype, rrset, flags);
     261 [ +  + ][ +  + ]:         77 :         if (!hit || !rrset || (flags & DataSrc::CNAME_FOUND) != 0) {
         [ +  - ][ +  + ]
     262                 :         75 :             hit = cache.retrieve(task.qname, task.qclass, RRType::CNAME(),
     263         [ +  - ]:         75 :                                  rrset, flags);
     264         [ +  + ]:         75 :             if (!rrset) {
     265                 :            :                 // If we don't have a positive cache, forget it; otherwise the
     266                 :            :                 // intermediate result may confuse the subsequent processing.
     267                 :         60 :                 hit = false;
     268                 :            :             }
     269                 :            :         }
     270                 :            : 
     271         [ +  + ]:         77 :         if (hit) {
     272         [ +  - ]:         17 :             if (rrset) {
     273         [ +  - ]:         17 :                 rrsets.addRRset(rrset);
     274         [ +  - ]:         17 :                 target.append(rrsets);
     275                 :            :             }
     276                 :         17 :             task.flags = flags;
     277                 :            :             return (true);
     278                 :            :         }
     279                 :            :         break;
     280                 :            : 
     281                 :            :     case QueryTask::GLUE_QUERY:         // Find addresses
     282                 :            :     case QueryTask::NOGLUE_QUERY:
     283                 :            :         // (XXX: need to figure out how to deal with noglue case)
     284                 :         83 :         flags = 0;
     285                 :            : 
     286                 :         83 :         hit = cache.retrieve(task.qname, task.qclass, RRType::A(),
     287         [ +  - ]:         83 :                              rrset, cflags);
     288         [ +  + ]:         83 :         if (hit) {
     289                 :          8 :             flags |= cflags;
     290                 :          8 :             ++count;
     291         [ +  - ]:          8 :             if (rrset) {
     292         [ +  - ]:          8 :                 rrsets.addRRset(rrset);
     293                 :            :                 found = true;
     294                 :            :             }
     295                 :            :         }
     296                 :            : 
     297                 :         83 :         hit = cache.retrieve(task.qname, task.qclass, RRType::AAAA(),
     298         [ +  - ]:         83 :                              rrset, flags);
     299         [ +  + ]:         83 :         if (hit) {
     300                 :          6 :             flags |= cflags;
     301                 :          6 :             ++count;
     302         [ -  + ]:          6 :             if (rrset) {
     303         [ #  # ]:          0 :                 rrsets.addRRset(rrset);
     304                 :            :                 found = true;
     305                 :            :             }
     306                 :            :         }
     307                 :            : 
     308         [ +  + ]:         83 :         if (count == 2) {
     309         [ +  - ]:          6 :             if (found) {
     310                 :          6 :                 flags &= ~DataSrc::TYPE_NOT_FOUND;
     311         [ +  - ]:          6 :                 target.append(rrsets);
     312                 :            :             }
     313                 :          6 :             task.flags = flags;
     314                 :            :             return (true);
     315                 :            :         } 
     316                 :            :         break;
     317                 :            : 
     318                 :            : 
     319                 :            :     case QueryTask::REF_QUERY:          // Find NS, DS and/or DNAME
     320                 :         48 :         flags = count = 0;
     321                 :            : 
     322                 :         48 :         hit = cache.retrieve(task.qname, task.qclass, RRType::NS(),
     323         [ +  - ]:         48 :                              rrset, cflags);
     324         [ +  + ]:         48 :         if (hit) {
     325                 :          3 :             flags |= cflags;
     326                 :          3 :             ++count;
     327         [ +  - ]:          3 :             if (rrset) {
     328         [ +  - ]:          3 :                 rrsets.addRRset(rrset);
     329                 :            :                 found = true;
     330                 :            :             }
     331                 :            :         }
     332                 :            : 
     333                 :         48 :         hit = cache.retrieve(task.qname, task.qclass, RRType::DS(),
     334         [ +  - ]:         48 :                              rrset, flags);
     335         [ +  + ]:         48 :         if (hit) {
     336                 :          2 :             flags |= cflags;
     337                 :          2 :             ++count;
     338         [ +  + ]:          2 :             if (rrset) {
     339         [ +  - ]:          1 :                 rrsets.addRRset(rrset);
     340                 :            :                 found = true;
     341                 :            :             }
     342                 :            :         }
     343                 :            : 
     344                 :         48 :         hit = cache.retrieve(task.qname, task.qclass, RRType::DNAME(),
     345         [ +  - ]:         48 :                              rrset, flags);
     346         [ +  + ]:         48 :         if (hit) {
     347                 :          2 :             flags |= cflags;
     348                 :          2 :             ++count;
     349         [ -  + ]:          2 :             if (rrset) {
     350         [ #  # ]:          0 :                 rrsets.addRRset(rrset);
     351                 :            :                 found = true;
     352                 :            :             }
     353                 :            :         }
     354                 :            : 
     355         [ +  + ]:         48 :         if (count == 3) {
     356         [ +  - ]:          1 :             if (found) {
     357                 :          1 :                 flags &= ~DataSrc::TYPE_NOT_FOUND;
     358                 :          1 :                 flags &= DataSrc::REFERRAL;
     359         [ +  - ]:          1 :                 target.append(rrsets);
     360                 :            :             }
     361                 :          1 :             task.flags = flags;
     362                 :            :             return (true);
     363                 :            :         } 
     364                 :            :         break;
     365                 :            :     }
     366                 :            : 
     367                 :            :     return (false);
     368                 :            : }
     369                 :            : 
     370                 :            : // Carry out the query specified in a QueryTask object
     371                 :            : DataSrc::Result
     372                 :        279 : doQueryTask(QueryTask& task, ZoneInfo& zoneinfo, RRsetList& target) {
     373                 :        558 :     HotCache& cache = task.q.getCache();
     374                 :            :     RRsetPtr rrset;
     375 [ +  - ][ +  - ]:        558 :     LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_DO_QUERY).arg(task.qname).
         [ +  - ][ +  - ]
                 [ +  - ]
     376         [ +  - ]:        279 :         arg(task.qtype);
     377                 :            : 
     378                 :            :     // First off, make sure at least we have a matching zone in some data
     379                 :            :     // source.  We must do this before checking the cache, because it can
     380                 :            :     // happen that the matching zone has been removed after an RRset of that
     381                 :            :     // zone is cached.  Such inconsistency will cause various problems,
     382                 :            :     // including a crash.
     383                 :        279 :     const DataSrc* ds = zoneinfo.getDataSource();
     384                 :        279 :     const Name* const zonename = zoneinfo.getEnclosingZone();
     385         [ +  + ]:        279 :     if (ds == NULL) {
     386                 :         12 :         task.flags |= DataSrc::NO_SUCH_ZONE;
     387 [ +  - ][ +  - ]:         24 :         LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_QUERY_NO_ZONE).
                 [ +  - ]
     388 [ +  - ][ +  - ]:         12 :             arg(task.qname).arg(task.qclass);
                 [ +  - ]
     389                 :            :         return (DataSrc::SUCCESS);
     390                 :            :     }
     391                 :            : 
     392                 :            :     // Then check the cache for matching data
     393 [ +  - ][ +  + ]:        267 :     if (checkCache(task, target)) {
     394 [ +  - ][ +  - ]:         54 :         LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_QUERY_CACHED).
                 [ +  - ]
     395 [ +  - ][ +  - ]:         27 :             arg(task.qname).arg(task.qtype);
                 [ +  - ]
     396                 :            :         return (DataSrc::SUCCESS);
     397                 :            :     }
     398                 :            : 
     399                 :            :     // Requested data weren't in the cache (or were, but had expired),
     400                 :            :     // so now we proceed with the low-level data source lookup, and cache
     401                 :            :     // whatever we find.
     402                 :            : 
     403                 :            :     DataSrc::Result result;
     404   [ +  +  +  +  :        240 :     switch (task.op) {
                      - ]
     405                 :            :     case QueryTask::SIMPLE_QUERY:
     406 [ +  - ][ +  - ]:         90 :         LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_QUERY_IS_SIMPLE).
                 [ +  - ]
     407 [ +  - ][ +  - ]:         45 :             arg(task.qname).arg(task.qtype);
                 [ +  - ]
     408                 :            :         result = ds->findExactRRset(task.qname, task.qclass, task.qtype,
     409         [ +  - ]:         45 :                                     target, task.flags, zonename);
     410                 :            : 
     411         [ -  + ]:         45 :         if (result != DataSrc::SUCCESS) {
     412 [ #  # ][ #  # ]:          0 :             logger.error(DATASRC_QUERY_SIMPLE_FAIL).arg(result);
                 [ #  # ]
     413                 :          0 :             return (result);
     414                 :            :         }
     415                 :            : 
     416         [ +  + ]:         45 :         if (task.qclass == RRClass::ANY()) {
     417                 :            :             // XXX: Currently, RRsetList::findRRset() doesn't handle
     418                 :            :             // ANY queries, and without that we can't cache the results,
     419                 :            :             // so we just return in that case.
     420                 :          7 :             return (result);
     421                 :            :         }
     422                 :            : 
     423         [ +  + ]:         38 :         if (task.flags == 0) {
     424 [ +  - ][ +  - ]:         20 :             rrset = target.findRRset(task.qtype, task.qclass);
     425         [ -  + ]:         20 :             assert(rrset);
     426         [ +  - ]:         20 :             cache.addPositive(rrset, task.flags);
     427                 :            :         } else {
     428         [ +  - ]:         18 :             cache.addNegative(task.qname, task.qclass, task.qtype, task.flags);
     429                 :            :         }
     430                 :            : 
     431                 :         38 :         return (result);
     432                 :            : 
     433                 :            :     case QueryTask::AUTH_QUERY:
     434 [ +  - ][ +  - ]:        142 :         LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_QUERY_IS_AUTH).
                 [ +  - ]
     435 [ +  - ][ +  - ]:         71 :             arg(task.qname).arg(task.qtype);
                 [ +  - ]
     436                 :            :         result = ds->findRRset(task.qname, task.qclass, task.qtype,
     437         [ +  + ]:         71 :                                target, task.flags, zonename);
     438                 :            : 
     439         [ -  + ]:         70 :         if (result != DataSrc::SUCCESS) {
     440 [ #  # ][ #  # ]:          0 :             logger.error(DATASRC_QUERY_AUTH_FAIL).arg(result);
                 [ #  # ]
     441                 :          0 :             return (result);
     442                 :            :         }
     443                 :            : 
     444         [ +  + ]:         70 :         if (task.qclass == RRClass::ANY()) {
     445                 :         10 :             return (result);
     446                 :            :         }
     447                 :            : 
     448         [ +  + ]:         60 :         if (task.qtype == RRType::ANY()) {
     449 [ +  + ][ +  - ]:         13 :             BOOST_FOREACH(RRsetPtr rr, target) {
         [ +  - ][ +  + ]
                 [ +  + ]
     450         [ +  - ]:          3 :                 cache.addPositive(rr, task.flags);
     451                 :            :             }
     452         [ +  + ]:         59 :         } else if ((task.flags & DataSrc::CNAME_FOUND) != 0) {
     453         [ +  - ]:          8 :             cache.addNegative(task.qname, task.qclass, task.qtype, task.flags);
     454 [ +  - ][ +  - ]:          8 :             rrset = target.findRRset(RRType::CNAME(), task.qclass);
     455         [ -  + ]:          8 :             assert(rrset);
     456         [ +  - ]:          8 :             cache.addPositive(rrset, task.flags);
     457         [ +  + ]:         51 :         } else if ((task.flags & DataSrc::DATA_NOT_FOUND) == 0) {
     458         [ +  - ]:         25 :             if (task.qtype != RRType::CNAME()) {
     459                 :         25 :                 cache.addNegative(task.qname, task.qclass, RRType::CNAME(),
     460         [ +  - ]:         25 :                                   task.flags);
     461                 :            :             }
     462 [ +  - ][ +  - ]:         25 :             rrset = target.findRRset(task.qtype, task.qclass);
     463         [ -  + ]:         25 :             assert(rrset);
     464         [ +  - ]:         25 :             cache.addPositive(rrset, task.flags);
     465                 :            :         } else {
     466         [ +  - ]:         26 :             cache.addNegative(task.qname, task.qclass, task.qtype, task.flags);
     467                 :            :         }
     468                 :            : 
     469                 :         60 :         return (result);
     470                 :            : 
     471                 :            :     case QueryTask::GLUE_QUERY:
     472                 :            :     case QueryTask::NOGLUE_QUERY:
     473 [ +  - ][ +  - ]:        154 :         LOG_DEBUG(logger, DBG_TRACE_DATA, task.op == QueryTask::GLUE_QUERY ?
                 [ +  - ]
     474                 :            :                      DATASRC_QUERY_IS_GLUE : DATASRC_QUERY_IS_NOGLUE).
     475 [ -  + ][ +  - ]:         77 :             arg(task.qname).arg(task.qtype);
         [ +  - ][ +  - ]
     476                 :            :         result = ds->findAddrs(task.qname, task.qclass, target,
     477         [ +  - ]:         77 :                                task.flags, zonename);
     478                 :            : 
     479         [ -  + ]:         77 :         if (result != DataSrc::SUCCESS) {
     480                 :            :             logger.error(task.op == QueryTask::GLUE_QUERY ?
     481         [ #  # ]:          0 :                          DATASRC_QUERY_GLUE_FAIL : DATASRC_QUERY_NOGLUE_FAIL).
     482 [ #  # ][ #  # ]:          0 :                 arg(result);
                 [ #  # ]
     483                 :          0 :             return (result);
     484                 :            :         }
     485                 :            : 
     486         [ +  + ]:         77 :         if (task.qclass == RRClass::ANY()) {
     487                 :         12 :             return (result);
     488                 :            :         }
     489                 :            : 
     490 [ +  - ][ +  - ]:         65 :         rrset = target.findRRset(RRType::A(), task.qclass);
     491         [ +  + ]:         65 :         if (rrset) {
     492         [ +  - ]:         57 :             cache.addPositive(rrset, task.flags);
     493                 :            :         } else {
     494         [ +  - ]:          8 :             cache.addNegative(task.qname, task.qclass, RRType::A(), task.flags);
     495                 :            :         }
     496                 :            : 
     497 [ +  - ][ +  - ]:         65 :         rrset = target.findRRset(RRType::AAAA(), task.qclass);
     498         [ -  + ]:         65 :         if (rrset) {
     499         [ #  # ]:          0 :             cache.addPositive(rrset, task.flags);
     500                 :            :         } else {
     501                 :         65 :             cache.addNegative(task.qname, task.qclass, RRType::AAAA(),
     502         [ +  - ]:         65 :                               task.flags);
     503                 :            :         }
     504                 :            : 
     505                 :         65 :         return (result);
     506                 :            : 
     507                 :            :     case QueryTask::REF_QUERY:
     508 [ +  - ][ +  - ]:         94 :         LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_QUERY_IS_REF).
                 [ +  - ]
     509 [ +  - ][ +  - ]:         47 :             arg(task.qname).arg(task.qtype);
                 [ +  - ]
     510                 :            :         result = ds->findReferral(task.qname, task.qclass, target,
     511         [ +  - ]:         47 :                                  task.flags, zonename);
     512                 :            : 
     513         [ -  + ]:         47 :         if (result != DataSrc::SUCCESS) {
     514 [ #  # ][ #  # ]:          0 :             logger.error(DATASRC_QUERY_REF_FAIL).arg(result);
                 [ #  # ]
     515                 :          0 :             return (result);
     516                 :            :         }
     517                 :            : 
     518         [ +  + ]:         47 :         if (task.qclass == RRClass::ANY()) {
     519                 :          6 :             return (result);
     520                 :            :         }
     521                 :            : 
     522 [ +  - ][ +  - ]:         41 :         rrset = target.findRRset(RRType::NS(), task.qclass);
     523         [ +  + ]:         41 :         if (rrset) {
     524         [ +  - ]:         26 :             cache.addPositive(rrset, task.flags);
     525                 :            :         } else {
     526                 :         15 :             cache.addNegative(task.qname, task.qclass, RRType::NS(),
     527         [ +  - ]:         15 :                               task.flags);
     528                 :            :         }
     529 [ +  - ][ +  - ]:         41 :         rrset = target.findRRset(RRType::DS(), task.qclass);
     530         [ +  + ]:         41 :         if (rrset) {
     531         [ +  - ]:          4 :             cache.addPositive(rrset, task.flags);
     532                 :            :         } else {
     533                 :         37 :             cache.addNegative(task.qname, task.qclass, RRType::DS(),
     534         [ +  - ]:         37 :                               task.flags);
     535                 :            :         }
     536 [ +  - ][ +  - ]:         41 :         rrset = target.findRRset(RRType::DNAME(), task.qclass);
     537         [ +  + ]:         41 :         if (rrset) {
     538         [ +  - ]:          2 :             cache.addPositive(rrset, task.flags);
     539                 :            :         } else {
     540                 :         39 :             cache.addNegative(task.qname, task.qclass, RRType::DNAME(),
     541         [ +  - ]:         39 :                               task.flags);
     542                 :            :         }
     543                 :            : 
     544                 :         41 :         return (result);
     545                 :            :     }
     546                 :            : 
     547                 :            :     // Not reached
     548 [ #  # ][ #  # ]:          0 :     logger.error(DATASRC_QUERY_INVALID_OP);
     549                 :            :     return (DataSrc::ERROR);
     550                 :            : }
     551                 :            : 
     552                 :            : 
     553                 :            : // Add an RRset (and its associated RRSIG) to a message section,
     554                 :            : // checking first to ensure that there isn't already an RRset with
     555                 :            : // the same name and type.
     556                 :            : inline void
     557                 :        244 : addToMessage(Query& q, const Message::Section sect, RRsetPtr rrset,
     558                 :            :              bool no_dnssec = false)
     559                 :            : {
     560         [ +  - ]:        488 :     LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_QUERY_ADD_RRSET).
     561 [ +  - ][ +  - ]:        244 :         arg(rrset->getName()).arg(rrset->getType());
     562                 :        244 :     Message& m = q.message();
     563         [ +  + ]:        244 :     if (no_dnssec) {
     564   [ +  +  +  - ]:        197 :         if (rrset->getType() == RRType::RRSIG() ||
                 [ +  - ]
     565                 :         73 :             !m.hasRRset(sect, rrset->getName(), rrset->getClass(),
     566                 :        146 :                         rrset->getType())) {
     567         [ +  - ]:        124 :             m.addRRset(sect, rrset, false);
     568                 :            :         }
     569                 :            :     } else {
     570         [ +  + ]:        240 :         if (!m.hasRRset(sect, rrset->getName(), rrset->getClass(),
     571                 :        240 :                         rrset->getType())) {
     572         [ +  - ]:        105 :             m.addRRset(sect, rrset, q.wantDnssec());
     573                 :            :         }
     574                 :            :     }
     575                 :        244 : }
     576                 :            : 
     577                 :            : // Copy referral information into the authority section of a message
     578                 :            : inline void
     579                 :         27 : copyAuth(Query& q, RRsetList& auth) {
     580         [ +  - ]:         27 :     LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_QUERY_COPY_AUTH);
     581   [ +  +  +  - ]:        139 :     BOOST_FOREACH(RRsetPtr rrset, auth) {
         [ +  - ][ +  + ]
                 [ +  + ]
     582 [ +  - ][ -  + ]:         28 :         if (rrset->getType() == RRType::DNAME()) {
     583                 :          0 :             continue;
     584                 :            :         }
     585 [ +  - ][ +  + ]:         28 :         if (rrset->getType() == RRType::DS() && !q.wantDnssec()) {
         [ +  - ][ -  + ]
     586                 :          0 :             continue;
     587                 :            :         }
     588         [ +  - ]:         28 :         addToMessage(q, Message::SECTION_AUTHORITY, rrset);
     589         [ +  - ]:         28 :         getAdditional(q, rrset);
     590                 :            :     }
     591                 :         27 : }
     592                 :            : 
     593                 :            : // Query for referrals (i.e., NS/DS or DNAME) at a given name
     594                 :            : inline bool
     595                 :         48 : refQuery(const Query& q, const Name& name, ZoneInfo& zoneinfo,
     596                 :            :          RRsetList& target)
     597                 :            : {
     598                 :         96 :     QueryTask newtask(q, name, QueryTask::REF_QUERY);
     599                 :            : 
     600 [ +  - ][ +  - ]:         48 :     if (doQueryTask(newtask, zoneinfo, target) != DataSrc::SUCCESS) {
     601                 :            :         // Lookup failed
     602                 :            :         return (false);
     603                 :            :     }
     604                 :            : 
     605                 :            :     // Referral bit is expected, so clear it when checking flags
     606         [ +  + ]:         48 :     if ((newtask.flags & ~DataSrc::REFERRAL) != 0) {
     607                 :            :         return (false);
     608                 :            :     }
     609                 :            : 
     610                 :            :     return (true);
     611                 :            : }
     612                 :            : 
     613                 :            : // Match downward, from the zone apex to the query name, looking for
     614                 :            : // referrals.  Note that we exclude the apex name and query name themselves;
     615                 :            : // they'll be handled in a normal lookup in the zone.
     616                 :            : inline bool
     617                 :         90 : hasDelegation(Query& q, QueryTaskPtr task, ZoneInfo& zoneinfo) {
     618         [ +  - ]:        180 :     LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_QUERY_DELEGATION).
     619         [ +  - ]:         90 :         arg(task->qname);
     620                 :            : 
     621                 :         90 :     const Name* const zonename = zoneinfo.getEnclosingZone();
     622         [ +  + ]:         90 :     if (zonename == NULL) {
     623         [ +  + ]:         12 :         if (task->state == QueryTask::GETANSWER) {
     624                 :         10 :             q.message().setRcode(Rcode::REFUSED());
     625                 :            :         }
     626                 :            :         return (false);
     627                 :            :     }
     628                 :            : 
     629                 :         78 :     const int diff = task->qname.getLabelCount() - zonename->getLabelCount();
     630         [ +  + ]:         78 :     if (diff > 1) {
     631                 :         14 :         bool found = false;
     632                 :            :         RRsetList ref;
     633         [ +  + ]:         27 :         for (int i = diff - 1; i > 0; --i) {
     634         [ +  - ]:         34 :             const Name sub(task->qname.split(i));
     635 [ +  - ][ +  + ]:         17 :             if (refQuery(q, sub, zoneinfo, ref)) {
     636                 :          4 :                 found = true;
     637                 :            :                 break;
     638                 :            :             }
     639                 :            :         }
     640                 :            : 
     641                 :            :         // Found a referral while getting additional data
     642                 :            :         // for something other than NS; we skip it.
     643 [ +  + ][ +  - ]:         14 :         if (found && task->op == QueryTask::NOGLUE_QUERY) {
                 [ +  - ]
     644                 :            :             return (true);
     645                 :            :         }
     646                 :            : 
     647                 :            :         // Found a referral while getting answer data;
     648                 :            :         // send a delegation.
     649         [ +  + ]:         14 :         if (found) {
     650         [ +  - ]:          4 :             RRsetPtr r = findRRsetFromList(ref, RRType::DNAME());
     651         [ +  + ]:          4 :             if (r != NULL) {
     652                 :            :                 RRsetList syn;
     653         [ +  - ]:          2 :                 addToMessage(q, Message::SECTION_ANSWER, r);
     654         [ +  - ]:          2 :                 q.message().setHeaderFlag(Message::HEADERFLAG_AA);
     655         [ +  - ]:          2 :                 synthesizeCname(task, r, syn);
     656         [ +  - ]:          2 :                 if (syn.size() == 1) {
     657                 :            :                     RRsetPtr cname_rrset = findRRsetFromList(syn,
     658         [ +  - ]:          2 :                                                              RRType::CNAME());
     659         [ +  - ]:          2 :                     addToMessage(q, Message::SECTION_ANSWER, cname_rrset);
     660         [ +  - ]:          2 :                     chaseCname(q, task, cname_rrset);
     661                 :          2 :                     return (true);
     662                 :            :                 }
     663                 :            :             }
     664                 :            : 
     665         [ +  - ]:          2 :             copyAuth(q, ref);
     666                 :            :             return (true);
     667                 :            :         }
     668                 :            :     }
     669                 :            : 
     670                 :            :     // We appear to have authoritative data; set the header
     671                 :            :     // flag.  (We may clear it later if we find a referral
     672                 :            :     // at the actual qname node.)
     673   [ +  -  +  + ]:        148 :     if (task->op == QueryTask::AUTH_QUERY &&
                 [ +  + ]
     674                 :         74 :         task->state == QueryTask::GETANSWER) {
     675                 :         90 :         q.message().setHeaderFlag(Message::HEADERFLAG_AA);
     676                 :            :     }
     677                 :            : 
     678                 :            :     return (false);
     679                 :            : }
     680                 :            : 
     681                 :            : inline DataSrc::Result
     682                 :         12 : addSOA(Query& q, ZoneInfo& zoneinfo) {
     683                 :            :     RRsetList soa;
     684                 :            : 
     685                 :         12 :     const Name* const zonename = zoneinfo.getEnclosingZone();
     686 [ +  - ][ +  - ]:         12 :     LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_QUERY_ADD_SOA).arg(*zonename);
         [ +  - ][ +  - ]
                 [ +  - ]
     687 [ +  - ][ +  - ]:         24 :     QueryTask newtask(q, *zonename, RRType::SOA(), QueryTask::SIMPLE_QUERY);
     688 [ +  - ][ +  - ]:         12 :     RETERR(doQueryTask(newtask, zoneinfo, soa));
     689         [ +  + ]:         12 :     if (newtask.flags != 0) {
     690                 :            :         return (DataSrc::ERROR);
     691                 :            :     }
     692                 :            : 
     693                 :            :     addToMessage(q, Message::SECTION_AUTHORITY,
     694 [ +  - ][ +  - ]:         10 :                  findRRsetFromList(soa, RRType::SOA()));
     695                 :            :     return (DataSrc::SUCCESS);
     696                 :            : }
     697                 :            : 
     698                 :            : inline DataSrc::Result
     699                 :         21 : addNSEC(Query& q, const Name& name, ZoneInfo& zoneinfo) {
     700 [ +  - ][ +  - ]:         21 :     LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_QUERY_ADD_NSEC).arg(name);
     701                 :            :     RRsetList nsec;
     702                 :            : 
     703 [ +  - ][ +  - ]:         42 :     QueryTask newtask(q, name, RRType::NSEC(), QueryTask::SIMPLE_QUERY); 
     704 [ +  - ][ +  - ]:         21 :     RETERR(doQueryTask(newtask, zoneinfo, nsec));
     705         [ +  + ]:         21 :     if (newtask.flags == 0) {
     706                 :            :         addToMessage(q, Message::SECTION_AUTHORITY,
     707 [ +  - ][ +  - ]:         16 :                      findRRsetFromList(nsec, RRType::NSEC()));
     708                 :            :     }
     709                 :            : 
     710                 :            :     return (DataSrc::SUCCESS);
     711                 :            : }
     712                 :            : 
     713                 :            : inline DataSrc::Result
     714                 :          0 : getNsec3(Query& q, ZoneInfo& zoneinfo, string& hash, RRsetPtr& target) {
     715                 :          0 :     const DataSrc* ds = zoneinfo.getDataSource();
     716                 :          0 :     const Name* const zonename = zoneinfo.getEnclosingZone();
     717 [ #  # ][ #  # ]:          0 :     LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_QUERY_ADD_NSEC3).arg(*zonename);
     718                 :            : 
     719         [ #  # ]:          0 :     if (ds == NULL) {
     720                 :          0 :         q.message().setRcode(Rcode::SERVFAIL());
     721         [ #  # ]:          0 :         logger.error(DATASRC_QUERY_NO_DS_NSEC3).arg(*zonename);
     722                 :          0 :         return (DataSrc::ERROR);
     723                 :            :     }
     724                 :            : 
     725                 :            :     RRsetList rl;
     726 [ #  # ][ #  # ]:          0 :     RETERR(ds->findCoveringNSEC3(*zonename, hash, rl));
     727 [ #  # ][ #  # ]:          0 :     target = rl.findRRset(RRType::NSEC3(), q.qclass());
     728                 :            : 
     729                 :            :     return (DataSrc::SUCCESS);
     730                 :            : }
     731                 :            : 
     732                 :            : ConstNsec3ParamPtr
     733                 :         15 : getNsec3Param(Query& q, ZoneInfo& zoneinfo) {
     734                 :            :     DataSrc::Result result;
     735                 :            :     RRsetList nsec3param;
     736                 :            : 
     737                 :         15 :     const Name* const zonename = zoneinfo.getEnclosingZone();
     738                 :         15 :     QueryTask newtask(q, *zonename, RRType::NSEC3PARAM(),
     739 [ +  - ][ +  - ]:         30 :                       QueryTask::SIMPLE_QUERY); 
     740         [ +  - ]:         15 :     result = doQueryTask(newtask, zoneinfo, nsec3param);
     741                 :         15 :     newtask.flags &= ~DataSrc::REFERRAL;
     742 [ +  - ][ +  - ]:         15 :     if (result != DataSrc::SUCCESS || newtask.flags != 0) {
     743                 :            :         return (ConstNsec3ParamPtr());
     744                 :            :     }
     745                 :            : 
     746         [ #  # ]:          0 :     RRsetPtr rrset = nsec3param.findRRset(RRType::NSEC3PARAM(), q.qclass());
     747         [ #  # ]:          0 :     if (!rrset) {
     748                 :            :         return (ConstNsec3ParamPtr());
     749                 :            :     }
     750                 :            : 
     751                 :            :     // XXX: currently only one NSEC3 chain per zone is supported;
     752                 :            :     // we will need to revisit this.
     753         [ #  # ]:          0 :     RdataIteratorPtr it = rrset->getRdataIterator();
     754 [ #  # ][ #  # ]:          0 :     if (it->isLast()) {
     755                 :            :         return (ConstNsec3ParamPtr());
     756                 :            :     }
     757                 :            : 
     758                 :            :     const generic::NSEC3PARAM& np =
     759 [ #  # ][ #  # ]:          0 :             dynamic_cast<const generic::NSEC3PARAM&>(it->getCurrent());
     760 [ #  # ][ #  # ]:          0 :     return (ConstNsec3ParamPtr(new Nsec3Param(np.getHashalg(), np.getFlags(),
     761         [ #  # ]:          0 :                                               np.getIterations(),
     762 [ #  # ][ #  # ]:          0 :                                               np.getSalt())));
                 [ #  # ]
     763                 :            : }
     764                 :            : 
     765                 :            : inline DataSrc::Result
     766                 :         15 : proveNX(Query& q, QueryTaskPtr task, ZoneInfo& zoneinfo, const bool wildcard) {
     767                 :         15 :     Message& m = q.message();
     768                 :         15 :     const Name* const zonename = zoneinfo.getEnclosingZone();
     769                 :         15 :     ConstNsec3ParamPtr nsec3 = getNsec3Param(q, zoneinfo);
     770                 :            : 
     771         [ -  + ]:         15 :     if (nsec3 != NULL) {
     772                 :            :         // Attach the NSEC3 record covering the QNAME
     773                 :            :         RRsetPtr rrset;
     774         [ #  # ]:          0 :         string hash1(nsec3->getHash(task->qname));
     775 [ #  # ][ #  # ]:          0 :         RETERR(getNsec3(q, zoneinfo, hash1, rrset));
     776         [ #  # ]:          0 :         addToMessage(q, Message::SECTION_AUTHORITY, rrset);
     777                 :            : 
     778                 :            :         // If this is an NXRRSET or NOERROR/NODATA, we're done
     779         [ #  # ]:          0 :         if ((task->flags & DataSrc::TYPE_NOT_FOUND) != 0) {
     780                 :            :             return (DataSrc::SUCCESS);
     781                 :            :         }
     782                 :            : 
     783                 :            :         // Find the closest provable enclosing name for QNAME
     784         [ #  # ]:          0 :         Name enclosure(*zonename);
     785                 :          0 :         const int diff = task->qname.getLabelCount() -
     786                 :          0 :             enclosure.getLabelCount();
     787                 :          0 :         string hash2;
     788         [ #  # ]:          0 :         for (int i = 1; i <= diff; ++i) {
     789         [ #  # ]:          0 :             enclosure = task->qname.split(i);
     790         [ #  # ]:          0 :             string nodehash(nsec3->getHash(enclosure));
     791         [ #  # ]:          0 :             if (nodehash == hash1) {
     792                 :            :                 break;
     793                 :            :             }
     794                 :            :             hash2 = nodehash;
     795                 :            :             RRsetList rl;
     796                 :            : 
     797                 :            :             // hash2 will be overwritten with the actual hash found;
     798                 :            :             // we don't want to use one until we find an exact match
     799 [ #  # ][ #  # ]:          0 :             RETERR(getNsec3(q, zoneinfo, hash2, rrset));
     800         [ #  # ]:          0 :             if (hash2 == nodehash) {
     801         [ #  # ]:          0 :                 addToMessage(q, Message::SECTION_AUTHORITY, rrset);
     802                 :            :                 break;
     803                 :            :             }
     804                 :            :         }
     805                 :            : 
     806                 :            :         // If we are processing a wildcard answer, we're done.
     807         [ #  # ]:          0 :         if (wildcard) {
     808                 :            :             return (DataSrc::SUCCESS);
     809                 :            :         }
     810                 :            : 
     811                 :            :         // Otherwise, there is no wildcard record, so we must add a
     812                 :            :         // covering NSEC3 to prove that it doesn't exist.
     813 [ #  # ][ #  # ]:          0 :         string hash3(nsec3->getHash(Name("*").concatenate(enclosure)));
         [ #  # ][ #  # ]
     814 [ #  # ][ #  # ]:          0 :         RETERR(getNsec3(q, zoneinfo, hash3, rrset));
     815   [ #  #  #  # ]:          0 :         if (hash3 != hash1 && hash3 != hash2) {
                 [ #  # ]
     816         [ #  # ]:          0 :             addToMessage(q, Message::SECTION_AUTHORITY, rrset);
     817                 :            :         }
     818                 :            :     } else {
     819         [ +  - ]:         30 :         Name nsecname(task->qname);
     820 [ +  + ][ +  + ]:         15 :         if ((task->flags & DataSrc::NAME_NOT_FOUND) != 0 || wildcard) {
                 [ +  + ]
     821                 :          9 :             const DataSrc* ds = zoneinfo.getDataSource();
     822         [ -  + ]:          9 :             if (ds == NULL) {
     823 [ #  # ][ #  # ]:          0 :                 m.setRcode(Rcode::SERVFAIL());
     824 [ #  # ][ #  # ]:          0 :                 logger.error(DATASRC_QUERY_NO_DS_NSEC).arg(*zonename);
                 [ #  # ]
     825                 :            :                 return (DataSrc::ERROR);
     826                 :            :             }
     827         [ +  - ]:          9 :             ds->findPreviousName(task->qname, nsecname, zonename);
     828                 :            :         }
     829                 :            : 
     830 [ +  - ][ +  - ]:         15 :         RETERR(addNSEC(q, nsecname, zoneinfo));
     831 [ +  + ][ -  + ]:         24 :         if ((task->flags & DataSrc::TYPE_NOT_FOUND) != 0 ||
                 [ +  + ]
     832                 :            :             nsecname == *zonename)
     833                 :            :         {
     834                 :            :             return (DataSrc::SUCCESS);
     835                 :            :         }
     836                 :            : 
     837                 :            :         // If we are processing a wildcard answer, we're done.
     838         [ +  + ]:          9 :         if (wildcard) {
     839                 :            :             return (DataSrc::SUCCESS);
     840                 :            :         }
     841                 :            : 
     842                 :            :         // Otherwise, there is no wildcard record, so we must add an
     843                 :            :         // NSEC for the zone to prove the wildcard doesn't exist.
     844 [ +  - ][ +  - ]:          6 :         RETERR(addNSEC(q, *zonename, zoneinfo));
     845                 :            :     }
     846                 :            : 
     847                 :            :     return (DataSrc::SUCCESS);
     848                 :            : }
     849                 :            : 
     850                 :            : // Attempt a wildcard lookup
     851                 :            : inline DataSrc::Result
     852                 :         19 : tryWildcard(Query& q, QueryTaskPtr task, ZoneInfo& zoneinfo, bool& found) {
     853 [ +  - ][ +  - ]:         19 :     LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_QUERY_WILDCARD).arg(task->qname);
     854                 :         19 :     Message& m = q.message();
     855                 :            :     DataSrc::Result result;
     856                 :         19 :     found = false;
     857                 :            : 
     858   [ +  +  +  +  :         34 :     if ((task->flags & DataSrc::NAME_NOT_FOUND) == 0 || 
           +  - ][ +  + ]
     859                 :         14 :         (task->state != QueryTask::GETANSWER &&
     860                 :          1 :          task->state != QueryTask::FOLLOWCNAME)) {
     861                 :            :         return (DataSrc::SUCCESS);
     862                 :            :     }
     863                 :            : 
     864                 :         14 :     const Name* const zonename = zoneinfo.getEnclosingZone();
     865                 :         14 :     const int diff = task->qname.getLabelCount() - zonename->getLabelCount();
     866         [ +  - ]:         14 :     if (diff < 1) {
     867                 :            :         return (DataSrc::SUCCESS);
     868                 :            :     }
     869                 :            : 
     870                 :            :     RRsetList wild;
     871 [ +  - ][ +  - ]:         28 :     const Name star("*");
     872                 :            :     bool cname = false;
     873                 :            : 
     874         [ +  + ]:         22 :     for (int i = 1; i <= diff; ++i) {
     875 [ +  - ][ +  - ]:         28 :         const Name& wname(star.concatenate(task->qname.split(i)));
     876                 :         14 :         QueryTask newtask(q, wname, task->qtype, Message::SECTION_ANSWER,
     877 [ +  - ][ +  - ]:         28 :                           QueryTask::AUTH_QUERY); 
                 [ +  - ]
     878         [ +  - ]:         14 :         result = doQueryTask(newtask, zoneinfo, wild);
     879         [ +  - ]:         14 :         if (result == DataSrc::SUCCESS) {
     880         [ +  + ]:         14 :             if (newtask.flags == 0) {
     881                 :          1 :                 task->flags &= ~DataSrc::NAME_NOT_FOUND;
     882                 :          1 :                 task->flags &= ~DataSrc::TYPE_NOT_FOUND;
     883                 :          1 :                 found = true;
     884                 :            :                 break;
     885         [ +  + ]:         13 :             } else if ((newtask.flags & DataSrc::CNAME_FOUND) != 0) {
     886                 :          4 :                 task->flags &= ~DataSrc::NAME_NOT_FOUND;
     887                 :          4 :                 task->flags &= ~DataSrc::TYPE_NOT_FOUND;
     888                 :          4 :                 task->flags |= DataSrc::CNAME_FOUND;
     889                 :          4 :                 found = true;
     890                 :          4 :                 cname = true;
     891                 :            :                 break;
     892         [ +  + ]:          9 :             } else if ((newtask.flags & DataSrc::TYPE_NOT_FOUND) != 0) {
     893                 :          1 :                 task->flags &= ~DataSrc::NAME_NOT_FOUND;
     894                 :          1 :                 task->flags |= DataSrc::TYPE_NOT_FOUND;
     895                 :            :                 break;
     896                 :            :             }
     897                 :            :         }
     898                 :            :     }
     899                 :            : 
     900                 :            :     // A wildcard was found.
     901         [ +  + ]:         14 :     if (found) {
     902                 :            :         // Prove the nonexistence of the name we were looking for
     903         [ +  + ]:          5 :         if (q.wantDnssec()) {
     904         [ +  - ]:          3 :             result = proveNX(q, task, zoneinfo, true);
     905         [ -  + ]:          3 :             if (result != DataSrc::SUCCESS) {
     906 [ #  # ][ #  # ]:          0 :                 m.setRcode(Rcode::SERVFAIL());
     907         [ #  # ]:          0 :                 logger.error(DATASRC_QUERY_WILDCARD_PROVE_NX_FAIL).
     908 [ #  # ][ #  # ]:          0 :                     arg(task->qname).arg(result);
                 [ #  # ]
     909                 :            :                 return (DataSrc::ERROR);
     910                 :            :             }
     911                 :            :         }
     912                 :            : 
     913                 :            :         // Add the data to the answer section (but with the name changed to
     914                 :            :         // match the qname), and then continue as if this were a normal
     915                 :            :         // answer: if a CNAME, chase the target, otherwise add authority.
     916         [ +  + ]:          5 :         if (cname) {
     917         [ +  - ]:          4 :             RRsetPtr rrset = findRRsetFromList(wild, RRType::CNAME());
     918         [ +  - ]:          4 :             if (rrset != NULL) {
     919         [ +  - ]:          4 :                 rrset->setName(task->qname);
     920         [ +  - ]:          4 :                 addToMessage(q, Message::SECTION_ANSWER, rrset);
     921         [ +  - ]:          4 :                 chaseCname(q, task, rrset);
     922                 :            :             }
     923                 :            :         } else {
     924 [ +  + ][ +  - ]:          5 :             BOOST_FOREACH (RRsetPtr rrset, wild) {
         [ +  - ][ +  + ]
                 [ +  + ]
     925         [ +  - ]:          1 :                 rrset->setName(task->qname);
     926         [ +  - ]:          1 :                 addToMessage(q, Message::SECTION_ANSWER, rrset);
     927                 :            :             }
     928                 :            : 
     929                 :            :             RRsetList auth;
     930 [ +  - ][ -  + ]:          1 :             if (!refQuery(q, *zonename, zoneinfo, auth)) {
     931 [ #  # ][ #  # ]:          0 :                 logger.error(DATASRC_QUERY_WILDCARD_REFERRAL).arg(task->qname).
                 [ #  # ]
     932         [ #  # ]:          0 :                     arg(result);
     933                 :          0 :                 return (DataSrc::ERROR);
     934                 :            :             }
     935                 :            : 
     936         [ +  - ]:          1 :             copyAuth(q, auth);
     937                 :            :         }
     938                 :            :     }
     939                 :            : 
     940                 :            :     return (DataSrc::SUCCESS);
     941                 :            : }
     942                 :            : 
     943                 :            : //
     944                 :            : // doQuery: Processes a query.
     945                 :            : // 
     946                 :            : void
     947                 :         64 : DataSrc::doQuery(Query& q) {
     948 [ +  - ][ +  - ]:        128 :     LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_QUERY_PROCESS).arg(q.qname()).
     949 [ +  - ][ +  - ]:         64 :         arg(q.qtype()).arg(q.qclass());
     950                 :         64 :     Message& m = q.message();
     951                 :         64 :     vector<RRsetPtr> additional;
     952                 :            : 
     953                 :            :     // Record the fact that the query is being processed by the
     954                 :            :     // current data source.
     955                 :            :     q.setDatasrc(this);
     956                 :            : 
     957                 :            :     // Process the query task queue.  (The queue is initialized
     958                 :            :     // and the first task placed on it by the Query constructor.)
     959         [ +  - ]:         64 :     m.setHeaderFlag(Message::HEADERFLAG_AA, false);
     960         [ +  + ]:        210 :     while (!q.tasks().empty()) {
     961                 :        346 :         QueryTaskPtr task = q.tasks().front();
     962                 :        173 :         q.tasks().pop();
     963                 :            : 
     964                 :            :         // Can't query directly for RRSIG.
     965         [ -  + ]:        173 :         if (task->qtype == RRType::RRSIG()) {
     966 [ #  # ][ #  # ]:          0 :             m.setRcode(Rcode::REFUSED());
     967 [ #  # ][ #  # ]:          0 :             logger.warn(DATASRC_QUERY_RRSIG).arg(task->qname);
                 [ #  # ]
     968                 :            :             return;
     969                 :            :         }
     970                 :            : 
     971                 :            :         // These task types should never be on the task queue.
     972   [ +  -  +  - ]:        346 :         if (task->op == QueryTask::SIMPLE_QUERY ||
                 [ -  + ]
     973                 :        173 :             task->op == QueryTask::REF_QUERY) {
     974 [ #  # ][ #  # ]:          0 :             m.setRcode(Rcode::SERVFAIL());
     975 [ #  # ][ #  # ]:          0 :             logger.error(DATASRC_QUERY_MISPLACED_TASK);
     976                 :            :             return;
     977                 :            :         }
     978                 :            : 
     979                 :        173 :         ZoneInfo zoneinfo(this, task->qname, task->qclass, task->qtype);
     980                 :            :         RRsetList data;
     981                 :        173 :         Result result = SUCCESS;
     982                 :            : 
     983                 :            :         // For these query task types, if there is more than
     984                 :            :         // one level between the zone name and qname, we need to
     985                 :            :         // check the intermediate nodes for referrals.
     986   [ +  +  -  + ]:        519 :         if ((task->op == QueryTask::AUTH_QUERY ||
         [ +  + ][ +  + ]
     987                 :         83 :              task->op == QueryTask::NOGLUE_QUERY) &&
     988 [ +  - ][ +  + ]:        263 :             hasDelegation(q, task, zoneinfo)) {
     989                 :          4 :             continue;
     990                 :            :         }
     991                 :            : 
     992         [ +  + ]:        169 :         result = doQueryTask(*task, zoneinfo, data);
     993         [ -  + ]:        168 :         if (result != SUCCESS) {
     994 [ #  # ][ #  # ]:          0 :             m.setRcode(Rcode::SERVFAIL());
     995 [ #  # ][ #  # ]:          0 :             logger.error(DATASRC_QUERY_TASK_FAIL).arg(result);
                 [ #  # ]
     996                 :            :             return;
     997                 :            :         }
     998                 :            : 
     999                 :            :         // No such zone.  If we're chasing cnames or adding additional
    1000                 :            :         // data, that's okay, but if doing an original query, return
    1001                 :            :         // REFUSED.
    1002         [ +  + ]:        168 :         if (task->flags == NO_SUCH_ZONE) {
    1003         [ +  + ]:         12 :             if (task->state == QueryTask::GETANSWER) {
    1004 [ +  - ][ +  - ]:         10 :                 m.setRcode(Rcode::REFUSED());
    1005                 :            :                 // No need to log it here, it was already logged in doQueryTask
    1006                 :            :                 return;
    1007                 :            :             }
    1008                 :          2 :             continue;
    1009                 :            :         }
    1010                 :            : 
    1011                 :            :         // Query found a referral; let's find out if that was expected--
    1012                 :            :         // i.e., if an NS was at the zone apex, or if we were querying
    1013                 :            :         // specifically for, and found, a DS, NSEC, or DNAME record.
    1014                 :        156 :         const Name* const zonename = zoneinfo.getEnclosingZone();
    1015   [ +  +  +  +  :        351 :         if ((task->flags & REFERRAL) != 0 &&
          +  +  +  +  +  
              + ][ +  + ]
                 [ +  + ]
    1016                 :         18 :             (zonename->getLabelCount() == task->qname.getLabelCount() ||
    1017                 :          7 :              ((task->qtype == RRType::NSEC() ||
    1018                 :          5 :                task->qtype == RRType::DS() ||
    1019                 :          4 :                task->qtype == RRType::DNAME()) &&
    1020 [ +  - ][ +  + ]:        161 :               findRRsetFromList(data, task->qtype)))) {
    1021                 :         14 :             task->flags &= ~REFERRAL;
    1022                 :            :         }
    1023                 :            : 
    1024 [ +  - ][ +  + ]:        156 :         if (result == SUCCESS && task->flags == 0) {
                 [ +  + ]
    1025                 :        104 :             bool have_ns = false, need_auth = false;
    1026      [ +  +  - ]:        104 :             switch (task->state) {
    1027                 :            :             case QueryTask::GETANSWER:
    1028                 :            :             case QueryTask::FOLLOWCNAME:
    1029 [ +  + ][ +  - ]:        145 :                 BOOST_FOREACH(RRsetPtr rrset, data) {
         [ +  - ][ +  + ]
                 [ +  + ]
    1030         [ +  - ]:         29 :                     addToMessage(q, task->section, rrset);
    1031         [ +  - ]:         29 :                     if (q.tasks().empty()) {
    1032                 :         29 :                         need_auth = true;
    1033                 :            :                     }
    1034         [ +  - ]:         29 :                     getAdditional(q, rrset);
    1035 [ +  - ][ +  + ]:         29 :                     if (rrset->getType() == RRType::NS()) {
    1036                 :         29 :                         have_ns = true;
    1037                 :            :                     }
    1038                 :            :                 }
    1039                 :            :                 q.setStatus(Query::ANSWERED);
    1040 [ +  - ][ +  + ]:         29 :                 if (need_auth && !have_ns) {
    1041                 :            :                     // Data found, no additional processing needed.
    1042                 :            :                     // Add the NS records for the enclosing zone to
    1043                 :            :                     // the authority section.
    1044                 :            :                     RRsetList auth;
    1045 [ +  - ][ +  - ]:         77 :                     if (!refQuery(q, Name(*zonename), zoneinfo, auth) ||
         [ +  + ][ +  + ]
         [ +  + ][ #  # ]
    1046 [ +  - ][ +  + ]:         51 :                         !findRRsetFromList(auth, RRType::NS())) {
    1047 [ +  - ][ +  - ]:          2 :                         logger.error(DATASRC_QUERY_MISSING_NS).arg(*zonename);
                 [ +  - ]
    1048 [ +  - ][ +  - ]:          4 :                         isc_throw(DataSourceError,
         [ +  - ][ +  - ]
                 [ +  - ]
    1049                 :            :                                   "NS RR not found in " << *zonename << "/" <<
    1050                 :            :                                   q.qclass());
    1051                 :            :                     }
    1052                 :            : 
    1053         [ +  - ]:         24 :                     copyAuth(q, auth);
    1054                 :            :                 }
    1055                 :         27 :                 continue;
    1056                 :            : 
    1057                 :            :             case QueryTask::GETADDITIONAL:
    1058                 :            :                 // Got additional data.  Do not add it to the message
    1059                 :            :                 // yet; instead store it and copy it in at the end
    1060                 :            :                 // (this allow RRSIGs to be omitted if necessary).
    1061 [ +  + ][ +  - ]:        375 :                 BOOST_FOREACH(RRsetPtr rrset, data) {
         [ +  - ][ +  + ]
                 [ +  + ]
    1062 [ +  + ][ +  + ]:        139 :                     if (q.status() == Query::ANSWERED &&
         [ -  + ][ +  + ]
    1063         [ +  - ]:         62 :                         rrset->getName() == q.qname() &&
    1064         [ +  - ]:          2 :                         rrset->getType() == q.qtype()) {
    1065                 :          2 :                         continue;
    1066                 :            :                     }
    1067                 :            :                     additional.push_back(rrset);
    1068                 :            :                 }
    1069                 :         75 :                 continue;
    1070                 :            : 
    1071                 :            :             default:
    1072 [ #  # ][ #  # ]:          0 :                 logger.error(DATASRC_UNEXPECTED_QUERY_STATE);
    1073 [ #  # ][ #  # ]:          0 :                 isc_throw (Unexpected, "unexpected query state");
    1074                 :            :             }
    1075         [ -  + ]:         52 :         } else if (result == ERROR || result == NOT_IMPLEMENTED) {
    1076 [ #  # ][ #  # ]:          0 :             m.setRcode(Rcode::SERVFAIL());
    1077 [ #  # ][ #  # ]:          0 :             logger.error(DATASRC_QUERY_FAIL);
    1078                 :            :             return;
    1079         [ +  + ]:         52 :         } else if ((task->flags & CNAME_FOUND) != 0) {
    1080                 :            :             // The qname node contains a CNAME.  Add a new task to the
    1081                 :            :             // queue to look up its target.
    1082         [ +  - ]:         21 :             RRsetPtr rrset = findRRsetFromList(data, RRType::CNAME());
    1083         [ +  - ]:         21 :             if (rrset != NULL) {
    1084         [ +  - ]:         21 :                 addToMessage(q, task->section, rrset);
    1085         [ +  - ]:         21 :                 chaseCname(q, task, rrset);
    1086                 :            :             }
    1087                 :         21 :             continue;
    1088         [ +  + ]:         31 :         } else if ((task->flags & REFERRAL) != 0) {
    1089                 :            :             // The qname node contains an out-of-zone referral.
    1090         [ +  - ]:          4 :             if (task->state == QueryTask::GETANSWER) {
    1091                 :            :                 RRsetList auth;
    1092         [ +  - ]:          4 :                 m.setHeaderFlag(Message::HEADERFLAG_AA, false);
    1093 [ +  - ][ -  + ]:          4 :                 if (!refQuery(q, task->qname, zoneinfo, auth)) {
    1094 [ #  # ][ #  # ]:          0 :                     m.setRcode(Rcode::SERVFAIL());
    1095 [ #  # ][ #  # ]:          0 :                     logger.error(DATASRC_QUERY_BAD_REFERRAL).arg(task->qname);
                 [ #  # ]
    1096                 :            :                     return;
    1097                 :            :                 }
    1098 [ +  + ][ +  - ]:         32 :                 BOOST_FOREACH (RRsetPtr rrset, auth) {
         [ +  - ][ +  + ]
                 [ +  + ]
    1099 [ +  - ][ +  + ]:          7 :                     if (rrset->getType() == RRType::NS()) {
    1100         [ +  - ]:          4 :                         addToMessage(q, Message::SECTION_AUTHORITY, rrset);
    1101 [ +  - ][ -  + ]:          3 :                     } else if (rrset->getType() == task->qtype) {
    1102         [ #  # ]:          0 :                         addToMessage(q, Message::SECTION_ANSWER, rrset);
    1103 [ +  - ][ +  - ]:          3 :                     } else if (rrset->getType() == RRType::DS() &&
         [ -  + ][ +  - ]
    1104                 :            :                                q.wantDnssec()) {
    1105         [ +  - ]:          3 :                         addToMessage(q, Message::SECTION_AUTHORITY, rrset);
    1106                 :            :                     }
    1107         [ +  - ]:          7 :                     getAdditional(q, rrset);
    1108                 :            :                 }
    1109                 :            :             } 
    1110                 :          4 :             continue;
    1111         [ +  - ]:         27 :         } else if ((task->flags & (NAME_NOT_FOUND|TYPE_NOT_FOUND)) != 0) {
    1112                 :            :             // No data found at this qname/qtype.
    1113                 :            : 
    1114                 :            :             // If we were looking for additional data, we should simply
    1115                 :            :             // ignore this result.
    1116         [ +  + ]:         27 :             if (task->state == QueryTask::GETADDITIONAL) {
    1117                 :          8 :                 continue;
    1118                 :            :             }
    1119                 :            : 
    1120                 :            :             // If we were looking for answer data, not additional,
    1121                 :            :             // and the name was not found, we need to find out whether
    1122                 :            :             // there are any relevant wildcards.
    1123                 :         19 :             bool wildcard_found = false;
    1124         [ +  - ]:         19 :             result = tryWildcard(q, task, zoneinfo, wildcard_found);
    1125         [ -  + ]:         19 :             if (result != SUCCESS) {
    1126 [ #  # ][ #  # ]:          0 :                 m.setRcode(Rcode::SERVFAIL());
    1127 [ #  # ][ #  # ]:          0 :                 logger.error(DATASRC_QUERY_WILDCARD_FAIL).arg(task->qname);
                 [ #  # ]
    1128                 :            :                 return;
    1129                 :            :             }
    1130                 :            : 
    1131         [ +  + ]:         19 :             if (wildcard_found) {
    1132                 :          5 :                 continue;
    1133                 :            :             }
    1134                 :            : 
    1135                 :            :             // If we've reached this point, there is definitely no answer.
    1136                 :            :             // If we were chasing cnames or adding additional data, that's
    1137                 :            :             // okay, but if we were doing an original query, reply with the
    1138                 :            :             // SOA in the authority section.  For NAME_NOT_FOUND, set
    1139                 :            :             // NXDOMAIN, and also add the previous NSEC to the authority
    1140                 :            :             // section.  For TYPE_NOT_FOUND, do not set an error rcode,
    1141                 :            :             // and send the current NSEC in the authority section.
    1142         [ +  + ]:         14 :             if (task->state == QueryTask::GETANSWER) {
    1143         [ +  + ]:         12 :                 if ((task->flags & NAME_NOT_FOUND) != 0) {
    1144         [ +  - ]:          7 :                     m.setRcode(Rcode::NXDOMAIN());
    1145                 :            :                 }
    1146                 :            : 
    1147         [ +  - ]:         12 :                 result = addSOA(q, zoneinfo);
    1148         [ +  + ]:         12 :                 if (result != SUCCESS) {
    1149 [ +  - ][ +  - ]:          2 :                     logger.error(DATASRC_QUERY_MISSING_SOA).arg(*zonename);
                 [ +  - ]
    1150 [ +  - ][ +  - ]:          4 :                     isc_throw(DataSourceError,
         [ +  - ][ +  - ]
                 [ +  - ]
    1151                 :            :                               "SOA RR not found in " << *zonename <<
    1152                 :            :                               "/" << q.qclass());
    1153                 :            :                 }
    1154                 :            :             }
    1155                 :            : 
    1156         [ +  - ]:         24 :             Name nsecname(task->qname);
    1157         [ +  + ]:         12 :             if ((task->flags & NAME_NOT_FOUND) != 0) {
    1158                 :          6 :                 const DataSrc* ds = zoneinfo.getDataSource();
    1159         [ +  - ]:          6 :                 ds->findPreviousName(task->qname, nsecname, zonename);
    1160                 :            :             }
    1161                 :            : 
    1162         [ +  - ]:         12 :             if (q.wantDnssec()) {
    1163         [ +  - ]:         12 :                 result = proveNX(q, task, zoneinfo, false);
    1164         [ -  + ]:         12 :                 if (result != DataSrc::SUCCESS) {
    1165 [ #  # ][ #  # ]:          0 :                     m.setRcode(Rcode::SERVFAIL());
    1166 [ #  # ][ #  # ]:          0 :                     logger.error(DATASRC_QUERY_PROVE_NX_FAIL).arg(task->qname);
                 [ #  # ]
    1167                 :            :                     return;
    1168                 :            :                 }
    1169                 :            :             }
    1170                 :            : 
    1171                 :            :             return;
    1172                 :            :         } else {
    1173                 :            :             // Should never be reached!
    1174 [ #  # ][ #  # ]:          0 :             m.setRcode(Rcode::SERVFAIL());
    1175 [ #  # ][ #  # ]:          0 :             logger.error(DATASRC_QUERY_UNKNOWN_RESULT);
    1176                 :            :             return;
    1177                 :            :         }
    1178                 :            :     }
    1179                 :            : 
    1180                 :            :     // We're done, so now copy in the additional data:
    1181                 :            :     // data first, then signatures.  (If we run out of
    1182                 :            :     // space, signatures in additional section are
    1183                 :            :     // optional.)
    1184 [ +  + ][ +  - ]:        329 :     BOOST_FOREACH(RRsetPtr rrset, additional) {
         [ +  - ][ +  + ]
                 [ +  + ]
    1185         [ +  - ]:         73 :         addToMessage(q, Message::SECTION_ADDITIONAL, rrset, true);
    1186                 :            :     }
    1187                 :            : 
    1188         [ +  + ]:         37 :     if (q.wantDnssec()) {
    1189 [ +  + ][ +  - ]:        270 :         BOOST_FOREACH(RRsetPtr rrset, additional) {
         [ +  - ][ +  + ]
                 [ +  + ]
    1190 [ +  - ][ +  + ]:        122 :             if (rrset->getRRsig()) {
    1191                 :         51 :                 addToMessage(q, Message::SECTION_ADDITIONAL, rrset->getRRsig(),
    1192 [ +  - ][ +  - ]:         51 :                              true);
    1193                 :            :             }
    1194                 :            :         }
    1195                 :            :     }
    1196                 :            : }
    1197                 :            : 
    1198                 :            : DataSrc::Result
    1199                 :          4 : DataSrc::findAddrs(const Name& qname, const RRClass& qclass,
    1200                 :            :                    RRsetList& target, uint32_t& flags,
    1201                 :            :                    const Name* zonename) const
    1202                 :            : {
    1203                 :            :     Result r;
    1204                 :          4 :     bool a = false, aaaa = false;
    1205                 :            : 
    1206                 :          4 :     flags = 0;
    1207                 :          4 :     r = findExactRRset(qname, qclass, RRType::A(), target, flags, zonename);
    1208 [ +  - ][ -  + ]:          4 :     if (r == SUCCESS && flags == 0) {
    1209                 :          0 :         a = true;
    1210                 :            :     }
    1211                 :            : 
    1212                 :          4 :     flags = 0;
    1213                 :          4 :     r = findExactRRset(qname, qclass, RRType::AAAA(), target, flags,
    1214                 :          4 :                        zonename);
    1215 [ +  - ][ -  + ]:          4 :     if (r == SUCCESS && flags == 0) {
    1216                 :          0 :         aaaa = true;
    1217                 :            :     }
    1218                 :            : 
    1219 [ +  - ][ +  - ]:          4 :     if (!a && !aaaa) {
    1220                 :          4 :         flags = TYPE_NOT_FOUND;
    1221                 :            :     } else {
    1222                 :          0 :         flags = 0;
    1223                 :            :     }
    1224                 :            : 
    1225                 :          4 :     return (SUCCESS);
    1226                 :            : }
    1227                 :            : 
    1228                 :            : DataSrc::Result
    1229                 :          4 : DataSrc::findReferral(const Name& qname, const RRClass& qclass,
    1230                 :            :                       RRsetList& target, uint32_t& flags,
    1231                 :            :                       const Name* zonename) const
    1232                 :            : {
    1233                 :            :     Result r;
    1234                 :          4 :     bool ns = false, ds = false, dname = false;
    1235                 :            : 
    1236                 :          4 :     flags = 0;
    1237                 :          4 :     r = findExactRRset(qname, qclass, RRType::NS(), target, flags, zonename);
    1238 [ +  - ][ -  + ]:          4 :     if (r == SUCCESS && flags == 0) {
    1239                 :            :         ns = true;
    1240         [ #  # ]:          0 :     } else if ((flags & (NO_SUCH_ZONE|NAME_NOT_FOUND))) {
    1241                 :            :         return (SUCCESS);
    1242                 :            :     }
    1243                 :            : 
    1244                 :          4 :     flags = 0;
    1245                 :          4 :     r = findExactRRset(qname, qclass, RRType::DS(), target, flags, zonename);
    1246 [ +  - ][ -  + ]:          4 :     if (r == SUCCESS && flags == 0) {
    1247                 :            :         ds = true;
    1248         [ #  # ]:          0 :     } else if ((flags & (NO_SUCH_ZONE|NAME_NOT_FOUND))) {
    1249                 :            :         return (SUCCESS);
    1250                 :            :     }
    1251                 :            : 
    1252                 :          4 :     flags = 0;
    1253                 :          4 :     r = findExactRRset(qname, qclass, RRType::DNAME(), target, flags, zonename);
    1254 [ +  - ][ -  + ]:          4 :     if (r == SUCCESS && flags == 0) {
    1255                 :            :         dname = true;
    1256         [ #  # ]:          0 :     } else if ((flags & (NO_SUCH_ZONE|NAME_NOT_FOUND))) {
    1257                 :            :         return (SUCCESS);
    1258                 :            :     }
    1259                 :            : 
    1260 [ -  + ][ #  # ]:          4 :     if (!ns && !dname && !ds) {
                 [ #  # ]
    1261                 :          0 :         flags = TYPE_NOT_FOUND;
    1262                 :            :     } else {
    1263                 :          4 :         flags = 0;
    1264                 :            :     }
    1265                 :            : 
    1266                 :            :     return (SUCCESS);
    1267                 :            : }
    1268                 :            : 
    1269                 :            : void
    1270                 :        233 : MetaDataSrc::addDataSrc(ConstDataSrcPtr data_src) {
    1271         [ +  - ]:        233 :     LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_META_ADD);
    1272 [ -  + ][ #  # ]:        233 :     if (getClass() != RRClass::ANY() && data_src->getClass() != getClass()) {
                 [ -  + ]
    1273                 :          0 :         logger.error(DATASRC_META_ADD_CLASS_MISMATCH).
    1274 [ #  # ][ #  # ]:          0 :             arg(data_src->getClass()).arg(getClass());
    1275         [ #  # ]:          0 :         isc_throw(Unexpected, "class mismatch");
    1276                 :            :     }
    1277                 :            : 
    1278                 :        233 :     data_sources.push_back(data_src);
    1279                 :        233 : }
    1280                 :            : 
    1281                 :            : void
    1282                 :          1 : MetaDataSrc::removeDataSrc(ConstDataSrcPtr data_src) {
    1283         [ +  - ]:          1 :     LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_META_REMOVE);
    1284                 :            :     std::vector<ConstDataSrcPtr>::iterator it, itr;
    1285         [ +  + ]:          2 :     for (it = data_sources.begin(); it != data_sources.end(); ++it) {
    1286         [ +  - ]:          1 :         if (*it == data_src) {
    1287                 :          1 :             itr = it;
    1288                 :            :         }
    1289                 :            :     }
    1290                 :            : 
    1291                 :          1 :     data_sources.erase(itr);
    1292                 :          1 : }
    1293                 :            : 
    1294                 :            : void
    1295                 :        196 : MetaDataSrc::findClosestEnclosure(DataSrcMatch& match) const {
    1296   [ +  +  -  +  :        368 :     if (getClass() != match.getClass() &&
           #  # ][ +  - ]
    1297                 :        172 :         getClass() != RRClass::ANY() && match.getClass() != RRClass::ANY()) {
    1298                 :        196 :         return;
    1299                 :            :     }
    1300                 :            : 
    1301   [ +  +  +  - ]:       2344 :     BOOST_FOREACH (ConstDataSrcPtr data_src, data_sources) {
         [ +  - ][ +  + ]
                 [ +  + ]
    1302         [ +  - ]:        537 :         data_src->findClosestEnclosure(match);
    1303                 :            :     }
    1304                 :            : }
    1305                 :            : 
    1306                 :        195 : DataSrcMatch::~DataSrcMatch() {
    1307         [ +  + ]:        195 :     delete closest_name_;
    1308                 :        195 : }
    1309                 :            : 
    1310                 :            : void
    1311                 :        181 : DataSrcMatch::update(const DataSrc& new_source, const Name& container) {
    1312         [ +  + ]:        183 :     if (getClass() != new_source.getClass() && getClass() != RRClass::ANY() &&
           [ +  +  -  + ]
                 [ +  + ]
    1313                 :          2 :         new_source.getClass() != RRClass::ANY())
    1314                 :            :     {
    1315                 :            :         return;
    1316                 :            :     }
    1317                 :            : 
    1318         [ +  + ]:        179 :     if (closest_name_ == NULL) {
    1319                 :            :         const NameComparisonResult::NameRelation cmp =
    1320                 :        176 :             getName().compare(container).getRelation();
    1321         [ +  + ]:        176 :         if (cmp != NameComparisonResult::EQUAL &&
    1322                 :            :             cmp != NameComparisonResult::SUBDOMAIN)
    1323                 :            :         {
    1324                 :            :             return;
    1325                 :            :         }
    1326                 :            : 
    1327         [ +  - ]:        175 :         closest_name_ = new Name(container);
    1328                 :        175 :         best_source_ = &new_source;
    1329                 :        175 :         return;
    1330                 :            :     }
    1331                 :            : 
    1332         [ +  + ]:          3 :     if (container.compare(*closest_name_).getRelation() ==
    1333                 :            :         NameComparisonResult::SUBDOMAIN) {
    1334         [ +  - ]:          1 :         Name* newname = new Name(container);
    1335         [ +  - ]:          1 :         delete closest_name_;
    1336                 :          1 :         closest_name_ = newname;
    1337                 :        181 :         best_source_ = &new_source;
    1338                 :            :     }
    1339                 :            : }
    1340                 :            : 
    1341                 :          1 : Nsec3Param::Nsec3Param(const uint8_t a, const uint8_t f, const uint16_t i,
    1342                 :            :                        const std::vector<uint8_t>& s) :
    1343                 :          1 :     algorithm_(a), flags_(f), iterations_(i), salt_(s)
    1344                 :          1 : {}
    1345                 :            : 
    1346                 :            : string
    1347                 :          3 : Nsec3Param::getHash(const Name& name) const {
    1348                 :          3 :     OutputBuffer buf(0);
    1349         [ +  - ]:          3 :     name.toWire(buf);
    1350                 :            : 
    1351                 :            :     uint8_t digest[SHA1_HASHSIZE];
    1352                 :          3 :     const uint8_t* input = static_cast<const uint8_t*>(buf.getData());
    1353                 :          3 :     size_t inlength = buf.getLength();
    1354                 :          3 :     const uint8_t saltlen = salt_.size();
    1355                 :            : 
    1356                 :          3 :     int n = 0;
    1357                 :            :     SHA1Context sha;
    1358         [ +  + ]:         33 :     do {
    1359         [ +  - ]:         33 :         SHA1Reset(&sha);
    1360         [ +  - ]:         33 :         SHA1Input(&sha, input, inlength);
    1361         [ +  - ]:         33 :         SHA1Input(&sha, &salt_[0], saltlen);
    1362         [ +  - ]:         33 :         SHA1Result(&sha, digest);
    1363                 :         33 :         input = digest;
    1364                 :         33 :         inlength = SHA1_HASHSIZE;
    1365                 :            :     } while (n++ < iterations_);
    1366                 :            : 
    1367         [ +  - ]:          6 :     return (encodeBase32Hex(vector<uint8_t>(digest, digest + SHA1_HASHSIZE)));
    1368                 :            : }
    1369                 :            : 
    1370                 :            : DataSrc::Result
    1371                 :          0 : DataSrc::init(isc::data::ConstElementPtr) {
    1372                 :          0 :     return (NOT_IMPLEMENTED);
    1373                 :            : }
    1374                 :            : 
    1375                 :            : DataSrc::Result
    1376                 :          0 : MetaDataSrc::findRRset(const isc::dns::Name&,
    1377                 :            :                        const isc::dns::RRClass&,
    1378                 :            :                        const isc::dns::RRType&,
    1379                 :            :                        isc::dns::RRsetList&,
    1380                 :            :                        uint32_t&,
    1381                 :            :                        const isc::dns::Name*) const
    1382                 :            : {
    1383                 :          0 :     return (NOT_IMPLEMENTED);
    1384                 :            : }
    1385                 :            : 
    1386                 :            : DataSrc::Result
    1387                 :          0 : MetaDataSrc::findExactRRset(const isc::dns::Name&,
    1388                 :            :                             const isc::dns::RRClass&,
    1389                 :            :                             const isc::dns::RRType&,
    1390                 :            :                             isc::dns::RRsetList&,
    1391                 :            :                             uint32_t&,
    1392                 :            :                             const isc::dns::Name*) const
    1393                 :            : {
    1394                 :          0 :     return (NOT_IMPLEMENTED);
    1395                 :            : }
    1396                 :            : 
    1397                 :            : DataSrc::Result
    1398                 :          0 : MetaDataSrc::findAddrs(const isc::dns::Name&,
    1399                 :            :                        const isc::dns::RRClass&,
    1400                 :            :                        isc::dns::RRsetList&,
    1401                 :            :                        uint32_t&,
    1402                 :            :                        const isc::dns::Name*) const
    1403                 :            : {
    1404                 :          0 :     return (NOT_IMPLEMENTED);
    1405                 :            : }
    1406                 :            : 
    1407                 :            : DataSrc::Result
    1408                 :          0 : MetaDataSrc::findReferral(const isc::dns::Name&,
    1409                 :            :                           const isc::dns::RRClass&,
    1410                 :            :                           isc::dns::RRsetList&,
    1411                 :            :                           uint32_t&,
    1412                 :            :                           const isc::dns::Name*) const
    1413                 :            : {
    1414                 :          0 :     return (NOT_IMPLEMENTED);
    1415                 :            : }
    1416                 :            : 
    1417                 :            : DataSrc::Result
    1418                 :          0 : MetaDataSrc::findPreviousName(const isc::dns::Name&,
    1419                 :            :                               isc::dns::Name&,
    1420                 :            :                               const isc::dns::Name*) const
    1421                 :            : {
    1422                 :          0 :     return (NOT_IMPLEMENTED);
    1423                 :            : }
    1424                 :            : 
    1425                 :            : DataSrc::Result
    1426                 :          0 : MetaDataSrc::findCoveringNSEC3(const isc::dns::Name&,
    1427                 :            :                                std::string&,
    1428                 :            :                                isc::dns::RRsetList&) const
    1429                 :            : {
    1430                 :          0 :     return (NOT_IMPLEMENTED);
    1431                 :            : }
    1432                 :            : 
    1433                 :            : }
    1434                 :        115 : }

Generated by: LCOV version 1.9