rpzloader.cc rpzloader.hh \
secpoll.cc \
settings/cxxsupport.cc \
+ shuffle.cc shuffle.hh \
sholder.hh \
sillyrecords.cc \
sortlist.cc sortlist.hh \
}
if (!ret.empty()) {
+ pdns::dedup(ret);
pdns::orderAndShuffle(ret, false);
if (auto listToSort = luaconfsLocal->sortlist.getOrderCmp(comboWriter->d_source)) {
stable_sort(ret.begin(), ret.end(), *listToSort);
#include "dnsseckeeper.hh"
#include "validate-recursor.hh"
#include "rec-taskqueue.hh"
+#include "shuffle.hh"
rec::GlobalCounters g_Counters;
thread_local rec::TCounters t_Counters(g_Counters);
}
lwr.d_records = std::move(vec);
}
+ pdns::dedup(lwr.d_records);
}
void SyncRes::rememberParentSetIfNeeded(const DNSName& domain, const vector<DNSRecord>& newRecords, unsigned int depth, const string& prefix)
typedef std::unordered_map<DNSName, std::pair<DNSSECPrivateKey, DSRecordContent>> testkeysset_t;
-bool addRRSIG(const testkeysset_t& keys, std::vector<DNSRecord>& records, const DNSName& signer, uint32_t sigValidity, bool broken, boost::optional<uint8_t> algo, boost::optional<DNSName> wildcard, boost::optional<time_t> now)
+bool addRRSIG(const testkeysset_t& keys, std::vector<DNSRecord>& records, const DNSName& signer, uint32_t sigValidity, std::variant<bool, int> broken, boost::optional<uint8_t> algo, boost::optional<DNSName> wildcard, boost::optional<time_t> now)
{
if (records.empty()) {
return false;
RRSIGRecordContent rrc;
computeRRSIG(it->second.first, signer, wildcard ? *wildcard : name, type, ttl, sigValidity, rrc, recordcontents, algo, boost::none, now);
- if (broken) {
+ if (auto* bval = std::get_if<bool>(&broken); bval != nullptr && *bval) {
rrc.d_signature[0] ^= 42;
}
+ else if (auto *ival = std::get_if<int>(&broken)) {
+ rrc.d_signature[0] ^= *ival; // NOLINT(*-narrowing-conversions)
+ }
DNSRecord rec;
rec.d_type = QType::RRSIG;
typedef std::unordered_map<DNSName, std::pair<DNSSECPrivateKey, DSRecordContent>> testkeysset_t;
-bool addRRSIG(const testkeysset_t& keys, std::vector<DNSRecord>& records, const DNSName& signer, uint32_t sigValidity, bool broken = false, boost::optional<uint8_t> algo = boost::none, boost::optional<DNSName> wildcard = boost::none, boost::optional<time_t> now = boost::none);
+bool addRRSIG(const testkeysset_t& keys, std::vector<DNSRecord>& records, const DNSName& signer, uint32_t sigValidity, std::variant<bool, int> broken = false, boost::optional<uint8_t> algo = boost::none, boost::optional<DNSName> wildcard = boost::none, boost::optional<time_t> now = boost::none);
void addDNSKEY(const testkeysset_t& keys, const DNSName& signer, uint32_t ttl, std::vector<DNSRecord>& records);
addRecordToLW(res, domain, QType::NS, std::string(addr), DNSResourceRecord::ANSWER, 3600);
}
- addRRSIG(keys, res->d_records, domain, 300, true, boost::none, boost::none, fixedNow);
- addRRSIG(keys, res->d_records, domain, 300, true, boost::none, boost::none, fixedNow);
- addRRSIG(keys, res->d_records, domain, 300, false, boost::none, boost::none, fixedNow);
+ addRRSIG(keys, res->d_records, domain, 300, 1, boost::none, boost::none, fixedNow);
+ addRRSIG(keys, res->d_records, domain, 300, 2, boost::none, boost::none, fixedNow);
+ addRRSIG(keys, res->d_records, domain, 300, 0, boost::none, boost::none, fixedNow);
addRecordToLW(res, "a.root-servers.net.", QType::A, "198.41.0.4", DNSResourceRecord::ADDITIONAL, 3600);
addRecordToLW(res, "a.root-servers.net.", QType::AAAA, "2001:503:ba3e::2:30", DNSResourceRecord::ADDITIONAL, 3600);
int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
BOOST_CHECK_EQUAL(res, RCode::NoError);
BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Secure);
- /* because we pass along the duplicated NSEC3 */
- BOOST_REQUIRE_EQUAL(ret.size(), 9U);
+ /* the duplicated NSEC3 should have been dedupped */
+ BOOST_REQUIRE_EQUAL(ret.size(), 8U);
BOOST_CHECK_EQUAL(queriesCount, 4U);
/* again, to test the cache */
res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
BOOST_CHECK_EQUAL(res, RCode::NoError);
BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Secure);
- /* because we pass along the duplicated NSEC3 */
- BOOST_REQUIRE_EQUAL(ret.size(), 9U);
+ /* the duplicated NSEC3 should have been dedupped */
+ BOOST_REQUIRE_EQUAL(ret.size(), 8U);
BOOST_CHECK_EQUAL(queriesCount, 4U);
}
});
shuffle(rrs, includingAdditionals);
}
+
+void pdns::dedup(vector<DNSRecord>& rrs)
+{
+ // This functino tries to avoid unneccesary work
+ // First a vector with zero or one element does not need dedupping
+ if (rrs.size() <= 1) {
+ return;
+ }
+
+ // If we have a larger vector, first check if we actually have duplicates.
+ // We assume the most common case is: no
+ std::unordered_set<std::string> seen;
+ std::vector<bool> unique(rrs.size(), false);
+
+ unsigned int counter = 0;
+ unsigned int numUnique = 0;
+
+ for (const auto& rec : rrs) {
+ // This ignores class, ttl and place
+ if (seen.emplace(rec.getContent()->serialize(rec.d_name, true, true)).second) {
+ unique[counter] = true;
+ numUnique++;
+ }
+ ++counter;
+ }
+
+ if (numUnique == rrs.size()) {
+ // Original is fine as-is.
+ return;
+ }
+
+ // We avoid calling erase, as it calls a lot of move constructors. This can hurt, especially if
+ // you call it on a large vector muliple times.
+ // So we just take the elements that are unique
+ std::vector<DNSRecord> ret;
+ ret.reserve(numUnique);
+ for (counter = 0; counter < rrs.size(); ++counter) {
+ if (unique[counter]) {
+ ret.emplace_back(std::move(rrs[counter]));
+ }
+ }
+ rrs = std::move(ret);
+}
{
void shuffle(std::vector<DNSZoneRecord>& rrs);
void orderAndShuffle(std::vector<DNSRecord>& rrs, bool includingAdditionals);
+void dedup(std::vector<DNSRecord>& rrs);
}