From de9ac8f1938e09f3c6c3d6f261db4749b3b9ff01 Mon Sep 17 00:00:00 2001 From: Vsevolod Stakhov Date: Fri, 4 Mar 2011 19:38:04 +0300 Subject: [PATCH] * Add multimaps for "FROM" and "TO" headers (mime an smtp data can be checked) * Improve lua api for getting message's sender and recipients --- src/lua/lua_task.c | 128 +++++++++++++++++++++++++- src/message.c | 6 +- src/plugins/lua/forged_recipients.lua | 53 +---------- src/plugins/lua/multimap.lua | 96 ++++++++++++++++++- 4 files changed, 227 insertions(+), 56 deletions(-) diff --git a/src/lua/lua_task.c b/src/lua/lua_task.c index 0a6185f7e..4a40008f3 100644 --- a/src/lua/lua_task.c +++ b/src/lua/lua_task.c @@ -57,6 +57,8 @@ LUA_FUNCTION_DEF (task, resolve_dns_txt); LUA_FUNCTION_DEF (task, call_rspamd_function); LUA_FUNCTION_DEF (task, get_recipients); LUA_FUNCTION_DEF (task, get_from); +LUA_FUNCTION_DEF (task, get_recipients_headers); +LUA_FUNCTION_DEF (task, get_from_headers); LUA_FUNCTION_DEF (task, get_from_ip); LUA_FUNCTION_DEF (task, get_from_ip_num); LUA_FUNCTION_DEF (task, get_client_ip_num); @@ -83,6 +85,8 @@ static const struct luaL_reg tasklib_m[] = { LUA_INTERFACE_DEF (task, call_rspamd_function), LUA_INTERFACE_DEF (task, get_recipients), LUA_INTERFACE_DEF (task, get_from), + LUA_INTERFACE_DEF (task, get_recipients_headers), + LUA_INTERFACE_DEF (task, get_from_headers), LUA_INTERFACE_DEF (task, get_from_ip), LUA_INTERFACE_DEF (task, get_from_ip_num), LUA_INTERFACE_DEF (task, get_client_ip_num), @@ -694,20 +698,74 @@ lua_task_call_rspamd_function (lua_State * L) } + + +/* + * Push internet addresses to lua as a table + */ +static void +lua_push_internet_address (lua_State *L, InternetAddressList *addrs) +{ + InternetAddress *ia; + gint idx = 1; + +#ifndef GMIME24 + /* Gmime 2.2 version */ + InternetAddressList *cur; + + lua_newtable (L); + cur = addrs; + while (cur) { + ia = internet_address_list_get_address (cur); + lua_newtable (L); + lua_set_table_index (L, "name", internet_address_get_name (ia)); + lua_set_table_index (L, "addr", internet_address_get_addr (ia)); + msg_info ("name: %s, addr: %s", internet_address_get_name (ia), internet_address_get_addr (ia)); + lua_rawseti (L, -2, idx++); + cur = internet_address_list_next (cur); + } +#else + /* Gmime 2.4 version */ + gsize len, i; + InternetAddressMailbox *iamb; + + lua_newtable (L); + len = internet_address_list_length (list); + for (i = 0; i < len; i ++) { + ia = internet_address_list_get_address (list, i); + if (ia) { + lua_newtable (L); + iamb = INTERNET_ADDRESS_MAILBOX (ia); + lua_set_table_index (L, "name", internet_address_get_name (ia)); + lua_set_table_index (L, "addr", internet_address_mailbox_get_addr (iamb)); + lua_rawseti (L, -2, idx++); + } + } +#endif +} + static gint lua_task_get_recipients (lua_State *L) { struct worker_task *task = lua_check_task (L); - gint i = 1; GList *cur; + InternetAddressList *addrs; if (task) { cur = task->rcpt; if (cur != NULL) { - lua_newtable (L); while (cur) { - lua_pushstring (L, (gchar *)cur->data); - lua_rawseti (L, -2, i++); +#ifndef GMIME24 + addrs = internet_address_parse_string (cur->data); +#else + addrs = internet_address_list_parse_string (cur->data); +#endif + lua_push_internet_address (L, addrs); +#ifndef GMIME24 + internet_address_list_destroy (addrs); +#else + g_object_unref (addrs); +#endif cur = g_list_next (cur); } return 1; @@ -722,10 +780,21 @@ static gint lua_task_get_from (lua_State *L) { struct worker_task *task = lua_check_task (L); + InternetAddressList *addrs; if (task) { if (task->from != NULL) { - lua_pushstring (L, (gchar *)task->from); +#ifndef GMIME24 + addrs = internet_address_parse_string (task->from); +#else + addrs = internet_address_list_parse_string (task->from); +#endif + lua_push_internet_address (L, addrs); +#ifndef GMIME24 + internet_address_list_destroy (addrs); +#else + g_object_unref (addrs); +#endif return 1; } } @@ -734,6 +803,55 @@ lua_task_get_from (lua_State *L) return 1; } +/* + * Headers versions + */ +static gint +lua_task_get_recipients_headers (lua_State *L) +{ + struct worker_task *task = lua_check_task (L); + InternetAddressList *addrs; + + if (task) { + addrs = g_mime_message_get_all_recipients(task->message); + lua_push_internet_address (L, addrs); +#ifndef GMIME24 + internet_address_list_destroy (addrs); +#else + g_object_unref (addrs); +#endif + return 1; + } + + lua_pushnil (L); + return 1; +} + +static gint +lua_task_get_from_headers (lua_State *L) +{ + struct worker_task *task = lua_check_task (L); + InternetAddressList *addrs; + + if (task) { +#ifndef GMIME24 + addrs = internet_address_parse_string (g_mime_message_get_sender (task->message)); +#else + addrs = internet_address_list_parse_string (g_mime_message_get_sender (task->message)); +#endif + lua_push_internet_address (L, addrs); +#ifndef GMIME24 + internet_address_list_destroy (addrs); +#else + g_object_unref (addrs); +#endif + return 1; + } + + lua_pushnil (L); + return 1; +} + static gint lua_task_get_from_ip (lua_State *L) { diff --git a/src/message.c b/src/message.c index 86e333dc1..80711b791 100644 --- a/src/message.c +++ b/src/message.c @@ -1113,7 +1113,9 @@ enum { HEADER_UNKNOWN }; - +/* + * Iterate throught all headers and make a list + */ #ifndef GMIME24 static void header_iterate (memory_pool_t * pool, struct gmime_raw_header *h, GList ** ret, const gchar *field, gboolean strong) @@ -1146,6 +1148,7 @@ header_iterate (memory_pool_t * pool, struct gmime_raw_header *h, GList ** ret, static void header_iterate (memory_pool_t * pool, GMimeHeaderList * ls, GList ** ret, const gchar *field, gboolean strong) { + /* Use iterator in case of gmime 2.4 */ GMimeHeaderIter *iter; const gchar *name; @@ -1156,6 +1159,7 @@ header_iterate (memory_pool_t * pool, GMimeHeaderList * ls, GList ** ret, const iter = g_mime_header_iter_new (); if (g_mime_header_list_get_iter (ls, iter) && g_mime_header_iter_first (iter)) { + /* Iterate throught headers */ while (g_mime_header_iter_is_valid (iter)) { name = g_mime_header_iter_get_name (iter); if (G_LIKELY (!strong)) { diff --git a/src/plugins/lua/forged_recipients.lua b/src/plugins/lua/forged_recipients.lua index d082b386d..366591377 100644 --- a/src/plugins/lua/forged_recipients.lua +++ b/src/plugins/lua/forged_recipients.lua @@ -10,57 +10,21 @@ function check_forged_headers(task) local res = false if smtp_rcpt then - local mime_rcpt = msg:get_header('To') - local mime_cc = msg:get_header('Cc') - local count = 0 - if mime_rcpt then - count = table.maxn(mime_rcpt) - end - if mime_cc then - count = count + table.maxn(mime_cc) - end - -- Check recipients count + local mime_rcpt = task:get_recipients_headers() + local count = table.maxn(mime_rcpt) if count < table.maxn(smtp_rcpt) then task:insert_result(symbol_rcpt, 1) else -- Find pair for each smtp recipient recipient in To or Cc headers for _,sr in ipairs(smtp_rcpt) do - if sr:sub(1,1) == '<' then - -- Trim brackets - sr = string.sub(sr, 2, -2) - end if mime_rcpt then for _,mr in ipairs(mime_rcpt) do - local i = string.find(mr, '<', 1, true) - if i then - local j = string.find(mr, '>', i, true) - if j then - mr = string.sub(mr, i+1, j-1) - end - end - - if string.lower(mr) == string.lower(sr) then + if string.lower(mr['addr']) == string.lower(sr['addr']) then res = true break end end end - if mime_cc then - for _,mr in ipairs(mime_cc) do - local i = string.find(mr, '<', 1, true) - if i then - local j = string.find(mr, '>', i, true) - if j then - mr = string.sub(mr, i+1, j-1) - end - end - if string.lower(mr) == string.lower(sr) then - res = true - break - end - end - end - if not res then task:insert_result(symbol_rcpt, 1) break @@ -71,15 +35,8 @@ function check_forged_headers(task) -- Check sender local smtp_from = task:get_from() if smtp_form then - local mime_from = msg:get_header('From') - local i = string.find(mime_from[0], '<', 1, true) - if i then - local j = string.find(mime_from[0], '>', i, true) - if j then - mime_from[0] = string.sub(mime_from[0], i+1, j-1) - end - end - if not mime_from or not (string.lower(mime_from[0]) == string.lower(smtp_from)) then + local mime_from = task:get_from_headers() + if not mime_from or not (string.lower(mime_from[1]['addr']) == string.lower(smtp_from[1]['addr'])) then task:insert_result(symbol_sender, 1) end end diff --git a/src/plugins/lua/multimap.lua b/src/plugins/lua/multimap.lua index 9512ff890..15c906657 100644 --- a/src/plugins/lua/multimap.lua +++ b/src/plugins/lua/multimap.lua @@ -73,6 +73,94 @@ function check_multimap(task) local rbl_str = o4 .. '.' .. o3 .. '.' .. o2 .. '.' .. o1 .. '.' .. rule['map'] task:resolve_dns_a(rbl_str, 'multimap_rbl_cb') end + elseif rule['type'] == 'rcpt' then + -- First try to get rcpt field + local rcpts = task:get_recipients() + if rcpts then + for _,r in ipairs(rcpts) do + if r['addr'] then + if rule['pattern'] then + -- extract a part from header + local _,_,ext = string.find(r['addr'], rule['pattern']) + if ext then + if rule['hash']:get_key(ext) then + task:insert_result(rule['symbol'], 1) + end + end + else + if rule['hash']:get_key(r['addr']) then + task:insert_result(rule['symbol'], 1) + end + end + end + end + else + -- Get from headers + local rcpts = task:get_recipients_headers() + if rcpts then + for _,r in ipairs(rcpts) do + if r['addr'] then + if rule['pattern'] then + -- extract a part from header + local _,_,ext = string.find(r['addr'], rule['pattern']) + if ext then + if rule['hash']:get_key(ext) then + task:insert_result(rule['symbol'], 1) + end + end + else + if rule['hash']:get_key(r['addr']) then + task:insert_result(rule['symbol'], 1) + end + end + end + end + end + end + elseif rule['type'] == 'from' then + -- First try to get from field + local from = task:get_from() + if from then + for _,r in ipairs(from) do + if r['addr'] then + if rule['pattern'] then + -- extract a part from header + local _,_,ext = string.find(r['addr'], rule['pattern']) + if ext then + if rule['hash']:get_key(ext) then + task:insert_result(rule['symbol'], 1) + end + end + else + if rule['hash']:get_key(r['addr']) then + task:insert_result(rule['symbol'], 1) + end + end + end + end + else + -- Get from headers + local from = task:get_from_headers() + if from then + for _,r in ipairs(from) do + if r['addr'] then + if rule['pattern'] then + -- extract a part from header + local _,_,ext = string.find(r['addr'], rule['pattern']) + if ext then + if rule['hash']:get_key(ext) then + task:insert_result(rule['symbol'], 1) + end + end + else + if rule['hash']:get_key(r['addr']) then + task:insert_result(rule['symbol'], 1) + end + end + end + end + end + end end end end @@ -98,6 +186,10 @@ local function add_multimap_rule(params) newrule['type'] = 'dnsbl' elseif value == 'header' then newrule['type'] = 'header' + elseif value == 'rcpt' then + newrule['type'] = 'rcpt' + elseif value == 'from' then + newrule['type'] = 'from' else rspamd_logger:err('invalid rule type: '.. value) return nil @@ -116,13 +208,13 @@ local function add_multimap_rule(params) end end - if not newrule['symbol'] or not newrule['map'] or not newrule['symbol'] then + if not newrule['symbol'] or not newrule['map'] then rspamd_logger:err('incomplete rule') return nil end if newrule['type'] == 'ip' then newrule['ips'] = rspamd_config:add_radix_map (newrule['map']) - elseif newrule['type'] == 'header' then + elseif newrule['type'] == 'header' or newrule['type'] == 'rcpt' or newrule['type'] == 'from' then newrule['hash'] = rspamd_config:add_hash_map (newrule['map']) end table.insert(rules, newrule) -- 2.39.5