summaryrefslogtreecommitdiffstats
path: root/test-dnsdistrules_cc.cc
diff options
context:
space:
mode:
Diffstat (limited to 'test-dnsdistrules_cc.cc')
-rw-r--r--test-dnsdistrules_cc.cc157
1 files changed, 157 insertions, 0 deletions
diff --git a/test-dnsdistrules_cc.cc b/test-dnsdistrules_cc.cc
new file mode 100644
index 0000000..b636ea9
--- /dev/null
+++ b/test-dnsdistrules_cc.cc
@@ -0,0 +1,157 @@
+
+#define BOOST_TEST_DYN_LINK
+#define BOOST_TEST_NO_MAIN
+
+#include <thread>
+#include <boost/test/unit_test.hpp>
+
+#include "dnsdist-rules.hh"
+
+void checkParameterBound(const std::string& parameter, uint64_t value, size_t max);
+void checkParameterBound(const std::string& parameter, uint64_t value, size_t max)
+{
+ if (value > max) {
+ throw std::runtime_error("The value passed to " + parameter + " is too large, the maximum is " + std::to_string(max));
+ }
+}
+
+static DNSQuestion getDQ(const DNSName* providedName = nullptr)
+{
+ static const DNSName qname("powerdns.com.");
+ static PacketBuffer packet(sizeof(dnsheader));
+ static InternalQueryState ids;
+ ids.origDest = ComboAddress("127.0.0.1:53");
+ ids.origRemote = ComboAddress("192.0.2.1:42");
+ ids.qname = providedName ? *providedName : qname;
+ ids.qtype = QType::A;
+ ids.qclass = QClass::IN;
+ ids.protocol = dnsdist::Protocol::DoUDP;
+ ids.queryRealTime.start();
+
+ DNSQuestion dq(ids, packet);
+ return dq;
+}
+
+BOOST_AUTO_TEST_SUITE(dnsdistluarules_cc)
+
+BOOST_AUTO_TEST_CASE(test_MaxQPSIPRule) {
+ size_t maxQPS = 10;
+ size_t maxBurst = maxQPS;
+ unsigned int expiration = 300;
+ unsigned int cleanupDelay = 60;
+ unsigned int scanFraction = 10;
+ MaxQPSIPRule rule(maxQPS, maxBurst, 32, 64, expiration, cleanupDelay, scanFraction);
+
+ InternalQueryState ids;
+ ids.qname = DNSName("powerdns.com.");
+ ids.qtype = QType::A;
+ ids.qclass = QClass::IN;
+ ids.origDest = ComboAddress("127.0.0.1:53");
+ ids.origRemote = ComboAddress("192.0.2.1:42");
+ ids.protocol = dnsdist::Protocol::DoUDP;
+ ids.queryRealTime.start();
+ PacketBuffer packet(sizeof(dnsheader));
+ struct timespec expiredTime;
+ /* the internal QPS limiter does not use the real time */
+ gettime(&expiredTime);
+
+ DNSQuestion dq(ids, packet);
+
+ for (size_t idx = 0; idx < maxQPS; idx++) {
+ /* let's use different source ports, it shouldn't matter */
+ ids.origRemote = ComboAddress("192.0.2.1:" + std::to_string(idx));
+ BOOST_CHECK_EQUAL(rule.matches(&dq), false);
+ BOOST_CHECK_EQUAL(rule.getEntriesCount(), 1U);
+ }
+
+ /* maxQPS + 1, we should be blocked */
+ BOOST_CHECK_EQUAL(rule.matches(&dq), true);
+ BOOST_CHECK_EQUAL(rule.getEntriesCount(), 1U);
+
+ /* remove all entries that have not been updated since 'now' + 1,
+ so all of them */
+ expiredTime.tv_sec += 1;
+ rule.cleanup(expiredTime);
+
+ /* we should have been cleaned up */
+ BOOST_CHECK_EQUAL(rule.getEntriesCount(), 0U);
+
+ struct timespec beginInsertionTime;
+ gettime(&beginInsertionTime);
+ /* we should not be blocked anymore */
+ BOOST_CHECK_EQUAL(rule.matches(&dq), false);
+ /* and we be back */
+ BOOST_CHECK_EQUAL(rule.getEntriesCount(), 1U);
+
+
+ /* Let's insert a lot of different sources now */
+ for (size_t idxByte3 = 0; idxByte3 < 256; idxByte3++) {
+ for (size_t idxByte4 = 0; idxByte4 < 256; idxByte4++) {
+ ids.origRemote = ComboAddress("10.0." + std::to_string(idxByte3) + "." + std::to_string(idxByte4));
+ BOOST_CHECK_EQUAL(rule.matches(&dq), false);
+ }
+ }
+ struct timespec endInsertionTime;
+ gettime(&endInsertionTime);
+
+ /* don't forget the existing entry */
+ size_t total = 1 + 256 * 256;
+ BOOST_CHECK_EQUAL(rule.getEntriesCount(), total);
+
+ /* make sure all entries are still valid */
+ struct timespec notExpiredTime = beginInsertionTime;
+ notExpiredTime.tv_sec -= 1;
+
+ size_t scanned = 0;
+ auto removed = rule.cleanup(notExpiredTime, &scanned);
+ BOOST_CHECK_EQUAL(removed, 0U);
+ /* the first entry should still have been valid, we should not have scanned more */
+ BOOST_CHECK_EQUAL(scanned, rule.getNumberOfShards());
+ BOOST_CHECK_EQUAL(rule.getEntriesCount(), total);
+
+ /* make sure all entries are _not_ valid anymore */
+ expiredTime = endInsertionTime;
+ expiredTime.tv_sec += 1;
+
+ removed = rule.cleanup(expiredTime, &scanned);
+ BOOST_CHECK_EQUAL(removed, (total / scanFraction) + 1 + rule.getNumberOfShards());
+ /* we should not have scanned more than scanFraction */
+ BOOST_CHECK_EQUAL(scanned, removed);
+ BOOST_CHECK_EQUAL(rule.getEntriesCount(), total - removed);
+
+ rule.clear();
+ BOOST_CHECK_EQUAL(rule.getEntriesCount(), 0U);
+ removed = rule.cleanup(expiredTime, &scanned);
+ BOOST_CHECK_EQUAL(removed, 0U);
+ BOOST_CHECK_EQUAL(scanned, 0U);
+}
+
+BOOST_AUTO_TEST_CASE(test_poolOutstandingRule) {
+ auto dq = getDQ();
+
+ ServerPool sp{};
+ auto ds1 = std::make_shared<DownstreamState>(ComboAddress("192.0.2.1:53"));
+ auto ds2 = std::make_shared<DownstreamState>(ComboAddress("192.0.2.2:53"));
+
+ /* increase the outstanding count of both */
+ ds1->outstanding = 400;
+ ds2->outstanding = 30;
+
+ sp.addServer(ds1);
+ sp.addServer(ds2);
+
+ BOOST_CHECK_EQUAL(sp.poolLoad(), 400U + 30U);
+
+ auto localPool = g_pools.getCopy();
+ addServerToPool(localPool, "test", ds1);
+ addServerToPool(localPool, "test", ds2);
+ g_pools.setState(localPool);
+
+ PoolOutstandingRule pOR1("test", 10);
+ BOOST_CHECK_EQUAL(pOR1.matches(&dq), true);
+
+ PoolOutstandingRule pOR2("test", 1000);
+ BOOST_CHECK_EQUAL(pOR2.matches(&dq), false);
+}
+
+BOOST_AUTO_TEST_SUITE_END()