]> source.dussan.org Git - rspamd.git/commitdiff
[Minor] Better naming: renamed old module - lua_dns -> lua_dns_resolver
authorMikhail Galanin <mgalanin@mimecast.com>
Fri, 17 Aug 2018 15:41:30 +0000 (16:41 +0100)
committerMikhail Galanin <mgalanin@mimecast.com>
Fri, 17 Aug 2018 15:41:30 +0000 (16:41 +0100)
src/lua/CMakeLists.txt
src/lua/lua_dns.c [deleted file]
src/lua/lua_dns.h [deleted file]
src/lua/lua_dns_resolver.c [new file with mode: 0644]
src/lua/lua_dns_resolver.h [new file with mode: 0644]
src/lua/lua_rspamd_dns.c

index cb2bd223213390b1dd0d891ea7af3751f168814f..98a8203c314467a30a73bc3b607cd8eda97fab19 100644 (file)
@@ -12,7 +12,7 @@ SET(LUASRC                      ${CMAKE_CURRENT_SOURCE_DIR}/lua_common.c
                                          ${CMAKE_CURRENT_SOURCE_DIR}/lua_redis.c
                                          ${CMAKE_CURRENT_SOURCE_DIR}/lua_upstream.c
                                          ${CMAKE_CURRENT_SOURCE_DIR}/lua_mempool.c
-                                         ${CMAKE_CURRENT_SOURCE_DIR}/lua_dns.c
+                                         ${CMAKE_CURRENT_SOURCE_DIR}/lua_dns_resolver.c
                                          ${CMAKE_CURRENT_SOURCE_DIR}/lua_rsa.c
                                          ${CMAKE_CURRENT_SOURCE_DIR}/lua_ip.c
                                          ${CMAKE_CURRENT_SOURCE_DIR}/lua_expression.c
diff --git a/src/lua/lua_dns.c b/src/lua/lua_dns.c
deleted file mode 100644 (file)
index 5c056b7..0000000
+++ /dev/null
@@ -1,631 +0,0 @@
-/*-
- * 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:get_session(), task:get_mempool(),
-               host, dns_cb)
-end
- */
-struct rspamd_dns_resolver * lua_check_dns_resolver (lua_State * L);
-void luaopen_dns_resolver (lua_State * L);
-
-/* 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);
-
-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),
-       {"__tostring", rspamd_lua_class_tostring},
-       {NULL, NULL}
-};
-
-struct rspamd_dns_resolver *
-lua_check_dns_resolver (lua_State * L)
-{
-       void *ud = rspamd_lua_check_udata (L, 1, "rspamd{resolver}");
-       luaL_argcheck (L, ud != NULL, 1, "'resolver' expected");
-       return ud ? *((struct rspamd_dns_resolver **)ud) : NULL;
-}
-
-struct lua_dns_cbdata {
-       struct rspamd_task *task;
-       struct rspamd_dns_resolver *resolver;
-       gint cbref;
-       const gchar *to_resolve;
-       const gchar *user_str;
-       struct rspamd_async_watcher *w;
-       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);
-
-               if (g_ascii_strcasecmp (strtype, "a") == 0) {
-                       type = RDNS_REQUEST_A;
-               }
-               else if (g_ascii_strcasecmp (strtype, "aaaa") == 0) {
-                       type = RDNS_REQUEST_AAAA;
-               }
-               else if (g_ascii_strcasecmp (strtype, "mx") == 0) {
-                       type = RDNS_REQUEST_MX;
-               }
-               else if (g_ascii_strcasecmp (strtype, "txt") == 0) {
-                       type = RDNS_REQUEST_TXT;
-               }
-               else if (g_ascii_strcasecmp (strtype, "ptr") == 0) {
-                       type = RDNS_REQUEST_PTR;
-               }
-               else if (g_ascii_strcasecmp (strtype, "soa") == 0) {
-                       type = RDNS_REQUEST_SOA;
-               }
-               else {
-                       msg_err ("bad DNS type: %s", strtype);
-               }
-       }
-
-       return type;
-}
-
-static void
-lua_dns_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;
-
-       lua_thread_pool_prepare_callback (cd->resolver->cfg->lua_thread_pool, &cbs);
-       L = cbs.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->authenticated
-        */
-       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->authenticated);
-
-       if (lua_pcall (L, 6, 0, 0) != 0) {
-               msg_info ("call to dns callback failed: %s", lua_tostring (L, -1));
-               lua_pop (L, 1);
-       }
-
-       /* Unref function */
-       luaL_unref (L, LUA_REGISTRYINDEX, cd->cbref);
-
-       lua_thread_pool_restore_callback (&cbs);
-
-       if (cd->s) {
-               rspamd_session_watcher_pop (cd->s, cd->w);
-       }
-}
-
-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)
-               {
-                       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;
-                       }
-               }
-               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 event_base *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 = 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;
-
-       /* Check arguments */
-       if (!rspamd_lua_parse_table_arguments (L, first, &err,
-                       "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;
-       }
-       else if (!session || !pool) {
-               return luaL_error (L, "invalid arguments: either 'task' or 'session'/'mempool' should be set");
-       }
-
-       if (pool != NULL && to_resolve != NULL) {
-               cbdata = rspamd_mempool_alloc0 (pool, sizeof (struct lua_dns_cbdata));
-               cbdata->resolver = resolver;
-               cbdata->cbref = cbref;
-               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);
-                               lua_pushnil (L);
-
-                               return 1;
-                       }
-
-                       cbdata->to_resolve = rspamd_mempool_strdup (pool, ptr_str);
-                       to_resolve = cbdata->to_resolve;
-                       free (ptr_str);
-               }
-
-               if (task == NULL) {
-                       if (make_dns_request (resolver,
-                                       session,
-                                       pool,
-                                       lua_dns_callback,
-                                       cbdata,
-                                       type,
-                                       to_resolve)) {
-
-                               lua_pushboolean (L, TRUE);
-
-                               if (session) {
-                                       cbdata->s = session;
-                                       cbdata->w = rspamd_session_get_watcher (session);
-                                       rspamd_session_watcher_push (session);
-                               }
-                       }
-                       else {
-                               lua_pushnil (L);
-                       }
-               }
-               else {
-                       cbdata->task = task;
-
-                       if (forced) {
-                               ret = make_dns_request_task_forced (task,
-                                               lua_dns_callback,
-                                               cbdata,
-                                               type,
-                                               to_resolve);
-                       }
-                       else {
-                               ret = make_dns_request_task (task,
-                                               lua_dns_callback,
-                                               cbdata,
-                                               type,
-                                               to_resolve);
-                       }
-
-                       if (ret) {
-                               cbdata->s = session;
-                               cbdata->w = rspamd_session_get_watcher (session);
-                               rspamd_session_watcher_push (session);
-                               /* callback was set up */
-                               lua_pushboolean (L, TRUE);
-                       }
-                       else {
-                               lua_pushnil (L);
-                       }
-               }
-       }
-       else {
-               return luaL_error (L, "invalid arguments to lua_resolve");
-       }
-
-       return 1;
-
-}
-
-/***
- * @method resolver:resolve_a(session, pool, host, callback)
- * Resolve A record for a specified host.
- * @param {async_session} session asynchronous session normally associated with rspamd task (`task:get_session()`)
- * @param {mempool} pool memory pool for storing intermediate data
- * @param {string} host name to resolve
- * @param {function} callback callback function to be called upon name resolution is finished; must be of type `function (resolver, to_resolve, results, err)`
- * @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);
-
-       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(session, pool, ip, callback)
- * Resolve PTR record for a specified host.
- * @param {async_session} session asynchronous session normally associated with rspamd task (`task:get_session()`)
- * @param {mempool} pool memory pool for storing intermediate data
- * @param {string} ip name to resolve in string form (e.g. '8.8.8.8' or '2001:dead::')
- * @param {function} callback callback function to be called upon name resolution is finished; must be of type `function (resolver, to_resolve, results, err)`
- * @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);
-
-       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(session, pool, host, callback)
- * Resolve TXT record for a specified host.
- * @param {async_session} session asynchronous session normally associated with rspamd task (`task:get_session()`)
- * @param {mempool} pool memory pool for storing intermediate data
- * @param {string} host name to get TXT record for
- * @param {function} callback callback function to be called upon name resolution is finished; must be of type `function (resolver, to_resolve, results, err)`
- * @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);
-
-       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(session, pool, host, callback)
- * Resolve MX record for a specified host.
- * @param {async_session} session asynchronous session normally associated with rspamd task (`task:get_session()`)
- * @param {mempool} pool memory pool for storing intermediate data
- * @param {string} host name to get MX record for
- * @param {function} callback callback function to be called upon name resolution is finished; must be of type `function (resolver, to_resolve, results, err)`
- * @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);
-
-       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(session, pool, host, callback)
- * Resolve NS records for a specified host.
- * @param {async_session} session asynchronous session normally associated with rspamd task (`task:get_session()`)
- * @param {mempool} pool memory pool for storing intermediate data
- * @param {string} host name to get NS records for
- * @param {function} callback callback function to be called upon name resolution is finished; must be of type `function (resolver, to_resolve, results, err)`
- * @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);
-
-       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);
-       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;
-}
-
-static gint
-lua_load_dns (lua_State * L)
-{
-       lua_newtable (L);
-       luaL_register (L, NULL, dns_resolverlib_f);
-
-       return 1;
-}
-
-void
-luaopen_dns_resolver (lua_State * L)
-{
-
-       luaL_newmetatable (L, "rspamd{resolver}");
-       lua_pushstring (L, "__index");
-       lua_pushvalue (L, -2);
-       lua_settable (L, -3);
-
-       lua_pushstring (L, "class");
-       lua_pushstring (L, "rspamd{resolver}");
-       lua_rawset (L, -3);
-
-       {
-               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);
-       }
-
-       luaL_register (L, NULL, dns_resolverlib_m);
-       rspamd_lua_add_preload (L, "rspamd_resolver", lua_load_dns);
-
-       lua_pop (L, 1);                      /* remove metatable from stack */
-}
diff --git a/src/lua/lua_dns.h b/src/lua/lua_dns.h
deleted file mode 100644 (file)
index f5c71aa..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-#ifndef RSPAMD_LUA_DNS_H
-#define RSPAMD_LUA_DNS_H
-
-typedef struct lua_State lua_State;
-struct rdns_reply;
-
-/**
- * Pushes dns reply onto Lua stack
- *
- * @param L
- * @param reply
- */
-void
-lua_push_dns_reply (lua_State *L, const struct rdns_reply *reply);
-
-#endif //RSPAMD_LUA_DNS_H
diff --git a/src/lua/lua_dns_resolver.c b/src/lua/lua_dns_resolver.c
new file mode 100644 (file)
index 0000000..dc475f2
--- /dev/null
@@ -0,0 +1,631 @@
+/*-
+ * 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:get_session(), task:get_mempool(),
+               host, dns_cb)
+end
+ */
+struct rspamd_dns_resolver * lua_check_dns_resolver (lua_State * L);
+void luaopen_dns_resolver (lua_State * L);
+
+/* 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);
+
+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),
+       {"__tostring", rspamd_lua_class_tostring},
+       {NULL, NULL}
+};
+
+struct rspamd_dns_resolver *
+lua_check_dns_resolver (lua_State * L)
+{
+       void *ud = rspamd_lua_check_udata (L, 1, "rspamd{resolver}");
+       luaL_argcheck (L, ud != NULL, 1, "'resolver' expected");
+       return ud ? *((struct rspamd_dns_resolver **)ud) : NULL;
+}
+
+struct lua_dns_cbdata {
+       struct rspamd_task *task;
+       struct rspamd_dns_resolver *resolver;
+       gint cbref;
+       const gchar *to_resolve;
+       const gchar *user_str;
+       struct rspamd_async_watcher *w;
+       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);
+
+               if (g_ascii_strcasecmp (strtype, "a") == 0) {
+                       type = RDNS_REQUEST_A;
+               }
+               else if (g_ascii_strcasecmp (strtype, "aaaa") == 0) {
+                       type = RDNS_REQUEST_AAAA;
+               }
+               else if (g_ascii_strcasecmp (strtype, "mx") == 0) {
+                       type = RDNS_REQUEST_MX;
+               }
+               else if (g_ascii_strcasecmp (strtype, "txt") == 0) {
+                       type = RDNS_REQUEST_TXT;
+               }
+               else if (g_ascii_strcasecmp (strtype, "ptr") == 0) {
+                       type = RDNS_REQUEST_PTR;
+               }
+               else if (g_ascii_strcasecmp (strtype, "soa") == 0) {
+                       type = RDNS_REQUEST_SOA;
+               }
+               else {
+                       msg_err ("bad DNS type: %s", 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;
+
+       lua_thread_pool_prepare_callback (cd->resolver->cfg->lua_thread_pool, &cbs);
+       L = cbs.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->authenticated
+        */
+       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->authenticated);
+
+       if (lua_pcall (L, 6, 0, 0) != 0) {
+               msg_info ("call to dns callback failed: %s", lua_tostring (L, -1));
+               lua_pop (L, 1);
+       }
+
+       /* Unref function */
+       luaL_unref (L, LUA_REGISTRYINDEX, cd->cbref);
+
+       lua_thread_pool_restore_callback (&cbs);
+
+       if (cd->s) {
+               rspamd_session_watcher_pop (cd->s, cd->w);
+       }
+}
+
+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)
+               {
+                       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;
+                       }
+               }
+               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 event_base *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 = 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;
+
+       /* Check arguments */
+       if (!rspamd_lua_parse_table_arguments (L, first, &err,
+                       "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;
+       }
+       else if (!session || !pool) {
+               return luaL_error (L, "invalid arguments: either 'task' or 'session'/'mempool' should be set");
+       }
+
+       if (pool != NULL && to_resolve != NULL) {
+               cbdata = rspamd_mempool_alloc0 (pool, sizeof (struct lua_dns_cbdata));
+               cbdata->resolver = resolver;
+               cbdata->cbref = cbref;
+               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);
+                               lua_pushnil (L);
+
+                               return 1;
+                       }
+
+                       cbdata->to_resolve = rspamd_mempool_strdup (pool, ptr_str);
+                       to_resolve = cbdata->to_resolve;
+                       free (ptr_str);
+               }
+
+               if (task == NULL) {
+                       if ( make_dns_request (resolver,
+                                                                  session,
+                                                                  pool,
+                                                                  lua_dns_resolver_callback,
+                                                                  cbdata,
+                                                                  type,
+                                                                  to_resolve)) {
+
+                               lua_pushboolean (L, TRUE);
+
+                               if (session) {
+                                       cbdata->s = session;
+                                       cbdata->w = rspamd_session_get_watcher (session);
+                                       rspamd_session_watcher_push (session);
+                               }
+                       }
+                       else {
+                               lua_pushnil (L);
+                       }
+               }
+               else {
+                       cbdata->task = task;
+
+                       if (forced) {
+                               ret = make_dns_request_task_forced (task,
+                                                                                                       lua_dns_resolver_callback,
+                                                                                                       cbdata,
+                                                                                                       type,
+                                                                                                       to_resolve);
+                       }
+                       else {
+                               ret = make_dns_request_task (task,
+                                                                                        lua_dns_resolver_callback,
+                                                                                        cbdata,
+                                                                                        type,
+                                                                                        to_resolve);
+                       }
+
+                       if (ret) {
+                               cbdata->s = session;
+                               cbdata->w = rspamd_session_get_watcher (session);
+                               rspamd_session_watcher_push (session);
+                               /* callback was set up */
+                               lua_pushboolean (L, TRUE);
+                       }
+                       else {
+                               lua_pushnil (L);
+                       }
+               }
+       }
+       else {
+               return luaL_error (L, "invalid arguments to lua_resolve");
+       }
+
+       return 1;
+
+}
+
+/***
+ * @method resolver:resolve_a(session, pool, host, callback)
+ * Resolve A record for a specified host.
+ * @param {async_session} session asynchronous session normally associated with rspamd task (`task:get_session()`)
+ * @param {mempool} pool memory pool for storing intermediate data
+ * @param {string} host name to resolve
+ * @param {function} callback callback function to be called upon name resolution is finished; must be of type `function (resolver, to_resolve, results, err)`
+ * @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);
+
+       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(session, pool, ip, callback)
+ * Resolve PTR record for a specified host.
+ * @param {async_session} session asynchronous session normally associated with rspamd task (`task:get_session()`)
+ * @param {mempool} pool memory pool for storing intermediate data
+ * @param {string} ip name to resolve in string form (e.g. '8.8.8.8' or '2001:dead::')
+ * @param {function} callback callback function to be called upon name resolution is finished; must be of type `function (resolver, to_resolve, results, err)`
+ * @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);
+
+       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(session, pool, host, callback)
+ * Resolve TXT record for a specified host.
+ * @param {async_session} session asynchronous session normally associated with rspamd task (`task:get_session()`)
+ * @param {mempool} pool memory pool for storing intermediate data
+ * @param {string} host name to get TXT record for
+ * @param {function} callback callback function to be called upon name resolution is finished; must be of type `function (resolver, to_resolve, results, err)`
+ * @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);
+
+       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(session, pool, host, callback)
+ * Resolve MX record for a specified host.
+ * @param {async_session} session asynchronous session normally associated with rspamd task (`task:get_session()`)
+ * @param {mempool} pool memory pool for storing intermediate data
+ * @param {string} host name to get MX record for
+ * @param {function} callback callback function to be called upon name resolution is finished; must be of type `function (resolver, to_resolve, results, err)`
+ * @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);
+
+       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(session, pool, host, callback)
+ * Resolve NS records for a specified host.
+ * @param {async_session} session asynchronous session normally associated with rspamd task (`task:get_session()`)
+ * @param {mempool} pool memory pool for storing intermediate data
+ * @param {string} host name to get NS records for
+ * @param {function} callback callback function to be called upon name resolution is finished; must be of type `function (resolver, to_resolve, results, err)`
+ * @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);
+
+       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);
+       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;
+}
+
+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)
+{
+
+       luaL_newmetatable (L, "rspamd{resolver}");
+       lua_pushstring (L, "__index");
+       lua_pushvalue (L, -2);
+       lua_settable (L, -3);
+
+       lua_pushstring (L, "class");
+       lua_pushstring (L, "rspamd{resolver}");
+       lua_rawset (L, -3);
+
+       {
+               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);
+       }
+
+       luaL_register (L, NULL, dns_resolverlib_m);
+       rspamd_lua_add_preload (L, "rspamd_resolver", lua_load_dns_resolver);
+
+       lua_pop (L, 1);                      /* remove metatable from stack */
+}
diff --git a/src/lua/lua_dns_resolver.h b/src/lua/lua_dns_resolver.h
new file mode 100644 (file)
index 0000000..f5c71aa
--- /dev/null
@@ -0,0 +1,16 @@
+#ifndef RSPAMD_LUA_DNS_H
+#define RSPAMD_LUA_DNS_H
+
+typedef struct lua_State lua_State;
+struct rdns_reply;
+
+/**
+ * Pushes dns reply onto Lua stack
+ *
+ * @param L
+ * @param reply
+ */
+void
+lua_push_dns_reply (lua_State *L, const struct rdns_reply *reply);
+
+#endif //RSPAMD_LUA_DNS_H
index 9c3764c06290c36b618a1eb272ddb40115f318ec..3fee5bb7f84fe8d8dcdcca90fcb6aea6ad35a574 100644 (file)
@@ -12,7 +12,7 @@
  * limitations under the License.
  */
 #include "lua_common.h"
-#include "lua_dns.h"
+#include "lua_dns_resolver.h"
 #include "lua_thread_pool.h"
 
 LUA_FUNCTION_DEF (dns, request);