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:
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user