postfix: ETRN discarded from EHLO silently

After the 2.14.4 rollout the test server's mail.log held "discarding EHLO
keywords: ETRN" for every connection on every port: smtpd logs a discard
unless the mask has EHLO_MASK_SILENT (Postfix 3.10.13, src/smtpd/smtpd.c:2016;
src/global/ehlo_mask.c:88 "SILENT-DISCARD"; postconf(5)
smtpd_discard_ehlo_keywords, "Specify the silent-discard pseudo keyword to
prevent this action from being logged"). smtpd_discard_ehlo_keywords is now
silent-discard,etrn; ETRN is still refused (smtpd_etrn_restrictions=reject)
and still not offered.

make e2e (64 passed; checkPostfixHardening reads the value back,
testInboundRelay still sees no ETRN in EHLO and 554) and go vet + go test
(26 packages) on the test server for this tree.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
mix
2026-10-18 01:01:41 +03:00
co-authored by Claude Opus 5.5
parent 58356fb4d4
commit 8eec6728d4
4 changed files with 14 additions and 4 deletions
+7
View File
@@ -5,6 +5,13 @@ Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); version
## [Unreleased] ## [Unreleased]
### Fixed
- **ETRN is discarded from the EHLO reply silently**: since `2.14.4` Postfix
logged "discarding EHLO keywords: ETRN" for every connection on every port
(seen on the test server after the rollout); `silent-discard` keeps the
discard and drops the line.
## [2.14.4] - 2026-10-17 ## [2.14.4] - 2026-10-17
The follow-ups of the security audit of 2026-10-17 The follow-ups of the security audit of 2026-10-17
+5 -2
View File
@@ -327,14 +327,17 @@ postconf -e \
# client flush the queue toward an inbound domain's upstream # client flush the queue toward an inbound domain's upstream
# (fast_flush_domains = $relay_domains), and nothing here needs it (security # (fast_flush_domains = $relay_domains), and nothing here needs it (security
# audit 2026-10-17, S6; Postfix 3.10.13, src/smtpd/smtpd.c, etrn_cmd() asks # audit 2026-10-17, S6; Postfix 3.10.13, src/smtpd/smtpd.c, etrn_cmd() asks
# smtpd_check_etrn(), whose "reject" answers reject_code, 554). # smtpd_check_etrn(), whose "reject" answers reject_code, 554). The discard is
# silent: without the pseudo keyword smtpd logs "discarding EHLO keywords:
# ETRN" for every connection (src/smtpd/smtpd.c:2016, EHLO_MASK_SILENT;
# src/global/ehlo_mask.c:88; seen on the test server after 2.14.4).
postconf -e \ postconf -e \
"smtpd_tls_protocols=>=TLSv1.2" \ "smtpd_tls_protocols=>=TLSv1.2" \
"smtpd_tls_mandatory_protocols=>=TLSv1.2" \ "smtpd_tls_mandatory_protocols=>=TLSv1.2" \
"smtp_tls_mandatory_protocols=>=TLSv1.2" \ "smtp_tls_mandatory_protocols=>=TLSv1.2" \
"disable_vrfy_command=yes" \ "disable_vrfy_command=yes" \
"smtpd_etrn_restrictions=reject" \ "smtpd_etrn_restrictions=reject" \
"smtpd_discard_ehlo_keywords=etrn" \ "smtpd_discard_ehlo_keywords=silent-discard,etrn" \
'smtpd_banner=$myhostname ESMTP' 'smtpd_banner=$myhostname ESMTP'
# SASL: Cyrus with the local sasldb2 the panel maintains. The realm is left # SASL: Cyrus with the local sasldb2 the panel maintains. The realm is left
+1 -1
View File
@@ -104,7 +104,7 @@ smtp/inet` removes Debian's stock smtpd). Outbound delivery still uses the
submission chain would otherwise let a signing outage defer relayed mail and submission chain would otherwise let a signing outage defer relayed mail and
would file inbound mail into the outbound send log under the sender's would file inbound mail into the outbound send log under the sender's
domain. `ETRN` is refused on every listener and not offered in the EHLO domain. `ETRN` is refused on every listener and not offered in the EHLO
reply (`smtpd_etrn_restrictions=reject`, `smtpd_discard_ehlo_keywords=etrn`): reply (`smtpd_etrn_restrictions=reject`, `smtpd_discard_ehlo_keywords=silent-discard,etrn`):
Postfix's default lets any client flush the queue toward an inbound Postfix's default lets any client flush the queue toward an inbound
domain's upstream. With the inbound relay on the chain is the optional antispam milter, domain's upstream. With the inbound relay on the chain is the optional antispam milter,
then the panel's **inbound journal milter** (unix socket then the panel's **inbound journal milter** (unix socket
+1 -1
View File
@@ -168,7 +168,7 @@ func checkPostfixHardening(s *stack) error {
return fmt.Errorf("postconf: %v\n%s", err, out) return fmt.Errorf("postconf: %v\n%s", err, out)
} }
got := strings.Split(strings.TrimSpace(out), "\n") got := strings.Split(strings.TrimSpace(out), "\n")
want := []string{">=TLSv1.2", ">=TLSv1.2", "yes", "$myhostname ESMTP", "reject", "etrn"} want := []string{">=TLSv1.2", ">=TLSv1.2", "yes", "$myhostname ESMTP", "reject", "silent-discard,etrn"}
if strings.Join(got, "|") != strings.Join(want, "|") { if strings.Join(got, "|") != strings.Join(want, "|") {
return fmt.Errorf("postconf -h of the hardened settings = %q, want %q", got, want) return fmt.Errorf("postconf -h of the hardened settings = %q, want %q", got, want)
} }