]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/packethandler.cc
Merge pull request #7787 from rgacogne/auth-api-replace-ent
[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
675fa24c 966void PacketHandler::makeNXDomain(DNSPacket* p, DNSPacket* r, const DNSName& target, const DNSName& wildcard, SOAData& sd)
35fe50c3 967{
90ba52e0 968 DNSZoneRecord rr;
969 rr.dr.d_name=sd.qname;
970 rr.dr.d_type=QType::SOA;
90ba52e0 971 rr.dr.d_content=makeSOAContent(sd);
972 rr.dr.d_ttl=min(sd.ttl, sd.default_ttl);
794c2f92 973 rr.signttl=sd.ttl;
35fe50c3 974 rr.domain_id=sd.domain_id;
90ba52e0 975 rr.dr.d_place=DNSResourceRecord::AUTHORITY;
0957a99f 976 rr.auth = 1;
35fe50c3 977 r->addRecord(rr);
6865d5c0 978
6dbf337f 979 if(d_dnssec) {
c5c4fbdc 980 addNSECX(p, r, target, wildcard, sd.qname, 4);
6dbf337f 981 }
6865d5c0
KM
982
983 r->setRcode(RCode::NXDomain);
35fe50c3
BH
984}
985
675fa24c 986void PacketHandler::makeNOError(DNSPacket* p, DNSPacket* r, const DNSName& target, const DNSName& wildcard, SOAData& sd, int mode)
35fe50c3 987{
90ba52e0 988 DNSZoneRecord rr;
989 rr.dr.d_name=sd.qname;
990 rr.dr.d_type=QType::SOA;
991 rr.dr.d_content=makeSOAContent(sd);
90ba52e0 992 rr.dr.d_ttl=min(sd.ttl, sd.default_ttl);
794c2f92 993 rr.signttl=sd.ttl;
35fe50c3 994 rr.domain_id=sd.domain_id;
90ba52e0 995 rr.dr.d_place=DNSResourceRecord::AUTHORITY;
bccefefa 996 rr.auth = 1;
35fe50c3 997 r->addRecord(rr);
ed9c3a50 998
6dbf337f 999 if(d_dnssec) {
c5c4fbdc 1000 addNSECX(p, r, target, wildcard, sd.qname, mode);
6dbf337f 1001 }
9951e2d0 1002
eb029b8e 1003 S.ringAccount("noerror-queries", p->qdomain, p->qtype);
35fe50c3
BH
1004}
1005
1006
675fa24c 1007bool PacketHandler::addDSforNS(DNSPacket* p, DNSPacket* r, SOAData& sd, const DNSName& dsname)
35fe50c3 1008{
e4090157 1009 //cerr<<"Trying to find a DS for '"<<dsname<<"', domain_id = "<<sd.domain_id<<endl;
35fe50c3 1010 B.lookup(QType(QType::DS), dsname, p, sd.domain_id);
90ba52e0 1011 DNSZoneRecord rr;
35fe50c3
BH
1012 bool gotOne=false;
1013 while(B.get(rr)) {
1014 gotOne=true;
90ba52e0 1015 rr.dr.d_place = DNSResourceRecord::AUTHORITY;
35fe50c3
BH
1016 r->addRecord(rr);
1017 }
1018 return gotOne;
1019}
1020
675fa24c 1021bool PacketHandler::tryReferral(DNSPacket *p, DNSPacket*r, SOAData& sd, const DNSName &target, bool retargeted)
35fe50c3 1022{
90ba52e0 1023 vector<DNSZoneRecord> rrset = getBestReferralNS(p, sd, target);
35fe50c3
BH
1024 if(rrset.empty())
1025 return false;
1026
424b92c6 1027 for(auto& rr: rrset) {
90ba52e0 1028 rr.dr.d_place=DNSResourceRecord::AUTHORITY;
35fe50c3
BH
1029 r->addRecord(rr);
1030 }
d2323cd0
PD
1031 if(!retargeted)
1032 r->setA(false);
35fe50c3 1033
fc8ed1ad 1034 if(d_dk.isSecuredZone(sd.qname) && !addDSforNS(p, r, sd, rrset.begin()->dr.d_name) && d_dnssec) {
90ba52e0 1035 addNSECX(p, r, rrset.begin()->dr.d_name, DNSName(), sd.qname, 1);
6dbf337f
KM
1036 }
1037
35fe50c3
BH
1038 return true;
1039}
1040
675fa24c 1041void PacketHandler::completeANYRecords(DNSPacket *p, DNSPacket*r, SOAData& sd, const DNSName &target)
35fe50c3 1042{
290a083d 1043 addNSECX(p, r, target, DNSName(), sd.qname, 5);
e325f20c 1044 if(sd.qname == p->qdomain) {
794c2f92 1045 addDNSKEY(p, r, sd);
f889ab99 1046 addCDNSKEY(p, r, sd);
ef542223 1047 addCDS(p, r, sd);
794c2f92 1048 addNSEC3PARAM(p, r, sd);
70b18120 1049 }
35fe50c3
BH
1050}
1051
675fa24c 1052bool PacketHandler::tryDNAME(DNSPacket *p, DNSPacket*r, SOAData& sd, DNSName &target)
8dee0750 1053{
1054 if(!d_doDNAME)
1055 return false;
e6a9dde5 1056 DLOG(g_log<<Logger::Warning<<"Let's try DNAME.."<<endl);
90ba52e0 1057 vector<DNSZoneRecord> rrset = getBestDNAMESynth(p, sd, target);
8dee0750 1058 if(!rrset.empty()) {
424b92c6 1059 for(auto& rr: rrset) {
90ba52e0 1060 rr.dr.d_place = DNSResourceRecord::ANSWER;
8dee0750 1061 r->addRecord(rr);
1062 }
1063 return true;
1064 }
1065 return false;
1066}
675fa24c 1067bool PacketHandler::tryWildcard(DNSPacket *p, DNSPacket*r, SOAData& sd, DNSName &target, DNSName &wildcard, bool& retargeted, bool& nodata)
35fe50c3 1068{
e3f388cd 1069 retargeted = nodata = false;
561434a6 1070 DNSName bestmatch;
35fe50c3 1071
90ba52e0 1072 vector<DNSZoneRecord> rrset;
75a89ce6 1073 if(!getBestWildcard(p, sd, target, wildcard, &rrset))
35fe50c3
BH
1074 return false;
1075
e3f388cd 1076 if(rrset.empty()) {
e6a9dde5 1077 DLOG(g_log<<"Wildcard matched something, but not of the correct type"<<endl);
e3f388cd
BH
1078 nodata=true;
1079 }
1080 else {
424b92c6 1081 for(auto& rr: rrset) {
90ba52e0 1082 rr.wildcardname = rr.dr.d_name;
1083 rr.dr.d_name=bestmatch=target;
bcb8aebe 1084
90ba52e0 1085 if(rr.dr.d_type == QType::CNAME) {
e3f388cd 1086 retargeted=true;
90ba52e0 1087 target=getRR<CNAMERecordContent>(rr.dr)->getTarget();
e3f388cd
BH
1088 }
1089
90ba52e0 1090 rr.dr.d_place=DNSResourceRecord::ANSWER;
e3f388cd 1091 r->addRecord(rr);
35fe50c3 1092 }
35fe50c3 1093 }
6dbf337f 1094 if(d_dnssec && !nodata) {
c5c4fbdc 1095 addNSECX(p, r, bestmatch, wildcard, sd.qname, 3);
35fe50c3 1096 }
6dbf337f 1097
35fe50c3
BH
1098 return true;
1099}
1100
ff76e8b4 1101//! Called by the Distributor to ask a question. Returns 0 in case of an error
e89efca5 1102DNSPacket *PacketHandler::doQuestion(DNSPacket *p)
ff76e8b4 1103{
90ba52e0 1104 DNSZoneRecord rr;
12c86877 1105 SOAData sd;
81c486ad 1106
12c86877 1107 int retargetcount=0;
675fa24c 1108 set<DNSName> authSet;
35fe50c3 1109
90ba52e0 1110 vector<DNSZoneRecord> rrset;
926321a8 1111 bool weDone=0, weRedirected=0, weHaveUnauth=0, doSigs=0;
561434a6 1112 DNSName haveAlias;
0abea1ca 1113 uint8_t aliasScopeMask;
12c86877 1114
0c127168 1115 DNSPacket *r=0;
78bcb858 1116 bool noCache=false;
8900e2e3
CHB
1117
1118#ifdef HAVE_LUA_RECORDS
cb6bd1a9 1119 bool doLua=g_doLuaRecord;
8900e2e3 1120#endif
a16e8e3a
BH
1121
1122 if(p->d.qr) { // QR bit from dns packet (thanks RA from N)
641d32aa 1123 if(d_logDNSDetails)
e6a9dde5 1124 g_log<<Logger::Error<<"Received an answer (non-query) packet from "<<p->getRemote()<<", dropping"<<endl;
a16e8e3a 1125 S.inc("corrupt-packets");
41aacb6a 1126 S.ringAccount("remotes-corrupt", p->d_remote);
a16e8e3a
BH
1127 return 0;
1128 }
1129
43b50405
CH
1130 if(p->d.tc) { // truncated query. MOADNSParser would silently parse this packet in an incomplete way.
1131 if(d_logDNSDetails)
e6a9dde5 1132 g_log<<Logger::Error<<"Received truncated query packet from "<<p->getRemote()<<", dropping"<<endl;
43b50405
CH
1133 S.inc("corrupt-packets");
1134 S.ringAccount("remotes-corrupt", p->d_remote);
1135 return 0;
1136 }
1137
298fabc3
AT
1138 if (p->hasEDNS() && p->getEDNSVersion() > 0) {
1139 r = p->replyPacket();
5d21450e
PL
1140
1141 // PacketWriter::addOpt will take care of setting this correctly in the packet
1142 r->setEDNSRcode(ERCode::BADVERS);
298fabc3
AT
1143 return r;
1144 }
1145
78bcb858 1146 if(p->d_havetsig) {
7abbc40f
PD
1147 DNSName keyname;
1148 string secret;
78bcb858 1149 TSIGRecordContent trc;
ea3816cf 1150 if(!p->checkForCorrectTSIG(&B, &keyname, &secret, &trc)) {
0c127168 1151 r=p->replyPacket(); // generate an empty reply packet
78bcb858 1152 if(d_logDNSDetails)
e6a9dde5 1153 g_log<<Logger::Error<<"Received a TSIG signed message with a non-validating key"<<endl;
f7a69a4c
RA
1154 // RFC3007 describes that a non-secure message should be sending Refused for DNS Updates
1155 if (p->d.opcode == Opcode::Update)
914353ca
KM
1156 r->setRcode(RCode::Refused);
1157 else
f7a69a4c 1158 r->setRcode(RCode::NotAuth);
78bcb858 1159 return r;
7f9ac49b
AT
1160 } else {
1161 getTSIGHashEnum(trc.d_algoName, p->d_tsig_algo);
1162 if (p->d_tsig_algo == TSIG_GSS) {
1635f12b 1163 GssContext gssctx(keyname);
7f9ac49b 1164 if (!gssctx.getPeerPrincipal(p->d_peer_principal)) {
e6a9dde5 1165 g_log<<Logger::Warning<<"Failed to extract peer principal from GSS context with keyname '"<<keyname<<"'"<<endl;
7f9ac49b
AT
1166 }
1167 }
78bcb858
BH
1168 }
1169 p->setTSIGDetails(trc, keyname, secret, trc.d_mac); // this will get copied by replyPacket()
1170 noCache=true;
1171 }
1172
0c127168 1173 r=p->replyPacket(); // generate an empty reply packet, possibly with TSIG details inside
c00d7891
AT
1174
1175 if (p->qtype == QType::TKEY) {
1176 this->tkeyHandler(p, r);
1177 return r;
1178 }
1179
12c86877 1180 try {
12c86877
BH
1181
1182 // XXX FIXME do this in DNSPacket::parse ?
1183
1d563353
KM
1184 if(!validDNSName(p->qdomain)) {
1185 if(d_logDNSDetails)
e6a9dde5 1186 g_log<<Logger::Error<<"Received a malformed qdomain from "<<p->getRemote()<<", '"<<p->qdomain<<"': sending servfail"<<endl;
1d563353
KM
1187 S.inc("corrupt-packets");
1188 S.ringAccount("remotes-corrupt", p->d_remote);
1189 S.inc("servfail-packets");
1190 r->setRcode(RCode::ServFail);
1191 return r;
1192 }
12c86877
BH
1193 if(p->d.opcode) { // non-zero opcode (again thanks RA!)
1194 if(p->d.opcode==Opcode::Update) {
71f758e0 1195 S.inc("dnsupdate-queries");
f7a69a4c 1196 int res=processUpdate(p);
63cb8c10 1197 if (res == RCode::Refused)
71f758e0 1198 S.inc("dnsupdate-refused");
63cb8c10 1199 else if (res != RCode::ServFail)
71f758e0 1200 S.inc("dnsupdate-answers");
f7a69a4c
RA
1201 r->setRcode(res);
1202 r->setOpcode(Opcode::Update);
1203 return r;
12c86877
BH
1204 }
1205 else if(p->d.opcode==Opcode::Notify) {
93aecccc 1206 S.inc("incoming-notifications");
4957a608
BH
1207 int res=processNotify(p);
1208 if(res>=0) {
4957a608
BH
1209 r->setRcode(res);
1210 r->setOpcode(Opcode::Notify);
1211 return r;
1212 }
f3a91936 1213 delete r;
4957a608 1214 return 0;
12c86877
BH
1215 }
1216
e6a9dde5 1217 g_log<<Logger::Error<<"Received an unknown opcode "<<p->d.opcode<<" from "<<p->getRemote()<<" for "<<p->qdomain<<endl;
12c86877 1218
12c86877
BH
1219 r->setRcode(RCode::NotImp);
1220 return r;
1221 }
c2413a68 1222
e6a9dde5 1223 // g_log<<Logger::Warning<<"Query for '"<<p->qdomain<<"' "<<p->qtype.getName()<<" from "<<p->getRemote()<< " (tcp="<<p->d_tcp<<")"<<endl;
12c86877 1224
dc45a198 1225 if(p->qtype.getCode()==QType::IXFR) {
8d7543ba 1226 r->setRcode(RCode::Refused);
dc45a198
BH
1227 return r;
1228 }
1229
561434a6 1230 DNSName target=p->qdomain;
c76a16b7 1231
49e8d5d5
KM
1232 // catch chaos qclass requests
1233 if(p->qclass == QClass::CHAOS) {
1234 if (doChaosRequest(p,r,target))
1235 goto sendit;
1236 else
1237 return r;
1238 }
12c86877 1239
8d7543ba 1240 // we only know about qclass IN (and ANY), send Refused for everything else.
c76a16b7 1241 if(p->qclass != QClass::IN && p->qclass!=QClass::ANY) {
8d7543ba 1242 r->setRcode(RCode::Refused);
c4ac5865
BH
1243 return r;
1244 }
12c86877 1245
ec62f3c0
KM
1246 // send TC for udp ANY query if any-to-tcp is enabled.
1247 if(p->qtype.getCode() == QType::ANY && !p->d_tcp && g_anyToTcp) {
abc8f3f9 1248 r->d.tc = 1;
1249 r->commitD();
1250 return r;
1251 }
1252
49e8d5d5 1253 // for qclass ANY the response should never be authoritative unless the response covers all classes.
c76a16b7 1254 if(p->qclass==QClass::ANY)
12c86877 1255 r->setA(false);
c76a16b7 1256
12c86877
BH
1257
1258 retargeted:;
35fe50c3 1259 if(retargetcount > 10) { // XXX FIXME, retargetcount++?
e6a9dde5 1260 g_log<<Logger::Warning<<"Abort CNAME chain resolution after "<<--retargetcount<<" redirects, sending out servfail. Initial query: '"<<p->qdomain<<"'"<<endl;
75c8ebb4
KM
1261 delete r;
1262 r=p->replyPacket();
12c86877 1263 r->setRcode(RCode::ServFail);
35fe50c3 1264 return r;
12c86877 1265 }
507823d1 1266
cec52de6 1267 if(!B.getAuth(target, p->qtype, &sd)) {
e6a9dde5 1268 DLOG(g_log<<Logger::Error<<"We have no authority over zone '"<<target<<"'"<<endl);
40fc506f 1269 if(!retargetcount) {
8d3cbffa 1270 r->setA(false); // drop AA if we never had a SOA in the first place
40fc506f 1271 r->setRcode(RCode::Refused); // send REFUSED - but only on empty 'no idea'
82cc1f71 1272 }
507823d1
BH
1273 goto sendit;
1274 }
e6a9dde5 1275 DLOG(g_log<<Logger::Error<<"We have authority, zone='"<<sd.qname<<"', id="<<sd.domain_id<<endl);
6dbf337f 1276
926321a8 1277 authSet.insert(sd.qname);
6dbf337f 1278 d_dnssec=(p->d_dnssecOk && d_dk.isSecuredZone(sd.qname));
926321a8 1279 doSigs |= d_dnssec;
12c86877 1280
3e8216c8
PD
1281 if(!retargetcount) r->qdomainzone=sd.qname;
1282
e325f20c 1283 if(sd.qname==p->qdomain) {
794c2f92
PD
1284 if(p->qtype.getCode() == QType::DNSKEY)
1285 {
1286 if(addDNSKEY(p, r, sd))
1287 goto sendit;
1288 }
088370cd
PL
1289 else if(p->qtype.getCode() == QType::CDNSKEY)
1290 {
f889ab99 1291 if(addCDNSKEY(p,r, sd))
088370cd
PL
1292 goto sendit;
1293 }
ef542223
PL
1294 else if(p->qtype.getCode() == QType::CDS)
1295 {
1296 if(addCDS(p,r, sd))
1297 goto sendit;
1298 }
6dbf337f 1299 else if(d_dnssec && p->qtype.getCode() == QType::NSEC3PARAM)
794c2f92
PD
1300 {
1301 if(addNSEC3PARAM(p,r, sd))
1302 goto sendit;
1303 }
fbcdac7e
BH
1304 }
1305
e325f20c 1306 if(p->qtype.getCode() == QType::SOA && sd.qname==p->qdomain) {
90ba52e0 1307 rr.dr.d_name=sd.qname;
1308 rr.dr.d_type=QType::SOA;
13f9e280 1309 sd.serial = calculateEditSOA(sd.serial, d_dk, sd.qname);
90ba52e0 1310 rr.dr.d_content=makeSOAContent(sd);
1311 rr.dr.d_ttl=sd.ttl;
507823d1 1312 rr.domain_id=sd.domain_id;
90ba52e0 1313 rr.dr.d_place=DNSResourceRecord::ANSWER;
d24589bc 1314 rr.auth = true;
507823d1
BH
1315 r->addRecord(rr);
1316 goto sendit;
1317 }
12c86877 1318
35fe50c3 1319 // this TRUMPS a cname!
6dbf337f 1320 if(d_dnssec && p->qtype.getCode() == QType::NSEC && !d_dk.getNSEC3PARAM(sd.qname, 0)) {
290a083d 1321 addNSEC(p, r, target, DNSName(), sd.qname, 5);
7cd99296
KM
1322 if (!r->isEmpty())
1323 goto sendit;
12c86877 1324 }
571726e9 1325
35fe50c3 1326 // this TRUMPS a cname!
ec62f3c0 1327 if(p->qtype.getCode() == QType::RRSIG) {
e6a9dde5 1328 g_log<<Logger::Info<<"Direct RRSIG query for "<<target<<" from "<<p->getRemote()<<endl;
8d7543ba 1329 r->setRcode(RCode::Refused);
52e0d783 1330 goto sendit;
cac7e485 1331 }
35fe50c3 1332
e6a9dde5 1333 DLOG(g_log<<"Checking for referrals first, unless this is a DS query"<<endl);
d2323cd0 1334 if(p->qtype.getCode() != QType::DS && tryReferral(p, r, sd, target, retargetcount))
571726e9
PD
1335 goto sendit;
1336
e6a9dde5 1337 DLOG(g_log<<"Got no referrals, trying ANY"<<endl);
571726e9 1338
8900e2e3 1339#ifdef HAVE_LUA_RECORDS
25bcfaec 1340 if(!doLua) {
1341 string val;
27a630b4 1342 d_dk.getFromMeta(sd.qname, "ENABLE-LUA-RECORDS", val);
25bcfaec 1343 doLua = (val=="1");
1344 }
8900e2e3 1345#endif
ff2e84e9
PD
1346
1347 // see what we get..
1348 B.lookup(QType(QType::ANY), target, p, sd.domain_id);
1349 rrset.clear();
1350 haveAlias.trimToLabels(0);
0abea1ca 1351 aliasScopeMask = 0;
ff2e84e9 1352 weDone = weRedirected = weHaveUnauth = false;
35fe50c3
BH
1353
1354 while(B.get(rr)) {
8900e2e3 1355#ifdef HAVE_LUA_RECORDS
6b547a53 1356 if(rr.dr.d_type == QType::LUA) {
25bcfaec 1357 if(!doLua)
1358 continue;
5dbd408c 1359 auto rec=getRR<LUARecordContent>(rr.dr);
98fa3598
RG
1360 if (!rec) {
1361 continue;
1362 }
1363 if(rec->d_type == QType::CNAME || rec->d_type == p->qtype.getCode() || (p->qtype.getCode() == QType::ANY && rec->d_type != QType::RRSIG)) {
bce078d4 1364 noCache=true;
1bc56192
CHB
1365 try {
1366 auto recvec=luaSynth(rec->getCode(), target, sd.qname, sd.domain_id, *p, rec->d_type);
1367 if(!recvec.empty()) {
1368 for(const auto& r : recvec) {
1369 rr.dr.d_type = rec->d_type; // might be CNAME
1370 rr.dr.d_content = r;
1371 rr.scopeMask = p->getRealRemote().getBits(); // this makes sure answer is a specific as your question
1372 rrset.push_back(rr);
1373 }
1374 if(rec->d_type == QType::CNAME && p->qtype.getCode() != QType::CNAME)
1375 weRedirected = 1;
1376 else
1377 weDone = 1;
bce078d4 1378 }
1bc56192
CHB
1379 }
1380 catch(std::exception &e) {
1381 r=p->replyPacket();
1382 r->setRcode(RCode::ServFail);
1383
1384 return r;
6b547a53 1385 }
6b547a53 1386 }
1387 }
8900e2e3 1388#endif
1fda8e87 1389 //cerr<<"got content: ["<<rr.content<<"]"<<endl;
6dbf337f
KM
1390 if (!d_dnssec && p->qtype.getCode() == QType::ANY && (rr.dr.d_type == QType:: DNSKEY || rr.dr.d_type == QType::NSEC3PARAM))
1391 continue; // Don't send dnssec info.
90ba52e0 1392 if (rr.dr.d_type == QType::RRSIG) // RRSIGS are added later any way.
65538369 1393 continue; // TODO: this actually means addRRSig should check if the RRSig is already there
794c2f92 1394
90ba52e0 1395 // cerr<<"Auth: "<<rr.auth<<", "<<(rr.dr.d_type == p->qtype)<<", "<<rr.dr.d_type.getName()<<endl;
1396 if((p->qtype.getCode() == QType::ANY || rr.dr.d_type == p->qtype.getCode()) && rr.auth)
82cc1f71 1397 weDone=1;
5b739515 1398 // the line below fakes 'unauth NS' for delegations for non-DNSSEC backends.
90ba52e0 1399 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 1400 weHaveUnauth=1;
35fe50c3 1401
90ba52e0 1402 if(rr.dr.d_type == QType::CNAME && p->qtype.getCode() != QType::CNAME)
82cc1f71 1403 weRedirected=1;
1dfd8ada 1404
90ba52e0 1405 if(DP && rr.dr.d_type == QType::ALIAS && (p->qtype.getCode() == QType::A || p->qtype.getCode() == QType::AAAA || p->qtype.getCode() == QType::ANY)) {
389b7a05 1406 if (!d_doExpandALIAS) {
e6a9dde5 1407 g_log<<Logger::Info<<"ALIAS record found for "<<target<<", but ALIAS expansion is disabled."<<endl;
389b7a05
PL
1408 continue;
1409 }
90ba52e0 1410 haveAlias=getRR<ALIASRecordContent>(rr.dr)->d_content;
0abea1ca 1411 aliasScopeMask=rr.scopeMask;
d59b894d 1412 }
1413
1dfd8ada 1414 // Filter out all SOA's and add them in later
90ba52e0 1415 if(rr.dr.d_type == QType::SOA)
1dfd8ada
MZ
1416 continue;
1417
35fe50c3 1418 rrset.push_back(rr);
12c86877
BH
1419 }
1420
1dfd8ada 1421 /* Add in SOA if required */
e325f20c 1422 if(target==sd.qname) {
13f9e280 1423 rr.dr.d_name = sd.qname;
90ba52e0 1424 rr.dr.d_type = QType::SOA;
13f9e280 1425 sd.serial = calculateEditSOA(sd.serial, d_dk, sd.qname);
90ba52e0 1426 rr.dr.d_content = makeSOAContent(sd);
90ba52e0 1427 rr.dr.d_ttl = sd.ttl;
1dfd8ada
MZ
1428 rr.domain_id = sd.domain_id;
1429 rr.auth = true;
1430 rrset.push_back(rr);
1431 }
1432
8dee0750 1433
e6a9dde5 1434 DLOG(g_log<<"After first ANY query for '"<<target<<"', id="<<sd.domain_id<<": weDone="<<weDone<<", weHaveUnauth="<<weHaveUnauth<<", weRedirected="<<weRedirected<<", haveAlias='"<<haveAlias<<"'"<<endl);
32d24117
PD
1435 if(p->qtype.getCode() == QType::DS && weHaveUnauth && !weDone && !weRedirected) {
1436 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 1437 makeNOError(p, r, target, DNSName(), sd, 1);
849bd7f1
BH
1438 goto sendit;
1439 }
12c86877 1440
65d2032b 1441 if(!haveAlias.empty() && (!weDone || p->qtype.getCode() == QType::ANY)) {
e6a9dde5 1442 DLOG(g_log<<Logger::Warning<<"Found nothing that matched for '"<<target<<"', but did get alias to '"<<haveAlias<<"', referring"<<endl);
0abea1ca 1443 DP->completePacket(r, haveAlias, target, aliasScopeMask);
d59b894d 1444 return 0;
1445 }
1446
fd65c85d
KM
1447
1448 // referral for DS query
1449 if(p->qtype.getCode() == QType::DS) {
1450 DLOG(g_log<<"Qtype is DS"<<endl);
1451 bool doReferral = true;
1452 if(d_dk.doesDNSSEC()) {
1453 for(auto& loopRR: rrset) {
e7838719
KM
1454 // In a dnssec capable backend auth=true means, there is no delagation at
1455 // or above this qname in this zone (for DS queries). Without a delegation,
1456 // at or above this level, it is pointless to search for refferals.
fd65c85d
KM
1457 if(loopRR.auth) {
1458 doReferral = false;
1459 break;
1460 }
1461 }
1462 } else {
1463 for(auto& loopRR: rrset) {
e7838719
KM
1464 // In a non dnssec capable backend auth is always true, so our only option
1465 // is, always look for referals. Unless there is a direct match for DS.
fd65c85d
KM
1466 if(loopRR.dr.d_type == QType::DS) {
1467 doReferral = false;
1468 break;
1469 }
1470 }
1471 }
1472 if(doReferral) {
e6a9dde5 1473 DLOG(g_log<<"DS query found no direct result, trying referral now"<<endl);
d2323cd0 1474 if(tryReferral(p, r, sd, target, retargetcount))
0a0f4112 1475 {
fd65c85d 1476 DLOG(g_log<<"Got referral for DS query"<<endl);
0a0f4112
PD
1477 goto sendit;
1478 }
1479 }
fd65c85d 1480 }
0a0f4112 1481
d59b894d 1482
fd65c85d 1483 if(rrset.empty()) {
e6a9dde5 1484 DLOG(g_log<<Logger::Warning<<"Found nothing in the by-name ANY, but let's try wildcards.."<<endl);
e3f388cd 1485 bool wereRetargeted(false), nodata(false);
561434a6 1486 DNSName wildcard;
75a89ce6 1487 if(tryWildcard(p, r, sd, target, wildcard, wereRetargeted, nodata)) {
82cc1f71 1488 if(wereRetargeted) {
3e8216c8 1489 if(!retargetcount) r->qdomainwild=wildcard;
82cc1f71
BH
1490 retargetcount++;
1491 goto retargeted;
1492 }
c5c4fbdc
PD
1493 if(nodata)
1494 makeNOError(p, r, target, wildcard, sd, 2);
1495
82cc1f71 1496 goto sendit;
8e50cd4c 1497 }
8dee0750 1498 else if(tryDNAME(p, r, sd, target)) {
1499 retargetcount++;
1500 goto retargeted;
1501 }
a87b7e3f
PD
1502 else
1503 {
c5c4fbdc
PD
1504 if (!(((p->qtype.getCode() == QType::CNAME) || (p->qtype.getCode() == QType::ANY)) && retargetcount > 0))
1505 makeNXDomain(p, r, target, wildcard, sd);
a87b7e3f
PD
1506 }
1507
82cc1f71
BH
1508 goto sendit;
1509 }
232f0877 1510
35fe50c3 1511 if(weRedirected) {
2010ac95
RG
1512 for(auto& loopRR: rrset) {
1513 if(loopRR.dr.d_type == QType::CNAME) {
1514 r->addRecord(loopRR);
1515 target = getRR<CNAMERecordContent>(loopRR.dr)->getTarget();
82cc1f71
BH
1516 retargetcount++;
1517 goto retargeted;
4957a608 1518 }
82cc1f71 1519 }
82cc1f71 1520 }
35fe50c3 1521 else if(weDone) {
b5baefaf 1522 bool haveRecords = false;
2010ac95 1523 for(const auto& loopRR: rrset) {
8900e2e3 1524#ifdef HAVE_LUA_RECORDS
bce078d4 1525 if(loopRR.dr.d_type == QType::LUA)
1526 continue;
8900e2e3 1527#endif
2010ac95
RG
1528 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) {
1529 r->addRecord(loopRR);
b5baefaf
PD
1530 haveRecords = true;
1531 }
82cc1f71 1532 }
4957a608 1533
b5baefaf 1534 if (haveRecords) {
6dbf337f 1535 if(d_dnssec && p->qtype.getCode() == QType::ANY)
b5baefaf 1536 completeANYRecords(p, r, sd, target);
82cc1f71 1537 }
b5baefaf 1538 else
b9817f2b 1539 makeNOError(p, r, target, DNSName(), sd, 0);
4957a608 1540
35fe50c3 1541 goto sendit;
82cc1f71 1542 }
35fe50c3 1543 else if(weHaveUnauth) {
e6a9dde5 1544 DLOG(g_log<<"Have unauth data, so need to hunt for best NS records"<<endl);
d2323cd0 1545 if(tryReferral(p, r, sd, target, retargetcount))
82cc1f71 1546 goto sendit;
2b18bcf3 1547 // check whether this could be fixed easily
90ba52e0 1548 // if (*(rr.dr.d_name.rbegin()) == '.') {
e6a9dde5 1549 // 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 1550 // } else {
e6a9dde5 1551 g_log<<Logger::Error<<"Should not get here ("<<p->qdomain<<"|"<<p->qtype.getCode()<<"): please run pdnsutil rectify-zone "<<sd.qname<<endl;
561434a6 1552 // }
82cc1f71
BH
1553 }
1554 else {
e6a9dde5 1555 DLOG(g_log<<"Have some data, but not the right data"<<endl);
290a083d 1556 makeNOError(p, r, target, DNSName(), sd, 0);
82cc1f71 1557 }
12c86877
BH
1558
1559 sendit:;
d2323cd0 1560 if(doAdditionalProcessingAndDropAA(p, r, sd, retargetcount)<0) {
f3a91936 1561 delete r;
12c86877 1562 return 0;
f3a91936 1563 }
8ea10bfc 1564
2010ac95
RG
1565 for(const auto& loopRR: r->getRRS()) {
1566 if(loopRR.scopeMask) {
bf269e28 1567 noCache=true;
c28bf199 1568 break;
606018f2 1569 }
1570 }
926321a8 1571 if(doSigs)
8d3cbffa 1572 addRRSigs(d_dk, B, authSet, r->getRRS());
f3a91936 1573
e02d0a59 1574 r->wrapup(); // needed for inserting in cache
bf269e28 1575 if(!noCache && p->couldBeCached())
071d2d90 1576 PC.insert(p, r, r->getMinTTL()); // in the packet cache
12c86877
BH
1577 }
1578 catch(DBException &e) {
e6a9dde5 1579 g_log<<Logger::Error<<"Backend reported condition which prevented lookup ("+e.reason+") sending out servfail"<<endl;
25e7af37
KM
1580 delete r;
1581 r=p->replyPacket(); // generate an empty reply packet
12c86877 1582 r->setRcode(RCode::ServFail);
eefd15f9 1583 S.inc("servfail-packets");
eb029b8e 1584 S.ringAccount("servfail-queries", p->qdomain, p->qtype);
12c86877 1585 }
3f81d239 1586 catch(PDNSException &e) {
e6a9dde5 1587 g_log<<Logger::Error<<"Backend reported permanent error which prevented lookup ("+e.reason+"), aborting"<<endl;
31d9bb01 1588 throw; // we WANT to die at this point
86113ac9 1589 }
5172cb78 1590 catch(std::exception &e) {
e6a9dde5 1591 g_log<<Logger::Error<<"Exception building answer packet for "<<p->qdomain<<"/"<<p->qtype.getName()<<" ("<<e.what()<<") sending out servfail"<<endl;
8ea10bfc 1592 delete r;
25e7af37 1593 r=p->replyPacket(); // generate an empty reply packet
8ea10bfc
BH
1594 r->setRcode(RCode::ServFail);
1595 S.inc("servfail-packets");
eb029b8e 1596 S.ringAccount("servfail-queries", p->qdomain, p->qtype);
8ea10bfc 1597 }
12c86877
BH
1598 return r;
1599
1600}