From: Remi Gacogne Date: Wed, 12 Jan 2022 13:58:34 +0000 (+0100) Subject: dnsdist: Add MaxReturnedTTLResponseAction to cap the TTL after packet cache X-Git-Tag: dnsdist-1.8.0-rc1~120^2~3 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=f5676cc87e84f69de1974f9cfb6e9da184ef2cdd;p=thirdparty%2Fpdns.git dnsdist: Add MaxReturnedTTLResponseAction to cap the TTL after packet cache --- diff --git a/pdns/dnsdist-idstate.hh b/pdns/dnsdist-idstate.hh index a7a5200d16..5b42f986f5 100644 --- a/pdns/dnsdist-idstate.hh +++ b/pdns/dnsdist-idstate.hh @@ -134,6 +134,7 @@ struct InternalQueryState uint32_t cacheKeyNoECS{0}; // 4 // DoH-only */ uint32_t cacheKeyUDP{0}; // 4 + uint32_t ttlCap{0}; // cap the TTL _after_ inserting into the packet cache // 4 int backendFD{-1}; // 4 int delayMsec{0}; uint16_t qtype{0}; // 2 diff --git a/pdns/dnsdist-lua-actions.cc b/pdns/dnsdist-lua-actions.cc index 3975004c50..5d093bc25c 100644 --- a/pdns/dnsdist-lua-actions.cc +++ b/pdns/dnsdist-lua-actions.cc @@ -1739,8 +1739,6 @@ private: class ClearRecordTypesResponseAction : public DNSResponseAction, public boost::noncopyable { public: - ClearRecordTypesResponseAction() {} - ClearRecordTypesResponseAction(const std::set& qtypes) : d_qtypes(qtypes) { } @@ -1901,6 +1899,50 @@ private: }; #endif /* defined(HAVE_LMDB) || defined(HAVE_CDB) */ +class MaxReturnedTTLAction : public DNSAction +{ +public: + MaxReturnedTTLAction(uint32_t cap) : d_cap(cap) + { + } + + DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override + { + dq->ids.ttlCap = d_cap; + return DNSAction::Action::None; + } + + std::string toString() const override + { + return "cap the TTL of the returned response to " + std::to_string(d_cap); + } + +private: + uint32_t d_cap; +}; + +class MaxReturnedTTLResponseAction : public DNSResponseAction +{ +public: + MaxReturnedTTLResponseAction(uint32_t cap) : d_cap(cap) + { + } + + DNSResponseAction::Action operator()(DNSResponse* dr, std::string* ruleresult) const override + { + dr->ids.ttlCap = d_cap; + return DNSResponseAction::Action::None; + } + + std::string toString() const override + { + return "cap the TTL of the returned response to " + std::to_string(d_cap); + } + +private: + uint32_t d_cap; +}; + class NegativeAndSOAAction: public DNSAction { public: @@ -2298,6 +2340,14 @@ void setupLuaActions(LuaContext& luaCtx) return std::shared_ptr(new LimitTTLResponseAction(0, max)); }); + luaCtx.writeFunction("SetMaxReturnedTTLAction", [](uint32_t max) { + return std::shared_ptr(new MaxReturnedTTLAction(max)); + }); + + luaCtx.writeFunction("SetMaxReturnedTTLResponseAction", [](uint32_t max) { + return std::shared_ptr(new MaxReturnedTTLResponseAction(max)); + }); + luaCtx.writeFunction("SetReducedTTLResponseAction", [](uint8_t percentage) { if (percentage > 100) { throw std::runtime_error(std::string("SetReducedTTLResponseAction takes a percentage between 0 and 100.")); diff --git a/pdns/dnsdist.cc b/pdns/dnsdist.cc index 9f76591b5a..ddc933861b 100644 --- a/pdns/dnsdist.cc +++ b/pdns/dnsdist.cc @@ -552,6 +552,12 @@ bool processResponse(PacketBuffer& response, const std::vector 0) { + std::string result; + LimitTTLResponseAction ac(0, dr.ids.ttlCap); + ac(&dr, &result); + } + #ifdef HAVE_DNSCRYPT if (!muted) { if (!encryptResponse(response, dr.getMaximumSize(), dr.overTCP(), dr.ids.dnsCryptQuery)) { @@ -1218,6 +1224,12 @@ static bool prepareOutgoingResponse(LocalHolders& holders, ClientState& cs, DNSQ return false; } + if (dr.ids.ttlCap > 0) { + std::string result; + LimitTTLResponseAction ac(0, dr.ids.ttlCap); + ac(&dr, &result); + } + #ifdef HAVE_DNSCRYPT if (!cs.muted) { if (!encryptResponse(dq.getMutableData(), dq.getMaximumSize(), dq.overTCP(), dq.ids.dnsCryptQuery)) { diff --git a/pdns/dnsdistdist/dnsdist-lua-ffi-interface.h b/pdns/dnsdistdist/dnsdist-lua-ffi-interface.h index b74409f2c7..3a509058a2 100644 --- a/pdns/dnsdistdist/dnsdist-lua-ffi-interface.h +++ b/pdns/dnsdistdist/dnsdist-lua-ffi-interface.h @@ -122,6 +122,9 @@ void dnsdist_ffi_dnsquestion_spoof_addrs(dnsdist_ffi_dnsquestion_t* dq, const dn // spoof raw response. will just replace qid to match question void dnsdist_ffi_dnsquestion_spoof_packet(dnsdist_ffi_dnsquestion_t* dq, const char* rawresponse, size_t len) __attribute__ ((visibility ("default"))); +/* decrease the returned TTL but _after_ inserting the original response into the packet cache */ +void dnsdist_ffi_dnsquestion_set_max_returned_ttl(dnsdist_ffi_dnsquestion_t* dq, uint32_t max) __attribute__ ((visibility ("default"))); + typedef struct dnsdist_ffi_servers_list_t dnsdist_ffi_servers_list_t; typedef struct dnsdist_ffi_server_t dnsdist_ffi_server_t; @@ -141,6 +144,8 @@ double dnsdist_ffi_server_get_latency(const dnsdist_ffi_server_t* server) __attr void dnsdist_ffi_dnsresponse_set_min_ttl(dnsdist_ffi_dnsresponse_t* dr, uint32_t min) __attribute__ ((visibility ("default"))); void dnsdist_ffi_dnsresponse_set_max_ttl(dnsdist_ffi_dnsresponse_t* dr, uint32_t max) __attribute__ ((visibility ("default"))); void dnsdist_ffi_dnsresponse_limit_ttl(dnsdist_ffi_dnsresponse_t* dr, uint32_t min, uint32_t max) __attribute__ ((visibility ("default"))); +/* decrease the returned TTL but _after_ inserting the original response into the packet cache */ +void dnsdist_ffi_dnsresponse_set_max_returned_ttl(dnsdist_ffi_dnsresponse_t* dr, uint32_t max) __attribute__ ((visibility ("default"))); void dnsdist_ffi_dnsresponse_clear_records_type(dnsdist_ffi_dnsresponse_t* dr, uint16_t qtype) __attribute__ ((visibility ("default"))); typedef struct dnsdist_ffi_proxy_protocol_value { diff --git a/pdns/dnsdistdist/dnsdist-lua-ffi.cc b/pdns/dnsdistdist/dnsdist-lua-ffi.cc index 391da097f3..a0f782710a 100644 --- a/pdns/dnsdistdist/dnsdist-lua-ffi.cc +++ b/pdns/dnsdistdist/dnsdist-lua-ffi.cc @@ -542,6 +542,13 @@ void dnsdist_ffi_dnsquestion_spoof_addrs(dnsdist_ffi_dnsquestion_t* dq, const dn sa(dq->dq, &result); } +void dnsdist_ffi_dnsquestion_set_max_returned_ttl(dnsdist_ffi_dnsquestion_t* dq, uint32_t max) +{ + if (dq != nullptr && dq->dq != nullptr) { + dq->dq->ids.ttlCap = max; + } +} + size_t dnsdist_ffi_servers_list_get_count(const dnsdist_ffi_servers_list_t* list) { return list->ffiServers.size(); @@ -621,16 +628,23 @@ void dnsdist_ffi_dnsresponse_set_max_ttl(dnsdist_ffi_dnsresponse_t* dr, uint32_t void dnsdist_ffi_dnsresponse_limit_ttl(dnsdist_ffi_dnsresponse_t* dr, uint32_t min, uint32_t max) { - if (dr->dr != nullptr) { + if (dr != nullptr && dr->dr != nullptr) { std::string result; LimitTTLResponseAction ac(min, max); ac(dr->dr, &result); } } +void dnsdist_ffi_dnsresponse_set_max_returned_ttl(dnsdist_ffi_dnsresponse_t* dr, uint32_t max) +{ + if (dr != nullptr && dr->dr != nullptr) { + dr->dr->ids.ttlCap = max; + } +} + void dnsdist_ffi_dnsresponse_clear_records_type(dnsdist_ffi_dnsresponse_t* dr, uint16_t qtype) { - if (dr->dr != nullptr) { + if (dr != nullptr && dr->dr != nullptr) { clearDNSPacketRecordTypes(dr->dr->getMutableData(), std::set{qtype}); } } diff --git a/pdns/dnsdistdist/docs/rules-actions.rst b/pdns/dnsdistdist/docs/rules-actions.rst index 1077859a0d..8b0c017573 100644 --- a/pdns/dnsdistdist/docs/rules-actions.rst +++ b/pdns/dnsdistdist/docs/rules-actions.rst @@ -883,6 +883,10 @@ Some actions allow further processing of rules, this is noted in their descripti - :func:`NoneAction` - :func:`RemoteLogAction` - :func:`RemoteLogResponseAction` +- :func:`SetMaxReturnedTTLResponseAction` +- :func:`SetMaxReturnedTTLAction` +- :func:`SetMinTTLResponseAction` +- :func:`SetMaxTTLResponseAction` - :func:`SNMPTrapAction` - :func:`SNMPTrapResponseAction` - :func:`TeeAction` @@ -1433,6 +1437,22 @@ The following actions exist. :param int option: The EDNS0 option number +.. function:: SetMaxReturnedTTLAction(max) + + .. versionadded:: 1.8.0 + + Cap the TTLs of the response to the given maximum, but only after inserting the response into the packet cache with the initial TTL values. + + :param int max: The maximum allowed value + +.. function:: SetMaxReturnedTTLResponseAction(max) + + .. versionadded:: 1.8.0 + + Cap the TTLs of the response to the given maximum, but only after inserting the response into the packet cache with the initial TTL values. + + :param int max: The maximum allowed value + .. function:: SetMaxTTLResponseAction(max) .. versionadded:: 1.8.0