]> source.dussan.org Git - rspamd.git/commitdiff
* Add multimaps for "FROM" and "TO" headers (mime an smtp data can be checked)
authorVsevolod Stakhov <vsevolod@rambler-co.ru>
Fri, 4 Mar 2011 16:38:04 +0000 (19:38 +0300)
committerVsevolod Stakhov <vsevolod@rambler-co.ru>
Fri, 4 Mar 2011 16:38:04 +0000 (19:38 +0300)
* Improve lua api for getting message's sender and recipients

src/lua/lua_task.c
src/message.c
src/plugins/lua/forged_recipients.lua
src/plugins/lua/multimap.lua

index 0a6185f7e25ac7e645c12d0de419de7ba66d5997..4a40008f325ade3521784162bc2472fab23ee130 100644 (file)
@@ -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)
 {
index 86e333dc1972777b1f69e98aa0117230396c28d2..80711b79178ae71fc70e3e46d08280199df65efb 100644 (file)
@@ -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)) {
index d082b386d343929906329b5b64ed2ab6e043d6dd..36659137787c6d86968aba18c4211ecce897d2d9 100644 (file)
@@ -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
index 9512ff89041fc44a7a7b73d31375a1f35c3c9a57..15c90665732a0d29542ddb9e36ce069209927bb3 100644 (file)
@@ -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)