[Mimedefang] Sharing local changes to mimedefang-filter

Philip Prindeville philipp_subx at redfish-solutions.com
Thu Feb 22 03:07:03 EST 2007


Made the following changes here that we're using, and thought
I'd share them to see if anyone else got any use from them:

  # %DESCRIPTION:
  #  Called just before e-mail parts are processed
  #***********************************************************************
  sub filter_begin {
      my($entity) = @_;
      # ALWAYS drop messages with suspicious chars in headers
      if ($SuspiciousCharsInHeaders) {
        md_graphdefang_log('suspicious_chars');
        # action_quarantine_entire_message("Message quarantined because of suspicious characters in headers");
        # Do NOT allow message to reach recipient(s)
+       action_bounce("Message rejected; illegal characters in message (per RFC 2821, 2822)");
        return action_discard();
      }


...
      # Block message/partial parts
      if (lc($type) eq "message/partial") {
        md_graphdefang_log('message/partial');
        action_bounce("MIME type message/partial not accepted here");
        return action_discard();
      }

      if (filter_bad_filename($entity)) {
        md_graphdefang_log('bad_filename', $fname, $type);
!       return action_bounce("Message rejected; an attachment named $fname of\ndubious nature was found in this message.\nContact the postmaster if this was a legitimate transfer.\n");
      }

      return action_accept();
  }
...

  sub defang_warning {
      my($oldfname, $fname) = @_;
      return
        "An attachment named '$oldfname' was converted to '$fname'.\n" .
        "To recover the file, right-click on the attachment and Save As\n" .
        "'$oldfname'\n";
  }

+ sub send_mail_flattened {
+     my($entity) = @_;
+
+     my $msg = '';
+
+     $msg .= "From: mimedefang\n";
+     $msg .= "To: spamdrop\n";
+     $msg .= "Subject: [Spam from " . $RelayAddr . "] " . $Subject . "\n";
+     $msg .= gen_date_msgid_headers();
+     $msg .= "Content-type: text/plain\n";
+     $msg .= "\n";
+     $msg .= "The following message was received.  Please secure this source.\n\n===== Offending message follows =====\n";
+     $msg .= synthesize_received_header();
+     $msg .= $entity->stringify();
+     send_mail('mimedefang', '', 'spamdrop', $msg);
+ }
+
  # If SpamAssassin found SPAM, append report.  We do it as a separate
  # attachment of type text/plain
  sub filter_end {
      my($entity) = @_;

      # If you want quarantine reports, uncomment next line
      # send_quarantine_notifications();

      # IMPORTANT NOTE:  YOU MUST CALL send_quarantine_notifications() AFTER
      # ANY PARTS HAVE BEEN QUARANTINED.  SO IF YOU MODIFY THIS FILTER TO
      # QUARANTINE SPAM, REWORK THE LOGIC TO CALL send_quarantine_notifications()
      # AT THE END!!!

      # No sense doing any extra work
      return if message_rejected();

+     # Skip if locally originated
+     return if ($RelayAddr eq '127.0.0.1');
+
      # Spam checks if SpamAssassin is installed
!     if ($Features{"SpamAssassin"} && !defined($SendmailMacros{'auth_type'})) {
         if (-s "./INPUTMSG" < 100*1024) {
            # Only scan messages smaller than 100kB.  Larger messages
            # are extremely unlikely to be spam, and SpamAssassin is
            # dreadfully slow on very large messages.
            my($hits, $req, $names, $report) = spam_assassin_check();
            my($score);
            if ($hits < 40) {
                $score = "*" x int($hits);
            } else {
                $score = "*" x 40;
            }
            # We add a header which looks like this:
            # X-Spam-Score: 6.8 (******) NAME_OF_TEST,NAME_OF_TEST
            # The number of asterisks in parens is the integer part
            # of the spam score clamped to a maximum of 40.
            # MUA filters can easily be written to trigger on a
            # minimum number of asterisks...
            if ($hits >= $req) {
-               action_change_header("X-Spam-Score", "$hits ($score) $names");
                md_graphdefang_log('spam', $hits, $RelayAddr);

!               action_bounce("Message rejected; scored too high on the Spam test.");
!               send_mail_flattened($entity);
!
!               return action_discard();
            } else {
                # Delete any existing X-Spam-Score header?
                action_delete_header("X-Spam-Score");



I mangled the diffs a little to shorten them (and because
there were some cosmetic changes that didn't need to be
included).

Hopefully they are still readable.

We take the original message, add a received header, and then
stuff it as flat text into the body of a message which we then
deliver to the "spamdrop" mailbox.  We also add a header which
is a clone of the original Subject:, plus the address of the
relay from whence it came.

Locally I have this forward to another mailbox, and when I
access that mailbox with Thunderbird, I can do "Edit as new",
replace the "From" and "To" fields, and send it off as a spam
report to the appropriate ARIN (or RIPE or LACNIC or...)
contact address.

It seems to work fairly well.  The hard part was getting the
flattened message to not loop as spam.

That's why I was asking earlier about having a foolproof way
to avoid running filtering on locally submitted messages, and
making it a permanent part of the base mimedefang-filter code.

One unfortunate side-effect of the code is that it mangles the
message, so it can't simply be forwarded intact to it's originally
intended recipient if it turns out to be Ham.  The reason for
this being that there are a lot of braindead ISP's out there that
strip attachments on submissions to their abuse mailbox... even
though forwarding an original message as an attachment is one of
the foolproof ways of making sure it gets included verbatim.

Oh, well.  Lowest common denominator...

Anyone have any useful comments?  Insights?  Benedictions?

Thanks,

-Philip





More information about the MIMEDefang mailing list