aboutsummaryrefslogtreecommitdiffstats
path: root/rspamc.pl.in
diff options
context:
space:
mode:
authorVsevolod Stakhov <vsevolod@rambler-co.ru>2009-02-27 12:44:18 +0300
committerVsevolod Stakhov <vsevolod@rambler-co.ru>2009-02-27 12:44:18 +0300
commit749503560ef72d7b20f935487a77ee4fbc8a9e3f (patch)
treee5d76effbcffaa834efaaf2f0c83db3e32d31c12 /rspamc.pl.in
parent7551c7a9483ea4821dc76bd72fe5441d99a63ed3 (diff)
downloadrspamd-749503560ef72d7b20f935487a77ee4fbc8a9e3f.tar.gz
rspamd-749503560ef72d7b20f935487a77ee4fbc8a9e3f.zip
* Fix dependencies on perlxs target (do not rebuild it constantly)
* Fix rspamc to understand lmtp and delivery sections in config * Fix parser's states when reading module options * Add sample config for surbl module with comments --HG-- rename : rspamc.pl => rspamc.pl.in
Diffstat (limited to 'rspamc.pl.in')
-rwxr-xr-xrspamc.pl.in228
1 files changed, 228 insertions, 0 deletions
diff --git a/rspamc.pl.in b/rspamc.pl.in
new file mode 100755
index 000000000..8caeb28a3
--- /dev/null
+++ b/rspamc.pl.in
@@ -0,0 +1,228 @@
+#!/usr/bin/perl -w
+
+# Simple script that read message from STDIN and test it on rspamd server
+# using specified command.
+#
+# Usage: rspamc.pl [-c conf_file] [command] [-s statfile]
+#
+# By default rspamc.pl would read ./rspamd.conf and default command is SYMBOLS
+
+use Socket qw(:DEFAULT :crlf);
+
+my %cfg = (
+ 'conf_file' => '@CMAKE_INSTALL_PREFIX@/etc/rspamd.conf',
+ 'command' => 'SYMBOLS',
+ 'host' => 'localhost',
+ 'port' => '11333',
+ 'is_unix' => 0,
+ 'password' => '',
+ 'control' => 0,
+ 'statfile' => '',
+);
+
+
+sub usage {
+ return "Usage: rspamc.pl [-c conf_file] [-s statfile] [command]";
+}
+
+# Load rspamd config params
+sub parse_config {
+ my ($is_ctrl) = @_;
+
+ open CONF, "< $cfg{'conf_file'}" or die "config file $cfg{'conf_file'} cannot be opened";
+
+ my $ctrl = 0;
+ while (<CONF>) {
+ if ($_ =~ /control\s*{/i || $_ =~ /lmtp\s*{/i || $_ =~ /delivery\s*{/i) {
+ $ctrl = 1;
+ }
+ if ($ctrl && $_ =~ /}/) {
+ $ctrl = 0;
+ }
+ if (((!$is_ctrl && !$ctrl) || ($ctrl && $is_ctrl))
+ && $_ =~ /^\s*bind_socket\s*=\s*((([^:]+):(\d+))|(\/\S*))/i) {
+ if ($3 && $4) {
+ $cfg{'host'} = $3;
+ $cfg{'port'} = $4;
+ $cfg{'is_unix'} = 0;
+ }
+ else {
+ $cfg{'host'} = $5;
+ $cfg{'is_unix'} = 1;
+ }
+ }
+ if ($ctrl && $is_ctrl && $_ =~ /^\s*password\s*=\s*"(\S+)"/) {
+ $cfg{'password'} = $1;
+ }
+ }
+
+ close CONF;
+
+}
+
+sub connect_socket {
+ my $sock;
+
+ if ($cfg{'is_unix'}) {
+ socket ($sock, PF_UNIX, SOCK_STREAM, 0) or die "cannot create unix socket";
+ my $sun = sockaddr_un($cfg{'host'});
+ connect ($sock, $sun) or die "cannot connect to socket $cfg{'host'}";
+ }
+ else {
+ my $proto = getprotobyname('tcp');
+ my $sin;
+ socket ($sock, PF_INET, SOCK_STREAM, $proto) or die "cannot create tcp socket";
+ if (inet_aton ($cfg{'host'})) {
+ $sin = sockaddr_in ($cfg{'port'}, inet_aton($cfg{'host'}));
+ }
+ else {
+ my $addr = gethostbyname($cfg{'host'});
+ if (!$addr) {
+ die "cannot resolve $cfg{'host'}";
+ }
+ $sin = sockaddr_in ($cfg{'port'}, $addr);
+ }
+
+ connect ($sock, $sin) or die "cannot connect to socket $cfg{'host'}:$cfg{'port'}";
+ }
+ return $sock;
+}
+
+# Currently just read stdin for user's message and pass it to rspamd
+sub do_rspamc_command {
+ my ($sock) = @_;
+
+ my $input;
+ while (defined (my $line = <>)) {
+ $input .= $line;
+ }
+
+ print "Sending ". length ($input) ." bytes...\n";
+
+ syswrite $sock, "$cfg{'command'} RSPAMC/1.0 $CRLF";
+ syswrite $sock, "Content-Length: " . length ($input) . $CRLF . $CRLF;
+ syswrite $sock, $input;
+ syswrite $sock, $CRLF;
+ while (defined (my $line = <$sock>)) {
+ print $line;
+ }
+}
+
+sub do_ctrl_auth {
+ my ($sock) = @_;
+
+ syswrite $sock, "password $cfg{'password'}" . $CRLF;
+ if (defined (my $reply = <$sock>)) {
+ my $end = <$sock>;
+ if ($reply =~ /^password accepted/) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+sub do_control_command {
+ my ($sock) = @_;
+
+ # Read greeting first
+ if (defined (my $greeting = <$sock>)) {
+ if ($greeting !~ /^Rspamd version/) {
+ die "not rspamd greeting line $greeting";
+ }
+ }
+ if ($cfg{'command'} =~ /^learn$/i) {
+ my $input;
+ die "statfile is not specified to learn command" if !$cfg{'statfile'};
+
+ while (defined (my $line = <>)) {
+ $input .= $line;
+ }
+
+ if (do_ctrl_auth ($sock)) {
+ my $len = length ($input);
+ print "Sending $len bytes...\n";
+ syswrite $sock, "learn $cfg{'statfile'} $len" . $CRLF;
+ syswrite $sock, $input . $CRLF;
+ if (defined (my $reply = <$sock>)) {
+ if ($reply =~ /^learn ok/) {
+ print "Learn succeed\n";
+ }
+ else {
+ print "Learn failed\n";
+ }
+ }
+ }
+ else {
+ print "Authentication failed\n";
+ }
+ }
+ elsif ($cfg{'command'} =~ /(reload|shutdown)/i) {
+ if (do_ctrl_auth ($sock)) {
+ syswrite $sock, $cfg{'command'} . $CRLF;
+ while (defined (my $line = <$sock>)) {
+ last if $line =~ /^END/;
+ print $line;
+ }
+ }
+ else {
+ print "Authentication failed\n";
+ }
+ }
+ else {
+ syswrite $sock, $cfg{'command'} . $CRLF;
+ while (defined (my $line = <$sock>)) {
+ last if $line =~ /^END/;
+ print $line;
+ }
+ }
+}
+
+while (my $param = shift) {
+ if ($param eq '-c') {
+ my $value = shift;
+ if ($value) {
+ if (-r $value) {
+ $cfg{'conf_file'} = $value;
+ }
+ else {
+ die "config file $value is not readable";
+ }
+ }
+ else {
+ die usage();
+ }
+ }
+ elsif ($param eq '-s') {
+ my $value = shift;
+ if ($value) {
+ $cfg{'statfile'} = $value;
+ }
+ else {
+ die usage();
+ }
+ }
+ elsif ($param =~ /(SYMBOLS|SCAN|PROCESS|CHECK|REPORT_IFSPAM|REPORT)/i) {
+ $cfg{'command'} = $1;
+ $cfg{'control'} = 0;
+ }
+ elsif ($param =~ /(STAT|LEARN|SHUTDOWN|RELOAD|UPTIME)/i) {
+ $cfg{'command'} = $1;
+ $cfg{'control'} = 1;
+ }
+ else {
+ die usage();
+ }
+}
+
+parse_config ($cfg{'control'});
+my $sock = connect_socket ();
+
+if ($cfg{'control'}) {
+ do_control_command ($sock);
+}
+else {
+ do_rspamc_command ($sock);
+}
+
+close ($sock);