[If you followed the 'quick configuration' based on the config-all script, this feature was already configured for you at that time with the default settings.]
Changelog
- Feb 9, 2025
- clang compat
- dropped I and V options - Aug 17, 2023
- C++ version - Aug 13, 2023
- v. 8.2.0 bug fix: segfault in case of no result in DNS record
- default action changed to GNLR - Jul 27, 2023
-Pwill now pass through making all filters ignored. You are invited to remove this option if already using this program.
- addedGfilter, i.e.HELO/EHLOwith an invalid syntax are denied (random strings but also typing errors like sagredo..eu).
- compile with-lpcre
- code revision. Please report any issue.
The RFC-821 Section 3.5 states that
The sender-SMTP MUST ensure that the <domain> parameter in a HELO command is a valid principal host domain name for the client host. As a result, the receiver-SMTP will not have to perform MX resolution on this name in order to validate the HELO parameter.
The HELO receiver MAY verify that the HELO parameter really corresponds to the IP address of the sender. However, the receiver MUST NOT refuse to accept a message, even if the sender's HELO command fails verification.
Not denying clients with a bad HELO/EHLO DNS can be considered a wise thing, just to avoid to update too frequently our welcomelist for those clients who didn't set up their DNS properly.
On the other hand, it is a matter of fact that most spammers use fake domains -sometimes our own domains-, or even random strings or not solving domains, as their HELO/EHLOs.
For example, consider the following log lines (I have plenty of them in my logs):
2022-02-01 10:19:53.142643500 helo-dns-check: HELO [yq3H9cDKgS] from [109.237.103.41] doesn't solve 2022-02-01 09:53:05.772497500 helo-dns-check: HELO [sagredo.eu] is a local domain but IP [183.240.55.119] is not a RELAYCLIENT
I think that at least such kind of failures should be blocked.
I'll explain below how to set up a filter which denies clients with one of these particular DNS failures:
HELO/EHLOs domains with an invalid syntax. Random strings but also typing errors like sagredo..eu will be banned.- fake
HELO/EHLOs containing one of our domains, whenRELAYCLIENTis NOT set and theHELO/EHLOmatches one of ourIPs. You can safely turn on this one. - not solving
HELO/EHLOs domains (noArecord). You'll get some false positive if you turn this on, as clients whose administrator forgot to add theArecord will be banned. - clients whose remote
doesn't match theIPArecord. This is completely againstRFC-821, so my configuration will not refuse these connections by default, just log them.
We'll make use of a qmail-spp helodnscheck plugin that I derived from an original work of Perolo Silantico, Jason Frisvold with modifications by Ren Bing. Here is my modified program:
- C++ version 9.0.2
- C version 8.2.1 (same usage as the above)
The logic of the original plugin is to deny clients of type 4, which of course includes types 1, 2 and 3, but without being able to select 1 and/or 2 and/or 3 from the others. My modified version, instead, can ban only clients of type 1 and/or 2 and/or 3 or work as the original program (4).
Installation and configuration
I assume that you have already patched qmail with qmail-spp. If you are using my qmail distribution you are ok.
Download, compile and install:
wget https://raw.githubusercontent.com/sagredo-dev/helodnscheck/main/helodnscheck.cpp g++ -o /var/qmail/plugins/helodnscheck helodnscheck.cpp -lpcre
Now enable the plugin, adding it to /var/qmail/control/smtpplugins in the [helo] section:
[helo] plugins/helodnscheck
List all your IPs inside the file control/moreipme (you should have already done this if you configured the "moreipme" patch):
1.2.3.4 5.6.7.8
Then enable qmail-spp and set up the plugin parameters to your needs. I suggest the following in your qmail-smtpd run file:
export ENABLE_SPP=1 export HELO_DNS_CHECK=RLNG
In this way only bad HELOs of type 1 (G) and 2 (N) will be denied unless RELAYCLIENT is defined (R). All other DNS failures will pass through and each of them will be logged (L).
If you want to disable the HELO_DNS_CHECK just comment out that line.
Be aware that the HELO check can't work well on the submission port, where your IP cannot match the HELO, so you don't have to define HELO_DNS_CHECK in your qmail-submission run file.
Of course you can define HELO_DNS_CHECK via tcprules or allow a particular IP via NOHELODNSCHECK as follows:
111.222.333.444:allow, NOHELODNSCHECK="" :allow,HELO_DNS_CHECK="RNLG"
The program's behaviour is defined in the HELO_DNS_CHECK variable:
L- (default) LogH- add Header "X-Helo-Check"D- Debug mode (use withL)R- (default) if "RELAYCLIENT" is set, don't do anythingP- passthrough, never deny. Use withLand/orH.
Filters are executed in the following order:
G- (Garbage, default)HELO/EHLOwith an invalid syntax are denied.A- Not solving hostname inHELO/EHLOare denied. These clients do not even have anArecord. UsingGtogether withAis redundant (just useA).N- (Not me, default) deny ifRELAYCLIENTis NOT set and theHELO/EHLO's solves to one of ourIPs contained in control/moreipme.localhostwill be denied as well. UsingNtogether withAis redundant (just useA).B- Block if the remoteIP(TCPREMOTEIP) does not match the addresses solved. This is the original program's mode. UsingGand/orAand/orNtogether withBis redundant (just useB).
The above can be combined, so BL means block & log.
If P is defined all filters are ignored.
The default option is GNLR, which is defined if HELO_DNS_CHECK has no argument (HELO_DNS_CHECK="").
Testing
Test as follows:
HELO_DNS_CHECK="BLRD" \ SMTPHELOHOST="test.tld" \ TCPREMOTEIP="111.222.333.444" \ /var/qmail/plugins/helodnscheck helo-dns-check: dbg: action is BLRD helo-dns-check: dbg: no_helo_check is (null) helo-dns-check: dbg: helo_domain is test.tld helo-dns-check: dbg: remote_ip is 111.222.333.444 helo-dns-check: dbg: G filter 'nomatch': [2] helo-dns-check: dbg: no result in A record helo-dns-check: HELO [test.tld] from [111.222.333.444] doesn't solve R553 sorry, invalid host name in HELO/EHLO command. (#5.7.1) helo-dns-check: blocked with: invalid host name in HELO/EHLO command. [111.222.333.444]
Examples
tcprules usage
111.222.333.444:allow, NOHELODNSCHECK="" // allow IP :allow,HELO_DNS_CHECK="LB" // block & log others
qmail-smtpd run file usage
export HELO_DNS_CHECK="" // defaults to GNLR export HELO_DNS_CHECK // HELO_DNS_CHECK turned off #export HELO_DNS_CHECK // HELO_DNS_CHECK turned off export HELO_DNS_CHECK=RLGN // allow RELAYCLIENT, log, ban malformed domains, ban clients with my own domains in their HELO/EHLOs (safe choice)


Comments
Small bug fix
Andreas Gerstlauer June 17, 2025 06:51 CET
Hi Roberto,
there is a small bug in helodnscheck.c where the last character in the header ends up being cut off - in one case, the output of the plugin is missing the end of line character. Patch is here.
Reply | Permalink
Small bug fix
Roberto Puzzanghera Andreas Gerstlauer June 17, 2025 07:49 CET
Thank you. Corrected
Reply | Permalink
plugins Directory not created
GoofY April 2, 2023 10:06 CET
Howdy,
Just a minor thing, there is no '/var/qmail/plugins' directory, create with
Reply | Permalink
plugins Directory not created
Roberto Puzzanghera GoofY April 2, 2023 10:13 CET
Thank you. I'll make that directory created at compilation time in the next release
Reply | Permalink