declare(suffix, "any-query", "Any query", record_query + " disabled=0 and name=?");
declare(suffix, "any-id-query", "Any with ID query", record_query + " disabled=0 and name=? and domain_id=?");
- declare(suffix, "list-query", "AXFR query", record_query + " (disabled=0 OR ?) and domain_id=? order by name, type");
+ declare(suffix, "list-query", "AXFR query", "SELECT content,ttl,prio,type,domain_id,disabled,name,auth,ordername FROM records WHERE (disabled=0 OR ?) and domain_id=? order by name, type");
declare(suffix, "list-subzone-query", "Subzone listing", record_query + " disabled=0 and (name=? OR name like ?) and domain_id=?");
declare(suffix, "remove-empty-non-terminals-from-zone-query", "remove all empty non-terminals from zone", "delete from records where domain_id=? and type is null");
declare(suffix, "any-query", "Any query", record_query + " disabled=0 and name=?");
declare(suffix, "any-id-query", "Any with ID query", record_query + " disabled=0 and name=? and domain_id=?");
- declare(suffix, "list-query", "AXFR query", record_query + " (disabled=0 OR disabled=?) and domain_id=? order by name, type");
+ declare(suffix, "list-query", "AXFR query", "SELECT content,ttl,prio,type,domain_id,disabled,name,auth,CONVERT(varchar(255), ordername, 0) FROM records WHERE (disabled=0 OR disabled=?) and domain_id=? order by name, type");
declare(suffix, "list-subzone-query", "Subzone listing", record_query + " disabled=0 and (name=? OR name like ?) and domain_id=?");
declare(suffix, "remove-empty-non-terminals-from-zone-query", "remove all empty non-terminals from zone", "delete from records where domain_id=? and type is null");
declare(suffix, "any-query", "Any query", record_query + " disabled=false and name=$1");
declare(suffix, "any-id-query", "Any with ID query", record_query + " disabled=false and name=$1 and domain_id=$2");
- declare(suffix, "list-query", "AXFR query", record_query + " (disabled=false OR $1) and domain_id=$2 order by name, type");
+ declare(suffix, "list-query", "AXFR query", "SELECT content,ttl,prio,type,domain_id,disabled::int,name,auth::int,ordername FROM records WHERE (disabled=false OR $1) and domain_id=$2 order by name, type");
declare(suffix, "list-subzone-query", "Subzone listing", record_query + " disabled=false and (name=$1 OR name like $2) and domain_id=$3");
declare(suffix, "remove-empty-non-terminals-from-zone-query", "remove all empty non-terminals from zone", "delete from records where domain_id=$1 and type is null");
declare(suffix, "any-query", "Any query", record_query + " disabled=0 and name=:qname");
declare(suffix, "any-id-query", "Any with ID query", record_query + " disabled=0 and name=:qname and domain_id=:domain_id");
- declare(suffix, "list-query", "AXFR query", record_query + " (disabled=0 OR :include_disabled) and domain_id=:domain_id order by name, type");
+ declare(suffix, "list-query", "AXFR query", "SELECT content,ttl,prio,type,domain_id,disabled,name,auth,ordername FROM records WHERE (disabled=0 OR :include_disabled) and domain_id=:domain_id order by name, type");
declare(suffix, "list-subzone-query", "Subzone listing", record_query + " disabled=0 and (name=:zone OR name like :wildzone) and domain_id=:domain_id");
declare(suffix, "remove-empty-non-terminals-from-zone-query", "remove all empty non-terminals from zone", "delete from records where domain_id=:domain_id and type is null");
throw PDNSException("GSQLBackend unable to lookup '" + qname.toLogString() + "|" + qtype.getName() + "':"+e.txtReason());
}
+ d_list=false;
d_qname=qname;
}
throw PDNSException("GSQLBackend unable to list domain '" + target.toLogString() + "': "+e.txtReason());
}
+ d_list=true;
d_qname.clear();
+
return true;
}
catch(SSqlException &e) {
throw PDNSException("GSQLBackend unable to list SubZones for domain '" + zone.toLogString() + "': "+e.txtReason());
}
+
+ d_list=false;
d_qname.clear();
+
return true;
}
if((*d_query_stmt)->hasNextRow()) {
try {
(*d_query_stmt)->nextRow(row);
- ASSERT_ROW_COLUMNS(d_query_name, row, 8);
+ if (!d_list) {
+ ASSERT_ROW_COLUMNS(d_query_name, row, 8); // lookup(), listSubZone()
+ }
+ else {
+ ASSERT_ROW_COLUMNS(d_query_name, row, 9); // list()
+ }
} catch (SSqlException &e) {
throw PDNSException("GSQLBackend get: "+e.txtReason());
}
r.disabled = !row[5].empty() && row[5][0]=='1';
r.domain_id=pdns_stou(row[4]);
+
+ if (row.size() > 8) {
+ if (!row.at(8).empty()) {
+ r.ordername=DNSName(boost::replace_all_copy(row.at(8), " ", ".")).labelReverse();
+ }
+ else {
+ r.ordername.clear();
+ }
+ }
+ else {
+ r.ordername.clear();
+ }
}
void GSQLBackend::extractComment(SSqlStatement::row_t& row, Comment& comment)
return d_inTransaction;
}
+ bool d_list{false};
string d_query_name;
DNSName d_qname;
SSqlStatement::result_t d_result;
return true;
}
+
+struct RecordStatus
+{
+ DNSName ordername;
+ bool auth{false};
+ bool update{false};
+};
+
+
/* Rectifies the zone
*
* \param zone The zone to rectify
ostringstream infostream;
DNSResourceRecord rr;
set<DNSName> qnames, nsset, dsnames, insnonterm, delnonterm;
- map<DNSName,bool> nonterm;
+ std::unordered_map<DNSName,bool> nonterm;
vector<DNSResourceRecord> rrs;
+ std::unordered_map<DNSName,RecordStatus> rss;
+
+ NSEC3PARAMRecordContent ns3pr;
+ bool securedZone = isSecuredZone(zone, doTransaction);
+ bool haveNSEC3 = false, isOptOut = false, narrow = false;
+
+ if(securedZone) {
+ haveNSEC3 = getNSEC3PARAM(zone, &ns3pr, &narrow, doTransaction);
+ isOptOut = (haveNSEC3 && ns3pr.d_flags);
+ }
while(sd.db->get(rr)) {
rr.qname.makeUsLowerCase();
+
+ auto res=rss.insert({rr.qname,{rr.ordername, rr.auth, rr.ordername.empty() != (!securedZone || narrow)}}); // only a set ordername is reliable
+ if (!res.second && !res.first->second.update) {
+ res.first->second.update = res.first->second.auth != rr.auth || res.first->second.ordername != rr.ordername;
+ }
+ else if ((!securedZone || narrow) && rr.qname == zone) {
+ res.first->second.update = true;
+ }
+
if (rr.qtype.getCode())
{
- rrs.push_back(rr);
qnames.insert(rr.qname);
if(rr.qtype.getCode() == QType::NS && rr.qname != zone)
nsset.insert(rr.qname);
if(rr.qtype.getCode() == QType::DS)
dsnames.insert(rr.qname);
+ rrs.emplace_back(rr);
}
else
- delnonterm.insert(rr.qname);
+ delnonterm.insert(std::move(rr.qname));
}
- NSEC3PARAMRecordContent ns3pr;
- bool securedZone = isSecuredZone(zone, doTransaction);
- bool haveNSEC3 = false, isOptOut = false, narrow = false;
-
if(securedZone) {
- haveNSEC3 = getNSEC3PARAM(zone, &ns3pr, &narrow, doTransaction);
- isOptOut = (haveNSEC3 && ns3pr.d_flags);
-
if(!haveNSEC3) {
- infostream<<"Adding NSEC ordering information ";
+ infostream<<"Adding NSEC ordering information for zone '"<<zone<<"'";
}
else if(!narrow) {
if(!isOptOut) {
- infostream<<"Adding NSEC3 hashed ordering information for '"<<zone<<"'";
+ infostream<<"Adding NSEC3 hashed ordering information for zone '"<<zone<<"'";
}
else {
- infostream<<"Adding NSEC3 opt-out hashed ordering information for '"<<zone<<"'";
+ infostream<<"Adding NSEC3 opt-out hashed ordering information for zone '"<<zone<<"'";
}
} else {
- infostream<<"Erasing NSEC3 ordering since we are narrow, only setting 'auth' fields";
+ infostream<<"Erasing NSEC3 ordering since we are narrow, only setting 'auth' fields for zone '"<<zone<<"'";
}
}
else {
- infostream<<"Adding empty non-terminals for non-DNSSEC zone";
+ infostream<<"Adding empty non-terminals for non-DNSSEC zone '"<<zone<<"'";
}
set<DNSName> nsec3set;
bool realrr=true;
bool doent=true;
+ int updates=0;
uint32_t maxent = ::arg().asNum("max-ent-entries");
dononterm:;
+ std::unordered_map<DNSName,RecordStatus>::const_iterator it;
for (const auto& qname: qnames)
{
bool auth=true;
}
}
else if (realrr && securedZone) // NSEC
+ {
ordername=qname.makeRelative(zone);
+ }
- sd.db->updateDNSSECOrderNameAndAuth(sd.domain_id, qname, ordername, auth);
+ it = rss.find(qname);
+ if(it == rss.end() || it->second.update || it->second.auth != auth || it->second.ordername != ordername) {
+ sd.db->updateDNSSECOrderNameAndAuth(sd.domain_id, qname, ordername, auth);
+ ++updates;
+ }
if(realrr)
{
- if (dsnames.count(qname))
+ if (dsnames.count(qname)) {
sd.db->updateDNSSECOrderNameAndAuth(sd.domain_id, qname, ordername, true, QType::DS);
+ ++updates;
+ }
if (!auth || nsset.count(qname)) {
ordername.clear();
- if(isOptOut && !dsnames.count(qname))
+ if(isOptOut && !dsnames.count(qname)){
sd.db->updateDNSSECOrderNameAndAuth(sd.domain_id, qname, ordername, false, QType::NS);
+ ++updates;
+ }
sd.db->updateDNSSECOrderNameAndAuth(sd.domain_id, qname, ordername, false, QType::A);
+ ++updates;
sd.db->updateDNSSECOrderNameAndAuth(sd.domain_id, qname, ordername, false, QType::AAAA);
+ ++updates;
}
if(doent)
if (doTransaction)
sd.db->commitTransaction();
+ infostream<<", "<<updates<<" updates";
info = infostream.str();
return true;
}
// data
DNSName qname; //!< the name of this record, for example: www.powerdns.com
+ DNSName ordername;
DNSName wildcardname;
string content; //!< what this record points to. Example: 10.1.2.3
godbc-insert-zone-query=insert into domains (type,name,master,account,last_check,notified_serial) values(?, ?, ?, ?, null, null)
godbc-list-comments-query=SELECT domain_id,name,type,modified_at,account,comment FROM comments WHERE domain_id=?
godbc-list-domain-keys-query=select cryptokeys.id, flags, active, published, content from domains, cryptokeys where cryptokeys.domain_id=domains.id and name=?
-godbc-list-query=SELECT content,ttl,prio,type,domain_id,disabled,name,auth FROM records WHERE (disabled=0 OR ?) and domain_id=? order by name, type
+godbc-list-query=SELECT content,ttl,prio,type,domain_id,disabled,name,auth,ordername FROM records WHERE (disabled=0 OR ?) and domain_id=? order by name, type
godbc-list-subzone-query=SELECT content,ttl,prio,type,domain_id,disabled,name,auth FROM records WHERE disabled=0 and (name=? OR name like ?) and domain_id=?
godbc-nullify-ordername-and-update-auth-query=update records set ordername=NULL,auth=? where domain_id=? and name=? and disabled=0
godbc-nullify-ordername-and-update-auth-type-query=update records set ordername=NULL,auth=? where domain_id=? and name=? and type=? and disabled=0