Crude blacklist for rt-mailgate

I’ve hacked a crude blacklist into rt-mailgate that helps keep
annoying things like bounces from broken mailers and worm droppings
from creating new tickets. It matches incoming mail against a list of
patterns and bounces the message to $RT::OwnerEmail if there is a
match.

There’s currently no way to “approve” an incoming message that would
otherwise be blacklisted. I’ve thought of a few ways to do it, but
haven’t implemented anything yet.

This patch also changes the behavior of MailError. It now attaches
the original message as a message/rfc822 attachment to the error
message. This way, the original message is preserved as much as
possible.

Jesse – you can do whatever you like with this if you find it
useful…

You need to add something like this to etc/config.pm:

Blacklist is a reference to an array of references to two element

arrays. Each outer element describes one blacklist entry. Each

entry is a reference to an array containing the header name and a

regular expression.

If any blacklist entry matches the corresponding header in an

incoming message, the message will be send to OwnerEmail instead of

being handled normally. Using “Body” as the header name will look

for matches in all the text body parts.

$Blacklist = [
[ “From”, “maildaemon@broken-mailer\.com” ],
[ “Subject”, “Snowhite and the Seven Dwarfs” ],
[ “Body”, “\nI send you this file in order to have your advice\n” ],
];

Here’s a patch against RT 2.0.7:

*** bin/rt-mailgate.orig Thu Aug 23 16:49:18 2001
— bin/rt-mailgate Sat Sep 15 19:47:00 2001
*** 27,32 ****
— 27,33 ----
ParseCcAddressesFromHead
ParseSenderAddressFromHead
ParseErrorsToAddressFromHead

  •   	     MatchBodyPattern
      	    );
    

    #Clean out all the nasties from the environment
    *** 123,128 ****
    — 124,152 ----
    my $IsSuspiciousSender = CheckForSuspiciousSender($head);

    my $IsALoop = CheckForLoops($head);

  • Send message to RT Owner if it is in the blacklist

  • my $blacklist = $RT::Blacklist;

  • for my $entry (@$blacklist) {

  • my ($field, $pattern) = @$entry;
    
  • if ($field eq "Body") {
    
  • if (MatchBodyPattern ($entity, $pattern)) {

  •   MailError(To => $RT::OwnerEmail,
    
  •         Subject => "RT Blacklist: $Subject",
    
  •         Explanation => "RT Blacklist: Body matches $pattern",
    
  •         MIMEObj => $entity);
    
  •   exit;
    
  • }

  • }
    
  • elsif ($head->get ($field) =~ /$pattern/) {
    
  • MailError(To => $RT::OwnerEmail,

  •     Subject => "RT Blacklist: $Subject",
    
  •     Explanation => "RT Blacklist: $field header matches $pattern",
    
  •     MIMEObj => $entity);
    
  • exit;

  • }
    
  • }

    #If the message is autogenerated, we need to know, so we can not
    *** lib/RT/Interface/Email.pm.orig Thu Aug 23 21:08:30 2001
    — lib/RT/Interface/Email.pm Sat Sep 15 20:24:00 2001
    *** 32,38 ****
    &ParseCcAddressesFromHead
    &ParseSenderAddressFromHead
    &ParseErrorsToAddressFromHead
    !
    &debug);
    }
    =head1 NAME
    — 32,39 ----
    &ParseCcAddressesFromHead
    &ParseSenderAddressFromHead
    &ParseErrorsToAddressFromHead
    ! &MatchBodyPattern
    !
    &debug);
    }
    =head1 NAME
    *** 292,299 ****
    $entity->attach( Data => $args{‘Explanation’}."\n");

    my $mimeobj = $args{'MIMEObj'};
    

! $mimeobj->sync_headers();
! $entity->add_part($mimeobj);

  if ($RT::MailCommand eq 'sendmailpipe') {
      open (MAIL, "|$RT::SendmailPath $RT::SendmailArguments") || return(0);

— 293,300 ----
$entity->attach( Data => $args{‘Explanation’}."\n");

  my $mimeobj = $args{'MIMEObj'};

! $entity->attach( Type => “message/rfc822”,
! Data => $mimeobj->as_string);

  if ($RT::MailCommand eq 'sendmailpipe') {
      open (MAIL, "|$RT::SendmailPath $RT::SendmailArguments") || return(0);

*** 538,543 ****
— 539,572 ----
my $Address = $AddrObj->address;

  return ($Address, $Name);
  • }
  • }}}

  • {{{ MatchBodyPattern

  • =head2 MatchBodyPattern ENTITY PATTERN
  • Return 1 if the body part of ENTITY matches pattern. Recursively decends
  • through multipart bodies.
  • =cut
  • sub MatchBodyPattern {
  • my $entity = shift;
    
  • my $pattern = shift;
    
  • my $bh = $entity->bodyhandle;
    
  • if ($bh) {
    
  • if ($entity->effective_type() =~ /^text//) {
  •   return $bh->as_string =~ $pattern;
    
  • }
  • }
    
  • else {
    
  • for my $part ($entity->parts) {
  •   return 1 if MatchBodyPattern ($part, $pattern);
    
  • }
  • }
    
    }

    }}}

– Bob