Implementing procmail filters on a sendmail 8.x.x gateway
  for outgoing email filtering

Karl Dunn <k.l.dunn@ieee.org>, 2001/September/29

With credit to John Hardin <jhardin@wolfenet.com> for a good start,
who in turn credits Joshua Marshall <marshallj@switch.aust.com>.

This method assumes that all outgoing mail will be directed to a host
referred to below as "outmail.mydomain.com" (the one that will do the
filtering), and that "outmail" directs all mail to the actual gateway for
your installation.  See the test environment diagram, below.  In sendmail
parlance, all your clients should have "outmail" as their SMART_HOST, and
"outmail" should have your real gateway as its SMART_HOST.

Set up "outmail" so it can run sendmail 8.x.x, and install the sendmail m4
configuration file tree.

Edit the -.mc file (see below) to suit your own domain.  Be sure to
preserve the tabs in the LOCAL_RULE_0 section at the end.  The file lies
between the cut marks.  The file is provided separately; it is presented
here in case it got lost.

This file was tested as is for RedHat Linux 6.2.  The test environment is
described below.  If you have some other OS, start with the generic -.mc
file for that OS, and edit that.

The important additions that make sendmail filter all outgoing mail
through procmail are the line that reads "MAILER(procmail)dnl" and all
those following that line through the end.

Be sure to change the SMART_HOST line to point to your outer email
gateway. In the test environment diagram it is "gw.mydomain.com".  This
machine will be the "next hop".

If your procmail lives somewhere other than in /usr/bin, fix the path.

Once you like your -.mc file, run it through m4 as its comments show. That
generates sendmail.cf.  Be sure you put sendmail.cf where your OS expects
it to be.  The sendmail.cf that the provided -.mc generates is also
provided, both as a check and as a model to start from if you can't use
the m4 method.

Put the filter scripts and your poison list where they should be.  In this
tested case, the filters go in /etc/procmailrcs, and the poison list goes
in /etc/procmail.  It is wise to use those directories, unless you have a
good reason not to.

When all the above is ready, stop (kill) sendmail, and start it up again.

You can tell if the filter is being run by sending some mail out, and
examining the headers of the mail at its destination; there should be two
"Received" headers showing that the mail was handled by your outgoing host
(the one you did all this work on): one with and one without the .procmail
pseudo-domain on the "for" address.

-.mc file for generating sendmail.cf:

 -----------------Cut here----------------
divert(-1)
###########################################################################
###########################################################################
# @(#)outgoing.mydomain.com.mc 1.0 2001/08/22 VMIC
###########################################################################
# Sendmail m4 configuration for outgoing.mydomain.com
###########################################################################
#
dnl This is the macro config file used to generate the /etc/sendmail.cf
dnl file. If you modify this file you will have to regenerate the
dnl /etc/sendmail.cf by running this macro config through the m4
dnl preprocessor:
dnl
dnl        m4 /etc/outgoing.mc > /etc/sendmail.cf
dnl
dnl You will need to have the sendmail-cf package installed for this to
dnl work.
#
include(`/usr/lib/sendmail-cf/m4/cf.m4')
VERSIONID(`@(#)outgoing.mydomain.com.mc 1.0 2001/08/22 VMIC')dnl
define(`confDEF_USER_ID',``8:12'')
OSTYPE(`linux')dnl
undefine(`UUCP_RELAY')
undefine(`BITNET_RELAY')
define(`SMART_HOST',`gw.mydomain.com')dnl
define(`PROCMAIL_MAILER_PATH',`/usr/bin/procmail')dnl
define(`PROCMAIL_MAILER_ARGS',`procmail -f- -Y -m $h $f $u')dnl
FEATURE(`access_db')
FEATURE(local_procmail)
MAILER(smtp)dnl
MAILER(procmail)dnl
########################################################################
LOCAL_CONFIG
# Avoid host map lookups if address has this pseudo-domain on it
CPprocmail
LOCAL_RULE_0
# Filter all mail through procmail
#
# Strip the pseudo-domain and continue (already gone through the filter)
R$*<@$+.procmail>$*	$@ $1<@$2.>$3
R$*<@$+.procmail.>$*	$@ $1<@$2.>$3
#
# No pseudo-domain, send to filtering mailer
R$*<@$+.>$*	$#procmail $@/etc/procmailrcs/filterrc $:$1<@$2.procmail>$3
R$*<@$+>$*	$#procmail $@/etc/procmailrcs/filterrc $:$1<@$2.procmail>$3
########################################################################
 -----------------Cut here----------------

Test environment:

 -----------------------------------------

        |-----------------------|
        |                       |
        |  a.root-servers.net   | DNS root, simulated Internet
        |                       |
        |-----------------------|
                    | 192.5.6.30
                    |
                    |
                    |
                    | 192.5.6.254
   |---------------------------------|
   |  borderrouter.root-servers.net  |
   |                                 |
   |                                 | DNS, firewall, and mail gateway
   |         gw.mydomain.com         |
   |---------------------------------|
                    | 199.233.89.2
                    |
                    |----------------------------------|
                    |                                  |
                    | 199.233.89.10                    | 199.233.89.20
      |---------------------------|      |---------------------------|
      |                           |      |                           |
      |   outmail.mydomain.com    |      |   roebling.mydomain.com   |
      |                           |      |                           |
      |---------------------------|      |---------------------------|
          Outgoing mail filter                    Test client

 -----------------------------------------

Editing sendmail.cf itself (if you can't use m4):

  If you want to edit sendmail.cf directly (not recommended),
    follow the "Add" directions below.  Do not cut-paste,
    but save the lines out as three files, and insert those
    files at the places indicated.  This preserves the tabs
    and spaces as they are, which is very important.  Use
    the vi editor; if you use something else, be sure it is
    set up not to wrap lines, add carriage-returns, and so on.
    The lines to be added are between the ------- marks.

    When you get the above done, edit the line that begins with
    DS to point to your real mail gateway; if that machine is
    gw.mydomain.com, then the line reads "DSgw.mydomain.com".
    This sets the SMART_HOST, that is, the next hop.

  Add these two lines right before the line starting with:
        # Configuration version number
  This keeps sendmail from trying to resolve the pseudo-domain
  that the rulesets tack on as a marker to indicate that the
  procmail program has already processed the mail.  If you can't
  find the right place, put these somewhere near the top.

-------
# Avoid host map lookups if address has this pseudo-domain on it
CPprocmail
-------

  Add these nine lines after the line that starts with S98
  (if there is not such line, create one at the very end).
  This expects the outer procmail script (the one that invokes
  John's html-trap.procmail) to be /etc/procmailrcs/filterrc.
  You can change that, but don't lose the tab characters, and
  don't insert any others.  Notice that these appear to be in
  duplicated pairs; they are not, and must be as they are.

-------
# Filter all mail through procmail
#
# Strip the pseudo-domain and continue (already gone through the filter)
R$*<@$+.procmail>$*	$@ $1<@$2.>$3
R$*<@$+.procmail.>$*	$@ $1<@$2.>$3
#
# No pseudo-domain, send to filtering mailer
R$*<@$+.>$*	$#procmail $@/etc/procmailrcs/filterrc $:$1<@$2.procmail>$3
R$*<@$+>$*	$#procmail $@/etc/procmailrcs/filterrc $:$1<@$2.procmail>$3
-------

  Add these three lines before the "Local and Program Mailer specification"
  section, which has lines starting Mlocal and Mprog.  This is the
  delivery agent that runs procmail.  If your OS has procmail located
  somewhere else, either make a link to it in /usr/bin, or (preferably)
  edit the path.  (Note that the A flag does not include the path.)
  Again, be careful to preserve the tabs.

-------
Mprocmail,	P=/usr/bin/procmail, F=DFMSPhnu9, S=11/31, R=21/31, T=DNS/RFC822/X-Unix,
		A=procmail -f- -Y -m $h $f $u
-------



Here is a sample /etc/procmailrcs/filterrc file (Courtesy J. Hardin):

################################################################
#
# procmail rules to filter mail on a gateway
#

LOGFILE=/var/log/procmail.log
NL="
"
LOGABSTRACT=no

POISONED_EXECUTABLES=/etc/procmail/poisoned
# other configuration stuff here as well

INCLUDERC=/etc/procmail/html-trap.procmail

:0                              # re-send the message
! -oi -f "$@"

#
################################################################



Some remarks:

This scheme might work for both incoming and outgoing mail.  I have not
tried it for other than outgoing, however.

You should read John Hardin's writeup on putting procmail on a gateway, if
only to be better educated.  You need it on your outer (real) gateway,
anyway, to do incoming filtering.

The scheme presented here differs from John's primarily in that the rules
do not depend on the destination domain, and because they don't, they have
to be written in a different order.  The curious are encouraged to study
the sendmail configuration docs.

This scheme is the result of testing in the isolated environment given.
It is derived directly (same rulesets) from one we have used for about two
years at my company.

In my company's setup, the "outmail" host is an UltraSparc 10 running
Solaris 2.7 and sendmail 8.9.1, and the "real" gateway has been until
recently a pair of load-sharing Sun IPX machines running SunOS4.1.3 and
sendmail 8.10.1; they have been replaced by two 1 GHZ Pentium III machines
running FreeBSD 4.3 and sendmail 8.11.3, because the Sun IPXs were
becoming close to overloaded.  There is also a FreeBSD firewall between
"outmail" and the "real" gateways.  The current setup shows at most about
a 1% average CPU load over each five seconds, with a maximum allowed (by
sendmail) mail size of 5MB, while processing mail for about 200 clients.
Our mail traffic has about 5% mail with attachments, and those messages
that have attachments average about 500KB.  The setup should easily handle
50-100 times more load.  (The UltraSparc 10 is about an even match for the
Pentiums.)

And lastly:

To quote from some sixty-year-old instructions for putting a new piece of
gold leaf in an electroscope:  "You will probably have difficulty".

Karl Dunn <k.l.dunn@ieee.org>

