From 2332b03c9c591f5e5539b6e482034047a25388f4 Mon Sep 17 00:00:00 2001 From: bert hubert Date: Fri, 4 Sep 2015 15:45:57 +0200 Subject: [PATCH] hook up TCAction() for use in addAction(). Add global MaxQPSLimit(), not just per IP(range). Document these and big up our https://repo.powerdns.com service --- pdns/README-dnsdist.md | 42 ++++++++++++++++++++++++++++++++++++++++++ pdns/dnsdist-lua.cc | 12 ++++++++++++ pdns/dnsrulactions.hh | 28 ++++++++++++++++++++++++++++ 3 files changed, 82 insertions(+) diff --git a/pdns/README-dnsdist.md b/pdns/README-dnsdist.md index efc11fdca..cd4b667ee 100644 --- a/pdns/README-dnsdist.md +++ b/pdns/README-dnsdist.md @@ -34,6 +34,7 @@ make Packaged -------- +We build packages for dnsdist on our [repositories](https://repo.powerdns.com). In addition dnsdist has been packaged for FreeBSD and can be found on https://freshports.org/dns/dnsdist Examples @@ -41,7 +42,9 @@ Examples The absolute minimum configuration: +```` # dnsdist 2001:4860:4860::8888 8.8.8.8 +``` This will listen on 0.0.0.0:53 and forward queries to the two listed IP addresses, with a sensible load balancing policy. @@ -195,6 +198,8 @@ Rules have selectors and actions. Current selectors are: * Source address * Query type * Query domain + * QPS Limit total + * QPS Limit per IP address or subnet Current actions are: * Drop @@ -203,6 +208,7 @@ Current actions are: * Force a ServFail, NotImp or Refused answer * Send out a crafted response (NXDOMAIN or "real" data) * Delay a response by n milliseconds + * Modify query to remove RD bit More power ---------- @@ -228,6 +234,42 @@ servers that lack this feature. Note that calling `addAnyTCRule()` achieves the same thing, without involving Lua. +Rules for traffic exceeding QPS limits +-------------------------------------- +Traffic that exceeds a QPS limit, in total or per IP (subnet) can be matched by a rule. + +For example: + +``` +addDelay(MaxQPSIPRule(5, 32, 48), 100) +``` + +This measures traffic per IPv4 address and per /48 of IPv6, and if traffic for such +an address (range) exceeds 5 qps, it gets delayed by 100ms. + +As another example: + +``` +addAction(MaxQPSIPRule(5), NoRecurseAction()) +``` + +This strips the Recursion Desired (RD) bit from any traffic per IPv4 or IPv6 /64 +that exceeds 5 qps. This means any those traffic bins is allowed to make a recursor do 'work' +for only 5 qps. + +If this is not enough, try: + +``` +addAction(MaxQPSIPRule(5), DropAction()) +-- or +addAction(MaxQPSIPRule(5), TCAction()) +``` + +This will respectively drop traffic exceeding that 5 QPS limit per IP or range, or return it with TC=1, forcing +clients to fall back to TCP/IP. + +To turn this per IP or range limit into a global limt, use MaxQPSRule(5000) instead of MaxQPSIPRule. + Lua actions in rules -------------------- While we can pass every packet through the `blockFilter()` functions, it is also diff --git a/pdns/dnsdist-lua.cc b/pdns/dnsdist-lua.cc index 85f911132..be5d8496c 100644 --- a/pdns/dnsdist-lua.cc +++ b/pdns/dnsdist-lua.cc @@ -354,12 +354,24 @@ vector> setupLua(bool client, const std::string& confi return std::shared_ptr(new DropAction); }); + g_lua.writeFunction("TCAction", []() { + return std::shared_ptr(new TCAction); + }); + g_lua.writeFunction("MaxQPSIPRule", [](unsigned int qps, boost::optional ipv4trunc, boost::optional ipv6trunc) { return std::shared_ptr(new MaxQPSIPRule(qps, ipv4trunc.get_value_or(32), ipv6trunc.get_value_or(64))); }); + g_lua.writeFunction("MaxQPSRule", [](unsigned int qps, boost::optional burst) { + if(!burst) + return std::shared_ptr(new MaxQPSRule(qps)); + else + return std::shared_ptr(new MaxQPSRule(qps, *burst)); + }); + + g_lua.writeFunction("addAction", [](luadnsrule_t var, std::shared_ptr ea) { auto rule=makeRule(var); diff --git a/pdns/dnsrulactions.hh b/pdns/dnsrulactions.hh index 2eb64e31c..6e16825cf 100644 --- a/pdns/dnsrulactions.hh +++ b/pdns/dnsrulactions.hh @@ -32,6 +32,34 @@ private: }; +class MaxQPSRule : public DNSRule +{ +public: + MaxQPSRule(unsigned int qps) + : d_qps(qps, qps) + {} + + MaxQPSRule(unsigned int qps, unsigned int burst) + : d_qps(qps, burst) + {} + + + bool matches(const ComboAddress& remote, const DNSName& qname, uint16_t qtype, dnsheader* dh, int len) const override + { + return d_qps.check(); + } + + string toString() const override + { + return "Max " + std::to_string(d_qps.getRate()) + " qps"; + } + + +private: + mutable QPSLimiter d_qps; +}; + + class NetmaskGroupRule : public DNSRule { -- 2.40.0