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 set
<string
> PacketHandler::s_forwardNotify
;
58 extern string s_programname
;
60 PacketHandler::PacketHandler():B(s_programname
), d_dk(&B
)
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"];
74 d_pdl
= std::unique_ptr
<AuthLua4
>(new AuthLua4());
75 d_pdl
->loadFile(fname
);
77 fname
= ::arg()["lua-dnsupdate-policy-script"];
80 d_update_policy_lua
= NULL
;
84 d_update_policy_lua
= std::unique_ptr
<AuthLua4
>(new AuthLua4());
85 d_update_policy_lua
->loadFile(fname
);
89 UeberBackend
*PacketHandler::getBackend()
94 PacketHandler::~PacketHandler()
97 DLOG(L
<<Logger::Error
<<"PacketHandler destructor called - "<<s_count
<<" left"<<endl
);
101 * This adds CDNSKEY records to the answer packet. Returns true if one was added.
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
108 bool PacketHandler::addCDNSKEY(DNSPacket
*p
, DNSPacket
*r
, const SOAData
& sd
)
110 string publishCDNSKEY
;
111 d_dk
.getFromMeta(p
->qdomain
, "PUBLISH-CDNSKEY", publishCDNSKEY
);
112 if (publishCDNSKEY
!= "1")
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());
129 if(::arg().mustDo("direct-dnskey")) {
130 B
.lookup(QType(QType::CDNSKEY
), p
->qdomain
, p
, sd
.domain_id
);
133 rr
.dr
.d_ttl
=sd
.default_ttl
;
142 * This adds DNSKEY records to the answer packet. Returns true if one was added.
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
149 bool PacketHandler::addDNSKEY(DNSPacket
*p
, DNSPacket
*r
, const SOAData
& sd
)
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());
165 if(::arg().mustDo("direct-dnskey")) {
166 B
.lookup(QType(QType::DNSKEY
), p
->qdomain
, p
, sd
.domain_id
);
169 rr
.dr
.d_ttl
=sd
.default_ttl
;
179 * This adds CDS records to the answer packet r.
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.
187 bool PacketHandler::addCDS(DNSPacket
*p
, DNSPacket
*r
, const SOAData
& sd
)
190 d_dk
.getFromMeta(p
->qdomain
, "PUBLISH-CDS", publishCDS
);
191 if (publishCDS
.empty())
194 vector
<string
> digestAlgos
;
195 stringtok(digestAlgos
, publishCDS
, ", ");
198 rr
.dr
.d_type
=QType::CDS
;
199 rr
.dr
.d_ttl
=sd
.default_ttl
;
200 rr
.dr
.d_name
=p
->qdomain
;
205 DNSSECKeeper::keyset_t keyset
= d_dk
.getEntryPoints(p
->qdomain
);
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
)));
215 if(::arg().mustDo("direct-dnskey")) {
216 B
.lookup(QType(QType::CDS
), p
->qdomain
, p
, sd
.domain_id
);
219 rr
.dr
.d_ttl
=sd
.default_ttl
;
228 /** This adds NSEC3PARAM records. Returns true if one was added */
229 bool PacketHandler::addNSEC3PARAM(DNSPacket
*p
, DNSPacket
*r
, const SOAData
& sd
)
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
);
248 // This is our chaos class requests handler. Return 1 if content was added, 0 if it wasn't
249 int PacketHandler::doChaosRequest(DNSPacket
*p
, DNSPacket
*r
, DNSName
&target
)
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"];
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
);
269 rr
.dr
.d_content
= DNSRecordContent::mastermake(QType::TXT
, 1, "\""+content
+"\"");
271 else if (target
==idserver
) {
272 // modes: disabled, hostname or custom
273 const static string id
=::arg()["server-id"];
275 if (id
== "disabled") {
276 r
->setRcode(RCode::Refused
);
280 if(!tid
.empty() && tid
[0]!='"') { // see #6010 however
281 tid
= "\"" + tid
+ "\"";
283 rr
.dr
.d_content
=DNSRecordContent::mastermake(QType::TXT
, 1, tid
);
286 r
->setRcode(RCode::Refused
);
292 rr
.dr
.d_type
=QType::TXT
;
293 rr
.dr
.d_class
=QClass::CHAOS
;
298 r
->setRcode(RCode::NotImp
);
302 vector
<DNSZoneRecord
> PacketHandler::getBestReferralNS(DNSPacket
*p
, SOAData
& sd
, const DNSName
&target
)
304 vector
<DNSZoneRecord
> ret
;
306 DNSName
subdomain(target
);
308 if(subdomain
== sd
.qname
) // stop at SOA
310 B
.lookup(QType(QType::NS
), subdomain
, p
, sd
.domain_id
);
312 ret
.push_back(rr
); // this used to exclude auth NS records for some reason
316 } while( subdomain
.chopOff() ); // 'www.powerdns.org' -> 'powerdns.org' -> 'org' -> ''
320 vector
<DNSZoneRecord
> PacketHandler::getBestDNAMESynth(DNSPacket
*p
, SOAData
& sd
, DNSName
&target
)
322 vector
<DNSZoneRecord
> ret
;
325 DNSName
subdomain(target
);
327 DLOG(L
<<"Attempting DNAME lookup for "<<subdomain
<<", sd.qname="<<sd
.qname
<<endl
);
329 B
.lookup(QType(QType::DNAME
), subdomain
, p
, sd
.domain_id
);
331 ret
.push_back(rr
); // put in the original
332 rr
.dr
.d_type
= QType::CNAME
;
333 rr
.dr
.d_name
= prefix
+ rr
.dr
.d_name
;
334 rr
.dr
.d_content
= std::make_shared
<CNAMERecordContent
>(CNAMERecordContent(prefix
+ getRR
<DNAMERecordContent
>(rr
.dr
)->d_content
));
335 rr
.auth
= 0; // don't sign CNAME
336 target
= getRR
<CNAMERecordContent
>(rr
.dr
)->getTarget();
341 if(subdomain
.countLabels())
342 prefix
.appendRawLabel(subdomain
.getRawLabels()[0]); // XXX DNSName pain this feels wrong
343 if(subdomain
== sd
.qname
) // stop at SOA
346 } while( subdomain
.chopOff() ); // 'www.powerdns.org' -> 'powerdns.org' -> 'org' -> ''
351 // Return best matching wildcard or next closer name
352 bool PacketHandler::getBestWildcard(DNSPacket
*p
, SOAData
& sd
, const DNSName
&target
, DNSName
&wildcard
, vector
<DNSZoneRecord
>* ret
)
356 DNSName
subdomain(target
);
357 bool haveSomething
=false;
360 while( subdomain
.chopOff() && !haveSomething
) {
361 if (subdomain
.empty()) {
362 B
.lookup(QType(QType::ANY
), g_wildcarddnsname
, p
, sd
.domain_id
);
364 B
.lookup(QType(QType::ANY
), g_wildcarddnsname
+subdomain
, p
, sd
.domain_id
);
367 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
))
369 wildcard
=g_wildcarddnsname
+subdomain
;
373 if ( subdomain
== sd
.qname
|| haveSomething
) // stop at SOA or result
376 B
.lookup(QType(QType::ANY
), subdomain
, p
, sd
.domain_id
);
378 DLOG(L
<<"No wildcard match, ancestor exists"<<endl
);
385 return haveSomething
;
388 /** dangling is declared true if we were unable to resolve everything */
389 int PacketHandler::doAdditionalProcessingAndDropAA(DNSPacket
*p
, DNSPacket
*r
, const SOAData
& soadata
, bool retargeted
)
395 if(p
->qtype
.getCode()!=QType::AXFR
) { // this packet needs additional processing
396 // we now have a copy, push_back on packet might reallocate!
397 auto& records
= r
->getRRS();
398 vector
<DNSZoneRecord
> toAdd
;
400 for(auto i
= records
.cbegin() ; i
!= records
.cend(); ++i
) {
401 if(i
->dr
.d_place
==DNSResourceRecord::ADDITIONAL
||
402 !(i
->dr
.d_type
==QType::MX
|| i
->dr
.d_type
==QType::NS
|| i
->dr
.d_type
==QType::SRV
))
405 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
407 // i->d_place=DNSResourceRecord::AUTHORITY; // XXX FIXME
412 if(i
->dr
.d_type
== QType::MX
)
413 lookup
= getRR
<MXRecordContent
>(i
->dr
)->d_mxname
;
414 else if(i
->dr
.d_type
== QType::SRV
)
415 lookup
= getRR
<SRVRecordContent
>(i
->dr
)->d_target
;
416 else if(i
->dr
.d_type
== QType::NS
)
417 lookup
= getRR
<NSRecordContent
>(i
->dr
)->getNS();
420 B
.lookup(QType(d_doIPv6AdditionalProcessing
? QType::ANY
: QType::A
), lookup
, p
);
423 if(rr
.dr
.d_type
!= QType::A
&& rr
.dr
.d_type
!=QType::AAAA
)
425 if(rr
.domain_id
!=i
->domain_id
&& ::arg()["out-of-zone-additional-processing"]=="no") {
426 DLOG(L
<<Logger::Warning
<<"Not including out-of-zone additional processing of "<<i
->dr
.d_name
<<" ("<<rr
.dr
.d_name
<<")"<<endl
);
427 continue; // not adding out-of-zone additional data
430 if(rr
.auth
&& !rr
.dr
.d_name
.isPartOf(soadata
.qname
)) // don't sign out of zone data using the main key
432 rr
.dr
.d_place
=DNSResourceRecord::ADDITIONAL
;
436 for(const auto& rec
: toAdd
)
439 //records.insert(records.end(), toAdd.cbegin(), toAdd.cend()); // would be faster, but no dedup
445 void PacketHandler::emitNSEC(DNSPacket
*r
, const SOAData
& sd
, const DNSName
& name
, const DNSName
& next
, int mode
)
447 NSECRecordContent nrc
;
450 nrc
.d_set
.insert(QType::NSEC
);
451 nrc
.d_set
.insert(QType::RRSIG
);
452 if(sd
.qname
== name
) {
453 nrc
.d_set
.insert(QType::SOA
); // 1dfd8ad SOA can live outside the records table
454 nrc
.d_set
.insert(QType::DNSKEY
);
455 string publishCDNSKEY
;
456 d_dk
.getFromMeta(name
, "PUBLISH-CDNSKEY", publishCDNSKEY
);
457 if (publishCDNSKEY
== "1")
458 nrc
.d_set
.insert(QType::CDNSKEY
);
460 d_dk
.getFromMeta(name
, "PUBLISH-CDS", publishCDS
);
461 if (! publishCDS
.empty())
462 nrc
.d_set
.insert(QType::CDS
);
467 B
.lookup(QType(QType::ANY
), name
, NULL
, sd
.domain_id
);
469 if(rr
.dr
.d_type
== QType::NS
|| rr
.auth
)
470 nrc
.d_set
.insert(rr
.dr
.d_type
);
474 rr
.dr
.d_ttl
= sd
.default_ttl
;
475 rr
.dr
.d_type
= QType::NSEC
;
476 rr
.dr
.d_content
= std::make_shared
<NSECRecordContent
>(nrc
);
477 rr
.dr
.d_place
= (mode
== 5 ) ? DNSResourceRecord::ANSWER
: DNSResourceRecord::AUTHORITY
;
483 void PacketHandler::emitNSEC3(DNSPacket
*r
, const SOAData
& sd
, const NSEC3PARAMRecordContent
& ns3prc
, const DNSName
& name
, const string
& namehash
, const string
& nexthash
, int mode
)
485 NSEC3RecordContent n3rc
;
486 n3rc
.d_algorithm
= ns3prc
.d_algorithm
;
487 n3rc
.d_flags
= ns3prc
.d_flags
;
488 n3rc
.d_iterations
= ns3prc
.d_iterations
;
489 n3rc
.d_salt
= ns3prc
.d_salt
;
490 n3rc
.d_nexthash
= nexthash
;
495 if (sd
.qname
== name
) {
496 n3rc
.d_set
.insert(QType::SOA
); // 1dfd8ad SOA can live outside the records table
497 n3rc
.d_set
.insert(QType::NSEC3PARAM
);
498 n3rc
.d_set
.insert(QType::DNSKEY
);
499 string publishCDNSKEY
;
500 d_dk
.getFromMeta(name
, "PUBLISH-CDNSKEY", publishCDNSKEY
);
501 if (publishCDNSKEY
== "1")
502 n3rc
.d_set
.insert(QType::CDNSKEY
);
504 d_dk
.getFromMeta(name
, "PUBLISH-CDS", publishCDS
);
505 if (! publishCDS
.empty())
506 n3rc
.d_set
.insert(QType::CDS
);
509 B
.lookup(QType(QType::ANY
), name
, NULL
, sd
.domain_id
);
511 if(rr
.dr
.d_type
&& (rr
.dr
.d_type
== QType::NS
|| rr
.auth
)) // skip empty non-terminals
512 n3rc
.d_set
.insert(rr
.dr
.d_type
);
516 if (n3rc
.d_set
.size() && !(n3rc
.d_set
.size() == 1 && n3rc
.d_set
.count(QType::NS
)))
517 n3rc
.d_set
.insert(QType::RRSIG
);
519 rr
.dr
.d_name
= DNSName(toBase32Hex(namehash
))+sd
.qname
;
520 rr
.dr
.d_ttl
= sd
.default_ttl
;
521 rr
.dr
.d_type
=QType::NSEC3
;
522 rr
.dr
.d_content
=std::make_shared
<NSEC3RecordContent
>(n3rc
);
523 rr
.dr
.d_place
= (mode
== 5 ) ? DNSResourceRecord::ANSWER
: DNSResourceRecord::AUTHORITY
;
530 mode 0 = No Data Responses, QTYPE is not DS
531 mode 1 = No Data Responses, QTYPE is DS
532 mode 2 = Wildcard No Data Responses
533 mode 3 = Wildcard Answer Responses
534 mode 4 = Name Error Responses
535 mode 5 = Direct NSEC request
537 void PacketHandler::addNSECX(DNSPacket
*p
, DNSPacket
*r
, const DNSName
& target
, const DNSName
& wildcard
, const DNSName
& auth
, int mode
)
539 if(!p
->d_dnssecOk
&& mode
!= 5)
542 NSEC3PARAMRecordContent ns3rc
;
544 if(d_dk
.getNSEC3PARAM(auth
, &ns3rc
, &narrow
)) {
545 if (mode
!= 5) // no direct NSEC3 queries, rfc5155 7.2.8
546 addNSEC3(p
, r
, target
, wildcard
, auth
, ns3rc
, narrow
, mode
);
549 addNSEC(p
, r
, target
, wildcard
, auth
, mode
);
553 bool getNSEC3Hashes(bool narrow
, DNSBackend
* db
, int id
, const std::string
& hashed
, bool decrement
, DNSName
& unhashed
, std::string
& before
, std::string
& after
, int mode
)
556 if(narrow
) { // nsec3-narrow
560 decrementHash(before
);
564 incrementHash(after
);
567 DNSName hashedName
= DNSName(toBase32Hex(hashed
));
568 DNSName beforeName
, afterName
;
569 if (!decrement
&& mode
>= 2)
570 beforeName
= hashedName
;
571 ret
=db
->getBeforeAndAfterNamesAbsolute(id
, hashedName
, unhashed
, beforeName
, afterName
);
572 before
=fromBase32Hex(beforeName
.toString());
573 after
=fromBase32Hex(afterName
.toString());
578 void PacketHandler::addNSEC3(DNSPacket
*p
, DNSPacket
*r
, const DNSName
& target
, const DNSName
& wildcard
, const DNSName
& auth
, const NSEC3PARAMRecordContent
& ns3rc
, bool narrow
, int mode
)
580 DLOG(L
<<"addNSEC3() mode="<<mode
<<" auth="<<auth
<<" target="<<target
<<" wildcard="<<wildcard
<<endl
);
583 if(!B
.getSOAUncached(auth
, sd
)) {
584 DLOG(L
<<"Could not get SOA for domain");
588 bool doNextcloser
= false;
589 string before
, after
, hashed
;
590 DNSName unhashed
, closest
;
592 if (mode
== 2 || mode
== 3 || mode
== 4) {
598 // add matching NSEC3 RR
600 unhashed
=(mode
== 0 || mode
== 1 || mode
== 5) ? target
: closest
;
601 hashed
=hashQNameWithSalt(ns3rc
, unhashed
);
602 DLOG(L
<<"1 hash: "<<toBase32Hex(hashed
)<<" "<<unhashed
<<endl
);
604 getNSEC3Hashes(narrow
, sd
.db
, sd
.domain_id
, hashed
, false, unhashed
, before
, after
, mode
);
606 if (((mode
== 0 && ns3rc
.d_flags
) || mode
== 1) && (hashed
!= before
)) {
607 DLOG(L
<<"No matching NSEC3, do closest (provable) encloser"<<endl
);
609 bool doBreak
= false;
611 while( closest
.chopOff() && (closest
!= sd
.qname
)) { // stop at SOA
612 B
.lookup(QType(QType::ANY
), closest
, p
, sd
.domain_id
);
621 hashed
=hashQNameWithSalt(ns3rc
, unhashed
);
622 DLOG(L
<<"1 hash: "<<toBase32Hex(hashed
)<<" "<<unhashed
<<endl
);
624 getNSEC3Hashes(narrow
, sd
.db
, sd
.domain_id
, hashed
, false, unhashed
, before
, after
);
627 if (!after
.empty()) {
628 DLOG(L
<<"Done calling for matching, hashed: '"<<toBase32Hex(hashed
)<<"' before='"<<toBase32Hex(before
)<<"', after='"<<toBase32Hex(after
)<<"'"<<endl
);
629 emitNSEC3(r
, sd
, ns3rc
, unhashed
, before
, after
, mode
);
633 // add covering NSEC3 RR
634 if ((mode
>= 2 && mode
<= 4) || doNextcloser
) {
635 DNSName
next(target
);
639 while( next
.chopOff() && !(next
==closest
));
641 hashed
=hashQNameWithSalt(ns3rc
, unhashed
);
642 DLOG(L
<<"2 hash: "<<toBase32Hex(hashed
)<<" "<<unhashed
<<endl
);
644 getNSEC3Hashes(narrow
, sd
.db
,sd
.domain_id
, hashed
, true, unhashed
, before
, after
);
645 DLOG(L
<<"Done calling for covering, hashed: '"<<toBase32Hex(hashed
)<<"' before='"<<toBase32Hex(before
)<<"', after='"<<toBase32Hex(after
)<<"'"<<endl
);
646 emitNSEC3( r
, sd
, ns3rc
, unhashed
, before
, after
, mode
);
650 if (mode
== 2 || mode
== 4) {
651 unhashed
=g_wildcarddnsname
+closest
;
653 hashed
=hashQNameWithSalt(ns3rc
, unhashed
);
654 DLOG(L
<<"3 hash: "<<toBase32Hex(hashed
)<<" "<<unhashed
<<endl
);
656 getNSEC3Hashes(narrow
, sd
.db
, sd
.domain_id
, hashed
, (mode
!= 2), unhashed
, before
, after
);
657 DLOG(L
<<"Done calling for '*', hashed: '"<<toBase32Hex(hashed
)<<"' before='"<<toBase32Hex(before
)<<"', after='"<<toBase32Hex(after
)<<"'"<<endl
);
658 emitNSEC3( r
, sd
, ns3rc
, unhashed
, before
, after
, mode
);
662 void PacketHandler::addNSEC(DNSPacket
*p
, DNSPacket
*r
, const DNSName
& target
, const DNSName
& wildcard
, const DNSName
& auth
, int mode
)
664 DLOG(L
<<"addNSEC() mode="<<mode
<<" auth="<<auth
<<" target="<<target
<<" wildcard="<<wildcard
<<endl
);
667 if(!B
.getSOAUncached(auth
, sd
)) {
668 DLOG(L
<<"Could not get SOA for domain"<<endl
);
672 DNSName before
,after
;
673 sd
.db
->getBeforeAndAfterNames(sd
.domain_id
, auth
, target
, before
, after
);
674 if (mode
!= 5 || before
== target
)
675 emitNSEC(r
, sd
, before
, after
, mode
);
677 if (mode
== 2 || mode
== 4) {
678 // wildcard NO-DATA or wildcard denial
680 DNSName
closest(wildcard
);
683 closest
.prependRawLabel("*");
685 sd
.db
->getBeforeAndAfterNames(sd
.domain_id
, auth
, closest
, before
, after
);
686 emitNSEC(r
, sd
, before
, after
, mode
);
693 - only one backend owns the SOA of a zone
694 - only one AXFR per zone at a time - double startTransaction should fail
695 - backends need to implement transaction semantics
698 How BindBackend would implement this:
699 startTransaction makes a file
700 feedRecord sends everything to that file
701 commitTransaction moves that file atomically over the regular file, and triggers a reload
702 rollbackTransaction removes the file
705 How PostgreSQLBackend would implement this:
706 startTransaction starts a sql transaction, which also deletes all records
707 feedRecord is an insert statement
708 commitTransaction commits the transaction
709 rollbackTransaction aborts it
711 How MySQLBackend would implement this:
716 int PacketHandler::trySuperMaster(DNSPacket
*p
, const DNSName
& tsigkeyname
)
720 // do it right now if the client is TCP
722 return trySuperMasterSynchronous(p
, tsigkeyname
);
726 // queue it if the client is on UDP
727 Communicator
.addTrySuperMasterRequest(p
);
732 int PacketHandler::trySuperMasterSynchronous(DNSPacket
*p
, const DNSName
& tsigkeyname
)
734 string remote
= p
->getRemote().toString();
735 if(p
->hasEDNSSubnet() && ::arg().contains("trusted-notification-proxy", remote
)) {
736 remote
= p
->getRealRemote().toStringNoMask();
739 Resolver::res_t nsset
;
742 uint32_t theirserial
;
743 resolver
.getSoaSerial(remote
,p
->qdomain
, &theirserial
);
744 resolver
.resolve(remote
, p
->qdomain
, QType::NS
, &nsset
);
746 catch(ResolverException
&re
) {
747 L
<<Logger::Error
<<"Error resolving SOA or NS for "<<p
->qdomain
<<" at: "<< remote
<<": "<<re
.reason
<<endl
;
748 return RCode::ServFail
;
751 // check if the returned records are NS records
753 for(const auto& ns
: nsset
) {
754 if(ns
.qtype
==QType::NS
)
759 L
<<Logger::Error
<<"While checking for supermaster, did not find NS for "<<p
->qdomain
<<" at: "<< remote
<<endl
;
760 return RCode::ServFail
;
763 string nameserver
, account
;
766 if (!::arg().mustDo("allow-unsigned-supermaster") && tsigkeyname
.empty()) {
767 L
<<Logger::Error
<<"Received unsigned NOTIFY for "<<p
->qdomain
<<" from potential supermaster "<<remote
<<". Refusing."<<endl
;
768 return RCode::Refused
;
771 if(!B
.superMasterBackend(remote
, p
->qdomain
, nsset
, &nameserver
, &account
, &db
)) {
772 L
<<Logger::Error
<<"Unable to find backend willing to host "<<p
->qdomain
<<" for potential supermaster "<<remote
<<". Remote nameservers: "<<endl
;
773 for(const auto& rr
: nsset
) {
774 if(rr
.qtype
==QType::NS
)
775 L
<<Logger::Error
<<rr
.content
<<endl
;
777 return RCode::Refused
;
780 db
->createSlaveDomain(p
->getRemote().toString(), p
->qdomain
, nameserver
, account
);
781 if (tsigkeyname
.empty() == false) {
783 meta
.push_back(tsigkeyname
.toStringNoDot());
784 db
->setDomainMetadata(p
->qdomain
, "AXFR-MASTER-TSIG", meta
);
787 catch(PDNSException
& ae
) {
788 L
<<Logger::Error
<<"Database error trying to create "<<p
->qdomain
<<" for potential supermaster "<<remote
<<": "<<ae
.reason
<<endl
;
789 return RCode::ServFail
;
791 L
<<Logger::Warning
<<"Created new slave zone '"<<p
->qdomain
<<"' from supermaster "<<remote
<<endl
;
792 return RCode::NoError
;
795 int PacketHandler::processNotify(DNSPacket
*p
)
798 was this notification from an approved address?
799 was this notification approved by TSIG?
800 We determine our internal SOA id (via UeberBackend)
801 We determine the SOA at our (known) master
802 if master is higher -> do stuff
806 if(!::arg().mustDo("slave") && s_forwardNotify
.empty()) {
807 L
<<Logger::Error
<<"Received NOTIFY for "<<p
->qdomain
<<" from "<<p
->getRemote()<<" but slave support is disabled in the configuration"<<endl
;
808 return RCode::NotImp
;
811 if(!s_allowNotifyFrom
.match((ComboAddress
*) &p
->d_remote
) || p
->d_havetsig
) {
812 if (p
->d_havetsig
&& p
->getTSIGKeyname().empty() == false) {
813 L
<<Logger::Notice
<<"Received secure NOTIFY for "<<p
->qdomain
<<" from "<<p
->getRemote()<<", allowed by TSIG key '"<<p
->getTSIGKeyname()<<"'"<<endl
;
815 L
<<Logger::Error
<<"Received NOTIFY for "<<p
->qdomain
<<" from "<<p
->getRemote()<<" but remote is not permitted by TSIG or allow-notify-from"<<endl
;
816 return RCode::Refused
;
823 if(!B
.getDomainInfo(p
->qdomain
, di
) || !(db
=di
.backend
)) {
824 L
<<Logger::Error
<<"Received NOTIFY for "<<p
->qdomain
<<" from "<<p
->getRemote()<<" for which we are not authoritative"<<endl
;
825 return trySuperMaster(p
, p
->getTSIGKeyname());
829 if (B
.getDomainMetadata(p
->qdomain
,"AXFR-MASTER-TSIG",meta
) && meta
.size() > 0) {
830 if (!p
->d_havetsig
) {
831 if (::arg().mustDo("allow-unsigned-notify")) {
832 L
<<Logger::Warning
<<"Received unsigned NOTIFY for "<<p
->qdomain
<<" from "<<p
->getRemote()<<": permitted because allow-unsigned-notify";
834 L
<<Logger::Warning
<<"Received unsigned NOTIFY for "<<p
->qdomain
<<" from "<<p
->getRemote()<<": refused"<<endl
;
835 return RCode::Refused
;
837 } else if (meta
[0] != p
->getTSIGKeyname().toStringNoDot()) {
838 L
<<Logger::Error
<<"Received secure NOTIFY for "<<p
->qdomain
<<" from "<<p
->getRemote()<<": expected TSIG key '"<<meta
[0]<<", got '"<<p
->getTSIGKeyname()<<"'"<<endl
;
839 return RCode::Refused
;
843 if(::arg().contains("trusted-notification-proxy", p
->getRemote().toString())) {
844 L
<<Logger::Error
<<"Received NOTIFY for "<<p
->qdomain
<<" from trusted-notification-proxy "<< p
->getRemote()<<endl
;
845 if(di
.masters
.empty()) {
846 L
<<Logger::Error
<<"However, "<<p
->qdomain
<<" does not have any masters defined"<<endl
;
847 return RCode::Refused
;
850 else if(::arg().mustDo("master") && di
.kind
== DomainInfo::Master
) {
851 L
<<Logger::Error
<<"Received NOTIFY for "<<p
->qdomain
<<" from "<<p
->getRemote()<<" but we are master, rejecting"<<endl
;
852 return RCode::Refused
;
854 else if(!db
->isMaster(p
->qdomain
, p
->getRemote().toString())) {
855 L
<<Logger::Error
<<"Received NOTIFY for "<<p
->qdomain
<<" from "<<p
->getRemote()<<" which is not a master"<<endl
;
856 return RCode::Refused
;
859 // ok, we've done our checks
862 if(!s_forwardNotify
.empty()) {
863 set
<string
> forwardNotify(s_forwardNotify
);
864 for(set
<string
>::const_iterator j
=forwardNotify
.begin();j
!=forwardNotify
.end();++j
) {
865 L
<<Logger::Warning
<<"Relaying notification of domain "<<p
->qdomain
<<" from "<<p
->getRemote()<<" to "<<*j
<<endl
;
866 Communicator
.notify(p
->qdomain
,*j
);
870 if(::arg().mustDo("slave"))
871 Communicator
.addSlaveCheckRequest(di
, p
->d_remote
);
875 bool validDNSName(const DNSName
&name
)
878 string::size_type pos
, length
;
880 for(const auto& s
: name
.getRawLabels()) {
882 for(pos
=0; pos
< length
; ++pos
) {
884 if(!((c
>= 'a' && c
<= 'z') ||
885 (c
>= 'A' && c
<= 'Z') ||
886 (c
>= '0' && c
<= '9') ||
887 c
=='-' || c
== '_' || c
=='*' || c
=='.' || c
=='/' || c
=='@' || c
==' ' || c
=='\\' || c
==':'))
895 DNSPacket
*PacketHandler::question(DNSPacket
*p
)
901 ret
=d_pdl
->prequery(p
);
907 static AtomicCounter
&rdqueries
=*S
.getPointer("rd-queries");
911 return doQuestion(p
);
915 void PacketHandler::makeNXDomain(DNSPacket
* p
, DNSPacket
* r
, const DNSName
& target
, const DNSName
& wildcard
, SOAData
& sd
)
918 rr
.dr
.d_name
=sd
.qname
;
919 rr
.dr
.d_type
=QType::SOA
;
921 rr
.dr
.d_content
=makeSOAContent(sd
);
922 rr
.dr
.d_ttl
=min(sd
.ttl
, sd
.default_ttl
);
924 rr
.domain_id
=sd
.domain_id
;
925 rr
.dr
.d_place
=DNSResourceRecord::AUTHORITY
;
927 rr
.scopeMask
= sd
.scopeMask
;
930 if(d_dk
.isSecuredZone(sd
.qname
))
931 addNSECX(p
, r
, target
, wildcard
, sd
.qname
, 4);
933 r
->setRcode(RCode::NXDomain
);
936 void PacketHandler::makeNOError(DNSPacket
* p
, DNSPacket
* r
, const DNSName
& target
, const DNSName
& wildcard
, SOAData
& sd
, int mode
)
939 rr
.dr
.d_name
=sd
.qname
;
940 rr
.dr
.d_type
=QType::SOA
;
941 rr
.dr
.d_content
=makeSOAContent(sd
);
943 rr
.dr
.d_ttl
=min(sd
.ttl
, sd
.default_ttl
);
945 rr
.domain_id
=sd
.domain_id
;
946 rr
.dr
.d_place
=DNSResourceRecord::AUTHORITY
;
950 if(d_dk
.isSecuredZone(sd
.qname
))
951 addNSECX(p
, r
, target
, wildcard
, sd
.qname
, mode
);
953 S
.ringAccount("noerror-queries",p
->qdomain
.toLogString()+"/"+p
->qtype
.getName());
957 bool PacketHandler::addDSforNS(DNSPacket
* p
, DNSPacket
* r
, SOAData
& sd
, const DNSName
& dsname
)
959 //cerr<<"Trying to find a DS for '"<<dsname<<"', domain_id = "<<sd.domain_id<<endl;
960 B
.lookup(QType(QType::DS
), dsname
, p
, sd
.domain_id
);
965 rr
.dr
.d_place
= DNSResourceRecord::AUTHORITY
;
971 bool PacketHandler::tryReferral(DNSPacket
*p
, DNSPacket
*r
, SOAData
& sd
, const DNSName
&target
, bool retargeted
)
973 vector
<DNSZoneRecord
> rrset
= getBestReferralNS(p
, sd
, target
);
977 for(auto& rr
: rrset
) {
978 rr
.dr
.d_place
=DNSResourceRecord::AUTHORITY
;
984 if(d_dk
.isSecuredZone(sd
.qname
) && !addDSforNS(p
, r
, sd
, rrset
.begin()->dr
.d_name
))
985 addNSECX(p
, r
, rrset
.begin()->dr
.d_name
, DNSName(), sd
.qname
, 1);
990 void PacketHandler::completeANYRecords(DNSPacket
*p
, DNSPacket
*r
, SOAData
& sd
, const DNSName
&target
)
993 return; // Don't send dnssec info to non validating resolvers.
995 if(!d_dk
.isSecuredZone(sd
.qname
))
998 addNSECX(p
, r
, target
, DNSName(), sd
.qname
, 5);
999 if(sd
.qname
== p
->qdomain
) {
1000 addDNSKEY(p
, r
, sd
);
1001 addCDNSKEY(p
, r
, sd
);
1003 addNSEC3PARAM(p
, r
, sd
);
1007 bool PacketHandler::tryDNAME(DNSPacket
*p
, DNSPacket
*r
, SOAData
& sd
, DNSName
&target
)
1011 DLOG(L
<<Logger::Warning
<<"Let's try DNAME.."<<endl
);
1012 vector
<DNSZoneRecord
> rrset
= getBestDNAMESynth(p
, sd
, target
);
1013 if(!rrset
.empty()) {
1014 for(auto& rr
: rrset
) {
1015 rr
.dr
.d_place
= DNSResourceRecord::ANSWER
;
1022 bool PacketHandler::tryWildcard(DNSPacket
*p
, DNSPacket
*r
, SOAData
& sd
, DNSName
&target
, DNSName
&wildcard
, bool& retargeted
, bool& nodata
)
1024 retargeted
= nodata
= false;
1027 vector
<DNSZoneRecord
> rrset
;
1028 if(!getBestWildcard(p
, sd
, target
, wildcard
, &rrset
))
1032 DLOG(L
<<"Wildcard matched something, but not of the correct type"<<endl
);
1036 for(auto& rr
: rrset
) {
1037 rr
.wildcardname
= rr
.dr
.d_name
;
1038 rr
.dr
.d_name
=bestmatch
=target
;
1040 if(rr
.dr
.d_type
== QType::CNAME
) {
1042 target
=getRR
<CNAMERecordContent
>(rr
.dr
)->getTarget();
1045 rr
.dr
.d_place
=DNSResourceRecord::ANSWER
;
1049 if(d_dk
.isSecuredZone(sd
.qname
) && !nodata
) {
1050 addNSECX(p
, r
, bestmatch
, wildcard
, sd
.qname
, 3);
1055 //! Called by the Distributor to ask a question. Returns 0 in case of an error
1056 DNSPacket
*PacketHandler::doQuestion(DNSPacket
*p
)
1061 int retargetcount
=0;
1062 set
<DNSName
> authSet
;
1064 vector
<DNSZoneRecord
> rrset
;
1065 bool weDone
=0, weRedirected
=0, weHaveUnauth
=0;
1071 if(p
->d
.qr
) { // QR bit from dns packet (thanks RA from N)
1073 L
<<Logger::Error
<<"Received an answer (non-query) packet from "<<p
->getRemote()<<", dropping"<<endl
;
1074 S
.inc("corrupt-packets");
1075 S
.ringAccount("remotes-corrupt", p
->d_remote
);
1079 if(p
->d
.tc
) { // truncated query. MOADNSParser would silently parse this packet in an incomplete way.
1081 L
<<Logger::Error
<<"Received truncated query packet from "<<p
->getRemote()<<", dropping"<<endl
;
1082 S
.inc("corrupt-packets");
1083 S
.ringAccount("remotes-corrupt", p
->d_remote
);
1087 if (p
->hasEDNS() && p
->getEDNSVersion() > 0) {
1088 r
= p
->replyPacket();
1089 r
->setRcode(16 & 0xF);
1090 r
->setEDNSRcode((16 & 0xFFF0)>>4); // set rcode to BADVERS
1097 TSIGRecordContent trc
;
1098 if(!p
->checkForCorrectTSIG(&B
, &keyname
, &secret
, &trc
)) {
1099 r
=p
->replyPacket(); // generate an empty reply packet
1101 L
<<Logger::Error
<<"Received a TSIG signed message with a non-validating key"<<endl
;
1102 // RFC3007 describes that a non-secure message should be sending Refused for DNS Updates
1103 if (p
->d
.opcode
== Opcode::Update
)
1104 r
->setRcode(RCode::Refused
);
1106 r
->setRcode(RCode::NotAuth
);
1109 getTSIGHashEnum(trc
.d_algoName
, p
->d_tsig_algo
);
1110 if (p
->d_tsig_algo
== TSIG_GSS
) {
1111 GssContext
gssctx(keyname
);
1112 if (!gssctx
.getPeerPrincipal(p
->d_peer_principal
)) {
1113 L
<<Logger::Warning
<<"Failed to extract peer principal from GSS context with keyname '"<<keyname
<<"'"<<endl
;
1117 p
->setTSIGDetails(trc
, keyname
, secret
, trc
.d_mac
); // this will get copied by replyPacket()
1121 r
=p
->replyPacket(); // generate an empty reply packet, possibly with TSIG details inside
1123 if (p
->qtype
== QType::TKEY
) {
1124 this->tkeyHandler(p
, r
);
1130 // XXX FIXME do this in DNSPacket::parse ?
1132 if(!validDNSName(p
->qdomain
)) {
1134 L
<<Logger::Error
<<"Received a malformed qdomain from "<<p
->getRemote()<<", '"<<p
->qdomain
<<"': sending servfail"<<endl
;
1135 S
.inc("corrupt-packets");
1136 S
.ringAccount("remotes-corrupt", p
->d_remote
);
1137 S
.inc("servfail-packets");
1138 r
->setRcode(RCode::ServFail
);
1141 if(p
->d
.opcode
) { // non-zero opcode (again thanks RA!)
1142 if(p
->d
.opcode
==Opcode::Update
) {
1143 S
.inc("dnsupdate-queries");
1144 int res
=processUpdate(p
);
1145 if (res
== RCode::Refused
)
1146 S
.inc("dnsupdate-refused");
1147 else if (res
!= RCode::ServFail
)
1148 S
.inc("dnsupdate-answers");
1150 r
->setOpcode(Opcode::Update
);
1153 else if(p
->d
.opcode
==Opcode::Notify
) {
1154 S
.inc("incoming-notifications");
1155 int res
=processNotify(p
);
1158 r
->setOpcode(Opcode::Notify
);
1165 L
<<Logger::Error
<<"Received an unknown opcode "<<p
->d
.opcode
<<" from "<<p
->getRemote()<<" for "<<p
->qdomain
<<endl
;
1167 r
->setRcode(RCode::NotImp
);
1171 // L<<Logger::Warning<<"Query for '"<<p->qdomain<<"' "<<p->qtype.getName()<<" from "<<p->getRemote()<< " (tcp="<<p->d_tcp<<")"<<endl;
1173 if(p
->qtype
.getCode()==QType::IXFR
) {
1174 r
->setRcode(RCode::Refused
);
1178 DNSName target
=p
->qdomain
;
1180 // catch chaos qclass requests
1181 if(p
->qclass
== QClass::CHAOS
) {
1182 if (doChaosRequest(p
,r
,target
))
1188 // we only know about qclass IN (and ANY), send Refused for everything else.
1189 if(p
->qclass
!= QClass::IN
&& p
->qclass
!=QClass::ANY
) {
1190 r
->setRcode(RCode::Refused
);
1194 // send TC for udp ANY query if any-to-tcp is enabled.
1195 if(p
->qtype
.getCode() == QType::ANY
&& !p
->d_tcp
&& g_anyToTcp
) {
1201 // for qclass ANY the response should never be authoritative unless the response covers all classes.
1202 if(p
->qclass
==QClass::ANY
)
1207 if(retargetcount
> 10) { // XXX FIXME, retargetcount++?
1208 L
<<Logger::Warning
<<"Abort CNAME chain resolution after "<<--retargetcount
<<" redirects, sending out servfail. Initial query: '"<<p
->qdomain
<<"'"<<endl
;
1211 r
->setRcode(RCode::ServFail
);
1215 if(!B
.getAuth(target
, p
->qtype
, &sd
)) {
1216 DLOG(L
<<Logger::Error
<<"We have no authority over zone '"<<target
<<"'"<<endl
);
1217 if(!retargetcount
) {
1218 r
->setA(false); // drop AA if we never had a SOA in the first place
1219 r
->setRcode(RCode::Refused
); // send REFUSED - but only on empty 'no idea'
1223 DLOG(L
<<Logger::Error
<<"We have authority, zone='"<<sd
.qname
<<"', id="<<sd
.domain_id
<<endl
);
1224 authSet
.insert(sd
.qname
);
1226 if(!retargetcount
) r
->qdomainzone
=sd
.qname
;
1228 if(sd
.qname
==p
->qdomain
) {
1229 if(p
->qtype
.getCode() == QType::DNSKEY
)
1231 if(addDNSKEY(p
, r
, sd
))
1234 else if(p
->qtype
.getCode() == QType::CDNSKEY
)
1236 if(addCDNSKEY(p
,r
, sd
))
1239 else if(p
->qtype
.getCode() == QType::CDS
)
1244 else if(p
->qtype
.getCode() == QType::NSEC3PARAM
&& d_dk
.isSecuredZone(sd
.qname
))
1246 if(addNSEC3PARAM(p
,r
, sd
))
1251 if(p
->qtype
.getCode() == QType::SOA
&& sd
.qname
==p
->qdomain
) {
1252 rr
.dr
.d_name
=sd
.qname
;
1253 rr
.dr
.d_type
=QType::SOA
;
1254 sd
.serial
= calculateEditSOA(sd
.serial
, d_dk
, sd
.qname
);
1255 rr
.dr
.d_content
=makeSOAContent(sd
);
1257 rr
.domain_id
=sd
.domain_id
;
1258 rr
.dr
.d_place
=DNSResourceRecord::ANSWER
;
1264 // this TRUMPS a cname!
1265 if(p
->qtype
.getCode() == QType::NSEC
&& d_dk
.isSecuredZone(sd
.qname
) && !d_dk
.getNSEC3PARAM(sd
.qname
, 0)) {
1266 addNSEC(p
, r
, target
, DNSName(), sd
.qname
, 5);
1271 // this TRUMPS a cname!
1272 if(p
->qtype
.getCode() == QType::RRSIG
) {
1273 L
<<Logger::Info
<<"Direct RRSIG query for "<<target
<<" from "<<p
->getRemote()<<endl
;
1274 r
->setRcode(RCode::Refused
);
1278 DLOG(L
<<"Checking for referrals first, unless this is a DS query"<<endl
);
1279 if(p
->qtype
.getCode() != QType::DS
&& tryReferral(p
, r
, sd
, target
, retargetcount
))
1282 DLOG(L
<<"Got no referrals, trying ANY"<<endl
);
1284 // see what we get..
1285 B
.lookup(QType(QType::ANY
), target
, p
, sd
.domain_id
);
1287 haveAlias
.trimToLabels(0);
1288 weDone
= weRedirected
= weHaveUnauth
= false;
1291 //cerr<<"got content: ["<<rr.content<<"]"<<endl;
1292 if (p
->qtype
.getCode() == QType::ANY
&& !p
->d_dnssecOk
&& (rr
.dr
.d_type
== QType:: DNSKEY
|| rr
.dr
.d_type
== QType::NSEC3PARAM
))
1293 continue; // Don't send dnssec info to non validating resolvers.
1294 if (rr
.dr
.d_type
== QType::RRSIG
) // RRSIGS are added later any way.
1295 continue; // TODO: this actually means addRRSig should check if the RRSig is already there
1297 // cerr<<"Auth: "<<rr.auth<<", "<<(rr.dr.d_type == p->qtype)<<", "<<rr.dr.d_type.getName()<<endl;
1298 if((p
->qtype
.getCode() == QType::ANY
|| rr
.dr
.d_type
== p
->qtype
.getCode()) && rr
.auth
)
1300 // the line below fakes 'unauth NS' for delegations for non-DNSSEC backends.
1301 if((rr
.dr
.d_type
== p
->qtype
.getCode() && !rr
.auth
) || (rr
.dr
.d_type
== QType::NS
&& (!rr
.auth
|| !(sd
.qname
==rr
.dr
.d_name
))))
1304 if(rr
.dr
.d_type
== QType::CNAME
&& p
->qtype
.getCode() != QType::CNAME
)
1307 if(DP
&& rr
.dr
.d_type
== QType::ALIAS
&& (p
->qtype
.getCode() == QType::A
|| p
->qtype
.getCode() == QType::AAAA
|| p
->qtype
.getCode() == QType::ANY
)) {
1308 if (!d_doExpandALIAS
) {
1309 L
<<Logger::Info
<<"ALIAS record found for "<<target
<<", but ALIAS expansion is disabled."<<endl
;
1312 haveAlias
=getRR
<ALIASRecordContent
>(rr
.dr
)->d_content
;
1315 // Filter out all SOA's and add them in later
1316 if(rr
.dr
.d_type
== QType::SOA
)
1319 rrset
.push_back(rr
);
1322 /* Add in SOA if required */
1323 if(target
==sd
.qname
) {
1324 rr
.dr
.d_name
= sd
.qname
;
1325 rr
.dr
.d_type
= QType::SOA
;
1326 sd
.serial
= calculateEditSOA(sd
.serial
, d_dk
, sd
.qname
);
1327 rr
.dr
.d_content
= makeSOAContent(sd
);
1328 rr
.dr
.d_ttl
= sd
.ttl
;
1329 rr
.domain_id
= sd
.domain_id
;
1331 rrset
.push_back(rr
);
1335 DLOG(L
<<"After first ANY query for '"<<target
<<"', id="<<sd
.domain_id
<<": weDone="<<weDone
<<", weHaveUnauth="<<weHaveUnauth
<<", weRedirected="<<weRedirected
<<", haveAlias='"<<haveAlias
<<"'"<<endl
);
1336 if(p
->qtype
.getCode() == QType::DS
&& weHaveUnauth
&& !weDone
&& !weRedirected
&& d_dk
.isSecuredZone(sd
.qname
)) {
1337 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
);
1338 makeNOError(p
, r
, target
, DNSName(), sd
, 1);
1342 if(!haveAlias
.empty() && (!weDone
|| p
->qtype
.getCode() == QType::ANY
)) {
1343 DLOG(L
<<Logger::Warning
<<"Found nothing that matched for '"<<target
<<"', but did get alias to '"<<haveAlias
<<"', referring"<<endl
);
1344 DP
->completePacket(r
, haveAlias
, target
);
1349 DLOG(L
<<"checking qtype.getCode() ["<<(p
->qtype
.getCode())<<"] against QType::DS ["<<(QType::DS
)<<"]"<<endl
);
1350 if(p
->qtype
.getCode() == QType::DS
)
1352 DLOG(L
<<"DS query found no direct result, trying referral now"<<endl
);
1353 if(tryReferral(p
, r
, sd
, target
, retargetcount
))
1355 DLOG(L
<<"got referral for DS query"<<endl
);
1361 DLOG(L
<<Logger::Warning
<<"Found nothing in the by-name ANY, but let's try wildcards.."<<endl
);
1362 bool wereRetargeted(false), nodata(false);
1364 if(tryWildcard(p
, r
, sd
, target
, wildcard
, wereRetargeted
, nodata
)) {
1365 if(wereRetargeted
) {
1366 if(!retargetcount
) r
->qdomainwild
=wildcard
;
1371 makeNOError(p
, r
, target
, wildcard
, sd
, 2);
1375 else if(tryDNAME(p
, r
, sd
, target
)) {
1381 if (!(((p
->qtype
.getCode() == QType::CNAME
) || (p
->qtype
.getCode() == QType::ANY
)) && retargetcount
> 0))
1382 makeNXDomain(p
, r
, target
, wildcard
, sd
);
1389 for(auto& loopRR
: rrset
) {
1390 if(loopRR
.dr
.d_type
== QType::CNAME
) {
1391 r
->addRecord(loopRR
);
1392 target
= getRR
<CNAMERecordContent
>(loopRR
.dr
)->getTarget();
1399 bool haveRecords
= false;
1400 for(const auto& loopRR
: rrset
) {
1401 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
) {
1402 r
->addRecord(loopRR
);
1408 if(p
->qtype
.getCode() == QType::ANY
)
1409 completeANYRecords(p
, r
, sd
, target
);
1412 makeNOError(p
, r
, target
, DNSName(), sd
, 0);
1416 else if(weHaveUnauth
) {
1417 DLOG(L
<<"Have unauth data, so need to hunt for best NS records"<<endl
);
1418 if(tryReferral(p
, r
, sd
, target
, retargetcount
))
1420 // check whether this could be fixed easily
1421 // if (*(rr.dr.d_name.rbegin()) == '.') {
1422 // 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;
1424 L
<<Logger::Error
<<"Should not get here ("<<p
->qdomain
<<"|"<<p
->qtype
.getCode()<<"): please run pdnsutil rectify-zone "<<sd
.qname
<<endl
;
1428 DLOG(L
<<"Have some data, but not the right data"<<endl
);
1429 makeNOError(p
, r
, target
, DNSName(), sd
, 0);
1433 if(doAdditionalProcessingAndDropAA(p
, r
, sd
, retargetcount
)<0) {
1438 for(const auto& loopRR
: r
->getRRS()) {
1439 if(loopRR
.scopeMask
) {
1445 addRRSigs(d_dk
, B
, authSet
, r
->getRRS());
1447 r
->wrapup(); // needed for inserting in cache
1448 if(!noCache
&& p
->couldBeCached())
1449 PC
.insert(p
, r
, r
->getMinTTL()); // in the packet cache
1451 catch(DBException
&e
) {
1452 L
<<Logger::Error
<<"Backend reported condition which prevented lookup ("+e
.reason
+") sending out servfail"<<endl
;
1454 r
=p
->replyPacket(); // generate an empty reply packet
1455 r
->setRcode(RCode::ServFail
);
1456 S
.inc("servfail-packets");
1457 S
.ringAccount("servfail-queries",p
->qdomain
.toLogString());
1459 catch(PDNSException
&e
) {
1460 L
<<Logger::Error
<<"Backend reported permanent error which prevented lookup ("+e
.reason
+"), aborting"<<endl
;
1461 throw; // we WANT to die at this point
1463 catch(std::exception
&e
) {
1464 L
<<Logger::Error
<<"Exception building answer packet for "<<p
->qdomain
<<"/"<<p
->qtype
.getName()<<" ("<<e
.what()<<") sending out servfail"<<endl
;
1466 r
=p
->replyPacket(); // generate an empty reply packet
1467 r
->setRcode(RCode::ServFail
);
1468 S
.inc("servfail-packets");
1469 S
.ringAccount("servfail-queries",p
->qdomain
.toLogString());