]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
dnsdist: Implement the ability to cap TTLs for some record types only
authorRemi Gacogne <remi.gacogne@powerdns.com>
Fri, 11 Feb 2022 14:34:26 +0000 (15:34 +0100)
committerRemi Gacogne <remi.gacogne@powerdns.com>
Wed, 11 Jan 2023 13:42:27 +0000 (14:42 +0100)
pdns/dnsdist-idstate.hh
pdns/dnsdist-lua-actions.cc
pdns/dnsdist-lua.hh
pdns/dnsdist.cc
pdns/dnsdistdist/dnsdist-lua-ffi-interface.h
pdns/dnsdistdist/dnsdist-lua-ffi.cc
pdns/dnsdistdist/docs/rules-actions.rst

index 5b42f986f561f764767b9835298904f816ec441a..d11c5c4226e2c4656027cf79e44c75d9b2e9ae0f 100644 (file)
@@ -117,6 +117,7 @@ struct InternalQueryState
   InternalQueryState& operator=(const InternalQueryState& orig) = delete;
 
   boost::optional<Netmask> subnet{boost::none}; // 40
+  std::set<QType> ttlCapTypes;
   ComboAddress origRemote; // 28
   ComboAddress origDest; // 28
   ComboAddress hopRemote;
index 5d093bc25c184dffb5d8ca14d0abe1cfb3493f9f..af6fec942f01f402507ba8ceb848ad2923966824 100644 (file)
@@ -2328,8 +2328,14 @@ void setupLuaActions(LuaContext& luaCtx)
       return std::shared_ptr<DNSResponseAction>(new LogResponseAction(fname ? *fname : "", append ? *append : false, buffered ? *buffered : false, verboseOnly ? *verboseOnly : true, includeTimestamp ? *includeTimestamp : false));
     });
 
-  luaCtx.writeFunction("LimitTTLResponseAction", [](uint32_t min, uint32_t max) {
-      return std::shared_ptr<DNSResponseAction>(new LimitTTLResponseAction(min, max));
+  luaCtx.writeFunction("LimitTTLResponseAction", [](uint32_t min, uint32_t max, boost::optional<LuaArray<uint16_t>> types) {
+      std::set<QType> capTypes;
+      if (types) {
+        for (const auto& [idx, type] : *types) {
+          capTypes.insert(QType(type));
+        }
+      }
+      return std::shared_ptr<DNSResponseAction>(new LimitTTLResponseAction(min, max, capTypes));
     });
 
   luaCtx.writeFunction("SetMinTTLResponseAction", [](uint32_t min) {
index 54049fa07b337d0ac4f17ba8b0c616bf41489988..abaf11904a108089b4998d1ba1f6a39b6f92acf7 100644 (file)
@@ -99,13 +99,17 @@ class LimitTTLResponseAction : public DNSResponseAction, public boost::noncopyab
 public:
   LimitTTLResponseAction() {}
 
-  LimitTTLResponseAction(uint32_t min, uint32_t max = std::numeric_limits<uint32_t>::max()) : d_min(min), d_max(max)
+  LimitTTLResponseAction(uint32_t min, uint32_t max = std::numeric_limits<uint32_t>::max(), std::set<QType> types = {}) : d_types(types), d_min(min), d_max(max)
   {
   }
 
   DNSResponseAction::Action operator()(DNSResponse* dr, std::string* ruleresult) const override
   {
     auto visitor = [&](uint8_t section, uint16_t qclass, uint16_t qtype, uint32_t ttl) {
+      if (!d_types.empty() && qclass == QClass::IN && d_types.count(qtype) == 0) {
+        return ttl;
+      }
+
       if (d_min > 0) {
         if (ttl < d_min) {
           ttl = d_min;
@@ -122,10 +126,27 @@ public:
 
   std::string toString() const override
   {
-    return "limit ttl (" + std::to_string(d_min) + " <= ttl <= " + std::to_string(d_max) + ")";
+    std::string result = "limit ttl (" + std::to_string(d_min) + " <= ttl <= " + std::to_string(d_max);
+    if (!d_types.empty()) {
+      bool first = true;
+      result += ", types in [";
+      for (const auto& type : d_types) {
+        if (first) {
+          first = false;
+        }
+        else {
+          result += " ";
+        }
+        result += type.toString();
+      }
+      result += "]";
+    }
+    result += + ")";
+    return result;
   }
 
 private:
+  std::set<QType> d_types;
   uint32_t d_min{0};
   uint32_t d_max{std::numeric_limits<uint32_t>::max()};
 };
index ddc933861b4f98f12b790ed938f247edecb0498e..2faeede4e1bb073b5a12b36570b834ea3a20932e 100644 (file)
@@ -554,7 +554,7 @@ bool processResponse(PacketBuffer& response, const std::vector<DNSDistResponseRu
 
   if (dr.ids.ttlCap > 0) {
     std::string result;
-    LimitTTLResponseAction ac(0, dr.ids.ttlCap);
+    LimitTTLResponseAction ac(0, dr.ids.ttlCap, dr.ids.ttlCapTypes);
     ac(&dr, &result);
   }
 
@@ -1226,7 +1226,7 @@ static bool prepareOutgoingResponse(LocalHolders& holders, ClientState& cs, DNSQ
 
   if (dr.ids.ttlCap > 0) {
     std::string result;
-    LimitTTLResponseAction ac(0, dr.ids.ttlCap);
+    LimitTTLResponseAction ac(0, dr.ids.ttlCap, dr.ids.ttlCapTypes);
     ac(&dr, &result);
   }
 
index 3a509058a2a9f4038deb0e50dd6cdd39fa737f6f..ee61517028744c7d843d84969c5666e90117c9e3 100644 (file)
@@ -124,6 +124,8 @@ void dnsdist_ffi_dnsquestion_spoof_packet(dnsdist_ffi_dnsquestion_t* dq, const c
 
 /* 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")));
+/* add a record type to apply the TTL cap to (see above) */
+void dnsdist_ffi_dnsquestion_add_type_to_max_returned_ttl(dnsdist_ffi_dnsquestion_t* dr, uint16_t type) __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;
@@ -146,6 +148,8 @@ 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) __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")));
+/* add a record type to apply the TTL cap to (see above) */
+void dnsdist_ffi_dnsresponse_add_type_to_max_returned_ttl(dnsdist_ffi_dnsresponse_t* dr, uint16_t type) __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 a0f782710a069a151265976c91005b5f5d782a8f..979e7f7627367b83be2f487ff0203aa122c28aa0 100644 (file)
@@ -549,6 +549,13 @@ void dnsdist_ffi_dnsquestion_set_max_returned_ttl(dnsdist_ffi_dnsquestion_t* dq,
   }
 }
 
+void dnsdist_ffi_dnsquestion_add_type_to_max_returned_ttl(dnsdist_ffi_dnsquestion_t* dq, uint16_t type)
+{
+  if (dq != nullptr && dq->dq != nullptr) {
+    dq->dq->ids.ttlCapTypes.insert(type);
+  }
+}
+
 size_t dnsdist_ffi_servers_list_get_count(const dnsdist_ffi_servers_list_t* list)
 {
   return list->ffiServers.size();
@@ -642,6 +649,13 @@ void dnsdist_ffi_dnsresponse_set_max_returned_ttl(dnsdist_ffi_dnsresponse_t* dr,
   }
 }
 
+void dnsdist_ffi_dnsresponse_add_type_to_max_returned_ttl(dnsdist_ffi_dnsresponse_t* dr, uint16_t type)
+{
+  if (dr != nullptr && dr->dr != nullptr) {
+    dr->dr->ids.ttlCapTypes.insert(type);
+  }
+}
+
 void dnsdist_ffi_dnsresponse_clear_records_type(dnsdist_ffi_dnsresponse_t* dr, uint16_t qtype)
 {
   if (dr != nullptr && dr->dr != nullptr) {
index 8b0c017573843fdeb9f24e12563bc5a0b14f40d3..38bf7b564bf24e1171cfb1f221413753c91b1cbd 100644 (file)
@@ -1089,7 +1089,7 @@ The following actions exist.
   :param KeyValueLookupKey lookupKey: The key to use for the lookup
   :param string destinationTag: The name of the tag to store the result into
 
-.. function:: LimitTTLResponseAction(min[, max])
+.. function:: LimitTTLResponseAction(min[, max [, types]])
 
   .. versionadded:: 1.8.0
 
@@ -1097,6 +1097,7 @@ The following actions exist.
 
   :param int min: The minimum allowed value
   :param int max: The maximum allowed value
+  :param list of int: The record types to cap the TTL for. Default is empty which means all records will be capped.
 
 .. function:: LogAction([filename[, binary[, append[, buffered[, verboseOnly[, includeTimestamp]]]]]])