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