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