Rapid spam filtering system https://rspamd.com/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

212 lines
5.9 KiB

/* Copyright (c) 2010-2012, Vsevolod Stakhov
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "config.h"
#include "main.h"
#include "roll_history.h"
/**
* Returns new roll history
* @param pool pool for shared memory
* @return new structure
*/
struct roll_history*
rspamd_roll_history_new (rspamd_mempool_t *pool)
{
struct roll_history *new;
if (pool == NULL) {
return NULL;
}
new = rspamd_mempool_alloc0_shared (pool, sizeof (struct roll_history));
new->pool = pool;
new->mtx = rspamd_mempool_get_mutex (pool);
return new;
}
struct history_metric_callback_data {
gchar *pos;
gint remain;
};
static void
roll_history_symbols_callback (gpointer key, gpointer value, void *user_data)
{
struct history_metric_callback_data *cb = user_data;
struct symbol *s = value;
guint wr;
if (cb->remain > 0) {
wr = rspamd_snprintf (cb->pos, cb->remain, "%s, ", s->name);
cb->pos += wr;
cb->remain -= wr;
}
}
/**
* Update roll history with data from task
* @param history roll history object
* @param task task object
*/
void
rspamd_roll_history_update (struct roll_history *history, struct rspamd_task *task)
{
gint row_num;
struct roll_history_row *row;
struct metric_result *metric_res;
struct history_metric_callback_data cbdata;
if (history->need_lock) {
/* Some process is getting history, so wait on a mutex */
rspamd_mempool_lock_mutex (history->mtx);
history->need_lock = FALSE;
rspamd_mempool_unlock_mutex (history->mtx);
}
/* First of all obtain check and obtain row number */
g_atomic_int_compare_and_exchange (&history->cur_row, HISTORY_MAX_ROWS, 0);
#if ((GLIB_MAJOR_VERSION == 2) && (GLIB_MINOR_VERSION > 30))
row_num = g_atomic_int_add (&history->cur_row, 1);
#else
row_num = g_atomic_int_exchange_and_add (&history->cur_row, 1);
#endif
if (row_num < HISTORY_MAX_ROWS) {
row = &history->rows[row_num];
row->completed = FALSE;
}
else {
/* Race condition */
history->cur_row = 0;
return;
}
/* Add information from task to roll history */
memcpy (&row->from_addr, &task->from_addr, sizeof (row->from_addr));
memcpy (&row->tv, &task->tv, sizeof (row->tv));
/* Strings */
rspamd_strlcpy (row->message_id, task->message_id, sizeof (row->message_id));
if (task->user) {
rspamd_strlcpy (row->user, task->user, sizeof (row->message_id));
}
else {
row->user[0] = '\0';
}
/* Get default metric */
metric_res = g_hash_table_lookup (task->results, DEFAULT_METRIC);
if (metric_res == NULL) {
row->symbols[0] = '\0';
row->action = METRIC_ACTION_NOACTION;
}
else {
row->score = metric_res->score;
row->required_score = metric_res->metric->actions[METRIC_ACTION_REJECT].score;
row->action = check_metric_action (metric_res->score,
metric_res->metric->actions[METRIC_ACTION_REJECT].score, metric_res->metric);
cbdata.pos = row->symbols;
cbdata.remain = sizeof (row->symbols);
g_hash_table_foreach (metric_res->symbols, roll_history_symbols_callback, &cbdata);
if (cbdata.remain > 0) {
/* Remove last whitespace and comma */
*cbdata.pos-- = '\0';
*cbdata.pos-- = '\0';
*cbdata.pos = '\0';
}
}
row->scan_time = task->scan_milliseconds;
row->len = (task->msg == NULL ? 0 : task->msg->len);
row->completed = TRUE;
}
/**
* Load previously saved history from file
* @param history roll history object
* @param filename filename to load from
* @return TRUE if history has been loaded
*/
gboolean
rspamd_roll_history_load (struct roll_history *history, const gchar *filename)
{
gint fd;
struct stat st;
if (stat (filename, &st) == -1) {
msg_info ("cannot load history from %s: %s", filename, strerror (errno));
return FALSE;
}
if (st.st_size != sizeof (history->rows)) {
msg_info ("cannot load history from %s: size mismatch", filename);
return FALSE;
}
if ((fd = open (filename, O_RDONLY)) == -1) {
msg_info ("cannot load history from %s: %s", filename, strerror (errno));
return FALSE;
}
if (read (fd, history->rows, sizeof (history->rows)) == -1) {
close (fd);
msg_info ("cannot read history from %s: %s", filename, strerror (errno));
return FALSE;
}
close (fd);
return TRUE;
}
/**
* Save history to file
* @param history roll history object
* @param filename filename to load from
* @return TRUE if history has been saved
*/
gboolean
rspamd_roll_history_save (struct roll_history *history, const gchar *filename)
{
gint fd;
if ((fd = open (filename, O_WRONLY | O_CREAT | O_TRUNC, 00600)) == -1) {
msg_info ("cannot save history to %s: %s", filename, strerror (errno));
return FALSE;
}
if (write (fd, history->rows, sizeof (history->rows)) == -1) {
close (fd);
msg_info ("cannot write history to %s: %s", filename, strerror (errno));
return FALSE;
}
close (fd);
return TRUE;
}