2010/3/22 David F. Skoll <[email protected]>: > Jakub Wasielewski wrote: > >> Thanks for an reply. I tried using stream_by_recipient() function in >> filter_begin as it is >> recommended in manual: > > I didn't say you *should* use it. I was asking if you were > already using it.
I was trying to solve this problem with it. But no, I do not use stream_by_*(). > The only way I can see a DSN being generated is if (1) you're misusing > md_check_against_smtp_server or (2) you're somehow remailing messages. > You will need to post your entire filter for us to figure it out. Ok, here it is. Some stuff has been changed - like domain names or IP addrs. # -*- Perl -*- #*********************************************************************** # # mimedefang-filter # # Suggested minimum-protection filter for Microsoft Windows clients, plus # SpamAssassin checks if SpamAssassin is installed. # # Copyright (C) 2002 Roaring Penguin Software Inc. # # This program may be distributed under the terms of the GNU General # Public License, Version 2, or (at your option) any later version. # # $Id$ #*********************************************************************** use Mail::SPF::Query; $AdminAddress = '[email protected]'; $AdminName = "System pocztowy example.pl"; $DaemonAddress = '[email protected]'; $NotifySenderSubject = '=?ISO-8859-2?Q?Wiadomo=B6=E6_od_systemu_pocztowego_example=2Epl?='; $NotifyAdministratorSubject = '=?ISO-8859-2?Q?Wiadomo=B6=E6_od_systemu_pocztowego_example=2Epl?='; $Features{'SpamAssassin'} = 0; $Stupidity{"flatten"} = 0; $Stupidity{"NoMultipleInlines"} = 0; $NotifyNoPreamble = 1; $AddWarningsInline = 0; $MaxMIMEParts = 25; $ClamdSock = '/var/run/clamav/clamd.sock'; #*********************************************************************** # To enable syslogging of virus and spam activity, add the following # to the filter: # md_graphdefang_log_enable(); # You may optionally provide a syslogging facility by passing an # argument such as: md_graphdefang_log_enable('local4'); If you do this, be # sure to setup the new syslog facility (probably in /etc/syslog.conf). # An optional second argument causes a line of output to be produced # for each recipient (if it is 1), or only a single summary line # for all recipients (if it is 0.) The default is 1. # Comment this line out to disable logging. #*********************************************************************** md_graphdefang_log_enable('mail', 1); # Detect and load Perl modules detect_and_load_perl_modules(); sub check_spf { my $spfq = Mail::SPF::Query->new(@_); my($result, $smtp_comment, $header_comment, $spf_record) = $spfq->result(); if ($result eq 'pass' or $result eq 'fail') { md_syslog('info', "$QueueID: SPF implemented=yes, result=$result, smtp_comment=$smtp_comment, header_comment=$header_comment"); } else { my($result, $smtp_comment, $header_comment) = $spfq->best_guess(); $smtp_comment ||= ''; $header_comment ||= ''; md_syslog('info', "$QueueID: SPF implemented=no, result=$result, smtp_comment=$smtp_comment, header_comment=$header_comment"); } return ($result, $smtp_comment, $header_comment); } sub filter_sender { my($sender, $ip, $hostname, $helo) = @_; return('CONTINUE', "ok") if ($ip eq "127.0.0.1"); md_syslog('info', " == SENDER == :: $sender"); # sprawdzenie czy host nie podszywa się pod moje serwery if ($helo =~ /(^|.)example\.pl$/i) { if ($ip ne "1.2.3.8" and $ip ne "1.2.3.9" and $ip ne "1.2.3.10" and $ip ne "1.2.3.11" and $ip ne "1.2.3.12" and $ip ne "1.2.3.13" and $ip ne "1.2.3.14" and $ip ne "1.2.3.15" and $ip ne "1.2.3.18" and $ip ne "1.2.3.130" and $ip ne "1.2.3.178") { md_syslog('info', "Host $ip sent fake HELO : $helo"); return('REJECT', "Go away. $ip is not a example.pl machine."); } } # oczywista fałszywka ip w HELO != ip hosta if (($helo =~ /^(d{1,3})(.)(d{1,3})(.)(d{1,3})(.)(d{1,3})$/) && ($ip ne $helo)) { return('REJECT', "Header forgery attempt, $ip claims to be $helo"); } read_commands_file(); # if ($sender eq "<>") { # return ('REJECT', 'Message rejected. Administrative messages not accepted.'); # } # SPF jeśli niezautoryzowany if ($SendmailMacros{auth_authen} eq "") { my ($result, $smtp_comment, $header_comment) = check_spf(ip => $ip, sender => $sender, helo => $helo); if ($result eq 'fail') { return ('REJECT', 'Message rejected. ' . $smtp_comment); } } else { if ($sender eq "<>") { return ('REJECT', 'Message rejected. Authorized users should not send administrative messages.'); } } return('CONTINUE', "ok"); } sub filter_recipient { my ($recipient, $sender, $ip, $hostname, $first, $helo, $rcpt_mailer, $rcpt_host, $rcpt_addr) = @_; return('CONTINUE', "ok") if ($ip eq "127.0.0.1"); read_commands_file(); if ($ip eq '127.0.0.1') { return ('CONTINUE', "ok"); } elsif ($recipient =~ /\...@example\.pl/i) { return ('CONTINUE', "ok"); } elsif ($recipient =~ /\...@example2\.pl/i or $recipient =~ /\...@example3\.pl/i or $recipient =~ /\...@example4\.pl/i or $recipient =~ /\...@example5\.pl/i or $recipient =~ /\...@example6\.pl/i) { my ($result, $msg) = md_check_against_smtp_server($sender, $recipient, "smtp1.example.pl", "smtp2.example.pl"); md_syslog('info', "Recipient check: $result - $msg"); return ($result, $msg); } return ('CONTINUE', "ok"); } # This procedure returns true for entities with bad filenames. sub filter_bad_filename { my($entity) = @_; my($bad_exts, $re); # Bad extensions $bad_exts = '(ade|adp|app|asd|asf|asx|bas|bat|chm|cmd|com|cpl|crt|dll|exe|fxp|hlp|hta|hto|inf|ini|ins|isp|jse?|lib|lnk|mdb|mde|msc|msi|msp|mst|ocx|pcd|pif|prg|reg|scr|sct|sh|shb|shs|sys|url|vb|vbe|vbs|vcs|vxd|wmd|wms|wmz|wsc|wsf|wsh|\{[^\}]+\})'; # Do not allow: # - CLSIDs {foobarbaz} # - bad extensions (possibly with trailing dots) at end $re = '\.' . $bad_exts . '\.*$'; return 1 if (re_match($entity, $re)); # Look inside ZIP files # if (re_match($entity, '\.zip$') and # $Features{"Archive::Zip"}) { # my $bh = $entity->bodyhandle(); # if (defined($bh)) { # my $path = $bh->path(); # if (defined($path)) { # return re_match_in_zip_directory($path, $re); # } # } # } return 0; } #*********************************************************************** # %PROCEDURE: filter_begin # %ARGUMENTS: # $entity -- the parsed MIME::Entity # %RETURNS: # Nothing # %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) return action_discard(); } # if ($RelayAddr ne "127.0.0.1") { # md_syslog('info', " == RELAY == :: $RelayAddr"); # if (stream_by_recipient()) { # md_syslog('info', " == STREAM_BY_DOMAIN() =="); # return; # } # } # Copy original message into work directory as an "mbox" file for # virus-scanning md_copy_orig_msg_to_work_dir_as_mbox_file(); # Scan for viruses if any virus-scanners are installed my($code, $category, $action) = message_contains_virus(); # Lower level of paranoia - only looks for actual viruses $FoundVirus = ($category eq "virus"); # Higher level of paranoia - takes care of "suspicious" objects # $FoundVirus = ($action eq "quarantine"); if ($FoundVirus) { md_graphdefang_log('virus', $VirusName, $RelayAddr); md_syslog('warning', "Discarding because of virus $VirusName"); return action_discard(); } if ($action eq "tempfail") { action_tempfail("Problem running virus-scanner"); md_syslog('warning', "Problem running virus scanner: code=$code, category=$category, action=$action"); } } #*********************************************************************** # %PROCEDURE: filter # %ARGUMENTS: # entity -- a Mime::Entity object (see MIME-tools documentation for details) # fname -- the suggested filename, taken from the MIME Content-Disposition: # header. If no filename was suggested, then fname is "" # ext -- the file extension (everything from the last period in the name # to the end of the name, including the period.) # type -- the MIME type, taken from the Content-Type: header. # # NOTE: There are two likely and one unlikely place for a filename to # appear in a MIME message: In Content-Disposition: filename, in # Content-Type: name, and in Content-Description. If you are paranoid, # you will use the re_match and re_match_ext functions, which return true # if ANY of these possibilities match. re_match checks the whole name; # re_match_ext checks the extension. See the sample filter below for usage. # %RETURNS: # Nothing # %DESCRIPTION: # This function is called once for each part of a MIME message. # There are many action_*() routines which can decide the fate # of each part; see the mimedefang-filter man page. #*********************************************************************** sub filter { my($entity, $fname, $ext, $type) = @_; return if message_rejected(); # Avoid unnecessary work # 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_drop_with_warning("An attachment named $fname was removed from this document as it\nconstituted a security hazard. If you require this document, please contact\nthe sender and arrange an alternate means of receiving it.\n"); } return action_accept(); } #*********************************************************************** # %PROCEDURE: filter_multipart # %ARGUMENTS: # entity -- a Mime::Entity object (see MIME-tools documentation for details) # fname -- the suggested filename, taken from the MIME Content-Disposition: # header. If no filename was suggested, then fname is "" # ext -- the file extension (everything from the last period in the name # to the end of the name, including the period.) # type -- the MIME type, taken from the Content-Type: header. # %RETURNS: # Nothing # %DESCRIPTION: # This is called for multipart "container" parts such as message/rfc822. # You cannot replace the body (because multipart parts have no body), # but you should check for bad filenames. #*********************************************************************** sub filter_multipart { my($entity, $fname, $ext, $type) = @_; return if message_rejected(); # Avoid unnecessary work if (filter_bad_filename($entity)) { md_graphdefang_log('bad_filename', $fname, $type); action_notify_administrator("A MULTIPART attachment of type $type, named $fname was dropped.\n"); return action_drop_with_warning("An attachment of type $type, named $fname was removed from this document as it\nconstituted a security hazard. If you require this document, please contact\nthe sender and arrange an alternate means of receiving it.\n"); } # 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; } return action_accept(); } #*********************************************************************** # %PROCEDURE: defang_warning # %ARGUMENTS: # oldfname -- the old file name of an attachment # fname -- the new "defanged" name # %RETURNS: # A warning message # %DESCRIPTION: # This function customizes the warning message when an attachment # is defanged. #*********************************************************************** 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"; } # 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(); # I HATE HTML MAIL! If there's a multipart/alternative with both # text/plain and text/html parts, nuke the text/html. Thanks for # wasting our disk space and bandwidth... # If you want to strip out HTML parts if there is a corresponding # plain-text part, uncomment the next line. # remove_redundant_html_parts($entity); md_graphdefang_log('mail_in'); # Deal with malformed MIME. # Some viruses produce malformed MIME messages that are misinterpreted # by mail clients. They also might slip under the radar of MIMEDefang. # If you are worried about this, you should canonicalize all # e-mail by uncommenting the action_rebuild() line. This will # force _all_ messages to be reconstructed as valid MIME. It will # increase the load on your server, and might break messages produced # by marginal software. Your call. # action_rebuild(); } # DO NOT delete the next line, or Perl will complain. 1; Cheers, -- Jakub Wasielewski _______________________________________________ NOTE: If there is a disclaimer or other legal boilerplate in the above message, it is NULL AND VOID. You may ignore it. Visit http://www.mimedefang.org and http://www.roaringpenguin.com MIMEDefang mailing list [email protected] http://lists.roaringpenguin.com/mailman/listinfo/mimedefang

