declare(suffix, "update-serial-query", "", "update domains set notified_serial=? where id=?");
declare(suffix, "update-lastcheck-query", "", "update domains set last_check=? where id=?");
declare(suffix, "info-all-master-query", "", "select d.id, d.name, d.type, d.notified_serial,d.options, d.catalog,r.content from records r join domains d on r.domain_id=d.id and r.name=d.name where r.type='SOA' and r.disabled=0 and d.type in ('MASTER', 'PRODUCER')");
+ declare(suffix, "info-producer-members-query", "", "select domains.id, domains.name, domains.options from records join domains on records.domain_id=domains.id and records.name=domains.name where domains.catalog=? and records.type='SOA' and records.disabled=0");
+ declare(suffix, "info-consumer-members-query", "", "select domains.id, domains.name, domains.options from domains left join records ON records.domain_id=domains.id and records.type='SOA' and records.name=domains.name where domains.catalog=?'");
declare(suffix, "delete-domain-query", "", "delete from domains where name=?");
declare(suffix, "delete-zone-query", "", "delete from records where domain_id=?");
declare(suffix, "delete-rrset-query", "", "delete from records where domain_id=? and name=? and type=?");
declare(suffix, "update-serial-query", "", "update domains set notified_serial=? where id=?");
declare(suffix, "update-lastcheck-query", "", "update domains set last_check=? where id=?");
declare(suffix, "info-all-master-query", "", "select domains.id, domains.name, domains.type, domains.notified_serial, domains.options, domains.catalog, records.content from records join domains on records.domain_id=domains.id and records.name=domains.name where records.type='SOA' and records.disabled=0 and domains.type in ('MASTER', 'PRODUCER')");
+ declare(suffix, "info-producer-members-query", "", "select domains.id, domains.name, domains.options from records join domains on records.domain_id=domains.id and records.name=domains.name where domains.catalog=? and records.type='SOA' and records.disabled=0");
+ declare(suffix, "info-consumer-members-query", "", "select domains.id, domains.name, domains.options from domains left join records ON records.domain_id=domains.id and records.type='SOA' and records.name=domains.name where domains.catalog=?'");
declare(suffix, "delete-domain-query", "", "delete from domains where name=?");
declare(suffix, "delete-zone-query", "", "delete from records where domain_id=?");
declare(suffix, "delete-rrset-query", "", "delete from records where domain_id=? and name=? and type=?");
declare(suffix, "update-serial-query", "", "update domains set notified_serial=$1 where id=$2");
declare(suffix, "update-lastcheck-query", "", "update domains set last_check=$1 where id=$2");
declare(suffix, "info-all-master-query", "", "select domains.id, domains.name, domains.type, domains.notified_serial, domains.options, domains.catalog, records.content from records join domains on records.domain_id=domains.id and records.name=domains.name where records.type='SOA' and records.disabled=false and domains.type in ('MASTER', 'PRODUCER')");
+ declare(suffix, "info-producer-members-query", "", "select domains.id, domains.name, domains.options from records join domains on records.domain_id=domains.id and records.name=domains.name where domains.catalog=$1 and records.type='SOA' and records.disabled=0");
+ declare(suffix, "info-consumer-members-query", "", "select domains.id, domains.name, domains.options from domains left join records ON records.domain_id=domains.id and records.type='SOA' and records.name=domains.name where domains.catalog=$1'");
declare(suffix, "delete-domain-query", "", "delete from domains where name=$1");
declare(suffix, "delete-zone-query", "", "delete from records where domain_id=$1");
declare(suffix, "delete-rrset-query", "", "delete from records where domain_id=$1 and name=$2 and type=$3");
declare(suffix, "update-serial-query", "", "update domains set notified_serial=:serial where id=:domain_id");
declare(suffix, "update-lastcheck-query", "", "update domains set last_check=:last_check where id=:domain_id");
declare(suffix, "info-all-master-query", "", "select domains.id, domains.name, domains.type, domains.notified_serial, domains.options, domains.catalog, records.content from records join domains on records.domain_id=domains.id and records.name=domains.name where records.type='SOA' and records.disabled=0 and domains.type in ('MASTER', 'PRODUCER')");
+ declare(suffix, "info-producer-members-query", "", "select domains.id, domains.name, domains.options from records join domains on records.domain_id=domains.id and records.name=domains.name where domains.catalog:catalog and records.type='SOA' and records.disabled=0");
+ declare(suffix, "info-consumer-members-query", "", "select domains.id, domains.name, domains.options from domains left join records ON records.domain_id=domains.id and records.type='SOA' and records.name=domains.name where domains.catalog:catalog'");
declare(suffix, "delete-domain-query", "", "delete from domains where name=:domain");
declare(suffix, "delete-zone-query", "", "delete from records where domain_id=:domain_id");
declare(suffix, "delete-rrset-query", "", "delete from records where domain_id=:domain_id and name=:qname and type=:qtype");
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
-#include "pdns/auth-catalogzone.hh"
#include "pdns/utility.hh"
#include "pdns/dnsbackend.hh"
#include "pdns/dns.hh"
});
}
-bool LMDBBackend::setOptions(const DNSName& domain, const std::string& options)
-{
- return genChangeDomain(domain, [options](DomainInfo& di) {
- di.options = options;
- });
-}
-
-bool LMDBBackend::setCatalog(const DNSName& domain, const DNSName& catalog)
-{
- return genChangeDomain(domain, [catalog](DomainInfo& di) {
- di.catalog = catalog;
- });
-}
-
bool LMDBBackend::setAccount(const DNSName& domain, const std::string& account)
{
return genChangeDomain(domain, [account](DomainInfo& di) {
auto txn = d_tdomains->getROTransaction();
for (auto iter = txn.begin(); iter != txn.end(); ++iter) {
- if (iter->kind != DomainInfo::Slave && iter->kind != DomainInfo::Consumer) {
+ if (!iter->isSecondaryType()) {
continue;
}
auto txn = d_tdomains->getROTransaction();
for (auto iter = txn.begin(); iter != txn.end(); ++iter) {
- if (iter->kind != DomainInfo::Master) {
+ if (!iter->isPrimaryType()) {
continue;
}
});
}
+bool LMDBBackend::getCatalogMembers(const DNSName& catalog, vector<CatalogInfo>& members, CatalogInfo::CatalogType type)
+{
+ auto txn = d_tdomains->getROTransaction();
+ for (auto iter = txn.begin(); iter != txn.end(); ++iter) {
+ if ((type == CatalogInfo::CatalogType::Producer && iter->kind != DomainInfo::Master) || (type == CatalogInfo::CatalogType::Consumer && iter->kind != DomainInfo::Slave) || iter->catalog != catalog) {
+ continue;
+ }
+
+ CatalogInfo ci;
+ ci.d_id = iter->id;
+ ci.d_zone = iter->zone;
+ try {
+ ci.fromJson(iter->options, type);
+ }
+ catch (const std::runtime_error& e) {
+ g_log << Logger::Warning << __PRETTY_FUNCTION__ << " options '" << iter->options << "' for zone '" << iter->zone << "' is no valid JSON: " << e.what() << endl;
+ members.clear();
+ return false;
+ }
+ members.emplace_back(ci);
+ }
+ return true;
+}
+
+bool LMDBBackend::setOptions(const DNSName& domain, const std::string& options)
+{
+ return genChangeDomain(domain, [options](DomainInfo& di) {
+ di.options = options;
+ });
+}
+
+bool LMDBBackend::setCatalog(const DNSName& domain, const DNSName& catalog)
+{
+ return genChangeDomain(domain, [catalog](DomainInfo& di) {
+ di.catalog = catalog;
+ });
+}
+
bool LMDBBackend::getAllDomainMetadata(const DNSName& name, std::map<std::string, std::vector<std::string>>& meta)
{
meta.clear();
void getUpdatedMasters(vector<DomainInfo>& updatedDomains, std::unordered_set<DNSName>& catalogs, CatalogHashMap& catalogHashes) override;
void setNotified(uint32_t id, uint32_t serial) override;
+ // catalog zones
+ bool getCatalogMembers(const DNSName& catalog, vector<CatalogInfo>& members, CatalogInfo::CatalogType type) override;
+ bool setOptions(const DNSName& domain, const std::string& options) override;
+ bool setCatalog(const DNSName& domain, const DNSName& options) override;
+
bool setMasters(const DNSName& domain, const vector<ComboAddress>& masters) override;
bool setKind(const DNSName& domain, const DomainInfo::DomainKind kind) override;
bool getAllDomainMetadata(const DNSName& name, std::map<std::string, std::vector<std::string>>& meta) override;
}
bool setDomainMetadata(const DNSName& name, const std::string& kind, const std::vector<std::string>& meta) override;
- bool setOptions(const DNSName& domain, const std::string& options) override;
- bool setCatalog(const DNSName& domain, const DNSName& options) override;
bool setAccount(const DNSName& domain, const std::string& account) override;
bool deleteDomain(const DNSName& domain) override;
#include "config.h"
#endif
-#include "auth-catalogzone.hh"
+#include "dnsbackend.hh"
void CatalogInfo::fromJson(const std::string& json, CatalogType type)
{
if (!d_doc.is_null()) {
if (!d_doc[getTypeString(d_type)].is_null()) {
auto items = d_doc[getTypeString(type)].object_items();
- if (items["coo"].is_string()) {
- if (!items["coo"].string_value().empty()) {
- this->coo = DNSName(items["coo"].string_value());
+ if (!items["coo"].is_null()) {
+ if (items["coo"].is_string()) {
+ if (!items["coo"].string_value().empty()) {
+ d_coo = DNSName(items["coo"].string_value());
+ }
}
- }
- else {
- throw std::out_of_range("Key 'coo' is not a string");
- }
- if (items["unique"].is_string()) {
- if (!items["uniq"].string_value().empty()) {
- this->unique = DNSName(items["unique"].string_value());
+ else {
+ throw std::out_of_range("Key 'coo' is not a string");
}
}
- else {
- throw std::out_of_range("Key 'unique' is not a string");
+ if (!items["unique"].is_null()) {
+ if (items["unique"].is_string()) {
+ if (!items["unique"].string_value().empty()) {
+ d_unique = DNSName(items["unique"].string_value());
+ }
+ }
+ else {
+ throw std::out_of_range("Key 'unique' is not a string");
+ }
}
}
}
throw std::runtime_error("CatalogType is set to None");
}
json11::Json::object object;
- if (!coo.empty()) {
- object["coo"] = coo.toString();
+ if (!d_coo.empty()) {
+ object["coo"] = d_coo.toString();
}
- if (!unique.empty()) {
- object["unique"] = unique.toString();
+ if (!d_unique.empty()) {
+ object["unique"] = d_unique.toString();
}
auto tmp = d_doc.object_items();
tmp[getTypeString(d_type)] = object;
void CatalogInfo::updateHash(CatalogHashMap& hashes, const DomainInfo& di) const
{
- hashes[di.catalog].process(static_cast<char>(di.id) + di.zone.toLogString() + "\0" + this->coo.toLogString() + "\0" + this->unique.toLogString());
+ hashes[di.catalog].process(static_cast<char>(di.id) + di.zone.toLogString() + "\0" + d_coo.toLogString() + "\0" + d_unique.toLogString());
+}
+
+DNSZoneRecord CatalogInfo::getCatalogVersionRecord(const DNSName& zone)
+{
+ DNSZoneRecord dzr;
+ dzr.dr.d_name = DNSName("version") + zone;
+ dzr.dr.d_ttl = 0;
+ dzr.dr.d_type = QType::TXT;
+ dzr.dr.d_content = std::make_shared<TXTRecordContent>("2");
+ return dzr;
+}
+
+void CatalogInfo::toDNSZoneRecords(const DNSName& zone, vector<DNSZoneRecord>& dzrs) const
+{
+ DNSName prefix;
+ if (d_unique.empty()) {
+ prefix = getUnique();
+ }
+ else {
+ prefix = d_unique;
+ }
+ prefix += DNSName("zones") + zone;
+
+ DNSZoneRecord dzr;
+ dzr.dr.d_name = prefix;
+ dzr.dr.d_ttl = 0;
+ dzr.dr.d_type = QType::PTR;
+ dzr.dr.d_content = std::make_shared<PTRRecordContent>(d_zone.toString());
+ dzrs.emplace_back(dzr);
+
+ if (!d_coo.empty()) {
+ dzr.dr.d_name = DNSName("coo") + prefix;
+ dzr.dr.d_ttl = 0;
+ dzr.dr.d_type = QType::PTR;
+ dzr.dr.d_content = std::make_shared<PTRRecordContent>(d_coo);
+ dzrs.emplace_back(dzr);
+ }
}
#pragma once
#include "ext/json11/json11.hpp"
+#include "base32.hh"
#include "dnsbackend.hh"
+#include "dnssecinfra.hh"
+
+struct DomainInfo;
+
+typedef map<DNSName, pdns::SHADigest> CatalogHashMap;
class CatalogInfo
{
}
CatalogInfo() :
- d_type(CatalogType::None) {}
- CatalogInfo(const DNSName& zone, CatalogType type)
+ d_id(0), d_type(CatalogType::None) {}
+ CatalogInfo(uint32_t id, const DNSName& zone, const std::string& options, CatalogType type)
{
- this->zone = zone;
- d_type = type;
+ d_id = id;
+ d_zone = zone;
+ fromJson(options, type);
}
- void setType(CatalogType type) { d_type = type; }
-
void fromJson(const std::string& json, CatalogType type);
std::string toJson() const;
void updateHash(CatalogHashMap& hashes, const DomainInfo& di) const;
+ DNSName getUnique() const { return DNSName(toBase32Hex(hashQNameWithSalt(std::to_string(d_id), 0, d_zone))); } // salt with domain id to detect recreated zones
+ static DNSZoneRecord getCatalogVersionRecord(const DNSName& zone);
+ void toDNSZoneRecords(const DNSName& zone, vector<DNSZoneRecord>& dzrs) const;
bool operator<(const CatalogInfo& rhs) const
{
- return zone < rhs.zone;
+ return d_zone < rhs.d_zone;
}
- DNSName coo, unique, zone;
+ uint32_t d_id;
+ DNSName d_zone, d_coo, d_unique;
private:
CatalogType d_type;
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
-#include "pdns/auth-catalogzone.hh"
#include "pdns/dns.hh"
#include "pdns/dnsbackend.hh"
#include "gsqlbackend.hh"
d_UpdateCatalogOfZoneQuery = getArg("update-catalog-query");
d_UpdateAccountOfZoneQuery=getArg("update-account-query");
d_InfoOfAllMasterDomainsQuery=getArg("info-all-master-query");
+ d_InfoProducerMembersQuery = getArg("info-producer-members-query");
+ d_InfoConsumerMembersQuery = getArg("info-consumer-members-query");
d_DeleteDomainQuery=getArg("delete-domain-query");
d_DeleteZoneQuery=getArg("delete-zone-query");
d_DeleteRRSetQuery=getArg("delete-rrset-query");
d_UpdateCatalogOfZoneQuery_stmt = nullptr;
d_UpdateAccountOfZoneQuery_stmt = nullptr;
d_InfoOfAllMasterDomainsQuery_stmt = nullptr;
+ d_InfoProducerMembersQuery_stmt = nullptr;
+ d_InfoConsumerMembersQuery_stmt = nullptr;
d_DeleteDomainQuery_stmt = nullptr;
d_DeleteZoneQuery_stmt = nullptr;
d_DeleteRRSetQuery_stmt = nullptr;
SOAData sd;
DomainInfo di;
- for (const auto& row : d_result) { // id, name, type, master, last_check, content
+ for (const auto& row : d_result) { // id, name, type, master, last_check, catalog, content
ASSERT_ROW_COLUMNS("info-all-slaves-query", row, 6);
try {
try {
if (!row[5].empty()) {
- ci.fromJson(row[3], CatalogInfo::CatalogType::Producer);
+ ci.fromJson(row[4], CatalogInfo::CatalogType::Producer);
ci.updateHash(catalogHashes, di);
}
}
}
try {
- pdns::checked_stoi_into(di.id, row[4]);
+ pdns::checked_stoi_into(di.id, row[3]);
}
catch (const std::exception& e) {
g_log << Logger::Warning << "Could not convert notified_serial '" << row[4] << "' for zone '" << di.zone << "' into an integer: " << e.what() << endl;
fillSOAData(row[6], sd);
}
catch (const std::exception& exp) {
- g_log << Logger::Warning << "Error while parsing SOA data for zone '" << di.zone << "': " << exp.what() << endl;
+ g_log << Logger::Warning << "Error while parsing SOA content '" << row[6] << "' for zone '" << di.zone << "': " << exp.what() << endl;
continue;
}
catch (...) {
- g_log << Logger::Warning << "Error while parsing SOA data for zone '" << di.zone << endl;
+ g_log << Logger::Warning << "Error while parsing SOA content '" << row[6] << "' for zone '" << di.zone << endl;
continue;
}
}
}
+bool GSQLBackend::getCatalogMembers(const DNSName& catalog, vector<CatalogInfo>& members, CatalogInfo::CatalogType type)
+{
+ try {
+ reconnectIfNeeded();
+
+ if (type == CatalogInfo::CatalogType::Producer) {
+ // clang-format off
+ d_InfoProducerMembersQuery_stmt->
+ bind("catalog", catalog)->
+ execute()->
+ getResult(d_result)->
+ reset();
+ // clang-format on
+ }
+ else if (type == CatalogInfo::CatalogType::Consumer) {
+ // clang-format off
+ d_InfoProducerMembersQuery_stmt->
+ bind("catalog", catalog)->
+ execute()->
+ getResult(d_result)->
+ reset();
+ // clang-format on
+ }
+ else {
+ PDNSException(std::string(__PRETTY_FUNCTION__) + " unknown type '" + CatalogInfo::getTypeString(type) + "'");
+ }
+ }
+ catch (SSqlException& e) {
+ throw PDNSException(std::string(__PRETTY_FUNCTION__) + " unable to retrieve list of member zones: " + e.txtReason());
+ }
+
+ for (const auto& row : d_result) { // id, zone, options
+ ASSERT_ROW_COLUMNS("info-producer/consumer-members-query", row, 3);
+
+ CatalogInfo ci;
+
+ try {
+ ci.d_zone = DNSName(row[1]);
+ }
+ catch (const std::runtime_error& e) {
+ g_log << Logger::Warning << __PRETTY_FUNCTION__ << " zone name '" << row[1] << "' is not a valid DNS name: " << e.what() << endl;
+ members.clear();
+ return false;
+ }
+ catch (PDNSException& ae) {
+ g_log << Logger::Warning << __PRETTY_FUNCTION__ << " zone name '" << row[1] << "' is not a valid DNS name: " << ae.reason << endl;
+ members.clear();
+ return false;
+ }
+
+ try {
+ pdns::checked_stoi_into(ci.d_id, row[0]);
+ }
+ catch (const std::exception& e) {
+ g_log << Logger::Warning << __PRETTY_FUNCTION__ << " could not convert id '" << row[0] << "' for zone '" << ci.d_zone << "' into an integer: " << e.what() << endl;
+ members.clear();
+ return false;
+ }
+
+ try {
+ ci.fromJson(row[2], type);
+ }
+ catch (const std::runtime_error& e) {
+ g_log << Logger::Warning << __PRETTY_FUNCTION__ << " options '" << row[2] << "' for zone '" << ci.d_zone << "' is no valid JSON: " << e.what() << endl;
+ members.clear();
+ return false;
+ }
+
+ members.emplace_back(ci);
+ }
+ return true;
+}
+
bool GSQLBackend::updateDNSSECOrderNameAndAuth(uint32_t domain_id, const DNSName& qname, const DNSName& ordername, bool auth, const uint16_t qtype)
{
if(!d_dnssecQueries)
d_UpdateSerialOfZoneQuery_stmt = d_db->prepare(d_UpdateSerialOfZoneQuery, 2);
d_UpdateLastCheckOfZoneQuery_stmt = d_db->prepare(d_UpdateLastCheckOfZoneQuery, 2);
d_InfoOfAllMasterDomainsQuery_stmt = d_db->prepare(d_InfoOfAllMasterDomainsQuery, 0);
+ d_InfoProducerMembersQuery_stmt = d_db->prepare(d_InfoProducerMembersQuery, 1);
+ d_InfoConsumerMembersQuery_stmt = d_db->prepare(d_InfoConsumerMembersQuery, 1);
d_DeleteDomainQuery_stmt = d_db->prepare(d_DeleteDomainQuery, 1);
d_DeleteZoneQuery_stmt = d_db->prepare(d_DeleteZoneQuery, 1);
d_DeleteRRSetQuery_stmt = d_db->prepare(d_DeleteRRSetQuery, 3);
d_UpdateSerialOfZoneQuery_stmt.reset();
d_UpdateLastCheckOfZoneQuery_stmt.reset();
d_InfoOfAllMasterDomainsQuery_stmt.reset();
+ d_InfoProducerMembersQuery_stmt.reset();
+ d_InfoConsumerMembersQuery_stmt.reset();
d_DeleteDomainQuery_stmt.reset();
d_DeleteZoneQuery_stmt.reset();
d_DeleteRRSetQuery_stmt.reset();
void setFresh(uint32_t domain_id) override;
void getUnfreshSlaveInfos(vector<DomainInfo> *domains) override;
void getUpdatedMasters(vector<DomainInfo>& updatedDomains, std::unordered_set<DNSName>& catalogs, CatalogHashMap& catalogHashes) override;
+ bool getCatalogMembers(const DNSName& catalog, vector<CatalogInfo>& members, CatalogInfo::CatalogType type) override;
bool getDomainInfo(const DNSName &domain, DomainInfo &di, bool getSerial=true) override;
void setNotified(uint32_t domain_id, uint32_t serial) override;
bool setMasters(const DNSName &domain, const vector<ComboAddress> &masters) override;
string d_UpdateSerialOfZoneQuery;
string d_UpdateLastCheckOfZoneQuery;
string d_InfoOfAllMasterDomainsQuery;
+ string d_InfoProducerMembersQuery;
+ string d_InfoConsumerMembersQuery;
string d_DeleteDomainQuery;
string d_DeleteZoneQuery;
string d_DeleteRRSetQuery;
unique_ptr<SSqlStatement> d_UpdateSerialOfZoneQuery_stmt;
unique_ptr<SSqlStatement> d_UpdateLastCheckOfZoneQuery_stmt;
unique_ptr<SSqlStatement> d_InfoOfAllMasterDomainsQuery_stmt;
+ unique_ptr<SSqlStatement> d_InfoProducerMembersQuery_stmt;
+ unique_ptr<SSqlStatement> d_InfoConsumerMembersQuery_stmt;
unique_ptr<SSqlStatement> d_DeleteDomainQuery_stmt;
unique_ptr<SSqlStatement> d_DeleteZoneQuery_stmt;
unique_ptr<SSqlStatement> d_DeleteRRSetQuery_stmt;
#include "dnsrecords.hh"
#include "iputils.hh"
#include "sha.hh"
+#include "auth-catalogzone.hh"
class DNSBackend;
struct DomainInfo
};
-typedef map<DNSName, pdns::SHADigest> CatalogHashMap;
-
struct TSIGKey {
DNSName name;
DNSName algorithm;
{
}
+ //! get list of all members in a catalog
+ virtual bool getCatalogMembers(const DNSName& catalog, vector<CatalogInfo>& members, CatalogInfo::CatalogType type)
+ {
+ return false;
+ }
+
//! Called by PowerDNS to inform a backend that a domain need to be checked for freshness
virtual void setStale(uint32_t domain_id)
{
std::string metaHash;
std::string mapHash;
for (auto& ch : catalogHashes) {
- g_log << Logger::Error << catalogs.size() << " " << ch.first << endl;
if (!catalogs.count(ch.first)) {
g_log << Logger::Warning << "orphaned member zones found with catalog '" << ch.first << "'" << endl;
continue;
pdns_recursor_SOURCES = \
aggressive_nsec.cc aggressive_nsec.hh \
arguments.cc \
+ auth-catalogzone.hh \
axfr-retriever.hh axfr-retriever.cc \
base32.cc base32.hh \
base64.cc base64.hh \
--- /dev/null
+../auth-catalogzone.hh
\ No newline at end of file
g_log<<Logger::Warning<<logPrefix<<"transfer initiated"<<endl;
// determine if zone exists and AXFR is allowed using existing backend before spawning a new backend.
- SOAData sd;
+ DomainInfo di;
{
auto packetHandler = s_P.lock();
DLOG(g_log<<logPrefix<<"looking for SOA"<<endl); // find domain_id via SOA and list complete domain. No SOA, no AXFR
return 0;
}
- if(!(*packetHandler)->getBackend()->getSOAUncached(target, sd)) {
+ if (!(*packetHandler)->getBackend()->getDomainInfo(target, di, false)) {
g_log<<Logger::Warning<<logPrefix<<"failed: not authoritative"<<endl;
outpacket->setRcode(RCode::NotAuth);
sendPacket(outpacket,outsock);
}
UeberBackend db;
+ SOAData sd;
if(!db.getSOAUncached(target, sd)) {
g_log<<Logger::Warning<<logPrefix<<"failed: not authoritative in second instance"<<endl;
outpacket->setRcode(RCode::NotAuth);
return 0;
}
+ bool securedZone = false;
+ bool presignedZone = false;
+ bool NSEC3Zone = false;
+ bool narrow = false;
+
+ NSEC3PARAMRecordContent ns3pr;
+
DNSSECKeeper dk(&db);
DNSSECKeeper::clearCaches(target);
- bool securedZone = dk.isSecuredZone(target);
- bool presignedZone = dk.isPresigned(target);
+ if (!di.isCatalogType()) {
+ securedZone = dk.isSecuredZone(target);
+ presignedZone = dk.isPresigned(target);
+ }
- NSEC3PARAMRecordContent ns3pr;
- bool narrow;
- bool NSEC3Zone=false;
if(securedZone && dk.getNSEC3PARAM(target, &ns3pr, &narrow)) {
NSEC3Zone=true;
if(narrow) {
zrrs.push_back(zrr);
}
+ const bool rectify = !(presignedZone || ::arg().mustDo("disable-axfr-rectify"));
+ set<DNSName> qnames, nsset, terms;
+
+ // Catalog zone start
+ if (di.kind == DomainInfo::Producer) {
+ // Ignore all records except NS at apex
+ sd.db->lookup(QType::NS, target, di.id);
+ while (sd.db->get(zrr)) {
+ zrrs.emplace_back(zrr);
+ }
+ if (zrrs.empty()) {
+ zrr.dr.d_name = target;
+ zrr.dr.d_ttl = 0;
+ zrr.dr.d_type = QType::NS;
+ zrr.dr.d_content = std::make_shared<TXTRecordContent>("invalid.");
+ zrrs.emplace_back(zrr);
+ }
+
+ zrrs.emplace_back(CatalogInfo::getCatalogVersionRecord(target));
+
+ vector<CatalogInfo> members;
+ sd.db->getCatalogMembers(target, members, CatalogInfo::CatalogType::Producer);
+ for (const auto& ci : members) {
+ ci.toDNSZoneRecords(target, zrrs);
+ }
+ if (members.empty()) {
+ g_log << Logger::Warning << logPrefix << "catalog zone '" << target << "' has no members" << endl;
+ }
+ goto send;
+ }
+ // Catalog zone end
+
// now start list zone
- if(!(sd.db->list(target, sd.domain_id))) {
+ if (!(sd.db->list(target, sd.domain_id, di.isCatalogType()))) {
g_log<<Logger::Error<<logPrefix<<"backend signals error condition, aborting AXFR"<<endl;
outpacket->setRcode(RCode::ServFail);
sendPacket(outpacket,outsock);
return 0;
}
-
- const bool rectify = !(presignedZone || ::arg().mustDo("disable-axfr-rectify"));
- set<DNSName> qnames, nsset, terms;
-
while(sd.db->get(zrr)) {
if (!presignedZone) {
if (zrr.dr.d_type == QType::RRSIG) {
}
}
+send:
/* now write all other records */