]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
dnsdist: Add MaxReturnedTTLResponseAction to cap the TTL after packet cache
authorRemi Gacogne <remi.gacogne@powerdns.com>
Wed, 12 Jan 2022 13:58:34 +0000 (14:58 +0100)
committerRemi Gacogne <remi.gacogne@powerdns.com>
Wed, 11 Jan 2023 13:42:24 +0000 (14:42 +0100)
pdns/dnsdist-idstate.hh
pdns/dnsdist-lua-actions.cc
pdns/dnsdist.cc
pdns/dnsdistdist/dnsdist-lua-ffi-interface.h
pdns/dnsdistdist/dnsdist-lua-ffi.cc
pdns/dnsdistdist/docs/rules-actions.rst

index a7a5200d16825f14346bab323f3f7b0f32e6ce8b..5b42f986f561f764767b9835298904f816ec441a 100644 (file)
@@ -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
index 3975004c50973233ce05ae8447a90adea2157c67..5d093bc25c184dffb5d8ca14d0abe1cfb3493f9f 100644 (file)
@@ -1739,8 +1739,6 @@ private:
 class ClearRecordTypesResponseAction : public DNSResponseAction, public boost::noncopyable
 {
 public:
-  ClearRecordTypesResponseAction() {}
-
   ClearRecordTypesResponseAction(const std::set<QType>& 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<DNSResponseAction>(new LimitTTLResponseAction(0, max));
     });
 
+  luaCtx.writeFunction("SetMaxReturnedTTLAction", [](uint32_t max) {
+    return std::shared_ptr<DNSAction>(new MaxReturnedTTLAction(max));
+  });
+
+  luaCtx.writeFunction("SetMaxReturnedTTLResponseAction", [](uint32_t max) {
+    return std::shared_ptr<DNSResponseAction>(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."));
index 9f76591b5a27a609d94fe0073f2dbf69c21988b2..ddc933861b4f98f12b790ed938f247edecb0498e 100644 (file)
@@ -552,6 +552,12 @@ bool processResponse(PacketBuffer& response, const std::vector<DNSDistResponseRu
     }
   }
 
+  if (dr.ids.ttlCap > 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)) {
index b74409f2c7691ff65e6f75bcd1f7f386bf76c771..3a509058a2a9f4038deb0e50dd6cdd39fa737f6f 100644 (file)
@@ -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 {
index 391da097f3ba8748dca71baecbfcc50d45b95687..a0f782710a069a151265976c91005b5f5d782a8f 100644 (file)
@@ -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>{qtype});
   }
 }
index 1077859a0df046220de636bd2c264950b5fe547e..8b0c017573843fdeb9f24e12563bc5a0b14f40d3 100644 (file)
@@ -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