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.manual ('= _full_rights') DB/smtp-policy.relay ('= _full_rights') DB/smtp-policy.mx.manual ('= _relaytarget') DB/smtp-policy.mx ('= _relaytarget') DB/smtp-policy.spam.manual ('= _bulk_mail') DB/smtp-policy.spam ('= _bulk_mail') IF YOU WANT, YOU CAN MODIFY YOUR BOILER PLATE AS WELL AS YOUR INSTALLED POLICY-BUILDER.SH SCRIPT. (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. Some datasets have TWO input source files, smtp-policy.NN and smtp-policy.NN.manual, the ".manual" is intended to be overrider of of possibly auto- generated data at the "plain" version of files: - localnames Who we are -- ok for receiving; does not grant outgoing relay capability. - smtp-policy.relay.manual - 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 + maxinsize 30000000 filterint +/- The first pair will accept any source address, and any recipient addresses that are fed to the server. The second will verify the source IP-address, but after that it will accept any recipient addresses. The third pair sets EHLO-reported "SIZE nn" parameter to be limited to 30 million bytes. (Or to global definition, if that is in range of 1 thru 'nn'.) The fourth pair sets explicite content-filtering activation/disabling ('+'/'-') for IP address masks given in these files. See the comments in the smtp-policy.src about this! 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) We can set the "always_accept" flag at the source IP test, and never after. - smtp-policy.mx.manual - 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. You CAN also list here all POSTMASTER addresses you accept email routed to: postmaster@local.domain postmaster@client.domain these are magic addresses that email is accepted to, even when everything else is blocked. - smtp-policy.spam.manual - smtp-policy.spam Those users & domains that are absolutely no-no for the senders, or the recipients, no matter what earlier analysis has shown. (Except for those that we absolutely trust..) Short usage instructions: - Fill in/modify related files - execute MAILBIN/policy-builder.sh script Testing instructions: You can run the smtpserver in a mode where you can claim to be from any address in the outside world you wish: $MAILBIN/smtpserver -i -d 1 -T '[1.2.3.4]' The mode must be interactive (-i), and supplying debug mode (-d 1) to it is good help. Actual claimed connection source address is to be given inside square brackets as a SMTP IP address literal. Now you can try things like: 220 ... EHLO foo ... MAIL FROM:<> ... RCPT TO: ... RCPT TO: ... (Substitute some real domains into those RCPT TO lines -- "local.domain" is a hint about what to pick for it..) Depending what kind of address you have supplied to the -T parameter, they get either accepted, or rejected. 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: - You can start rejecting at the connection setup and then at MAIL FROM (and RCPT TO). However many (especially M$ environment) SMTP clients won't react on that properly, and will just keep repeating the delivery attempts. - You can delay the rejections until RCPT addresses are given. 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: ``+'' alias ``rbl.maps.vix.com'' ``relays.mail-abuse.org'' ``dul.maps.vix.com'' ``relays.orbs.org'' ``ok.orbs.org:relays.orbs.org'' <-- THIS IS A PAIR! 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 #| #| File syntax and semantics are explained towards the _end_ of this file. #| #| Further documentation about related files, see file: #| doc/guides/smtp-policy #| See also comments in this file about various sub-options! #|----------- #| #| 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: # # _default_dot relaycustomer - relaytarget - # _default_ipaddr 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. # # _default_dot relaycustomer - relaytarget - senderokwithdns + = _rbl1 # _default_ipaddr 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. _default_dot relaycustomer - acceptifmx - senderokwithdns + = _rbl1 _default_ipaddr 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! # # _default_dot senderokwithdns - acceptifdns - # _default_ipaddr senderokwithdns - acceptifdns - # #| ----------------------------------- #| Now use above defined macroes at these default labels: . = _default_dot [0.0.0.0]/0 = _default_ipaddr #| ----------------------------------- #| #| RBL type test rules: #| First RBL variant: NONE OF THE 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 "+" at the DNS zone defines 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 ".") #| (Or inverting: If some recipient domain is *not* wanting RBL-type tests, #| that domain shall have ``test-rcpt-dns-rbl -'' attribute pair given for #| it at the input datasets -- consider smtp-policy.mx file!) #| #|----------- #| #| 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. #| #|----------- #| #| If you want explicitely to run content-filter even for locally #| accepted source IP addresses, you can activate it by adding #| 'filtering +' attribute pair to a) the wild-card IP address test: #| [0.0.0.0]/0 #| of your choice above, and b) into _full_rights further below. #| #| This attribute pair is looked up only in early connect tests, never #| afterwards. If the attribute pair is not present, tests causing #| internal 'always_accept' flag to be set will disable the lookup #| (effectively 'filtering -'). #| #| With 'filtering +' added into _full_rights, entering explicite #| 'filtering -' for an address literal in smtp-policy.relay* file #| will disable the content filtering for given address, while it #| is activated for all others. #| #|----------- #| #| 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 #| #| Thanks, no bulk mails! Drop them when used as sources, also reject #| when asked to send for them. #| _bulk_mail message "Your address 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 #---------------------------------- #| Syntax: #| #| key [attribute value]... [= _tag] #| #| The db compiler does not accept completely empty value-set input, #| therefore there are comments in all _ZZZ entries if nothing else! #| #| 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) #| Recursion up to 3 levels is supported #| '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' { '+', '-', "suffix.one:suffix.two" } #| 'message' "quoted constant string message" #| 'localdomain' { '+', '-' } #| 'maxinsize' nnn #| 'maxoutsize' nnn #| 'fulltrustnet' { '+', '-' } #| 'trustrecipients' { '+', '-' } #| 'trust-whoson' { '+', '-' } #| 'filtering' { '+', '-' } #| #| 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 'FILTERING' attribute) then #| set state->content_filter 1/0 depending on '+'/'-' value #| If this attribute doesn't exist, set: state->content_filter = -1 #| This will latter interact with state->always_accept variable #| in the content-filter interface... #| 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;] #| if (IP address of SMTP client has "RCPT-DNS-RBL" attribute then #| save RBL lookup result for processing at "RCPTO TO:" phase #| [state->rbl_msg = ;] #| 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 (source domain of address of SMTP client has 'REJECTNET +' attribute) then #| any further conversation refused #| [state->always_reject = 1; return REJECT;] #| if (source domain of 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 (source domain of SMTP client has 'RCPT-DNS-RBL "_Message' like attributes #| then save it for rejection at rcpt to: phase #| [state->rbl_msg = values[P_A_RcptDnsRBL] + 1;] #| 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 address has 'TEST-RCPT-DNS-RBL +' attribute) then #| return REJECT if have state->rblmsg #| #| 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 (recipient domain has 'TEST-RCPT-DNS-RBL +' attribute) then #| return REJECT if have state->rblmsg #| #| #| 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 #| #| ------ #|