]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/packethandler.cc
Merge pull request #7903 from Habbie/dnsdist-doc-nits
[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(g_log<<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(g_log<<"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)->getTarget()));
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 #ifdef HAVE_LUA_RECORDS
360 bool doLua=g_doLuaRecord;
361 if(!doLua) {
362 string val;
363 d_dk.getFromMeta(sd.qname, "ENABLE-LUA-RECORDS", val);
364 doLua = (val=="1");
365 }
366 #endif
367
368 wildcard=subdomain;
369 while( subdomain.chopOff() && !haveSomething ) {
370 if (subdomain.empty()) {
371 B.lookup(QType(QType::ANY), g_wildcarddnsname, p, sd.domain_id);
372 } else {
373 B.lookup(QType(QType::ANY), g_wildcarddnsname+subdomain, p, sd.domain_id);
374 }
375 while(B.get(rr)) {
376 #ifdef HAVE_LUA_RECORDS
377 if(rr.dr.d_type == QType::LUA) {
378 if(!doLua) {
379 DLOG(g_log<<"Have a wildcard LUA match, but not doing LUA record for this zone"<<endl);
380 continue;
381 }
382
383 DLOG(g_log<<"Have a wildcard LUA match"<<endl);
384
385 auto rec=getRR<LUARecordContent>(rr.dr);
386 if (!rec) {
387 continue;
388 }
389 if(rec->d_type == QType::CNAME || rec->d_type == p->qtype.getCode() || (p->qtype.getCode() == QType::ANY && rec->d_type != QType::RRSIG)) {
390 // noCache=true;
391 DLOG(g_log<<"Executing Lua: '"<<rec->getCode()<<"'"<<endl);
392 auto recvec=luaSynth(rec->getCode(), target, sd.qname, sd.domain_id, *p, rec->d_type);
393 for(const auto& r : recvec) {
394 rr.dr.d_type = rec->d_type; // might be CNAME
395 rr.dr.d_content = r;
396 rr.scopeMask = p->getRealRemote().getBits(); // this makes sure answer is a specific as your question
397 ret->push_back(rr);
398 }
399 }
400 }
401 else
402 #endif
403 if(rr.dr.d_type == p->qtype.getCode() || rr.dr.d_type == QType::CNAME || (p->qtype.getCode() == QType::ANY && rr.dr.d_type != QType::RRSIG)) {
404 ret->push_back(rr);
405 }
406
407 wildcard=g_wildcarddnsname+subdomain;
408 haveSomething=true;
409 }
410
411 if ( subdomain == sd.qname || haveSomething ) // stop at SOA or result
412 break;
413
414 B.lookup(QType(QType::ANY), subdomain, p, sd.domain_id);
415 if (B.get(rr)) {
416 DLOG(g_log<<"No wildcard match, ancestor exists"<<endl);
417 while (B.get(rr)) ;
418 break;
419 }
420 wildcard=subdomain;
421 }
422
423 return haveSomething;
424 }
425
426 /** dangling is declared true if we were unable to resolve everything */
427 int PacketHandler::doAdditionalProcessingAndDropAA(DNSPacket *p, DNSPacket *r, const SOAData& soadata, bool retargeted)
428 {
429 DNSZoneRecord rr;
430 SOAData sd;
431 sd.db=0;
432
433 if(p->qtype.getCode()!=QType::AXFR) { // this packet needs additional processing
434 // we now have a copy, push_back on packet might reallocate!
435 auto& records = r->getRRS();
436 vector<DNSZoneRecord> toAdd;
437
438 for(auto i = records.cbegin() ; i!= records.cend(); ++i) {
439 if(i->dr.d_place==DNSResourceRecord::ADDITIONAL ||
440 !(i->dr.d_type==QType::MX || i->dr.d_type==QType::NS || i->dr.d_type==QType::SRV))
441 continue;
442
443 if(r->d.aa && i->dr.d_name.countLabels() && i->dr.d_type==QType::NS && !B.getSOA(i->dr.d_name,sd) && !retargeted) { // drop AA in case of non-SOA-level NS answer, except for root referral
444 r->setA(false);
445 // i->d_place=DNSResourceRecord::AUTHORITY; // XXX FIXME
446 }
447
448 DNSName lookup;
449
450 if(i->dr.d_type == QType::MX)
451 lookup = getRR<MXRecordContent>(i->dr)->d_mxname;
452 else if(i->dr.d_type == QType::SRV)
453 lookup = getRR<SRVRecordContent>(i->dr)->d_target;
454 else if(i->dr.d_type == QType::NS)
455 lookup = getRR<NSRecordContent>(i->dr)->getNS();
456 else
457 continue;
458
459 B.lookup(QType(d_doIPv6AdditionalProcessing ? QType::ANY : QType::A), lookup, p, soadata.domain_id);
460
461 while(B.get(rr)) {
462 if(rr.dr.d_type != QType::A && rr.dr.d_type!=QType::AAAA)
463 continue;
464 if(!rr.dr.d_name.isPartOf(soadata.qname)) {
465 // FIXME we might still pass on the record if it is occluded and the
466 // backend uses a single id for all zones
467 continue;
468 }
469 rr.dr.d_place=DNSResourceRecord::ADDITIONAL;
470 toAdd.push_back(rr);
471 }
472 }
473 for(const auto& rec : toAdd)
474 r->addRecord(rec);
475
476 //records.insert(records.end(), toAdd.cbegin(), toAdd.cend()); // would be faster, but no dedup
477 }
478 return 1;
479 }
480
481
482 void PacketHandler::emitNSEC(DNSPacket *r, const SOAData& sd, const DNSName& name, const DNSName& next, int mode)
483 {
484 NSECRecordContent nrc;
485 nrc.d_next = next;
486
487 nrc.set(QType::NSEC);
488 nrc.set(QType::RRSIG);
489 if(sd.qname == name) {
490 nrc.set(QType::SOA); // 1dfd8ad SOA can live outside the records table
491 nrc.set(QType::DNSKEY);
492 string publishCDNSKEY;
493 d_dk.getFromMeta(name, "PUBLISH-CDNSKEY", publishCDNSKEY);
494 if (publishCDNSKEY == "1")
495 nrc.set(QType::CDNSKEY);
496 string publishCDS;
497 d_dk.getFromMeta(name, "PUBLISH-CDS", publishCDS);
498 if (! publishCDS.empty())
499 nrc.set(QType::CDS);
500 }
501
502 DNSZoneRecord rr;
503
504 B.lookup(QType(QType::ANY), name, NULL, sd.domain_id);
505 while(B.get(rr)) {
506 #ifdef HAVE_LUA_RECORDS
507 if(rr.dr.d_type == QType::LUA)
508 nrc.set(getRR<LUARecordContent>(rr.dr)->d_type);
509 else
510 #endif
511 if(rr.dr.d_type == QType::NS || rr.auth)
512 nrc.set(rr.dr.d_type);
513 }
514
515 rr.dr.d_name = name;
516 rr.dr.d_ttl = sd.default_ttl;
517 rr.dr.d_type = QType::NSEC;
518 rr.dr.d_content = std::make_shared<NSECRecordContent>(std::move(nrc));
519 rr.dr.d_place = (mode == 5 ) ? DNSResourceRecord::ANSWER: DNSResourceRecord::AUTHORITY;
520 rr.auth = true;
521
522 r->addRecord(rr);
523 }
524
525 void PacketHandler::emitNSEC3(DNSPacket *r, const SOAData& sd, const NSEC3PARAMRecordContent& ns3prc, const DNSName& name, const string& namehash, const string& nexthash, int mode)
526 {
527 NSEC3RecordContent n3rc;
528 n3rc.d_algorithm = ns3prc.d_algorithm;
529 n3rc.d_flags = ns3prc.d_flags;
530 n3rc.d_iterations = ns3prc.d_iterations;
531 n3rc.d_salt = ns3prc.d_salt;
532 n3rc.d_nexthash = nexthash;
533
534 DNSZoneRecord rr;
535
536 if(!name.empty()) {
537 if (sd.qname == name) {
538 n3rc.set(QType::SOA); // 1dfd8ad SOA can live outside the records table
539 n3rc.set(QType::NSEC3PARAM);
540 n3rc.set(QType::DNSKEY);
541 string publishCDNSKEY;
542 d_dk.getFromMeta(name, "PUBLISH-CDNSKEY", publishCDNSKEY);
543 if (publishCDNSKEY == "1")
544 n3rc.set(QType::CDNSKEY);
545 string publishCDS;
546 d_dk.getFromMeta(name, "PUBLISH-CDS", publishCDS);
547 if (! publishCDS.empty())
548 n3rc.set(QType::CDS);
549 }
550
551 B.lookup(QType(QType::ANY), name, NULL, sd.domain_id);
552 while(B.get(rr)) {
553 #ifdef HAVE_LUA_RECORDS
554 if(rr.dr.d_type == QType::LUA)
555 n3rc.set(getRR<LUARecordContent>(rr.dr)->d_type);
556 else
557 #endif
558 if(rr.dr.d_type && (rr.dr.d_type == QType::NS || rr.auth)) // skip empty non-terminals
559 n3rc.set(rr.dr.d_type);
560 }
561 }
562
563 const auto numberOfTypesSet = n3rc.numberOfTypesSet();
564 if (numberOfTypesSet != 0 && !(numberOfTypesSet == 1 && n3rc.isSet(QType::NS))) {
565 n3rc.set(QType::RRSIG);
566 }
567
568 rr.dr.d_name = DNSName(toBase32Hex(namehash))+sd.qname;
569 rr.dr.d_ttl = sd.default_ttl;
570 rr.dr.d_type=QType::NSEC3;
571 rr.dr.d_content=std::make_shared<NSEC3RecordContent>(std::move(n3rc));
572 rr.dr.d_place = (mode == 5 ) ? DNSResourceRecord::ANSWER: DNSResourceRecord::AUTHORITY;
573 rr.auth = true;
574
575 r->addRecord(rr);
576 }
577
578 /*
579 mode 0 = No Data Responses, QTYPE is not DS
580 mode 1 = No Data Responses, QTYPE is DS
581 mode 2 = Wildcard No Data Responses
582 mode 3 = Wildcard Answer Responses
583 mode 4 = Name Error Responses
584 mode 5 = Direct NSEC request
585 */
586 void PacketHandler::addNSECX(DNSPacket *p, DNSPacket *r, const DNSName& target, const DNSName& wildcard, const DNSName& auth, int mode)
587 {
588 NSEC3PARAMRecordContent ns3rc;
589 bool narrow;
590 if(d_dk.getNSEC3PARAM(auth, &ns3rc, &narrow)) {
591 if (mode != 5) // no direct NSEC3 queries, rfc5155 7.2.8
592 addNSEC3(p, r, target, wildcard, auth, ns3rc, narrow, mode);
593 }
594 else {
595 addNSEC(p, r, target, wildcard, auth, mode);
596 }
597 }
598
599 bool getNSEC3Hashes(bool narrow, DNSBackend* db, int id, const std::string& hashed, bool decrement, DNSName& unhashed, std::string& before, std::string& after, int mode)
600 {
601 bool ret;
602 if(narrow) { // nsec3-narrow
603 ret=true;
604 before=hashed;
605 if(decrement) {
606 decrementHash(before);
607 unhashed.clear();
608 }
609 after=hashed;
610 incrementHash(after);
611 }
612 else {
613 DNSName hashedName = DNSName(toBase32Hex(hashed));
614 DNSName beforeName, afterName;
615 if (!decrement && mode >= 2)
616 beforeName = hashedName;
617 ret=db->getBeforeAndAfterNamesAbsolute(id, hashedName, unhashed, beforeName, afterName);
618 before=fromBase32Hex(beforeName.toString());
619 after=fromBase32Hex(afterName.toString());
620 }
621 return ret;
622 }
623
624 void PacketHandler::addNSEC3(DNSPacket *p, DNSPacket *r, const DNSName& target, const DNSName& wildcard, const DNSName& auth, const NSEC3PARAMRecordContent& ns3rc, bool narrow, int mode)
625 {
626 DLOG(g_log<<"addNSEC3() mode="<<mode<<" auth="<<auth<<" target="<<target<<" wildcard="<<wildcard<<endl);
627
628 SOAData sd;
629 if(!B.getSOAUncached(auth, sd)) {
630 DLOG(g_log<<"Could not get SOA for domain");
631 return;
632 }
633
634 bool doNextcloser = false;
635 string before, after, hashed;
636 DNSName unhashed, closest;
637
638 if (mode == 2 || mode == 3 || mode == 4) {
639 closest=wildcard;
640 closest.chopOff();
641 } else
642 closest=target;
643
644 // add matching NSEC3 RR
645 if (mode != 3) {
646 unhashed=(mode == 0 || mode == 1 || mode == 5) ? target : closest;
647 hashed=hashQNameWithSalt(ns3rc, unhashed);
648 DLOG(g_log<<"1 hash: "<<toBase32Hex(hashed)<<" "<<unhashed<<endl);
649
650 getNSEC3Hashes(narrow, sd.db, sd.domain_id, hashed, false, unhashed, before, after, mode);
651
652 if (((mode == 0 && ns3rc.d_flags) || mode == 1) && (hashed != before)) {
653 DLOG(g_log<<"No matching NSEC3, do closest (provable) encloser"<<endl);
654
655 bool doBreak = false;
656 DNSZoneRecord rr;
657 while( closest.chopOff() && (closest != sd.qname)) { // stop at SOA
658 B.lookup(QType(QType::ANY), closest, p, sd.domain_id);
659 while(B.get(rr))
660 if (rr.auth)
661 doBreak = true;
662 if(doBreak)
663 break;
664 }
665 doNextcloser = true;
666 unhashed=closest;
667 hashed=hashQNameWithSalt(ns3rc, unhashed);
668 DLOG(g_log<<"1 hash: "<<toBase32Hex(hashed)<<" "<<unhashed<<endl);
669
670 getNSEC3Hashes(narrow, sd.db, sd.domain_id, hashed, false, unhashed, before, after);
671 }
672
673 if (!after.empty()) {
674 DLOG(g_log<<"Done calling for matching, hashed: '"<<toBase32Hex(hashed)<<"' before='"<<toBase32Hex(before)<<"', after='"<<toBase32Hex(after)<<"'"<<endl);
675 emitNSEC3(r, sd, ns3rc, unhashed, before, after, mode);
676 }
677 }
678
679 // add covering NSEC3 RR
680 if ((mode >= 2 && mode <= 4) || doNextcloser) {
681 DNSName next(target);
682 do {
683 unhashed=next;
684 }
685 while( next.chopOff() && !(next==closest));
686
687 hashed=hashQNameWithSalt(ns3rc, unhashed);
688 DLOG(g_log<<"2 hash: "<<toBase32Hex(hashed)<<" "<<unhashed<<endl);
689
690 getNSEC3Hashes(narrow, sd.db,sd.domain_id, hashed, true, unhashed, before, after);
691 DLOG(g_log<<"Done calling for covering, hashed: '"<<toBase32Hex(hashed)<<"' before='"<<toBase32Hex(before)<<"', after='"<<toBase32Hex(after)<<"'"<<endl);
692 emitNSEC3( r, sd, ns3rc, unhashed, before, after, mode);
693 }
694
695 // wildcard denial
696 if (mode == 2 || mode == 4) {
697 unhashed=g_wildcarddnsname+closest;
698
699 hashed=hashQNameWithSalt(ns3rc, unhashed);
700 DLOG(g_log<<"3 hash: "<<toBase32Hex(hashed)<<" "<<unhashed<<endl);
701
702 getNSEC3Hashes(narrow, sd.db, sd.domain_id, hashed, (mode != 2), unhashed, before, after);
703 DLOG(g_log<<"Done calling for '*', hashed: '"<<toBase32Hex(hashed)<<"' before='"<<toBase32Hex(before)<<"', after='"<<toBase32Hex(after)<<"'"<<endl);
704 emitNSEC3( r, sd, ns3rc, unhashed, before, after, mode);
705 }
706 }
707
708 void PacketHandler::addNSEC(DNSPacket *p, DNSPacket *r, const DNSName& target, const DNSName& wildcard, const DNSName& auth, int mode)
709 {
710 DLOG(g_log<<"addNSEC() mode="<<mode<<" auth="<<auth<<" target="<<target<<" wildcard="<<wildcard<<endl);
711
712 SOAData sd;
713 if(!B.getSOAUncached(auth, sd)) {
714 DLOG(g_log<<"Could not get SOA for domain"<<endl);
715 return;
716 }
717
718 DNSName before,after;
719 sd.db->getBeforeAndAfterNames(sd.domain_id, auth, target, before, after);
720 if (mode != 5 || before == target)
721 emitNSEC(r, sd, before, after, mode);
722
723 if (mode == 2 || mode == 4) {
724 // wildcard NO-DATA or wildcard denial
725 before.clear();
726 DNSName closest(wildcard);
727 if (mode == 4) {
728 closest.chopOff();
729 closest.prependRawLabel("*");
730 }
731 sd.db->getBeforeAndAfterNames(sd.domain_id, auth, closest, before, after);
732 emitNSEC(r, sd, before, after, mode);
733 }
734 return;
735 }
736
737 /* Semantics:
738
739 - only one backend owns the SOA of a zone
740 - only one AXFR per zone at a time - double startTransaction should fail
741 - backends need to implement transaction semantics
742
743
744 How BindBackend would implement this:
745 startTransaction makes a file
746 feedRecord sends everything to that file
747 commitTransaction moves that file atomically over the regular file, and triggers a reload
748 rollbackTransaction removes the file
749
750
751 How PostgreSQLBackend would implement this:
752 startTransaction starts a sql transaction, which also deletes all records
753 feedRecord is an insert statement
754 commitTransaction commits the transaction
755 rollbackTransaction aborts it
756
757 How MySQLBackend would implement this:
758 (good question!)
759
760 */
761
762 int PacketHandler::trySuperMaster(DNSPacket *p, const DNSName& tsigkeyname)
763 {
764 if(p->d_tcp)
765 {
766 // do it right now if the client is TCP
767 // rarely happens
768 return trySuperMasterSynchronous(p, tsigkeyname);
769 }
770 else
771 {
772 // queue it if the client is on UDP
773 Communicator.addTrySuperMasterRequest(p);
774 return 0;
775 }
776 }
777
778 int PacketHandler::trySuperMasterSynchronous(const DNSPacket *p, const DNSName& tsigkeyname)
779 {
780 ComboAddress remote = p->getRemote().setPort(53);
781 if(p->hasEDNSSubnet() && ::arg().contains("trusted-notification-proxy", remote.toString())) {
782 remote = p->getRealRemote().getNetwork();
783 }
784
785 Resolver::res_t nsset;
786 try {
787 Resolver resolver;
788 uint32_t theirserial;
789 resolver.getSoaSerial(remote, p->qdomain, &theirserial);
790 resolver.resolve(remote, p->qdomain, QType::NS, &nsset);
791 }
792 catch(ResolverException &re) {
793 g_log<<Logger::Error<<"Error resolving SOA or NS for "<<p->qdomain<<" at: "<< remote <<": "<<re.reason<<endl;
794 return RCode::ServFail;
795 }
796
797 // check if the returned records are NS records
798 bool haveNS=false;
799 for(const auto& ns: nsset) {
800 if(ns.qtype==QType::NS)
801 haveNS=true;
802 }
803
804 if(!haveNS) {
805 g_log<<Logger::Error<<"While checking for supermaster, did not find NS for "<<p->qdomain<<" at: "<< remote <<endl;
806 return RCode::ServFail;
807 }
808
809 string nameserver, account;
810 DNSBackend *db;
811
812 if (!::arg().mustDo("allow-unsigned-supermaster") && tsigkeyname.empty()) {
813 g_log<<Logger::Error<<"Received unsigned NOTIFY for "<<p->qdomain<<" from potential supermaster "<<remote<<". Refusing."<<endl;
814 return RCode::Refused;
815 }
816
817 if(!B.superMasterBackend(remote.toString(), p->qdomain, nsset, &nameserver, &account, &db)) {
818 g_log<<Logger::Error<<"Unable to find backend willing to host "<<p->qdomain<<" for potential supermaster "<<remote<<". Remote nameservers: "<<endl;
819 for(const auto& rr: nsset) {
820 if(rr.qtype==QType::NS)
821 g_log<<Logger::Error<<rr.content<<endl;
822 }
823 return RCode::Refused;
824 }
825 try {
826 db->createSlaveDomain(p->getRemote().toString(), p->qdomain, nameserver, account);
827 if (tsigkeyname.empty() == false) {
828 vector<string> meta;
829 meta.push_back(tsigkeyname.toStringNoDot());
830 db->setDomainMetadata(p->qdomain, "AXFR-MASTER-TSIG", meta);
831 }
832 }
833 catch(PDNSException& ae) {
834 g_log<<Logger::Error<<"Database error trying to create "<<p->qdomain<<" for potential supermaster "<<remote<<": "<<ae.reason<<endl;
835 return RCode::ServFail;
836 }
837 g_log<<Logger::Warning<<"Created new slave zone '"<<p->qdomain<<"' from supermaster "<<remote<<endl;
838 return RCode::NoError;
839 }
840
841 int PacketHandler::processNotify(DNSPacket *p)
842 {
843 /* now what?
844 was this notification from an approved address?
845 was this notification approved by TSIG?
846 We determine our internal SOA id (via UeberBackend)
847 We determine the SOA at our (known) master
848 if master is higher -> do stuff
849 */
850
851 g_log<<Logger::Debug<<"Received NOTIFY for "<<p->qdomain<<" from "<<p->getRemote()<<endl;
852
853 if(!::arg().mustDo("slave") && s_forwardNotify.empty()) {
854 g_log<<Logger::Warning<<"Received NOTIFY for "<<p->qdomain<<" from "<<p->getRemote()<<" but slave support is disabled in the configuration"<<endl;
855 return RCode::Refused;
856 }
857
858 // Sender verification
859 //
860 if(!s_allowNotifyFrom.match((ComboAddress *) &p->d_remote ) || p->d_havetsig) {
861 if (p->d_havetsig && p->getTSIGKeyname().empty() == false) {
862 g_log<<Logger::Notice<<"Received secure NOTIFY for "<<p->qdomain<<" from "<<p->getRemote()<<", with TSIG key '"<<p->getTSIGKeyname()<<"'"<<endl;
863 } else {
864 g_log<<Logger::Warning<<"Received NOTIFY for "<<p->qdomain<<" from "<<p->getRemote()<<" but the remote is not providing a TSIG key or in allow-notify-from (Refused)"<<endl;
865 return RCode::Refused;
866 }
867 }
868
869 if ((!::arg().mustDo("allow-unsigned-notify") && !p->d_havetsig) || p->d_havetsig) {
870 if (!p->d_havetsig) {
871 g_log<<Logger::Warning<<"Received unsigned NOTIFY for "<<p->qdomain<<" from "<<p->getRemote()<<" while a TSIG key was required (Refused)"<<endl;
872 return RCode::Refused;
873 }
874 vector<string> meta;
875 if (B.getDomainMetadata(p->qdomain,"AXFR-MASTER-TSIG",meta) && meta.size() > 0) {
876 if (!pdns_iequals(meta[0], p->getTSIGKeyname().toStringNoDot())) {
877 g_log<<Logger::Warning<<"Received secure NOTIFY for "<<p->qdomain<<" from "<<p->getRemote()<<": expected TSIG key '"<<meta[0]<<", got '"<<p->getTSIGKeyname()<<"' (Refused)"<<endl;
878 return RCode::Refused;
879 }
880 }
881 }
882
883 // Domain verification
884 //
885 DomainInfo di;
886 if(!B.getDomainInfo(p->qdomain, di, false) || !di.backend) {
887 if(::arg().mustDo("superslave")) {
888 g_log<<Logger::Warning<<"Received NOTIFY for "<<p->qdomain<<" from "<<p->getRemote()<<" for which we are not authoritative, trying supermaster"<<endl;
889 return trySuperMaster(p, p->getTSIGKeyname());
890 }
891 g_log<<Logger::Notice<<"Received NOTIFY for "<<p->qdomain<<" from "<<p->getRemote()<<" for which we are not authoritative (Refused)"<<endl;
892 return RCode::Refused;
893 }
894
895 if(::arg().contains("trusted-notification-proxy", p->getRemote().toString())) {
896 g_log<<Logger::Error<<"Received NOTIFY for "<<p->qdomain<<" from trusted-notification-proxy "<< p->getRemote()<<endl;
897 if(di.masters.empty()) {
898 g_log<<Logger::Error<<"However, "<<p->qdomain<<" does not have any masters defined (Refused)"<<endl;
899 return RCode::Refused;
900 }
901 }
902 else if(::arg().mustDo("master") && di.kind == DomainInfo::Master) {
903 g_log<<Logger::Warning<<"Received NOTIFY for "<<p->qdomain<<" from "<<p->getRemote()<<" but we are master (Refused)"<<endl;
904 return RCode::Refused;
905 }
906 else if(!di.isMaster(p->getRemote())) {
907 g_log<<Logger::Warning<<"Received NOTIFY for "<<p->qdomain<<" from "<<p->getRemote()<<" which is not a master (Refused)"<<endl;
908 return RCode::Refused;
909 }
910
911 if(!s_forwardNotify.empty()) {
912 set<string> forwardNotify(s_forwardNotify);
913 for(set<string>::const_iterator j=forwardNotify.begin();j!=forwardNotify.end();++j) {
914 g_log<<Logger::Notice<<"Relaying notification of domain "<<p->qdomain<<" from "<<p->getRemote()<<" to "<<*j<<endl;
915 Communicator.notify(p->qdomain,*j);
916 }
917 }
918
919 if(::arg().mustDo("slave")) {
920 g_log<<Logger::Debug<<"Queueing slave check for "<<p->qdomain<<endl;
921 Communicator.addSlaveCheckRequest(di, p->d_remote);
922 }
923 return 0;
924 }
925
926 bool validDNSName(const DNSName &name)
927 {
928 if (!g_8bitDNS) {
929 string::size_type pos, length;
930 char c;
931 for(const auto& s : name.getRawLabels()) {
932 length=s.length();
933 for(pos=0; pos < length; ++pos) {
934 c=s[pos];
935 if(!((c >= 'a' && c <= 'z') ||
936 (c >= 'A' && c <= 'Z') ||
937 (c >= '0' && c <= '9') ||
938 c =='-' || c == '_' || c=='*' || c=='.' || c=='/' || c=='@' || c==' ' || c=='\\' || c==':'))
939 return false;
940 }
941 }
942 }
943 return true;
944 }
945
946 DNSPacket *PacketHandler::question(DNSPacket *p)
947 {
948 DNSPacket *ret;
949
950 if(d_pdl)
951 {
952 ret=d_pdl->prequery(p);
953 if(ret)
954 return ret;
955 }
956
957 if(p->d.rd) {
958 static AtomicCounter &rdqueries=*S.getPointer("rd-queries");
959 rdqueries++;
960 }
961
962 return doQuestion(p);
963 }
964
965
966 void PacketHandler::makeNXDomain(DNSPacket* p, DNSPacket* r, const DNSName& target, const DNSName& wildcard, const SOAData& sd)
967 {
968 DNSZoneRecord rr;
969 rr=makeEditedDNSZRFromSOAData(d_dk, sd, DNSResourceRecord::AUTHORITY);
970 rr.dr.d_ttl=min(sd.ttl, sd.default_ttl);
971 r->addRecord(rr);
972
973 if(d_dnssec) {
974 addNSECX(p, r, target, wildcard, sd.qname, 4);
975 }
976
977 r->setRcode(RCode::NXDomain);
978 }
979
980 void PacketHandler::makeNOError(DNSPacket* p, DNSPacket* r, const DNSName& target, const DNSName& wildcard, const SOAData& sd, int mode)
981 {
982 DNSZoneRecord rr;
983 rr=makeEditedDNSZRFromSOAData(d_dk, sd, DNSResourceRecord::AUTHORITY);
984 rr.dr.d_ttl=min(sd.ttl, sd.default_ttl);
985 r->addRecord(rr);
986
987 if(d_dnssec) {
988 addNSECX(p, r, target, wildcard, sd.qname, mode);
989 }
990
991 S.ringAccount("noerror-queries", p->qdomain, p->qtype);
992 }
993
994
995 bool PacketHandler::addDSforNS(DNSPacket* p, DNSPacket* r, SOAData& sd, const DNSName& dsname)
996 {
997 //cerr<<"Trying to find a DS for '"<<dsname<<"', domain_id = "<<sd.domain_id<<endl;
998 B.lookup(QType(QType::DS), dsname, p, sd.domain_id);
999 DNSZoneRecord rr;
1000 bool gotOne=false;
1001 while(B.get(rr)) {
1002 gotOne=true;
1003 rr.dr.d_place = DNSResourceRecord::AUTHORITY;
1004 r->addRecord(rr);
1005 }
1006 return gotOne;
1007 }
1008
1009 bool PacketHandler::tryReferral(DNSPacket *p, DNSPacket*r, SOAData& sd, const DNSName &target, bool retargeted)
1010 {
1011 vector<DNSZoneRecord> rrset = getBestReferralNS(p, sd, target);
1012 if(rrset.empty())
1013 return false;
1014
1015 for(auto& rr: rrset) {
1016 rr.dr.d_place=DNSResourceRecord::AUTHORITY;
1017 r->addRecord(rr);
1018 }
1019 if(!retargeted)
1020 r->setA(false);
1021
1022 if(d_dk.isSecuredZone(sd.qname) && !addDSforNS(p, r, sd, rrset.begin()->dr.d_name) && d_dnssec) {
1023 addNSECX(p, r, rrset.begin()->dr.d_name, DNSName(), sd.qname, 1);
1024 }
1025
1026 return true;
1027 }
1028
1029 void PacketHandler::completeANYRecords(DNSPacket *p, DNSPacket*r, SOAData& sd, const DNSName &target)
1030 {
1031 addNSECX(p, r, target, DNSName(), sd.qname, 5);
1032 if(sd.qname == p->qdomain) {
1033 addDNSKEY(p, r, sd);
1034 addCDNSKEY(p, r, sd);
1035 addCDS(p, r, sd);
1036 addNSEC3PARAM(p, r, sd);
1037 }
1038 }
1039
1040 bool PacketHandler::tryDNAME(DNSPacket *p, DNSPacket*r, SOAData& sd, DNSName &target)
1041 {
1042 if(!d_doDNAME)
1043 return false;
1044 DLOG(g_log<<Logger::Warning<<"Let's try DNAME.."<<endl);
1045 vector<DNSZoneRecord> rrset = getBestDNAMESynth(p, sd, target);
1046 if(!rrset.empty()) {
1047 for(auto& rr: rrset) {
1048 rr.dr.d_place = DNSResourceRecord::ANSWER;
1049 r->addRecord(rr);
1050 }
1051 return true;
1052 }
1053 return false;
1054 }
1055 bool PacketHandler::tryWildcard(DNSPacket *p, DNSPacket*r, SOAData& sd, DNSName &target, DNSName &wildcard, bool& retargeted, bool& nodata)
1056 {
1057 retargeted = nodata = false;
1058 DNSName bestmatch;
1059
1060 vector<DNSZoneRecord> rrset;
1061 if(!getBestWildcard(p, sd, target, wildcard, &rrset))
1062 return false;
1063
1064 if(rrset.empty()) {
1065 DLOG(g_log<<"Wildcard matched something, but not of the correct type"<<endl);
1066 nodata=true;
1067 }
1068 else {
1069 for(auto& rr: rrset) {
1070 rr.wildcardname = rr.dr.d_name;
1071 rr.dr.d_name=bestmatch=target;
1072
1073 if(rr.dr.d_type == QType::CNAME) {
1074 retargeted=true;
1075 target=getRR<CNAMERecordContent>(rr.dr)->getTarget();
1076 }
1077
1078 rr.dr.d_place=DNSResourceRecord::ANSWER;
1079 r->addRecord(rr);
1080 }
1081 }
1082 if(d_dnssec && !nodata) {
1083 addNSECX(p, r, bestmatch, wildcard, sd.qname, 3);
1084 }
1085
1086 return true;
1087 }
1088
1089 //! Called by the Distributor to ask a question. Returns 0 in case of an error
1090 DNSPacket *PacketHandler::doQuestion(DNSPacket *p)
1091 {
1092 DNSZoneRecord rr;
1093 SOAData sd;
1094
1095 int retargetcount=0;
1096 set<DNSName> authSet;
1097
1098 vector<DNSZoneRecord> rrset;
1099 bool weDone=0, weRedirected=0, weHaveUnauth=0, doSigs=0;
1100 DNSName haveAlias;
1101 uint8_t aliasScopeMask;
1102
1103 DNSPacket *r=0;
1104 bool noCache=false;
1105
1106 #ifdef HAVE_LUA_RECORDS
1107 bool doLua=g_doLuaRecord;
1108 #endif
1109
1110 if(p->d.qr) { // QR bit from dns packet (thanks RA from N)
1111 if(d_logDNSDetails)
1112 g_log<<Logger::Error<<"Received an answer (non-query) packet from "<<p->getRemote()<<", dropping"<<endl;
1113 S.inc("corrupt-packets");
1114 S.ringAccount("remotes-corrupt", p->d_remote);
1115 return 0;
1116 }
1117
1118 if(p->d.tc) { // truncated query. MOADNSParser would silently parse this packet in an incomplete way.
1119 if(d_logDNSDetails)
1120 g_log<<Logger::Error<<"Received truncated query packet from "<<p->getRemote()<<", dropping"<<endl;
1121 S.inc("corrupt-packets");
1122 S.ringAccount("remotes-corrupt", p->d_remote);
1123 return 0;
1124 }
1125
1126 if (p->hasEDNS() && p->getEDNSVersion() > 0) {
1127 r = p->replyPacket();
1128
1129 // PacketWriter::addOpt will take care of setting this correctly in the packet
1130 r->setEDNSRcode(ERCode::BADVERS);
1131 return r;
1132 }
1133
1134 if(p->d_havetsig) {
1135 DNSName keyname;
1136 string secret;
1137 TSIGRecordContent trc;
1138 if(!p->checkForCorrectTSIG(&B, &keyname, &secret, &trc)) {
1139 r=p->replyPacket(); // generate an empty reply packet
1140 if(d_logDNSDetails)
1141 g_log<<Logger::Error<<"Received a TSIG signed message with a non-validating key"<<endl;
1142 // RFC3007 describes that a non-secure message should be sending Refused for DNS Updates
1143 if (p->d.opcode == Opcode::Update)
1144 r->setRcode(RCode::Refused);
1145 else
1146 r->setRcode(RCode::NotAuth);
1147 return r;
1148 } else {
1149 getTSIGHashEnum(trc.d_algoName, p->d_tsig_algo);
1150 if (p->d_tsig_algo == TSIG_GSS) {
1151 GssContext gssctx(keyname);
1152 if (!gssctx.getPeerPrincipal(p->d_peer_principal)) {
1153 g_log<<Logger::Warning<<"Failed to extract peer principal from GSS context with keyname '"<<keyname<<"'"<<endl;
1154 }
1155 }
1156 }
1157 p->setTSIGDetails(trc, keyname, secret, trc.d_mac); // this will get copied by replyPacket()
1158 noCache=true;
1159 }
1160
1161 r=p->replyPacket(); // generate an empty reply packet, possibly with TSIG details inside
1162
1163 if (p->qtype == QType::TKEY) {
1164 this->tkeyHandler(p, r);
1165 return r;
1166 }
1167
1168 try {
1169
1170 // XXX FIXME do this in DNSPacket::parse ?
1171
1172 if(!validDNSName(p->qdomain)) {
1173 if(d_logDNSDetails)
1174 g_log<<Logger::Error<<"Received a malformed qdomain from "<<p->getRemote()<<", '"<<p->qdomain<<"': sending servfail"<<endl;
1175 S.inc("corrupt-packets");
1176 S.ringAccount("remotes-corrupt", p->d_remote);
1177 S.inc("servfail-packets");
1178 r->setRcode(RCode::ServFail);
1179 return r;
1180 }
1181 if(p->d.opcode) { // non-zero opcode (again thanks RA!)
1182 if(p->d.opcode==Opcode::Update) {
1183 S.inc("dnsupdate-queries");
1184 int res=processUpdate(p);
1185 if (res == RCode::Refused)
1186 S.inc("dnsupdate-refused");
1187 else if (res != RCode::ServFail)
1188 S.inc("dnsupdate-answers");
1189 r->setRcode(res);
1190 r->setOpcode(Opcode::Update);
1191 return r;
1192 }
1193 else if(p->d.opcode==Opcode::Notify) {
1194 S.inc("incoming-notifications");
1195 int res=processNotify(p);
1196 if(res>=0) {
1197 r->setRcode(res);
1198 r->setOpcode(Opcode::Notify);
1199 return r;
1200 }
1201 delete r;
1202 return 0;
1203 }
1204
1205 g_log<<Logger::Error<<"Received an unknown opcode "<<p->d.opcode<<" from "<<p->getRemote()<<" for "<<p->qdomain<<endl;
1206
1207 r->setRcode(RCode::NotImp);
1208 return r;
1209 }
1210
1211 // g_log<<Logger::Warning<<"Query for '"<<p->qdomain<<"' "<<p->qtype.getName()<<" from "<<p->getRemote()<< " (tcp="<<p->d_tcp<<")"<<endl;
1212
1213 if(p->qtype.getCode()==QType::IXFR) {
1214 r->setRcode(RCode::Refused);
1215 return r;
1216 }
1217
1218 DNSName target=p->qdomain;
1219
1220 // catch chaos qclass requests
1221 if(p->qclass == QClass::CHAOS) {
1222 if (doChaosRequest(p,r,target))
1223 goto sendit;
1224 else
1225 return r;
1226 }
1227
1228 // we only know about qclass IN (and ANY), send Refused for everything else.
1229 if(p->qclass != QClass::IN && p->qclass!=QClass::ANY) {
1230 r->setRcode(RCode::Refused);
1231 return r;
1232 }
1233
1234 // send TC for udp ANY query if any-to-tcp is enabled.
1235 if(p->qtype.getCode() == QType::ANY && !p->d_tcp && g_anyToTcp) {
1236 r->d.tc = 1;
1237 r->commitD();
1238 return r;
1239 }
1240
1241 // for qclass ANY the response should never be authoritative unless the response covers all classes.
1242 if(p->qclass==QClass::ANY)
1243 r->setA(false);
1244
1245
1246 retargeted:;
1247 if(retargetcount > 10) { // XXX FIXME, retargetcount++?
1248 g_log<<Logger::Warning<<"Abort CNAME chain resolution after "<<--retargetcount<<" redirects, sending out servfail. Initial query: '"<<p->qdomain<<"'"<<endl;
1249 delete r;
1250 r=p->replyPacket();
1251 r->setRcode(RCode::ServFail);
1252 return r;
1253 }
1254
1255 if(!B.getAuth(target, p->qtype, &sd)) {
1256 DLOG(g_log<<Logger::Error<<"We have no authority over zone '"<<target<<"'"<<endl);
1257 if(!retargetcount) {
1258 r->setA(false); // drop AA if we never had a SOA in the first place
1259 r->setRcode(RCode::Refused); // send REFUSED - but only on empty 'no idea'
1260 }
1261 goto sendit;
1262 }
1263 DLOG(g_log<<Logger::Error<<"We have authority, zone='"<<sd.qname<<"', id="<<sd.domain_id<<endl);
1264
1265 authSet.insert(sd.qname);
1266 d_dnssec=(p->d_dnssecOk && d_dk.isSecuredZone(sd.qname));
1267 doSigs |= d_dnssec;
1268
1269 if(!retargetcount) r->qdomainzone=sd.qname;
1270
1271 if(sd.qname==p->qdomain) {
1272 if(p->qtype.getCode() == QType::DNSKEY)
1273 {
1274 if(addDNSKEY(p, r, sd))
1275 goto sendit;
1276 }
1277 else if(p->qtype.getCode() == QType::CDNSKEY)
1278 {
1279 if(addCDNSKEY(p,r, sd))
1280 goto sendit;
1281 }
1282 else if(p->qtype.getCode() == QType::CDS)
1283 {
1284 if(addCDS(p,r, sd))
1285 goto sendit;
1286 }
1287 else if(d_dnssec && p->qtype.getCode() == QType::NSEC3PARAM)
1288 {
1289 if(addNSEC3PARAM(p,r, sd))
1290 goto sendit;
1291 }
1292 }
1293
1294 if(p->qtype.getCode() == QType::SOA && sd.qname==p->qdomain) {
1295 rr=makeEditedDNSZRFromSOAData(d_dk, sd);
1296 r->addRecord(rr);
1297 goto sendit;
1298 }
1299
1300 // this TRUMPS a cname!
1301 if(d_dnssec && p->qtype.getCode() == QType::NSEC && !d_dk.getNSEC3PARAM(sd.qname, 0)) {
1302 addNSEC(p, r, target, DNSName(), sd.qname, 5);
1303 if (!r->isEmpty())
1304 goto sendit;
1305 }
1306
1307 // this TRUMPS a cname!
1308 if(p->qtype.getCode() == QType::RRSIG) {
1309 g_log<<Logger::Info<<"Direct RRSIG query for "<<target<<" from "<<p->getRemote()<<endl;
1310 r->setRcode(RCode::Refused);
1311 goto sendit;
1312 }
1313
1314 DLOG(g_log<<"Checking for referrals first, unless this is a DS query"<<endl);
1315 if(p->qtype.getCode() != QType::DS && tryReferral(p, r, sd, target, retargetcount))
1316 goto sendit;
1317
1318 DLOG(g_log<<"Got no referrals, trying ANY"<<endl);
1319
1320 #ifdef HAVE_LUA_RECORDS
1321 if(!doLua) {
1322 string val;
1323 d_dk.getFromMeta(sd.qname, "ENABLE-LUA-RECORDS", val);
1324 doLua = (val=="1");
1325 }
1326 #endif
1327
1328 // see what we get..
1329 B.lookup(QType(QType::ANY), target, p, sd.domain_id);
1330 rrset.clear();
1331 haveAlias.trimToLabels(0);
1332 aliasScopeMask = 0;
1333 weDone = weRedirected = weHaveUnauth = false;
1334
1335 while(B.get(rr)) {
1336 #ifdef HAVE_LUA_RECORDS
1337 if(rr.dr.d_type == QType::LUA) {
1338 if(!doLua)
1339 continue;
1340 auto rec=getRR<LUARecordContent>(rr.dr);
1341 if (!rec) {
1342 continue;
1343 }
1344 if(rec->d_type == QType::CNAME || rec->d_type == p->qtype.getCode() || (p->qtype.getCode() == QType::ANY && rec->d_type != QType::RRSIG)) {
1345 noCache=true;
1346 try {
1347 auto recvec=luaSynth(rec->getCode(), target, sd.qname, sd.domain_id, *p, rec->d_type);
1348 if(!recvec.empty()) {
1349 for(const auto& r : recvec) {
1350 rr.dr.d_type = rec->d_type; // might be CNAME
1351 rr.dr.d_content = r;
1352 rr.scopeMask = p->getRealRemote().getBits(); // this makes sure answer is a specific as your question
1353 rrset.push_back(rr);
1354 }
1355 if(rec->d_type == QType::CNAME && p->qtype.getCode() != QType::CNAME)
1356 weRedirected = 1;
1357 else
1358 weDone = 1;
1359 }
1360 }
1361 catch(std::exception &e) {
1362 r=p->replyPacket();
1363 r->setRcode(RCode::ServFail);
1364
1365 return r;
1366 }
1367 }
1368 }
1369 #endif
1370 //cerr<<"got content: ["<<rr.content<<"]"<<endl;
1371 if (!d_dnssec && p->qtype.getCode() == QType::ANY && (rr.dr.d_type == QType:: DNSKEY || rr.dr.d_type == QType::NSEC3PARAM))
1372 continue; // Don't send dnssec info.
1373 if (rr.dr.d_type == QType::RRSIG) // RRSIGS are added later any way.
1374 continue; // TODO: this actually means addRRSig should check if the RRSig is already there
1375
1376 // cerr<<"Auth: "<<rr.auth<<", "<<(rr.dr.d_type == p->qtype)<<", "<<rr.dr.d_type.getName()<<endl;
1377 if((p->qtype.getCode() == QType::ANY || rr.dr.d_type == p->qtype.getCode()) && rr.auth)
1378 weDone=1;
1379 // the line below fakes 'unauth NS' for delegations for non-DNSSEC backends.
1380 if((rr.dr.d_type == p->qtype.getCode() && !rr.auth) || (rr.dr.d_type == QType::NS && (!rr.auth || !(sd.qname==rr.dr.d_name))))
1381 weHaveUnauth=1;
1382
1383 if(rr.dr.d_type == QType::CNAME && p->qtype.getCode() != QType::CNAME)
1384 weRedirected=1;
1385
1386 if(DP && rr.dr.d_type == QType::ALIAS && (p->qtype.getCode() == QType::A || p->qtype.getCode() == QType::AAAA || p->qtype.getCode() == QType::ANY)) {
1387 if (!d_doExpandALIAS) {
1388 g_log<<Logger::Info<<"ALIAS record found for "<<target<<", but ALIAS expansion is disabled."<<endl;
1389 continue;
1390 }
1391 haveAlias=getRR<ALIASRecordContent>(rr.dr)->d_content;
1392 aliasScopeMask=rr.scopeMask;
1393 }
1394
1395 // Filter out all SOA's and add them in later
1396 if(rr.dr.d_type == QType::SOA)
1397 continue;
1398
1399 rrset.push_back(rr);
1400 }
1401
1402 /* Add in SOA if required */
1403 if(target==sd.qname) {
1404 rr=makeEditedDNSZRFromSOAData(d_dk, sd);
1405 rrset.push_back(rr);
1406 }
1407
1408
1409 DLOG(g_log<<"After first ANY query for '"<<target<<"', id="<<sd.domain_id<<": weDone="<<weDone<<", weHaveUnauth="<<weHaveUnauth<<", weRedirected="<<weRedirected<<", haveAlias='"<<haveAlias<<"'"<<endl);
1410 if(p->qtype.getCode() == QType::DS && weHaveUnauth && !weDone && !weRedirected) {
1411 DLOG(g_log<<"Q for DS of a name for which we do have NS, but for which we don't have DS; need to provide an AUTH answer that shows we don't"<<endl);
1412 makeNOError(p, r, target, DNSName(), sd, 1);
1413 goto sendit;
1414 }
1415
1416 if(!haveAlias.empty() && (!weDone || p->qtype.getCode() == QType::ANY)) {
1417 DLOG(g_log<<Logger::Warning<<"Found nothing that matched for '"<<target<<"', but did get alias to '"<<haveAlias<<"', referring"<<endl);
1418 DP->completePacket(r, haveAlias, target, aliasScopeMask);
1419 return 0;
1420 }
1421
1422
1423 // referral for DS query
1424 if(p->qtype.getCode() == QType::DS) {
1425 DLOG(g_log<<"Qtype is DS"<<endl);
1426 bool doReferral = true;
1427 if(d_dk.doesDNSSEC()) {
1428 for(auto& loopRR: rrset) {
1429 // In a dnssec capable backend auth=true means, there is no delagation at
1430 // or above this qname in this zone (for DS queries). Without a delegation,
1431 // at or above this level, it is pointless to search for refferals.
1432 if(loopRR.auth) {
1433 doReferral = false;
1434 break;
1435 }
1436 }
1437 } else {
1438 for(auto& loopRR: rrset) {
1439 // In a non dnssec capable backend auth is always true, so our only option
1440 // is, always look for referals. Unless there is a direct match for DS.
1441 if(loopRR.dr.d_type == QType::DS) {
1442 doReferral = false;
1443 break;
1444 }
1445 }
1446 }
1447 if(doReferral) {
1448 DLOG(g_log<<"DS query found no direct result, trying referral now"<<endl);
1449 if(tryReferral(p, r, sd, target, retargetcount))
1450 {
1451 DLOG(g_log<<"Got referral for DS query"<<endl);
1452 goto sendit;
1453 }
1454 }
1455 }
1456
1457
1458 if(rrset.empty()) {
1459 DLOG(g_log<<Logger::Warning<<"Found nothing in the by-name ANY, but let's try wildcards.."<<endl);
1460 bool wereRetargeted(false), nodata(false);
1461 DNSName wildcard;
1462 if(tryWildcard(p, r, sd, target, wildcard, wereRetargeted, nodata)) {
1463 if(wereRetargeted) {
1464 if(!retargetcount) r->qdomainwild=wildcard;
1465 retargetcount++;
1466 goto retargeted;
1467 }
1468 if(nodata)
1469 makeNOError(p, r, target, wildcard, sd, 2);
1470
1471 goto sendit;
1472 }
1473 else if(tryDNAME(p, r, sd, target)) {
1474 retargetcount++;
1475 goto retargeted;
1476 }
1477 else
1478 {
1479 if (!(((p->qtype.getCode() == QType::CNAME) || (p->qtype.getCode() == QType::ANY)) && retargetcount > 0))
1480 makeNXDomain(p, r, target, wildcard, sd);
1481 }
1482
1483 goto sendit;
1484 }
1485
1486 if(weRedirected) {
1487 for(auto& loopRR: rrset) {
1488 if(loopRR.dr.d_type == QType::CNAME) {
1489 r->addRecord(loopRR);
1490 target = getRR<CNAMERecordContent>(loopRR.dr)->getTarget();
1491 retargetcount++;
1492 goto retargeted;
1493 }
1494 }
1495 }
1496 else if(weDone) {
1497 bool haveRecords = false;
1498 for(const auto& loopRR: rrset) {
1499 #ifdef HAVE_LUA_RECORDS
1500 if(loopRR.dr.d_type == QType::LUA)
1501 continue;
1502 #endif
1503 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) {
1504 r->addRecord(loopRR);
1505 haveRecords = true;
1506 }
1507 }
1508
1509 if (haveRecords) {
1510 if(d_dnssec && p->qtype.getCode() == QType::ANY)
1511 completeANYRecords(p, r, sd, target);
1512 }
1513 else
1514 makeNOError(p, r, target, DNSName(), sd, 0);
1515
1516 goto sendit;
1517 }
1518 else if(weHaveUnauth) {
1519 DLOG(g_log<<"Have unauth data, so need to hunt for best NS records"<<endl);
1520 if(tryReferral(p, r, sd, target, retargetcount))
1521 goto sendit;
1522 // check whether this could be fixed easily
1523 // if (*(rr.dr.d_name.rbegin()) == '.') {
1524 // g_log<<Logger::Error<<"Should not get here ("<<p->qdomain<<"|"<<p->qtype.getCode()<<"): you have a trailing dot, this could be the problem (or run pdnsutil rectify-zone " <<sd.qname<<")"<<endl;
1525 // } else {
1526 g_log<<Logger::Error<<"Should not get here ("<<p->qdomain<<"|"<<p->qtype.getCode()<<"): please run pdnsutil rectify-zone "<<sd.qname<<endl;
1527 // }
1528 }
1529 else {
1530 DLOG(g_log<<"Have some data, but not the right data"<<endl);
1531 makeNOError(p, r, target, DNSName(), sd, 0);
1532 }
1533
1534 sendit:;
1535 if(doAdditionalProcessingAndDropAA(p, r, sd, retargetcount)<0) {
1536 delete r;
1537 return 0;
1538 }
1539
1540 for(const auto& loopRR: r->getRRS()) {
1541 if(loopRR.scopeMask) {
1542 noCache=true;
1543 break;
1544 }
1545 }
1546 if(doSigs)
1547 addRRSigs(d_dk, B, authSet, r->getRRS());
1548
1549 r->wrapup(); // needed for inserting in cache
1550 if(!noCache && p->couldBeCached())
1551 PC.insert(p, r, r->getMinTTL()); // in the packet cache
1552 }
1553 catch(DBException &e) {
1554 g_log<<Logger::Error<<"Backend reported condition which prevented lookup ("+e.reason+") sending out servfail"<<endl;
1555 delete r;
1556 r=p->replyPacket(); // generate an empty reply packet
1557 r->setRcode(RCode::ServFail);
1558 S.inc("servfail-packets");
1559 S.ringAccount("servfail-queries", p->qdomain, p->qtype);
1560 }
1561 catch(PDNSException &e) {
1562 g_log<<Logger::Error<<"Backend reported permanent error which prevented lookup ("+e.reason+"), aborting"<<endl;
1563 throw; // we WANT to die at this point
1564 }
1565 catch(std::exception &e) {
1566 g_log<<Logger::Error<<"Exception building answer packet for "<<p->qdomain<<"/"<<p->qtype.getName()<<" ("<<e.what()<<") sending out servfail"<<endl;
1567 delete r;
1568 r=p->replyPacket(); // generate an empty reply packet
1569 r->setRcode(RCode::ServFail);
1570 S.inc("servfail-packets");
1571 S.ringAccount("servfail-queries", p->qdomain, p->qtype);
1572 }
1573 return r;
1574
1575 }