Likely API needs tweaks.
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")));
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")));
}
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);
}
{
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;
+ }
+}
+
}
};
+// 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:
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;
}
}
- 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;
+ }
}
}
}
NameEntry(LuaPreOutQuery),
NameEntry(LuaPostResolve),
NameEntry(LuaNoData),
- NameEntry(LuaNXDomain)};
+ NameEntry(LuaNXDomain),
+ NameEntry(LuaPostResolveFFI)};
LuaPostResolve = 107,
LuaNoData = 108,
LuaNXDomain = 109,
+ LuaPostResolveFFI = 110,
};
static const std::unordered_map<EventType, std::string> s_eventNames;