Hello,
On Mon, Mar 22, 2004 at 11:23:53PM -0500, Ari Jort wrote:
> I've been looking for a SA rule that will do something
> comparable to what postfix does with reject_unverified_sender.
>
> The postfix address verification is described here:
>
> http://www.porcupine.org/postfix-mirror/newdoc/ADDRESS_VERIFICATION_README.html
>
> I'd like to use this technique, but would rather assign
> a score with SA, rather than make a reject/accept decision
> based on the result.
I've implemented a verify_sender routine as inspired by
the postfix address verification, noted above. Patch
is attached.
This is a naive implementation in many ways.
1) It assumes the envelope-from is retreivable from the
Return-Path: header which is true in postfix-land. I'm not
sure about elsewhere.
2) There's still a bunch of debugging code in here. I thought
I'd leave it in in this patch, in case it helps anyone else
get it working.
3) It relies on 2 extra perl modules: Net::DNS and Net::SMTP
which might be better outside the spamd process space. Maybe
a sender verification daemon?
4) It only checks with the highest priority mx record for a given
domain and does not move on to lower priority records.
I'd love some feedback or reports on whether anyone else
can get this working.
Thanks,
ari
--
Ari Jort
[EMAIL PROTECTED]
--- lib/Mail/SpamAssassin/EvalTests.pm.orig Tue Mar 23 01:08:04 2004
+++ lib/Mail/SpamAssassin/EvalTests.pm Tue Mar 23 18:39:28 2004
@@ -3595,6 +3595,89 @@
return;
}
+# return the value of the Return-Path: header
+sub get_return_path() {
+ my($self) = @_;
+ my($return_path) = $self->get('Return-Path');
+ chomp($return_path);
+ dbg(sprintf "raw return path %s", $return_path );
+ $return_path =~ s/^<//;
+ $return_path =~ s/>$//;
+ dbg(sprintf "adjusted return path %s", $return_path );
+ $self->{return_path} = $return_path;
+ return $return_path
+}
+
+# do address verification on mail Return-Path
+
+sub verify_sender() {
+ my($self) = @_;
+ use Net::SMTP;
+ use Net::DNS;
+
+ my($mailhost, $domain_part);
+ my($probefrom) = '[EMAIL PROTECTED]';
+ my(@mxs);
+
+ # question: which is best way to get $return_path,
+ # from method or member var. Both seem to work fine.
+ my($return_path) = $self->get_return_path();
+# my($return_path_v) = $self->{return_path};
+# my($return_path) = $return_path_m;
+# dbg(sprintf "using return path from method %s", $return_path_m );
+# dbg(sprintf "using return path from var %s", $return_path_v );
+ dbg(sprintf "using return path - %s -", $return_path );
+
+ # return_path looks like this: '[EMAIL PROTECTED]'
+ # we want to get the domain part, or 'speakeasy.net'
+ if ( $return_path =~ /([EMAIL PROTECTED])*\@([EMAIL PROTECTED])/ ) {
+ $domain_part = $2;
+ }
+ dbg(sprintf "using domain part - %s -", $domain_part );
+ # get mx from domain part
+ my($res) = Net::DNS::Resolver->new()
+ or die "cannot create resolver object\n";
+
+ unless ( @mxs = &mx($res, $domain_part) ) {
+ dbg ("cannot assign mx records: $?\n");
+ return 1;
+ }
+
+ # assumption: we only grab the first mx and try that
+ # in future we can cycle through lower priority mx's
+ $mailhost = $mxs[0];
+ dbg(sprintf "using mailhost %s", $mailhost->string );
+ my($rr) = $mailhost->exchange();
+ dbg(sprintf "using rr %s", $rr );
+
+ # must untaint rr record value
+ if ( $rr =~ /^([-A-Za-z0-9.]+)$/ ) {
+ # we check only for alphanumerics, dashes and periods
+ $rr = $1;
+ dbg(sprintf "rr successfully untainted: %s", $rr);
+ } else {
+ dbg(sprintf "could not untaint rr: %s", $rr);
+ return 1;
+ }
+ my($smtp_probe);
+ unless ( $smtp_probe = Net::SMTP->new($rr) ) {
+ dbg(sprintf "could not connect to mx: %s", $rr);
+ return 1;
+ }
+ unless ( $smtp_probe->mail($probefrom) ) {
+ dbg(sprintf "MAIL FROM: %s was denied at mx: %s", $probefrom,
$rr);
+ return 1;
+ }
+ unless ( $smtp_probe->to( $self->get_return_path() ) ) {
+ dbg(sprintf "RCPT TO: %s was denied at mx: %s", $return_path,
$rr);
+ return 1;
+ }
+ $smtp_probe->reset();
+ $smtp_probe->quit();
+
+ dbg(sprintf "successfully verified sender %s", $return_path );
+ return 0;
+}
###########################################################################
1;