]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/packethandler.cc
Logging: have a global g_log
[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 {
7c99293d
AT
74 d_pdl = std::unique_ptr<AuthLua4>(new AuthLua4());
75 d_pdl->loadFile(fname);
5704e107 76 }
0ecc1158
AT
77 fname = ::arg()["lua-dnsupdate-policy-script"];
78 if (fname.empty())
79 {
80 d_update_policy_lua = NULL;
81 }
82 else
83 {
9694e14f
AT
84 d_update_policy_lua = std::unique_ptr<AuthLua4>(new AuthLua4());
85 d_update_policy_lua->loadFile(fname);
0ecc1158 86 }
12c86877
BH
87}
88
3971cf53 89UeberBackend *PacketHandler::getBackend()
12c86877
BH
90{
91 return &B;
92}
93
94PacketHandler::~PacketHandler()
95{
96 --s_count;
e6a9dde5 97 DLOG(g_log<<Logger::Error<<"PacketHandler destructor called - "<<s_count<<" left"<<endl);
12c86877
BH
98}
99
088370cd 100/**
f889ab99 101 * This adds CDNSKEY records to the answer packet. Returns true if one was added.
088370cd
PL
102 *
103 * @param p Pointer to the DNSPacket containing the original question
104 * @param r Pointer to the DNSPacket where the records should be inserted into
f889ab99 105 * @param sd SOAData of the zone for which CDNSKEY records sets should be added
088370cd
PL
106 * @return bool that shows if any records were added
107**/
f889ab99 108bool PacketHandler::addCDNSKEY(DNSPacket *p, DNSPacket *r, const SOAData& sd)
35fe50c3 109{
088370cd 110 string publishCDNSKEY;
0900d2d3 111 d_dk.getFromMeta(p->qdomain, "PUBLISH-CDNSKEY", publishCDNSKEY);
f889ab99 112 if (publishCDNSKEY != "1")
088370cd
PL
113 return false;
114
90ba52e0 115 DNSZoneRecord rr;
35fe50c3 116 bool haveOne=false;
35fe50c3 117
f889ab99
PL
118 DNSSECKeeper::keyset_t entryPoints = d_dk.getEntryPoints(p->qdomain);
119 for(const auto& value: entryPoints) {
90ba52e0 120 rr.dr.d_type=QType::CDNSKEY;
121 rr.dr.d_ttl=sd.default_ttl;
122 rr.dr.d_name=p->qdomain;
123 rr.dr.d_content=std::make_shared<DNSKEYRecordContent>(value.first.getDNSKEY());
f889ab99
PL
124 rr.auth=true;
125 r->addRecord(rr);
126 haveOne=true;
127 }
128
129 if(::arg().mustDo("direct-dnskey")) {
130 B.lookup(QType(QType::CDNSKEY), p->qdomain, p, sd.domain_id);
131
132 while(B.get(rr)) {
90ba52e0 133 rr.dr.d_ttl=sd.default_ttl;
f889ab99
PL
134 r->addRecord(rr);
135 haveOne=true;
136 }
137 }
138 return haveOne;
139}
140
141/**
142 * This adds DNSKEY records to the answer packet. Returns true if one was added.
143 *
144 * @param p Pointer to the DNSPacket containing the original question
145 * @param r Pointer to the DNSPacket where the records should be inserted into
146 * @param sd SOAData of the zone for which DNSKEY records sets should be added
147 * @return bool that shows if any records were added
148**/
149bool PacketHandler::addDNSKEY(DNSPacket *p, DNSPacket *r, const SOAData& sd)
150{
90ba52e0 151 DNSZoneRecord rr;
f889ab99 152 bool haveOne=false;
f889ab99 153
ade1b1e9 154 DNSSECKeeper::keyset_t keyset = d_dk.getKeys(p->qdomain);
424b92c6 155 for(const auto& value: keyset) {
90ba52e0 156 rr.dr.d_type=QType::DNSKEY;
157 rr.dr.d_ttl=sd.default_ttl;
158 rr.dr.d_name=p->qdomain;
159 rr.dr.d_content=std::make_shared<DNSKEYRecordContent>(value.first.getDNSKEY());
ade1b1e9 160 rr.auth=true;
35fe50c3
BH
161 r->addRecord(rr);
162 haveOne=true;
163 }
4a6ea260 164
cc8df07f 165 if(::arg().mustDo("direct-dnskey")) {
f889ab99 166 B.lookup(QType(QType::DNSKEY), p->qdomain, p, sd.domain_id);
088370cd 167
4a6ea260 168 while(B.get(rr)) {
90ba52e0 169 rr.dr.d_ttl=sd.default_ttl;
4a6ea260
PD
170 r->addRecord(rr);
171 haveOne=true;
172 }
173 }
174
35fe50c3
BH
175 return haveOne;
176}
177
ef542223
PL
178/**
179 * This adds CDS records to the answer packet r.
180 *
181 * @param p Pointer to the DNSPacket containing the original question.
182 * @param r Pointer to the DNSPacket where the records should be inserted into.
183 * @param sd SOAData of the zone for which CDS records sets should be added,
184 * used to determine record TTL.
185 * @return bool that shows if any records were added.
186**/
187bool PacketHandler::addCDS(DNSPacket *p, DNSPacket *r, const SOAData& sd)
188{
189 string publishCDS;
0900d2d3 190 d_dk.getFromMeta(p->qdomain, "PUBLISH-CDS", publishCDS);
ef542223
PL
191 if (publishCDS.empty())
192 return false;
193
194 vector<string> digestAlgos;
195 stringtok(digestAlgos, publishCDS, ", ");
196
90ba52e0 197 DNSZoneRecord rr;
198 rr.dr.d_type=QType::CDS;
199 rr.dr.d_ttl=sd.default_ttl;
200 rr.dr.d_name=p->qdomain;
ef542223
PL
201 rr.auth=true;
202
203 bool haveOne=false;
ef542223 204
f889ab99 205 DNSSECKeeper::keyset_t keyset = d_dk.getEntryPoints(p->qdomain);
ef542223 206
56225bd3 207 for(auto const &value : keyset) {
56225bd3 208 for(auto const &digestAlgo : digestAlgos){
8455425c 209 rr.dr.d_content=std::make_shared<DSRecordContent>(makeDSFromDNSKey(p->qdomain, value.first.getDNSKEY(), pdns_stou(digestAlgo)));
ef542223
PL
210 r->addRecord(rr);
211 haveOne=true;
212 }
213 }
214
215 if(::arg().mustDo("direct-dnskey")) {
216 B.lookup(QType(QType::CDS), p->qdomain, p, sd.domain_id);
217
218 while(B.get(rr)) {
90ba52e0 219 rr.dr.d_ttl=sd.default_ttl;
ef542223
PL
220 r->addRecord(rr);
221 haveOne=true;
222 }
223 }
224
225 return haveOne;
226}
35fe50c3 227
794c2f92
PD
228/** This adds NSEC3PARAM records. Returns true if one was added */
229bool PacketHandler::addNSEC3PARAM(DNSPacket *p, DNSPacket *r, const SOAData& sd)
c3c89361 230{
90ba52e0 231 DNSZoneRecord rr;
c3c89361
BH
232
233 NSEC3PARAMRecordContent ns3prc;
e0d84497 234 if(d_dk.getNSEC3PARAM(p->qdomain, &ns3prc)) {
90ba52e0 235 rr.dr.d_type=QType::NSEC3PARAM;
236 rr.dr.d_ttl=sd.default_ttl;
237 rr.dr.d_name=p->qdomain;
1c405b6a 238 ns3prc.d_flags = 0; // the NSEC3PARAM 'flag' is defined to always be zero in RFC5155.
90ba52e0 239 rr.dr.d_content=std::make_shared<NSEC3PARAMRecordContent>(ns3prc);
c3c89361
BH
240 rr.auth = true;
241 r->addRecord(rr);
242 return true;
243 }
244 return false;
245}
246
247
49e8d5d5 248// This is our chaos class requests handler. Return 1 if content was added, 0 if it wasn't
675fa24c 249int PacketHandler::doChaosRequest(DNSPacket *p, DNSPacket *r, DNSName &target)
12c86877 250{
90ba52e0 251 DNSZoneRecord rr;
8ca1a435 252
49e8d5d5 253 if(p->qtype.getCode()==QType::TXT) {
290a083d 254 static const DNSName versionbind("version.bind."), versionpdns("version.pdns."), idserver("id.server.");
00582c16 255 if (target==versionbind || target==versionpdns) {
49e8d5d5
KM
256 // modes: full, powerdns only, anonymous or custom
257 const static string mode=::arg()["version-string"];
90ba52e0 258 string content;
49e8d5d5 259 if(mode.empty() || mode=="full")
90ba52e0 260 content=fullVersionString();
49e8d5d5 261 else if(mode=="powerdns")
90ba52e0 262 content="Served by PowerDNS - https://www.powerdns.com/";
49e8d5d5 263 else if(mode=="anonymous") {
8ca1a435 264 r->setRcode(RCode::ServFail);
8ca1a435
DB
265 return 0;
266 }
267 else
90ba52e0 268 content=mode;
6177a176 269 rr.dr.d_content = DNSRecordContent::mastermake(QType::TXT, 1, "\""+content+"\"");
49e8d5d5 270 }
290a083d 271 else if (target==idserver) {
49e8d5d5
KM
272 // modes: disabled, hostname or custom
273 const static string id=::arg()["server-id"];
274
275 if (id == "disabled") {
276 r->setRcode(RCode::Refused);
277 return 0;
8ca1a435 278 }
0e684fda 279 string tid=id;
9a1a24a9 280 if(!tid.empty() && tid[0]!='"') { // see #6010 however
281 tid = "\"" + tid + "\"";
282 }
0e684fda 283 rr.dr.d_content=DNSRecordContent::mastermake(QType::TXT, 1, tid);
49e8d5d5
KM
284 }
285 else {
286 r->setRcode(RCode::Refused);
287 return 0;
e5d684f9 288 }
e5d684f9 289
90ba52e0 290 rr.dr.d_ttl=5;
291 rr.dr.d_name=target;
292 rr.dr.d_type=QType::TXT;
293 rr.dr.d_class=QClass::CHAOS;
12c86877 294 r->addRecord(rr);
12c86877
BH
295 return 1;
296 }
49e8d5d5
KM
297
298 r->setRcode(RCode::NotImp);
12c86877
BH
299 return 0;
300}
301
90ba52e0 302vector<DNSZoneRecord> PacketHandler::getBestReferralNS(DNSPacket *p, SOAData& sd, const DNSName &target)
35fe50c3 303{
90ba52e0 304 vector<DNSZoneRecord> ret;
305 DNSZoneRecord rr;
675fa24c 306 DNSName subdomain(target);
35fe50c3 307 do {
82cc1f71
BH
308 if(subdomain == sd.qname) // stop at SOA
309 break;
35fe50c3
BH
310 B.lookup(QType(QType::NS), subdomain, p, sd.domain_id);
311 while(B.get(rr)) {
0da371d7 312 ret.push_back(rr); // this used to exclude auth NS records for some reason
35fe50c3
BH
313 }
314 if(!ret.empty())
315 return ret;
675fa24c 316 } while( subdomain.chopOff() ); // 'www.powerdns.org' -> 'powerdns.org' -> 'org' -> ''
35fe50c3
BH
317 return ret;
318}
319
90ba52e0 320vector<DNSZoneRecord> PacketHandler::getBestDNAMESynth(DNSPacket *p, SOAData& sd, DNSName &target)
8dee0750 321{
90ba52e0 322 vector<DNSZoneRecord> ret;
323 DNSZoneRecord rr;
561434a6 324 DNSName prefix;
675fa24c 325 DNSName subdomain(target);
8dee0750 326 do {
e6a9dde5 327 DLOG(g_log<<"Attempting DNAME lookup for "<<subdomain<<", sd.qname="<<sd.qname<<endl);
8dee0750 328
329 B.lookup(QType(QType::DNAME), subdomain, p, sd.domain_id);
330 while(B.get(rr)) {
331 ret.push_back(rr); // put in the original
90ba52e0 332 rr.dr.d_type = QType::CNAME;
333 rr.dr.d_name = prefix + rr.dr.d_name;
334 rr.dr.d_content = std::make_shared<CNAMERecordContent>(CNAMERecordContent(prefix + getRR<DNAMERecordContent>(rr.dr)->d_content));
dce1e90d 335 rr.auth = 0; // don't sign CNAME
90ba52e0 336 target= getRR<CNAMERecordContent>(rr.dr)->getTarget();
8dee0750 337 ret.push_back(rr);
338 }
339 if(!ret.empty())
340 return ret;
561434a6 341 if(subdomain.countLabels())
f48c35c0 342 prefix.appendRawLabel(subdomain.getRawLabels()[0]); // XXX DNSName pain this feels wrong
8dee0750 343 if(subdomain == sd.qname) // stop at SOA
344 break;
345
675fa24c 346 } while( subdomain.chopOff() ); // 'www.powerdns.org' -> 'powerdns.org' -> 'org' -> ''
8dee0750 347 return ret;
348}
349
350
75a89ce6 351// Return best matching wildcard or next closer name
90ba52e0 352bool PacketHandler::getBestWildcard(DNSPacket *p, SOAData& sd, const DNSName &target, DNSName &wildcard, vector<DNSZoneRecord>* ret)
35fe50c3 353{
e3f388cd 354 ret->clear();
90ba52e0 355 DNSZoneRecord rr;
675fa24c 356 DNSName subdomain(target);
75a89ce6
PD
357 bool haveSomething=false;
358
359 wildcard=subdomain;
675fa24c 360 while( subdomain.chopOff() && !haveSomething ) {
598b152c 361 if (subdomain.empty()) {
12c06211 362 B.lookup(QType(QType::ANY), g_wildcarddnsname, p, sd.domain_id);
598b152c 363 } else {
12c06211 364 B.lookup(QType(QType::ANY), g_wildcarddnsname+subdomain, p, sd.domain_id);
598b152c 365 }
35fe50c3 366 while(B.get(rr)) {
90ba52e0 367 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 368 ret->push_back(rr);
12c06211 369 wildcard=g_wildcarddnsname+subdomain;
e3f388cd 370 haveSomething=true;
35fe50c3 371 }
75a89ce6
PD
372
373 if ( subdomain == sd.qname || haveSomething ) // stop at SOA or result
82cc1f71 374 break;
35fe50c3 375
75a89ce6
PD
376 B.lookup(QType(QType::ANY), subdomain, p, sd.domain_id);
377 if (B.get(rr)) {
e6a9dde5 378 DLOG(g_log<<"No wildcard match, ancestor exists"<<endl);
75a89ce6
PD
379 while (B.get(rr)) ;
380 break;
381 }
382 wildcard=subdomain;
383 }
384
385 return haveSomething;
35fe50c3
BH
386}
387
12c86877 388/** dangling is declared true if we were unable to resolve everything */
d2323cd0 389int PacketHandler::doAdditionalProcessingAndDropAA(DNSPacket *p, DNSPacket *r, const SOAData& soadata, bool retargeted)
12c86877 390{
90ba52e0 391 DNSZoneRecord rr;
fd8bc993 392 SOAData sd;
313923a8 393 sd.db=0;
b636533b 394
b8e0f341 395 if(p->qtype.getCode()!=QType::AXFR) { // this packet needs additional processing
aa7b2405 396 // we now have a copy, push_back on packet might reallocate!
397 auto& records = r->getRRS();
398 vector<DNSZoneRecord> toAdd;
8513f025 399
aa7b2405 400 for(auto i = records.cbegin() ; i!= records.cend(); ++i) {
401 if(i->dr.d_place==DNSResourceRecord::ADDITIONAL ||
402 !(i->dr.d_type==QType::MX || i->dr.d_type==QType::NS || i->dr.d_type==QType::SRV))
403 continue;
8513f025 404
94bfa5b6 405 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 406 r->setA(false);
232f0877 407 // i->d_place=DNSResourceRecord::AUTHORITY; // XXX FIXME
f6ba332a 408 }
fd8bc993 409
90ba52e0 410 DNSName lookup;
411
412 if(i->dr.d_type == QType::MX)
413 lookup = getRR<MXRecordContent>(i->dr)->d_mxname;
414 else if(i->dr.d_type == QType::SRV)
415 lookup = getRR<SRVRecordContent>(i->dr)->d_target;
aa7b2405 416 else if(i->dr.d_type == QType::NS)
417 lookup = getRR<NSRecordContent>(i->dr)->getNS();
418 else
419 continue;
90ba52e0 420 B.lookup(QType(d_doIPv6AdditionalProcessing ? QType::ANY : QType::A), lookup, p);
794c2f92 421
0ece3f09 422 while(B.get(rr)) {
90ba52e0 423 if(rr.dr.d_type != QType::A && rr.dr.d_type!=QType::AAAA)
0ece3f09 424 continue;
425 if(rr.domain_id!=i->domain_id && ::arg()["out-of-zone-additional-processing"]=="no") {
e6a9dde5 426 DLOG(g_log<<Logger::Warning<<"Not including out-of-zone additional processing of "<<i->dr.d_name<<" ("<<rr.dr.d_name<<")"<<endl);
0ece3f09 427 continue; // not adding out-of-zone additional data
4957a608 428 }
0ece3f09 429
90ba52e0 430 if(rr.auth && !rr.dr.d_name.isPartOf(soadata.qname)) // don't sign out of zone data using the main key
0ece3f09 431 rr.auth=false;
90ba52e0 432 rr.dr.d_place=DNSResourceRecord::ADDITIONAL;
aa7b2405 433 toAdd.push_back(rr);
b636533b 434 }
12c86877 435 }
336f11d8 436 for(const auto& rec : toAdd)
437 r->addRecord(rec);
438
439 //records.insert(records.end(), toAdd.cbegin(), toAdd.cend()); // would be faster, but no dedup
12c86877
BH
440 }
441 return 1;
442}
443
35fe50c3 444
ca617317 445void PacketHandler::emitNSEC(DNSPacket *r, const SOAData& sd, const DNSName& name, const DNSName& next, int mode)
35fe50c3 446{
35fe50c3 447 NSECRecordContent nrc;
ca617317
KM
448 nrc.d_next = next;
449
35fe50c3 450 nrc.d_set.insert(QType::NSEC);
ca617317 451 nrc.d_set.insert(QType::RRSIG);
576e7e0f
KM
452 if(sd.qname == name) {
453 nrc.d_set.insert(QType::SOA); // 1dfd8ad SOA can live outside the records table
9b30cd1a 454 nrc.d_set.insert(QType::DNSKEY);
088370cd 455 string publishCDNSKEY;
0900d2d3 456 d_dk.getFromMeta(name, "PUBLISH-CDNSKEY", publishCDNSKEY);
088370cd
PL
457 if (publishCDNSKEY == "1")
458 nrc.d_set.insert(QType::CDNSKEY);
ef542223 459 string publishCDS;
0900d2d3 460 d_dk.getFromMeta(name, "PUBLISH-CDS", publishCDS);
ef542223
PL
461 if (! publishCDS.empty())
462 nrc.d_set.insert(QType::CDS);
576e7e0f 463 }
35fe50c3 464
90ba52e0 465 DNSZoneRecord rr;
576e7e0f 466
ca617317 467 B.lookup(QType(QType::ANY), name, NULL, sd.domain_id);
35fe50c3 468 while(B.get(rr)) {
90ba52e0 469 if(rr.dr.d_type == QType::NS || rr.auth)
470 nrc.d_set.insert(rr.dr.d_type);
35fe50c3 471 }
50eb4144 472
90ba52e0 473 rr.dr.d_name = name;
474 rr.dr.d_ttl = sd.default_ttl;
475 rr.dr.d_type = QType::NSEC;
476 rr.dr.d_content = std::make_shared<NSECRecordContent>(nrc);
477 rr.dr.d_place = (mode == 5 ) ? DNSResourceRecord::ANSWER: DNSResourceRecord::AUTHORITY;
35fe50c3 478 rr.auth = true;
50eb4144 479
35fe50c3
BH
480 r->addRecord(rr);
481}
482
576e7e0f 483void PacketHandler::emitNSEC3(DNSPacket *r, const SOAData& sd, const NSEC3PARAMRecordContent& ns3prc, const DNSName& name, const string& namehash, const string& nexthash, int mode)
5c3bf2db 484{
5c3bf2db 485 NSEC3RecordContent n3rc;
576e7e0f 486 n3rc.d_algorithm = ns3prc.d_algorithm;
b9dba5c1 487 n3rc.d_flags = ns3prc.d_flags;
c3c89361 488 n3rc.d_iterations = ns3prc.d_iterations;
576e7e0f
KM
489 n3rc.d_salt = ns3prc.d_salt;
490 n3rc.d_nexthash = nexthash;
5c3bf2db 491
90ba52e0 492 DNSZoneRecord rr;
c3c89361 493
576e7e0f
KM
494 if(!name.empty()) {
495 if (sd.qname == name) {
496 n3rc.d_set.insert(QType::SOA); // 1dfd8ad SOA can live outside the records table
b5baefaf
PD
497 n3rc.d_set.insert(QType::NSEC3PARAM);
498 n3rc.d_set.insert(QType::DNSKEY);
088370cd 499 string publishCDNSKEY;
0900d2d3 500 d_dk.getFromMeta(name, "PUBLISH-CDNSKEY", publishCDNSKEY);
088370cd
PL
501 if (publishCDNSKEY == "1")
502 n3rc.d_set.insert(QType::CDNSKEY);
ef542223 503 string publishCDS;
0900d2d3 504 d_dk.getFromMeta(name, "PUBLISH-CDS", publishCDS);
ef542223
PL
505 if (! publishCDS.empty())
506 n3rc.d_set.insert(QType::CDS);
b5baefaf 507 }
576e7e0f
KM
508
509 B.lookup(QType(QType::ANY), name, NULL, sd.domain_id);
510 while(B.get(rr)) {
90ba52e0 511 if(rr.dr.d_type && (rr.dr.d_type == QType::NS || rr.auth)) // skip empty non-terminals
512 n3rc.d_set.insert(rr.dr.d_type);
576e7e0f 513 }
c3c89361 514 }
b5baefaf 515
b8adb30d 516 if (n3rc.d_set.size() && !(n3rc.d_set.size() == 1 && n3rc.d_set.count(QType::NS)))
b5baefaf 517 n3rc.d_set.insert(QType::RRSIG);
50eb4144 518
90ba52e0 519 rr.dr.d_name = DNSName(toBase32Hex(namehash))+sd.qname;
520 rr.dr.d_ttl = sd.default_ttl;
521 rr.dr.d_type=QType::NSEC3;
522 rr.dr.d_content=std::make_shared<NSEC3RecordContent>(n3rc);
523 rr.dr.d_place = (mode == 5 ) ? DNSResourceRecord::ANSWER: DNSResourceRecord::AUTHORITY;
5c3bf2db 524 rr.auth = true;
50eb4144 525
5c3bf2db
BH
526 r->addRecord(rr);
527}
528
75a89ce6
PD
529/*
530 mode 0 = No Data Responses, QTYPE is not DS
b5baefaf 531 mode 1 = No Data Responses, QTYPE is DS
75a89ce6
PD
532 mode 2 = Wildcard No Data Responses
533 mode 3 = Wildcard Answer Responses
534 mode 4 = Name Error Responses
dcb8c5d7 535 mode 5 = Direct NSEC request
35fe50c3 536*/
675fa24c 537void PacketHandler::addNSECX(DNSPacket *p, DNSPacket *r, const DNSName& target, const DNSName& wildcard, const DNSName& auth, int mode)
01fde57c 538{
52e0d783
KM
539 if(!p->d_dnssecOk && mode != 5)
540 return;
541
c3c89361 542 NSEC3PARAMRecordContent ns3rc;
22c5aa60
BH
543 bool narrow;
544 if(d_dk.getNSEC3PARAM(auth, &ns3rc, &narrow)) {
d31e9b23 545 if (mode != 5) // no direct NSEC3 queries, rfc5155 7.2.8
dcb8c5d7 546 addNSEC3(p, r, target, wildcard, auth, ns3rc, narrow, mode);
9b30cd1a
BH
547 }
548 else {
c5c4fbdc 549 addNSEC(p, r, target, wildcard, auth, mode);
9b30cd1a 550 }
01fde57c
BH
551}
552
29e0008a 553bool 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
554{
555 bool ret;
556 if(narrow) { // nsec3-narrow
557 ret=true;
558 before=hashed;
b5baefaf 559 if(decrement) {
af3ffdf1 560 decrementHash(before);
b5baefaf
PD
561 unhashed.clear();
562 }
22c5aa60
BH
563 after=hashed;
564 incrementHash(after);
565 }
566 else {
29e0008a
KM
567 DNSName hashedName = DNSName(toBase32Hex(hashed));
568 DNSName beforeName, afterName;
569 if (!decrement && mode >= 2)
570 beforeName = hashedName;
571 ret=db->getBeforeAndAfterNamesAbsolute(id, hashedName, unhashed, beforeName, afterName);
572 before=fromBase32Hex(beforeName.toString());
573 after=fromBase32Hex(afterName.toString());
22c5aa60 574 }
22c5aa60
BH
575 return ret;
576}
577
561434a6 578void PacketHandler::addNSEC3(DNSPacket *p, DNSPacket *r, const DNSName& target, const DNSName& wildcard, const DNSName& auth, const NSEC3PARAMRecordContent& ns3rc, bool narrow, int mode)
01fde57c 579{
e6a9dde5 580 DLOG(g_log<<"addNSEC3() mode="<<mode<<" auth="<<auth<<" target="<<target<<" wildcard="<<wildcard<<endl);
53977f80 581
5c3bf2db 582 SOAData sd;
79ba7763 583 if(!B.getSOAUncached(auth, sd)) {
e6a9dde5 584 DLOG(g_log<<"Could not get SOA for domain");
5c3bf2db
BH
585 return;
586 }
53977f80 587
3a741d7f 588 bool doNextcloser = false;
561434a6
PD
589 string before, after, hashed;
590 DNSName unhashed, closest;
53977f80 591
75a89ce6 592 if (mode == 2 || mode == 3 || mode == 4) {
f0306634 593 closest=wildcard;
561434a6 594 closest.chopOff();
f0306634
KM
595 } else
596 closest=target;
53977f80 597
75a89ce6 598 // add matching NSEC3 RR
b50efd61 599 if (mode != 3) {
3a741d7f 600 unhashed=(mode == 0 || mode == 1 || mode == 5) ? target : closest;
28e2e78e 601 hashed=hashQNameWithSalt(ns3rc, unhashed);
e6a9dde5 602 DLOG(g_log<<"1 hash: "<<toBase32Hex(hashed)<<" "<<unhashed<<endl);
53977f80 603
15c9bf3b 604 getNSEC3Hashes(narrow, sd.db, sd.domain_id, hashed, false, unhashed, before, after, mode);
3a741d7f 605
2e9c8710 606 if (((mode == 0 && ns3rc.d_flags) || mode == 1) && (hashed != before)) {
e6a9dde5 607 DLOG(g_log<<"No matching NSEC3, do closest (provable) encloser"<<endl);
3a741d7f 608
54c9247e 609 bool doBreak = false;
90ba52e0 610 DNSZoneRecord rr;
561434a6 611 while( closest.chopOff() && (closest != sd.qname)) { // stop at SOA
3a741d7f 612 B.lookup(QType(QType::ANY), closest, p, sd.domain_id);
54c9247e
KM
613 while(B.get(rr))
614 if (rr.auth)
615 doBreak = true;
616 if(doBreak)
3a741d7f 617 break;
3a741d7f
KM
618 }
619 doNextcloser = true;
620 unhashed=closest;
28e2e78e 621 hashed=hashQNameWithSalt(ns3rc, unhashed);
e6a9dde5 622 DLOG(g_log<<"1 hash: "<<toBase32Hex(hashed)<<" "<<unhashed<<endl);
3a741d7f 623
15c9bf3b 624 getNSEC3Hashes(narrow, sd.db, sd.domain_id, hashed, false, unhashed, before, after);
3a741d7f
KM
625 }
626
d88babea 627 if (!after.empty()) {
e6a9dde5 628 DLOG(g_log<<"Done calling for matching, hashed: '"<<toBase32Hex(hashed)<<"' before='"<<toBase32Hex(before)<<"', after='"<<toBase32Hex(after)<<"'"<<endl);
576e7e0f 629 emitNSEC3(r, sd, ns3rc, unhashed, before, after, mode);
2010ac95 630 }
16cf9135 631 }
75a89ce6
PD
632
633 // add covering NSEC3 RR
3a741d7f 634 if ((mode >= 2 && mode <= 4) || doNextcloser) {
561434a6 635 DNSName next(target);
75a89ce6
PD
636 do {
637 unhashed=next;
638 }
e325f20c 639 while( next.chopOff() && !(next==closest));
75a89ce6 640
28e2e78e 641 hashed=hashQNameWithSalt(ns3rc, unhashed);
e6a9dde5 642 DLOG(g_log<<"2 hash: "<<toBase32Hex(hashed)<<" "<<unhashed<<endl);
15c9bf3b
KM
643
644 getNSEC3Hashes(narrow, sd.db,sd.domain_id, hashed, true, unhashed, before, after);
e6a9dde5 645 DLOG(g_log<<"Done calling for covering, hashed: '"<<toBase32Hex(hashed)<<"' before='"<<toBase32Hex(before)<<"', after='"<<toBase32Hex(after)<<"'"<<endl);
15c9bf3b 646 emitNSEC3( r, sd, ns3rc, unhashed, before, after, mode);
75a89ce6 647 }
53977f80 648
75a89ce6 649 // wildcard denial
7bb8e202 650 if (mode == 2 || mode == 4) {
12c06211 651 unhashed=g_wildcarddnsname+closest;
75a89ce6 652
28e2e78e 653 hashed=hashQNameWithSalt(ns3rc, unhashed);
e6a9dde5 654 DLOG(g_log<<"3 hash: "<<toBase32Hex(hashed)<<" "<<unhashed<<endl);
53977f80 655
15c9bf3b 656 getNSEC3Hashes(narrow, sd.db, sd.domain_id, hashed, (mode != 2), unhashed, before, after);
e6a9dde5 657 DLOG(g_log<<"Done calling for '*', hashed: '"<<toBase32Hex(hashed)<<"' before='"<<toBase32Hex(before)<<"', after='"<<toBase32Hex(after)<<"'"<<endl);
15c9bf3b 658 emitNSEC3( r, sd, ns3rc, unhashed, before, after, mode);
75a89ce6 659 }
01fde57c 660}
35fe50c3 661
561434a6 662void PacketHandler::addNSEC(DNSPacket *p, DNSPacket *r, const DNSName& target, const DNSName& wildcard, const DNSName& auth, int mode)
35fe50c3 663{
e6a9dde5 664 DLOG(g_log<<"addNSEC() mode="<<mode<<" auth="<<auth<<" target="<<target<<" wildcard="<<wildcard<<endl);
35fe50c3 665
53977f80 666 SOAData sd;
79ba7763 667 if(!B.getSOAUncached(auth, sd)) {
e6a9dde5 668 DLOG(g_log<<"Could not get SOA for domain"<<endl);
35fe50c3
BH
669 return;
670 }
671
561434a6 672 DNSName before,after;
15c9bf3b 673 sd.db->getBeforeAndAfterNames(sd.domain_id, auth, target, before, after);
7cd99296
KM
674 if (mode != 5 || before == target)
675 emitNSEC(r, sd, before, after, mode);
b5baefaf 676
337dd27b
KM
677 if (mode == 2 || mode == 4) {
678 // wildcard NO-DATA or wildcard denial
628ab42d 679 before.clear();
561434a6 680 DNSName closest(wildcard);
337dd27b 681 if (mode == 4) {
561434a6
PD
682 closest.chopOff();
683 closest.prependRawLabel("*");
337dd27b 684 }
15c9bf3b
KM
685 sd.db->getBeforeAndAfterNames(sd.domain_id, auth, closest, before, after);
686 emitNSEC(r, sd, before, after, mode);
75a89ce6 687 }
35fe50c3
BH
688 return;
689}
690
12c86877
BH
691/* Semantics:
692
693- only one backend owns the SOA of a zone
694- only one AXFR per zone at a time - double startTransaction should fail
695- backends need to implement transaction semantics
696
697
698How BindBackend would implement this:
699 startTransaction makes a file
700 feedRecord sends everything to that file
701 commitTransaction moves that file atomically over the regular file, and triggers a reload
702 rollbackTransaction removes the file
703
704
705How PostgreSQLBackend would implement this:
706 startTransaction starts a sql transaction, which also deletes all records
707 feedRecord is an insert statement
708 commitTransaction commits the transaction
709 rollbackTransaction aborts it
710
711How MySQLBackend would implement this:
712 (good question!)
713
714*/
715
6fe866b4 716int PacketHandler::trySuperMaster(DNSPacket *p, const DNSName& tsigkeyname)
7108e055
PD
717{
718 if(p->d_tcp)
719 {
720 // do it right now if the client is TCP
721 // rarely happens
7731e32c 722 return trySuperMasterSynchronous(p, tsigkeyname);
7108e055
PD
723 }
724 else
725 {
726 // queue it if the client is on UDP
727 Communicator.addTrySuperMasterRequest(p);
728 return 0;
729 }
730}
731
6fe866b4 732int PacketHandler::trySuperMasterSynchronous(DNSPacket *p, const DNSName& tsigkeyname)
12c86877 733{
a94fe494
RG
734 string remote = p->getRemote().toString();
735 if(p->hasEDNSSubnet() && ::arg().contains("trusted-notification-proxy", remote)) {
736 remote = p->getRealRemote().toStringNoMask();
737 }
738
12c86877
BH
739 Resolver::res_t nsset;
740 try {
741 Resolver resolver;
092f210a 742 uint32_t theirserial;
a94fe494
RG
743 resolver.getSoaSerial(remote,p->qdomain, &theirserial);
744 resolver.resolve(remote, p->qdomain, QType::NS, &nsset);
12c86877
BH
745 }
746 catch(ResolverException &re) {
e6a9dde5 747 g_log<<Logger::Error<<"Error resolving SOA or NS for "<<p->qdomain<<" at: "<< remote <<": "<<re.reason<<endl;
12c86877
BH
748 return RCode::ServFail;
749 }
750
39b23e69
RK
751 // check if the returned records are NS records
752 bool haveNS=false;
424b92c6 753 for(const auto& ns: nsset) {
90ba52e0 754 if(ns.qtype==QType::NS)
39b23e69
RK
755 haveNS=true;
756 }
757
758 if(!haveNS) {
e6a9dde5 759 g_log<<Logger::Error<<"While checking for supermaster, did not find NS for "<<p->qdomain<<" at: "<< remote <<endl;
39b23e69
RK
760 return RCode::ServFail;
761 }
762
719f9024 763 string nameserver, account;
12c86877 764 DNSBackend *db;
771bb0b0
AT
765
766 if (!::arg().mustDo("allow-unsigned-supermaster") && tsigkeyname.empty()) {
e6a9dde5 767 g_log<<Logger::Error<<"Received unsigned NOTIFY for "<<p->qdomain<<" from potential supermaster "<<remote<<". Refusing."<<endl;
771bb0b0
AT
768 return RCode::Refused;
769 }
770
a94fe494 771 if(!B.superMasterBackend(remote, p->qdomain, nsset, &nameserver, &account, &db)) {
e6a9dde5 772 g_log<<Logger::Error<<"Unable to find backend willing to host "<<p->qdomain<<" for potential supermaster "<<remote<<". Remote nameservers: "<<endl;
424b92c6 773 for(const auto& rr: nsset) {
90ba52e0 774 if(rr.qtype==QType::NS)
e6a9dde5 775 g_log<<Logger::Error<<rr.content<<endl;
a7372c6f 776 }
12c86877
BH
777 return RCode::Refused;
778 }
8c80c4f4 779 try {
ded6b08d 780 db->createSlaveDomain(p->getRemote().toString(), p->qdomain, nameserver, account);
7731e32c
AT
781 if (tsigkeyname.empty() == false) {
782 vector<string> meta;
6fe866b4 783 meta.push_back(tsigkeyname.toStringNoDot());
7731e32c
AT
784 db->setDomainMetadata(p->qdomain, "AXFR-MASTER-TSIG", meta);
785 }
8c80c4f4 786 }
3f81d239 787 catch(PDNSException& ae) {
e6a9dde5 788 g_log<<Logger::Error<<"Database error trying to create "<<p->qdomain<<" for potential supermaster "<<remote<<": "<<ae.reason<<endl;
8c80c4f4
BH
789 return RCode::ServFail;
790 }
e6a9dde5 791 g_log<<Logger::Warning<<"Created new slave zone '"<<p->qdomain<<"' from supermaster "<<remote<<endl;
12c86877
BH
792 return RCode::NoError;
793}
794
3777f434 795int PacketHandler::processNotify(DNSPacket *p)
12c86877
BH
796{
797 /* now what?
798 was this notification from an approved address?
c68ab952 799 was this notification approved by TSIG?
12c86877
BH
800 We determine our internal SOA id (via UeberBackend)
801 We determine the SOA at our (known) master
802 if master is higher -> do stuff
803 */
c68ab952 804 vector<string> meta;
c68ab952 805
dad0736b 806 if(!::arg().mustDo("slave") && s_forwardNotify.empty()) {
e6a9dde5 807 g_log<<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) {
e6a9dde5 813 g_log<<Logger::Notice<<"Received secure NOTIFY for "<<p->qdomain<<" from "<<p->getRemote()<<", allowed by TSIG key '"<<p->getTSIGKeyname()<<"'"<<endl;
c68ab952 814 } else {
e6a9dde5 815 g_log<<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)) {
e6a9dde5 824 g_log<<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 831 if (::arg().mustDo("allow-unsigned-notify")) {
e6a9dde5 832 g_log<<Logger::Warning<<"Received unsigned NOTIFY for "<<p->qdomain<<" from "<<p->getRemote()<<": permitted because allow-unsigned-notify";
771bb0b0 833 } else {
e6a9dde5 834 g_log<<Logger::Warning<<"Received unsigned NOTIFY for "<<p->qdomain<<" from "<<p->getRemote()<<": refused"<<endl;
771bb0b0
AT
835 return RCode::Refused;
836 }
2fa2a51a 837 } else if (meta[0] != p->getTSIGKeyname().toStringNoDot()) {
e6a9dde5 838 g_log<<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())) {
e6a9dde5 844 g_log<<Logger::Error<<"Received NOTIFY for "<<p->qdomain<<" from trusted-notification-proxy "<< p->getRemote()<<endl;
f7fb7022 845 if(di.masters.empty()) {
e6a9dde5 846 g_log<<Logger::Error<<"However, "<<p->qdomain<<" does not have any masters defined"<<endl;
f7fb7022
BH
847 return RCode::Refused;
848 }
f7fb7022 849 }
d2adca9d 850 else if(::arg().mustDo("master") && di.kind == DomainInfo::Master) {
e6a9dde5 851 g_log<<Logger::Error<<"Received NOTIFY for "<<p->qdomain<<" from "<<p->getRemote()<<" but we are master, rejecting"<<endl;
d2adca9d
PL
852 return RCode::Refused;
853 }
ded6b08d 854 else if(!db->isMaster(p->qdomain, p->getRemote().toString())) {
e6a9dde5 855 g_log<<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) {
e6a9dde5 865 g_log<<Logger::Warning<<"Relaying notification of domain "<<p->qdomain<<" from "<<p->getRemote()<<" to "<<*j<<endl;
dad0736b
RC
866 Communicator.notify(p->qdomain,*j);
867 }
868 }
869
870 if(::arg().mustDo("slave"))
871 Communicator.addSlaveCheckRequest(di, p->d_remote);
7f3d870e 872 return 0;
12c86877
BH
873}
874
1d563353
KM
875bool validDNSName(const DNSName &name)
876{
fc41a1a6
KM
877 if (!g_8bitDNS) {
878 string::size_type pos, length;
879 char c;
880 for(const auto& s : name.getRawLabels()) {
881 length=s.length();
882 for(pos=0; pos < length; ++pos) {
883 c=s[pos];
884 if(!((c >= 'a' && c <= 'z') ||
885 (c >= 'A' && c <= 'Z') ||
886 (c >= '0' && c <= '9') ||
887 c =='-' || c == '_' || c=='*' || c=='.' || c=='/' || c=='@' || c==' ' || c=='\\' || c==':'))
888 return false;
889 }
1d563353
KM
890 }
891 }
892 return true;
893}
894
12c86877
BH
895DNSPacket *PacketHandler::question(DNSPacket *p)
896{
5704e107
PD
897 DNSPacket *ret;
898
899 if(d_pdl)
900 {
901 ret=d_pdl->prequery(p);
902 if(ret)
903 return ret;
904 }
905
bb6e54fe 906 if(p->d.rd) {
1566533a 907 static AtomicCounter &rdqueries=*S.getPointer("rd-queries");
bb6e54fe 908 rdqueries++;
909 }
910
da286f66 911 return doQuestion(p);
ff76e8b4
BH
912}
913
90ba52e0 914
675fa24c 915void PacketHandler::makeNXDomain(DNSPacket* p, DNSPacket* r, const DNSName& target, const DNSName& wildcard, SOAData& sd)
35fe50c3 916{
90ba52e0 917 DNSZoneRecord rr;
918 rr.dr.d_name=sd.qname;
919 rr.dr.d_type=QType::SOA;
920
921 rr.dr.d_content=makeSOAContent(sd);
922 rr.dr.d_ttl=min(sd.ttl, sd.default_ttl);
794c2f92 923 rr.signttl=sd.ttl;
35fe50c3 924 rr.domain_id=sd.domain_id;
90ba52e0 925 rr.dr.d_place=DNSResourceRecord::AUTHORITY;
0957a99f 926 rr.auth = 1;
af7d3ea6 927 rr.scopeMask = sd.scopeMask;
35fe50c3 928 r->addRecord(rr);
6865d5c0 929
52e0d783 930 if(d_dk.isSecuredZone(sd.qname))
c5c4fbdc 931 addNSECX(p, r, target, wildcard, sd.qname, 4);
6865d5c0
KM
932
933 r->setRcode(RCode::NXDomain);
35fe50c3
BH
934}
935
675fa24c 936void PacketHandler::makeNOError(DNSPacket* p, DNSPacket* r, const DNSName& target, const DNSName& wildcard, SOAData& sd, int mode)
35fe50c3 937{
90ba52e0 938 DNSZoneRecord rr;
939 rr.dr.d_name=sd.qname;
940 rr.dr.d_type=QType::SOA;
941 rr.dr.d_content=makeSOAContent(sd);
942 rr.dr.d_ttl=sd.ttl;
943 rr.dr.d_ttl=min(sd.ttl, sd.default_ttl);
794c2f92 944 rr.signttl=sd.ttl;
35fe50c3 945 rr.domain_id=sd.domain_id;
90ba52e0 946 rr.dr.d_place=DNSResourceRecord::AUTHORITY;
bccefefa 947 rr.auth = 1;
35fe50c3 948 r->addRecord(rr);
ed9c3a50 949
52e0d783 950 if(d_dk.isSecuredZone(sd.qname))
c5c4fbdc 951 addNSECX(p, r, target, wildcard, sd.qname, mode);
9951e2d0 952
74f6d6e1 953 S.ringAccount("noerror-queries",p->qdomain.toLogString()+"/"+p->qtype.getName());
35fe50c3
BH
954}
955
956
675fa24c 957bool PacketHandler::addDSforNS(DNSPacket* p, DNSPacket* r, SOAData& sd, const DNSName& dsname)
35fe50c3 958{
e4090157 959 //cerr<<"Trying to find a DS for '"<<dsname<<"', domain_id = "<<sd.domain_id<<endl;
35fe50c3 960 B.lookup(QType(QType::DS), dsname, p, sd.domain_id);
90ba52e0 961 DNSZoneRecord rr;
35fe50c3
BH
962 bool gotOne=false;
963 while(B.get(rr)) {
964 gotOne=true;
90ba52e0 965 rr.dr.d_place = DNSResourceRecord::AUTHORITY;
35fe50c3
BH
966 r->addRecord(rr);
967 }
968 return gotOne;
969}
970
675fa24c 971bool PacketHandler::tryReferral(DNSPacket *p, DNSPacket*r, SOAData& sd, const DNSName &target, bool retargeted)
35fe50c3 972{
90ba52e0 973 vector<DNSZoneRecord> rrset = getBestReferralNS(p, sd, target);
35fe50c3
BH
974 if(rrset.empty())
975 return false;
976
424b92c6 977 for(auto& rr: rrset) {
90ba52e0 978 rr.dr.d_place=DNSResourceRecord::AUTHORITY;
35fe50c3
BH
979 r->addRecord(rr);
980 }
d2323cd0
PD
981 if(!retargeted)
982 r->setA(false);
35fe50c3 983
90ba52e0 984 if(d_dk.isSecuredZone(sd.qname) && !addDSforNS(p, r, sd, rrset.begin()->dr.d_name))
985 addNSECX(p, r, rrset.begin()->dr.d_name, DNSName(), sd.qname, 1);
35fe50c3
BH
986
987 return true;
988}
989
675fa24c 990void PacketHandler::completeANYRecords(DNSPacket *p, DNSPacket*r, SOAData& sd, const DNSName &target)
35fe50c3
BH
991{
992 if(!p->d_dnssecOk)
df554502 993 return; // Don't send dnssec info to non validating resolvers.
52e0d783 994
d3e7090c 995 if(!d_dk.isSecuredZone(sd.qname))
fbcdac7e 996 return;
f889ab99 997
290a083d 998 addNSECX(p, r, target, DNSName(), sd.qname, 5);
e325f20c 999 if(sd.qname == p->qdomain) {
794c2f92 1000 addDNSKEY(p, r, sd);
f889ab99 1001 addCDNSKEY(p, r, sd);
ef542223 1002 addCDS(p, r, sd);
794c2f92 1003 addNSEC3PARAM(p, r, sd);
70b18120 1004 }
35fe50c3
BH
1005}
1006
675fa24c 1007bool PacketHandler::tryDNAME(DNSPacket *p, DNSPacket*r, SOAData& sd, DNSName &target)
8dee0750 1008{
1009 if(!d_doDNAME)
1010 return false;
e6a9dde5 1011 DLOG(g_log<<Logger::Warning<<"Let's try DNAME.."<<endl);
90ba52e0 1012 vector<DNSZoneRecord> rrset = getBestDNAMESynth(p, sd, target);
8dee0750 1013 if(!rrset.empty()) {
424b92c6 1014 for(auto& rr: rrset) {
90ba52e0 1015 rr.dr.d_place = DNSResourceRecord::ANSWER;
8dee0750 1016 r->addRecord(rr);
1017 }
1018 return true;
1019 }
1020 return false;
1021}
675fa24c 1022bool PacketHandler::tryWildcard(DNSPacket *p, DNSPacket*r, SOAData& sd, DNSName &target, DNSName &wildcard, bool& retargeted, bool& nodata)
35fe50c3 1023{
e3f388cd 1024 retargeted = nodata = false;
561434a6 1025 DNSName bestmatch;
35fe50c3 1026
90ba52e0 1027 vector<DNSZoneRecord> rrset;
75a89ce6 1028 if(!getBestWildcard(p, sd, target, wildcard, &rrset))
35fe50c3
BH
1029 return false;
1030
e3f388cd 1031 if(rrset.empty()) {
e6a9dde5 1032 DLOG(g_log<<"Wildcard matched something, but not of the correct type"<<endl);
e3f388cd
BH
1033 nodata=true;
1034 }
1035 else {
424b92c6 1036 for(auto& rr: rrset) {
90ba52e0 1037 rr.wildcardname = rr.dr.d_name;
1038 rr.dr.d_name=bestmatch=target;
bcb8aebe 1039
90ba52e0 1040 if(rr.dr.d_type == QType::CNAME) {
e3f388cd 1041 retargeted=true;
90ba52e0 1042 target=getRR<CNAMERecordContent>(rr.dr)->getTarget();
e3f388cd
BH
1043 }
1044
90ba52e0 1045 rr.dr.d_place=DNSResourceRecord::ANSWER;
e3f388cd 1046 r->addRecord(rr);
35fe50c3 1047 }
35fe50c3 1048 }
52e0d783 1049 if(d_dk.isSecuredZone(sd.qname) && !nodata) {
c5c4fbdc 1050 addNSECX(p, r, bestmatch, wildcard, sd.qname, 3);
35fe50c3
BH
1051 }
1052 return true;
1053}
1054
ff76e8b4 1055//! Called by the Distributor to ask a question. Returns 0 in case of an error
e89efca5 1056DNSPacket *PacketHandler::doQuestion(DNSPacket *p)
ff76e8b4 1057{
90ba52e0 1058 DNSZoneRecord rr;
12c86877 1059 SOAData sd;
81c486ad 1060
12c86877 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 1072 if(d_logDNSDetails)
e6a9dde5 1073 g_log<<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)
e6a9dde5 1081 g_log<<Logger::Error<<"Received truncated query packet from "<<p->getRemote()<<", dropping"<<endl;
43b50405
CH
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 1100 if(d_logDNSDetails)
e6a9dde5 1101 g_log<<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)) {
e6a9dde5 1113 g_log<<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)
e6a9dde5 1134 g_log<<Logger::Error<<"Received a malformed qdomain from "<<p->getRemote()<<", '"<<p->qdomain<<"': sending servfail"<<endl;
1d563353
KM
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
e6a9dde5 1165 g_log<<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
e6a9dde5 1171 // g_log<<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++?
e6a9dde5 1208 g_log<<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)) {
e6a9dde5 1216 DLOG(g_log<<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 }
e6a9dde5 1223 DLOG(g_log<<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;
13f9e280 1254 sd.serial = calculateEditSOA(sd.serial, d_dk, sd.qname);
90ba52e0 1255 rr.dr.d_content=makeSOAContent(sd);
1256 rr.dr.d_ttl=sd.ttl;
507823d1 1257 rr.domain_id=sd.domain_id;
90ba52e0 1258 rr.dr.d_place=DNSResourceRecord::ANSWER;
d24589bc 1259 rr.auth = true;
507823d1
BH
1260 r->addRecord(rr);
1261 goto sendit;
1262 }
12c86877 1263
35fe50c3 1264 // this TRUMPS a cname!
52e0d783 1265 if(p->qtype.getCode() == QType::NSEC && d_dk.isSecuredZone(sd.qname) && !d_dk.getNSEC3PARAM(sd.qname, 0)) {
290a083d 1266 addNSEC(p, r, target, DNSName(), sd.qname, 5);
7cd99296
KM
1267 if (!r->isEmpty())
1268 goto sendit;
12c86877 1269 }
571726e9 1270
35fe50c3 1271 // this TRUMPS a cname!
ec62f3c0 1272 if(p->qtype.getCode() == QType::RRSIG) {
e6a9dde5 1273 g_log<<Logger::Info<<"Direct RRSIG query for "<<target<<" from "<<p->getRemote()<<endl;
8d7543ba 1274 r->setRcode(RCode::Refused);
52e0d783 1275 goto sendit;
cac7e485 1276 }
35fe50c3 1277
e6a9dde5 1278 DLOG(g_log<<"Checking for referrals first, unless this is a DS query"<<endl);
d2323cd0 1279 if(p->qtype.getCode() != QType::DS && tryReferral(p, r, sd, target, retargetcount))
571726e9
PD
1280 goto sendit;
1281
e6a9dde5 1282 DLOG(g_log<<"Got no referrals, trying ANY"<<endl);
571726e9 1283
35fe50c3
BH
1284 // see what we get..
1285 B.lookup(QType(QType::ANY), target, p, sd.domain_id);
1286 rrset.clear();
561434a6 1287 haveAlias.trimToLabels(0);
8dee0750 1288 weDone = weRedirected = weHaveUnauth = false;
35fe50c3
BH
1289
1290 while(B.get(rr)) {
1fda8e87 1291 //cerr<<"got content: ["<<rr.content<<"]"<<endl;
90ba52e0 1292 if (p->qtype.getCode() == QType::ANY && !p->d_dnssecOk && (rr.dr.d_type == QType:: DNSKEY || rr.dr.d_type == QType::NSEC3PARAM))
65538369 1293 continue; // Don't send dnssec info to non validating resolvers.
90ba52e0 1294 if (rr.dr.d_type == QType::RRSIG) // RRSIGS are added later any way.
65538369 1295 continue; // TODO: this actually means addRRSig should check if the RRSig is already there
794c2f92 1296
90ba52e0 1297 // cerr<<"Auth: "<<rr.auth<<", "<<(rr.dr.d_type == p->qtype)<<", "<<rr.dr.d_type.getName()<<endl;
1298 if((p->qtype.getCode() == QType::ANY || rr.dr.d_type == p->qtype.getCode()) && rr.auth)
82cc1f71 1299 weDone=1;
5b739515 1300 // the line below fakes 'unauth NS' for delegations for non-DNSSEC backends.
90ba52e0 1301 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 1302 weHaveUnauth=1;
35fe50c3 1303
90ba52e0 1304 if(rr.dr.d_type == QType::CNAME && p->qtype.getCode() != QType::CNAME)
82cc1f71 1305 weRedirected=1;
1dfd8ada 1306
90ba52e0 1307 if(DP && rr.dr.d_type == QType::ALIAS && (p->qtype.getCode() == QType::A || p->qtype.getCode() == QType::AAAA || p->qtype.getCode() == QType::ANY)) {
389b7a05 1308 if (!d_doExpandALIAS) {
e6a9dde5 1309 g_log<<Logger::Info<<"ALIAS record found for "<<target<<", but ALIAS expansion is disabled."<<endl;
389b7a05
PL
1310 continue;
1311 }
90ba52e0 1312 haveAlias=getRR<ALIASRecordContent>(rr.dr)->d_content;
d59b894d 1313 }
1314
1dfd8ada 1315 // Filter out all SOA's and add them in later
90ba52e0 1316 if(rr.dr.d_type == QType::SOA)
1dfd8ada
MZ
1317 continue;
1318
35fe50c3 1319 rrset.push_back(rr);
12c86877
BH
1320 }
1321
1dfd8ada 1322 /* Add in SOA if required */
e325f20c 1323 if(target==sd.qname) {
13f9e280 1324 rr.dr.d_name = sd.qname;
90ba52e0 1325 rr.dr.d_type = QType::SOA;
13f9e280 1326 sd.serial = calculateEditSOA(sd.serial, d_dk, sd.qname);
90ba52e0 1327 rr.dr.d_content = makeSOAContent(sd);
90ba52e0 1328 rr.dr.d_ttl = sd.ttl;
1dfd8ada
MZ
1329 rr.domain_id = sd.domain_id;
1330 rr.auth = true;
1331 rrset.push_back(rr);
1332 }
1333
8dee0750 1334
e6a9dde5 1335 DLOG(g_log<<"After first ANY query for '"<<target<<"', id="<<sd.domain_id<<": weDone="<<weDone<<", weHaveUnauth="<<weHaveUnauth<<", weRedirected="<<weRedirected<<", haveAlias='"<<haveAlias<<"'"<<endl);
849bd7f1 1336 if(p->qtype.getCode() == QType::DS && weHaveUnauth && !weDone && !weRedirected && d_dk.isSecuredZone(sd.qname)) {
e6a9dde5 1337 DLOG(g_log<<"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 1338 makeNOError(p, r, target, DNSName(), sd, 1);
849bd7f1
BH
1339 goto sendit;
1340 }
12c86877 1341
65d2032b 1342 if(!haveAlias.empty() && (!weDone || p->qtype.getCode() == QType::ANY)) {
e6a9dde5 1343 DLOG(g_log<<Logger::Warning<<"Found nothing that matched for '"<<target<<"', but did get alias to '"<<haveAlias<<"', referring"<<endl);
d59b894d 1344 DP->completePacket(r, haveAlias, target);
1345 return 0;
1346 }
1347
35fe50c3 1348 if(rrset.empty()) {
e6a9dde5 1349 DLOG(g_log<<"checking qtype.getCode() ["<<(p->qtype.getCode())<<"] against QType::DS ["<<(QType::DS)<<"]"<<endl);
0a0f4112
PD
1350 if(p->qtype.getCode() == QType::DS)
1351 {
e6a9dde5 1352 DLOG(g_log<<"DS query found no direct result, trying referral now"<<endl);
d2323cd0 1353 if(tryReferral(p, r, sd, target, retargetcount))
0a0f4112 1354 {
e6a9dde5 1355 DLOG(g_log<<"got referral for DS query"<<endl);
0a0f4112
PD
1356 goto sendit;
1357 }
1358 }
1359
d59b894d 1360
e6a9dde5 1361 DLOG(g_log<<Logger::Warning<<"Found nothing in the by-name ANY, but let's try wildcards.."<<endl);
e3f388cd 1362 bool wereRetargeted(false), nodata(false);
561434a6 1363 DNSName wildcard;
75a89ce6 1364 if(tryWildcard(p, r, sd, target, wildcard, wereRetargeted, nodata)) {
82cc1f71 1365 if(wereRetargeted) {
3e8216c8 1366 if(!retargetcount) r->qdomainwild=wildcard;
82cc1f71
BH
1367 retargetcount++;
1368 goto retargeted;
1369 }
c5c4fbdc
PD
1370 if(nodata)
1371 makeNOError(p, r, target, wildcard, sd, 2);
1372
82cc1f71 1373 goto sendit;
8e50cd4c 1374 }
8dee0750 1375 else if(tryDNAME(p, r, sd, target)) {
1376 retargetcount++;
1377 goto retargeted;
1378 }
a87b7e3f
PD
1379 else
1380 {
c5c4fbdc
PD
1381 if (!(((p->qtype.getCode() == QType::CNAME) || (p->qtype.getCode() == QType::ANY)) && retargetcount > 0))
1382 makeNXDomain(p, r, target, wildcard, sd);
a87b7e3f
PD
1383 }
1384
82cc1f71
BH
1385 goto sendit;
1386 }
232f0877 1387
35fe50c3 1388 if(weRedirected) {
2010ac95
RG
1389 for(auto& loopRR: rrset) {
1390 if(loopRR.dr.d_type == QType::CNAME) {
1391 r->addRecord(loopRR);
1392 target = getRR<CNAMERecordContent>(loopRR.dr)->getTarget();
82cc1f71
BH
1393 retargetcount++;
1394 goto retargeted;
4957a608 1395 }
82cc1f71 1396 }
82cc1f71 1397 }
35fe50c3 1398 else if(weDone) {
b5baefaf 1399 bool haveRecords = false;
2010ac95
RG
1400 for(const auto& loopRR: rrset) {
1401 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) {
1402 r->addRecord(loopRR);
b5baefaf
PD
1403 haveRecords = true;
1404 }
82cc1f71 1405 }
4957a608 1406
b5baefaf
PD
1407 if (haveRecords) {
1408 if(p->qtype.getCode() == QType::ANY)
1409 completeANYRecords(p, r, sd, target);
82cc1f71 1410 }
b5baefaf 1411 else
b9817f2b 1412 makeNOError(p, r, target, DNSName(), sd, 0);
4957a608 1413
35fe50c3 1414 goto sendit;
82cc1f71 1415 }
35fe50c3 1416 else if(weHaveUnauth) {
e6a9dde5 1417 DLOG(g_log<<"Have unauth data, so need to hunt for best NS records"<<endl);
d2323cd0 1418 if(tryReferral(p, r, sd, target, retargetcount))
82cc1f71 1419 goto sendit;
2b18bcf3 1420 // check whether this could be fixed easily
90ba52e0 1421 // if (*(rr.dr.d_name.rbegin()) == '.') {
e6a9dde5 1422 // g_log<<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 1423 // } else {
e6a9dde5 1424 g_log<<Logger::Error<<"Should not get here ("<<p->qdomain<<"|"<<p->qtype.getCode()<<"): please run pdnsutil rectify-zone "<<sd.qname<<endl;
561434a6 1425 // }
82cc1f71
BH
1426 }
1427 else {
e6a9dde5 1428 DLOG(g_log<<"Have some data, but not the right data"<<endl);
290a083d 1429 makeNOError(p, r, target, DNSName(), sd, 0);
82cc1f71 1430 }
12c86877
BH
1431
1432 sendit:;
d2323cd0 1433 if(doAdditionalProcessingAndDropAA(p, r, sd, retargetcount)<0) {
f3a91936 1434 delete r;
12c86877 1435 return 0;
f3a91936 1436 }
8ea10bfc 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) {
e6a9dde5 1452 g_log<<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) {
e6a9dde5 1460 g_log<<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) {
e6a9dde5 1464 g_log<<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}