diff options
Diffstat (limited to 'utils/cgp_rspamd.pl')
-rw-r--r-- | utils/cgp_rspamd.pl | 452 |
1 files changed, 225 insertions, 227 deletions
diff --git a/utils/cgp_rspamd.pl b/utils/cgp_rspamd.pl index e55ac5791..1d4d4406f 100644 --- a/utils/cgp_rspamd.pl +++ b/utils/cgp_rspamd.pl @@ -21,278 +21,276 @@ my $request_timeout = 15; # 15 seconds by default my $reject_message = "Spam message rejected"; GetOptions( - "host=s" => \$rspamd_host, - "header=s" => \$header, - "reject-message=s" => \$reject_message, - "max-size=i" => \$max_size, - "timeout=f" => \$request_timeout, - "help|?" => \$help, - "man" => \$man + "host=s" => \$rspamd_host, + "header=s" => \$header, + "reject-message=s" => \$reject_message, + "max-size=i" => \$max_size, + "timeout=f" => \$request_timeout, + "help|?" => \$help, + "man" => \$man ) or pod2usage(2); pod2usage(1) if $help; pod2usage( -exitval => 0, -verbose => 2 ) if $man; my $main_domain = cgp_main_domain(); -my $scanned = 0; +my $scanned = 0; # Turn off bufferization as required by CGP $| = 1; sub cgp_main_domain { - if ( open(my $fh, 'Settings/Main.settings') ) { - while (<$fh>) { - if ( /^\s+DomainName\s+=\s+([^;]+);/ ) { - return $1; - } + if ( open( my $fh, 'Settings/Main.settings' ) ) { + while (<$fh>) { + if (/^\s+DomainName\s+=\s+([^;]+);/) { + return $1; + } + } } - } } sub cgp_string { - my ($in) = @_; + my ($in) = @_; - $in =~ s/\"/\\"/g; - $in =~ s/\n/\\n/gms; - $in =~ s/\r/\\r/mgs; - $in =~ s/\t/ /g; + $in =~ s/\"/\\"/g; + $in =~ s/\n/\\n/gms; + $in =~ s/\r/\\r/mgs; + $in =~ s/\t/ /g; - return "\"$in\""; + return "\"$in\""; } sub rspamd_scan { - my ( $tag, $file ) = @_; - - my $http_callback = sub { - my ( $body, $hdr ) = @_; - - if ( $hdr && $hdr->{Status} =~ /^2/ ) { - my $js = eval('decode_json($body)'); - $scanned++; - - if ( !$js ) { - print "* Rspamd: Bad response for $file: invalid JSON: parse error\n"; - print "$tag FAILURE\n"; - } - else { - my $def = $js; - my $headers = ""; - - if ( !$def ) { - print -"* Rspamd: Bad response for $file: invalid JSON: default is missing\n"; - print "$tag FAILURE\n"; - } - else { - my $action = $def->{'action'}; - my $id = $js->{'message-id'}; - - my $symbols = ""; - while ( my ( $k, $s ) = each( %{$def->{'symbols'}}) ) { - $symbols .= sprintf "%s(%.2f);", $k, $s->{'score'}; - } - - printf -"* Rspamd: Scanned %s; id: <%s>; Score: %.2f / %.2f; Symbols: [%s]\n", - $file, $id, $def->{'score'}, $def->{'required_score'}, $symbols; - - if ( $js->{'dkim-signature'} ) { - $headers .= "DKIM-Signature: " . $js->{'dkim-signature'}; - } - - if ( $js->{'milter'} ) { - my $block = $js->{'milter'}; - - if ( $block->{'add_headers'} ) { - while ( my ( $h, $v ) = each( %{ $block->{'add_headers'} } ) ) { - if (ref($v) eq 'HASH') { - if ($headers eq "") { - $headers .= "$h: $v->{value}"; - } - else { - $headers .= "\\e$h: $v->{value}"; - } + my ( $tag, $file ) = @_; + + my $http_callback = sub { + my ( $body, $hdr ) = @_; + + if ( $hdr && $hdr->{Status} =~ /^2/ ) { + my $js = eval('decode_json($body)'); + $scanned++; + + if ( !$js ) { + print "* Rspamd: Bad response for $file: invalid JSON: parse error\n"; + print "$tag FAILURE\n"; + } + else { + my $def = $js; + my $headers = ""; + + if ( !$def ) { + print "* Rspamd: Bad response for $file: invalid JSON: default is missing\n"; + print "$tag FAILURE\n"; } else { - if ($headers eq "") { - $headers .= "$h: $v"; - } - else { - $headers .= "\\e$h: $v"; - } + my $action = $def->{'action'}; + my $id = $js->{'message-id'}; + + my $symbols = ""; + while ( my ( $k, $s ) = each( %{ $def->{'symbols'} } ) ) { + $symbols .= sprintf "%s(%.2f);", $k, $s->{'score'}; + } + + printf + "* Rspamd: Scanned %s; id: <%s>; Score: %.2f / %.2f; Symbols: [%s]\n", + $file, $id, $def->{'score'}, $def->{'required_score'}, $symbols; + + if ( $js->{'dkim-signature'} ) { + $headers .= "DKIM-Signature: " . $js->{'dkim-signature'}; + } + + if ( $js->{'milter'} ) { + my $block = $js->{'milter'}; + + if ( $block->{'add_headers'} ) { + while ( my ( $h, $v ) = each( %{ $block->{'add_headers'} } ) ) { + if ( ref($v) eq 'HASH' ) { + if ( $headers eq "" ) { + $headers .= "$h: $v->{value}"; + } + else { + $headers .= "\\e$h: $v->{value}"; + } + } + else { + if ( $headers eq "" ) { + $headers .= "$h: $v"; + } + else { + $headers .= "\\e$h: $v"; + } + } + } + } + } + + if ( $action eq 'reject' ) { + print "$tag DISCARD\n"; + return; + } + elsif ( $action eq 'add header' || $action eq 'rewrite subject' ) { + if ( $headers eq "" ) { + $headers .= "$header"; + } + else { + $headers .= "\\e$header"; + } + } + elsif ( $action eq 'soft reject' ) { + print "$tag REJECT Try again later\n"; + return; + } + + if ( $headers eq "" ) { + print "$tag OK\n"; + } + else { + print "$tag ADDHEADER " . cgp_string($headers) . " OK\n"; + } } - } } - } - - if ( $action eq 'reject' ) { - print "$tag DISCARD\n"; - return; - } - elsif ( $action eq 'add header' || $action eq 'rewrite subject' ) { - if ( $headers eq "" ) { - $headers .= "$header"; + } + else { + if ($hdr) { + print "* Rspamd: Bad response for $file: HTTP error: $hdr->{Status} $hdr->{Reason}\n"; } else { - $headers .= "\\e$header"; + print "* Rspamd: Bad response for $file: IO error: $!\n"; } - } - elsif ( $action eq 'soft reject' ) { - print "$tag REJECT Try again later\n"; - return; - } - - if ( $headers eq "" ) { - print "$tag OK\n"; - } - else { - print "$tag ADDHEADER " . cgp_string($headers) . " OK\n"; - } + print "$tag FAILURE\n"; } - } + }; + + if ($local) { + + # Use file scan + # XXX: not implemented now due to CGP queue format + http_get( + "http://$rspamd_host/symbols?file=$file", + timeout => $request_timeout, + $http_callback + ); } else { - if ($hdr) { - print -"* Rspamd: Bad response for $file: HTTP error: $hdr->{Status} $hdr->{Reason}\n"; - } - else { - print "* Rspamd: Bad response for $file: IO error: $!\n"; - } - print "$tag FAILURE\n"; - } - }; - - if ($local) { - - # Use file scan - # XXX: not implemented now due to CGP queue format - http_get( - "http://$rspamd_host/symbols?file=$file", - timeout => $request_timeout, - $http_callback - ); - } - else { - my $sb = stat($file); - - if ( !$sb || $sb->size > $max_size ) { - if ($sb) { - print "* File $file is too large: " . $sb->size . "\n$tag FAILURE\n"; - - } - else { - print "* Cannot stat $file: $!\n$tag FAILURE\n"; - } - return; - } - aio_load( - $file, - sub { - my ($data) = @_; - - if ( !$data ) { - print "* Cannot open $file: $!\n$tag FAILURE\n"; - return; - } + my $sb = stat($file); + + if ( !$sb || $sb->size > $max_size ) { + if ($sb) { + print "* File $file is too large: " . $sb->size . "\n$tag FAILURE\n"; - # Parse CGP format - $data =~ s/^((?:[^\n]*\n)*?)\n(.*)$/$2/ms; - my @envelope = split /\n/, $1; - chomp(@envelope); - my $from; - my @rcpts; - my $ip; - my $user; - - foreach my $elt (@envelope) { - if ( $elt =~ /^P\s[^<]*(<[^>]*>).*$/ ) { - $from = $1; - } - elsif ( $elt =~ /^R\s[^<]*(<[^>]*>).*$/ ) { - push @rcpts, $1; - } - elsif ( $elt =~ /^S (?:<([^>]+)> )?(?:SMTP|HTTPU?|AIRSYNC|XIMSS) \[([0-9a-f.:]+)\]/ ) { - if ($1) { - $user = $1; - } - if ($2) { - $ip = $2; } - } - elsif ( $elt =~ /^S (?:<([^>]+)> )?(?:DSN|GROUP|LIST|PBX|PIPE|RULE) \[0\.0\.0\.0\]/ ) { - if ($1) { - $user = $1; + else { + print "* Cannot stat $file: $!\n$tag FAILURE\n"; } - $ip = '127.2.4.7'; - } + return; } + aio_load( + $file, + sub { + my ($data) = @_; + + if ( !$data ) { + print "* Cannot open $file: $!\n$tag FAILURE\n"; + return; + } - my $headers = {}; - if ( $file =~ /\/([^\/.]+)\.msg$/ ) { - $headers->{'Queue-ID'} = $1; - } - if ($from) { - $headers->{From} = $from; - } - if ( scalar(@rcpts) > 0 ) { + # Parse CGP format + $data =~ s/^((?:[^\n]*\n)*?)\n(.*)$/$2/ms; + my @envelope = split /\n/, $1; + chomp(@envelope); + my $from; + my @rcpts; + my $ip; + my $user; + + foreach my $elt (@envelope) { + if ( $elt =~ /^P\s[^<]*(<[^>]*>).*$/ ) { + $from = $1; + } + elsif ( $elt =~ /^R\s[^<]*(<[^>]*>).*$/ ) { + push @rcpts, $1; + } + elsif ( $elt =~ /^S (?:<([^>]+)> )?(?:SMTP|HTTPU?|AIRSYNC|XIMSS) \[([0-9a-f.:]+)\]/ ) { + if ($1) { + $user = $1; + } + if ($2) { + $ip = $2; + } + } + elsif ( $elt =~ /^S (?:<([^>]+)> )?(?:DSN|GROUP|LIST|PBX|PIPE|RULE) \[0\.0\.0\.0\]/ ) { + if ($1) { + $user = $1; + } + $ip = '127.2.4.7'; + } + } - # XXX: Anyevent cannot parse headers with multiple values - $headers->{Rcpt} = join(',', @rcpts); - } - if ($ip) { - $headers->{IP} = $ip; - } - if ($user) { - $headers->{User} = $user; - } - if ($main_domain) { - $headers->{'MTA-Tag'} = $main_domain; - } + my $headers = {}; + if ( $file =~ /\/([^\/.]+)\.msg$/ ) { + $headers->{'Queue-ID'} = $1; + } + if ($from) { + $headers->{From} = $from; + } + if ( scalar(@rcpts) > 0 ) { - http_post( - "http://$rspamd_host/checkv2", $data, - timeout => $request_timeout, - headers => $headers, - $http_callback + # XXX: Anyevent cannot parse headers with multiple values + $headers->{Rcpt} = join( ',', @rcpts ); + } + if ($ip) { + $headers->{IP} = $ip; + } + if ($user) { + $headers->{User} = $user; + } + if ($main_domain) { + $headers->{'MTA-Tag'} = $main_domain; + } + + http_post( + "http://$rspamd_host/checkv2", $data, + timeout => $request_timeout, + headers => $headers, + $http_callback + ); + } ); - } - ); - } + } } # Show informational message print "* Rspamd CGP filter has been started\n"; my $w = AnyEvent->io( - fh => \*STDIN, - poll => 'r', - cb => sub { - chomp( my $input = <STDIN> ); - - if ( $input =~ /^(\d+)\s+(\S+)(\s+(\S+)\s*)?$/ ) { - my $tag = $1; - my $cmd = $2; - - if ( $cmd eq "INTF" ) { - print "$input\n"; - } - elsif ( $cmd eq "FILE" && $4 ) { - my $file = $4; - print "* Scanning file $file\n"; - rspamd_scan $tag, $file; - } - elsif ( $cmd eq "QUIT" ) { - print "* Terminating after scanning of $scanned files\n"; - print "$tag OK\n"; - exit 0; - } - else { - print "* Unknown command $cmd\n"; - print "$tag FAILURE\n"; - } + fh => \*STDIN, + poll => 'r', + cb => sub { + chomp( my $input = <STDIN> ); + + if ( $input =~ /^(\d+)\s+(\S+)(\s+(\S+)\s*)?$/ ) { + my $tag = $1; + my $cmd = $2; + + if ( $cmd eq "INTF" ) { + print "$input\n"; + } + elsif ( $cmd eq "FILE" && $4 ) { + my $file = $4; + print "* Scanning file $file\n"; + rspamd_scan $tag, $file; + } + elsif ( $cmd eq "QUIT" ) { + print "* Terminating after scanning of $scanned files\n"; + print "$tag OK\n"; + exit 0; + } + else { + print "* Unknown command $cmd\n"; + print "$tag FAILURE\n"; + } + } } - } ); EV::run; |