Skip to content

Commit

Permalink
Move shuffle functions to new file and put some symbols in the
Browse files Browse the repository at this point in the history
pdns namespace.
  • Loading branch information
omoerbeek committed Apr 8, 2020
1 parent 7fe1b8e commit e19b663
Show file tree
Hide file tree
Showing 10 changed files with 168 additions and 103 deletions.
2 changes: 2 additions & 0 deletions pdns/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,7 @@ pdns_server_SOURCES = \
secpoll-auth.cc secpoll-auth.hh \
serialtweaker.cc \
sha.hh \
shuffle.cc shuffle.hh \
signingpipe.cc signingpipe.hh \
sillyrecords.cc \
slavecommunicator.cc \
Expand Down Expand Up @@ -324,6 +325,7 @@ pdnsutil_SOURCES = \
qtype.cc \
rcpgenerator.cc rcpgenerator.hh \
serialtweaker.cc \
shuffle.cc shuffle.hh \
signingpipe.cc \
sillyrecords.cc \
sstuff.hh \
Expand Down
78 changes: 0 additions & 78 deletions pdns/dns_random.cc
Original file line number Diff line number Diff line change
Expand Up @@ -334,81 +334,3 @@ uint16_t dns_random_uint16()
return dns_random(0x10000);
}

// shuffle, maintaining some semblance of order
void shuffle(vector<DNSZoneRecord>& rrs)
{
vector<DNSZoneRecord>::iterator first, second;
for(first=rrs.begin();first!=rrs.end();++first)
if(first->dr.d_place==DNSResourceRecord::ANSWER && first->dr.d_type != QType::CNAME) // CNAME must come first
break;
for(second=first;second!=rrs.end();++second)
if(second->dr.d_place!=DNSResourceRecord::ANSWER)
break;

dns_random_engine r;
if(second-first > 1)
shuffle(first, second, r);

// now shuffle the additional records
for(first=second;first!=rrs.end();++first)
if(first->dr.d_place==DNSResourceRecord::ADDITIONAL && first->dr.d_type != QType::CNAME) // CNAME must come first
break;
for(second=first;second!=rrs.end();++second)
if(second->dr.d_place!=DNSResourceRecord::ADDITIONAL)
break;

if(second-first>1)
shuffle(first, second, r);

// we don't shuffle the rest
}


// shuffle, maintaining some semblance of order
void shuffle(vector<DNSRecord>& rrs)
{
vector<DNSRecord>::iterator first, second;
for(first=rrs.begin();first!=rrs.end();++first)
if(first->d_place==DNSResourceRecord::ANSWER && first->d_type != QType::CNAME) // CNAME must come first
break;
for(second=first;second!=rrs.end();++second)
if(second->d_place!=DNSResourceRecord::ANSWER || second->d_type == QType::RRSIG) // leave RRSIGs at the end
break;

dns_random_engine r;
if(second-first>1)
shuffle(first, second, r);

// now shuffle the additional records
for(first=second;first!=rrs.end();++first)
if(first->d_place==DNSResourceRecord::ADDITIONAL && first->d_type != QType::CNAME) // CNAME must come first
break;
for(second=first; second!=rrs.end(); ++second)
if(second->d_place!=DNSResourceRecord::ADDITIONAL)
break;

if(second-first>1)
shuffle(first, second, r);

// we don't shuffle the rest
}

static uint16_t mapTypesToOrder(uint16_t type)
{
if (type == QType::CNAME)
return 0;
if (type == QType::RRSIG)
return 65535;
else
return 1;
}

// make sure rrs is sorted in d_place order to avoid surprises later
// then shuffle the parts that desire shuffling
void orderAndShuffle(vector<DNSRecord>& rrs)
{
std::stable_sort(rrs.begin(), rrs.end(), [](const DNSRecord&a, const DNSRecord& b) {
return std::make_tuple(a.d_place, mapTypesToOrder(a.d_type)) < std::make_tuple(b.d_place, mapTypesToOrder(b.d_type));
});
shuffle(rrs);
}
40 changes: 17 additions & 23 deletions pdns/dns_random.hh
Original file line number Diff line number Diff line change
Expand Up @@ -22,36 +22,30 @@
#pragma once
#include <cstdint>
#include <limits>
#include <vector>

void dns_random_init(const std::string& data = "", bool force_reinit = false);
uint32_t dns_random(uint32_t n);
uint16_t dns_random_uint16();

namespace pdns {
struct dns_random_engine {

struct dns_random_engine {
typedef uint32_t result_type;

typedef uint32_t result_type;
static constexpr result_type min()
{
return 0;
}

static constexpr result_type min()
{
return 0;
}
static constexpr result_type max()
{
return std::numeric_limits<result_type>::max() - 1;
}

static constexpr result_type max()
{
return std::numeric_limits<result_type>::max() - 1;
}

result_type operator()()
{
return dns_random(std::numeric_limits<result_type>::max());
}
};

struct DNSRecord;
struct DNSZoneRecord;
void shuffle(std::vector<DNSRecord>& rrs);
void shuffle(std::vector<DNSZoneRecord>& rrs);
void orderAndShuffle(std::vector<DNSRecord>& rrs);
result_type operator()()
{
return dns_random(std::numeric_limits<result_type>::max());
}
};
}

3 changes: 2 additions & 1 deletion pdns/dnspacket.cc
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
#include "ednssubnet.hh"
#include "gss_context.hh"
#include "dns_random.hh"
#include "shuffle.hh"

bool DNSPacket::s_doEDNSSubnetProcessing;
uint16_t DNSPacket::s_udpTruncationThreshold;
Expand Down Expand Up @@ -226,7 +227,7 @@ void DNSPacket::wrapup()
static bool mustNotShuffle = ::arg().mustDo("no-shuffle");

if(!d_tcp && !mustNotShuffle) {
shuffle(d_rrs);
pdns::shuffle(d_rrs);
}
d_wrapped=true;

Expand Down
3 changes: 2 additions & 1 deletion pdns/pdns_recursor.cc
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@
#include "gettime.hh"
#include "proxy-protocol.hh"
#include "pubsuffix.hh"
#include "shuffle.hh"
#ifdef NOD_ENABLED
#include "nod.hh"
#endif /* NOD_ENABLED */
Expand Down Expand Up @@ -1557,7 +1558,7 @@ static void startDoResolve(void *p)
}

if(ret.size()) {
orderAndShuffle(ret);
pdns::orderAndShuffle(ret);
if(auto sl = luaconfsLocal->sortlist.getOrderCmp(dc->d_source)) {
stable_sort(ret.begin(), ret.end(), *sl);
variableAnswer=true;
Expand Down
1 change: 1 addition & 0 deletions pdns/recursordist/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,7 @@ pdns_recursor_SOURCES = \
secpoll-recursor.cc secpoll-recursor.hh \
secpoll.cc secpoll.hh \
sholder.hh \
shuffle.cc shuffle.hh \
sillyrecords.cc \
snmp-agent.hh snmp-agent.cc \
sortlist.cc sortlist.hh \
Expand Down
1 change: 1 addition & 0 deletions pdns/recursordist/shuffle.cc
1 change: 1 addition & 0 deletions pdns/recursordist/shuffle.hh
109 changes: 109 additions & 0 deletions pdns/shuffle.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
/*
* This file is part of PowerDNS or dnsdist.
* Copyright -- PowerDNS.COM B.V. and its contributors
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* In addition, for the avoidance of any doubt, permission is granted to
* link this program with OpenSSL and to (re)distribute the binaries
* produced as the result of such linking.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <string>

#include "shuffle.hh"
#include "dns_random.hh"
#include "dnsparser.hh"

// shuffle, maintaining some semblance of order
void pdns::shuffle(std::vector<DNSZoneRecord>& rrs)
{
std::vector<DNSZoneRecord>::iterator first, second;
for(first=rrs.begin();first!=rrs.end();++first)
if(first->dr.d_place==DNSResourceRecord::ANSWER && first->dr.d_type != QType::CNAME) // CNAME must come first
break;
for(second=first;second!=rrs.end();++second)
if(second->dr.d_place!=DNSResourceRecord::ANSWER)
break;

dns_random_engine r;
if(second-first > 1)
shuffle(first, second, r);

// now shuffle the additional records
for(first=second;first!=rrs.end();++first)
if(first->dr.d_place==DNSResourceRecord::ADDITIONAL && first->dr.d_type != QType::CNAME) // CNAME must come first
break;
for(second=first;second!=rrs.end();++second)
if(second->dr.d_place!=DNSResourceRecord::ADDITIONAL)
break;

if(second-first>1)
shuffle(first, second, r);

// we don't shuffle the rest
}


// shuffle, maintaining some semblance of order
void pdns::shuffle(std::vector<DNSRecord>& rrs)
{
std::vector<DNSRecord>::iterator first, second;
for(first=rrs.begin();first!=rrs.end();++first)
if(first->d_place==DNSResourceRecord::ANSWER && first->d_type != QType::CNAME) // CNAME must come first
break;
for(second=first;second!=rrs.end();++second)
if(second->d_place!=DNSResourceRecord::ANSWER || second->d_type == QType::RRSIG) // leave RRSIGs at the end
break;

dns_random_engine r;
if(second-first>1)
shuffle(first, second, r);

// now shuffle the additional records
for(first=second;first!=rrs.end();++first)
if(first->d_place==DNSResourceRecord::ADDITIONAL && first->d_type != QType::CNAME) // CNAME must come first
break;
for(second=first; second!=rrs.end(); ++second)
if(second->d_place!=DNSResourceRecord::ADDITIONAL)
break;

if(second-first>1)
shuffle(first, second, r);

// we don't shuffle the rest
}

static uint16_t mapTypesToOrder(uint16_t type)
{
if (type == QType::CNAME)
return 0;
if (type == QType::RRSIG)
return 65535;
else
return 1;
}

// make sure rrs is sorted in d_place order to avoid surprises later
// then shuffle the parts that desire shuffling
void pdns::orderAndShuffle(vector<DNSRecord>& rrs)
{
std::stable_sort(rrs.begin(), rrs.end(), [](const DNSRecord&a, const DNSRecord& b) {
return std::make_tuple(a.d_place, mapTypesToOrder(a.d_type)) < std::make_tuple(b.d_place, mapTypesToOrder(b.d_type));
});
shuffle(rrs);
}
33 changes: 33 additions & 0 deletions pdns/shuffle.hh
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
* This file is part of PowerDNS or dnsdist.
* Copyright -- PowerDNS.COM B.V. and its contributors
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* In addition, for the avoidance of any doubt, permission is granted to
* link this program with OpenSSL and to (re)distribute the binaries
* produced as the result of such linking.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#pragma once
#include <vector>

struct DNSRecord;
struct DNSZoneRecord;

namespace pdns {
void shuffle(std::vector<DNSRecord>& rrs);
void shuffle(std::vector<DNSZoneRecord>& rrs);
void orderAndShuffle(std::vector<DNSRecord>& rrs);
}

0 comments on commit e19b663

Please sign in to comment.