From d90af092cd7bb62a1a7f8e232a019c4f80b063f5 Mon Sep 17 00:00:00 2001 From: Mario Fetka Date: Tue, 28 Jul 2026 14:48:53 +0200 Subject: [PATCH] docs: record SMTP-24 live evidence --- contrib/testing/README.md | 16 ++++++++++++++++ docs/release-testing-0.7.md | 2 +- docs/test-evidence/0.7-r1.md | 35 +++++++++++++++++++++++++++++++++++ 3 files changed, 52 insertions(+), 1 deletion(-) diff --git a/contrib/testing/README.md b/contrib/testing/README.md index a375ae7..a59ddfa 100644 --- a/contrib/testing/README.md +++ b/contrib/testing/README.md @@ -110,6 +110,13 @@ one-off files in `/tmp`: trusted destination receives one correct generated copy of each. A final case enables XFORWARD with `ADDR` and verifies that protocol metadata suppresses the fallback headers. +- `smtp-proxy-protocol-check.py` temporarily binds trusted SMTP to loopback + port 10026. PROXY v1 and v2 synthetic client addresses must pass a relay ACL + which excludes the real socket peer, while `UNKNOWN` retains that peer. + Malformed and missing trusted-proxy framing closes before the greeting. + Native clients outside the proxy trust list work normally and cannot turn a + forged `PROXY` SMTP command into trusted connection metadata. The exact + SMTP document and active service are restored after the run. - `smtp-client-interoperability-check.py` repeats real delivery with curl, swaks, Xeams Email Sender, GNU Mailutils, and paced Telnet input. It covers authenticated STARTTLS submission plus unauthenticated local delivery on @@ -695,3 +702,12 @@ The test listeners are SMTP `11025`, submission `11587`, submissions `11465`, IMAP `11143`, IMAPS `11993`, POP3 `11110`, POP3S `11995`, and ManageSieve `14190`. Exercise real protocol greetings, capabilities, authentication, and TLS handshakes through these ports, then restore the original Bongo documents. + +For the destructive-but-self-restoring SMTP trust and framing matrix, run: + +```sh +./contrib/testing/smtp-proxy-protocol-check.py +``` + +It requires an active disposable Bongo installation and uses only the +authorized `bongo-admin` and `systemctl restart/is-active` operations. diff --git a/docs/release-testing-0.7.md b/docs/release-testing-0.7.md index 1c12088..8a3a055 100644 --- a/docs/release-testing-0.7.md +++ b/docs/release-testing-0.7.md @@ -157,7 +157,7 @@ review does not mark an open live test as passed. | SMTP-21 | LMTP per-recipient 2xx, 4xx, 5xx, retry, and duplicate prevention | [PASS](test-evidence/0.7-r1.md#smtp-21) | | | | SMTP-22 | XCLIENT/XFORWARD negotiation only to trusted destinations | [PASS](test-evidence/0.7-r1.md#smtp-22) | | | | SMTP-23 | Fallback client-address header only for configured trusted peers | [PASS](test-evidence/0.7-r1.md#smtp-23) | | | -| SMTP-24 | Incoming PROXY v1/v2 only from configured proxy networks | | | | +| SMTP-24 | Incoming PROXY v1/v2 only from configured proxy networks | [PASS](test-evidence/0.7-r1.md#smtp-24) | | | | SMTP-25 | Malformed commands, long lines, floods, timeout, and disconnect | | | | | SMTP-28 | TLSRPT preserves the exact DNS policy, aggregates completed UTC days, and emits valid RFC 8460 JSON | | | | | SMTP-29 | TLSRPT gzip mail/HTTPS delivery, DKIM requirement, random delay, durable retry, expiry, and report-loop suppression | | | | diff --git a/docs/test-evidence/0.7-r1.md b/docs/test-evidence/0.7-r1.md index 6aee98b..eaa2d0a 100644 --- a/docs/test-evidence/0.7-r1.md +++ b/docs/test-evidence/0.7-r1.md @@ -3136,6 +3136,41 @@ The exact SMTP Store document and public port 25 were restored afterward. `bongo.service` was active, all three proxy destination lists were empty, and `bongo-queuetool list` produced no entries. +## SMTP-24 + +Result: **PASS** + +Commit `fcac5413` added `smtp-proxy-protocol-check.py`. The live fixture +temporarily moved trusted internal SMTP to loopback port 10026 and enabled +PROXY protocol only for `127.0.0.1/32`. Its port-26 ACL deliberately excluded +the actual loopback peer and allowed only the synthetic v1 and v2 client +networks. Both handshakes received a normal SMTP greeting and completed +EHLO/QUIT, proving that Bongo consumed the framing and applied the supplied +client address before its relay ACL. + +A v1 `UNKNOWN` header retained the socket peer as specified. A malformed v1 +port and a trusted proxy which sent no header were closed silently, the latter +after Bongo's bounded five-second pre-greeting timeout. With loopback removed +from `proxy_protocol_networks`, an ordinary client received the greeting +without a PROXY block. A forged `PROXY TCP4` line was rejected as an unknown +SMTP command, and the same native session could still issue EHLO and QUIT; +the attacker-selected address never reached the trusted identity path. + +This was compared with Postfix 3.11.1 `src/smtpd/smtpd_haproxy.c` and +`src/global/haproxy_srvr.c`: the PROXY block is likewise read before any SMTP +I/O, malformed or timed-out framing fails the connection, v1/v2 TCP4 update +the peer, and the non-proxy forms retain the socket peer. Bongo additionally +requires the immediate proxy address to match an explicit exact-IP or CIDR +trust rule. + +```text +SMTP-24 PASS proxy=v1/v2 client-address=applied-before-port26-acl trusted=exact/cidr unknown=passthrough malformed=closed missing=timeout/closed untrusted=native/forgery-rejected config-restored=yes service-restored=active +``` + +The exact SMTP Store document was restored afterward. PROXY protocol was +disabled again with an empty proxy network list, trusted SMTP returned to +`172.16.11.133:26` with `172.16.11.0/24`, and `bongo.service` was active. + ## SMTP-27 Result: **PASS**