diff --git a/config.sample/badhelo b/config.sample/badhelo new file mode 100644 index 0000000..a13ebfa --- /dev/null +++ b/config.sample/badhelo @@ -0,0 +1,4 @@ +# these domains never uses their domain when greeting us, so reject transactions +aol.com +yahoo.com + diff --git a/lib/Qpsmtpd/SMTP.pm b/lib/Qpsmtpd/SMTP.pm index 1384fa3..d9a3105 100644 --- a/lib/Qpsmtpd/SMTP.pm +++ b/lib/Qpsmtpd/SMTP.pm @@ -101,10 +101,19 @@ sub helo { my $conn = $self->connection; return $self->respond (503, "but you already said HELO ...") if $conn->hello; - $conn->hello("helo"); - $conn->hello_host($hello_host); - $self->transaction; - $self->respond(250, $self->config('me') ." Hi " . $conn->remote_info . " [" . $conn->remote_ip ."]; I am so happy to meet you."); + my ($rc, $msg) = $self->run_hooks("helo", $hello_host); + if ($rc == DONE) { + # do nothing + } elsif ($rc == DENY) { + $self->respond(550, $msg); + } elsif ($rc == DENYSOFT) { + $self->respond(450, $msg); + } else { + $conn->hello("helo"); + $conn->hello_host($hello_host); + $self->transaction; + $self->respond(250, $self->config('me') ." Hi " . $conn->remote_info . " [" . $conn->remote_ip ."]; I am so happy to meet you."); + } } sub ehlo { @@ -112,16 +121,25 @@ sub ehlo { my $conn = $self->connection; return $self->respond (503, "but you already said HELO ...") if $conn->hello; - $conn->hello("ehlo"); - $conn->hello_host($hello_host); - $self->transaction; + my ($rc, $msg) = $self->run_hooks("ehlo", $hello_host); + if ($rc == DONE) { + # do nothing + } elsif ($rc == DENY) { + $self->respond(550, $msg); + } elsif ($rc == DENYSOFT) { + $self->respond(450, $msg); + } else { + $conn->hello("ehlo"); + $conn->hello_host($hello_host); + $self->transaction; - $self->respond(250, + $self->respond(250, $self->config("me") . " Hi " . $conn->remote_info . " [" . $conn->remote_ip ."]", "PIPELINING", "8BITMIME", ($self->config('databytes') ? "SIZE ". ($self->config('databytes'))[0] : ()), ); + } } sub mail { diff --git a/plugins/check_spamhelo b/plugins/check_spamhelo new file mode 100644 index 0000000..c776f84 --- /dev/null +++ b/plugins/check_spamhelo @@ -0,0 +1,37 @@ +=head1 NAME + +check_spamhelo - Check a HELO message delivered from a connecting host. + +=head1 DESCRIPTION + +Check a HELO message delivered from a connecting host. Reject any +that appear in the badhelo config -- e.g. yahoo.com and aol.com, which +neither the real Yahoo or the real AOL use, but which spammers use +rather a lot. + +=head1 CONFIGURATION + +Add domains or hostnames to the F configuration file; one +per line. + +=cut + +sub register { + my ($self, $qp) = @_; + $self->register_hook("helo", "check_helo"); + $self->register_hook("ehlo", "check_helo"); +} + +sub check_helo { + my ($self, $transaction, $host) = @_; + ($host = lc $host) or return DECLINED; + + for my $bad ($self->qp->config('badhelo')) { + if ($host eq lc $bad) { + $self->log(5, "Denying HELO from host claiming to be $bad"); + return (DENY, "Uh-huh. You're $host, and I'm a boil on the bottom of the Marquess of Queensbury's great-aunt."); + } + } + return DECLINED; +} +