1. ZMailer SMTP-server policy filtering rules

At the end of this is actually the default boiler-plate file from the distribution pretty much as is.

In addition to that, policy-builder.sh script adds a set of other things before policy filter is ready for use:

    DB/smtp-policy.src                   The boilerplate
    DB/localnames               ('= _local_names')
    DB/smtp-policy.relay        ('= _full_rights')
    DB/smtp-policy.mx           ('= _relaytarget')
    DB/smtp-policy.spam         ('= _bulk_mail')
    DB/smtp-policy.spam.manual  ('= _bulk_mail')
If you want, you can modify your boiler plate as well as your installed policy-builder.sh script. (In fact you SHOULD modify it!) (Doing 'make install' will overwrite policy-builder.sh, but not smtp-policy.src)

Basically these various source files (when existing) are used to combine knowledge of valid users around us:

localnames

Who we are; ok domains for receiving locally.

smtp-policy.relay

Who can use us as outbound relay.

Use here

  [ip.number]/maskwidth
for listing those senders (networks) we absolutely trust. Additionally you may give (at the same line) some attributes as parameters for this key entry:
  fulltrustnet +
  trustrecipient +
First pair will accept any source address, and any recipient addresses that are fed to the server; the second will verify the source address, but after that it will accept any recipient addresses.

You may also enter domains which are looked up for the hostname of reversed IP address, but it is not very wise; IP-reversal is not trustworthy data. It may also cause double- entry/level descendance problems when two domain-suffixes have same ending suffix (or are the same).. (Name/keyspace problem)

smtp-policy.mx

Who really are our MX clients. Use this when you really know them, and don't want just to trust that if recipient has MX to you, it would be ok...

You can substitute this knowledge with a fuzzy feeling by using 'acceptifmx -' attribute at the generic boilerplate. List here domain names.

  mx-target.dom
  .mx-target.dom

You CAN also list here all POSTMASTER addresses you accept email routed to:

  postmaster@local.domain
  postmaster@client.domain
these are then magic addresses that email is accepted to, even when everything else is blocked.

smtp-policy.spam ( + smtp-policy.spam.manual )

Those users & domains that are absolutely no-no for senders, or recipients no matter what earlier analysis has shown. (Except for those senders that we absolutely trust..)

  user@domain
  user@
  domain
  [1.2.3.4]/32

The policy-builder.sh builds this file from external sources.


2. RBL-type blocking lists

Per default the system DOES NOT use RBL-type blocking lists. There are two ways how to take them into use:

2.1 Immediate rejection by RBL

Like mentioned above, this method has a problem with many clients who don't believe that HELO can give 500-series response.

Method is as follows:

Pick your choice of databases to the second variant ``_RBL0'' label by joining your selection from various things exemplified here below by using ``:'' character as glue in between:

For the ``ok.orbs.org:relays.orbs.org'' the ZMailer 2.99.52patch2 has special support, but it isn't entirely fool-proof thing...
(Due to false OKs in the OK zone while NETBLOCK type things exist at the RELAYS zone.)

An example for the resulting attribute pair: (RBL+DUL+RSS)

  #| Second RBL variant: Early block with RBL+DUL+RSS
  _RBL0   test-dns-rbl  +:dul.maps.vix.com:relays.mail-abuse.org
  _RBL1   # Nothing

2.2 Delayed rejection by RBL

Delay the rejection report to ``RCPT TO'' verbs by using the ``Third RBL variant'':

  #| Third RBL variant: Late block with RBL+DUL+RSS
  _RBL0   rcpt-dns-rbl      +:dul.maps.vix.com:relays.mail-abuse.org
  _RBL1   test-rcpt-dns-rbl +

The sample boilerplace will use these as defaults unless you choose to explicitely have ``test-rcpt-dns-rbl -'' at some of the recipient domains you list at ``smtp-policy.mx'' file:

  #sample.domain.with.rbl
  sample.domain.no.rbl    test-rcpt-dns-rbl -


3. smtp-policy.src boiler-plate

#| File:  $MAILVAR/db/smtp-policy.src
#|
#|   Policy based filter database boilerplate for smtpserver
#|   This file is compiled into actual database by command:
#|         $MAILBIN/policy-builder.sh
#|
#| Syntax:
#|
#| key  [attribute value]... [= _tag]
#| 
#| Where:
#|
#| 'key' is 
#|   - a domain name optionally preceded by a dot (.)
#|   - "user@" / "user@domain" names.
#|   - an IP address expression in canonical [nn.nn.nn.nn]/prefix form.
#|      Unspecified bits must be 0. (Network IPv6 addresses containing
#|       IPv4-mapped addresses are translated into plain IPv4.)
#|   - any arbitrary word referred as '_tag' at the right side
#|     '_tag' may be any key of this database
#| 'attribute' and 'value' are tokens. They are used by policytest() to
#|     make decisions.  Attribute names, and understood value tokens are:
#|
#|      '='             '_any_token_with_starting_underscore' (aliasing)
#|      'rejectnet'     { '+', '-' }
#|      'freezenet'     { '+', '-' }
#|      'rejectsource'  { '+', '-' }
#|      'freezesource'  { '+', '-' }
#|      'relaycustomer' { '+', '-' }
#|      'relaycustnet'  { '+', '-' }
#|      'relaytarget'   { '+', '-' }
#|      'freeze'        { '+', '-' }
#|      'senderokwithdns' { '+', '-' }
#|      'acceptifmx'    { '+', '-' }
#|      'acceptifdns'   { '+', '-' }
#|      'sendernorelay' { '+', '-' }
#|      'test-dns-rbl'  { '+', '-', "suffix.one:suffix.two" }
#|        Sample suffixes: rbl.maps.vix.com  relays.mail-abuse.org
#|                         dul.maps.vix.com
#|                         ok.orbs.org:relays.orbs.org  <-- that is a PAIR!
#|      'rcpt-dns-rbl'  { '+', '-', "suffix.one:suffix.two" }
#|      'test-rcpt-dns-rbl' { '+', '-' }
#|      'message'       "quoted constant string message"
#|      'localdomain'   { '+', '-' }
#|      'maxinsize'     nnn
#|      'maxoutsize'    nnn
#|      'fulltrustnet'  { '+', '-' }
#|      'trustrecipients' { '+', '-' }
#|      'trust-whoson'  { '+', '-' }
#|
#| Semantics:
#|
#| The policytest() functions called by smtpserver to check the client host,
#| the sender's and recipients' addresses.  policytest() looks for name, and
#| address of client host as well as full and partial user address, and domain
#| part of sender and recipient addresses in this database.  The retrieved
#| attributes are used to make decissions on acepting or rejecting the incoming
#| mail.
#|
#| If looking for 'foo.bar.edu' and exact match failed, the database looks keys
#| in sequence:  '.foo.bar.edu', '.bar.edu', '.edu', and '.'.
#|
#| The order of entries in this file is indifferent.
#|
#| When searching an IP address the entry with the most common (leftside) bits
#| is returned. So you can have a [0.0.0.0]/0 entry what specifies the default
#| addributes for all unlisted IP addresses. (Both IPv4 and IPv6)
#|
#| '=' is a special attribute.
#| The notation '= _tag' means "See also at '_tag'". If server() doesn't
#| find the requested attribute of the object, it will replace object name
#| with '_tag' and restarts search.
#| 

#| Here is an example configuration, assumed the following decision
#| chains of smtpserver/policytest.c routines:
#|
#| Connection establishment:  (IP address tested)
#|
#|  if (IP address of SMTP client has 'REJECTNET +' attribute) then
#|   any further conversation refused
#|   [state->always_reject = 1; return REJECT;]
#|  if (IP address of SMTP client has 'FREEZENET +' attribute) then
#|   we present happy face, but always put the messages into a freezer..
#|   [state->always_freeze = 1; return FREEZE;]
#|  if (IP address of SMTP client has 'RELAYCUSTNET +' attribute) then
#|   sender accepted, recipients not checked
#|   [state->always_accept = 1; return ACCEPT;]
#|  if (IP address of SMTP client has 'TEST-DNS-RBL +' attribute) then
#|   we use RealtimeBlockingList DNS database.  If we get match from
#|   there, we do: [state->always_reject = 1; return REJECT;]
#|  else
#|   return ACCEPT
#|
#| Connection extablishment; connection source DOMAIN test
#| (This is done on the reverser information of the IP address
#|  of the session source.)
#|
#|  if (state->always_reject == 1) return REJECT;
#|  if (state->always_freeze == 1) return FREEZE;
#|  if (state->always_accept == 1) return ACCEPT;
#|
#|  if (IP address of SMTP client has 'REJECTNET +' attribute) then
#|   any further conversation refused
#|   [state->always_reject = 1; return REJECT;]
#|  if (IP address of SMTP client has 'FREEZENET +' attribute) then
#|   we present happy face, but always put the messages into a freezer..
#|   [state->always_freeze = 1; return FREEZE;]
#|  else
#|   return ACCEPT
#|
#| HELO/EHLO parameter string:
#|
#|  if (state->always_reject == 1) return REJECT;
#|  if (state->always_freeze == 1) return FREEZE;
#|  if (state->always_accept == 1) return ACCEPT;
#|
#|  if (HELO-name of SMTP client has 'REJECTNET +' attribute) then
#|   any further conversation refused
#|   [state->always_reject = 1; return REJECT;]
#|  if (HELO-name of SMTP client has 'FREEZENET +' attribute) then
#|   we present happy face, but always put the messages into a freezer..
#|   [state->always_freeze = 1; return FREEZE;]
#|  default: return ACCEPT
#|
#| MAIL FROM address:
#|
#|  set state->rcpt_nocheck  = 0;
#|  set state->sender_reject = 0;
#|  set state->sender_freeze = 0;
#|
#|  if (state->always_reject == 1) return REJECT;
#|  if (state->always_freeze == 1) return FREEZE;
#|  if (state->always_accept == 1) return ACCEPT;
#|
#|  if (sender's address has 'REJECTSOURCE +' attribute) then
#|   sender rejected, any further conversation refused
#|   [state->always_reject = 1; return REJECT;]
#|  if (sender's address has 'FREEZESOURCE +' attribute) then
#|   we accept with the happy face, but place it into a freezer
#|   [state->always_freeze = 1; return FREEZE;]
#|  when (sender's address is not in policy-db, continue with sender's domain)
#|
#|  if (sender's domain is not in policy-db) then
#|    return ACCEPT
#|
#|  if (sender's domain has 'REJECTSOURCE +' attribute) then
#|   sender rejected, any further conversation refused
#|   [state->sender_reject = 1; return REJECT;]
#|  if (sender's domain has 'FREEZESOURCE +' attribute) then
#|   we accept with the happy face, but place it into a freezer
#|   [state->sender_freeze = 1; return FREEZE;]
#|  if (sender's domain has 'RELAYCUSTOMER +' attribute) then
#|   DANGER ! DANGER !
#|   We will accept all destination addresses for this MAIL FROM,
#|   except those that are explicitely blocked, of course..
#|   [state->rcpt_nocheck = 1; return ACCEPT;]
#|  if (sender's domain has 'SENDEROKWITHDNS +' attribute) then
#|    verify that is DNS data for the target domain.  If yes, return ACCEPT;
#|    if not, return SOFTREJECT
#|  if (sender's domain has 'SENDEROKWITHDNS -' attribute) then
#|    verify that is DNS data for the target domain.  If yes, return ACCEPT;
#|    if not, return REJECT
#|  else
#|    return ACCEPT
#|
#| RCPT TO address:
#|
#|  if (state->always_reject == 1) return REJECT;
#|  if (state->sender_reject == 1) return REJECT;
#|  if (state->always_freeze == 1) return FREEZE;
#|  if (state->sender_freeze == 1) return FREEZE;
#|  if (state->always_accept == 1) return ACCEPT;
#|
#|  if (recipient address has 'RELAYTARGET +' attribute) then
#|    return ACCEPT
#|  if (recipient address has 'RELAYTARGET -' attribute) then
#|    return REJECT
#|  if (recipient address has 'FREEZE +' attribute) then
#|    we accept with the happy face, but place it into a freezer
#|    [status->sender_freeze = 1; return FREEZE;]
#|
#|  if (recipient's domain has 'RELAYTARGET +' attribute) then
#|    return ACCEPT
#|  if (recipient's domain has 'RELAYTARGET -' attribute) then
#|    return REJECT
#|  if (recipient's domain has 'FREEZE +' attribute) then
#|    we accept with the happy face, but place it into a freezer
#|    [status->sender_freeze = 1; return FREEZE;]
#|
#|  If (state->rcpt_nocheck  == 1) return ACCEPT;
#|
#|  If (recipient's domain has 'ACCEPTIFMX +' attribute) then
#|    Verify that we are MX for the target domain.  If yes, return ACCEPT;
#|    If not, return SOFTREJECT
#|  If (recipient's domain has 'ACCEPTIFMX -' attribute) then
#|    Verify that we are MX for the target domain.  If yes, return ACCEPT;
#|    If not, return REJECT
#|  If (recipient's domain has 'ACCEPTIFDNS +' attribute) then
#|    Verify that we are MX for the target domain.  If yes, return ACCEPT;
#|    If not, return SOFTREJECT
#|  If (recipient's domain has 'ACCEPTIFDNS -' attribute) then
#|    Verify that we are MX for the target domain.  If yes, return ACCEPT;
#|    If not, return REJECT
#|  Else
#|    return ACCEPT
#| 
#| ------
#|

#|-----------
#|
#| Default handling boilerplates:
#|
#|   "We are not relaying between off-site hosts, except when ..."
#|
#| You MUST uncomment one of these default-defining pairs, or the blocking
#| of relay hijack will not work at all !
#|
#| -- 1st alternate: No MX target usage, no DNS existence verify
#|    Will accept for reception only those domains explicitely listed
#|    in  'smtp-policy.mx'  and  'localnames'  files.  Will not do
#|    verifications on validity/invalidity of source domains:  
#
# .                     relaycustomer - relaytarget -
# [0.0.0.0]/0           relaycustomer - relaytarget -
#
#| -- 2nd alternate: No MX target usage, DNS existence verify
#|    Like the 1st alternate, except will verify the sender (mail from:<..>)
#|    address for existence of the DNS MX and/or A/AAAA data -- e.g. validity.
#|    If RBL parameters are set below, will use them.
#
# .                     relaycustomer - relaytarget - senderokwithdns + = _RBL1
# [0.0.0.0]/0           relaycustomer - relaytarget - senderokwithdns + = _RBL0
#
#| -- 3rd alternate: MX relay trust, DNS existence verify
#|    For the people who are in deep s*...  That is, those who for some
#|    reason have given open permissions for people to use their server
#|    as MX backup for their clients, but don't know all domains valid
#|    to go thru...  Substitutes accurate data to user's whimsical DNS
#|    maintenance activities.  Vulnerable to unauthorized inbound MX
#|    service abuse.
#|    If RBL parameters are set below, will use them.

.                       relaycustomer - acceptifmx - senderokwithdns + = _RBL1
[0.0.0.0]/0             relaycustomer - acceptifmx - senderokwithdns + = _RBL0

#| -- 4th alternate: Sender & recipient DNS existence verify
#|    This is more of an example for the symmetry's sake, verifies that
#|    the source and destination domains are DNS resolvable, but does not
#|    block relaying -- DANGER! DANGER! WILL ROBINSON! DANGER!
#
# .                     senderokwithdns - acceptifdns -
# [0.0.0.0]/0           senderokwithdns - acceptifdns -
#
#|
#| -----------------------------------
#|
#| RBL type rules:

#| First RBL variant: NONE OF RBL TESTS
_RBL0           # Nothing at early phase
_RBL1           # Nothing at late phase

#| Second RBL variant: Early block with RBL+DUL+RSS
#_RBL0          test-dns-rbl      +:dul.maps.vix.com:relays.mail-abuse.org
#_RBL1          # Nothing at late phase

#| Third RBL variant: Late block with RBL+DUL+RSS
#_RBL0          rcpt-dns-rbl      +:dul.maps.vix.com:relays.mail-abuse.org
#_RBL1          test-rcpt-dns-rbl +

#|  (The "+" is treated as shorthand to  "rbl.maps.vix.com")
#|
#|  The Third RBL variant means that all target domains can all by themselves
#|  choose if they use RBL to do source filtering.  The ``= _RBL1'' test
#|  *must* be added to all domain instances where the check is wanted.
#|  (Including the last-resort domain default of ".")
#|
#| These rules mean that locally accepted hostnames MUST be listed in
#| the database with  'relaytarget +' attribute.  ("acceptifmx *" allows
#| reception if the local system is amonst the MXes.)
#|
#|-----------
#|
#| If your system has ``whoson'' server (see contrib/whoson-*.tgz),
#| you can activate it by adding  'trust-whoson +' attribute pair to
#| the wild-card IP address test:  [0.0.0.0]/0  of your choise.
#|
#|-----------
#|
#| For outbound relaying control for fixed IP address networks, see
#| comments in file:  smtp-policy.relay
#|
#|-----------
#|
#| Generally we refuse SMTP connections from host in private address space
#| and refuse mails to or from  if nn.nn.nn.nn is a
#| private IP address...
#|
_private_address    message "We reject your network" rejectnet + message "We don't accept email from this source address" rejectsource + relaycustomer - relaytarget -
#[172.16.0.0]/12         = _private_address
#[192.168.0.0]/16        = _private_address
#[10.0.0.0]/8            = _private_address
#|
#| ...but hosts in the address range 192.168.16.0-192.168.17.255 may be
#| our SMTP clients.
#|
#[192.168.16.0]/23      rejectnet - = _private_address

#| Hosts of our organization can do anything...
#|
_our_network    = _full_rights

#|    Boilerplate macroes for various things.
#|    If RBL parameters are set above, will use them.

_full_rights    rejectnet - relaycustnet + relaytarget +               = _RBL1
_localnames     rejectnet - relaycustnet - localdomain + relaytarget + = _RBL1
_relaytarget    relaytarget +                                          = _RBL1

#
#sztaki.hu              = _full_rights
#.sztaki.hu             = _full_rights
#[192.84.225.0]/24      = _our_network
#[192.84.226.0]/23      = _our_network
#[192.84.228.0]/23      = _our_network
#|
#| ... except that no use to relaying for dial-up hosts
#|
#.dial.sztaki.hu                relaytarget - = _full_rights
#|
#| ... and we have a misconfigured SMTP client somewhere
#|
#[192.84.225.1]/32      message "Your network is not liked message source" rejectnet + = _our_network
#|
#|
#| We are MX for some UUCP nodes;  The actual list of domains should
#| be gotten from some listing, and inserted here, or generated from
#| a file into compatible format, and appended into the database
#|
#.uucp.iif.hu           relaytarget +
#|
#| Thanks, no bulk mails! Drop them when used as sources, also reject
#| when asked to send for them.
#|
_bulk_mail      message "Your domain is not liked source for email" rejectsource + message "Your IP address is not liked source for email" rejectnet + message "This is not accepted relay target" relaytarget -
#|
#| The actual list of domains, and perhaps user addresses should
#| be gotten from some active Anti-SPAM database
#|
#nobody.com             = _bulk_mail
#.nobody.com            = _bulk_mail
#nodomain.com           = _bulk_mail
#.nodomain.com          = _bulk_mail
#|
#| Some source users we reject always: (frequent spammers..)
#| (see comment above about Anti-SPAM databases)
#| (Do note that these are SMTP ENVELOPE items, not RFC-822 items!)
#|
#friend@                = _bulk_mail
#friends@               = _bulk_mail

#----------------------------------


4. localnames sample

#a
#b  Remap local names (and recognize them) to their "canonic" forms.
#c  thus having multiple machines on the same mailer..
#d
#z nicname		canonic.name


5. smtp-policy.relay sample

#|
#| This file is called:  smtp-policy.relay 
#|
#| Into this file you should list all those ip addresses from which you
#| will accept SMTP input traffic that is allowed to have unrestricted
#| outbound relaying thru this server.
#|
#| Per default the  policy-builder.sh  script adds attribute-alias
#|    = _full_rights
#| (which maps to: rejectnet - relaycustnet + relaycustomer + relaytarget +)
#| to the address given below.  Any attributes following the address here
#| are appended AFTER the "= _full_rights" pair.  (I.e. everything is not
#| settable here -- resetting attributes already set in _full_rights is
#| not possible, for example.)
#|
#|   Examples:
#|
#|   Default behaviour on loopback users; default meaning
#|   verifying that source and destination addresses are resolvable
#|   thru the DNS, but not doing any other limitations:
#|
#| [127.0.0.0]/8
#|
#|   In case you want to allow unverified input relaying from some
#|   source, add "fulltrustnet +" attribute pair like here.  Then
#|   the addresses (source and destination) are accepted as is without
#|   any sort of checking at the smtpserver.  Possible errors in the
#|   addresses are flagged at latter stages (output, very likely):
#|
#| [1.2.3.4]/32 fulltrustnet +
#|
#|   DEPRECATED USE:  You give a DOMAIN NAME in here which is looked
#|   at connection setup time (against IP reversal ptr value), and
#|   against MAIL FROM:<...> domain name.  However there are lots
#|   of reasons why you SHOULD NOT use this technique for allowing
#|   relaying thru your machine -- foremost of which is that then
#|   anybody who just claims any address with this domain can relay
#|   thru your server -- and you get the blame...
#|
#| some.domain.name
#|


6. smtp-policy.mx sample

#|
#| Sample root for  smtp-policy.mx  file
#|
#|
#| List here domains/domain suffixes for which you want to
#| serve as relayer, and/or want to have non-default value
#| behaviour at destination domain at RBL tests, etc.
#|
#|    .domain.suffix
#|    exact.domain
#|
#| You can replace exact knowledge with fuzzy feeling by using
#| ``acceptofmx -'' at the boilerplate defaults and no need
#| anything at this file.
#|