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 "auth-main.hh"
48 #include "trusted-notification-proxy.hh"
49 #include "gss_context.hh"
56 AtomicCounter
PacketHandler::s_count
;
57 NetmaskGroup
PacketHandler::s_allowNotifyFrom
;
58 set
<string
> PacketHandler::s_forwardNotify
;
59 bool PacketHandler::s_SVCAutohints
{false};
61 extern string g_programname
;
63 // See https://www.rfc-editor.org/rfc/rfc8078.txt and https://www.rfc-editor.org/errata/eid5049 for details
64 const std::shared_ptr
<CDNSKEYRecordContent
> PacketHandler::s_deleteCDNSKEYContent
= std::make_shared
<CDNSKEYRecordContent
>("0 3 0 AA==");
65 const std::shared_ptr
<CDSRecordContent
> PacketHandler::s_deleteCDSContent
= std::make_shared
<CDSRecordContent
>("0 0 0 00");
67 PacketHandler::PacketHandler():B(g_programname
), d_dk(&B
)
70 d_doDNAME
=::arg().mustDo("dname-processing");
71 d_doExpandALIAS
= ::arg().mustDo("expand-alias");
72 d_logDNSDetails
= ::arg().mustDo("log-dns-details");
73 string fname
= ::arg()["lua-prequery-script"];
80 d_pdl
= std::make_unique
<AuthLua4
>();
81 d_pdl
->loadFile(fname
); // XXX exception handling?
83 fname
= ::arg()["lua-dnsupdate-policy-script"];
86 d_update_policy_lua
= nullptr;
90 d_update_policy_lua
= std::make_unique
<AuthLua4
>();
92 d_update_policy_lua
->loadFile(fname
);
94 catch (const std::runtime_error
&) {
95 d_update_policy_lua
= nullptr;
100 UeberBackend
*PacketHandler::getBackend()
105 PacketHandler::~PacketHandler()
108 DLOG(g_log
<<Logger::Error
<<"PacketHandler destructor called - "<<s_count
<<" left"<<endl
);
112 * This adds CDNSKEY records to the answer packet. Returns true if one was added.
114 * @param p Pointer to the DNSPacket containing the original question
115 * @param r Pointer to the DNSPacket where the records should be inserted into
116 * @return bool that shows if any records were added
118 bool PacketHandler::addCDNSKEY(DNSPacket
& p
, std::unique_ptr
<DNSPacket
>& r
)
120 string publishCDNSKEY
;
121 d_dk
.getPublishCDNSKEY(p
.qdomain
,publishCDNSKEY
);
122 if (publishCDNSKEY
.empty())
126 rr
.dr
.d_type
=QType::CDNSKEY
;
127 rr
.dr
.d_ttl
=d_sd
.minimum
;
128 rr
.dr
.d_name
=p
.qdomain
;
131 if (publishCDNSKEY
== "0") { // delete DS via CDNSKEY
132 rr
.dr
.setContent(s_deleteCDNSKEYContent
);
133 r
->addRecord(std::move(rr
));
138 DNSSECKeeper::keyset_t entryPoints
= d_dk
.getEntryPoints(p
.qdomain
);
139 for(const auto& value
: entryPoints
) {
140 if (!value
.second
.published
) {
143 rr
.dr
.setContent(std::make_shared
<DNSKEYRecordContent
>(value
.first
.getDNSKEY()));
144 r
->addRecord(DNSZoneRecord(rr
));
148 if(::arg().mustDo("direct-dnskey")) {
149 B
.lookup(QType(QType::CDNSKEY
), p
.qdomain
, d_sd
.domain_id
, &p
);
152 rr
.dr
.d_ttl
=d_sd
.minimum
;
153 r
->addRecord(std::move(rr
));
161 * This adds DNSKEY records to the answer packet. Returns true if one was added.
163 * @param p Pointer to the DNSPacket containing the original question
164 * @param r Pointer to the DNSPacket where the records should be inserted into
165 * @return bool that shows if any records were added
167 bool PacketHandler::addDNSKEY(DNSPacket
& p
, std::unique_ptr
<DNSPacket
>& r
)
172 DNSSECKeeper::keyset_t keyset
= d_dk
.getKeys(p
.qdomain
);
173 for(const auto& value
: keyset
) {
174 if (!value
.second
.published
) {
177 rr
.dr
.d_type
=QType::DNSKEY
;
178 rr
.dr
.d_ttl
=d_sd
.minimum
;
179 rr
.dr
.d_name
=p
.qdomain
;
180 rr
.dr
.setContent(std::make_shared
<DNSKEYRecordContent
>(value
.first
.getDNSKEY()));
182 r
->addRecord(std::move(rr
));
186 if(::arg().mustDo("direct-dnskey")) {
187 B
.lookup(QType(QType::DNSKEY
), p
.qdomain
, d_sd
.domain_id
, &p
);
190 rr
.dr
.d_ttl
=d_sd
.minimum
;
191 r
->addRecord(std::move(rr
));
200 * This adds CDS records to the answer packet r.
202 * @param p Pointer to the DNSPacket containing the original question.
203 * @param r Pointer to the DNSPacket where the records should be inserted into.
204 * used to determine record TTL.
205 * @return bool that shows if any records were added.
207 bool PacketHandler::addCDS(DNSPacket
& p
, std::unique_ptr
<DNSPacket
>& r
)
210 d_dk
.getPublishCDS(p
.qdomain
, publishCDS
);
211 if (publishCDS
.empty())
214 vector
<string
> digestAlgos
;
215 stringtok(digestAlgos
, publishCDS
, ", ");
218 rr
.dr
.d_type
=QType::CDS
;
219 rr
.dr
.d_ttl
=d_sd
.minimum
;
220 rr
.dr
.d_name
=p
.qdomain
;
223 if(std::find(digestAlgos
.begin(), digestAlgos
.end(), "0") != digestAlgos
.end()) { // delete DS via CDS
224 rr
.dr
.setContent(s_deleteCDSContent
);
225 r
->addRecord(std::move(rr
));
231 DNSSECKeeper::keyset_t keyset
= d_dk
.getEntryPoints(p
.qdomain
);
233 for(auto const &value
: keyset
) {
234 if (!value
.second
.published
) {
237 for(auto const &digestAlgo
: digestAlgos
){
238 rr
.dr
.setContent(std::make_shared
<DSRecordContent
>(makeDSFromDNSKey(p
.qdomain
, value
.first
.getDNSKEY(), pdns::checked_stoi
<uint8_t>(digestAlgo
))));
239 r
->addRecord(DNSZoneRecord(rr
));
244 if(::arg().mustDo("direct-dnskey")) {
245 B
.lookup(QType(QType::CDS
), p
.qdomain
, d_sd
.domain_id
, &p
);
248 rr
.dr
.d_ttl
=d_sd
.minimum
;
249 r
->addRecord(std::move(rr
));
257 /** This adds NSEC3PARAM records. Returns true if one was added */
258 bool PacketHandler::addNSEC3PARAM(const DNSPacket
& p
, std::unique_ptr
<DNSPacket
>& r
)
262 NSEC3PARAMRecordContent ns3prc
;
263 if(d_dk
.getNSEC3PARAM(p
.qdomain
, &ns3prc
)) {
264 rr
.dr
.d_type
=QType::NSEC3PARAM
;
265 rr
.dr
.d_ttl
=d_sd
.minimum
;
266 rr
.dr
.d_name
=p
.qdomain
;
267 ns3prc
.d_flags
= 0; // the NSEC3PARAM 'flag' is defined to always be zero in RFC5155.
268 rr
.dr
.setContent(std::make_shared
<NSEC3PARAMRecordContent
>(ns3prc
));
270 r
->addRecord(std::move(rr
));
277 // This is our chaos class requests handler. Return 1 if content was added, 0 if it wasn't
278 int PacketHandler::doChaosRequest(const DNSPacket
& p
, std::unique_ptr
<DNSPacket
>& r
, DNSName
&target
) const
282 if(p
.qtype
.getCode()==QType::TXT
) {
283 static const DNSName
versionbind("version.bind."), versionpdns("version.pdns."), idserver("id.server.");
284 if (target
==versionbind
|| target
==versionpdns
) {
285 // modes: full, powerdns only, anonymous or custom
286 const static string mode
=::arg()["version-string"];
288 if(mode
.empty() || mode
=="full")
289 content
=fullVersionString();
290 else if(mode
=="powerdns")
291 content
="Served by PowerDNS - https://www.powerdns.com/";
292 else if(mode
=="anonymous") {
293 r
->setRcode(RCode::ServFail
);
298 rr
.dr
.setContent(DNSRecordContent::mastermake(QType::TXT
, 1, "\""+content
+"\""));
300 else if (target
==idserver
) {
301 // modes: disabled, hostname or custom
302 const static string id
=::arg()["server-id"];
304 if (id
== "disabled") {
305 r
->setRcode(RCode::Refused
);
309 if(!tid
.empty() && tid
[0]!='"') { // see #6010 however
310 tid
= "\"" + tid
+ "\"";
312 rr
.dr
.setContent(DNSRecordContent::mastermake(QType::TXT
, 1, tid
));
315 r
->setRcode(RCode::Refused
);
321 rr
.dr
.d_type
=QType::TXT
;
322 rr
.dr
.d_class
=QClass::CHAOS
;
323 r
->addRecord(std::move(rr
));
327 r
->setRcode(RCode::NotImp
);
331 vector
<DNSZoneRecord
> PacketHandler::getBestReferralNS(DNSPacket
& p
, const DNSName
&target
)
333 vector
<DNSZoneRecord
> ret
;
335 DNSName
subdomain(target
);
337 if(subdomain
== d_sd
.qname
) // stop at SOA
339 B
.lookup(QType(QType::NS
), subdomain
, d_sd
.domain_id
, &p
);
341 ret
.push_back(rr
); // this used to exclude auth NS records for some reason
345 } while( subdomain
.chopOff() ); // 'www.powerdns.org' -> 'powerdns.org' -> 'org' -> ''
349 void PacketHandler::getBestDNAMESynth(DNSPacket
& p
, DNSName
&target
, vector
<DNSZoneRecord
> &ret
)
354 DNSName
subdomain(target
);
356 DLOG(g_log
<<"Attempting DNAME lookup for "<<subdomain
<<", d_sd.qname="<<d_sd
.qname
<<endl
);
358 B
.lookup(QType(QType::DNAME
), subdomain
, d_sd
.domain_id
, &p
);
360 ret
.push_back(rr
); // put in the original
361 rr
.dr
.d_type
= QType::CNAME
;
362 rr
.dr
.d_name
= prefix
+ rr
.dr
.d_name
;
363 rr
.dr
.setContent(std::make_shared
<CNAMERecordContent
>(CNAMERecordContent(prefix
+ getRR
<DNAMERecordContent
>(rr
.dr
)->getTarget())));
364 rr
.auth
= false; // don't sign CNAME
365 target
= getRR
<CNAMERecordContent
>(rr
.dr
)->getTarget();
370 if(subdomain
.countLabels())
371 prefix
.appendRawLabel(subdomain
.getRawLabels()[0]); // XXX DNSName pain this feels wrong
372 if(subdomain
== d_sd
.qname
) // stop at SOA
375 } while( subdomain
.chopOff() ); // 'www.powerdns.org' -> 'powerdns.org' -> 'org' -> ''
380 // Return best matching wildcard or next closer name
381 bool PacketHandler::getBestWildcard(DNSPacket
& p
, const DNSName
&target
, DNSName
&wildcard
, vector
<DNSZoneRecord
>* ret
)
385 DNSName
subdomain(target
);
386 bool haveSomething
=false;
388 #ifdef HAVE_LUA_RECORDS
389 bool doLua
=g_doLuaRecord
;
392 d_dk
.getFromMeta(d_sd
.qname
, "ENABLE-LUA-RECORDS", val
);
398 while( subdomain
.chopOff() && !haveSomething
) {
399 if (subdomain
.empty()) {
400 B
.lookup(QType(QType::ANY
), g_wildcarddnsname
, d_sd
.domain_id
, &p
);
402 B
.lookup(QType(QType::ANY
), g_wildcarddnsname
+subdomain
, d_sd
.domain_id
, &p
);
405 #ifdef HAVE_LUA_RECORDS
406 if (rr
.dr
.d_type
== QType::LUA
&& !d_dk
.isPresigned(d_sd
.qname
)) {
408 DLOG(g_log
<<"Have a wildcard LUA match, but not doing LUA record for this zone"<<endl
);
412 DLOG(g_log
<<"Have a wildcard LUA match"<<endl
);
414 auto rec
=getRR
<LUARecordContent
>(rr
.dr
);
418 if(rec
->d_type
== QType::CNAME
|| rec
->d_type
== p
.qtype
.getCode() || (p
.qtype
.getCode() == QType::ANY
&& rec
->d_type
!= QType::RRSIG
)) {
420 DLOG(g_log
<<"Executing Lua: '"<<rec
->getCode()<<"'"<<endl
);
422 auto recvec
=luaSynth(rec
->getCode(), target
, d_sd
.qname
, d_sd
.domain_id
, p
, rec
->d_type
, s_LUA
);
423 for (const auto& r
: recvec
) {
424 rr
.dr
.d_type
= rec
->d_type
; // might be CNAME
426 rr
.scopeMask
= p
.getRealRemote().getBits(); // this makes sure answer is a specific as your question
430 catch (std::exception
&e
) {
431 while (B
.get(rr
)) ; // don't leave DB handle in bad state
439 if(rr
.dr
.d_type
!= QType::ENT
&& (rr
.dr
.d_type
== p
.qtype
.getCode() || rr
.dr
.d_type
== QType::CNAME
|| (p
.qtype
.getCode() == QType::ANY
&& rr
.dr
.d_type
!= QType::RRSIG
))) {
443 wildcard
=g_wildcarddnsname
+subdomain
;
447 if ( subdomain
== d_sd
.qname
|| haveSomething
) // stop at SOA or result
450 B
.lookup(QType(QType::ANY
), subdomain
, d_sd
.domain_id
, &p
);
452 DLOG(g_log
<<"No wildcard match, ancestor exists"<<endl
);
459 return haveSomething
;
462 DNSName
PacketHandler::doAdditionalServiceProcessing(const DNSName
&firstTarget
, const uint16_t &qtype
, std::unique_ptr
<DNSPacket
>& /* r */, vector
<DNSZoneRecord
>& extraRecords
) {
463 DNSName ret
= firstTarget
;
464 size_t ctr
= 5; // Max 5 SVCB Aliasforms per query
466 while (!done
&& ctr
> 0) {
470 if(!ret
.isPartOf(d_sd
.qname
)) {
474 B
.lookup(QType(qtype
), ret
, d_sd
.domain_id
);
476 rr
.dr
.d_place
= DNSResourceRecord::ADDITIONAL
;
478 case QType::SVCB
: /* fall-through */
480 auto rrc
= getRR
<SVCBBaseRecordContent
>(rr
.dr
);
481 extraRecords
.push_back(std::move(rr
));
482 ret
= rrc
->getTarget().isRoot() ? ret
: rrc
->getTarget();
483 if (rrc
->getPriority() == 0) {
489 while (B
.get(rr
)) ; // don't leave DB handle in bad state
491 throw PDNSException("Unknown type (" + QType(qtype
).toString() + ") for additional service processing");
500 void PacketHandler::doAdditionalProcessing(DNSPacket
& p
, std::unique_ptr
<DNSPacket
>& r
)
503 std::unordered_set
<DNSName
> lookup
;
504 vector
<DNSZoneRecord
> extraRecords
;
505 const auto& rrs
= r
->getRRS();
507 lookup
.reserve(rrs
.size());
508 for(auto& rr
: rrs
) {
509 if(rr
.dr
.d_place
!= DNSResourceRecord::ADDITIONAL
) {
510 switch(rr
.dr
.d_type
) {
512 content
=getRR
<NSRecordContent
>(rr
.dr
)->getNS();
515 content
=getRR
<MXRecordContent
>(rr
.dr
)->d_mxname
;
518 content
=getRR
<SRVRecordContent
>(rr
.dr
)->d_target
;
520 case QType::SVCB
: /* fall-through */
522 auto rrc
= getRR
<SVCBBaseRecordContent
>(rr
.dr
);
523 content
= rrc
->getTarget();
524 if (content
.isRoot()) {
525 content
= rr
.dr
.d_name
;
527 if (rrc
->getPriority() == 0) {
528 content
= doAdditionalServiceProcessing(content
, rr
.dr
.d_type
, r
, extraRecords
);
535 if(content
.isPartOf(d_sd
.qname
)) {
536 lookup
.emplace(content
);
541 for(auto& rr
: extraRecords
) {
542 r
->addRecord(std::move(rr
));
544 extraRecords
.clear();
545 // TODO should we have a setting to do this?
546 for (auto &rec
: r
->getServiceRecords()) {
547 // Process auto hints
548 auto rrc
= getRR
<SVCBBaseRecordContent
>(rec
->dr
);
549 DNSName target
= rrc
->getTarget().isRoot() ? rec
->dr
.d_name
: rrc
->getTarget();
551 if (rrc
->hasParam(SvcParam::ipv4hint
) && rrc
->autoHint(SvcParam::ipv4hint
)) {
552 auto newRRC
= rrc
->clone();
556 if (s_SVCAutohints
) {
557 auto hints
= getIPAddressFor(target
, QType::A
);
558 if (hints
.size() == 0) {
559 newRRC
->removeParam(SvcParam::ipv4hint
);
561 newRRC
->setHints(SvcParam::ipv4hint
, hints
);
564 newRRC
->removeParam(SvcParam::ipv4hint
);
567 rec
->dr
.setContent(std::move(newRRC
));
570 if (rrc
->hasParam(SvcParam::ipv6hint
) && rrc
->autoHint(SvcParam::ipv6hint
)) {
571 auto newRRC
= rrc
->clone();
575 if (s_SVCAutohints
) {
576 auto hints
= getIPAddressFor(target
, QType::AAAA
);
577 if (hints
.size() == 0) {
578 newRRC
->removeParam(SvcParam::ipv6hint
);
580 newRRC
->setHints(SvcParam::ipv6hint
, hints
);
583 newRRC
->removeParam(SvcParam::ipv6hint
);
585 rec
->dr
.setContent(std::move(newRRC
));
590 for(const auto& name
: lookup
) {
591 B
.lookup(QType(QType::ANY
), name
, d_sd
.domain_id
, &p
);
593 if(dzr
.dr
.d_type
== QType::A
|| dzr
.dr
.d_type
== QType::AAAA
) {
594 dzr
.dr
.d_place
=DNSResourceRecord::ADDITIONAL
;
595 r
->addRecord(std::move(dzr
));
601 vector
<ComboAddress
> PacketHandler::getIPAddressFor(const DNSName
&target
, const uint16_t qtype
) {
602 vector
<ComboAddress
> ret
;
603 if (qtype
!= QType::A
&& qtype
!= QType::AAAA
) {
606 B
.lookup(qtype
, target
, d_sd
.domain_id
);
609 if (qtype
== QType::AAAA
) {
610 auto aaaarrc
= getRR
<AAAARecordContent
>(rr
.dr
);
611 ret
.push_back(aaaarrc
->getCA());
612 } else if (qtype
== QType::A
) {
613 auto arrc
= getRR
<ARecordContent
>(rr
.dr
);
614 ret
.push_back(arrc
->getCA());
620 void PacketHandler::emitNSEC(std::unique_ptr
<DNSPacket
>& r
, const DNSName
& name
, const DNSName
& next
, int mode
)
622 NSECRecordContent nrc
;
625 nrc
.set(QType::NSEC
);
626 nrc
.set(QType::RRSIG
);
627 if(d_sd
.qname
== name
) {
628 nrc
.set(QType::SOA
); // 1dfd8ad SOA can live outside the records table
629 if(!d_dk
.isPresigned(d_sd
.qname
)) {
630 auto keyset
= d_dk
.getKeys(name
);
631 for(const auto& value
: keyset
) {
632 if (value
.second
.published
) {
633 nrc
.set(QType::DNSKEY
);
634 string publishCDNSKEY
;
635 d_dk
.getPublishCDNSKEY(name
, publishCDNSKEY
);
636 if (! publishCDNSKEY
.empty())
637 nrc
.set(QType::CDNSKEY
);
639 d_dk
.getPublishCDS(name
, publishCDS
);
640 if (! publishCDS
.empty())
649 #ifdef HAVE_LUA_RECORDS
654 B
.lookup(QType(QType::ANY
), name
, d_sd
.domain_id
);
656 #ifdef HAVE_LUA_RECORDS
657 if (rr
.dr
.d_type
== QType::LUA
&& first
&& !d_dk
.isPresigned(d_sd
.qname
)) {
659 doLua
= g_doLuaRecord
;
662 d_dk
.getFromMeta(d_sd
.qname
, "ENABLE-LUA-RECORDS", val
);
663 doLua
= (val
== "1");
667 if (rr
.dr
.d_type
== QType::LUA
&& doLua
) {
668 nrc
.set(getRR
<LUARecordContent
>(rr
.dr
)->d_type
);
672 if (d_doExpandALIAS
&& rr
.dr
.d_type
== QType::ALIAS
) {
673 // Set the A and AAAA in the NSEC bitmap so aggressive NSEC
674 // does not falsely deny the type for this name.
675 // This does NOT add the ALIAS to the bitmap, as that record cannot
677 if (!d_dk
.isPresigned(d_sd
.qname
)) {
679 nrc
.set(QType::AAAA
);
682 else if((rr
.dr
.d_type
== QType::DNSKEY
|| rr
.dr
.d_type
== QType::CDS
|| rr
.dr
.d_type
== QType::CDNSKEY
) && !d_dk
.isPresigned(d_sd
.qname
) && !::arg().mustDo("direct-dnskey")) {
685 else if(rr
.dr
.d_type
== QType::NS
|| rr
.auth
) {
686 nrc
.set(rr
.dr
.d_type
);
691 rr
.dr
.d_ttl
= d_sd
.getNegativeTTL();
692 rr
.dr
.d_type
= QType::NSEC
;
693 rr
.dr
.setContent(std::make_shared
<NSECRecordContent
>(std::move(nrc
)));
694 rr
.dr
.d_place
= (mode
== 5 ) ? DNSResourceRecord::ANSWER
: DNSResourceRecord::AUTHORITY
;
697 r
->addRecord(std::move(rr
));
700 void PacketHandler::emitNSEC3(std::unique_ptr
<DNSPacket
>& r
, const NSEC3PARAMRecordContent
& ns3prc
, const DNSName
& name
, const string
& namehash
, const string
& nexthash
, int mode
)
702 NSEC3RecordContent n3rc
;
703 n3rc
.d_algorithm
= ns3prc
.d_algorithm
;
704 n3rc
.d_flags
= ns3prc
.d_flags
;
705 n3rc
.d_iterations
= ns3prc
.d_iterations
;
706 n3rc
.d_salt
= ns3prc
.d_salt
;
707 n3rc
.d_nexthash
= nexthash
;
712 if (d_sd
.qname
== name
) {
713 n3rc
.set(QType::SOA
); // 1dfd8ad SOA can live outside the records table
714 n3rc
.set(QType::NSEC3PARAM
);
715 if(!d_dk
.isPresigned(d_sd
.qname
)) {
716 auto keyset
= d_dk
.getKeys(name
);
717 for(const auto& value
: keyset
) {
718 if (value
.second
.published
) {
719 n3rc
.set(QType::DNSKEY
);
720 string publishCDNSKEY
;
721 d_dk
.getPublishCDNSKEY(name
, publishCDNSKEY
);
722 if (! publishCDNSKEY
.empty())
723 n3rc
.set(QType::CDNSKEY
);
725 d_dk
.getPublishCDS(name
, publishCDS
);
726 if (! publishCDS
.empty())
727 n3rc
.set(QType::CDS
);
734 #ifdef HAVE_LUA_RECORDS
739 B
.lookup(QType(QType::ANY
), name
, d_sd
.domain_id
);
741 #ifdef HAVE_LUA_RECORDS
742 if (rr
.dr
.d_type
== QType::LUA
&& first
&& !d_dk
.isPresigned(d_sd
.qname
)) {
744 doLua
= g_doLuaRecord
;
747 d_dk
.getFromMeta(d_sd
.qname
, "ENABLE-LUA-RECORDS", val
);
748 doLua
= (val
== "1");
752 if (rr
.dr
.d_type
== QType::LUA
&& doLua
) {
753 n3rc
.set(getRR
<LUARecordContent
>(rr
.dr
)->d_type
);
757 if (d_doExpandALIAS
&& rr
.dr
.d_type
== QType::ALIAS
) {
758 // Set the A and AAAA in the NSEC3 bitmap so aggressive NSEC
759 // does not falsely deny the type for this name.
760 // This does NOT add the ALIAS to the bitmap, as that record cannot
762 if (!d_dk
.isPresigned(d_sd
.qname
)) {
764 n3rc
.set(QType::AAAA
);
767 else if((rr
.dr
.d_type
== QType::DNSKEY
|| rr
.dr
.d_type
== QType::CDS
|| rr
.dr
.d_type
== QType::CDNSKEY
) && !d_dk
.isPresigned(d_sd
.qname
) && !::arg().mustDo("direct-dnskey")) {
770 else if(rr
.dr
.d_type
&& (rr
.dr
.d_type
== QType::NS
|| rr
.auth
)) {
771 // skip empty non-terminals
772 n3rc
.set(rr
.dr
.d_type
);
777 const auto numberOfTypesSet
= n3rc
.numberOfTypesSet();
778 if (numberOfTypesSet
!= 0 && !(numberOfTypesSet
== 1 && n3rc
.isSet(QType::NS
))) {
779 n3rc
.set(QType::RRSIG
);
782 rr
.dr
.d_name
= DNSName(toBase32Hex(namehash
))+d_sd
.qname
;
783 rr
.dr
.d_ttl
= d_sd
.getNegativeTTL();
784 rr
.dr
.d_type
=QType::NSEC3
;
785 rr
.dr
.setContent(std::make_shared
<NSEC3RecordContent
>(std::move(n3rc
)));
786 rr
.dr
.d_place
= (mode
== 5 ) ? DNSResourceRecord::ANSWER
: DNSResourceRecord::AUTHORITY
;
789 r
->addRecord(std::move(rr
));
793 mode 0 = No Data Responses, QTYPE is not DS
794 mode 1 = No Data Responses, QTYPE is DS
795 mode 2 = Wildcard No Data Responses
796 mode 3 = Wildcard Answer Responses
797 mode 4 = Name Error Responses
798 mode 5 = Direct NSEC request
800 void PacketHandler::addNSECX(DNSPacket
& p
, std::unique_ptr
<DNSPacket
>& r
, const DNSName
& target
, const DNSName
& wildcard
, int mode
)
802 NSEC3PARAMRecordContent ns3rc
;
804 if(d_dk
.getNSEC3PARAM(d_sd
.qname
, &ns3rc
, &narrow
)) {
805 if (mode
!= 5) // no direct NSEC3 queries, rfc5155 7.2.8
806 addNSEC3(p
, r
, target
, wildcard
, ns3rc
, narrow
, mode
);
809 addNSEC(p
, r
, target
, wildcard
, mode
);
813 bool PacketHandler::getNSEC3Hashes(bool narrow
, const std::string
& hashed
, bool decrement
, DNSName
& unhashed
, std::string
& before
, std::string
& after
, int mode
)
816 if(narrow
) { // nsec3-narrow
820 decrementHash(before
);
824 incrementHash(after
);
827 DNSName hashedName
= DNSName(toBase32Hex(hashed
));
828 DNSName beforeName
, afterName
;
829 if (!decrement
&& mode
>= 2)
830 beforeName
= hashedName
;
831 ret
=d_sd
.db
->getBeforeAndAfterNamesAbsolute(d_sd
.domain_id
, hashedName
, unhashed
, beforeName
, afterName
);
832 before
=fromBase32Hex(beforeName
.toString());
833 after
=fromBase32Hex(afterName
.toString());
838 void PacketHandler::addNSEC3(DNSPacket
& p
, std::unique_ptr
<DNSPacket
>& r
, const DNSName
& target
, const DNSName
& wildcard
, const NSEC3PARAMRecordContent
& ns3rc
, bool narrow
, int mode
)
840 DLOG(g_log
<<"addNSEC3() mode="<<mode
<<" auth="<<d_sd
.qname
<<" target="<<target
<<" wildcard="<<wildcard
<<endl
);
842 if (d_sd
.db
== nullptr) {
843 if(!B
.getSOAUncached(d_sd
.qname
, d_sd
)) {
844 DLOG(g_log
<<"Could not get SOA for domain");
849 bool doNextcloser
= false;
850 string before
, after
, hashed
;
851 DNSName unhashed
, closest
;
853 if (mode
== 2 || mode
== 3 || mode
== 4) {
859 // add matching NSEC3 RR
861 unhashed
=(mode
== 0 || mode
== 1 || mode
== 5) ? target
: closest
;
862 hashed
=hashQNameWithSalt(ns3rc
, unhashed
);
863 DLOG(g_log
<<"1 hash: "<<toBase32Hex(hashed
)<<" "<<unhashed
<<endl
);
865 getNSEC3Hashes(narrow
, hashed
, false, unhashed
, before
, after
, mode
);
867 if (((mode
== 0 && ns3rc
.d_flags
) || mode
== 1) && (hashed
!= before
)) {
868 DLOG(g_log
<<"No matching NSEC3, do closest (provable) encloser"<<endl
);
870 bool doBreak
= false;
872 while( closest
.chopOff() && (closest
!= d_sd
.qname
)) { // stop at SOA
873 B
.lookup(QType(QType::ANY
), closest
, d_sd
.domain_id
, &p
);
882 hashed
=hashQNameWithSalt(ns3rc
, unhashed
);
883 DLOG(g_log
<<"1 hash: "<<toBase32Hex(hashed
)<<" "<<unhashed
<<endl
);
885 getNSEC3Hashes(narrow
, hashed
, false, unhashed
, before
, after
);
888 if (!after
.empty()) {
889 DLOG(g_log
<<"Done calling for matching, hashed: '"<<toBase32Hex(hashed
)<<"' before='"<<toBase32Hex(before
)<<"', after='"<<toBase32Hex(after
)<<"'"<<endl
);
890 emitNSEC3(r
, ns3rc
, unhashed
, before
, after
, mode
);
894 // add covering NSEC3 RR
895 if ((mode
>= 2 && mode
<= 4) || doNextcloser
) {
896 DNSName
next(target
);
900 while( next
.chopOff() && !(next
==closest
));
902 hashed
=hashQNameWithSalt(ns3rc
, unhashed
);
903 DLOG(g_log
<<"2 hash: "<<toBase32Hex(hashed
)<<" "<<unhashed
<<endl
);
905 getNSEC3Hashes(narrow
, hashed
, true, unhashed
, before
, after
);
906 DLOG(g_log
<<"Done calling for covering, hashed: '"<<toBase32Hex(hashed
)<<"' before='"<<toBase32Hex(before
)<<"', after='"<<toBase32Hex(after
)<<"'"<<endl
);
907 emitNSEC3( r
, ns3rc
, unhashed
, before
, after
, mode
);
911 if (mode
== 2 || mode
== 4) {
912 unhashed
=g_wildcarddnsname
+closest
;
914 hashed
=hashQNameWithSalt(ns3rc
, unhashed
);
915 DLOG(g_log
<<"3 hash: "<<toBase32Hex(hashed
)<<" "<<unhashed
<<endl
);
917 getNSEC3Hashes(narrow
, hashed
, (mode
!= 2), unhashed
, before
, after
);
918 DLOG(g_log
<<"Done calling for '*', hashed: '"<<toBase32Hex(hashed
)<<"' before='"<<toBase32Hex(before
)<<"', after='"<<toBase32Hex(after
)<<"'"<<endl
);
919 emitNSEC3( r
, ns3rc
, unhashed
, before
, after
, mode
);
923 void PacketHandler::addNSEC(DNSPacket
& /* p */, std::unique_ptr
<DNSPacket
>& r
, const DNSName
& target
, const DNSName
& wildcard
, int mode
)
925 DLOG(g_log
<<"addNSEC() mode="<<mode
<<" auth="<<d_sd
.qname
<<" target="<<target
<<" wildcard="<<wildcard
<<endl
);
927 if (d_sd
.db
== nullptr) {
928 if(!B
.getSOAUncached(d_sd
.qname
, d_sd
)) {
929 DLOG(g_log
<<"Could not get SOA for domain"<<endl
);
934 DNSName before
,after
;
935 d_sd
.db
->getBeforeAndAfterNames(d_sd
.domain_id
, d_sd
.qname
, target
, before
, after
);
936 if (mode
!= 5 || before
== target
)
937 emitNSEC(r
, before
, after
, mode
);
939 if (mode
== 2 || mode
== 4) {
940 // wildcard NO-DATA or wildcard denial
942 DNSName
closest(wildcard
);
945 closest
.prependRawLabel("*");
947 d_sd
.db
->getBeforeAndAfterNames(d_sd
.domain_id
, d_sd
.qname
, closest
, before
, after
);
948 emitNSEC(r
, before
, after
, mode
);
955 - only one backend owns the SOA of a zone
956 - only one AXFR per zone at a time - double startTransaction should fail
957 - backends need to implement transaction semantics
960 How BindBackend would implement this:
961 startTransaction makes a file
962 feedRecord sends everything to that file
963 commitTransaction moves that file atomically over the regular file, and triggers a reload
964 rollbackTransaction removes the file
967 How PostgreSQLBackend would implement this:
968 startTransaction starts a sql transaction, which also deletes all records
969 feedRecord is an insert statement
970 commitTransaction commits the transaction
971 rollbackTransaction aborts it
973 How MySQLBackend would implement this:
978 int PacketHandler::trySuperMaster(const DNSPacket
& p
, const DNSName
& tsigkeyname
)
982 // do it right now if the client is TCP
984 return trySuperMasterSynchronous(p
, tsigkeyname
);
988 // queue it if the client is on UDP
989 Communicator
.addTrySuperMasterRequest(p
);
994 int PacketHandler::trySuperMasterSynchronous(const DNSPacket
& p
, const DNSName
& tsigkeyname
)
996 ComboAddress remote
= p
.getInnerRemote();
997 if(p
.hasEDNSSubnet() && pdns::isAddressTrustedNotificationProxy(remote
)) {
998 remote
= p
.getRealRemote().getNetwork();
1001 remote
= p
.getInnerRemote();
1005 Resolver::res_t nsset
;
1008 uint32_t theirserial
;
1009 resolver
.getSoaSerial(remote
, p
.qdomain
, &theirserial
);
1010 resolver
.resolve(remote
, p
.qdomain
, QType::NS
, &nsset
);
1012 catch(ResolverException
&re
) {
1013 g_log
<<Logger::Error
<<"Error resolving SOA or NS for "<<p
.qdomain
<<" at: "<< remote
<<": "<<re
.reason
<<endl
;
1014 return RCode::ServFail
;
1017 // check if the returned records are NS records
1019 for(const auto& ns
: nsset
) {
1020 if(ns
.qtype
==QType::NS
)
1025 g_log
<<Logger::Error
<<"While checking for supermaster, did not find NS for "<<p
.qdomain
<<" at: "<< remote
<<endl
;
1026 return RCode::ServFail
;
1029 string nameserver
, account
;
1032 if (!::arg().mustDo("allow-unsigned-autoprimary") && tsigkeyname
.empty()) {
1033 g_log
<<Logger::Error
<<"Received unsigned NOTIFY for "<<p
.qdomain
<<" from potential supermaster "<<remote
<<". Refusing."<<endl
;
1034 return RCode::Refused
;
1037 if(!B
.superMasterBackend(remote
.toString(), p
.qdomain
, nsset
, &nameserver
, &account
, &db
)) {
1038 g_log
<<Logger::Error
<<"Unable to find backend willing to host "<<p
.qdomain
<<" for potential supermaster "<<remote
<<". Remote nameservers: "<<endl
;
1039 for(const auto& rr
: nsset
) {
1040 if(rr
.qtype
==QType::NS
)
1041 g_log
<<Logger::Error
<<rr
.content
<<endl
;
1043 return RCode::Refused
;
1046 db
->createSlaveDomain(remote
.toString(), p
.qdomain
, nameserver
, account
);
1048 if (!db
->getDomainInfo(p
.qdomain
, di
, false)) {
1049 g_log
<< Logger::Error
<< "Failed to create " << p
.qdomain
<< " for potential supermaster " << remote
<< endl
;
1050 return RCode::ServFail
;
1052 g_zoneCache
.add(p
.qdomain
, di
.id
);
1053 if (tsigkeyname
.empty() == false) {
1054 vector
<string
> meta
;
1055 meta
.push_back(tsigkeyname
.toStringNoDot());
1056 db
->setDomainMetadata(p
.qdomain
, "AXFR-MASTER-TSIG", meta
);
1059 catch(PDNSException
& ae
) {
1060 g_log
<<Logger::Error
<<"Database error trying to create "<<p
.qdomain
<<" for potential supermaster "<<remote
<<": "<<ae
.reason
<<endl
;
1061 return RCode::ServFail
;
1063 g_log
<<Logger::Warning
<<"Created new slave zone '"<<p
.qdomain
<<"' from supermaster "<<remote
<<endl
;
1064 return RCode::NoError
;
1067 int PacketHandler::processNotify(const DNSPacket
& p
)
1070 was this notification from an approved address?
1071 was this notification approved by TSIG?
1072 We determine our internal SOA id (via UeberBackend)
1073 We determine the SOA at our (known) master
1074 if master is higher -> do stuff
1077 g_log
<<Logger::Debug
<<"Received NOTIFY for "<<p
.qdomain
<<" from "<<p
.getRemoteString()<<endl
;
1079 if(!::arg().mustDo("secondary") && s_forwardNotify
.empty()) {
1080 g_log
<<Logger::Warning
<<"Received NOTIFY for "<<p
.qdomain
<<" from "<<p
.getRemoteString()<<" but slave support is disabled in the configuration"<<endl
;
1081 return RCode::Refused
;
1084 // Sender verification
1086 if(!s_allowNotifyFrom
.match(p
.getInnerRemote()) || p
.d_havetsig
) {
1087 if (p
.d_havetsig
&& p
.getTSIGKeyname().empty() == false) {
1088 g_log
<<Logger::Notice
<<"Received secure NOTIFY for "<<p
.qdomain
<<" from "<<p
.getRemoteString()<<", with TSIG key '"<<p
.getTSIGKeyname()<<"'"<<endl
;
1090 g_log
<<Logger::Warning
<<"Received NOTIFY for "<<p
.qdomain
<<" from "<<p
.getRemoteString()<<" but the remote is not providing a TSIG key or in allow-notify-from (Refused)"<<endl
;
1091 return RCode::Refused
;
1095 if ((!::arg().mustDo("allow-unsigned-notify") && !p
.d_havetsig
) || p
.d_havetsig
) {
1096 if (!p
.d_havetsig
) {
1097 g_log
<<Logger::Warning
<<"Received unsigned NOTIFY for "<<p
.qdomain
<<" from "<<p
.getRemoteString()<<" while a TSIG key was required (Refused)"<<endl
;
1098 return RCode::Refused
;
1100 vector
<string
> meta
;
1101 if (B
.getDomainMetadata(p
.qdomain
,"AXFR-MASTER-TSIG",meta
) && meta
.size() > 0) {
1102 DNSName expected
{meta
[0]};
1103 if (p
.getTSIGKeyname() != expected
) {
1104 g_log
<<Logger::Warning
<<"Received secure NOTIFY for "<<p
.qdomain
<<" from "<<p
.getRemoteString()<<": expected TSIG key '"<<expected
<<"', got '"<<p
.getTSIGKeyname()<<"' (Refused)"<<endl
;
1105 return RCode::Refused
;
1110 // Domain verification
1113 if(!B
.getDomainInfo(p
.qdomain
, di
, false) || !di
.backend
) {
1114 if(::arg().mustDo("autosecondary")) {
1115 g_log
<<Logger::Warning
<<"Received NOTIFY for "<<p
.qdomain
<<" from "<<p
.getRemoteString()<<" for which we are not authoritative, trying supermaster"<<endl
;
1116 return trySuperMaster(p
, p
.getTSIGKeyname());
1118 g_log
<<Logger::Notice
<<"Received NOTIFY for "<<p
.qdomain
<<" from "<<p
.getRemoteString()<<" for which we are not authoritative (Refused)"<<endl
;
1119 return RCode::Refused
;
1122 if(pdns::isAddressTrustedNotificationProxy(p
.getInnerRemote())) {
1123 if(di
.masters
.empty()) {
1124 g_log
<<Logger::Warning
<<"Received NOTIFY for "<<p
.qdomain
<<" from trusted-notification-proxy "<<p
.getRemoteString()<<", zone does not have any masters defined (Refused)"<<endl
;
1125 return RCode::Refused
;
1127 g_log
<<Logger::Notice
<<"Received NOTIFY for "<<p
.qdomain
<<" from trusted-notification-proxy "<<p
.getRemoteString()<<endl
;
1129 else if (::arg().mustDo("primary") && di
.isPrimaryType()) {
1130 g_log
<< Logger::Warning
<< "Received NOTIFY for " << p
.qdomain
<< " from " << p
.getRemoteString() << " but we are primary (Refused)" << endl
;
1131 return RCode::Refused
;
1133 else if(!di
.isMaster(p
.getInnerRemote())) {
1134 g_log
<<Logger::Warning
<<"Received NOTIFY for "<<p
.qdomain
<<" from "<<p
.getRemoteString()<<" which is not a master (Refused)"<<endl
;
1135 return RCode::Refused
;
1138 if(!s_forwardNotify
.empty()) {
1139 set
<string
> forwardNotify(s_forwardNotify
);
1140 for(const auto & j
: forwardNotify
) {
1141 g_log
<<Logger::Notice
<<"Relaying notification of domain "<<p
.qdomain
<<" from "<<p
.getRemoteString()<<" to "<<j
<<endl
;
1142 Communicator
.notify(p
.qdomain
,j
);
1146 if(::arg().mustDo("secondary")) {
1147 g_log
<<Logger::Notice
<<"Received NOTIFY for "<<p
.qdomain
<<" from "<<p
.getRemoteString()<<" - queueing check"<<endl
;
1148 di
.receivedNotify
= true;
1149 Communicator
.addSlaveCheckRequest(di
, p
.getInnerRemote());
1154 static bool validDNSName(const DNSName
& name
)
1157 return name
.has8bitBytes() == false;
1162 std::unique_ptr
<DNSPacket
> PacketHandler::question(DNSPacket
& p
)
1164 std::unique_ptr
<DNSPacket
> ret
{nullptr};
1168 ret
=d_pdl
->prequery(p
);
1174 static AtomicCounter
&rdqueries
=*S
.getPointer("rd-queries");
1178 return doQuestion(p
);
1182 void PacketHandler::makeNXDomain(DNSPacket
& p
, std::unique_ptr
<DNSPacket
>& r
, const DNSName
& target
, const DNSName
& wildcard
)
1185 rr
=makeEditedDNSZRFromSOAData(d_dk
, d_sd
, DNSResourceRecord::AUTHORITY
);
1186 rr
.dr
.d_ttl
=d_sd
.getNegativeTTL();
1187 r
->addRecord(std::move(rr
));
1190 addNSECX(p
, r
, target
, wildcard
, 4);
1193 r
->setRcode(RCode::NXDomain
);
1196 void PacketHandler::makeNOError(DNSPacket
& p
, std::unique_ptr
<DNSPacket
>& r
, const DNSName
& target
, const DNSName
& wildcard
, int mode
)
1199 rr
=makeEditedDNSZRFromSOAData(d_dk
, d_sd
, DNSResourceRecord::AUTHORITY
);
1200 rr
.dr
.d_ttl
=d_sd
.getNegativeTTL();
1201 r
->addRecord(std::move(rr
));
1204 addNSECX(p
, r
, target
, wildcard
, mode
);
1207 S
.inc("noerror-packets");
1208 S
.ringAccount("noerror-queries", p
.qdomain
, p
.qtype
);
1212 bool PacketHandler::addDSforNS(DNSPacket
& p
, std::unique_ptr
<DNSPacket
>& r
, const DNSName
& dsname
)
1214 //cerr<<"Trying to find a DS for '"<<dsname<<"', domain_id = "<<d_sd.domain_id<<endl;
1215 B
.lookup(QType(QType::DS
), dsname
, d_sd
.domain_id
, &p
);
1220 rr
.dr
.d_place
= DNSResourceRecord::AUTHORITY
;
1221 r
->addRecord(std::move(rr
));
1226 bool PacketHandler::tryReferral(DNSPacket
& p
, std::unique_ptr
<DNSPacket
>& r
, const DNSName
&target
, bool retargeted
)
1228 vector
<DNSZoneRecord
> rrset
= getBestReferralNS(p
, target
);
1232 DNSName name
= rrset
.begin()->dr
.d_name
;
1233 for(auto& rr
: rrset
) {
1234 rr
.dr
.d_place
=DNSResourceRecord::AUTHORITY
;
1235 r
->addRecord(std::move(rr
));
1240 if(d_dk
.isSecuredZone(d_sd
.qname
) && !addDSforNS(p
, r
, name
) && d_dnssec
) {
1241 addNSECX(p
, r
, name
, DNSName(), 1);
1247 void PacketHandler::completeANYRecords(DNSPacket
& p
, std::unique_ptr
<DNSPacket
>& r
, const DNSName
&target
)
1249 addNSECX(p
, r
, target
, DNSName(), 5);
1250 if(d_sd
.qname
== p
.qdomain
) {
1251 if(!d_dk
.isPresigned(d_sd
.qname
)) {
1256 addNSEC3PARAM(p
, r
);
1260 bool PacketHandler::tryDNAME(DNSPacket
& p
, std::unique_ptr
<DNSPacket
>& r
, DNSName
&target
)
1264 DLOG(g_log
<<Logger::Warning
<<"Let's try DNAME.."<<endl
);
1265 vector
<DNSZoneRecord
> rrset
;
1267 getBestDNAMESynth(p
, target
, rrset
);
1268 if(!rrset
.empty()) {
1269 for(size_t i
= 0; i
< rrset
.size(); i
++) {
1270 rrset
.at(i
).dr
.d_place
= DNSResourceRecord::ANSWER
;
1271 r
->addRecord(std::move(rrset
.at(i
)));
1275 } catch (const std::range_error
&e
) {
1276 // Add the DNAME regardless, but throw to let the caller know we could not
1277 // synthesize a CNAME
1278 if(!rrset
.empty()) {
1279 for(size_t i
= 0; i
< rrset
.size(); i
++) {
1280 rrset
.at(i
).dr
.d_place
= DNSResourceRecord::ANSWER
;
1281 r
->addRecord(std::move(rrset
.at(i
)));
1288 bool PacketHandler::tryWildcard(DNSPacket
& p
, std::unique_ptr
<DNSPacket
>& r
, DNSName
&target
, DNSName
&wildcard
, bool& retargeted
, bool& nodata
)
1290 retargeted
= nodata
= false;
1293 vector
<DNSZoneRecord
> rrset
;
1294 if(!getBestWildcard(p
, target
, wildcard
, &rrset
))
1298 DLOG(g_log
<<"Wildcard matched something, but not of the correct type"<<endl
);
1302 for(auto& rr
: rrset
) {
1303 rr
.wildcardname
= rr
.dr
.d_name
;
1304 rr
.dr
.d_name
=bestmatch
=target
;
1306 if(rr
.dr
.d_type
== QType::CNAME
) {
1308 target
=getRR
<CNAMERecordContent
>(rr
.dr
)->getTarget();
1311 rr
.dr
.d_place
=DNSResourceRecord::ANSWER
;
1312 r
->addRecord(std::move(rr
));
1315 if(d_dnssec
&& !nodata
) {
1316 addNSECX(p
, r
, bestmatch
, wildcard
, 3);
1322 //! Called by the Distributor to ask a question. Returns 0 in case of an error
1323 std::unique_ptr
<DNSPacket
> PacketHandler::doQuestion(DNSPacket
& p
)
1327 int retargetcount
=0;
1328 set
<DNSName
> authSet
;
1330 vector
<DNSZoneRecord
> rrset
;
1331 bool weDone
=false, weRedirected
=false, weHaveUnauth
=false, doSigs
=false;
1333 uint8_t aliasScopeMask
;
1335 std::unique_ptr
<DNSPacket
> r
{nullptr};
1338 #ifdef HAVE_LUA_RECORDS
1339 bool doLua
=g_doLuaRecord
;
1342 if(p
.d
.qr
) { // QR bit from dns packet (thanks RA from N)
1344 g_log
<<Logger::Error
<<"Received an answer (non-query) packet from "<<p
.getRemoteString()<<", dropping"<<endl
;
1345 S
.inc("corrupt-packets");
1346 S
.ringAccount("remotes-corrupt", p
.getInnerRemote());
1350 if(p
.d
.tc
) { // truncated query. MOADNSParser would silently parse this packet in an incomplete way.
1352 g_log
<<Logger::Error
<<"Received truncated query packet from "<<p
.getRemoteString()<<", dropping"<<endl
;
1353 S
.inc("corrupt-packets");
1354 S
.ringAccount("remotes-corrupt", p
.getInnerRemote());
1359 if(p
.getEDNSVersion() > 0) {
1360 r
= p
.replyPacket();
1362 // PacketWriter::addOpt will take care of setting this correctly in the packet
1363 r
->setEDNSRcode(ERCode::BADVERS
);
1366 if (p
.hasEDNSCookie()) {
1367 if (!p
.hasWellFormedEDNSCookie()) {
1368 r
= p
.replyPacket();
1369 r
->setRcode(RCode::FormErr
);
1372 if (!p
.hasValidEDNSCookie() && !p
.d_tcp
) {
1373 r
= p
.replyPacket();
1374 r
->setEDNSRcode(ERCode::BADCOOKIE
);
1383 TSIGRecordContent trc
;
1384 if(!p
.checkForCorrectTSIG(&B
, &keyname
, &secret
, &trc
)) {
1385 r
=p
.replyPacket(); // generate an empty reply packet
1387 g_log
<<Logger::Error
<<"Received a TSIG signed message with a non-validating key"<<endl
;
1388 // RFC3007 describes that a non-secure message should be sending Refused for DNS Updates
1389 if (p
.d
.opcode
== Opcode::Update
)
1390 r
->setRcode(RCode::Refused
);
1392 r
->setRcode(RCode::NotAuth
);
1395 getTSIGHashEnum(trc
.d_algoName
, p
.d_tsig_algo
);
1396 #ifdef ENABLE_GSS_TSIG
1397 if (g_doGssTSIG
&& p
.d_tsig_algo
== TSIG_GSS
) {
1398 GssContext
gssctx(keyname
);
1399 if (!gssctx
.getPeerPrincipal(p
.d_peer_principal
)) {
1400 g_log
<<Logger::Warning
<<"Failed to extract peer principal from GSS context with keyname '"<<keyname
<<"'"<<endl
;
1405 p
.setTSIGDetails(trc
, keyname
, secret
, trc
.d_mac
); // this will get copied by replyPacket()
1409 r
=p
.replyPacket(); // generate an empty reply packet, possibly with TSIG details inside
1411 if (p
.qtype
== QType::TKEY
) {
1412 this->tkeyHandler(p
, r
);
1418 // XXX FIXME do this in DNSPacket::parse ?
1420 if(!validDNSName(p
.qdomain
)) {
1422 g_log
<<Logger::Error
<<"Received a malformed qdomain from "<<p
.getRemoteString()<<", '"<<p
.qdomain
<<"': sending servfail"<<endl
;
1423 S
.inc("corrupt-packets");
1424 S
.ringAccount("remotes-corrupt", p
.getInnerRemote());
1425 S
.inc("servfail-packets");
1426 r
->setRcode(RCode::ServFail
);
1429 if(p
.d
.opcode
) { // non-zero opcode (again thanks RA!)
1430 if(p
.d
.opcode
==Opcode::Update
) {
1431 S
.inc("dnsupdate-queries");
1432 int res
=processUpdate(p
);
1433 if (res
== RCode::Refused
)
1434 S
.inc("dnsupdate-refused");
1435 else if (res
!= RCode::ServFail
)
1436 S
.inc("dnsupdate-answers");
1438 r
->setOpcode(Opcode::Update
);
1441 else if(p
.d
.opcode
==Opcode::Notify
) {
1442 S
.inc("incoming-notifications");
1443 int res
=processNotify(p
);
1446 r
->setOpcode(Opcode::Notify
);
1452 g_log
<<Logger::Error
<<"Received an unknown opcode "<<p
.d
.opcode
<<" from "<<p
.getRemoteString()<<" for "<<p
.qdomain
<<endl
;
1454 r
->setRcode(RCode::NotImp
);
1458 // g_log<<Logger::Warning<<"Query for '"<<p.qdomain<<"' "<<p.qtype.toString()<<" from "<<p.getRemoteString()<< " (tcp="<<p.d_tcp<<")"<<endl;
1460 if(p
.qtype
.getCode()==QType::IXFR
) {
1461 r
->setRcode(RCode::Refused
);
1465 DNSName target
=p
.qdomain
;
1467 // catch chaos qclass requests
1468 if(p
.qclass
== QClass::CHAOS
) {
1469 if (doChaosRequest(p
,r
,target
))
1475 // we only know about qclass IN (and ANY), send Refused for everything else.
1476 if(p
.qclass
!= QClass::IN
&& p
.qclass
!=QClass::ANY
) {
1477 r
->setRcode(RCode::Refused
);
1481 // send TC for udp ANY query if any-to-tcp is enabled.
1482 if(p
.qtype
.getCode() == QType::ANY
&& !p
.d_tcp
&& g_anyToTcp
) {
1488 // for qclass ANY the response should never be authoritative unless the response covers all classes.
1489 if(p
.qclass
==QClass::ANY
)
1494 if(retargetcount
> 10) { // XXX FIXME, retargetcount++?
1495 g_log
<<Logger::Warning
<<"Abort CNAME chain resolution after "<<--retargetcount
<<" redirects, sending out servfail. Initial query: '"<<p
.qdomain
<<"'"<<endl
;
1497 r
->setRcode(RCode::ServFail
);
1501 if(!B
.getAuth(target
, p
.qtype
, &d_sd
)) {
1502 DLOG(g_log
<<Logger::Error
<<"We have no authority over zone '"<<target
<<"'"<<endl
);
1503 if(!retargetcount
) {
1504 r
->setA(false); // drop AA if we never had a SOA in the first place
1505 r
->setRcode(RCode::Refused
); // send REFUSED - but only on empty 'no idea'
1509 DLOG(g_log
<<Logger::Error
<<"We have authority, zone='"<<d_sd
.qname
<<"', id="<<d_sd
.domain_id
<<endl
);
1511 authSet
.insert(d_sd
.qname
);
1512 d_dnssec
=(p
.d_dnssecOk
&& d_dk
.isSecuredZone(d_sd
.qname
));
1515 if(!retargetcount
) r
->qdomainzone
=d_sd
.qname
;
1517 if(d_sd
.qname
==p
.qdomain
) {
1518 if(!d_dk
.isPresigned(d_sd
.qname
)) {
1519 if(p
.qtype
.getCode() == QType::DNSKEY
)
1524 else if(p
.qtype
.getCode() == QType::CDNSKEY
)
1529 else if(p
.qtype
.getCode() == QType::CDS
)
1535 if(p
.qtype
.getCode() == QType::NSEC3PARAM
)
1537 if(addNSEC3PARAM(p
,r
))
1542 if(p
.qtype
.getCode() == QType::SOA
&& d_sd
.qname
==p
.qdomain
) {
1543 rr
=makeEditedDNSZRFromSOAData(d_dk
, d_sd
);
1544 r
->addRecord(std::move(rr
));
1548 // this TRUMPS a cname!
1549 if(d_dnssec
&& p
.qtype
.getCode() == QType::NSEC
&& !d_dk
.getNSEC3PARAM(d_sd
.qname
, nullptr)) {
1550 addNSEC(p
, r
, target
, DNSName(), 5);
1555 // this TRUMPS a cname!
1556 if(p
.qtype
.getCode() == QType::RRSIG
) {
1557 g_log
<<Logger::Info
<<"Direct RRSIG query for "<<target
<<" from "<<p
.getRemoteString()<<endl
;
1558 r
->setRcode(RCode::Refused
);
1562 DLOG(g_log
<<"Checking for referrals first, unless this is a DS query"<<endl
);
1563 if(p
.qtype
.getCode() != QType::DS
&& tryReferral(p
, r
, target
, retargetcount
))
1566 DLOG(g_log
<<"Got no referrals, trying ANY"<<endl
);
1568 #ifdef HAVE_LUA_RECORDS
1571 d_dk
.getFromMeta(d_sd
.qname
, "ENABLE-LUA-RECORDS", val
);
1576 // see what we get..
1577 B
.lookup(QType(QType::ANY
), target
, d_sd
.domain_id
, &p
);
1581 weDone
= weRedirected
= weHaveUnauth
= false;
1584 #ifdef HAVE_LUA_RECORDS
1585 if (rr
.dr
.d_type
== QType::LUA
&& !d_dk
.isPresigned(d_sd
.qname
)) {
1588 auto rec
=getRR
<LUARecordContent
>(rr
.dr
);
1592 if(rec
->d_type
== QType::CNAME
|| rec
->d_type
== p
.qtype
.getCode() || (p
.qtype
.getCode() == QType::ANY
&& rec
->d_type
!= QType::RRSIG
)) {
1595 auto recvec
=luaSynth(rec
->getCode(), target
, d_sd
.qname
, d_sd
.domain_id
, p
, rec
->d_type
, s_LUA
);
1596 if(!recvec
.empty()) {
1597 for (const auto& r_it
: recvec
) {
1598 rr
.dr
.d_type
= rec
->d_type
; // might be CNAME
1599 rr
.dr
.setContent(r_it
);
1600 rr
.scopeMask
= p
.getRealRemote().getBits(); // this makes sure answer is a specific as your question
1601 rrset
.push_back(rr
);
1603 if(rec
->d_type
== QType::CNAME
&& p
.qtype
.getCode() != QType::CNAME
)
1604 weRedirected
= true;
1609 catch(std::exception
&e
) {
1610 while (B
.get(rr
)) ; // don't leave DB handle in bad state
1613 r
->setRcode(RCode::ServFail
);
1620 //cerr<<"got content: ["<<rr.content<<"]"<<endl;
1621 if (!d_dnssec
&& p
.qtype
.getCode() == QType::ANY
&& (rr
.dr
.d_type
== QType:: DNSKEY
|| rr
.dr
.d_type
== QType::NSEC3PARAM
))
1622 continue; // Don't send dnssec info.
1623 if (rr
.dr
.d_type
== QType::RRSIG
) // RRSIGS are added later any way.
1624 continue; // TODO: this actually means addRRSig should check if the RRSig is already there
1626 // cerr<<"Auth: "<<rr.auth<<", "<<(rr.dr.d_type == p.qtype)<<", "<<rr.dr.d_type.toString()<<endl;
1627 if((p
.qtype
.getCode() == QType::ANY
|| rr
.dr
.d_type
== p
.qtype
.getCode()) && rr
.auth
)
1629 // the line below fakes 'unauth NS' for delegations for non-DNSSEC backends.
1630 if((rr
.dr
.d_type
== p
.qtype
.getCode() && !rr
.auth
) || (rr
.dr
.d_type
== QType::NS
&& (!rr
.auth
|| !(d_sd
.qname
==rr
.dr
.d_name
))))
1633 if(rr
.dr
.d_type
== QType::CNAME
&& p
.qtype
.getCode() != QType::CNAME
)
1636 if (DP
&& rr
.dr
.d_type
== QType::ALIAS
&& (p
.qtype
.getCode() == QType::A
|| p
.qtype
.getCode() == QType::AAAA
|| p
.qtype
.getCode() == QType::ANY
) && !d_dk
.isPresigned(d_sd
.qname
)) {
1637 if (!d_doExpandALIAS
) {
1638 g_log
<<Logger::Info
<<"ALIAS record found for "<<target
<<", but ALIAS expansion is disabled."<<endl
;
1641 haveAlias
=getRR
<ALIASRecordContent
>(rr
.dr
)->getContent();
1642 aliasScopeMask
=rr
.scopeMask
;
1645 // Filter out all SOA's and add them in later
1646 if(rr
.dr
.d_type
== QType::SOA
)
1649 rrset
.push_back(rr
);
1652 /* Add in SOA if required */
1653 if(target
==d_sd
.qname
) {
1654 rr
=makeEditedDNSZRFromSOAData(d_dk
, d_sd
);
1655 rrset
.push_back(rr
);
1659 DLOG(g_log
<<"After first ANY query for '"<<target
<<"', id="<<d_sd
.domain_id
<<": weDone="<<weDone
<<", weHaveUnauth="<<weHaveUnauth
<<", weRedirected="<<weRedirected
<<", haveAlias='"<<haveAlias
<<"'"<<endl
);
1660 if(p
.qtype
.getCode() == QType::DS
&& weHaveUnauth
&& !weDone
&& !weRedirected
) {
1661 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
);
1662 makeNOError(p
, r
, target
, DNSName(), 1);
1666 if(!haveAlias
.empty() && (!weDone
|| p
.qtype
.getCode() == QType::ANY
)) {
1667 DLOG(g_log
<<Logger::Warning
<<"Found nothing that matched for '"<<target
<<"', but did get alias to '"<<haveAlias
<<"', referring"<<endl
);
1668 DP
->completePacket(r
, haveAlias
, target
, aliasScopeMask
);
1673 // referral for DS query
1674 if(p
.qtype
.getCode() == QType::DS
) {
1675 DLOG(g_log
<<"Qtype is DS"<<endl
);
1676 bool doReferral
= true;
1677 if(d_dk
.doesDNSSEC()) {
1678 for(auto& loopRR
: rrset
) {
1679 // In a dnssec capable backend auth=true means, there is no delegation at
1680 // or above this qname in this zone (for DS queries). Without a delegation,
1681 // at or above this level, it is pointless to search for referrals.
1688 for(auto& loopRR
: rrset
) {
1689 // In a non dnssec capable backend auth is always true, so our only option
1690 // is, always look for referrals. Unless there is a direct match for DS.
1691 if(loopRR
.dr
.d_type
== QType::DS
) {
1698 DLOG(g_log
<<"DS query found no direct result, trying referral now"<<endl
);
1699 if(tryReferral(p
, r
, target
, retargetcount
))
1701 DLOG(g_log
<<"Got referral for DS query"<<endl
);
1709 DLOG(g_log
<<Logger::Warning
<<"Found nothing in the by-name ANY, but let's try wildcards.."<<endl
);
1710 bool wereRetargeted(false), nodata(false);
1712 if(tryWildcard(p
, r
, target
, wildcard
, wereRetargeted
, nodata
)) {
1713 if(wereRetargeted
) {
1714 if(!retargetcount
) r
->qdomainwild
=wildcard
;
1719 makeNOError(p
, r
, target
, wildcard
, 2);
1724 if (tryDNAME(p
, r
, target
)) {
1728 } catch (const std::range_error
&e
) {
1729 // We couldn't make a CNAME.....
1730 r
->setRcode(RCode::YXDomain
);
1734 if (!(((p
.qtype
.getCode() == QType::CNAME
) || (p
.qtype
.getCode() == QType::ANY
)) && retargetcount
> 0))
1735 makeNXDomain(p
, r
, target
, wildcard
);
1741 for(auto& loopRR
: rrset
) {
1742 if(loopRR
.dr
.d_type
== QType::CNAME
) {
1743 r
->addRecord(DNSZoneRecord(loopRR
));
1744 target
= getRR
<CNAMERecordContent
>(loopRR
.dr
)->getTarget();
1751 bool haveRecords
= false;
1752 bool presigned
= d_dk
.isPresigned(d_sd
.qname
);
1753 for(const auto& loopRR
: rrset
) {
1754 if (loopRR
.dr
.d_type
== QType::ENT
) {
1757 if (loopRR
.dr
.d_type
== QType::ALIAS
&& d_doExpandALIAS
&& !presigned
) {
1760 #ifdef HAVE_LUA_RECORDS
1761 if (loopRR
.dr
.d_type
== QType::LUA
&& !presigned
) {
1765 if ((p
.qtype
.getCode() == QType::ANY
|| loopRR
.dr
.d_type
== p
.qtype
.getCode()) && loopRR
.auth
) {
1766 r
->addRecord(DNSZoneRecord(loopRR
));
1772 if(d_dnssec
&& p
.qtype
.getCode() == QType::ANY
)
1773 completeANYRecords(p
, r
, target
);
1776 makeNOError(p
, r
, target
, DNSName(), 0);
1780 else if(weHaveUnauth
) {
1781 DLOG(g_log
<<"Have unauth data, so need to hunt for best NS records"<<endl
);
1782 if(tryReferral(p
, r
, target
, retargetcount
))
1784 // check whether this could be fixed easily
1785 // if (*(rr.dr.d_name.rbegin()) == '.') {
1786 // g_log<<Logger::Error<<"Should not get here ("<<p.qdomain<<"|"<<p.qtype.toString()<<"): you have a trailing dot, this could be the problem (or run pdnsutil rectify-zone " <<d_sd.qname<<")"<<endl;
1788 g_log
<<Logger::Error
<<"Should not get here ("<<p
.qdomain
<<"|"<<p
.qtype
.toString()<<"): please run pdnsutil rectify-zone "<<d_sd
.qname
<<endl
;
1792 DLOG(g_log
<<"Have some data, but not the right data"<<endl
);
1793 makeNOError(p
, r
, target
, DNSName(), 0);
1797 doAdditionalProcessing(p
, r
);
1799 for(const auto& loopRR
: r
->getRRS()) {
1800 if(loopRR
.scopeMask
) {
1806 addRRSigs(d_dk
, B
, authSet
, r
->getRRS());
1808 if(PC
.enabled() && !noCache
&& p
.couldBeCached())
1809 PC
.insert(p
, *r
, r
->getMinTTL()); // in the packet cache
1811 catch(const DBException
&e
) {
1812 g_log
<<Logger::Error
<<"Backend reported condition which prevented lookup ("+e
.reason
+") sending out servfail"<<endl
;
1813 r
=p
.replyPacket(); // generate an empty reply packet
1814 r
->setRcode(RCode::ServFail
);
1815 S
.inc("servfail-packets");
1816 S
.ringAccount("servfail-queries", p
.qdomain
, p
.qtype
);
1818 catch(const PDNSException
&e
) {
1819 g_log
<<Logger::Error
<<"Backend reported permanent error which prevented lookup ("+e
.reason
+"), aborting"<<endl
;
1820 throw; // we WANT to die at this point
1822 catch(const std::exception
&e
) {
1823 g_log
<<Logger::Error
<<"Exception building answer packet for "<<p
.qdomain
<<"/"<<p
.qtype
.toString()<<" ("<<e
.what()<<") sending out servfail"<<endl
;
1824 r
=p
.replyPacket(); // generate an empty reply packet
1825 r
->setRcode(RCode::ServFail
);
1826 S
.inc("servfail-packets");
1827 S
.ringAccount("servfail-queries", p
.qdomain
, p
.qtype
);