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