]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/shuffle.cc
spelling: answer
[thirdparty/pdns.git] / pdns / shuffle.cc
CommitLineData
bbec1961 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#ifdef HAVE_CONFIG_H
23#include "config.h"
24#endif
25
26#include <string>
27
28#include "shuffle.hh"
29#include "dns_random.hh"
30#include "dnsparser.hh"
31
32// shuffle, maintaining some semblance of order
33void pdns::shuffle(std::vector<DNSZoneRecord>& rrs)
34{
35 std::vector<DNSZoneRecord>::iterator first, second;
d720eb8a 36
f0dc5d2d 37 // We assume the CNAMES are listed firts in the ANSWER section and the the other records
d720eb8a
OM
38 // and we want to shuffle the other records only
39
40 // First we scan for the first non-CNAME ANSWER record
41 for (first = rrs.begin(); first != rrs.end(); ++first) {
42 if (first->dr.d_place == DNSResourceRecord::ANSWER && first->dr.d_type != QType::CNAME) {
bbec1961 43 break;
d720eb8a
OM
44 }
45 }
46 // And then for one past the last ANSWER recordd
47 for (second = first; second != rrs.end(); ++second)
48 if (second->dr.d_place != DNSResourceRecord::ANSWER)
bbec1961 49 break;
50
d720eb8a 51 // Now shuffle the non-CNAME ANSWER records
bbec1961 52 dns_random_engine r;
d720eb8a 53 if (second - first > 1) {
bbec1961 54 shuffle(first, second, r);
d720eb8a 55 }
bbec1961 56
d720eb8a
OM
57 // now shuffle the ADDITIONAL records in the same manner as the ANSWER records
58 for (first = second; first != rrs.end(); ++first) {
59 if (first->dr.d_place == DNSResourceRecord::ADDITIONAL && first->dr.d_type != QType::CNAME) {
bbec1961 60 break;
d720eb8a
OM
61 }
62 }
63 for (second = first; second != rrs.end(); ++second) {
64 if (second->dr.d_place != DNSResourceRecord::ADDITIONAL) {
bbec1961 65 break;
d720eb8a
OM
66 }
67 }
bbec1961 68
d720eb8a 69 if (second - first > 1) {
bbec1961 70 shuffle(first, second, r);
d720eb8a 71 }
bbec1961 72 // we don't shuffle the rest
73}
74
bbec1961 75// shuffle, maintaining some semblance of order
d720eb8a 76static void shuffle(std::vector<DNSRecord>& rrs)
bbec1961 77{
d720eb8a 78 // This shuffles in the same style as the above method, keeping CNAME in the front and RRSIGs at the end
bbec1961 79 std::vector<DNSRecord>::iterator first, second;
d720eb8a
OM
80 for (first = rrs.begin(); first != rrs.end(); ++first) {
81 if (first->d_place == DNSResourceRecord::ANSWER && first->d_type != QType::CNAME) {
bbec1961 82 break;
d720eb8a
OM
83 }
84 }
85 for (second = first; second != rrs.end(); ++second) {
86 if (second->d_place != DNSResourceRecord::ANSWER || second->d_type == QType::RRSIG) {
bbec1961 87 break;
d720eb8a
OM
88 }
89 }
bbec1961 90
d720eb8a
OM
91 pdns::dns_random_engine r;
92 if (second - first > 1) {
bbec1961 93 shuffle(first, second, r);
d720eb8a 94 }
bbec1961 95
96 // now shuffle the additional records
d720eb8a
OM
97 for (first = second; first != rrs.end(); ++first) {
98 if (first->d_place == DNSResourceRecord::ADDITIONAL && first->d_type != QType::CNAME) {
bbec1961 99 break;
d720eb8a
OM
100 }
101 }
102 for (second = first; second != rrs.end(); ++second) {
103 if (second->d_place != DNSResourceRecord::ADDITIONAL) {
bbec1961 104 break;
d720eb8a
OM
105 }
106 }
bbec1961 107
d720eb8a 108 if (second - first > 1) {
bbec1961 109 shuffle(first, second, r);
d720eb8a 110 }
bbec1961 111 // we don't shuffle the rest
112}
113
114static uint16_t mapTypesToOrder(uint16_t type)
115{
116 if (type == QType::CNAME)
117 return 0;
118 if (type == QType::RRSIG)
119 return 65535;
120 else
121 return 1;
122}
123
124// make sure rrs is sorted in d_place order to avoid surprises later
125// then shuffle the parts that desire shuffling
126void pdns::orderAndShuffle(vector<DNSRecord>& rrs)
127{
d720eb8a
OM
128 std::stable_sort(rrs.begin(), rrs.end(), [](const DNSRecord& a, const DNSRecord& b) {
129 return std::make_tuple(a.d_place, mapTypesToOrder(a.d_type)) < std::make_tuple(b.d_place, mapTypesToOrder(b.d_type));
130 });
bbec1961 131 shuffle(rrs);
132}