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

PowerDNS / pdns / 13111317048

03 Feb 2025 10:22AM UTC coverage: 64.724% (+9.5%) from 55.194%
13111317048

Pull #14724

github

web-flow
Merge cced151a0 into db18c3a17
Pull Request #14724: dnsdist: Add meson support

38354 of 90334 branches covered (42.46%)

Branch coverage included in aggregate %.

449 of 624 new or added lines in 40 files covered. (71.96%)

6809 existing lines in 147 files now uncovered.

128214 of 167016 relevant lines covered (76.77%)

4848378.55 hits per line

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

90.23
/pdns/dnsdistdist/test-dnsdistrules_cc.cc
1

2
#ifndef BOOST_TEST_DYN_LINK
3
#define BOOST_TEST_DYN_LINK
4
#endif
5

6
#define BOOST_TEST_NO_MAIN
7

8
#include <thread>
9
#include <boost/test/unit_test.hpp>
10

11
#include "dnsdist-rules.hh"
12
#include "dnsdist-rules-factory.hh"
13

14
void checkParameterBound(const std::string& parameter, uint64_t value, size_t max)
15
{
×
16
  if (value > max) {
×
17
    throw std::runtime_error("The value passed to " + parameter + " is too large, the maximum is " + std::to_string(max));
×
18
  }
×
19
}
×
20

21
struct RuleParameter
22
{
23
  std::string name;
24
  std::variant<unsigned int, std::string> value;
25
};
26

27
template <typename ParameterType>
28
ParameterType getRequiredRuleParameter(const std::string& ruleName, std::vector<RuleParameter>& parameters, const std::string& parameterName)
29
{
2✔
30
  for (auto paramIt = parameters.begin(); paramIt != parameters.end(); ) {
2!
31
    if (paramIt->name != parameterName) {
2!
UNCOV
32
      ++paramIt;
×
UNCOV
33
      continue;
×
UNCOV
34
    }
×
35
    auto value = std::get<ParameterType>(paramIt->value);
2✔
36
    parameters.erase(paramIt);
2✔
37
    return value;
2✔
38
  }
2✔
39

UNCOV
40
  throw std::runtime_error("Missing required parameter '" + parameterName + "' for selector '" + ruleName + "'");
×
41
}
2✔
42

43
template <typename ParameterType>
44
ParameterType getOptionalRuleParameter(const std::string& ruleName, std::vector<RuleParameter>& parameters, const std::string& parameterName, ParameterType defaultValue)
45
{
4✔
46
  (void)ruleName;
4✔
47

48
  for (auto paramIt = parameters.begin(); paramIt != parameters.end(); ) {
6✔
49
    if (paramIt->name != parameterName) {
4✔
50
      ++paramIt;
2✔
51
      continue;
2✔
52
    }
2✔
53
    auto value = std::get<ParameterType>(paramIt->value);
2✔
54
    parameters.erase(paramIt);
2✔
55
    return value;
2✔
56
  }
4✔
57

58
  return defaultValue;
2✔
59
}
4✔
60

61
class TestMaxQPSIPRule : public DNSRule
62
{
63
public:
64
  TestMaxQPSIPRule(const std::string& ruleName, std::vector<RuleParameter>& parameters):
65
    d_qps(getRequiredRuleParameter<unsigned int>(ruleName, parameters, "qps")),
66
    d_burst(getOptionalRuleParameter<unsigned int>(ruleName, parameters, "burst", d_qps)),
67
    d_ipv4trunc(getOptionalRuleParameter<unsigned int>(ruleName, parameters, "ipv4-truncation", 32))
68
  {
2✔
69
  }
2✔
70

71
  bool matches(const DNSQuestion* dnsQuestion) const override
UNCOV
72
  {
×
NEW
73
    (void)dnsQuestion;
×
UNCOV
74
    return true;
×
UNCOV
75
  }
×
76

77
  string toString() const override
UNCOV
78
  {
×
UNCOV
79
    return "";
×
UNCOV
80
  }
×
81
private:
82
  unsigned int d_qps;
83
  unsigned int d_burst;
84
  unsigned int d_ipv4trunc;
85
};
86

87
static std::shared_ptr<DNSRule> buildSelector(const std::string& type, std::vector<RuleParameter>& parameters)
88
{
2✔
89
  return std::make_shared<TestMaxQPSIPRule>(type, parameters);
2✔
90
}
2✔
91

92
static DNSQuestion getDQ(const DNSName* providedName = nullptr)
93
{
4✔
94
  static const DNSName qname("powerdns.com.");
4✔
95
  static PacketBuffer packet(sizeof(dnsheader));
4✔
96
  static InternalQueryState ids;
4✔
97
  ids.origDest = ComboAddress("127.0.0.1:53");
4✔
98
  ids.origRemote = ComboAddress("192.0.2.1:42");
4✔
99
  ids.qname = providedName ? *providedName : qname;
4!
100
  ids.qtype = QType::A;
4✔
101
  ids.qclass = QClass::IN;
4✔
102
  ids.protocol = dnsdist::Protocol::DoUDP;
4✔
103
  ids.queryRealTime.start();
4✔
104

105
  DNSQuestion dq(ids, packet);
4✔
106
  return dq;
4✔
107
}
4✔
108

109
BOOST_AUTO_TEST_SUITE(dnsdistluarules_cc)
110

111
BOOST_AUTO_TEST_CASE(test_MaxQPSIPRule) {
2✔
112
  size_t maxQPS = 10;
2✔
113
  size_t maxBurst = maxQPS;
2✔
114
  unsigned int expiration = 300;
2✔
115
  unsigned int cleanupDelay = 60;
2✔
116
  unsigned int scanFraction = 10;
2✔
117
  auto rule = dnsdist::selectors::getMaxQPSIPSelector(maxQPS, 32, 64, maxBurst, expiration, cleanupDelay, scanFraction, 1);
2✔
118

119
  InternalQueryState ids;
2✔
120
  ids.qname = DNSName("powerdns.com.");
2✔
121
  ids.qtype = QType::A;
2✔
122
  ids.qclass = QClass::IN;
2✔
123
  ids.origDest = ComboAddress("127.0.0.1:53");
2✔
124
  ids.origRemote = ComboAddress("192.0.2.1:42");
2✔
125
  ids.protocol = dnsdist::Protocol::DoUDP;
2✔
126
  ids.queryRealTime.start();
2✔
127
  PacketBuffer packet(sizeof(dnsheader));
2✔
128
  struct timespec expiredTime;
2✔
129
  /* the internal QPS limiter does not use the real time */
130
  gettime(&expiredTime);
2✔
131

132
  DNSQuestion dq(ids, packet);
2✔
133

134
  for (size_t idx = 0; idx < maxQPS; idx++) {
22✔
135
    /* let's use different source ports, it shouldn't matter */
136
    ids.origRemote = ComboAddress("192.0.2.1:" + std::to_string(idx));
20✔
137
    BOOST_CHECK_EQUAL(rule->matches(&dq), false);
20✔
138
    BOOST_CHECK_EQUAL(rule->getEntriesCount(), 1U);
20✔
139
  }
20✔
140

141
  /* maxQPS + 1, we should be blocked */
142
  BOOST_CHECK_EQUAL(rule->matches(&dq), true);
2✔
143
  BOOST_CHECK_EQUAL(rule->getEntriesCount(), 1U);
2✔
144

145
  /* remove all entries that have not been updated since 'now' + 1,
146
     so all of them */
147
  expiredTime.tv_sec += 1;
2✔
148
  rule->cleanup(expiredTime);
2✔
149

150
  /* we should have been cleaned up */
151
  BOOST_CHECK_EQUAL(rule->getEntriesCount(), 0U);
2✔
152

153
  struct timespec beginInsertionTime;
2✔
154
  gettime(&beginInsertionTime);
2✔
155
  /* we should not be blocked anymore */
156
  BOOST_CHECK_EQUAL(rule->matches(&dq), false);
2✔
157
  /* and we be back */
158
  BOOST_CHECK_EQUAL(rule->getEntriesCount(), 1U);
2✔
159

160

161
  /* Let's insert a lot of different sources now */
162
  for (size_t idxByte3 = 0; idxByte3 < 256; idxByte3++) {
514✔
163
    for (size_t idxByte4 = 0; idxByte4 < 256; idxByte4++) {
131,584✔
164
      ids.origRemote = ComboAddress("10.0." + std::to_string(idxByte3) + "." + std::to_string(idxByte4));
131,072✔
165
      BOOST_CHECK_EQUAL(rule->matches(&dq), false);
131,072✔
166
    }
131,072✔
167
  }
512✔
168
  struct timespec endInsertionTime;
2✔
169
  gettime(&endInsertionTime);
2✔
170

171
  /* don't forget the existing entry */
172
  size_t total = 1 + 256 * 256;
2✔
173
  BOOST_CHECK_EQUAL(rule->getEntriesCount(), total);
2✔
174

175
  /* make sure all entries are still valid */
176
  struct timespec notExpiredTime = beginInsertionTime;
2✔
177
  notExpiredTime.tv_sec -= 1;
2✔
178

179
  size_t scanned = 0;
2✔
180
  auto removed = rule->cleanup(notExpiredTime, &scanned);
2✔
181
  BOOST_CHECK_EQUAL(removed, 0U);
2✔
182
  /* the first entry should still have been valid, we should not have scanned more */
183
  BOOST_CHECK_EQUAL(scanned, rule->getNumberOfShards());
2✔
184
  BOOST_CHECK_EQUAL(rule->getEntriesCount(), total);
2✔
185

186
  /* make sure all entries are _not_ valid anymore */
187
  expiredTime = endInsertionTime;
2✔
188
  expiredTime.tv_sec += 1;
2✔
189

190
  removed = rule->cleanup(expiredTime, &scanned);
2✔
191
  BOOST_CHECK_EQUAL(removed, (total / scanFraction) + 1 + rule->getNumberOfShards());
2✔
192
  /* we should not have scanned more than scanFraction */
193
  BOOST_CHECK_EQUAL(scanned, removed);
2✔
194
  BOOST_CHECK_EQUAL(rule->getEntriesCount(), total - removed);
2✔
195

196
  rule->clear();
2✔
197
  BOOST_CHECK_EQUAL(rule->getEntriesCount(), 0U);
2✔
198
  removed = rule->cleanup(expiredTime, &scanned);
2✔
199
  BOOST_CHECK_EQUAL(removed, 0U);
2✔
200
  BOOST_CHECK_EQUAL(scanned, 0U);
2✔
201
}
2✔
202

203
BOOST_AUTO_TEST_CASE(test_poolOutstandingRule) {
2✔
204
  auto dq = getDQ();
2✔
205

206
  ServerPool sp{};
2✔
207
  auto ds1 = std::make_shared<DownstreamState>(ComboAddress("192.0.2.1:53"));
2✔
208
  auto ds2 = std::make_shared<DownstreamState>(ComboAddress("192.0.2.2:53"));
2✔
209

210
  /* increase the outstanding count of both */
211
  ds1->outstanding = 400;
2✔
212
  ds2->outstanding = 30;
2✔
213

214
  sp.addServer(ds1);
2✔
215
  sp.addServer(ds2);
2✔
216

217
  BOOST_CHECK_EQUAL(sp.poolLoad(), 400U + 30U);
2✔
218

219
  addServerToPool("test", ds1);
2✔
220
  addServerToPool("test", ds2);
2✔
221

222
  PoolOutstandingRule pOR1("test", 10);
2✔
223
  BOOST_CHECK_EQUAL(pOR1.matches(&dq), true);
2✔
224

225
  PoolOutstandingRule pOR2("test", 1000);
2✔
226
  BOOST_CHECK_EQUAL(pOR2.matches(&dq), false);
2✔
227
}
2✔
228

229
BOOST_AUTO_TEST_CASE(test_payloadSizeRule) {
2✔
230
  auto dnsQuestion = getDQ();
2✔
231

232
  {
2✔
233
    PayloadSizeRule rule("equal", dnsQuestion.getData().size());
2✔
234
    BOOST_CHECK_EQUAL(rule.matches(&dnsQuestion), true);
2✔
235
    BOOST_CHECK_EQUAL(rule.toString(), "payload size is equal to " + std::to_string(dnsQuestion.getData().size()));
2✔
236
  }
2✔
237

238
  {
2✔
239
    PayloadSizeRule rule("equal", dnsQuestion.getData().size() + 1);
2✔
240
    BOOST_CHECK_EQUAL(rule.matches(&dnsQuestion), false);
2✔
241
  }
2✔
242

243
  {
2✔
244
    PayloadSizeRule rule("greater", dnsQuestion.getData().size());
2✔
245
    BOOST_CHECK_EQUAL(rule.matches(&dnsQuestion), false);
2✔
246
    BOOST_CHECK_EQUAL(rule.toString(), "payload size is greater than " + std::to_string(dnsQuestion.getData().size()));
2✔
247
  }
2✔
248

249
  {
2✔
250
    PayloadSizeRule rule("greater", dnsQuestion.getData().size() - 1);
2✔
251
    BOOST_CHECK_EQUAL(rule.matches(&dnsQuestion), true);
2✔
252
  }
2✔
253

254
  {
2✔
255
    PayloadSizeRule rule("smaller", dnsQuestion.getData().size());
2✔
256
    BOOST_CHECK_EQUAL(rule.matches(&dnsQuestion), false);
2✔
257
    BOOST_CHECK_EQUAL(rule.toString(), "payload size is smaller than " + std::to_string(dnsQuestion.getData().size()));
2✔
258
  }
2✔
259

260
  {
2✔
261
    PayloadSizeRule rule("smaller", dnsQuestion.getData().size() + 1);
2✔
262
    BOOST_CHECK_EQUAL(rule.matches(&dnsQuestion), true);
2✔
263
  }
2✔
264

265
  {
2✔
266
    PayloadSizeRule rule("greaterOrEqual", dnsQuestion.getData().size());
2✔
267
    BOOST_CHECK_EQUAL(rule.matches(&dnsQuestion), true);
2✔
268
    BOOST_CHECK_EQUAL(rule.toString(), "payload size is equal to or greater than " + std::to_string(dnsQuestion.getData().size()));
2✔
269
  }
2✔
270

271
  {
2✔
272
    PayloadSizeRule rule("greaterOrEqual", dnsQuestion.getData().size() - 1);
2✔
273
    BOOST_CHECK_EQUAL(rule.matches(&dnsQuestion), true);
2✔
274
  }
2✔
275

276
  {
2✔
277
    PayloadSizeRule rule("greaterOrEqual", dnsQuestion.getData().size() + 1);
2✔
278
    BOOST_CHECK_EQUAL(rule.matches(&dnsQuestion), false);
2✔
279
  }
2✔
280

281
  {
2✔
282
    PayloadSizeRule rule("smallerOrEqual", dnsQuestion.getData().size());
2✔
283
    BOOST_CHECK_EQUAL(rule.matches(&dnsQuestion), true);
2✔
284
    BOOST_CHECK_EQUAL(rule.toString(), "payload size is equal to or smaller than " + std::to_string(dnsQuestion.getData().size()));
2✔
285
  }
2✔
286

287
  {
2✔
288
    PayloadSizeRule rule("smallerOrEqual", dnsQuestion.getData().size() + 1);
2✔
289
    BOOST_CHECK_EQUAL(rule.matches(&dnsQuestion), true);
2✔
290
  }
2✔
291

292
  {
2✔
293
    PayloadSizeRule rule("smallerOrEqual", dnsQuestion.getData().size() - 1);
2✔
294
    BOOST_CHECK_EQUAL(rule.matches(&dnsQuestion), false);
2✔
295
  }
2✔
296

297
  BOOST_CHECK_THROW(PayloadSizeRule("invalid", 42U), std::runtime_error);
2✔
298

299
  std::vector<RuleParameter> parameters{
2✔
300
    RuleParameter{ "qps", 5U },
2✔
301
    RuleParameter{ "ipv4-truncation", 24U },
2✔
302
  };
2✔
303
  auto got = buildSelector("TestMaxQPSIPRule", parameters);
2✔
304
}
2✔
305

306
BOOST_AUTO_TEST_SUITE_END()
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