From: Otto Date: Fri, 3 Dec 2021 12:07:44 +0000 (+0100) Subject: Proof of coccept for postresove_ffi X-Git-Tag: auth-4.7.0-alpha1~111^2~10 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=bb3596da11a98471f2b877f2bd6d9bd89501d7cd;p=thirdparty%2Fpdns.git Proof of coccept for postresove_ffi Likely API needs tweaks. --- diff --git a/pdns/lua-recursor4-ffi.hh b/pdns/lua-recursor4-ffi.hh index bffc9618f7..7cbcb351d1 100644 --- a/pdns/lua-recursor4-ffi.hh +++ b/pdns/lua-recursor4-ffi.hh @@ -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"))); } diff --git a/pdns/lua-recursor4.cc b/pdns/lua-recursor4.cc index e2578bfab4..94bb9bcebd 100644 --- a/pdns/lua-recursor4.cc +++ b/pdns/lua-recursor4.cc @@ -482,6 +482,7 @@ void RecursorLua4::postLoad() d_ipfilter = d_lw->readVariable>("ipfilter").get_value_or(0); d_gettag = d_lw->readVariable>("gettag").get_value_or(0); d_gettag_ffi = d_lw->readVariable>("gettag_ffi").get_value_or(0); + d_postresolve_ffi = d_lw->readVariable>("postresolve_ffi").get_value_or(0); d_policyHitEventFilter = d_lw->readVariable>("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 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(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(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(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; + } +} + diff --git a/pdns/lua-recursor4.hh b/pdns/lua-recursor4.hh index a86c9eaa8e..46ee88116f 100644 --- a/pdns/lua-recursor4.hh +++ b/pdns/lua-recursor4.hh @@ -58,6 +58,21 @@ struct LuaContext::Pusher } }; +// pdns_postresolve_ffi_param_t is a lightuserdata +template <> +struct LuaContext::Pusher +{ + 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>, boost::optional, boost::optional, boost::optional, boost::optional, boost::optional>(ComboAddress, Netmask, ComboAddress, DNSName, uint16_t, const EDNSOptionViewMap&, bool, const std::vector>&)> gettag_t; gettag_t d_gettag; // public so you can query if we have this hooked + typedef std::function(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 postresolve_ffi_t; + postresolve_ffi_t d_postresolve_ffi; + protected: virtual void postPrepareContext() override; virtual void postLoad() override; diff --git a/pdns/pdns_recursor.cc b/pdns/pdns_recursor.cc index 83f644f8d5..a77e2a36a7 100644 --- a/pdns/pdns_recursor.cc +++ b/pdns/pdns_recursor.cc @@ -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; + } } } } diff --git a/pdns/recursordist/rec-eventtrace.cc b/pdns/recursordist/rec-eventtrace.cc index 6060dbd5f7..8a3112d9cf 100644 --- a/pdns/recursordist/rec-eventtrace.cc +++ b/pdns/recursordist/rec-eventtrace.cc @@ -40,4 +40,5 @@ const std::unordered_map RecEventTrace::s NameEntry(LuaPreOutQuery), NameEntry(LuaPostResolve), NameEntry(LuaNoData), - NameEntry(LuaNXDomain)}; + NameEntry(LuaNXDomain), + NameEntry(LuaPostResolveFFI)}; diff --git a/pdns/recursordist/rec-eventtrace.hh b/pdns/recursordist/rec-eventtrace.hh index 4c64ac45c3..157e306d6f 100644 --- a/pdns/recursordist/rec-eventtrace.hh +++ b/pdns/recursordist/rec-eventtrace.hh @@ -54,6 +54,7 @@ public: LuaPostResolve = 107, LuaNoData = 108, LuaNXDomain = 109, + LuaPostResolveFFI = 110, }; static const std::unordered_map s_eventNames;