Re: [exim] Reject servers that use my ip address as EHLO

Top Page
Delete this message
Reply to this message
Author: Mike Tubby
Date:  
To: exim-users
Subject: Re: [exim] Reject servers that use my ip address as EHLO
You can do a lot to stop spam-bots and the like by policing of the
HELO/EHLO ... there are still bots that say "HELO OEMCOMPUTER" and
Windoze servers that say things like "HELO XYZDOMAIN" which we reject.

Here's how we do it on our public servers:

     * accept if host is in relay_from_hosts list
     * deny if HELO is single word
     * deny if HELO is raw IP address
     * deny if HELO is our host name (attack vector)
     * deny if HELO is from domains that handle (local domains or relay for)
     * deny if HELO is in a local MySQL backlist
     * attempt to verify the HELO FQDN - generates a warning
     * accept everything else


Here's what the ACL looks like:


###
### acl_check_helo: check the HELO/EHLO
###

acl_check_helo:

         #
         # report TLS status
         #
         warn    condition = ${if def:tls_in_cipher {1}{0}}
                 logwrite = CRYPTO: Client 
$sender_host_address:$sender_host_port using SSL/TLS cipher: $tls_in_cipher


         #
         # accept for relay_from_hosts
         #
         accept  condition = ${if 
match_domain{$sender_helo_name}{$+relay_from_hosts}{true}{false}}
                 logwrite = HELO: Accepted HELO/EHLO $sender_helo_name 
from remote host: $sender_host_address ${if def:sender_host_name 
{($sender_host_name) }} in hostlist relay_from_hosts


         #
         # check for single word greeting messages like "HELO COMPUTER"
         #
         deny    condition = ${if match {$sender_helo_name} {\\.} {no}{yes}}
                 message = Your HELO/EHLO greeting ($sender_helo_name) 
is a single word. \
                         According to RFC2821 you must use your 
fully-qualified domain-name. \
                         Please fix your configuration if you want to 
talk to us
                 logwrite = HELO: HELO/EHLO was not a FQDN : 
$sender_helo_name from $sender_fullhost


         #
         # check for raw IP address in greeting like "HELO 1.2.3.4"
         #
         deny    condition = ${if isip{$sender_helo_name}}
                 #condition = ${if match 
{$sender_helo_name}{^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+\$}{yes}{no}}
                 message = Your HELO/EHLO greeting ($sender_helo_name) 
is a plain IP address. \
                         According to RFC2821 you must use your 
fully-qualified domain-name. \
                         Please fix your configuration if you want to 
talk to us
                 logwrite = HELO: HELO/EHLO with bare IP : 
$sender_helo_name from $sender_fullhost


         #
         # check for HELO from our host name... must be a faker!
         #
         deny    condition = ${if match 
{$sender_helo_name}{$primary_hostname}{true}{false}}
                 message = Your HELO/EHLO greeting ($sender_helo_name) 
is using our name! \
                         According to RFC2821 you must use your 
fully-qualified domain-name. \
                         Please fix your configuration if you want to 
talk to us
                 logwrite = HELO: Rejected because remote host used our 
hostname: $sender_helo_name


         #
         # check for HELO from domains that we handle (local domains and 
relay domains)... if so this is fake
         #
         deny    condition = ${if 
match_domain{$sender_helo_name}{$+local_domains:+relay_to_domains}{true}{false}}
                 message = Your HELO/EHLO greeting ($sender_helo_name) 
is using one of our domains! \
                         According to RFC2821 you must use your 
fully-qualified domain-name. \
                         Please fix your configuration if you want to 
talk to us
                 logwrite = HELO: Rejected because remote host used one 
of our domains: $sender_helo_name


         #
         # check for HELO names blacklisted in our database, if we 
reject don't give too much help as to why
         #
         deny    condition = ${if 
match_domain{$sender_helo_name}{+blacklist_helo}{yes}{no}}
                 message = Your HELO/EHLO is not acceptable here
                 logwrite = HELO: Rejected: $sender_helo_name (from 
$sender_fullhost) - blacklisted in database


         #
         # attempt to verify the HELO/EHLO, if it fails just generate a 
log warning - we cannot reject
         # based on this. See also the check_content ACL where we add a 
warning to headers for invalid HELO
         #
         warn    !verify = helo
                 logwrite = HELO: Could not verify HELO/EHLO: 
$sender_helo_name from remote host: $sender_host_address ${if 
def:sender_host_name {($sender_host_name) }}


         #
         # accept everything else
         #
         accept  message = Hello $sender_helo_name
                 logwrite = HELO: Accepted HELO/EHLO $sender_helo_name 
from remote host: $sender_host_address ${if def:sender_host_name 
{($sender_host_name) }}






On 20/04/2016 12:09, Patrick von der Hagen wrote:
> Hi Udera,
>
> I believe some configuration like
>    deny
>      condition   = ${if isip{$sender_helo_name}}
>      !hosts = PROBLEMFAELLE_HELO
>      message     = Access denied - Invalid HELO name (See RFC2821 4.1.3)
>   # Neither an address literal nor something containing dots
>    deny
>      !hosts = PROBLEMFAELLE_HELO
>      condition   = ${if match{$sender_helo_name}{\N^\[\N}{no}{yes}}
>      condition   = ${if match{$sender_helo_name}{\N\.\N}{no}{yes}}
>      message     = Access denied - Invalid HELO name (See RFC2821 4.1.1.1)

>
>    warn
>      condition   = ${if match{$sender_helo_name}{\N\.$\N}}
>      log_message = HELO ending with dot
>      set acl_c_greylisting = 1
>    warn
>      condition   = ${if match{$sender_helo_name}{\N\.\.\N}}
>      log_message = HELO contains two subsequent dots.
>      set acl_c_greylisting = 1

>
>    warn
>      condition = ${if match{$sender_helo_name}{$primary_hostname}}
>      log_message = HELO is MY primary hostname
>      set acl_c_greylisting = 1

>
>
> is quite common.
>
> But keep in mind: if you simply deny in HELO will simply signal a deny
> to the client but if the client simply ingores your response and starts
> sending a message anyway, it will be accepted by exim.
>
> There was a discussion in January about that issue, have a look at the
> discussion in the archive ("exim still accepting email after 550 from
> acl_check_helo").
>
> On 20.04.2016 09:47, Udera Udera wrote:
>> Dear list,
>>
>> I tried to implement a ACL-helo-check from the exim-wiki on github:
>> https://github.com/Exim/exim/wiki/AclHeloTricks#helo-is-faked-interface-address
>>
>> drop    message     = Bad helo name
>>          condition   = ${if  \
>>                           and{    \
>>                               {isip {$sender_helo_name}}  \
>>                               {match_ip{$sender_helo_name}{@[]}}  \
>>                           }{yes}{no}  \
>>                       }

>>
>> But it doesn't work. Just suppose my server ip is 10.0.0.1.
>>
>> I want to reject servers that use my ip address as their EHLO, that would
>> be:
>> EHLO [10.0.0.1]
>>
>> Unfortunately, that does not work because
>>
>> isip {$sender_helo_name}
>>
>>
>> isn't true. If the plain ip address is used, this would work but plain ip
>> addresses are not allowed (and already covered by:
>> https://github.com/Exim/exim/wiki/AclHeloTricks#helo-is-an-ip-address).
>>
>> I tried to get rid of the brackets but I didn't get the syntax right and
>> I'm not sure if this is the way to go:
>> drop condition = ${if
>> match{${substr{1}{${length{$sender_helo_name}-2}}{$sender_helo_name}}}{@
>> []}{yes}{no}}
>>
>> I hope someone can help me out here.
>>
>> Thanks a lot,
>> Udera
>>
>
>