From ddb8489d1b595a8c5472be4186352cfd148bf800 Mon Sep 17 00:00:00 2001 From: Vsevolod Stakhov Date: Thu, 17 Mar 2016 09:57:40 +0000 Subject: [PATCH] [Feature] Add config:add_map table form method, add regexp maps --- src/lua/lua_common.h | 2 + src/lua/lua_config.c | 30 +++--- src/lua/lua_map.c | 217 ++++++++++++++++++++++++++++++++++--------- 3 files changed, 195 insertions(+), 54 deletions(-) diff --git a/src/lua/lua_common.h b/src/lua/lua_common.h index 39f578ea6..54ad9d706 100644 --- a/src/lua/lua_common.h +++ b/src/lua/lua_common.h @@ -90,6 +90,7 @@ enum rspamd_lua_map_type { RSPAMD_LUA_MAP_RADIX = 0, RSPAMD_LUA_MAP_SET, RSPAMD_LUA_MAP_HASH, + RSPAMD_LUA_MAP_REGEXP, RSPAMD_LUA_MAP_CALLBACK }; @@ -104,6 +105,7 @@ struct rspamd_lua_map { struct radix_tree_compressed *radix; GHashTable *hash; struct lua_map_callback_data *cbdata; + struct rspamd_regexp_map *re_map; } data; }; diff --git a/src/lua/lua_config.c b/src/lua/lua_config.c index 4237ff97a..ea53c53ae 100644 --- a/src/lua/lua_config.c +++ b/src/lua/lua_config.c @@ -65,7 +65,7 @@ LUA_FUNCTION_DEF (config, get_mempool); * Creates new dynamic map of IP/mask addresses. * @param {string} mapline URL for a map * @param {string} description optional map description - * @return {radix} radix tree object + * @return {map} radix tree object * @example local ip_map = rspamd_config:add_radix_map ('file:///path/to/file', 'my radix map') ... @@ -80,10 +80,10 @@ end /*** * @method rspamd_config:radix_from_config(mname, optname) - * Creates new static map of IP/mask addresses from config. + * Creates new embedded map of IP/mask addresses from config. * @param {string} mname name of module * @param {string} optname option to get - * @return {radix} radix tree object + * @return {map} radix tree object * @example local ip_map = rspamd_config:radix_from_config ('mymodule', 'ips') ... @@ -100,7 +100,7 @@ end * Creates new dynamic map string objects. * @param {string} mapline URL for a map * @param {string} description optional map description - * @return {hash} hash set object + * @return {map} hash set object * @example local hash_map = rspamd_config:add_hash_map ('file:///path/to/file', 'my hash map') ... @@ -117,7 +117,7 @@ end * Creates new dynamic map of key/values associations. * @param {string} mapline URL for a map * @param {string} description optional map description - * @return {hash} hash table object + * @return {map} hash table object * @example local kv_map = rspamd_config:add_kv_map ('file:///path/to/file', 'my kv map') ... @@ -133,12 +133,20 @@ local function foo(task) end */ /*** - * @method rspamd_config:add_map(mapline[, description], callback) - * Creates new dynamic map with free-form callback - * @param {string} mapline URL for a map - * @param {string} description optional map description - * @param {function} callback function to be called on map load and/or update - * @return {bool} `true` if map has been added + * @method rspamd_config:add_map({args}) + * Creates new dynamic map according to the attributes passed. + * + * - `type`: type of map to be created, can be one of the following set: + * + `set`: set of strings + * + `radix`: map of IP addresses to strings + * + `map`: map of strings to strings + * + `regexp`: map of regexps to strings + * + `callback`: map processed by lua callback + * - `url`: url to load map from + * - `description`: map's description + * - `callback`: lua callback for the map + * + * @return {map} `true` if map has been added * @example local str = '' diff --git a/src/lua/lua_map.c b/src/lua/lua_map.c index 51db9f97b..4d4dc2285 100644 --- a/src/lua/lua_map.c +++ b/src/lua/lua_map.c @@ -342,58 +342,176 @@ gint lua_config_add_map (lua_State *L) { struct rspamd_config *cfg = lua_check_config (L, 1); - const gchar *map_line, *description; + const gchar *map_line = NULL, *description = NULL; + const gchar *type = NULL; struct lua_map_callback_data *cbdata; struct rspamd_lua_map *map, **pmap; struct rspamd_map *m; - int cbidx; + int cbidx = -1, ret; + GError *err = NULL; if (cfg) { - map_line = luaL_checkstring (L, 2); + if (lua_type (L, 2) == LUA_TTABLE) { + if (!rspamd_lua_parse_table_arguments (L, 2, &err, + "type=*S;description=S;callback=F;url=*S", + &type, &description, &cbidx, &map_line)) { + ret = luaL_error (L, "invalid table arguments: %s", err->message); + g_error_free (err); + + return ret; + } - if (lua_gettop (L) == 4) { - description = lua_tostring (L, 3); - cbidx = 4; - } - else { - description = NULL; - cbidx = 3; - } + g_assert (type != NULL && map_line != NULL); - map = rspamd_mempool_alloc0 (cfg->cfg_pool, sizeof (*map)); - map->type = RSPAMD_LUA_MAP_CALLBACK; - map->data.cbdata = rspamd_mempool_alloc0 (cfg->cfg_pool, - sizeof (*map->data.cbdata)); - cbdata = map->data.cbdata; - cbdata->L = L; - cbdata->data = NULL; - cbdata->lua_map = map; - - if (lua_type (L, cbidx) == LUA_TFUNCTION) { - lua_pushvalue (L, cbidx); - /* Get a reference */ - cbdata->ref = luaL_ref (L, LUA_REGISTRYINDEX); - } - else { - /* - * Now we can create maps with delayed callbacks, to allow better - * closures generation - */ - cbdata->ref = -1; - } + if (strcmp (type, "callback") == 0) { + if (cbidx == -1) { + ret = luaL_error (L, "invalid table arguments: callback missing"); + return ret; + } + + map = rspamd_mempool_alloc0 (cfg->cfg_pool, sizeof (*map)); + map->type = RSPAMD_LUA_MAP_CALLBACK; + map->data.cbdata = rspamd_mempool_alloc0 (cfg->cfg_pool, + sizeof (*map->data.cbdata)); + cbdata = map->data.cbdata; + cbdata->L = L; + cbdata->data = NULL; + cbdata->lua_map = map; + cbdata->ref = cbidx; + + if ((m = rspamd_map_add (cfg, map_line, description, + lua_map_read, lua_map_fin, + (void **)&map->data.cbdata)) == NULL) { + msg_warn_config ("invalid map %s", map_line); + luaL_unref (L, LUA_REGISTRYINDEX, cbidx); + lua_pushnil (L); + + return 1; + } + } + else if (strcmp (type, "set") == 0) { + map = rspamd_mempool_alloc0 (cfg->cfg_pool, sizeof (*map)); + map->data.hash = g_hash_table_new (rspamd_strcase_hash, + rspamd_strcase_equal); + map->type = RSPAMD_LUA_MAP_SET; + + if ((m = rspamd_map_add (cfg, map_line, description, + rspamd_hosts_read, + rspamd_hosts_fin, + (void **)&map->data.hash)) == NULL) { + msg_warn_config ("invalid set map %s", map_line); + g_hash_table_destroy (map->data.hash); + lua_pushnil (L); + + return 1; + } + } + else if (strcmp (type, "map") == 0) { + map = rspamd_mempool_alloc0 (cfg->cfg_pool, sizeof (*map)); + map->data.hash = g_hash_table_new (rspamd_strcase_hash, + rspamd_strcase_equal); + map->type = RSPAMD_LUA_MAP_HASH; + + if ((m = rspamd_map_add (cfg, map_line, description, + rspamd_kv_list_read, + rspamd_kv_list_fin, + (void **)&map->data.hash)) == NULL) { + msg_warn_config ("invalid hash map %s", map_line); + g_hash_table_destroy (map->data.hash); + lua_pushnil (L); + return 1; + } + } + else if (strcmp (type, "radix") == 0) { + map = rspamd_mempool_alloc0 (cfg->cfg_pool, sizeof (*map)); + map->data.radix = radix_create_compressed (); + map->type = RSPAMD_LUA_MAP_RADIX; + + if ((m = rspamd_map_add (cfg, map_line, description, + rspamd_radix_read, + rspamd_radix_fin, + (void **)&map->data.radix)) == NULL) { + msg_warn_config ("invalid radix map %s", map_line); + radix_destroy_compressed (map->data.radix); + lua_pushnil (L); + return 1; + } + } + else if (strcmp (type, "regexp") == 0) { + map = rspamd_mempool_alloc0 (cfg->cfg_pool, sizeof (*map)); + map->data.radix = radix_create_compressed (); + map->type = RSPAMD_LUA_MAP_RADIX; + + if ((m = rspamd_map_add (cfg, map_line, description, + rspamd_regexp_list_read, + rspamd_regexp_list_fin, + (void **)&map->data.re_map)) == NULL) { + msg_warn_config ("invalid regexp map %s", map_line); + lua_pushnil (L); + return 1; + } + } + else { + ret = luaL_error (L, "invalid arguments: unknown type '%s'", type); + + return ret; + } - if ((m = rspamd_map_add (cfg, map_line, description, - lua_map_read, lua_map_fin, - (void **)&map->data.cbdata)) == NULL) { - msg_warn_config ("invalid map %s", map_line); - lua_pushnil (L); - } - else { map->map = m; pmap = lua_newuserdata (L, sizeof (void *)); *pmap = map; rspamd_lua_setclass (L, "rspamd{map}", -1); } + else { + /* + * Legacy format add_map(map_line, description, callback) + */ + map_line = luaL_checkstring (L, 2); + + if (lua_gettop (L) == 4) { + description = lua_tostring (L, 3); + cbidx = 4; + } + else { + description = NULL; + cbidx = 3; + } + + map = rspamd_mempool_alloc0 (cfg->cfg_pool, sizeof (*map)); + map->type = RSPAMD_LUA_MAP_CALLBACK; + map->data.cbdata = rspamd_mempool_alloc0 (cfg->cfg_pool, + sizeof (*map->data.cbdata)); + cbdata = map->data.cbdata; + cbdata->L = L; + cbdata->data = NULL; + cbdata->lua_map = map; + + if (lua_type (L, cbidx) == LUA_TFUNCTION) { + lua_pushvalue (L, cbidx); + /* Get a reference */ + cbdata->ref = luaL_ref (L, LUA_REGISTRYINDEX); + } + else { + /* + * Now we can create maps with delayed callbacks, to allow better + * closures generation + */ + cbdata->ref = -1; + } + + if ((m = rspamd_map_add (cfg, map_line, description, + lua_map_read, lua_map_fin, + (void **)&map->data.cbdata)) == NULL) { + msg_warn_config ("invalid map %s", map_line); + lua_pushnil (L); + } + else { + map->map = m; + pmap = lua_newuserdata (L, sizeof (void *)); + *pmap = map; + rspamd_lua_setclass (L, "rspamd{map}", -1); + } + } } else { return luaL_error (L, "invalid arguments"); @@ -411,6 +529,7 @@ lua_map_get_key (lua_State * L) struct rspamd_lua_ip *addr = NULL; const gchar *key, *value = NULL; gpointer ud; + gsize len; guint32 key_num = 0; gboolean ret = FALSE; @@ -456,12 +575,11 @@ lua_map_get_key (lua_State * L) ret = g_hash_table_lookup (map->data.hash, key) != NULL; } } - else { - /* key-value map */ - key = lua_tostring (L, 2); + else if (map->type == RSPAMD_LUA_MAP_REGEXP) { + key = lua_tolstring (L, 2, &len); if (key) { - value = g_hash_table_lookup (map->data.hash, key); + value = rspamd_match_regexp_map (map->data.re_map, key, len); if (value) { lua_pushstring (L, value); @@ -469,6 +587,19 @@ lua_map_get_key (lua_State * L) } } } + else { + /* key-value map */ + key = lua_tostring (L, 2); + + if (key) { + value = g_hash_table_lookup (map->data.hash, key); + } + + if (value) { + lua_pushstring (L, value); + return 1; + } + } } else { return luaL_error (L, "invalid arguments"); -- 2.39.5