• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

PowerDNS / pdns / 18679017918

21 Oct 2025 09:15AM UTC coverage: 69.743% (+2.0%) from 67.713%
18679017918

Pull #16307

github

web-flow
Merge ba88af487 into da98764c6
Pull Request #16307: rec: explicit disabling/enabling of tls-gnutls for full and least configs and packages

26192 of 45526 branches covered (57.53%)

Branch coverage included in aggregate %.

6 of 6 new or added lines in 1 file covered. (100.0%)

2282 existing lines in 57 files now uncovered.

86265 of 115719 relevant lines covered (74.55%)

4323875.05 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/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;
×
36
  std::vector<DNSZoneRecord>::iterator second;
×
37

38
  // We assume the CNAMES are listed first in the ANSWER section and the the other records
39
  // and we want to shuffle the other records only
40

41
  // First we scan for the first non-CNAME ANSWER record
42
  for (first = rrs.begin(); first != rrs.end(); ++first) {
×
43
    if (first->dr.d_place == DNSResourceRecord::ANSWER && first->dr.d_type != QType::CNAME) {
×
44
      break;
×
45
    }
×
46
  }
×
47
  // And then for one past the last ANSWER record
48
  for (second = first; second != rrs.end(); ++second) {
×
49
    if (second->dr.d_place != DNSResourceRecord::ANSWER) {
×
50
      break;
×
51
    }
×
52
  }
×
53

54
  // Now shuffle the non-CNAME ANSWER records
55
  dns_random_engine randomEngine;
×
56
  if (second - first > 1) {
×
57
    shuffle(first, second, randomEngine);
×
58
  }
×
59

60
  // now shuffle the ADDITIONAL records in the same manner as the ANSWER records
61
  for (first = second; first != rrs.end(); ++first) {
×
62
    if (first->dr.d_place == DNSResourceRecord::ADDITIONAL && first->dr.d_type != QType::CNAME) {
×
63
      break;
×
64
    }
×
65
  }
×
66
  for (second = first; second != rrs.end(); ++second) {
×
67
    if (second->dr.d_place != DNSResourceRecord::ADDITIONAL) {
×
68
      break;
×
69
    }
×
70
  }
×
71

72
  if (second - first > 1) {
×
73
    shuffle(first, second, randomEngine);
×
74
  }
×
75
  // we don't shuffle the rest
76
}
×
77

78
// shuffle, maintaining some semblance of order
79
static void shuffle(std::vector<DNSRecord>& rrs, bool includingAdditionals)
UNCOV
80
{
×
81
  // This shuffles in the same style as the above method, keeping CNAME in the front and RRSIGs at the end
UNCOV
82
  std::vector<DNSRecord>::iterator first;
×
UNCOV
83
  std::vector<DNSRecord>::iterator second;
×
84

UNCOV
85
  for (first = rrs.begin(); first != rrs.end(); ++first) {
×
UNCOV
86
    if (first->d_place == DNSResourceRecord::ANSWER && first->d_type != QType::CNAME) {
×
UNCOV
87
      break;
×
UNCOV
88
    }
×
UNCOV
89
  }
×
UNCOV
90
  for (second = first; second != rrs.end(); ++second) {
×
UNCOV
91
    if (second->d_place != DNSResourceRecord::ANSWER || second->d_type == QType::RRSIG) {
×
UNCOV
92
      break;
×
UNCOV
93
    }
×
UNCOV
94
  }
×
95

UNCOV
96
  pdns::dns_random_engine randomEngine;
×
UNCOV
97
  if (second - first > 1) {
×
UNCOV
98
    shuffle(first, second, randomEngine);
×
UNCOV
99
  }
×
100

UNCOV
101
  if (!includingAdditionals) {
×
UNCOV
102
    return;
×
UNCOV
103
  }
×
104

105
  // now shuffle the additional records
106
  for (first = second; first != rrs.end(); ++first) {
×
107
    if (first->d_place == DNSResourceRecord::ADDITIONAL && first->d_type != QType::CNAME) {
×
108
      break;
×
109
    }
×
110
  }
×
111
  for (second = first; second != rrs.end(); ++second) {
×
112
    if (second->d_place != DNSResourceRecord::ADDITIONAL) {
×
113
      break;
×
114
    }
×
115
  }
×
116

117
  if (second - first > 1) {
×
118
    shuffle(first, second, randomEngine);
×
119
  }
×
120
  // we don't shuffle the rest
121
}
×
122

123
static uint16_t mapTypesToOrder(uint16_t type)
UNCOV
124
{
×
UNCOV
125
  if (type == QType::CNAME) {
×
UNCOV
126
    return 0;
×
UNCOV
127
  }
×
UNCOV
128
  if (type == QType::RRSIG) {
×
UNCOV
129
    return 65535;
×
UNCOV
130
  }
×
UNCOV
131
  return 1;
×
UNCOV
132
}
×
133

134
// make sure rrs is sorted in d_place order to avoid surprises later
135
// then shuffle the parts that desire shuffling
136
void pdns::orderAndShuffle(vector<DNSRecord>& rrs, bool includingAdditionals)
UNCOV
137
{
×
UNCOV
138
  std::stable_sort(rrs.begin(), rrs.end(), [](const DNSRecord& lhs, const DNSRecord& rhs) {
×
UNCOV
139
    return std::tuple(lhs.d_place, mapTypesToOrder(lhs.d_type)) < std::tuple(rhs.d_place, mapTypesToOrder(rhs.d_type));
×
UNCOV
140
  });
×
UNCOV
141
  shuffle(rrs, includingAdditionals);
×
UNCOV
142
}
×
143

144
unsigned int pdns::dedupRecords(vector<DNSRecord>& rrs)
UNCOV
145
{
×
146
  // This function tries to avoid unnecessary work
147
  // First a vector with zero or one element does not need dedupping
UNCOV
148
  if (rrs.size() <= 1) {
×
UNCOV
149
    return 0;
×
UNCOV
150
  }
×
151

152
  // If we have a larger vector, first check if we actually have duplicates.
153
  // We assume the most common case is: no
UNCOV
154
  std::unordered_set<std::string> seen;
×
UNCOV
155
  std::vector<bool> dups(rrs.size(), false);
×
156

UNCOV
157
  unsigned int counter = 0;
×
UNCOV
158
  unsigned int numDups = 0;
×
159

UNCOV
160
  seen.reserve(rrs.size());
×
UNCOV
161
  for (const auto& rec : rrs) {
×
UNCOV
162
    auto key = rec.getContent()->serialize(rec.d_name, true, true, true);
×
163
    // This ignores class, ttl and place by using constants for those
UNCOV
164
    if (!seen.emplace(std::move(key)).second) {
×
UNCOV
165
      dups[counter] = true;
×
UNCOV
166
      numDups++;
×
UNCOV
167
    }
×
UNCOV
168
    ++counter;
×
UNCOV
169
  }
×
170

UNCOV
171
  if (numDups == 0) {
×
172
    // Original is fine as-is.
UNCOV
173
    return 0;
×
UNCOV
174
  }
×
175

176
  // We avoid calling erase, as it calls a lot of move constructors. This can hurt, especially if
177
  // you call it on a large vector multiple times.
178
  // So we just take the elements that are unique
UNCOV
179
  std::vector<DNSRecord> ret;
×
UNCOV
180
  ret.reserve(rrs.size() - numDups);
×
UNCOV
181
  for (counter = 0; counter < rrs.size(); ++counter) {
×
UNCOV
182
    if (!dups[counter]) {
×
UNCOV
183
      ret.emplace_back(std::move(rrs[counter]));
×
UNCOV
184
    }
×
UNCOV
185
  }
×
UNCOV
186
  rrs = std::move(ret);
×
UNCOV
187
  return numDups;
×
UNCOV
188
}
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc