aboutsummaryrefslogtreecommitdiffstats
path: root/src/lua
diff options
context:
space:
mode:
Diffstat (limited to 'src/lua')
-rw-r--r--src/lua/lua_config.c290
-rw-r--r--src/lua/lua_http.c82
-rw-r--r--src/lua/lua_ip.c2
-rw-r--r--src/lua/lua_map.c14
4 files changed, 327 insertions, 61 deletions
diff --git a/src/lua/lua_config.c b/src/lua/lua_config.c
index 147e4ff80..e846fd4d7 100644
--- a/src/lua/lua_config.c
+++ b/src/lua/lua_config.c
@@ -721,7 +721,7 @@ LUA_FUNCTION_DEF (config, has_torch);
LUA_FUNCTION_DEF (config, experimental_enabled);
/***
- * @method rspamd_config:load_ucl(filename)
+ * @method rspamd_config:load_ucl(filename[, include_trace])
* Loads config from the UCL file (but does not perform parsing using rcl)
* @param {string} filename file to load
* @return true or false + error message
@@ -1113,6 +1113,119 @@ rspamd_compare_order_func (gconstpointer a, gconstpointer b)
return cb2->order - cb1->order;
}
+static void
+lua_metric_symbol_callback (struct rspamd_task *task,
+ struct rspamd_symcache_item *item,
+ gpointer ud)
+{
+ struct lua_callback_data *cd = ud;
+ struct rspamd_task **ptask;
+ gint level = lua_gettop (cd->L), nresults, err_idx, ret;
+ lua_State *L = cd->L;
+ GString *tb;
+ struct rspamd_symbol_result *s;
+
+ cd->item = item;
+ rspamd_symcache_item_async_inc (task, item, "lua symbol");
+ lua_pushcfunction (L, &rspamd_lua_traceback);
+ err_idx = lua_gettop (L);
+
+ level ++;
+
+ if (cd->cb_is_ref) {
+ lua_rawgeti (L, LUA_REGISTRYINDEX, cd->callback.ref);
+ }
+ else {
+ lua_getglobal (L, cd->callback.name);
+ }
+
+ ptask = lua_newuserdata (L, sizeof (struct rspamd_task *));
+ rspamd_lua_setclass (L, "rspamd{task}", -1);
+ *ptask = task;
+
+ if ((ret = lua_pcall (L, 1, LUA_MULTRET, err_idx)) != 0) {
+ tb = lua_touserdata (L, -1);
+ msg_err_task ("call to (%s) failed (%d): %v", cd->symbol, ret, tb);
+
+ if (tb) {
+ g_string_free (tb, TRUE);
+ lua_pop (L, 1);
+ }
+ }
+ else {
+ nresults = lua_gettop (L) - level;
+
+ if (nresults >= 1) {
+ /* Function returned boolean, so maybe we need to insert result? */
+ gint res = 0;
+ gint i;
+ gdouble flag = 1.0;
+ gint type;
+
+ type = lua_type (cd->L, level + 1);
+
+ if (type == LUA_TBOOLEAN) {
+ res = lua_toboolean (L, level + 1);
+ }
+ else if (type == LUA_TNUMBER) {
+ res = lua_tonumber (L, level + 1);
+ }
+ else if (type == LUA_TNIL) {
+ /* Can happen sometimes... */
+ res = FALSE;
+ }
+ else {
+ g_assert_not_reached ();
+ }
+
+ if (res) {
+ gint first_opt = 2;
+
+ if (lua_type (L, level + 2) == LUA_TNUMBER) {
+ flag = lua_tonumber (L, level + 2);
+ /* Shift opt index */
+ first_opt = 3;
+ }
+ else {
+ flag = res;
+ }
+
+ s = rspamd_task_insert_result (task, cd->symbol, flag, NULL);
+
+ if (s) {
+ guint last_pos = lua_gettop (L);
+
+ for (i = level + first_opt; i <= last_pos; i++) {
+ if (lua_type (L, i) == LUA_TSTRING) {
+ const char *opt = lua_tostring (L, i);
+
+ rspamd_task_add_result_option (task, s, opt);
+ }
+ else if (lua_type (L, i) == LUA_TTABLE) {
+ lua_pushvalue (L, i);
+
+ for (lua_pushnil (L); lua_next (L, -2); lua_pop (L, 1)) {
+ const char *opt = lua_tostring (L, -1);
+
+ rspamd_task_add_result_option (task, s, opt);
+ }
+
+ lua_pop (L, 1);
+ }
+ }
+ }
+
+ }
+
+ lua_pop (L, nresults);
+ }
+ }
+
+ lua_pop (L, 1); /* Error function */
+ rspamd_symcache_item_async_dec_check (task, cd->item, "lua symbol");
+ g_assert (lua_gettop (L) == level - 1);
+}
+
static void lua_metric_symbol_callback_return (struct thread_entry *thread_entry,
int ret);
@@ -1121,15 +1234,15 @@ static void lua_metric_symbol_callback_error (struct thread_entry *thread_entry,
const char *msg);
static void
-lua_metric_symbol_callback (struct rspamd_task *task,
- struct rspamd_symcache_item *item,
- gpointer ud)
+lua_metric_symbol_callback_coro (struct rspamd_task *task,
+ struct rspamd_symcache_item *item,
+ gpointer ud)
{
struct lua_callback_data *cd = ud;
struct rspamd_task **ptask;
struct thread_entry *thread_entry;
- rspamd_symcache_item_async_inc (task, item, "lua symbol");
+ rspamd_symcache_item_async_inc (task, item, "lua coro symbol");
thread_entry = lua_thread_pool_get_for_task (task);
g_assert(thread_entry->cd == NULL);
@@ -1163,9 +1276,9 @@ lua_metric_symbol_callback_error (struct thread_entry *thread_entry,
{
struct lua_callback_data *cd = thread_entry->cd;
struct rspamd_task *task = thread_entry->task;
- msg_err_task ("call to (%s) failed (%d): %s", cd->symbol, ret, msg);
+ msg_err_task ("call to coroutine (%s) failed (%d): %s", cd->symbol, ret, msg);
- rspamd_symcache_item_async_dec_check (task, cd->item, "lua symbol");
+ rspamd_symcache_item_async_dec_check (task, cd->item, "lua coro symbol");
}
static void
@@ -1246,7 +1359,7 @@ lua_metric_symbol_callback_return (struct thread_entry *thread_entry, int ret)
g_assert (lua_gettop (L) == cd->stack_level); /* we properly cleaned up the stack */
cd->stack_level = 0;
- rspamd_symcache_item_async_dec_check (task, cd->item, "lua symbol");
+ rspamd_symcache_item_async_dec_check (task, cd->item, "lua coro symbol");
}
static gint
@@ -1282,6 +1395,10 @@ rspamd_register_symbol_fromlua (lua_State *L,
}
if (ref != -1) {
+ if (type & SYMBOL_TYPE_USE_CORO) {
+ /* Coroutines are incompatible with squeezing */
+ no_squeeze = TRUE;
+ }
/*
* We call for routine called lua_squeeze_rules.squeeze_rule if it exists
*/
@@ -1349,15 +1466,27 @@ rspamd_register_symbol_fromlua (lua_State *L,
cd->symbol = rspamd_mempool_strdup (cfg->cfg_pool, name);
}
- ret = rspamd_symcache_add_symbol (cfg->cache,
- name,
- priority,
- lua_metric_symbol_callback,
- cd,
- type,
- parent);
+ if (type & SYMBOL_TYPE_USE_CORO) {
+ ret = rspamd_symcache_add_symbol (cfg->cache,
+ name,
+ priority,
+ lua_metric_symbol_callback_coro,
+ cd,
+ type,
+ parent);
+ }
+ else {
+ ret = rspamd_symcache_add_symbol (cfg->cache,
+ name,
+ priority,
+ lua_metric_symbol_callback,
+ cd,
+ type,
+ parent);
+ }
+
rspamd_mempool_add_destructor (cfg->cfg_pool,
- (rspamd_mempool_destruct_t)lua_destroy_cfg_symbol,
+ (rspamd_mempool_destruct_t) lua_destroy_cfg_symbol,
cd);
}
}
@@ -1373,13 +1502,24 @@ rspamd_register_symbol_fromlua (lua_State *L,
cd->symbol = rspamd_mempool_strdup (cfg->cfg_pool, name);
}
- ret = rspamd_symcache_add_symbol (cfg->cache,
- name,
- priority,
- lua_metric_symbol_callback,
- cd,
- type,
- parent);
+ if (type & SYMBOL_TYPE_USE_CORO) {
+ ret = rspamd_symcache_add_symbol (cfg->cache,
+ name,
+ priority,
+ lua_metric_symbol_callback_coro,
+ cd,
+ type,
+ parent);
+ }
+ else {
+ ret = rspamd_symcache_add_symbol (cfg->cache,
+ name,
+ priority,
+ lua_metric_symbol_callback,
+ cd,
+ type,
+ parent);
+ }
rspamd_mempool_add_destructor (cfg->cfg_pool,
(rspamd_mempool_destruct_t)lua_destroy_cfg_symbol,
cd);
@@ -1556,6 +1696,9 @@ lua_parse_symbol_flags (const gchar *str)
if (strstr (str, "explicit_disable") != NULL) {
ret |= SYMBOL_TYPE_EXPLICIT_DISABLE;
}
+ if (strstr (str, "coro") != NULL) {
+ ret |= SYMBOL_TYPE_USE_CORO;
+ }
}
return ret;
@@ -2450,7 +2593,7 @@ lua_config_newindex (lua_State *L)
LUA_TRACE_POINT;
struct rspamd_config *cfg = lua_check_config (L, 1);
const gchar *name;
- gint id, nshots;
+ gint id, nshots, flags = 0;
gboolean optional = FALSE, no_squeeze = FALSE;
name = luaL_checkstring (L, 2);
@@ -2476,7 +2619,6 @@ lua_config_newindex (lua_State *L)
gint type = SYMBOL_TYPE_NORMAL, priority = 0, idx;
gdouble weight = 1.0, score = NAN;
const char *type_str, *group = NULL, *description = NULL;
- guint flags = 0;
no_squeeze = cfg->disable_lua_squeeze;
/*
@@ -2485,6 +2627,7 @@ lua_config_newindex (lua_State *L)
* "weight" - optional weight
* "priority" - optional priority
* "type" - optional type (normal, virtual, callback)
+ * "flags" - optional flags
* -- Metric options
* "score" - optional default score (overridden by metric)
* "group" - optional default group
@@ -2537,6 +2680,15 @@ lua_config_newindex (lua_State *L)
}
lua_pop (L, 1);
+ lua_pushstring (L, "flags");
+ lua_gettable (L, -2);
+
+ if (lua_type (L, -1) == LUA_TSTRING) {
+ type_str = lua_tostring (L, -1);
+ type |= lua_parse_symbol_flags (type_str);
+ }
+ lua_pop (L, 1);
+
lua_pushstring (L, "condition");
lua_gettable (L, -2);
@@ -3509,6 +3661,60 @@ lua_config_experimental_enabled (lua_State *L)
return 1;
}
+struct rspamd_lua_include_trace_cbdata {
+ lua_State *L;
+ gint cbref;
+};
+
+static void
+lua_include_trace_cb (struct ucl_parser *parser,
+ const ucl_object_t *parent,
+ const ucl_object_t *args,
+ const char *path,
+ size_t pathlen,
+ void *user_data)
+{
+ struct rspamd_lua_include_trace_cbdata *cbdata =
+ (struct rspamd_lua_include_trace_cbdata *)user_data;
+ gint err_idx;
+ GString *tb;
+ lua_State *L;
+
+ L = cbdata->L;
+ lua_pushcfunction (L, &rspamd_lua_traceback);
+ err_idx = lua_gettop (L);
+
+ lua_rawgeti (L, LUA_REGISTRYINDEX, cbdata->cbref);
+ /* Current filename */
+ lua_pushstring (L, ucl_parser_get_cur_file (parser));
+ /* Included filename */
+ lua_pushlstring (L, path, pathlen);
+ /* Params */
+ if (args) {
+ ucl_object_push_lua (L, args, true);
+ }
+ else {
+ lua_newtable (L);
+ }
+ /* Parent */
+ if (parent) {
+ lua_pushstring (L, ucl_object_key (parent));
+ }
+ else {
+ lua_pushnil (L);
+ }
+
+ if (lua_pcall (L, 4, 0, err_idx) != 0) {
+ tb = lua_touserdata (L, -1);
+ msg_err ("lua call to local include trace failed: %v", tb);
+ if (tb) {
+ g_string_free (tb, TRUE);
+ }
+ }
+
+ lua_settop (L, err_idx - 1);
+}
+
#define LUA_TABLE_TO_HASH(htb, idx) do { \
lua_pushstring (L, (idx)); \
lua_gettable (L, -2); \
@@ -3553,13 +3759,35 @@ lua_config_load_ucl (lua_State *L)
lua_pop (L, 1);
- if (!rspamd_config_parse_ucl (cfg, filename, paths, &err)) {
- lua_pushboolean (L, false);
- lua_pushfstring (L, "failed to load config: %s", err->message);
- g_error_free (err);
- g_hash_table_unref (paths);
+ if (lua_isfunction (L, 3)) {
+ struct rspamd_lua_include_trace_cbdata cbd;
- return 2;
+ lua_pushvalue (L, 3);
+ cbd.cbref = luaL_ref (L, LUA_REGISTRYINDEX);
+ cbd.L = L;
+
+ if (!rspamd_config_parse_ucl (cfg, filename, paths,
+ lua_include_trace_cb, &cbd, &err)) {
+ luaL_unref (L, LUA_REGISTRYINDEX, cbd.cbref);
+ lua_pushboolean (L, false);
+ lua_pushfstring (L, "failed to load config: %s", err->message);
+ g_error_free (err);
+ g_hash_table_unref (paths);
+
+ return 2;
+ }
+
+ luaL_unref (L, LUA_REGISTRYINDEX, cbd.cbref);
+ }
+ else {
+ if (!rspamd_config_parse_ucl (cfg, filename, paths, NULL, NULL, &err)) {
+ lua_pushboolean (L, false);
+ lua_pushfstring (L, "failed to load config: %s", err->message);
+ g_error_free (err);
+ g_hash_table_unref (paths);
+
+ return 2;
+ }
}
rspamd_rcl_maybe_apply_lua_transform (cfg);
diff --git a/src/lua/lua_http.c b/src/lua/lua_http.c
index a8616e82a..4378aea89 100644
--- a/src/lua/lua_http.c
+++ b/src/lua/lua_http.c
@@ -58,6 +58,7 @@ static const struct luaL_reg httplib_m[] = {
#define RSPAMD_LUA_HTTP_FLAG_TEXT (1 << 0)
#define RSPAMD_LUA_HTTP_FLAG_NOVERIFY (1 << 1)
#define RSPAMD_LUA_HTTP_FLAG_RESOLVED (1 << 2)
+#define RSPAMD_LUA_HTTP_FLAG_KEEP_ALIVE (1 << 3)
struct lua_http_cbdata {
struct rspamd_http_connection *conn;
@@ -370,27 +371,29 @@ lua_http_make_connection (struct lua_http_cbdata *cbd)
int fd;
rspamd_inet_address_set_port (cbd->addr, cbd->msg->port);
- fd = rspamd_inet_address_connect (cbd->addr, SOCK_STREAM, TRUE);
- if (fd == -1) {
- msg_info ("cannot connect to %V", cbd->msg->host);
- return FALSE;
- }
- cbd->fd = fd;
+ if (cbd->flags & RSPAMD_LUA_HTTP_FLAG_KEEP_ALIVE) {
+ cbd->fd = -1; /* FD is owned by keepalive connection */
- if (cbd->cfg) {
- cbd->conn = rspamd_http_connection_new (
- NULL,
- fd,
+ cbd->conn = rspamd_http_connection_new_keepalive (
+ NULL, /* Default context */
NULL,
lua_http_error_handler,
lua_http_finish_handler,
- RSPAMD_HTTP_CLIENT_SIMPLE,
- RSPAMD_HTTP_CLIENT);
+ cbd->addr,
+ cbd->host);
}
else {
+ fd = rspamd_inet_address_connect (cbd->addr, SOCK_STREAM, TRUE);
+
+ if (fd == -1) {
+ msg_info ("cannot connect to %V", cbd->msg->host);
+ return FALSE;
+ }
+
+ cbd->fd = fd;
cbd->conn = rspamd_http_connection_new (
- NULL,
+ NULL, /* Default context */
fd,
NULL,
lua_http_error_handler,
@@ -554,7 +557,6 @@ lua_http_request (lua_State *L)
struct rspamd_cryptobox_keypair *local_kp = NULL;
const gchar *url, *lua_body;
rspamd_fstring_t *body = NULL;
- gchar *to_resolve;
gint cbref = -1;
gsize bodylen;
gdouble timeout = default_http_timeout;
@@ -722,6 +724,9 @@ lua_http_request (lua_State *L)
body = rspamd_fstring_new_init (t->start, t->len);
}
else {
+ rspamd_http_message_unref (msg);
+ g_free (mime_type);
+
return luaL_error (L, "invalid body argument type: %s",
lua_typename (L, lua_type (L, -1)));
}
@@ -741,17 +746,28 @@ lua_http_request (lua_State *L)
body = rspamd_fstring_append (body, t->start, t->len);
}
else {
+ rspamd_http_message_unref (msg);
+ if (body) {
+ rspamd_fstring_free (body);
+ }
+
return luaL_error (L, "invalid body argument: %s",
lua_typename (L, lua_type (L, -1)));
}
}
else {
+ rspamd_http_message_unref (msg);
+ if (body) {
+ rspamd_fstring_free (body);
+ }
+
return luaL_error (L, "invalid body argument type: %s",
lua_typename (L, lua_type (L, -1)));
}
}
}
else if (lua_type (L, -1) != LUA_TNONE && lua_type (L, -1) != LUA_TNIL) {
+ rspamd_http_message_unref (msg);
return luaL_error (L, "invalid body argument type: %s",
lua_typename (L, lua_type (L, -1)));
}
@@ -810,6 +826,15 @@ lua_http_request (lua_State *L)
lua_pop (L, 1);
+ lua_pushstring (L, "keepalive");
+ lua_gettable (L, 1);
+
+ if (!!lua_toboolean (L, -1)) {
+ flags |= RSPAMD_LUA_HTTP_FLAG_KEEP_ALIVE;
+ }
+
+ lua_pop (L, 1);
+
lua_pushstring (L, "max_size");
lua_gettable (L, 1);
@@ -870,9 +895,21 @@ lua_http_request (lua_State *L)
if (session && rspamd_session_blocked (session)) {
lua_pushboolean (L, FALSE);
+ g_free (auth);
+ rspamd_http_message_unref (msg);
+ if (body) {
+ rspamd_fstring_free (body);
+ }
+
return 1;
}
if (task == NULL && cfg == NULL) {
+ g_free (auth);
+ rspamd_http_message_unref (msg);
+ if (body) {
+ rspamd_fstring_free (body);
+ }
+
return luaL_error (L,
"Bad params to rspamd_http:request(): either task or config should be set");
}
@@ -930,28 +967,25 @@ lua_http_request (lua_State *L)
}
}
else {
+ if (!cbd->host) {
+ lua_http_maybe_free (cbd);
+
+ return luaL_error (L, "no host has been specified");
+ }
if (task == NULL) {
- to_resolve = g_malloc (msg->host->len + 1);
- rspamd_strlcpy (to_resolve, msg->host->str, msg->host->len + 1);
if (!make_dns_request (resolver, session, NULL, lua_http_dns_handler, cbd,
RDNS_REQUEST_A,
- to_resolve)) {
+ cbd->host)) {
lua_http_maybe_free (cbd);
lua_pushboolean (L, FALSE);
- g_free (to_resolve);
return 1;
}
-
-
- g_free (to_resolve);
}
else {
- to_resolve = rspamd_mempool_fstrdup (task->task_pool, msg->host);
-
if (!make_dns_request_task_forced (task, lua_http_dns_handler, cbd,
- RDNS_REQUEST_A, to_resolve)) {
+ RDNS_REQUEST_A, cbd->host)) {
lua_http_maybe_free (cbd);
lua_pushboolean (L, FALSE);
diff --git a/src/lua/lua_ip.c b/src/lua/lua_ip.c
index 5ee4a39b4..7f24f7712 100644
--- a/src/lua/lua_ip.c
+++ b/src/lua/lua_ip.c
@@ -490,7 +490,7 @@ lua_ip_equal (lua_State *L)
gboolean res = FALSE;
if (ip1 && ip2 && ip1->addr && ip2->addr) {
- res = rspamd_inet_address_compare (ip1->addr, ip2->addr);
+ res = rspamd_inet_address_compare (ip1->addr, ip2->addr, TRUE);
}
lua_pushboolean (L, res);
diff --git a/src/lua/lua_map.c b/src/lua/lua_map.c
index 98b025ea2..3ba7d0ed1 100644
--- a/src/lua/lua_map.c
+++ b/src/lua/lua_map.c
@@ -416,7 +416,7 @@ lua_map_read (gchar *chunk, gint len,
}
static void
-lua_map_fin (struct map_cb_data *data)
+lua_map_fin (struct map_cb_data *data, void **target)
{
struct lua_map_callback_data *cbdata;
struct rspamd_lua_map **pmap;
@@ -432,10 +432,6 @@ lua_map_fin (struct map_cb_data *data)
return;
}
- if (data->prev_data) {
- data->prev_data = NULL;
- }
-
if (cbdata->ref == -1) {
msg_err_map ("map has no callback set");
}
@@ -454,6 +450,14 @@ lua_map_fin (struct map_cb_data *data)
}
cbdata->data = rspamd_fstring_assign (cbdata->data, "", 0);
+
+ if (target) {
+ *target = data->cur_data;
+ }
+
+ if (data->prev_data) {
+ data->prev_data = NULL;
+ }
}
static void