[Mimedefang] Re: md_check_against_smtp_server
Scott Silva
ssilva at sgvwater.com
Fri May 25 13:04:58 EDT 2007
Daniel Aquino spake the following on 5/25/2007 6:51 AM:
> This seems like an easy way to remove the need for me to dip into a
> ldap server...
> Has anyone thought/created some type of cache for making this function
> more practical?
I found the following from the archives.
--------------------snip--------------------------
In case it might be of interest, here's the code we're using
for caching the results of md_check_against_smtp_sender.
[...in filter_initialize...]
# location of cache files for md_check_against_smtp_server results lookups
$cachedir="/var/spool/MIMEDefang/smtpcheck";
if (! -d "$cachedir") {
mkdir "$cachedir", 0775;
}
[...]
# strip an email address down to the bare minimum, no optional text
# parts and no <>
sub address_strip ($) {
my ($a) = @_;
$a = "" if (!defined($a));
$a =~ s/^[<\[]//;
$a =~ s/[>\]]$//;
return ($a);
}
#+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# %PROCEDURE: writedb
# %ARGUMENTS: (database filename), (keystring), (value)
# %RETURNS: 0 if database write failed, 1 if success
#+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
sub writedb($$$) {
my ($dbfile, $key, $val) = @_;
my ($db);
if (tie (%db, "DB_File", $dbfile, O_RDWR|O_CREAT, 0775, $DB_HASH)) {
# insert new val
$db{$key} = "$val";
untie %db;
return 1;
} else {
md_syslog('warning', "Couldn't tie/write DB \'$dbfile\': $!");
return 0;
}
}
#+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# %PROCEDURE: cache_write
# %ARGUMENTS: username, server, code
# %RETURNS: 0 if database write failed, 1 if success
# %DESCRIPTION: Basically a wrapper for writedb. (We use writedb
# elsewhere, that's why. :-)
#+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
sub cache_write ($$$) {
my ($luser, $server, $code)=@_;
my $dbfile="$cachedir/$server.cache.db";
my $tstamp=rfc2822_date;
md_syslog('debug', "cache_write: adding $luser:$code to cache for $server
with stamp $tstamp");
return writedb($dbfile, $luser, "$code|$tstamp");
}
#+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# %PROCEDURE: cache_check
# %ARGUMENTS: username, servername (fqdn)
# %RETURNS: CONTINUE if username at server is cached known good
# REJECT if username at server is cached known bad
# TEMPFAIL if username at server is not cached
#+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
sub cache_check ($$) {
my ($luser, $server)=@_;
my $dbfile="$cachedir/$server.cache.db";
return 'TEMPFAIL' unless (my $h = &opendb_read($dbfile));
my $rval = $h->{$luser};
closedb($dbfile);
return 'TEMPFAIL' unless $rval;
my ($test, $tstamp) = split (/\|/, $rval, 2);
if ($test =~ /REJECT/) {
# previous lookup returned negative result
md_syslog('debug', "cache_check: lookup succeeded: REJECT $luser on $server,
record dated $tstamp");
return 'REJECT';
} else {
# valid users we've already seen and added to the local cache
md_syslog('debug', "cache_check: lookup succeeded: ACCEPT $luser on $server,
record dated $tstamp");
return 'CONTINUE';
}
}
[ and then, in filter_recipient...]
my $relay="";
my ($code, $msg, $smtp_code, $smtp_dsn, $delay) = ('CONTINUE', 'ok',
'250', '2.1.5', '0');
my $lusername="";
my $testsender="smtpcheck\@bifrost.cs.umass.edu";
my ($recipient, $sender, $ip, $hostname, $first, $helo, $rcpt_mailer,
$rcpt_host, $rcpt_addr) = @_;
my $cacheadd=0;
# normalize $recipient into local username part and hostname part
my $rcpt = address_strip($recipient);
if ($rcpt =~ /^(.+)\@([\w_.]+)$/) {
$lusername = $1;
$relay = $2;
# is this a host we know to accept mail for?
if ($relay =~ /$Cw_hosts/i ) {
# find actual relay
my $end_server = relayget($relay);
# if relay is not localhost, then check deliverability on the end-server
if ($end_server) {
# first check local cache
if (($code = cache_check($lusername, $end_server)) =~ /TEMPFAIL/) {
# means recipient is not in local cache
($code, $msg) = md_check_against_smtp_server($testsender, $recipient,
$helo, $end_server);
$cacheadd=1;
}
if ($code =~ /TEMPFAIL/) {
md_syslog('warning', "rcpt check on $lusername against $end_server
FAILED: \'$code\', \'$msg\'");
($code, $msg, $smtp_code, $smtp_dsn, $delay) = ('TEMPFAIL', "Unable to
verify LUser", "451", "4.3.0", $delay);
} else {
$cacheadd && cache_write($lusername, $end_server, $code);
if ($code =~/CONTINUE/) { # we got verification from the end-server
md_syslog('debug', "rcpt check on $lusername against $end_server
succeeded:\'$code\', \'$msg\'");
($code, $msg, $smtp_code, $smtp_dsn, $delay) = ('CONTINUE', "ok", "251",
"2.1.5", $delay);
} else { # must be a bad user
md_syslog('info', "rcpt check on $lusername against $end_server rejected
with \'$code\', \'$msg\'");
($code, $msg, $smtp_code, $smtp_dsn, $delay) = ('REJECT', "$recipient...
LUser unknown", "550", "5.1.1", $delay);
}
}
} else {
# must be a valid alias for this host
md_syslog('debug', "filter_recipient: no relay information found for $relay");
}
} else {
md_syslog('debug', "\$relay \'$relay\' not in \$Cw_hosts");
($code, $msg, $smtp_code, $smtp_dsn, $delay) = ('REJECT', "$relay: cannot
relay", "550", "5.1.1", $delay);
}
} else {
md_syslog('warning', "bad RCPT value \'$rcpt\' from \'$recipient\'");
($code, $msg, $smtp_code, $smtp_dsn, $delay) = ('REJECT', "$rcpt: invalid",
"550", "5.1.1", $delay);
}
return ("$code", "$msg", "$smtp_code", "$smtp_dsn", $delay);
}
Cheers,
Ole
-- Ole Craig * UNIX, linux, SMTP-fu; news, web; SGI martyr * CS Computing
Facility, UMass * <www.cs.umass.edu/~olc/pgppubkey.txt> for public key Need a
seasoned *NIX admin in the Denver/Boulder area? Hire me!
----------------------------snip--------------------------------------
--
MailScanner is like deodorant...
You hope everybody uses it, and
you notice quickly if they don't!!!!
More information about the MIMEDefang
mailing list