]>
Commit | Line | Data |
---|---|---|
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 | |
33 | void 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 | 76 | static 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 | ||
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 | |
88da1249 | 130 | void 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 | } |