2 * This file is part of PowerDNS or dnsdist.
3 * Copyright -- PowerDNS.COM B.V. and its contributors
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.
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.
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.
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.
25 #include "packetcache.hh"
29 #include <sys/types.h>
30 #include <boost/algorithm/string.hpp>
31 #include "dnssecinfra.hh"
32 #include "dnsseckeeper.hh"
34 #include "dnsbackend.hh"
35 #include "ueberbackend.hh"
36 #include "dnspacket.hh"
37 #include "nameserver.hh"
38 #include "distributor.hh"
40 #include "arguments.hh"
41 #include "packethandler.hh"
43 #include "resolver.hh"
44 #include "communicator.hh"
45 #include "dnsproxy.hh"
47 #include "common_startup.hh"
54 AtomicCounter
PacketHandler::s_count
;
55 NetmaskGroup
PacketHandler::s_allowNotifyFrom
;
56 extern string s_programname
;
58 PacketHandler::PacketHandler():B(s_programname
), d_dk(&B
)
61 d_doDNAME
=::arg().mustDo("dname-processing");
62 d_doRecursion
= ::arg().mustDo("recursor");
63 d_logDNSDetails
= ::arg().mustDo("log-dns-details");
64 d_doIPv6AdditionalProcessing
= ::arg().mustDo("do-ipv6-additional-processing");
65 string fname
= ::arg()["lua-prequery-script"];
72 d_pdl
= std::unique_ptr
<AuthLua
>(new AuthLua(fname
));
74 fname
= ::arg()["lua-dnsupdate-policy-script"];
77 d_update_policy_lua
= NULL
;
81 d_update_policy_lua
= std::unique_ptr
<AuthLua4
>(new AuthLua4(fname
));
85 UeberBackend
*PacketHandler::getBackend()
90 PacketHandler::~PacketHandler()
93 DLOG(L
<<Logger::Error
<<"PacketHandler destructor called - "<<s_count
<<" left"<<endl
);
97 * This adds CDNSKEY records to the answer packet. Returns true if one was added.
99 * @param p Pointer to the DNSPacket containing the original question
100 * @param r Pointer to the DNSPacket where the records should be inserted into
101 * @param sd SOAData of the zone for which CDNSKEY records sets should be added
102 * @return bool that shows if any records were added
104 bool PacketHandler::addCDNSKEY(DNSPacket
*p
, DNSPacket
*r
, const SOAData
& sd
)
106 string publishCDNSKEY
;
107 d_dk
.getFromMeta(p
->qdomain
, "PUBLISH-CDNSKEY", publishCDNSKEY
);
108 if (publishCDNSKEY
!= "1")
113 DNSSECPrivateKey dpk
;
115 DNSSECKeeper::keyset_t entryPoints
= d_dk
.getEntryPoints(p
->qdomain
);
116 for(const auto& value
: entryPoints
) {
117 rr
.dr
.d_type
=QType::CDNSKEY
;
118 rr
.dr
.d_ttl
=sd
.default_ttl
;
119 rr
.dr
.d_name
=p
->qdomain
;
120 rr
.dr
.d_content
=std::make_shared
<DNSKEYRecordContent
>(value
.first
.getDNSKEY());
126 if(::arg().mustDo("direct-dnskey")) {
127 B
.lookup(QType(QType::CDNSKEY
), p
->qdomain
, p
, sd
.domain_id
);
130 rr
.dr
.d_ttl
=sd
.default_ttl
;
139 * This adds DNSKEY records to the answer packet. Returns true if one was added.
141 * @param p Pointer to the DNSPacket containing the original question
142 * @param r Pointer to the DNSPacket where the records should be inserted into
143 * @param sd SOAData of the zone for which DNSKEY records sets should be added
144 * @return bool that shows if any records were added
146 bool PacketHandler::addDNSKEY(DNSPacket
*p
, DNSPacket
*r
, const SOAData
& sd
)
150 DNSSECPrivateKey dpk
;
152 DNSSECKeeper::keyset_t keyset
= d_dk
.getKeys(p
->qdomain
);
153 for(const auto& value
: keyset
) {
154 rr
.dr
.d_type
=QType::DNSKEY
;
155 rr
.dr
.d_ttl
=sd
.default_ttl
;
156 rr
.dr
.d_name
=p
->qdomain
;
157 rr
.dr
.d_content
=std::make_shared
<DNSKEYRecordContent
>(value
.first
.getDNSKEY());
163 if(::arg().mustDo("direct-dnskey")) {
164 B
.lookup(QType(QType::DNSKEY
), p
->qdomain
, p
, sd
.domain_id
);
167 rr
.dr
.d_ttl
=sd
.default_ttl
;
177 * This adds CDS records to the answer packet r.
179 * @param p Pointer to the DNSPacket containing the original question.
180 * @param r Pointer to the DNSPacket where the records should be inserted into.
181 * @param sd SOAData of the zone for which CDS records sets should be added,
182 * used to determine record TTL.
183 * @return bool that shows if any records were added.
185 bool PacketHandler::addCDS(DNSPacket
*p
, DNSPacket
*r
, const SOAData
& sd
)
188 d_dk
.getFromMeta(p
->qdomain
, "PUBLISH-CDS", publishCDS
);
189 if (publishCDS
.empty())
192 vector
<string
> digestAlgos
;
193 stringtok(digestAlgos
, publishCDS
, ", ");
196 rr
.dr
.d_type
=QType::CDS
;
197 rr
.dr
.d_ttl
=sd
.default_ttl
;
198 rr
.dr
.d_name
=p
->qdomain
;
202 DNSSECPrivateKey dpk
;
204 DNSSECKeeper::keyset_t keyset
= d_dk
.getEntryPoints(p
->qdomain
);
206 for(auto const &value
: keyset
) {
207 for(auto const &digestAlgo
: digestAlgos
){
208 rr
.dr
.d_content
=std::make_shared
<DSRecordContent
>(makeDSFromDNSKey(p
->qdomain
, value
.first
.getDNSKEY(), std::stoi(digestAlgo
)));
214 if(::arg().mustDo("direct-dnskey")) {
215 B
.lookup(QType(QType::CDS
), p
->qdomain
, p
, sd
.domain_id
);
218 rr
.dr
.d_ttl
=sd
.default_ttl
;
227 /** This adds NSEC3PARAM records. Returns true if one was added */
228 bool PacketHandler::addNSEC3PARAM(DNSPacket
*p
, DNSPacket
*r
, const SOAData
& sd
)
232 NSEC3PARAMRecordContent ns3prc
;
233 if(d_dk
.getNSEC3PARAM(p
->qdomain
, &ns3prc
)) {
234 rr
.dr
.d_type
=QType::NSEC3PARAM
;
235 rr
.dr
.d_ttl
=sd
.default_ttl
;
236 rr
.dr
.d_name
=p
->qdomain
;
237 ns3prc
.d_flags
= 0; // the NSEC3PARAM 'flag' is defined to always be zero in RFC5155.
238 rr
.dr
.d_content
=std::make_shared
<NSEC3PARAMRecordContent
>(ns3prc
);
247 // This is our chaos class requests handler. Return 1 if content was added, 0 if it wasn't
248 int PacketHandler::doChaosRequest(DNSPacket
*p
, DNSPacket
*r
, DNSName
&target
)
252 if(p
->qtype
.getCode()==QType::TXT
) {
253 static const DNSName
versionbind("version.bind."), versionpdns("version.pdns."), idserver("id.server.");
254 if (target
==versionbind
|| target
==versionpdns
) {
255 // modes: full, powerdns only, anonymous or custom
256 const static string mode
=::arg()["version-string"];
258 if(mode
.empty() || mode
=="full")
259 content
=fullVersionString();
260 else if(mode
=="powerdns")
261 content
="Served by PowerDNS - https://www.powerdns.com/";
262 else if(mode
=="anonymous") {
263 r
->setRcode(RCode::ServFail
);
268 rr
.dr
.d_content
= shared_ptr
<DNSRecordContent
>(DNSRecordContent::mastermake(QType::TXT
, 1, "\""+content
+"\""));
270 else if (target
==idserver
) {
271 // modes: disabled, hostname or custom
272 const static string id
=::arg()["server-id"];
274 if (id
== "disabled") {
275 r
->setRcode(RCode::Refused
);
278 rr
.dr
.d_content
=shared_ptr
<DNSRecordContent
>(DNSRecordContent::mastermake(QType::TXT
, 1, id
));
281 r
->setRcode(RCode::Refused
);
287 rr
.dr
.d_type
=QType::TXT
;
288 rr
.dr
.d_class
=QClass::CHAOS
;
293 r
->setRcode(RCode::NotImp
);
297 vector
<DNSZoneRecord
> PacketHandler::getBestReferralNS(DNSPacket
*p
, SOAData
& sd
, const DNSName
&target
)
299 vector
<DNSZoneRecord
> ret
;
301 DNSName
subdomain(target
);
303 if(subdomain
== sd
.qname
) // stop at SOA
305 B
.lookup(QType(QType::NS
), subdomain
, p
, sd
.domain_id
);
307 ret
.push_back(rr
); // this used to exclude auth NS records for some reason
311 } while( subdomain
.chopOff() ); // 'www.powerdns.org' -> 'powerdns.org' -> 'org' -> ''
315 vector
<DNSZoneRecord
> PacketHandler::getBestDNAMESynth(DNSPacket
*p
, SOAData
& sd
, DNSName
&target
)
317 vector
<DNSZoneRecord
> ret
;
320 DNSName
subdomain(target
);
322 DLOG(L
<<"Attempting DNAME lookup for "<<subdomain
<<", sd.qname="<<sd
.qname
<<endl
);
324 B
.lookup(QType(QType::DNAME
), subdomain
, p
, sd
.domain_id
);
326 ret
.push_back(rr
); // put in the original
327 rr
.dr
.d_type
= QType::CNAME
;
328 rr
.dr
.d_name
= prefix
+ rr
.dr
.d_name
;
329 rr
.dr
.d_content
= std::make_shared
<CNAMERecordContent
>(CNAMERecordContent(prefix
+ getRR
<DNAMERecordContent
>(rr
.dr
)->d_content
));
330 rr
.auth
= 0; // don't sign CNAME
331 target
= getRR
<CNAMERecordContent
>(rr
.dr
)->getTarget();
336 if(subdomain
.countLabels())
337 prefix
+= DNSName(subdomain
.getRawLabels()[0]); // XXX DNSName pain this feels wrong
338 if(subdomain
== sd
.qname
) // stop at SOA
341 } while( subdomain
.chopOff() ); // 'www.powerdns.org' -> 'powerdns.org' -> 'org' -> ''
346 // Return best matching wildcard or next closer name
347 bool PacketHandler::getBestWildcard(DNSPacket
*p
, SOAData
& sd
, const DNSName
&target
, DNSName
&wildcard
, vector
<DNSZoneRecord
>* ret
)
351 DNSName
subdomain(target
);
352 bool haveSomething
=false;
355 while( subdomain
.chopOff() && !haveSomething
) {
356 if (subdomain
.empty()) {
357 B
.lookup(QType(QType::ANY
), g_wildcarddnsname
, p
, sd
.domain_id
);
359 B
.lookup(QType(QType::ANY
), g_wildcarddnsname
+subdomain
, p
, sd
.domain_id
);
362 if(rr
.dr
.d_type
== p
->qtype
.getCode() || rr
.dr
.d_type
== QType::CNAME
|| (p
->qtype
.getCode() == QType::ANY
&& rr
.dr
.d_type
!= QType::RRSIG
))
364 wildcard
=g_wildcarddnsname
+subdomain
;
368 if ( subdomain
== sd
.qname
|| haveSomething
) // stop at SOA or result
371 B
.lookup(QType(QType::ANY
), subdomain
, p
, sd
.domain_id
);
373 DLOG(L
<<"No wildcard match, ancestor exists"<<endl
);
380 return haveSomething
;
383 /** dangling is declared true if we were unable to resolve everything */
384 int PacketHandler::doAdditionalProcessingAndDropAA(DNSPacket
*p
, DNSPacket
*r
, const SOAData
& soadata
, bool retargeted
)
390 if(p
->qtype
.getCode()!=QType::AXFR
) { // this packet needs additional processing
391 // we now have a copy, push_back on packet might reallocate!
392 auto& records
= r
->getRRS();
393 vector
<DNSZoneRecord
> toAdd
;
395 for(auto i
= records
.cbegin() ; i
!= records
.cend(); ++i
) {
396 if(i
->dr
.d_place
==DNSResourceRecord::ADDITIONAL
||
397 !(i
->dr
.d_type
==QType::MX
|| i
->dr
.d_type
==QType::NS
|| i
->dr
.d_type
==QType::SRV
))
400 if(r
->d
.aa
&& i
->dr
.d_name
.countLabels() && i
->dr
.d_type
==QType::NS
&& !B
.getSOA(i
->dr
.d_name
,sd
,p
) && !retargeted
) { // drop AA in case of non-SOA-level NS answer, except for root referral
402 // i->d_place=DNSResourceRecord::AUTHORITY; // XXX FIXME
407 if(i
->dr
.d_type
== QType::MX
)
408 lookup
= getRR
<MXRecordContent
>(i
->dr
)->d_mxname
;
409 else if(i
->dr
.d_type
== QType::SRV
)
410 lookup
= getRR
<SRVRecordContent
>(i
->dr
)->d_target
;
411 else if(i
->dr
.d_type
== QType::NS
)
412 lookup
= getRR
<NSRecordContent
>(i
->dr
)->getNS();
415 B
.lookup(QType(d_doIPv6AdditionalProcessing
? QType::ANY
: QType::A
), lookup
, p
);
418 if(rr
.dr
.d_type
!= QType::A
&& rr
.dr
.d_type
!=QType::AAAA
)
420 if(rr
.domain_id
!=i
->domain_id
&& ::arg()["out-of-zone-additional-processing"]=="no") {
421 DLOG(L
<<Logger::Warning
<<"Not including out-of-zone additional processing of "<<i
->dr
.d_name
<<" ("<<rr
.dr
.d_name
<<")"<<endl
);
422 continue; // not adding out-of-zone additional data
425 if(rr
.auth
&& !rr
.dr
.d_name
.isPartOf(soadata
.qname
)) // don't sign out of zone data using the main key
427 rr
.dr
.d_place
=DNSResourceRecord::ADDITIONAL
;
431 for(const auto& rec
: toAdd
)
434 //records.insert(records.end(), toAdd.cbegin(), toAdd.cend()); // would be faster, but no dedup
440 void PacketHandler::emitNSEC(DNSPacket
*r
, const SOAData
& sd
, const DNSName
& name
, const DNSName
& next
, int mode
)
442 NSECRecordContent nrc
;
445 nrc
.d_set
.insert(QType::NSEC
);
446 nrc
.d_set
.insert(QType::RRSIG
);
447 if(sd
.qname
== name
) {
448 nrc
.d_set
.insert(QType::SOA
); // 1dfd8ad SOA can live outside the records table
449 nrc
.d_set
.insert(QType::DNSKEY
);
450 string publishCDNSKEY
;
451 d_dk
.getFromMeta(name
, "PUBLISH-CDNSKEY", publishCDNSKEY
);
452 if (publishCDNSKEY
== "1")
453 nrc
.d_set
.insert(QType::CDNSKEY
);
455 d_dk
.getFromMeta(name
, "PUBLISH-CDS", publishCDS
);
456 if (! publishCDS
.empty())
457 nrc
.d_set
.insert(QType::CDS
);
462 B
.lookup(QType(QType::ANY
), name
, NULL
, sd
.domain_id
);
464 if(rr
.dr
.d_type
== QType::NS
|| rr
.auth
)
465 nrc
.d_set
.insert(rr
.dr
.d_type
);
469 rr
.dr
.d_ttl
= sd
.default_ttl
;
470 rr
.dr
.d_type
= QType::NSEC
;
471 rr
.dr
.d_content
= std::make_shared
<NSECRecordContent
>(nrc
);
472 rr
.dr
.d_place
= (mode
== 5 ) ? DNSResourceRecord::ANSWER
: DNSResourceRecord::AUTHORITY
;
478 void PacketHandler::emitNSEC3(DNSPacket
*r
, const SOAData
& sd
, const NSEC3PARAMRecordContent
& ns3prc
, const DNSName
& name
, const string
& namehash
, const string
& nexthash
, int mode
)
480 NSEC3RecordContent n3rc
;
481 n3rc
.d_algorithm
= ns3prc
.d_algorithm
;
482 n3rc
.d_flags
= ns3prc
.d_flags
;
483 n3rc
.d_iterations
= ns3prc
.d_iterations
;
484 n3rc
.d_salt
= ns3prc
.d_salt
;
485 n3rc
.d_nexthash
= nexthash
;
490 if (sd
.qname
== name
) {
491 n3rc
.d_set
.insert(QType::SOA
); // 1dfd8ad SOA can live outside the records table
492 n3rc
.d_set
.insert(QType::NSEC3PARAM
);
493 n3rc
.d_set
.insert(QType::DNSKEY
);
494 string publishCDNSKEY
;
495 d_dk
.getFromMeta(name
, "PUBLISH-CDNSKEY", publishCDNSKEY
);
496 if (publishCDNSKEY
== "1")
497 n3rc
.d_set
.insert(QType::CDNSKEY
);
499 d_dk
.getFromMeta(name
, "PUBLISH-CDS", publishCDS
);
500 if (! publishCDS
.empty())
501 n3rc
.d_set
.insert(QType::CDS
);
504 B
.lookup(QType(QType::ANY
), name
, NULL
, sd
.domain_id
);
506 if(rr
.dr
.d_type
&& (rr
.dr
.d_type
== QType::NS
|| rr
.auth
)) // skip empty non-terminals
507 n3rc
.d_set
.insert(rr
.dr
.d_type
);
511 if (n3rc
.d_set
.size() && !(n3rc
.d_set
.size() == 1 && n3rc
.d_set
.count(QType::NS
)))
512 n3rc
.d_set
.insert(QType::RRSIG
);
514 rr
.dr
.d_name
= DNSName(toBase32Hex(namehash
))+sd
.qname
;
515 rr
.dr
.d_ttl
= sd
.default_ttl
;
516 rr
.dr
.d_type
=QType::NSEC3
;
517 rr
.dr
.d_content
=std::make_shared
<NSEC3RecordContent
>(n3rc
);
518 rr
.dr
.d_place
= (mode
== 5 ) ? DNSResourceRecord::ANSWER
: DNSResourceRecord::AUTHORITY
;
525 mode 0 = No Data Responses, QTYPE is not DS
526 mode 1 = No Data Responses, QTYPE is DS
527 mode 2 = Wildcard No Data Responses
528 mode 3 = Wildcard Answer Responses
529 mode 4 = Name Error Responses
530 mode 5 = Direct NSEC request
532 void PacketHandler::addNSECX(DNSPacket
*p
, DNSPacket
*r
, const DNSName
& target
, const DNSName
& wildcard
, const DNSName
& auth
, int mode
)
534 if(!p
->d_dnssecOk
&& mode
!= 5)
537 NSEC3PARAMRecordContent ns3rc
;
539 if(d_dk
.getNSEC3PARAM(auth
, &ns3rc
, &narrow
)) {
540 if (mode
!= 5) // no direct NSEC3 queries, rfc5155 7.2.8
541 addNSEC3(p
, r
, target
, wildcard
, auth
, ns3rc
, narrow
, mode
);
544 addNSEC(p
, r
, target
, wildcard
, auth
, mode
);
548 static void incrementHash(std::string
& raw
) // I wonder if this is correct, cmouse? ;-)
553 for(string::size_type pos
=raw
.size(); pos
; ) {
555 unsigned char c
= (unsigned char)raw
[pos
];
563 static void decrementHash(std::string
& raw
) // I wonder if this is correct, cmouse? ;-)
568 for(string::size_type pos
=raw
.size(); pos
; ) {
570 unsigned char c
= (unsigned char)raw
[pos
];
579 bool getNSEC3Hashes(bool narrow
, DNSBackend
* db
, int id
, const std::string
& hashed
, bool decrement
, DNSName
& unhashed
, std::string
& before
, std::string
& after
, int mode
)
582 if(narrow
) { // nsec3-narrow
586 decrementHash(before
);
590 incrementHash(after
);
593 DNSName hashedName
= DNSName(toBase32Hex(hashed
));
594 DNSName beforeName
, afterName
;
595 if (!decrement
&& mode
>= 2)
596 beforeName
= hashedName
;
597 ret
=db
->getBeforeAndAfterNamesAbsolute(id
, hashedName
, unhashed
, beforeName
, afterName
);
598 before
=fromBase32Hex(beforeName
.toString());
599 after
=fromBase32Hex(afterName
.toString());
604 void PacketHandler::addNSEC3(DNSPacket
*p
, DNSPacket
*r
, const DNSName
& target
, const DNSName
& wildcard
, const DNSName
& auth
, const NSEC3PARAMRecordContent
& ns3rc
, bool narrow
, int mode
)
606 DLOG(L
<<"addNSEC3() mode="<<mode
<<" auth="<<auth
<<" target="<<target
<<" wildcard="<<wildcard
<<endl
);
609 if(!B
.getSOAUncached(auth
, sd
)) {
610 DLOG(L
<<"Could not get SOA for domain");
614 bool doNextcloser
= false;
615 string before
, after
, hashed
;
616 DNSName unhashed
, closest
;
619 if (mode
== 2 || mode
== 3 || mode
== 4) {
625 // add matching NSEC3 RR
627 unhashed
=(mode
== 0 || mode
== 1 || mode
== 5) ? target
: closest
;
628 hashed
=hashQNameWithSalt(ns3rc
, unhashed
);
629 DLOG(L
<<"1 hash: "<<toBase32Hex(hashed
)<<" "<<unhashed
<<endl
);
631 getNSEC3Hashes(narrow
, sd
.db
, sd
.domain_id
, hashed
, false, unhashed
, before
, after
, mode
);
633 if (((mode
== 0 && ns3rc
.d_flags
) || mode
== 1) && (hashed
!= before
)) {
634 DLOG(L
<<"No matching NSEC3, do closest (provable) encloser"<<endl
);
636 bool doBreak
= false;
638 while( closest
.chopOff() && (closest
!= sd
.qname
)) { // stop at SOA
639 B
.lookup(QType(QType::ANY
), closest
, p
, sd
.domain_id
);
648 hashed
=hashQNameWithSalt(ns3rc
, unhashed
);
649 DLOG(L
<<"1 hash: "<<toBase32Hex(hashed
)<<" "<<unhashed
<<endl
);
651 getNSEC3Hashes(narrow
, sd
.db
, sd
.domain_id
, hashed
, false, unhashed
, before
, after
);
654 if (!after
.empty()) {
655 DLOG(L
<<"Done calling for matching, hashed: '"<<toBase32Hex(hashed
)<<"' before='"<<toBase32Hex(before
)<<"', after='"<<toBase32Hex(after
)<<"'"<<endl
);
656 emitNSEC3(r
, sd
, ns3rc
, unhashed
, before
, after
, mode
);
657 } else if(!before
.empty())
661 // add covering NSEC3 RR
662 if ((mode
>= 2 && mode
<= 4) || doNextcloser
) {
663 DNSName
next(target
);
667 while( next
.chopOff() && !(next
==closest
));
669 hashed
=hashQNameWithSalt(ns3rc
, unhashed
);
670 DLOG(L
<<"2 hash: "<<toBase32Hex(hashed
)<<" "<<unhashed
<<endl
);
672 getNSEC3Hashes(narrow
, sd
.db
,sd
.domain_id
, hashed
, true, unhashed
, before
, after
);
673 DLOG(L
<<"Done calling for covering, hashed: '"<<toBase32Hex(hashed
)<<"' before='"<<toBase32Hex(before
)<<"', after='"<<toBase32Hex(after
)<<"'"<<endl
);
674 emitNSEC3( r
, sd
, ns3rc
, unhashed
, before
, after
, mode
);
678 if (mode
== 2 || mode
== 4) {
679 unhashed
=g_wildcarddnsname
+closest
;
681 hashed
=hashQNameWithSalt(ns3rc
, unhashed
);
682 DLOG(L
<<"3 hash: "<<toBase32Hex(hashed
)<<" "<<unhashed
<<endl
);
684 getNSEC3Hashes(narrow
, sd
.db
, sd
.domain_id
, hashed
, (mode
!= 2), unhashed
, before
, after
);
685 DLOG(L
<<"Done calling for '*', hashed: '"<<toBase32Hex(hashed
)<<"' before='"<<toBase32Hex(before
)<<"', after='"<<toBase32Hex(after
)<<"'"<<endl
);
686 emitNSEC3( r
, sd
, ns3rc
, unhashed
, before
, after
, mode
);
690 void PacketHandler::addNSEC(DNSPacket
*p
, DNSPacket
*r
, const DNSName
& target
, const DNSName
& wildcard
, const DNSName
& auth
, int mode
)
692 DLOG(L
<<"addNSEC() mode="<<mode
<<" auth="<<auth
<<" target="<<target
<<" wildcard="<<wildcard
<<endl
);
695 if(!B
.getSOAUncached(auth
, sd
)) {
696 DLOG(L
<<"Could not get SOA for domain"<<endl
);
700 DNSName before
,after
;
701 sd
.db
->getBeforeAndAfterNames(sd
.domain_id
, auth
, target
, before
, after
);
702 if (mode
!= 5 || before
== target
)
703 emitNSEC(r
, sd
, before
, after
, mode
);
705 if (mode
== 2 || mode
== 4) {
706 // wildcard NO-DATA or wildcard denial
708 DNSName
closest(wildcard
);
711 closest
.prependRawLabel("*");
713 sd
.db
->getBeforeAndAfterNames(sd
.domain_id
, auth
, closest
, before
, after
);
714 emitNSEC(r
, sd
, before
, after
, mode
);
721 - only one backend owns the SOA of a zone
722 - only one AXFR per zone at a time - double startTransaction should fail
723 - backends need to implement transaction semantics
726 How BindBackend would implement this:
727 startTransaction makes a file
728 feedRecord sends everything to that file
729 commitTransaction moves that file atomically over the regular file, and triggers a reload
730 rollbackTransaction removes the file
733 How PostgreSQLBackend would implement this:
734 startTransaction starts a sql transaction, which also deletes all records
735 feedRecord is an insert statement
736 commitTransaction commits the transaction
737 rollbackTransaction aborts it
739 How MySQLBackend would implement this:
744 int PacketHandler::trySuperMaster(DNSPacket
*p
, const DNSName
& tsigkeyname
)
748 // do it right now if the client is TCP
750 return trySuperMasterSynchronous(p
, tsigkeyname
);
754 // queue it if the client is on UDP
755 Communicator
.addTrySuperMasterRequest(p
);
760 int PacketHandler::trySuperMasterSynchronous(DNSPacket
*p
, const DNSName
& tsigkeyname
)
762 string remote
= p
->getRemote().toString();
763 if(p
->hasEDNSSubnet() && ::arg().contains("trusted-notification-proxy", remote
)) {
764 remote
= p
->getRealRemote().toStringNoMask();
767 Resolver::res_t nsset
;
770 uint32_t theirserial
;
771 resolver
.getSoaSerial(remote
,p
->qdomain
, &theirserial
);
772 resolver
.resolve(remote
, p
->qdomain
, QType::NS
, &nsset
);
774 catch(ResolverException
&re
) {
775 L
<<Logger::Error
<<"Error resolving SOA or NS for "<<p
->qdomain
<<" at: "<< remote
<<": "<<re
.reason
<<endl
;
776 return RCode::ServFail
;
779 // check if the returned records are NS records
781 for(const auto& ns
: nsset
) {
782 if(ns
.qtype
==QType::NS
)
787 L
<<Logger::Error
<<"While checking for supermaster, did not find NS for "<<p
->qdomain
<<" at: "<< remote
<<endl
;
788 return RCode::ServFail
;
791 string nameserver
, account
;
794 if (!::arg().mustDo("allow-unsigned-supermaster") && tsigkeyname
.empty()) {
795 L
<<Logger::Error
<<"Received unsigned NOTIFY for "<<p
->qdomain
<<" from potential supermaster "<<remote
<<". Refusing."<<endl
;
796 return RCode::Refused
;
799 if(!B
.superMasterBackend(remote
, p
->qdomain
, nsset
, &nameserver
, &account
, &db
)) {
800 L
<<Logger::Error
<<"Unable to find backend willing to host "<<p
->qdomain
<<" for potential supermaster "<<remote
<<". Remote nameservers: "<<endl
;
801 for(const auto& rr
: nsset
) {
802 if(rr
.qtype
==QType::NS
)
803 L
<<Logger::Error
<<rr
.content
<<endl
;
805 return RCode::Refused
;
808 db
->createSlaveDomain(p
->getRemote().toString(), p
->qdomain
, nameserver
, account
);
809 if (tsigkeyname
.empty() == false) {
811 meta
.push_back(tsigkeyname
.toStringNoDot());
812 db
->setDomainMetadata(p
->qdomain
, "AXFR-MASTER-TSIG", meta
);
815 catch(PDNSException
& ae
) {
816 L
<<Logger::Error
<<"Database error trying to create "<<p
->qdomain
<<" for potential supermaster "<<remote
<<": "<<ae
.reason
<<endl
;
817 return RCode::ServFail
;
819 L
<<Logger::Warning
<<"Created new slave zone '"<<p
->qdomain
<<"' from supermaster "<<remote
<<endl
;
820 return RCode::NoError
;
823 int PacketHandler::processNotify(DNSPacket
*p
)
826 was this notification from an approved address?
827 was this notification approved by TSIG?
828 We determine our internal SOA id (via UeberBackend)
829 We determine the SOA at our (known) master
830 if master is higher -> do stuff
834 if(!::arg().mustDo("slave")) {
835 L
<<Logger::Error
<<"Received NOTIFY for "<<p
->qdomain
<<" from "<<p
->getRemote()<<" but slave support is disabled in the configuration"<<endl
;
836 return RCode::NotImp
;
839 if(!s_allowNotifyFrom
.match((ComboAddress
*) &p
->d_remote
) || p
->d_havetsig
) {
840 if (p
->d_havetsig
&& p
->getTSIGKeyname().empty() == false) {
841 L
<<Logger::Notice
<<"Received secure NOTIFY for "<<p
->qdomain
<<" from "<<p
->getRemote()<<", allowed by TSIG key '"<<p
->getTSIGKeyname()<<"'"<<endl
;
843 L
<<Logger::Error
<<"Received NOTIFY for "<<p
->qdomain
<<" from "<<p
->getRemote()<<" but remote is not permitted by TSIG or allow-notify-from"<<endl
;
844 return RCode::Refused
;
851 if(!B
.getDomainInfo(p
->qdomain
, di
) || !(db
=di
.backend
)) {
852 L
<<Logger::Error
<<"Received NOTIFY for "<<p
->qdomain
<<" from "<<p
->getRemote()<<" for which we are not authoritative"<<endl
;
853 return trySuperMaster(p
, p
->getTSIGKeyname());
857 if (B
.getDomainMetadata(p
->qdomain
,"AXFR-MASTER-TSIG",meta
) && meta
.size() > 0) {
858 if (!p
->d_havetsig
) {
859 if (::arg().mustDo("allow-unsigned-notify")) {
860 L
<<Logger::Warning
<<"Received unsigned NOTIFY for "<<p
->qdomain
<<" from "<<p
->getRemote()<<": permitted because allow-unsigned-notify";
862 L
<<Logger::Warning
<<"Received unsigned NOTIFY for "<<p
->qdomain
<<" from "<<p
->getRemote()<<": refused"<<endl
;
863 return RCode::Refused
;
865 } else if (meta
[0] != p
->getTSIGKeyname().toStringNoDot()) {
866 L
<<Logger::Error
<<"Received secure NOTIFY for "<<p
->qdomain
<<" from "<<p
->getRemote()<<": expected TSIG key '"<<meta
[0]<<", got '"<<p
->getTSIGKeyname()<<"'"<<endl
;
867 return RCode::Refused
;
871 if(::arg().contains("trusted-notification-proxy", p
->getRemote().toString())) {
872 L
<<Logger::Error
<<"Received NOTIFY for "<<p
->qdomain
<<" from trusted-notification-proxy "<< p
->getRemote()<<endl
;
873 if(di
.masters
.empty()) {
874 L
<<Logger::Error
<<"However, "<<p
->qdomain
<<" does not have any masters defined"<<endl
;
875 return RCode::Refused
;
878 else if(::arg().mustDo("master") && di
.kind
== DomainInfo::Master
) {
879 L
<<Logger::Error
<<"Received NOTIFY for "<<p
->qdomain
<<" from "<<p
->getRemote()<<" but we are master, rejecting"<<endl
;
880 return RCode::Refused
;
882 else if(!db
->isMaster(p
->qdomain
, p
->getRemote().toString())) {
883 L
<<Logger::Error
<<"Received NOTIFY for "<<p
->qdomain
<<" from "<<p
->getRemote()<<" which is not a master"<<endl
;
884 return RCode::Refused
;
887 // ok, we've done our checks
889 Communicator
.addSlaveCheckRequest(di
, p
->d_remote
);
893 bool validDNSName(const DNSName
&name
)
896 string::size_type pos
, length
;
898 for(const auto& s
: name
.getRawLabels()) {
900 for(pos
=0; pos
< length
; ++pos
) {
902 if(!((c
>= 'a' && c
<= 'z') ||
903 (c
>= 'A' && c
<= 'Z') ||
904 (c
>= '0' && c
<= '9') ||
905 c
=='-' || c
== '_' || c
=='*' || c
=='.' || c
=='/' || c
=='@' || c
==' ' || c
=='\\' || c
==':'))
913 DNSPacket
*PacketHandler::question(DNSPacket
*p
)
916 int policyres
= PolicyDecision::PASS
;
920 ret
=d_pdl
->prequery(p
);
926 static AtomicCounter
&rdqueries
=*S
.getPointer("rd-queries");
932 policyres
= LPE
->police(p
, NULL
);
935 if (policyres
== PolicyDecision::DROP
)
938 if (policyres
== PolicyDecision::TRUNCATE
) {
939 ret
=p
->replyPacket(); // generate an empty reply packet
945 bool shouldRecurse
=false;
946 ret
=questionOrRecurse(p
, &shouldRecurse
);
951 policyres
= LPE
->police(p
, ret
);
952 if(policyres
== PolicyDecision::DROP
) {
956 if (policyres
== PolicyDecision::TRUNCATE
) {
958 ret
=p
->replyPacket(); // generate an empty reply packet
968 void PacketHandler::makeNXDomain(DNSPacket
* p
, DNSPacket
* r
, const DNSName
& target
, const DNSName
& wildcard
, SOAData
& sd
)
971 rr
.dr
.d_name
=sd
.qname
;
972 rr
.dr
.d_type
=QType::SOA
;
974 rr
.dr
.d_content
=makeSOAContent(sd
);
975 rr
.dr
.d_ttl
=min(sd
.ttl
, sd
.default_ttl
);
977 rr
.domain_id
=sd
.domain_id
;
978 rr
.dr
.d_place
=DNSResourceRecord::AUTHORITY
;
980 rr
.scopeMask
= sd
.scopeMask
;
983 if(d_dk
.isSecuredZone(sd
.qname
))
984 addNSECX(p
, r
, target
, wildcard
, sd
.qname
, 4);
986 r
->setRcode(RCode::NXDomain
);
989 void PacketHandler::makeNOError(DNSPacket
* p
, DNSPacket
* r
, const DNSName
& target
, const DNSName
& wildcard
, SOAData
& sd
, int mode
)
992 rr
.dr
.d_name
=sd
.qname
;
993 rr
.dr
.d_type
=QType::SOA
;
994 rr
.dr
.d_content
=makeSOAContent(sd
);
996 rr
.dr
.d_ttl
=min(sd
.ttl
, sd
.default_ttl
);
998 rr
.domain_id
=sd
.domain_id
;
999 rr
.dr
.d_place
=DNSResourceRecord::AUTHORITY
;
1003 if(d_dk
.isSecuredZone(sd
.qname
))
1004 addNSECX(p
, r
, target
, wildcard
, sd
.qname
, mode
);
1006 S
.ringAccount("noerror-queries",p
->qdomain
.toLogString()+"/"+p
->qtype
.getName());
1010 bool PacketHandler::addDSforNS(DNSPacket
* p
, DNSPacket
* r
, SOAData
& sd
, const DNSName
& dsname
)
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
);
1018 rr
.dr
.d_place
= DNSResourceRecord::AUTHORITY
;
1024 bool PacketHandler::tryReferral(DNSPacket
*p
, DNSPacket
*r
, SOAData
& sd
, const DNSName
&target
, bool retargeted
)
1026 vector
<DNSZoneRecord
> rrset
= getBestReferralNS(p
, sd
, target
);
1030 DLOG(L
<<"The best NS is: "<<rrset
.begin()->qname
<<endl
);
1031 for(auto& rr
: rrset
) {
1032 DLOG(L
<<"\tadding '"<<rr
.content
<<"'"<<endl
);
1033 rr
.dr
.d_place
=DNSResourceRecord::AUTHORITY
;
1039 if(d_dk
.isSecuredZone(sd
.qname
) && !addDSforNS(p
, r
, sd
, rrset
.begin()->dr
.d_name
))
1040 addNSECX(p
, r
, rrset
.begin()->dr
.d_name
, DNSName(), sd
.qname
, 1);
1045 void PacketHandler::completeANYRecords(DNSPacket
*p
, DNSPacket
*r
, SOAData
& sd
, const DNSName
&target
)
1048 return; // Don't send dnssec info to non validating resolvers.
1050 if(!d_dk
.isSecuredZone(sd
.qname
))
1053 addNSECX(p
, r
, target
, DNSName(), sd
.qname
, 5);
1054 if(sd
.qname
== p
->qdomain
) {
1055 addDNSKEY(p
, r
, sd
);
1056 addCDNSKEY(p
, r
, sd
);
1058 addNSEC3PARAM(p
, r
, sd
);
1062 bool PacketHandler::tryDNAME(DNSPacket
*p
, DNSPacket
*r
, SOAData
& sd
, DNSName
&target
)
1066 DLOG(L
<<Logger::Warning
<<"Let's try DNAME.."<<endl
);
1067 vector
<DNSZoneRecord
> rrset
= getBestDNAMESynth(p
, sd
, target
);
1068 if(!rrset
.empty()) {
1069 for(auto& rr
: rrset
) {
1070 rr
.dr
.d_place
= DNSResourceRecord::ANSWER
;
1077 bool PacketHandler::tryWildcard(DNSPacket
*p
, DNSPacket
*r
, SOAData
& sd
, DNSName
&target
, DNSName
&wildcard
, bool& retargeted
, bool& nodata
)
1079 retargeted
= nodata
= false;
1082 vector
<DNSZoneRecord
> rrset
;
1083 if(!getBestWildcard(p
, sd
, target
, wildcard
, &rrset
))
1087 DLOG(L
<<"Wildcard matched something, but not of the correct type"<<endl
);
1091 DLOG(L
<<"The best wildcard match: "<<rrset
.begin()->qname
<<endl
);
1092 for(auto& rr
: rrset
) {
1093 rr
.wildcardname
= rr
.dr
.d_name
;
1094 rr
.dr
.d_name
=bestmatch
=target
;
1096 if(rr
.dr
.d_type
== QType::CNAME
) {
1098 target
=getRR
<CNAMERecordContent
>(rr
.dr
)->getTarget();
1101 DLOG(L
<<"\tadding '"<<rr
.content
<<"'"<<endl
);
1102 rr
.dr
.d_place
=DNSResourceRecord::ANSWER
;
1106 if(d_dk
.isSecuredZone(sd
.qname
) && !nodata
) {
1107 addNSECX(p
, r
, bestmatch
, wildcard
, sd
.qname
, 3);
1112 //! Called by the Distributor to ask a question. Returns 0 in case of an error
1113 DNSPacket
*PacketHandler::questionOrRecurse(DNSPacket
*p
, bool *shouldRecurse
)
1115 *shouldRecurse
=false;
1119 // string subdomain="";
1121 int retargetcount
=0;
1122 set
<DNSName
> authSet
;
1124 vector
<DNSZoneRecord
> rrset
;
1125 bool weDone
=0, weRedirected
=0, weHaveUnauth
=0;
1131 if(p
->d
.qr
) { // QR bit from dns packet (thanks RA from N)
1133 L
<<Logger::Error
<<"Received an answer (non-query) packet from "<<p
->getRemote()<<", dropping"<<endl
;
1134 S
.inc("corrupt-packets");
1135 S
.ringAccount("remotes-corrupt", p
->d_remote
);
1139 if(p
->d
.tc
) { // truncated query. MOADNSParser would silently parse this packet in an incomplete way.
1141 L
<<Logger::Error
<<"Received truncated query packet from "<<p
->getRemote()<<", dropping"<<endl
;
1142 S
.inc("corrupt-packets");
1143 S
.ringAccount("remotes-corrupt", p
->d_remote
);
1147 if (p
->hasEDNS() && p
->getEDNSVersion() > 0) {
1148 r
= p
->replyPacket();
1149 r
->setRcode(16 & 0xF);
1150 r
->setEDNSRcode((16 & 0xFFF0)>>4); // set rcode to BADVERS
1157 TSIGRecordContent trc
;
1158 if(!checkForCorrectTSIG(p
, &B
, &keyname
, &secret
, &trc
)) {
1159 r
=p
->replyPacket(); // generate an empty reply packet
1161 L
<<Logger::Error
<<"Received a TSIG signed message with a non-validating key"<<endl
;
1162 // RFC3007 describes that a non-secure message should be sending Refused for DNS Updates
1163 if (p
->d
.opcode
== Opcode::Update
)
1164 r
->setRcode(RCode::Refused
);
1166 r
->setRcode(RCode::NotAuth
);
1169 getTSIGHashEnum(trc
.d_algoName
, p
->d_tsig_algo
);
1170 if (p
->d_tsig_algo
== TSIG_GSS
) {
1171 GssContext
gssctx(keyname
);
1172 if (!gssctx
.getPeerPrincipal(p
->d_peer_principal
)) {
1173 L
<<Logger::Warning
<<"Failed to extract peer principal from GSS context with keyname '"<<keyname
<<"'"<<endl
;
1177 p
->setTSIGDetails(trc
, keyname
, secret
, trc
.d_mac
); // this will get copied by replyPacket()
1181 r
=p
->replyPacket(); // generate an empty reply packet, possibly with TSIG details inside
1183 if (p
->qtype
== QType::TKEY
) {
1184 this->tkeyHandler(p
, r
);
1190 // XXX FIXME do this in DNSPacket::parse ?
1192 if(!validDNSName(p
->qdomain
)) {
1194 L
<<Logger::Error
<<"Received a malformed qdomain from "<<p
->getRemote()<<", '"<<p
->qdomain
<<"': sending servfail"<<endl
;
1195 S
.inc("corrupt-packets");
1196 S
.ringAccount("remotes-corrupt", p
->d_remote
);
1197 S
.inc("servfail-packets");
1198 r
->setRcode(RCode::ServFail
);
1201 if(p
->d
.opcode
) { // non-zero opcode (again thanks RA!)
1202 if(p
->d
.opcode
==Opcode::Update
) {
1203 S
.inc("dnsupdate-queries");
1204 int res
=processUpdate(p
);
1205 if (res
== RCode::Refused
)
1206 S
.inc("dnsupdate-refused");
1207 else if (res
!= RCode::ServFail
)
1208 S
.inc("dnsupdate-answers");
1210 r
->setOpcode(Opcode::Update
);
1213 else if(p
->d
.opcode
==Opcode::Notify
) {
1214 S
.inc("incoming-notifications");
1215 int res
=processNotify(p
);
1218 r
->setOpcode(Opcode::Notify
);
1225 L
<<Logger::Error
<<"Received an unknown opcode "<<p
->d
.opcode
<<" from "<<p
->getRemote()<<" for "<<p
->qdomain
<<endl
;
1227 r
->setRcode(RCode::NotImp
);
1231 // L<<Logger::Warning<<"Query for '"<<p->qdomain<<"' "<<p->qtype.getName()<<" from "<<p->getRemote()<< " (tcp="<<p->d_tcp<<")"<<endl;
1233 r
->d
.ra
= (p
->d
.rd
&& d_doRecursion
&& DP
->recurseFor(p
)); // make sure we set ra if rd was set, and we'll do it
1235 if(p
->qtype
.getCode()==QType::IXFR
) {
1236 r
->setRcode(RCode::NotImp
);
1240 DNSName target
=p
->qdomain
;
1242 // catch chaos qclass requests
1243 if(p
->qclass
== QClass::CHAOS
) {
1244 if (doChaosRequest(p
,r
,target
))
1250 // we only know about qclass IN (and ANY), send NotImp for everything else.
1251 if(p
->qclass
!= QClass::IN
&& p
->qclass
!=QClass::ANY
) {
1252 r
->setRcode(RCode::NotImp
);
1256 // send TC for udp ANY query if any-to-tcp is enabled.
1257 if(p
->qtype
.getCode() == QType::ANY
&& !p
->d_tcp
&& g_anyToTcp
) {
1263 // for qclass ANY the response should never be authoritative unless the response covers all classes.
1264 if(p
->qclass
==QClass::ANY
)
1269 if(retargetcount
> 10) { // XXX FIXME, retargetcount++?
1270 L
<<Logger::Warning
<<"Abort CNAME chain resolution after "<<--retargetcount
<<" redirects, sending out servfail. Initial query: '"<<p
->qdomain
<<"'"<<endl
;
1273 r
->setRcode(RCode::ServFail
);
1277 if(!B
.getAuth(p
, &sd
, target
)) {
1278 DLOG(L
<<Logger::Error
<<"We have no authority over zone '"<<target
<<"'"<<endl
);
1280 DLOG(L
<<Logger::Error
<<"Recursion is available for this remote, doing that"<<endl
);
1281 *shouldRecurse
=true;
1286 if(!retargetcount
) {
1287 r
->setA(false); // drop AA if we never had a SOA in the first place
1288 r
->setRcode(RCode::Refused
); // send REFUSED - but only on empty 'no idea'
1292 DLOG(L
<<Logger::Error
<<"We have authority, zone='"<<sd
.qname
<<"', id="<<sd
.domain_id
<<endl
);
1293 authSet
.insert(sd
.qname
);
1295 if(!retargetcount
) r
->qdomainzone
=sd
.qname
;
1297 if(sd
.qname
==p
->qdomain
) {
1298 if(p
->qtype
.getCode() == QType::DNSKEY
)
1300 if(addDNSKEY(p
, r
, sd
))
1303 else if(p
->qtype
.getCode() == QType::CDNSKEY
)
1305 if(addCDNSKEY(p
,r
, sd
))
1308 else if(p
->qtype
.getCode() == QType::CDS
)
1313 else if(p
->qtype
.getCode() == QType::NSEC3PARAM
)
1315 if(addNSEC3PARAM(p
,r
, sd
))
1320 if(p
->qtype
.getCode() == QType::SOA
&& sd
.qname
==p
->qdomain
) {
1321 rr
.dr
.d_name
=sd
.qname
;
1322 rr
.dr
.d_type
=QType::SOA
;
1323 rr
.dr
.d_content
=makeSOAContent(sd
);
1325 rr
.domain_id
=sd
.domain_id
;
1326 rr
.dr
.d_place
=DNSResourceRecord::ANSWER
;
1332 // this TRUMPS a cname!
1333 if(p
->qtype
.getCode() == QType::NSEC
&& d_dk
.isSecuredZone(sd
.qname
) && !d_dk
.getNSEC3PARAM(sd
.qname
, 0)) {
1334 addNSEC(p
, r
, target
, DNSName(), sd
.qname
, 5);
1339 // this TRUMPS a cname!
1340 if(p
->qtype
.getCode() == QType::RRSIG
) {
1341 L
<<Logger::Info
<<"Direct RRSIG query for "<<target
<<" from "<<p
->getRemote()<<endl
;
1342 r
->setRcode(RCode::NotImp
);
1346 DLOG(L
<<"Checking for referrals first, unless this is a DS query"<<endl
);
1347 if(p
->qtype
.getCode() != QType::DS
&& tryReferral(p
, r
, sd
, target
, retargetcount
))
1350 DLOG(L
<<"Got no referrals, trying ANY"<<endl
);
1352 // see what we get..
1353 B
.lookup(QType(QType::ANY
), target
, p
, sd
.domain_id
);
1355 haveAlias
.trimToLabels(0);
1356 weDone
= weRedirected
= weHaveUnauth
= false;
1359 //cerr<<"got content: ["<<rr.content<<"]"<<endl;
1360 if (p
->qtype
.getCode() == QType::ANY
&& !p
->d_dnssecOk
&& (rr
.dr
.d_type
== QType:: DNSKEY
|| rr
.dr
.d_type
== QType::NSEC3PARAM
))
1361 continue; // Don't send dnssec info to non validating resolvers.
1362 if (rr
.dr
.d_type
== QType::RRSIG
) // RRSIGS are added later any way.
1363 continue; // TODO: this actually means addRRSig should check if the RRSig is already there
1365 // cerr<<"Auth: "<<rr.auth<<", "<<(rr.dr.d_type == p->qtype)<<", "<<rr.dr.d_type.getName()<<endl;
1366 if((p
->qtype
.getCode() == QType::ANY
|| rr
.dr
.d_type
== p
->qtype
.getCode()) && rr
.auth
)
1368 // the line below fakes 'unauth NS' for delegations for non-DNSSEC backends.
1369 if((rr
.dr
.d_type
== p
->qtype
.getCode() && !rr
.auth
) || (rr
.dr
.d_type
== QType::NS
&& (!rr
.auth
|| !(sd
.qname
==rr
.dr
.d_name
))))
1372 if(rr
.dr
.d_type
== QType::CNAME
&& p
->qtype
.getCode() != QType::CNAME
)
1375 if(DP
&& rr
.dr
.d_type
== QType::ALIAS
&& (p
->qtype
.getCode() == QType::A
|| p
->qtype
.getCode() == QType::AAAA
|| p
->qtype
.getCode() == QType::ANY
)) {
1376 haveAlias
=getRR
<ALIASRecordContent
>(rr
.dr
)->d_content
;
1379 // Filter out all SOA's and add them in later
1380 if(rr
.dr
.d_type
== QType::SOA
)
1383 rrset
.push_back(rr
);
1386 /* Add in SOA if required */
1387 if(target
==sd
.qname
) {
1388 rr
.dr
.d_type
= QType::SOA
;
1389 rr
.dr
.d_content
= makeSOAContent(sd
);
1390 rr
.dr
.d_name
= sd
.qname
;
1391 rr
.dr
.d_ttl
= sd
.ttl
;
1392 rr
.domain_id
= sd
.domain_id
;
1394 rrset
.push_back(rr
);
1398 DLOG(L
<<"After first ANY query for '"<<target
<<"', id="<<sd
.domain_id
<<": weDone="<<weDone
<<", weHaveUnauth="<<weHaveUnauth
<<", weRedirected="<<weRedirected
<<", haveAlias='"<<haveAlias
<<"'"<<endl
);
1399 if(p
->qtype
.getCode() == QType::DS
&& weHaveUnauth
&& !weDone
&& !weRedirected
&& d_dk
.isSecuredZone(sd
.qname
)) {
1400 DLOG(L
<<"Q for DS of a name for which we do have NS, but for which we don't have on a zone with DNSSEC need to provide an AUTH answer that proves we don't"<<endl
);
1401 makeNOError(p
, r
, target
, DNSName(), sd
, 1);
1405 if(!haveAlias
.empty() && (!weDone
|| p
->qtype
.getCode() == QType::ANY
)) {
1406 DLOG(L
<<Logger::Warning
<<"Found nothing that matched for '"<<target
<<"', but did get alias to '"<<haveAlias
<<"', referring"<<endl
);
1407 DP
->completePacket(r
, haveAlias
, target
);
1412 DLOG(L
<<"checking qtype.getCode() ["<<(p
->qtype
.getCode())<<"] against QType::DS ["<<(QType::DS
)<<"]"<<endl
);
1413 if(p
->qtype
.getCode() == QType::DS
)
1415 DLOG(L
<<"DS query found no direct result, trying referral now"<<endl
);
1416 if(tryReferral(p
, r
, sd
, target
, retargetcount
))
1418 DLOG(L
<<"got referral for DS query"<<endl
);
1424 DLOG(L
<<Logger::Warning
<<"Found nothing in the by-name ANY, but let's try wildcards.."<<endl
);
1425 bool wereRetargeted(false), nodata(false);
1427 if(tryWildcard(p
, r
, sd
, target
, wildcard
, wereRetargeted
, nodata
)) {
1428 if(wereRetargeted
) {
1429 if(!retargetcount
) r
->qdomainwild
=wildcard
;
1434 makeNOError(p
, r
, target
, wildcard
, sd
, 2);
1438 else if(tryDNAME(p
, r
, sd
, target
)) {
1444 if (!(((p
->qtype
.getCode() == QType::CNAME
) || (p
->qtype
.getCode() == QType::ANY
)) && retargetcount
> 0))
1445 makeNXDomain(p
, r
, target
, wildcard
, sd
);
1452 for(auto& rr
: rrset
) {
1453 if(rr
.dr
.d_type
== QType::CNAME
) {
1455 target
= getRR
<CNAMERecordContent
>(rr
.dr
)->getTarget();
1462 bool haveRecords
= false;
1463 for(const auto& rr
: rrset
) {
1464 if((p
->qtype
.getCode() == QType::ANY
|| rr
.dr
.d_type
== p
->qtype
.getCode()) && rr
.dr
.d_type
&& rr
.dr
.d_type
!= QType::ALIAS
&& rr
.auth
) {
1471 if(p
->qtype
.getCode() == QType::ANY
)
1472 completeANYRecords(p
, r
, sd
, target
);
1475 makeNOError(p
, r
, target
, DNSName(), sd
, 0);
1479 else if(weHaveUnauth
) {
1480 DLOG(L
<<"Have unauth data, so need to hunt for best NS records"<<endl
);
1481 if(tryReferral(p
, r
, sd
, target
, retargetcount
))
1483 // check whether this could be fixed easily
1484 // if (*(rr.dr.d_name.rbegin()) == '.') {
1485 // L<<Logger::Error<<"Should not get here ("<<p->qdomain<<"|"<<p->qtype.getCode()<<"): you have a trailing dot, this could be the problem (or run pdnsutil rectify-zone " <<sd.qname<<")"<<endl;
1487 L
<<Logger::Error
<<"Should not get here ("<<p
->qdomain
<<"|"<<p
->qtype
.getCode()<<"): please run pdnsutil rectify-zone "<<sd
.qname
<<endl
;
1491 DLOG(L
<<"Have some data, but not the right data"<<endl
);
1492 makeNOError(p
, r
, target
, DNSName(), sd
, 0);
1496 if(doAdditionalProcessingAndDropAA(p
, r
, sd
, retargetcount
)<0) {
1501 editSOA(d_dk
, sd
.qname
, r
);
1503 for(const auto& rr
: r
->getRRS()) {
1510 addRRSigs(d_dk
, B
, authSet
, r
->getRRS());
1512 r
->wrapup(); // needed for inserting in cache
1514 PC
.insert(p
, r
, false, r
->getMinTTL()); // in the packet cache
1516 catch(DBException
&e
) {
1517 L
<<Logger::Error
<<"Backend reported condition which prevented lookup ("+e
.reason
+") sending out servfail"<<endl
;
1519 r
=p
->replyPacket(); // generate an empty reply packet
1520 r
->setRcode(RCode::ServFail
);
1521 S
.inc("servfail-packets");
1522 S
.ringAccount("servfail-queries",p
->qdomain
.toLogString());
1524 catch(PDNSException
&e
) {
1525 L
<<Logger::Error
<<"Backend reported permanent error which prevented lookup ("+e
.reason
+"), aborting"<<endl
;
1526 throw; // we WANT to die at this point
1528 catch(std::exception
&e
) {
1529 L
<<Logger::Error
<<"Exception building answer packet for "<<p
->qdomain
<<"/"<<p
->qtype
.getName()<<" ("<<e
.what()<<") sending out servfail"<<endl
;
1531 r
=p
->replyPacket(); // generate an empty reply packet
1532 r
->setRcode(RCode::ServFail
);
1533 S
.inc("servfail-packets");
1534 S
.ringAccount("servfail-queries",p
->qdomain
.toLogString());