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 : }
|