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
)->getTarget()));
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 NSEC3PARAMRecordContent ns3rc
;
590 if(d_dk
.getNSEC3PARAM(auth
, &ns3rc
, &narrow
)) {
591 if (mode
!= 5) // no direct NSEC3 queries, rfc5155 7.2.8
592 addNSEC3(p
, r
, target
, wildcard
, auth
, ns3rc
, narrow
, mode
);
595 addNSEC(p
, r
, target
, wildcard
, auth
, mode
);
599 bool getNSEC3Hashes(bool narrow
, DNSBackend
* db
, int id
, const std::string
& hashed
, bool decrement
, DNSName
& unhashed
, std::string
& before
, std::string
& after
, int mode
)
602 if(narrow
) { // nsec3-narrow
606 decrementHash(before
);
610 incrementHash(after
);
613 DNSName hashedName
= DNSName(toBase32Hex(hashed
));
614 DNSName beforeName
, afterName
;
615 if (!decrement
&& mode
>= 2)
616 beforeName
= hashedName
;
617 ret
=db
->getBeforeAndAfterNamesAbsolute(id
, hashedName
, unhashed
, beforeName
, afterName
);
618 before
=fromBase32Hex(beforeName
.toString());
619 after
=fromBase32Hex(afterName
.toString());
624 void PacketHandler::addNSEC3(DNSPacket
*p
, DNSPacket
*r
, const DNSName
& target
, const DNSName
& wildcard
, const DNSName
& auth
, const NSEC3PARAMRecordContent
& ns3rc
, bool narrow
, int mode
)
626 DLOG(g_log
<<"addNSEC3() mode="<<mode
<<" auth="<<auth
<<" target="<<target
<<" wildcard="<<wildcard
<<endl
);
629 if(!B
.getSOAUncached(auth
, sd
)) {
630 DLOG(g_log
<<"Could not get SOA for domain");
634 bool doNextcloser
= false;
635 string before
, after
, hashed
;
636 DNSName unhashed
, closest
;
638 if (mode
== 2 || mode
== 3 || mode
== 4) {
644 // add matching NSEC3 RR
646 unhashed
=(mode
== 0 || mode
== 1 || mode
== 5) ? target
: closest
;
647 hashed
=hashQNameWithSalt(ns3rc
, unhashed
);
648 DLOG(g_log
<<"1 hash: "<<toBase32Hex(hashed
)<<" "<<unhashed
<<endl
);
650 getNSEC3Hashes(narrow
, sd
.db
, sd
.domain_id
, hashed
, false, unhashed
, before
, after
, mode
);
652 if (((mode
== 0 && ns3rc
.d_flags
) || mode
== 1) && (hashed
!= before
)) {
653 DLOG(g_log
<<"No matching NSEC3, do closest (provable) encloser"<<endl
);
655 bool doBreak
= false;
657 while( closest
.chopOff() && (closest
!= sd
.qname
)) { // stop at SOA
658 B
.lookup(QType(QType::ANY
), closest
, p
, sd
.domain_id
);
667 hashed
=hashQNameWithSalt(ns3rc
, unhashed
);
668 DLOG(g_log
<<"1 hash: "<<toBase32Hex(hashed
)<<" "<<unhashed
<<endl
);
670 getNSEC3Hashes(narrow
, sd
.db
, sd
.domain_id
, hashed
, false, unhashed
, before
, after
);
673 if (!after
.empty()) {
674 DLOG(g_log
<<"Done calling for matching, hashed: '"<<toBase32Hex(hashed
)<<"' before='"<<toBase32Hex(before
)<<"', after='"<<toBase32Hex(after
)<<"'"<<endl
);
675 emitNSEC3(r
, sd
, ns3rc
, unhashed
, before
, after
, mode
);
679 // add covering NSEC3 RR
680 if ((mode
>= 2 && mode
<= 4) || doNextcloser
) {
681 DNSName
next(target
);
685 while( next
.chopOff() && !(next
==closest
));
687 hashed
=hashQNameWithSalt(ns3rc
, unhashed
);
688 DLOG(g_log
<<"2 hash: "<<toBase32Hex(hashed
)<<" "<<unhashed
<<endl
);
690 getNSEC3Hashes(narrow
, sd
.db
,sd
.domain_id
, hashed
, true, unhashed
, before
, after
);
691 DLOG(g_log
<<"Done calling for covering, hashed: '"<<toBase32Hex(hashed
)<<"' before='"<<toBase32Hex(before
)<<"', after='"<<toBase32Hex(after
)<<"'"<<endl
);
692 emitNSEC3( r
, sd
, ns3rc
, unhashed
, before
, after
, mode
);
696 if (mode
== 2 || mode
== 4) {
697 unhashed
=g_wildcarddnsname
+closest
;
699 hashed
=hashQNameWithSalt(ns3rc
, unhashed
);
700 DLOG(g_log
<<"3 hash: "<<toBase32Hex(hashed
)<<" "<<unhashed
<<endl
);
702 getNSEC3Hashes(narrow
, sd
.db
, sd
.domain_id
, hashed
, (mode
!= 2), unhashed
, before
, after
);
703 DLOG(g_log
<<"Done calling for '*', hashed: '"<<toBase32Hex(hashed
)<<"' before='"<<toBase32Hex(before
)<<"', after='"<<toBase32Hex(after
)<<"'"<<endl
);
704 emitNSEC3( r
, sd
, ns3rc
, unhashed
, before
, after
, mode
);
708 void PacketHandler::addNSEC(DNSPacket
*p
, DNSPacket
*r
, const DNSName
& target
, const DNSName
& wildcard
, const DNSName
& auth
, int mode
)
710 DLOG(g_log
<<"addNSEC() mode="<<mode
<<" auth="<<auth
<<" target="<<target
<<" wildcard="<<wildcard
<<endl
);
713 if(!B
.getSOAUncached(auth
, sd
)) {
714 DLOG(g_log
<<"Could not get SOA for domain"<<endl
);
718 DNSName before
,after
;
719 sd
.db
->getBeforeAndAfterNames(sd
.domain_id
, auth
, target
, before
, after
);
720 if (mode
!= 5 || before
== target
)
721 emitNSEC(r
, sd
, before
, after
, mode
);
723 if (mode
== 2 || mode
== 4) {
724 // wildcard NO-DATA or wildcard denial
726 DNSName
closest(wildcard
);
729 closest
.prependRawLabel("*");
731 sd
.db
->getBeforeAndAfterNames(sd
.domain_id
, auth
, closest
, before
, after
);
732 emitNSEC(r
, sd
, before
, after
, mode
);
739 - only one backend owns the SOA of a zone
740 - only one AXFR per zone at a time - double startTransaction should fail
741 - backends need to implement transaction semantics
744 How BindBackend would implement this:
745 startTransaction makes a file
746 feedRecord sends everything to that file
747 commitTransaction moves that file atomically over the regular file, and triggers a reload
748 rollbackTransaction removes the file
751 How PostgreSQLBackend would implement this:
752 startTransaction starts a sql transaction, which also deletes all records
753 feedRecord is an insert statement
754 commitTransaction commits the transaction
755 rollbackTransaction aborts it
757 How MySQLBackend would implement this:
762 int PacketHandler::trySuperMaster(DNSPacket
*p
, const DNSName
& tsigkeyname
)
766 // do it right now if the client is TCP
768 return trySuperMasterSynchronous(p
, tsigkeyname
);
772 // queue it if the client is on UDP
773 Communicator
.addTrySuperMasterRequest(p
);
778 int PacketHandler::trySuperMasterSynchronous(const DNSPacket
*p
, const DNSName
& tsigkeyname
)
780 ComboAddress remote
= p
->getRemote().setPort(53);
781 if(p
->hasEDNSSubnet() && ::arg().contains("trusted-notification-proxy", remote
.toString())) {
782 remote
= p
->getRealRemote().getNetwork();
785 Resolver::res_t nsset
;
788 uint32_t theirserial
;
789 resolver
.getSoaSerial(remote
, p
->qdomain
, &theirserial
);
790 resolver
.resolve(remote
, p
->qdomain
, QType::NS
, &nsset
);
792 catch(ResolverException
&re
) {
793 g_log
<<Logger::Error
<<"Error resolving SOA or NS for "<<p
->qdomain
<<" at: "<< remote
<<": "<<re
.reason
<<endl
;
794 return RCode::ServFail
;
797 // check if the returned records are NS records
799 for(const auto& ns
: nsset
) {
800 if(ns
.qtype
==QType::NS
)
805 g_log
<<Logger::Error
<<"While checking for supermaster, did not find NS for "<<p
->qdomain
<<" at: "<< remote
<<endl
;
806 return RCode::ServFail
;
809 string nameserver
, account
;
812 if (!::arg().mustDo("allow-unsigned-supermaster") && tsigkeyname
.empty()) {
813 g_log
<<Logger::Error
<<"Received unsigned NOTIFY for "<<p
->qdomain
<<" from potential supermaster "<<remote
<<". Refusing."<<endl
;
814 return RCode::Refused
;
817 if(!B
.superMasterBackend(remote
.toString(), p
->qdomain
, nsset
, &nameserver
, &account
, &db
)) {
818 g_log
<<Logger::Error
<<"Unable to find backend willing to host "<<p
->qdomain
<<" for potential supermaster "<<remote
<<". Remote nameservers: "<<endl
;
819 for(const auto& rr
: nsset
) {
820 if(rr
.qtype
==QType::NS
)
821 g_log
<<Logger::Error
<<rr
.content
<<endl
;
823 return RCode::Refused
;
826 db
->createSlaveDomain(p
->getRemote().toString(), p
->qdomain
, nameserver
, account
);
827 if (tsigkeyname
.empty() == false) {
829 meta
.push_back(tsigkeyname
.toStringNoDot());
830 db
->setDomainMetadata(p
->qdomain
, "AXFR-MASTER-TSIG", meta
);
833 catch(PDNSException
& ae
) {
834 g_log
<<Logger::Error
<<"Database error trying to create "<<p
->qdomain
<<" for potential supermaster "<<remote
<<": "<<ae
.reason
<<endl
;
835 return RCode::ServFail
;
837 g_log
<<Logger::Warning
<<"Created new slave zone '"<<p
->qdomain
<<"' from supermaster "<<remote
<<endl
;
838 return RCode::NoError
;
841 int PacketHandler::processNotify(DNSPacket
*p
)
844 was this notification from an approved address?
845 was this notification approved by TSIG?
846 We determine our internal SOA id (via UeberBackend)
847 We determine the SOA at our (known) master
848 if master is higher -> do stuff
851 g_log
<<Logger::Debug
<<"Received NOTIFY for "<<p
->qdomain
<<" from "<<p
->getRemote()<<endl
;
853 if(!::arg().mustDo("slave") && s_forwardNotify
.empty()) {
854 g_log
<<Logger::Warning
<<"Received NOTIFY for "<<p
->qdomain
<<" from "<<p
->getRemote()<<" but slave support is disabled in the configuration"<<endl
;
855 return RCode::Refused
;
858 // Sender verification
860 if(!s_allowNotifyFrom
.match((ComboAddress
*) &p
->d_remote
) || p
->d_havetsig
) {
861 if (p
->d_havetsig
&& p
->getTSIGKeyname().empty() == false) {
862 g_log
<<Logger::Notice
<<"Received secure NOTIFY for "<<p
->qdomain
<<" from "<<p
->getRemote()<<", with TSIG key '"<<p
->getTSIGKeyname()<<"'"<<endl
;
864 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
;
865 return RCode::Refused
;
869 if ((!::arg().mustDo("allow-unsigned-notify") && !p
->d_havetsig
) || p
->d_havetsig
) {
870 if (!p
->d_havetsig
) {
871 g_log
<<Logger::Warning
<<"Received unsigned NOTIFY for "<<p
->qdomain
<<" from "<<p
->getRemote()<<" while a TSIG key was required (Refused)"<<endl
;
872 return RCode::Refused
;
875 if (B
.getDomainMetadata(p
->qdomain
,"AXFR-MASTER-TSIG",meta
) && meta
.size() > 0) {
876 DNSName expected
{meta
[0]};
877 if (p
->getTSIGKeyname() != expected
) {
878 g_log
<<Logger::Warning
<<"Received secure NOTIFY for "<<p
->qdomain
<<" from "<<p
->getRemote()<<": expected TSIG key '"<<expected
<<"', got '"<<p
->getTSIGKeyname()<<"' (Refused)"<<endl
;
879 return RCode::Refused
;
884 // Domain verification
887 if(!B
.getDomainInfo(p
->qdomain
, di
, false) || !di
.backend
) {
888 if(::arg().mustDo("superslave")) {
889 g_log
<<Logger::Warning
<<"Received NOTIFY for "<<p
->qdomain
<<" from "<<p
->getRemote()<<" for which we are not authoritative, trying supermaster"<<endl
;
890 return trySuperMaster(p
, p
->getTSIGKeyname());
892 g_log
<<Logger::Notice
<<"Received NOTIFY for "<<p
->qdomain
<<" from "<<p
->getRemote()<<" for which we are not authoritative (Refused)"<<endl
;
893 return RCode::Refused
;
896 if(::arg().contains("trusted-notification-proxy", p
->getRemote().toString())) {
897 g_log
<<Logger::Error
<<"Received NOTIFY for "<<p
->qdomain
<<" from trusted-notification-proxy "<< p
->getRemote()<<endl
;
898 if(di
.masters
.empty()) {
899 g_log
<<Logger::Error
<<"However, "<<p
->qdomain
<<" does not have any masters defined (Refused)"<<endl
;
900 return RCode::Refused
;
903 else if(::arg().mustDo("master") && di
.kind
== DomainInfo::Master
) {
904 g_log
<<Logger::Warning
<<"Received NOTIFY for "<<p
->qdomain
<<" from "<<p
->getRemote()<<" but we are master (Refused)"<<endl
;
905 return RCode::Refused
;
907 else if(!di
.isMaster(p
->getRemote())) {
908 g_log
<<Logger::Warning
<<"Received NOTIFY for "<<p
->qdomain
<<" from "<<p
->getRemote()<<" which is not a master (Refused)"<<endl
;
909 return RCode::Refused
;
912 if(!s_forwardNotify
.empty()) {
913 set
<string
> forwardNotify(s_forwardNotify
);
914 for(set
<string
>::const_iterator j
=forwardNotify
.begin();j
!=forwardNotify
.end();++j
) {
915 g_log
<<Logger::Notice
<<"Relaying notification of domain "<<p
->qdomain
<<" from "<<p
->getRemote()<<" to "<<*j
<<endl
;
916 Communicator
.notify(p
->qdomain
,*j
);
920 if(::arg().mustDo("slave")) {
921 g_log
<<Logger::Debug
<<"Queueing slave check for "<<p
->qdomain
<<endl
;
922 Communicator
.addSlaveCheckRequest(di
, p
->d_remote
);
927 bool validDNSName(const DNSName
&name
)
930 string::size_type pos
, length
;
932 for(const auto& s
: name
.getRawLabels()) {
934 for(pos
=0; pos
< length
; ++pos
) {
936 if(!((c
>= 'a' && c
<= 'z') ||
937 (c
>= 'A' && c
<= 'Z') ||
938 (c
>= '0' && c
<= '9') ||
939 c
=='-' || c
== '_' || c
=='*' || c
=='.' || c
=='/' || c
=='@' || c
==' ' || c
=='\\' || c
==':'))
947 DNSPacket
*PacketHandler::question(DNSPacket
*p
)
953 ret
=d_pdl
->prequery(p
);
959 static AtomicCounter
&rdqueries
=*S
.getPointer("rd-queries");
963 return doQuestion(p
);
967 void PacketHandler::makeNXDomain(DNSPacket
* p
, DNSPacket
* r
, const DNSName
& target
, const DNSName
& wildcard
, const SOAData
& sd
)
970 rr
=makeEditedDNSZRFromSOAData(d_dk
, sd
, DNSResourceRecord::AUTHORITY
);
971 rr
.dr
.d_ttl
=min(sd
.ttl
, sd
.default_ttl
);
975 addNSECX(p
, r
, target
, wildcard
, sd
.qname
, 4);
978 r
->setRcode(RCode::NXDomain
);
981 void PacketHandler::makeNOError(DNSPacket
* p
, DNSPacket
* r
, const DNSName
& target
, const DNSName
& wildcard
, const SOAData
& sd
, int mode
)
984 rr
=makeEditedDNSZRFromSOAData(d_dk
, sd
, DNSResourceRecord::AUTHORITY
);
985 rr
.dr
.d_ttl
=min(sd
.ttl
, sd
.default_ttl
);
989 addNSECX(p
, r
, target
, wildcard
, sd
.qname
, mode
);
992 S
.ringAccount("noerror-queries", p
->qdomain
, p
->qtype
);
996 bool PacketHandler::addDSforNS(DNSPacket
* p
, DNSPacket
* r
, SOAData
& sd
, const DNSName
& dsname
)
998 //cerr<<"Trying to find a DS for '"<<dsname<<"', domain_id = "<<sd.domain_id<<endl;
999 B
.lookup(QType(QType::DS
), dsname
, p
, sd
.domain_id
);
1004 rr
.dr
.d_place
= DNSResourceRecord::AUTHORITY
;
1010 bool PacketHandler::tryReferral(DNSPacket
*p
, DNSPacket
*r
, SOAData
& sd
, const DNSName
&target
, bool retargeted
)
1012 vector
<DNSZoneRecord
> rrset
= getBestReferralNS(p
, sd
, target
);
1016 for(auto& rr
: rrset
) {
1017 rr
.dr
.d_place
=DNSResourceRecord::AUTHORITY
;
1023 if(d_dk
.isSecuredZone(sd
.qname
) && !addDSforNS(p
, r
, sd
, rrset
.begin()->dr
.d_name
) && d_dnssec
) {
1024 addNSECX(p
, r
, rrset
.begin()->dr
.d_name
, DNSName(), sd
.qname
, 1);
1030 void PacketHandler::completeANYRecords(DNSPacket
*p
, DNSPacket
*r
, SOAData
& sd
, const DNSName
&target
)
1032 addNSECX(p
, r
, target
, DNSName(), sd
.qname
, 5);
1033 if(sd
.qname
== p
->qdomain
) {
1034 addDNSKEY(p
, r
, sd
);
1035 addCDNSKEY(p
, r
, sd
);
1037 addNSEC3PARAM(p
, r
, sd
);
1041 bool PacketHandler::tryDNAME(DNSPacket
*p
, DNSPacket
*r
, SOAData
& sd
, DNSName
&target
)
1045 DLOG(g_log
<<Logger::Warning
<<"Let's try DNAME.."<<endl
);
1046 vector
<DNSZoneRecord
> rrset
= getBestDNAMESynth(p
, sd
, target
);
1047 if(!rrset
.empty()) {
1048 for(auto& rr
: rrset
) {
1049 rr
.dr
.d_place
= DNSResourceRecord::ANSWER
;
1056 bool PacketHandler::tryWildcard(DNSPacket
*p
, DNSPacket
*r
, SOAData
& sd
, DNSName
&target
, DNSName
&wildcard
, bool& retargeted
, bool& nodata
)
1058 retargeted
= nodata
= false;
1061 vector
<DNSZoneRecord
> rrset
;
1062 if(!getBestWildcard(p
, sd
, target
, wildcard
, &rrset
))
1066 DLOG(g_log
<<"Wildcard matched something, but not of the correct type"<<endl
);
1070 for(auto& rr
: rrset
) {
1071 rr
.wildcardname
= rr
.dr
.d_name
;
1072 rr
.dr
.d_name
=bestmatch
=target
;
1074 if(rr
.dr
.d_type
== QType::CNAME
) {
1076 target
=getRR
<CNAMERecordContent
>(rr
.dr
)->getTarget();
1079 rr
.dr
.d_place
=DNSResourceRecord::ANSWER
;
1083 if(d_dnssec
&& !nodata
) {
1084 addNSECX(p
, r
, bestmatch
, wildcard
, sd
.qname
, 3);
1090 //! Called by the Distributor to ask a question. Returns 0 in case of an error
1091 DNSPacket
*PacketHandler::doQuestion(DNSPacket
*p
)
1096 int retargetcount
=0;
1097 set
<DNSName
> authSet
;
1099 vector
<DNSZoneRecord
> rrset
;
1100 bool weDone
=0, weRedirected
=0, weHaveUnauth
=0, doSigs
=0;
1102 uint8_t aliasScopeMask
;
1104 DNSPacket
*r
=nullptr;
1107 #ifdef HAVE_LUA_RECORDS
1108 bool doLua
=g_doLuaRecord
;
1111 if(p
->d
.qr
) { // QR bit from dns packet (thanks RA from N)
1113 g_log
<<Logger::Error
<<"Received an answer (non-query) packet from "<<p
->getRemote()<<", dropping"<<endl
;
1114 S
.inc("corrupt-packets");
1115 S
.ringAccount("remotes-corrupt", p
->d_remote
);
1119 if(p
->d
.tc
) { // truncated query. MOADNSParser would silently parse this packet in an incomplete way.
1121 g_log
<<Logger::Error
<<"Received truncated query packet from "<<p
->getRemote()<<", dropping"<<endl
;
1122 S
.inc("corrupt-packets");
1123 S
.ringAccount("remotes-corrupt", p
->d_remote
);
1127 if (p
->hasEDNS() && p
->getEDNSVersion() > 0) {
1128 r
= p
->replyPacket();
1130 // PacketWriter::addOpt will take care of setting this correctly in the packet
1131 r
->setEDNSRcode(ERCode::BADVERS
);
1138 TSIGRecordContent trc
;
1139 if(!p
->checkForCorrectTSIG(&B
, &keyname
, &secret
, &trc
)) {
1140 r
=p
->replyPacket(); // generate an empty reply packet
1142 g_log
<<Logger::Error
<<"Received a TSIG signed message with a non-validating key"<<endl
;
1143 // RFC3007 describes that a non-secure message should be sending Refused for DNS Updates
1144 if (p
->d
.opcode
== Opcode::Update
)
1145 r
->setRcode(RCode::Refused
);
1147 r
->setRcode(RCode::NotAuth
);
1150 getTSIGHashEnum(trc
.d_algoName
, p
->d_tsig_algo
);
1151 if (p
->d_tsig_algo
== TSIG_GSS
) {
1152 GssContext
gssctx(keyname
);
1153 if (!gssctx
.getPeerPrincipal(p
->d_peer_principal
)) {
1154 g_log
<<Logger::Warning
<<"Failed to extract peer principal from GSS context with keyname '"<<keyname
<<"'"<<endl
;
1158 p
->setTSIGDetails(trc
, keyname
, secret
, trc
.d_mac
); // this will get copied by replyPacket()
1162 r
=p
->replyPacket(); // generate an empty reply packet, possibly with TSIG details inside
1164 if (p
->qtype
== QType::TKEY
) {
1165 this->tkeyHandler(p
, r
);
1171 // XXX FIXME do this in DNSPacket::parse ?
1173 if(!validDNSName(p
->qdomain
)) {
1175 g_log
<<Logger::Error
<<"Received a malformed qdomain from "<<p
->getRemote()<<", '"<<p
->qdomain
<<"': sending servfail"<<endl
;
1176 S
.inc("corrupt-packets");
1177 S
.ringAccount("remotes-corrupt", p
->d_remote
);
1178 S
.inc("servfail-packets");
1179 r
->setRcode(RCode::ServFail
);
1182 if(p
->d
.opcode
) { // non-zero opcode (again thanks RA!)
1183 if(p
->d
.opcode
==Opcode::Update
) {
1184 S
.inc("dnsupdate-queries");
1185 int res
=processUpdate(p
);
1186 if (res
== RCode::Refused
)
1187 S
.inc("dnsupdate-refused");
1188 else if (res
!= RCode::ServFail
)
1189 S
.inc("dnsupdate-answers");
1191 r
->setOpcode(Opcode::Update
);
1194 else if(p
->d
.opcode
==Opcode::Notify
) {
1195 S
.inc("incoming-notifications");
1196 int res
=processNotify(p
);
1199 r
->setOpcode(Opcode::Notify
);
1206 g_log
<<Logger::Error
<<"Received an unknown opcode "<<p
->d
.opcode
<<" from "<<p
->getRemote()<<" for "<<p
->qdomain
<<endl
;
1208 r
->setRcode(RCode::NotImp
);
1212 // g_log<<Logger::Warning<<"Query for '"<<p->qdomain<<"' "<<p->qtype.getName()<<" from "<<p->getRemote()<< " (tcp="<<p->d_tcp<<")"<<endl;
1214 if(p
->qtype
.getCode()==QType::IXFR
) {
1215 r
->setRcode(RCode::Refused
);
1219 DNSName target
=p
->qdomain
;
1221 // catch chaos qclass requests
1222 if(p
->qclass
== QClass::CHAOS
) {
1223 if (doChaosRequest(p
,r
,target
))
1229 // we only know about qclass IN (and ANY), send Refused for everything else.
1230 if(p
->qclass
!= QClass::IN
&& p
->qclass
!=QClass::ANY
) {
1231 r
->setRcode(RCode::Refused
);
1235 // send TC for udp ANY query if any-to-tcp is enabled.
1236 if(p
->qtype
.getCode() == QType::ANY
&& !p
->d_tcp
&& g_anyToTcp
) {
1242 // for qclass ANY the response should never be authoritative unless the response covers all classes.
1243 if(p
->qclass
==QClass::ANY
)
1248 if(retargetcount
> 10) { // XXX FIXME, retargetcount++?
1249 g_log
<<Logger::Warning
<<"Abort CNAME chain resolution after "<<--retargetcount
<<" redirects, sending out servfail. Initial query: '"<<p
->qdomain
<<"'"<<endl
;
1252 r
->setRcode(RCode::ServFail
);
1256 if(!B
.getAuth(target
, p
->qtype
, &sd
)) {
1257 DLOG(g_log
<<Logger::Error
<<"We have no authority over zone '"<<target
<<"'"<<endl
);
1258 if(!retargetcount
) {
1259 r
->setA(false); // drop AA if we never had a SOA in the first place
1260 r
->setRcode(RCode::Refused
); // send REFUSED - but only on empty 'no idea'
1264 DLOG(g_log
<<Logger::Error
<<"We have authority, zone='"<<sd
.qname
<<"', id="<<sd
.domain_id
<<endl
);
1266 authSet
.insert(sd
.qname
);
1267 d_dnssec
=(p
->d_dnssecOk
&& d_dk
.isSecuredZone(sd
.qname
));
1270 if(!retargetcount
) r
->qdomainzone
=sd
.qname
;
1272 if(sd
.qname
==p
->qdomain
) {
1273 if(p
->qtype
.getCode() == QType::DNSKEY
)
1275 if(addDNSKEY(p
, r
, sd
))
1278 else if(p
->qtype
.getCode() == QType::CDNSKEY
)
1280 if(addCDNSKEY(p
,r
, sd
))
1283 else if(p
->qtype
.getCode() == QType::CDS
)
1288 else if(d_dnssec
&& p
->qtype
.getCode() == QType::NSEC3PARAM
)
1290 if(addNSEC3PARAM(p
,r
, sd
))
1295 if(p
->qtype
.getCode() == QType::SOA
&& sd
.qname
==p
->qdomain
) {
1296 rr
=makeEditedDNSZRFromSOAData(d_dk
, sd
);
1301 // this TRUMPS a cname!
1302 if(d_dnssec
&& p
->qtype
.getCode() == QType::NSEC
&& !d_dk
.getNSEC3PARAM(sd
.qname
, 0)) {
1303 addNSEC(p
, r
, target
, DNSName(), sd
.qname
, 5);
1308 // this TRUMPS a cname!
1309 if(p
->qtype
.getCode() == QType::RRSIG
) {
1310 g_log
<<Logger::Info
<<"Direct RRSIG query for "<<target
<<" from "<<p
->getRemote()<<endl
;
1311 r
->setRcode(RCode::Refused
);
1315 DLOG(g_log
<<"Checking for referrals first, unless this is a DS query"<<endl
);
1316 if(p
->qtype
.getCode() != QType::DS
&& tryReferral(p
, r
, sd
, target
, retargetcount
))
1319 DLOG(g_log
<<"Got no referrals, trying ANY"<<endl
);
1321 #ifdef HAVE_LUA_RECORDS
1324 d_dk
.getFromMeta(sd
.qname
, "ENABLE-LUA-RECORDS", val
);
1329 // see what we get..
1330 B
.lookup(QType(QType::ANY
), target
, p
, sd
.domain_id
);
1332 haveAlias
.trimToLabels(0);
1334 weDone
= weRedirected
= weHaveUnauth
= false;
1337 #ifdef HAVE_LUA_RECORDS
1338 if(rr
.dr
.d_type
== QType::LUA
) {
1341 auto rec
=getRR
<LUARecordContent
>(rr
.dr
);
1345 if(rec
->d_type
== QType::CNAME
|| rec
->d_type
== p
->qtype
.getCode() || (p
->qtype
.getCode() == QType::ANY
&& rec
->d_type
!= QType::RRSIG
)) {
1348 auto recvec
=luaSynth(rec
->getCode(), target
, sd
.qname
, sd
.domain_id
, *p
, rec
->d_type
);
1349 if(!recvec
.empty()) {
1350 for(const auto& r
: recvec
) {
1351 rr
.dr
.d_type
= rec
->d_type
; // might be CNAME
1352 rr
.dr
.d_content
= r
;
1353 rr
.scopeMask
= p
->getRealRemote().getBits(); // this makes sure answer is a specific as your question
1354 rrset
.push_back(rr
);
1356 if(rec
->d_type
== QType::CNAME
&& p
->qtype
.getCode() != QType::CNAME
)
1362 catch(std::exception
&e
) {
1364 r
->setRcode(RCode::ServFail
);
1371 //cerr<<"got content: ["<<rr.content<<"]"<<endl;
1372 if (!d_dnssec
&& p
->qtype
.getCode() == QType::ANY
&& (rr
.dr
.d_type
== QType:: DNSKEY
|| rr
.dr
.d_type
== QType::NSEC3PARAM
))
1373 continue; // Don't send dnssec info.
1374 if (rr
.dr
.d_type
== QType::RRSIG
) // RRSIGS are added later any way.
1375 continue; // TODO: this actually means addRRSig should check if the RRSig is already there
1377 // cerr<<"Auth: "<<rr.auth<<", "<<(rr.dr.d_type == p->qtype)<<", "<<rr.dr.d_type.getName()<<endl;
1378 if((p
->qtype
.getCode() == QType::ANY
|| rr
.dr
.d_type
== p
->qtype
.getCode()) && rr
.auth
)
1380 // the line below fakes 'unauth NS' for delegations for non-DNSSEC backends.
1381 if((rr
.dr
.d_type
== p
->qtype
.getCode() && !rr
.auth
) || (rr
.dr
.d_type
== QType::NS
&& (!rr
.auth
|| !(sd
.qname
==rr
.dr
.d_name
))))
1384 if(rr
.dr
.d_type
== QType::CNAME
&& p
->qtype
.getCode() != QType::CNAME
)
1387 if(DP
&& rr
.dr
.d_type
== QType::ALIAS
&& (p
->qtype
.getCode() == QType::A
|| p
->qtype
.getCode() == QType::AAAA
|| p
->qtype
.getCode() == QType::ANY
)) {
1388 if (!d_doExpandALIAS
) {
1389 g_log
<<Logger::Info
<<"ALIAS record found for "<<target
<<", but ALIAS expansion is disabled."<<endl
;
1392 haveAlias
=getRR
<ALIASRecordContent
>(rr
.dr
)->d_content
;
1393 aliasScopeMask
=rr
.scopeMask
;
1396 // Filter out all SOA's and add them in later
1397 if(rr
.dr
.d_type
== QType::SOA
)
1400 rrset
.push_back(rr
);
1403 /* Add in SOA if required */
1404 if(target
==sd
.qname
) {
1405 rr
=makeEditedDNSZRFromSOAData(d_dk
, sd
);
1406 rrset
.push_back(rr
);
1410 DLOG(g_log
<<"After first ANY query for '"<<target
<<"', id="<<sd
.domain_id
<<": weDone="<<weDone
<<", weHaveUnauth="<<weHaveUnauth
<<", weRedirected="<<weRedirected
<<", haveAlias='"<<haveAlias
<<"'"<<endl
);
1411 if(p
->qtype
.getCode() == QType::DS
&& weHaveUnauth
&& !weDone
&& !weRedirected
) {
1412 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
);
1413 makeNOError(p
, r
, target
, DNSName(), sd
, 1);
1417 if(!haveAlias
.empty() && (!weDone
|| p
->qtype
.getCode() == QType::ANY
)) {
1418 DLOG(g_log
<<Logger::Warning
<<"Found nothing that matched for '"<<target
<<"', but did get alias to '"<<haveAlias
<<"', referring"<<endl
);
1419 DP
->completePacket(r
, haveAlias
, target
, aliasScopeMask
);
1424 // referral for DS query
1425 if(p
->qtype
.getCode() == QType::DS
) {
1426 DLOG(g_log
<<"Qtype is DS"<<endl
);
1427 bool doReferral
= true;
1428 if(d_dk
.doesDNSSEC()) {
1429 for(auto& loopRR
: rrset
) {
1430 // In a dnssec capable backend auth=true means, there is no delagation at
1431 // or above this qname in this zone (for DS queries). Without a delegation,
1432 // at or above this level, it is pointless to search for refferals.
1439 for(auto& loopRR
: rrset
) {
1440 // In a non dnssec capable backend auth is always true, so our only option
1441 // is, always look for referals. Unless there is a direct match for DS.
1442 if(loopRR
.dr
.d_type
== QType::DS
) {
1449 DLOG(g_log
<<"DS query found no direct result, trying referral now"<<endl
);
1450 if(tryReferral(p
, r
, sd
, target
, retargetcount
))
1452 DLOG(g_log
<<"Got referral for DS query"<<endl
);
1460 DLOG(g_log
<<Logger::Warning
<<"Found nothing in the by-name ANY, but let's try wildcards.."<<endl
);
1461 bool wereRetargeted(false), nodata(false);
1463 if(tryWildcard(p
, r
, sd
, target
, wildcard
, wereRetargeted
, nodata
)) {
1464 if(wereRetargeted
) {
1465 if(!retargetcount
) r
->qdomainwild
=wildcard
;
1470 makeNOError(p
, r
, target
, wildcard
, sd
, 2);
1474 else if(tryDNAME(p
, r
, sd
, target
)) {
1480 if (!(((p
->qtype
.getCode() == QType::CNAME
) || (p
->qtype
.getCode() == QType::ANY
)) && retargetcount
> 0))
1481 makeNXDomain(p
, r
, target
, wildcard
, sd
);
1488 for(auto& loopRR
: rrset
) {
1489 if(loopRR
.dr
.d_type
== QType::CNAME
) {
1490 r
->addRecord(loopRR
);
1491 target
= getRR
<CNAMERecordContent
>(loopRR
.dr
)->getTarget();
1498 bool haveRecords
= false;
1499 for(const auto& loopRR
: rrset
) {
1500 #ifdef HAVE_LUA_RECORDS
1501 if(loopRR
.dr
.d_type
== QType::LUA
)
1504 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
) {
1505 r
->addRecord(loopRR
);
1511 if(d_dnssec
&& p
->qtype
.getCode() == QType::ANY
)
1512 completeANYRecords(p
, r
, sd
, target
);
1515 makeNOError(p
, r
, target
, DNSName(), sd
, 0);
1519 else if(weHaveUnauth
) {
1520 DLOG(g_log
<<"Have unauth data, so need to hunt for best NS records"<<endl
);
1521 if(tryReferral(p
, r
, sd
, target
, retargetcount
))
1523 // check whether this could be fixed easily
1524 // if (*(rr.dr.d_name.rbegin()) == '.') {
1525 // 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;
1527 g_log
<<Logger::Error
<<"Should not get here ("<<p
->qdomain
<<"|"<<p
->qtype
.getCode()<<"): please run pdnsutil rectify-zone "<<sd
.qname
<<endl
;
1531 DLOG(g_log
<<"Have some data, but not the right data"<<endl
);
1532 makeNOError(p
, r
, target
, DNSName(), sd
, 0);
1536 if(doAdditionalProcessingAndDropAA(p
, r
, sd
, retargetcount
)<0) {
1541 for(const auto& loopRR
: r
->getRRS()) {
1542 if(loopRR
.scopeMask
) {
1548 addRRSigs(d_dk
, B
, authSet
, r
->getRRS());
1550 if(PC
.enabled() && !noCache
&& p
->couldBeCached())
1551 PC
.insert(p
, r
, r
->getMinTTL()); // in the packet cache
1553 catch(DBException
&e
) {
1554 g_log
<<Logger::Error
<<"Backend reported condition which prevented lookup ("+e
.reason
+") sending out servfail"<<endl
;
1556 r
=p
->replyPacket(); // generate an empty reply packet
1557 r
->setRcode(RCode::ServFail
);
1558 S
.inc("servfail-packets");
1559 S
.ringAccount("servfail-queries", p
->qdomain
, p
->qtype
);
1561 catch(PDNSException
&e
) {
1562 g_log
<<Logger::Error
<<"Backend reported permanent error which prevented lookup ("+e
.reason
+"), aborting"<<endl
;
1564 throw; // we WANT to die at this point
1566 catch(std::exception
&e
) {
1567 g_log
<<Logger::Error
<<"Exception building answer packet for "<<p
->qdomain
<<"/"<<p
->qtype
.getName()<<" ("<<e
.what()<<") sending out servfail"<<endl
;
1569 r
=p
->replyPacket(); // generate an empty reply packet
1570 r
->setRcode(RCode::ServFail
);
1571 S
.inc("servfail-packets");
1572 S
.ringAccount("servfail-queries", p
->qdomain
, p
->qtype
);