// There's a special condition where deleting the last NS record at zone apex is never deleted (3.4.2.4)
// This means we must do it outside the normal performUpdate() because that focusses only on a separate RR.
vector<const DNSRecord *> nsRRtoDelete;
+
+ // Another special case is the addition of both a CNAME and a non-CNAME for the same name (#6270)
+ set<DNSName> cn, nocn;
+ for (const auto &rr : mdp.d_answers) {
+ if (rr.first.d_place == DNSResourceRecord::AUTHORITY && rr.first.d_class == QClass::IN && rr.first.d_ttl > 0) {
+ // Addition
+ if (rr.first.d_type == QType::CNAME) {
+ cn.insert(rr.first.d_name);
+ } else if (rr.first.d_type != QType::RRSIG) {
+ nocn.insert(rr.first.d_name);
+ }
+ }
+ }
+ for (auto const &n : cn) {
+ if (nocn.count(n) > 0) {
+ L<<Logger::Error<<msgPrefix<<"Refusing update, found CNAME and non-CNAME addition"<<endl;
+ di.backend->abortTransaction();
+ return RCode::FormErr;
+ }
+ }
+
+ vector<const DNSRecord *> cnamesToAdd, nonCnamesToAdd;
for(MOADNSParser::answers_t::const_iterator i=mdp.d_answers.begin(); i != mdp.d_answers.end(); ++i) {
const DNSRecord *rr = &i->first;
if (rr->d_place == DNSResourceRecord::AUTHORITY) {
if (rr->d_class == QClass::NONE && rr->d_type == QType::NS && rr->d_name == di.zone)
nsRRtoDelete.push_back(rr);
+ else if (rr->d_class == QClass::IN && rr->d_ttl > 0) {
+ if (rr->d_type == QType::CNAME) {
+ cnamesToAdd.push_back(rr);
+ } else {
+ nonCnamesToAdd.push_back(rr);
+ }
+ }
else
changedRecords += performUpdate(msgPrefix, rr, &di, isPresigned, &narrow, &haveNSEC3, &ns3pr, &updatedSerial);
}
}
+ for (const auto &rr : cnamesToAdd) {
+ DNSResourceRecord rec;
+ di.backend->lookup(QType(QType::ANY), rr->d_name);
+ while (di.backend->get(rec)) {
+ if (rec.qtype != QType::CNAME && rec.qtype != QType::RRSIG) {
+ L<<Logger::Warning<<msgPrefix<<"Refusing update for " << rr->d_name << "/" << QType(rr->d_type).getName() << ": Data other than CNAME exists for the same name"<<endl;
+ di.backend->abortTransaction();
+ return RCode::Refused;
+ }
+ }
+ changedRecords += performUpdate(msgPrefix, rr, &di, isPresigned, &narrow, &haveNSEC3, &ns3pr, &updatedSerial);
+ }
+ for (const auto &rr : nonCnamesToAdd) {
+ DNSResourceRecord rec;
+ di.backend->lookup(QType(QType::CNAME), rr->d_name);
+ while (di.backend->get(rec)) {
+ if (rec.qtype == QType::CNAME && rr->d_type != QType::RRSIG) {
+ L<<Logger::Warning<<msgPrefix<<"Refusing update for " << rr->d_name << "/" << QType(rr->d_type).getName() << ": CNAME exists for the same name"<<endl;
+ di.backend->abortTransaction();
+ return RCode::Refused;
+ }
+ }
+ changedRecords += performUpdate(msgPrefix, rr, &di, isPresigned, &narrow, &haveNSEC3, &ns3pr, &updatedSerial);
+ }
if (nsRRtoDelete.size()) {
vector<DNSResourceRecord> nsRRInZone;
DNSResourceRecord rec;