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