diff options
Diffstat (limited to 'src/lua/lua_dns.c')
-rw-r--r-- | src/lua/lua_dns.c | 198 |
1 files changed, 198 insertions, 0 deletions
diff --git a/src/lua/lua_dns.c b/src/lua/lua_dns.c new file mode 100644 index 0000000..cffa312 --- /dev/null +++ b/src/lua/lua_dns.c @@ -0,0 +1,198 @@ +/*- + * 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_dns_resolver.h" +#include "lua_thread_pool.h" + +LUA_FUNCTION_DEF(dns, request); + +static const struct luaL_reg dns_f[] = { + LUA_INTERFACE_DEF(dns, request), + {"__tostring", rspamd_lua_class_tostring}, + {NULL, NULL}}; + +static const gchar *M = "rspamd lua dns"; + +void lua_dns_callback(struct rdns_reply *reply, void *arg); + +struct lua_rspamd_dns_cbdata { + struct thread_entry *thread; + struct rspamd_task *task; + struct rspamd_dns_resolver *resolver; + struct rspamd_symcache_dynamic_item *item; + struct rspamd_async_session *s; +}; + +static gint +lua_dns_request(lua_State *L) +{ + GError *err = NULL; + struct rspamd_async_session *session = NULL; + struct rspamd_config *cfg = NULL; + struct lua_rspamd_dns_cbdata *cbdata = NULL; + const gchar *to_resolve = NULL; + const gchar *type_str = NULL; + struct rspamd_task *task = NULL; + rspamd_mempool_t *pool = NULL; + gint ret = 0; + gboolean forced = FALSE; + + /* Check arguments */ + if (!rspamd_lua_parse_table_arguments(L, 1, &err, + RSPAMD_LUA_PARSE_ARGUMENTS_DEFAULT, + "*name=S;task=U{task};*type=S;forced=B;session=U{session};config=U{config}", + &to_resolve, + &task, + &type_str, + &forced, + &session, + &cfg)) { + + 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) { + session = task->s; + pool = task->task_pool; + cfg = task->cfg; + } + else if (session && cfg) { + pool = cfg->cfg_pool; + } + else { + return luaL_error(L, "invalid arguments: either task or session/config should be set"); + } + + enum rdns_request_type type = rdns_type_fromstr(type_str); + + if (type == RDNS_REQUEST_INVALID) { + return luaL_error(L, "invalid arguments: this record type is not supported"); + } + + cbdata = rspamd_mempool_alloc0(pool, sizeof(*cbdata)); + + cbdata->task = task; + + if (type == RDNS_REQUEST_PTR) { + 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; + } + + to_resolve = rspamd_mempool_strdup(pool, ptr_str); + free(ptr_str); + } + + + if (task == NULL) { + ret = (rspamd_dns_resolver_request(cfg->dns_resolver, + session, + pool, + lua_dns_callback, + cbdata, + type, + to_resolve) != NULL); + } + else { + if (forced) { + ret = rspamd_dns_resolver_request_task_forced(task, + lua_dns_callback, + cbdata, + type, + to_resolve); + } + else { + ret = rspamd_dns_resolver_request_task(task, + lua_dns_callback, + cbdata, + type, + to_resolve); + } + } + + if (ret) { + cbdata->thread = lua_thread_pool_get_running_entry(cfg->lua_thread_pool); + cbdata->s = session; + + if (task) { + cbdata->item = rspamd_symcache_get_cur_item(task); + rspamd_symcache_item_async_inc(task, cbdata->item, M); + } + + return lua_thread_yield(cbdata->thread, 0); + } + else { + lua_pushnil(L); + return 1; + } +} + +void lua_dns_callback(struct rdns_reply *reply, void *arg) +{ + struct lua_rspamd_dns_cbdata *cbdata = arg; + lua_State *L = cbdata->thread->lua_state; + + if (reply->code != RDNS_RC_NOERROR) { + lua_pushboolean(L, false); + lua_pushstring(L, rdns_strerror(reply->code)); + } + else { + lua_push_dns_reply(L, reply); + + lua_pushboolean(L, reply->flags & RDNS_AUTH); + lua_setfield(L, -3, "authenticated"); + + lua_pushboolean(L, reply->flags & RDNS_TRUNCATED); + lua_setfield(L, -3, "truncated"); + + /* result 1 - not and error */ + lua_pushboolean(L, true); + /* push table into stack, result 2 - results itself */ + lua_pushvalue(L, -3); + } + + lua_thread_resume(cbdata->thread, 2); + + if (cbdata->item) { + rspamd_symcache_item_async_dec_check(cbdata->task, cbdata->item, M); + } +} + +static gint +lua_load_dns(lua_State *L) +{ + lua_newtable(L); + luaL_register(L, NULL, dns_f); + + return 1; +} + +void luaopen_dns(lua_State *L) +{ + rspamd_lua_add_preload(L, "rspamd_dns", lua_load_dns); +} |