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