Hello exim users.
I have an ACL question for you guys. It's more of a policy question than
a technical question. I would like to deny hosts whose
$sender_helo_name/address doesn't match their $sender_host_name/address.
I started off with the following in my acl_smtp_mail ACL:
# Get hostname
warn
# IF: $sender_host_name is empty
condition = ${if eq{$sender_host_name}{}{true}{false}}
# THEN: set acl_m8 = DNS lookup of $sender_host_address
set acl_m8 = ${lookup dnsdb{ptr=$sender_host_address}{${lc:$value}}{}}
warn
# IF: $sender_host_name is not empty
condition = ${if eq{$sender_host_name}{}{false}{true}}
# THEN: set acl_m8 = $sender_host_name
set acl_m8 = $sender_host_name
...
# Lookup HELO
warn
# Initialize acl_m9
set acl_m9 = defer
warn
# Set acl_m9 = DNS lookup of $sender_helo_name
set acl_m9 = ${lookup dnsdb{a=$sender_helo_name}{$value}{}}
defer
# IF: DNS lookup failed, defer
condition = ${if eq{$acl_m9}{defer}{true}{false}}
message = Lookup of $sender_helo_name did not complete
log_message = bad HELO: Lookup failed
warn
# IF: DNS lookup did not return empty
condition = ${if eq{$acl_m9}{}{false}{true}}
# THEN: set acl_m9 to the list of hosts returned.
set acl_m9 = ${tr{$acl_m9}{\n}{:}}
...
# Deny if HELO does not match host
deny
condition = ${if !match{$acl_m8}{$acl_m9}{true}{false}}
message = Forged HELO/EHLO: You are not $sender_helo_name
log_message = bad HELO: Hostname/HELOname mismatch: $sender_helo_name
!= $acl_m9
The problem with this is that so many legitimate hosts aren't configured
to tell me who they really are. Exim will deny mail from roam4321.utk.edu
if they HELO as mail.utk.edu.
So my next brilliant idea was to accept HELO's that are "close" to each
other, and I defined close as being if the first 3 out of 4 octets of
their IP addresses are the same. I replaced the final deny above with the
following:
# Deny if HELO does not match host and IPs are too far appart.
deny
condition = \
${if \
and{ \
{!match{$acl_m8}{$acl_m9}} \
{or{ \
{and{ \
{isip4{$sender_host_address}} \
{isip4{$acl_m9}} \
{!eq{${mask:$sender_host_address/24}}{${mask:$acl_m9/24}}} \
}} \
{and{ \
{isip6{$sender_host_address}} \
{isip6{$acl_m9}} \
{!eq{${mask:$sender_host_address/96}}{${mask:$acl_m9/96}}} \
}} \
{and{{isip4{$sender_host_address}}{isip6{$acl_m9}}}} \
{and{{isip6{$sender_host_address}}{isip4{$acl_m9}}}} \
}} \
} \
{true} \
{false} \
}
message = Forged HELO/EHLO: You are not $sender_helo_name
log_message = bad HELO: Hostname/HELOname mismatch with distant
addresses: $sender_helo_name != $acl_m9 and $sender_host_address is
not close enough to $acl_m9
This is probably a terrible hack job that will make more knowledegable
gurus cringe, but it worked... sort of. This still denies some things
like
eagle.colostate.edu [129.82.103.90] as not being "close enough" to
eagle.acns.colostate.edu [129.82.100.90].
Before I go much farther with this (like dropping the required "closeness"
from 24 bits to 16 bits -- all I really care about is that the remote host
isn't obviously lying), what clever things have you guys implemented?
I suppose it would be nice to be able to look up the owner of both
addresses in whois and check to see if they're both in the same block, but
my guess is that's darned near impossible to automate, what with whois
being broken up and deregulated and all.
Is there a rule in the SMTP protocol that says the HELO name has to match
the remote sender's hostname/address in some way?
Maybe I should just chuck it out the window?
Whaddaya think sirs?
--
Michael Peek
peek@???
------------------------------------------------------------------------------
Systems Administrator / C++ Database Programmer 569 Dabney Hall
Department of Ecology and Evolutionary Biology Knoxville, TN
37996-1610
University of Tennessee at Knoxville
------------------------------------------------------------------------------
(865)974-0224 phone, (865)974-3067 fax
http://www.tiem.utk.edu/~peek