]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
Proof of coccept for postresove_ffi
authorOtto <otto.moerbeek@open-xchange.com>
Fri, 3 Dec 2021 12:07:44 +0000 (13:07 +0100)
committerOtto <otto.moerbeek@open-xchange.com>
Tue, 7 Dec 2021 08:26:15 +0000 (09:26 +0100)
Likely API needs tweaks.

pdns/lua-recursor4-ffi.hh
pdns/lua-recursor4.cc
pdns/lua-recursor4.hh
pdns/pdns_recursor.cc
pdns/recursordist/rec-eventtrace.cc
pdns/recursordist/rec-eventtrace.hh

index bffc9618f72d41594937136d68d7028e13bba0cf..7cbcb351d1208558f3f0eceb29ae0ea752a122ab 100644 (file)
@@ -40,11 +40,31 @@ extern "C"
 
   typedef enum
   {
-    answer = 1,
-    authority = 2,
-    additional = 3
+    pdns_record_place_answer = 1,
+    pdns_record_place_authority = 2,
+    pdns_record_place_additional = 3
   } pdns_record_place_t;
 
+  // Must match DNSFilterEngine::PolicyKind
+  typedef enum
+  {
+    pdns_policy_kind_noaction = 0,
+    pdns_policy_kind_drop = 1,
+    pdns_policy_kind_nxdomain = 2,
+    pdns_policy_kind_nodata = 3,
+    pdns_policy_kind_truncate = 4,
+    pdns_policy_kind_custom = 5
+  } pdns_policy_kind_t;
+
+  typedef struct pdns_ffi_record {
+    const char* name;
+    const char* content;
+    size_t content_len;
+    uint32_t ttl;
+    pdns_record_place_t place;
+    uint16_t type;
+  } pdns_ffi_record_t;
+
   const char* pdns_ffi_param_get_qname(pdns_ffi_param_t* ref) __attribute__((visibility("default")));
   void pdns_ffi_param_get_qname_raw(pdns_ffi_param_t* ref, const char** qname, size_t* qnameSize) __attribute__((visibility("default")));
   uint16_t pdns_ffi_param_get_qtype(const pdns_ffi_param_t* ref) __attribute__((visibility("default")));
@@ -89,4 +109,16 @@ extern "C"
   void pdns_ffi_param_set_padding_disabled(pdns_ffi_param_t* ref, bool disabled) __attribute__((visibility("default")));
   void pdns_ffi_param_add_meta_single_string_kv(pdns_ffi_param_t* ref, const char* key, const char* val) __attribute__((visibility("default")));
   void pdns_ffi_param_add_meta_single_int64_kv(pdns_ffi_param_t* ref, const char* key, int64_t val) __attribute__((visibility("default")));
+
+  typedef struct pdns_postresolve_ffi_handle pdns_postresolve_ffi_handle_t;
+
+  const char* pdns_postresolve_ffi_handle_get_qname(pdns_postresolve_ffi_handle_t* ref) __attribute__((visibility("default")));
+  uint16_t pdns_postresolve_ffi_handle_get_qtype(const pdns_postresolve_ffi_handle_t* ref) __attribute__((visibility("default")));
+  uint16_t pdns_postresolve_ffi_handle_get_rcode(const pdns_postresolve_ffi_handle_t* ref) __attribute__((visibility("default")));
+  pdns_policy_kind_t pdns_postresolve_ffi_handle_get_appliedpolicy_kind(const pdns_postresolve_ffi_handle_t* ref) __attribute__((visibility("default")));
+  void pdns_postresolve_ffi_handle_set_appliedpolicy_kind(pdns_postresolve_ffi_handle_t* ref, pdns_policy_kind_t kind) __attribute__((visibility("default")));
+  bool pdns_postresolve_ffi_handle_get_record(pdns_postresolve_ffi_handle_t* ref, unsigned int i, pdns_ffi_record_t *record, bool raw) __attribute__((visibility("default")));
+  bool pdns_postresolve_ffi_handle_set_record(pdns_postresolve_ffi_handle_t* ref, unsigned int i, const char* content, size_t contentLen, bool raw) __attribute__((visibility("default")));
+  void pdns_postresolve_ffi_handle_clear_records(pdns_postresolve_ffi_handle_t* ref) __attribute__((visibility("default")));
+  bool pdns_postresolve_ffi_handle_add_record(pdns_postresolve_ffi_handle_t* ref, const char* name, uint16_t type, uint32_t ttl, const char* content, size_t contentLen, pdns_record_place_t place, bool raw) __attribute__((visibility("default")));
 }
index e2578bfab4acd1d951effb8e3e2a4db26ebcc57d..94bb9bcebd9970a8957dd8f9e382f6e021036e49 100644 (file)
@@ -482,6 +482,7 @@ void RecursorLua4::postLoad()
   d_ipfilter = d_lw->readVariable<boost::optional<ipfilter_t>>("ipfilter").get_value_or(0);
   d_gettag = d_lw->readVariable<boost::optional<gettag_t>>("gettag").get_value_or(0);
   d_gettag_ffi = d_lw->readVariable<boost::optional<gettag_ffi_t>>("gettag_ffi").get_value_or(0);
+  d_postresolve_ffi = d_lw->readVariable<boost::optional<postresolve_ffi_t>>("postresolve_ffi").get_value_or(0);
 
   d_policyHitEventFilter = d_lw->readVariable<boost::optional<policyEventFilter_t>>("policyEventFilter").get_value_or(0);
 }
@@ -1033,3 +1034,140 @@ void pdns_ffi_param_add_meta_single_int64_kv(pdns_ffi_param_t* ref, const char*
 {
   ref->params.meta[std::string(key)].intVal.insert(val);
 }
+
+struct pdns_postresolve_ffi_handle
+{
+public:
+  pdns_postresolve_ffi_handle(RecursorLua4::PostResolveFFIHandle& h) :
+    handle(h)
+  {
+  }
+  ~pdns_postresolve_ffi_handle()
+  {
+    cerr << "~pdns_postresolve_ffi_handle: " << pool.size() << endl;
+  }
+  RecursorLua4::PostResolveFFIHandle& handle;
+  std::unordered_set<std::string> pool;
+  auto insert(const std::string& str)
+  {
+    auto [it, inserted] = pool.insert(str);
+    return it;
+  }
+};
+
+bool RecursorLua4::postresolve_ffi(RecursorLua4::PostResolveFFIHandle& h) const
+{
+  if (d_postresolve_ffi) {
+    pdns_postresolve_ffi_handle_t handle(h);
+
+    auto ret = d_postresolve_ffi(&handle);
+    return ret;
+  }
+  return false;
+}
+
+const char* pdns_postresolve_ffi_handle_get_qname(pdns_postresolve_ffi_handle_t* ref)
+{
+  auto str = ref->insert(ref->handle.d_dq.qname.toStringNoDot());
+  return str->c_str();
+}
+
+uint16_t pdns_postresolve_ffi_handle_get_qtype(const pdns_postresolve_ffi_handle_t* ref)
+{
+  return ref->handle.d_dq.qtype;
+}
+
+uint16_t pdns_postresolve_ffi_handle_get_rcode(const pdns_postresolve_ffi_handle_t* ref)
+{
+  return ref->handle.d_dq.rcode;
+}
+
+pdns_policy_kind_t pdns_postresolve_ffi_handle_get_appliedpolicy_kind(const pdns_postresolve_ffi_handle_t* ref)
+{
+  return static_cast<pdns_policy_kind_t>(ref->handle.d_dq.appliedPolicy->d_kind);
+}
+
+void pdns_postresolve_ffi_handle_set_appliedpolicy_kind(pdns_postresolve_ffi_handle_t* ref, pdns_policy_kind_t kind)
+{
+  ref->handle.d_dq.appliedPolicy->d_kind = static_cast<DNSFilterEngine::PolicyKind>(kind);
+}
+
+bool pdns_postresolve_ffi_handle_get_record(pdns_postresolve_ffi_handle_t* ref, unsigned int i, pdns_ffi_record_t *record, bool raw)
+{
+  if (i >= ref->handle.d_dq.currentRecords->size()) {
+    return false;
+  }
+  try {
+    DNSRecord& r = ref->handle.d_dq.currentRecords->at(i);
+    record->name = ref->insert(r.d_name.toStringNoDot())->c_str();
+    if (raw) {
+      auto content = ref->insert(r.d_content->serialize(r.d_name, true));
+      record->content = content->data();
+      record->content_len = content->size();
+    } else {
+      auto content = ref->insert(r.d_content->getZoneRepresentation());
+      record->content = content->data();
+      record->content_len = content->size();
+    }
+    record->ttl = r.d_ttl;
+    record->place = static_cast<pdns_record_place_t>(r.d_place);
+    record->type = r.d_type;
+  }
+  catch (const std::exception& e) {
+    g_log << Logger::Error << "Error attempting to get a record from Lua via pdns_postresolve_ffi_handle_get_record: " << e.what() << endl;
+    return false;
+  }
+
+  return true;
+}
+
+bool pdns_postresolve_ffi_handle_set_record(pdns_postresolve_ffi_handle_t* ref, unsigned int i, const char* content, size_t contentLen, bool raw)
+{
+  if (i >= ref->handle.d_dq.currentRecords->size()) {
+    return false;
+  }
+  try {
+    DNSRecord& r = ref->handle.d_dq.currentRecords->at(i);
+    if (raw) {
+      r.d_content = DNSRecordContent::deserialize(r.d_name, r.d_type, string(content, contentLen));
+    } else {
+      r.d_content = DNSRecordContent::mastermake(r.d_type, QClass::IN, string(content, contentLen));
+    }
+
+    return true;
+  }
+  catch (const std::exception& e) {
+    g_log << Logger::Error << "Error attempting to add a record from Lua via pdns_postresolve_ffi_handle_set_record(): " << e.what() << endl;
+    return false;
+  }
+}
+
+void pdns_postresolve_ffi_handle_clear_records(pdns_postresolve_ffi_handle_t* ref)
+{
+  ref->handle.d_dq.currentRecords->clear();
+}
+
+bool pdns_postresolve_ffi_handle_add_record(pdns_postresolve_ffi_handle_t* ref, const char* name, uint16_t type, uint32_t ttl, const char* content, size_t contentLen, pdns_record_place_t place, bool raw)
+{
+  try {
+    DNSRecord dr;
+    dr.d_name = name != nullptr ? DNSName(name) : ref->handle.d_dq.qname;
+    dr.d_ttl = ttl;
+    dr.d_type = type;
+    dr.d_class = QClass::IN;
+    dr.d_place = DNSResourceRecord::Place(place);
+    if (raw) {
+      dr.d_content = DNSRecordContent::deserialize(dr.d_name, dr.d_type, string(content, contentLen));
+    } else {
+      dr.d_content = DNSRecordContent::mastermake(type, QClass::IN, string(content, contentLen));
+    }
+    ref->handle.d_dq.currentRecords->push_back(std::move(dr));
+
+    return true;
+  }
+  catch (const std::exception& e) {
+    g_log << Logger::Error << "Error attempting to add a record from Lua via pdns_postresolve_ffi_handle_add_record(): " << e.what() << endl;
+    return false;
+  }
+}
+
index a86c9eaa8e8ea12c93b23486e1567bf3cd6d5f77..46ee88116f65cb62149bd1d5bcd998e5e835d1ce 100644 (file)
@@ -58,6 +58,21 @@ struct LuaContext::Pusher<pdns_ffi_param*>
   }
 };
 
+// pdns_postresolve_ffi_param_t is a lightuserdata
+template <>
+struct LuaContext::Pusher<pdns_postresolve_ffi_handle*>
+{
+  static const int minSize = 1;
+  static const int maxSize = 1;
+
+  static PushedObject push(lua_State* state, pdns_postresolve_ffi_handle* ptr) noexcept
+  {
+    lua_pushlightuserdata(state, ptr);
+    return PushedObject{state, 1};
+  }
+};
+
+
 class RecursorLua4 : public BaseLua4
 {
 public:
@@ -204,9 +219,23 @@ public:
 
   typedef std::function<std::tuple<unsigned int, boost::optional<std::unordered_map<int, string>>, boost::optional<LuaContext::LuaObject>, boost::optional<std::string>, boost::optional<std::string>, boost::optional<std::string>, boost::optional<string>>(ComboAddress, Netmask, ComboAddress, DNSName, uint16_t, const EDNSOptionViewMap&, bool, const std::vector<std::pair<int, const ProxyProtocolValue*>>&)> gettag_t;
   gettag_t d_gettag; // public so you can query if we have this hooked
+
   typedef std::function<boost::optional<LuaContext::LuaObject>(pdns_ffi_param_t*)> gettag_ffi_t;
   gettag_ffi_t d_gettag_ffi;
 
+
+  struct PostResolveFFIHandle
+  {
+    PostResolveFFIHandle(DNSQuestion& dq) : d_dq(dq)
+    {
+    }
+    DNSQuestion& d_dq;
+    bool d_ret{false};
+  };
+  bool postresolve_ffi(PostResolveFFIHandle&) const;
+  typedef std::function<bool(pdns_postresolve_ffi_handle_t*)> postresolve_ffi_t;
+  postresolve_ffi_t d_postresolve_ffi;
+
 protected:
   virtual void postPrepareContext() override;
   virtual void postLoad() override;
index 83f644f8d5d2f462611958e33e9dac42e0ebe386..a77e2a36a78ce6ac6bdbef7c41beb22e648562fa 100644 (file)
@@ -2002,12 +2002,28 @@ static void startDoResolve(void *p)
           }
         }
 
-       if (t_pdl && t_pdl->postresolve(dq, res, sr.d_eventTrace)) {
-          shouldNotValidate = true;
-          auto policyResult = handlePolicyHit(appliedPolicy, dc, sr, res, ret, pw, tcpGuard);
-          // haveAnswer case redundant
-          if (policyResult == PolicyResult::Drop) {
-            return;
+        if (t_pdl) {
+          if (t_pdl->d_postresolve_ffi) {
+            RecursorLua4::PostResolveFFIHandle handle(dq);
+            sr.d_eventTrace.add(RecEventTrace::LuaPostResolveFFI);
+            bool pr = t_pdl->postresolve_ffi(handle);
+            sr.d_eventTrace.add(RecEventTrace::LuaPostResolveFFI, pr, false);
+            if (pr) {
+              shouldNotValidate = true;
+              auto policyResult = handlePolicyHit(appliedPolicy, dc, sr, res, ret, pw, tcpGuard);
+              // haveAnswer case redundant
+              if (policyResult == PolicyResult::Drop) {
+                return;
+              }
+            }
+          }
+          else if (t_pdl->postresolve(dq, res, sr.d_eventTrace)) {
+            shouldNotValidate = true;
+            auto policyResult = handlePolicyHit(appliedPolicy, dc, sr, res, ret, pw, tcpGuard);
+            // haveAnswer case redundant
+            if (policyResult == PolicyResult::Drop) {
+              return;
+            }
           }
         }
       }
index 6060dbd5f7677f36236e16959db976054158e294..8a3112d9cf86e1a4832480354d743c92a50b0f96 100644 (file)
@@ -40,4 +40,5 @@ const std::unordered_map<RecEventTrace::EventType, std::string> RecEventTrace::s
   NameEntry(LuaPreOutQuery),
   NameEntry(LuaPostResolve),
   NameEntry(LuaNoData),
-  NameEntry(LuaNXDomain)};
+  NameEntry(LuaNXDomain),
+  NameEntry(LuaPostResolveFFI)};
index 4c64ac45c3e9da8c22700484f57a76498ca3ebeb..157e306d6f4fdcc85438952075304e82531a3981 100644 (file)
@@ -54,6 +54,7 @@ public:
     LuaPostResolve = 107,
     LuaNoData = 108,
     LuaNXDomain = 109,
+    LuaPostResolveFFI = 110,
   };
 
   static const std::unordered_map<EventType, std::string> s_eventNames;