This implements CSV (
http://mipassoc.org/csv/) in a HELO ACL.
At the moment, the useful part is CSA -- checking which hosts are
authorised to use a given domain name in HELO:
helo infradead.org
550 CSV record for infradead.org does not include 205.233.218.70
The accreditation part (DNA) is implemented as a proof of concept but
needs the one-line PTR lookup patch which I just posted, and I can't
actually see any immediate practical use for the information.
# $Id: acl-helo-csv,v 1.1 2004/12/13 17:13:17 dwmw2 Exp $
#
# Exim 4 CSA check. Written 2004 David Woodhouse <dwmw2@???>
#
# This is placed in the public domain. You may copy, modify, distribute
# and use it in any way you see fit.
#
# Ways in which you might want to use it include invoking it directly
# to reject bogus HELO outright, with 'acl_smtp_helo = check_csv' or
# from an existing HELO ACL with 'require acl = check_csv'.
#
# Alternatively, to allow sites which fail the CSA check to still send
# messages to postmaster@, you could set an ACL variable upon CSV failure...
#
# warn !acl = check_csv
# set acl_c4 = rejectmelater
#
# ... and later test for it in your RCPT ACL:
#
# deny condition = ${if eq{$acl_c4}{rejectmelater} {1}}
# !local_parts = postmaster
# message = CSA record for $sender_helo_name does not authorise $sender_host_address
#
# The DNA check is included here as a proof of concept in case anyone
# actually works out what they want to _do_ with the information. As of
# Exim 4.43, you also need a one-line fix to prevent Exim's dnsdb lookup
# for PTR records from attempting to reverse $sender_helo_name as if it
# were an IPv4 address and appending '.in-addr.arpa' to it. It stores the
# accreditation service(s) in $acl_c0 and the results in $acl_c1, separated
# by newlines if there is more than one.
check_csv:
# Don't force everyone to include localhost in their CSA record,
# just so that connections to the local MTA work properly.
accept hosts = localhost
# Find CSA record.
warn set acl_m1 = ${lookup dnsdb{srv=_client._smtp.$sender_helo_name}}
# If there's no CSA record, accept the HELO name.
accept condition = ${if eq {$acl_m1}{} {1}}
# Check the CSA record. Each SRV record should match {^1 [0123] [0-9]+ <hostname>}
# or we treat it as no record at all. The uncommented <hostname> regex is taken from
# the Exim default dns_check_names_pattern; the commented version below is the
# UTF-8 version of same. Switch them over if you use the 'allow_utf8_domains' option
# to allow Exim to use raw UTF-8 in DNS.
accept condition = ${if !match{\n$acl_m1} {(?i)^(\n1 [0123] [0-9]+ \
(?>(?(2)\.|())[^\W_](?>[a-z0-9-]*[^\W_])?)+\
# (?>(?(2)\.|())[_a-z0-9\xc0-\xff](?>[-_a-z0-9\x80-\xff]*[_a-z0-9\x80-\xbf])?)+\
)*\$} {1}}
# Extract good hosts (1 2 x <hostname>)
warn set acl_m2 = ${sg {${sg {${sg {${sg {$acl_m1} \
{(?m)^1 ([0-9]+) [0-9]+ (.*)\$} \
{\N${if eq{$1}{2} {$2}}\N} \
}} {[\n]+}{:}}} {^:}{}}} {:\$}{} }
# Extract hosts which are authorised, but not to be used for authentication
# (1 3 x <hostname>)
warn set acl_m3 = ${sg {${sg {${sg {${sg {$acl_m1} \
{(?m)^1 ([0-9]+) [0-9]+ (.*)\$} \
{\N${if eq{$1}{3} {$2}}\N} \
}} {[\n]+}{:}}} {^:}{}}} {:\$}{} }
# Extract explicitly denied hosts (1 [01] x <hostname>)
warn set acl_m4 = ${sg {${sg {${sg {${sg {$acl_m1} \
{(?m)^1 ([0-9]+) [0-9]+ (.*)\$} \
{\N${if or {{eq{$1}{0}} {eq{$1}{1}}} {$2}}\N} \
}} {[\n]+}{:}}} {^:}{}}} {:\$}{} }
deny hosts = $acl_m4
message = CSA record for $sender_helo_name explicitly forbids $sender_host_address
deny message = CSA record for $sender_helo_name does not include $sender_host_address
!hosts = $acl_m2
!hosts = $acl_m3
# require acl = check_dna
accept
###########################################
# DNA checks here as proof of concept.
check_dna:
# Avoid DNA checks for hosts with 'Weight' field of 3.
accept hosts = $acl_m3
# Now look for DNA record, for hosts which may use it for authentication.
# Look up the reputation service(s) which this host wants us to use for it.
warn set acl_c0 = ${lookup dnsdb{ptr=$sender_helo_name}}
accept condition = ${if eq {$acl_c0}{} {1}}
# Extract the PTR records which start '_vouch._smtp.'
warn set acl_c0 = ${sg {${sg{\n$acl_c0} \
{(?i)(\n_vouch\\._smtp\\.([^\n]*)|\n[^\n]*)} \
{\N${if !eq{$2}{} {\n$2}}\N}}\
} {^\n}{}}
# .. and bail if there are none.
accept condition = ${if eq {$acl_c0}{} {1}}
warn set acl_c1 = ${sg {${sg{\n$acl_c0} \
{(?m)^(.*)\$} \
{\N${lookup dnsdb{txt=$sender_helo_name.$1}}\N} \
}} {^\n}{}}
accept
--
dwmw2