Initial commit.
This commit is contained in:
273
mail/spamassassin/DNSWLh.pm
Normal file
273
mail/spamassassin/DNSWLh.pm
Normal file
@@ -0,0 +1,273 @@
|
||||
# Adds DNSWL.org to recipients of spamassassin --report.
|
||||
#
|
||||
# In a SpamAssassin config file, add the lines:
|
||||
#
|
||||
# loadplugin Mail::SpamAssassin::Plugin::DNSWLh
|
||||
# dnswl_address user@example.com
|
||||
# dnswl_password yourpassword
|
||||
#
|
||||
# The last two must be from an account created via
|
||||
# http://www.dnswl.org/registerreporter.pl
|
||||
#
|
||||
#
|
||||
# 2010-02-26-23 Initial release.
|
||||
# 2010-02-27-11 Also call report successful on unlisted IPs.
|
||||
# 2010-02-28-20 State when reported email has trust level "Unlisted".
|
||||
# 2010-03-02-10 Report the IP DNSWL thought was interesting.
|
||||
|
||||
# <@LICENSE>
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
# contributor license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright ownership.
|
||||
# The ASF licenses this file to you under the Apache License, Version 2.0
|
||||
# (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at:
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
# </@LICENSE>
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Mail::SpamAssassin::Plugin::DNSWL - perform DNSWL reporting of messages
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
loadplugin Mail::SpamAssassin::Plugin::DNSWL
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
DNSWL is a service which lists known legitimate mail servers.
|
||||
This module enables automatic reporting of spam to DNSWL, to improve
|
||||
the accuracy of their database.
|
||||
|
||||
Note that spam reports sent by this plugin to DNSWL each include the
|
||||
entire spam message.
|
||||
|
||||
See http://www.dnswl.org/ for more information about DNSWL.
|
||||
|
||||
=cut
|
||||
|
||||
package Mail::SpamAssassin::Plugin::DNSWLh;
|
||||
|
||||
use Mail::SpamAssassin::Plugin;
|
||||
use Mail::SpamAssassin::Logger;
|
||||
use IO::Socket;
|
||||
use strict;
|
||||
use warnings;
|
||||
use bytes;
|
||||
use re 'taint';
|
||||
|
||||
use constant HAS_LWP_USERAGENT => eval { require LWP::UserAgent; };
|
||||
|
||||
use vars qw(@ISA);
|
||||
@ISA = qw(Mail::SpamAssassin::Plugin);
|
||||
|
||||
sub new {
|
||||
my $class = shift;
|
||||
my $mailsaobject = shift;
|
||||
|
||||
$class = ref($class) || $class;
|
||||
my $self = $class->SUPER::new($mailsaobject);
|
||||
bless ($self, $class);
|
||||
|
||||
# are network tests enabled?
|
||||
if (!$mailsaobject->{local_tests_only} && HAS_LWP_USERAGENT) {
|
||||
$self->{dnswl_available} = 1;
|
||||
dbg("DNSWL: network tests on, attempting DNSWL");
|
||||
}
|
||||
else {
|
||||
$self->{dnswl_available} = 0;
|
||||
dbg("DNSWL: local tests only, disabling DNSWL");
|
||||
}
|
||||
|
||||
$self->set_config($mailsaobject->{conf});
|
||||
|
||||
return $self;
|
||||
}
|
||||
|
||||
sub set_config {
|
||||
my($self, $conf) = @_;
|
||||
my @cmds;
|
||||
|
||||
=head1 USER OPTIONS
|
||||
|
||||
=over 4
|
||||
|
||||
=cut
|
||||
|
||||
push (@cmds, {
|
||||
setting => 'dnswl_address',
|
||||
default => 'spamassassin-submit@spam.dnswl.chaosreigns.com',
|
||||
type => $Mail::SpamAssassin::Conf::CONF_TYPE_STRING,
|
||||
code => sub {
|
||||
my ($self, $key, $value, $line) = @_;
|
||||
if ($value =~ /^([^<\s]+\@[^>\s]+)$/) {
|
||||
$self->{dnswl_address} = $1;
|
||||
}
|
||||
elsif ($value =~ /^$/) {
|
||||
return $Mail::SpamAssassin::Conf::MISSING_REQUIRED_VALUE;
|
||||
}
|
||||
else {
|
||||
return $Mail::SpamAssassin::Conf::INVALID_VALUE;
|
||||
}
|
||||
},
|
||||
});
|
||||
push (@cmds, {
|
||||
setting => 'dnswl_password',
|
||||
type => $Mail::SpamAssassin::Conf::CONF_TYPE_STRING,
|
||||
code => sub {
|
||||
my ($self, $key, $value, $line) = @_;
|
||||
if ($value =~ /^(\S+)$/) {
|
||||
$self->{dnswl_password} = $1;
|
||||
}
|
||||
elsif ($value =~ /^$/) {
|
||||
return $Mail::SpamAssassin::Conf::MISSING_REQUIRED_VALUE;
|
||||
}
|
||||
else {
|
||||
return $Mail::SpamAssassin::Conf::INVALID_VALUE;
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
=item dnswl_max_report_size (default: 50)
|
||||
|
||||
Messages larger than this size (in kilobytes) will be truncated in
|
||||
report messages sent to DNSWL. The default setting is the maximum
|
||||
size that DNSWL will accept at the time of release.
|
||||
|
||||
=cut
|
||||
|
||||
push (@cmds, {
|
||||
setting => 'dnswl_max_report_size',
|
||||
default => 50,
|
||||
type => $Mail::SpamAssassin::Conf::CONF_TYPE_NUMERIC
|
||||
});
|
||||
|
||||
$conf->{parser}->register_commands(\@cmds);
|
||||
}
|
||||
|
||||
sub plugin_report {
|
||||
my ($self, $options) = @_;
|
||||
|
||||
return unless $self->{dnswl_available};
|
||||
|
||||
#dbg("DNSWL: address/pass: " . $options->{report}->{conf}->{dnswl_address}
|
||||
# .' '. $options->{report}->{conf}->{dnswl_password} );
|
||||
|
||||
if (!$options->{report}->{options}->{dont_report_to_dnswl}) {
|
||||
if ($options->{report}->{conf}->{dnswl_address} and
|
||||
$options->{report}->{conf}->{dnswl_password}) {
|
||||
if ($self->dnswl_report($options)) {
|
||||
$options->{report}->{report_available} = 1;
|
||||
info("DNSWL: spam reported to DNSWL");
|
||||
$options->{report}->{report_return} = 1;
|
||||
} else {
|
||||
info("DNSWL: could not report spam to DNSWL");
|
||||
}
|
||||
} else {
|
||||
dbg("DNSWL: dnswl_address and/or dnswl_password not defined.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub dnswl_report {
|
||||
my ($self, $options) = @_;
|
||||
|
||||
# original text
|
||||
my $original = ${$options->{text}};
|
||||
|
||||
# check date
|
||||
my $header = $original;
|
||||
$header =~ s/\r?\n\r?\n.*//s;
|
||||
my $date = Mail::SpamAssassin::Util::receive_date($header);
|
||||
if ($date && $date < time - 2*86400) {
|
||||
warn("DNSWL: Message older than 2 days, not reporting\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
# message variables
|
||||
my $description = "spam report via " . Mail::SpamAssassin::Version();
|
||||
my $trusted = $options->{msg}->{metadata}->{relays_trusted_str};
|
||||
my $untrusted = $options->{msg}->{metadata}->{relays_untrusted_str};
|
||||
|
||||
# message data
|
||||
|
||||
# truncate message
|
||||
if (length($original) > $self->{main}->{conf}->{dnswl_max_report_size} * 1024) {
|
||||
substr($original, ($self->{main}->{conf}->{dnswl_max_report_size} * 1024)) =
|
||||
"\n[truncated by SpamAssassin]\n";
|
||||
}
|
||||
|
||||
my $body = <<"EOM";
|
||||
Content-Description: $description
|
||||
X-Spam-Relays-Trusted: $trusted
|
||||
X-Spam-Relays-Untrusted: $untrusted
|
||||
$original
|
||||
EOM
|
||||
|
||||
# compose message
|
||||
my $message;
|
||||
$message = $body;
|
||||
|
||||
# send message
|
||||
|
||||
my %form = (
|
||||
'action', 'save',
|
||||
'abuseReport',$message,
|
||||
);
|
||||
|
||||
my $ua = LWP::UserAgent->new;
|
||||
|
||||
my $netloc = 'www.dnswl.org:80';
|
||||
my $realm = 'dnswl.org Abuse Reporting';
|
||||
$ua->credentials( $netloc, $realm, $options->{report}->{conf}->{dnswl_address}, $options->{report}->{conf}->{dnswl_password} );
|
||||
|
||||
my $response = $ua->post('http://www.dnswl.org/abuse/report.pl', \%form);
|
||||
# my $response = $ua->post('http://www.dnswl.org/abuse/report.test.pl', \%form);
|
||||
# open OUT, ">/tmp/dnswlbody.".time.".txt";
|
||||
# print OUT $form{'abuseReport'};
|
||||
# close OUT;
|
||||
|
||||
if ($response->is_success) {
|
||||
#if ( $response->content =~ m#Thank you for your report# ) {
|
||||
if ( $response->content =~ m#IP ([\d\.]+) matches with DNSWL# ) {
|
||||
my $reportedip = $1;
|
||||
dbg("DNSWL: Successfully reported $reportedip.");
|
||||
print "Successfully reported to DNSWL $reportedip.\n";
|
||||
return 1;
|
||||
#} elsif ( $response->content =~ m#No matching entry found for#) {
|
||||
} elsif ( $response->content =~ m#No matching entry found for IP ([\d\.]+)#) {
|
||||
my $reportedip = $1;
|
||||
dbg("DNSWL: Successfully reported $reportedip. Current trust level is: Unlisted.");
|
||||
print "Successfully reported to DNSWL $reportedip. Current trust level is: Unlisted.\n";
|
||||
return 1;
|
||||
} else {
|
||||
dbg("DNSWL: Failed to report, acknowledgement not received.");
|
||||
print "Failed to report to DNSWL, acknowledgement not received.\n";
|
||||
# open OUT, ">/tmp/dnswlerr.".time.".txt";
|
||||
# print OUT $response->content;
|
||||
# close OUT;
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
dbg("DNSWL: Failed to report: ". $response->status_line);
|
||||
print "Failed to report to DNSWL, HTTP error: ". $response->status_line ."\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
dbg("DNSWL: Error: This isn't possible.");
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
=back
|
||||
|
||||
=cut
|
||||
Reference in New Issue
Block a user