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
, std::unique_ptr
<DNSPacket
>& r
, const SOAData
& sd
)
110 string publishCDNSKEY
;
111 d_dk
.getPublishCDNSKEY(p
.qdomain
,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
, sd
.domain_id
, &p
);
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
, std::unique_ptr
<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
, sd
.domain_id
, &p
);
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
, std::unique_ptr
<DNSPacket
>& r
, const SOAData
& sd
)
190 d_dk
.getPublishCDS(p
.qdomain
, 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
, sd
.domain_id
, &p
);
219 rr
.dr
.d_ttl
=sd
.default_ttl
;
228 /** This adds NSEC3PARAM records. Returns true if one was added */
229 bool PacketHandler::addNSEC3PARAM(const DNSPacket
& p
, std::unique_ptr
<DNSPacket
>& r
, const SOAData
& sd
)
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(const DNSPacket
& p
, std::unique_ptr
<DNSPacket
>& r
, DNSName
&target
) const
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
, const 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
, sd
.domain_id
, &p
);
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
, const 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
, sd
.domain_id
, &p
);
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
, const 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
, sd
.domain_id
, &p
);
373 B
.lookup(QType(QType::ANY
), g_wildcarddnsname
+subdomain
, sd
.domain_id
, &p
);
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
);
393 auto recvec
=luaSynth(rec
->getCode(), target
, sd
.qname
, sd
.domain_id
, p
, rec
->d_type
);
394 for(const auto& r
: recvec
) {
395 rr
.dr
.d_type
= rec
->d_type
; // might be CNAME
397 rr
.scopeMask
= p
.getRealRemote().getBits(); // this makes sure answer is a specific as your question
401 catch (std::exception
&e
) {
402 while (B
.get(rr
)) ; // don't leave DB handle in bad state
410 if(rr
.dr
.d_type
== p
.qtype
.getCode() || rr
.dr
.d_type
== QType::CNAME
|| (p
.qtype
.getCode() == QType::ANY
&& rr
.dr
.d_type
!= QType::RRSIG
)) {
414 wildcard
=g_wildcarddnsname
+subdomain
;
418 if ( subdomain
== sd
.qname
|| haveSomething
) // stop at SOA or result
421 B
.lookup(QType(QType::ANY
), subdomain
, sd
.domain_id
, &p
);
423 DLOG(g_log
<<"No wildcard match, ancestor exists"<<endl
);
430 return haveSomething
;
433 /** dangling is declared true if we were unable to resolve everything */
434 int PacketHandler::doAdditionalProcessingAndDropAA(DNSPacket
& p
, std::unique_ptr
<DNSPacket
>& r
, const SOAData
& soadata
, bool retargeted
)
440 if(p
.qtype
.getCode()!=QType::AXFR
) { // this packet needs additional processing
441 // we now have a copy, push_back on packet might reallocate!
442 auto& records
= r
->getRRS();
443 vector
<DNSZoneRecord
> toAdd
;
445 for(auto i
= records
.cbegin() ; i
!= records
.cend(); ++i
) {
446 if(i
->dr
.d_place
==DNSResourceRecord::ADDITIONAL
||
447 !(i
->dr
.d_type
==QType::MX
|| i
->dr
.d_type
==QType::NS
|| i
->dr
.d_type
==QType::SRV
))
450 if(r
->d
.aa
&& i
->dr
.d_name
.countLabels() && i
->dr
.d_type
==QType::NS
&& !B
.getSOA(i
->dr
.d_name
,sd
) && !retargeted
) { // drop AA in case of non-SOA-level NS answer, except for root referral
452 // i->d_place=DNSResourceRecord::AUTHORITY; // XXX FIXME
457 if(i
->dr
.d_type
== QType::MX
)
458 lookup
= getRR
<MXRecordContent
>(i
->dr
)->d_mxname
;
459 else if(i
->dr
.d_type
== QType::SRV
)
460 lookup
= getRR
<SRVRecordContent
>(i
->dr
)->d_target
;
461 else if(i
->dr
.d_type
== QType::NS
)
462 lookup
= getRR
<NSRecordContent
>(i
->dr
)->getNS();
466 B
.lookup(QType(d_doIPv6AdditionalProcessing
? QType::ANY
: QType::A
), lookup
, soadata
.domain_id
, &p
);
469 if(rr
.dr
.d_type
!= QType::A
&& rr
.dr
.d_type
!=QType::AAAA
)
471 if(!rr
.dr
.d_name
.isPartOf(soadata
.qname
)) {
472 // FIXME we might still pass on the record if it is occluded and the
473 // backend uses a single id for all zones
476 rr
.dr
.d_place
=DNSResourceRecord::ADDITIONAL
;
480 for(const auto& rec
: toAdd
)
483 //records.insert(records.end(), toAdd.cbegin(), toAdd.cend()); // would be faster, but no dedup
489 void PacketHandler::emitNSEC(std::unique_ptr
<DNSPacket
>& r
, const SOAData
& sd
, const DNSName
& name
, const DNSName
& next
, int mode
)
491 NSECRecordContent nrc
;
494 nrc
.set(QType::NSEC
);
495 nrc
.set(QType::RRSIG
);
496 if(sd
.qname
== name
) {
497 nrc
.set(QType::SOA
); // 1dfd8ad SOA can live outside the records table
498 nrc
.set(QType::DNSKEY
);
499 string publishCDNSKEY
;
500 d_dk
.getPublishCDNSKEY(name
, publishCDNSKEY
);
501 if (publishCDNSKEY
== "1")
502 nrc
.set(QType::CDNSKEY
);
504 d_dk
.getPublishCDS(name
, publishCDS
);
505 if (! publishCDS
.empty())
511 B
.lookup(QType(QType::ANY
), name
, sd
.domain_id
);
513 #ifdef HAVE_LUA_RECORDS
514 if(rr
.dr
.d_type
== QType::LUA
)
515 nrc
.set(getRR
<LUARecordContent
>(rr
.dr
)->d_type
);
518 if(rr
.dr
.d_type
== QType::NS
|| rr
.auth
)
519 nrc
.set(rr
.dr
.d_type
);
523 rr
.dr
.d_ttl
= sd
.default_ttl
;
524 rr
.dr
.d_type
= QType::NSEC
;
525 rr
.dr
.d_content
= std::make_shared
<NSECRecordContent
>(std::move(nrc
));
526 rr
.dr
.d_place
= (mode
== 5 ) ? DNSResourceRecord::ANSWER
: DNSResourceRecord::AUTHORITY
;
532 void PacketHandler::emitNSEC3(std::unique_ptr
<DNSPacket
>& r
, const SOAData
& sd
, const NSEC3PARAMRecordContent
& ns3prc
, const DNSName
& name
, const string
& namehash
, const string
& nexthash
, int mode
)
534 NSEC3RecordContent n3rc
;
535 n3rc
.d_algorithm
= ns3prc
.d_algorithm
;
536 n3rc
.d_flags
= ns3prc
.d_flags
;
537 n3rc
.d_iterations
= ns3prc
.d_iterations
;
538 n3rc
.d_salt
= ns3prc
.d_salt
;
539 n3rc
.d_nexthash
= nexthash
;
544 if (sd
.qname
== name
) {
545 n3rc
.set(QType::SOA
); // 1dfd8ad SOA can live outside the records table
546 n3rc
.set(QType::NSEC3PARAM
);
547 n3rc
.set(QType::DNSKEY
);
548 string publishCDNSKEY
;
549 d_dk
.getPublishCDNSKEY(name
, publishCDNSKEY
);
550 if (publishCDNSKEY
== "1")
551 n3rc
.set(QType::CDNSKEY
);
553 d_dk
.getPublishCDS(name
, publishCDS
);
554 if (! publishCDS
.empty())
555 n3rc
.set(QType::CDS
);
558 B
.lookup(QType(QType::ANY
), name
, sd
.domain_id
);
560 #ifdef HAVE_LUA_RECORDS
561 if(rr
.dr
.d_type
== QType::LUA
)
562 n3rc
.set(getRR
<LUARecordContent
>(rr
.dr
)->d_type
);
565 if(rr
.dr
.d_type
&& (rr
.dr
.d_type
== QType::NS
|| rr
.auth
)) // skip empty non-terminals
566 n3rc
.set(rr
.dr
.d_type
);
570 const auto numberOfTypesSet
= n3rc
.numberOfTypesSet();
571 if (numberOfTypesSet
!= 0 && !(numberOfTypesSet
== 1 && n3rc
.isSet(QType::NS
))) {
572 n3rc
.set(QType::RRSIG
);
575 rr
.dr
.d_name
= DNSName(toBase32Hex(namehash
))+sd
.qname
;
576 rr
.dr
.d_ttl
= sd
.default_ttl
;
577 rr
.dr
.d_type
=QType::NSEC3
;
578 rr
.dr
.d_content
=std::make_shared
<NSEC3RecordContent
>(std::move(n3rc
));
579 rr
.dr
.d_place
= (mode
== 5 ) ? DNSResourceRecord::ANSWER
: DNSResourceRecord::AUTHORITY
;
586 mode 0 = No Data Responses, QTYPE is not DS
587 mode 1 = No Data Responses, QTYPE is DS
588 mode 2 = Wildcard No Data Responses
589 mode 3 = Wildcard Answer Responses
590 mode 4 = Name Error Responses
591 mode 5 = Direct NSEC request
593 void PacketHandler::addNSECX(DNSPacket
& p
, std::unique_ptr
<DNSPacket
>& r
, const DNSName
& target
, const DNSName
& wildcard
, const DNSName
& auth
, int mode
)
595 NSEC3PARAMRecordContent ns3rc
;
597 if(d_dk
.getNSEC3PARAM(auth
, &ns3rc
, &narrow
)) {
598 if (mode
!= 5) // no direct NSEC3 queries, rfc5155 7.2.8
599 addNSEC3(p
, r
, target
, wildcard
, auth
, ns3rc
, narrow
, mode
);
602 addNSEC(p
, r
, target
, wildcard
, auth
, mode
);
606 static bool getNSEC3Hashes(bool narrow
, DNSBackend
* db
, int id
, const std::string
& hashed
, bool decrement
, DNSName
& unhashed
, std::string
& before
, std::string
& after
, int mode
=0)
609 if(narrow
) { // nsec3-narrow
613 decrementHash(before
);
617 incrementHash(after
);
620 DNSName hashedName
= DNSName(toBase32Hex(hashed
));
621 DNSName beforeName
, afterName
;
622 if (!decrement
&& mode
>= 2)
623 beforeName
= hashedName
;
624 ret
=db
->getBeforeAndAfterNamesAbsolute(id
, hashedName
, unhashed
, beforeName
, afterName
);
625 before
=fromBase32Hex(beforeName
.toString());
626 after
=fromBase32Hex(afterName
.toString());
631 void PacketHandler::addNSEC3(DNSPacket
& p
, std::unique_ptr
<DNSPacket
>& r
, const DNSName
& target
, const DNSName
& wildcard
, const DNSName
& auth
, const NSEC3PARAMRecordContent
& ns3rc
, bool narrow
, int mode
)
633 DLOG(g_log
<<"addNSEC3() mode="<<mode
<<" auth="<<auth
<<" target="<<target
<<" wildcard="<<wildcard
<<endl
);
636 if(!B
.getSOAUncached(auth
, sd
)) {
637 DLOG(g_log
<<"Could not get SOA for domain");
641 bool doNextcloser
= false;
642 string before
, after
, hashed
;
643 DNSName unhashed
, closest
;
645 if (mode
== 2 || mode
== 3 || mode
== 4) {
651 // add matching NSEC3 RR
653 unhashed
=(mode
== 0 || mode
== 1 || mode
== 5) ? target
: closest
;
654 hashed
=hashQNameWithSalt(ns3rc
, unhashed
);
655 DLOG(g_log
<<"1 hash: "<<toBase32Hex(hashed
)<<" "<<unhashed
<<endl
);
657 getNSEC3Hashes(narrow
, sd
.db
, sd
.domain_id
, hashed
, false, unhashed
, before
, after
, mode
);
659 if (((mode
== 0 && ns3rc
.d_flags
) || mode
== 1) && (hashed
!= before
)) {
660 DLOG(g_log
<<"No matching NSEC3, do closest (provable) encloser"<<endl
);
662 bool doBreak
= false;
664 while( closest
.chopOff() && (closest
!= sd
.qname
)) { // stop at SOA
665 B
.lookup(QType(QType::ANY
), closest
, sd
.domain_id
, &p
);
674 hashed
=hashQNameWithSalt(ns3rc
, unhashed
);
675 DLOG(g_log
<<"1 hash: "<<toBase32Hex(hashed
)<<" "<<unhashed
<<endl
);
677 getNSEC3Hashes(narrow
, sd
.db
, sd
.domain_id
, hashed
, false, unhashed
, before
, after
);
680 if (!after
.empty()) {
681 DLOG(g_log
<<"Done calling for matching, hashed: '"<<toBase32Hex(hashed
)<<"' before='"<<toBase32Hex(before
)<<"', after='"<<toBase32Hex(after
)<<"'"<<endl
);
682 emitNSEC3(r
, sd
, ns3rc
, unhashed
, before
, after
, mode
);
686 // add covering NSEC3 RR
687 if ((mode
>= 2 && mode
<= 4) || doNextcloser
) {
688 DNSName
next(target
);
692 while( next
.chopOff() && !(next
==closest
));
694 hashed
=hashQNameWithSalt(ns3rc
, unhashed
);
695 DLOG(g_log
<<"2 hash: "<<toBase32Hex(hashed
)<<" "<<unhashed
<<endl
);
697 getNSEC3Hashes(narrow
, sd
.db
,sd
.domain_id
, hashed
, true, unhashed
, before
, after
);
698 DLOG(g_log
<<"Done calling for covering, hashed: '"<<toBase32Hex(hashed
)<<"' before='"<<toBase32Hex(before
)<<"', after='"<<toBase32Hex(after
)<<"'"<<endl
);
699 emitNSEC3( r
, sd
, ns3rc
, unhashed
, before
, after
, mode
);
703 if (mode
== 2 || mode
== 4) {
704 unhashed
=g_wildcarddnsname
+closest
;
706 hashed
=hashQNameWithSalt(ns3rc
, unhashed
);
707 DLOG(g_log
<<"3 hash: "<<toBase32Hex(hashed
)<<" "<<unhashed
<<endl
);
709 getNSEC3Hashes(narrow
, sd
.db
, sd
.domain_id
, hashed
, (mode
!= 2), unhashed
, before
, after
);
710 DLOG(g_log
<<"Done calling for '*', hashed: '"<<toBase32Hex(hashed
)<<"' before='"<<toBase32Hex(before
)<<"', after='"<<toBase32Hex(after
)<<"'"<<endl
);
711 emitNSEC3( r
, sd
, ns3rc
, unhashed
, before
, after
, mode
);
715 void PacketHandler::addNSEC(DNSPacket
& p
, std::unique_ptr
<DNSPacket
>& r
, const DNSName
& target
, const DNSName
& wildcard
, const DNSName
& auth
, int mode
)
717 DLOG(g_log
<<"addNSEC() mode="<<mode
<<" auth="<<auth
<<" target="<<target
<<" wildcard="<<wildcard
<<endl
);
720 if(!B
.getSOAUncached(auth
, sd
)) {
721 DLOG(g_log
<<"Could not get SOA for domain"<<endl
);
725 DNSName before
,after
;
726 sd
.db
->getBeforeAndAfterNames(sd
.domain_id
, auth
, target
, before
, after
);
727 if (mode
!= 5 || before
== target
)
728 emitNSEC(r
, sd
, before
, after
, mode
);
730 if (mode
== 2 || mode
== 4) {
731 // wildcard NO-DATA or wildcard denial
733 DNSName
closest(wildcard
);
736 closest
.prependRawLabel("*");
738 sd
.db
->getBeforeAndAfterNames(sd
.domain_id
, auth
, closest
, before
, after
);
739 emitNSEC(r
, sd
, before
, after
, mode
);
746 - only one backend owns the SOA of a zone
747 - only one AXFR per zone at a time - double startTransaction should fail
748 - backends need to implement transaction semantics
751 How BindBackend would implement this:
752 startTransaction makes a file
753 feedRecord sends everything to that file
754 commitTransaction moves that file atomically over the regular file, and triggers a reload
755 rollbackTransaction removes the file
758 How PostgreSQLBackend would implement this:
759 startTransaction starts a sql transaction, which also deletes all records
760 feedRecord is an insert statement
761 commitTransaction commits the transaction
762 rollbackTransaction aborts it
764 How MySQLBackend would implement this:
769 int PacketHandler::trySuperMaster(const DNSPacket
& p
, const DNSName
& tsigkeyname
)
773 // do it right now if the client is TCP
775 return trySuperMasterSynchronous(p
, tsigkeyname
);
779 // queue it if the client is on UDP
780 Communicator
.addTrySuperMasterRequest(p
);
785 int PacketHandler::trySuperMasterSynchronous(const DNSPacket
& p
, const DNSName
& tsigkeyname
)
787 ComboAddress remote
= p
.getRemote();
788 if(p
.hasEDNSSubnet() && ::arg().contains("trusted-notification-proxy", remote
.toString())) {
789 remote
= p
.getRealRemote().getNetwork();
793 Resolver::res_t nsset
;
796 uint32_t theirserial
;
797 resolver
.getSoaSerial(remote
, p
.qdomain
, &theirserial
);
798 resolver
.resolve(remote
, p
.qdomain
, QType::NS
, &nsset
);
800 catch(ResolverException
&re
) {
801 g_log
<<Logger::Error
<<"Error resolving SOA or NS for "<<p
.qdomain
<<" at: "<< remote
<<": "<<re
.reason
<<endl
;
802 return RCode::ServFail
;
805 // check if the returned records are NS records
807 for(const auto& ns
: nsset
) {
808 if(ns
.qtype
==QType::NS
)
813 g_log
<<Logger::Error
<<"While checking for supermaster, did not find NS for "<<p
.qdomain
<<" at: "<< remote
<<endl
;
814 return RCode::ServFail
;
817 string nameserver
, account
;
820 if (!::arg().mustDo("allow-unsigned-supermaster") && tsigkeyname
.empty()) {
821 g_log
<<Logger::Error
<<"Received unsigned NOTIFY for "<<p
.qdomain
<<" from potential supermaster "<<remote
<<". Refusing."<<endl
;
822 return RCode::Refused
;
825 if(!B
.superMasterBackend(remote
.toString(), p
.qdomain
, nsset
, &nameserver
, &account
, &db
)) {
826 g_log
<<Logger::Error
<<"Unable to find backend willing to host "<<p
.qdomain
<<" for potential supermaster "<<remote
<<". Remote nameservers: "<<endl
;
827 for(const auto& rr
: nsset
) {
828 if(rr
.qtype
==QType::NS
)
829 g_log
<<Logger::Error
<<rr
.content
<<endl
;
831 return RCode::Refused
;
834 db
->createSlaveDomain(p
.getRemote().toString(), p
.qdomain
, nameserver
, account
);
835 if (tsigkeyname
.empty() == false) {
837 meta
.push_back(tsigkeyname
.toStringNoDot());
838 db
->setDomainMetadata(p
.qdomain
, "AXFR-MASTER-TSIG", meta
);
841 catch(PDNSException
& ae
) {
842 g_log
<<Logger::Error
<<"Database error trying to create "<<p
.qdomain
<<" for potential supermaster "<<remote
<<": "<<ae
.reason
<<endl
;
843 return RCode::ServFail
;
845 g_log
<<Logger::Warning
<<"Created new slave zone '"<<p
.qdomain
<<"' from supermaster "<<remote
<<endl
;
846 return RCode::NoError
;
849 int PacketHandler::processNotify(const DNSPacket
& p
)
852 was this notification from an approved address?
853 was this notification approved by TSIG?
854 We determine our internal SOA id (via UeberBackend)
855 We determine the SOA at our (known) master
856 if master is higher -> do stuff
859 g_log
<<Logger::Debug
<<"Received NOTIFY for "<<p
.qdomain
<<" from "<<p
.getRemote()<<endl
;
861 if(!::arg().mustDo("slave") && s_forwardNotify
.empty()) {
862 g_log
<<Logger::Warning
<<"Received NOTIFY for "<<p
.qdomain
<<" from "<<p
.getRemote()<<" but slave support is disabled in the configuration"<<endl
;
863 return RCode::Refused
;
866 // Sender verification
868 if(!s_allowNotifyFrom
.match((ComboAddress
*) &p
.d_remote
) || p
.d_havetsig
) {
869 if (p
.d_havetsig
&& p
.getTSIGKeyname().empty() == false) {
870 g_log
<<Logger::Notice
<<"Received secure NOTIFY for "<<p
.qdomain
<<" from "<<p
.getRemote()<<", with TSIG key '"<<p
.getTSIGKeyname()<<"'"<<endl
;
872 g_log
<<Logger::Warning
<<"Received NOTIFY for "<<p
.qdomain
<<" from "<<p
.getRemote()<<" but the remote is not providing a TSIG key or in allow-notify-from (Refused)"<<endl
;
873 return RCode::Refused
;
877 if ((!::arg().mustDo("allow-unsigned-notify") && !p
.d_havetsig
) || p
.d_havetsig
) {
879 g_log
<<Logger::Warning
<<"Received unsigned NOTIFY for "<<p
.qdomain
<<" from "<<p
.getRemote()<<" while a TSIG key was required (Refused)"<<endl
;
880 return RCode::Refused
;
883 if (B
.getDomainMetadata(p
.qdomain
,"AXFR-MASTER-TSIG",meta
) && meta
.size() > 0) {
884 DNSName expected
{meta
[0]};
885 if (p
.getTSIGKeyname() != expected
) {
886 g_log
<<Logger::Warning
<<"Received secure NOTIFY for "<<p
.qdomain
<<" from "<<p
.getRemote()<<": expected TSIG key '"<<expected
<<"', got '"<<p
.getTSIGKeyname()<<"' (Refused)"<<endl
;
887 return RCode::Refused
;
892 // Domain verification
895 if(!B
.getDomainInfo(p
.qdomain
, di
, false) || !di
.backend
) {
896 if(::arg().mustDo("superslave")) {
897 g_log
<<Logger::Warning
<<"Received NOTIFY for "<<p
.qdomain
<<" from "<<p
.getRemote()<<" for which we are not authoritative, trying supermaster"<<endl
;
898 return trySuperMaster(p
, p
.getTSIGKeyname());
900 g_log
<<Logger::Notice
<<"Received NOTIFY for "<<p
.qdomain
<<" from "<<p
.getRemote()<<" for which we are not authoritative (Refused)"<<endl
;
901 return RCode::Refused
;
904 if(::arg().contains("trusted-notification-proxy", p
.getRemote().toString())) {
905 g_log
<<Logger::Error
<<"Received NOTIFY for "<<p
.qdomain
<<" from trusted-notification-proxy "<< p
.getRemote()<<endl
;
906 if(di
.masters
.empty()) {
907 g_log
<<Logger::Error
<<"However, "<<p
.qdomain
<<" does not have any masters defined (Refused)"<<endl
;
908 return RCode::Refused
;
911 else if(::arg().mustDo("master") && di
.kind
== DomainInfo::Master
) {
912 g_log
<<Logger::Warning
<<"Received NOTIFY for "<<p
.qdomain
<<" from "<<p
.getRemote()<<" but we are master (Refused)"<<endl
;
913 return RCode::Refused
;
915 else if(!di
.isMaster(p
.getRemote())) {
916 g_log
<<Logger::Warning
<<"Received NOTIFY for "<<p
.qdomain
<<" from "<<p
.getRemote()<<" which is not a master (Refused)"<<endl
;
917 return RCode::Refused
;
920 if(!s_forwardNotify
.empty()) {
921 set
<string
> forwardNotify(s_forwardNotify
);
922 for(set
<string
>::const_iterator j
=forwardNotify
.begin();j
!=forwardNotify
.end();++j
) {
923 g_log
<<Logger::Notice
<<"Relaying notification of domain "<<p
.qdomain
<<" from "<<p
.getRemote()<<" to "<<*j
<<endl
;
924 Communicator
.notify(p
.qdomain
,*j
);
928 if(::arg().mustDo("slave")) {
929 g_log
<<Logger::Debug
<<"Queueing slave check for "<<p
.qdomain
<<endl
;
930 Communicator
.addSlaveCheckRequest(di
, p
.d_remote
);
935 static bool validDNSName(const DNSName
&name
)
938 string::size_type pos
, length
;
940 for(const auto& s
: name
.getRawLabels()) {
942 for(pos
=0; pos
< length
; ++pos
) {
944 if(!((c
>= 'a' && c
<= 'z') ||
945 (c
>= 'A' && c
<= 'Z') ||
946 (c
>= '0' && c
<= '9') ||
947 c
=='-' || c
== '_' || c
=='*' || c
=='.' || c
=='/' || c
=='@' || c
==' ' || c
=='\\' || c
==':'))
955 std::unique_ptr
<DNSPacket
> PacketHandler::question(DNSPacket
& p
)
957 std::unique_ptr
<DNSPacket
> ret
{nullptr};
961 ret
=d_pdl
->prequery(p
);
967 static AtomicCounter
&rdqueries
=*S
.getPointer("rd-queries");
971 return doQuestion(p
);
975 void PacketHandler::makeNXDomain(DNSPacket
& p
, std::unique_ptr
<DNSPacket
>& r
, const DNSName
& target
, const DNSName
& wildcard
, const SOAData
& sd
)
978 rr
=makeEditedDNSZRFromSOAData(d_dk
, sd
, DNSResourceRecord::AUTHORITY
);
979 rr
.dr
.d_ttl
=min(sd
.ttl
, sd
.default_ttl
);
983 addNSECX(p
, r
, target
, wildcard
, sd
.qname
, 4);
986 r
->setRcode(RCode::NXDomain
);
989 void PacketHandler::makeNOError(DNSPacket
& p
, std::unique_ptr
<DNSPacket
>& r
, const DNSName
& target
, const DNSName
& wildcard
, const SOAData
& sd
, int mode
)
992 rr
=makeEditedDNSZRFromSOAData(d_dk
, sd
, DNSResourceRecord::AUTHORITY
);
993 rr
.dr
.d_ttl
=min(sd
.ttl
, sd
.default_ttl
);
997 addNSECX(p
, r
, target
, wildcard
, sd
.qname
, mode
);
1000 S
.ringAccount("noerror-queries", p
.qdomain
, p
.qtype
);
1004 bool PacketHandler::addDSforNS(DNSPacket
& p
, std::unique_ptr
<DNSPacket
>& r
, const SOAData
& sd
, const DNSName
& dsname
)
1006 //cerr<<"Trying to find a DS for '"<<dsname<<"', domain_id = "<<sd.domain_id<<endl;
1007 B
.lookup(QType(QType::DS
), dsname
, sd
.domain_id
, &p
);
1012 rr
.dr
.d_place
= DNSResourceRecord::AUTHORITY
;
1018 bool PacketHandler::tryReferral(DNSPacket
& p
, std::unique_ptr
<DNSPacket
>& r
, const SOAData
& sd
, const DNSName
&target
, bool retargeted
)
1020 vector
<DNSZoneRecord
> rrset
= getBestReferralNS(p
, sd
, target
);
1024 for(auto& rr
: rrset
) {
1025 rr
.dr
.d_place
=DNSResourceRecord::AUTHORITY
;
1031 if(d_dk
.isSecuredZone(sd
.qname
) && !addDSforNS(p
, r
, sd
, rrset
.begin()->dr
.d_name
) && d_dnssec
) {
1032 addNSECX(p
, r
, rrset
.begin()->dr
.d_name
, DNSName(), sd
.qname
, 1);
1038 void PacketHandler::completeANYRecords(DNSPacket
& p
, std::unique_ptr
<DNSPacket
>& r
, const SOAData
& sd
, const DNSName
&target
)
1040 addNSECX(p
, r
, target
, DNSName(), sd
.qname
, 5);
1041 if(sd
.qname
== p
.qdomain
) {
1042 addDNSKEY(p
, r
, sd
);
1043 addCDNSKEY(p
, r
, sd
);
1045 addNSEC3PARAM(p
, r
, sd
);
1049 bool PacketHandler::tryDNAME(DNSPacket
& p
, std::unique_ptr
<DNSPacket
>& r
, const SOAData
& sd
, DNSName
&target
)
1053 DLOG(g_log
<<Logger::Warning
<<"Let's try DNAME.."<<endl
);
1054 vector
<DNSZoneRecord
> rrset
= getBestDNAMESynth(p
, sd
, target
);
1055 if(!rrset
.empty()) {
1056 for(auto& rr
: rrset
) {
1057 rr
.dr
.d_place
= DNSResourceRecord::ANSWER
;
1064 bool PacketHandler::tryWildcard(DNSPacket
& p
, std::unique_ptr
<DNSPacket
>& r
, const SOAData
& sd
, DNSName
&target
, DNSName
&wildcard
, bool& retargeted
, bool& nodata
)
1066 retargeted
= nodata
= false;
1069 vector
<DNSZoneRecord
> rrset
;
1070 if(!getBestWildcard(p
, sd
, target
, wildcard
, &rrset
))
1074 DLOG(g_log
<<"Wildcard matched something, but not of the correct type"<<endl
);
1078 for(auto& rr
: rrset
) {
1079 rr
.wildcardname
= rr
.dr
.d_name
;
1080 rr
.dr
.d_name
=bestmatch
=target
;
1082 if(rr
.dr
.d_type
== QType::CNAME
) {
1084 target
=getRR
<CNAMERecordContent
>(rr
.dr
)->getTarget();
1087 rr
.dr
.d_place
=DNSResourceRecord::ANSWER
;
1091 if(d_dnssec
&& !nodata
) {
1092 addNSECX(p
, r
, bestmatch
, wildcard
, sd
.qname
, 3);
1098 //! Called by the Distributor to ask a question. Returns 0 in case of an error
1099 std::unique_ptr
<DNSPacket
> PacketHandler::doQuestion(DNSPacket
& p
)
1104 int retargetcount
=0;
1105 set
<DNSName
> authSet
;
1107 vector
<DNSZoneRecord
> rrset
;
1108 bool weDone
=0, weRedirected
=0, weHaveUnauth
=0, doSigs
=0;
1110 uint8_t aliasScopeMask
;
1112 std::unique_ptr
<DNSPacket
> r
{nullptr};
1115 #ifdef HAVE_LUA_RECORDS
1116 bool doLua
=g_doLuaRecord
;
1119 if(p
.d
.qr
) { // QR bit from dns packet (thanks RA from N)
1121 g_log
<<Logger::Error
<<"Received an answer (non-query) packet from "<<p
.getRemote()<<", dropping"<<endl
;
1122 S
.inc("corrupt-packets");
1123 S
.ringAccount("remotes-corrupt", p
.d_remote
);
1127 if(p
.d
.tc
) { // truncated query. MOADNSParser would silently parse this packet in an incomplete way.
1129 g_log
<<Logger::Error
<<"Received truncated query packet from "<<p
.getRemote()<<", dropping"<<endl
;
1130 S
.inc("corrupt-packets");
1131 S
.ringAccount("remotes-corrupt", p
.d_remote
);
1135 if (p
.hasEDNS() && p
.getEDNSVersion() > 0) {
1136 r
= p
.replyPacket();
1138 // PacketWriter::addOpt will take care of setting this correctly in the packet
1139 r
->setEDNSRcode(ERCode::BADVERS
);
1146 TSIGRecordContent trc
;
1147 if(!p
.checkForCorrectTSIG(&B
, &keyname
, &secret
, &trc
)) {
1148 r
=p
.replyPacket(); // generate an empty reply packet
1150 g_log
<<Logger::Error
<<"Received a TSIG signed message with a non-validating key"<<endl
;
1151 // RFC3007 describes that a non-secure message should be sending Refused for DNS Updates
1152 if (p
.d
.opcode
== Opcode::Update
)
1153 r
->setRcode(RCode::Refused
);
1155 r
->setRcode(RCode::NotAuth
);
1158 getTSIGHashEnum(trc
.d_algoName
, p
.d_tsig_algo
);
1159 if (p
.d_tsig_algo
== TSIG_GSS
) {
1160 GssContext
gssctx(keyname
);
1161 if (!gssctx
.getPeerPrincipal(p
.d_peer_principal
)) {
1162 g_log
<<Logger::Warning
<<"Failed to extract peer principal from GSS context with keyname '"<<keyname
<<"'"<<endl
;
1166 p
.setTSIGDetails(trc
, keyname
, secret
, trc
.d_mac
); // this will get copied by replyPacket()
1170 r
=p
.replyPacket(); // generate an empty reply packet, possibly with TSIG details inside
1172 if (p
.qtype
== QType::TKEY
) {
1173 this->tkeyHandler(p
, r
);
1179 // XXX FIXME do this in DNSPacket::parse ?
1181 if(!validDNSName(p
.qdomain
)) {
1183 g_log
<<Logger::Error
<<"Received a malformed qdomain from "<<p
.getRemote()<<", '"<<p
.qdomain
<<"': sending servfail"<<endl
;
1184 S
.inc("corrupt-packets");
1185 S
.ringAccount("remotes-corrupt", p
.d_remote
);
1186 S
.inc("servfail-packets");
1187 r
->setRcode(RCode::ServFail
);
1190 if(p
.d
.opcode
) { // non-zero opcode (again thanks RA!)
1191 if(p
.d
.opcode
==Opcode::Update
) {
1192 S
.inc("dnsupdate-queries");
1193 int res
=processUpdate(p
);
1194 if (res
== RCode::Refused
)
1195 S
.inc("dnsupdate-refused");
1196 else if (res
!= RCode::ServFail
)
1197 S
.inc("dnsupdate-answers");
1199 r
->setOpcode(Opcode::Update
);
1202 else if(p
.d
.opcode
==Opcode::Notify
) {
1203 S
.inc("incoming-notifications");
1204 int res
=processNotify(p
);
1207 r
->setOpcode(Opcode::Notify
);
1213 g_log
<<Logger::Error
<<"Received an unknown opcode "<<p
.d
.opcode
<<" from "<<p
.getRemote()<<" for "<<p
.qdomain
<<endl
;
1215 r
->setRcode(RCode::NotImp
);
1219 // g_log<<Logger::Warning<<"Query for '"<<p.qdomain<<"' "<<p.qtype.getName()<<" from "<<p.getRemote()<< " (tcp="<<p.d_tcp<<")"<<endl;
1221 if(p
.qtype
.getCode()==QType::IXFR
) {
1222 r
->setRcode(RCode::Refused
);
1226 DNSName target
=p
.qdomain
;
1228 // catch chaos qclass requests
1229 if(p
.qclass
== QClass::CHAOS
) {
1230 if (doChaosRequest(p
,r
,target
))
1236 // we only know about qclass IN (and ANY), send Refused for everything else.
1237 if(p
.qclass
!= QClass::IN
&& p
.qclass
!=QClass::ANY
) {
1238 r
->setRcode(RCode::Refused
);
1242 // send TC for udp ANY query if any-to-tcp is enabled.
1243 if(p
.qtype
.getCode() == QType::ANY
&& !p
.d_tcp
&& g_anyToTcp
) {
1249 // for qclass ANY the response should never be authoritative unless the response covers all classes.
1250 if(p
.qclass
==QClass::ANY
)
1255 if(retargetcount
> 10) { // XXX FIXME, retargetcount++?
1256 g_log
<<Logger::Warning
<<"Abort CNAME chain resolution after "<<--retargetcount
<<" redirects, sending out servfail. Initial query: '"<<p
.qdomain
<<"'"<<endl
;
1258 r
->setRcode(RCode::ServFail
);
1262 if(!B
.getAuth(target
, p
.qtype
, &sd
)) {
1263 DLOG(g_log
<<Logger::Error
<<"We have no authority over zone '"<<target
<<"'"<<endl
);
1264 if(!retargetcount
) {
1265 r
->setA(false); // drop AA if we never had a SOA in the first place
1266 r
->setRcode(RCode::Refused
); // send REFUSED - but only on empty 'no idea'
1270 DLOG(g_log
<<Logger::Error
<<"We have authority, zone='"<<sd
.qname
<<"', id="<<sd
.domain_id
<<endl
);
1272 authSet
.insert(sd
.qname
);
1273 d_dnssec
=(p
.d_dnssecOk
&& d_dk
.isSecuredZone(sd
.qname
));
1276 if(!retargetcount
) r
->qdomainzone
=sd
.qname
;
1278 if(sd
.qname
==p
.qdomain
) {
1279 if(p
.qtype
.getCode() == QType::DNSKEY
)
1281 if(addDNSKEY(p
, r
, sd
))
1284 else if(p
.qtype
.getCode() == QType::CDNSKEY
)
1286 if(addCDNSKEY(p
,r
, sd
))
1289 else if(p
.qtype
.getCode() == QType::CDS
)
1294 else if(d_dnssec
&& p
.qtype
.getCode() == QType::NSEC3PARAM
)
1296 if(addNSEC3PARAM(p
,r
, sd
))
1301 if(p
.qtype
.getCode() == QType::SOA
&& sd
.qname
==p
.qdomain
) {
1302 rr
=makeEditedDNSZRFromSOAData(d_dk
, sd
);
1307 // this TRUMPS a cname!
1308 if(d_dnssec
&& p
.qtype
.getCode() == QType::NSEC
&& !d_dk
.getNSEC3PARAM(sd
.qname
, 0)) {
1309 addNSEC(p
, r
, target
, DNSName(), sd
.qname
, 5);
1314 // this TRUMPS a cname!
1315 if(p
.qtype
.getCode() == QType::RRSIG
) {
1316 g_log
<<Logger::Info
<<"Direct RRSIG query for "<<target
<<" from "<<p
.getRemote()<<endl
;
1317 r
->setRcode(RCode::Refused
);
1321 DLOG(g_log
<<"Checking for referrals first, unless this is a DS query"<<endl
);
1322 if(p
.qtype
.getCode() != QType::DS
&& tryReferral(p
, r
, sd
, target
, retargetcount
))
1325 DLOG(g_log
<<"Got no referrals, trying ANY"<<endl
);
1327 #ifdef HAVE_LUA_RECORDS
1330 d_dk
.getFromMeta(sd
.qname
, "ENABLE-LUA-RECORDS", val
);
1335 // see what we get..
1336 B
.lookup(QType(QType::ANY
), target
, sd
.domain_id
, &p
);
1338 haveAlias
.trimToLabels(0);
1340 weDone
= weRedirected
= weHaveUnauth
= false;
1343 #ifdef HAVE_LUA_RECORDS
1344 if(rr
.dr
.d_type
== QType::LUA
) {
1347 auto rec
=getRR
<LUARecordContent
>(rr
.dr
);
1351 if(rec
->d_type
== QType::CNAME
|| rec
->d_type
== p
.qtype
.getCode() || (p
.qtype
.getCode() == QType::ANY
&& rec
->d_type
!= QType::RRSIG
)) {
1354 auto recvec
=luaSynth(rec
->getCode(), target
, sd
.qname
, sd
.domain_id
, p
, rec
->d_type
);
1355 if(!recvec
.empty()) {
1356 for(const auto& r_it
: recvec
) {
1357 rr
.dr
.d_type
= rec
->d_type
; // might be CNAME
1358 rr
.dr
.d_content
= r_it
;
1359 rr
.scopeMask
= p
.getRealRemote().getBits(); // this makes sure answer is a specific as your question
1360 rrset
.push_back(rr
);
1362 if(rec
->d_type
== QType::CNAME
&& p
.qtype
.getCode() != QType::CNAME
)
1368 catch(std::exception
&e
) {
1369 while (B
.get(rr
)) ; // don't leave DB handle in bad state
1372 r
->setRcode(RCode::ServFail
);
1379 //cerr<<"got content: ["<<rr.content<<"]"<<endl;
1380 if (!d_dnssec
&& p
.qtype
.getCode() == QType::ANY
&& (rr
.dr
.d_type
== QType:: DNSKEY
|| rr
.dr
.d_type
== QType::NSEC3PARAM
))
1381 continue; // Don't send dnssec info.
1382 if (rr
.dr
.d_type
== QType::RRSIG
) // RRSIGS are added later any way.
1383 continue; // TODO: this actually means addRRSig should check if the RRSig is already there
1385 // cerr<<"Auth: "<<rr.auth<<", "<<(rr.dr.d_type == p.qtype)<<", "<<rr.dr.d_type.getName()<<endl;
1386 if((p
.qtype
.getCode() == QType::ANY
|| rr
.dr
.d_type
== p
.qtype
.getCode()) && rr
.auth
)
1388 // the line below fakes 'unauth NS' for delegations for non-DNSSEC backends.
1389 if((rr
.dr
.d_type
== p
.qtype
.getCode() && !rr
.auth
) || (rr
.dr
.d_type
== QType::NS
&& (!rr
.auth
|| !(sd
.qname
==rr
.dr
.d_name
))))
1392 if(rr
.dr
.d_type
== QType::CNAME
&& p
.qtype
.getCode() != QType::CNAME
)
1395 if(DP
&& rr
.dr
.d_type
== QType::ALIAS
&& (p
.qtype
.getCode() == QType::A
|| p
.qtype
.getCode() == QType::AAAA
|| p
.qtype
.getCode() == QType::ANY
)) {
1396 if (!d_doExpandALIAS
) {
1397 g_log
<<Logger::Info
<<"ALIAS record found for "<<target
<<", but ALIAS expansion is disabled."<<endl
;
1400 haveAlias
=getRR
<ALIASRecordContent
>(rr
.dr
)->d_content
;
1401 aliasScopeMask
=rr
.scopeMask
;
1404 // Filter out all SOA's and add them in later
1405 if(rr
.dr
.d_type
== QType::SOA
)
1408 rrset
.push_back(rr
);
1411 /* Add in SOA if required */
1412 if(target
==sd
.qname
) {
1413 rr
=makeEditedDNSZRFromSOAData(d_dk
, sd
);
1414 rrset
.push_back(rr
);
1418 DLOG(g_log
<<"After first ANY query for '"<<target
<<"', id="<<sd
.domain_id
<<": weDone="<<weDone
<<", weHaveUnauth="<<weHaveUnauth
<<", weRedirected="<<weRedirected
<<", haveAlias='"<<haveAlias
<<"'"<<endl
);
1419 if(p
.qtype
.getCode() == QType::DS
&& weHaveUnauth
&& !weDone
&& !weRedirected
) {
1420 DLOG(g_log
<<"Q for DS of a name for which we do have NS, but for which we don't have DS; need to provide an AUTH answer that shows we don't"<<endl
);
1421 makeNOError(p
, r
, target
, DNSName(), sd
, 1);
1425 if(!haveAlias
.empty() && (!weDone
|| p
.qtype
.getCode() == QType::ANY
)) {
1426 DLOG(g_log
<<Logger::Warning
<<"Found nothing that matched for '"<<target
<<"', but did get alias to '"<<haveAlias
<<"', referring"<<endl
);
1427 DP
->completePacket(r
, haveAlias
, target
, aliasScopeMask
);
1432 // referral for DS query
1433 if(p
.qtype
.getCode() == QType::DS
) {
1434 DLOG(g_log
<<"Qtype is DS"<<endl
);
1435 bool doReferral
= true;
1436 if(d_dk
.doesDNSSEC()) {
1437 for(auto& loopRR
: rrset
) {
1438 // In a dnssec capable backend auth=true means, there is no delagation at
1439 // or above this qname in this zone (for DS queries). Without a delegation,
1440 // at or above this level, it is pointless to search for refferals.
1447 for(auto& loopRR
: rrset
) {
1448 // In a non dnssec capable backend auth is always true, so our only option
1449 // is, always look for referals. Unless there is a direct match for DS.
1450 if(loopRR
.dr
.d_type
== QType::DS
) {
1457 DLOG(g_log
<<"DS query found no direct result, trying referral now"<<endl
);
1458 if(tryReferral(p
, r
, sd
, target
, retargetcount
))
1460 DLOG(g_log
<<"Got referral for DS query"<<endl
);
1468 DLOG(g_log
<<Logger::Warning
<<"Found nothing in the by-name ANY, but let's try wildcards.."<<endl
);
1469 bool wereRetargeted(false), nodata(false);
1471 if(tryWildcard(p
, r
, sd
, target
, wildcard
, wereRetargeted
, nodata
)) {
1472 if(wereRetargeted
) {
1473 if(!retargetcount
) r
->qdomainwild
=wildcard
;
1478 makeNOError(p
, r
, target
, wildcard
, sd
, 2);
1482 else if(tryDNAME(p
, r
, sd
, target
)) {
1488 if (!(((p
.qtype
.getCode() == QType::CNAME
) || (p
.qtype
.getCode() == QType::ANY
)) && retargetcount
> 0))
1489 makeNXDomain(p
, r
, target
, wildcard
, sd
);
1496 for(auto& loopRR
: rrset
) {
1497 if(loopRR
.dr
.d_type
== QType::CNAME
) {
1498 r
->addRecord(loopRR
);
1499 target
= getRR
<CNAMERecordContent
>(loopRR
.dr
)->getTarget();
1506 bool haveRecords
= false;
1507 for(const auto& loopRR
: rrset
) {
1508 #ifdef HAVE_LUA_RECORDS
1509 if(loopRR
.dr
.d_type
== QType::LUA
)
1512 if((p
.qtype
.getCode() == QType::ANY
|| loopRR
.dr
.d_type
== p
.qtype
.getCode()) && loopRR
.dr
.d_type
&& loopRR
.dr
.d_type
!= QType::ALIAS
&& loopRR
.auth
) {
1513 r
->addRecord(loopRR
);
1519 if(d_dnssec
&& p
.qtype
.getCode() == QType::ANY
)
1520 completeANYRecords(p
, r
, sd
, target
);
1523 makeNOError(p
, r
, target
, DNSName(), sd
, 0);
1527 else if(weHaveUnauth
) {
1528 DLOG(g_log
<<"Have unauth data, so need to hunt for best NS records"<<endl
);
1529 if(tryReferral(p
, r
, sd
, target
, retargetcount
))
1531 // check whether this could be fixed easily
1532 // if (*(rr.dr.d_name.rbegin()) == '.') {
1533 // g_log<<Logger::Error<<"Should not get here ("<<p.qdomain<<"|"<<p.qtype.getCode()<<"): you have a trailing dot, this could be the problem (or run pdnsutil rectify-zone " <<sd.qname<<")"<<endl;
1535 g_log
<<Logger::Error
<<"Should not get here ("<<p
.qdomain
<<"|"<<p
.qtype
.getCode()<<"): please run pdnsutil rectify-zone "<<sd
.qname
<<endl
;
1539 DLOG(g_log
<<"Have some data, but not the right data"<<endl
);
1540 makeNOError(p
, r
, target
, DNSName(), sd
, 0);
1544 if(doAdditionalProcessingAndDropAA(p
, r
, sd
, retargetcount
)<0) {
1548 for(const auto& loopRR
: r
->getRRS()) {
1549 if(loopRR
.scopeMask
) {
1555 addRRSigs(d_dk
, B
, authSet
, r
->getRRS());
1557 if(PC
.enabled() && !noCache
&& p
.couldBeCached())
1558 PC
.insert(p
, *r
, r
->getMinTTL()); // in the packet cache
1560 catch(const DBException
&e
) {
1561 g_log
<<Logger::Error
<<"Backend reported condition which prevented lookup ("+e
.reason
+") sending out servfail"<<endl
;
1562 r
=p
.replyPacket(); // generate an empty reply packet
1563 r
->setRcode(RCode::ServFail
);
1564 S
.inc("servfail-packets");
1565 S
.ringAccount("servfail-queries", p
.qdomain
, p
.qtype
);
1567 catch(const PDNSException
&e
) {
1568 g_log
<<Logger::Error
<<"Backend reported permanent error which prevented lookup ("+e
.reason
+"), aborting"<<endl
;
1569 throw; // we WANT to die at this point
1571 catch(const std::exception
&e
) {
1572 g_log
<<Logger::Error
<<"Exception building answer packet for "<<p
.qdomain
<<"/"<<p
.qtype
.getName()<<" ("<<e
.what()<<") sending out servfail"<<endl
;
1573 r
=p
.replyPacket(); // generate an empty reply packet
1574 r
->setRcode(RCode::ServFail
);
1575 S
.inc("servfail-packets");
1576 S
.ringAccount("servfail-queries", p
.qdomain
, p
.qtype
);