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(g_log
<<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(g_log
<<"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;
359 #ifdef HAVE_LUA_RECORDS
360 bool doLua
=g_doLuaRecord
;
363 d_dk
.getFromMeta(sd
.qname
, "ENABLE-LUA-RECORDS", val
);
369 while( subdomain
.chopOff() && !haveSomething
) {
370 if (subdomain
.empty()) {
371 B
.lookup(QType(QType::ANY
), g_wildcarddnsname
, p
, sd
.domain_id
);
373 B
.lookup(QType(QType::ANY
), g_wildcarddnsname
+subdomain
, p
, sd
.domain_id
);
376 #ifdef HAVE_LUA_RECORDS
377 if(rr
.dr
.d_type
== QType::LUA
) {
379 DLOG(g_log
<<"Have a wildcard LUA match, but not doing LUA record for this zone"<<endl
);
383 DLOG(g_log
<<"Have a wildcard LUA match"<<endl
);
385 auto rec
=getRR
<LUARecordContent
>(rr
.dr
);
389 if(rec
->d_type
== QType::CNAME
|| rec
->d_type
== p
->qtype
.getCode() || (p
->qtype
.getCode() == QType::ANY
&& rec
->d_type
!= QType::RRSIG
)) {
391 DLOG(g_log
<<"Executing Lua: '"<<rec
->getCode()<<"'"<<endl
);
392 auto recvec
=luaSynth(rec
->getCode(), target
, sd
.qname
, sd
.domain_id
, *p
, rec
->d_type
);
393 for(const auto& r
: recvec
) {
394 rr
.dr
.d_type
= rec
->d_type
; // might be CNAME
396 rr
.scopeMask
= p
->getRealRemote().getBits(); // this makes sure answer is a specific as your question
403 if(rr
.dr
.d_type
== p
->qtype
.getCode() || rr
.dr
.d_type
== QType::CNAME
|| (p
->qtype
.getCode() == QType::ANY
&& rr
.dr
.d_type
!= QType::RRSIG
)) {
407 wildcard
=g_wildcarddnsname
+subdomain
;
411 if ( subdomain
== sd
.qname
|| haveSomething
) // stop at SOA or result
414 B
.lookup(QType(QType::ANY
), subdomain
, p
, sd
.domain_id
);
416 DLOG(g_log
<<"No wildcard match, ancestor exists"<<endl
);
423 return haveSomething
;
426 /** dangling is declared true if we were unable to resolve everything */
427 int PacketHandler::doAdditionalProcessingAndDropAA(DNSPacket
*p
, DNSPacket
*r
, const SOAData
& soadata
, bool retargeted
)
433 if(p
->qtype
.getCode()!=QType::AXFR
) { // this packet needs additional processing
434 // we now have a copy, push_back on packet might reallocate!
435 auto& records
= r
->getRRS();
436 vector
<DNSZoneRecord
> toAdd
;
438 for(auto i
= records
.cbegin() ; i
!= records
.cend(); ++i
) {
439 if(i
->dr
.d_place
==DNSResourceRecord::ADDITIONAL
||
440 !(i
->dr
.d_type
==QType::MX
|| i
->dr
.d_type
==QType::NS
|| i
->dr
.d_type
==QType::SRV
))
443 if(r
->d
.aa
&& i
->dr
.d_name
.countLabels() && i
->dr
.d_type
==QType::NS
&& !B
.getSOA(i
->dr
.d_name
,sd
) && !retargeted
) { // drop AA in case of non-SOA-level NS answer, except for root referral
445 // i->d_place=DNSResourceRecord::AUTHORITY; // XXX FIXME
450 if(i
->dr
.d_type
== QType::MX
)
451 lookup
= getRR
<MXRecordContent
>(i
->dr
)->d_mxname
;
452 else if(i
->dr
.d_type
== QType::SRV
)
453 lookup
= getRR
<SRVRecordContent
>(i
->dr
)->d_target
;
454 else if(i
->dr
.d_type
== QType::NS
)
455 lookup
= getRR
<NSRecordContent
>(i
->dr
)->getNS();
459 B
.lookup(QType(d_doIPv6AdditionalProcessing
? QType::ANY
: QType::A
), lookup
, p
, soadata
.domain_id
);
462 if(rr
.dr
.d_type
!= QType::A
&& rr
.dr
.d_type
!=QType::AAAA
)
464 if(!rr
.dr
.d_name
.isPartOf(soadata
.qname
)) {
465 // FIXME we might still pass on the record if it is occluded and the
466 // backend uses a single id for all zones
469 rr
.dr
.d_place
=DNSResourceRecord::ADDITIONAL
;
473 for(const auto& rec
: toAdd
)
476 //records.insert(records.end(), toAdd.cbegin(), toAdd.cend()); // would be faster, but no dedup
482 void PacketHandler::emitNSEC(DNSPacket
*r
, const SOAData
& sd
, const DNSName
& name
, const DNSName
& next
, int mode
)
484 NSECRecordContent nrc
;
487 nrc
.set(QType::NSEC
);
488 nrc
.set(QType::RRSIG
);
489 if(sd
.qname
== name
) {
490 nrc
.set(QType::SOA
); // 1dfd8ad SOA can live outside the records table
491 nrc
.set(QType::DNSKEY
);
492 string publishCDNSKEY
;
493 d_dk
.getFromMeta(name
, "PUBLISH-CDNSKEY", publishCDNSKEY
);
494 if (publishCDNSKEY
== "1")
495 nrc
.set(QType::CDNSKEY
);
497 d_dk
.getFromMeta(name
, "PUBLISH-CDS", publishCDS
);
498 if (! publishCDS
.empty())
504 B
.lookup(QType(QType::ANY
), name
, NULL
, sd
.domain_id
);
506 #ifdef HAVE_LUA_RECORDS
507 if(rr
.dr
.d_type
== QType::LUA
)
508 nrc
.set(getRR
<LUARecordContent
>(rr
.dr
)->d_type
);
511 if(rr
.dr
.d_type
== QType::NS
|| rr
.auth
)
512 nrc
.set(rr
.dr
.d_type
);
516 rr
.dr
.d_ttl
= sd
.default_ttl
;
517 rr
.dr
.d_type
= QType::NSEC
;
518 rr
.dr
.d_content
= std::make_shared
<NSECRecordContent
>(std::move(nrc
));
519 rr
.dr
.d_place
= (mode
== 5 ) ? DNSResourceRecord::ANSWER
: DNSResourceRecord::AUTHORITY
;
525 void PacketHandler::emitNSEC3(DNSPacket
*r
, const SOAData
& sd
, const NSEC3PARAMRecordContent
& ns3prc
, const DNSName
& name
, const string
& namehash
, const string
& nexthash
, int mode
)
527 NSEC3RecordContent n3rc
;
528 n3rc
.d_algorithm
= ns3prc
.d_algorithm
;
529 n3rc
.d_flags
= ns3prc
.d_flags
;
530 n3rc
.d_iterations
= ns3prc
.d_iterations
;
531 n3rc
.d_salt
= ns3prc
.d_salt
;
532 n3rc
.d_nexthash
= nexthash
;
537 if (sd
.qname
== name
) {
538 n3rc
.set(QType::SOA
); // 1dfd8ad SOA can live outside the records table
539 n3rc
.set(QType::NSEC3PARAM
);
540 n3rc
.set(QType::DNSKEY
);
541 string publishCDNSKEY
;
542 d_dk
.getFromMeta(name
, "PUBLISH-CDNSKEY", publishCDNSKEY
);
543 if (publishCDNSKEY
== "1")
544 n3rc
.set(QType::CDNSKEY
);
546 d_dk
.getFromMeta(name
, "PUBLISH-CDS", publishCDS
);
547 if (! publishCDS
.empty())
548 n3rc
.set(QType::CDS
);
551 B
.lookup(QType(QType::ANY
), name
, NULL
, sd
.domain_id
);
553 #ifdef HAVE_LUA_RECORDS
554 if(rr
.dr
.d_type
== QType::LUA
)
555 n3rc
.set(getRR
<LUARecordContent
>(rr
.dr
)->d_type
);
558 if(rr
.dr
.d_type
&& (rr
.dr
.d_type
== QType::NS
|| rr
.auth
)) // skip empty non-terminals
559 n3rc
.set(rr
.dr
.d_type
);
563 const auto numberOfTypesSet
= n3rc
.numberOfTypesSet();
564 if (numberOfTypesSet
!= 0 && !(numberOfTypesSet
== 1 && n3rc
.isSet(QType::NS
))) {
565 n3rc
.set(QType::RRSIG
);
568 rr
.dr
.d_name
= DNSName(toBase32Hex(namehash
))+sd
.qname
;
569 rr
.dr
.d_ttl
= sd
.default_ttl
;
570 rr
.dr
.d_type
=QType::NSEC3
;
571 rr
.dr
.d_content
=std::make_shared
<NSEC3RecordContent
>(std::move(n3rc
));
572 rr
.dr
.d_place
= (mode
== 5 ) ? DNSResourceRecord::ANSWER
: DNSResourceRecord::AUTHORITY
;
579 mode 0 = No Data Responses, QTYPE is not DS
580 mode 1 = No Data Responses, QTYPE is DS
581 mode 2 = Wildcard No Data Responses
582 mode 3 = Wildcard Answer Responses
583 mode 4 = Name Error Responses
584 mode 5 = Direct NSEC request
586 void PacketHandler::addNSECX(DNSPacket
*p
, DNSPacket
*r
, const DNSName
& target
, const DNSName
& wildcard
, const DNSName
& auth
, int mode
)
588 if(!p
->d_dnssecOk
&& mode
!= 5)
591 NSEC3PARAMRecordContent ns3rc
;
593 if(d_dk
.getNSEC3PARAM(auth
, &ns3rc
, &narrow
)) {
594 if (mode
!= 5) // no direct NSEC3 queries, rfc5155 7.2.8
595 addNSEC3(p
, r
, target
, wildcard
, auth
, ns3rc
, narrow
, mode
);
598 addNSEC(p
, r
, target
, wildcard
, auth
, mode
);
602 bool getNSEC3Hashes(bool narrow
, DNSBackend
* db
, int id
, const std::string
& hashed
, bool decrement
, DNSName
& unhashed
, std::string
& before
, std::string
& after
, int mode
)
605 if(narrow
) { // nsec3-narrow
609 decrementHash(before
);
613 incrementHash(after
);
616 DNSName hashedName
= DNSName(toBase32Hex(hashed
));
617 DNSName beforeName
, afterName
;
618 if (!decrement
&& mode
>= 2)
619 beforeName
= hashedName
;
620 ret
=db
->getBeforeAndAfterNamesAbsolute(id
, hashedName
, unhashed
, beforeName
, afterName
);
621 before
=fromBase32Hex(beforeName
.toString());
622 after
=fromBase32Hex(afterName
.toString());
627 void PacketHandler::addNSEC3(DNSPacket
*p
, DNSPacket
*r
, const DNSName
& target
, const DNSName
& wildcard
, const DNSName
& auth
, const NSEC3PARAMRecordContent
& ns3rc
, bool narrow
, int mode
)
629 DLOG(g_log
<<"addNSEC3() mode="<<mode
<<" auth="<<auth
<<" target="<<target
<<" wildcard="<<wildcard
<<endl
);
632 if(!B
.getSOAUncached(auth
, sd
)) {
633 DLOG(g_log
<<"Could not get SOA for domain");
637 bool doNextcloser
= false;
638 string before
, after
, hashed
;
639 DNSName unhashed
, closest
;
641 if (mode
== 2 || mode
== 3 || mode
== 4) {
647 // add matching NSEC3 RR
649 unhashed
=(mode
== 0 || mode
== 1 || mode
== 5) ? target
: closest
;
650 hashed
=hashQNameWithSalt(ns3rc
, unhashed
);
651 DLOG(g_log
<<"1 hash: "<<toBase32Hex(hashed
)<<" "<<unhashed
<<endl
);
653 getNSEC3Hashes(narrow
, sd
.db
, sd
.domain_id
, hashed
, false, unhashed
, before
, after
, mode
);
655 if (((mode
== 0 && ns3rc
.d_flags
) || mode
== 1) && (hashed
!= before
)) {
656 DLOG(g_log
<<"No matching NSEC3, do closest (provable) encloser"<<endl
);
658 bool doBreak
= false;
660 while( closest
.chopOff() && (closest
!= sd
.qname
)) { // stop at SOA
661 B
.lookup(QType(QType::ANY
), closest
, p
, sd
.domain_id
);
670 hashed
=hashQNameWithSalt(ns3rc
, unhashed
);
671 DLOG(g_log
<<"1 hash: "<<toBase32Hex(hashed
)<<" "<<unhashed
<<endl
);
673 getNSEC3Hashes(narrow
, sd
.db
, sd
.domain_id
, hashed
, false, unhashed
, before
, after
);
676 if (!after
.empty()) {
677 DLOG(g_log
<<"Done calling for matching, hashed: '"<<toBase32Hex(hashed
)<<"' before='"<<toBase32Hex(before
)<<"', after='"<<toBase32Hex(after
)<<"'"<<endl
);
678 emitNSEC3(r
, sd
, ns3rc
, unhashed
, before
, after
, mode
);
682 // add covering NSEC3 RR
683 if ((mode
>= 2 && mode
<= 4) || doNextcloser
) {
684 DNSName
next(target
);
688 while( next
.chopOff() && !(next
==closest
));
690 hashed
=hashQNameWithSalt(ns3rc
, unhashed
);
691 DLOG(g_log
<<"2 hash: "<<toBase32Hex(hashed
)<<" "<<unhashed
<<endl
);
693 getNSEC3Hashes(narrow
, sd
.db
,sd
.domain_id
, hashed
, true, unhashed
, before
, after
);
694 DLOG(g_log
<<"Done calling for covering, hashed: '"<<toBase32Hex(hashed
)<<"' before='"<<toBase32Hex(before
)<<"', after='"<<toBase32Hex(after
)<<"'"<<endl
);
695 emitNSEC3( r
, sd
, ns3rc
, unhashed
, before
, after
, mode
);
699 if (mode
== 2 || mode
== 4) {
700 unhashed
=g_wildcarddnsname
+closest
;
702 hashed
=hashQNameWithSalt(ns3rc
, unhashed
);
703 DLOG(g_log
<<"3 hash: "<<toBase32Hex(hashed
)<<" "<<unhashed
<<endl
);
705 getNSEC3Hashes(narrow
, sd
.db
, sd
.domain_id
, hashed
, (mode
!= 2), unhashed
, before
, after
);
706 DLOG(g_log
<<"Done calling for '*', hashed: '"<<toBase32Hex(hashed
)<<"' before='"<<toBase32Hex(before
)<<"', after='"<<toBase32Hex(after
)<<"'"<<endl
);
707 emitNSEC3( r
, sd
, ns3rc
, unhashed
, before
, after
, mode
);
711 void PacketHandler::addNSEC(DNSPacket
*p
, DNSPacket
*r
, const DNSName
& target
, const DNSName
& wildcard
, const DNSName
& auth
, int mode
)
713 DLOG(g_log
<<"addNSEC() mode="<<mode
<<" auth="<<auth
<<" target="<<target
<<" wildcard="<<wildcard
<<endl
);
716 if(!B
.getSOAUncached(auth
, sd
)) {
717 DLOG(g_log
<<"Could not get SOA for domain"<<endl
);
721 DNSName before
,after
;
722 sd
.db
->getBeforeAndAfterNames(sd
.domain_id
, auth
, target
, before
, after
);
723 if (mode
!= 5 || before
== target
)
724 emitNSEC(r
, sd
, before
, after
, mode
);
726 if (mode
== 2 || mode
== 4) {
727 // wildcard NO-DATA or wildcard denial
729 DNSName
closest(wildcard
);
732 closest
.prependRawLabel("*");
734 sd
.db
->getBeforeAndAfterNames(sd
.domain_id
, auth
, closest
, before
, after
);
735 emitNSEC(r
, sd
, before
, after
, mode
);
742 - only one backend owns the SOA of a zone
743 - only one AXFR per zone at a time - double startTransaction should fail
744 - backends need to implement transaction semantics
747 How BindBackend would implement this:
748 startTransaction makes a file
749 feedRecord sends everything to that file
750 commitTransaction moves that file atomically over the regular file, and triggers a reload
751 rollbackTransaction removes the file
754 How PostgreSQLBackend would implement this:
755 startTransaction starts a sql transaction, which also deletes all records
756 feedRecord is an insert statement
757 commitTransaction commits the transaction
758 rollbackTransaction aborts it
760 How MySQLBackend would implement this:
765 int PacketHandler::trySuperMaster(DNSPacket
*p
, const DNSName
& tsigkeyname
)
769 // do it right now if the client is TCP
771 return trySuperMasterSynchronous(p
, tsigkeyname
);
775 // queue it if the client is on UDP
776 Communicator
.addTrySuperMasterRequest(p
);
781 int PacketHandler::trySuperMasterSynchronous(const DNSPacket
*p
, const DNSName
& tsigkeyname
)
783 ComboAddress remote
= p
->getRemote().setPort(53);
784 if(p
->hasEDNSSubnet() && ::arg().contains("trusted-notification-proxy", remote
.toString())) {
785 remote
= p
->getRealRemote().getNetwork();
788 Resolver::res_t nsset
;
791 uint32_t theirserial
;
792 resolver
.getSoaSerial(remote
, p
->qdomain
, &theirserial
);
793 resolver
.resolve(remote
, p
->qdomain
, QType::NS
, &nsset
);
795 catch(ResolverException
&re
) {
796 g_log
<<Logger::Error
<<"Error resolving SOA or NS for "<<p
->qdomain
<<" at: "<< remote
<<": "<<re
.reason
<<endl
;
797 return RCode::ServFail
;
800 // check if the returned records are NS records
802 for(const auto& ns
: nsset
) {
803 if(ns
.qtype
==QType::NS
)
808 g_log
<<Logger::Error
<<"While checking for supermaster, did not find NS for "<<p
->qdomain
<<" at: "<< remote
<<endl
;
809 return RCode::ServFail
;
812 string nameserver
, account
;
815 if (!::arg().mustDo("allow-unsigned-supermaster") && tsigkeyname
.empty()) {
816 g_log
<<Logger::Error
<<"Received unsigned NOTIFY for "<<p
->qdomain
<<" from potential supermaster "<<remote
<<". Refusing."<<endl
;
817 return RCode::Refused
;
820 if(!B
.superMasterBackend(remote
.toString(), p
->qdomain
, nsset
, &nameserver
, &account
, &db
)) {
821 g_log
<<Logger::Error
<<"Unable to find backend willing to host "<<p
->qdomain
<<" for potential supermaster "<<remote
<<". Remote nameservers: "<<endl
;
822 for(const auto& rr
: nsset
) {
823 if(rr
.qtype
==QType::NS
)
824 g_log
<<Logger::Error
<<rr
.content
<<endl
;
826 return RCode::Refused
;
829 db
->createSlaveDomain(p
->getRemote().toString(), p
->qdomain
, nameserver
, account
);
830 if (tsigkeyname
.empty() == false) {
832 meta
.push_back(tsigkeyname
.toStringNoDot());
833 db
->setDomainMetadata(p
->qdomain
, "AXFR-MASTER-TSIG", meta
);
836 catch(PDNSException
& ae
) {
837 g_log
<<Logger::Error
<<"Database error trying to create "<<p
->qdomain
<<" for potential supermaster "<<remote
<<": "<<ae
.reason
<<endl
;
838 return RCode::ServFail
;
840 g_log
<<Logger::Warning
<<"Created new slave zone '"<<p
->qdomain
<<"' from supermaster "<<remote
<<endl
;
841 return RCode::NoError
;
844 int PacketHandler::processNotify(DNSPacket
*p
)
847 was this notification from an approved address?
848 was this notification approved by TSIG?
849 We determine our internal SOA id (via UeberBackend)
850 We determine the SOA at our (known) master
851 if master is higher -> do stuff
854 g_log
<<Logger::Debug
<<"Received NOTIFY for "<<p
->qdomain
<<" from "<<p
->getRemote()<<endl
;
856 if(!::arg().mustDo("slave") && s_forwardNotify
.empty()) {
857 g_log
<<Logger::Warning
<<"Received NOTIFY for "<<p
->qdomain
<<" from "<<p
->getRemote()<<" but slave support is disabled in the configuration"<<endl
;
858 return RCode::Refused
;
861 // Sender verification
863 if(!s_allowNotifyFrom
.match((ComboAddress
*) &p
->d_remote
) || p
->d_havetsig
) {
864 if (p
->d_havetsig
&& p
->getTSIGKeyname().empty() == false) {
865 g_log
<<Logger::Notice
<<"Received secure NOTIFY for "<<p
->qdomain
<<" from "<<p
->getRemote()<<", with TSIG key '"<<p
->getTSIGKeyname()<<"'"<<endl
;
867 g_log
<<Logger::Warning
<<"Received NOTIFY for "<<p
->qdomain
<<" from "<<p
->getRemote()<<" but the remote is not providing a TSIG key or in allow-notify-from (Refused)"<<endl
;
868 return RCode::Refused
;
872 if ((!::arg().mustDo("allow-unsigned-notify") && !p
->d_havetsig
) || p
->d_havetsig
) {
873 if (!p
->d_havetsig
) {
874 g_log
<<Logger::Warning
<<"Received unsigned NOTIFY for "<<p
->qdomain
<<" from "<<p
->getRemote()<<" while a TSIG key was required (Refused)"<<endl
;
875 return RCode::Refused
;
878 if (B
.getDomainMetadata(p
->qdomain
,"AXFR-MASTER-TSIG",meta
) && meta
.size() > 0) {
879 if (!pdns_iequals(meta
[0], p
->getTSIGKeyname().toStringNoDot())) {
880 g_log
<<Logger::Warning
<<"Received secure NOTIFY for "<<p
->qdomain
<<" from "<<p
->getRemote()<<": expected TSIG key '"<<meta
[0]<<", got '"<<p
->getTSIGKeyname()<<"' (Refused)"<<endl
;
881 return RCode::Refused
;
886 // Domain verification
889 if(!B
.getDomainInfo(p
->qdomain
, di
, false) || !di
.backend
) {
890 if(::arg().mustDo("supermaster")) {
891 g_log
<<Logger::Warning
<<"Received NOTIFY for "<<p
->qdomain
<<" from "<<p
->getRemote()<<" for which we are not authoritative, trying supermaster"<<endl
;
892 return trySuperMaster(p
, p
->getTSIGKeyname());
894 g_log
<<Logger::Notice
<<"Received NOTIFY for "<<p
->qdomain
<<" from "<<p
->getRemote()<<" for which we are not authoritative (Refused)"<<endl
;
895 return RCode::Refused
;
898 if(::arg().contains("trusted-notification-proxy", p
->getRemote().toString())) {
899 g_log
<<Logger::Error
<<"Received NOTIFY for "<<p
->qdomain
<<" from trusted-notification-proxy "<< p
->getRemote()<<endl
;
900 if(di
.masters
.empty()) {
901 g_log
<<Logger::Error
<<"However, "<<p
->qdomain
<<" does not have any masters defined (Refused)"<<endl
;
902 return RCode::Refused
;
905 else if(::arg().mustDo("master") && di
.kind
== DomainInfo::Master
) {
906 g_log
<<Logger::Warning
<<"Received NOTIFY for "<<p
->qdomain
<<" from "<<p
->getRemote()<<" but we are master (Refused)"<<endl
;
907 return RCode::Refused
;
909 else if(!di
.isMaster(p
->getRemote())) {
910 g_log
<<Logger::Warning
<<"Received NOTIFY for "<<p
->qdomain
<<" from "<<p
->getRemote()<<" which is not a master (Refused)"<<endl
;
911 return RCode::Refused
;
914 if(!s_forwardNotify
.empty()) {
915 set
<string
> forwardNotify(s_forwardNotify
);
916 for(set
<string
>::const_iterator j
=forwardNotify
.begin();j
!=forwardNotify
.end();++j
) {
917 g_log
<<Logger::Notice
<<"Relaying notification of domain "<<p
->qdomain
<<" from "<<p
->getRemote()<<" to "<<*j
<<endl
;
918 Communicator
.notify(p
->qdomain
,*j
);
922 if(::arg().mustDo("slave")) {
923 g_log
<<Logger::Debug
<<"Queueing slave check for "<<p
->qdomain
<<endl
;
924 Communicator
.addSlaveCheckRequest(di
, p
->d_remote
);
929 bool validDNSName(const DNSName
&name
)
932 string::size_type pos
, length
;
934 for(const auto& s
: name
.getRawLabels()) {
936 for(pos
=0; pos
< length
; ++pos
) {
938 if(!((c
>= 'a' && c
<= 'z') ||
939 (c
>= 'A' && c
<= 'Z') ||
940 (c
>= '0' && c
<= '9') ||
941 c
=='-' || c
== '_' || c
=='*' || c
=='.' || c
=='/' || c
=='@' || c
==' ' || c
=='\\' || c
==':'))
949 DNSPacket
*PacketHandler::question(DNSPacket
*p
)
955 ret
=d_pdl
->prequery(p
);
961 static AtomicCounter
&rdqueries
=*S
.getPointer("rd-queries");
965 return doQuestion(p
);
969 void PacketHandler::makeNXDomain(DNSPacket
* p
, DNSPacket
* r
, const DNSName
& target
, const DNSName
& wildcard
, SOAData
& sd
)
972 rr
.dr
.d_name
=sd
.qname
;
973 rr
.dr
.d_type
=QType::SOA
;
975 rr
.dr
.d_content
=makeSOAContent(sd
);
976 rr
.dr
.d_ttl
=min(sd
.ttl
, sd
.default_ttl
);
978 rr
.domain_id
=sd
.domain_id
;
979 rr
.dr
.d_place
=DNSResourceRecord::AUTHORITY
;
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
, p
->qtype
);
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 for(auto& rr
: rrset
) {
1031 rr
.dr
.d_place
=DNSResourceRecord::AUTHORITY
;
1037 if(d_dk
.isSecuredZone(sd
.qname
) && !addDSforNS(p
, r
, sd
, rrset
.begin()->dr
.d_name
))
1038 addNSECX(p
, r
, rrset
.begin()->dr
.d_name
, DNSName(), sd
.qname
, 1);
1043 void PacketHandler::completeANYRecords(DNSPacket
*p
, DNSPacket
*r
, SOAData
& sd
, const DNSName
&target
)
1046 return; // Don't send dnssec info to non validating resolvers.
1048 if(!d_dk
.isSecuredZone(sd
.qname
))
1051 addNSECX(p
, r
, target
, DNSName(), sd
.qname
, 5);
1052 if(sd
.qname
== p
->qdomain
) {
1053 addDNSKEY(p
, r
, sd
);
1054 addCDNSKEY(p
, r
, sd
);
1056 addNSEC3PARAM(p
, r
, sd
);
1060 bool PacketHandler::tryDNAME(DNSPacket
*p
, DNSPacket
*r
, SOAData
& sd
, DNSName
&target
)
1064 DLOG(g_log
<<Logger::Warning
<<"Let's try DNAME.."<<endl
);
1065 vector
<DNSZoneRecord
> rrset
= getBestDNAMESynth(p
, sd
, target
);
1066 if(!rrset
.empty()) {
1067 for(auto& rr
: rrset
) {
1068 rr
.dr
.d_place
= DNSResourceRecord::ANSWER
;
1075 bool PacketHandler::tryWildcard(DNSPacket
*p
, DNSPacket
*r
, SOAData
& sd
, DNSName
&target
, DNSName
&wildcard
, bool& retargeted
, bool& nodata
)
1077 retargeted
= nodata
= false;
1080 vector
<DNSZoneRecord
> rrset
;
1081 if(!getBestWildcard(p
, sd
, target
, wildcard
, &rrset
))
1085 DLOG(g_log
<<"Wildcard matched something, but not of the correct type"<<endl
);
1089 for(auto& rr
: rrset
) {
1090 rr
.wildcardname
= rr
.dr
.d_name
;
1091 rr
.dr
.d_name
=bestmatch
=target
;
1093 if(rr
.dr
.d_type
== QType::CNAME
) {
1095 target
=getRR
<CNAMERecordContent
>(rr
.dr
)->getTarget();
1098 rr
.dr
.d_place
=DNSResourceRecord::ANSWER
;
1102 if(d_dk
.isSecuredZone(sd
.qname
) && !nodata
) {
1103 addNSECX(p
, r
, bestmatch
, wildcard
, sd
.qname
, 3);
1108 //! Called by the Distributor to ask a question. Returns 0 in case of an error
1109 DNSPacket
*PacketHandler::doQuestion(DNSPacket
*p
)
1114 int retargetcount
=0;
1115 set
<DNSName
> authSet
;
1117 vector
<DNSZoneRecord
> rrset
;
1118 bool weDone
=0, weRedirected
=0, weHaveUnauth
=0;
1120 uint8_t aliasScopeMask
;
1125 #ifdef HAVE_LUA_RECORDS
1126 bool doLua
=g_doLuaRecord
;
1129 if(p
->d
.qr
) { // QR bit from dns packet (thanks RA from N)
1131 g_log
<<Logger::Error
<<"Received an answer (non-query) packet from "<<p
->getRemote()<<", dropping"<<endl
;
1132 S
.inc("corrupt-packets");
1133 S
.ringAccount("remotes-corrupt", p
->d_remote
);
1137 if(p
->d
.tc
) { // truncated query. MOADNSParser would silently parse this packet in an incomplete way.
1139 g_log
<<Logger::Error
<<"Received truncated query packet from "<<p
->getRemote()<<", dropping"<<endl
;
1140 S
.inc("corrupt-packets");
1141 S
.ringAccount("remotes-corrupt", p
->d_remote
);
1145 if (p
->hasEDNS() && p
->getEDNSVersion() > 0) {
1146 r
= p
->replyPacket();
1148 // PacketWriter::addOpt will take care of setting this correctly in the packet
1149 r
->setEDNSRcode(ERCode::BADVERS
);
1156 TSIGRecordContent trc
;
1157 if(!p
->checkForCorrectTSIG(&B
, &keyname
, &secret
, &trc
)) {
1158 r
=p
->replyPacket(); // generate an empty reply packet
1160 g_log
<<Logger::Error
<<"Received a TSIG signed message with a non-validating key"<<endl
;
1161 // RFC3007 describes that a non-secure message should be sending Refused for DNS Updates
1162 if (p
->d
.opcode
== Opcode::Update
)
1163 r
->setRcode(RCode::Refused
);
1165 r
->setRcode(RCode::NotAuth
);
1168 getTSIGHashEnum(trc
.d_algoName
, p
->d_tsig_algo
);
1169 if (p
->d_tsig_algo
== TSIG_GSS
) {
1170 GssContext
gssctx(keyname
);
1171 if (!gssctx
.getPeerPrincipal(p
->d_peer_principal
)) {
1172 g_log
<<Logger::Warning
<<"Failed to extract peer principal from GSS context with keyname '"<<keyname
<<"'"<<endl
;
1176 p
->setTSIGDetails(trc
, keyname
, secret
, trc
.d_mac
); // this will get copied by replyPacket()
1180 r
=p
->replyPacket(); // generate an empty reply packet, possibly with TSIG details inside
1182 if (p
->qtype
== QType::TKEY
) {
1183 this->tkeyHandler(p
, r
);
1189 // XXX FIXME do this in DNSPacket::parse ?
1191 if(!validDNSName(p
->qdomain
)) {
1193 g_log
<<Logger::Error
<<"Received a malformed qdomain from "<<p
->getRemote()<<", '"<<p
->qdomain
<<"': sending servfail"<<endl
;
1194 S
.inc("corrupt-packets");
1195 S
.ringAccount("remotes-corrupt", p
->d_remote
);
1196 S
.inc("servfail-packets");
1197 r
->setRcode(RCode::ServFail
);
1200 if(p
->d
.opcode
) { // non-zero opcode (again thanks RA!)
1201 if(p
->d
.opcode
==Opcode::Update
) {
1202 S
.inc("dnsupdate-queries");
1203 int res
=processUpdate(p
);
1204 if (res
== RCode::Refused
)
1205 S
.inc("dnsupdate-refused");
1206 else if (res
!= RCode::ServFail
)
1207 S
.inc("dnsupdate-answers");
1209 r
->setOpcode(Opcode::Update
);
1212 else if(p
->d
.opcode
==Opcode::Notify
) {
1213 S
.inc("incoming-notifications");
1214 int res
=processNotify(p
);
1217 r
->setOpcode(Opcode::Notify
);
1224 g_log
<<Logger::Error
<<"Received an unknown opcode "<<p
->d
.opcode
<<" from "<<p
->getRemote()<<" for "<<p
->qdomain
<<endl
;
1226 r
->setRcode(RCode::NotImp
);
1230 // g_log<<Logger::Warning<<"Query for '"<<p->qdomain<<"' "<<p->qtype.getName()<<" from "<<p->getRemote()<< " (tcp="<<p->d_tcp<<")"<<endl;
1232 if(p
->qtype
.getCode()==QType::IXFR
) {
1233 r
->setRcode(RCode::Refused
);
1237 DNSName target
=p
->qdomain
;
1239 // catch chaos qclass requests
1240 if(p
->qclass
== QClass::CHAOS
) {
1241 if (doChaosRequest(p
,r
,target
))
1247 // we only know about qclass IN (and ANY), send Refused for everything else.
1248 if(p
->qclass
!= QClass::IN
&& p
->qclass
!=QClass::ANY
) {
1249 r
->setRcode(RCode::Refused
);
1253 // send TC for udp ANY query if any-to-tcp is enabled.
1254 if(p
->qtype
.getCode() == QType::ANY
&& !p
->d_tcp
&& g_anyToTcp
) {
1260 // for qclass ANY the response should never be authoritative unless the response covers all classes.
1261 if(p
->qclass
==QClass::ANY
)
1266 if(retargetcount
> 10) { // XXX FIXME, retargetcount++?
1267 g_log
<<Logger::Warning
<<"Abort CNAME chain resolution after "<<--retargetcount
<<" redirects, sending out servfail. Initial query: '"<<p
->qdomain
<<"'"<<endl
;
1270 r
->setRcode(RCode::ServFail
);
1274 if(!B
.getAuth(target
, p
->qtype
, &sd
)) {
1275 DLOG(g_log
<<Logger::Error
<<"We have no authority over zone '"<<target
<<"'"<<endl
);
1276 if(!retargetcount
) {
1277 r
->setA(false); // drop AA if we never had a SOA in the first place
1278 r
->setRcode(RCode::Refused
); // send REFUSED - but only on empty 'no idea'
1282 DLOG(g_log
<<Logger::Error
<<"We have authority, zone='"<<sd
.qname
<<"', id="<<sd
.domain_id
<<endl
);
1283 authSet
.insert(sd
.qname
);
1285 if(!retargetcount
) r
->qdomainzone
=sd
.qname
;
1287 if(sd
.qname
==p
->qdomain
) {
1288 if(p
->qtype
.getCode() == QType::DNSKEY
)
1290 if(addDNSKEY(p
, r
, sd
))
1293 else if(p
->qtype
.getCode() == QType::CDNSKEY
)
1295 if(addCDNSKEY(p
,r
, sd
))
1298 else if(p
->qtype
.getCode() == QType::CDS
)
1303 else if(p
->qtype
.getCode() == QType::NSEC3PARAM
&& d_dk
.isSecuredZone(sd
.qname
))
1305 if(addNSEC3PARAM(p
,r
, sd
))
1310 if(p
->qtype
.getCode() == QType::SOA
&& sd
.qname
==p
->qdomain
) {
1311 rr
.dr
.d_name
=sd
.qname
;
1312 rr
.dr
.d_type
=QType::SOA
;
1313 sd
.serial
= calculateEditSOA(sd
.serial
, d_dk
, sd
.qname
);
1314 rr
.dr
.d_content
=makeSOAContent(sd
);
1316 rr
.domain_id
=sd
.domain_id
;
1317 rr
.dr
.d_place
=DNSResourceRecord::ANSWER
;
1323 // this TRUMPS a cname!
1324 if(p
->qtype
.getCode() == QType::NSEC
&& d_dk
.isSecuredZone(sd
.qname
) && !d_dk
.getNSEC3PARAM(sd
.qname
, 0)) {
1325 addNSEC(p
, r
, target
, DNSName(), sd
.qname
, 5);
1330 // this TRUMPS a cname!
1331 if(p
->qtype
.getCode() == QType::RRSIG
) {
1332 g_log
<<Logger::Info
<<"Direct RRSIG query for "<<target
<<" from "<<p
->getRemote()<<endl
;
1333 r
->setRcode(RCode::Refused
);
1337 DLOG(g_log
<<"Checking for referrals first, unless this is a DS query"<<endl
);
1338 if(p
->qtype
.getCode() != QType::DS
&& tryReferral(p
, r
, sd
, target
, retargetcount
))
1341 DLOG(g_log
<<"Got no referrals, trying ANY"<<endl
);
1343 #ifdef HAVE_LUA_RECORDS
1346 d_dk
.getFromMeta(sd
.qname
, "ENABLE-LUA-RECORDS", val
);
1351 // see what we get..
1352 B
.lookup(QType(QType::ANY
), target
, p
, sd
.domain_id
);
1354 haveAlias
.trimToLabels(0);
1356 weDone
= weRedirected
= weHaveUnauth
= false;
1359 #ifdef HAVE_LUA_RECORDS
1360 if(rr
.dr
.d_type
== QType::LUA
) {
1363 auto rec
=getRR
<LUARecordContent
>(rr
.dr
);
1367 if(rec
->d_type
== QType::CNAME
|| rec
->d_type
== p
->qtype
.getCode() || (p
->qtype
.getCode() == QType::ANY
&& rec
->d_type
!= QType::RRSIG
)) {
1370 auto recvec
=luaSynth(rec
->getCode(), target
, sd
.qname
, sd
.domain_id
, *p
, rec
->d_type
);
1371 if(!recvec
.empty()) {
1372 for(const auto& r
: recvec
) {
1373 rr
.dr
.d_type
= rec
->d_type
; // might be CNAME
1374 rr
.dr
.d_content
= r
;
1375 rr
.scopeMask
= p
->getRealRemote().getBits(); // this makes sure answer is a specific as your question
1376 rrset
.push_back(rr
);
1378 if(rec
->d_type
== QType::CNAME
&& p
->qtype
.getCode() != QType::CNAME
)
1384 catch(std::exception
&e
) {
1386 r
->setRcode(RCode::ServFail
);
1393 //cerr<<"got content: ["<<rr.content<<"]"<<endl;
1394 if (p
->qtype
.getCode() == QType::ANY
&& !p
->d_dnssecOk
&& (rr
.dr
.d_type
== QType:: DNSKEY
|| rr
.dr
.d_type
== QType::NSEC3PARAM
))
1395 continue; // Don't send dnssec info to non validating resolvers.
1396 if (rr
.dr
.d_type
== QType::RRSIG
) // RRSIGS are added later any way.
1397 continue; // TODO: this actually means addRRSig should check if the RRSig is already there
1399 // cerr<<"Auth: "<<rr.auth<<", "<<(rr.dr.d_type == p->qtype)<<", "<<rr.dr.d_type.getName()<<endl;
1400 if((p
->qtype
.getCode() == QType::ANY
|| rr
.dr
.d_type
== p
->qtype
.getCode()) && rr
.auth
)
1402 // the line below fakes 'unauth NS' for delegations for non-DNSSEC backends.
1403 if((rr
.dr
.d_type
== p
->qtype
.getCode() && !rr
.auth
) || (rr
.dr
.d_type
== QType::NS
&& (!rr
.auth
|| !(sd
.qname
==rr
.dr
.d_name
))))
1406 if(rr
.dr
.d_type
== QType::CNAME
&& p
->qtype
.getCode() != QType::CNAME
)
1409 if(DP
&& rr
.dr
.d_type
== QType::ALIAS
&& (p
->qtype
.getCode() == QType::A
|| p
->qtype
.getCode() == QType::AAAA
|| p
->qtype
.getCode() == QType::ANY
)) {
1410 if (!d_doExpandALIAS
) {
1411 g_log
<<Logger::Info
<<"ALIAS record found for "<<target
<<", but ALIAS expansion is disabled."<<endl
;
1414 haveAlias
=getRR
<ALIASRecordContent
>(rr
.dr
)->d_content
;
1415 aliasScopeMask
=rr
.scopeMask
;
1418 // Filter out all SOA's and add them in later
1419 if(rr
.dr
.d_type
== QType::SOA
)
1422 rrset
.push_back(rr
);
1425 /* Add in SOA if required */
1426 if(target
==sd
.qname
) {
1427 rr
.dr
.d_name
= sd
.qname
;
1428 rr
.dr
.d_type
= QType::SOA
;
1429 sd
.serial
= calculateEditSOA(sd
.serial
, d_dk
, sd
.qname
);
1430 rr
.dr
.d_content
= makeSOAContent(sd
);
1431 rr
.dr
.d_ttl
= sd
.ttl
;
1432 rr
.domain_id
= sd
.domain_id
;
1434 rrset
.push_back(rr
);
1438 DLOG(g_log
<<"After first ANY query for '"<<target
<<"', id="<<sd
.domain_id
<<": weDone="<<weDone
<<", weHaveUnauth="<<weHaveUnauth
<<", weRedirected="<<weRedirected
<<", haveAlias='"<<haveAlias
<<"'"<<endl
);
1439 if(p
->qtype
.getCode() == QType::DS
&& weHaveUnauth
&& !weDone
&& !weRedirected
) {
1440 DLOG(g_log
<<"Q for DS of a name for which we do have NS, but for which we don't have DS; need to provide an AUTH answer that shows we don't"<<endl
);
1441 makeNOError(p
, r
, target
, DNSName(), sd
, 1);
1445 if(!haveAlias
.empty() && (!weDone
|| p
->qtype
.getCode() == QType::ANY
)) {
1446 DLOG(g_log
<<Logger::Warning
<<"Found nothing that matched for '"<<target
<<"', but did get alias to '"<<haveAlias
<<"', referring"<<endl
);
1447 DP
->completePacket(r
, haveAlias
, target
, aliasScopeMask
);
1452 DLOG(g_log
<<"checking if qtype is DS"<<endl
);
1453 if(p
->qtype
.getCode() == QType::DS
)
1455 DLOG(g_log
<<"DS query found no direct result, trying referral now"<<endl
);
1456 if(tryReferral(p
, r
, sd
, target
, retargetcount
))
1458 DLOG(g_log
<<"got referral for DS query"<<endl
);
1464 DLOG(g_log
<<Logger::Warning
<<"Found nothing in the by-name ANY, but let's try wildcards.."<<endl
);
1465 bool wereRetargeted(false), nodata(false);
1467 if(tryWildcard(p
, r
, sd
, target
, wildcard
, wereRetargeted
, nodata
)) {
1468 if(wereRetargeted
) {
1469 if(!retargetcount
) r
->qdomainwild
=wildcard
;
1474 makeNOError(p
, r
, target
, wildcard
, sd
, 2);
1478 else if(tryDNAME(p
, r
, sd
, target
)) {
1484 if (!(((p
->qtype
.getCode() == QType::CNAME
) || (p
->qtype
.getCode() == QType::ANY
)) && retargetcount
> 0))
1485 makeNXDomain(p
, r
, target
, wildcard
, sd
);
1492 for(auto& loopRR
: rrset
) {
1493 if(loopRR
.dr
.d_type
== QType::CNAME
) {
1494 r
->addRecord(loopRR
);
1495 target
= getRR
<CNAMERecordContent
>(loopRR
.dr
)->getTarget();
1502 bool haveRecords
= false;
1503 for(const auto& loopRR
: rrset
) {
1504 #ifdef HAVE_LUA_RECORDS
1505 if(loopRR
.dr
.d_type
== QType::LUA
)
1508 if((p
->qtype
.getCode() == QType::ANY
|| loopRR
.dr
.d_type
== p
->qtype
.getCode()) && loopRR
.dr
.d_type
&& loopRR
.dr
.d_type
!= QType::ALIAS
&& loopRR
.auth
) {
1509 r
->addRecord(loopRR
);
1515 if(p
->qtype
.getCode() == QType::ANY
)
1516 completeANYRecords(p
, r
, sd
, target
);
1519 makeNOError(p
, r
, target
, DNSName(), sd
, 0);
1523 else if(weHaveUnauth
) {
1524 DLOG(g_log
<<"Have unauth data, so need to hunt for best NS records"<<endl
);
1525 if(tryReferral(p
, r
, sd
, target
, retargetcount
))
1527 // check whether this could be fixed easily
1528 // if (*(rr.dr.d_name.rbegin()) == '.') {
1529 // g_log<<Logger::Error<<"Should not get here ("<<p->qdomain<<"|"<<p->qtype.getCode()<<"): you have a trailing dot, this could be the problem (or run pdnsutil rectify-zone " <<sd.qname<<")"<<endl;
1531 g_log
<<Logger::Error
<<"Should not get here ("<<p
->qdomain
<<"|"<<p
->qtype
.getCode()<<"): please run pdnsutil rectify-zone "<<sd
.qname
<<endl
;
1535 DLOG(g_log
<<"Have some data, but not the right data"<<endl
);
1536 makeNOError(p
, r
, target
, DNSName(), sd
, 0);
1540 if(doAdditionalProcessingAndDropAA(p
, r
, sd
, retargetcount
)<0) {
1545 for(const auto& loopRR
: r
->getRRS()) {
1546 if(loopRR
.scopeMask
) {
1552 addRRSigs(d_dk
, B
, authSet
, r
->getRRS());
1554 r
->wrapup(); // needed for inserting in cache
1555 if(!noCache
&& p
->couldBeCached())
1556 PC
.insert(p
, r
, r
->getMinTTL()); // in the packet cache
1558 catch(DBException
&e
) {
1559 g_log
<<Logger::Error
<<"Backend reported condition which prevented lookup ("+e
.reason
+") sending out servfail"<<endl
;
1561 r
=p
->replyPacket(); // generate an empty reply packet
1562 r
->setRcode(RCode::ServFail
);
1563 S
.inc("servfail-packets");
1564 S
.ringAccount("servfail-queries", p
->qdomain
, p
->qtype
);
1566 catch(PDNSException
&e
) {
1567 g_log
<<Logger::Error
<<"Backend reported permanent error which prevented lookup ("+e
.reason
+"), aborting"<<endl
;
1568 throw; // we WANT to die at this point
1570 catch(std::exception
&e
) {
1571 g_log
<<Logger::Error
<<"Exception building answer packet for "<<p
->qdomain
<<"/"<<p
->qtype
.getName()<<" ("<<e
.what()<<") sending out servfail"<<endl
;
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
);