Skip to content

Commit 1ec2bb1

Browse files
authored
Merge pull request #14617 from omoerbeek/rec-dedup-recs
rec: dedup records
2 parents 4380428 + 0941cf9 commit 1ec2bb1

File tree

17 files changed

+216
-38
lines changed

17 files changed

+216
-38
lines changed

pdns/Makefile.am

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -949,6 +949,7 @@ speedtest_SOURCES = \
949949
nsecrecords.cc \
950950
qtype.cc \
951951
rcpgenerator.cc rcpgenerator.hh \
952+
shuffle.cc shuffle.hh \
952953
sillyrecords.cc \
953954
speedtest.cc \
954955
statbag.cc \

pdns/dnsparser.hh

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -202,22 +202,28 @@ public:
202202
virtual std::string getZoneRepresentation(bool noDot=false) const = 0;
203203
virtual ~DNSRecordContent() = default;
204204
virtual void toPacket(DNSPacketWriter& pw) const = 0;
205-
// returns the wire format of the content, possibly including compressed pointers pointing to the owner name (unless canonic or lowerCase are set)
206-
string serialize(const DNSName& qname, bool canonic=false, bool lowerCase=false) const
205+
// returns the wire format of the content or the full record, possibly including compressed pointers pointing to the owner name (unless canonic or lowerCase are set)
206+
[[nodiscard]] string serialize(const DNSName& qname, bool canonic = false, bool lowerCase = false, bool full = false) const
207207
{
208208
vector<uint8_t> packet;
209-
DNSPacketWriter pw(packet, g_rootdnsname, 1);
210-
if(canonic)
211-
pw.setCanonic(true);
209+
DNSPacketWriter packetWriter(packet, g_rootdnsname, QType::A);
212210

213-
if(lowerCase)
214-
pw.setLowercase(true);
211+
if (canonic) {
212+
packetWriter.setCanonic(true);
213+
}
214+
if (lowerCase) {
215+
packetWriter.setLowercase(true);
216+
}
215217

216-
pw.startRecord(qname, this->getType());
217-
this->toPacket(pw);
218+
packetWriter.startRecord(qname, getType());
219+
toPacket(packetWriter);
218220

219221
string record;
220-
pw.getRecordPayload(record); // needs to be called before commit()
222+
if (full) {
223+
packetWriter.getWireFormatContent(record); // needs to be called before commit()
224+
} else {
225+
packetWriter.getRecordPayload(record); // needs to be called before commit()
226+
}
221227
return record;
222228
}
223229

pdns/dnswriter.cc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -457,6 +457,12 @@ template <typename Container> void GenericDNSPacketWriter<Container>::getRecordP
457457
records.assign(d_content.begin() + d_sor, d_content.end());
458458
}
459459

460+
// call __before commit__
461+
template <typename Container> void GenericDNSPacketWriter<Container>::getWireFormatContent(string& record)
462+
{
463+
record.assign(d_content.begin() + d_rollbackmarker, d_content.end());
464+
}
465+
460466
template <typename Container> uint32_t GenericDNSPacketWriter<Container>::size() const
461467
{
462468
return d_content.size();

pdns/dnswriter.hh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,7 @@ public:
138138

139139
dnsheader* getHeader();
140140
void getRecordPayload(string& records); // call __before commit__
141+
void getWireFormatContent(string& record); // call __before commit__
141142

142143
void setCanonic(bool val)
143144
{

pdns/recursordist/Makefile.am

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,7 @@ testrunner_SOURCES = \
339339
secpoll.cc \
340340
settings/cxxsupport.cc \
341341
sholder.hh \
342+
shuffle.cc shuffle.hh \
342343
sillyrecords.cc \
343344
sortlist.cc sortlist.hh \
344345
sstuff.hh \
@@ -380,6 +381,7 @@ testrunner_SOURCES = \
380381
test-secpoll_cc.cc \
381382
test-settings.cc \
382383
test-sholder_hh.cc \
384+
test-shuffle_cc.cc \
383385
test-signers.cc \
384386
test-syncres_cc.cc \
385387
test-syncres_cc.hh \

pdns/recursordist/meson.build

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -472,6 +472,7 @@ test_sources += files(
472472
src_dir / 'test-rpzloader_cc.cc',
473473
src_dir / 'test-secpoll_cc.cc',
474474
src_dir / 'test-settings.cc',
475+
src_dir / 'test-shuffle_cc.cc',
475476
src_dir / 'test-signers.cc',
476477
src_dir / 'test-syncres_cc.cc',
477478
src_dir / 'test-syncres_cc.hh',

pdns/recursordist/pdns_recursor.cc

Lines changed: 7 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -780,22 +780,7 @@ int getFakeAAAARecords(const DNSName& qname, ComboAddress prefix, vector<DNSReco
780780
ret.end());
781781
}
782782
else {
783-
// Remove double SOA records
784-
std::set<DNSName> seenSOAs;
785-
ret.erase(std::remove_if(
786-
ret.begin(),
787-
ret.end(),
788-
[&seenSOAs](DNSRecord& record) {
789-
if (record.d_type == QType::SOA) {
790-
if (seenSOAs.count(record.d_name) > 0) {
791-
// We've had this SOA before, remove it
792-
return true;
793-
}
794-
seenSOAs.insert(record.d_name);
795-
}
796-
return false;
797-
}),
798-
ret.end());
783+
pdns::dedupRecords(ret);
799784
}
800785
t_Counters.at(rec::Counter::dns64prefixanswers)++;
801786
return rcode;
@@ -1527,6 +1512,12 @@ void startDoResolve(void* arg) // NOLINT(readability-function-cognitive-complexi
15271512
}
15281513

15291514
if (!ret.empty()) {
1515+
#ifdef notyet
1516+
// As dedupping is relatively expensive do not dedup in general. We do have a few cases
1517+
// where we call dedup explicitly, e.g. when doing NAT64 or when adding NSEC records in
1518+
// doCNAMECacheCheck
1519+
pdns::dedupRecords(ret);
1520+
#endif
15301521
pdns::orderAndShuffle(ret, false);
15311522
if (auto listToSort = luaconfsLocal->sortlist.getOrderCmp(comboWriter->d_source)) {
15321523
stable_sort(ret.begin(), ret.end(), *listToSort);

pdns/recursordist/syncres.cc

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
#include "dnsseckeeper.hh"
4040
#include "validate-recursor.hh"
4141
#include "rec-taskqueue.hh"
42+
#include "shuffle.hh"
4243

4344
rec::GlobalCounters g_Counters;
4445
thread_local rec::TCounters t_Counters(g_Counters);
@@ -2759,6 +2760,7 @@ bool SyncRes::doCNAMECacheCheck(const DNSName& qname, const QType qtype, vector<
27592760
// so you can't trust that a real lookup will have been made.
27602761
res = doResolve(newTarget, qtype, ret, depth + 1, beenthere, cnameContext);
27612762
LOG(prefix << qname << ": Updating validation state for response to " << qname << " from " << context.state << " with the state from the DNAME/CNAME quest: " << cnameContext.state << endl);
2763+
pdns::dedupRecords(ret); // multiple NSECS could have been added, #14120
27622764
updateValidationState(qname, context.state, cnameContext.state, prefix);
27632765

27642766
return true;
@@ -4478,6 +4480,12 @@ void SyncRes::sanitizeRecordsPass2(const std::string& prefix, LWResult& lwr, con
44784480
}
44794481
lwr.d_records = std::move(vec);
44804482
}
4483+
#ifdef notyet
4484+
// As dedupping is relatively expensive and having dup records not really hurts as far as we have seen, do not dedup.
4485+
if (auto count = pdns::dedupRecords(lwr.d_records); count > 0) {
4486+
LOG(prefix << qname << ": Removed " << count << " duplicate records from response received from " << auth << endl);
4487+
}
4488+
#endif
44814489
}
44824490

44834491
void SyncRes::rememberParentSetIfNeeded(const DNSName& domain, const vector<DNSRecord>& newRecords, unsigned int depth, const string& prefix)
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
/*
2+
* This file is part of PowerDNS or dnsdist.
3+
* Copyright -- PowerDNS.COM B.V. and its contributors
4+
*
5+
* This program is free software; you can redistribute it and/or modify
6+
* it under the terms of version 2 of the GNU General Public License as
7+
* published by the Free Software Foundation.
8+
*
9+
* In addition, for the avoidance of any doubt, permission is granted to
10+
* link this program with OpenSSL and to (re)distribute the binaries
11+
* produced as the result of such linking.
12+
*
13+
* This program is distributed in the hope that it will be useful,
14+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
15+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16+
* GNU General Public License for more details.
17+
*
18+
* You should have received a copy of the GNU General Public License
19+
* along with this program; if not, write to the Free Software
20+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21+
*/
22+
23+
#ifndef BOOST_TEST_DYN_LINK
24+
#define BOOST_TEST_DYN_LINK
25+
#endif
26+
27+
#define BOOST_TEST_NO_MAIN
28+
29+
#include "config.h"
30+
#include <boost/test/unit_test.hpp>
31+
32+
#include "shuffle.hh"
33+
#include "test-common.hh"
34+
35+
BOOST_AUTO_TEST_SUITE(shuffle_cc)
36+
37+
BOOST_AUTO_TEST_CASE(test_simple)
38+
{
39+
std::vector<DNSRecord> list;
40+
auto* address = &list;
41+
addRecordToList(list, DNSName("foo"), QType::A, "1.2.3.4");
42+
addRecordToList(list, DNSName("foo2"), QType::A, "1.2.3.4");
43+
auto dups = pdns::dedupRecords(list);
44+
BOOST_CHECK_EQUAL(dups, 0U);
45+
BOOST_CHECK_EQUAL(list.size(), 2U);
46+
addRecordToList(list, DNSName("foo"), QType::A, "1.2.3.4");
47+
dups = pdns::dedupRecords(list);
48+
BOOST_CHECK_EQUAL(dups, 1U);
49+
BOOST_CHECK_EQUAL(list.size(), 2U);
50+
addRecordToList(list, DNSName("Foo"), QType::A, "1.2.3.4");
51+
addRecordToList(list, DNSName("FoO"), QType::A, "1.2.3.4", DNSResourceRecord::ADDITIONAL, 999);
52+
dups = pdns::dedupRecords(list);
53+
BOOST_CHECK_EQUAL(dups, 2U);
54+
BOOST_CHECK_EQUAL(list.size(), 2U);
55+
BOOST_CHECK_EQUAL(address, &list);
56+
}
57+
58+
BOOST_AUTO_TEST_SUITE_END()

pdns/recursordist/test-syncres_cc.cc

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -326,7 +326,7 @@ void computeRRSIG(const DNSSECPrivateKey& dpk, const DNSName& signer, const DNSN
326326

327327
typedef std::unordered_map<DNSName, std::pair<DNSSECPrivateKey, DSRecordContent>> testkeysset_t;
328328

329-
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)
329+
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)
330330
{
331331
if (records.empty()) {
332332
return false;
@@ -368,9 +368,12 @@ bool addRRSIG(const testkeysset_t& keys, std::vector<DNSRecord>& records, const
368368

369369
RRSIGRecordContent rrc;
370370
computeRRSIG(it->second.first, signer, wildcard ? *wildcard : name, type, ttl, sigValidity, rrc, recordcontents, algo, boost::none, now);
371-
if (broken) {
371+
if (auto* bval = std::get_if<bool>(&broken); bval != nullptr && *bval) {
372372
rrc.d_signature[0] ^= 42;
373373
}
374+
else if (auto* ival = std::get_if<int>(&broken)) {
375+
rrc.d_signature[0] ^= *ival; // NOLINT(*-narrowing-conversions)
376+
}
374377

375378
DNSRecord rec;
376379
rec.d_type = QType::RRSIG;

0 commit comments

Comments
 (0)