>>>>> "Tony" == Tony Finch <dot@???> writes:
>> This can be done in ACLs already - _but_ that currently doesn't
>> work well due to the deferral problem with dnsdb; it's very common
>> with helo and return-path domains to have problems resolving the
>> nameservers even though the domain itself is resolvable.
Tony> I don't think you can do it in ACLs already, because zone
Tony> boundaries don't always coincide with domain
Tony> boundaries. E.g. hermes.cam.ac.uk has no nameservers of its own
Tony> since it resides in the cam.ac.uk zone. You have to retry after
Tony> trimming off a label if the NS lookup fails, and possibly
Tony> repeat.
Yes, so? While the recursion depth of ACLs is limited, it's sufficient
to deal with all plausible cases of that:
# warning: the code that follows is known not to work well in the wild
# due to dnsdb's inability to handle deferrals in a controllable manner
# variable convention: c0-c8 are scratch variables, m9 contains named
# per-message variables, m8 is the rejection text if set
# Given a domain in acl_c0, find the nearest zone cut, and return the zone
# base in c0, and the NS records in c1
check_domain_ns:
warn set acl_c1 = ${lookup dnsdb {NS=$acl_c0}{$value}{}}
warn condition = ${if eq{$acl_c1}{} {yes}{no}}
condition = ${if match{$acl_c0}{\N\.\N} {yes}{no}}
set acl_c0 = ${substr{${strlen:${extract{1}{.}{$acl_c0}}}}{$acl_c0}}
set acl_c0 = ${s_1:$acl_c0}
acl = check_domain_ns
# given a newline-delimited list of addresses in $acl_c0, look them all up
# in the dnslist $acl_c1, stopping if we find one (returned in c0)
check_addresses:
deny condition = ${if eq{$acl_c0}{} {yes}{no}}
warn set acl_c2 = ${extract{1}{\n}{$acl_c0}}
set acl_c0 = ${substr{${strlen:$acl_c2}}{$acl_c0}}
set acl_c0 = ${s_1:$acl_c0}
warn set acl_c3 = ${sg{4.3.2.1}{\N(\d)\N}{\N${extract{$1}{.}{$acl_c2}}\N}}
accept dnslists = $acl_c1/$acl_c3
set acl_c0 = $acl_c2
accept acl = check_addresses
# given a newline-delimited list of NS names in acl_c0, see if any are
# locally considered bad.
check_nameservers:
warn set acl_c0 = ${sg{$acl_c0}{\N(.+)\n?\N}\
{\N${lookup{$1}\
partial()lsearch{EXIM_HOME/bad_ns_domains}\
{,$1.$2}{}}\N}}
set acl_c0 = ${s_1:$acl_c0}
accept condition = ${if !eq{$acl_c0}{} {yes}{no}}
check_client_domain:
warn set acl_c0 = $sender_host_name
deny condition = ${if eq{$acl_c0}{} {yes}{no}}
warn acl = check_domain_ns
warn set acl_m9 = czone=${quote:$acl_c0} cns=${quote:$acl_c1} $acl_m9
set acl_c2 = $acl_c0
set acl_c0 = ${sg{$acl_c1}\
{\N(.+)(\n?)\N}\
{\N${lookup dnsdb {A=$1}{$value$2}{}}\N}}
log_message = nameservers: $sender_host_name zone ${quote:$acl_c2} NS ${quote:$acl_c1} A ${quote:$acl_c0}
warn set acl_c1 = sbl.spamhaus.org
acl = check_addresses
set acl_m8 = bad client: $sender_host_name NS $acl_c0 on $dnslist_domain $dnslist_value: $dnslist_text
log_message = $acl_m8
warn set acl_c0 = ${extract{cns}{$acl_m9}}
acl = check_nameservers
set acl_m8 = bad client: $sender_host_name NS $acl_c0 is locally banned
log_message = $acl_m8
Tony> Consider also the amusement that can be had with classless
Tony> in-addr.arpa delegation and chasing CNAMEs.
Yeah, finding the nameservers for the reverse zone is harder, but I'm
less convinced that it is useful.
--
Andrew, Supernews
http://www.supernews.com