]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
dnsdist: Add a Lua FFI interface to get SMT dynamic blocks
authorRemi Gacogne <remi.gacogne@powerdns.com>
Mon, 13 Nov 2023 10:18:55 +0000 (11:18 +0100)
committerRemi Gacogne <remi.gacogne@powerdns.com>
Tue, 14 Nov 2023 14:43:38 +0000 (15:43 +0100)
pdns/dnsdistdist/dnsdist-lua-ffi-interface.h
pdns/dnsdistdist/dnsdist-lua-ffi.cc

index 93d476ccdee68c2671c90491f72c46b0e996f9e1..a0ff3bf9fbb4f69fc98375f8d7a22fbde13aa549 100644 (file)
@@ -252,9 +252,10 @@ uint16_t dnsdist_ffi_network_message_get_endpoint_id(const dnsdist_ffi_network_m
    - clientIPPort indicates It is also possible to take the IPv4 UDP and TCP ports into account, for CGNAT deployments, by setting the number of bits of the port to consider. For example passing 2 as the last parameter, which only makes sense if the previous parameters are respectively 32 and 128, will split a given IP address into four port ranges: 0-16383, 16384-32767, 32768-49151 and 49152-65535.
 */
 bool dnsdist_ffi_dynamic_blocks_add(const char* address, const char* message, uint8_t action, unsigned int duration, uint8_t clientIPMask, uint8_t clientIPPortMask) __attribute__ ((visibility ("default")));
+bool dnsdist_ffi_dynamic_blocks_smt_add(const char* suffix, const char* message, uint8_t action, unsigned int duration) __attribute__ ((visibility ("default")));
 
 typedef struct dnsdist_ffi_dynamic_block_entry {
-  char* client;
+  char* key; /* Client IP for NMT blocks, domain name for SMT ones */
   char* reason;
   uint64_t blockedQueries;
   uint64_t remainingTime;
@@ -266,5 +267,6 @@ typedef struct dnsdist_ffi_dynamic_block_entry {
 typedef struct dnsdist_ffi_dynamic_blocks_list_t dnsdist_ffi_dynamic_blocks_list_t;
 
 size_t dnsdist_ffi_dynamic_blocks_get_entries(dnsdist_ffi_dynamic_blocks_list_t** out) __attribute__ ((visibility ("default")));
+size_t dnsdist_ffi_dynamic_blocks_smt_get_entries(dnsdist_ffi_dynamic_blocks_list_t** out) __attribute__ ((visibility ("default")));
 const dnsdist_ffi_dynamic_block_entry_t* dnsdist_ffi_dynamic_blocks_list_get(const dnsdist_ffi_dynamic_blocks_list_t* list, size_t idx) __attribute__ ((visibility ("default")));
 void dnsdist_ffi_dynamic_blocks_list_free(dnsdist_ffi_dynamic_blocks_list_t*) __attribute__ ((visibility ("default")));
index a9765218f9deb62813d0f69c0d310ae7e06018b8..4b7ae8cf49fb6f136a9e66efa9b1cd822c85ce52 100644 (file)
@@ -1707,11 +1707,11 @@ bool dnsdist_ffi_dynamic_blocks_add(const char* address, const char* message, ui
       clientIPCA = ComboAddress(address);
     }
     catch (const std::exception& exp) {
-      errlog("addDynamicBlock: Unable to parse '%s': %s", address, exp.what());
+      errlog("dnsdist_ffi_dynamic_blocks_add: Unable to parse '%s': %s", address, exp.what());
       return false;
     }
     catch (const PDNSException& exp) {
-      errlog("addDynamicBlock: Unable to parse '%s': %s", address, exp.reason);
+      errlog("dnsdist_ffi_dynamic_blocks_add: Unable to parse '%s': %s", address, exp.reason);
       return false;
     }
 
@@ -1737,6 +1737,43 @@ bool dnsdist_ffi_dynamic_blocks_add(const char* address, const char* message, ui
   return false;
 }
 
+bool dnsdist_ffi_dynamic_blocks_smt_add(const char* suffix, const char* message, uint8_t action, unsigned int duration)
+{
+  try {
+    DNSName domain;
+    try {
+      domain = DNSName(suffix);
+      domain.makeUsLowerCase();
+    }
+    catch (const std::exception& exp) {
+      errlog("dnsdist_ffi_dynamic_blocks_smt_add: Unable to parse '%s': %s", suffix, exp.what());
+      return false;
+    }
+    catch (const PDNSException& exp) {
+      errlog("dnsdist_ffi_dynamic_blocks_smt_add: Unable to parse '%s': %s", suffix, exp.reason);
+      return false;
+    }
+
+    struct timespec now;
+    gettime(&now);
+    auto slow = g_dynblockSMT.getCopy();
+    if (dnsdist::DynamicBlocks::addOrRefreshBlockSMT(slow, now, domain, message, duration, static_cast<DNSAction::Action>(action), false)) {
+      g_dynblockSMT.setState(slow);
+      return true;
+    }
+  }
+  catch (const std::exception& exp) {
+    errlog("Exception in dnsdist_ffi_dynamic_blocks_smt_add: %s", exp.what());
+  }
+  catch (const PDNSException& exp) {
+    errlog("Exception in dnsdist_ffi_dynamic_blocks_smt_add: %s", exp.reason);
+  }
+  catch (...) {
+    errlog("Exception in dnsdist_ffi_dynamic_blocks_smt_add");
+  }
+  return false;
+}
+
 struct dnsdist_ffi_dynamic_blocks_list_t
 {
   std::vector<dnsdist_ffi_dynamic_block_entry_t> d_entries;
@@ -1773,6 +1810,38 @@ size_t dnsdist_ffi_dynamic_blocks_get_entries(dnsdist_ffi_dynamic_blocks_list_t*
   return count;
 }
 
+size_t dnsdist_ffi_dynamic_blocks_smt_get_entries(dnsdist_ffi_dynamic_blocks_list_t** out)
+{
+  if (out == nullptr) {
+    return 0;
+  }
+
+  auto list = std::make_unique<dnsdist_ffi_dynamic_blocks_list_t>();
+
+  struct timespec now;
+  gettime(&now);
+
+  auto fullCopy = g_dynblockSMT.getCopy();
+  fullCopy.visit([&now, &list](const SuffixMatchTree<DynBlock>& node) {
+    if (!(now < node.d_value.until)) {
+      return;
+    }
+    auto entry = node.d_value;
+    string key("empty");
+    if (!entry.domain.empty()) {
+      key = entry.domain.toString();
+    }
+    if (entry.action == DNSAction::Action::None) {
+      entry.action = g_dynBlockAction;
+    }
+    list->d_entries.push_back({strdup(key.c_str()), strdup(entry.reason.c_str()), entry.blocks, static_cast<uint64_t>(entry.until.tv_sec - now.tv_sec), static_cast<uint8_t>(entry.action), entry.bpf, entry.warning});
+  });
+
+  auto count = list->d_entries.size();
+  *out = list.release();
+  return count;
+}
+
 const dnsdist_ffi_dynamic_block_entry_t* dnsdist_ffi_dynamic_blocks_list_get(const dnsdist_ffi_dynamic_blocks_list_t* list, size_t idx)
 {
   if (list == nullptr) {
@@ -1793,7 +1862,7 @@ void dnsdist_ffi_dynamic_blocks_list_free(dnsdist_ffi_dynamic_blocks_list_t* lis
   }
 
   for (auto& entry : list->d_entries) {
-    free(entry.client);
+    free(entry.key);
     free(entry.reason);
   }