@dalias Ages ago, I twisted my brain enough to learn Sendmail rules and came up with two HELO / EHLO checks: one which requires that the HELO / EHLO name resolves to the connecting IP(v6), and that the PTR for that address also resolves to the same address, and one that’s not as aggressive and just makes sure that the HELO / EHLO name resolves in DNS.
Checking that the PTR name resolves to the same address as the PTR is beyond Microsoft. I think they’re not allowed to have O’Reilly animal books. They really take “not invented here” seriously, and considering they haven’t invented shit, nothing of theirs works properly.
LOCAL_RULESETS
Scheck_mail
Kcheckdns dns -R A
Kcheckv6 dns -R AAAA
Kcheckptr dns -R PTR
FH /etc/mail/access
# require_dns.m4, 9-November-2003, John Klos (jklos@netbsd.org)
# Updated 6-January-2007
# Checks that HELO IP literal matches connecting machine, and
# checks that HELO domain name resolves (but not necessarily back
# to the connecting server), and that it isn't our name.
# This HELO checking is what should be done, anyway; syntactically
# invalid HELOs are allowed to be rejected. Checking whether a
# HELO hostname resolves is my lazy way of checking the syntax.
# localhost (real address, not HELO localhost) is always Ok.
R$* $: $&{client_addr}
R127.0.0.1 $@
RIPv6:::1 $@
RIPv6:0:0:0:0:0:0:0:1 $@
# Skip checking if connection is authenticated
R$* $: <$&{auth_type}>
R<PLAIN> $@
# Reject addresses with no / broken reverse DNS
R$* $: < $&{client_resolve} >
R<TEMP> $#TEMP $@ 4.4.0 $: "450 Relaying temporarily denied. Cannot resolve PTR record for " $&{client_addr}
R<FORGED> $#error $@ 5.7.1 $: "550 Relaying denied. PTR likely forged " $&{client_name}
R<FAIL> $#error $@ 5.7.1 $: "550 Relaying denied. PTR lookup failed " $&{client_name}
# Reject our own names. Anything that's in /etc/mail/access or
# /etc/mail/local-host-names should not match any HELO name.
R$* $: $&s
Rlocalhost $#error $@ 5.1.8 $: "550 Access denied. You are not obviously not localhost."
R$=w $#error $@ 5.1.8 $: "550 Access denied. You are not "$&s"."
R$=H $#error $@ 5.1.8 $: "550 Access denied (access file). You are not "$&s"."
# Reject common domain names which all use proper HELO strings.
Ryahoo.com $#error $@ 5.1.8 $: "550 Access denied. You are not "$&s"."
Rjuno.com $#error $@ 5.1.8 $: "550 Access denied. You are not "$&s"."
Rgoogle.com $#error $@ 5.1.8 $: "550 Access denied. You are not "$&s"."
Routlook.com $#error $@ 5.1.8 $: "550 Access denied. You are not "$&s"."
Rhotmail.com $#error $@ 5.1.8 $: "550 Access denied. You are not "$&s"."
Rmsn.com $#error $@ 5.1.8 $: "550 Access denied. You are not "$&s"."
# This test checks if the HELO string either matches or is the last part of
# the PTR record for services such as Hotmail and Gmail.
R$* $: <$&{client_name}> <$&{client_resolve}>
R<$*$&s> <OK> $@
# Skip checking if connection is authenticated
R$* $: <$&{auth_type}>
R<PLAIN> $@
# These rules assume that all will be OK if:
# HELO [IP address] matches [{client_addr}] or
# HELO [IPv6:IPv6 address] matches [{client_addr}]
# Or, if neither of the above, that the HELO string must be a FQDN (primary
# host name) as per the RFCs and therefore should resolve. Non-matching
# [IP address] or [IPv6:IPv6 address] do not resolve as FQDN and fail below.
R$* $: $&s
R [$&{client_addr}] $@
# Stick the connecting IP address into the workspace; if it's an IPv6 address,
# replace it with the IPv6 address of the AAAA HELO lookup. If it matches
# the connecting IP, it's Ok.
R$* $: $&{client_addr}
RIPv6:$+ $: <$( checkv6 $&s $: FAIL $)>V6
R<$&{client_addr}>V6 $@
# Stick the IP address of the A HELO lookup into the workspace. Fail
# if the lookup fails.
R$* $: <$( checkdns $&s $: FAIL $)>V4
R<FAIL>V4 $#error $@ 4.1.8 $: "550 Access denied. HELO does not resolve. (HELO " $&s ")"
R<$&{client_addr}>V4 $@