diff --git a/templates/smtp/server.py b/templates/smtp/server.py index 7b22181..8bf21a3 100644 --- a/templates/smtp/server.py +++ b/templates/smtp/server.py @@ -142,6 +142,11 @@ class SMTPProtocol(asyncio.Protocol): args = parts[1] if len(parts) > 1 else "" if cmd in ("EHLO", "HELO"): + if not args: + self._transport.write( + f"501 5.5.4 Syntax: {cmd} hostname\r\n".encode() + ) + return _log("ehlo", src=self._peer[0], domain=args) self._transport.write( f"250-{_SMTP_MTA}\r\n" diff --git a/tests/service_testing/test_smtp.py b/tests/service_testing/test_smtp.py index b4005e3..64051b9 100644 --- a/tests/service_testing/test_smtp.py +++ b/tests/service_testing/test_smtp.py @@ -114,6 +114,20 @@ def test_ehlo_returns_250_multiline(relay_mod): assert "PIPELINING" in combined +def test_ehlo_empty_domain_rejected(relay_mod): + proto, _, written = _make_protocol(relay_mod) + _send(proto, "EHLO") + replies = _replies(written) + assert any(r.startswith("501") for r in replies) + + +def test_helo_empty_domain_rejected(relay_mod): + proto, _, written = _make_protocol(relay_mod) + _send(proto, "HELO") + replies = _replies(written) + assert any(r.startswith("501") for r in replies) + + # ── OPEN RELAY MODE ─────────────────────────────────────────────────────────── class TestOpenRelay: