]>
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 | |
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 | 76 | static 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 | ||
114 | static 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 | |
126 | void 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 | } |