]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/shuffle.cc
dnsdist: Fix DNS over plain HTTP broken by `reloadAllCertificates()`
[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
c4d9cae9 37 // We assume the CNAMES are listed first 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 }
1a871f62 46 // And then for one past the last ANSWER record
d720eb8a
OM
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
88da1249 76static void shuffle(std::vector<DNSRecord>& rrs, bool includingAdditionals)
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
88da1249
OM
96 if (!includingAdditionals) {
97 return;
98 }
99
bbec1961 100 // now shuffle the additional records
d720eb8a
OM
101 for (first = second; first != rrs.end(); ++first) {
102 if (first->d_place == DNSResourceRecord::ADDITIONAL && first->d_type != QType::CNAME) {
bbec1961 103 break;
d720eb8a
OM
104 }
105 }
106 for (second = first; second != rrs.end(); ++second) {
107 if (second->d_place != DNSResourceRecord::ADDITIONAL) {
bbec1961 108 break;
d720eb8a
OM
109 }
110 }
bbec1961 111
d720eb8a 112 if (second - first > 1) {
bbec1961 113 shuffle(first, second, r);
d720eb8a 114 }
bbec1961 115 // we don't shuffle the rest
116}
117
118static uint16_t mapTypesToOrder(uint16_t type)
119{
120 if (type == QType::CNAME)
121 return 0;
122 if (type == QType::RRSIG)
123 return 65535;
124 else
125 return 1;
126}
127
128// make sure rrs is sorted in d_place order to avoid surprises later
129// then shuffle the parts that desire shuffling
88da1249 130void pdns::orderAndShuffle(vector<DNSRecord>& rrs, bool includingAdditionals)
bbec1961 131{
d720eb8a 132 std::stable_sort(rrs.begin(), rrs.end(), [](const DNSRecord& a, const DNSRecord& b) {
0b0882f5 133 return std::tuple(a.d_place, mapTypesToOrder(a.d_type)) < std::tuple(b.d_place, mapTypesToOrder(b.d_type));
d720eb8a 134 });
88da1249 135 shuffle(rrs, includingAdditionals);
bbec1961 136}