]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/packethandler.cc
Revert "Bail out when no Context library is available"
[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 DNSName expected{meta[0]};
877 if (p->getTSIGKeyname() != expected) {
878 g_log<<Logger::Warning<<"Received secure NOTIFY for "<<p->qdomain<<" from "<<p->getRemote()<<": expected TSIG key '"<<expected<<"', got '"<<p->getTSIGKeyname()<<"' (Refused)"<<endl;
879 return RCode::Refused;
880 }
881 }
882 }
883
884 // Domain verification
885 //
886 DomainInfo di;
887 if(!B.getDomainInfo(p->qdomain, di, false) || !di.backend) {
888 if(::arg().mustDo("superslave")) {
889 g_log<<Logger::Warning<<"Received NOTIFY for "<<p->qdomain<<" from "<<p->getRemote()<<" for which we are not authoritative, trying supermaster"<<endl;
890 return trySuperMaster(p, p->getTSIGKeyname());
891 }
892 g_log<<Logger::Notice<<"Received NOTIFY for "<<p->qdomain<<" from "<<p->getRemote()<<" for which we are not authoritative (Refused)"<<endl;
893 return RCode::Refused;
894 }
895
896 if(::arg().contains("trusted-notification-proxy", p->getRemote().toString())) {
897 g_log<<Logger::Error<<"Received NOTIFY for "<<p->qdomain<<" from trusted-notification-proxy "<< p->getRemote()<<endl;
898 if(di.masters.empty()) {
899 g_log<<Logger::Error<<"However, "<<p->qdomain<<" does not have any masters defined (Refused)"<<endl;
900 return RCode::Refused;
901 }
902 }
903 else if(::arg().mustDo("master") && di.kind == DomainInfo::Master) {
904 g_log<<Logger::Warning<<"Received NOTIFY for "<<p->qdomain<<" from "<<p->getRemote()<<" but we are master (Refused)"<<endl;
905 return RCode::Refused;
906 }
907 else if(!di.isMaster(p->getRemote())) {
908 g_log<<Logger::Warning<<"Received NOTIFY for "<<p->qdomain<<" from "<<p->getRemote()<<" which is not a master (Refused)"<<endl;
909 return RCode::Refused;
910 }
911
912 if(!s_forwardNotify.empty()) {
913 set<string> forwardNotify(s_forwardNotify);
914 for(set<string>::const_iterator j=forwardNotify.begin();j!=forwardNotify.end();++j) {
915 g_log<<Logger::Notice<<"Relaying notification of domain "<<p->qdomain<<" from "<<p->getRemote()<<" to "<<*j<<endl;
916 Communicator.notify(p->qdomain,*j);
917 }
918 }
919
920 if(::arg().mustDo("slave")) {
921 g_log<<Logger::Debug<<"Queueing slave check for "<<p->qdomain<<endl;
922 Communicator.addSlaveCheckRequest(di, p->d_remote);
923 }
924 return 0;
925 }
926
927 bool validDNSName(const DNSName &name)
928 {
929 if (!g_8bitDNS) {
930 string::size_type pos, length;
931 char c;
932 for(const auto& s : name.getRawLabels()) {
933 length=s.length();
934 for(pos=0; pos < length; ++pos) {
935 c=s[pos];
936 if(!((c >= 'a' && c <= 'z') ||
937 (c >= 'A' && c <= 'Z') ||
938 (c >= '0' && c <= '9') ||
939 c =='-' || c == '_' || c=='*' || c=='.' || c=='/' || c=='@' || c==' ' || c=='\\' || c==':'))
940 return false;
941 }
942 }
943 }
944 return true;
945 }
946
947 DNSPacket *PacketHandler::question(DNSPacket *p)
948 {
949 DNSPacket *ret;
950
951 if(d_pdl)
952 {
953 ret=d_pdl->prequery(p);
954 if(ret)
955 return ret;
956 }
957
958 if(p->d.rd) {
959 static AtomicCounter &rdqueries=*S.getPointer("rd-queries");
960 rdqueries++;
961 }
962
963 return doQuestion(p);
964 }
965
966
967 void PacketHandler::makeNXDomain(DNSPacket* p, DNSPacket* r, const DNSName& target, const DNSName& wildcard, const SOAData& sd)
968 {
969 DNSZoneRecord rr;
970 rr=makeEditedDNSZRFromSOAData(d_dk, sd, DNSResourceRecord::AUTHORITY);
971 rr.dr.d_ttl=min(sd.ttl, sd.default_ttl);
972 r->addRecord(rr);
973
974 if(d_dnssec) {
975 addNSECX(p, r, target, wildcard, sd.qname, 4);
976 }
977
978 r->setRcode(RCode::NXDomain);
979 }
980
981 void PacketHandler::makeNOError(DNSPacket* p, DNSPacket* r, const DNSName& target, const DNSName& wildcard, const SOAData& sd, int mode)
982 {
983 DNSZoneRecord rr;
984 rr=makeEditedDNSZRFromSOAData(d_dk, sd, DNSResourceRecord::AUTHORITY);
985 rr.dr.d_ttl=min(sd.ttl, sd.default_ttl);
986 r->addRecord(rr);
987
988 if(d_dnssec) {
989 addNSECX(p, r, target, wildcard, sd.qname, mode);
990 }
991
992 S.ringAccount("noerror-queries", p->qdomain, p->qtype);
993 }
994
995
996 bool PacketHandler::addDSforNS(DNSPacket* p, DNSPacket* r, SOAData& sd, const DNSName& dsname)
997 {
998 //cerr<<"Trying to find a DS for '"<<dsname<<"', domain_id = "<<sd.domain_id<<endl;
999 B.lookup(QType(QType::DS), dsname, p, sd.domain_id);
1000 DNSZoneRecord rr;
1001 bool gotOne=false;
1002 while(B.get(rr)) {
1003 gotOne=true;
1004 rr.dr.d_place = DNSResourceRecord::AUTHORITY;
1005 r->addRecord(rr);
1006 }
1007 return gotOne;
1008 }
1009
1010 bool PacketHandler::tryReferral(DNSPacket *p, DNSPacket*r, SOAData& sd, const DNSName &target, bool retargeted)
1011 {
1012 vector<DNSZoneRecord> rrset = getBestReferralNS(p, sd, target);
1013 if(rrset.empty())
1014 return false;
1015
1016 for(auto& rr: rrset) {
1017 rr.dr.d_place=DNSResourceRecord::AUTHORITY;
1018 r->addRecord(rr);
1019 }
1020 if(!retargeted)
1021 r->setA(false);
1022
1023 if(d_dk.isSecuredZone(sd.qname) && !addDSforNS(p, r, sd, rrset.begin()->dr.d_name) && d_dnssec) {
1024 addNSECX(p, r, rrset.begin()->dr.d_name, DNSName(), sd.qname, 1);
1025 }
1026
1027 return true;
1028 }
1029
1030 void PacketHandler::completeANYRecords(DNSPacket *p, DNSPacket*r, SOAData& sd, const DNSName &target)
1031 {
1032 addNSECX(p, r, target, DNSName(), sd.qname, 5);
1033 if(sd.qname == p->qdomain) {
1034 addDNSKEY(p, r, sd);
1035 addCDNSKEY(p, r, sd);
1036 addCDS(p, r, sd);
1037 addNSEC3PARAM(p, r, sd);
1038 }
1039 }
1040
1041 bool PacketHandler::tryDNAME(DNSPacket *p, DNSPacket*r, SOAData& sd, DNSName &target)
1042 {
1043 if(!d_doDNAME)
1044 return false;
1045 DLOG(g_log<<Logger::Warning<<"Let's try DNAME.."<<endl);
1046 vector<DNSZoneRecord> rrset = getBestDNAMESynth(p, sd, target);
1047 if(!rrset.empty()) {
1048 for(auto& rr: rrset) {
1049 rr.dr.d_place = DNSResourceRecord::ANSWER;
1050 r->addRecord(rr);
1051 }
1052 return true;
1053 }
1054 return false;
1055 }
1056 bool PacketHandler::tryWildcard(DNSPacket *p, DNSPacket*r, SOAData& sd, DNSName &target, DNSName &wildcard, bool& retargeted, bool& nodata)
1057 {
1058 retargeted = nodata = false;
1059 DNSName bestmatch;
1060
1061 vector<DNSZoneRecord> rrset;
1062 if(!getBestWildcard(p, sd, target, wildcard, &rrset))
1063 return false;
1064
1065 if(rrset.empty()) {
1066 DLOG(g_log<<"Wildcard matched something, but not of the correct type"<<endl);
1067 nodata=true;
1068 }
1069 else {
1070 for(auto& rr: rrset) {
1071 rr.wildcardname = rr.dr.d_name;
1072 rr.dr.d_name=bestmatch=target;
1073
1074 if(rr.dr.d_type == QType::CNAME) {
1075 retargeted=true;
1076 target=getRR<CNAMERecordContent>(rr.dr)->getTarget();
1077 }
1078
1079 rr.dr.d_place=DNSResourceRecord::ANSWER;
1080 r->addRecord(rr);
1081 }
1082 }
1083 if(d_dnssec && !nodata) {
1084 addNSECX(p, r, bestmatch, wildcard, sd.qname, 3);
1085 }
1086
1087 return true;
1088 }
1089
1090 //! Called by the Distributor to ask a question. Returns 0 in case of an error
1091 DNSPacket *PacketHandler::doQuestion(DNSPacket *p)
1092 {
1093 DNSZoneRecord rr;
1094 SOAData sd;
1095
1096 int retargetcount=0;
1097 set<DNSName> authSet;
1098
1099 vector<DNSZoneRecord> rrset;
1100 bool weDone=0, weRedirected=0, weHaveUnauth=0, doSigs=0;
1101 DNSName haveAlias;
1102 uint8_t aliasScopeMask;
1103
1104 DNSPacket *r=nullptr;
1105 bool noCache=false;
1106
1107 #ifdef HAVE_LUA_RECORDS
1108 bool doLua=g_doLuaRecord;
1109 #endif
1110
1111 if(p->d.qr) { // QR bit from dns packet (thanks RA from N)
1112 if(d_logDNSDetails)
1113 g_log<<Logger::Error<<"Received an answer (non-query) packet from "<<p->getRemote()<<", dropping"<<endl;
1114 S.inc("corrupt-packets");
1115 S.ringAccount("remotes-corrupt", p->d_remote);
1116 return 0;
1117 }
1118
1119 if(p->d.tc) { // truncated query. MOADNSParser would silently parse this packet in an incomplete way.
1120 if(d_logDNSDetails)
1121 g_log<<Logger::Error<<"Received truncated query packet from "<<p->getRemote()<<", dropping"<<endl;
1122 S.inc("corrupt-packets");
1123 S.ringAccount("remotes-corrupt", p->d_remote);
1124 return 0;
1125 }
1126
1127 if (p->hasEDNS() && p->getEDNSVersion() > 0) {
1128 r = p->replyPacket();
1129
1130 // PacketWriter::addOpt will take care of setting this correctly in the packet
1131 r->setEDNSRcode(ERCode::BADVERS);
1132 return r;
1133 }
1134
1135 if(p->d_havetsig) {
1136 DNSName keyname;
1137 string secret;
1138 TSIGRecordContent trc;
1139 if(!p->checkForCorrectTSIG(&B, &keyname, &secret, &trc)) {
1140 r=p->replyPacket(); // generate an empty reply packet
1141 if(d_logDNSDetails)
1142 g_log<<Logger::Error<<"Received a TSIG signed message with a non-validating key"<<endl;
1143 // RFC3007 describes that a non-secure message should be sending Refused for DNS Updates
1144 if (p->d.opcode == Opcode::Update)
1145 r->setRcode(RCode::Refused);
1146 else
1147 r->setRcode(RCode::NotAuth);
1148 return r;
1149 } else {
1150 getTSIGHashEnum(trc.d_algoName, p->d_tsig_algo);
1151 if (p->d_tsig_algo == TSIG_GSS) {
1152 GssContext gssctx(keyname);
1153 if (!gssctx.getPeerPrincipal(p->d_peer_principal)) {
1154 g_log<<Logger::Warning<<"Failed to extract peer principal from GSS context with keyname '"<<keyname<<"'"<<endl;
1155 }
1156 }
1157 }
1158 p->setTSIGDetails(trc, keyname, secret, trc.d_mac); // this will get copied by replyPacket()
1159 noCache=true;
1160 }
1161
1162 r=p->replyPacket(); // generate an empty reply packet, possibly with TSIG details inside
1163
1164 if (p->qtype == QType::TKEY) {
1165 this->tkeyHandler(p, r);
1166 return r;
1167 }
1168
1169 try {
1170
1171 // XXX FIXME do this in DNSPacket::parse ?
1172
1173 if(!validDNSName(p->qdomain)) {
1174 if(d_logDNSDetails)
1175 g_log<<Logger::Error<<"Received a malformed qdomain from "<<p->getRemote()<<", '"<<p->qdomain<<"': sending servfail"<<endl;
1176 S.inc("corrupt-packets");
1177 S.ringAccount("remotes-corrupt", p->d_remote);
1178 S.inc("servfail-packets");
1179 r->setRcode(RCode::ServFail);
1180 return r;
1181 }
1182 if(p->d.opcode) { // non-zero opcode (again thanks RA!)
1183 if(p->d.opcode==Opcode::Update) {
1184 S.inc("dnsupdate-queries");
1185 int res=processUpdate(p);
1186 if (res == RCode::Refused)
1187 S.inc("dnsupdate-refused");
1188 else if (res != RCode::ServFail)
1189 S.inc("dnsupdate-answers");
1190 r->setRcode(res);
1191 r->setOpcode(Opcode::Update);
1192 return r;
1193 }
1194 else if(p->d.opcode==Opcode::Notify) {
1195 S.inc("incoming-notifications");
1196 int res=processNotify(p);
1197 if(res>=0) {
1198 r->setRcode(res);
1199 r->setOpcode(Opcode::Notify);
1200 return r;
1201 }
1202 delete r;
1203 return 0;
1204 }
1205
1206 g_log<<Logger::Error<<"Received an unknown opcode "<<p->d.opcode<<" from "<<p->getRemote()<<" for "<<p->qdomain<<endl;
1207
1208 r->setRcode(RCode::NotImp);
1209 return r;
1210 }
1211
1212 // g_log<<Logger::Warning<<"Query for '"<<p->qdomain<<"' "<<p->qtype.getName()<<" from "<<p->getRemote()<< " (tcp="<<p->d_tcp<<")"<<endl;
1213
1214 if(p->qtype.getCode()==QType::IXFR) {
1215 r->setRcode(RCode::Refused);
1216 return r;
1217 }
1218
1219 DNSName target=p->qdomain;
1220
1221 // catch chaos qclass requests
1222 if(p->qclass == QClass::CHAOS) {
1223 if (doChaosRequest(p,r,target))
1224 goto sendit;
1225 else
1226 return r;
1227 }
1228
1229 // we only know about qclass IN (and ANY), send Refused for everything else.
1230 if(p->qclass != QClass::IN && p->qclass!=QClass::ANY) {
1231 r->setRcode(RCode::Refused);
1232 return r;
1233 }
1234
1235 // send TC for udp ANY query if any-to-tcp is enabled.
1236 if(p->qtype.getCode() == QType::ANY && !p->d_tcp && g_anyToTcp) {
1237 r->d.tc = 1;
1238 r->commitD();
1239 return r;
1240 }
1241
1242 // for qclass ANY the response should never be authoritative unless the response covers all classes.
1243 if(p->qclass==QClass::ANY)
1244 r->setA(false);
1245
1246
1247 retargeted:;
1248 if(retargetcount > 10) { // XXX FIXME, retargetcount++?
1249 g_log<<Logger::Warning<<"Abort CNAME chain resolution after "<<--retargetcount<<" redirects, sending out servfail. Initial query: '"<<p->qdomain<<"'"<<endl;
1250 delete r;
1251 r=p->replyPacket();
1252 r->setRcode(RCode::ServFail);
1253 return r;
1254 }
1255
1256 if(!B.getAuth(target, p->qtype, &sd)) {
1257 DLOG(g_log<<Logger::Error<<"We have no authority over zone '"<<target<<"'"<<endl);
1258 if(!retargetcount) {
1259 r->setA(false); // drop AA if we never had a SOA in the first place
1260 r->setRcode(RCode::Refused); // send REFUSED - but only on empty 'no idea'
1261 }
1262 goto sendit;
1263 }
1264 DLOG(g_log<<Logger::Error<<"We have authority, zone='"<<sd.qname<<"', id="<<sd.domain_id<<endl);
1265
1266 authSet.insert(sd.qname);
1267 d_dnssec=(p->d_dnssecOk && d_dk.isSecuredZone(sd.qname));
1268 doSigs |= d_dnssec;
1269
1270 if(!retargetcount) r->qdomainzone=sd.qname;
1271
1272 if(sd.qname==p->qdomain) {
1273 if(p->qtype.getCode() == QType::DNSKEY)
1274 {
1275 if(addDNSKEY(p, r, sd))
1276 goto sendit;
1277 }
1278 else if(p->qtype.getCode() == QType::CDNSKEY)
1279 {
1280 if(addCDNSKEY(p,r, sd))
1281 goto sendit;
1282 }
1283 else if(p->qtype.getCode() == QType::CDS)
1284 {
1285 if(addCDS(p,r, sd))
1286 goto sendit;
1287 }
1288 else if(d_dnssec && p->qtype.getCode() == QType::NSEC3PARAM)
1289 {
1290 if(addNSEC3PARAM(p,r, sd))
1291 goto sendit;
1292 }
1293 }
1294
1295 if(p->qtype.getCode() == QType::SOA && sd.qname==p->qdomain) {
1296 rr=makeEditedDNSZRFromSOAData(d_dk, sd);
1297 r->addRecord(rr);
1298 goto sendit;
1299 }
1300
1301 // this TRUMPS a cname!
1302 if(d_dnssec && p->qtype.getCode() == QType::NSEC && !d_dk.getNSEC3PARAM(sd.qname, 0)) {
1303 addNSEC(p, r, target, DNSName(), sd.qname, 5);
1304 if (!r->isEmpty())
1305 goto sendit;
1306 }
1307
1308 // this TRUMPS a cname!
1309 if(p->qtype.getCode() == QType::RRSIG) {
1310 g_log<<Logger::Info<<"Direct RRSIG query for "<<target<<" from "<<p->getRemote()<<endl;
1311 r->setRcode(RCode::Refused);
1312 goto sendit;
1313 }
1314
1315 DLOG(g_log<<"Checking for referrals first, unless this is a DS query"<<endl);
1316 if(p->qtype.getCode() != QType::DS && tryReferral(p, r, sd, target, retargetcount))
1317 goto sendit;
1318
1319 DLOG(g_log<<"Got no referrals, trying ANY"<<endl);
1320
1321 #ifdef HAVE_LUA_RECORDS
1322 if(!doLua) {
1323 string val;
1324 d_dk.getFromMeta(sd.qname, "ENABLE-LUA-RECORDS", val);
1325 doLua = (val=="1");
1326 }
1327 #endif
1328
1329 // see what we get..
1330 B.lookup(QType(QType::ANY), target, p, sd.domain_id);
1331 rrset.clear();
1332 haveAlias.trimToLabels(0);
1333 aliasScopeMask = 0;
1334 weDone = weRedirected = weHaveUnauth = false;
1335
1336 while(B.get(rr)) {
1337 #ifdef HAVE_LUA_RECORDS
1338 if(rr.dr.d_type == QType::LUA) {
1339 if(!doLua)
1340 continue;
1341 auto rec=getRR<LUARecordContent>(rr.dr);
1342 if (!rec) {
1343 continue;
1344 }
1345 if(rec->d_type == QType::CNAME || rec->d_type == p->qtype.getCode() || (p->qtype.getCode() == QType::ANY && rec->d_type != QType::RRSIG)) {
1346 noCache=true;
1347 try {
1348 auto recvec=luaSynth(rec->getCode(), target, sd.qname, sd.domain_id, *p, rec->d_type);
1349 if(!recvec.empty()) {
1350 for(const auto& r : recvec) {
1351 rr.dr.d_type = rec->d_type; // might be CNAME
1352 rr.dr.d_content = r;
1353 rr.scopeMask = p->getRealRemote().getBits(); // this makes sure answer is a specific as your question
1354 rrset.push_back(rr);
1355 }
1356 if(rec->d_type == QType::CNAME && p->qtype.getCode() != QType::CNAME)
1357 weRedirected = 1;
1358 else
1359 weDone = 1;
1360 }
1361 }
1362 catch(std::exception &e) {
1363 r=p->replyPacket();
1364 r->setRcode(RCode::ServFail);
1365
1366 return r;
1367 }
1368 }
1369 }
1370 #endif
1371 //cerr<<"got content: ["<<rr.content<<"]"<<endl;
1372 if (!d_dnssec && p->qtype.getCode() == QType::ANY && (rr.dr.d_type == QType:: DNSKEY || rr.dr.d_type == QType::NSEC3PARAM))
1373 continue; // Don't send dnssec info.
1374 if (rr.dr.d_type == QType::RRSIG) // RRSIGS are added later any way.
1375 continue; // TODO: this actually means addRRSig should check if the RRSig is already there
1376
1377 // cerr<<"Auth: "<<rr.auth<<", "<<(rr.dr.d_type == p->qtype)<<", "<<rr.dr.d_type.getName()<<endl;
1378 if((p->qtype.getCode() == QType::ANY || rr.dr.d_type == p->qtype.getCode()) && rr.auth)
1379 weDone=1;
1380 // the line below fakes 'unauth NS' for delegations for non-DNSSEC backends.
1381 if((rr.dr.d_type == p->qtype.getCode() && !rr.auth) || (rr.dr.d_type == QType::NS && (!rr.auth || !(sd.qname==rr.dr.d_name))))
1382 weHaveUnauth=1;
1383
1384 if(rr.dr.d_type == QType::CNAME && p->qtype.getCode() != QType::CNAME)
1385 weRedirected=1;
1386
1387 if(DP && rr.dr.d_type == QType::ALIAS && (p->qtype.getCode() == QType::A || p->qtype.getCode() == QType::AAAA || p->qtype.getCode() == QType::ANY)) {
1388 if (!d_doExpandALIAS) {
1389 g_log<<Logger::Info<<"ALIAS record found for "<<target<<", but ALIAS expansion is disabled."<<endl;
1390 continue;
1391 }
1392 haveAlias=getRR<ALIASRecordContent>(rr.dr)->d_content;
1393 aliasScopeMask=rr.scopeMask;
1394 }
1395
1396 // Filter out all SOA's and add them in later
1397 if(rr.dr.d_type == QType::SOA)
1398 continue;
1399
1400 rrset.push_back(rr);
1401 }
1402
1403 /* Add in SOA if required */
1404 if(target==sd.qname) {
1405 rr=makeEditedDNSZRFromSOAData(d_dk, sd);
1406 rrset.push_back(rr);
1407 }
1408
1409
1410 DLOG(g_log<<"After first ANY query for '"<<target<<"', id="<<sd.domain_id<<": weDone="<<weDone<<", weHaveUnauth="<<weHaveUnauth<<", weRedirected="<<weRedirected<<", haveAlias='"<<haveAlias<<"'"<<endl);
1411 if(p->qtype.getCode() == QType::DS && weHaveUnauth && !weDone && !weRedirected) {
1412 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);
1413 makeNOError(p, r, target, DNSName(), sd, 1);
1414 goto sendit;
1415 }
1416
1417 if(!haveAlias.empty() && (!weDone || p->qtype.getCode() == QType::ANY)) {
1418 DLOG(g_log<<Logger::Warning<<"Found nothing that matched for '"<<target<<"', but did get alias to '"<<haveAlias<<"', referring"<<endl);
1419 DP->completePacket(r, haveAlias, target, aliasScopeMask);
1420 return 0;
1421 }
1422
1423
1424 // referral for DS query
1425 if(p->qtype.getCode() == QType::DS) {
1426 DLOG(g_log<<"Qtype is DS"<<endl);
1427 bool doReferral = true;
1428 if(d_dk.doesDNSSEC()) {
1429 for(auto& loopRR: rrset) {
1430 // In a dnssec capable backend auth=true means, there is no delagation at
1431 // or above this qname in this zone (for DS queries). Without a delegation,
1432 // at or above this level, it is pointless to search for refferals.
1433 if(loopRR.auth) {
1434 doReferral = false;
1435 break;
1436 }
1437 }
1438 } else {
1439 for(auto& loopRR: rrset) {
1440 // In a non dnssec capable backend auth is always true, so our only option
1441 // is, always look for referals. Unless there is a direct match for DS.
1442 if(loopRR.dr.d_type == QType::DS) {
1443 doReferral = false;
1444 break;
1445 }
1446 }
1447 }
1448 if(doReferral) {
1449 DLOG(g_log<<"DS query found no direct result, trying referral now"<<endl);
1450 if(tryReferral(p, r, sd, target, retargetcount))
1451 {
1452 DLOG(g_log<<"Got referral for DS query"<<endl);
1453 goto sendit;
1454 }
1455 }
1456 }
1457
1458
1459 if(rrset.empty()) {
1460 DLOG(g_log<<Logger::Warning<<"Found nothing in the by-name ANY, but let's try wildcards.."<<endl);
1461 bool wereRetargeted(false), nodata(false);
1462 DNSName wildcard;
1463 if(tryWildcard(p, r, sd, target, wildcard, wereRetargeted, nodata)) {
1464 if(wereRetargeted) {
1465 if(!retargetcount) r->qdomainwild=wildcard;
1466 retargetcount++;
1467 goto retargeted;
1468 }
1469 if(nodata)
1470 makeNOError(p, r, target, wildcard, sd, 2);
1471
1472 goto sendit;
1473 }
1474 else if(tryDNAME(p, r, sd, target)) {
1475 retargetcount++;
1476 goto retargeted;
1477 }
1478 else
1479 {
1480 if (!(((p->qtype.getCode() == QType::CNAME) || (p->qtype.getCode() == QType::ANY)) && retargetcount > 0))
1481 makeNXDomain(p, r, target, wildcard, sd);
1482 }
1483
1484 goto sendit;
1485 }
1486
1487 if(weRedirected) {
1488 for(auto& loopRR: rrset) {
1489 if(loopRR.dr.d_type == QType::CNAME) {
1490 r->addRecord(loopRR);
1491 target = getRR<CNAMERecordContent>(loopRR.dr)->getTarget();
1492 retargetcount++;
1493 goto retargeted;
1494 }
1495 }
1496 }
1497 else if(weDone) {
1498 bool haveRecords = false;
1499 for(const auto& loopRR: rrset) {
1500 #ifdef HAVE_LUA_RECORDS
1501 if(loopRR.dr.d_type == QType::LUA)
1502 continue;
1503 #endif
1504 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) {
1505 r->addRecord(loopRR);
1506 haveRecords = true;
1507 }
1508 }
1509
1510 if (haveRecords) {
1511 if(d_dnssec && p->qtype.getCode() == QType::ANY)
1512 completeANYRecords(p, r, sd, target);
1513 }
1514 else
1515 makeNOError(p, r, target, DNSName(), sd, 0);
1516
1517 goto sendit;
1518 }
1519 else if(weHaveUnauth) {
1520 DLOG(g_log<<"Have unauth data, so need to hunt for best NS records"<<endl);
1521 if(tryReferral(p, r, sd, target, retargetcount))
1522 goto sendit;
1523 // check whether this could be fixed easily
1524 // if (*(rr.dr.d_name.rbegin()) == '.') {
1525 // 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;
1526 // } else {
1527 g_log<<Logger::Error<<"Should not get here ("<<p->qdomain<<"|"<<p->qtype.getCode()<<"): please run pdnsutil rectify-zone "<<sd.qname<<endl;
1528 // }
1529 }
1530 else {
1531 DLOG(g_log<<"Have some data, but not the right data"<<endl);
1532 makeNOError(p, r, target, DNSName(), sd, 0);
1533 }
1534
1535 sendit:;
1536 if(doAdditionalProcessingAndDropAA(p, r, sd, retargetcount)<0) {
1537 delete r;
1538 return 0;
1539 }
1540
1541 for(const auto& loopRR: r->getRRS()) {
1542 if(loopRR.scopeMask) {
1543 noCache=true;
1544 break;
1545 }
1546 }
1547 if(doSigs)
1548 addRRSigs(d_dk, B, authSet, r->getRRS());
1549
1550 if(PC.enabled() && !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 delete r;
1564 throw; // we WANT to die at this point
1565 }
1566 catch(std::exception &e) {
1567 g_log<<Logger::Error<<"Exception building answer packet for "<<p->qdomain<<"/"<<p->qtype.getName()<<" ("<<e.what()<<") sending out servfail"<<endl;
1568 delete r;
1569 r=p->replyPacket(); // generate an empty reply packet
1570 r->setRcode(RCode::ServFail);
1571 S.inc("servfail-packets");
1572 S.ringAccount("servfail-queries", p->qdomain, p->qtype);
1573 }
1574 return r;
1575
1576 }