namespace Check
{
-void checkRRSet(vector<DNSResourceRecord>& records, const ZoneName& zone, vector<pair<DNSResourceRecord, string>>& errors)
+void checkRRSet(const vector<DNSResourceRecord>& oldrrs, vector<DNSResourceRecord>& allrrs, const ZoneName& zone, vector<pair<DNSResourceRecord, string>>& errors)
{
// QTypes that MUST NOT have multiple records of the same type in a given RRset.
static const std::set<uint16_t> onlyOneEntryTypes = {QType::CNAME, QType::DNAME, QType::SOA};
// QTypes that are NOT allowed at apex.
static const std::set<uint16_t> nonApexTypes = {QType::DS};
- sort(records.begin(), records.end(),
+ sort(allrrs.begin(), allrrs.end(),
[](const DNSResourceRecord& rec_a, const DNSResourceRecord& rec_b) -> bool {
/* we need _strict_ weak ordering */
return std::tie(rec_a.qname, rec_a.qtype, rec_a.content) < std::tie(rec_b.qname, rec_b.qtype, rec_b.content);
});
DNSResourceRecord previous;
- for (const auto& rec : records) {
+ for (const auto& rec : allrrs) {
if (previous.qname == rec.qname) {
if (previous.qtype == rec.qtype) {
if (onlyOneEntryTypes.count(rec.qtype.getCode()) != 0) {
else {
if (QType::exclusiveEntryTypes.count(rec.qtype.getCode()) != 0
|| QType::exclusiveEntryTypes.count(previous.qtype.getCode()) != 0) {
- errors.emplace_back(std::make_pair(rec, std::string{"conflicts with existing "} + previous.qtype.toString() + " RRset of the same name"));
+ // The `rec' record can't be added because of `previous'. However
+ // `rec' might be one of the existing records, and `previous' the
+ // added one. Or they might both be new records.
+ // We thus check if `rec' appears in the existing records in
+ // order to decide which record to blame in order to make the error
+ // message as less confusing as possible.
+ if (std::find(oldrrs.begin(), oldrrs.end(), rec) != oldrrs.end()) {
+ errors.emplace_back(std::make_pair(previous, std::string{"conflicts with existing "} + rec.qtype.toString() + " RRset of the same name"));
+ }
+ else {
+ errors.emplace_back(std::make_pair(rec, std::string{"conflicts with existing "} + previous.qtype.toString() + " RRset of the same name"));
+ }
}
}
}
namespace Check
{
-// Returns the list of errors found for records which violate RRset constraints.
+// Returns the list of errors found for new records which violate RRset
+// constraints.
// NOTE: sorts records in-place.
//
// Constraints being checked:
// *) no exact duplicates
// *) no duplicates for QTypes that can only be present once per RRset
// *) hostnames are hostnames
-void checkRRSet(vector<DNSResourceRecord>& records, const ZoneName& zone, vector<pair<DNSResourceRecord, string>>& errors);
+void checkRRSet(const vector<DNSResourceRecord>& oldrrs, vector<DNSResourceRecord>& allrrs, const ZoneName& zone, vector<pair<DNSResourceRecord, string>>& errors);
} // namespace Check
rr.auth = true;
rr.domain_id = di.id;
rr.qname = name;
- DNSResourceRecord oldrr;
unsigned int contentStart = 3;
if(cmds.size() > 4) {
di.backend->startTransaction(zone, UnknownDomainID);
+ DNSResourceRecord oldrr;
+ vector<DNSResourceRecord> oldrrs;
if (isAdd) {
// the 'add' case; preserve existing records, making sure to discard
// would-be new records which contents are identical to the existing ones.
- vector<DNSResourceRecord> oldrrs;
di.backend->lookup(QType(QType::ANY), rr.qname, static_cast<int>(di.id));
while (di.backend->get(oldrr)) {
oldrrs.push_back(oldrr);
}
}
}
- oldrrs.insert(oldrrs.end(), newrrs.begin(), newrrs.end());
- newrrs = std::move(oldrrs);
+ newrrs.insert(newrrs.end(), oldrrs.begin(), oldrrs.end());
}
std::vector<std::pair<DNSResourceRecord, string>> errors;
- Check::checkRRSet(newrrs, zone, errors);
+ Check::checkRRSet(oldrrs, newrrs, zone, errors);
+ oldrrs.clear(); // no longer needed
if (!errors.empty()) {
for (const auto& error : errors) {
const auto [rec, why] = error;
{
std::vector<std::pair<DNSResourceRecord, string>> errors;
- Check::checkRRSet(records, zone, errors);
+ Check::checkRRSet({}, records, zone, errors);
if (errors.empty()) {
return true;
}
Ignoring duplicate record content "127.0.0.2"
New rrset:
host2.bug.less. 3600 IN A 127.0.0.2
-RRset cname.bug.less. IN CNAME: conflicts with existing A RRset of the same name
+RRset cname.bug.less. IN A: conflicts with existing CNAME RRset of the same name
RRset host.bug.less. IN CNAME: conflicts with existing A RRset of the same name
New rrset:
host2.bug.less. 3600 IN A 127.0.0.2
Ignoring duplicate record content "127.0.0.2"
New rrset:
host2.bug.less. 3600 IN A 127.0.0.2
-RRset cname.bug.less. IN CNAME: conflicts with existing A RRset of the same name
+RRset cname.bug.less. IN A: conflicts with existing CNAME RRset of the same name
RRset host.bug.less. IN CNAME: conflicts with existing A RRset of the same name
New rrset:
host2.bug.less. 3600 IN A 127.0.0.2