Fix possible deadlock in lua_redis.
Version is now 0.4.8 as there are enough changes.
SET(RSPAMD_VERSION_MAJOR 0)
SET(RSPAMD_VERSION_MINOR 4)
-SET(RSPAMD_VERSION_PATCH 7)
+SET(RSPAMD_VERSION_PATCH 8)
SET(RSPAMD_VERSION "${RSPAMD_VERSION_MAJOR}.${RSPAMD_VERSION_MINOR}.${RSPAMD_VERSION_PATCH}")
reconf['FORGED_GENERIC_RECEIVED4'] = 'Received=/^\\s*(.+\\n)*from localhost by \\S+;\\s+\\w{3}, \\d+ \\w{3} 20\\d\\d \\d\\d\\:\\d\\d\\:\\d\\d [+-]\\d\\d\\d0[\\s\\r\\n]*$/X'
reconf['FORGED_GENERIC_RECEIVED5'] = function (task)
- local regexp_text = 'Received:\\s*from \\[(\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3})\\].*\\n(.+\\n)*Received:\\s*from \\1 by \\S+;\\s+\\w{3}, \\d+ \\w{3} 20\\d\\d \\d\\d\\:\\d\\d\\:\\d\\d [+-]\\d\\d\\d0\\n'
+ local regexp_text = '^\\s*from \\[(\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3})\\].*\\n(.+\\n)*\\s*from \\1 by \\S+;\\s+\\w{3}, \\d+ \\w{3} 20\\d\\d \\d\\d\\:\\d\\d\\:\\d\\d [+-]\\d\\d\\d0$'
local re = regexp.get_cached(regexp_text)
if not re then re = regexp.create(regexp_text, 'i') end
- local res = re:match(task:get_raw_headers())
- if res then
- return true
- else
- return false
- end
+ local headers_recv = task:get_raw_header('Received')
+ if headers_recv then
+ for _,header_r in ipairs(headers_recv) do
+ if re:match(header_r['value']) then
+ return true
+ end
+ end
+ end
+ return false
end
reconf['INVALID_POSTFIX_RECEIVED'] = 'Received=/ \\(Postfix\\) with ESMTP id [A-Z\\d]+([\\s\\r\\n]+for <\\S+?>)?;[\\s\\r\\n]*[A-Z][a-z]{2}, \\d{1,2} [A-Z][a-z]{2} \\d\\d\\d\\d \\d\\d:\\d\\d:\\d\\d [\\+\\-]\\d\\d\\d\\d$/X'
reconf['INVALID_EXIM_RECEIVED'] = function (task)
local headers_to = task:get_message():get_header('To')
- if headers_to then
- local raw_headers = task:get_raw_headers()
+ if headers_to and table.maxn(headers_to) < 5 then
+ local headers_recv = task:get_raw_header('Received')
local regexp_text = '^[^\\n]*?<?\\S+?\\@(\\S+)>?\\|.*from \\d+\\.\\d+\\.\\d+\\.\\d+ \\(HELO \\S+\\)[\\s\\r\\n]*by \\1 with esmtp \\(\\S*?[\\?\\@\\(\\)\\s\\.\\+\\*\'\'\\/\\\\,]\\S*\\)[\\s\\r\\n]+id \\S*?[\\)\\(<>\\/\\\\,\\-:=]'
local re = regexp.get_cached(regexp_text)
if not re then re = regexp.create(regexp_text, 's') end
- for _,header_to in ipairs(headers_to) do
- if re:match(header_to.."|"..raw_headers) then
+ if headers_recv then
+ for _,header_to in ipairs(headers_to) do
+ for _,header_r in ipairs(headers_recv) do
+ if re:match(header_to.."|"..header_r['value']) then
return true
- end
+ end
+ end
+ end
end
end
return false
reconf['INVALID_EXIM_RECEIVED2'] = function (task)
local headers_to = task:get_message():get_header('To')
- if headers_to then
- local raw_headers = task:get_raw_headers()
+ if headers_to and table.maxn(headers_to) < 5 then
+ local headers_recv = task:get_raw_header('Received')
local regexp_text = '^[^\\n]*?<?\\S+?\\@(\\S+)>?\\|.*from \\d+\\.\\d+\\.\\d+\\.\\d+ \\(HELO \\S+\\)[\\s\\r\\n]*by \\1 with esmtp \\([A-Z]{9,12} [A-Z]{5,6}\\)[\\s\\r\\n]+id [a-zA-Z\\d]{6}-[a-zA-Z\\d]{6}-[a-zA-Z\\d]{2}[\\s\\r\\n]+'
local re = regexp.get_cached(regexp_text)
if not re then re = regexp.create(regexp_text, 's') end
- for _,header_to in ipairs(headers_to) do
- if re:match(header_to.."|"..raw_headers) then
+ if headers_recv then
+ for _,header_to in ipairs(headers_to) do
+ for _,header_r in ipairs(headers_recv) do
+ if re:match(header_to.."|"..header_r['value']) then
return true
- end
+ end
+ end
+ end
end
end
return false
lua_redis_push_error (const gchar *err, struct lua_redis_userdata *ud, gboolean connected)
{
struct worker_task **ptask;
+ gboolean need_unlock = FALSE;
- g_mutex_lock (lua_mtx);
+ /* Avoid LOR here as mutex can be acquired before in lua_call */
+ if (g_mutex_trylock (lua_mtx)) {
+ need_unlock = TRUE;
+ }
/* Push error */
lua_rawgeti (ud->L, LUA_REGISTRYINDEX, ud->cbref);
ptask = lua_newuserdata (ud->L, sizeof (struct worker_task *));
if (lua_pcall (ud->L, 3, 0, 0) != 0) {
msg_info ("call to callback failed: %s", lua_tostring (ud->L, -1));
}
- g_mutex_unlock (lua_mtx);
+ if (need_unlock) {
+ g_mutex_unlock (lua_mtx);
+ }
if (connected) {
remove_normal_event (ud->task->s, lua_redis_fin, ud);
lua_redis_push_data (const redisReply *r, struct lua_redis_userdata *ud)
{
struct worker_task **ptask;
+ gboolean need_unlock = FALSE;
- g_mutex_lock (lua_mtx);
+ if (g_mutex_trylock (lua_mtx)) {
+ need_unlock = TRUE;
+ }
/* Push error */
lua_rawgeti (ud->L, LUA_REGISTRYINDEX, ud->cbref);
ptask = lua_newuserdata (ud->L, sizeof (struct worker_task *));
if (lua_pcall (ud->L, 3, 0, 0) != 0) {
msg_info ("call to callback failed: %s", lua_tostring (ud->L, -1));
}
- g_mutex_unlock (lua_mtx);
+ if (need_unlock) {
+ g_mutex_unlock (lua_mtx);
+ }
remove_normal_event (ud->task->s, lua_redis_fin, ud);
}
LUA_FUNCTION_DEF (task, get_images);
LUA_FUNCTION_DEF (task, get_symbol);
LUA_FUNCTION_DEF (task, get_date);
+LUA_FUNCTION_DEF (task, get_message_id);
LUA_FUNCTION_DEF (task, get_timeval);
LUA_FUNCTION_DEF (task, get_metric_score);
LUA_FUNCTION_DEF (task, get_metric_action);
LUA_INTERFACE_DEF (task, get_images),
LUA_INTERFACE_DEF (task, get_symbol),
LUA_INTERFACE_DEF (task, get_date),
+ LUA_INTERFACE_DEF (task, get_message_id),
LUA_INTERFACE_DEF (task, get_timeval),
LUA_INTERFACE_DEF (task, get_metric_score),
LUA_INTERFACE_DEF (task, get_metric_action),
return 1;
}
+static gint
+lua_task_get_message_id (lua_State *L)
+{
+ struct worker_task *task = lua_check_task (L);
+
+ if (task != NULL && task->message_id != NULL) {
+ lua_pushstring (L, task->message_id);
+ }
+ else {
+ lua_pushnil (L);
+ }
+
+ return 1;
+}
+
static gint
lua_task_get_timeval (lua_State *L)
{
-- Do not check ratelimits for these senders
local whitelisted_rcpts = {'postmaster', 'mailer-daemon'}
local whitelisted_ip = nil
+local max_rcpt = 5
local upstreams = nil
--- Parse atime and bucket of limit
rcpts = task:get_recipients_headers()
end
if rcpts then
+ if table.maxn(rcpts) > max_rcpt then
+ rspamd_logger.info(string.format('message <%s> contains %d recipients, maximum is %d',
+ task:get_message_id(), table.maxn(rcpts), max_rcpt))
+ return
+ end
for i,r in ipairs(rcpts) do
rcpts_user[i] = get_local_part(r['addr'])
end
rspamd_config:register_module_option('ratelimit', 'whitelisted_rcpts', 'string')
rspamd_config:register_module_option('ratelimit', 'whitelisted_ip', 'map')
rspamd_config:register_module_option('ratelimit', 'limit', 'string')
+ rspamd_config:register_module_option('ratelimit', 'max_rcpt', 'uint')
end
local function parse_whitelisted_rcpts(str)
whitelisted_ip = rspamd_config:add_hash_map (opts['whitelisted_ip'])
end
+ if opts['max_rcpt'] then
+ max_rcpt = tonumber (opts['max_rcpt'])
+ end
+
if not opts['servers'] then
rspamd_logger.err('no servers are specified')
else
rspamd_config:register_post_filter(rate_set)
end
end
-end
+end
\ No newline at end of file