]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/packethandler.cc
rec: Only log qname parsing errors when 'log-common-errors' is set
[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;
c3491dd6 334 rr.dr.d_content = std::make_shared<CNAMERecordContent>(CNAMERecordContent(prefix + getRR<DNAMERecordContent>(rr.dr)->getTarget()));
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
8900e2e3 359#ifdef HAVE_LUA_RECORDS
cb6bd1a9 360 bool doLua=g_doLuaRecord;
25bcfaec 361 if(!doLua) {
362 string val;
27a630b4 363 d_dk.getFromMeta(sd.qname, "ENABLE-LUA-RECORDS", val);
25bcfaec 364 doLua = (val=="1");
365 }
8900e2e3 366#endif
25bcfaec 367
75a89ce6 368 wildcard=subdomain;
675fa24c 369 while( subdomain.chopOff() && !haveSomething ) {
598b152c 370 if (subdomain.empty()) {
12c06211 371 B.lookup(QType(QType::ANY), g_wildcarddnsname, p, sd.domain_id);
598b152c 372 } else {
12c06211 373 B.lookup(QType(QType::ANY), g_wildcarddnsname+subdomain, p, sd.domain_id);
598b152c 374 }
35fe50c3 375 while(B.get(rr)) {
8900e2e3 376#ifdef HAVE_LUA_RECORDS
b7edebf8 377 if(rr.dr.d_type == QType::LUA) {
25bcfaec 378 if(!doLua) {
f5f3d7f5 379 DLOG(g_log<<"Have a wildcard LUA match, but not doing LUA record for this zone"<<endl);
25bcfaec 380 continue;
381 }
382
f5f3d7f5 383 DLOG(g_log<<"Have a wildcard LUA match"<<endl);
25bcfaec 384
b7edebf8 385 auto rec=getRR<LUARecordContent>(rr.dr);
98fa3598
RG
386 if (!rec) {
387 continue;
388 }
389 if(rec->d_type == QType::CNAME || rec->d_type == p->qtype.getCode() || (p->qtype.getCode() == QType::ANY && rec->d_type != QType::RRSIG)) {
b7edebf8 390 // noCache=true;
f5f3d7f5 391 DLOG(g_log<<"Executing Lua: '"<<rec->getCode()<<"'"<<endl);
cc5c4f6b
CHB
392 auto recvec=luaSynth(rec->getCode(), target, sd.qname, sd.domain_id, *p, rec->d_type);
393 for(const auto& r : recvec) {
394 rr.dr.d_type = rec->d_type; // might be CNAME
395 rr.dr.d_content = r;
396 rr.scopeMask = p->getRealRemote().getBits(); // this makes sure answer is a specific as your question
397 ret->push_back(rr);
b7edebf8 398 }
399 }
400 }
8900e2e3
CHB
401 else
402#endif
403 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 404 ret->push_back(rr);
8900e2e3 405 }
b7edebf8 406
12c06211 407 wildcard=g_wildcarddnsname+subdomain;
e3f388cd 408 haveSomething=true;
35fe50c3 409 }
75a89ce6
PD
410
411 if ( subdomain == sd.qname || haveSomething ) // stop at SOA or result
82cc1f71 412 break;
35fe50c3 413
75a89ce6
PD
414 B.lookup(QType(QType::ANY), subdomain, p, sd.domain_id);
415 if (B.get(rr)) {
e6a9dde5 416 DLOG(g_log<<"No wildcard match, ancestor exists"<<endl);
75a89ce6
PD
417 while (B.get(rr)) ;
418 break;
419 }
420 wildcard=subdomain;
421 }
422
423 return haveSomething;
35fe50c3
BH
424}
425
12c86877 426/** dangling is declared true if we were unable to resolve everything */
d2323cd0 427int PacketHandler::doAdditionalProcessingAndDropAA(DNSPacket *p, DNSPacket *r, const SOAData& soadata, bool retargeted)
12c86877 428{
90ba52e0 429 DNSZoneRecord rr;
fd8bc993 430 SOAData sd;
313923a8 431 sd.db=0;
b636533b 432
b8e0f341 433 if(p->qtype.getCode()!=QType::AXFR) { // this packet needs additional processing
aa7b2405 434 // we now have a copy, push_back on packet might reallocate!
435 auto& records = r->getRRS();
436 vector<DNSZoneRecord> toAdd;
8513f025 437
aa7b2405 438 for(auto i = records.cbegin() ; i!= records.cend(); ++i) {
439 if(i->dr.d_place==DNSResourceRecord::ADDITIONAL ||
440 !(i->dr.d_type==QType::MX || i->dr.d_type==QType::NS || i->dr.d_type==QType::SRV))
441 continue;
8513f025 442
94bfa5b6 443 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 444 r->setA(false);
232f0877 445 // i->d_place=DNSResourceRecord::AUTHORITY; // XXX FIXME
f6ba332a 446 }
fd8bc993 447
90ba52e0 448 DNSName lookup;
449
450 if(i->dr.d_type == QType::MX)
451 lookup = getRR<MXRecordContent>(i->dr)->d_mxname;
452 else if(i->dr.d_type == QType::SRV)
453 lookup = getRR<SRVRecordContent>(i->dr)->d_target;
aa7b2405 454 else if(i->dr.d_type == QType::NS)
455 lookup = getRR<NSRecordContent>(i->dr)->getNS();
456 else
457 continue;
75676790 458
137d738a 459 B.lookup(QType(d_doIPv6AdditionalProcessing ? QType::ANY : QType::A), lookup, p, soadata.domain_id);
794c2f92 460
0ece3f09 461 while(B.get(rr)) {
90ba52e0 462 if(rr.dr.d_type != QType::A && rr.dr.d_type!=QType::AAAA)
0ece3f09 463 continue;
87c261bc
PL
464 if(!rr.dr.d_name.isPartOf(soadata.qname)) {
465 // FIXME we might still pass on the record if it is occluded and the
466 // backend uses a single id for all zones
467 continue;
468 }
90ba52e0 469 rr.dr.d_place=DNSResourceRecord::ADDITIONAL;
aa7b2405 470 toAdd.push_back(rr);
b636533b 471 }
12c86877 472 }
336f11d8 473 for(const auto& rec : toAdd)
474 r->addRecord(rec);
475
476 //records.insert(records.end(), toAdd.cbegin(), toAdd.cend()); // would be faster, but no dedup
12c86877
BH
477 }
478 return 1;
479}
480
35fe50c3 481
ca617317 482void PacketHandler::emitNSEC(DNSPacket *r, const SOAData& sd, const DNSName& name, const DNSName& next, int mode)
35fe50c3 483{
35fe50c3 484 NSECRecordContent nrc;
ca617317
KM
485 nrc.d_next = next;
486
27d4a65b
RG
487 nrc.set(QType::NSEC);
488 nrc.set(QType::RRSIG);
576e7e0f 489 if(sd.qname == name) {
27d4a65b
RG
490 nrc.set(QType::SOA); // 1dfd8ad SOA can live outside the records table
491 nrc.set(QType::DNSKEY);
088370cd 492 string publishCDNSKEY;
0900d2d3 493 d_dk.getFromMeta(name, "PUBLISH-CDNSKEY", publishCDNSKEY);
088370cd 494 if (publishCDNSKEY == "1")
27d4a65b 495 nrc.set(QType::CDNSKEY);
ef542223 496 string publishCDS;
0900d2d3 497 d_dk.getFromMeta(name, "PUBLISH-CDS", publishCDS);
ef542223 498 if (! publishCDS.empty())
27d4a65b 499 nrc.set(QType::CDS);
576e7e0f 500 }
35fe50c3 501
90ba52e0 502 DNSZoneRecord rr;
576e7e0f 503
ca617317 504 B.lookup(QType(QType::ANY), name, NULL, sd.domain_id);
35fe50c3 505 while(B.get(rr)) {
8900e2e3 506#ifdef HAVE_LUA_RECORDS
d0c7ecf1 507 if(rr.dr.d_type == QType::LUA)
27d4a65b 508 nrc.set(getRR<LUARecordContent>(rr.dr)->d_type);
8900e2e3
CHB
509 else
510#endif
511 if(rr.dr.d_type == QType::NS || rr.auth)
27d4a65b 512 nrc.set(rr.dr.d_type);
35fe50c3 513 }
50eb4144 514
90ba52e0 515 rr.dr.d_name = name;
516 rr.dr.d_ttl = sd.default_ttl;
517 rr.dr.d_type = QType::NSEC;
27d4a65b 518 rr.dr.d_content = std::make_shared<NSECRecordContent>(std::move(nrc));
90ba52e0 519 rr.dr.d_place = (mode == 5 ) ? DNSResourceRecord::ANSWER: DNSResourceRecord::AUTHORITY;
35fe50c3 520 rr.auth = true;
50eb4144 521
35fe50c3
BH
522 r->addRecord(rr);
523}
524
576e7e0f 525void PacketHandler::emitNSEC3(DNSPacket *r, const SOAData& sd, const NSEC3PARAMRecordContent& ns3prc, const DNSName& name, const string& namehash, const string& nexthash, int mode)
5c3bf2db 526{
5c3bf2db 527 NSEC3RecordContent n3rc;
576e7e0f 528 n3rc.d_algorithm = ns3prc.d_algorithm;
b9dba5c1 529 n3rc.d_flags = ns3prc.d_flags;
c3c89361 530 n3rc.d_iterations = ns3prc.d_iterations;
576e7e0f
KM
531 n3rc.d_salt = ns3prc.d_salt;
532 n3rc.d_nexthash = nexthash;
5c3bf2db 533
90ba52e0 534 DNSZoneRecord rr;
c3c89361 535
576e7e0f
KM
536 if(!name.empty()) {
537 if (sd.qname == name) {
27d4a65b
RG
538 n3rc.set(QType::SOA); // 1dfd8ad SOA can live outside the records table
539 n3rc.set(QType::NSEC3PARAM);
540 n3rc.set(QType::DNSKEY);
088370cd 541 string publishCDNSKEY;
0900d2d3 542 d_dk.getFromMeta(name, "PUBLISH-CDNSKEY", publishCDNSKEY);
088370cd 543 if (publishCDNSKEY == "1")
27d4a65b 544 n3rc.set(QType::CDNSKEY);
ef542223 545 string publishCDS;
0900d2d3 546 d_dk.getFromMeta(name, "PUBLISH-CDS", publishCDS);
ef542223 547 if (! publishCDS.empty())
27d4a65b 548 n3rc.set(QType::CDS);
b5baefaf 549 }
576e7e0f
KM
550
551 B.lookup(QType(QType::ANY), name, NULL, sd.domain_id);
552 while(B.get(rr)) {
8900e2e3 553#ifdef HAVE_LUA_RECORDS
d0c7ecf1 554 if(rr.dr.d_type == QType::LUA)
27d4a65b 555 n3rc.set(getRR<LUARecordContent>(rr.dr)->d_type);
8900e2e3
CHB
556 else
557#endif
558 if(rr.dr.d_type && (rr.dr.d_type == QType::NS || rr.auth)) // skip empty non-terminals
27d4a65b 559 n3rc.set(rr.dr.d_type);
576e7e0f 560 }
c3c89361 561 }
b5baefaf 562
27d4a65b
RG
563 const auto numberOfTypesSet = n3rc.numberOfTypesSet();
564 if (numberOfTypesSet != 0 && !(numberOfTypesSet == 1 && n3rc.isSet(QType::NS))) {
565 n3rc.set(QType::RRSIG);
566 }
50eb4144 567
90ba52e0 568 rr.dr.d_name = DNSName(toBase32Hex(namehash))+sd.qname;
569 rr.dr.d_ttl = sd.default_ttl;
570 rr.dr.d_type=QType::NSEC3;
27d4a65b 571 rr.dr.d_content=std::make_shared<NSEC3RecordContent>(std::move(n3rc));
90ba52e0 572 rr.dr.d_place = (mode == 5 ) ? DNSResourceRecord::ANSWER: DNSResourceRecord::AUTHORITY;
5c3bf2db 573 rr.auth = true;
50eb4144 574
5c3bf2db
BH
575 r->addRecord(rr);
576}
577
75a89ce6
PD
578/*
579 mode 0 = No Data Responses, QTYPE is not DS
b5baefaf 580 mode 1 = No Data Responses, QTYPE is DS
75a89ce6
PD
581 mode 2 = Wildcard No Data Responses
582 mode 3 = Wildcard Answer Responses
583 mode 4 = Name Error Responses
dcb8c5d7 584 mode 5 = Direct NSEC request
35fe50c3 585*/
675fa24c 586void PacketHandler::addNSECX(DNSPacket *p, DNSPacket *r, const DNSName& target, const DNSName& wildcard, const DNSName& auth, int mode)
01fde57c 587{
c3c89361 588 NSEC3PARAMRecordContent ns3rc;
22c5aa60
BH
589 bool narrow;
590 if(d_dk.getNSEC3PARAM(auth, &ns3rc, &narrow)) {
d31e9b23 591 if (mode != 5) // no direct NSEC3 queries, rfc5155 7.2.8
dcb8c5d7 592 addNSEC3(p, r, target, wildcard, auth, ns3rc, narrow, mode);
9b30cd1a
BH
593 }
594 else {
c5c4fbdc 595 addNSEC(p, r, target, wildcard, auth, mode);
9b30cd1a 596 }
01fde57c
BH
597}
598
29e0008a 599bool 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
600{
601 bool ret;
602 if(narrow) { // nsec3-narrow
603 ret=true;
604 before=hashed;
b5baefaf 605 if(decrement) {
af3ffdf1 606 decrementHash(before);
b5baefaf
PD
607 unhashed.clear();
608 }
22c5aa60
BH
609 after=hashed;
610 incrementHash(after);
611 }
612 else {
29e0008a
KM
613 DNSName hashedName = DNSName(toBase32Hex(hashed));
614 DNSName beforeName, afterName;
615 if (!decrement && mode >= 2)
616 beforeName = hashedName;
617 ret=db->getBeforeAndAfterNamesAbsolute(id, hashedName, unhashed, beforeName, afterName);
618 before=fromBase32Hex(beforeName.toString());
619 after=fromBase32Hex(afterName.toString());
22c5aa60 620 }
22c5aa60
BH
621 return ret;
622}
623
561434a6 624void PacketHandler::addNSEC3(DNSPacket *p, DNSPacket *r, const DNSName& target, const DNSName& wildcard, const DNSName& auth, const NSEC3PARAMRecordContent& ns3rc, bool narrow, int mode)
01fde57c 625{
e6a9dde5 626 DLOG(g_log<<"addNSEC3() mode="<<mode<<" auth="<<auth<<" target="<<target<<" wildcard="<<wildcard<<endl);
53977f80 627
5c3bf2db 628 SOAData sd;
79ba7763 629 if(!B.getSOAUncached(auth, sd)) {
e6a9dde5 630 DLOG(g_log<<"Could not get SOA for domain");
5c3bf2db
BH
631 return;
632 }
53977f80 633
3a741d7f 634 bool doNextcloser = false;
561434a6
PD
635 string before, after, hashed;
636 DNSName unhashed, closest;
53977f80 637
75a89ce6 638 if (mode == 2 || mode == 3 || mode == 4) {
f0306634 639 closest=wildcard;
561434a6 640 closest.chopOff();
f0306634
KM
641 } else
642 closest=target;
53977f80 643
75a89ce6 644 // add matching NSEC3 RR
b50efd61 645 if (mode != 3) {
3a741d7f 646 unhashed=(mode == 0 || mode == 1 || mode == 5) ? target : closest;
28e2e78e 647 hashed=hashQNameWithSalt(ns3rc, unhashed);
e6a9dde5 648 DLOG(g_log<<"1 hash: "<<toBase32Hex(hashed)<<" "<<unhashed<<endl);
53977f80 649
15c9bf3b 650 getNSEC3Hashes(narrow, sd.db, sd.domain_id, hashed, false, unhashed, before, after, mode);
3a741d7f 651
2e9c8710 652 if (((mode == 0 && ns3rc.d_flags) || mode == 1) && (hashed != before)) {
e6a9dde5 653 DLOG(g_log<<"No matching NSEC3, do closest (provable) encloser"<<endl);
3a741d7f 654
54c9247e 655 bool doBreak = false;
90ba52e0 656 DNSZoneRecord rr;
561434a6 657 while( closest.chopOff() && (closest != sd.qname)) { // stop at SOA
3a741d7f 658 B.lookup(QType(QType::ANY), closest, p, sd.domain_id);
54c9247e
KM
659 while(B.get(rr))
660 if (rr.auth)
661 doBreak = true;
662 if(doBreak)
3a741d7f 663 break;
3a741d7f
KM
664 }
665 doNextcloser = true;
666 unhashed=closest;
28e2e78e 667 hashed=hashQNameWithSalt(ns3rc, unhashed);
e6a9dde5 668 DLOG(g_log<<"1 hash: "<<toBase32Hex(hashed)<<" "<<unhashed<<endl);
3a741d7f 669
15c9bf3b 670 getNSEC3Hashes(narrow, sd.db, sd.domain_id, hashed, false, unhashed, before, after);
3a741d7f
KM
671 }
672
d88babea 673 if (!after.empty()) {
e6a9dde5 674 DLOG(g_log<<"Done calling for matching, hashed: '"<<toBase32Hex(hashed)<<"' before='"<<toBase32Hex(before)<<"', after='"<<toBase32Hex(after)<<"'"<<endl);
576e7e0f 675 emitNSEC3(r, sd, ns3rc, unhashed, before, after, mode);
2010ac95 676 }
16cf9135 677 }
75a89ce6
PD
678
679 // add covering NSEC3 RR
3a741d7f 680 if ((mode >= 2 && mode <= 4) || doNextcloser) {
561434a6 681 DNSName next(target);
75a89ce6
PD
682 do {
683 unhashed=next;
684 }
e325f20c 685 while( next.chopOff() && !(next==closest));
75a89ce6 686
28e2e78e 687 hashed=hashQNameWithSalt(ns3rc, unhashed);
e6a9dde5 688 DLOG(g_log<<"2 hash: "<<toBase32Hex(hashed)<<" "<<unhashed<<endl);
15c9bf3b
KM
689
690 getNSEC3Hashes(narrow, sd.db,sd.domain_id, hashed, true, unhashed, before, after);
e6a9dde5 691 DLOG(g_log<<"Done calling for covering, hashed: '"<<toBase32Hex(hashed)<<"' before='"<<toBase32Hex(before)<<"', after='"<<toBase32Hex(after)<<"'"<<endl);
15c9bf3b 692 emitNSEC3( r, sd, ns3rc, unhashed, before, after, mode);
75a89ce6 693 }
53977f80 694
75a89ce6 695 // wildcard denial
7bb8e202 696 if (mode == 2 || mode == 4) {
12c06211 697 unhashed=g_wildcarddnsname+closest;
75a89ce6 698
28e2e78e 699 hashed=hashQNameWithSalt(ns3rc, unhashed);
e6a9dde5 700 DLOG(g_log<<"3 hash: "<<toBase32Hex(hashed)<<" "<<unhashed<<endl);
53977f80 701
15c9bf3b 702 getNSEC3Hashes(narrow, sd.db, sd.domain_id, hashed, (mode != 2), unhashed, before, after);
e6a9dde5 703 DLOG(g_log<<"Done calling for '*', hashed: '"<<toBase32Hex(hashed)<<"' before='"<<toBase32Hex(before)<<"', after='"<<toBase32Hex(after)<<"'"<<endl);
15c9bf3b 704 emitNSEC3( r, sd, ns3rc, unhashed, before, after, mode);
75a89ce6 705 }
01fde57c 706}
35fe50c3 707
561434a6 708void PacketHandler::addNSEC(DNSPacket *p, DNSPacket *r, const DNSName& target, const DNSName& wildcard, const DNSName& auth, int mode)
35fe50c3 709{
e6a9dde5 710 DLOG(g_log<<"addNSEC() mode="<<mode<<" auth="<<auth<<" target="<<target<<" wildcard="<<wildcard<<endl);
35fe50c3 711
53977f80 712 SOAData sd;
79ba7763 713 if(!B.getSOAUncached(auth, sd)) {
e6a9dde5 714 DLOG(g_log<<"Could not get SOA for domain"<<endl);
35fe50c3
BH
715 return;
716 }
717
561434a6 718 DNSName before,after;
15c9bf3b 719 sd.db->getBeforeAndAfterNames(sd.domain_id, auth, target, before, after);
7cd99296
KM
720 if (mode != 5 || before == target)
721 emitNSEC(r, sd, before, after, mode);
b5baefaf 722
337dd27b
KM
723 if (mode == 2 || mode == 4) {
724 // wildcard NO-DATA or wildcard denial
628ab42d 725 before.clear();
561434a6 726 DNSName closest(wildcard);
337dd27b 727 if (mode == 4) {
561434a6
PD
728 closest.chopOff();
729 closest.prependRawLabel("*");
337dd27b 730 }
15c9bf3b
KM
731 sd.db->getBeforeAndAfterNames(sd.domain_id, auth, closest, before, after);
732 emitNSEC(r, sd, before, after, mode);
75a89ce6 733 }
35fe50c3
BH
734 return;
735}
736
12c86877
BH
737/* Semantics:
738
739- only one backend owns the SOA of a zone
740- only one AXFR per zone at a time - double startTransaction should fail
741- backends need to implement transaction semantics
742
743
744How BindBackend would implement this:
745 startTransaction makes a file
746 feedRecord sends everything to that file
747 commitTransaction moves that file atomically over the regular file, and triggers a reload
748 rollbackTransaction removes the file
749
750
751How PostgreSQLBackend would implement this:
752 startTransaction starts a sql transaction, which also deletes all records
753 feedRecord is an insert statement
754 commitTransaction commits the transaction
755 rollbackTransaction aborts it
756
757How MySQLBackend would implement this:
758 (good question!)
759
760*/
761
6fe866b4 762int PacketHandler::trySuperMaster(DNSPacket *p, const DNSName& tsigkeyname)
7108e055
PD
763{
764 if(p->d_tcp)
765 {
766 // do it right now if the client is TCP
767 // rarely happens
7731e32c 768 return trySuperMasterSynchronous(p, tsigkeyname);
7108e055
PD
769 }
770 else
771 {
772 // queue it if the client is on UDP
773 Communicator.addTrySuperMasterRequest(p);
774 return 0;
775 }
776}
777
02980dc2 778int PacketHandler::trySuperMasterSynchronous(const DNSPacket *p, const DNSName& tsigkeyname)
12c86877 779{
f43e6a40 780 ComboAddress remote = p->getRemote().setPort(53);
d622042f 781 if(p->hasEDNSSubnet() && ::arg().contains("trusted-notification-proxy", remote.toString())) {
782 remote = p->getRealRemote().getNetwork();
a94fe494
RG
783 }
784
12c86877
BH
785 Resolver::res_t nsset;
786 try {
787 Resolver resolver;
092f210a 788 uint32_t theirserial;
d622042f 789 resolver.getSoaSerial(remote, p->qdomain, &theirserial);
a94fe494 790 resolver.resolve(remote, p->qdomain, QType::NS, &nsset);
12c86877
BH
791 }
792 catch(ResolverException &re) {
e6a9dde5 793 g_log<<Logger::Error<<"Error resolving SOA or NS for "<<p->qdomain<<" at: "<< remote <<": "<<re.reason<<endl;
12c86877
BH
794 return RCode::ServFail;
795 }
796
39b23e69
RK
797 // check if the returned records are NS records
798 bool haveNS=false;
424b92c6 799 for(const auto& ns: nsset) {
90ba52e0 800 if(ns.qtype==QType::NS)
39b23e69
RK
801 haveNS=true;
802 }
803
804 if(!haveNS) {
e6a9dde5 805 g_log<<Logger::Error<<"While checking for supermaster, did not find NS for "<<p->qdomain<<" at: "<< remote <<endl;
39b23e69
RK
806 return RCode::ServFail;
807 }
808
719f9024 809 string nameserver, account;
12c86877 810 DNSBackend *db;
771bb0b0
AT
811
812 if (!::arg().mustDo("allow-unsigned-supermaster") && tsigkeyname.empty()) {
e6a9dde5 813 g_log<<Logger::Error<<"Received unsigned NOTIFY for "<<p->qdomain<<" from potential supermaster "<<remote<<". Refusing."<<endl;
771bb0b0
AT
814 return RCode::Refused;
815 }
816
d622042f 817 if(!B.superMasterBackend(remote.toString(), p->qdomain, nsset, &nameserver, &account, &db)) {
e6a9dde5 818 g_log<<Logger::Error<<"Unable to find backend willing to host "<<p->qdomain<<" for potential supermaster "<<remote<<". Remote nameservers: "<<endl;
424b92c6 819 for(const auto& rr: nsset) {
90ba52e0 820 if(rr.qtype==QType::NS)
e6a9dde5 821 g_log<<Logger::Error<<rr.content<<endl;
a7372c6f 822 }
12c86877
BH
823 return RCode::Refused;
824 }
8c80c4f4 825 try {
ded6b08d 826 db->createSlaveDomain(p->getRemote().toString(), p->qdomain, nameserver, account);
7731e32c
AT
827 if (tsigkeyname.empty() == false) {
828 vector<string> meta;
6fe866b4 829 meta.push_back(tsigkeyname.toStringNoDot());
7731e32c
AT
830 db->setDomainMetadata(p->qdomain, "AXFR-MASTER-TSIG", meta);
831 }
8c80c4f4 832 }
3f81d239 833 catch(PDNSException& ae) {
e6a9dde5 834 g_log<<Logger::Error<<"Database error trying to create "<<p->qdomain<<" for potential supermaster "<<remote<<": "<<ae.reason<<endl;
8c80c4f4
BH
835 return RCode::ServFail;
836 }
e6a9dde5 837 g_log<<Logger::Warning<<"Created new slave zone '"<<p->qdomain<<"' from supermaster "<<remote<<endl;
12c86877
BH
838 return RCode::NoError;
839}
840
3777f434 841int PacketHandler::processNotify(DNSPacket *p)
12c86877
BH
842{
843 /* now what?
844 was this notification from an approved address?
c68ab952 845 was this notification approved by TSIG?
12c86877
BH
846 We determine our internal SOA id (via UeberBackend)
847 We determine the SOA at our (known) master
848 if master is higher -> do stuff
849 */
c68ab952 850
1793df78 851 g_log<<Logger::Debug<<"Received NOTIFY for "<<p->qdomain<<" from "<<p->getRemote()<<endl;
c68ab952 852
dad0736b 853 if(!::arg().mustDo("slave") && s_forwardNotify.empty()) {
5b07dc82
KM
854 g_log<<Logger::Warning<<"Received NOTIFY for "<<p->qdomain<<" from "<<p->getRemote()<<" but slave support is disabled in the configuration"<<endl;
855 return RCode::Refused;
12c86877 856 }
d207ad63 857
5b07dc82
KM
858 // Sender verification
859 //
c68ab952 860 if(!s_allowNotifyFrom.match((ComboAddress *) &p->d_remote ) || p->d_havetsig) {
7731e32c 861 if (p->d_havetsig && p->getTSIGKeyname().empty() == false) {
5b07dc82 862 g_log<<Logger::Notice<<"Received secure NOTIFY for "<<p->qdomain<<" from "<<p->getRemote()<<", with TSIG key '"<<p->getTSIGKeyname()<<"'"<<endl;
c68ab952 863 } else {
5b07dc82 864 g_log<<Logger::Warning<<"Received NOTIFY for "<<p->qdomain<<" from "<<p->getRemote()<<" but the remote is not providing a TSIG key or in allow-notify-from (Refused)"<<endl;
c68ab952
AT
865 return RCode::Refused;
866 }
d207ad63
RK
867 }
868
5b07dc82 869 if ((!::arg().mustDo("allow-unsigned-notify") && !p->d_havetsig) || p->d_havetsig) {
2fa2a51a 870 if (!p->d_havetsig) {
5b07dc82
KM
871 g_log<<Logger::Warning<<"Received unsigned NOTIFY for "<<p->qdomain<<" from "<<p->getRemote()<<" while a TSIG key was required (Refused)"<<endl;
872 return RCode::Refused;
873 }
874 vector<string> meta;
875 if (B.getDomainMetadata(p->qdomain,"AXFR-MASTER-TSIG",meta) && meta.size() > 0) {
876 if (!pdns_iequals(meta[0], p->getTSIGKeyname().toStringNoDot())) {
877 g_log<<Logger::Warning<<"Received secure NOTIFY for "<<p->qdomain<<" from "<<p->getRemote()<<": expected TSIG key '"<<meta[0]<<", got '"<<p->getTSIGKeyname()<<"' (Refused)"<<endl;
771bb0b0
AT
878 return RCode::Refused;
879 }
c68ab952
AT
880 }
881 }
882
5b07dc82
KM
883 // Domain verification
884 //
885 DomainInfo di;
ce7dc7e9 886 if(!B.getDomainInfo(p->qdomain, di, false) || !di.backend) {
d3dfd71e 887 if(::arg().mustDo("superslave")) {
b8013977
KM
888 g_log<<Logger::Warning<<"Received NOTIFY for "<<p->qdomain<<" from "<<p->getRemote()<<" for which we are not authoritative, trying supermaster"<<endl;
889 return trySuperMaster(p, p->getTSIGKeyname());
890 }
891 g_log<<Logger::Notice<<"Received NOTIFY for "<<p->qdomain<<" from "<<p->getRemote()<<" for which we are not authoritative (Refused)"<<endl;
892 return RCode::Refused;
5b07dc82
KM
893 }
894
ded6b08d 895 if(::arg().contains("trusted-notification-proxy", p->getRemote().toString())) {
e6a9dde5 896 g_log<<Logger::Error<<"Received NOTIFY for "<<p->qdomain<<" from trusted-notification-proxy "<< p->getRemote()<<endl;
f7fb7022 897 if(di.masters.empty()) {
5b07dc82 898 g_log<<Logger::Error<<"However, "<<p->qdomain<<" does not have any masters defined (Refused)"<<endl;
f7fb7022
BH
899 return RCode::Refused;
900 }
f7fb7022 901 }
d2adca9d 902 else if(::arg().mustDo("master") && di.kind == DomainInfo::Master) {
5b07dc82 903 g_log<<Logger::Warning<<"Received NOTIFY for "<<p->qdomain<<" from "<<p->getRemote()<<" but we are master (Refused)"<<endl;
d2adca9d
PL
904 return RCode::Refused;
905 }
a2dfc9ea 906 else if(!di.isMaster(p->getRemote())) {
5b07dc82 907 g_log<<Logger::Warning<<"Received NOTIFY for "<<p->qdomain<<" from "<<p->getRemote()<<" which is not a master (Refused)"<<endl;
12c86877
BH
908 return RCode::Refused;
909 }
dad0736b
RC
910
911 if(!s_forwardNotify.empty()) {
912 set<string> forwardNotify(s_forwardNotify);
913 for(set<string>::const_iterator j=forwardNotify.begin();j!=forwardNotify.end();++j) {
5b07dc82 914 g_log<<Logger::Notice<<"Relaying notification of domain "<<p->qdomain<<" from "<<p->getRemote()<<" to "<<*j<<endl;
dad0736b
RC
915 Communicator.notify(p->qdomain,*j);
916 }
917 }
918
1793df78 919 if(::arg().mustDo("slave")) {
ce7dc7e9 920 g_log<<Logger::Debug<<"Queueing slave check for "<<p->qdomain<<endl;
dad0736b 921 Communicator.addSlaveCheckRequest(di, p->d_remote);
1793df78 922 }
7f3d870e 923 return 0;
12c86877
BH
924}
925
1d563353
KM
926bool validDNSName(const DNSName &name)
927{
fc41a1a6
KM
928 if (!g_8bitDNS) {
929 string::size_type pos, length;
930 char c;
931 for(const auto& s : name.getRawLabels()) {
932 length=s.length();
933 for(pos=0; pos < length; ++pos) {
934 c=s[pos];
935 if(!((c >= 'a' && c <= 'z') ||
936 (c >= 'A' && c <= 'Z') ||
937 (c >= '0' && c <= '9') ||
938 c =='-' || c == '_' || c=='*' || c=='.' || c=='/' || c=='@' || c==' ' || c=='\\' || c==':'))
939 return false;
940 }
1d563353
KM
941 }
942 }
943 return true;
944}
945
12c86877
BH
946DNSPacket *PacketHandler::question(DNSPacket *p)
947{
5704e107
PD
948 DNSPacket *ret;
949
950 if(d_pdl)
951 {
952 ret=d_pdl->prequery(p);
953 if(ret)
954 return ret;
955 }
956
bb6e54fe 957 if(p->d.rd) {
1566533a 958 static AtomicCounter &rdqueries=*S.getPointer("rd-queries");
bb6e54fe 959 rdqueries++;
960 }
961
da286f66 962 return doQuestion(p);
ff76e8b4
BH
963}
964
90ba52e0 965
5fff7d51 966void PacketHandler::makeNXDomain(DNSPacket* p, DNSPacket* r, const DNSName& target, const DNSName& wildcard, const SOAData& sd)
35fe50c3 967{
90ba52e0 968 DNSZoneRecord rr;
5fff7d51 969 rr=makeEditedDNSZRFromSOAData(d_dk, sd, DNSResourceRecord::AUTHORITY);
90ba52e0 970 rr.dr.d_ttl=min(sd.ttl, sd.default_ttl);
35fe50c3 971 r->addRecord(rr);
6865d5c0 972
6dbf337f 973 if(d_dnssec) {
c5c4fbdc 974 addNSECX(p, r, target, wildcard, sd.qname, 4);
6dbf337f 975 }
6865d5c0
KM
976
977 r->setRcode(RCode::NXDomain);
35fe50c3
BH
978}
979
5fff7d51 980void PacketHandler::makeNOError(DNSPacket* p, DNSPacket* r, const DNSName& target, const DNSName& wildcard, const SOAData& sd, int mode)
35fe50c3 981{
90ba52e0 982 DNSZoneRecord rr;
5fff7d51 983 rr=makeEditedDNSZRFromSOAData(d_dk, sd, DNSResourceRecord::AUTHORITY);
90ba52e0 984 rr.dr.d_ttl=min(sd.ttl, sd.default_ttl);
35fe50c3 985 r->addRecord(rr);
ed9c3a50 986
6dbf337f 987 if(d_dnssec) {
c5c4fbdc 988 addNSECX(p, r, target, wildcard, sd.qname, mode);
6dbf337f 989 }
9951e2d0 990
eb029b8e 991 S.ringAccount("noerror-queries", p->qdomain, p->qtype);
35fe50c3
BH
992}
993
994
675fa24c 995bool PacketHandler::addDSforNS(DNSPacket* p, DNSPacket* r, SOAData& sd, const DNSName& dsname)
35fe50c3 996{
e4090157 997 //cerr<<"Trying to find a DS for '"<<dsname<<"', domain_id = "<<sd.domain_id<<endl;
35fe50c3 998 B.lookup(QType(QType::DS), dsname, p, sd.domain_id);
90ba52e0 999 DNSZoneRecord rr;
35fe50c3
BH
1000 bool gotOne=false;
1001 while(B.get(rr)) {
1002 gotOne=true;
90ba52e0 1003 rr.dr.d_place = DNSResourceRecord::AUTHORITY;
35fe50c3
BH
1004 r->addRecord(rr);
1005 }
1006 return gotOne;
1007}
1008
675fa24c 1009bool PacketHandler::tryReferral(DNSPacket *p, DNSPacket*r, SOAData& sd, const DNSName &target, bool retargeted)
35fe50c3 1010{
90ba52e0 1011 vector<DNSZoneRecord> rrset = getBestReferralNS(p, sd, target);
35fe50c3
BH
1012 if(rrset.empty())
1013 return false;
1014
424b92c6 1015 for(auto& rr: rrset) {
90ba52e0 1016 rr.dr.d_place=DNSResourceRecord::AUTHORITY;
35fe50c3
BH
1017 r->addRecord(rr);
1018 }
d2323cd0
PD
1019 if(!retargeted)
1020 r->setA(false);
35fe50c3 1021
fc8ed1ad 1022 if(d_dk.isSecuredZone(sd.qname) && !addDSforNS(p, r, sd, rrset.begin()->dr.d_name) && d_dnssec) {
90ba52e0 1023 addNSECX(p, r, rrset.begin()->dr.d_name, DNSName(), sd.qname, 1);
6dbf337f
KM
1024 }
1025
35fe50c3
BH
1026 return true;
1027}
1028
675fa24c 1029void PacketHandler::completeANYRecords(DNSPacket *p, DNSPacket*r, SOAData& sd, const DNSName &target)
35fe50c3 1030{
290a083d 1031 addNSECX(p, r, target, DNSName(), sd.qname, 5);
e325f20c 1032 if(sd.qname == p->qdomain) {
794c2f92 1033 addDNSKEY(p, r, sd);
f889ab99 1034 addCDNSKEY(p, r, sd);
ef542223 1035 addCDS(p, r, sd);
794c2f92 1036 addNSEC3PARAM(p, r, sd);
70b18120 1037 }
35fe50c3
BH
1038}
1039
675fa24c 1040bool PacketHandler::tryDNAME(DNSPacket *p, DNSPacket*r, SOAData& sd, DNSName &target)
8dee0750 1041{
1042 if(!d_doDNAME)
1043 return false;
e6a9dde5 1044 DLOG(g_log<<Logger::Warning<<"Let's try DNAME.."<<endl);
90ba52e0 1045 vector<DNSZoneRecord> rrset = getBestDNAMESynth(p, sd, target);
8dee0750 1046 if(!rrset.empty()) {
424b92c6 1047 for(auto& rr: rrset) {
90ba52e0 1048 rr.dr.d_place = DNSResourceRecord::ANSWER;
8dee0750 1049 r->addRecord(rr);
1050 }
1051 return true;
1052 }
1053 return false;
1054}
675fa24c 1055bool PacketHandler::tryWildcard(DNSPacket *p, DNSPacket*r, SOAData& sd, DNSName &target, DNSName &wildcard, bool& retargeted, bool& nodata)
35fe50c3 1056{
e3f388cd 1057 retargeted = nodata = false;
561434a6 1058 DNSName bestmatch;
35fe50c3 1059
90ba52e0 1060 vector<DNSZoneRecord> rrset;
75a89ce6 1061 if(!getBestWildcard(p, sd, target, wildcard, &rrset))
35fe50c3
BH
1062 return false;
1063
e3f388cd 1064 if(rrset.empty()) {
e6a9dde5 1065 DLOG(g_log<<"Wildcard matched something, but not of the correct type"<<endl);
e3f388cd
BH
1066 nodata=true;
1067 }
1068 else {
424b92c6 1069 for(auto& rr: rrset) {
90ba52e0 1070 rr.wildcardname = rr.dr.d_name;
1071 rr.dr.d_name=bestmatch=target;
bcb8aebe 1072
90ba52e0 1073 if(rr.dr.d_type == QType::CNAME) {
e3f388cd 1074 retargeted=true;
90ba52e0 1075 target=getRR<CNAMERecordContent>(rr.dr)->getTarget();
e3f388cd
BH
1076 }
1077
90ba52e0 1078 rr.dr.d_place=DNSResourceRecord::ANSWER;
e3f388cd 1079 r->addRecord(rr);
35fe50c3 1080 }
35fe50c3 1081 }
6dbf337f 1082 if(d_dnssec && !nodata) {
c5c4fbdc 1083 addNSECX(p, r, bestmatch, wildcard, sd.qname, 3);
35fe50c3 1084 }
6dbf337f 1085
35fe50c3
BH
1086 return true;
1087}
1088
ff76e8b4 1089//! Called by the Distributor to ask a question. Returns 0 in case of an error
e89efca5 1090DNSPacket *PacketHandler::doQuestion(DNSPacket *p)
ff76e8b4 1091{
90ba52e0 1092 DNSZoneRecord rr;
12c86877 1093 SOAData sd;
81c486ad 1094
12c86877 1095 int retargetcount=0;
675fa24c 1096 set<DNSName> authSet;
35fe50c3 1097
90ba52e0 1098 vector<DNSZoneRecord> rrset;
926321a8 1099 bool weDone=0, weRedirected=0, weHaveUnauth=0, doSigs=0;
561434a6 1100 DNSName haveAlias;
0abea1ca 1101 uint8_t aliasScopeMask;
12c86877 1102
0c127168 1103 DNSPacket *r=0;
78bcb858 1104 bool noCache=false;
8900e2e3
CHB
1105
1106#ifdef HAVE_LUA_RECORDS
cb6bd1a9 1107 bool doLua=g_doLuaRecord;
8900e2e3 1108#endif
a16e8e3a
BH
1109
1110 if(p->d.qr) { // QR bit from dns packet (thanks RA from N)
641d32aa 1111 if(d_logDNSDetails)
e6a9dde5 1112 g_log<<Logger::Error<<"Received an answer (non-query) packet from "<<p->getRemote()<<", dropping"<<endl;
a16e8e3a 1113 S.inc("corrupt-packets");
41aacb6a 1114 S.ringAccount("remotes-corrupt", p->d_remote);
a16e8e3a
BH
1115 return 0;
1116 }
1117
43b50405
CH
1118 if(p->d.tc) { // truncated query. MOADNSParser would silently parse this packet in an incomplete way.
1119 if(d_logDNSDetails)
e6a9dde5 1120 g_log<<Logger::Error<<"Received truncated query packet from "<<p->getRemote()<<", dropping"<<endl;
43b50405
CH
1121 S.inc("corrupt-packets");
1122 S.ringAccount("remotes-corrupt", p->d_remote);
1123 return 0;
1124 }
1125
298fabc3
AT
1126 if (p->hasEDNS() && p->getEDNSVersion() > 0) {
1127 r = p->replyPacket();
5d21450e
PL
1128
1129 // PacketWriter::addOpt will take care of setting this correctly in the packet
1130 r->setEDNSRcode(ERCode::BADVERS);
298fabc3
AT
1131 return r;
1132 }
1133
78bcb858 1134 if(p->d_havetsig) {
7abbc40f
PD
1135 DNSName keyname;
1136 string secret;
78bcb858 1137 TSIGRecordContent trc;
ea3816cf 1138 if(!p->checkForCorrectTSIG(&B, &keyname, &secret, &trc)) {
0c127168 1139 r=p->replyPacket(); // generate an empty reply packet
78bcb858 1140 if(d_logDNSDetails)
e6a9dde5 1141 g_log<<Logger::Error<<"Received a TSIG signed message with a non-validating key"<<endl;
f7a69a4c
RA
1142 // RFC3007 describes that a non-secure message should be sending Refused for DNS Updates
1143 if (p->d.opcode == Opcode::Update)
914353ca
KM
1144 r->setRcode(RCode::Refused);
1145 else
f7a69a4c 1146 r->setRcode(RCode::NotAuth);
78bcb858 1147 return r;
7f9ac49b
AT
1148 } else {
1149 getTSIGHashEnum(trc.d_algoName, p->d_tsig_algo);
1150 if (p->d_tsig_algo == TSIG_GSS) {
1635f12b 1151 GssContext gssctx(keyname);
7f9ac49b 1152 if (!gssctx.getPeerPrincipal(p->d_peer_principal)) {
e6a9dde5 1153 g_log<<Logger::Warning<<"Failed to extract peer principal from GSS context with keyname '"<<keyname<<"'"<<endl;
7f9ac49b
AT
1154 }
1155 }
78bcb858
BH
1156 }
1157 p->setTSIGDetails(trc, keyname, secret, trc.d_mac); // this will get copied by replyPacket()
1158 noCache=true;
1159 }
1160
0c127168 1161 r=p->replyPacket(); // generate an empty reply packet, possibly with TSIG details inside
c00d7891
AT
1162
1163 if (p->qtype == QType::TKEY) {
1164 this->tkeyHandler(p, r);
1165 return r;
1166 }
1167
12c86877 1168 try {
12c86877
BH
1169
1170 // XXX FIXME do this in DNSPacket::parse ?
1171
1d563353
KM
1172 if(!validDNSName(p->qdomain)) {
1173 if(d_logDNSDetails)
e6a9dde5 1174 g_log<<Logger::Error<<"Received a malformed qdomain from "<<p->getRemote()<<", '"<<p->qdomain<<"': sending servfail"<<endl;
1d563353
KM
1175 S.inc("corrupt-packets");
1176 S.ringAccount("remotes-corrupt", p->d_remote);
1177 S.inc("servfail-packets");
1178 r->setRcode(RCode::ServFail);
1179 return r;
1180 }
12c86877
BH
1181 if(p->d.opcode) { // non-zero opcode (again thanks RA!)
1182 if(p->d.opcode==Opcode::Update) {
71f758e0 1183 S.inc("dnsupdate-queries");
f7a69a4c 1184 int res=processUpdate(p);
63cb8c10 1185 if (res == RCode::Refused)
71f758e0 1186 S.inc("dnsupdate-refused");
63cb8c10 1187 else if (res != RCode::ServFail)
71f758e0 1188 S.inc("dnsupdate-answers");
f7a69a4c
RA
1189 r->setRcode(res);
1190 r->setOpcode(Opcode::Update);
1191 return r;
12c86877
BH
1192 }
1193 else if(p->d.opcode==Opcode::Notify) {
93aecccc 1194 S.inc("incoming-notifications");
4957a608
BH
1195 int res=processNotify(p);
1196 if(res>=0) {
4957a608
BH
1197 r->setRcode(res);
1198 r->setOpcode(Opcode::Notify);
1199 return r;
1200 }
f3a91936 1201 delete r;
4957a608 1202 return 0;
12c86877
BH
1203 }
1204
e6a9dde5 1205 g_log<<Logger::Error<<"Received an unknown opcode "<<p->d.opcode<<" from "<<p->getRemote()<<" for "<<p->qdomain<<endl;
12c86877 1206
12c86877
BH
1207 r->setRcode(RCode::NotImp);
1208 return r;
1209 }
c2413a68 1210
e6a9dde5 1211 // g_log<<Logger::Warning<<"Query for '"<<p->qdomain<<"' "<<p->qtype.getName()<<" from "<<p->getRemote()<< " (tcp="<<p->d_tcp<<")"<<endl;
12c86877 1212
dc45a198 1213 if(p->qtype.getCode()==QType::IXFR) {
8d7543ba 1214 r->setRcode(RCode::Refused);
dc45a198
BH
1215 return r;
1216 }
1217
561434a6 1218 DNSName target=p->qdomain;
c76a16b7 1219
49e8d5d5
KM
1220 // catch chaos qclass requests
1221 if(p->qclass == QClass::CHAOS) {
1222 if (doChaosRequest(p,r,target))
1223 goto sendit;
1224 else
1225 return r;
1226 }
12c86877 1227
8d7543ba 1228 // we only know about qclass IN (and ANY), send Refused for everything else.
c76a16b7 1229 if(p->qclass != QClass::IN && p->qclass!=QClass::ANY) {
8d7543ba 1230 r->setRcode(RCode::Refused);
c4ac5865
BH
1231 return r;
1232 }
12c86877 1233
ec62f3c0
KM
1234 // send TC for udp ANY query if any-to-tcp is enabled.
1235 if(p->qtype.getCode() == QType::ANY && !p->d_tcp && g_anyToTcp) {
abc8f3f9 1236 r->d.tc = 1;
1237 r->commitD();
1238 return r;
1239 }
1240
49e8d5d5 1241 // for qclass ANY the response should never be authoritative unless the response covers all classes.
c76a16b7 1242 if(p->qclass==QClass::ANY)
12c86877 1243 r->setA(false);
c76a16b7 1244
12c86877
BH
1245
1246 retargeted:;
35fe50c3 1247 if(retargetcount > 10) { // XXX FIXME, retargetcount++?
e6a9dde5 1248 g_log<<Logger::Warning<<"Abort CNAME chain resolution after "<<--retargetcount<<" redirects, sending out servfail. Initial query: '"<<p->qdomain<<"'"<<endl;
75c8ebb4
KM
1249 delete r;
1250 r=p->replyPacket();
12c86877 1251 r->setRcode(RCode::ServFail);
35fe50c3 1252 return r;
12c86877 1253 }
507823d1 1254
cec52de6 1255 if(!B.getAuth(target, p->qtype, &sd)) {
e6a9dde5 1256 DLOG(g_log<<Logger::Error<<"We have no authority over zone '"<<target<<"'"<<endl);
40fc506f 1257 if(!retargetcount) {
8d3cbffa 1258 r->setA(false); // drop AA if we never had a SOA in the first place
40fc506f 1259 r->setRcode(RCode::Refused); // send REFUSED - but only on empty 'no idea'
82cc1f71 1260 }
507823d1
BH
1261 goto sendit;
1262 }
e6a9dde5 1263 DLOG(g_log<<Logger::Error<<"We have authority, zone='"<<sd.qname<<"', id="<<sd.domain_id<<endl);
6dbf337f 1264
926321a8 1265 authSet.insert(sd.qname);
6dbf337f 1266 d_dnssec=(p->d_dnssecOk && d_dk.isSecuredZone(sd.qname));
926321a8 1267 doSigs |= d_dnssec;
12c86877 1268
3e8216c8
PD
1269 if(!retargetcount) r->qdomainzone=sd.qname;
1270
e325f20c 1271 if(sd.qname==p->qdomain) {
794c2f92
PD
1272 if(p->qtype.getCode() == QType::DNSKEY)
1273 {
1274 if(addDNSKEY(p, r, sd))
1275 goto sendit;
1276 }
088370cd
PL
1277 else if(p->qtype.getCode() == QType::CDNSKEY)
1278 {
f889ab99 1279 if(addCDNSKEY(p,r, sd))
088370cd
PL
1280 goto sendit;
1281 }
ef542223
PL
1282 else if(p->qtype.getCode() == QType::CDS)
1283 {
1284 if(addCDS(p,r, sd))
1285 goto sendit;
1286 }
6dbf337f 1287 else if(d_dnssec && p->qtype.getCode() == QType::NSEC3PARAM)
794c2f92
PD
1288 {
1289 if(addNSEC3PARAM(p,r, sd))
1290 goto sendit;
1291 }
fbcdac7e
BH
1292 }
1293
e325f20c 1294 if(p->qtype.getCode() == QType::SOA && sd.qname==p->qdomain) {
5fff7d51 1295 rr=makeEditedDNSZRFromSOAData(d_dk, sd);
507823d1
BH
1296 r->addRecord(rr);
1297 goto sendit;
1298 }
12c86877 1299
35fe50c3 1300 // this TRUMPS a cname!
6dbf337f 1301 if(d_dnssec && p->qtype.getCode() == QType::NSEC && !d_dk.getNSEC3PARAM(sd.qname, 0)) {
290a083d 1302 addNSEC(p, r, target, DNSName(), sd.qname, 5);
7cd99296
KM
1303 if (!r->isEmpty())
1304 goto sendit;
12c86877 1305 }
571726e9 1306
35fe50c3 1307 // this TRUMPS a cname!
ec62f3c0 1308 if(p->qtype.getCode() == QType::RRSIG) {
e6a9dde5 1309 g_log<<Logger::Info<<"Direct RRSIG query for "<<target<<" from "<<p->getRemote()<<endl;
8d7543ba 1310 r->setRcode(RCode::Refused);
52e0d783 1311 goto sendit;
cac7e485 1312 }
35fe50c3 1313
e6a9dde5 1314 DLOG(g_log<<"Checking for referrals first, unless this is a DS query"<<endl);
d2323cd0 1315 if(p->qtype.getCode() != QType::DS && tryReferral(p, r, sd, target, retargetcount))
571726e9
PD
1316 goto sendit;
1317
e6a9dde5 1318 DLOG(g_log<<"Got no referrals, trying ANY"<<endl);
571726e9 1319
8900e2e3 1320#ifdef HAVE_LUA_RECORDS
25bcfaec 1321 if(!doLua) {
1322 string val;
27a630b4 1323 d_dk.getFromMeta(sd.qname, "ENABLE-LUA-RECORDS", val);
25bcfaec 1324 doLua = (val=="1");
1325 }
8900e2e3 1326#endif
ff2e84e9
PD
1327
1328 // see what we get..
1329 B.lookup(QType(QType::ANY), target, p, sd.domain_id);
1330 rrset.clear();
1331 haveAlias.trimToLabels(0);
0abea1ca 1332 aliasScopeMask = 0;
ff2e84e9 1333 weDone = weRedirected = weHaveUnauth = false;
35fe50c3
BH
1334
1335 while(B.get(rr)) {
8900e2e3 1336#ifdef HAVE_LUA_RECORDS
6b547a53 1337 if(rr.dr.d_type == QType::LUA) {
25bcfaec 1338 if(!doLua)
1339 continue;
5dbd408c 1340 auto rec=getRR<LUARecordContent>(rr.dr);
98fa3598
RG
1341 if (!rec) {
1342 continue;
1343 }
1344 if(rec->d_type == QType::CNAME || rec->d_type == p->qtype.getCode() || (p->qtype.getCode() == QType::ANY && rec->d_type != QType::RRSIG)) {
bce078d4 1345 noCache=true;
1bc56192
CHB
1346 try {
1347 auto recvec=luaSynth(rec->getCode(), target, sd.qname, sd.domain_id, *p, rec->d_type);
1348 if(!recvec.empty()) {
1349 for(const auto& r : recvec) {
1350 rr.dr.d_type = rec->d_type; // might be CNAME
1351 rr.dr.d_content = r;
1352 rr.scopeMask = p->getRealRemote().getBits(); // this makes sure answer is a specific as your question
1353 rrset.push_back(rr);
1354 }
1355 if(rec->d_type == QType::CNAME && p->qtype.getCode() != QType::CNAME)
1356 weRedirected = 1;
1357 else
1358 weDone = 1;
bce078d4 1359 }
1bc56192
CHB
1360 }
1361 catch(std::exception &e) {
1362 r=p->replyPacket();
1363 r->setRcode(RCode::ServFail);
1364
1365 return r;
6b547a53 1366 }
6b547a53 1367 }
1368 }
8900e2e3 1369#endif
1fda8e87 1370 //cerr<<"got content: ["<<rr.content<<"]"<<endl;
6dbf337f
KM
1371 if (!d_dnssec && p->qtype.getCode() == QType::ANY && (rr.dr.d_type == QType:: DNSKEY || rr.dr.d_type == QType::NSEC3PARAM))
1372 continue; // Don't send dnssec info.
90ba52e0 1373 if (rr.dr.d_type == QType::RRSIG) // RRSIGS are added later any way.
65538369 1374 continue; // TODO: this actually means addRRSig should check if the RRSig is already there
794c2f92 1375
90ba52e0 1376 // cerr<<"Auth: "<<rr.auth<<", "<<(rr.dr.d_type == p->qtype)<<", "<<rr.dr.d_type.getName()<<endl;
1377 if((p->qtype.getCode() == QType::ANY || rr.dr.d_type == p->qtype.getCode()) && rr.auth)
82cc1f71 1378 weDone=1;
5b739515 1379 // the line below fakes 'unauth NS' for delegations for non-DNSSEC backends.
90ba52e0 1380 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 1381 weHaveUnauth=1;
35fe50c3 1382
90ba52e0 1383 if(rr.dr.d_type == QType::CNAME && p->qtype.getCode() != QType::CNAME)
82cc1f71 1384 weRedirected=1;
1dfd8ada 1385
90ba52e0 1386 if(DP && rr.dr.d_type == QType::ALIAS && (p->qtype.getCode() == QType::A || p->qtype.getCode() == QType::AAAA || p->qtype.getCode() == QType::ANY)) {
389b7a05 1387 if (!d_doExpandALIAS) {
e6a9dde5 1388 g_log<<Logger::Info<<"ALIAS record found for "<<target<<", but ALIAS expansion is disabled."<<endl;
389b7a05
PL
1389 continue;
1390 }
90ba52e0 1391 haveAlias=getRR<ALIASRecordContent>(rr.dr)->d_content;
0abea1ca 1392 aliasScopeMask=rr.scopeMask;
d59b894d 1393 }
1394
1dfd8ada 1395 // Filter out all SOA's and add them in later
90ba52e0 1396 if(rr.dr.d_type == QType::SOA)
1dfd8ada
MZ
1397 continue;
1398
35fe50c3 1399 rrset.push_back(rr);
12c86877
BH
1400 }
1401
1dfd8ada 1402 /* Add in SOA if required */
e325f20c 1403 if(target==sd.qname) {
5fff7d51 1404 rr=makeEditedDNSZRFromSOAData(d_dk, sd);
1dfd8ada
MZ
1405 rrset.push_back(rr);
1406 }
1407
8dee0750 1408
e6a9dde5 1409 DLOG(g_log<<"After first ANY query for '"<<target<<"', id="<<sd.domain_id<<": weDone="<<weDone<<", weHaveUnauth="<<weHaveUnauth<<", weRedirected="<<weRedirected<<", haveAlias='"<<haveAlias<<"'"<<endl);
32d24117
PD
1410 if(p->qtype.getCode() == QType::DS && weHaveUnauth && !weDone && !weRedirected) {
1411 DLOG(g_log<<"Q for DS of a name for which we do have NS, but for which we don't have DS; need to provide an AUTH answer that shows we don't"<<endl);
290a083d 1412 makeNOError(p, r, target, DNSName(), sd, 1);
849bd7f1
BH
1413 goto sendit;
1414 }
12c86877 1415
65d2032b 1416 if(!haveAlias.empty() && (!weDone || p->qtype.getCode() == QType::ANY)) {
e6a9dde5 1417 DLOG(g_log<<Logger::Warning<<"Found nothing that matched for '"<<target<<"', but did get alias to '"<<haveAlias<<"', referring"<<endl);
0abea1ca 1418 DP->completePacket(r, haveAlias, target, aliasScopeMask);
d59b894d 1419 return 0;
1420 }
1421
fd65c85d
KM
1422
1423 // referral for DS query
1424 if(p->qtype.getCode() == QType::DS) {
1425 DLOG(g_log<<"Qtype is DS"<<endl);
1426 bool doReferral = true;
1427 if(d_dk.doesDNSSEC()) {
1428 for(auto& loopRR: rrset) {
e7838719
KM
1429 // In a dnssec capable backend auth=true means, there is no delagation at
1430 // or above this qname in this zone (for DS queries). Without a delegation,
1431 // at or above this level, it is pointless to search for refferals.
fd65c85d
KM
1432 if(loopRR.auth) {
1433 doReferral = false;
1434 break;
1435 }
1436 }
1437 } else {
1438 for(auto& loopRR: rrset) {
e7838719
KM
1439 // In a non dnssec capable backend auth is always true, so our only option
1440 // is, always look for referals. Unless there is a direct match for DS.
fd65c85d
KM
1441 if(loopRR.dr.d_type == QType::DS) {
1442 doReferral = false;
1443 break;
1444 }
1445 }
1446 }
1447 if(doReferral) {
e6a9dde5 1448 DLOG(g_log<<"DS query found no direct result, trying referral now"<<endl);
d2323cd0 1449 if(tryReferral(p, r, sd, target, retargetcount))
0a0f4112 1450 {
fd65c85d 1451 DLOG(g_log<<"Got referral for DS query"<<endl);
0a0f4112
PD
1452 goto sendit;
1453 }
1454 }
fd65c85d 1455 }
0a0f4112 1456
d59b894d 1457
fd65c85d 1458 if(rrset.empty()) {
e6a9dde5 1459 DLOG(g_log<<Logger::Warning<<"Found nothing in the by-name ANY, but let's try wildcards.."<<endl);
e3f388cd 1460 bool wereRetargeted(false), nodata(false);
561434a6 1461 DNSName wildcard;
75a89ce6 1462 if(tryWildcard(p, r, sd, target, wildcard, wereRetargeted, nodata)) {
82cc1f71 1463 if(wereRetargeted) {
3e8216c8 1464 if(!retargetcount) r->qdomainwild=wildcard;
82cc1f71
BH
1465 retargetcount++;
1466 goto retargeted;
1467 }
c5c4fbdc
PD
1468 if(nodata)
1469 makeNOError(p, r, target, wildcard, sd, 2);
1470
82cc1f71 1471 goto sendit;
8e50cd4c 1472 }
8dee0750 1473 else if(tryDNAME(p, r, sd, target)) {
1474 retargetcount++;
1475 goto retargeted;
1476 }
a87b7e3f
PD
1477 else
1478 {
c5c4fbdc
PD
1479 if (!(((p->qtype.getCode() == QType::CNAME) || (p->qtype.getCode() == QType::ANY)) && retargetcount > 0))
1480 makeNXDomain(p, r, target, wildcard, sd);
a87b7e3f
PD
1481 }
1482
82cc1f71
BH
1483 goto sendit;
1484 }
232f0877 1485
35fe50c3 1486 if(weRedirected) {
2010ac95
RG
1487 for(auto& loopRR: rrset) {
1488 if(loopRR.dr.d_type == QType::CNAME) {
1489 r->addRecord(loopRR);
1490 target = getRR<CNAMERecordContent>(loopRR.dr)->getTarget();
82cc1f71
BH
1491 retargetcount++;
1492 goto retargeted;
4957a608 1493 }
82cc1f71 1494 }
82cc1f71 1495 }
35fe50c3 1496 else if(weDone) {
b5baefaf 1497 bool haveRecords = false;
2010ac95 1498 for(const auto& loopRR: rrset) {
8900e2e3 1499#ifdef HAVE_LUA_RECORDS
bce078d4 1500 if(loopRR.dr.d_type == QType::LUA)
1501 continue;
8900e2e3 1502#endif
2010ac95
RG
1503 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) {
1504 r->addRecord(loopRR);
b5baefaf
PD
1505 haveRecords = true;
1506 }
82cc1f71 1507 }
4957a608 1508
b5baefaf 1509 if (haveRecords) {
6dbf337f 1510 if(d_dnssec && p->qtype.getCode() == QType::ANY)
b5baefaf 1511 completeANYRecords(p, r, sd, target);
82cc1f71 1512 }
b5baefaf 1513 else
b9817f2b 1514 makeNOError(p, r, target, DNSName(), sd, 0);
4957a608 1515
35fe50c3 1516 goto sendit;
82cc1f71 1517 }
35fe50c3 1518 else if(weHaveUnauth) {
e6a9dde5 1519 DLOG(g_log<<"Have unauth data, so need to hunt for best NS records"<<endl);
d2323cd0 1520 if(tryReferral(p, r, sd, target, retargetcount))
82cc1f71 1521 goto sendit;
2b18bcf3 1522 // check whether this could be fixed easily
90ba52e0 1523 // if (*(rr.dr.d_name.rbegin()) == '.') {
e6a9dde5 1524 // 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 1525 // } else {
e6a9dde5 1526 g_log<<Logger::Error<<"Should not get here ("<<p->qdomain<<"|"<<p->qtype.getCode()<<"): please run pdnsutil rectify-zone "<<sd.qname<<endl;
561434a6 1527 // }
82cc1f71
BH
1528 }
1529 else {
e6a9dde5 1530 DLOG(g_log<<"Have some data, but not the right data"<<endl);
290a083d 1531 makeNOError(p, r, target, DNSName(), sd, 0);
82cc1f71 1532 }
12c86877
BH
1533
1534 sendit:;
d2323cd0 1535 if(doAdditionalProcessingAndDropAA(p, r, sd, retargetcount)<0) {
f3a91936 1536 delete r;
12c86877 1537 return 0;
f3a91936 1538 }
8ea10bfc 1539
2010ac95
RG
1540 for(const auto& loopRR: r->getRRS()) {
1541 if(loopRR.scopeMask) {
bf269e28 1542 noCache=true;
c28bf199 1543 break;
606018f2 1544 }
1545 }
926321a8 1546 if(doSigs)
8d3cbffa 1547 addRRSigs(d_dk, B, authSet, r->getRRS());
f3a91936 1548
e02d0a59 1549 r->wrapup(); // needed for inserting in cache
bf269e28 1550 if(!noCache && p->couldBeCached())
071d2d90 1551 PC.insert(p, r, r->getMinTTL()); // in the packet cache
12c86877
BH
1552 }
1553 catch(DBException &e) {
e6a9dde5 1554 g_log<<Logger::Error<<"Backend reported condition which prevented lookup ("+e.reason+") sending out servfail"<<endl;
25e7af37
KM
1555 delete r;
1556 r=p->replyPacket(); // generate an empty reply packet
12c86877 1557 r->setRcode(RCode::ServFail);
eefd15f9 1558 S.inc("servfail-packets");
eb029b8e 1559 S.ringAccount("servfail-queries", p->qdomain, p->qtype);
12c86877 1560 }
3f81d239 1561 catch(PDNSException &e) {
e6a9dde5 1562 g_log<<Logger::Error<<"Backend reported permanent error which prevented lookup ("+e.reason+"), aborting"<<endl;
31d9bb01 1563 throw; // we WANT to die at this point
86113ac9 1564 }
5172cb78 1565 catch(std::exception &e) {
e6a9dde5 1566 g_log<<Logger::Error<<"Exception building answer packet for "<<p->qdomain<<"/"<<p->qtype.getName()<<" ("<<e.what()<<") sending out servfail"<<endl;
8ea10bfc 1567 delete r;
25e7af37 1568 r=p->replyPacket(); // generate an empty reply packet
8ea10bfc
BH
1569 r->setRcode(RCode::ServFail);
1570 S.inc("servfail-packets");
eb029b8e 1571 S.ringAccount("servfail-queries", p->qdomain, p->qtype);
8ea10bfc 1572 }
12c86877
BH
1573 return r;
1574
1575}