]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/packethandler.cc
6f18b63d0e31d4ca9daa2df80a78fe0473ab7f69
[thirdparty/pdns.git] / pdns / packethandler.cc
1 /*
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 */
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25 #include "packetcache.hh"
26 #include "utility.hh"
27 #include "base32.hh"
28 #include <string>
29 #include <sys/types.h>
30 #include <boost/algorithm/string.hpp>
31 #include "dnssecinfra.hh"
32 #include "dnsseckeeper.hh"
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"
46 #include "version.hh"
47 #include "common_startup.hh"
48
49 #if 0
50 #undef DLOG
51 #define DLOG(x) x
52 #endif
53
54 AtomicCounter PacketHandler::s_count;
55 NetmaskGroup PacketHandler::s_allowNotifyFrom;
56 set<string> PacketHandler::s_forwardNotify;
57
58 extern string s_programname;
59
60 PacketHandler::PacketHandler():B(s_programname), d_dk(&B)
61 {
62 ++s_count;
63 d_doDNAME=::arg().mustDo("dname-processing");
64 d_doExpandALIAS = ::arg().mustDo("expand-alias");
65 d_logDNSDetails= ::arg().mustDo("log-dns-details");
66 d_doIPv6AdditionalProcessing = ::arg().mustDo("do-ipv6-additional-processing");
67 string fname= ::arg()["lua-prequery-script"];
68 if(fname.empty())
69 {
70 d_pdl = NULL;
71 }
72 else
73 {
74 d_pdl = std::unique_ptr<AuthLua4>(new AuthLua4());
75 d_pdl->loadFile(fname);
76 }
77 fname = ::arg()["lua-dnsupdate-policy-script"];
78 if (fname.empty())
79 {
80 d_update_policy_lua = NULL;
81 }
82 else
83 {
84 d_update_policy_lua = std::unique_ptr<AuthLua4>(new AuthLua4());
85 d_update_policy_lua->loadFile(fname);
86 }
87 }
88
89 UeberBackend *PacketHandler::getBackend()
90 {
91 return &B;
92 }
93
94 PacketHandler::~PacketHandler()
95 {
96 --s_count;
97 DLOG(L<<Logger::Error<<"PacketHandler destructor called - "<<s_count<<" left"<<endl);
98 }
99
100 /**
101 * This adds CDNSKEY records to the answer packet. Returns true if one was added.
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
105 * @param sd SOAData of the zone for which CDNSKEY records sets should be added
106 * @return bool that shows if any records were added
107 **/
108 bool PacketHandler::addCDNSKEY(DNSPacket *p, DNSPacket *r, const SOAData& sd)
109 {
110 string publishCDNSKEY;
111 d_dk.getFromMeta(p->qdomain, "PUBLISH-CDNSKEY", publishCDNSKEY);
112 if (publishCDNSKEY != "1")
113 return false;
114
115 DNSZoneRecord rr;
116 bool haveOne=false;
117
118 DNSSECKeeper::keyset_t entryPoints = d_dk.getEntryPoints(p->qdomain);
119 for(const auto& value: entryPoints) {
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());
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)) {
133 rr.dr.d_ttl=sd.default_ttl;
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 **/
149 bool PacketHandler::addDNSKEY(DNSPacket *p, DNSPacket *r, const SOAData& sd)
150 {
151 DNSZoneRecord rr;
152 bool haveOne=false;
153
154 DNSSECKeeper::keyset_t keyset = d_dk.getKeys(p->qdomain);
155 for(const auto& value: keyset) {
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());
160 rr.auth=true;
161 r->addRecord(rr);
162 haveOne=true;
163 }
164
165 if(::arg().mustDo("direct-dnskey")) {
166 B.lookup(QType(QType::DNSKEY), p->qdomain, p, sd.domain_id);
167
168 while(B.get(rr)) {
169 rr.dr.d_ttl=sd.default_ttl;
170 r->addRecord(rr);
171 haveOne=true;
172 }
173 }
174
175 return haveOne;
176 }
177
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 **/
187 bool PacketHandler::addCDS(DNSPacket *p, DNSPacket *r, const SOAData& sd)
188 {
189 string publishCDS;
190 d_dk.getFromMeta(p->qdomain, "PUBLISH-CDS", publishCDS);
191 if (publishCDS.empty())
192 return false;
193
194 vector<string> digestAlgos;
195 stringtok(digestAlgos, publishCDS, ", ");
196
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;
201 rr.auth=true;
202
203 bool haveOne=false;
204
205 DNSSECKeeper::keyset_t keyset = d_dk.getEntryPoints(p->qdomain);
206
207 for(auto const &value : keyset) {
208 for(auto const &digestAlgo : digestAlgos){
209 rr.dr.d_content=std::make_shared<DSRecordContent>(makeDSFromDNSKey(p->qdomain, value.first.getDNSKEY(), pdns_stou(digestAlgo)));
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)) {
219 rr.dr.d_ttl=sd.default_ttl;
220 r->addRecord(rr);
221 haveOne=true;
222 }
223 }
224
225 return haveOne;
226 }
227
228 /** This adds NSEC3PARAM records. Returns true if one was added */
229 bool PacketHandler::addNSEC3PARAM(DNSPacket *p, DNSPacket *r, const SOAData& sd)
230 {
231 DNSZoneRecord rr;
232
233 NSEC3PARAMRecordContent ns3prc;
234 if(d_dk.getNSEC3PARAM(p->qdomain, &ns3prc)) {
235 rr.dr.d_type=QType::NSEC3PARAM;
236 rr.dr.d_ttl=sd.default_ttl;
237 rr.dr.d_name=p->qdomain;
238 ns3prc.d_flags = 0; // the NSEC3PARAM 'flag' is defined to always be zero in RFC5155.
239 rr.dr.d_content=std::make_shared<NSEC3PARAMRecordContent>(ns3prc);
240 rr.auth = true;
241 r->addRecord(rr);
242 return true;
243 }
244 return false;
245 }
246
247
248 // This is our chaos class requests handler. Return 1 if content was added, 0 if it wasn't
249 int PacketHandler::doChaosRequest(DNSPacket *p, DNSPacket *r, DNSName &target)
250 {
251 DNSZoneRecord rr;
252
253 if(p->qtype.getCode()==QType::TXT) {
254 static const DNSName versionbind("version.bind."), versionpdns("version.pdns."), idserver("id.server.");
255 if (target==versionbind || target==versionpdns) {
256 // modes: full, powerdns only, anonymous or custom
257 const static string mode=::arg()["version-string"];
258 string content;
259 if(mode.empty() || mode=="full")
260 content=fullVersionString();
261 else if(mode=="powerdns")
262 content="Served by PowerDNS - https://www.powerdns.com/";
263 else if(mode=="anonymous") {
264 r->setRcode(RCode::ServFail);
265 return 0;
266 }
267 else
268 content=mode;
269 rr.dr.d_content = DNSRecordContent::mastermake(QType::TXT, 1, "\""+content+"\"");
270 }
271 else if (target==idserver) {
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;
278 }
279 string tid=id;
280 if(!tid.empty() && tid[0]!='"') { // see #6010 however
281 tid = "\"" + tid + "\"";
282 }
283 rr.dr.d_content=DNSRecordContent::mastermake(QType::TXT, 1, tid);
284 }
285 else {
286 r->setRcode(RCode::Refused);
287 return 0;
288 }
289
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;
294 r->addRecord(rr);
295 return 1;
296 }
297
298 r->setRcode(RCode::NotImp);
299 return 0;
300 }
301
302 vector<DNSZoneRecord> PacketHandler::getBestReferralNS(DNSPacket *p, SOAData& sd, const DNSName &target)
303 {
304 vector<DNSZoneRecord> ret;
305 DNSZoneRecord rr;
306 DNSName subdomain(target);
307 do {
308 if(subdomain == sd.qname) // stop at SOA
309 break;
310 B.lookup(QType(QType::NS), subdomain, p, sd.domain_id);
311 while(B.get(rr)) {
312 ret.push_back(rr); // this used to exclude auth NS records for some reason
313 }
314 if(!ret.empty())
315 return ret;
316 } while( subdomain.chopOff() ); // 'www.powerdns.org' -> 'powerdns.org' -> 'org' -> ''
317 return ret;
318 }
319
320 vector<DNSZoneRecord> PacketHandler::getBestDNAMESynth(DNSPacket *p, SOAData& sd, DNSName &target)
321 {
322 vector<DNSZoneRecord> ret;
323 DNSZoneRecord rr;
324 DNSName prefix;
325 DNSName subdomain(target);
326 do {
327 DLOG(L<<"Attempting DNAME lookup for "<<subdomain<<", sd.qname="<<sd.qname<<endl);
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
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));
335 rr.auth = 0; // don't sign CNAME
336 target= getRR<CNAMERecordContent>(rr.dr)->getTarget();
337 ret.push_back(rr);
338 }
339 if(!ret.empty())
340 return ret;
341 if(subdomain.countLabels())
342 prefix.appendRawLabel(subdomain.getRawLabels()[0]); // XXX DNSName pain this feels wrong
343 if(subdomain == sd.qname) // stop at SOA
344 break;
345
346 } while( subdomain.chopOff() ); // 'www.powerdns.org' -> 'powerdns.org' -> 'org' -> ''
347 return ret;
348 }
349
350
351 // Return best matching wildcard or next closer name
352 bool PacketHandler::getBestWildcard(DNSPacket *p, SOAData& sd, const DNSName &target, DNSName &wildcard, vector<DNSZoneRecord>* ret)
353 {
354 ret->clear();
355 DNSZoneRecord rr;
356 DNSName subdomain(target);
357 bool haveSomething=false;
358
359 wildcard=subdomain;
360 while( subdomain.chopOff() && !haveSomething ) {
361 if (subdomain.empty()) {
362 B.lookup(QType(QType::ANY), g_wildcarddnsname, p, sd.domain_id);
363 } else {
364 B.lookup(QType(QType::ANY), g_wildcarddnsname+subdomain, p, sd.domain_id);
365 }
366 while(B.get(rr)) {
367 if(rr.dr.d_type == p->qtype.getCode() || rr.dr.d_type == QType::CNAME || (p->qtype.getCode() == QType::ANY && rr.dr.d_type != QType::RRSIG))
368 ret->push_back(rr);
369 wildcard=g_wildcarddnsname+subdomain;
370 haveSomething=true;
371 }
372
373 if ( subdomain == sd.qname || haveSomething ) // stop at SOA or result
374 break;
375
376 B.lookup(QType(QType::ANY), subdomain, p, sd.domain_id);
377 if (B.get(rr)) {
378 DLOG(L<<"No wildcard match, ancestor exists"<<endl);
379 while (B.get(rr)) ;
380 break;
381 }
382 wildcard=subdomain;
383 }
384
385 return haveSomething;
386 }
387
388 /** dangling is declared true if we were unable to resolve everything */
389 int PacketHandler::doAdditionalProcessingAndDropAA(DNSPacket *p, DNSPacket *r, const SOAData& soadata, bool retargeted)
390 {
391 DNSZoneRecord rr;
392 SOAData sd;
393 sd.db=0;
394
395 if(p->qtype.getCode()!=QType::AXFR) { // this packet needs additional processing
396 // we now have a copy, push_back on packet might reallocate!
397 auto& records = r->getRRS();
398 vector<DNSZoneRecord> toAdd;
399
400 for(auto i = records.cbegin() ; i!= records.cend(); ++i) {
401 if(i->dr.d_place==DNSResourceRecord::ADDITIONAL ||
402 !(i->dr.d_type==QType::MX || i->dr.d_type==QType::NS || i->dr.d_type==QType::SRV))
403 continue;
404
405 if(r->d.aa && i->dr.d_name.countLabels() && i->dr.d_type==QType::NS && !B.getSOA(i->dr.d_name,sd) && !retargeted) { // drop AA in case of non-SOA-level NS answer, except for root referral
406 r->setA(false);
407 // i->d_place=DNSResourceRecord::AUTHORITY; // XXX FIXME
408 }
409
410 DNSName lookup;
411
412 if(i->dr.d_type == QType::MX)
413 lookup = getRR<MXRecordContent>(i->dr)->d_mxname;
414 else if(i->dr.d_type == QType::SRV)
415 lookup = getRR<SRVRecordContent>(i->dr)->d_target;
416 else if(i->dr.d_type == QType::NS)
417 lookup = getRR<NSRecordContent>(i->dr)->getNS();
418 else
419 continue;
420 B.lookup(QType(d_doIPv6AdditionalProcessing ? QType::ANY : QType::A), lookup, p);
421
422 while(B.get(rr)) {
423 if(rr.dr.d_type != QType::A && rr.dr.d_type!=QType::AAAA)
424 continue;
425 if(rr.domain_id!=i->domain_id && ::arg()["out-of-zone-additional-processing"]=="no") {
426 DLOG(L<<Logger::Warning<<"Not including out-of-zone additional processing of "<<i->dr.d_name<<" ("<<rr.dr.d_name<<")"<<endl);
427 continue; // not adding out-of-zone additional data
428 }
429
430 if(rr.auth && !rr.dr.d_name.isPartOf(soadata.qname)) // don't sign out of zone data using the main key
431 rr.auth=false;
432 rr.dr.d_place=DNSResourceRecord::ADDITIONAL;
433 toAdd.push_back(rr);
434 }
435 }
436 for(const auto& rec : toAdd)
437 r->addRecord(rec);
438
439 //records.insert(records.end(), toAdd.cbegin(), toAdd.cend()); // would be faster, but no dedup
440 }
441 return 1;
442 }
443
444
445 void PacketHandler::emitNSEC(DNSPacket *r, const SOAData& sd, const DNSName& name, const DNSName& next, int mode)
446 {
447 NSECRecordContent nrc;
448 nrc.d_next = next;
449
450 nrc.d_set.insert(QType::NSEC);
451 nrc.d_set.insert(QType::RRSIG);
452 if(sd.qname == name) {
453 nrc.d_set.insert(QType::SOA); // 1dfd8ad SOA can live outside the records table
454 nrc.d_set.insert(QType::DNSKEY);
455 string publishCDNSKEY;
456 d_dk.getFromMeta(name, "PUBLISH-CDNSKEY", publishCDNSKEY);
457 if (publishCDNSKEY == "1")
458 nrc.d_set.insert(QType::CDNSKEY);
459 string publishCDS;
460 d_dk.getFromMeta(name, "PUBLISH-CDS", publishCDS);
461 if (! publishCDS.empty())
462 nrc.d_set.insert(QType::CDS);
463 }
464
465 DNSZoneRecord rr;
466
467 B.lookup(QType(QType::ANY), name, NULL, sd.domain_id);
468 while(B.get(rr)) {
469 if(rr.dr.d_type == QType::NS || rr.auth)
470 nrc.d_set.insert(rr.dr.d_type);
471 }
472
473 rr.dr.d_name = name;
474 rr.dr.d_ttl = sd.default_ttl;
475 rr.dr.d_type = QType::NSEC;
476 rr.dr.d_content = std::make_shared<NSECRecordContent>(nrc);
477 rr.dr.d_place = (mode == 5 ) ? DNSResourceRecord::ANSWER: DNSResourceRecord::AUTHORITY;
478 rr.auth = true;
479
480 r->addRecord(rr);
481 }
482
483 void PacketHandler::emitNSEC3(DNSPacket *r, const SOAData& sd, const NSEC3PARAMRecordContent& ns3prc, const DNSName& name, const string& namehash, const string& nexthash, int mode)
484 {
485 NSEC3RecordContent n3rc;
486 n3rc.d_algorithm = ns3prc.d_algorithm;
487 n3rc.d_flags = ns3prc.d_flags;
488 n3rc.d_iterations = ns3prc.d_iterations;
489 n3rc.d_salt = ns3prc.d_salt;
490 n3rc.d_nexthash = nexthash;
491
492 DNSZoneRecord rr;
493
494 if(!name.empty()) {
495 if (sd.qname == name) {
496 n3rc.d_set.insert(QType::SOA); // 1dfd8ad SOA can live outside the records table
497 n3rc.d_set.insert(QType::NSEC3PARAM);
498 n3rc.d_set.insert(QType::DNSKEY);
499 string publishCDNSKEY;
500 d_dk.getFromMeta(name, "PUBLISH-CDNSKEY", publishCDNSKEY);
501 if (publishCDNSKEY == "1")
502 n3rc.d_set.insert(QType::CDNSKEY);
503 string publishCDS;
504 d_dk.getFromMeta(name, "PUBLISH-CDS", publishCDS);
505 if (! publishCDS.empty())
506 n3rc.d_set.insert(QType::CDS);
507 }
508
509 B.lookup(QType(QType::ANY), name, NULL, sd.domain_id);
510 while(B.get(rr)) {
511 if(rr.dr.d_type && (rr.dr.d_type == QType::NS || rr.auth)) // skip empty non-terminals
512 n3rc.d_set.insert(rr.dr.d_type);
513 }
514 }
515
516 if (n3rc.d_set.size() && !(n3rc.d_set.size() == 1 && n3rc.d_set.count(QType::NS)))
517 n3rc.d_set.insert(QType::RRSIG);
518
519 rr.dr.d_name = DNSName(toBase32Hex(namehash))+sd.qname;
520 rr.dr.d_ttl = sd.default_ttl;
521 rr.dr.d_type=QType::NSEC3;
522 rr.dr.d_content=std::make_shared<NSEC3RecordContent>(n3rc);
523 rr.dr.d_place = (mode == 5 ) ? DNSResourceRecord::ANSWER: DNSResourceRecord::AUTHORITY;
524 rr.auth = true;
525
526 r->addRecord(rr);
527 }
528
529 /*
530 mode 0 = No Data Responses, QTYPE is not DS
531 mode 1 = No Data Responses, QTYPE is DS
532 mode 2 = Wildcard No Data Responses
533 mode 3 = Wildcard Answer Responses
534 mode 4 = Name Error Responses
535 mode 5 = Direct NSEC request
536 */
537 void PacketHandler::addNSECX(DNSPacket *p, DNSPacket *r, const DNSName& target, const DNSName& wildcard, const DNSName& auth, int mode)
538 {
539 if(!p->d_dnssecOk && mode != 5)
540 return;
541
542 NSEC3PARAMRecordContent ns3rc;
543 bool narrow;
544 if(d_dk.getNSEC3PARAM(auth, &ns3rc, &narrow)) {
545 if (mode != 5) // no direct NSEC3 queries, rfc5155 7.2.8
546 addNSEC3(p, r, target, wildcard, auth, ns3rc, narrow, mode);
547 }
548 else {
549 addNSEC(p, r, target, wildcard, auth, mode);
550 }
551 }
552
553 bool getNSEC3Hashes(bool narrow, DNSBackend* db, int id, const std::string& hashed, bool decrement, DNSName& unhashed, std::string& before, std::string& after, int mode)
554 {
555 bool ret;
556 if(narrow) { // nsec3-narrow
557 ret=true;
558 before=hashed;
559 if(decrement) {
560 decrementHash(before);
561 unhashed.clear();
562 }
563 after=hashed;
564 incrementHash(after);
565 }
566 else {
567 DNSName hashedName = DNSName(toBase32Hex(hashed));
568 DNSName beforeName, afterName;
569 if (!decrement && mode >= 2)
570 beforeName = hashedName;
571 ret=db->getBeforeAndAfterNamesAbsolute(id, hashedName, unhashed, beforeName, afterName);
572 before=fromBase32Hex(beforeName.toString());
573 after=fromBase32Hex(afterName.toString());
574 }
575 return ret;
576 }
577
578 void PacketHandler::addNSEC3(DNSPacket *p, DNSPacket *r, const DNSName& target, const DNSName& wildcard, const DNSName& auth, const NSEC3PARAMRecordContent& ns3rc, bool narrow, int mode)
579 {
580 DLOG(L<<"addNSEC3() mode="<<mode<<" auth="<<auth<<" target="<<target<<" wildcard="<<wildcard<<endl);
581
582 SOAData sd;
583 if(!B.getSOAUncached(auth, sd)) {
584 DLOG(L<<"Could not get SOA for domain");
585 return;
586 }
587
588 bool doNextcloser = false;
589 string before, after, hashed;
590 DNSName unhashed, closest;
591
592 if (mode == 2 || mode == 3 || mode == 4) {
593 closest=wildcard;
594 closest.chopOff();
595 } else
596 closest=target;
597
598 // add matching NSEC3 RR
599 if (mode != 3) {
600 unhashed=(mode == 0 || mode == 1 || mode == 5) ? target : closest;
601 hashed=hashQNameWithSalt(ns3rc, unhashed);
602 DLOG(L<<"1 hash: "<<toBase32Hex(hashed)<<" "<<unhashed<<endl);
603
604 getNSEC3Hashes(narrow, sd.db, sd.domain_id, hashed, false, unhashed, before, after, mode);
605
606 if (((mode == 0 && ns3rc.d_flags) || mode == 1) && (hashed != before)) {
607 DLOG(L<<"No matching NSEC3, do closest (provable) encloser"<<endl);
608
609 bool doBreak = false;
610 DNSZoneRecord rr;
611 while( closest.chopOff() && (closest != sd.qname)) { // stop at SOA
612 B.lookup(QType(QType::ANY), closest, p, sd.domain_id);
613 while(B.get(rr))
614 if (rr.auth)
615 doBreak = true;
616 if(doBreak)
617 break;
618 }
619 doNextcloser = true;
620 unhashed=closest;
621 hashed=hashQNameWithSalt(ns3rc, unhashed);
622 DLOG(L<<"1 hash: "<<toBase32Hex(hashed)<<" "<<unhashed<<endl);
623
624 getNSEC3Hashes(narrow, sd.db, sd.domain_id, hashed, false, unhashed, before, after);
625 }
626
627 if (!after.empty()) {
628 DLOG(L<<"Done calling for matching, hashed: '"<<toBase32Hex(hashed)<<"' before='"<<toBase32Hex(before)<<"', after='"<<toBase32Hex(after)<<"'"<<endl);
629 emitNSEC3(r, sd, ns3rc, unhashed, before, after, mode);
630 }
631 }
632
633 // add covering NSEC3 RR
634 if ((mode >= 2 && mode <= 4) || doNextcloser) {
635 DNSName next(target);
636 do {
637 unhashed=next;
638 }
639 while( next.chopOff() && !(next==closest));
640
641 hashed=hashQNameWithSalt(ns3rc, unhashed);
642 DLOG(L<<"2 hash: "<<toBase32Hex(hashed)<<" "<<unhashed<<endl);
643
644 getNSEC3Hashes(narrow, sd.db,sd.domain_id, hashed, true, unhashed, before, after);
645 DLOG(L<<"Done calling for covering, hashed: '"<<toBase32Hex(hashed)<<"' before='"<<toBase32Hex(before)<<"', after='"<<toBase32Hex(after)<<"'"<<endl);
646 emitNSEC3( r, sd, ns3rc, unhashed, before, after, mode);
647 }
648
649 // wildcard denial
650 if (mode == 2 || mode == 4) {
651 unhashed=g_wildcarddnsname+closest;
652
653 hashed=hashQNameWithSalt(ns3rc, unhashed);
654 DLOG(L<<"3 hash: "<<toBase32Hex(hashed)<<" "<<unhashed<<endl);
655
656 getNSEC3Hashes(narrow, sd.db, sd.domain_id, hashed, (mode != 2), unhashed, before, after);
657 DLOG(L<<"Done calling for '*', hashed: '"<<toBase32Hex(hashed)<<"' before='"<<toBase32Hex(before)<<"', after='"<<toBase32Hex(after)<<"'"<<endl);
658 emitNSEC3( r, sd, ns3rc, unhashed, before, after, mode);
659 }
660 }
661
662 void PacketHandler::addNSEC(DNSPacket *p, DNSPacket *r, const DNSName& target, const DNSName& wildcard, const DNSName& auth, int mode)
663 {
664 DLOG(L<<"addNSEC() mode="<<mode<<" auth="<<auth<<" target="<<target<<" wildcard="<<wildcard<<endl);
665
666 SOAData sd;
667 if(!B.getSOAUncached(auth, sd)) {
668 DLOG(L<<"Could not get SOA for domain"<<endl);
669 return;
670 }
671
672 DNSName before,after;
673 sd.db->getBeforeAndAfterNames(sd.domain_id, auth, target, before, after);
674 if (mode != 5 || before == target)
675 emitNSEC(r, sd, before, after, mode);
676
677 if (mode == 2 || mode == 4) {
678 // wildcard NO-DATA or wildcard denial
679 before.clear();
680 DNSName closest(wildcard);
681 if (mode == 4) {
682 closest.chopOff();
683 closest.prependRawLabel("*");
684 }
685 sd.db->getBeforeAndAfterNames(sd.domain_id, auth, closest, before, after);
686 emitNSEC(r, sd, before, after, mode);
687 }
688 return;
689 }
690
691 /* Semantics:
692
693 - only one backend owns the SOA of a zone
694 - only one AXFR per zone at a time - double startTransaction should fail
695 - backends need to implement transaction semantics
696
697
698 How BindBackend would implement this:
699 startTransaction makes a file
700 feedRecord sends everything to that file
701 commitTransaction moves that file atomically over the regular file, and triggers a reload
702 rollbackTransaction removes the file
703
704
705 How PostgreSQLBackend would implement this:
706 startTransaction starts a sql transaction, which also deletes all records
707 feedRecord is an insert statement
708 commitTransaction commits the transaction
709 rollbackTransaction aborts it
710
711 How MySQLBackend would implement this:
712 (good question!)
713
714 */
715
716 int PacketHandler::trySuperMaster(DNSPacket *p, const DNSName& tsigkeyname)
717 {
718 if(p->d_tcp)
719 {
720 // do it right now if the client is TCP
721 // rarely happens
722 return trySuperMasterSynchronous(p, tsigkeyname);
723 }
724 else
725 {
726 // queue it if the client is on UDP
727 Communicator.addTrySuperMasterRequest(p);
728 return 0;
729 }
730 }
731
732 int PacketHandler::trySuperMasterSynchronous(DNSPacket *p, const DNSName& tsigkeyname)
733 {
734 string remote = p->getRemote().toString();
735 if(p->hasEDNSSubnet() && ::arg().contains("trusted-notification-proxy", remote)) {
736 remote = p->getRealRemote().toStringNoMask();
737 }
738
739 Resolver::res_t nsset;
740 try {
741 Resolver resolver;
742 uint32_t theirserial;
743 resolver.getSoaSerial(remote,p->qdomain, &theirserial);
744 resolver.resolve(remote, p->qdomain, QType::NS, &nsset);
745 }
746 catch(ResolverException &re) {
747 L<<Logger::Error<<"Error resolving SOA or NS for "<<p->qdomain<<" at: "<< remote <<": "<<re.reason<<endl;
748 return RCode::ServFail;
749 }
750
751 // check if the returned records are NS records
752 bool haveNS=false;
753 for(const auto& ns: nsset) {
754 if(ns.qtype==QType::NS)
755 haveNS=true;
756 }
757
758 if(!haveNS) {
759 L<<Logger::Error<<"While checking for supermaster, did not find NS for "<<p->qdomain<<" at: "<< remote <<endl;
760 return RCode::ServFail;
761 }
762
763 string nameserver, account;
764 DNSBackend *db;
765
766 if (!::arg().mustDo("allow-unsigned-supermaster") && tsigkeyname.empty()) {
767 L<<Logger::Error<<"Received unsigned NOTIFY for "<<p->qdomain<<" from potential supermaster "<<remote<<". Refusing."<<endl;
768 return RCode::Refused;
769 }
770
771 if(!B.superMasterBackend(remote, p->qdomain, nsset, &nameserver, &account, &db)) {
772 L<<Logger::Error<<"Unable to find backend willing to host "<<p->qdomain<<" for potential supermaster "<<remote<<". Remote nameservers: "<<endl;
773 for(const auto& rr: nsset) {
774 if(rr.qtype==QType::NS)
775 L<<Logger::Error<<rr.content<<endl;
776 }
777 return RCode::Refused;
778 }
779 try {
780 db->createSlaveDomain(p->getRemote().toString(), p->qdomain, nameserver, account);
781 if (tsigkeyname.empty() == false) {
782 vector<string> meta;
783 meta.push_back(tsigkeyname.toStringNoDot());
784 db->setDomainMetadata(p->qdomain, "AXFR-MASTER-TSIG", meta);
785 }
786 }
787 catch(PDNSException& ae) {
788 L<<Logger::Error<<"Database error trying to create "<<p->qdomain<<" for potential supermaster "<<remote<<": "<<ae.reason<<endl;
789 return RCode::ServFail;
790 }
791 L<<Logger::Warning<<"Created new slave zone '"<<p->qdomain<<"' from supermaster "<<remote<<endl;
792 return RCode::NoError;
793 }
794
795 int PacketHandler::processNotify(DNSPacket *p)
796 {
797 /* now what?
798 was this notification from an approved address?
799 was this notification approved by TSIG?
800 We determine our internal SOA id (via UeberBackend)
801 We determine the SOA at our (known) master
802 if master is higher -> do stuff
803 */
804 vector<string> meta;
805
806 if(!::arg().mustDo("slave") && s_forwardNotify.empty()) {
807 L<<Logger::Error<<"Received NOTIFY for "<<p->qdomain<<" from "<<p->getRemote()<<" but slave support is disabled in the configuration"<<endl;
808 return RCode::NotImp;
809 }
810
811 if(!s_allowNotifyFrom.match((ComboAddress *) &p->d_remote ) || p->d_havetsig) {
812 if (p->d_havetsig && p->getTSIGKeyname().empty() == false) {
813 L<<Logger::Notice<<"Received secure NOTIFY for "<<p->qdomain<<" from "<<p->getRemote()<<", allowed by TSIG key '"<<p->getTSIGKeyname()<<"'"<<endl;
814 } else {
815 L<<Logger::Error<<"Received NOTIFY for "<<p->qdomain<<" from "<<p->getRemote()<<" but remote is not permitted by TSIG or allow-notify-from"<<endl;
816 return RCode::Refused;
817 }
818 }
819
820 DNSBackend *db=0;
821 DomainInfo di;
822 di.serial = 0;
823 if(!B.getDomainInfo(p->qdomain, di) || !(db=di.backend)) {
824 L<<Logger::Error<<"Received NOTIFY for "<<p->qdomain<<" from "<<p->getRemote()<<" for which we are not authoritative"<<endl;
825 return trySuperMaster(p, p->getTSIGKeyname());
826 }
827
828 meta.clear();
829 if (B.getDomainMetadata(p->qdomain,"AXFR-MASTER-TSIG",meta) && meta.size() > 0) {
830 if (!p->d_havetsig) {
831 if (::arg().mustDo("allow-unsigned-notify")) {
832 L<<Logger::Warning<<"Received unsigned NOTIFY for "<<p->qdomain<<" from "<<p->getRemote()<<": permitted because allow-unsigned-notify";
833 } else {
834 L<<Logger::Warning<<"Received unsigned NOTIFY for "<<p->qdomain<<" from "<<p->getRemote()<<": refused"<<endl;
835 return RCode::Refused;
836 }
837 } else if (meta[0] != p->getTSIGKeyname().toStringNoDot()) {
838 L<<Logger::Error<<"Received secure NOTIFY for "<<p->qdomain<<" from "<<p->getRemote()<<": expected TSIG key '"<<meta[0]<<", got '"<<p->getTSIGKeyname()<<"'"<<endl;
839 return RCode::Refused;
840 }
841 }
842
843 if(::arg().contains("trusted-notification-proxy", p->getRemote().toString())) {
844 L<<Logger::Error<<"Received NOTIFY for "<<p->qdomain<<" from trusted-notification-proxy "<< p->getRemote()<<endl;
845 if(di.masters.empty()) {
846 L<<Logger::Error<<"However, "<<p->qdomain<<" does not have any masters defined"<<endl;
847 return RCode::Refused;
848 }
849 }
850 else if(::arg().mustDo("master") && di.kind == DomainInfo::Master) {
851 L<<Logger::Error<<"Received NOTIFY for "<<p->qdomain<<" from "<<p->getRemote()<<" but we are master, rejecting"<<endl;
852 return RCode::Refused;
853 }
854 else if(!db->isMaster(p->qdomain, p->getRemote().toString())) {
855 L<<Logger::Error<<"Received NOTIFY for "<<p->qdomain<<" from "<<p->getRemote()<<" which is not a master"<<endl;
856 return RCode::Refused;
857 }
858
859 // ok, we've done our checks
860 di.backend = 0;
861
862 if(!s_forwardNotify.empty()) {
863 set<string> forwardNotify(s_forwardNotify);
864 for(set<string>::const_iterator j=forwardNotify.begin();j!=forwardNotify.end();++j) {
865 L<<Logger::Warning<<"Relaying notification of domain "<<p->qdomain<<" from "<<p->getRemote()<<" to "<<*j<<endl;
866 Communicator.notify(p->qdomain,*j);
867 }
868 }
869
870 if(::arg().mustDo("slave"))
871 Communicator.addSlaveCheckRequest(di, p->d_remote);
872 return 0;
873 }
874
875 bool validDNSName(const DNSName &name)
876 {
877 if (!g_8bitDNS) {
878 string::size_type pos, length;
879 char c;
880 for(const auto& s : name.getRawLabels()) {
881 length=s.length();
882 for(pos=0; pos < length; ++pos) {
883 c=s[pos];
884 if(!((c >= 'a' && c <= 'z') ||
885 (c >= 'A' && c <= 'Z') ||
886 (c >= '0' && c <= '9') ||
887 c =='-' || c == '_' || c=='*' || c=='.' || c=='/' || c=='@' || c==' ' || c=='\\' || c==':'))
888 return false;
889 }
890 }
891 }
892 return true;
893 }
894
895 DNSPacket *PacketHandler::question(DNSPacket *p)
896 {
897 DNSPacket *ret;
898
899 if(d_pdl)
900 {
901 ret=d_pdl->prequery(p);
902 if(ret)
903 return ret;
904 }
905
906 if(p->d.rd) {
907 static AtomicCounter &rdqueries=*S.getPointer("rd-queries");
908 rdqueries++;
909 }
910
911 return doQuestion(p);
912 }
913
914
915 void PacketHandler::makeNXDomain(DNSPacket* p, DNSPacket* r, const DNSName& target, const DNSName& wildcard, SOAData& sd)
916 {
917 DNSZoneRecord rr;
918 rr.dr.d_name=sd.qname;
919 rr.dr.d_type=QType::SOA;
920
921 rr.dr.d_content=makeSOAContent(sd);
922 rr.dr.d_ttl=min(sd.ttl, sd.default_ttl);
923 rr.signttl=sd.ttl;
924 rr.domain_id=sd.domain_id;
925 rr.dr.d_place=DNSResourceRecord::AUTHORITY;
926 rr.auth = 1;
927 rr.scopeMask = sd.scopeMask;
928 r->addRecord(rr);
929
930 if(d_dk.isSecuredZone(sd.qname))
931 addNSECX(p, r, target, wildcard, sd.qname, 4);
932
933 r->setRcode(RCode::NXDomain);
934 }
935
936 void PacketHandler::makeNOError(DNSPacket* p, DNSPacket* r, const DNSName& target, const DNSName& wildcard, SOAData& sd, int mode)
937 {
938 DNSZoneRecord rr;
939 rr.dr.d_name=sd.qname;
940 rr.dr.d_type=QType::SOA;
941 rr.dr.d_content=makeSOAContent(sd);
942 rr.dr.d_ttl=sd.ttl;
943 rr.dr.d_ttl=min(sd.ttl, sd.default_ttl);
944 rr.signttl=sd.ttl;
945 rr.domain_id=sd.domain_id;
946 rr.dr.d_place=DNSResourceRecord::AUTHORITY;
947 rr.auth = 1;
948 r->addRecord(rr);
949
950 if(d_dk.isSecuredZone(sd.qname))
951 addNSECX(p, r, target, wildcard, sd.qname, mode);
952
953 S.ringAccount("noerror-queries",p->qdomain.toLogString()+"/"+p->qtype.getName());
954 }
955
956
957 bool PacketHandler::addDSforNS(DNSPacket* p, DNSPacket* r, SOAData& sd, const DNSName& dsname)
958 {
959 //cerr<<"Trying to find a DS for '"<<dsname<<"', domain_id = "<<sd.domain_id<<endl;
960 B.lookup(QType(QType::DS), dsname, p, sd.domain_id);
961 DNSZoneRecord rr;
962 bool gotOne=false;
963 while(B.get(rr)) {
964 gotOne=true;
965 rr.dr.d_place = DNSResourceRecord::AUTHORITY;
966 r->addRecord(rr);
967 }
968 return gotOne;
969 }
970
971 bool PacketHandler::tryReferral(DNSPacket *p, DNSPacket*r, SOAData& sd, const DNSName &target, bool retargeted)
972 {
973 vector<DNSZoneRecord> rrset = getBestReferralNS(p, sd, target);
974 if(rrset.empty())
975 return false;
976
977 for(auto& rr: rrset) {
978 rr.dr.d_place=DNSResourceRecord::AUTHORITY;
979 r->addRecord(rr);
980 }
981 if(!retargeted)
982 r->setA(false);
983
984 if(d_dk.isSecuredZone(sd.qname) && !addDSforNS(p, r, sd, rrset.begin()->dr.d_name))
985 addNSECX(p, r, rrset.begin()->dr.d_name, DNSName(), sd.qname, 1);
986
987 return true;
988 }
989
990 void PacketHandler::completeANYRecords(DNSPacket *p, DNSPacket*r, SOAData& sd, const DNSName &target)
991 {
992 if(!p->d_dnssecOk)
993 return; // Don't send dnssec info to non validating resolvers.
994
995 if(!d_dk.isSecuredZone(sd.qname))
996 return;
997
998 addNSECX(p, r, target, DNSName(), sd.qname, 5);
999 if(sd.qname == p->qdomain) {
1000 addDNSKEY(p, r, sd);
1001 addCDNSKEY(p, r, sd);
1002 addCDS(p, r, sd);
1003 addNSEC3PARAM(p, r, sd);
1004 }
1005 }
1006
1007 bool PacketHandler::tryDNAME(DNSPacket *p, DNSPacket*r, SOAData& sd, DNSName &target)
1008 {
1009 if(!d_doDNAME)
1010 return false;
1011 DLOG(L<<Logger::Warning<<"Let's try DNAME.."<<endl);
1012 vector<DNSZoneRecord> rrset = getBestDNAMESynth(p, sd, target);
1013 if(!rrset.empty()) {
1014 for(auto& rr: rrset) {
1015 rr.dr.d_place = DNSResourceRecord::ANSWER;
1016 r->addRecord(rr);
1017 }
1018 return true;
1019 }
1020 return false;
1021 }
1022 bool PacketHandler::tryWildcard(DNSPacket *p, DNSPacket*r, SOAData& sd, DNSName &target, DNSName &wildcard, bool& retargeted, bool& nodata)
1023 {
1024 retargeted = nodata = false;
1025 DNSName bestmatch;
1026
1027 vector<DNSZoneRecord> rrset;
1028 if(!getBestWildcard(p, sd, target, wildcard, &rrset))
1029 return false;
1030
1031 if(rrset.empty()) {
1032 DLOG(L<<"Wildcard matched something, but not of the correct type"<<endl);
1033 nodata=true;
1034 }
1035 else {
1036 for(auto& rr: rrset) {
1037 rr.wildcardname = rr.dr.d_name;
1038 rr.dr.d_name=bestmatch=target;
1039
1040 if(rr.dr.d_type == QType::CNAME) {
1041 retargeted=true;
1042 target=getRR<CNAMERecordContent>(rr.dr)->getTarget();
1043 }
1044
1045 rr.dr.d_place=DNSResourceRecord::ANSWER;
1046 r->addRecord(rr);
1047 }
1048 }
1049 if(d_dk.isSecuredZone(sd.qname) && !nodata) {
1050 addNSECX(p, r, bestmatch, wildcard, sd.qname, 3);
1051 }
1052 return true;
1053 }
1054
1055 //! Called by the Distributor to ask a question. Returns 0 in case of an error
1056 DNSPacket *PacketHandler::doQuestion(DNSPacket *p)
1057 {
1058 DNSZoneRecord rr;
1059 SOAData sd;
1060
1061 int retargetcount=0;
1062 set<DNSName> authSet;
1063
1064 vector<DNSZoneRecord> rrset;
1065 bool weDone=0, weRedirected=0, weHaveUnauth=0;
1066 DNSName haveAlias;
1067
1068 DNSPacket *r=0;
1069 bool noCache=false;
1070
1071 if(p->d.qr) { // QR bit from dns packet (thanks RA from N)
1072 if(d_logDNSDetails)
1073 L<<Logger::Error<<"Received an answer (non-query) packet from "<<p->getRemote()<<", dropping"<<endl;
1074 S.inc("corrupt-packets");
1075 S.ringAccount("remotes-corrupt", p->d_remote);
1076 return 0;
1077 }
1078
1079 if(p->d.tc) { // truncated query. MOADNSParser would silently parse this packet in an incomplete way.
1080 if(d_logDNSDetails)
1081 L<<Logger::Error<<"Received truncated query packet from "<<p->getRemote()<<", dropping"<<endl;
1082 S.inc("corrupt-packets");
1083 S.ringAccount("remotes-corrupt", p->d_remote);
1084 return 0;
1085 }
1086
1087 if (p->hasEDNS() && p->getEDNSVersion() > 0) {
1088 r = p->replyPacket();
1089 r->setRcode(16 & 0xF);
1090 r->setEDNSRcode((16 & 0xFFF0)>>4); // set rcode to BADVERS
1091 return r;
1092 }
1093
1094 if(p->d_havetsig) {
1095 DNSName keyname;
1096 string secret;
1097 TSIGRecordContent trc;
1098 if(!p->checkForCorrectTSIG(&B, &keyname, &secret, &trc)) {
1099 r=p->replyPacket(); // generate an empty reply packet
1100 if(d_logDNSDetails)
1101 L<<Logger::Error<<"Received a TSIG signed message with a non-validating key"<<endl;
1102 // RFC3007 describes that a non-secure message should be sending Refused for DNS Updates
1103 if (p->d.opcode == Opcode::Update)
1104 r->setRcode(RCode::Refused);
1105 else
1106 r->setRcode(RCode::NotAuth);
1107 return r;
1108 } else {
1109 getTSIGHashEnum(trc.d_algoName, p->d_tsig_algo);
1110 if (p->d_tsig_algo == TSIG_GSS) {
1111 GssContext gssctx(keyname);
1112 if (!gssctx.getPeerPrincipal(p->d_peer_principal)) {
1113 L<<Logger::Warning<<"Failed to extract peer principal from GSS context with keyname '"<<keyname<<"'"<<endl;
1114 }
1115 }
1116 }
1117 p->setTSIGDetails(trc, keyname, secret, trc.d_mac); // this will get copied by replyPacket()
1118 noCache=true;
1119 }
1120
1121 r=p->replyPacket(); // generate an empty reply packet, possibly with TSIG details inside
1122
1123 if (p->qtype == QType::TKEY) {
1124 this->tkeyHandler(p, r);
1125 return r;
1126 }
1127
1128 try {
1129
1130 // XXX FIXME do this in DNSPacket::parse ?
1131
1132 if(!validDNSName(p->qdomain)) {
1133 if(d_logDNSDetails)
1134 L<<Logger::Error<<"Received a malformed qdomain from "<<p->getRemote()<<", '"<<p->qdomain<<"': sending servfail"<<endl;
1135 S.inc("corrupt-packets");
1136 S.ringAccount("remotes-corrupt", p->d_remote);
1137 S.inc("servfail-packets");
1138 r->setRcode(RCode::ServFail);
1139 return r;
1140 }
1141 if(p->d.opcode) { // non-zero opcode (again thanks RA!)
1142 if(p->d.opcode==Opcode::Update) {
1143 S.inc("dnsupdate-queries");
1144 int res=processUpdate(p);
1145 if (res == RCode::Refused)
1146 S.inc("dnsupdate-refused");
1147 else if (res != RCode::ServFail)
1148 S.inc("dnsupdate-answers");
1149 r->setRcode(res);
1150 r->setOpcode(Opcode::Update);
1151 return r;
1152 }
1153 else if(p->d.opcode==Opcode::Notify) {
1154 S.inc("incoming-notifications");
1155 int res=processNotify(p);
1156 if(res>=0) {
1157 r->setRcode(res);
1158 r->setOpcode(Opcode::Notify);
1159 return r;
1160 }
1161 delete r;
1162 return 0;
1163 }
1164
1165 L<<Logger::Error<<"Received an unknown opcode "<<p->d.opcode<<" from "<<p->getRemote()<<" for "<<p->qdomain<<endl;
1166
1167 r->setRcode(RCode::NotImp);
1168 return r;
1169 }
1170
1171 // L<<Logger::Warning<<"Query for '"<<p->qdomain<<"' "<<p->qtype.getName()<<" from "<<p->getRemote()<< " (tcp="<<p->d_tcp<<")"<<endl;
1172
1173 if(p->qtype.getCode()==QType::IXFR) {
1174 r->setRcode(RCode::Refused);
1175 return r;
1176 }
1177
1178 DNSName target=p->qdomain;
1179
1180 // catch chaos qclass requests
1181 if(p->qclass == QClass::CHAOS) {
1182 if (doChaosRequest(p,r,target))
1183 goto sendit;
1184 else
1185 return r;
1186 }
1187
1188 // we only know about qclass IN (and ANY), send Refused for everything else.
1189 if(p->qclass != QClass::IN && p->qclass!=QClass::ANY) {
1190 r->setRcode(RCode::Refused);
1191 return r;
1192 }
1193
1194 // send TC for udp ANY query if any-to-tcp is enabled.
1195 if(p->qtype.getCode() == QType::ANY && !p->d_tcp && g_anyToTcp) {
1196 r->d.tc = 1;
1197 r->commitD();
1198 return r;
1199 }
1200
1201 // for qclass ANY the response should never be authoritative unless the response covers all classes.
1202 if(p->qclass==QClass::ANY)
1203 r->setA(false);
1204
1205
1206 retargeted:;
1207 if(retargetcount > 10) { // XXX FIXME, retargetcount++?
1208 L<<Logger::Warning<<"Abort CNAME chain resolution after "<<--retargetcount<<" redirects, sending out servfail. Initial query: '"<<p->qdomain<<"'"<<endl;
1209 delete r;
1210 r=p->replyPacket();
1211 r->setRcode(RCode::ServFail);
1212 return r;
1213 }
1214
1215 if(!B.getAuth(target, p->qtype, &sd)) {
1216 DLOG(L<<Logger::Error<<"We have no authority over zone '"<<target<<"'"<<endl);
1217 if(!retargetcount) {
1218 r->setA(false); // drop AA if we never had a SOA in the first place
1219 r->setRcode(RCode::Refused); // send REFUSED - but only on empty 'no idea'
1220 }
1221 goto sendit;
1222 }
1223 DLOG(L<<Logger::Error<<"We have authority, zone='"<<sd.qname<<"', id="<<sd.domain_id<<endl);
1224 authSet.insert(sd.qname);
1225
1226 if(!retargetcount) r->qdomainzone=sd.qname;
1227
1228 if(sd.qname==p->qdomain) {
1229 if(p->qtype.getCode() == QType::DNSKEY)
1230 {
1231 if(addDNSKEY(p, r, sd))
1232 goto sendit;
1233 }
1234 else if(p->qtype.getCode() == QType::CDNSKEY)
1235 {
1236 if(addCDNSKEY(p,r, sd))
1237 goto sendit;
1238 }
1239 else if(p->qtype.getCode() == QType::CDS)
1240 {
1241 if(addCDS(p,r, sd))
1242 goto sendit;
1243 }
1244 else if(p->qtype.getCode() == QType::NSEC3PARAM && d_dk.isSecuredZone(sd.qname))
1245 {
1246 if(addNSEC3PARAM(p,r, sd))
1247 goto sendit;
1248 }
1249 }
1250
1251 if(p->qtype.getCode() == QType::SOA && sd.qname==p->qdomain) {
1252 rr.dr.d_name=sd.qname;
1253 rr.dr.d_type=QType::SOA;
1254 sd.serial = calculateEditSOA(sd.serial, d_dk, sd.qname);
1255 rr.dr.d_content=makeSOAContent(sd);
1256 rr.dr.d_ttl=sd.ttl;
1257 rr.domain_id=sd.domain_id;
1258 rr.dr.d_place=DNSResourceRecord::ANSWER;
1259 rr.auth = true;
1260 r->addRecord(rr);
1261 goto sendit;
1262 }
1263
1264 // this TRUMPS a cname!
1265 if(p->qtype.getCode() == QType::NSEC && d_dk.isSecuredZone(sd.qname) && !d_dk.getNSEC3PARAM(sd.qname, 0)) {
1266 addNSEC(p, r, target, DNSName(), sd.qname, 5);
1267 if (!r->isEmpty())
1268 goto sendit;
1269 }
1270
1271 // this TRUMPS a cname!
1272 if(p->qtype.getCode() == QType::RRSIG) {
1273 L<<Logger::Info<<"Direct RRSIG query for "<<target<<" from "<<p->getRemote()<<endl;
1274 r->setRcode(RCode::Refused);
1275 goto sendit;
1276 }
1277
1278 DLOG(L<<"Checking for referrals first, unless this is a DS query"<<endl);
1279 if(p->qtype.getCode() != QType::DS && tryReferral(p, r, sd, target, retargetcount))
1280 goto sendit;
1281
1282 DLOG(L<<"Got no referrals, trying ANY"<<endl);
1283
1284 // see what we get..
1285 B.lookup(QType(QType::ANY), target, p, sd.domain_id);
1286 rrset.clear();
1287 haveAlias.trimToLabels(0);
1288 weDone = weRedirected = weHaveUnauth = false;
1289
1290 while(B.get(rr)) {
1291 //cerr<<"got content: ["<<rr.content<<"]"<<endl;
1292 if (p->qtype.getCode() == QType::ANY && !p->d_dnssecOk && (rr.dr.d_type == QType:: DNSKEY || rr.dr.d_type == QType::NSEC3PARAM))
1293 continue; // Don't send dnssec info to non validating resolvers.
1294 if (rr.dr.d_type == QType::RRSIG) // RRSIGS are added later any way.
1295 continue; // TODO: this actually means addRRSig should check if the RRSig is already there
1296
1297 // cerr<<"Auth: "<<rr.auth<<", "<<(rr.dr.d_type == p->qtype)<<", "<<rr.dr.d_type.getName()<<endl;
1298 if((p->qtype.getCode() == QType::ANY || rr.dr.d_type == p->qtype.getCode()) && rr.auth)
1299 weDone=1;
1300 // the line below fakes 'unauth NS' for delegations for non-DNSSEC backends.
1301 if((rr.dr.d_type == p->qtype.getCode() && !rr.auth) || (rr.dr.d_type == QType::NS && (!rr.auth || !(sd.qname==rr.dr.d_name))))
1302 weHaveUnauth=1;
1303
1304 if(rr.dr.d_type == QType::CNAME && p->qtype.getCode() != QType::CNAME)
1305 weRedirected=1;
1306
1307 if(DP && rr.dr.d_type == QType::ALIAS && (p->qtype.getCode() == QType::A || p->qtype.getCode() == QType::AAAA || p->qtype.getCode() == QType::ANY)) {
1308 if (!d_doExpandALIAS) {
1309 L<<Logger::Info<<"ALIAS record found for "<<target<<", but ALIAS expansion is disabled."<<endl;
1310 continue;
1311 }
1312 haveAlias=getRR<ALIASRecordContent>(rr.dr)->d_content;
1313 }
1314
1315 // Filter out all SOA's and add them in later
1316 if(rr.dr.d_type == QType::SOA)
1317 continue;
1318
1319 rrset.push_back(rr);
1320 }
1321
1322 /* Add in SOA if required */
1323 if(target==sd.qname) {
1324 rr.dr.d_name = sd.qname;
1325 rr.dr.d_type = QType::SOA;
1326 sd.serial = calculateEditSOA(sd.serial, d_dk, sd.qname);
1327 rr.dr.d_content = makeSOAContent(sd);
1328 rr.dr.d_ttl = sd.ttl;
1329 rr.domain_id = sd.domain_id;
1330 rr.auth = true;
1331 rrset.push_back(rr);
1332 }
1333
1334
1335 DLOG(L<<"After first ANY query for '"<<target<<"', id="<<sd.domain_id<<": weDone="<<weDone<<", weHaveUnauth="<<weHaveUnauth<<", weRedirected="<<weRedirected<<", haveAlias='"<<haveAlias<<"'"<<endl);
1336 if(p->qtype.getCode() == QType::DS && weHaveUnauth && !weDone && !weRedirected && d_dk.isSecuredZone(sd.qname)) {
1337 DLOG(L<<"Q for DS of a name for which we do have NS, but for which we don't have on a zone with DNSSEC need to provide an AUTH answer that proves we don't"<<endl);
1338 makeNOError(p, r, target, DNSName(), sd, 1);
1339 goto sendit;
1340 }
1341
1342 if(!haveAlias.empty() && (!weDone || p->qtype.getCode() == QType::ANY)) {
1343 DLOG(L<<Logger::Warning<<"Found nothing that matched for '"<<target<<"', but did get alias to '"<<haveAlias<<"', referring"<<endl);
1344 DP->completePacket(r, haveAlias, target);
1345 return 0;
1346 }
1347
1348 if(rrset.empty()) {
1349 DLOG(L<<"checking qtype.getCode() ["<<(p->qtype.getCode())<<"] against QType::DS ["<<(QType::DS)<<"]"<<endl);
1350 if(p->qtype.getCode() == QType::DS)
1351 {
1352 DLOG(L<<"DS query found no direct result, trying referral now"<<endl);
1353 if(tryReferral(p, r, sd, target, retargetcount))
1354 {
1355 DLOG(L<<"got referral for DS query"<<endl);
1356 goto sendit;
1357 }
1358 }
1359
1360
1361 DLOG(L<<Logger::Warning<<"Found nothing in the by-name ANY, but let's try wildcards.."<<endl);
1362 bool wereRetargeted(false), nodata(false);
1363 DNSName wildcard;
1364 if(tryWildcard(p, r, sd, target, wildcard, wereRetargeted, nodata)) {
1365 if(wereRetargeted) {
1366 if(!retargetcount) r->qdomainwild=wildcard;
1367 retargetcount++;
1368 goto retargeted;
1369 }
1370 if(nodata)
1371 makeNOError(p, r, target, wildcard, sd, 2);
1372
1373 goto sendit;
1374 }
1375 else if(tryDNAME(p, r, sd, target)) {
1376 retargetcount++;
1377 goto retargeted;
1378 }
1379 else
1380 {
1381 if (!(((p->qtype.getCode() == QType::CNAME) || (p->qtype.getCode() == QType::ANY)) && retargetcount > 0))
1382 makeNXDomain(p, r, target, wildcard, sd);
1383 }
1384
1385 goto sendit;
1386 }
1387
1388 if(weRedirected) {
1389 for(auto& loopRR: rrset) {
1390 if(loopRR.dr.d_type == QType::CNAME) {
1391 r->addRecord(loopRR);
1392 target = getRR<CNAMERecordContent>(loopRR.dr)->getTarget();
1393 retargetcount++;
1394 goto retargeted;
1395 }
1396 }
1397 }
1398 else if(weDone) {
1399 bool haveRecords = false;
1400 for(const auto& loopRR: rrset) {
1401 if((p->qtype.getCode() == QType::ANY || loopRR.dr.d_type == p->qtype.getCode()) && loopRR.dr.d_type && loopRR.dr.d_type != QType::ALIAS && loopRR.auth) {
1402 r->addRecord(loopRR);
1403 haveRecords = true;
1404 }
1405 }
1406
1407 if (haveRecords) {
1408 if(p->qtype.getCode() == QType::ANY)
1409 completeANYRecords(p, r, sd, target);
1410 }
1411 else
1412 makeNOError(p, r, target, DNSName(), sd, 0);
1413
1414 goto sendit;
1415 }
1416 else if(weHaveUnauth) {
1417 DLOG(L<<"Have unauth data, so need to hunt for best NS records"<<endl);
1418 if(tryReferral(p, r, sd, target, retargetcount))
1419 goto sendit;
1420 // check whether this could be fixed easily
1421 // if (*(rr.dr.d_name.rbegin()) == '.') {
1422 // L<<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;
1423 // } else {
1424 L<<Logger::Error<<"Should not get here ("<<p->qdomain<<"|"<<p->qtype.getCode()<<"): please run pdnsutil rectify-zone "<<sd.qname<<endl;
1425 // }
1426 }
1427 else {
1428 DLOG(L<<"Have some data, but not the right data"<<endl);
1429 makeNOError(p, r, target, DNSName(), sd, 0);
1430 }
1431
1432 sendit:;
1433 if(doAdditionalProcessingAndDropAA(p, r, sd, retargetcount)<0) {
1434 delete r;
1435 return 0;
1436 }
1437
1438 for(const auto& loopRR: r->getRRS()) {
1439 if(loopRR.scopeMask) {
1440 noCache=true;
1441 break;
1442 }
1443 }
1444 if(p->d_dnssecOk)
1445 addRRSigs(d_dk, B, authSet, r->getRRS());
1446
1447 r->wrapup(); // needed for inserting in cache
1448 if(!noCache && p->couldBeCached())
1449 PC.insert(p, r, r->getMinTTL()); // in the packet cache
1450 }
1451 catch(DBException &e) {
1452 L<<Logger::Error<<"Backend reported condition which prevented lookup ("+e.reason+") sending out servfail"<<endl;
1453 delete r;
1454 r=p->replyPacket(); // generate an empty reply packet
1455 r->setRcode(RCode::ServFail);
1456 S.inc("servfail-packets");
1457 S.ringAccount("servfail-queries",p->qdomain.toLogString());
1458 }
1459 catch(PDNSException &e) {
1460 L<<Logger::Error<<"Backend reported permanent error which prevented lookup ("+e.reason+"), aborting"<<endl;
1461 throw; // we WANT to die at this point
1462 }
1463 catch(std::exception &e) {
1464 L<<Logger::Error<<"Exception building answer packet for "<<p->qdomain<<"/"<<p->qtype.getName()<<" ("<<e.what()<<") sending out servfail"<<endl;
1465 delete r;
1466 r=p->replyPacket(); // generate an empty reply packet
1467 r->setRcode(RCode::ServFail);
1468 S.inc("servfail-packets");
1469 S.ringAccount("servfail-queries",p->qdomain.toLogString());
1470 }
1471 return r;
1472
1473 }