From: Vsevolod Stakhov Date: Tue, 2 Oct 2012 16:32:49 +0000 (+0400) Subject: * Add support for dynamic configuration to the client. X-Git-Tag: 0.5.3~9 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=14e1129068d55bc8de0618832d4f7d33bb1b0f06;p=rspamd.git * Add support for dynamic configuration to the client. Cleanup client's code. Update manual page for client. Make 'bayes' as the default classifier for client learning operations. --- diff --git a/doc/rspamc.1 b/doc/rspamc.1 index 63d301051..e8f38bf81 100644 --- a/doc/rspamc.1 +++ b/doc/rspamc.1 @@ -1,4 +1,4 @@ -.\" Automatically generated by Pod::Man 2.22 (Pod::Simple 3.07) +.\" Automatically generated by Pod::Man 2.25 (Pod::Simple 3.16) .\" .\" Standard preamble: .\" ======================================================================== @@ -124,18 +124,19 @@ .\" ======================================================================== .\" .IX Title "rspamc 1" -.TH rspamc 1 "2011-03-15" "rspamd-0.3.8" "Rspamd documentation" +.TH rspamc 1 "2012-10-02" "rspamd-0.5.2" "Rspamd documentation" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l .nh -.SH "NAME" +.SH "RSPAMC" .IX Header "RSPAMC" rspamc \- a simple client for rspamd spam filtering system .SH "SYNOPSIS" .IX Header "SYNOPSIS" -rspamc [\fB\-h\fR \fIhost[:port]\fR] [\fB\-p\fR] [\fB\-v\fR] -[\fB\-i\fR \fIip\fR] [\fB\-s\fR \fIstatfile\fR] [\fB\-w\fR \fIweight\fR] +rspamc [\fB\-h\fR \fIhost[:port]\fR] [\fB\-p\fR] [\fB\-v\fR] [\fB\-b\fR \fIbind_address\fR] [\fB\-u\fR \fIuser\fR] +[\fB\-F\fR \fIfrom\fR] [\fB\-r\fR \fIrcpt\fR] [\fB\-d\fR \fIdeliver-to\fR] +[\fB\-i\fR \fIip\fR] [\fB\-c\fR \fIclassifier\fR] [\fB\-w\fR \fIweight\fR] [\fB\-P\fR \fIpassword\fR] [\fB\-f\fR \fIflag\fR] [\fB\-t\fR \fItimeout\fR] [command] [file [file ...]] .PP rspamc [\fB\-\-help\fR] @@ -148,7 +149,24 @@ rspamc [\fB\-\-help\fR] .IP "\fB\-h\fR \fIhost[:port]\fR, \fB\-\-connect\fR \fIhost[:port]\fR" 4 .IX Item "-h host[:port], --connect host[:port]" Specify host and port for connecting to rspamd server. Default host is \fIlocalhost\fR and -default port is \fI11333\fR for checking messages and \fI11334\fR for learning and statistic. +default port is \fI11333\fR for checking messages and \fI11334\fR for learning and statistic. +Also it is possible to specify a unix socket for all operations (for example: +\&\fBrspamc\fR \fB\-h\fR /path/to/soket) +.IP "\fB\-b\fR \fIlocal_ip\fR, \fB\-\-bind\fR \fIlocal_ip\fR" 4 +.IX Item "-b local_ip, --bind local_ip" +Specify explicit \s-1IP\s0 address to bind a client for operations. +.IP "\fB\-u\fR \fIuser\fR, \fB\-\-user\fR \fIuser\fR" 4 +.IX Item "-u user, --user user" +Specify username for connection with rspamd server. +.IP "\fB\-F\fR \fIfrom_addr\fR, \fB\-\-from\fR \fIfrom_addr\fR" 4 +.IX Item "-F from_addr, --from from_addr" +Specify \s-1SMTP\s0 \s-1FROM\s0 address for connection with rspamd server. +.IP "\fB\-r\fR \fIrcpt_addr\fR, \fB\-\-rcpt\fR \fIrcpt_addr\fR" 4 +.IX Item "-r rcpt_addr, --rcpt rcpt_addr" +Specify \s-1SMTP\s0 \s-1RCPT\s0 \s-1TO\s0 address for connection with rspamd server. +.IP "\fB\-d\fR \fIdeliver_addr\fR, \fB\-\-deliver\fR \fIdeliver_addr\fR" 4 +.IX Item "-d deliver_addr, --deliver deliver_addr" +Specify real delivery address for connection with rspamd server. .IP "\fB\-p\fR, \fB\-\-pass\-all\fR" 4 .IX Item "-p, --pass-all" Pass all filters when checking messages. Ignored in case of learning. @@ -158,9 +176,9 @@ Be more verbose while displaying results. For example show descriptions of symbo .IP "\fB\-P\fR \fIpassword\fR, \fB\-\-password\fR \fIpassword\fR" 4 .IX Item "-P password, --password password" Specify controller's password. Mandatory option for learning. -.IP "\fB\-s\fR \fIstatfile\fR, \fB\-\-statfile\fR \fIstatfile\fR" 4 -.IX Item "-s statfile, --statfile statfile" -Specify statfile's symbol to learn message. Mandatory option for learning. +.IP "\fB\-c\fR \fIclassifier\fR, \fB\-\-classifier\fR \fIclassifier\fR" 4 +.IX Item "-c classifier, --classifier classifier" +Specify classifier to learn message. Mandatory option for learning. Bayes classifier is used by default if this option is omitted. .IP "\fB\-i\fR \fIip\fR, \fB\-\-ip\fR \fIip\fR" 4 .IX Item "-i ip, --ip ip" Add \s-1IP\s0 header when scanning message. Useful for checking messages and emulating that client comes from @@ -194,7 +212,7 @@ Check files: Learn files: .PP .Vb 1 -\& rspamc \-P pass \-s BAYES_SPAM file1 file2 file3 +\& rspamc \-P pass learn_spam file1 file2 file3 .Ve .PP Add fuzzy hash to set 2: @@ -220,12 +238,24 @@ Get uptime: .Vb 1 \& rspamc uptime .Ve +.PP +Add custom rule's weight: +.PP +.Vb 1 +\& rspamc add_symbol test 1.5 +.Ve +.PP +Add custom action's weight: +.PP +.Vb 1 +\& rspamc add_action reject 7.1 +.Ve .SH "AUTHOR" .IX Header "AUTHOR" Vsevolod Stakhov .SH "COPYRIGHT AND LICENSE" .IX Header "COPYRIGHT AND LICENSE" -Copyright 2011 by Vsevolod Stakhov . +Copyright 2011\-2012 by Vsevolod Stakhov . .PP This program is free software; you may redistribute it and/or modify it under the terms of \s-1BSD\s0 license. diff --git a/doc/rspamc.pod b/doc/rspamc.pod index ebb452b4d..ddf5d81fb 100644 --- a/doc/rspamc.pod +++ b/doc/rspamc.pod @@ -4,8 +4,9 @@ rspamc - a simple client for rspamd spam filtering system =head1 SYNOPSIS -rspamc [B<-h> I] [B<-p>] [B<-v>] -[B<-i> I] [B<-s> I] [B<-w> I] +rspamc [B<-h> I] [B<-p>] [B<-v>] [B<-b> I] [B<-u> I] +[B<-F> I] [B<-r> I] [B<-d> I] +[B<-i> I] [B<-c> I] [B<-w> I] [B<-P> I] [B<-f> I] [B<-t> I] [command] [file [file ...]] rspamc [B<--help>] @@ -23,6 +24,28 @@ B has several mandatory options for learning: I and I and default port is I<11333> for checking messages and I<11334> for learning and statistic. +Also it is possible to specify a unix socket for all operations (for example: +B B<-h> /path/to/soket) + +=item B<-b> I, B<--bind> I + +Specify explicit IP address to bind a client for operations. + +=item B<-u> I, B<--user> I + +Specify username for connection with rspamd server. + +=item B<-F> I, B<--from> I + +Specify SMTP FROM address for connection with rspamd server. + +=item B<-r> I, B<--rcpt> I + +Specify SMTP RCPT TO address for connection with rspamd server. + +=item B<-d> I, B<--deliver> I + +Specify real delivery address for connection with rspamd server. =item B<-p>, B<--pass-all> @@ -36,9 +59,9 @@ Be more verbose while displaying results. For example show descriptions of symbo Specify controller's password. Mandatory option for learning. -=item B<-s> I, B<--statfile> I +=item B<-c> I, B<--classifier> I -Specify statfile's symbol to learn message. Mandatory option for learning. +Specify classifier to learn message. Mandatory option for learning. Bayes classifier is used by default if this option is omitted. =item B<-i> I, B<--ip> I @@ -75,7 +98,7 @@ Check files: Learn files: - rspamc -P pass -s BAYES_SPAM file1 file2 file3 + rspamc -P pass learn_spam file1 file2 file3 Add fuzzy hash to set 2: @@ -93,13 +116,21 @@ Get uptime: rspamc uptime +Add custom rule's weight: + + rspamc add_symbol test 1.5 + +Add custom action's weight: + + rspamc add_action reject 7.1 + =head1 AUTHOR Vsevolod Stakhov =head1 COPYRIGHT AND LICENSE -Copyright 2011 by Vsevolod Stakhov . +Copyright 2011-2012 by Vsevolod Stakhov . This program is free software; you may redistribute it and/or modify it under the terms of BSD license. diff --git a/doc/rspamd.8 b/doc/rspamd.8 index 498784d73..68a004387 100644 --- a/doc/rspamd.8 +++ b/doc/rspamd.8 @@ -1,4 +1,4 @@ -.\" Automatically generated by Pod::Man 2.22 (Pod::Simple 3.07) +.\" Automatically generated by Pod::Man 2.25 (Pod::Simple 3.16) .\" .\" Standard preamble: .\" ======================================================================== @@ -124,12 +124,12 @@ .\" ======================================================================== .\" .IX Title "rspamd 8" -.TH rspamd 8 "2011-03-15" "rspamd-0.3.8" "Rspamd documentation" +.TH rspamd 8 "2012-10-02" "rspamd-0.5.2" "Rspamd documentation" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l .nh -.SH "NAME" +.SH "RSPAMD" .IX Header "RSPAMD" rspamd \- main daemon for rspamd spam filtering system .SH "SYNOPSIS" diff --git a/src/client/rspamc.c b/src/client/rspamc.c index 877b0285f..aae8345d5 100644 --- a/src/client/rspamc.c +++ b/src/client/rspamc.c @@ -38,7 +38,7 @@ static gchar *from = NULL; static gchar *deliver_to = NULL; static gchar *rcpt = NULL; static gchar *user = NULL; -static gchar *classifier = NULL; +static gchar *classifier = "bayes"; static gchar *local_addr = NULL; static gint weight = 1; static gint flag; @@ -75,7 +75,9 @@ enum rspamc_command { RSPAMC_COMMAND_FUZZY_ADD, RSPAMC_COMMAND_FUZZY_DEL, RSPAMC_COMMAND_STAT, - RSPAMC_COMMAND_UPTIME + RSPAMC_COMMAND_UPTIME, + RSPAMC_COMMAND_ADD_SYMBOL, + RSPAMC_COMMAND_ADD_ACTION }; /* @@ -131,6 +133,12 @@ check_rspamc_command (const gchar *cmd) else if (g_ascii_strcasecmp (cmd, "UPTIME") == 0) { return RSPAMC_COMMAND_UPTIME; } + else if (g_ascii_strcasecmp (cmd, "ADD_SYMBOL") == 0) { + return RSPAMC_COMMAND_ADD_SYMBOL; + } + else if (g_ascii_strcasecmp (cmd, "ADD_ACTION") == 0) { + return RSPAMC_COMMAND_ADD_ACTION; + } return RSPAMC_COMMAND_UNKNOWN; } @@ -379,6 +387,8 @@ scan_rspamd_file (const gchar *file) struct rspamd_result *res; GHashTable *opts; + /* Add server */ + add_rspamd_server (FALSE); /* Init options hash */ opts = g_hash_table_new (g_str_hash, g_str_equal); add_options (opts); @@ -470,6 +480,8 @@ learn_rspamd_file (gboolean is_spam, const gchar *file) exit (EXIT_FAILURE); } + /* Add server */ + add_rspamd_server (TRUE); params = g_hash_table_new (g_str_hash, g_str_equal); g_hash_table_insert (params, "Classifier", classifier); @@ -573,6 +585,9 @@ fuzzy_rspamd_file (const gchar *file, gboolean delete) gchar valuebuf[sizeof("65535")], flagbuf[sizeof("65535")]; struct rspamd_controller_result *res; + /* Add server */ + add_rspamd_server (TRUE); + params = g_hash_table_new (g_str_hash, g_str_equal); rspamd_snprintf (valuebuf, sizeof (valuebuf), "%d", weight); rspamd_snprintf (flagbuf, sizeof (flagbuf), "%d", flag); @@ -609,16 +624,15 @@ fuzzy_rspamd_file (const gchar *file, gboolean delete) } static void -rspamd_do_controller_simple_command (gchar *command) +rspamd_do_controller_simple_command (gchar *command, GHashTable *kwattrs) { GError *err = NULL; GList *results, *cur; struct rspamd_controller_result *res; - /* Add server */ add_rspamd_server (TRUE); - results = rspamd_controller_command_simple (client, command, password, NULL, &err); + results = rspamd_controller_command_simple (client, command, password, kwattrs, &err); if (results == NULL || err != NULL) { if (err != NULL) { fprintf (stderr, "cannot perform command: %s\n", err->message); @@ -651,10 +665,13 @@ rspamd_do_controller_simple_command (gchar *command) gint main (gint argc, gchar **argv, gchar **env) { - enum rspamc_command cmd; - gint i; - struct in_addr ina; + enum rspamc_command cmd; + gint i; + struct in_addr ina; + GHashTable *kwattrs; + + kwattrs = g_hash_table_new (g_str_hash, g_str_equal); read_cmd_line (&argc, &argv); @@ -711,10 +728,10 @@ main (gint argc, gchar **argv, gchar **env) fuzzy_rspamd_stdin (TRUE); break; case RSPAMC_COMMAND_STAT: - rspamd_do_controller_simple_command ("stat"); + rspamd_do_controller_simple_command ("stat", NULL); break; case RSPAMC_COMMAND_UPTIME: - rspamd_do_controller_simple_command ("uptime"); + rspamd_do_controller_simple_command ("uptime", NULL); break; default: fprintf (stderr, "invalid arguments\n"); @@ -722,61 +739,69 @@ main (gint argc, gchar **argv, gchar **env) } } else { - add_rspamd_server (FALSE); scan_rspamd_file (argv[1]); } } else { if ((cmd = check_rspamc_command (argv[1])) != RSPAMC_COMMAND_UNKNOWN) { /* In case of command read arguments starting from 2 */ - switch (cmd) { - case RSPAMC_COMMAND_SYMBOLS: - /* Add server */ - add_rspamd_server (FALSE); - break; - default: - add_rspamd_server (TRUE); - break; - } - for (i = 2; i < argc; i ++) { - if (tty) { - printf ("\033[1m"); + if (cmd == RSPAMC_COMMAND_ADD_SYMBOL || cmd == RSPAMC_COMMAND_ADD_ACTION) { + if (argc < 4 || argc > 5) { + fprintf (stderr, "invalid arguments\n"); + exit (EXIT_FAILURE); } - PRINT_FUNC ("Results for file: %s\n\n", argv[i]); - if (tty) { - printf ("\033[0m"); + if (argc == 5) { + g_hash_table_insert (kwattrs, "metric", argv[2]); + g_hash_table_insert (kwattrs, "name", argv[3]); + g_hash_table_insert (kwattrs, "value", argv[4]); } - switch (cmd) { - case RSPAMC_COMMAND_SYMBOLS: - scan_rspamd_file (argv[i]); - break; - case RSPAMC_COMMAND_LEARN_SPAM: - if (classifier != NULL) { - learn_rspamd_file (TRUE, argv[i]); - } - else { - fprintf (stderr, "no classifier specified\n"); - exit (EXIT_FAILURE); + else { + g_hash_table_insert (kwattrs, "name", argv[2]); + g_hash_table_insert (kwattrs, "value", argv[3]); + } + rspamd_do_controller_simple_command (cmd == RSPAMC_COMMAND_ADD_SYMBOL ? "add_symbol" : "add_action", kwattrs); + } + else { + for (i = 2; i < argc; i ++) { + if (tty) { + printf ("\033[1m"); } - break; - case RSPAMC_COMMAND_LEARN_HAM: - if (classifier != NULL) { - learn_rspamd_file (FALSE, argv[i]); + PRINT_FUNC ("Results for file: %s\n\n", argv[i]); + if (tty) { + printf ("\033[0m"); } - else { - fprintf (stderr, "no classifier specified\n"); + switch (cmd) { + case RSPAMC_COMMAND_SYMBOLS: + scan_rspamd_file (argv[i]); + break; + case RSPAMC_COMMAND_LEARN_SPAM: + if (classifier != NULL) { + learn_rspamd_file (TRUE, argv[i]); + } + else { + fprintf (stderr, "no classifier specified\n"); + exit (EXIT_FAILURE); + } + break; + case RSPAMC_COMMAND_LEARN_HAM: + if (classifier != NULL) { + learn_rspamd_file (FALSE, argv[i]); + } + else { + fprintf (stderr, "no classifier specified\n"); + exit (EXIT_FAILURE); + } + break; + case RSPAMC_COMMAND_FUZZY_ADD: + fuzzy_rspamd_file (argv[i], FALSE); + break; + case RSPAMC_COMMAND_FUZZY_DEL: + fuzzy_rspamd_file (argv[i], TRUE); + break; + default: + fprintf (stderr, "invalid arguments\n"); exit (EXIT_FAILURE); } - break; - case RSPAMC_COMMAND_FUZZY_ADD: - fuzzy_rspamd_file (argv[i], FALSE); - break; - case RSPAMC_COMMAND_FUZZY_DEL: - fuzzy_rspamd_file (argv[i], TRUE); - break; - default: - fprintf (stderr, "invalid arguments\n"); - exit (EXIT_FAILURE); } } } @@ -789,5 +814,7 @@ main (gint argc, gchar **argv, gchar **env) rspamd_client_close (client); + g_hash_table_destroy (kwattrs); + return 0; } diff --git a/src/dynamic_cfg.c b/src/dynamic_cfg.c index 1375463f0..279b1e0a9 100644 --- a/src/dynamic_cfg.c +++ b/src/dynamic_cfg.c @@ -499,7 +499,7 @@ add_dynamic_symbol (struct config_file *cfg, const gchar *metric_name, const gch { GList *cur; struct dynamic_cfg_metric *metric = NULL; - struct dynamic_cfg_symbol *sym; + struct dynamic_cfg_symbol *sym = NULL; if (cfg->dynamic_conf == NULL) { msg_info ("dynamic conf is disabled"); @@ -523,6 +523,7 @@ add_dynamic_symbol (struct config_file *cfg, const gchar *metric_name, const gch sym = cur->data; if (g_ascii_strcasecmp (sym->name, symbol) == 0) { sym->value = value; + msg_debug ("change value of action %s to %.2f", symbol, value); break; } sym = NULL; @@ -534,6 +535,7 @@ add_dynamic_symbol (struct config_file *cfg, const gchar *metric_name, const gch sym->name = g_strdup (symbol); sym->value = value; metric->symbols = g_list_prepend (metric->symbols, sym); + msg_debug ("create symbol %s in metric %s", symbol, metric_name); } } else { @@ -545,6 +547,7 @@ add_dynamic_symbol (struct config_file *cfg, const gchar *metric_name, const gch metric->symbols = g_list_prepend (metric->symbols, sym); metric->name = g_strdup (metric_name); cfg->current_dynamic_conf = g_list_prepend (cfg->current_dynamic_conf, metric); + msg_debug ("create metric %s for symbol %s", metric_name, symbol); } apply_dynamic_conf (cfg->current_dynamic_conf, cfg); @@ -566,7 +569,7 @@ add_dynamic_action (struct config_file *cfg, const gchar *metric_name, const gch { GList *cur; struct dynamic_cfg_metric *metric = NULL; - struct dynamic_cfg_action *act; + struct dynamic_cfg_action *act = NULL; gint real_act; if (cfg->dynamic_conf == NULL) { @@ -590,12 +593,13 @@ add_dynamic_action (struct config_file *cfg, const gchar *metric_name, const gch } if (metric != NULL) { - /* Search for a symbol */ - cur = metric->symbols; + /* Search for an action */ + cur = metric->actions; while (cur) { act = cur->data; if ((gint)act->action == real_act) { act->value = value; + msg_debug ("change value of action %s to %.2f", action, value); break; } act = NULL; @@ -603,21 +607,23 @@ add_dynamic_action (struct config_file *cfg, const gchar *metric_name, const gch } if (act == NULL) { /* Action not found, insert it */ - act = g_slice_alloc (sizeof (struct dynamic_cfg_symbol)); + act = g_slice_alloc (sizeof (struct dynamic_cfg_action)); act->action = real_act; act->value = value; - metric->actions = g_list_prepend (metric->symbols, act); + metric->actions = g_list_prepend (metric->actions, act); + msg_debug ("create action %s in metric %s", action, metric_name); } } else { /* Metric not found, create it */ metric = g_slice_alloc0 (sizeof (struct dynamic_cfg_metric)); - act = g_slice_alloc (sizeof (struct dynamic_cfg_symbol)); + act = g_slice_alloc (sizeof (struct dynamic_cfg_action)); act->action = real_act; act->value = value; - metric->actions = g_list_prepend (metric->symbols, act); + metric->actions = g_list_prepend (metric->actions, act); metric->name = g_strdup (metric_name); cfg->current_dynamic_conf = g_list_prepend (cfg->current_dynamic_conf, metric); + msg_debug ("create metric %s for action %s", metric_name, action); } apply_dynamic_conf (cfg->current_dynamic_conf, cfg);