diff options
Diffstat (limited to 'src/lua')
-rw-r--r-- | src/lua/lua_cdb.c | 14 | ||||
-rw-r--r-- | src/lua/lua_cfg_file.c | 42 | ||||
-rw-r--r-- | src/lua/lua_common.c | 126 | ||||
-rw-r--r-- | src/lua/lua_common.h | 34 | ||||
-rw-r--r-- | src/lua/lua_config.c | 7 | ||||
-rw-r--r-- | src/lua/lua_cryptobox.c | 50 | ||||
-rw-r--r-- | src/lua/lua_dns_resolver.c | 27 | ||||
-rw-r--r-- | src/lua/lua_expression.c | 14 | ||||
-rw-r--r-- | src/lua/lua_http.c | 3 | ||||
-rw-r--r-- | src/lua/lua_ip.c | 27 | ||||
-rw-r--r-- | src/lua/lua_logger.c | 53 | ||||
-rw-r--r-- | src/lua/lua_mempool.c | 14 | ||||
-rw-r--r-- | src/lua/lua_mimepart.c | 34 | ||||
-rw-r--r-- | src/lua/lua_redis.c | 18 | ||||
-rw-r--r-- | src/lua/lua_regexp.c | 69 | ||||
-rw-r--r-- | src/lua/lua_rsa.c | 36 | ||||
-rw-r--r-- | src/lua/lua_sqlite3.c | 22 | ||||
-rw-r--r-- | src/lua/lua_task.c | 117 | ||||
-rw-r--r-- | src/lua/lua_tcp.c | 6 | ||||
-rw-r--r-- | src/lua/lua_text.c | 143 | ||||
-rw-r--r-- | src/lua/lua_trie.c | 135 | ||||
-rw-r--r-- | src/lua/lua_udp.c | 3 | ||||
-rw-r--r-- | src/lua/lua_upstream.c | 28 | ||||
-rw-r--r-- | src/lua/lua_url.c | 9 | ||||
-rw-r--r-- | src/lua/lua_util.c | 116 | ||||
-rw-r--r-- | src/lua/lua_worker.c | 208 |
26 files changed, 966 insertions, 389 deletions
diff --git a/src/lua/lua_cdb.c b/src/lua/lua_cdb.c index 5d4c499a7..1f9b48260 100644 --- a/src/lua/lua_cdb.c +++ b/src/lua/lua_cdb.c @@ -151,17 +151,7 @@ lua_load_cdb (lua_State *L) void luaopen_cdb (lua_State * L) { - luaL_newmetatable (L, "rspamd{cdb}"); - lua_pushstring (L, "__index"); - lua_pushvalue (L, -2); - lua_settable (L, -3); - - lua_pushstring (L, "class"); - lua_pushstring (L, "rspamd{cdb}"); - lua_rawset (L, -3); - - luaL_register (L, NULL, cdblib_m); - lua_pop (L, 1); /* remove metatable from stack */ - + rspamd_lua_new_class (L, "rspamd{cdb}", cdblib_m); + lua_pop (L, 1); rspamd_lua_add_preload (L, "rspamd_cdb", lua_load_cdb); } diff --git a/src/lua/lua_cfg_file.c b/src/lua/lua_cfg_file.c index 26e9811bd..23001f8f1 100644 --- a/src/lua/lua_cfg_file.c +++ b/src/lua/lua_cfg_file.c @@ -97,28 +97,50 @@ rspamd_lua_post_load_config (struct rspamd_config *cfg) lua_State *L = cfg->lua_state; const gchar *name; ucl_object_t *obj; - gsize keylen; + gsize keylen, i; /* First check all module options that may be overridden in 'config' global */ lua_getglobal (L, "config"); if (lua_istable (L, -1)) { - /* Iterate */ - for (lua_pushnil (L); lua_next (L, -2); lua_pop (L, 1)) { - /* 'key' is at index -2 and 'value' is at index -1 */ - /* Key must be a string and value must be a table */ - name = luaL_checklstring (L, -2, &keylen); + /* Iterate to get all keys */ + GPtrArray *names = g_ptr_array_new_full (rspamd_lua_table_size (L, -1), + g_free); + + for (lua_pushnil (L); lua_next (L, -2); lua_pop (L, 2)) { + gchar *tmp; + lua_pushvalue (L, -2); + name = luaL_checklstring (L, -1, &keylen); + + if (name && lua_istable (L, -2)) { + tmp = g_malloc (keylen + 1); + rspamd_strlcpy (tmp, name, keylen + 1); + g_ptr_array_add (names, tmp); + } + if (name != NULL && lua_istable (L, -1)) { + + } + } + + PTR_ARRAY_FOREACH (names, i, name) { + lua_getfield (L, -1, name); + + if (lua_istable (L, -1)) { obj = ucl_object_lua_import (L, lua_gettop (L)); + if (obj != NULL) { + ucl_object_sort_keys (obj, UCL_SORT_KEYS_DEFAULT); ucl_object_insert_key_merged (cfg->rcl_obj, - obj, - name, - keylen, - true); + obj, + name, + strlen (name), + true); } } } + + g_ptr_array_free (names, TRUE); } /* Check metrics settings */ diff --git a/src/lua/lua_common.c b/src/lua/lua_common.c index 5de0fa9ce..bbcec4c1c 100644 --- a/src/lua/lua_common.c +++ b/src/lua/lua_common.c @@ -45,6 +45,35 @@ lua_error_quark (void) return g_quark_from_static_string ("lua-routines"); } +/* idea from daurnimator */ +#if defined(WITH_LUAJIT) && (defined(_LP64) || defined(_LLP64) || defined(__arch64__) || defined (__arm64__) || defined (__aarch64__) || defined(_WIN64)) +#define RSPAMD_USE_47BIT_LIGHTUSERDATA_HACK 1 +#else +#define RSPAMD_USE_47BIT_LIGHTUSERDATA_HACK 0 +#endif + +#if RSPAMD_USE_47BIT_LIGHTUSERDATA_HACK +#define RSPAMD_LIGHTUSERDATA_MASK(p) ((void *)((uintptr_t)(p) & ((1UL<<47)-1))) +#else +#define RSPAMD_LIGHTUSERDATA_MASK(p) ((void *)(p)) +#endif + +/* + * Used to map string to a pointer + */ +KHASH_INIT (lua_class_set, const gchar *, bool, 0, rspamd_str_hash, rspamd_str_equal); +khash_t (lua_class_set) *lua_classes = NULL; + +RSPAMD_CONSTRUCTOR (lua_classes_ctor) +{ + lua_classes = kh_init (lua_class_set); +} + +RSPAMD_DESTRUCTOR (lua_classes_dtor) +{ + kh_destroy (lua_class_set, lua_classes); +} + /* Util functions */ /** * Create new class and store metatable on top of the stack (must be popped if not needed) @@ -57,33 +86,44 @@ rspamd_lua_new_class (lua_State * L, const gchar *classname, const struct luaL_reg *methods) { - luaL_newmetatable (L, classname); /* mt */ + void *class_ptr; + khiter_t k; + gint r, nmethods = 0; + + k = kh_put (lua_class_set, lua_classes, classname, &r); + class_ptr = RSPAMD_LIGHTUSERDATA_MASK (kh_key (lua_classes, k)); + + if (methods) { + for (;;) { + if (methods[nmethods].name != NULL) { + nmethods ++; + } + else { + break; + } + } + } + + lua_createtable (L, 0, 3 + nmethods); lua_pushstring (L, "__index"); lua_pushvalue (L, -2); /* pushes the metatable */ lua_settable (L, -3); /* metatable.__index = metatable */ - lua_pushstring (L, "class"); /* mt,"class" */ - lua_pushstring (L, classname); /* mt,"class",classname */ - lua_rawset (L, -3); /* mt */ + lua_pushstring (L, "class"); + lua_pushstring (L, classname); + lua_rawset (L, -3); + + lua_pushstring (L, "class_ptr"); + lua_pushlightuserdata (L, class_ptr); + lua_rawset (L, -3); if (methods) { luaL_register (L, NULL, methods); /* pushes all methods as MT fields */ } - /* MT is left on stack ! */ -} -/** - * Create and register new class with static methods and store metatable on top of the stack - */ -void -rspamd_lua_new_class_full (lua_State *L, - const gchar *classname, - const gchar *static_name, - const struct luaL_reg *methods, - const struct luaL_reg *func) -{ - rspamd_lua_new_class (L, classname, methods); - luaL_register (L, static_name, func); + lua_pushvalue (L, -1); /* Preserves metatable */ + lua_rawsetp (L, LUA_REGISTRYINDEX, class_ptr); + /* MT is left on stack ! */ } static const gchar * @@ -97,14 +137,7 @@ rspamd_lua_class_tostring_buf (lua_State *L, gboolean print_pointer, gint pos) goto err; } - lua_pushstring (L, "__index"); - lua_gettable (L, -2); pop ++; - - if (!lua_istable (L, -1)) { - goto err; - } - lua_pushstring (L, "class"); lua_gettable (L, -2); pop ++; @@ -150,7 +183,14 @@ rspamd_lua_class_tostring (lua_State * L) void rspamd_lua_setclass (lua_State * L, const gchar *classname, gint objidx) { - luaL_getmetatable (L, classname); + khiter_t k; + + k = kh_get (lua_class_set, lua_classes, classname); + + g_assert (k != kh_end (lua_classes)); + lua_rawgetp (L, LUA_REGISTRYINDEX, + RSPAMD_LIGHTUSERDATA_MASK (kh_key (lua_classes, k))); + if (objidx < 0) { objidx--; } @@ -161,7 +201,6 @@ rspamd_lua_setclass (lua_State * L, const gchar *classname, gint objidx) void rspamd_lua_table_set (lua_State * L, const gchar *index, const gchar *value) { - lua_pushstring (L, index); if (value) { lua_pushstring (L, value); @@ -929,16 +968,10 @@ rspamd_lua_init (bool wipe_mem) lua_settop (L, 0); #endif - luaL_newmetatable (L, "rspamd{ev_base}"); - lua_pushstring (L, "class"); - lua_pushstring (L, "rspamd{ev_base}"); - lua_rawset (L, -3); + rspamd_lua_new_class (L, "rspamd{ev_base}", NULL); lua_pop (L, 1); - luaL_newmetatable (L, "rspamd{session}"); - lua_pushstring (L, "class"); - lua_pushstring (L, "rspamd{session}"); - lua_rawset (L, -3); + rspamd_lua_new_class (L, "rspamd{session}", NULL); lua_pop (L, 1); rspamd_lua_add_preload (L, "lpeg", luaopen_lpeg); @@ -1206,12 +1239,23 @@ gpointer rspamd_lua_check_class (lua_State *L, gint index, const gchar *name) { gpointer p; + khiter_t k; if (lua_type (L, index) == LUA_TUSERDATA) { p = lua_touserdata (L, index); if (p) { if (lua_getmetatable (L, index)) { - lua_getfield (L, LUA_REGISTRYINDEX, name); /* get correct metatable */ + k = kh_get (lua_class_set, lua_classes, name); + + if (k == kh_end (lua_classes)) { + lua_pop (L, 1); + + return NULL; + } + + lua_rawgetp (L, LUA_REGISTRYINDEX, + RSPAMD_LIGHTUSERDATA_MASK (kh_key (lua_classes, k))); + if (lua_rawequal (L, -1, -2)) { /* does it have the correct mt? */ lua_pop (L, 2); /* remove both metatables */ return p; @@ -1824,6 +1868,7 @@ rspamd_lua_check_udata_common (lua_State *L, gint pos, const gchar *classname, { void *p = lua_touserdata (L, pos); guint i, top = lua_gettop (L); + khiter_t k; if (p == NULL) { goto err; @@ -1831,7 +1876,14 @@ rspamd_lua_check_udata_common (lua_State *L, gint pos, const gchar *classname, else { /* Match class */ if (lua_getmetatable (L, pos)) { - luaL_getmetatable (L, classname); + k = kh_get (lua_class_set, lua_classes, (gchar *)classname); + + if (k == kh_end (lua_classes)) { + goto err; + } + + lua_rawgetp (L, LUA_REGISTRYINDEX, + RSPAMD_LIGHTUSERDATA_MASK (kh_key (lua_classes, k))); if (!lua_rawequal (L, -1, -2)) { goto err; diff --git a/src/lua/lua_common.h b/src/lua/lua_common.h index 40bbea772..9878cc521 100644 --- a/src/lua/lua_common.h +++ b/src/lua/lua_common.h @@ -40,6 +40,28 @@ luaL_register (lua_State *L, const gchar *name, const struct luaL_reg *methods) } #endif +#if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM == 501 +static inline int lua_absindex (lua_State *L, int i) { + if (i < 0 && i > LUA_REGISTRYINDEX) + i += lua_gettop(L) + 1; + return i; +} +static inline int lua_rawgetp (lua_State *L, int i, const void *p) { + int abs_i = lua_absindex(L, i); + lua_pushlightuserdata(L, (void*)p); + lua_rawget(L, abs_i); + return lua_type(L, -1); +} + +static inline void lua_rawsetp (lua_State *L, int i, const void *p) { + int abs_i = lua_absindex(L, i); + luaL_checkstack(L, 1, "not enough stack slots"); + lua_pushlightuserdata(L, (void*)p); + lua_insert(L, -2); + lua_rawset(L, abs_i); +} +#endif + /* Interface definitions */ #define LUA_FUNCTION_DEF(class, name) static int lua_ ## class ## _ ## name ( \ lua_State * L) @@ -133,15 +155,6 @@ void rspamd_lua_new_class (lua_State *L, const struct luaL_reg *methods); /** - * Create and register new class with static methods - */ -void rspamd_lua_new_class_full (lua_State *L, - const gchar *classname, - const gchar *static_name, - const struct luaL_reg *methods, - const struct luaL_reg *func); - -/** * Set class name for object at @param objidx position */ void rspamd_lua_setclass (lua_State *L, const gchar *classname, gint objidx); @@ -216,6 +229,9 @@ void rspamd_lua_task_push (lua_State *L, struct rspamd_task *task); struct rspamd_lua_ip *lua_check_ip (lua_State *L, gint pos); struct rspamd_lua_text *lua_check_text (lua_State *L, gint pos); +/* Creates and *pushes* new rspamd text, data is copied if RSPAMD_TEXT_FLAG_OWN is in flags*/ +struct rspamd_lua_text *lua_new_text (lua_State *L, const gchar *start, + gsize len, guint flags); struct rspamd_lua_regexp *lua_check_regexp (lua_State *L, gint pos); diff --git a/src/lua/lua_config.c b/src/lua/lua_config.c index 5c914af79..f047f1530 100644 --- a/src/lua/lua_config.c +++ b/src/lua/lua_config.c @@ -4157,7 +4157,12 @@ lua_config_init_subsystem (lua_State *L) rspamd_init_filters (cfg, FALSE); } else if (strcmp (parts[i], "langdet") == 0) { - cfg->lang_det = rspamd_language_detector_init (cfg); + if (!cfg->lang_det) { + cfg->lang_det = rspamd_language_detector_init (cfg); + rspamd_mempool_add_destructor (cfg->cfg_pool, + (rspamd_mempool_destruct_t) rspamd_language_detector_unref, + cfg->lang_det); + } } else if (strcmp (parts[i], "stat") == 0) { rspamd_stat_init (cfg, NULL); diff --git a/src/lua/lua_cryptobox.c b/src/lua/lua_cryptobox.c index 35faa0037..645b2495f 100644 --- a/src/lua/lua_cryptobox.c +++ b/src/lua/lua_cryptobox.c @@ -2437,54 +2437,20 @@ lua_load_cryptobox (lua_State * L) void luaopen_cryptobox (lua_State * L) { - luaL_newmetatable (L, "rspamd{cryptobox_pubkey}"); - lua_pushstring (L, "__index"); - lua_pushvalue (L, -2); - lua_settable (L, -3); - - lua_pushstring (L, "class"); - lua_pushstring (L, "rspamd{cryptobox_pubkey}"); - lua_rawset (L, -3); - - luaL_register (L, NULL, cryptoboxpubkeylib_m); + rspamd_lua_new_class (L, "rspamd{cryptobox_pubkey}", cryptoboxpubkeylib_m); + lua_pop (L, 1); rspamd_lua_add_preload (L, "rspamd_cryptobox_pubkey", lua_load_pubkey); - luaL_newmetatable (L, "rspamd{cryptobox_keypair}"); - lua_pushstring (L, "__index"); - lua_pushvalue (L, -2); - lua_settable (L, -3); - - lua_pushstring (L, "class"); - lua_pushstring (L, "rspamd{cryptobox_keypair}"); - lua_rawset (L, -3); - - luaL_register (L, NULL, cryptoboxkeypairlib_m); + rspamd_lua_new_class (L, "rspamd{cryptobox_keypair}", cryptoboxkeypairlib_m); + lua_pop (L, 1); rspamd_lua_add_preload (L, "rspamd_cryptobox_keypair", lua_load_keypair); - luaL_newmetatable (L, "rspamd{cryptobox_signature}"); - - lua_pushstring (L, "__index"); - lua_pushvalue (L, -2); - lua_settable (L, -3); - - lua_pushstring (L, "class"); - lua_pushstring (L, "rspamd{cryptobox_signature}"); - lua_rawset (L, -3); - - luaL_register (L, NULL, cryptoboxsignlib_m); + rspamd_lua_new_class (L, "rspamd{cryptobox_signature}", cryptoboxsignlib_m); + lua_pop (L, 1); rspamd_lua_add_preload (L, "rspamd_cryptobox_signature", lua_load_signature); - luaL_newmetatable (L, "rspamd{cryptobox_hash}"); - - lua_pushstring (L, "__index"); - lua_pushvalue (L, -2); - lua_settable (L, -3); - - lua_pushstring (L, "class"); - lua_pushstring (L, "rspamd{cryptobox_hash}"); - lua_rawset (L, -3); - - luaL_register (L, NULL, cryptoboxhashlib_m); + rspamd_lua_new_class (L, "rspamd{cryptobox_hash}", cryptoboxhashlib_m); + lua_pop (L, 1); rspamd_lua_add_preload (L, "rspamd_cryptobox_hash", lua_load_hash); rspamd_lua_add_preload (L, "rspamd_cryptobox", lua_load_cryptobox); diff --git a/src/lua/lua_dns_resolver.c b/src/lua/lua_dns_resolver.c index a4e3b4b03..75f7a3b6b 100644 --- a/src/lua/lua_dns_resolver.c +++ b/src/lua/lua_dns_resolver.c @@ -477,7 +477,6 @@ lua_dns_resolver_resolve_common (lua_State *L, if (ret) { cbdata->s = session; - if (item) { cbdata->item = item; rspamd_symcache_item_async_inc (task, item, M); @@ -486,7 +485,11 @@ lua_dns_resolver_resolve_common (lua_State *L, lua_pushboolean (L, TRUE); } else { - lua_pushnil (L); + if (item) { + rspamd_symcache_item_async_dec_check (task, item, M); + } + + goto err; } if (item) { @@ -506,6 +509,11 @@ err: g_free (cbdata->user_str); } + /* Callback is not called in this case */ + if (cbdata->cbref != -1) { + luaL_unref (L, LUA_REGISTRYINDEX, cbdata->cbref); + } + lua_pushnil (L); return 1; @@ -693,15 +701,7 @@ 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); - + 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); @@ -713,8 +713,7 @@ luaopen_dns_resolver (lua_State * L) 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); - lua_pop (L, 1); /* remove metatable from stack */ + rspamd_lua_add_preload (L, "rspamd_resolver", lua_load_dns_resolver); } diff --git a/src/lua/lua_expression.c b/src/lua/lua_expression.c index c0e75fe84..60ee8fdf7 100644 --- a/src/lua/lua_expression.c +++ b/src/lua/lua_expression.c @@ -511,17 +511,7 @@ lua_load_expression (lua_State * L) void luaopen_expression (lua_State * L) { - luaL_newmetatable (L, "rspamd{expr}"); - lua_pushstring (L, "__index"); - lua_pushvalue (L, -2); - lua_settable (L, -3); - - lua_pushstring (L, "class"); - lua_pushstring (L, "rspamd{expr}"); - lua_rawset (L, -3); - - luaL_register (L, NULL, exprlib_m); + rspamd_lua_new_class (L, "rspamd{expr}", exprlib_m); + lua_pop (L, 1); rspamd_lua_add_preload (L, "rspamd_expression", lua_load_expression); - - lua_pop (L, 1); /* remove metatable from stack */ } diff --git a/src/lua/lua_http.c b/src/lua/lua_http.c index ec42ab39e..d73bd7281 100644 --- a/src/lua/lua_http.c +++ b/src/lua/lua_http.c @@ -984,7 +984,8 @@ lua_http_request (lua_State *L) cbd->session = session; } - if (rspamd_parse_inet_address (&cbd->addr, msg->host->str, msg->host->len)) { + if (rspamd_parse_inet_address (&cbd->addr, + msg->host->str, msg->host->len, RSPAMD_INET_ADDRESS_PARSE_DEFAULT)) { /* Host is numeric IP, no need to resolve */ gboolean ret; diff --git a/src/lua/lua_ip.c b/src/lua/lua_ip.c index 3c3ef2d51..f873c4515 100644 --- a/src/lua/lua_ip.c +++ b/src/lua/lua_ip.c @@ -369,13 +369,15 @@ lua_ip_from_string (lua_State *L) LUA_TRACE_POINT; struct rspamd_lua_ip *ip; const gchar *ip_str; + gsize len; - ip_str = luaL_checkstring (L, 1); + ip_str = luaL_checklstring (L, 1, &len); if (ip_str) { ip = lua_ip_new (L, NULL); - if (!rspamd_parse_inet_address (&ip->addr, ip_str, 0)) { - msg_warn ("cannot parse ip: %s", ip_str); + if (!rspamd_parse_inet_address (&ip->addr, + ip_str, len, RSPAMD_INET_ADDRESS_PARSE_DEFAULT)) { + msg_warn ("cannot parse ip: %*s", (gint) len, ip_str); ip->addr = NULL; } } @@ -490,7 +492,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, TRUE); + res = rspamd_inet_address_compare (ip1->addr, ip2->addr, TRUE) == 0; } lua_pushboolean (L, res); @@ -559,7 +561,8 @@ rspamd_lua_ip_push_fromstring (lua_State *L, const gchar *ip_str) else { ip = g_malloc0 (sizeof (struct rspamd_lua_ip)); - if (rspamd_parse_inet_address (&ip->addr, ip_str, 0)) { + if (rspamd_parse_inet_address (&ip->addr, + ip_str, strlen (ip_str), RSPAMD_INET_ADDRESS_PARSE_DEFAULT)) { pip = lua_newuserdata (L, sizeof (struct rspamd_lua_ip *)); rspamd_lua_setclass (L, "rspamd{ip}", -1); @@ -584,17 +587,7 @@ lua_load_ip (lua_State * L) void luaopen_ip (lua_State * L) { - luaL_newmetatable (L, "rspamd{ip}"); - lua_pushstring (L, "__index"); - lua_pushvalue (L, -2); - lua_settable (L, -3); - - lua_pushstring (L, "class"); - lua_pushstring (L, "rspamd{ip}"); - lua_rawset (L, -3); - - luaL_register (L, NULL, iplib_m); - rspamd_lua_add_preload (L, "rspamd_ip", lua_load_ip); - + rspamd_lua_new_class (L, "rspamd{ip}", iplib_m); lua_pop (L, 1); + rspamd_lua_add_preload (L, "rspamd_ip", lua_load_ip); } diff --git a/src/lua/lua_logger.c b/src/lua/lua_logger.c index bca4bc6e3..f76db8877 100644 --- a/src/lua/lua_logger.c +++ b/src/lua/lua_logger.c @@ -575,31 +575,34 @@ lua_logger_out_type (lua_State *L, gint pos, trace->cur_level ++; switch (type) { - case LUA_TNUMBER: - r = lua_logger_out_num (L, pos, outbuf, len, trace); - break; - case LUA_TBOOLEAN: - r = lua_logger_out_boolean (L, pos, outbuf, len, trace); - break; - case LUA_TTABLE: - r = lua_logger_out_table (L, pos, outbuf, len, trace, esc_type); - break; - case LUA_TUSERDATA: - r = lua_logger_out_userdata (L, pos, outbuf, len, trace); - break; - case LUA_TFUNCTION: - r = rspamd_snprintf (outbuf, len + 1, "function"); - break; - case LUA_TNIL: - r = rspamd_snprintf (outbuf, len + 1, "nil"); - break; - case LUA_TNONE: - r = rspamd_snprintf (outbuf, len + 1, "no value"); - break; - default: - /* Try to push everything as string using tostring magic */ - r = lua_logger_out_str (L, pos, outbuf, len, trace, esc_type); - break; + case LUA_TNUMBER: + r = lua_logger_out_num (L, pos, outbuf, len, trace); + break; + case LUA_TBOOLEAN: + r = lua_logger_out_boolean (L, pos, outbuf, len, trace); + break; + case LUA_TTABLE: + r = lua_logger_out_table (L, pos, outbuf, len, trace, esc_type); + break; + case LUA_TUSERDATA: + r = lua_logger_out_userdata (L, pos, outbuf, len, trace); + break; + case LUA_TFUNCTION: + r = rspamd_snprintf (outbuf, len + 1, "function"); + break; + case LUA_TLIGHTUSERDATA: + r = rspamd_snprintf (outbuf, len + 1, "0x%p", lua_topointer (L, pos)); + break; + case LUA_TNIL: + r = rspamd_snprintf (outbuf, len + 1, "nil"); + break; + case LUA_TNONE: + r = rspamd_snprintf (outbuf, len + 1, "no value"); + break; + default: + /* Try to push everything as string using tostring magic */ + r = lua_logger_out_str (L, pos, outbuf, len, trace, esc_type); + break; } trace->cur_level --; diff --git a/src/lua/lua_mempool.c b/src/lua/lua_mempool.c index 62d294111..06dcd2d5c 100644 --- a/src/lua/lua_mempool.c +++ b/src/lua/lua_mempool.c @@ -582,17 +582,7 @@ lua_load_mempool (lua_State * L) void luaopen_mempool (lua_State * L) { - luaL_newmetatable (L, "rspamd{mempool}"); - lua_pushstring (L, "__index"); - lua_pushvalue (L, -2); - lua_settable (L, -3); - - lua_pushstring (L, "class"); - lua_pushstring (L, "rspamd{mempool}"); - lua_rawset (L, -3); - - luaL_register (L, NULL, mempoollib_m); + rspamd_lua_new_class (L, "rspamd{mempool}", mempoollib_m); + lua_pop (L, 1); rspamd_lua_add_preload (L, "rspamd_mempool", lua_load_mempool); - - lua_pop (L, 1); /* remove metatable from stack */ } diff --git a/src/lua/lua_mimepart.c b/src/lua/lua_mimepart.c index dfc4ee8fa..01c64ae64 100644 --- a/src/lua/lua_mimepart.c +++ b/src/lua/lua_mimepart.c @@ -365,19 +365,26 @@ LUA_FUNCTION_DEF (mimepart, get_type_full); /*** * @method mime_part:get_detected_type() - * Extract content-type string of the mime part. Use libmagic detection + * Extract content-type string of the mime part. Use lua_magic detection * @return {string,string} content type in form 'type','subtype' */ LUA_FUNCTION_DEF (mimepart, get_detected_type); /*** * @method mime_part:get_detected_type_full() - * Extract content-type string of the mime part with all attributes. Use libmagic detection + * Extract content-type string of the mime part with all attributes. Use lua_magic detection * @return {string,string,table} content type in form 'type','subtype', {attrs} */ LUA_FUNCTION_DEF (mimepart, get_detected_type_full); /*** + * @method mime_part:get_detected_ext() + * Returns a msdos extension name according to lua_magic detection + * @return {string} detected extension (see lua_magic.types) + */ +LUA_FUNCTION_DEF (mimepart, get_detected_ext); + +/*** * @method mime_part:get_cte() * Extract content-transfer-encoding for a part * @return {string} content transfer encoding (e.g. `base64` or `7bit`) @@ -523,6 +530,7 @@ static const struct luaL_reg mimepartlib_m[] = { LUA_INTERFACE_DEF (mimepart, get_type), LUA_INTERFACE_DEF (mimepart, get_type_full), LUA_INTERFACE_DEF (mimepart, get_detected_type), + LUA_INTERFACE_DEF (mimepart, get_detected_ext), LUA_INTERFACE_DEF (mimepart, get_detected_type_full), LUA_INTERFACE_DEF (mimepart, get_cte), LUA_INTERFACE_DEF (mimepart, get_filename), @@ -1495,6 +1503,26 @@ lua_mimepart_get_detected_type_full (lua_State * L) } static gint +lua_mimepart_get_detected_ext (lua_State * L) +{ + LUA_TRACE_POINT; + struct rspamd_mime_part *part = lua_check_mimepart (L); + + if (part == NULL) { + return luaL_error (L, "invalid arguments"); + } + + if (part->detected_ext) { + lua_pushstring (L, part->detected_ext); + } + else { + lua_pushnil (L); + } + + return 1; +} + +static gint lua_mimepart_get_cte (lua_State * L) { LUA_TRACE_POINT; @@ -1702,7 +1730,7 @@ lua_mimepart_is_attachment (lua_State * L) return luaL_error (L, "invalid arguments"); } - if (!(part->flags & (RSPAMD_MIME_PART_IMAGE|RSPAMD_MIME_PART_TEXT))) { + if (!(part->flags & (RSPAMD_MIME_PART_IMAGE))) { if (part->cd && part->cd->type == RSPAMD_CT_ATTACHMENT) { lua_pushboolean (L, true); } diff --git a/src/lua/lua_redis.c b/src/lua/lua_redis.c index ac1a8c297..32fa55476 100644 --- a/src/lua/lua_redis.c +++ b/src/lua/lua_redis.c @@ -896,7 +896,8 @@ rspamd_lua_redis_prepare_connection (lua_State *L, gint *pcbref, gboolean is_asy else if (lua_type (L, -1) == LUA_TSTRING) { host = lua_tostring (L, -1); - if (rspamd_parse_inet_address (&ip, host, strlen (host))) { + if (rspamd_parse_inet_address (&ip, + host, strlen (host), RSPAMD_INET_ADDRESS_PARSE_DEFAULT)) { addr = g_alloca (sizeof (*addr)); addr->addr = ip; @@ -1165,7 +1166,8 @@ lua_redis_make_request_sync (lua_State *L) } else if (lua_type (L, -1) == LUA_TSTRING) { host = lua_tostring (L, -1); - if (rspamd_parse_inet_address (&ip, host, strlen (host))) { + if (rspamd_parse_inet_address (&ip, + host, strlen (host), RSPAMD_INET_ADDRESS_PARSE_DEFAULT)) { addr = g_alloca (sizeof (*addr)); addr->addr = ip; @@ -1603,17 +1605,7 @@ lua_load_redis (lua_State * L) void luaopen_redis (lua_State * L) { - luaL_newmetatable (L, "rspamd{redis}"); - lua_pushstring (L, "__index"); - lua_pushvalue (L, -2); - lua_settable (L, -3); - - lua_pushstring (L, "class"); - lua_pushstring (L, "rspamd{redis}"); - lua_rawset (L, -3); - - luaL_register (L, NULL, redislib_m); + rspamd_lua_new_class (L, "rspamd{redis}", redislib_m); lua_pop (L, 1); - rspamd_lua_add_preload (L, "rspamd_redis", lua_load_redis); } diff --git a/src/lua/lua_regexp.c b/src/lua/lua_regexp.c index 4033722a3..ae1f2007a 100644 --- a/src/lua/lua_regexp.c +++ b/src/lua/lua_regexp.c @@ -543,7 +543,7 @@ lua_regexp_search (lua_State *L) raw = lua_toboolean (L, 3); } - if (data) { + if (data && len > 0) { if (lua_gettop (L) >= 4) { capture = TRUE; captures = g_array_new (FALSE, TRUE, @@ -588,12 +588,14 @@ lua_regexp_search (lua_State *L) if (capture) { g_array_free (captures, TRUE); } - - return 1; + } + else { + lua_pushnil (L); } } - - lua_pushnil (L); + else { + return luaL_error (L, "invalid arguments"); + } return 1; } @@ -633,7 +635,7 @@ lua_regexp_match (lua_State *L) raw = lua_toboolean (L, 3); } - if (data) { + if (data && len > 0) { if (re->match_limit > 0) { len = MIN (len, re->match_limit); } @@ -644,11 +646,14 @@ lua_regexp_match (lua_State *L) else { lua_pushboolean (L, FALSE); } - return 1; + } + else { + lua_pushboolean (L, FALSE); } } - - lua_pushnil (L); + else { + return luaL_error (L, "invalid arguments"); + } return 1; } @@ -689,13 +694,13 @@ lua_regexp_matchn (lua_State *L) } max_matches = lua_tointeger (L, 3); + matches = 0; if (lua_gettop (L) == 4) { raw = lua_toboolean (L, 4); } - if (data) { - matches = 0; + if (data && len > 0) { if (re->match_limit > 0) { len = MIN (len, re->match_limit); @@ -714,14 +719,14 @@ lua_regexp_matchn (lua_State *L) break; } } - - lua_pushinteger (L, matches); - - return 1; } + + lua_pushinteger (L, matches); + } + else { + return luaL_error (L, "invalid arguments"); } - lua_pushnil (L); return 1; } @@ -770,10 +775,11 @@ lua_regexp_split (lua_State *L) len = MIN (len, re->match_limit); } - if (data) { + if (data && len > 0) { lua_newtable (L); i = 0; old_start = data; + while (rspamd_regexp_search (re->re, data, len, &start, &end, FALSE, NULL)) { if (start - old_start > 0) { @@ -824,6 +830,9 @@ lua_regexp_split (lua_State *L) return 1; } } + else { + return luaL_error (L, "invalid arguments"); + } lua_pushnil (L); return 1; @@ -880,22 +889,16 @@ lua_load_regexp (lua_State * L) void luaopen_regexp (lua_State * L) { - luaL_newmetatable (L, "rspamd{regexp}"); - lua_pushstring (L, "__index"); - lua_pushvalue (L, -2); - lua_settable (L, -3); - - lua_pushstring (L, "class"); - lua_pushstring (L, "rspamd{regexp}"); - lua_rawset (L, -3); - - luaL_register (L, NULL, regexplib_m); + rspamd_lua_new_class (L, "rspamd{regexp}", regexplib_m); + lua_pop (L, 1); rspamd_lua_add_preload (L, "rspamd_regexp", lua_load_regexp); +} - if (regexp_static_pool == NULL) { - regexp_static_pool = rspamd_mempool_new (rspamd_mempool_suggest_size (), - "regexp_lua_pool"); - } - - lua_settop (L, 0); +RSPAMD_CONSTRUCTOR (lua_re_static_pool_ctor) { + regexp_static_pool = rspamd_mempool_new (rspamd_mempool_suggest_size (), + "regexp_lua_pool"); } + +RSPAMD_DESTRUCTOR (lua_re_static_pool_dtor) { + rspamd_mempool_delete (regexp_static_pool); +}
\ No newline at end of file diff --git a/src/lua/lua_rsa.c b/src/lua/lua_rsa.c index 58607f92c..4b2caa2bf 100644 --- a/src/lua/lua_rsa.c +++ b/src/lua/lua_rsa.c @@ -719,40 +719,16 @@ lua_load_rsa (lua_State * L) void luaopen_rsa (lua_State * L) { - luaL_newmetatable (L, "rspamd{rsa_pubkey}"); - lua_pushstring (L, "__index"); - lua_pushvalue (L, -2); - lua_settable (L, -3); - - lua_pushstring (L, "class"); - lua_pushstring (L, "rspamd{rsa_pubkey}"); - lua_rawset (L, -3); - - luaL_register (L, NULL, rsapubkeylib_m); + rspamd_lua_new_class (L, "rspamd{rsa_pubkey}", rsapubkeylib_m); + lua_pop (L, 1); rspamd_lua_add_preload (L, "rspamd_rsa_pubkey", lua_load_pubkey); - luaL_newmetatable (L, "rspamd{rsa_privkey}"); - lua_pushstring (L, "__index"); - lua_pushvalue (L, -2); - lua_settable (L, -3); - - lua_pushstring (L, "class"); - lua_pushstring (L, "rspamd{rsa_privkey}"); - lua_rawset (L, -3); - - luaL_register (L, NULL, rsaprivkeylib_m); + rspamd_lua_new_class (L, "rspamd{rsa_privkey}", rsaprivkeylib_m); + lua_pop (L, 1); rspamd_lua_add_preload (L, "rspamd_rsa_privkey", lua_load_privkey); - luaL_newmetatable (L, "rspamd{rsa_signature}"); - lua_pushstring (L, "__index"); - lua_pushvalue (L, -2); - lua_settable (L, -3); - - lua_pushstring (L, "class"); - lua_pushstring (L, "rspamd{rsa_signature}"); - lua_rawset (L, -3); - - luaL_register (L, NULL, rsasignlib_m); + rspamd_lua_new_class (L, "rspamd{rsa_signature}", rsasignlib_m); + lua_pop (L, 1); rspamd_lua_add_preload (L, "rspamd_rsa_signature", lua_load_signature); rspamd_lua_add_preload (L, "rspamd_rsa", lua_load_rsa); diff --git a/src/lua/lua_sqlite3.c b/src/lua/lua_sqlite3.c index 87d798666..95104d1b0 100644 --- a/src/lua/lua_sqlite3.c +++ b/src/lua/lua_sqlite3.c @@ -373,28 +373,10 @@ lua_load_sqlite3 (lua_State * L) void luaopen_sqlite3 (lua_State * L) { - luaL_newmetatable (L, "rspamd{sqlite3}"); - lua_pushstring (L, "__index"); - lua_pushvalue (L, -2); - lua_settable (L, -3); - - lua_pushstring (L, "class"); - lua_pushstring (L, "rspamd{sqlite3}"); - lua_rawset (L, -3); - - luaL_register (L, NULL, sqlitelib_m); + rspamd_lua_new_class (L, "rspamd{sqlite3}", sqlitelib_m); lua_pop (L, 1); - luaL_newmetatable (L, "rspamd{sqlite3_stmt}"); - lua_pushstring (L, "__index"); - lua_pushvalue (L, -2); - lua_settable (L, -3); - - lua_pushstring (L, "class"); - lua_pushstring (L, "rspamd{sqlite3_stmt}"); - lua_rawset (L, -3); - - luaL_register (L, NULL, sqlitestmtlib_m); + rspamd_lua_new_class (L, "rspamd{sqlite3_stmt}", sqlitestmtlib_m); lua_pop (L, 1); rspamd_lua_add_preload (L, "rspamd_sqlite3", lua_load_sqlite3); diff --git a/src/lua/lua_task.c b/src/lua/lua_task.c index 1664e415f..2ec6dc29b 100644 --- a/src/lua/lua_task.c +++ b/src/lua/lua_task.c @@ -200,9 +200,10 @@ end */ LUA_FUNCTION_DEF (task, append_message); /*** - * @method task:get_urls([need_emails|list_protos]) + * @method task:get_urls([need_emails|list_protos][, need_images]) * Get all URLs found in a message. Telephone urls and emails are not included unless explicitly asked in `list_protos` * @param {boolean} need_emails if `true` then reutrn also email urls, this can be a comma separated string of protocols desired or a table (e.g. `mailto` or `telephone`) + * @param {boolean} need_images return urls from images (<img src=...>) as well * @return {table rspamd_url} list of all urls found @example local function phishing_cb(task) @@ -646,6 +647,14 @@ LUA_FUNCTION_DEF (task, get_symbols_all); LUA_FUNCTION_DEF (task, get_symbols); /*** + * @method task:get_groups([need_private]) + * Returns a map [group -> group_score] for matched group. If `need_private` is + * unspecified, then the global option `public_groups_only` is used for default. + * @return {table, number} a map [group -> group_score] + */ +LUA_FUNCTION_DEF (task, get_groups); + +/*** * @method task:get_symbols_numeric() * Returns array of all symbols matched for this task * @return {table|number, table|number} table of numbers with symbols ids + table of theirs scores @@ -1149,6 +1158,7 @@ static const struct luaL_reg tasklib_m[] = { LUA_INTERFACE_DEF (task, get_symbols_all), LUA_INTERFACE_DEF (task, get_symbols_numeric), LUA_INTERFACE_DEF (task, get_symbols_tokens), + LUA_INTERFACE_DEF (task, get_groups), LUA_INTERFACE_DEF (task, process_ann_tokens), LUA_INTERFACE_DEF (task, has_symbol), LUA_INTERFACE_DEF (task, enable_symbol), @@ -1262,14 +1272,6 @@ lua_check_archive (lua_State * L) return ud ? *((struct rspamd_archive **)ud) : NULL; } -struct rspamd_lua_text * -lua_check_text (lua_State * L, gint pos) -{ - void *ud = rspamd_lua_check_udata (L, pos, "rspamd{text}"); - luaL_argcheck (L, ud != NULL, pos, "'text' expected"); - return ud ? (struct rspamd_lua_text *)ud : NULL; -} - static void lua_task_set_cached (lua_State *L, struct rspamd_task *task, const gchar *key, gint pos) @@ -1668,8 +1670,9 @@ lua_task_load_from_string (lua_State * L) } task = rspamd_task_new (NULL, cfg, NULL, NULL, NULL); - task->msg.begin = g_strdup (str_message); - task->msg.len = message_len; + task->msg.begin = g_malloc (message_len); + memcpy ((gchar *)task->msg.begin, str_message, message_len); + task->msg.len = message_len; rspamd_mempool_add_destructor (task->task_pool, lua_task_free_dtor, (gpointer)task->msg.begin); } @@ -2099,6 +2102,7 @@ struct lua_tree_cb_data { lua_State *L; int i; gint mask; + gint need_images; }; static void @@ -2109,6 +2113,10 @@ lua_tree_url_callback (gpointer key, gpointer value, gpointer ud) struct lua_tree_cb_data *cb = ud; if (url->protocol & cb->mask) { + if (!cb->need_images && (url->flags & RSPAMD_URL_FLAG_IMAGE)) { + return; + } + lua_url = lua_newuserdata (cb->L, sizeof (struct rspamd_lua_url)); rspamd_lua_setclass (cb->L, "rspamd{url}", -1); lua_url->url = url; @@ -2125,6 +2133,8 @@ lua_task_get_urls (lua_State * L) gint protocols_mask = 0; static const gint default_mask = PROTOCOL_HTTP|PROTOCOL_HTTPS| PROTOCOL_FILE|PROTOCOL_FTP; + const gchar *cache_name = "emails+urls"; + gboolean need_images = FALSE; gsize sz; if (task) { @@ -2184,29 +2194,42 @@ lua_task_get_urls (lua_State * L) else { protocols_mask = default_mask; } + + if (lua_type (L, 3) == LUA_TBOOLEAN) { + need_images = lua_toboolean (L, 3); + } } else { protocols_mask = default_mask; } + memset (&cb, 0, sizeof (cb)); cb.i = 1; cb.L = L; cb.mask = protocols_mask; + cb.need_images = need_images; if (protocols_mask & PROTOCOL_MAILTO) { + if (need_images) { + cache_name = "emails+urls+img"; + } + else { + cache_name = "emails+urls"; + } + sz = g_hash_table_size (MESSAGE_FIELD (task, urls)) + g_hash_table_size (MESSAGE_FIELD (task, emails)); if (protocols_mask == (default_mask|PROTOCOL_MAILTO)) { /* Can use cached version */ - if (!lua_task_get_cached (L, task, "emails+urls")) { + if (!lua_task_get_cached (L, task, cache_name)) { lua_createtable (L, sz, 0); g_hash_table_foreach (MESSAGE_FIELD (task, urls), lua_tree_url_callback, &cb); g_hash_table_foreach (MESSAGE_FIELD (task, emails), lua_tree_url_callback, &cb); - lua_task_set_cached (L, task, "emails+urls", -1); + lua_task_set_cached (L, task, cache_name, -1); } } else { @@ -2219,14 +2242,21 @@ lua_task_get_urls (lua_State * L) } else { + if (need_images) { + cache_name = "urls+img"; + } + else { + cache_name = "urls"; + } + sz = g_hash_table_size (MESSAGE_FIELD (task, urls)); if (protocols_mask == (default_mask)) { - if (!lua_task_get_cached (L, task, "urls")) { + if (!lua_task_get_cached (L, task, cache_name)) { lua_createtable (L, sz, 0); g_hash_table_foreach (MESSAGE_FIELD (task, urls), lua_tree_url_callback, &cb); - lua_task_set_cached (L, task, "urls", -1); + lua_task_set_cached (L, task, cache_name, -1); } } else { @@ -2386,6 +2416,7 @@ lua_task_get_emails (lua_State * L) if (task) { if (task->message) { lua_createtable (L, g_hash_table_size (MESSAGE_FIELD (task, emails)), 0); + memset (&cb, 0, sizeof (cb)); cb.i = 1; cb.L = L; cb.mask = PROTOCOL_MAILTO; @@ -3437,6 +3468,7 @@ lua_task_set_recipients (lua_State *L) } \ else { \ ret = addr->len > 0; \ + nrcpt = addr->len; \ } \ } while (0) @@ -3445,7 +3477,7 @@ lua_task_has_from (lua_State *L) { LUA_TRACE_POINT; struct rspamd_task *task = lua_check_task (L, 1); - gint what = 0; + gint what = 0, nrcpt = 0; gboolean ret = FALSE; if (task) { @@ -3487,7 +3519,7 @@ lua_task_has_recipients (lua_State *L) { LUA_TRACE_POINT; struct rspamd_task *task = lua_check_task (L, 1); - gint what = 0; + gint what = 0, nrcpt = 0; gboolean ret = FALSE; if (task) { @@ -3521,6 +3553,11 @@ lua_task_has_recipients (lua_State *L) lua_pushboolean (L, ret); + if (ret) { + lua_pushinteger (L, nrcpt); + return 2; + } + return 1; } @@ -3819,7 +3856,8 @@ lua_task_set_from_ip (lua_State *L) { LUA_TRACE_POINT; struct rspamd_task *task = lua_check_task (L, 1); - const gchar *ip_str = luaL_checkstring (L, 2); + gsize len; + const gchar *ip_str = luaL_checklstring (L, 2, &len); rspamd_inet_addr_t *addr = NULL; if (!task || !ip_str) { @@ -3829,7 +3867,8 @@ lua_task_set_from_ip (lua_State *L) else { if (!rspamd_parse_inet_address (&addr, ip_str, - 0)) { + len, + RSPAMD_INET_ADDRESS_PARSE_DEFAULT)) { msg_warn_task ("cannot get IP from received header: '%s'", ip_str); } @@ -4444,6 +4483,46 @@ lua_task_get_symbols_numeric (lua_State *L) return 2; } +static gint +lua_task_get_groups (lua_State *L) +{ + LUA_TRACE_POINT; + struct rspamd_task *task = lua_check_task (L, 1); + gboolean need_private; + struct rspamd_scan_result *mres; + struct rspamd_symbols_group *gr; + gdouble gr_score; + + if (task) { + mres = task->result; + + if (lua_isboolean (L, 2)) { + need_private = lua_toboolean (L, 2); + } + else { + need_private = !(task->cfg->public_groups_only); + } + + lua_createtable (L, 0, kh_size (mres->sym_groups)); + + kh_foreach (mres->sym_groups, gr, gr_score, { + if (!(gr->flags & RSPAMD_SYMBOL_GROUP_PUBLIC)) { + if (!need_private) { + continue; + } + } + + lua_pushnumber (L, gr_score); + lua_setfield (L, -2, gr->name); + }); + } + else { + return luaL_error (L, "invalid arguments"); + } + + return 1; +} + struct tokens_foreach_cbdata { struct rspamd_task *task; lua_State *L; diff --git a/src/lua/lua_tcp.c b/src/lua/lua_tcp.c index 10c57cea4..379d3d807 100644 --- a/src/lua/lua_tcp.c +++ b/src/lua/lua_tcp.c @@ -1760,7 +1760,8 @@ lua_tcp_request (lua_State *L) } } - if (rspamd_parse_inet_address (&cbd->addr, host, 0)) { + if (rspamd_parse_inet_address (&cbd->addr, + host, strlen (host), RSPAMD_INET_ADDRESS_PARSE_DEFAULT)) { rspamd_inet_address_set_port (cbd->addr, port); /* Host is numeric IP, no need to resolve */ lua_tcp_register_watcher (cbd); @@ -1942,7 +1943,8 @@ lua_tcp_connect_sync (lua_State *L) } } - if (rspamd_parse_inet_address (&cbd->addr, host, 0)) { + if (rspamd_parse_inet_address (&cbd->addr, + host, strlen (host), RSPAMD_INET_ADDRESS_PARSE_DEFAULT)) { rspamd_inet_address_set_port (cbd->addr, (guint16)port); /* Host is numeric IP, no need to resolve */ if (!lua_tcp_make_connection (cbd)) { diff --git a/src/lua/lua_text.c b/src/lua/lua_text.c index ab52bd32d..63b1b22a8 100644 --- a/src/lua/lua_text.c +++ b/src/lua/lua_text.c @@ -65,6 +65,28 @@ LUA_FUNCTION_DEF (text, ptr); * @return {boolean} true if save has been completed */ LUA_FUNCTION_DEF (text, save_in_file); +/*** + * @method rspamd_text:span(start[, len]) + * Returns a span for lua_text starting at pos [start] (1 indexed) and with + * length `len` (or to the end of the text) + * @param {integer} start start index + * @param {integer} len length of span + * @return {rspamd_text} new rspamd_text with span (must be careful when using with owned texts...) + */ +LUA_FUNCTION_DEF (text, span); +/*** + * @method rspamd_text:at(pos) + * Returns a byte at the position `pos` + * @param {integer} pos index + * @return {integer} byte at the position `pos` or nil if pos out of bound + */ +LUA_FUNCTION_DEF (text, at); +/*** + * @method rspamd_text:bytes() + * Converts text to an array of bytes + * @return {table|integer} bytes in the array (as unsigned char) + */ +LUA_FUNCTION_DEF (text, bytes); LUA_FUNCTION_DEF (text, take_ownership); LUA_FUNCTION_DEF (text, gc); LUA_FUNCTION_DEF (text, eq); @@ -81,6 +103,9 @@ static const struct luaL_reg textlib_m[] = { LUA_INTERFACE_DEF (text, ptr), LUA_INTERFACE_DEF (text, take_ownership), LUA_INTERFACE_DEF (text, save_in_file), + LUA_INTERFACE_DEF (text, span), + LUA_INTERFACE_DEF (text, at), + LUA_INTERFACE_DEF (text, bytes), {"write", lua_text_save_in_file}, {"__len", lua_text_len}, {"__tostring", lua_text_str}, @@ -89,23 +114,56 @@ static const struct luaL_reg textlib_m[] = { {NULL, NULL} }; +struct rspamd_lua_text * +lua_check_text (lua_State * L, gint pos) +{ + void *ud = rspamd_lua_check_udata (L, pos, "rspamd{text}"); + luaL_argcheck (L, ud != NULL, pos, "'text' expected"); + return ud ? (struct rspamd_lua_text *)ud : NULL; +} + +struct rspamd_lua_text * +lua_new_text (lua_State *L, const gchar *start, gsize len, guint flags) +{ + struct rspamd_lua_text *t; + + t = lua_newuserdata (L, sizeof (*t)); + + if (len > 0 && (flags & RSPAMD_TEXT_FLAG_OWN)) { + gchar *storage; + + storage = g_malloc (len); + memcpy (storage, start, len); + t->start = storage; + } + else { + t->start = start; + } + + t->len = len; + t->flags = flags; + rspamd_lua_setclass (L, "rspamd{text}", -1); + + return t; +} + + static gint lua_text_fromstring (lua_State *L) { LUA_TRACE_POINT; const gchar *str; gsize l = 0; - struct rspamd_lua_text *t; + gboolean transparent = FALSE; str = luaL_checklstring (L, 1, &l); if (str) { - t = lua_newuserdata (L, sizeof (*t)); - t->start = g_malloc (l + 1); - rspamd_strlcpy ((char *)t->start, str, l + 1); - t->len = l; - t->flags = RSPAMD_TEXT_FLAG_OWN; - rspamd_lua_setclass (L, "rspamd{text}", -1); + if (lua_isboolean (L, 2)) { + transparent = lua_toboolean (L, 2); + } + + lua_new_text (L, str, l, transparent ? 0 : RSPAMD_TEXT_FLAG_OWN); } else { return luaL_error (L, "invalid arguments"); @@ -271,6 +329,77 @@ lua_text_take_ownership (lua_State *L) } static gint +lua_text_span (lua_State *L) +{ + LUA_TRACE_POINT; + struct rspamd_lua_text *t = lua_check_text (L, 1); + gint start = lua_tointeger (L, 2), len = -1; + + if (t && start >= 1 && start <= t->len) { + if (lua_isnumber (L, 3)) { + len = lua_tonumber (L, 3); + } + + if (len == -1) { + len = t->len - (start - 1); + } + else if (len > (t->len - (start - 1))) { + return luaL_error (L, "invalid length"); + } + + lua_new_text (L, t->start + (start - 1), len, 0); + } + else { + return luaL_error (L, "invalid arguments"); + } + + return 1; +} + +static gint +lua_text_at (lua_State *L) +{ + LUA_TRACE_POINT; + struct rspamd_lua_text *t = lua_check_text (L, 1); + gint pos = lua_tointeger (L, 2); + + if (t) { + if (pos > 0 && pos <= t->len) { + lua_pushinteger (L, t->start[pos - 1]); + } + else { + lua_pushnil (L); + } + } + else { + return luaL_error (L, "invalid arguments"); + } + + return 1; +} + +static gint +lua_text_bytes (lua_State *L) +{ + LUA_TRACE_POINT; + struct rspamd_lua_text *t = lua_check_text (L, 1); + + if (t) { + lua_createtable (L, t->len, 0); + + for (gsize i = 0; i < t->len; i ++) { + lua_pushinteger (L, (guchar)t->start[i]); + lua_rawseti (L, -2, i + 1); + } + } + else { + return luaL_error (L, "invalid arguments"); + } + + return 1; +} + +static gint lua_text_save_in_file (lua_State *L) { LUA_TRACE_POINT; diff --git a/src/lua/lua_trie.c b/src/lua/lua_trie.c index bc90fef27..a1b0de118 100644 --- a/src/lua/lua_trie.c +++ b/src/lua/lua_trie.c @@ -81,7 +81,7 @@ lua_trie_destroy (lua_State *L) } /*** - * function trie.create(patterns) + * function trie.create(patterns, [flags]) * Creates new trie data structure * @param {table} array of string patterns * @return {trie} new trie object @@ -93,9 +93,12 @@ lua_trie_create (lua_State *L) gint npat = 0, flags = RSPAMD_MULTIPATTERN_ICASE|RSPAMD_MULTIPATTERN_GLOB; GError *err = NULL; + if (lua_isnumber (L, 2)) { + flags = lua_tointeger (L, 2); + } + if (!lua_istable (L, 1)) { - msg_err ("lua trie expects array of patterns for now"); - lua_pushnil (L); + return luaL_error (L, "lua trie expects array of patterns for now"); } else { lua_pushvalue (L, 1); @@ -142,6 +145,7 @@ lua_trie_create (lua_State *L) return 1; } +/* Normal callback type */ static gint lua_trie_callback (struct rspamd_multipattern *mp, guint strnum, @@ -173,18 +177,54 @@ lua_trie_callback (struct rspamd_multipattern *mp, return ret; } +/* Table like callback, expect result table on top of the stack */ +static gint +lua_trie_table_callback (struct rspamd_multipattern *mp, + guint strnum, + gint match_start, + gint textpos, + const gchar *text, + gsize len, + void *context) +{ + lua_State *L = context; + + /* Set table, indexed by pattern number */ + lua_rawgeti (L, -1, strnum + 1); + + if (lua_istable (L, -1)) { + /* Already have table, add offset */ + gsize last = rspamd_lua_table_size (L, -1); + lua_pushinteger (L, textpos); + lua_rawseti (L, -2, last + 1); + /* Remove table from the stack */ + lua_pop (L, 1); + } + else { + /* Pop none */ + lua_pop (L, 1); + /* New table */ + lua_newtable (L); + lua_pushinteger (L, textpos); + lua_rawseti (L, -2, 1); + lua_rawseti (L, -2, strnum + 1); + } + + return 0; +} + /* * We assume that callback argument is at pos 3 and icase is in position 4 */ static gint lua_trie_search_str (lua_State *L, struct rspamd_multipattern *trie, - const gchar *str, gsize len) + const gchar *str, gsize len, rspamd_multipattern_cb_t cb) { gint ret; guint nfound = 0; if ((ret = rspamd_multipattern_lookup (trie, str, len, - lua_trie_callback, L, &nfound)) == 0) { + cb, L, &nfound)) == 0) { return nfound; } @@ -192,12 +232,11 @@ lua_trie_search_str (lua_State *L, struct rspamd_multipattern *trie, } /*** - * @method trie:match(input, cb[, caseless]) + * @method trie:match(input, [cb]) * Search for patterns in `input` invoking `cb` optionally ignoring case * @param {table or string} input one or several (if `input` is an array) strings of input text * @param {function} cb callback called on each pattern match in form `function (idx, pos)` where `idx` is a numeric index of pattern (starting from 1) and `pos` is a numeric offset where the pattern ends - * @param {boolean} caseless if `true` then match ignores symbols case (ASCII only) - * @return {boolean} `true` if any pattern has been found (`cb` might be called multiple times however) + * @return {boolean} `true` if any pattern has been found (`cb` might be called multiple times however). If `cb` is not defined then it returns a table of match positions indexed by pattern number */ static gint lua_trie_match (lua_State *L) @@ -207,8 +246,16 @@ lua_trie_match (lua_State *L) const gchar *text; gsize len; gboolean found = FALSE; + struct rspamd_lua_text *t; + rspamd_multipattern_cb_t cb = lua_trie_callback; if (trie) { + if (lua_type (L, 3) != LUA_TFUNCTION) { + /* Table like match */ + lua_newtable (L); + cb = lua_trie_table_callback; + } + if (lua_type (L, 2) == LUA_TTABLE) { lua_pushvalue (L, 2); lua_pushnil (L); @@ -217,10 +264,19 @@ lua_trie_match (lua_State *L) if (lua_isstring (L, -1)) { text = lua_tolstring (L, -1, &len); - if (lua_trie_search_str (L, trie, text, len)) { + if (lua_trie_search_str (L, trie, text, len, cb)) { found = TRUE; } } + else if (lua_isuserdata (L, -1)) { + t = lua_check_text (L, -1); + + if (t) { + if (lua_trie_search_str (L, trie, t->start, t->len, cb)) { + found = TRUE; + } + } + } lua_pop (L, 1); } @@ -229,18 +285,28 @@ lua_trie_match (lua_State *L) else if (lua_type (L, 2) == LUA_TSTRING) { text = lua_tolstring (L, 2, &len); - if (lua_trie_search_str (L, trie, text, len)) { + if (lua_trie_search_str (L, trie, text, len, cb)) { + found = TRUE; + } + } + else if (lua_type (L, 2) == LUA_TUSERDATA) { + t = lua_check_text (L, 2); + + if (t && lua_trie_search_str (L, trie, t->start, t->len, cb)) { found = TRUE; } } } - lua_pushboolean (L, found); + if (lua_type (L, 3) == LUA_TFUNCTION) { + lua_pushboolean (L, found); + } + return 1; } /*** - * @method trie:search_mime(task, cb[, caseless]) + * @method trie:search_mime(task, cb) * This is a helper mehthod to search pattern within text parts of a message in rspamd task * @param {task} task object * @param {function} cb callback called on each pattern match @see trie:match @@ -257,6 +323,7 @@ lua_trie_search_mime (lua_State *L) const gchar *text; gsize len, i; gboolean found = FALSE; + rspamd_multipattern_cb_t cb = lua_trie_callback; if (trie && task) { PTR_ARRAY_FOREACH (MESSAGE_FIELD (task, text_parts), i, part) { @@ -264,7 +331,7 @@ lua_trie_search_mime (lua_State *L) text = part->utf_content->data; len = part->utf_content->len; - if (lua_trie_search_str (L, trie, text, len) != 0) { + if (lua_trie_search_str (L, trie, text, len, cb) != 0) { found = TRUE; } } @@ -297,7 +364,7 @@ lua_trie_search_rawmsg (lua_State *L) text = task->msg.begin; len = task->msg.len; - if (lua_trie_search_str (L, trie, text, len) != 0) { + if (lua_trie_search_str (L, trie, text, len, lua_trie_callback) != 0) { found = TRUE; } } @@ -335,7 +402,7 @@ lua_trie_search_rawbody (lua_State *L) len = task->msg.len; } - if (lua_trie_search_str (L, trie, text, len) != 0) { + if (lua_trie_search_str (L, trie, text, len, lua_trie_callback) != 0) { found = TRUE; } } @@ -348,6 +415,30 @@ static gint lua_load_trie (lua_State *L) { lua_newtable (L); + + /* Flags */ + lua_pushstring (L, "flags"); + lua_newtable (L); + + lua_pushinteger (L, RSPAMD_MULTIPATTERN_GLOB); + lua_setfield (L, -2, "glob"); + lua_pushinteger (L, RSPAMD_MULTIPATTERN_RE); + lua_setfield (L, -2, "re"); + lua_pushinteger (L, RSPAMD_MULTIPATTERN_ICASE); + lua_setfield (L, -2, "icase"); + lua_pushinteger (L, RSPAMD_MULTIPATTERN_UTF8); + lua_setfield (L, -2, "utf8"); + lua_pushinteger (L, RSPAMD_MULTIPATTERN_TLD); + lua_setfield (L, -2, "tld"); + lua_pushinteger (L, RSPAMD_MULTIPATTERN_DOTALL); + lua_setfield (L, -2, "dot_all"); + lua_pushinteger (L, RSPAMD_MULTIPATTERN_SINGLEMATCH); + lua_setfield (L, -2, "single_match"); + lua_pushinteger (L, RSPAMD_MULTIPATTERN_NO_START); + lua_setfield (L, -2, "no_start"); + lua_settable (L, -3); + + /* Main content */ luaL_register (L, NULL, trielib_f); return 1; @@ -356,17 +447,7 @@ lua_load_trie (lua_State *L) void luaopen_trie (lua_State * L) { - luaL_newmetatable (L, "rspamd{trie}"); - lua_pushstring (L, "__index"); - lua_pushvalue (L, -2); - lua_settable (L, -3); - - lua_pushstring (L, "class"); - lua_pushstring (L, "rspamd{trie}"); - lua_rawset (L, -3); - - luaL_register (L, NULL, trielib_m); + rspamd_lua_new_class (L, "rspamd{trie}", trielib_m); + lua_pop (L, 1); rspamd_lua_add_preload (L, "rspamd_trie", lua_load_trie); - - lua_pop (L, 1); /* remove metatable from stack */ } diff --git a/src/lua/lua_udp.c b/src/lua/lua_udp.c index 94d27bf63..b72108c34 100644 --- a/src/lua/lua_udp.c +++ b/src/lua/lua_udp.c @@ -373,7 +373,8 @@ lua_udp_sendto (lua_State *L) { if (lua_type (L, -1) == LUA_TSTRING) { host = luaL_checkstring (L, -1); - if (rspamd_parse_inet_address (&addr, host, 0)) { + if (rspamd_parse_inet_address (&addr, + host, strlen (host), RSPAMD_INET_ADDRESS_PARSE_DEFAULT)) { if (port != 0) { rspamd_inet_address_set_port (addr, port); } diff --git a/src/lua/lua_upstream.c b/src/lua/lua_upstream.c index 3c4f3f4c3..7ba77839f 100644 --- a/src/lua/lua_upstream.c +++ b/src/lua/lua_upstream.c @@ -569,30 +569,10 @@ lua_load_upstream_list (lua_State * L) void luaopen_upstream (lua_State * L) { - luaL_newmetatable (L, "rspamd{upstream_list}"); - lua_pushstring (L, "__index"); - lua_pushvalue (L, -2); - lua_settable (L, -3); - - lua_pushstring (L, "class"); - lua_pushstring (L, "rspamd{upstream_list}"); - lua_rawset (L, -3); - - luaL_register (L, NULL, upstream_list_m); + rspamd_lua_new_class (L, "rspamd{upstream_list}", upstream_list_m); + lua_pop (L, 1); rspamd_lua_add_preload (L, "rspamd_upstream_list", lua_load_upstream_list); - lua_pop (L, 1); /* remove metatable from stack */ - - luaL_newmetatable (L, "rspamd{upstream}"); - lua_pushstring (L, "__index"); - lua_pushvalue (L, -2); - lua_settable (L, -3); - - lua_pushstring (L, "class"); - lua_pushstring (L, "rspamd{upstream}"); - lua_rawset (L, -3); - - luaL_register (L, NULL, upstream_m); - - lua_pop (L, 1); /* remove metatable from stack */ + rspamd_lua_new_class (L, "rspamd{upstream}", upstream_m); + lua_pop (L, 1); } diff --git a/src/lua/lua_url.c b/src/lua/lua_url.c index b30e560c9..d21ab727f 100644 --- a/src/lua/lua_url.c +++ b/src/lua/lua_url.c @@ -110,7 +110,7 @@ lua_check_url (lua_State * L, gint pos) return ud ? ((struct rspamd_lua_url *)ud) : NULL; } -static void +static gboolean lua_url_single_inserter (struct rspamd_url *url, gsize start_offset, gsize end_offset, gpointer ud) { @@ -120,6 +120,8 @@ lua_url_single_inserter (struct rspamd_url *url, gsize start_offset, lua_url = lua_newuserdata (L, sizeof (struct rspamd_lua_url)); rspamd_lua_setclass (L, "rspamd{url}", -1); lua_url->url = url; + + return TRUE; } /*** @@ -770,7 +772,7 @@ lua_url_init (lua_State *L) return 0; } -static void +static gboolean lua_url_table_inserter (struct rspamd_url *url, gsize start_offset, gsize end_offset, gpointer ud) { @@ -785,6 +787,8 @@ lua_url_table_inserter (struct rspamd_url *url, gsize start_offset, lua_pushinteger (L, n + 1); lua_pushlstring (L, url->string, url->urllen); lua_settable (L, -3); + + return TRUE; } @@ -881,6 +885,7 @@ lua_url_get_flags (lua_State *L) PUSH_FLAG (RSPAMD_URL_FLAG_UNNORMALISED, "unnormalised"); PUSH_FLAG (RSPAMD_URL_FLAG_ZW_SPACES, "zw_spaces"); PUSH_FLAG (RSPAMD_URL_FLAG_DISPLAY_URL, "url_displayed"); + PUSH_FLAG (RSPAMD_URL_FLAG_IMAGE, "image"); } else { return luaL_error (L, "invalid arguments"); diff --git a/src/lua/lua_util.c b/src/lua/lua_util.c index be795bc55..0057dc472 100644 --- a/src/lua/lua_util.c +++ b/src/lua/lua_util.c @@ -23,7 +23,11 @@ #include "libmime/content_type.h" #include "libmime/mime_headers.h" #include "libutil/hash.h" -#include "linenoise.h" + +#ifdef WITH_LUA_REPL +#include "replxx.h" +#endif + #include <math.h> #include <glob.h> #include <zlib.h> @@ -229,6 +233,14 @@ LUA_FUNCTION_DEF (util, parse_mail_address); */ LUA_FUNCTION_DEF (util, strlen_utf8); +/*** + * @function util.lower_utf8(str) + * Converts utf8 string to lower case + * @param {string} str utf8 encoded string + * @return {string} lowercased utf8 string + */ +LUA_FUNCTION_DEF (util, lower_utf8); + /*** * @function util.strcasecmp(str1, str2) @@ -632,6 +644,7 @@ static const struct luaL_reg utillib_f[] = { LUA_INTERFACE_DEF (util, glob), LUA_INTERFACE_DEF (util, parse_mail_address), LUA_INTERFACE_DEF (util, strlen_utf8), + LUA_INTERFACE_DEF (util, lower_utf8), LUA_INTERFACE_DEF (util, strcasecmp_ascii), LUA_INTERFACE_DEF (util, strequal_caseless), LUA_INTERFACE_DEF (util, get_ticks), @@ -809,7 +822,6 @@ lua_util_config_from_ucl (lua_State *L) cfg->lua_state = L; cfg->rcl_obj = obj; - cfg->cache = rspamd_symcache_new (cfg); top = rspamd_rcl_config_init (cfg, NULL); if (!rspamd_rcl_parse (top, cfg, cfg, cfg->cfg_pool, cfg->rcl_obj, &err)) { @@ -1602,11 +1614,10 @@ lua_util_glob (lua_State *L) LUA_TRACE_POINT; const gchar *pattern; glob_t gl; - gint top, i, flags; + gint top, i, flags = 0; top = lua_gettop (L); memset (&gl, 0, sizeof (gl)); - flags = GLOB_NOSORT; for (i = 1; i <= top; i ++, flags |= GLOB_APPEND) { pattern = luaL_checkstring (L, i); @@ -1676,21 +1687,53 @@ static gint lua_util_strlen_utf8 (lua_State *L) { LUA_TRACE_POINT; - const gchar *str, *end; + const gchar *str; gsize len; str = lua_tolstring (L, 1, &len); if (str) { - if (g_utf8_validate (str, len, &end)) { - len = g_utf8_strlen (str, len); + gint32 i = 0, nchars = 0; + UChar32 uc; + + while (i < len) { + U8_NEXT ((guint8 *) str, i, len, uc); + nchars ++; } - else if (end != NULL && end > str) { - len = (g_utf8_strlen (str, end - str)) /* UTF part */ - + (len - (end - str)) /* raw part */; + + lua_pushinteger (L, nchars); + } + else { + return luaL_error (L, "invalid arguments"); + } + + return 1; +} + +static gint +lua_util_lower_utf8 (lua_State *L) +{ + LUA_TRACE_POINT; + const gchar *str; + gchar *dst; + gsize len; + UChar32 uc; + UBool err = 0; + gint32 i = 0, j = 0; + + str = lua_tolstring (L, 1, &len); + + if (str) { + dst = g_malloc (len); + + while (i < len && err == 0) { + U8_NEXT ((guint8 *) str, i, len, uc); + uc = u_tolower (uc); + U8_APPEND (dst, j, len, uc, err); } - lua_pushinteger (L, len); + lua_pushlstring (L, dst, j); + g_free (dst); } else { return luaL_error (L, "invalid arguments"); @@ -2865,17 +2908,41 @@ lua_util_readline (lua_State *L) if (lua_type (L, 1) == LUA_TSTRING) { prompt = lua_tostring (L, 1); } +#ifdef WITH_LUA_REPL + static Replxx *rx_instance = NULL; + + if (rx_instance == NULL) { + rx_instance = replxx_init (); + } - input = linenoise (prompt); + input = (gchar *)replxx_input (rx_instance, prompt); if (input) { lua_pushstring (L, input); - linenoiseHistoryAdd (input); - linenoiseFree (input); } else { lua_pushnil (L); } +#else + size_t linecap = 0; + ssize_t linelen; + + fprintf (stdout, "%s ", prompt); + + linelen = getline (&input, &linecap, stdin); + + if (linelen > 0) { + if (input[linelen - 1] == '\n') { + linelen --; + } + + lua_pushlstring (L, input, linelen); + free (input); + } + else { + lua_pushnil (L); + } +#endif return 1; } @@ -3687,11 +3754,28 @@ lua_util_unpack (lua_State *L) Header h; const char *fmt = luaL_checkstring(L, 1); size_t ld; - const char *data = luaL_checklstring (L, 2, &ld); - size_t pos = (size_t) posrelat (luaL_optinteger (L, 3, 1), ld) - 1; + const char *data; int n = 0; /* number of results */ + + if (lua_type (L, 2) == LUA_TUSERDATA) { + struct rspamd_lua_text *t = lua_check_text (L, 2); + + if (!t) { + return luaL_error (L, "invalid arguments"); + } + + data = t->start; + ld = t->len; + } + else { + data = luaL_checklstring (L, 2, &ld); + } + + size_t pos = (size_t) posrelat (luaL_optinteger (L, 3, 1), ld) - 1; luaL_argcheck(L, pos <= ld, 3, "initial position out of string"); + initheader (L, &h); + while (*fmt != '\0') { int size, ntoalign; KOption opt = getdetails (&h, pos, &fmt, &size, &ntoalign); diff --git a/src/lua/lua_worker.c b/src/lua/lua_worker.c index c3c9e729e..eaf0e02d7 100644 --- a/src/lua/lua_worker.c +++ b/src/lua/lua_worker.c @@ -25,6 +25,7 @@ #endif #include <sys/wait.h> +#include <src/libserver/rspamd_control.h> /*** * @module rspamd_worker @@ -42,6 +43,7 @@ LUA_FUNCTION_DEF (worker, is_scanner); LUA_FUNCTION_DEF (worker, is_primary_controller); LUA_FUNCTION_DEF (worker, spawn_process); LUA_FUNCTION_DEF (worker, get_mem_stats); +LUA_FUNCTION_DEF (worker, add_control_handler); const luaL_reg worker_reg[] = { LUA_INTERFACE_DEF (worker, get_name), @@ -53,6 +55,7 @@ const luaL_reg worker_reg[] = { LUA_INTERFACE_DEF (worker, is_scanner), LUA_INTERFACE_DEF (worker, is_primary_controller), LUA_INTERFACE_DEF (worker, get_mem_stats), + LUA_INTERFACE_DEF (worker, add_control_handler), {"__tostring", rspamd_lua_class_tostring}, {NULL, NULL} }; @@ -240,6 +243,211 @@ lua_worker_is_primary_controller (lua_State *L) return 1; } +struct rspamd_control_cbdata { + lua_State *L; + rspamd_mempool_t *pool; + struct rspamd_worker *w; + struct rspamd_config *cfg; + struct ev_loop *event_loop; + struct rspamd_async_session *session; + enum rspamd_control_type cmd; + gint cbref; + gint fd; +}; + +static gboolean +lua_worker_control_fin_session (void *ud) +{ + struct rspamd_control_reply rep; + struct rspamd_control_cbdata *cbd = (struct rspamd_control_cbdata *)ud; + rspamd_mempool_t *pool; + lua_State *L; + + L = cbd->L; + pool = cbd->pool; + + memset (&rep, 0, sizeof (rep)); + rep.type = cbd->cmd; + + if (write (cbd->fd, &rep, sizeof (rep)) != sizeof (rep)) { + msg_err_pool ("cannot write reply to the control socket: %s", + strerror (errno)); + } + + return TRUE; +} + +static void +lua_worker_control_session_dtor (void *ud) +{ + struct rspamd_control_cbdata *cbd = (struct rspamd_control_cbdata *)ud; + + rspamd_mempool_delete (cbd->pool); +} + +static gboolean +lua_worker_control_handler (struct rspamd_main *rspamd_main, + struct rspamd_worker *worker, + gint fd, + gint attached_fd, + struct rspamd_control_command *cmd, + gpointer ud) +{ + struct rspamd_async_session *session, **psession; + struct rspamd_control_cbdata *cbd = (struct rspamd_control_cbdata *)ud; + rspamd_mempool_t *pool; + lua_State *L; + gint err_idx, status; + + L = cbd->L; + pool = cbd->pool; + session = rspamd_session_create (cbd->pool, + lua_worker_control_fin_session, + NULL, + lua_worker_control_session_dtor, + cbd); + cbd->session = session; + cbd->fd = fd; + + lua_pushcfunction (L, &rspamd_lua_traceback); + err_idx = lua_gettop (L); + lua_rawgeti (L, LUA_REGISTRYINDEX, cbd->cbref); + psession = lua_newuserdata (L, sizeof (*psession)); + rspamd_lua_setclass (L, "rspamd{session}", -1); + *psession = session; + + /* Command name */ + lua_pushstring (L, rspamd_control_command_to_string (cmd->type)); + + /* Command's extras */ + lua_newtable (L); + + switch (cmd->type) { + case RSPAMD_CONTROL_CHILD_CHANGE: + lua_pushinteger (L, cmd->cmd.child_change.pid); + lua_setfield (L, -2, "pid"); + switch (cmd->cmd.child_change.what) { + case rspamd_child_offline: + lua_pushstring (L, "offline"); + lua_setfield (L, -2, "what"); + break; + case rspamd_child_online: + lua_pushstring (L, "online"); + lua_setfield (L, -2, "what"); + break; + case rspamd_child_terminated: + lua_pushstring (L, "terminated"); + lua_setfield (L, -2, "what"); + status = cmd->cmd.child_change.additional; + + if (WIFEXITED (status)) { + lua_pushinteger (L, WEXITSTATUS (status)); + lua_setfield (L, -2, "exit_code"); + } + + if (WIFSIGNALED (status)) { + lua_pushinteger (L, WTERMSIG (status)); + lua_setfield (L, -2, "signal"); +#ifdef WCOREDUMP + lua_pushboolean (L, WCOREDUMP (status)); + lua_setfield (L, -2, "core"); +#endif + } + break; + } + break; + case RSPAMD_CONTROL_MONITORED_CHANGE: + lua_pushinteger (L, cmd->cmd.monitored_change.sender); + lua_setfield (L, -2, "sender"); + lua_pushboolean (L, cmd->cmd.monitored_change.alive); + lua_setfield (L, -2, "alive"); + lua_pushlstring (L, cmd->cmd.monitored_change.tag, + sizeof (cmd->cmd.monitored_change.tag)); + lua_setfield (L, -2, "tag"); + break; + case RSPAMD_CONTROL_HYPERSCAN_LOADED: + lua_pushstring (L, cmd->cmd.hs_loaded.cache_dir); + lua_setfield (L, -2, "cache_dir"); + lua_pushboolean (L, cmd->cmd.hs_loaded.forced); + lua_setfield (L, -2, "forced"); + break; + case RSPAMD_CONTROL_STAT: + case RSPAMD_CONTROL_RELOAD: + case RSPAMD_CONTROL_RERESOLVE: + case RSPAMD_CONTROL_RECOMPILE: + case RSPAMD_CONTROL_LOG_PIPE: + case RSPAMD_CONTROL_FUZZY_STAT: + case RSPAMD_CONTROL_FUZZY_SYNC: + default: + break; + } + + if (lua_pcall (L, 3, 0, err_idx) != 0) { + msg_err_pool ("cannot init lua parser script: %s", lua_tostring (L, -1)); + lua_settop (L, err_idx - 1); + + struct rspamd_control_reply rep; + + memset (&rep, 0, sizeof (rep)); + rep.type = cbd->cmd; + rep.reply.monitored_change.status = -1; + + if (write (fd, &rep, sizeof (rep)) != sizeof (rep)) { + msg_err_pool ("cannot write reply to the control socket: %s", + strerror (errno)); + } + + rspamd_session_destroy (session); + } + else { + lua_settop (L, err_idx - 1); + rspamd_session_pending (session); + } + + return TRUE; +} + +static gint +lua_worker_add_control_handler (lua_State *L) +{ + struct rspamd_worker *w = lua_check_worker (L, 1); + struct rspamd_config *cfg = lua_check_config (L, 2); + struct ev_loop *event_loop = lua_check_ev_base (L, 3); + const gchar *cmd_name = luaL_checkstring (L, 4); + enum rspamd_control_type cmd; + struct rspamd_control_cbdata *cbd; + + if (w && cfg && event_loop && cmd_name && lua_isfunction (L, 5)) { + cmd = rspamd_control_command_from_string (cmd_name); + + if (cmd == RSPAMD_CONTROL_MAX) { + return luaL_error (L, "invalid command type: %s", cmd_name); + } + + rspamd_mempool_t *pool = rspamd_mempool_new ( + rspamd_mempool_suggest_size (), "lua_control"); + cbd = rspamd_mempool_alloc0 (pool, sizeof (*cbd)); + cbd->pool = pool; + cbd->event_loop = event_loop; + cbd->w = w; + cbd->cfg = cfg; + cbd->cmd = cmd; + cbd->L = L; + /* Refcount callback */ + lua_pushvalue (L, 5); + cbd->cbref = luaL_ref (L, LUA_REGISTRYINDEX); + + rspamd_control_worker_add_cmd_handler (w, cmd, lua_worker_control_handler, + cbd); + } + else { + return luaL_error (L, "invalid arguments, need worker, cfg, " + "ev_loop, cmd_name and callback function"); + } + + return 0; +} + #ifdef WITH_JEMALLOC static void lua_worker_jemalloc_stats_cb (void *ud, const char *msg) |