
				         Created: Mon Dec 31 17:39:29 EST 2001
					 Updated: Fri Oct  3 18:01:53 EDT 2003

Jim Seymour's suggestions/examples for Postfix anti-UCE configuration.
                    (Aka: Postfix anti-UCE Cheat Sheet)

			    USE AT YOUR OWN RISK!

            Note that *my* configuration may not be suitable for
            *your* purposes.  That is one reason I put lots of
            comments and so-forth in here.  Read it, understand
	    it, and formulate a stance that best suits *your*
	    needs.

The "general flow" of the smtp_recipient_restrictions in main.cf is as
follows (and yes: the order *is* important):

    1. (1st 6 statements): ensure the HELO/EHLO and smtp envelope stuff
       are "sane."  Prohibit verification checks of recipient addresses.
    2. Dis-allow command "pipelining."  (Generally only spamware tries
       to pipeline--particularly during dictionary attacks.)
    3. Permit anything that passes the above restrictions and is from my
       network.  (Destination doesn't matter.)
    4. Out-right reject anything from outside that's not destined for my
       network.
    5. Check certain recipient addresses before any local blacklisting
       or DNSbl checks.
    6. Check the local black-lists, white-lists and combined black-/white-
       lists (HELO/EHLO, sender [envelope from] and client [sending server]
       checks).
    7. Check the DNSbls and RHSbls

Check the Postfix docs for what it all means, in detail.  If you're in
doubt: join the postfix-users mailing list and ask.

For 1.x versions of Postfix:

    /etc/postfix/main.cf:

	smtpd_helo_required = yes
	disable_vrfy_command = yes

	maps_rbl_domains =
	    relays.ordb.org,
	    opm.blitzed.org,
	    list.dsbl.org,
	    sbl.spamhaus.org,
	    blackholes.easynet.nl,
	    cbl.abuseat.org

	smtpd_recipient_restrictions =
	    reject_invalid_hostname,
	    reject_non_fqdn_hostname,
	    reject_non_fqdn_sender,
	    reject_non_fqdn_recipient,
	    reject_unknown_sender_domain,
	    reject_unknown_recipient_domain,
	    reject_unauth_pipelining,
	    permit_mynetworks,
	    reject_unauth_destination,
	    check_recipient_access pcre:/etc/postfix/recipient_checks.pcre,
	    check_helo_access dbm:/etc/postfix/helo_checks,
	    check_sender_access dbm:/etc/postfix/sender_checks,
	    check_client_access dbm:/etc/postfix/client_checks,
	    check_client_access pcre:/etc/postfix/client_checks.pcre,
	    reject_maps_rbl,
	    permit

For 2.x versions of Postfix:

    /etc/postfix/main.cf:

	smtpd_helo_required = yes
	disable_vrfy_command = yes

	smtpd_recipient_restrictions =
	    reject_invalid_hostname,
	    reject_non_fqdn_hostname,
	    reject_non_fqdn_sender,
	    reject_non_fqdn_recipient,
	    reject_unknown_sender_domain,
	    reject_unknown_recipient_domain,
	    reject_unauth_pipelining,
	    permit_mynetworks,
	    reject_unauth_destination,
	    check_recipient_access pcre:/etc/postfix/recipient_checks.pcre,
	    check_helo_access dbm:/etc/postfix/helo_checks,
	    check_sender_access dbm:/etc/postfix/sender_checks,
	    check_client_access dbm:/etc/postfix/client_checks,
	    check_client_access pcre:/etc/postfix/client_checks.pcre,
	    reject_rbl_client relays.ordb.org,
	    reject_rbl_client opm.blitzed.org,
	    reject_rbl_client list.dsbl.org,
	    reject_rbl_client sbl.spamhaus.org,
	    reject_rbl_client blackholes.easynet.nl,
	    reject_rbl_client cbl.abuseat.org,
	    permit

    # IMPORTANT NOTES
    #
    # "dbm" or "hash" depends on your system.  The above is for my Sun
    # SPARC Solaris boxen.  Linux usually uses "hash".
    #
    # You need to have PCRE support built into Postfix at compile time to
    # use the "pcre:" types.
    #
    # If it's necessary that the mail server accept SMTP connections
    # from internal machines that don't HELO properly, you'll have to
    # move at least reject_non_fqdn_hostname, and possibly also
    # reject_invalid_hostname, to *after* permit_mynetworks.  There's no
    # harm in doing this, should you find it necessary.  See FAQ items
    # 2-4 for more on this topic.
    #
    # The trailing "permit" isn't necessary, strictly speaking, because
    # there's an earlier "permit_mynetworks."  I just put it there because
    # it makes clear that whatever passes the earlier "check" and "reject"
    # tests will be permitted.  I like "self-documenting ``code''".
    #
    # Lastly: You'll observe that all of my anti-UCE checks are under
    # smtpd_recipient_restrictions, instead of having a separate
    # smtpd_client_restrictions.  This is because, unless you have set
    # smtpd_delay_reject = no (default is "yes"), no rejecting takes
    # place until after RCPT TO anyway.  It's easier, cleaner and more
    # predictable when all of the anti-UCE stuff is under recipient
    # restrictions.

/etc/postfix/recipient_checks.pcre:

    # Note: You must have PCRE support support built in to Postfix at
    # compile time to use this.  (Tho I've been told the following are
    # valid POSIX RE's ["regexp:" map type], as well.)
    #
    # Postfix doesn't relay by default.  But it may *appear* to do so
    # to some testers.  The first two statements below remove all
    # doubt.

    /^\@/		550 Invalid address format.
    /[!%\@].*\@/	550 This server disallows weird address syntax.

    # Let email to the following destinations bypass all the remaining
    # "reject" and "check" tests.  We always want to let email for these
    # recipients in.

    /^postmaster\@/	OK
    /^hostmaster\@/	OK
    /^abuse\@/	OK

	# Note: The "OK"s above, for postmaster, etc., will *not*
	# bypass header and body checks.  There is currently no way
	# to do so with Postfix :(
	#
	# Remember where I said, at the very beginning, about how
	# order is important?  Whatever you do, do *not* place an
	# access map like this one before the "permit mynetworks"
	# and "reject_unauth_destination" statements.  Not unless
	# you want to be an open relay, anyway.


/etc/postfix/helo_checks:

    # This file has to be "compiled" with "postmap"

    # Reject anybody that HELO's as being in our own domain(s)
    # (Note that if you followed the order suggested in the main.cf
    # examples, above, that machines in mynetworks will be okay.)

    example.tld			REJECT You are not in example.tld
    foobarbaz.tld		REJECT You are not in foobarbaz.tld

    # Somebody HELO'ing with our IP address?
    192.168.1.2			REJECT You are not 192.168.1.2

    # Somebody HELO'ing as "localhost?"  Impossible, we're "localhost"
    localhost			REJECT You are not me


/etc/postfix/helo_checks.pcre:

    # Note: You must have PCRE support support built in to Postfix at
    # compile time to use this.
    #
    # No, you won't find this entry in my "smtpd_recipient_restrictions,"
    # above.  I'm not doing this check (at this time).

    # If you want to be really picky about it: HELO'ing with an IP
    # address is RFC-compliant - *if* it's enclosed in square-brackets
    # ("[]"s).  (One would think "reject_invalid_hostname" checks for
    # this, but it does not.)
    #
    # Somebody HELO'ing with a non-RFC-compliant dotted-quad IP
    # address?  For shame!  (I don't do this check, btw.)
    /^[0-9]+(\.[0-9]+){3}$/	REJECT Invalid hostname


/etc/postfix/sender_checks:

    # This file must be "compiled" with "postmap"

    # Using a domain name
    example.tld			554 Spam not tolerated here

    # Maybe example2.tld is on a DNSbl, but we want to let their
    # email in anyway.
    example2.tld		OK

    # We get lots of spam from example3.tld, but we have somebody
    # there from which we do want to hear
    someuser@example3.tld	OK
    example3.tld		REJECT


/etc/postfix/client_checks:

    # This file must be "compiled" with "postmap"

    # Using a domain name
    example.tld			554 Spam not tolerated here

    # Maybe example2.tld is on a DNSbl, but we want to let their
    # email in anyway.
    example2.tld		OK

    # Checking by IP address
    # 10.0.0.0/8
    10				554 Go away!

    # 172.16/16
    172.16			554 Bugger off!

    # 192.168.4/24 is bad, but 192.168.4.128 is okay
    192.168.4.128		OK
    192.168.4			554 Take a hike!


/etc/postfix/client_checks.pcre:

    # Postfix' dbm/hash files don't allow CIDR notation, netmasks
    # or address ranges, but you can achieve the same end with
    # regular expressions.
    #
    # Again: these are in PCRE notation.  But you could accomplish
    # the same with POSIX RE's.  (I just don't know how.)

    # 10.9.8.0 - 10.9.9.255
    /10\.9\.[89]\.\d+/		REJECT

    # 10.9.8.0 - 10.9.10.255 is generally no good, but 10.9.8.7 is OK
    /10\.9\.8\.7/		OK
    /10\.9\.([89]|10)\.\d+/	554 Go away. We don't want any!

    # A much more complex example of listing a (CIDR) IP range
    # (If this makes your eyes cross, just ignore it for now)
    # 10.33.192.0/19 = 10.33.192.0 - 10.33.223.255         
    /^10\.33\.(19[2-9])|(2(0[0-9]|1[0-9]|2[0-3]))\.\d{1,3}$/    REJECT


General Notes On "hostname," "helo," "client," "sender" and "recipient"
Access Lists and Restrictions

    What "hostname," "helo," "sender" and "client" mean

	HELO/EHLO is what the sending machine *tells* your machine it
	is.  It is easily spoofed and frequently mis-configured.
	Thus it may have no basis in reality.

	    HELO/EHLO is checked with the "helo" and "hostname"
	    smtpd restrictions and checks.

	"Sender" is the envelope-sender address (SMTP "MAIL FROM"), not
	the client machine's IP address or host name, or the "From:"
	field in the headers.  (Though envelope-sender may well match
	"From:" in the headers.)

	    "Sender" is checked with the smtpd sender restrictions
	    and checks.

	"Client" is the sending machine's IP address--and possibly host
	name (if one can be derived from a reverse lookup of the IP
	address).

	    "Client" is checked with the smtpd client restrictions
	    and checks.

    "Recipient" refers to the email address passed in the SMTP RCPT TO,
    not the "To:," "Cc:" or other fields in the header.

	"Recipient" is checked with the smtpd recipient restrictions
	and checks.

    If you put access lists *before* the DNSbl checks, as shown in the
    "main.cf" examples, above, they can serve as combined whitelists and
    blacklists.

    If you want smtpd access map entries to match hosts and sub-domains
    on just the domain part (e.g.: "example.com" matches "host.example.com"
    and "host.subdomain.example.com," you must specify:

	parent_domain_matches_subdomains = smtpd_access_maps

    in main.cf.  Otherwise, you have to do things like:

	example.com	REJECT
	.example.com	REJECT

    The "parent_domain_matches_subdomains" parameter became available in
    Postfix versions as of 20011119.  Prior to that, you must use the
    "multiple/leading-dot entry" solution.

    Postfix experimental release 20030706 contains experimental support
    for CIDR-based lookup tables, so the regexp-type lookups for address
    ranges may soon no longer be necessary.  To see if your version of
    Postfix supports CIDR-based maps, do a "man cidr_table" and look for
    "cidr" in the output of "postconf -m".

    See the FAQ regarding "null senders."  (Aka: Empty MAIL FROM or empty
    envelope sender.)


Understanding The Order In Which Restrictions Are Applied

    There are three parts to restrictions:

	restriction "stages"
	restrictions
	access lists (or maps)

    Postfix' restriction stages are as follows, and are processed in the
    following order:

	smtpd_client_restrictions
	smtpd_helo_restrictions
	smtpd_sender_restrictions
	smtpd_recipient_restrictions
	smtpd_data_restrictions

    regardless of the order in which they're listed in main.cf.

    Processing *within* a restriction stage ends on the first match,
    with the exception of a "DUNNO" result.

	What means "DUNNO?"  "DUNNO" means "I don't know, somebody
	else decide."  DUNNO is covered in more detail, later.

    Each restriction stage must evaluate to "OK" or "DUNNO" for processing
    to continue with the next stage.

    The default value of the smtpd_recipient_restrictions stage is the
    result of "permit_mynetworks, reject_unauth_destination".  The default
    for every other stage is empty--the default action for which is
    "DUNNO".

    Individual restrictions (within a restriction stage) are evaluated in
    the order in which they're listed.

    Items in an access list are are matched depending on the type of
    access list.  Regular expression tables, such as pcre and regexp, are
    checked in the order in which entries are listed.  Indexed table
    map types such as hash, dbm, btree, etc., use the value being checked
    as an index key.

    Here are some simple (and *not* fully-functional!) examples to
    demonstrate the principles described above:

	Notes:

	    We'll assume /etc/postfix is Postfix' configuration
	    directory.

	    "mumble:" refers to an indexed map type, such as
	    "hash:," "dbm:," etc.

    Suppose you have client_checks and sender_checks access maps that look
    like this:

	/etc/postfix/client_checks:
	    # Block most clients in 10.*
	    10          REJECT
	    # But not 10.1.2.3, specifically
	    10.1.2.3    DUNNO
	    # We specifically white-list 172.16.4.5 - maybe!
	    172.16.4.5  OK
	    # We specifically black-list 192.168.6.7
	    192.168.6.7 REJECT

	/etc/postfix/sender_checks:
	    joe@example.com  OK
	    bob@example.com  REJECT

    If placed in separate restriction stages:

	/etc/postfix/main.cf (partial):
	    ...

	    smtpd_client_restrictions =
		<first client restriction>,
		check_client_access mumble:/etc/postfix/client_checks,
		<third client restriction>,
		etc...

	    smtpd_sender_restrictions =
		<first sender restriction>,
		check_sender_access mumble:/etc/postfix/sender_checks,
		<third sender restriction>,
		etc...

	    ...

    A client address of 192.168.6.7 will result in a REJECT, and that's
    it.  If Joe's email was coming from that address, he's out of luck.
    Processing will never reach smtpd_sender_restrictions.

    A client address of 172.16.4.5 will stop further processing of
    additional client checks - so "<third client restriction>" will not be
    processed.  But since that restriction stage evaluated to "OK,"
    smtpd_sender_restrictions will still be processed.  A sender of
    bob@example.com will result in a REJECT.

    If instead you were to do something like this:

	/etc/postfix/main.cf (partial):
	    ...

	    smtpd_sender_restrictions =
		<first restriction>,
		check_client_access mumble:/etc/postfix/client_checks,
		check_sender_access mumble:/etc/postfix/sender_checks,
		<fourth restriction>,
		etc...

	    ...

    The "OK" of 172.16.4.5 would stop further processing of the sender
    restrictions stage, and good ol' Bob would get through.

    What do you mean, "DUNNO?"

	It was noted earlier that a match stops further processing of an
	access list, and of the restriction stage that "called" it.  But
	what does a restriction return when there's no match?  Well, it
	returns "DUNNO."  ("I don't know, somebody else decide.")

	It can be handy to explicitly specify DUNNO in certain
	circumstances, such as to suppress further lookups in an access
	list, but where you don't necessarily want to "OK" something.
	Postfix lets you do this.

	In the examples above, a client address of 10.1.2.3 would halt
	further checks in the client_checks access map, just as if an OK
	or REJECT were specified, but processing would resume with the
	next restriction check in that stage.

	How might this come in handy?

	    Well, let's say:

		You don't want to accept connections from 10.* IPs

		Except for example.com, at 10.1.2.3, which you do want

		But you don't want to hear from Bob.

	    Using the second example of smtpd_sender_restrictions, above:

		Everything but 10.1.2.3 will result in a REJECT because of
		the first two client_checks entries.

		Since 10.1.2.3 resulted in a DUNNO, rather than an OK,
		processing will resume with the sender checks.

		Bob will get REJECTed by the entry in the sender checks
		file.

    Finally, remember that unless you have set smtpd_delay_reject = no
    (default is "yes"), no actual rejecting takes place until after RCPT
    TO in the SMTP exchange.  In fact...

    You can put all restrictions under one restriction class?

	Yes.  As Liviu Daia notes:

	    Any of the smtpd restrictions may contain checks
	    referring to a preceding SMTP stage
	    (check_sender_access may appear [for example] in
	    smtpd_recipient_restrictions), with the exception of
	    smtpd_data_restrictions, which, as a rule of thumb,
	    should not refer to restrictions specific to
	    recipient checks.

        Victor Duchovni added:

	    With "smtpd_delay_reject = yes" (that is by
	    default), *all* the built-in restriction lists other
	    than "smtpd_data_restrictions" are evaluated for
	    every recipient. So if possible expensive checks on
	    the client ip or name, HELO name, or sender address
	    that are independent of the recipient address should
	    be moved to the "data" restrictions.  In this
	    scenario smtpd_recipient_restrictions can be used
	    for just relay control!

	    Note that results of RBL lookups are cached, so
	    these are cheap to evaluate multiple times.

	So, for performance reasons, one might be tempted to put all
	restrictions in smtpd_data_restrictions.  But note also this
	comment by Victor Duchovni:

	    Multi-recipient messages do not have a "distinguished"
	    recipient. So all restrictions that look at recipient
	    addresses evaluate to "DUNNO" when used in the data
	    restrictions. This is why they are not generally useful
	    in that context.

    Acknowledgments

	This section was created from contributions by Noel Jones,
	Liviu Daia and Victor Duchovni in the postfix-users mailing
	list.


Understanding Header and Body Checks

    Header and body checks files are not access maps.  You *don't*
    "postmap" them.  Nor do you "postmap" any other regexp or pcre file.
    (You do have to do a "postfix reload" after changing them, however.)

    Header checks regular expressions are applied in the order in which
    they are listed in your header checks file.  First match wins.   They
    are applied to each header in the email in the order in which the
    headers are seen.  Body checks work similarly, except against the
    email body, line-by-line.

    You cannot whitelist a sender or client in an access list to bypass
    header or body checks.  Header and body checks take place whether you
    explicitly "OK" a client or sender, in access lists, or not.

    Also, as Noel Jones noted in reply to a question in postfix-users:

	The FILTER action isn't performed until after the mail
	has been fully accepted stored in the queue.  Therefore,
	you cannot bypass header/body checks using the FILTER
	action.

    You cannot "OK" an entire set of headers based on one header.

    For example:  One might be tempted to try:

	/^To: postmaster@yourdom.ain/	OK
	/^To: abuse@yourdom.ain/	OK
	/^From: .*@example.com/		REJECT

    in an attempt to block everything from example.com, except if it's
    sent to "postmaster" or "abuse" at your end.

    This will not work.  Postfix header checks are header-by-header.  Even
    if you "OK" one header, the other headers will be checked
    independently.  Even were that not so: You have no way of knowing in
    what order headers will be present.  So, in the example above, if the
    "From:" is seen before the "To:", you'd be out-of-luck anyway.

    What *will* work is the following:

	/^From: joe@example.com/	OK
	/^From: .*@example.com/		REJECT

    to reject everything from users in example.com except Joe.

	Note: The above are not functional regular expressions.
	They're for demonstration purposes only.  Proper regular
	expression construction is beyond the scope of this
	document.

    Body checks are likewise: Evaluated line-by-line.

    Postfix presents multi-line text headers, e.g.:

	Received: from host.example.com (host.example.com [192.168.1.2])
	    by mail.example.com (Postfix) with ESMTP id 157B64304
	    for <phred@example.com>; Sun, 31 Aug 2003 09:20:55 -0400 (EDT)

    and (if it's a newer, "MIME-aware" version of Postfix):

	Content-Disposition: attachment;
	    filename=textfile.txt
    
    to header_checks as a single text string, with embedded newlines.

    Conditional Header Checks

	People often ask if they can check one kind of header based on the
	existence of something, or the lack thereof, in a different
	header.

	For example:

	    if !/^To:.*postmaster@example\.com/
		/^Subject: .*Make Money Fast!/ REJECT
	    endif

	The goal above obviously being to check for headers with "Make
	Money Fast!" in the Subject only if the recipient is *not* the
	postmaster.

	This won't work!  Remember: Header (and body) checks process one
	header (or line, with body checks) at a time.  Since it's
	impossible for the "To:" header to be "on the same line" as the
	"Subject:" header, the example above does nothing interesting.

	By the way, there's another problem with the example above: Do not
	indent lines within "if" conditionals.  Start all lines in header
	and body checks at the left margin.


Understanding DNSbl's and RHSbl's

    A DNSbl (DNS BlockList) works for IP addresses only.  Thus one can
    check client IP address' against DNSbl's, but not sender addresses.

    An RHSbl (Right-Hand Side BlockList - so-called because they are
    primarily meant to check the "right-hand side" of sender addresses)
    works on host and domain names.  Postfix supports the use of these for
    client host and domain names, as well, but the check is meaningful
    only *if* the client address has a hostname associated with it.

    Examples:

	reject_rbl_client sbl.spamhaus.org      valid - check client IP
						address' against the
						SpamHaus DNSbl

	reject_rhsbl_sender rhsbl.sorbs.net     valid - check the RHS of
						sender addresses against
						the SORBS RHSbl

	reject_rhsbl_client rhsbl.sorbs.net     valid - check the client's
						domain against the SORBS
						RHSbl.  Doesn't work if
						client is "unknown"

	reject_rbl_client rhsbl.sorbs.net       INVALID - attempt to check
						client IP address' against
						an RHSbl

	reject_rhsbl_sender sbl.spamhaus.org    INVALID - attempt to check
						sender domain names against
						a DNSbl

	reject_rhsbl_client sbl.spamhaus.org    INVALID - attempt to check
						client domain names
						against SpamHaus DNSbl

    See Also: "A Note About DNS BlackLists (DNSbl's and RHSbl's)," later
    in this document.

    If you're unclear on what's meant by "client" and "sender," see the
    section ``What "helo," "sender" and "client" mean,'' under ``General
    Notes On "recipient," "helo," "sender" and "client" Access Lists,''
    above.


Stopping Forged Freemail

    In main.cf, create an smtpd restriction class and, to that restriction
    class, add a client checks that lists all the "OK" hosts, followed by
    a reject.  Add a check_sender_access rule that checks against a list
    of freemail hosts.

    /etc/postfix/main.cf:
	smtpd_restriction_classes = from_freemail_host
	from_freemail_host = check_client_access dbm:/etc/postfix/freemail_hosts,
	    reject

	smtpd_recipient_restrictions =
	    check_sender_access dbm:/etc/postfix/freemail_access

    In the check_sender_access file, list all the freemail hosts you wish
    to check, and have the check defer to the from_freemail_host
    restriction class.

    /etc/postfix/freemail_access:
	yahoo.com	from_freemail_host
	earthlink.net	from_freemail_host
	excite.com	from_freemail_host

    In the restriction class' check_client_access list (file), "OK"
    freemail hosts only.

    /etc/postfix/freemail_hosts:
	yahoo.com		OK
	earthlink.net		OK
	excite.com		OK
	excitenetwork.com	OK

    What happens is: client host connects and attempts to deliver email.
    If the senders domain is listed in the freemail_access file, the
    restriction class causes the client host to be checked to see if it,
    too, is one of the freemail hosts.  If it is, it's "OK".  If it's not
    (e.g.: sender claims to be from yahoo.com and the client host is
    really in spamhaven.net), the terminating reject rule kills it.

    As noted under the "main.cf" examples at the beginning: "dbm" or
    "hash" depends on your system.  The above is for my Sun SPARC
    Solaris boxen.  Linux usually uses "hash".

    See also: FAQ Q1/A1 and Q15/A15.


Compensating For Verisign's Abuse Of The Domain Name System (DNS)

    (And other uses for check_*_mx_access.)

    On or about September 16th, 2003, Verisign put in wildcard records for
    the .com and .net top-level domains, causing lookups on non-existent
    domains, or even domains that simply have no DNS, to return a DNS
    record pointing to one of their own servers.  The result of this, from
    a mail server administrator's perspective, is that checks for valid
    sender and recipient domains (reject_unknown_sender_domain and
    reject_unknown_recipient_domain, respectively, in Postfix) wouldn't
    work for the .com and .net TLDs any more, because now *all* .com and
    .net domains would appear to be "valid."  Say "Thank you, Verisign."

    Wietse quickly released a new Postfix snapshot to address this
    problem.  You use it like this:

	/etc/postfix/main.cf:
	    smtpd_recipient_restrictions =
		...
		reject_unknown_sender_domain,
		check_sender_mx_access dbm:/etc/postfix/mx_access,
		reject_unknown_recipient_domain,
		check_recipient_mx_access dbm:/etc/postfix/mx_access,
		...

	/etc/postfix/mx_access:
	    # IP address Verisign returns for otherwise invalid
	    # .com and .net domains
	    64.94.110.11	REJECT Verisign hijacked domain

    Then "postmap" the mx_access file, "postfix reload" and you're all
    set.

	Remember: "dbm" or "hash" depends on your system.  The
	above is for my Sun SPARC Solaris boxen.  Linux usually
	uses "hash".

    If you wanted to *really* make sure, change the map types to "cidr:"
    and make the mx_access file look like this, for example:

	/etc/postfix/mx_access:
            # Netblock returned by Verisign domain hijacking
	    # .com and .net domains
	    64.94.110/24        REJECT Verisign hijacked domain

    Support for this requires snapshot release postfix-2.0.16-20030917,
    or later.

	While you're at it, you might wish to consider doing:

	    route add -net 64.94.110.0 -netmask 255.255.255.0 127.0.0.1 1

	as well.  Just to show Verisign you really care ;).

    Here are some other things you can do with check_*_mx_access (this is
    a "cidr:" map type):

	0.0.0.0/8	REJECT Domain MX in broadcast network
	10.0.0.0/8	REJECT Domain MX in RFC 1918 private network
	127.0.0.0/8	REJECT Domain MX in loopback network
	169.254.0.0/16	REJECT Domain MX in link local network
	172.16.0.0/12	REJECT Domain MX in RFC 1918 private network
	192.0.2.0/24	REJECT Domain MX in TEST-NET network
	192.168.0/16	REJECT Domain MX in RFC 1918 private network
	224.0.0.0/4	REJECT Domain MX in class D multicast network
	240.0.0.0/5	REJECT Domain MX in class E reserved network
	248.0.0.0/5	REJECT Domain MX in reserved network

    The point here being: Why accept email from senders, or attempt to
    deliver it to recipients, whose MX resolve to machines you can't
    possibly contact?

    One caution is in order: If you're running "split horizon" (aka:
    "split namespace") DNS, where hosts on your LAN, including your mail
    server, have a different view of IP addresses than hosts outside your
    LAN, and your LAN addressing is RFC 1918, you can end up rejecting all
    email to your own mail server.  (Yes, I'm sad to say, this author did
    this to himself!)  To work around this you need to either put
    "check_recipient_mx_access," and perhaps "check_sender_mx_access,"
    *after* permit_mynetworks, or whitelist the IP addresses in question.


A Note About DNS BlackLists (DNSbl's and RHSbl's)

    This bit's non-technical.  I put it in here, not so much for the
    experienced mail admin., but for those new to the game.  And because,
    as with the info above, I've been asked repeatedly for my opinion.

    Think about your use of DNSbl's carefully.  If you use a DNSbl to
    block/reject email, you are effectively giving some outside party
    control over your mail server.  This is not *necessarily* a Bad
    Thing--it's just something to keep in mind.  Choose wisely.

    Another thing that's *absolutely* critical, if you're going to use
    a DNSbl or RHSbl, is that you keep up-to-date on its status.
    Sometimes, when a blocklist goes out-of-service, you can end-up
    rejecting *all* email.

    That being said...

    DNSbl's I Currently Use (in alphabetical order)

	blackholes.easynet.nl (formerly blackholes.wirehub.net)
	cbl.abuseat.org
	list.dsbl.org
	opm.blitzed.org
	relays.ordb.org
	sbl.spamhaus.org
	spamdomains.blackholes.easynet.nl (RHSBL)

    Currently Under Evaluation

	I currently am not evaluating any new DNSbls or RHSbls.

    DNSbl's and RHSbl's I Specifically Recommend Against (And Why)

	relays.osirusoft.com - As of mid-August, 2003, this DNSbl had been
	    "erratic" for some time.  (I had stopped using it a couple
	    months before.)  Part of its problems no doubt resulted from
	    its being under nearly constant DoS and DDoS attacks for
	    months.  On Aug. 26, 2003, it was discovered that its
	    maintainer had replaced all the zone data with a single
	    "matches everything" wild-card entry that would cause *all*
	    queries, to all zones, to return a positive result.  This
	    meant that any mail server consulting relays.osirusoft.com
	    would reject everything that wasn't white-listed prior to
	    checking relays.osirusoft.com.  This was done without
	    warning.  Needless to say: This appalling act of
	    irresponsibility makes this DNSbl unfit *ever* to be used by
	    any sane admin, ever again, IMO.

	SPEWS - I used to use SPEWS, but became concerned about its
	    policies after a couple of what I felt to be "questionable"
	    listings, so I stopped using it.  I don't have a big problem
	    with SPEWS, per se, I just don't use it nor recommend others
	    do so.  My thanks to SPEWS for the use of its list in the
	    past.

	proxies.relays.monkeys.com - I've discontinued use of this zone.
	    Its operator changed policies and said he'd add IP addresses
	    of those that "attacked" Monkeys.Com.  His reasoning is that
	    people who use his free service can at least support it by
	    blocking those that attack it.  While I appreciate the
	    reasoning: IMO an open proxies zone ought to list open proxies
	    and that's all.  My thanks to monkeys.com's operator for the
	    use of his list in the past.

	    Note: As of Monday, Sep. 22nd, 2003, at midnight, Pacific
	    Daylight Time (US), relays.monkeys.com has been taken
	    out-of-service.  As of this writing: All of its zones are
	    returning negative responses to all queries.

	nomorefunn.moensted.dk - This sorry excuse for a DNSbl has my IP
	    netblock listed because it's a DSL netblock?  A business class
	    DSL netblock with static, routable IP address assignments?
	    Heh.  If you bounce me because you're using this abomination,
	    I will locally, permanently blacklist your domain at
	    LinxNet.com.

	xbl.selwerd.cx - Even the owner recommends against out-right
	    blocking based solely on this one.  If you bounce me because
	    you're using this list, I will come to the conclusion that
	    you're too stupid to be on the Internet and will locally,
	    permanently blacklist your domain at LinxNet.com.  (Erik's
	    apparently white-listed my specific IP address, so this won't
	    likely be a problem.)

	DRBL - Allegedly "Distributed Realtime Blocking List".  Appears
	    to be operated by Russian ISPs and administrators?  Hard to
	    say, being as every web site I went to that referred to this
	    "organization" was down or displayed a default Apache
	    installation page.  Anyway, they have all of the DSL space in
	    which I'm located blackholed.  That's their prerogative.  It's
	    also my prerogative to permanently locally blacklist anybody
	    that bounces my email because they're using it.

	rfc-ignorant.org - Technically a Right-Hand Side blocklist
	    (RHSbl), rather than a DNSbl.  RFCI's listing criteria takes
	    RFC requirements far too literally, in my opinion, and, some
	    argue, interprets them incorrectly.

	dorkslayers.com - Dead since May, 2003.  Announced to
	    news.admin.net-abuse.email, at least.  Wasn't set to
	    purposefully return "hits" on everything when it was
	    de-commissioned, but when Verisign pulled its recent .com and
	    .net hijack stunt, that's what happened.

	wirehub.net - Wirehub was purchased by easynet.nl and all wirehub
	    DNSbl zones renamed to easynet zones.  This change was
	    announced back on May 25, 2003.  I use easynet.nl zones.  I
            obviously no longer use wirehub.net zones.

    See Also: "Understanding DNSbl's and RHSbl's," earlier in this
              document.


Frequently Asked Questions (FAQs)

    Q1. Is there any reason why the "freemail senders" checks can't be
        extended to check other hosts that are commonly spoofed for UCE
        purposes?  AOL, for example, is commonly spoofed.

    A1. Not at all.  But understand what's really happening with the
        "freemail senders" check.  All it's doing is checking that if it's
        any of the listed freemail senders, the host is any of the listed
        freemail senders.  It does *not* check to make sure that the sender
        domain and host are consistent with one another.

	See also: FAQ Q15/A15.

    Q2. Regarding your checks "reject_invalid_hostname,"
        "reject_non_fqdn_hostname" and "check_helo_access": Isn't rejecting
        on HELO/EHLO not being a valid and FQDN'd hostname a violation of
        the RFC's?

    A2. Why yes, yes it is.  Doing so is a judgement call.  In *my*
        experience: it stops more spam than it does result in "false
        positives."  And in the few cases where it has resulted in false
        positives, I've found that a friendly dialog with the offending
        mail server's owner got it straightened out.  Your mileage may
        vary.

	Machines outside "mynetworks" should *never* HELO/EHLO as being in
	your domain.  So even if you want to forego
	"reject_invalid_hostname" and "reject_non_fqdn_hostname," it seems
	to me perfectly reasonable to still do the "check_helo_access"
	restriction.

    Q3. But MUAs under Microsoft Windows send HELO with only the
        hostname part, no domain name!

    A3. For internal machines (i.e.: on your LAN) this is a non-issue
        *if* "permit_mynetworks" precedes "reject_invalid_hostname" and
        "reject_non_fqdn_hostname."   (The examples I give above are
        primarily designed for Internet email gateways.)

    Q4. But a lot of people use Microsoft mail clients!

    A4. With regards to that point, I am guided by this philosophy:

	"If fifty million people say a stupid thing,
	 it is still a stupid thing."
				   - Anatole France

        Simply substitute "do" for "say" ;)

    Q5. Couldn't one do the same thing with check_sender_access
        (envelope-sender) as with the check_helo_access with regards to
        checking for somebody spoofing ones own domain?

    A5. Dangerous.  There are a number of scenarios where a sender from
        outside mynetworks might legitimately have an envelope-sender
        address in (one of) your domain(s).  E.g.:

	fred@yourdom.ain sends mail to jim@example.com

	But jim@example.com has, unknown to fred, a .forward pointing
	to jim@yourdom.ain

	That results in example.com's mailserver legitimately sending
	that email with yourdom.ain in the envelope-sender

        (Thanks a tip o' the hat to Andrew of SuperNews for pointing
	 this gotcha out.)

    Q6. Why are all of your restrictions under recipient restrictions?

    A6. You didn't read the comments below those examples, did you?
        Please go back and do so.

    Q7. Why don't you use reject_unknown_hostname or
        reject_unknown_client?

    A7. Too many "false positives" (that is: rejects too much non-spam
        email), in my experience.

	(By the way, Derrick 'dman' Hudson brought up a very
	good point in the postfix-users mailing list: If you're
	going to use reject_unknown_hostname anyway, you
	probably want to put it *after* reject_non_fqdn_hostname
	to prevent an unqualified hostname from matching one in
	your own domain.)

    Q8. Do you use header and body checks?

    A8. Yes

    Q9. Why don't you put header and body checks suggestions on a web
        page?

    A9. Two reasons: 1) I don't feel the need to show spammers how to get
        around them and 2) They change too frequently for anything
        published to stay up-to-date.  Sorry.  I do, however, have some
	of my anti-virus/worm/trojan header and body checks expressions
	shown here:

	    http://jimsun.linxnet.com/misc/header_checks.txt
	    http://jimsun.linxnet.com/misc/body_checks.txt

    Q10. I notice you have both sbl.spamhaus.org *and*
	 blackholes.easynet.nl in your list of DNSbls.  Since the latter
	 includes the former: What's the point?

    A10: You'll observe in my main.cf examples that I check the SBL before
	 blackholes.easynet.nl.  I do this so I can track SBL "hits"
	 separately.  There's no particular reason for this.  I just like
	 to do it.

	 Update: As of August 6, 2003, Steve Linford of the Spamhaus
	 Project announced that the SBL will no longer be available via
	 other DNSbls.  If you want to use the SBL, you'll have to use
	 sbl.spamhaus.org.

    Q11. Why do you use the DNSbl's/RHSbl's you use?

    A11. The main criteria is my personal determination, based in part on
	 the opinions of people I know and trust, as to whether I feel I
	 can trust the honesty, integrity, competence, consistency and,
	 well...  "sanity" of the list maintainer(s).  Then, of course,
	 what the list's published listing policy is.  (The latter is
	 meaningless w/o the former.)

	 In many cases: I've had one-on-one interaction with the
	 maintainer(s) of the DNSbl's I use.

	 Please note that a particular DNSbl's absence on my "uses" list
	 is NOT a condemnation.  It more likely means that the DNSbls I'm
	 using seem sufficient.  It might also mean that I've tried a
	 particular DNSbl and found that it doesn't catch anything that
	 the others I'm already using don't catch--so there's no point.

    Q12. Shouldn't "reject_unknown_sender_domain" reject email with an
	 empty envelope sender (empty MAIL FROM or "null sender")?

    A12. No!  The null sender (<>) is used to send bounces.  According to
	 RFCs, "An empty reverse path MUST be supported."  (Ref: RFC1123,
	 section 5.2.9)

    Q13. Is there a way to get Postfix to do DNSbl or RHSbl checks on
         "Received:" headers?

    A13. Not "natively."  That is: Not without an add-on of some type,
         such as SpamAssassin.

	 If you're trying to do this because you have a secondary MX
	 that's not under your control: Do away with the secondary MX.  A
	 secondary MX that only ends-up sending to your primary MX isn't
	 doing anything useful for you anyway, since the vast majority of
	 modern mail servers will keep email queued for delivery for 3-5
	 days.  All such secondary MX' really do is provide a nice back
	 door through which network abusers (i.e.: spammers) can push
	 their garbage.

	 Furthermore: Should you reject something relayed to you by such a
	 secondary MX: Since that machine has already accepted the email,
	 all it can do is bounce it to the alleged sender address--which
	 is almost invariably spoofed.  So it'll probably be bounced to an
	 innocent third party.

    Q14. When I issue "postmap header_checks" command I get things like
	 ``postmap: warning: header_checks, line 2: record is in "key:
	 value" format; is this an alias file?"  What is wrong?

    A14: You don't "postmap" header or body checks files, nor any other
	 "regexp:" or "pcre:" type file.  However you must "postfix
	 reload", after changing these, if you want your changes to take
	 effect immediately.

    Q15. As regards your "Stopping Forged Freemail" section, and FAQ
	 Q1/A1: Other than complexity of the configuration, what prevents
	 you from setting a from_freemail_host_yahoo,
	 from_freemail_host_excite, from_freemail_host_netscape, et al and
	 then having your /etc/postfix/freemail_access reference the
	 appropriate matching list for each one.

    A15: Nothing at all.  Feel free :)


Other Resources

    Some other stuff I've tripped across that's related to what's on this
    page.  In no particular order.  Mention here does not necessarily
    constitute endorsement.

    Advosys White Papers: Filtering malware and spam with Postfix
    http://www.advosys.ca/papers/printable/postfix-filtering.html

    Security Sage Support Guides
    POSTFIX UNSOLICITED COMMERCIAL EMAIL / ANTI-SPAM GUIDE - MAIN.CF
    http://www.securitysage.com/guides/postfix_uce_main.html

    Ralf Hildebrandt: Mailhub Configuration Mailhub
    http://www.stahl.bau.tu-bs.de/~hildeb/postfix/postfix_mailhub.shtml

    River of Stars: Spam Block List Implementation
    http://www.river.com/ops/nospam/mailconf.html

    Fairly-Secure Anti-SPAM Gateway Using OpenBSD, Postfix, Amavisd-new,
    SpamAssassin, Razor and DCC
    http://lawmonkey.org/anti-spam.html

    My Understanding Of How UCE Actually Works
    http://www.mengwong.com/misc/postfix-uce-guide.txt

    Postfix: Anti-Spam Utilities
    http://www.hispalinux.es/~data/postfix/

    And, of course...

    Postfix Documentation, Howtos and FAQs
    http://www.postfix.org/docs.html

