Index | Thread | Search

From:
"Omar Polo" <op@omarpolo.com>
Subject:
smtpd: add source address to error log lines
To:
tech@openbsd.org
Date:
Sun, 15 Mar 2026 16:51:37 +0100

Download raw body.

Thread
  • Omar Polo:

    smtpd: add source address to error log lines

this diff is taken as-is* from a PR in the -portable repo:

	https://github.com/OpenSMTPD/OpenSMTPD/pull/1303

(* with s/addr=/address=/g for consistency.)

The idea is that there are tools, in this case sshguard, which are
parsing the logs to detect "attacks".  We've changed since some time the
logs format, and now the information between the source address and the
failed commands are in different logs line, tied together only by the
id, i.e.

8f5fac8bf9cb7d93 smtp connected address=77.83.39.63 host=<unknown>
8f5fac8bf9cb7d93 smtp failed-command command="AUTH LOGIN" result="503 5.5.1 Invalid command: Command
8f5fac8bf9cb7d93 smtp disconnected reason=quit

so a log consumer has to keep in mind the inflight connections id while
parsing the scripts.

A solution would be to write a custom filter, that would keep track of
the inflight connections and log only, say, bad commands and failed
attempts, but this is still fairly complex in my opinion for a task that
is more or less equivalent to grep the logs.

So, are there objections to logging the remote address "parameter" to
these logs?

diff /home/op/w/smtpd
path + /home/op/w/smtpd
commit - 6965f4adac1ec8b9b9fcb3516ed56fae271049dc
blob - 3dd7af8b5c6aedaf78281af00dbec916ca692db1
file + smtp_session.c
--- smtp_session.c
+++ smtp_session.c
@@ -2142,33 +2142,40 @@ smtp_reply(struct smtp_session *s, char *fmt, ...)
 
 		if (s->flags & SF_BADINPUT) {
 			log_info("%016"PRIx64" smtp "
-			    "bad-input result=\"%.*s\"",
-			    s->id, n, buf);
+			    "bad-input "
+			    "address=%s "
+			    "result=\"%.*s\"",
+			    s->id, ss_to_text(&s->ss), n, buf);
 		}
 		else if (s->state == STATE_AUTH_INIT) {
 			log_info("%016"PRIx64" smtp "
 			    "failed-command "
+			    "address=%s "
 			    "command=\"AUTH PLAIN (...)\" result=\"%.*s\"",
-			    s->id, n, buf);
+			    s->id, ss_to_text(&s->ss), n, buf);
 		}
 		else if (s->state == STATE_AUTH_USERNAME) {
 			log_info("%016"PRIx64" smtp "
 			    "failed-command "
+			    "address=%s "
 			    "command=\"AUTH LOGIN (username)\" result=\"%.*s\"",
-			    s->id, n, buf);
+			    s->id, ss_to_text(&s->ss), n, buf);
 		}
 		else if (s->state == STATE_AUTH_PASSWORD) {
 			log_info("%016"PRIx64" smtp "
 			    "failed-command "
+			    "address=%s "
 			    "command=\"AUTH LOGIN (password)\" result=\"%.*s\"",
-			    s->id, n, buf);
+			    s->id, ss_to_text(&s->ss), n, buf);
 		}
 		else {
 			strnvis(tmp, s->cmd, sizeof tmp, VIS_SAFE | VIS_CSTYLE);
 			log_info("%016"PRIx64" smtp "
-			    "failed-command command=\"%s\" "
+			    "failed-command "
+			    "address=%s "
+			    "command=\"%s\" "
 			    "result=\"%.*s\"",
-			    s->id, tmp, n, buf);
+			    s->id, ss_to_text(&s->ss), tmp, n, buf);
 		}
 		break;
 	}