summaryrefslogtreecommitdiffstats
path: root/src/lua/lua_dns_resolver.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lua/lua_dns_resolver.c')
-rw-r--r--src/lua/lua_dns_resolver.c754
1 files changed, 754 insertions, 0 deletions
diff --git a/src/lua/lua_dns_resolver.c b/src/lua/lua_dns_resolver.c
new file mode 100644
index 0000000..b022e13
--- /dev/null
+++ b/src/lua/lua_dns_resolver.c
@@ -0,0 +1,754 @@
+/*-
+ * Copyright 2016 Vsevolod Stakhov
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "lua_common.h"
+#include "lua_thread_pool.h"
+#include "utlist.h"
+
+
+/***
+ * @module rspamd_resolver
+ * This module allows to resolve DNS names from LUA code. All resolving is executed
+ * asynchronously. Here is an example of name resolution:
+ * @example
+local function symbol_callback(task)
+ local host = 'example.com'
+
+ local function dns_cb(resolver, to_resolve, results, err, _, authenticated)
+ if not results then
+ rspamd_logger.infox('DNS resolving of %1 failed: %2', host, err)
+ return
+ end
+ for _,r in ipairs(results) do
+ -- r is of type rspamd{ip} here, but it can be converted to string
+ rspamd_logger.infox('Resolved %1 to %2', host, tostring(r))
+ end
+ end
+
+ task:get_resolver():resolve_a({task = task, name = host, callback = dns_cb})
+end
+ */
+
+static const gchar *M = "rspamd lua dns resolver";
+
+/* Lua bindings */
+LUA_FUNCTION_DEF(dns_resolver, init);
+LUA_FUNCTION_DEF(dns_resolver, resolve_a);
+LUA_FUNCTION_DEF(dns_resolver, resolve_ptr);
+LUA_FUNCTION_DEF(dns_resolver, resolve_txt);
+LUA_FUNCTION_DEF(dns_resolver, resolve_mx);
+LUA_FUNCTION_DEF(dns_resolver, resolve_ns);
+LUA_FUNCTION_DEF(dns_resolver, resolve);
+LUA_FUNCTION_DEF(dns_resolver, idna_convert_utf8);
+
+void lua_push_dns_reply(lua_State *L, const struct rdns_reply *reply);
+
+static const struct luaL_reg dns_resolverlib_f[] = {
+ LUA_INTERFACE_DEF(dns_resolver, init),
+ {NULL, NULL}};
+
+static const struct luaL_reg dns_resolverlib_m[] = {
+ LUA_INTERFACE_DEF(dns_resolver, resolve_a),
+ LUA_INTERFACE_DEF(dns_resolver, resolve_ptr),
+ LUA_INTERFACE_DEF(dns_resolver, resolve_txt),
+ LUA_INTERFACE_DEF(dns_resolver, resolve_mx),
+ LUA_INTERFACE_DEF(dns_resolver, resolve_ns),
+ LUA_INTERFACE_DEF(dns_resolver, resolve),
+ LUA_INTERFACE_DEF(dns_resolver, idna_convert_utf8),
+ {"__tostring", rspamd_lua_class_tostring},
+ {NULL, NULL}};
+
+struct rspamd_dns_resolver *
+lua_check_dns_resolver(lua_State *L, gint pos)
+{
+ void *ud = rspamd_lua_check_udata(L, pos, "rspamd{resolver}");
+ luaL_argcheck(L, ud != NULL, pos, "'resolver' expected");
+ return ud ? *((struct rspamd_dns_resolver **) ud) : NULL;
+}
+
+struct lua_dns_cbdata {
+ struct rspamd_task *task;
+ rspamd_mempool_t *pool;
+ struct rspamd_dns_resolver *resolver;
+ gint cbref;
+ gchar *to_resolve;
+ gchar *user_str;
+ struct rspamd_symcache_dynamic_item *item;
+ struct rspamd_async_session *s;
+};
+
+static int
+lua_dns_get_type(lua_State *L, int argno)
+{
+ int type = RDNS_REQUEST_A;
+ const gchar *strtype;
+
+ if (lua_type(L, argno) != LUA_TSTRING) {
+ lua_pushvalue(L, argno);
+ lua_gettable(L, lua_upvalueindex(1));
+
+ type = lua_tonumber(L, -1);
+ lua_pop(L, 1);
+ if (type == 0) {
+ rspamd_lua_typerror(L, argno, "dns_request_type");
+ }
+ }
+ else {
+ strtype = lua_tostring(L, argno);
+ type = rdns_type_fromstr(strtype);
+ }
+
+ return type;
+}
+
+static void
+lua_dns_resolver_callback(struct rdns_reply *reply, gpointer arg)
+{
+ struct lua_dns_cbdata *cd = arg;
+ struct rspamd_dns_resolver **presolver;
+ lua_State *L;
+ struct lua_callback_state cbs;
+ rspamd_mempool_t *pool;
+ gint err_idx;
+
+ pool = cd->pool;
+ lua_thread_pool_prepare_callback(cd->resolver->cfg->lua_thread_pool, &cbs);
+ L = cbs.L;
+
+ lua_pushcfunction(L, &rspamd_lua_traceback);
+ err_idx = lua_gettop(L);
+
+ lua_rawgeti(L, LUA_REGISTRYINDEX, cd->cbref);
+
+ presolver = lua_newuserdata(L, sizeof(gpointer));
+ rspamd_lua_setclass(L, "rspamd{resolver}", -1);
+
+ *presolver = cd->resolver;
+ lua_pushstring(L, cd->to_resolve);
+
+ lua_push_dns_reply(L, reply);
+
+ /*
+ * 1 - resolver
+ * 2 - to_resolve
+ * 3 - entries | nil
+ * 4 - error | nil
+ * 5 - user_str
+ * 6 - reply->flags & RDNS_AUTH
+ * 7 - server
+ */
+ if (reply->code != RDNS_RC_NOERROR) {
+ lua_pushnil(L);
+ lua_pushstring(L, rdns_strerror(reply->code));
+ }
+ if (cd->user_str != NULL) {
+ lua_pushstring(L, cd->user_str);
+ }
+ else {
+ lua_pushnil(L);
+ }
+
+ lua_pushboolean(L, reply->flags & RDNS_AUTH);
+
+ const gchar *servname = rdns_request_get_server(reply->request);
+
+ if (servname) {
+ lua_pushstring(L, servname);
+ }
+ else {
+ lua_pushnil(L);
+ }
+
+ if (cd->item) {
+ /* We also need to restore the item in case there are some chains */
+ rspamd_symcache_set_cur_item(cd->task, cd->item);
+ }
+
+ if (lua_pcall(L, 7, 0, err_idx) != 0) {
+ msg_err_pool_check("call to dns callback failed: %s",
+ lua_tostring(L, -1));
+ }
+
+ lua_settop(L, err_idx - 1);
+
+ /* Unref function */
+ luaL_unref(L, LUA_REGISTRYINDEX, cd->cbref);
+ lua_thread_pool_restore_callback(&cbs);
+
+ if (cd->item) {
+ rspamd_symcache_item_async_dec_check(cd->task, cd->item, M);
+ }
+
+ if (!cd->pool) {
+ g_free(cd->to_resolve);
+ g_free(cd->user_str);
+ g_free(cd);
+ }
+}
+
+void lua_push_dns_reply(lua_State *L, const struct rdns_reply *reply)
+{
+ gint i = 0, naddrs = 0;
+ struct rdns_reply_entry *elt;
+ rspamd_inet_addr_t *addr;
+
+ if (reply->code == RDNS_RC_NOERROR) {
+ LL_FOREACH(reply->entries, elt)
+ {
+ naddrs++;
+ }
+
+ lua_createtable(L, naddrs, 0);
+
+ LL_FOREACH(reply->entries, elt)
+ {
+ if (!rdns_request_has_type(reply->request, elt->type)) {
+ /* Unrequested type has been returned, ignore it */
+ continue;
+ }
+
+ switch (elt->type) {
+ case RDNS_REQUEST_A:
+ addr = rspamd_inet_address_new(AF_INET, &elt->content.a.addr);
+ rspamd_lua_ip_push(L, addr);
+ rspamd_inet_address_free(addr);
+ lua_rawseti(L, -2, ++i);
+ break;
+ case RDNS_REQUEST_AAAA:
+ addr = rspamd_inet_address_new(AF_INET6, &elt->content.aaa.addr);
+ rspamd_lua_ip_push(L, addr);
+ rspamd_inet_address_free(addr);
+ lua_rawseti(L, -2, ++i);
+ break;
+ case RDNS_REQUEST_NS:
+ lua_pushstring(L, elt->content.ns.name);
+ lua_rawseti(L, -2, ++i);
+ break;
+ case RDNS_REQUEST_PTR:
+ lua_pushstring(L, elt->content.ptr.name);
+ lua_rawseti(L, -2, ++i);
+ break;
+ case RDNS_REQUEST_TXT:
+ case RDNS_REQUEST_SPF:
+ lua_pushstring(L, elt->content.txt.data);
+ lua_rawseti(L, -2, ++i);
+ break;
+ case RDNS_REQUEST_MX:
+ /* mx['name'], mx['priority'] */
+ lua_createtable(L, 0, 2);
+ rspamd_lua_table_set(L, "name", elt->content.mx.name);
+ lua_pushstring(L, "priority");
+ lua_pushinteger(L, elt->content.mx.priority);
+ lua_settable(L, -3);
+
+ lua_rawseti(L, -2, ++i);
+ break;
+ case RDNS_REQUEST_SOA:
+ lua_createtable(L, 0, 7);
+ rspamd_lua_table_set(L, "ns", elt->content.soa.mname);
+ rspamd_lua_table_set(L, "contact", elt->content.soa.admin);
+ lua_pushstring(L, "serial");
+ lua_pushinteger(L, elt->content.soa.serial);
+ lua_settable(L, -3);
+ lua_pushstring(L, "refresh");
+ lua_pushinteger(L, elt->content.soa.refresh);
+ lua_settable(L, -3);
+ lua_pushstring(L, "retry");
+ lua_pushinteger(L, elt->content.soa.retry);
+ lua_settable(L, -3);
+ lua_pushstring(L, "expiry");
+ lua_pushinteger(L, elt->content.soa.expire);
+ lua_settable(L, -3);
+ /* Negative TTL */
+ lua_pushstring(L, "nx");
+ lua_pushinteger(L, elt->content.soa.minimum);
+ lua_settable(L, -3);
+
+ lua_rawseti(L, -2, ++i);
+ break;
+ case RDNS_REQUEST_CNAME:
+ lua_pushstring(L, elt->content.cname.name);
+ lua_rawseti(L, -2, ++i);
+ break;
+ default:
+ continue;
+ }
+ }
+ lua_pushnil(L);
+ }
+}
+
+/***
+ * @function rspamd_resolver.init(ev_base, config)
+ * @param {event_base} ev_base event base used for asynchronous events
+ * @param {rspamd_config} config rspamd configuration parameters
+ * @return {rspamd_resolver} new resolver object associated with the specified base
+ */
+static int
+lua_dns_resolver_init(lua_State *L)
+{
+ struct rspamd_dns_resolver *resolver, **presolver;
+ struct rspamd_config *cfg, **pcfg;
+ struct ev_loop *base, **pbase;
+
+ /* Check args */
+ pbase = rspamd_lua_check_udata(L, 1, "rspamd{ev_base}");
+ luaL_argcheck(L, pbase != NULL, 1, "'ev_base' expected");
+ base = pbase ? *(pbase) : NULL;
+ pcfg = rspamd_lua_check_udata(L, 2, "rspamd{config}");
+ luaL_argcheck(L, pcfg != NULL, 2, "'config' expected");
+ cfg = pcfg ? *(pcfg) : NULL;
+
+ if (base != NULL && cfg != NULL) {
+ resolver = rspamd_dns_resolver_init(NULL, base, cfg);
+ if (resolver) {
+ presolver = lua_newuserdata(L, sizeof(gpointer));
+ rspamd_lua_setclass(L, "rspamd{resolver}", -1);
+ *presolver = resolver;
+ }
+ else {
+ lua_pushnil(L);
+ }
+ }
+ else {
+ lua_pushnil(L);
+ }
+
+ return 1;
+}
+
+static int
+lua_dns_resolver_resolve_common(lua_State *L,
+ struct rspamd_dns_resolver *resolver,
+ enum rdns_request_type type,
+ int first)
+{
+ LUA_TRACE_POINT;
+ struct rspamd_async_session *session = NULL;
+ rspamd_mempool_t *pool = NULL;
+ const gchar *to_resolve = NULL, *user_str = NULL;
+ struct lua_dns_cbdata *cbdata;
+ gint cbref = -1, ret;
+ struct rspamd_task *task = NULL;
+ GError *err = NULL;
+ gboolean forced = FALSE;
+ struct rspamd_symcache_dynamic_item *item = NULL;
+
+ /* Check arguments */
+ if (!rspamd_lua_parse_table_arguments(L, first, &err,
+ RSPAMD_LUA_PARSE_ARGUMENTS_DEFAULT,
+ "session=U{session};mempool=U{mempool};*name=S;*callback=F;"
+ "option=S;task=U{task};forced=B",
+ &session, &pool, &to_resolve, &cbref, &user_str, &task, &forced)) {
+
+ if (err) {
+ ret = luaL_error(L, "invalid arguments: %s", err->message);
+ g_error_free(err);
+
+ return ret;
+ }
+
+ return luaL_error(L, "invalid arguments");
+ }
+
+ if (task) {
+ pool = task->task_pool;
+ session = task->s;
+ item = rspamd_symcache_get_cur_item(task);
+ }
+
+ if (to_resolve != NULL) {
+ if (pool != NULL) {
+ cbdata = rspamd_mempool_alloc0(pool, sizeof(struct lua_dns_cbdata));
+ cbdata->user_str = rspamd_mempool_strdup(pool, user_str);
+
+ if (type != RDNS_REQUEST_PTR) {
+ cbdata->to_resolve = rspamd_mempool_strdup(pool, to_resolve);
+ }
+ else {
+ char *ptr_str;
+
+ ptr_str = rdns_generate_ptr_from_str(to_resolve);
+
+ if (ptr_str == NULL) {
+ msg_err_task_check("wrong resolve string to PTR request: %s",
+ to_resolve);
+ goto err;
+ }
+
+ cbdata->to_resolve = rspamd_mempool_strdup(pool, ptr_str);
+ to_resolve = cbdata->to_resolve;
+ free(ptr_str);
+ }
+ }
+ else {
+ cbdata = g_malloc0(sizeof(struct lua_dns_cbdata));
+ cbdata->user_str = user_str ? g_strdup(user_str) : NULL;
+
+ if (type != RDNS_REQUEST_PTR) {
+ cbdata->to_resolve = g_strdup(to_resolve);
+ }
+ else {
+ char *ptr_str;
+
+ ptr_str = rdns_generate_ptr_from_str(to_resolve);
+
+ if (ptr_str == NULL) {
+ msg_err_task_check("wrong resolve string to PTR request: %s",
+ to_resolve);
+ goto err;
+ }
+
+ cbdata->to_resolve = g_strdup(ptr_str);
+ free(ptr_str);
+ }
+ }
+
+ cbdata->resolver = resolver;
+ cbdata->cbref = cbref;
+ cbdata->task = task;
+ cbdata->pool = pool;
+
+ if (task == NULL) {
+ if (rspamd_dns_resolver_request(resolver,
+ session,
+ pool,
+ lua_dns_resolver_callback,
+ cbdata,
+ type,
+ to_resolve)) {
+
+ lua_pushboolean(L, TRUE);
+
+ if (session) {
+ cbdata->s = session;
+ }
+ }
+ else {
+ goto err;
+ }
+ }
+ else {
+ /* Fail-safety as this function can, in theory, call
+ * lua_dns_resolver_callback without switching to the event loop
+ */
+ if (item) {
+ rspamd_symcache_item_async_inc(task, item, M);
+ }
+
+ if (forced) {
+ ret = rspamd_dns_resolver_request_task_forced(task,
+ lua_dns_resolver_callback,
+ cbdata,
+ type,
+ to_resolve);
+ }
+ else {
+ ret = rspamd_dns_resolver_request_task(task,
+ lua_dns_resolver_callback,
+ cbdata,
+ type,
+ to_resolve);
+ }
+
+ if (ret) {
+ cbdata->s = session;
+
+ if (item) {
+ cbdata->item = item;
+ rspamd_symcache_item_async_inc(task, item, M);
+ }
+ /* callback was set up */
+ lua_pushboolean(L, TRUE);
+ }
+ else {
+ if (item) {
+ rspamd_symcache_item_async_dec_check(task, item, M);
+ }
+
+ goto err;
+ }
+
+ if (item) {
+ rspamd_symcache_item_async_dec_check(task, item, M);
+ }
+ }
+ }
+ else {
+ return luaL_error(L, "invalid arguments to lua_resolve");
+ }
+
+ return 1;
+
+err:
+ /* Callback is not called in this case */
+ if (cbdata->cbref != -1) {
+ luaL_unref(L, LUA_REGISTRYINDEX, cbdata->cbref);
+ }
+
+ if (!pool) {
+ /* Free resources */
+ g_free(cbdata->to_resolve);
+ g_free(cbdata->user_str);
+ g_free(cbdata);
+ }
+
+ lua_pushnil(L);
+
+ return 1;
+}
+
+/***
+ * @method resolver:resolve_a(table)
+ * Resolve A record for a specified host.
+ * Table elements:
+ * * `task` - task element (preferred, required to track dependencies) -or-
+ * * `session` - asynchronous session normally associated with rspamd task (`task:get_session()`)
+ * * `mempool` - pool memory pool for storing intermediate data
+ * * `name` - host name to resolve
+ * * `callback` - callback callback function to be called upon name resolution is finished; must be of type `function (resolver, to_resolve, results, err)`
+ * * `forced` - true if needed to override normal limit for DNS requests
+ * @return {boolean} `true` if DNS request has been scheduled
+ */
+static int
+lua_dns_resolver_resolve_a(lua_State *L)
+{
+ struct rspamd_dns_resolver *dns_resolver = lua_check_dns_resolver(L, 1);
+
+ if (dns_resolver) {
+ return lua_dns_resolver_resolve_common(L,
+ dns_resolver,
+ RDNS_REQUEST_A,
+ 2);
+ }
+ else {
+ lua_pushnil(L);
+ }
+
+ return 1;
+}
+
+/***
+ * @method resolver:resolve_ptr(table)
+ * Resolve PTR record for a specified host.
+ * Table elements:
+ * * `task` - task element (preferred, required to track dependencies) -or-
+ * * `session` - asynchronous session normally associated with rspamd task (`task:get_session()`)
+ * * `mempool` - pool memory pool for storing intermediate data
+ * * `name` - host name to resolve
+ * * `callback` - callback callback function to be called upon name resolution is finished; must be of type `function (resolver, to_resolve, results, err)`
+ * * `forced` - true if needed to override normal limit for DNS requests
+ * @return {boolean} `true` if DNS request has been scheduled
+ */
+static int
+lua_dns_resolver_resolve_ptr(lua_State *L)
+{
+ struct rspamd_dns_resolver *dns_resolver = lua_check_dns_resolver(L, 1);
+
+ if (dns_resolver) {
+ return lua_dns_resolver_resolve_common(L,
+ dns_resolver,
+ RDNS_REQUEST_PTR,
+ 2);
+ }
+ else {
+ lua_pushnil(L);
+ }
+
+ return 1;
+}
+
+/***
+ * @method resolver:resolve_txt(table)
+ * Resolve TXT record for a specified host.
+ * Table elements:
+ * * `task` - task element (preferred, required to track dependencies) -or-
+ * * `session` - asynchronous session normally associated with rspamd task (`task:get_session()`)
+ * * `mempool` - pool memory pool for storing intermediate data
+ * * `name` - host name to resolve
+ * * `callback` - callback callback function to be called upon name resolution is finished; must be of type `function (resolver, to_resolve, results, err)`
+ * * `forced` - true if needed to override normal limit for DNS requests
+ * @return {boolean} `true` if DNS request has been scheduled
+ */
+static int
+lua_dns_resolver_resolve_txt(lua_State *L)
+{
+ struct rspamd_dns_resolver *dns_resolver = lua_check_dns_resolver(L, 1);
+
+ if (dns_resolver) {
+ return lua_dns_resolver_resolve_common(L,
+ dns_resolver,
+ RDNS_REQUEST_TXT,
+ 2);
+ }
+ else {
+ lua_pushnil(L);
+ }
+
+ return 1;
+}
+
+/***
+ * @method resolver:resolve_mx(table)
+ * Resolve MX record for a specified host.
+ * Table elements:
+ * * `task` - task element (preferred, required to track dependencies) -or-
+ * * `session` - asynchronous session normally associated with rspamd task (`task:get_session()`)
+ * * `mempool` - pool memory pool for storing intermediate data
+ * * `name` - host name to resolve
+ * * `callback` - callback callback function to be called upon name resolution is finished; must be of type `function (resolver, to_resolve, results, err)`
+ * * `forced` - true if needed to override normal limit for DNS requests
+ * @return {boolean} `true` if DNS request has been scheduled
+ */
+static int
+lua_dns_resolver_resolve_mx(lua_State *L)
+{
+ struct rspamd_dns_resolver *dns_resolver = lua_check_dns_resolver(L, 1);
+
+ if (dns_resolver) {
+ return lua_dns_resolver_resolve_common(L,
+ dns_resolver,
+ RDNS_REQUEST_MX,
+ 2);
+ }
+ else {
+ lua_pushnil(L);
+ }
+
+ return 1;
+}
+
+/***
+ * @method resolver:resolve_ns(table)
+ * Resolve NS records for a specified host.
+ * Table elements:
+ * * `task` - task element (preferred, required to track dependencies) -or-
+ * * `session` - asynchronous session normally associated with rspamd task (`task:get_session()`)
+ * * `mempool` - pool memory pool for storing intermediate data
+ * * `name` - host name to resolve
+ * * `callback` - callback callback function to be called upon name resolution is finished; must be of type `function (resolver, to_resolve, results, err)`
+ * * `forced` - true if needed to override normal limit for DNS requests
+ * @return {boolean} `true` if DNS request has been scheduled
+ */
+static int
+lua_dns_resolver_resolve_ns(lua_State *L)
+{
+ struct rspamd_dns_resolver *dns_resolver = lua_check_dns_resolver(L, 1);
+
+ if (dns_resolver) {
+ return lua_dns_resolver_resolve_common(L,
+ dns_resolver,
+ RDNS_REQUEST_NS,
+ 2);
+ }
+ else {
+ lua_pushnil(L);
+ }
+
+ return 1;
+}
+
+/* XXX: broken currently */
+static int
+lua_dns_resolver_resolve(lua_State *L)
+{
+ struct rspamd_dns_resolver *dns_resolver = lua_check_dns_resolver(L, 1);
+ int type;
+
+ type = lua_dns_get_type(L, 2);
+
+ if (dns_resolver && type != 0) {
+ return lua_dns_resolver_resolve_common(L, dns_resolver, type, 3);
+ }
+ else {
+ lua_pushnil(L);
+ }
+
+ return 1;
+}
+
+/***
+ * @method resolver:idna_convert_utf8(hostname[, pool])
+ * Converts domain name from IDN (in utf8 format) to punycode
+ * @return {string} new name converted
+ */
+static int
+lua_dns_resolver_idna_convert_utf8(lua_State *L)
+{
+ struct rspamd_dns_resolver *dns_resolver = lua_check_dns_resolver(L, 1);
+ gsize hlen;
+ guint conv_len = 0;
+ const gchar *hname = luaL_checklstring(L, 2, &hlen);
+ gchar *converted;
+ rspamd_mempool_t *pool = rspamd_lua_check_udata_maybe(L, 3, "rspamd{mempool}");
+
+
+ if (dns_resolver && hname) {
+ if (!rspamd_str_has_8bit(hname, hlen)) {
+ /* No 8 bit, no reasons to call idna */
+ lua_pushlstring(L, hname, hlen);
+ }
+ else {
+ converted = rspamd_dns_resolver_idna_convert_utf8(dns_resolver, pool,
+ hname, hlen, &conv_len);
+
+ if (converted == NULL) {
+ lua_pushnil(L);
+ }
+ else {
+ lua_pushlstring(L, converted, conv_len);
+
+ if (pool == NULL) {
+ g_free(converted);
+ }
+ }
+ }
+ }
+ else {
+ return luaL_error(L, "invalid arguments");
+ }
+
+ return 1;
+}
+
+static gint
+lua_load_dns_resolver(lua_State *L)
+{
+ lua_newtable(L);
+ luaL_register(L, NULL, dns_resolverlib_f);
+
+ return 1;
+}
+
+void luaopen_dns_resolver(lua_State *L)
+{
+
+ rspamd_lua_new_class(L, "rspamd{resolver}", dns_resolverlib_m);
+ {
+ LUA_ENUM(L, DNS_A, RDNS_REQUEST_A);
+ LUA_ENUM(L, DNS_PTR, RDNS_REQUEST_PTR);
+ LUA_ENUM(L, DNS_MX, RDNS_REQUEST_MX);
+ LUA_ENUM(L, DNS_TXT, RDNS_REQUEST_TXT);
+ LUA_ENUM(L, DNS_SRV, RDNS_REQUEST_SRV);
+ LUA_ENUM(L, DNS_SPF, RDNS_REQUEST_SPF);
+ LUA_ENUM(L, DNS_AAAA, RDNS_REQUEST_AAAA);
+ LUA_ENUM(L, DNS_SOA, RDNS_REQUEST_SOA);
+ LUA_ENUM(L, DNS_CNAME, RDNS_REQUEST_CNAME);
+ }
+
+ lua_pop(L, 1);
+
+ rspamd_lua_add_preload(L, "rspamd_resolver", lua_load_dns_resolver);
+}