diff options
Diffstat (limited to 'src/lua')
-rw-r--r-- | src/lua/lua_config.c | 290 | ||||
-rw-r--r-- | src/lua/lua_http.c | 82 | ||||
-rw-r--r-- | src/lua/lua_ip.c | 2 | ||||
-rw-r--r-- | src/lua/lua_map.c | 14 |
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 |