]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/packethandler.cc
auth 4.1 build: Switch to devtoolset 7 for el6
[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
e2e7174d 804 L<<Logger::Debug<<"Received NOTIFY for "<<p->qdomain<<" from "<<p->getRemote()<<endl;
350b2b06 805
dad0736b 806 if(!::arg().mustDo("slave") && s_forwardNotify.empty()) {
f43c4448 807 L<<Logger::Error<<"Received NOTIFY for "<<p->qdomain<<" from "<<p->getRemote()<<" but slave support is disabled in the configuration"<<endl;
12c86877
BH
808 return RCode::NotImp;
809 }
d207ad63 810
c68ab952 811 if(!s_allowNotifyFrom.match((ComboAddress *) &p->d_remote ) || p->d_havetsig) {
7731e32c 812 if (p->d_havetsig && p->getTSIGKeyname().empty() == false) {
0e116ef0 813 L<<Logger::Notice<<"Received secure NOTIFY for "<<p->qdomain<<" from "<<p->getRemote()<<", allowed by TSIG key '"<<p->getTSIGKeyname()<<"'"<<endl;
c68ab952 814 } else {
5b0de4d1 815 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
816 return RCode::Refused;
817 }
d207ad63
RK
818 }
819
12c86877
BH
820 DNSBackend *db=0;
821 DomainInfo di;
f7fb7022 822 di.serial = 0;
c38f6509 823 if(!B.getDomainInfo(p->qdomain, di) || !(db=di.backend)) {
f43c4448 824 L<<Logger::Error<<"Received NOTIFY for "<<p->qdomain<<" from "<<p->getRemote()<<" for which we are not authoritative"<<endl;
7731e32c 825 return trySuperMaster(p, p->getTSIGKeyname());
12c86877 826 }
c68ab952 827
c68ab952
AT
828 meta.clear();
829 if (B.getDomainMetadata(p->qdomain,"AXFR-MASTER-TSIG",meta) && meta.size() > 0) {
2fa2a51a 830 if (!p->d_havetsig) {
771bb0b0
AT
831 if (::arg().mustDo("allow-unsigned-notify")) {
832 L<<Logger::Warning<<"Received unsigned NOTIFY for "<<p->qdomain<<" from "<<p->getRemote()<<": permitted because allow-unsigned-notify";
833 } else {
834 L<<Logger::Warning<<"Received unsigned NOTIFY for "<<p->qdomain<<" from "<<p->getRemote()<<": refused"<<endl;
835 return RCode::Refused;
836 }
2fa2a51a 837 } else if (meta[0] != p->getTSIGKeyname().toStringNoDot()) {
0e116ef0 838 L<<Logger::Error<<"Received secure NOTIFY for "<<p->qdomain<<" from "<<p->getRemote()<<": expected TSIG key '"<<meta[0]<<", got '"<<p->getTSIGKeyname()<<"'"<<endl;
c68ab952
AT
839 return RCode::Refused;
840 }
841 }
842
ded6b08d 843 if(::arg().contains("trusted-notification-proxy", p->getRemote().toString())) {
f43c4448 844 L<<Logger::Error<<"Received NOTIFY for "<<p->qdomain<<" from trusted-notification-proxy "<< p->getRemote()<<endl;
f7fb7022 845 if(di.masters.empty()) {
f43c4448 846 L<<Logger::Error<<"However, "<<p->qdomain<<" does not have any masters defined"<<endl;
f7fb7022
BH
847 return RCode::Refused;
848 }
f7fb7022 849 }
d2adca9d
PL
850 else if(::arg().mustDo("master") && di.kind == DomainInfo::Master) {
851 L<<Logger::Error<<"Received NOTIFY for "<<p->qdomain<<" from "<<p->getRemote()<<" but we are master, rejecting"<<endl;
852 return RCode::Refused;
853 }
ded6b08d 854 else if(!db->isMaster(p->qdomain, p->getRemote().toString())) {
f43c4448 855 L<<Logger::Error<<"Received NOTIFY for "<<p->qdomain<<" from "<<p->getRemote()<<" which is not a master"<<endl;
12c86877
BH
856 return RCode::Refused;
857 }
e6e4836c 858
7f3d870e 859 // ok, we've done our checks
a16e8e3a 860 di.backend = 0;
dad0736b
RC
861
862 if(!s_forwardNotify.empty()) {
863 set<string> forwardNotify(s_forwardNotify);
864 for(set<string>::const_iterator j=forwardNotify.begin();j!=forwardNotify.end();++j) {
865 L<<Logger::Warning<<"Relaying notification of domain "<<p->qdomain<<" from "<<p->getRemote()<<" to "<<*j<<endl;
866 Communicator.notify(p->qdomain,*j);
867 }
868 }
869
350b2b06 870 if(::arg().mustDo("slave")) {
e2e7174d 871 L<<Logger::Debug<<"Queueing slave check for "<<p->qdomain<<endl;
dad0736b 872 Communicator.addSlaveCheckRequest(di, p->d_remote);
350b2b06 873 }
7f3d870e 874 return 0;
12c86877
BH
875}
876
1d563353
KM
877bool validDNSName(const DNSName &name)
878{
fc41a1a6
KM
879 if (!g_8bitDNS) {
880 string::size_type pos, length;
881 char c;
882 for(const auto& s : name.getRawLabels()) {
883 length=s.length();
884 for(pos=0; pos < length; ++pos) {
885 c=s[pos];
886 if(!((c >= 'a' && c <= 'z') ||
887 (c >= 'A' && c <= 'Z') ||
888 (c >= '0' && c <= '9') ||
889 c =='-' || c == '_' || c=='*' || c=='.' || c=='/' || c=='@' || c==' ' || c=='\\' || c==':'))
890 return false;
891 }
1d563353
KM
892 }
893 }
894 return true;
895}
896
12c86877
BH
897DNSPacket *PacketHandler::question(DNSPacket *p)
898{
5704e107
PD
899 DNSPacket *ret;
900
901 if(d_pdl)
902 {
903 ret=d_pdl->prequery(p);
904 if(ret)
905 return ret;
906 }
907
bb6e54fe 908 if(p->d.rd) {
1566533a 909 static AtomicCounter &rdqueries=*S.getPointer("rd-queries");
bb6e54fe 910 rdqueries++;
911 }
912
da286f66 913 return doQuestion(p);
ff76e8b4
BH
914}
915
90ba52e0 916
675fa24c 917void PacketHandler::makeNXDomain(DNSPacket* p, DNSPacket* r, const DNSName& target, const DNSName& wildcard, SOAData& sd)
35fe50c3 918{
90ba52e0 919 DNSZoneRecord rr;
920 rr.dr.d_name=sd.qname;
921 rr.dr.d_type=QType::SOA;
922
923 rr.dr.d_content=makeSOAContent(sd);
924 rr.dr.d_ttl=min(sd.ttl, sd.default_ttl);
794c2f92 925 rr.signttl=sd.ttl;
35fe50c3 926 rr.domain_id=sd.domain_id;
90ba52e0 927 rr.dr.d_place=DNSResourceRecord::AUTHORITY;
0957a99f 928 rr.auth = 1;
af7d3ea6 929 rr.scopeMask = sd.scopeMask;
35fe50c3 930 r->addRecord(rr);
6865d5c0 931
52e0d783 932 if(d_dk.isSecuredZone(sd.qname))
c5c4fbdc 933 addNSECX(p, r, target, wildcard, sd.qname, 4);
6865d5c0
KM
934
935 r->setRcode(RCode::NXDomain);
35fe50c3
BH
936}
937
675fa24c 938void PacketHandler::makeNOError(DNSPacket* p, DNSPacket* r, const DNSName& target, const DNSName& wildcard, SOAData& sd, int mode)
35fe50c3 939{
90ba52e0 940 DNSZoneRecord rr;
941 rr.dr.d_name=sd.qname;
942 rr.dr.d_type=QType::SOA;
943 rr.dr.d_content=makeSOAContent(sd);
944 rr.dr.d_ttl=sd.ttl;
945 rr.dr.d_ttl=min(sd.ttl, sd.default_ttl);
794c2f92 946 rr.signttl=sd.ttl;
35fe50c3 947 rr.domain_id=sd.domain_id;
90ba52e0 948 rr.dr.d_place=DNSResourceRecord::AUTHORITY;
bccefefa 949 rr.auth = 1;
35fe50c3 950 r->addRecord(rr);
ed9c3a50 951
52e0d783 952 if(d_dk.isSecuredZone(sd.qname))
c5c4fbdc 953 addNSECX(p, r, target, wildcard, sd.qname, mode);
9951e2d0 954
74f6d6e1 955 S.ringAccount("noerror-queries",p->qdomain.toLogString()+"/"+p->qtype.getName());
35fe50c3
BH
956}
957
958
675fa24c 959bool PacketHandler::addDSforNS(DNSPacket* p, DNSPacket* r, SOAData& sd, const DNSName& dsname)
35fe50c3 960{
e4090157 961 //cerr<<"Trying to find a DS for '"<<dsname<<"', domain_id = "<<sd.domain_id<<endl;
35fe50c3 962 B.lookup(QType(QType::DS), dsname, p, sd.domain_id);
90ba52e0 963 DNSZoneRecord rr;
35fe50c3
BH
964 bool gotOne=false;
965 while(B.get(rr)) {
966 gotOne=true;
90ba52e0 967 rr.dr.d_place = DNSResourceRecord::AUTHORITY;
35fe50c3
BH
968 r->addRecord(rr);
969 }
970 return gotOne;
971}
972
675fa24c 973bool PacketHandler::tryReferral(DNSPacket *p, DNSPacket*r, SOAData& sd, const DNSName &target, bool retargeted)
35fe50c3 974{
90ba52e0 975 vector<DNSZoneRecord> rrset = getBestReferralNS(p, sd, target);
35fe50c3
BH
976 if(rrset.empty())
977 return false;
978
424b92c6 979 for(auto& rr: rrset) {
90ba52e0 980 rr.dr.d_place=DNSResourceRecord::AUTHORITY;
35fe50c3
BH
981 r->addRecord(rr);
982 }
d2323cd0
PD
983 if(!retargeted)
984 r->setA(false);
35fe50c3 985
90ba52e0 986 if(d_dk.isSecuredZone(sd.qname) && !addDSforNS(p, r, sd, rrset.begin()->dr.d_name))
987 addNSECX(p, r, rrset.begin()->dr.d_name, DNSName(), sd.qname, 1);
35fe50c3
BH
988
989 return true;
990}
991
675fa24c 992void PacketHandler::completeANYRecords(DNSPacket *p, DNSPacket*r, SOAData& sd, const DNSName &target)
35fe50c3
BH
993{
994 if(!p->d_dnssecOk)
df554502 995 return; // Don't send dnssec info to non validating resolvers.
52e0d783 996
d3e7090c 997 if(!d_dk.isSecuredZone(sd.qname))
fbcdac7e 998 return;
f889ab99 999
290a083d 1000 addNSECX(p, r, target, DNSName(), sd.qname, 5);
e325f20c 1001 if(sd.qname == p->qdomain) {
794c2f92 1002 addDNSKEY(p, r, sd);
f889ab99 1003 addCDNSKEY(p, r, sd);
ef542223 1004 addCDS(p, r, sd);
794c2f92 1005 addNSEC3PARAM(p, r, sd);
70b18120 1006 }
35fe50c3
BH
1007}
1008
675fa24c 1009bool PacketHandler::tryDNAME(DNSPacket *p, DNSPacket*r, SOAData& sd, DNSName &target)
8dee0750 1010{
1011 if(!d_doDNAME)
1012 return false;
1013 DLOG(L<<Logger::Warning<<"Let's try DNAME.."<<endl);
90ba52e0 1014 vector<DNSZoneRecord> rrset = getBestDNAMESynth(p, sd, target);
8dee0750 1015 if(!rrset.empty()) {
424b92c6 1016 for(auto& rr: rrset) {
90ba52e0 1017 rr.dr.d_place = DNSResourceRecord::ANSWER;
8dee0750 1018 r->addRecord(rr);
1019 }
1020 return true;
1021 }
1022 return false;
1023}
675fa24c 1024bool PacketHandler::tryWildcard(DNSPacket *p, DNSPacket*r, SOAData& sd, DNSName &target, DNSName &wildcard, bool& retargeted, bool& nodata)
35fe50c3 1025{
e3f388cd 1026 retargeted = nodata = false;
561434a6 1027 DNSName bestmatch;
35fe50c3 1028
90ba52e0 1029 vector<DNSZoneRecord> rrset;
75a89ce6 1030 if(!getBestWildcard(p, sd, target, wildcard, &rrset))
35fe50c3
BH
1031 return false;
1032
e3f388cd 1033 if(rrset.empty()) {
6affea24 1034 DLOG(L<<"Wildcard matched something, but not of the correct type"<<endl);
e3f388cd
BH
1035 nodata=true;
1036 }
1037 else {
424b92c6 1038 for(auto& rr: rrset) {
90ba52e0 1039 rr.wildcardname = rr.dr.d_name;
1040 rr.dr.d_name=bestmatch=target;
bcb8aebe 1041
90ba52e0 1042 if(rr.dr.d_type == QType::CNAME) {
e3f388cd 1043 retargeted=true;
90ba52e0 1044 target=getRR<CNAMERecordContent>(rr.dr)->getTarget();
e3f388cd
BH
1045 }
1046
90ba52e0 1047 rr.dr.d_place=DNSResourceRecord::ANSWER;
e3f388cd 1048 r->addRecord(rr);
35fe50c3 1049 }
35fe50c3 1050 }
52e0d783 1051 if(d_dk.isSecuredZone(sd.qname) && !nodata) {
c5c4fbdc 1052 addNSECX(p, r, bestmatch, wildcard, sd.qname, 3);
35fe50c3
BH
1053 }
1054 return true;
1055}
1056
ff76e8b4 1057//! Called by the Distributor to ask a question. Returns 0 in case of an error
e89efca5 1058DNSPacket *PacketHandler::doQuestion(DNSPacket *p)
ff76e8b4 1059{
90ba52e0 1060 DNSZoneRecord rr;
12c86877 1061 SOAData sd;
81c486ad 1062
561434a6 1063 // string subdomain="";
12c86877
BH
1064 string soa;
1065 int retargetcount=0;
675fa24c 1066 set<DNSName> authSet;
35fe50c3 1067
90ba52e0 1068 vector<DNSZoneRecord> rrset;
35fe50c3 1069 bool weDone=0, weRedirected=0, weHaveUnauth=0;
561434a6 1070 DNSName haveAlias;
6a046bf3 1071 uint8_t aliasScopeMask;
12c86877 1072
0c127168 1073 DNSPacket *r=0;
78bcb858 1074 bool noCache=false;
a16e8e3a
BH
1075
1076 if(p->d.qr) { // QR bit from dns packet (thanks RA from N)
641d32aa
KM
1077 if(d_logDNSDetails)
1078 L<<Logger::Error<<"Received an answer (non-query) packet from "<<p->getRemote()<<", dropping"<<endl;
a16e8e3a 1079 S.inc("corrupt-packets");
41aacb6a 1080 S.ringAccount("remotes-corrupt", p->d_remote);
a16e8e3a
BH
1081 return 0;
1082 }
1083
43b50405
CH
1084 if(p->d.tc) { // truncated query. MOADNSParser would silently parse this packet in an incomplete way.
1085 if(d_logDNSDetails)
1086 L<<Logger::Error<<"Received truncated query packet from "<<p->getRemote()<<", dropping"<<endl;
1087 S.inc("corrupt-packets");
1088 S.ringAccount("remotes-corrupt", p->d_remote);
1089 return 0;
1090 }
1091
298fabc3
AT
1092 if (p->hasEDNS() && p->getEDNSVersion() > 0) {
1093 r = p->replyPacket();
1094 r->setRcode(16 & 0xF);
1095 r->setEDNSRcode((16 & 0xFFF0)>>4); // set rcode to BADVERS
1096 return r;
1097 }
1098
78bcb858 1099 if(p->d_havetsig) {
7abbc40f
PD
1100 DNSName keyname;
1101 string secret;
78bcb858 1102 TSIGRecordContent trc;
ea3816cf 1103 if(!p->checkForCorrectTSIG(&B, &keyname, &secret, &trc)) {
0c127168 1104 r=p->replyPacket(); // generate an empty reply packet
78bcb858
BH
1105 if(d_logDNSDetails)
1106 L<<Logger::Error<<"Received a TSIG signed message with a non-validating key"<<endl;
f7a69a4c
RA
1107 // RFC3007 describes that a non-secure message should be sending Refused for DNS Updates
1108 if (p->d.opcode == Opcode::Update)
914353ca
KM
1109 r->setRcode(RCode::Refused);
1110 else
f7a69a4c 1111 r->setRcode(RCode::NotAuth);
78bcb858 1112 return r;
7f9ac49b
AT
1113 } else {
1114 getTSIGHashEnum(trc.d_algoName, p->d_tsig_algo);
1115 if (p->d_tsig_algo == TSIG_GSS) {
1635f12b 1116 GssContext gssctx(keyname);
7f9ac49b 1117 if (!gssctx.getPeerPrincipal(p->d_peer_principal)) {
f43c4448 1118 L<<Logger::Warning<<"Failed to extract peer principal from GSS context with keyname '"<<keyname<<"'"<<endl;
7f9ac49b
AT
1119 }
1120 }
78bcb858
BH
1121 }
1122 p->setTSIGDetails(trc, keyname, secret, trc.d_mac); // this will get copied by replyPacket()
1123 noCache=true;
1124 }
1125
0c127168 1126 r=p->replyPacket(); // generate an empty reply packet, possibly with TSIG details inside
c00d7891
AT
1127
1128 if (p->qtype == QType::TKEY) {
1129 this->tkeyHandler(p, r);
1130 return r;
1131 }
1132
12c86877 1133 try {
12c86877
BH
1134
1135 // XXX FIXME do this in DNSPacket::parse ?
1136
1d563353
KM
1137 if(!validDNSName(p->qdomain)) {
1138 if(d_logDNSDetails)
1139 L<<Logger::Error<<"Received a malformed qdomain from "<<p->getRemote()<<", '"<<p->qdomain<<"': sending servfail"<<endl;
1140 S.inc("corrupt-packets");
1141 S.ringAccount("remotes-corrupt", p->d_remote);
1142 S.inc("servfail-packets");
1143 r->setRcode(RCode::ServFail);
1144 return r;
1145 }
12c86877
BH
1146 if(p->d.opcode) { // non-zero opcode (again thanks RA!)
1147 if(p->d.opcode==Opcode::Update) {
71f758e0 1148 S.inc("dnsupdate-queries");
f7a69a4c 1149 int res=processUpdate(p);
63cb8c10 1150 if (res == RCode::Refused)
71f758e0 1151 S.inc("dnsupdate-refused");
63cb8c10 1152 else if (res != RCode::ServFail)
71f758e0 1153 S.inc("dnsupdate-answers");
f7a69a4c
RA
1154 r->setRcode(res);
1155 r->setOpcode(Opcode::Update);
1156 return r;
12c86877
BH
1157 }
1158 else if(p->d.opcode==Opcode::Notify) {
93aecccc 1159 S.inc("incoming-notifications");
4957a608
BH
1160 int res=processNotify(p);
1161 if(res>=0) {
4957a608
BH
1162 r->setRcode(res);
1163 r->setOpcode(Opcode::Notify);
1164 return r;
1165 }
f3a91936 1166 delete r;
4957a608 1167 return 0;
12c86877
BH
1168 }
1169
f43c4448 1170 L<<Logger::Error<<"Received an unknown opcode "<<p->d.opcode<<" from "<<p->getRemote()<<" for "<<p->qdomain<<endl;
12c86877 1171
12c86877
BH
1172 r->setRcode(RCode::NotImp);
1173 return r;
1174 }
c2413a68 1175
f43c4448 1176 // L<<Logger::Warning<<"Query for '"<<p->qdomain<<"' "<<p->qtype.getName()<<" from "<<p->getRemote()<< " (tcp="<<p->d_tcp<<")"<<endl;
12c86877 1177
dc45a198 1178 if(p->qtype.getCode()==QType::IXFR) {
8d7543ba 1179 r->setRcode(RCode::Refused);
dc45a198
BH
1180 return r;
1181 }
1182
561434a6 1183 DNSName target=p->qdomain;
c76a16b7 1184
49e8d5d5
KM
1185 // catch chaos qclass requests
1186 if(p->qclass == QClass::CHAOS) {
1187 if (doChaosRequest(p,r,target))
1188 goto sendit;
1189 else
1190 return r;
1191 }
12c86877 1192
8d7543ba 1193 // we only know about qclass IN (and ANY), send Refused for everything else.
c76a16b7 1194 if(p->qclass != QClass::IN && p->qclass!=QClass::ANY) {
8d7543ba 1195 r->setRcode(RCode::Refused);
c4ac5865
BH
1196 return r;
1197 }
12c86877 1198
ec62f3c0
KM
1199 // send TC for udp ANY query if any-to-tcp is enabled.
1200 if(p->qtype.getCode() == QType::ANY && !p->d_tcp && g_anyToTcp) {
abc8f3f9 1201 r->d.tc = 1;
1202 r->commitD();
1203 return r;
1204 }
1205
49e8d5d5 1206 // for qclass ANY the response should never be authoritative unless the response covers all classes.
c76a16b7 1207 if(p->qclass==QClass::ANY)
12c86877 1208 r->setA(false);
c76a16b7 1209
12c86877
BH
1210
1211 retargeted:;
35fe50c3 1212 if(retargetcount > 10) { // XXX FIXME, retargetcount++?
f43c4448 1213 L<<Logger::Warning<<"Abort CNAME chain resolution after "<<--retargetcount<<" redirects, sending out servfail. Initial query: '"<<p->qdomain<<"'"<<endl;
75c8ebb4
KM
1214 delete r;
1215 r=p->replyPacket();
12c86877 1216 r->setRcode(RCode::ServFail);
35fe50c3 1217 return r;
12c86877 1218 }
507823d1 1219
cec52de6 1220 if(!B.getAuth(target, p->qtype, &sd)) {
f43c4448 1221 DLOG(L<<Logger::Error<<"We have no authority over zone '"<<target<<"'"<<endl);
40fc506f 1222 if(!retargetcount) {
8d3cbffa 1223 r->setA(false); // drop AA if we never had a SOA in the first place
40fc506f 1224 r->setRcode(RCode::Refused); // send REFUSED - but only on empty 'no idea'
82cc1f71 1225 }
507823d1
BH
1226 goto sendit;
1227 }
f43c4448 1228 DLOG(L<<Logger::Error<<"We have authority, zone='"<<sd.qname<<"', id="<<sd.domain_id<<endl);
8d3cbffa 1229 authSet.insert(sd.qname);
12c86877 1230
3e8216c8
PD
1231 if(!retargetcount) r->qdomainzone=sd.qname;
1232
e325f20c 1233 if(sd.qname==p->qdomain) {
794c2f92
PD
1234 if(p->qtype.getCode() == QType::DNSKEY)
1235 {
1236 if(addDNSKEY(p, r, sd))
1237 goto sendit;
1238 }
088370cd
PL
1239 else if(p->qtype.getCode() == QType::CDNSKEY)
1240 {
f889ab99 1241 if(addCDNSKEY(p,r, sd))
088370cd
PL
1242 goto sendit;
1243 }
ef542223
PL
1244 else if(p->qtype.getCode() == QType::CDS)
1245 {
1246 if(addCDS(p,r, sd))
1247 goto sendit;
1248 }
dacacb23 1249 else if(p->qtype.getCode() == QType::NSEC3PARAM && d_dk.isSecuredZone(sd.qname))
794c2f92
PD
1250 {
1251 if(addNSEC3PARAM(p,r, sd))
1252 goto sendit;
1253 }
fbcdac7e
BH
1254 }
1255
e325f20c 1256 if(p->qtype.getCode() == QType::SOA && sd.qname==p->qdomain) {
90ba52e0 1257 rr.dr.d_name=sd.qname;
1258 rr.dr.d_type=QType::SOA;
1259 rr.dr.d_content=makeSOAContent(sd);
1260 rr.dr.d_ttl=sd.ttl;
507823d1 1261 rr.domain_id=sd.domain_id;
90ba52e0 1262 rr.dr.d_place=DNSResourceRecord::ANSWER;
d24589bc 1263 rr.auth = true;
507823d1
BH
1264 r->addRecord(rr);
1265 goto sendit;
1266 }
12c86877 1267
35fe50c3 1268 // this TRUMPS a cname!
52e0d783 1269 if(p->qtype.getCode() == QType::NSEC && d_dk.isSecuredZone(sd.qname) && !d_dk.getNSEC3PARAM(sd.qname, 0)) {
290a083d 1270 addNSEC(p, r, target, DNSName(), sd.qname, 5);
7cd99296
KM
1271 if (!r->isEmpty())
1272 goto sendit;
12c86877 1273 }
571726e9 1274
35fe50c3 1275 // this TRUMPS a cname!
ec62f3c0 1276 if(p->qtype.getCode() == QType::RRSIG) {
f43c4448 1277 L<<Logger::Info<<"Direct RRSIG query for "<<target<<" from "<<p->getRemote()<<endl;
8d7543ba 1278 r->setRcode(RCode::Refused);
52e0d783 1279 goto sendit;
cac7e485 1280 }
35fe50c3 1281
571726e9 1282 DLOG(L<<"Checking for referrals first, unless this is a DS query"<<endl);
d2323cd0 1283 if(p->qtype.getCode() != QType::DS && tryReferral(p, r, sd, target, retargetcount))
571726e9
PD
1284 goto sendit;
1285
1286 DLOG(L<<"Got no referrals, trying ANY"<<endl);
1287
35fe50c3
BH
1288 // see what we get..
1289 B.lookup(QType(QType::ANY), target, p, sd.domain_id);
1290 rrset.clear();
561434a6 1291 haveAlias.trimToLabels(0);
6a046bf3 1292 aliasScopeMask = 0;
8dee0750 1293 weDone = weRedirected = weHaveUnauth = false;
35fe50c3
BH
1294
1295 while(B.get(rr)) {
1fda8e87 1296 //cerr<<"got content: ["<<rr.content<<"]"<<endl;
90ba52e0 1297 if (p->qtype.getCode() == QType::ANY && !p->d_dnssecOk && (rr.dr.d_type == QType:: DNSKEY || rr.dr.d_type == QType::NSEC3PARAM))
65538369 1298 continue; // Don't send dnssec info to non validating resolvers.
90ba52e0 1299 if (rr.dr.d_type == QType::RRSIG) // RRSIGS are added later any way.
65538369 1300 continue; // TODO: this actually means addRRSig should check if the RRSig is already there
794c2f92 1301
90ba52e0 1302 // cerr<<"Auth: "<<rr.auth<<", "<<(rr.dr.d_type == p->qtype)<<", "<<rr.dr.d_type.getName()<<endl;
1303 if((p->qtype.getCode() == QType::ANY || rr.dr.d_type == p->qtype.getCode()) && rr.auth)
82cc1f71 1304 weDone=1;
5b739515 1305 // the line below fakes 'unauth NS' for delegations for non-DNSSEC backends.
90ba52e0 1306 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 1307 weHaveUnauth=1;
35fe50c3 1308
90ba52e0 1309 if(rr.dr.d_type == QType::CNAME && p->qtype.getCode() != QType::CNAME)
82cc1f71 1310 weRedirected=1;
1dfd8ada 1311
90ba52e0 1312 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
1313 if (!d_doExpandALIAS) {
1314 L<<Logger::Info<<"ALIAS record found for "<<target<<", but ALIAS expansion is disabled."<<endl;
1315 continue;
1316 }
90ba52e0 1317 haveAlias=getRR<ALIASRecordContent>(rr.dr)->d_content;
6a046bf3 1318 aliasScopeMask=rr.scopeMask;
d59b894d 1319 }
1320
1dfd8ada 1321 // Filter out all SOA's and add them in later
90ba52e0 1322 if(rr.dr.d_type == QType::SOA)
1dfd8ada
MZ
1323 continue;
1324
35fe50c3 1325 rrset.push_back(rr);
12c86877
BH
1326 }
1327
1dfd8ada 1328 /* Add in SOA if required */
e325f20c 1329 if(target==sd.qname) {
90ba52e0 1330 rr.dr.d_type = QType::SOA;
1331 rr.dr.d_content = makeSOAContent(sd);
1332 rr.dr.d_name = sd.qname;
1333 rr.dr.d_ttl = sd.ttl;
1dfd8ada
MZ
1334 rr.domain_id = sd.domain_id;
1335 rr.auth = true;
1336 rrset.push_back(rr);
1337 }
1338
8dee0750 1339
d94f4908 1340 DLOG(L<<"After first ANY query for '"<<target<<"', id="<<sd.domain_id<<": weDone="<<weDone<<", weHaveUnauth="<<weHaveUnauth<<", weRedirected="<<weRedirected<<", haveAlias='"<<haveAlias<<"'"<<endl);
849bd7f1
BH
1341 if(p->qtype.getCode() == QType::DS && weHaveUnauth && !weDone && !weRedirected && d_dk.isSecuredZone(sd.qname)) {
1342 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 1343 makeNOError(p, r, target, DNSName(), sd, 1);
849bd7f1
BH
1344 goto sendit;
1345 }
12c86877 1346
65d2032b 1347 if(!haveAlias.empty() && (!weDone || p->qtype.getCode() == QType::ANY)) {
f43c4448 1348 DLOG(L<<Logger::Warning<<"Found nothing that matched for '"<<target<<"', but did get alias to '"<<haveAlias<<"', referring"<<endl);
6a046bf3 1349 DP->completePacket(r, haveAlias, target, aliasScopeMask);
d59b894d 1350 return 0;
1351 }
1352
35fe50c3 1353 if(rrset.empty()) {
75a89ce6 1354 DLOG(L<<"checking qtype.getCode() ["<<(p->qtype.getCode())<<"] against QType::DS ["<<(QType::DS)<<"]"<<endl);
0a0f4112
PD
1355 if(p->qtype.getCode() == QType::DS)
1356 {
1357 DLOG(L<<"DS query found no direct result, trying referral now"<<endl);
d2323cd0 1358 if(tryReferral(p, r, sd, target, retargetcount))
0a0f4112
PD
1359 {
1360 DLOG(L<<"got referral for DS query"<<endl);
1361 goto sendit;
1362 }
1363 }
1364
d59b894d 1365
571726e9 1366 DLOG(L<<Logger::Warning<<"Found nothing in the by-name ANY, but let's try wildcards.."<<endl);
e3f388cd 1367 bool wereRetargeted(false), nodata(false);
561434a6 1368 DNSName wildcard;
75a89ce6 1369 if(tryWildcard(p, r, sd, target, wildcard, wereRetargeted, nodata)) {
82cc1f71 1370 if(wereRetargeted) {
3e8216c8 1371 if(!retargetcount) r->qdomainwild=wildcard;
82cc1f71
BH
1372 retargetcount++;
1373 goto retargeted;
1374 }
c5c4fbdc
PD
1375 if(nodata)
1376 makeNOError(p, r, target, wildcard, sd, 2);
1377
82cc1f71 1378 goto sendit;
8e50cd4c 1379 }
8dee0750 1380 else if(tryDNAME(p, r, sd, target)) {
1381 retargetcount++;
1382 goto retargeted;
1383 }
a87b7e3f
PD
1384 else
1385 {
c5c4fbdc
PD
1386 if (!(((p->qtype.getCode() == QType::CNAME) || (p->qtype.getCode() == QType::ANY)) && retargetcount > 0))
1387 makeNXDomain(p, r, target, wildcard, sd);
a87b7e3f
PD
1388 }
1389
82cc1f71
BH
1390 goto sendit;
1391 }
232f0877 1392
35fe50c3 1393 if(weRedirected) {
2010ac95
RG
1394 for(auto& loopRR: rrset) {
1395 if(loopRR.dr.d_type == QType::CNAME) {
1396 r->addRecord(loopRR);
1397 target = getRR<CNAMERecordContent>(loopRR.dr)->getTarget();
82cc1f71
BH
1398 retargetcount++;
1399 goto retargeted;
4957a608 1400 }
82cc1f71 1401 }
82cc1f71 1402 }
35fe50c3 1403 else if(weDone) {
b5baefaf 1404 bool haveRecords = false;
2010ac95
RG
1405 for(const auto& loopRR: rrset) {
1406 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) {
1407 r->addRecord(loopRR);
b5baefaf
PD
1408 haveRecords = true;
1409 }
82cc1f71 1410 }
4957a608 1411
b5baefaf
PD
1412 if (haveRecords) {
1413 if(p->qtype.getCode() == QType::ANY)
1414 completeANYRecords(p, r, sd, target);
82cc1f71 1415 }
b5baefaf 1416 else
b9817f2b 1417 makeNOError(p, r, target, DNSName(), sd, 0);
4957a608 1418
35fe50c3 1419 goto sendit;
82cc1f71 1420 }
35fe50c3 1421 else if(weHaveUnauth) {
6affea24 1422 DLOG(L<<"Have unauth data, so need to hunt for best NS records"<<endl);
d2323cd0 1423 if(tryReferral(p, r, sd, target, retargetcount))
82cc1f71 1424 goto sendit;
2b18bcf3 1425 // check whether this could be fixed easily
90ba52e0 1426 // if (*(rr.dr.d_name.rbegin()) == '.') {
fd5076c8 1427 // 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 1428 // } else {
fd5076c8 1429 L<<Logger::Error<<"Should not get here ("<<p->qdomain<<"|"<<p->qtype.getCode()<<"): please run pdnsutil rectify-zone "<<sd.qname<<endl;
561434a6 1430 // }
82cc1f71
BH
1431 }
1432 else {
6affea24 1433 DLOG(L<<"Have some data, but not the right data"<<endl);
290a083d 1434 makeNOError(p, r, target, DNSName(), sd, 0);
82cc1f71 1435 }
12c86877
BH
1436
1437 sendit:;
d2323cd0 1438 if(doAdditionalProcessingAndDropAA(p, r, sd, retargetcount)<0) {
f3a91936 1439 delete r;
12c86877 1440 return 0;
f3a91936 1441 }
8ea10bfc 1442
f33065be 1443 editSOA(d_dk, sd.qname, r);
c76f6f48 1444
2010ac95
RG
1445 for(const auto& loopRR: r->getRRS()) {
1446 if(loopRR.scopeMask) {
bf269e28 1447 noCache=true;
c28bf199 1448 break;
606018f2 1449 }
1450 }
e02d0a59 1451 if(p->d_dnssecOk)
8d3cbffa 1452 addRRSigs(d_dk, B, authSet, r->getRRS());
f3a91936 1453
e02d0a59 1454 r->wrapup(); // needed for inserting in cache
bf269e28 1455 if(!noCache && p->couldBeCached())
071d2d90 1456 PC.insert(p, r, r->getMinTTL()); // in the packet cache
12c86877
BH
1457 }
1458 catch(DBException &e) {
f89fb897 1459 L<<Logger::Error<<"Backend reported condition which prevented lookup ("+e.reason+") sending out servfail"<<endl;
25e7af37
KM
1460 delete r;
1461 r=p->replyPacket(); // generate an empty reply packet
12c86877 1462 r->setRcode(RCode::ServFail);
eefd15f9 1463 S.inc("servfail-packets");
74f6d6e1 1464 S.ringAccount("servfail-queries",p->qdomain.toLogString());
12c86877 1465 }
3f81d239 1466 catch(PDNSException &e) {
63822d0e 1467 L<<Logger::Error<<"Backend reported permanent error which prevented lookup ("+e.reason+"), aborting"<<endl;
31d9bb01 1468 throw; // we WANT to die at this point
86113ac9 1469 }
5172cb78 1470 catch(std::exception &e) {
c348fec2 1471 L<<Logger::Error<<"Exception building answer packet for "<<p->qdomain<<"/"<<p->qtype.getName()<<" ("<<e.what()<<") sending out servfail"<<endl;
8ea10bfc 1472 delete r;
25e7af37 1473 r=p->replyPacket(); // generate an empty reply packet
8ea10bfc
BH
1474 r->setRcode(RCode::ServFail);
1475 S.inc("servfail-packets");
74f6d6e1 1476 S.ringAccount("servfail-queries",p->qdomain.toLogString());
8ea10bfc 1477 }
12c86877
BH
1478 return r;
1479
1480}