]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/shuffle.cc
rec: mention rust compiler in compiling docs
[thirdparty/pdns.git] / pdns / shuffle.cc
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
33 void pdns::shuffle(std::vector<DNSZoneRecord>& rrs)
34 {
35 std::vector<DNSZoneRecord>::iterator first, second;
36
37 // We assume the CNAMES are listed first in the ANSWER section and the the other records
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) {
43 break;
44 }
45 }
46 // And then for one past the last ANSWER record
47 for (second = first; second != rrs.end(); ++second)
48 if (second->dr.d_place != DNSResourceRecord::ANSWER)
49 break;
50
51 // Now shuffle the non-CNAME ANSWER records
52 dns_random_engine r;
53 if (second - first > 1) {
54 shuffle(first, second, r);
55 }
56
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) {
60 break;
61 }
62 }
63 for (second = first; second != rrs.end(); ++second) {
64 if (second->dr.d_place != DNSResourceRecord::ADDITIONAL) {
65 break;
66 }
67 }
68
69 if (second - first > 1) {
70 shuffle(first, second, r);
71 }
72 // we don't shuffle the rest
73 }
74
75 // shuffle, maintaining some semblance of order
76 static void shuffle(std::vector<DNSRecord>& rrs, bool includingAdditionals)
77 {
78 // This shuffles in the same style as the above method, keeping CNAME in the front and RRSIGs at the end
79 std::vector<DNSRecord>::iterator first, second;
80 for (first = rrs.begin(); first != rrs.end(); ++first) {
81 if (first->d_place == DNSResourceRecord::ANSWER && first->d_type != QType::CNAME) {
82 break;
83 }
84 }
85 for (second = first; second != rrs.end(); ++second) {
86 if (second->d_place != DNSResourceRecord::ANSWER || second->d_type == QType::RRSIG) {
87 break;
88 }
89 }
90
91 pdns::dns_random_engine r;
92 if (second - first > 1) {
93 shuffle(first, second, r);
94 }
95
96 if (!includingAdditionals) {
97 return;
98 }
99
100 // now shuffle the additional records
101 for (first = second; first != rrs.end(); ++first) {
102 if (first->d_place == DNSResourceRecord::ADDITIONAL && first->d_type != QType::CNAME) {
103 break;
104 }
105 }
106 for (second = first; second != rrs.end(); ++second) {
107 if (second->d_place != DNSResourceRecord::ADDITIONAL) {
108 break;
109 }
110 }
111
112 if (second - first > 1) {
113 shuffle(first, second, r);
114 }
115 // we don't shuffle the rest
116 }
117
118 static 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
130 void pdns::orderAndShuffle(vector<DNSRecord>& rrs, bool includingAdditionals)
131 {
132 std::stable_sort(rrs.begin(), rrs.end(), [](const DNSRecord& a, const DNSRecord& b) {
133 return std::tuple(a.d_place, mapTypesToOrder(a.d_type)) < std::tuple(b.d_place, mapTypesToOrder(b.d_type));
134 });
135 shuffle(rrs, includingAdditionals);
136 }