[SA-exim] Exim4 ACL snippets (Re: Klezmail with forged envelope)

Tor Slettnes tor at slett.net
Thu Apr 8 11:16:22 PDT 2004


On Apr 6, 2004, at 21:37, Rick Moen wrote:
> Honestly, has nobody on this list yet written and tested such a thing?

The following is what I use.   It may be a little bit more complex than 
what you would normally start with -- essentially, rather than rejecing 
a message right away once I discover a problem, I set a "flag" (by 
virtue of loading an error or warning message in $acl_c0 or $acl_c1, 
respectively), and stall the sender a little bit (up to 20 seconds per 
step/command in the SMTP transaction).  The actual rejection happens 
after the DATA stage.

For instance, if someone HELO's with a host name that resolves to my 
own IP address, or directly with an IP address, I have already decided 
to reject the mail.  But instead of doing so right away, I stall them 
for 20 seconds at the HELO command, 20 seconds at the MAIL command, 20 
seconds at the RCPT command, and finally 20 seconds after the message 
data, before ultimately rejecting the message.

Have a blast!


/etc/exim4/conf.d/main/09_local-config_options:
> # Define access control lists
> acl_smtp_connect = acl_connect
> acl_smtp_helo    = acl_check_helo
> acl_smtp_mail    = acl_check_mail
>
> # Perform HELO verification on _all_ callers
> # (but don't automatically reject just based on this)
> helo_try_verify_hosts = *
>
> # Allow an unlimited number of incoming SMTP connections at one time
> # (because we may be stalling/teergrubing several people at once)
> smtp_accept_max   = 0
> # .. unless the system load is above 10
> smtp_load_reserve = 10
>
> # Customize SMTP banner to include the contents of $acl_m0, if any.
> # This variable contains any results from an RBL lookup of the sender,
> # in the form:
> #     #.#.#.# is listed in rbl-list.somewhere (DNS TXT record/reason)
> smtp_banner = ${primary_hostname} ESMTP Exim ${version_number} \
>    ${if def:acl_m0 {\n$acl_m0\nThis means that you must proceed 
> slowly.}}


/etc/exim4/conf.d/acl/05_local-config_connect:
> acl_connect:
>   # Accept mail received over local SMTP (i.e. not over TCP/IP).  We do
>   # this by testing for an empty sending host field.
>   # Also accept mails received over a local interface, and from hosts
>   # for which we relay mail.
>   accept hosts     = : $interface_address : +relay_from_hosts
>
>
>   # If the connecting host is in one of several DNSbl's, then stall
>   # for 20 seconds, and prepare a warning message in acl_c1.
>   warn
>        dnslists    = sbl-xbl.spamhaus.org : \
>                      dsn.rfc-ignorant.org : \
>                      dnsbl.sorbs.net : \
>                      dnsbl.njabl.org : \
>                      list.dsbl.org : \
>                      bl.spamcop.net : \
>                      l1.spews.dnsbl.sorbs.net
>        set acl_m0  = $sender_host_address is listed in $dnslist_domain 
> \
>                      ${if def:dnslist_text {($dnslist_text)}{}}
>        set acl_c1  = X-RBL-Warning: $acl_m0
>        log_message = $acl_m0
>        delay       = 20s
>
>
>   accept

/etc/exim4/conf.d/acl/10_local-config_check_helo:
> acl_check_helo:
>   # Accept mail received over local SMTP (i.e. not over TCP/IP).  We do
>   # this by testing for an empty sending host field.
>   # Also accept mails received over a local interface, and from hosts
>   # for which we relay mail.
>   accept hosts     = : $interface_address : +relay_from_hosts
>
>
>   # If the remote host greets with an IP address, then stall for 20
>   # seconds, and prepare a message in $acl_c0.  Later we will use the
>   # presence of this message to stall the sender further and eventually
>   # to reject the message after the DATA block.
>   warn condition   = ${if isip {$sender_helo_name}{true}{false}}
>        set acl_c0  = You greeted me with an IP address.  I want your 
> name.
>        log_message = remote host used IP address in HELO/EHLO greeting
>
>
>   # Likewise if the peer greets with a name that resolves to our own 
> address
>   warn condition   = ${if eq {${lookup dnsdb{a=$sender_helo_name} 
> {$value}}} \
>                              {$interface_address} \
>                              {true}{false}}
>        set acl_c0  = CAN-SPAM act violation.
>        log_message = remote host used our name in HELO/EHLO greeting
>
>
>   # If HELO verification fails, we stall for 20 seconds, and prepare a
>   # message in acl_c1.  We will later use the presence of this message
>   # to stall the sender further and generate a warning.
>   warn condition   = ${if def:acl_c0 {false}{true}}
>        !verify     = helo
>        set acl_c1  = ${if def:acl_c1 {$acl_c1\n}}\
>                      X-Bogus-HELO-Warning: Remote host $sender_address 
> \
>                      ${if def:sender_host_name {($sender_host_name)}} \
>                      incorrectly presented itself as $sender_helo_name
>        log_message = remote host presented unverifiable HELO/EHLO 
> greeting.
>
>
>   # If we generated one or more warnings so far, stall the sender
>   accept
>        condition   = ${if or {{def:acl_c0}{def:acl_c1}}{true}{false}}
>        delay       = 20s
>
>
>   accept


/etc/exim4/conf.d/acl/15_local-config_check_mail:
> acl_check_mail:
>   # Accept mail received over local SMTP (i.e. not over TCP/IP).  We do
>   # this by testing for an empty sending host field.
>   # Also accept mails received over a local interface, and from hosts
>   # for which we relay mail.
>   accept hosts     = : $interface_address : +relay_from_hosts
>
>   # If sender did not provide a HELO/EHLO greeting, stall for 20 
> seconds,
>   # and prepare a message acl_c0.  We will later use the presence of 
> this
>   # message to stall the sender further, and eventually in a "deny" 
> rule.
>   warn condition   = ${if def:sender_helo_name {0}{1}}
>        set acl_c0  = You did not greet. You should at least say HELO.
>        log_message = remote host did not present HELO/EHLO greeting.
>
>
>   # If we have previously generated a message in acl_c1, add a warning 
> here.
>   warn message     = $acl_c1
>        condition   = ${if def:acl_c1 {true}{false}}
>
>
>   # Otherwise, if we could not look up the sender's IP address, 
> generate a
>   # warning message and save a copy in $acl_c1. We will later use the
>   # presence of this message to stall the sender.
>   warn condition   = ${if def:acl_c1 {false}{true}}
>        !verify     = reverse_host_lookup
>        set acl_c1  = no host name found for IP address 
> $sender_host_address
>        message     = X-Broken-Reverse-DNS: $acl_c1
>        log_message = $acl_c1
>
>
>   # Likewise, if sender address verification fails.
>   warn !verify     = sender/callout
>        set acl_c1  = Invalid sender address $sender_address
>        message     = X-Sender-Verify-Failed: $acl_c1
>        log_message = $acl_c1
>
>
>   # If we generated one or more warnings so far, stall the sender
>   accept
>        condition   = ${if or {{def:acl_c0}{def:acl_c1}}{true}{false}}
>        delay       = 20s
>
>
>   accept


/etc/exim4/conf.d/acl/30_exim4-config_check_rcpt:
> acl_check_rcpt:
>   # Deny if the local part contains @ or % or / or | or !. These are 
> rarely
>   # found in genuine local parts, but are often tried by people 
> looking to
>   # circumvent relaying restrictions.
>   #
>   # Also deny if the local part starts with a dot. Empty components 
> aren't
>   # strictly legal in RFC 2822, but Exim allows them because this is 
> common.
>   # However, actually starting with a dot may cause trouble if the 
> local part
>   # is used as a file name (e.g. for a mailing list).
>   #
>   deny local_parts = ^.*[@%!/|] : ^\\.
>
>
>   # Accept mail to postmaster in any local domain.  However, if we
>   # previously generated a message in $acl_c0 or $acl_c1, stall the 
> sender.
>   #
>   accept
>        local_parts = postmaster
>        domains     = +local_domains : +relay_to_domains
>        delay       = ${if or {{def:acl_c0}{def:acl_c1}}{20s}{0s}}
>
>
>
>   # Accept mail received over local SMTP (i.e. not over TCP/IP).  We do
>   # this by testing for an empty sending host field.
>   # Also accept mails received over a local interface, and from hosts
>   # for which we relay mail.
>   #
>   # Recipient verification is omitted here, because in many
>   # cases the clients are dumb MUAs that don't cope well with SMTP 
> error
>   # responses. If you are actually relaying out from MTAs, you should 
> probably
>   # add recipient verification here.
>   accept hosts     = : $interface_address : +relay_from_hosts
>
>
>   # Accept if the message arrived over an authenticated connection, 
> from
>   # any host. Again, these messages are usually from MUAs, so recipient
>   # verification is omitted.
>   #
>   accept
>        authenticated = *
>
>
>   # If the address is in a local domain or in a domain for which are
>   # relaying, but is invalid, stall the sender and then reject.
>   #
>   deny domains     = +local_domains : +relay_to_domains
>        message     = unknown user
>        !verify     = recipient/callout=20s,defer_ok
>        delay       = 20s
>
>
>   # Otherwise, if the address is in one of our domains, accept it.
>   # However, if we have previously generated a message in acl_c0 or 
> acl_c1,
>   # stall the sender.
>   accept
>        domains     = +local_domains : +relay_to_domains
>        delay       = ${if or {{def:acl_c0}{def:acl_c1}}{20s}{0s}}
>
>
>   # Reaching the end of the ACL causes a "deny", but we might as well 
> give
>   # an explicit message.
>   #
>   deny message     = relay not permitted
>          delay     = 20s


/etc/exim4/conf.d/acl/40_exim4-config_check_data:

> acl_check_data:
>    # Deny if we have previously given a reason for doing so in $acl_c0
>    deny message     = $acl_c0
>         condition   = ${if def:acl_c0 {true}{false}}
>         delay       = 20s
>
>    # Deny unless the address list headers are syntactically correct.
>    deny message     = Message headers fail syntax check
>         !acl        = acl_whitelist_local_deny
>         !verify     = header_syntax
>         delay       = 20s
> 		
>    # enforce a message-size limit
>    deny message     = Message size $message_size is larger than limit 
> of MESSAGE_SIZE_LIMIT
>    	condition   = ${if >{$message_size}{MESSAGE_SIZE_LIMIT}{yes}{no}}
>
>    # Add Message-ID if missing
>    warn condition   = ${if !def:h_Message-ID: {1}}
>         hosts       = +relay_from_hosts
>         message     = Message-ID: <E$message_id@$primary_hostname>
>
>    # Warn unless there is a verifiable sender address in at least
>    # one of the "Sender:", "Reply-To:", or "From:" header lines.
>    warn
>         !acl        = acl_whitelist_local_deny
>         !verify     = header_sender
>         set acl_c1  = No verifiable address in message headers
>         message     = X-Sender-Verify-Failed: $acl_c1
>         log_message = $acl_c1
>
>
>
>    # --- BEGIN EXISCAN configuration ---
>
>    # Do not scan messages submitted from our own hosts
>    # and locally submitted messages. Since the DATA ACL
>    # is not called for messages not submitted via SMTP
>    # protocols, we do not need to check for an empty
>    # host field.
>    #
>    accept hosts = : $interface_address : +relay_from_hosts
>
>
>    # Reject messages that have serious MIME errors.
>    #
>    deny message     = Serious MIME defect detected ($demime_reason)
>         demime      = *
>         condition   = ${if >{$demime_errorlevel}{2}{1}{0}}
>         delay       = 20s
>
>
>    # Unpack MIME containers and reject file extensions used by worms.
>    # This calls the demime condition again, but it will return cached 
> results.
>    # Note that the extension list may be incomplete.
>    #
>    deny message     = We do not accept ".$found_extension" attachments 
> here.
>         demime      = bat:btm:cmd:com:cpl:dll:exe:lnk:msi:pif:prf:\
>                        reg:scr:vbs:url
>         delay       = 20s
>
>

#### If you use SA-Exim, omit the following (which invokes SA through 
ExiScan-ACL).
#### If you do, simply add an "accept" control to accept the message at 
this point.

>    # Invoke SpamAssassin to obtain $spam_score and $spam_report.
>    # Add appropriate headers to the message, and if it turns out
>    # to be spam, stall and pretend to reject the message.
>    # Note that even though the "spam" condition is called several
>    # times, the results are cached, and only the first call invokes
>    # SpamAssassin.
>
>    warn message     = X-Spam-Score: $spam_score
>         spam        = mail:true
>
>    warn message     = X-Spam-Status: $spam_report
>         spam        = mail:true
>
>    accept
>         spam        = mail
>         control     = fakereject
>         logwrite    = :main: Classified as spam (score $spam_score)
>         logwrite    = :main: == $h_Subject: ==
>         logwrite    = :reject: rejected; spam: $spam_report
>         delay       = 20s
>
>
>    # Otherwise, accept the message normally.
>    # However, stall if we previously generated a warning in $acl_c1.
>    accept
>         logwrite    = :main: Classified as ham (score $spam_score)
>         logwrite    = :main: == $h_Subject: ==
>         delay       = ${if def:acl_c1 {20s}{0s}}
>




More information about the SA-Exim mailing list