virtual void lookup(const QType &qtype, const string &qdomain, domainid_t zoneId=UnknownDomainID, DNSPacket *pkt_p=nullptr)=0;
virtual bool list(const string &target, domainid_t domain_id)=0;
virtual bool get(DNSResourceRecord &r)=0;
- virtual bool getSOA(const string &name, SOAData &soadata);
+ virtual bool getSOA(const string &name, domainid_t zoneId, SOAData &soadata);
};
Note that the first four methods must be implemented. ``getSOA()`` has
.. code-block:: cpp
SOAData sd;
- if(!yb.getSOA("powerdns.com",sd)) // are we authoritative over powerdns.com?
- return RCode::NotAuth; // no
+ if(!yb.getSOA("powerdns.com", UnknownDomainID, sd)) // are we authoritative over powerdns.com?
+ return RCode::NotAuth; // no
yb.list(sd.domain_id);
while(yb.get(rr))
Should throw an PDNSException in case a database error occurred.
-.. cpp:function:: bool DNSBackend::getSOA(const string &name, SOAData &soadata)
+.. cpp:function:: bool DNSBackend::getSOA(const string &name, domainid_t zoneId, SOAData &soadata)
- If the backend considers itself authoritative over domain ``name``, this
- method should fill out the passed **SOAData** structure and return true.
+ If the backend considers itself authoritative over domain ``name``, of
+ id ``zoneId`` if known (otherwise, ``UnknownDomainID``), this method should
+ fill out the passed **SOAData** structure and return true.
If the backend is functioning correctly, but does not consider itself
authoritative, it should return false. In case of errors, an
PDNSException should be thrown.
for (DomainInfo& di : consider) {
soadata.serial = 0;
try {
- this->getSOA(di.zone, soadata); // we might not *have* a SOA yet, but this might trigger a load of it
+ this->getSOA(di.zone, di.id, soadata); // we might not *have* a SOA yet, but this might trigger a load of it
}
catch (...) {
continue;
if (di.backend != this)
continue;
try {
- this->getSOA(di.zone, soadata);
+ this->getSOA(di.zone, di.id, soadata);
}
catch (...) {
continue;
soadata.refresh = 0;
soadata.serial = 0;
try {
- getSOA(sd.zone, soadata); // we might not *have* a SOA yet
+ getSOA(sd.zone, sd.id, soadata); // we might not *have* a SOA yet
}
catch (...) {
}
SOAData sd;
sd.serial = 0;
- getSOA(bbd.d_name, sd); // we might not *have* a SOA yet
+ getSOA(bbd.d_name, bbd.d_id, sd); // we might not *have* a SOA yet
info.serial = sd.serial;
}
catch (...) {
for (const GeoIPDomain& dom : s_domains) {
if (dom.domain == domain) {
SOAData sd;
- this->getSOA(domain, sd);
+ this->getSOA(dom.domain, dom.id, sd);
info.id = dom.id;
info.zone = dom.domain;
info.serial = sd.serial;
DomainInfo di;
for (const auto& dom : s_domains) {
SOAData sd;
- this->getSOA(dom.domain, sd);
+ this->getSOA(dom.domain, dom.id, sd);
di.id = dom.id;
di.zone = dom.domain;
di.serial = sd.serial;
bool getDomainInfo(const ZoneName& domain, DomainInfo& di, bool /* getSerial */ = true) override
{
if (f_get_domaininfo == nullptr) {
- // use getAuth instead
+ // use getAuth instead... but getAuth wraps getSOA which will call
+ // getDomainInfo if this is a domain variant, so protect against this
+ // would-be infinite recursion.
+ if (domain.hasVariant()) {
+ g_log << Logger::Info << "Unable to return domain information for '" << domain.toLogString() << "' due to unimplemented dns_get_domaininfo" << endl;
+ return false;
+ }
SOAData sd;
if (!getAuth(domain, &sd))
return false;
#include "lock.hh"
#include "misc.hh"
#include "iputils.hh"
+#include "dnspacket.hh"
class AuthZoneCache : public boost::noncopyable
{
if(getSerial) {
try {
SOAData sd;
- if(!getSOA(domain, sd))
+ if(!getSOA(domain, info.id, sd)) {
g_log<<Logger::Notice<<"No serial for '"<<domain<<"' found - zone is missing?"<<endl;
+ }
else
info.serial = sd.serial;
}
bool DNSBackend::getAuth(const ZoneName& target, SOAData* soaData)
{
- return this->getSOA(target, *soaData);
+ return this->getSOA(target, UnknownDomainID, *soaData);
}
void DNSBackend::setArgPrefix(const string& prefix)
answer, in which case you need to perform a getDomainInfo call!
\param domain Domain we want to get the SOA details of
- \param sd SOAData which is filled with the SOA details
+ \param zoneId Domain id, if known
+ \param soaData SOAData which is filled with the SOA details
\param unmodifiedSerial bool if set, serial will be returned as stored in the backend (maybe 0)
*/
-bool DNSBackend::getSOA(const ZoneName& domain, SOAData& soaData)
+bool DNSBackend::getSOA(const ZoneName& domain, domainid_t zoneId, SOAData& soaData)
{
- this->lookup(QType(QType::SOA), domain.operator const DNSName&(), -1);
+ soaData.db = nullptr;
+
+ if (domain.hasVariant() && zoneId == UnknownDomainID) {
+ DomainInfo domaininfo;
+ if (!this->getDomainInfo(domain, domaininfo, false)) {
+ return false;
+ }
+ zoneId = domaininfo.id;
+ }
+ this->lookup(QType(QType::SOA), domain.operator const DNSName&(), zoneId);
S.inc("backend-queries");
DNSResourceRecord resourceRecord;
int hits = 0;
- soaData.db = nullptr;
-
try {
while (this->get(resourceRecord)) {
if (resourceRecord.qtype != QType::SOA) {
virtual ~DNSBackend() = default;
//! fills the soadata struct with the SOA details. Returns false if there is no SOA.
- virtual bool getSOA(const ZoneName& domain, SOAData& soaData);
+ virtual bool getSOA(const ZoneName& domain, domainid_t zoneId, SOAData& soaData);
virtual bool replaceRRSet(domainid_t /* domain_id */, const DNSName& /* qname */, const QType& /* qt */, const vector<DNSResourceRecord>& /* rrset */)
{
DNSName qdomain; //!< qname of the question 4 - unsure how this is used
DNSName qdomainwild; //!< wildcard matched by qname, used by LuaPolicyEngine
- ZoneName qdomainzone; //!< zone name for the answer (as reflected in SOA for negative responses), used by LuaPolicyEngine
+ ZoneName qdomainzone; //!< zone name for the answer (as reflected in SOA for negative responses), used by LuaPolicyEngine and AXFR
string d_peer_principal;
const DNSName& getTSIGKeyname() const;
void PacketHandler::increaseSerial(const string &msgPrefix, const DomainInfo *di, const string& soaEditSetting, bool haveNSEC3, bool narrow, const NSEC3PARAMRecordContent *ns3pr) {
SOAData sd;
- if (!di->backend->getSOA(di->zone, sd)) {
+ if (!di->backend->getSOA(di->zone, di->id, sd)) {
throw PDNSException("SOA-Serial update failed because there was no SOA. Wowie.");
}
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#include "pdns/auth-zonecache.hh"
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
if(packet->qtype.getCode()==QType::AXFR) {
packet->d_xfr=true;
- doAXFR(packet->qdomain, packet, fd);
+ g_zoneCache.setZoneVariant(packet);
+ doAXFR(packet->qdomainzone, packet, fd);
continue;
}
if(packet->qtype.getCode()==QType::IXFR) {
packet->d_xfr=true;
+ g_zoneCache.setZoneVariant(packet);
doIXFR(packet, fd);
continue;
}
if(::arg().mustDo("disable-axfr"))
return false;
- ZoneName zonename(q->qdomain);
- string logPrefix=string(isAXFR ? "A" : "I")+"XFR-out zone '"+zonename.toLogString()+"', client '"+q->getInnerRemote().toStringWithPort()+"', ";
+ string logPrefix=string(isAXFR ? "A" : "I")+"XFR-out zone '"+q->qdomainzone.toLogString()+"', client '"+q->getInnerRemote().toStringWithPort()+"', ";
if(q->d_havetsig) { // if you have one, it must be good
TSIGRecordContent tsigContent;
#ifdef ENABLE_GSS_TSIG
if (g_doGssTSIG && q->d_tsig_algo == TSIG_GSS) {
vector<string> princs;
- packetHandler->getBackend()->getDomainMetadata(zonename, "GSS-ALLOW-AXFR-PRINCIPAL", princs);
+ packetHandler->getBackend()->getDomainMetadata(q->qdomainzone, "GSS-ALLOW-AXFR-PRINCIPAL", princs);
for(const std::string& princ : princs) {
if (q->d_peer_principal == princ) {
- g_log<<Logger::Warning<<"AXFR of domain '"<<zonename<<"' allowed: TSIG signed request with authorized principal '"<<q->d_peer_principal<<"' and algorithm 'gss-tsig'"<<endl;
+ g_log<<Logger::Warning<<"AXFR of domain '"<<q->qdomainzone<<"' allowed: TSIG signed request with authorized principal '"<<q->d_peer_principal<<"' and algorithm 'gss-tsig'"<<endl;
return true;
}
}
- g_log<<Logger::Warning<<"AXFR of domain '"<<zonename<<"' denied: TSIG signed request with principal '"<<q->d_peer_principal<<"' and algorithm 'gss-tsig' is not permitted"<<endl;
+ g_log<<Logger::Warning<<"AXFR of domain '"<<q->qdomainzone<<"' denied: TSIG signed request with principal '"<<q->d_peer_principal<<"' and algorithm 'gss-tsig' is not permitted"<<endl;
return false;
}
#endif
- if(!dk.TSIGGrantsAccess(zonename, tsigkeyname)) {
+ if(!dk.TSIGGrantsAccess(q->qdomainzone, tsigkeyname)) {
g_log<<Logger::Warning<<logPrefix<<"denied: key with name '"<<tsigkeyname<<"' and algorithm '"<<getTSIGAlgoName(q->d_tsig_algo)<<"' does not grant access"<<endl;
return false;
}
// cerr<<"doing per-zone-axfr-acls"<<endl;
SOAData sd;
- if(packetHandler->getBackend()->getSOAUncached(zonename,sd)) {
+ if(packetHandler->getBackend()->getSOAUncached(q->qdomainzone,sd)) {
// cerr<<"got backend and SOA"<<endl;
vector<string> acl;
- packetHandler->getBackend()->getDomainMetadata(zonename, "ALLOW-AXFR-FROM", acl);
+ packetHandler->getBackend()->getDomainMetadata(q->qdomainzone, "ALLOW-AXFR-FROM", acl);
for (const auto & i : acl) {
// cerr<<"matching against "<<*i<<endl;
if(pdns_iequals(i, "AUTO-NS")) {
extern CommunicatorClass Communicator;
- if(Communicator.justNotified(zonename, q->getInnerRemote().toString())) { // we just notified this ip
+ if(Communicator.justNotified(q->qdomainzone, q->getInnerRemote().toString())) { // we just notified this ip
g_log<<Logger::Notice<<logPrefix<<"allowed: client IP is from recently notified secondary"<<endl;
return true;
}
/** do the actual zone transfer. Return 0 in case of error, 1 in case of success */
-int TCPNameserver::doAXFR(const DNSName &target, std::unique_ptr<DNSPacket>& q, int outsock) // NOLINT(readability-function-cognitive-complexity)
+int TCPNameserver::doAXFR(const ZoneName &targetZone, std::unique_ptr<DNSPacket>& q, int outsock) // NOLINT(readability-function-cognitive-complexity)
{
- ZoneName targetZone(target);
+ DNSName target = targetZone.operator const DNSName&();
string logPrefix="AXFR-out zone '"+targetZone.toLogString()+"', client '"+q->getRemoteStringWithPort()+"', ";
std::unique_ptr<DNSPacket> outpacket= getFreshAXFRPacket(q);
if(securedZone && !presignedZone) { // this is where the DNSKEYs, CDNSKEYs and CDSs go in
bool doCDNSKEY = true, doCDS = true;
string publishCDNSKEY, publishCDS;
- ZoneName zonename(q->qdomain);
- dk.getPublishCDNSKEY(zonename, publishCDNSKEY);
- dk.getPublishCDS(zonename, publishCDS);
+ dk.getPublishCDNSKEY(q->qdomainzone, publishCDNSKEY);
+ dk.getPublishCDS(q->qdomainzone, publishCDS);
set<uint32_t> entryPointIds;
DNSSECKeeper::keyset_t entryPoints = dk.getEntryPoints(targetZone);
int TCPNameserver::doIXFR(std::unique_ptr<DNSPacket>& q, int outsock)
{
- ZoneName zonename(q->qdomain);
- string logPrefix="IXFR-out zone '"+zonename.toLogString()+"', client '"+q->getRemoteStringWithPort()+"', ";
+ string logPrefix="IXFR-out zone '"+q->qdomainzone.toLogString()+"', client '"+q->getRemoteStringWithPort()+"', ";
std::unique_ptr<DNSPacket> outpacket=getFreshAXFRPacket(q);
if(q->d_dnssecOk)
}
// canDoAXFR does all the ACL checks, and has the if(disable-axfr) shortcut, call it first.
- if(!canDoAXFR(q, false, *packetHandler) || !(*packetHandler)->getBackend()->getSOAUncached(zonename, sd)) {
+ if(!canDoAXFR(q, false, *packetHandler) || !(*packetHandler)->getBackend()->getSOAUncached(q->qdomainzone, sd)) {
g_log<<Logger::Warning<<logPrefix<<"failed: not authoritative"<<endl;
outpacket->setRcode(RCode::NotAuth);
sendPacket(outpacket,outsock);
}
DNSSECKeeper dk((*packetHandler)->getBackend());
- DNSSECKeeper::clearCaches(zonename);
+ DNSSECKeeper::clearCaches(q->qdomainzone);
bool narrow = false;
- securedZone = dk.isSecuredZone(zonename);
- if(dk.getNSEC3PARAM(zonename, nullptr, &narrow)) {
+ securedZone = dk.isSecuredZone(q->qdomainzone);
+ if(dk.getNSEC3PARAM(q->qdomainzone, nullptr, &narrow)) {
if(narrow) {
g_log<<Logger::Warning<<logPrefix<<"not doing IXFR of an NSEC3 narrow zone"<<endl;
outpacket->setRcode(RCode::Refused);
}
if (serialPermitsIXFR) {
- const ZoneName& target = zonename;
+ const ZoneName& target = q->qdomainzone;
TSIGRecordContent trc;
DNSName tsigkeyname;
string tsigsecret;
}
g_log<<Logger::Notice<<logPrefix<<"IXFR fallback to AXFR"<<endl;
- return doAXFR(q->qdomain, q, outsock);
+ return doAXFR(q->qdomainzone, q, outsock);
}
TCPNameserver::~TCPNameserver() = default;
static void sendPacket(std::unique_ptr<DNSPacket>& p, int outsock, bool last=true);
static void getQuestion(int fd, char *mesg, int pktlen, const ComboAddress& remote, unsigned int totalTime);
- static int doAXFR(const DNSName &target, std::unique_ptr<DNSPacket>& q, int outsock);
+ static int doAXFR(const ZoneName &target, std::unique_ptr<DNSPacket>& q, int outsock);
static int doIXFR(std::unique_ptr<DNSPacket>& q, int outsock);
static bool canDoAXFR(std::unique_ptr<DNSPacket>& q, bool isAXFR, std::unique_ptr<PacketHandler>& packetHandler);
static void doConnection(int fd);
return true;
}
- return getSOA(target, *soadata);
+ return getSOA(target, UnknownDomainID, *soadata);
}
size_t d_authLookupCount{0};
if (domain.hasVariant() && (backend->getCapabilities() & DNSBackend::CAP_VIEWS) == 0) {
continue;
}
- if (backend->getSOA(domain, soaData)) {
+ if (backend->getSOA(domain, UnknownDomainID, soaData)) {
if (domain.operator const DNSName&() != soaData.qname) {
throw PDNSException("getSOA() returned an SOA for the wrong zone. Question: '" + domain.toLogString() + "', answer: '" + soaData.qname.toLogString() + "'");
}