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
>>
>
>