]> source.dussan.org Git - rspamd.git/commitdiff
* Add reject score setting for hard rejecting of mail (by Anton Nekhoroshin)
authorVsevolod Stakhov <vsevolod@rambler-co.ru>
Fri, 2 Oct 2009 16:23:16 +0000 (20:23 +0400)
committerVsevolod Stakhov <vsevolod@rambler-co.ru>
Fri, 2 Oct 2009 16:23:16 +0000 (20:23 +0400)
* Add rspamc protocol 1.1 (3 marks instead of 2)

12 files changed:
rspamc.pl.in
src/cfg_file.h
src/cfg_file.l
src/cfg_file.y
src/cfg_utils.c
src/filter.c
src/filter.h
src/main.h
src/protocol.c
src/protocol.h
src/settings.c
src/settings.h

index e82ec0b47ec1b1475e1d8b4cb46e223a06b957e1..17e830e3b4a602efe80245b6cac8215cf44017fc 100755 (executable)
@@ -120,7 +120,7 @@ sub do_rspamc_command {
 
     print "Sending ". length ($input) ." bytes...\n";
 
-    syswrite $sock, "$cfg{'command'} RSPAMC/1.0 $CRLF";
+    syswrite $sock, "$cfg{'command'} RSPAMC/1.1 $CRLF";
        if ($cfg{'deliver_to'}) {
                syswrite $sock, "Deliver-To: " . $cfg{'deliver_to'} . $CRLF;
        }
index 527c3f7c62cb9c9019fb76eff14769f57ffcf357..afa150a4cec6a9360ac1fef0315cf94ff33de5ab 100644 (file)
@@ -29,6 +29,9 @@
 /* 1 worker by default */
 #define DEFAULT_WORKERS_NUM 1
 
+#define DEFAULT_SCORE 10.0
+#define DEFAULT_REJECT_SCORE 999.0
+
 #define yyerror parse_err
 #define yywarn parse_warn
 
index 7646c87cf36343a5e195012be99e9ac938f8950e..671146be1556358c15e144de987e63d1c6facfa4 100644 (file)
@@ -66,6 +66,7 @@ factors                                                       return FACTORS;
 metric                                                 return METRIC;
 name                                                   return NAME;
 required_score                                 return REQUIRED_SCORE;
+reject_score                                   return REJECT_SCORE;
 function                                               return FUNCTION;
 cache_file                                             return CACHE_FILE;
 control                                                        return CONTROL;
index 7d9316b60b0126b6c849380cf2f5737a1148321a..85dcb9df51e4e3bd36be2360df57b55c05168f7e 100644 (file)
@@ -52,7 +52,7 @@ struct rspamd_view *cur_view = NULL;
 %token  MEMCACHED WORKER TYPE MODULES MODULE_PATH
 %token  MODULE_OPT PARAM VARIABLE
 %token  FILTERS FACTORS METRIC NAME CACHE_FILE
-%token  REQUIRED_SCORE FUNCTION FRACT COMPOSITES CONTROL PASSWORD
+%token  REQUIRED_SCORE REJECT_SCORE FUNCTION FRACT COMPOSITES CONTROL PASSWORD
 %token  LOGGING LOG_TYPE LOG_TYPE_CONSOLE LOG_TYPE_SYSLOG LOG_TYPE_FILE
 %token  LOG_LEVEL LOG_LEVEL_DEBUG LOG_LEVEL_INFO LOG_LEVEL_WARNING LOG_LEVEL_ERROR LOG_FACILITY LOG_FILENAME
 %token  STATFILE ALIAS PATTERN WEIGHT STATFILE_POOL_SIZE SIZE TOKENIZER CLASSIFIER
@@ -365,6 +365,7 @@ metriccmd:
        | metricname
        | metricfunction
        | metricscore
+       | metricrjscore
        | metricclassifier
        | metriccache
        ;
@@ -409,6 +410,21 @@ metricscore:
        }
        ;
 
+metricrjscore:
+       REJECT_SCORE EQSIGN NUMBER {
+               if (cur_metric == NULL) {
+                       cur_metric = memory_pool_alloc0 (cfg->cfg_pool, sizeof (struct metric));
+               }
+               cur_metric->reject_score = $3;
+       }
+       | REQUIRED_SCORE EQSIGN FRACT {
+               if (cur_metric == NULL) {
+                       cur_metric = memory_pool_alloc0 (cfg->cfg_pool, sizeof (struct metric));
+               }
+               cur_metric->reject_score = $3;
+       }
+       ;
+
 metricclassifier:
        CLASSIFIER EQSIGN QUOTEDSTRING {
                if (cur_metric == NULL) {
index 9387ca36faae31dca09296852da68ef2d95b01aa..a1113f516b858ff3c6a9419c312890176ad01341 100644 (file)
@@ -520,6 +520,7 @@ post_load_config (struct config_file *cfg)
                def_metric->func_name = "factors";
                def_metric->func = factor_consolidation_func;
                def_metric->required_score = DEFAULT_SCORE;
+               def_metric->reject_score = DEFAULT_REJECT_SCORE;
                def_metric->classifier = get_classifier ("winnow");
                cfg->metrics_list = g_list_prepend (cfg->metrics_list, def_metric);
                g_hash_table_insert (cfg->metrics, DEFAULT_METRIC, def_metric);
index 0ffec02d535ea98b02bd77c0405d9281c1d64bc4..efda9fa727ac585c561f9640950175088279ff16 100644 (file)
@@ -234,12 +234,12 @@ static                          gboolean
 check_metric_is_spam (struct worker_task *task, struct metric *metric)
 {
        struct metric_result           *res;
-       double                          ms;
+       double                          ms, rs;
 
        res = g_hash_table_lookup (task->results, metric->name);
        if (res) {
                metric_process_callback_forced (metric->name, res, task);
-               if (!check_metric_settings (task, metric, &ms)) {
+               if (!check_metric_settings (task, metric, &ms, &rs)) {
                        ms = metric->required_score;
                }
                return res->score >= ms;
@@ -572,18 +572,18 @@ insert_metric_header (gpointer metric_name, gpointer metric_value, gpointer data
        char                            header_name[128], outbuf[1000];
        GList                          *symbols = NULL, *cur;
        struct metric_result           *metric_res = (struct metric_result *)metric_value;
-       double                          ms;
+       double                          ms, rs;
 
        snprintf (header_name, sizeof (header_name), "X-Spam-%s", metric_res->metric->name);
 
-       if (!check_metric_settings (task, metric_res->metric, &ms)) {
+       if (!check_metric_settings (task, metric_res->metric, &ms, &rs)) {
                ms = metric_res->metric->required_score;
        }
        if (metric_res->score >= ms) {
-               r += snprintf (outbuf + r, sizeof (outbuf) - r, "yes; %.2f/%.2f; ", metric_res->score, ms);
+               r += snprintf (outbuf + r, sizeof (outbuf) - r, "yes; %.2f/%.2f/%.2f; ", metric_res->score, ms, rs);
        }
        else {
-               r += snprintf (outbuf + r, sizeof (outbuf) - r, "no; %.2f/%.2f; ", metric_res->score, ms);
+               r += snprintf (outbuf + r, sizeof (outbuf) - r, "no; %.2f/%.2f/%.2f; ", metric_res->score, ms, rs);
        }
 
        symbols = g_hash_table_get_keys (metric_res->symbols);
index 6ff3ae1d0c72c0771cf2502e91bdb94c90e1bfab..edc9523c6b2dd466ad00244cb8e47457b779ab19 100644 (file)
@@ -41,6 +41,7 @@ struct metric {
        char *func_name;                                                                /**< name of consolidation function                     */
        metric_cons_func func;                                                  /**< c consolidation function                           */
        double required_score;                                                  /**< required score for this metric                     */
+       double reject_score;                                                    /**< reject score for this metric                       */
        struct classifier *classifier;                                  /**< classifier that is used for metric         */
        struct symbols_cache *cache;                                    /**< symbols cache for metric                           */ 
        char *cache_filename;                                                   /**< filename of cache file                                     */
index cb922252cdcdbdcf8918f20e792459c18cd4afd6..55a62c86c21333827cfb689ded6f9d5152c03207 100644 (file)
@@ -169,6 +169,7 @@ struct worker_task {
        } state;                                                                                                        /**< current session state                                                      */
        size_t content_length;                                                                          /**< length of user's input                                                     */
        enum rspamd_protocol proto;                                                                     /**< protocol (rspamc or spamc)                                         */
+       const char *proto_ver;                                                                          /**< protocol version                                                           */
        enum rspamd_command cmd;                                                                        /**< command                                                                            */
        struct custom_command *custom_cmd;                                                      /**< custom command if any                                                      */      
        int sock;                                                                                                       /**< socket descriptor                                                          */
index a902cb50552372869ce748a4c14cdec51a392da5..6a8f9b8f0a2b35ad4c6c127858cadb3a6d19657e 100644 (file)
@@ -195,14 +195,25 @@ parse_command (struct worker_task *task, f_str_t * line)
 
        if (strncasecmp (line->begin, RSPAMC_GREETING, sizeof (RSPAMC_GREETING) - 1) == 0) {
                task->proto = RSPAMC_PROTO;
+               task->proto_ver = RSPAMC_PROTO_1_0;
+               if (*(line->begin + sizeof (RSPAMC_GREETING) - 1) == '/') {
+                       /* Extract protocol version */
+                       token = line->begin + sizeof (RSPAMC_GREETING);
+                       if (strncmp (token, RSPAMC_PROTO_1_1, sizeof (RSPAMC_PROTO_1_1) - 1) == 0) {
+                               task->proto_ver = RSPAMC_PROTO_1_1;
+                       }
+               }
        }
        else if (strncasecmp (line->begin, SPAMC_GREETING, sizeof (SPAMC_GREETING) - 1) == 0) {
                task->proto = SPAMC_PROTO;
+               task->proto_ver = RSPAMC_PROTO_1_1;
        }
        else {
                return -1;
        }
+
        task->state = READ_HEADER;
+       
        return 0;
 }
 
@@ -505,25 +516,32 @@ show_metric_result (gpointer metric_name, gpointer metric_value, void *user_data
        struct metric_result           *metric_res = (struct metric_result *)metric_value;
        struct metric                  *m;
        int                             is_spam = 0;
-       double                          ms;
+       double                          ms = 0, rs = 0;
 
 
        if (metric_name == NULL || metric_value == NULL) {
                m = g_hash_table_lookup (task->cfg->metrics, "default");
-               if (!check_metric_settings (task, m, &ms)) {
+               if (!check_metric_settings (task, m, &ms, &rs)) {
                        ms = m->required_score;
+                       rs = m->reject_score;
                }
                if (task->proto == SPAMC_PROTO) {
-                       r = snprintf (outbuf, sizeof (outbuf), "Spam: False ; 0 / %.2f" CRLF, m != NULL ? ms : 0);
+                       r = snprintf (outbuf, sizeof (outbuf), "Spam: False ; 0 / %.2f" CRLF, ms);
                }
                else {
-                       r = snprintf (outbuf, sizeof (outbuf), "Metric: default; False; 0 / %.2f" CRLF, m != NULL ? ms : 0);
+                       if (strcmp (task->proto_ver, RSPAMC_PROTO_1_1) == 0) {
+                               r = snprintf (outbuf, sizeof (outbuf), "Metric: default; False; 0 / %.2f / %.2f" CRLF, ms, rs);
+                       }
+                       else {
+                               r = snprintf (outbuf, sizeof (outbuf), "Metric: default; False; 0 / %.2f" CRLF, ms);
+                       }
                }
-               cd->log_offset += snprintf (cd->log_buf + cd->log_offset, cd->log_size - cd->log_offset, "(%s: F: [0/%.2f] [", "default", m != NULL ? ms : 0);
+               cd->log_offset += snprintf (cd->log_buf + cd->log_offset, cd->log_size - cd->log_offset, "(%s: F: [0/%.2f/%.2f] [", "default", ms, rs);
        }
        else {
-               if (!check_metric_settings (task, metric_res->metric, &ms)) {
+               if (!check_metric_settings (task, metric_res->metric, &ms, &rs)) {
                        ms = metric_res->metric->required_score;
+                       rs = metric_res->metric->reject_score;
                }
                if (metric_res->score >= ms) {
                        is_spam = 1;
@@ -532,9 +550,17 @@ show_metric_result (gpointer metric_name, gpointer metric_value, void *user_data
                        r = snprintf (outbuf, sizeof (outbuf), "Spam: %s ; %.2f / %.2f" CRLF, (is_spam) ? "True" : "False", metric_res->score, ms);
                }
                else {
-                       r = snprintf (outbuf, sizeof (outbuf), "Metric: %s; %s; %.2f / %.2f" CRLF, (char *)metric_name, (is_spam) ? "True" : "False", metric_res->score, ms);
+                       if (strcmp (task->proto_ver, RSPAMC_PROTO_1_1) == 0) {
+                               r = snprintf (outbuf, sizeof (outbuf), "Metric: %s; %s; %.2f / %.2f / %.2f" CRLF, 
+                                               (char *)metric_name, (is_spam) ? "True" : "False", metric_res->score, ms, rs);
+                       }
+                       else {
+                               r = snprintf (outbuf, sizeof (outbuf), "Metric: %s; %s; %.2f / %.2f" CRLF, 
+                                               (char *)metric_name, (is_spam) ? "True" : "False", metric_res->score, ms);
+                       }
                }
-               cd->log_offset += snprintf (cd->log_buf + cd->log_offset, cd->log_size - cd->log_offset, "(%s: %s: [%.2f/%.2f] [", (char *)metric_name, is_spam ? "T" : "F", metric_res->score, ms);
+               cd->log_offset += snprintf (cd->log_buf + cd->log_offset, cd->log_size - cd->log_offset, "(%s: %s: [%.2f/%.2f/%.2f] [", 
+                               (char *)metric_name, is_spam ? "T" : "F", metric_res->score, ms, rs);
        }
        if (task->cmd == CMD_PROCESS) {
 #ifndef GMIME24
@@ -562,7 +588,8 @@ write_check_reply (struct worker_task *task)
        struct metric_result           *metric_res;
        struct metric_callback_data     cd;
 
-       r = snprintf (outbuf, sizeof (outbuf), "%s 0 %s" CRLF, (task->proto == SPAMC_PROTO) ? SPAMD_REPLY_BANNER : RSPAMD_REPLY_BANNER, "OK");
+       r = snprintf (outbuf, sizeof (outbuf), "%s/%s 0 %s" CRLF, (task->proto == SPAMC_PROTO) ? SPAMD_REPLY_BANNER : RSPAMD_REPLY_BANNER,
+                                       task->proto_ver, "OK");
        rspamd_dispatcher_write (task->dispatcher, outbuf, r, TRUE, FALSE);
 
        cd.task = task;
@@ -613,7 +640,9 @@ write_process_reply (struct worker_task *task)
        struct metric_result           *metric_res;
        struct metric_callback_data     cd;
 
-       r = snprintf (outbuf, sizeof (outbuf), "%s 0 %s" CRLF "Content-Length: %zd" CRLF CRLF, (task->proto == SPAMC_PROTO) ? SPAMD_REPLY_BANNER : RSPAMD_REPLY_BANNER, "OK", task->msg->len);
+       r = snprintf (outbuf, sizeof (outbuf), "%s/%s 0 %s" CRLF "Content-Length: %zd" CRLF CRLF, 
+                       (task->proto == SPAMC_PROTO) ? SPAMD_REPLY_BANNER : RSPAMD_REPLY_BANNER, 
+                       task->proto_ver, "OK", task->msg->len);
 
        cd.task = task;
        cd.log_buf = logbuf;
@@ -669,11 +698,13 @@ write_reply (struct worker_task *task)
        if (task->error_code != 0) {
                /* Write error message and error code to reply */
                if (task->proto == SPAMC_PROTO) {
-                       r = snprintf (outbuf, sizeof (outbuf), "%s %d %s" CRLF CRLF, SPAMD_REPLY_BANNER, task->error_code, SPAMD_ERROR);
+                       r = snprintf (outbuf, sizeof (outbuf), "%s/%s %d %s" CRLF CRLF, 
+                                       SPAMD_REPLY_BANNER, task->proto_ver, task->error_code, SPAMD_ERROR);
                        msg_debug ("write_reply: writing error: %s", outbuf);
                }
                else {
-                       r = snprintf (outbuf, sizeof (outbuf), "%s %d %s" CRLF "%s: %s" CRLF CRLF, RSPAMD_REPLY_BANNER, task->error_code, SPAMD_ERROR, ERROR_HEADER, task->last_error);
+                       r = snprintf (outbuf, sizeof (outbuf), "%s/%s %d %s" CRLF "%s: %s" CRLF CRLF, 
+                                       RSPAMD_REPLY_BANNER, task->proto_ver, task->error_code, SPAMD_ERROR, ERROR_HEADER, task->last_error);
                        msg_debug ("write_reply: writing error: %s", outbuf);
                }
                /* Write to bufferevent error message */
@@ -691,11 +722,13 @@ write_reply (struct worker_task *task)
                        return write_process_reply (task);
                        break;
                case CMD_SKIP:
-                       r = snprintf (outbuf, sizeof (outbuf), "%s 0 %s" CRLF, (task->proto == SPAMC_PROTO) ? SPAMD_REPLY_BANNER : RSPAMD_REPLY_BANNER, SPAMD_OK);
+                       r = snprintf (outbuf, sizeof (outbuf), "%s/%s 0 %s" CRLF, 
+                                       (task->proto == SPAMC_PROTO) ? SPAMD_REPLY_BANNER : RSPAMD_REPLY_BANNER, task->proto_ver, SPAMD_OK);
                        rspamd_dispatcher_write (task->dispatcher, outbuf, r, FALSE, FALSE);
                        break;
                case CMD_PING:
-                       r = snprintf (outbuf, sizeof (outbuf), "%s 0 PONG" CRLF, (task->proto == SPAMC_PROTO) ? SPAMD_REPLY_BANNER : RSPAMD_REPLY_BANNER);
+                       r = snprintf (outbuf, sizeof (outbuf), "%s/%s 0 PONG" CRLF, 
+                                       (task->proto == SPAMC_PROTO) ? SPAMD_REPLY_BANNER : RSPAMD_REPLY_BANNER, task->proto_ver);
                        rspamd_dispatcher_write (task->dispatcher, outbuf, r, FALSE, FALSE);
                        break;
                case CMD_OTHER:
index b4783cb30771eb1fb81a8c9c0ee288015916fe6a..4c12cc4815ddc6741deddb94a92906ddb26c68c5 100644 (file)
 #define RSPAMD_PROTOCOL_ERROR 3
 #define RSPAMD_LENGTH_ERROR 4
 
+#define RSPAMC_PROTO_1_0 "1.0"
+#define RSPAMC_PROTO_1_1 "1.1"
+
 /*
  * Reply messages
  */
-#define RSPAMD_REPLY_BANNER "RSPAMD/1.0"
-#define SPAMD_REPLY_BANNER "SPAMD/1.1"
+#define RSPAMD_REPLY_BANNER "RSPAMD"
+#define SPAMD_REPLY_BANNER "SPAMD"
 #define SPAMD_OK "EX_OK"
 /* XXX: try to convert rspamd errors to spamd errors */
 #define SPAMD_ERROR "EX_ERROR"
index a4dca10dd6a5aa4a6ccb436b59ed1090f26c4e02..bcb40505c1c0b28487223a8099ce0d803440251f 100644 (file)
@@ -50,6 +50,9 @@ settings_free (gpointer data)
        if (s->metric_scores) {
                g_hash_table_destroy (s->metric_scores);
        }
+       if (s->reject_scores) {
+               g_hash_table_destroy (s->reject_scores);
+       }
        g_free (s);
 }
 
@@ -149,6 +152,7 @@ json_fin_cb (memory_pool_t * pool, struct map_cb_data *data)
        for (i = 0; i < nelts; i++) {
                cur_settings = g_malloc (sizeof (struct rspamd_settings));
                cur_settings->metric_scores = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
+               cur_settings->reject_scores = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
                cur_settings->factors = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
                cur_settings->statfile_alias = NULL;
                cur_settings->want_spam = FALSE;
@@ -198,6 +202,21 @@ json_fin_cb (memory_pool_t * pool, struct map_cb_data *data)
                                json_it = json_object_iter_next (cur_nm, json_it);
                        }
                }
+               /* Rejects object */
+               cur_nm = json_object_get (cur_elt, "rejects");
+               if (cur_nm != NULL && json_is_object (cur_nm)) {
+                       json_it = json_object_iter (cur_nm);
+                       while (json_it) {
+                               it_val = json_object_iter_value (json_it);
+                               if (it_val && json_is_number (it_val)) {
+                                       score = g_malloc (sizeof (double));
+                                       *score = json_number_value (it_val);
+                                       g_hash_table_insert (cur_settings->reject_scores, g_strdup (json_object_iter_key (json_it)), 
+                                                                                       score);
+                               }
+                               json_it = json_object_iter_next(cur_nm, json_it);
+                       }
+               }
                /* Want spam */
                cur_nm = json_object_get (cur_elt, "want_spam");
                if (cur_nm != NULL) {
@@ -284,25 +303,36 @@ check_setting (struct worker_task *task, struct rspamd_settings **user_settings,
 }
 
 gboolean
-check_metric_settings (struct worker_task * task, struct metric * metric, double *score)
+check_metric_settings (struct worker_task * task, struct metric * metric, double *score, double *rscore)
 {
        struct rspamd_settings         *us, *ds;
-       double                         *sc;
+       double                         *sc, *rs;
+
+       *rscore = DEFAULT_REJECT_SCORE;
 
        if (check_setting (task, &us, &ds)) {
                if (us != NULL) {
                        /* First search in user's settings */
+                       if ((rs = g_hash_table_lookup (us->reject_scores, metric->name)) != NULL) {
+                               *rscore = *rs;
+                       }
                        if ((sc = g_hash_table_lookup (us->metric_scores, metric->name)) != NULL) {
                                *score = *sc;
                                return TRUE;
                        }
                        /* Now check in domain settings */
+                       if (ds && ((rs = g_hash_table_lookup (ds->reject_scores, metric->name)) != NULL)) {
+                               *rscore = *rs;
+                       }
                        if (ds && (sc = g_hash_table_lookup (ds->metric_scores, metric->name)) != NULL) {
                                *score = *sc;
                                return TRUE;
                        }
                }
                else if (ds != NULL) {
+                       if ((rs = g_hash_table_lookup (ds->reject_scores, metric->name)) != NULL) {
+                               *rscore = *rs;
+                       }
                        if ((sc = g_hash_table_lookup (ds->metric_scores, metric->name)) != NULL) {
                                *score = *sc;
                                return TRUE;
index 696bd9d76c2433c01f192cb1501afde72720eff7..58e877570bda593e19d1649740590504f63d1df3 100644 (file)
@@ -5,7 +5,8 @@
 #include "main.h"
 
 struct rspamd_settings {
-       GHashTable *metric_scores;                      /**< hash table of metric scores for this setting               */
+       GHashTable *metric_scores;                      /**< hash table of metric require scores for this setting               */
+       GHashTable *reject_scores;                      /**< hash table of metric reject scores for this setting                */
        GHashTable *factors;                            /**< hash table of new factors for this setting                 */
        char *statfile_alias;                           /**< alias for statfile used                                                    */
        gboolean want_spam;                                     /**< if true disable rspamd checks                                              */
@@ -14,7 +15,7 @@ struct rspamd_settings {
 
 gboolean read_settings (const char *path, struct config_file *cfg, GHashTable *table);
 void init_settings (struct config_file *cfg);
-gboolean check_metric_settings (struct worker_task *task, struct metric *metric, double *score);
+gboolean check_metric_settings (struct worker_task *task, struct metric *metric, double *score, double *rscore);
 gboolean check_factor_settings (struct worker_task *task, const char *symbol, double *factor);
 gboolean check_want_spam (struct worker_task *task);