[Mimedefang] md_check_against_smtp_server

Kevin A. McGrail KMcGrail at PCCC.com
Mon Jan 12 18:19:37 EST 2015


On 1/2/2015 6:29 AM, joris dedieu wrote:
> 2014-12-30 23:53 GMT+01:00 Jon Rowlan <jon.rowlan at sads.com>:
>> I'd like to thank everyone who replied to my recent query regarding
>> md_check_against_smtp_server.
>>
>> The end result is now working beautfifully and inspired by the replies I
>> am looking into caching the lookup results.
> I use a Redis database for that. It's quite efficient.
>
> Joris
Thanks Joris,

We refined your caching and added more debugging and error checking so 
we thought we would post back to the list in like and kind.

Best,
KAM

#Thanks to Joris Dedieu for inspiration and example code for this function
sub cached_md_smtp_check {
   my ($sender, $recipient, $helo, $server, $port) = @_;
   my ($redis, $key, $status, $message, $redis_server, $redis_password, 
$start_time, $end_time, $status_message);

   md_syslog("warning", "DEBUG: Edge Test - Checking Recipient 
$recipient with cached_md_smtp_check");

   # IN ORDER TO MAKE SURE WE DON'T GET STUCK, RUN IN AN EVAL SO WE CAN 
TIME OUT THAN md_check_against_smtp_server
   ($status, $message) = eval {
     # SET TIMEOUT FUNCTION
     $SIG{ALRM} = sub { md_syslog("warning", "DEBUG: Edge Test - Timing 
Out"); die "timeout" }; # NB: \n required

     # SET TIMEOUT TO 15 SECONDS
     alarm 15;

     $redis_server = "XXX:6379";
     $redis_password = "YYY";

     $recipient =~ s/[<>]//g;

     # ATTEMPT CONNECTION TO REDIS SERVER
     eval { $redis = Redis->new(server => $redis_server, password => 
$redis_password); };

     # IF THERE IS AN ERROR WHEN TRYING TO CONNECT TO REDIS, JUST USE A 
REGULAR CALL
     if ($@) {

       # WARN THAT REDIS ISN'T WORKING
       md_syslog("warning", "WARNING: Edge Test - Redis Failed, calling 
md_check_against_smtp_server.  Error: $@");

       # RESET ALARM BEFORE RETURNING
       alarm 0;
       return md_check_against_smtp_server($sender, $recipient, $helo, 
$server, $port);

     } else {
       md_syslog("warning", "DEBUG: Edge Test - Redis connection 
success, checking for cached value for $recipient");

       $key = $redis->get("$recipient");

       # PARSE RESPONSE FROM REDIS IF IT IS SET
       if ($key ne '' and $key =~ /(.*):(.*)/) {
         $status = $1;
         $message = $2;

         if (uc($status) eq "CONTINUE" or uc($status) eq "REJECT") {
           md_syslog("warning", "DEBUG: Edge Test - Returning cached 
value from Redis Status: '$status' Message: '$message' Recipient: 
$recipient");

           $redis->quit;

           # RESET ALARM BEFORE RETURNING
           alarm 0;
           return ($status, $message);
         } else {
           $redis->quit;


           md_syslog("warning", "WARNING: Edge Test - Cached value in 
Redis returned an incorrect value for $recipient.  Calling 
md_check_against_smtp_server");

           # RESET ALARM BEFORE RETURNING
           alarm 0;
           return md_check_against_smtp_server($sender, $recipient, 
$helo, $server, $port);
         }

       } else {
         md_syslog("warning", "DEBUG: Edge Test - Response for 
$recipient Not Cached, calling md_check_against_smtp_server");

         ($status, $message) = md_check_against_smtp_server($sender, 
$recipient, $helo, $server, $port);

         # IF NOT TEMPFAIL, SAVE RESPONSE IN REDIS WITH APPROPRIATE 
EXPIRATION
         if(uc($status) eq "CONTINUE") {


           $redis->set($recipient,"$status:$message");

           # GOOD RESPONSE, CACHE FOR 5 DAYS
           $redis->expire("$recipient", 432000);

         } elsif(uc($status) eq "REJECT") {

           $redis->set($recipient,"$status:$message");

           # BAD RESPONSE, CACHE FOR 1 DAY
           $redis->expire("$recipient", 86400);

         } elsif (uc($status) eq "TEMPFAIL") {

           # IF THE RESPONSE IS TEMPORARY FAIL, DON'T CACHE THE RESULT
           alarm 0;
           return ($status, $message);

         }

         $redis->quit;

         # RESET ALARM BEFORE RETURNING
         alarm 0;
         return ($status, $message);
       }
     }
   };

   if ($@) {
     # FUNCTION TIMED OUT, FOR NOW, JUST SEND CONTINUE, LATER WE WILL 
NEED TO CALL THE md_check_against_smtp_server FUNCTION

     if ($@ =~ /timeout/) {
       md_syslog("warning", "DEBUG: Edge Test - Redis Eval timed out, 
sending CONTINUE, OK");
       return ("CONTINUE", "OK");
     } else {
       # FAILURE DID NOT COME FROM TIMEOUT, WARN AND DIE
       md_syslog("warning", "DEBUG: Edge Test - Redis Eval failed for 
reasons other than timeout $@, calling die");
       die;
     }

   } else {
     # NO TIMEOUT, RETURN VALUES SET
     return ($status, $message);
   }

}


More information about the MIMEDefang mailing list