]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/packethandler.cc
rec: Don't account chained queries more than once
[thirdparty/pdns.git] / pdns / packethandler.cc
CommitLineData
bcf21dff 1/*
12471842
PL
2 * This file is part of PowerDNS or dnsdist.
3 * Copyright -- PowerDNS.COM B.V. and its contributors
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of version 2 of the GNU General Public License as
7 * published by the Free Software Foundation.
8 *
9 * In addition, for the avoidance of any doubt, permission is granted to
10 * link this program with OpenSSL and to (re)distribute the binaries
11 * produced as the result of such linking.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 */
870a0fe4
AT
22#ifdef HAVE_CONFIG_H
23#include "config.h"
24#endif
e8d78143 25#include "packetcache.hh"
12c86877 26#include "utility.hh"
01fde57c 27#include "base32.hh"
12c86877
BH
28#include <string>
29#include <sys/types.h>
bc28bef8 30#include <boost/algorithm/string.hpp>
35fe50c3
BH
31#include "dnssecinfra.hh"
32#include "dnsseckeeper.hh"
12c86877
BH
33#include "dns.hh"
34#include "dnsbackend.hh"
35#include "ueberbackend.hh"
36#include "dnspacket.hh"
37#include "nameserver.hh"
38#include "distributor.hh"
39#include "logger.hh"
40#include "arguments.hh"
41#include "packethandler.hh"
42#include "statbag.hh"
43#include "resolver.hh"
44#include "communicator.hh"
45#include "dnsproxy.hh"
ba1a571d 46#include "version.hh"
357f6a75 47#include "common_startup.hh"
12c86877 48
51a3a4d4 49#if 0
2893c412
BH
50#undef DLOG
51#define DLOG(x) x
507823d1 52#endif
357f6a75 53
16f7d28d 54AtomicCounter PacketHandler::s_count;
d207ad63 55NetmaskGroup PacketHandler::s_allowNotifyFrom;
dad0736b
RC
56set<string> PacketHandler::s_forwardNotify;
57
12c86877
BH
58extern string s_programname;
59
e59b5787 60PacketHandler::PacketHandler():B(s_programname), d_dk(&B)
12c86877 61{
16f7d28d 62 ++s_count;
4dfe94ae 63 d_doDNAME=::arg().mustDo("dname-processing");
389b7a05 64 d_doExpandALIAS = ::arg().mustDo("expand-alias");
e8d78143
BH
65 d_logDNSDetails= ::arg().mustDo("log-dns-details");
66 d_doIPv6AdditionalProcessing = ::arg().mustDo("do-ipv6-additional-processing");
5704e107
PD
67 string fname= ::arg()["lua-prequery-script"];
68 if(fname.empty())
69 {
70 d_pdl = NULL;
71 }
72 else
73 {
3ce6361c 74 d_pdl = std::unique_ptr<AuthLua>(new AuthLua(fname));
5704e107 75 }
0ecc1158
AT
76 fname = ::arg()["lua-dnsupdate-policy-script"];
77 if (fname.empty())
78 {
79 d_update_policy_lua = NULL;
80 }
81 else
82 {
3ce6361c 83 d_update_policy_lua = std::unique_ptr<AuthLua4>(new AuthLua4(fname));
0ecc1158 84 }
12c86877
BH
85}
86
3971cf53 87UeberBackend *PacketHandler::getBackend()
12c86877
BH
88{
89 return &B;
90}
91
92PacketHandler::~PacketHandler()
93{
94 --s_count;
95 DLOG(L<<Logger::Error<<"PacketHandler destructor called - "<<s_count<<" left"<<endl);
12c86877
BH
96}
97
088370cd 98/**
f889ab99 99 * This adds CDNSKEY records to the answer packet. Returns true if one was added.
088370cd
PL
100 *
101 * @param p Pointer to the DNSPacket containing the original question
102 * @param r Pointer to the DNSPacket where the records should be inserted into
f889ab99 103 * @param sd SOAData of the zone for which CDNSKEY records sets should be added
088370cd
PL
104 * @return bool that shows if any records were added
105**/
f889ab99 106bool PacketHandler::addCDNSKEY(DNSPacket *p, DNSPacket *r, const SOAData& sd)
35fe50c3 107{
088370cd 108 string publishCDNSKEY;
0900d2d3 109 d_dk.getFromMeta(p->qdomain, "PUBLISH-CDNSKEY", publishCDNSKEY);
f889ab99 110 if (publishCDNSKEY != "1")
088370cd
PL
111 return false;
112
90ba52e0 113 DNSZoneRecord rr;
35fe50c3 114 bool haveOne=false;
35fe50c3 115
f889ab99
PL
116 DNSSECKeeper::keyset_t entryPoints = d_dk.getEntryPoints(p->qdomain);
117 for(const auto& value: entryPoints) {
90ba52e0 118 rr.dr.d_type=QType::CDNSKEY;
119 rr.dr.d_ttl=sd.default_ttl;
120 rr.dr.d_name=p->qdomain;
121 rr.dr.d_content=std::make_shared<DNSKEYRecordContent>(value.first.getDNSKEY());
f889ab99
PL
122 rr.auth=true;
123 r->addRecord(rr);
124 haveOne=true;
125 }
126
127 if(::arg().mustDo("direct-dnskey")) {
128 B.lookup(QType(QType::CDNSKEY), p->qdomain, p, sd.domain_id);
129
130 while(B.get(rr)) {
90ba52e0 131 rr.dr.d_ttl=sd.default_ttl;
f889ab99
PL
132 r->addRecord(rr);
133 haveOne=true;
134 }
135 }
136 return haveOne;
137}
138
139/**
140 * This adds DNSKEY records to the answer packet. Returns true if one was added.
141 *
142 * @param p Pointer to the DNSPacket containing the original question
143 * @param r Pointer to the DNSPacket where the records should be inserted into
144 * @param sd SOAData of the zone for which DNSKEY records sets should be added
145 * @return bool that shows if any records were added
146**/
147bool PacketHandler::addDNSKEY(DNSPacket *p, DNSPacket *r, const SOAData& sd)
148{
90ba52e0 149 DNSZoneRecord rr;
f889ab99 150 bool haveOne=false;
f889ab99 151
ade1b1e9 152 DNSSECKeeper::keyset_t keyset = d_dk.getKeys(p->qdomain);
424b92c6 153 for(const auto& value: keyset) {
90ba52e0 154 rr.dr.d_type=QType::DNSKEY;
155 rr.dr.d_ttl=sd.default_ttl;
156 rr.dr.d_name=p->qdomain;
157 rr.dr.d_content=std::make_shared<DNSKEYRecordContent>(value.first.getDNSKEY());
ade1b1e9 158 rr.auth=true;
35fe50c3
BH
159 r->addRecord(rr);
160 haveOne=true;
161 }
4a6ea260 162
cc8df07f 163 if(::arg().mustDo("direct-dnskey")) {
f889ab99 164 B.lookup(QType(QType::DNSKEY), p->qdomain, p, sd.domain_id);
088370cd 165
4a6ea260 166 while(B.get(rr)) {
90ba52e0 167 rr.dr.d_ttl=sd.default_ttl;
4a6ea260
PD
168 r->addRecord(rr);
169 haveOne=true;
170 }
171 }
172
35fe50c3
BH
173 return haveOne;
174}
175
ef542223
PL
176/**
177 * This adds CDS records to the answer packet r.
178 *
179 * @param p Pointer to the DNSPacket containing the original question.
180 * @param r Pointer to the DNSPacket where the records should be inserted into.
181 * @param sd SOAData of the zone for which CDS records sets should be added,
182 * used to determine record TTL.
183 * @return bool that shows if any records were added.
184**/
185bool PacketHandler::addCDS(DNSPacket *p, DNSPacket *r, const SOAData& sd)
186{
187 string publishCDS;
0900d2d3 188 d_dk.getFromMeta(p->qdomain, "PUBLISH-CDS", publishCDS);
ef542223
PL
189 if (publishCDS.empty())
190 return false;
191
192 vector<string> digestAlgos;
193 stringtok(digestAlgos, publishCDS, ", ");
194
90ba52e0 195 DNSZoneRecord rr;
196 rr.dr.d_type=QType::CDS;
197 rr.dr.d_ttl=sd.default_ttl;
198 rr.dr.d_name=p->qdomain;
ef542223
PL
199 rr.auth=true;
200
201 bool haveOne=false;
ef542223 202
f889ab99 203 DNSSECKeeper::keyset_t keyset = d_dk.getEntryPoints(p->qdomain);
ef542223 204
56225bd3 205 for(auto const &value : keyset) {
56225bd3 206 for(auto const &digestAlgo : digestAlgos){
8455425c 207 rr.dr.d_content=std::make_shared<DSRecordContent>(makeDSFromDNSKey(p->qdomain, value.first.getDNSKEY(), pdns_stou(digestAlgo)));
ef542223
PL
208 r->addRecord(rr);
209 haveOne=true;
210 }
211 }
212
213 if(::arg().mustDo("direct-dnskey")) {
214 B.lookup(QType(QType::CDS), p->qdomain, p, sd.domain_id);
215
216 while(B.get(rr)) {
90ba52e0 217 rr.dr.d_ttl=sd.default_ttl;
ef542223
PL
218 r->addRecord(rr);
219 haveOne=true;
220 }
221 }
222
223 return haveOne;
224}
35fe50c3 225
794c2f92
PD
226/** This adds NSEC3PARAM records. Returns true if one was added */
227bool PacketHandler::addNSEC3PARAM(DNSPacket *p, DNSPacket *r, const SOAData& sd)
c3c89361 228{
90ba52e0 229 DNSZoneRecord rr;
c3c89361
BH
230
231 NSEC3PARAMRecordContent ns3prc;
e0d84497 232 if(d_dk.getNSEC3PARAM(p->qdomain, &ns3prc)) {
90ba52e0 233 rr.dr.d_type=QType::NSEC3PARAM;
234 rr.dr.d_ttl=sd.default_ttl;
235 rr.dr.d_name=p->qdomain;
1c405b6a 236 ns3prc.d_flags = 0; // the NSEC3PARAM 'flag' is defined to always be zero in RFC5155.
90ba52e0 237 rr.dr.d_content=std::make_shared<NSEC3PARAMRecordContent>(ns3prc);
c3c89361
BH
238 rr.auth = true;
239 r->addRecord(rr);
240 return true;
241 }
242 return false;
243}
244
245
49e8d5d5 246// This is our chaos class requests handler. Return 1 if content was added, 0 if it wasn't
675fa24c 247int PacketHandler::doChaosRequest(DNSPacket *p, DNSPacket *r, DNSName &target)
12c86877 248{
90ba52e0 249 DNSZoneRecord rr;
8ca1a435 250
49e8d5d5 251 if(p->qtype.getCode()==QType::TXT) {
290a083d 252 static const DNSName versionbind("version.bind."), versionpdns("version.pdns."), idserver("id.server.");
00582c16 253 if (target==versionbind || target==versionpdns) {
49e8d5d5
KM
254 // modes: full, powerdns only, anonymous or custom
255 const static string mode=::arg()["version-string"];
90ba52e0 256 string content;
49e8d5d5 257 if(mode.empty() || mode=="full")
90ba52e0 258 content=fullVersionString();
49e8d5d5 259 else if(mode=="powerdns")
90ba52e0 260 content="Served by PowerDNS - https://www.powerdns.com/";
49e8d5d5 261 else if(mode=="anonymous") {
8ca1a435 262 r->setRcode(RCode::ServFail);
8ca1a435
DB
263 return 0;
264 }
265 else
90ba52e0 266 content=mode;
6177a176 267 rr.dr.d_content = DNSRecordContent::mastermake(QType::TXT, 1, "\""+content+"\"");
49e8d5d5 268 }
290a083d 269 else if (target==idserver) {
49e8d5d5
KM
270 // modes: disabled, hostname or custom
271 const static string id=::arg()["server-id"];
272
273 if (id == "disabled") {
274 r->setRcode(RCode::Refused);
275 return 0;
8ca1a435 276 }
0e684fda 277 string tid=id;
9a1a24a9 278 if(!tid.empty() && tid[0]!='"') { // see #6010 however
279 tid = "\"" + tid + "\"";
280 }
0e684fda 281 rr.dr.d_content=DNSRecordContent::mastermake(QType::TXT, 1, tid);
49e8d5d5
KM
282 }
283 else {
284 r->setRcode(RCode::Refused);
285 return 0;
e5d684f9 286 }
e5d684f9 287
90ba52e0 288 rr.dr.d_ttl=5;
289 rr.dr.d_name=target;
290 rr.dr.d_type=QType::TXT;
291 rr.dr.d_class=QClass::CHAOS;
12c86877 292 r->addRecord(rr);
12c86877
BH
293 return 1;
294 }
49e8d5d5
KM
295
296 r->setRcode(RCode::NotImp);
12c86877
BH
297 return 0;
298}
299
90ba52e0 300vector<DNSZoneRecord> PacketHandler::getBestReferralNS(DNSPacket *p, SOAData& sd, const DNSName &target)
35fe50c3 301{
90ba52e0 302 vector<DNSZoneRecord> ret;
303 DNSZoneRecord rr;
675fa24c 304 DNSName subdomain(target);
35fe50c3 305 do {
82cc1f71
BH
306 if(subdomain == sd.qname) // stop at SOA
307 break;
35fe50c3
BH
308 B.lookup(QType(QType::NS), subdomain, p, sd.domain_id);
309 while(B.get(rr)) {
0da371d7 310 ret.push_back(rr); // this used to exclude auth NS records for some reason
35fe50c3
BH
311 }
312 if(!ret.empty())
313 return ret;
675fa24c 314 } while( subdomain.chopOff() ); // 'www.powerdns.org' -> 'powerdns.org' -> 'org' -> ''
35fe50c3
BH
315 return ret;
316}
317
90ba52e0 318vector<DNSZoneRecord> PacketHandler::getBestDNAMESynth(DNSPacket *p, SOAData& sd, DNSName &target)
8dee0750 319{
90ba52e0 320 vector<DNSZoneRecord> ret;
321 DNSZoneRecord rr;
561434a6 322 DNSName prefix;
675fa24c 323 DNSName subdomain(target);
8dee0750 324 do {
f43c4448 325 DLOG(L<<"Attempting DNAME lookup for "<<subdomain<<", sd.qname="<<sd.qname<<endl);
8dee0750 326
327 B.lookup(QType(QType::DNAME), subdomain, p, sd.domain_id);
328 while(B.get(rr)) {
329 ret.push_back(rr); // put in the original
90ba52e0 330 rr.dr.d_type = QType::CNAME;
331 rr.dr.d_name = prefix + rr.dr.d_name;
332 rr.dr.d_content = std::make_shared<CNAMERecordContent>(CNAMERecordContent(prefix + getRR<DNAMERecordContent>(rr.dr)->d_content));
dce1e90d 333 rr.auth = 0; // don't sign CNAME
90ba52e0 334 target= getRR<CNAMERecordContent>(rr.dr)->getTarget();
8dee0750 335 ret.push_back(rr);
336 }
337 if(!ret.empty())
338 return ret;
561434a6 339 if(subdomain.countLabels())
f48c35c0 340 prefix.appendRawLabel(subdomain.getRawLabels()[0]); // XXX DNSName pain this feels wrong
8dee0750 341 if(subdomain == sd.qname) // stop at SOA
342 break;
343
675fa24c 344 } while( subdomain.chopOff() ); // 'www.powerdns.org' -> 'powerdns.org' -> 'org' -> ''
8dee0750 345 return ret;
346}
347
348
75a89ce6 349// Return best matching wildcard or next closer name
90ba52e0 350bool PacketHandler::getBestWildcard(DNSPacket *p, SOAData& sd, const DNSName &target, DNSName &wildcard, vector<DNSZoneRecord>* ret)
35fe50c3 351{
e3f388cd 352 ret->clear();
90ba52e0 353 DNSZoneRecord rr;
675fa24c 354 DNSName subdomain(target);
75a89ce6
PD
355 bool haveSomething=false;
356
357 wildcard=subdomain;
675fa24c 358 while( subdomain.chopOff() && !haveSomething ) {
598b152c 359 if (subdomain.empty()) {
12c06211 360 B.lookup(QType(QType::ANY), g_wildcarddnsname, p, sd.domain_id);
598b152c 361 } else {
12c06211 362 B.lookup(QType(QType::ANY), g_wildcarddnsname+subdomain, p, sd.domain_id);
598b152c 363 }
35fe50c3 364 while(B.get(rr)) {
90ba52e0 365 if(rr.dr.d_type == p->qtype.getCode() || rr.dr.d_type == QType::CNAME || (p->qtype.getCode() == QType::ANY && rr.dr.d_type != QType::RRSIG))
e3f388cd 366 ret->push_back(rr);
12c06211 367 wildcard=g_wildcarddnsname+subdomain;
e3f388cd 368 haveSomething=true;
35fe50c3 369 }
75a89ce6
PD
370
371 if ( subdomain == sd.qname || haveSomething ) // stop at SOA or result
82cc1f71 372 break;
35fe50c3 373
75a89ce6
PD
374 B.lookup(QType(QType::ANY), subdomain, p, sd.domain_id);
375 if (B.get(rr)) {
376 DLOG(L<<"No wildcard match, ancestor exists"<<endl);
377 while (B.get(rr)) ;
378 break;
379 }
380 wildcard=subdomain;
381 }
382
383 return haveSomething;
35fe50c3
BH
384}
385
12c86877 386/** dangling is declared true if we were unable to resolve everything */
d2323cd0 387int PacketHandler::doAdditionalProcessingAndDropAA(DNSPacket *p, DNSPacket *r, const SOAData& soadata, bool retargeted)
12c86877 388{
90ba52e0 389 DNSZoneRecord rr;
fd8bc993 390 SOAData sd;
313923a8 391 sd.db=0;
b636533b 392
b8e0f341 393 if(p->qtype.getCode()!=QType::AXFR) { // this packet needs additional processing
aa7b2405 394 // we now have a copy, push_back on packet might reallocate!
395 auto& records = r->getRRS();
396 vector<DNSZoneRecord> toAdd;
8513f025 397
aa7b2405 398 for(auto i = records.cbegin() ; i!= records.cend(); ++i) {
399 if(i->dr.d_place==DNSResourceRecord::ADDITIONAL ||
400 !(i->dr.d_type==QType::MX || i->dr.d_type==QType::NS || i->dr.d_type==QType::SRV))
401 continue;
8513f025 402
94bfa5b6 403 if(r->d.aa && i->dr.d_name.countLabels() && i->dr.d_type==QType::NS && !B.getSOA(i->dr.d_name,sd) && !retargeted) { // drop AA in case of non-SOA-level NS answer, except for root referral
76bf5f40 404 r->setA(false);
232f0877 405 // i->d_place=DNSResourceRecord::AUTHORITY; // XXX FIXME
f6ba332a 406 }
fd8bc993 407
90ba52e0 408 DNSName lookup;
409
410 if(i->dr.d_type == QType::MX)
411 lookup = getRR<MXRecordContent>(i->dr)->d_mxname;
412 else if(i->dr.d_type == QType::SRV)
413 lookup = getRR<SRVRecordContent>(i->dr)->d_target;
aa7b2405 414 else if(i->dr.d_type == QType::NS)
415 lookup = getRR<NSRecordContent>(i->dr)->getNS();
416 else
417 continue;
90ba52e0 418 B.lookup(QType(d_doIPv6AdditionalProcessing ? QType::ANY : QType::A), lookup, p);
794c2f92 419
0ece3f09 420 while(B.get(rr)) {
90ba52e0 421 if(rr.dr.d_type != QType::A && rr.dr.d_type!=QType::AAAA)
0ece3f09 422 continue;
423 if(rr.domain_id!=i->domain_id && ::arg()["out-of-zone-additional-processing"]=="no") {
90ba52e0 424 DLOG(L<<Logger::Warning<<"Not including out-of-zone additional processing of "<<i->dr.d_name<<" ("<<rr.dr.d_name<<")"<<endl);
0ece3f09 425 continue; // not adding out-of-zone additional data
4957a608 426 }
0ece3f09 427
90ba52e0 428 if(rr.auth && !rr.dr.d_name.isPartOf(soadata.qname)) // don't sign out of zone data using the main key
0ece3f09 429 rr.auth=false;
90ba52e0 430 rr.dr.d_place=DNSResourceRecord::ADDITIONAL;
aa7b2405 431 toAdd.push_back(rr);
b636533b 432 }
12c86877 433 }
336f11d8 434 for(const auto& rec : toAdd)
435 r->addRecord(rec);
436
437 //records.insert(records.end(), toAdd.cbegin(), toAdd.cend()); // would be faster, but no dedup
12c86877
BH
438 }
439 return 1;
440}
441
35fe50c3 442
ca617317 443void PacketHandler::emitNSEC(DNSPacket *r, const SOAData& sd, const DNSName& name, const DNSName& next, int mode)
35fe50c3 444{
35fe50c3 445 NSECRecordContent nrc;
ca617317
KM
446 nrc.d_next = next;
447
35fe50c3 448 nrc.d_set.insert(QType::NSEC);
ca617317 449 nrc.d_set.insert(QType::RRSIG);
576e7e0f
KM
450 if(sd.qname == name) {
451 nrc.d_set.insert(QType::SOA); // 1dfd8ad SOA can live outside the records table
9b30cd1a 452 nrc.d_set.insert(QType::DNSKEY);
088370cd 453 string publishCDNSKEY;
0900d2d3 454 d_dk.getFromMeta(name, "PUBLISH-CDNSKEY", publishCDNSKEY);
088370cd
PL
455 if (publishCDNSKEY == "1")
456 nrc.d_set.insert(QType::CDNSKEY);
ef542223 457 string publishCDS;
0900d2d3 458 d_dk.getFromMeta(name, "PUBLISH-CDS", publishCDS);
ef542223
PL
459 if (! publishCDS.empty())
460 nrc.d_set.insert(QType::CDS);
576e7e0f 461 }
35fe50c3 462
90ba52e0 463 DNSZoneRecord rr;
576e7e0f 464
ca617317 465 B.lookup(QType(QType::ANY), name, NULL, sd.domain_id);
35fe50c3 466 while(B.get(rr)) {
90ba52e0 467 if(rr.dr.d_type == QType::NS || rr.auth)
468 nrc.d_set.insert(rr.dr.d_type);
35fe50c3 469 }
50eb4144 470
90ba52e0 471 rr.dr.d_name = name;
472 rr.dr.d_ttl = sd.default_ttl;
473 rr.dr.d_type = QType::NSEC;
474 rr.dr.d_content = std::make_shared<NSECRecordContent>(nrc);
475 rr.dr.d_place = (mode == 5 ) ? DNSResourceRecord::ANSWER: DNSResourceRecord::AUTHORITY;
35fe50c3 476 rr.auth = true;
50eb4144 477
35fe50c3
BH
478 r->addRecord(rr);
479}
480
576e7e0f 481void PacketHandler::emitNSEC3(DNSPacket *r, const SOAData& sd, const NSEC3PARAMRecordContent& ns3prc, const DNSName& name, const string& namehash, const string& nexthash, int mode)
5c3bf2db 482{
5c3bf2db 483 NSEC3RecordContent n3rc;
576e7e0f 484 n3rc.d_algorithm = ns3prc.d_algorithm;
b9dba5c1 485 n3rc.d_flags = ns3prc.d_flags;
c3c89361 486 n3rc.d_iterations = ns3prc.d_iterations;
576e7e0f
KM
487 n3rc.d_salt = ns3prc.d_salt;
488 n3rc.d_nexthash = nexthash;
5c3bf2db 489
90ba52e0 490 DNSZoneRecord rr;
c3c89361 491
576e7e0f
KM
492 if(!name.empty()) {
493 if (sd.qname == name) {
494 n3rc.d_set.insert(QType::SOA); // 1dfd8ad SOA can live outside the records table
b5baefaf
PD
495 n3rc.d_set.insert(QType::NSEC3PARAM);
496 n3rc.d_set.insert(QType::DNSKEY);
088370cd 497 string publishCDNSKEY;
0900d2d3 498 d_dk.getFromMeta(name, "PUBLISH-CDNSKEY", publishCDNSKEY);
088370cd
PL
499 if (publishCDNSKEY == "1")
500 n3rc.d_set.insert(QType::CDNSKEY);
ef542223 501 string publishCDS;
0900d2d3 502 d_dk.getFromMeta(name, "PUBLISH-CDS", publishCDS);
ef542223
PL
503 if (! publishCDS.empty())
504 n3rc.d_set.insert(QType::CDS);
b5baefaf 505 }
576e7e0f
KM
506
507 B.lookup(QType(QType::ANY), name, NULL, sd.domain_id);
508 while(B.get(rr)) {
90ba52e0 509 if(rr.dr.d_type && (rr.dr.d_type == QType::NS || rr.auth)) // skip empty non-terminals
510 n3rc.d_set.insert(rr.dr.d_type);
576e7e0f 511 }
c3c89361 512 }
b5baefaf 513
b8adb30d 514 if (n3rc.d_set.size() && !(n3rc.d_set.size() == 1 && n3rc.d_set.count(QType::NS)))
b5baefaf 515 n3rc.d_set.insert(QType::RRSIG);
50eb4144 516
90ba52e0 517 rr.dr.d_name = DNSName(toBase32Hex(namehash))+sd.qname;
518 rr.dr.d_ttl = sd.default_ttl;
519 rr.dr.d_type=QType::NSEC3;
520 rr.dr.d_content=std::make_shared<NSEC3RecordContent>(n3rc);
521 rr.dr.d_place = (mode == 5 ) ? DNSResourceRecord::ANSWER: DNSResourceRecord::AUTHORITY;
5c3bf2db 522 rr.auth = true;
50eb4144 523
5c3bf2db
BH
524 r->addRecord(rr);
525}
526
75a89ce6
PD
527/*
528 mode 0 = No Data Responses, QTYPE is not DS
b5baefaf 529 mode 1 = No Data Responses, QTYPE is DS
75a89ce6
PD
530 mode 2 = Wildcard No Data Responses
531 mode 3 = Wildcard Answer Responses
532 mode 4 = Name Error Responses
dcb8c5d7 533 mode 5 = Direct NSEC request
35fe50c3 534*/
675fa24c 535void PacketHandler::addNSECX(DNSPacket *p, DNSPacket *r, const DNSName& target, const DNSName& wildcard, const DNSName& auth, int mode)
01fde57c 536{
52e0d783
KM
537 if(!p->d_dnssecOk && mode != 5)
538 return;
539
c3c89361 540 NSEC3PARAMRecordContent ns3rc;
22c5aa60
BH
541 bool narrow;
542 if(d_dk.getNSEC3PARAM(auth, &ns3rc, &narrow)) {
d31e9b23 543 if (mode != 5) // no direct NSEC3 queries, rfc5155 7.2.8
dcb8c5d7 544 addNSEC3(p, r, target, wildcard, auth, ns3rc, narrow, mode);
9b30cd1a
BH
545 }
546 else {
c5c4fbdc 547 addNSEC(p, r, target, wildcard, auth, mode);
9b30cd1a 548 }
01fde57c
BH
549}
550
29e0008a 551bool getNSEC3Hashes(bool narrow, DNSBackend* db, int id, const std::string& hashed, bool decrement, DNSName& unhashed, std::string& before, std::string& after, int mode)
22c5aa60
BH
552{
553 bool ret;
554 if(narrow) { // nsec3-narrow
555 ret=true;
556 before=hashed;
b5baefaf 557 if(decrement) {
af3ffdf1 558 decrementHash(before);
b5baefaf
PD
559 unhashed.clear();
560 }
22c5aa60
BH
561 after=hashed;
562 incrementHash(after);
563 }
564 else {
29e0008a
KM
565 DNSName hashedName = DNSName(toBase32Hex(hashed));
566 DNSName beforeName, afterName;
567 if (!decrement && mode >= 2)
568 beforeName = hashedName;
569 ret=db->getBeforeAndAfterNamesAbsolute(id, hashedName, unhashed, beforeName, afterName);
570 before=fromBase32Hex(beforeName.toString());
571 after=fromBase32Hex(afterName.toString());
22c5aa60 572 }
22c5aa60
BH
573 return ret;
574}
575
561434a6 576void PacketHandler::addNSEC3(DNSPacket *p, DNSPacket *r, const DNSName& target, const DNSName& wildcard, const DNSName& auth, const NSEC3PARAMRecordContent& ns3rc, bool narrow, int mode)
01fde57c 577{
c348fec2 578 DLOG(L<<"addNSEC3() mode="<<mode<<" auth="<<auth<<" target="<<target<<" wildcard="<<wildcard<<endl);
53977f80 579
5c3bf2db 580 SOAData sd;
79ba7763 581 if(!B.getSOAUncached(auth, sd)) {
53977f80 582 DLOG(L<<"Could not get SOA for domain");
5c3bf2db
BH
583 return;
584 }
53977f80 585
3a741d7f 586 bool doNextcloser = false;
561434a6
PD
587 string before, after, hashed;
588 DNSName unhashed, closest;
53977f80 589
75a89ce6 590 if (mode == 2 || mode == 3 || mode == 4) {
f0306634 591 closest=wildcard;
561434a6 592 closest.chopOff();
f0306634
KM
593 } else
594 closest=target;
53977f80 595
75a89ce6 596 // add matching NSEC3 RR
b50efd61 597 if (mode != 3) {
3a741d7f 598 unhashed=(mode == 0 || mode == 1 || mode == 5) ? target : closest;
28e2e78e 599 hashed=hashQNameWithSalt(ns3rc, unhashed);
f43c4448 600 DLOG(L<<"1 hash: "<<toBase32Hex(hashed)<<" "<<unhashed<<endl);
53977f80 601
15c9bf3b 602 getNSEC3Hashes(narrow, sd.db, sd.domain_id, hashed, false, unhashed, before, after, mode);
3a741d7f 603
2e9c8710 604 if (((mode == 0 && ns3rc.d_flags) || mode == 1) && (hashed != before)) {
54c9247e 605 DLOG(L<<"No matching NSEC3, do closest (provable) encloser"<<endl);
3a741d7f 606
54c9247e 607 bool doBreak = false;
90ba52e0 608 DNSZoneRecord rr;
561434a6 609 while( closest.chopOff() && (closest != sd.qname)) { // stop at SOA
3a741d7f 610 B.lookup(QType(QType::ANY), closest, p, sd.domain_id);
54c9247e
KM
611 while(B.get(rr))
612 if (rr.auth)
613 doBreak = true;
614 if(doBreak)
3a741d7f 615 break;
3a741d7f
KM
616 }
617 doNextcloser = true;
618 unhashed=closest;
28e2e78e 619 hashed=hashQNameWithSalt(ns3rc, unhashed);
f43c4448 620 DLOG(L<<"1 hash: "<<toBase32Hex(hashed)<<" "<<unhashed<<endl);
3a741d7f 621
15c9bf3b 622 getNSEC3Hashes(narrow, sd.db, sd.domain_id, hashed, false, unhashed, before, after);
3a741d7f
KM
623 }
624
d88babea
KM
625 if (!after.empty()) {
626 DLOG(L<<"Done calling for matching, hashed: '"<<toBase32Hex(hashed)<<"' before='"<<toBase32Hex(before)<<"', after='"<<toBase32Hex(after)<<"'"<<endl);
576e7e0f 627 emitNSEC3(r, sd, ns3rc, unhashed, before, after, mode);
2010ac95 628 }
16cf9135 629 }
75a89ce6
PD
630
631 // add covering NSEC3 RR
3a741d7f 632 if ((mode >= 2 && mode <= 4) || doNextcloser) {
561434a6 633 DNSName next(target);
75a89ce6
PD
634 do {
635 unhashed=next;
636 }
e325f20c 637 while( next.chopOff() && !(next==closest));
75a89ce6 638
28e2e78e 639 hashed=hashQNameWithSalt(ns3rc, unhashed);
f43c4448 640 DLOG(L<<"2 hash: "<<toBase32Hex(hashed)<<" "<<unhashed<<endl);
15c9bf3b
KM
641
642 getNSEC3Hashes(narrow, sd.db,sd.domain_id, hashed, true, unhashed, before, after);
643 DLOG(L<<"Done calling for covering, hashed: '"<<toBase32Hex(hashed)<<"' before='"<<toBase32Hex(before)<<"', after='"<<toBase32Hex(after)<<"'"<<endl);
644 emitNSEC3( r, sd, ns3rc, unhashed, before, after, mode);
75a89ce6 645 }
53977f80 646
75a89ce6 647 // wildcard denial
7bb8e202 648 if (mode == 2 || mode == 4) {
12c06211 649 unhashed=g_wildcarddnsname+closest;
75a89ce6 650
28e2e78e 651 hashed=hashQNameWithSalt(ns3rc, unhashed);
f43c4448 652 DLOG(L<<"3 hash: "<<toBase32Hex(hashed)<<" "<<unhashed<<endl);
53977f80 653
15c9bf3b
KM
654 getNSEC3Hashes(narrow, sd.db, sd.domain_id, hashed, (mode != 2), unhashed, before, after);
655 DLOG(L<<"Done calling for '*', hashed: '"<<toBase32Hex(hashed)<<"' before='"<<toBase32Hex(before)<<"', after='"<<toBase32Hex(after)<<"'"<<endl);
656 emitNSEC3( r, sd, ns3rc, unhashed, before, after, mode);
75a89ce6 657 }
01fde57c 658}
35fe50c3 659
561434a6 660void PacketHandler::addNSEC(DNSPacket *p, DNSPacket *r, const DNSName& target, const DNSName& wildcard, const DNSName& auth, int mode)
35fe50c3 661{
c348fec2 662 DLOG(L<<"addNSEC() mode="<<mode<<" auth="<<auth<<" target="<<target<<" wildcard="<<wildcard<<endl);
35fe50c3 663
53977f80 664 SOAData sd;
79ba7763 665 if(!B.getSOAUncached(auth, sd)) {
6affea24 666 DLOG(L<<"Could not get SOA for domain"<<endl);
35fe50c3
BH
667 return;
668 }
669
561434a6 670 DNSName before,after;
15c9bf3b 671 sd.db->getBeforeAndAfterNames(sd.domain_id, auth, target, before, after);
7cd99296
KM
672 if (mode != 5 || before == target)
673 emitNSEC(r, sd, before, after, mode);
b5baefaf 674
337dd27b
KM
675 if (mode == 2 || mode == 4) {
676 // wildcard NO-DATA or wildcard denial
628ab42d 677 before.clear();
561434a6 678 DNSName closest(wildcard);
337dd27b 679 if (mode == 4) {
561434a6
PD
680 closest.chopOff();
681 closest.prependRawLabel("*");
337dd27b 682 }
15c9bf3b
KM
683 sd.db->getBeforeAndAfterNames(sd.domain_id, auth, closest, before, after);
684 emitNSEC(r, sd, before, after, mode);
75a89ce6 685 }
35fe50c3
BH
686 return;
687}
688
12c86877
BH
689/* Semantics:
690
691- only one backend owns the SOA of a zone
692- only one AXFR per zone at a time - double startTransaction should fail
693- backends need to implement transaction semantics
694
695
696How BindBackend would implement this:
697 startTransaction makes a file
698 feedRecord sends everything to that file
699 commitTransaction moves that file atomically over the regular file, and triggers a reload
700 rollbackTransaction removes the file
701
702
703How PostgreSQLBackend would implement this:
704 startTransaction starts a sql transaction, which also deletes all records
705 feedRecord is an insert statement
706 commitTransaction commits the transaction
707 rollbackTransaction aborts it
708
709How MySQLBackend would implement this:
710 (good question!)
711
712*/
713
6fe866b4 714int PacketHandler::trySuperMaster(DNSPacket *p, const DNSName& tsigkeyname)
7108e055
PD
715{
716 if(p->d_tcp)
717 {
718 // do it right now if the client is TCP
719 // rarely happens
7731e32c 720 return trySuperMasterSynchronous(p, tsigkeyname);
7108e055
PD
721 }
722 else
723 {
724 // queue it if the client is on UDP
725 Communicator.addTrySuperMasterRequest(p);
726 return 0;
727 }
728}
729
6fe866b4 730int PacketHandler::trySuperMasterSynchronous(DNSPacket *p, const DNSName& tsigkeyname)
12c86877 731{
a94fe494
RG
732 string remote = p->getRemote().toString();
733 if(p->hasEDNSSubnet() && ::arg().contains("trusted-notification-proxy", remote)) {
734 remote = p->getRealRemote().toStringNoMask();
735 }
736
12c86877
BH
737 Resolver::res_t nsset;
738 try {
739 Resolver resolver;
092f210a 740 uint32_t theirserial;
a94fe494
RG
741 resolver.getSoaSerial(remote,p->qdomain, &theirserial);
742 resolver.resolve(remote, p->qdomain, QType::NS, &nsset);
12c86877
BH
743 }
744 catch(ResolverException &re) {
a94fe494 745 L<<Logger::Error<<"Error resolving SOA or NS for "<<p->qdomain<<" at: "<< remote <<": "<<re.reason<<endl;
12c86877
BH
746 return RCode::ServFail;
747 }
748
39b23e69
RK
749 // check if the returned records are NS records
750 bool haveNS=false;
424b92c6 751 for(const auto& ns: nsset) {
90ba52e0 752 if(ns.qtype==QType::NS)
39b23e69
RK
753 haveNS=true;
754 }
755
756 if(!haveNS) {
a94fe494 757 L<<Logger::Error<<"While checking for supermaster, did not find NS for "<<p->qdomain<<" at: "<< remote <<endl;
39b23e69
RK
758 return RCode::ServFail;
759 }
760
719f9024 761 string nameserver, account;
12c86877 762 DNSBackend *db;
771bb0b0
AT
763
764 if (!::arg().mustDo("allow-unsigned-supermaster") && tsigkeyname.empty()) {
a94fe494 765 L<<Logger::Error<<"Received unsigned NOTIFY for "<<p->qdomain<<" from potential supermaster "<<remote<<". Refusing."<<endl;
771bb0b0
AT
766 return RCode::Refused;
767 }
768
a94fe494
RG
769 if(!B.superMasterBackend(remote, p->qdomain, nsset, &nameserver, &account, &db)) {
770 L<<Logger::Error<<"Unable to find backend willing to host "<<p->qdomain<<" for potential supermaster "<<remote<<". Remote nameservers: "<<endl;
424b92c6 771 for(const auto& rr: nsset) {
90ba52e0 772 if(rr.qtype==QType::NS)
c16de2e7 773 L<<Logger::Error<<rr.content<<endl;
a7372c6f 774 }
12c86877
BH
775 return RCode::Refused;
776 }
8c80c4f4 777 try {
ded6b08d 778 db->createSlaveDomain(p->getRemote().toString(), p->qdomain, nameserver, account);
7731e32c
AT
779 if (tsigkeyname.empty() == false) {
780 vector<string> meta;
6fe866b4 781 meta.push_back(tsigkeyname.toStringNoDot());
7731e32c
AT
782 db->setDomainMetadata(p->qdomain, "AXFR-MASTER-TSIG", meta);
783 }
8c80c4f4 784 }
3f81d239 785 catch(PDNSException& ae) {
a94fe494 786 L<<Logger::Error<<"Database error trying to create "<<p->qdomain<<" for potential supermaster "<<remote<<": "<<ae.reason<<endl;
8c80c4f4
BH
787 return RCode::ServFail;
788 }
a94fe494 789 L<<Logger::Warning<<"Created new slave zone '"<<p->qdomain<<"' from supermaster "<<remote<<endl;
12c86877
BH
790 return RCode::NoError;
791}
792
3777f434 793int PacketHandler::processNotify(DNSPacket *p)
12c86877
BH
794{
795 /* now what?
796 was this notification from an approved address?
c68ab952 797 was this notification approved by TSIG?
12c86877
BH
798 We determine our internal SOA id (via UeberBackend)
799 We determine the SOA at our (known) master
800 if master is higher -> do stuff
801 */
c68ab952 802 vector<string> meta;
c68ab952 803
dad0736b 804 if(!::arg().mustDo("slave") && s_forwardNotify.empty()) {
f43c4448 805 L<<Logger::Error<<"Received NOTIFY for "<<p->qdomain<<" from "<<p->getRemote()<<" but slave support is disabled in the configuration"<<endl;
12c86877
BH
806 return RCode::NotImp;
807 }
d207ad63 808
c68ab952 809 if(!s_allowNotifyFrom.match((ComboAddress *) &p->d_remote ) || p->d_havetsig) {
7731e32c 810 if (p->d_havetsig && p->getTSIGKeyname().empty() == false) {
0e116ef0 811 L<<Logger::Notice<<"Received secure NOTIFY for "<<p->qdomain<<" from "<<p->getRemote()<<", allowed by TSIG key '"<<p->getTSIGKeyname()<<"'"<<endl;
c68ab952 812 } else {
5b0de4d1 813 L<<Logger::Error<<"Received NOTIFY for "<<p->qdomain<<" from "<<p->getRemote()<<" but remote is not permitted by TSIG or allow-notify-from"<<endl;
c68ab952
AT
814 return RCode::Refused;
815 }
d207ad63
RK
816 }
817
12c86877
BH
818 DNSBackend *db=0;
819 DomainInfo di;
f7fb7022 820 di.serial = 0;
c38f6509 821 if(!B.getDomainInfo(p->qdomain, di) || !(db=di.backend)) {
f43c4448 822 L<<Logger::Error<<"Received NOTIFY for "<<p->qdomain<<" from "<<p->getRemote()<<" for which we are not authoritative"<<endl;
7731e32c 823 return trySuperMaster(p, p->getTSIGKeyname());
12c86877 824 }
c68ab952 825
c68ab952
AT
826 meta.clear();
827 if (B.getDomainMetadata(p->qdomain,"AXFR-MASTER-TSIG",meta) && meta.size() > 0) {
2fa2a51a 828 if (!p->d_havetsig) {
771bb0b0
AT
829 if (::arg().mustDo("allow-unsigned-notify")) {
830 L<<Logger::Warning<<"Received unsigned NOTIFY for "<<p->qdomain<<" from "<<p->getRemote()<<": permitted because allow-unsigned-notify";
831 } else {
832 L<<Logger::Warning<<"Received unsigned NOTIFY for "<<p->qdomain<<" from "<<p->getRemote()<<": refused"<<endl;
833 return RCode::Refused;
834 }
2fa2a51a 835 } else if (meta[0] != p->getTSIGKeyname().toStringNoDot()) {
0e116ef0 836 L<<Logger::Error<<"Received secure NOTIFY for "<<p->qdomain<<" from "<<p->getRemote()<<": expected TSIG key '"<<meta[0]<<", got '"<<p->getTSIGKeyname()<<"'"<<endl;
c68ab952
AT
837 return RCode::Refused;
838 }
839 }
840
ded6b08d 841 if(::arg().contains("trusted-notification-proxy", p->getRemote().toString())) {
f43c4448 842 L<<Logger::Error<<"Received NOTIFY for "<<p->qdomain<<" from trusted-notification-proxy "<< p->getRemote()<<endl;
f7fb7022 843 if(di.masters.empty()) {
f43c4448 844 L<<Logger::Error<<"However, "<<p->qdomain<<" does not have any masters defined"<<endl;
f7fb7022
BH
845 return RCode::Refused;
846 }
f7fb7022 847 }
d2adca9d
PL
848 else if(::arg().mustDo("master") && di.kind == DomainInfo::Master) {
849 L<<Logger::Error<<"Received NOTIFY for "<<p->qdomain<<" from "<<p->getRemote()<<" but we are master, rejecting"<<endl;
850 return RCode::Refused;
851 }
ded6b08d 852 else if(!db->isMaster(p->qdomain, p->getRemote().toString())) {
f43c4448 853 L<<Logger::Error<<"Received NOTIFY for "<<p->qdomain<<" from "<<p->getRemote()<<" which is not a master"<<endl;
12c86877
BH
854 return RCode::Refused;
855 }
e6e4836c 856
7f3d870e 857 // ok, we've done our checks
a16e8e3a 858 di.backend = 0;
dad0736b
RC
859
860 if(!s_forwardNotify.empty()) {
861 set<string> forwardNotify(s_forwardNotify);
862 for(set<string>::const_iterator j=forwardNotify.begin();j!=forwardNotify.end();++j) {
863 L<<Logger::Warning<<"Relaying notification of domain "<<p->qdomain<<" from "<<p->getRemote()<<" to "<<*j<<endl;
864 Communicator.notify(p->qdomain,*j);
865 }
866 }
867
868 if(::arg().mustDo("slave"))
869 Communicator.addSlaveCheckRequest(di, p->d_remote);
7f3d870e 870 return 0;
12c86877
BH
871}
872
1d563353
KM
873bool validDNSName(const DNSName &name)
874{
fc41a1a6
KM
875 if (!g_8bitDNS) {
876 string::size_type pos, length;
877 char c;
878 for(const auto& s : name.getRawLabels()) {
879 length=s.length();
880 for(pos=0; pos < length; ++pos) {
881 c=s[pos];
882 if(!((c >= 'a' && c <= 'z') ||
883 (c >= 'A' && c <= 'Z') ||
884 (c >= '0' && c <= '9') ||
885 c =='-' || c == '_' || c=='*' || c=='.' || c=='/' || c=='@' || c==' ' || c=='\\' || c==':'))
886 return false;
887 }
1d563353
KM
888 }
889 }
890 return true;
891}
892
12c86877
BH
893DNSPacket *PacketHandler::question(DNSPacket *p)
894{
5704e107
PD
895 DNSPacket *ret;
896
897 if(d_pdl)
898 {
899 ret=d_pdl->prequery(p);
900 if(ret)
901 return ret;
902 }
903
bb6e54fe 904 if(p->d.rd) {
1566533a 905 static AtomicCounter &rdqueries=*S.getPointer("rd-queries");
bb6e54fe 906 rdqueries++;
907 }
908
da286f66 909 return doQuestion(p);
ff76e8b4
BH
910}
911
90ba52e0 912
675fa24c 913void PacketHandler::makeNXDomain(DNSPacket* p, DNSPacket* r, const DNSName& target, const DNSName& wildcard, SOAData& sd)
35fe50c3 914{
90ba52e0 915 DNSZoneRecord rr;
916 rr.dr.d_name=sd.qname;
917 rr.dr.d_type=QType::SOA;
918
919 rr.dr.d_content=makeSOAContent(sd);
920 rr.dr.d_ttl=min(sd.ttl, sd.default_ttl);
794c2f92 921 rr.signttl=sd.ttl;
35fe50c3 922 rr.domain_id=sd.domain_id;
90ba52e0 923 rr.dr.d_place=DNSResourceRecord::AUTHORITY;
0957a99f 924 rr.auth = 1;
af7d3ea6 925 rr.scopeMask = sd.scopeMask;
35fe50c3 926 r->addRecord(rr);
6865d5c0 927
52e0d783 928 if(d_dk.isSecuredZone(sd.qname))
c5c4fbdc 929 addNSECX(p, r, target, wildcard, sd.qname, 4);
6865d5c0
KM
930
931 r->setRcode(RCode::NXDomain);
35fe50c3
BH
932}
933
675fa24c 934void PacketHandler::makeNOError(DNSPacket* p, DNSPacket* r, const DNSName& target, const DNSName& wildcard, SOAData& sd, int mode)
35fe50c3 935{
90ba52e0 936 DNSZoneRecord rr;
937 rr.dr.d_name=sd.qname;
938 rr.dr.d_type=QType::SOA;
939 rr.dr.d_content=makeSOAContent(sd);
940 rr.dr.d_ttl=sd.ttl;
941 rr.dr.d_ttl=min(sd.ttl, sd.default_ttl);
794c2f92 942 rr.signttl=sd.ttl;
35fe50c3 943 rr.domain_id=sd.domain_id;
90ba52e0 944 rr.dr.d_place=DNSResourceRecord::AUTHORITY;
bccefefa 945 rr.auth = 1;
35fe50c3 946 r->addRecord(rr);
ed9c3a50 947
52e0d783 948 if(d_dk.isSecuredZone(sd.qname))
c5c4fbdc 949 addNSECX(p, r, target, wildcard, sd.qname, mode);
9951e2d0 950
74f6d6e1 951 S.ringAccount("noerror-queries",p->qdomain.toLogString()+"/"+p->qtype.getName());
35fe50c3
BH
952}
953
954
675fa24c 955bool PacketHandler::addDSforNS(DNSPacket* p, DNSPacket* r, SOAData& sd, const DNSName& dsname)
35fe50c3 956{
e4090157 957 //cerr<<"Trying to find a DS for '"<<dsname<<"', domain_id = "<<sd.domain_id<<endl;
35fe50c3 958 B.lookup(QType(QType::DS), dsname, p, sd.domain_id);
90ba52e0 959 DNSZoneRecord rr;
35fe50c3
BH
960 bool gotOne=false;
961 while(B.get(rr)) {
962 gotOne=true;
90ba52e0 963 rr.dr.d_place = DNSResourceRecord::AUTHORITY;
35fe50c3
BH
964 r->addRecord(rr);
965 }
966 return gotOne;
967}
968
675fa24c 969bool PacketHandler::tryReferral(DNSPacket *p, DNSPacket*r, SOAData& sd, const DNSName &target, bool retargeted)
35fe50c3 970{
90ba52e0 971 vector<DNSZoneRecord> rrset = getBestReferralNS(p, sd, target);
35fe50c3
BH
972 if(rrset.empty())
973 return false;
974
424b92c6 975 for(auto& rr: rrset) {
90ba52e0 976 rr.dr.d_place=DNSResourceRecord::AUTHORITY;
35fe50c3
BH
977 r->addRecord(rr);
978 }
d2323cd0
PD
979 if(!retargeted)
980 r->setA(false);
35fe50c3 981
90ba52e0 982 if(d_dk.isSecuredZone(sd.qname) && !addDSforNS(p, r, sd, rrset.begin()->dr.d_name))
983 addNSECX(p, r, rrset.begin()->dr.d_name, DNSName(), sd.qname, 1);
35fe50c3
BH
984
985 return true;
986}
987
675fa24c 988void PacketHandler::completeANYRecords(DNSPacket *p, DNSPacket*r, SOAData& sd, const DNSName &target)
35fe50c3
BH
989{
990 if(!p->d_dnssecOk)
df554502 991 return; // Don't send dnssec info to non validating resolvers.
52e0d783 992
d3e7090c 993 if(!d_dk.isSecuredZone(sd.qname))
fbcdac7e 994 return;
f889ab99 995
290a083d 996 addNSECX(p, r, target, DNSName(), sd.qname, 5);
e325f20c 997 if(sd.qname == p->qdomain) {
794c2f92 998 addDNSKEY(p, r, sd);
f889ab99 999 addCDNSKEY(p, r, sd);
ef542223 1000 addCDS(p, r, sd);
794c2f92 1001 addNSEC3PARAM(p, r, sd);
70b18120 1002 }
35fe50c3
BH
1003}
1004
675fa24c 1005bool PacketHandler::tryDNAME(DNSPacket *p, DNSPacket*r, SOAData& sd, DNSName &target)
8dee0750 1006{
1007 if(!d_doDNAME)
1008 return false;
1009 DLOG(L<<Logger::Warning<<"Let's try DNAME.."<<endl);
90ba52e0 1010 vector<DNSZoneRecord> rrset = getBestDNAMESynth(p, sd, target);
8dee0750 1011 if(!rrset.empty()) {
424b92c6 1012 for(auto& rr: rrset) {
90ba52e0 1013 rr.dr.d_place = DNSResourceRecord::ANSWER;
8dee0750 1014 r->addRecord(rr);
1015 }
1016 return true;
1017 }
1018 return false;
1019}
675fa24c 1020bool PacketHandler::tryWildcard(DNSPacket *p, DNSPacket*r, SOAData& sd, DNSName &target, DNSName &wildcard, bool& retargeted, bool& nodata)
35fe50c3 1021{
e3f388cd 1022 retargeted = nodata = false;
561434a6 1023 DNSName bestmatch;
35fe50c3 1024
90ba52e0 1025 vector<DNSZoneRecord> rrset;
75a89ce6 1026 if(!getBestWildcard(p, sd, target, wildcard, &rrset))
35fe50c3
BH
1027 return false;
1028
e3f388cd 1029 if(rrset.empty()) {
6affea24 1030 DLOG(L<<"Wildcard matched something, but not of the correct type"<<endl);
e3f388cd
BH
1031 nodata=true;
1032 }
1033 else {
424b92c6 1034 for(auto& rr: rrset) {
90ba52e0 1035 rr.wildcardname = rr.dr.d_name;
1036 rr.dr.d_name=bestmatch=target;
bcb8aebe 1037
90ba52e0 1038 if(rr.dr.d_type == QType::CNAME) {
e3f388cd 1039 retargeted=true;
90ba52e0 1040 target=getRR<CNAMERecordContent>(rr.dr)->getTarget();
e3f388cd
BH
1041 }
1042
90ba52e0 1043 rr.dr.d_place=DNSResourceRecord::ANSWER;
e3f388cd 1044 r->addRecord(rr);
35fe50c3 1045 }
35fe50c3 1046 }
52e0d783 1047 if(d_dk.isSecuredZone(sd.qname) && !nodata) {
c5c4fbdc 1048 addNSECX(p, r, bestmatch, wildcard, sd.qname, 3);
35fe50c3
BH
1049 }
1050 return true;
1051}
1052
ff76e8b4 1053//! Called by the Distributor to ask a question. Returns 0 in case of an error
e89efca5 1054DNSPacket *PacketHandler::doQuestion(DNSPacket *p)
ff76e8b4 1055{
90ba52e0 1056 DNSZoneRecord rr;
12c86877 1057 SOAData sd;
81c486ad 1058
561434a6 1059 // string subdomain="";
12c86877
BH
1060 string soa;
1061 int retargetcount=0;
675fa24c 1062 set<DNSName> authSet;
35fe50c3 1063
90ba52e0 1064 vector<DNSZoneRecord> rrset;
35fe50c3 1065 bool weDone=0, weRedirected=0, weHaveUnauth=0;
561434a6 1066 DNSName haveAlias;
12c86877 1067
0c127168 1068 DNSPacket *r=0;
78bcb858 1069 bool noCache=false;
a16e8e3a
BH
1070
1071 if(p->d.qr) { // QR bit from dns packet (thanks RA from N)
641d32aa
KM
1072 if(d_logDNSDetails)
1073 L<<Logger::Error<<"Received an answer (non-query) packet from "<<p->getRemote()<<", dropping"<<endl;
a16e8e3a 1074 S.inc("corrupt-packets");
41aacb6a 1075 S.ringAccount("remotes-corrupt", p->d_remote);
a16e8e3a
BH
1076 return 0;
1077 }
1078
43b50405
CH
1079 if(p->d.tc) { // truncated query. MOADNSParser would silently parse this packet in an incomplete way.
1080 if(d_logDNSDetails)
1081 L<<Logger::Error<<"Received truncated query packet from "<<p->getRemote()<<", dropping"<<endl;
1082 S.inc("corrupt-packets");
1083 S.ringAccount("remotes-corrupt", p->d_remote);
1084 return 0;
1085 }
1086
298fabc3
AT
1087 if (p->hasEDNS() && p->getEDNSVersion() > 0) {
1088 r = p->replyPacket();
1089 r->setRcode(16 & 0xF);
1090 r->setEDNSRcode((16 & 0xFFF0)>>4); // set rcode to BADVERS
1091 return r;
1092 }
1093
78bcb858 1094 if(p->d_havetsig) {
7abbc40f
PD
1095 DNSName keyname;
1096 string secret;
78bcb858 1097 TSIGRecordContent trc;
ea3816cf 1098 if(!p->checkForCorrectTSIG(&B, &keyname, &secret, &trc)) {
0c127168 1099 r=p->replyPacket(); // generate an empty reply packet
78bcb858
BH
1100 if(d_logDNSDetails)
1101 L<<Logger::Error<<"Received a TSIG signed message with a non-validating key"<<endl;
f7a69a4c
RA
1102 // RFC3007 describes that a non-secure message should be sending Refused for DNS Updates
1103 if (p->d.opcode == Opcode::Update)
914353ca
KM
1104 r->setRcode(RCode::Refused);
1105 else
f7a69a4c 1106 r->setRcode(RCode::NotAuth);
78bcb858 1107 return r;
7f9ac49b
AT
1108 } else {
1109 getTSIGHashEnum(trc.d_algoName, p->d_tsig_algo);
1110 if (p->d_tsig_algo == TSIG_GSS) {
1635f12b 1111 GssContext gssctx(keyname);
7f9ac49b 1112 if (!gssctx.getPeerPrincipal(p->d_peer_principal)) {
f43c4448 1113 L<<Logger::Warning<<"Failed to extract peer principal from GSS context with keyname '"<<keyname<<"'"<<endl;
7f9ac49b
AT
1114 }
1115 }
78bcb858
BH
1116 }
1117 p->setTSIGDetails(trc, keyname, secret, trc.d_mac); // this will get copied by replyPacket()
1118 noCache=true;
1119 }
1120
0c127168 1121 r=p->replyPacket(); // generate an empty reply packet, possibly with TSIG details inside
c00d7891
AT
1122
1123 if (p->qtype == QType::TKEY) {
1124 this->tkeyHandler(p, r);
1125 return r;
1126 }
1127
12c86877 1128 try {
12c86877
BH
1129
1130 // XXX FIXME do this in DNSPacket::parse ?
1131
1d563353
KM
1132 if(!validDNSName(p->qdomain)) {
1133 if(d_logDNSDetails)
1134 L<<Logger::Error<<"Received a malformed qdomain from "<<p->getRemote()<<", '"<<p->qdomain<<"': sending servfail"<<endl;
1135 S.inc("corrupt-packets");
1136 S.ringAccount("remotes-corrupt", p->d_remote);
1137 S.inc("servfail-packets");
1138 r->setRcode(RCode::ServFail);
1139 return r;
1140 }
12c86877
BH
1141 if(p->d.opcode) { // non-zero opcode (again thanks RA!)
1142 if(p->d.opcode==Opcode::Update) {
71f758e0 1143 S.inc("dnsupdate-queries");
f7a69a4c 1144 int res=processUpdate(p);
63cb8c10 1145 if (res == RCode::Refused)
71f758e0 1146 S.inc("dnsupdate-refused");
63cb8c10 1147 else if (res != RCode::ServFail)
71f758e0 1148 S.inc("dnsupdate-answers");
f7a69a4c
RA
1149 r->setRcode(res);
1150 r->setOpcode(Opcode::Update);
1151 return r;
12c86877
BH
1152 }
1153 else if(p->d.opcode==Opcode::Notify) {
93aecccc 1154 S.inc("incoming-notifications");
4957a608
BH
1155 int res=processNotify(p);
1156 if(res>=0) {
4957a608
BH
1157 r->setRcode(res);
1158 r->setOpcode(Opcode::Notify);
1159 return r;
1160 }
f3a91936 1161 delete r;
4957a608 1162 return 0;
12c86877
BH
1163 }
1164
f43c4448 1165 L<<Logger::Error<<"Received an unknown opcode "<<p->d.opcode<<" from "<<p->getRemote()<<" for "<<p->qdomain<<endl;
12c86877 1166
12c86877
BH
1167 r->setRcode(RCode::NotImp);
1168 return r;
1169 }
c2413a68 1170
f43c4448 1171 // L<<Logger::Warning<<"Query for '"<<p->qdomain<<"' "<<p->qtype.getName()<<" from "<<p->getRemote()<< " (tcp="<<p->d_tcp<<")"<<endl;
12c86877 1172
dc45a198 1173 if(p->qtype.getCode()==QType::IXFR) {
8d7543ba 1174 r->setRcode(RCode::Refused);
dc45a198
BH
1175 return r;
1176 }
1177
561434a6 1178 DNSName target=p->qdomain;
c76a16b7 1179
49e8d5d5
KM
1180 // catch chaos qclass requests
1181 if(p->qclass == QClass::CHAOS) {
1182 if (doChaosRequest(p,r,target))
1183 goto sendit;
1184 else
1185 return r;
1186 }
12c86877 1187
8d7543ba 1188 // we only know about qclass IN (and ANY), send Refused for everything else.
c76a16b7 1189 if(p->qclass != QClass::IN && p->qclass!=QClass::ANY) {
8d7543ba 1190 r->setRcode(RCode::Refused);
c4ac5865
BH
1191 return r;
1192 }
12c86877 1193
ec62f3c0
KM
1194 // send TC for udp ANY query if any-to-tcp is enabled.
1195 if(p->qtype.getCode() == QType::ANY && !p->d_tcp && g_anyToTcp) {
abc8f3f9 1196 r->d.tc = 1;
1197 r->commitD();
1198 return r;
1199 }
1200
49e8d5d5 1201 // for qclass ANY the response should never be authoritative unless the response covers all classes.
c76a16b7 1202 if(p->qclass==QClass::ANY)
12c86877 1203 r->setA(false);
c76a16b7 1204
12c86877
BH
1205
1206 retargeted:;
35fe50c3 1207 if(retargetcount > 10) { // XXX FIXME, retargetcount++?
f43c4448 1208 L<<Logger::Warning<<"Abort CNAME chain resolution after "<<--retargetcount<<" redirects, sending out servfail. Initial query: '"<<p->qdomain<<"'"<<endl;
75c8ebb4
KM
1209 delete r;
1210 r=p->replyPacket();
12c86877 1211 r->setRcode(RCode::ServFail);
35fe50c3 1212 return r;
12c86877 1213 }
507823d1 1214
cec52de6 1215 if(!B.getAuth(target, p->qtype, &sd)) {
f43c4448 1216 DLOG(L<<Logger::Error<<"We have no authority over zone '"<<target<<"'"<<endl);
40fc506f 1217 if(!retargetcount) {
8d3cbffa 1218 r->setA(false); // drop AA if we never had a SOA in the first place
40fc506f 1219 r->setRcode(RCode::Refused); // send REFUSED - but only on empty 'no idea'
82cc1f71 1220 }
507823d1
BH
1221 goto sendit;
1222 }
f43c4448 1223 DLOG(L<<Logger::Error<<"We have authority, zone='"<<sd.qname<<"', id="<<sd.domain_id<<endl);
8d3cbffa 1224 authSet.insert(sd.qname);
12c86877 1225
3e8216c8
PD
1226 if(!retargetcount) r->qdomainzone=sd.qname;
1227
e325f20c 1228 if(sd.qname==p->qdomain) {
794c2f92
PD
1229 if(p->qtype.getCode() == QType::DNSKEY)
1230 {
1231 if(addDNSKEY(p, r, sd))
1232 goto sendit;
1233 }
088370cd
PL
1234 else if(p->qtype.getCode() == QType::CDNSKEY)
1235 {
f889ab99 1236 if(addCDNSKEY(p,r, sd))
088370cd
PL
1237 goto sendit;
1238 }
ef542223
PL
1239 else if(p->qtype.getCode() == QType::CDS)
1240 {
1241 if(addCDS(p,r, sd))
1242 goto sendit;
1243 }
dacacb23 1244 else if(p->qtype.getCode() == QType::NSEC3PARAM && d_dk.isSecuredZone(sd.qname))
794c2f92
PD
1245 {
1246 if(addNSEC3PARAM(p,r, sd))
1247 goto sendit;
1248 }
fbcdac7e
BH
1249 }
1250
e325f20c 1251 if(p->qtype.getCode() == QType::SOA && sd.qname==p->qdomain) {
90ba52e0 1252 rr.dr.d_name=sd.qname;
1253 rr.dr.d_type=QType::SOA;
1254 rr.dr.d_content=makeSOAContent(sd);
1255 rr.dr.d_ttl=sd.ttl;
507823d1 1256 rr.domain_id=sd.domain_id;
90ba52e0 1257 rr.dr.d_place=DNSResourceRecord::ANSWER;
d24589bc 1258 rr.auth = true;
507823d1
BH
1259 r->addRecord(rr);
1260 goto sendit;
1261 }
12c86877 1262
35fe50c3 1263 // this TRUMPS a cname!
52e0d783 1264 if(p->qtype.getCode() == QType::NSEC && d_dk.isSecuredZone(sd.qname) && !d_dk.getNSEC3PARAM(sd.qname, 0)) {
290a083d 1265 addNSEC(p, r, target, DNSName(), sd.qname, 5);
7cd99296
KM
1266 if (!r->isEmpty())
1267 goto sendit;
12c86877 1268 }
571726e9 1269
35fe50c3 1270 // this TRUMPS a cname!
ec62f3c0 1271 if(p->qtype.getCode() == QType::RRSIG) {
f43c4448 1272 L<<Logger::Info<<"Direct RRSIG query for "<<target<<" from "<<p->getRemote()<<endl;
8d7543ba 1273 r->setRcode(RCode::Refused);
52e0d783 1274 goto sendit;
cac7e485 1275 }
35fe50c3 1276
571726e9 1277 DLOG(L<<"Checking for referrals first, unless this is a DS query"<<endl);
d2323cd0 1278 if(p->qtype.getCode() != QType::DS && tryReferral(p, r, sd, target, retargetcount))
571726e9
PD
1279 goto sendit;
1280
1281 DLOG(L<<"Got no referrals, trying ANY"<<endl);
1282
35fe50c3
BH
1283 // see what we get..
1284 B.lookup(QType(QType::ANY), target, p, sd.domain_id);
1285 rrset.clear();
561434a6 1286 haveAlias.trimToLabels(0);
8dee0750 1287 weDone = weRedirected = weHaveUnauth = false;
35fe50c3
BH
1288
1289 while(B.get(rr)) {
1fda8e87 1290 //cerr<<"got content: ["<<rr.content<<"]"<<endl;
90ba52e0 1291 if (p->qtype.getCode() == QType::ANY && !p->d_dnssecOk && (rr.dr.d_type == QType:: DNSKEY || rr.dr.d_type == QType::NSEC3PARAM))
65538369 1292 continue; // Don't send dnssec info to non validating resolvers.
90ba52e0 1293 if (rr.dr.d_type == QType::RRSIG) // RRSIGS are added later any way.
65538369 1294 continue; // TODO: this actually means addRRSig should check if the RRSig is already there
794c2f92 1295
90ba52e0 1296 // cerr<<"Auth: "<<rr.auth<<", "<<(rr.dr.d_type == p->qtype)<<", "<<rr.dr.d_type.getName()<<endl;
1297 if((p->qtype.getCode() == QType::ANY || rr.dr.d_type == p->qtype.getCode()) && rr.auth)
82cc1f71 1298 weDone=1;
5b739515 1299 // the line below fakes 'unauth NS' for delegations for non-DNSSEC backends.
90ba52e0 1300 if((rr.dr.d_type == p->qtype.getCode() && !rr.auth) || (rr.dr.d_type == QType::NS && (!rr.auth || !(sd.qname==rr.dr.d_name))))
82cc1f71 1301 weHaveUnauth=1;
35fe50c3 1302
90ba52e0 1303 if(rr.dr.d_type == QType::CNAME && p->qtype.getCode() != QType::CNAME)
82cc1f71 1304 weRedirected=1;
1dfd8ada 1305
90ba52e0 1306 if(DP && rr.dr.d_type == QType::ALIAS && (p->qtype.getCode() == QType::A || p->qtype.getCode() == QType::AAAA || p->qtype.getCode() == QType::ANY)) {
389b7a05
PL
1307 if (!d_doExpandALIAS) {
1308 L<<Logger::Info<<"ALIAS record found for "<<target<<", but ALIAS expansion is disabled."<<endl;
1309 continue;
1310 }
90ba52e0 1311 haveAlias=getRR<ALIASRecordContent>(rr.dr)->d_content;
d59b894d 1312 }
1313
1dfd8ada 1314 // Filter out all SOA's and add them in later
90ba52e0 1315 if(rr.dr.d_type == QType::SOA)
1dfd8ada
MZ
1316 continue;
1317
35fe50c3 1318 rrset.push_back(rr);
12c86877
BH
1319 }
1320
1dfd8ada 1321 /* Add in SOA if required */
e325f20c 1322 if(target==sd.qname) {
90ba52e0 1323 rr.dr.d_type = QType::SOA;
1324 rr.dr.d_content = makeSOAContent(sd);
1325 rr.dr.d_name = sd.qname;
1326 rr.dr.d_ttl = sd.ttl;
1dfd8ada
MZ
1327 rr.domain_id = sd.domain_id;
1328 rr.auth = true;
1329 rrset.push_back(rr);
1330 }
1331
8dee0750 1332
d94f4908 1333 DLOG(L<<"After first ANY query for '"<<target<<"', id="<<sd.domain_id<<": weDone="<<weDone<<", weHaveUnauth="<<weHaveUnauth<<", weRedirected="<<weRedirected<<", haveAlias='"<<haveAlias<<"'"<<endl);
849bd7f1
BH
1334 if(p->qtype.getCode() == QType::DS && weHaveUnauth && !weDone && !weRedirected && d_dk.isSecuredZone(sd.qname)) {
1335 DLOG(L<<"Q for DS of a name for which we do have NS, but for which we don't have on a zone with DNSSEC need to provide an AUTH answer that proves we don't"<<endl);
290a083d 1336 makeNOError(p, r, target, DNSName(), sd, 1);
849bd7f1
BH
1337 goto sendit;
1338 }
12c86877 1339
65d2032b 1340 if(!haveAlias.empty() && (!weDone || p->qtype.getCode() == QType::ANY)) {
f43c4448 1341 DLOG(L<<Logger::Warning<<"Found nothing that matched for '"<<target<<"', but did get alias to '"<<haveAlias<<"', referring"<<endl);
d59b894d 1342 DP->completePacket(r, haveAlias, target);
1343 return 0;
1344 }
1345
35fe50c3 1346 if(rrset.empty()) {
75a89ce6 1347 DLOG(L<<"checking qtype.getCode() ["<<(p->qtype.getCode())<<"] against QType::DS ["<<(QType::DS)<<"]"<<endl);
0a0f4112
PD
1348 if(p->qtype.getCode() == QType::DS)
1349 {
1350 DLOG(L<<"DS query found no direct result, trying referral now"<<endl);
d2323cd0 1351 if(tryReferral(p, r, sd, target, retargetcount))
0a0f4112
PD
1352 {
1353 DLOG(L<<"got referral for DS query"<<endl);
1354 goto sendit;
1355 }
1356 }
1357
d59b894d 1358
571726e9 1359 DLOG(L<<Logger::Warning<<"Found nothing in the by-name ANY, but let's try wildcards.."<<endl);
e3f388cd 1360 bool wereRetargeted(false), nodata(false);
561434a6 1361 DNSName wildcard;
75a89ce6 1362 if(tryWildcard(p, r, sd, target, wildcard, wereRetargeted, nodata)) {
82cc1f71 1363 if(wereRetargeted) {
3e8216c8 1364 if(!retargetcount) r->qdomainwild=wildcard;
82cc1f71
BH
1365 retargetcount++;
1366 goto retargeted;
1367 }
c5c4fbdc
PD
1368 if(nodata)
1369 makeNOError(p, r, target, wildcard, sd, 2);
1370
82cc1f71 1371 goto sendit;
8e50cd4c 1372 }
8dee0750 1373 else if(tryDNAME(p, r, sd, target)) {
1374 retargetcount++;
1375 goto retargeted;
1376 }
a87b7e3f
PD
1377 else
1378 {
c5c4fbdc
PD
1379 if (!(((p->qtype.getCode() == QType::CNAME) || (p->qtype.getCode() == QType::ANY)) && retargetcount > 0))
1380 makeNXDomain(p, r, target, wildcard, sd);
a87b7e3f
PD
1381 }
1382
82cc1f71
BH
1383 goto sendit;
1384 }
232f0877 1385
35fe50c3 1386 if(weRedirected) {
2010ac95
RG
1387 for(auto& loopRR: rrset) {
1388 if(loopRR.dr.d_type == QType::CNAME) {
1389 r->addRecord(loopRR);
1390 target = getRR<CNAMERecordContent>(loopRR.dr)->getTarget();
82cc1f71
BH
1391 retargetcount++;
1392 goto retargeted;
4957a608 1393 }
82cc1f71 1394 }
82cc1f71 1395 }
35fe50c3 1396 else if(weDone) {
b5baefaf 1397 bool haveRecords = false;
2010ac95
RG
1398 for(const auto& loopRR: rrset) {
1399 if((p->qtype.getCode() == QType::ANY || loopRR.dr.d_type == p->qtype.getCode()) && loopRR.dr.d_type && loopRR.dr.d_type != QType::ALIAS && loopRR.auth) {
1400 r->addRecord(loopRR);
b5baefaf
PD
1401 haveRecords = true;
1402 }
82cc1f71 1403 }
4957a608 1404
b5baefaf
PD
1405 if (haveRecords) {
1406 if(p->qtype.getCode() == QType::ANY)
1407 completeANYRecords(p, r, sd, target);
82cc1f71 1408 }
b5baefaf 1409 else
b9817f2b 1410 makeNOError(p, r, target, DNSName(), sd, 0);
4957a608 1411
35fe50c3 1412 goto sendit;
82cc1f71 1413 }
35fe50c3 1414 else if(weHaveUnauth) {
6affea24 1415 DLOG(L<<"Have unauth data, so need to hunt for best NS records"<<endl);
d2323cd0 1416 if(tryReferral(p, r, sd, target, retargetcount))
82cc1f71 1417 goto sendit;
2b18bcf3 1418 // check whether this could be fixed easily
90ba52e0 1419 // if (*(rr.dr.d_name.rbegin()) == '.') {
fd5076c8 1420 // L<<Logger::Error<<"Should not get here ("<<p->qdomain<<"|"<<p->qtype.getCode()<<"): you have a trailing dot, this could be the problem (or run pdnsutil rectify-zone " <<sd.qname<<")"<<endl;
561434a6 1421 // } else {
fd5076c8 1422 L<<Logger::Error<<"Should not get here ("<<p->qdomain<<"|"<<p->qtype.getCode()<<"): please run pdnsutil rectify-zone "<<sd.qname<<endl;
561434a6 1423 // }
82cc1f71
BH
1424 }
1425 else {
6affea24 1426 DLOG(L<<"Have some data, but not the right data"<<endl);
290a083d 1427 makeNOError(p, r, target, DNSName(), sd, 0);
82cc1f71 1428 }
12c86877
BH
1429
1430 sendit:;
d2323cd0 1431 if(doAdditionalProcessingAndDropAA(p, r, sd, retargetcount)<0) {
f3a91936 1432 delete r;
12c86877 1433 return 0;
f3a91936 1434 }
8ea10bfc 1435
f33065be 1436 editSOA(d_dk, sd.qname, r);
c76f6f48 1437
2010ac95
RG
1438 for(const auto& loopRR: r->getRRS()) {
1439 if(loopRR.scopeMask) {
bf269e28 1440 noCache=true;
c28bf199 1441 break;
606018f2 1442 }
1443 }
e02d0a59 1444 if(p->d_dnssecOk)
8d3cbffa 1445 addRRSigs(d_dk, B, authSet, r->getRRS());
f3a91936 1446
e02d0a59 1447 r->wrapup(); // needed for inserting in cache
bf269e28 1448 if(!noCache && p->couldBeCached())
071d2d90 1449 PC.insert(p, r, r->getMinTTL()); // in the packet cache
12c86877
BH
1450 }
1451 catch(DBException &e) {
f89fb897 1452 L<<Logger::Error<<"Backend reported condition which prevented lookup ("+e.reason+") sending out servfail"<<endl;
25e7af37
KM
1453 delete r;
1454 r=p->replyPacket(); // generate an empty reply packet
12c86877 1455 r->setRcode(RCode::ServFail);
eefd15f9 1456 S.inc("servfail-packets");
74f6d6e1 1457 S.ringAccount("servfail-queries",p->qdomain.toLogString());
12c86877 1458 }
3f81d239 1459 catch(PDNSException &e) {
63822d0e 1460 L<<Logger::Error<<"Backend reported permanent error which prevented lookup ("+e.reason+"), aborting"<<endl;
31d9bb01 1461 throw; // we WANT to die at this point
86113ac9 1462 }
5172cb78 1463 catch(std::exception &e) {
c348fec2 1464 L<<Logger::Error<<"Exception building answer packet for "<<p->qdomain<<"/"<<p->qtype.getName()<<" ("<<e.what()<<") sending out servfail"<<endl;
8ea10bfc 1465 delete r;
25e7af37 1466 r=p->replyPacket(); // generate an empty reply packet
8ea10bfc
BH
1467 r->setRcode(RCode::ServFail);
1468 S.inc("servfail-packets");
74f6d6e1 1469 S.ringAccount("servfail-queries",p->qdomain.toLogString());
8ea10bfc 1470 }
12c86877
BH
1471 return r;
1472
1473}