This patch adds a switch (via a control file or environment variable) to qmail to
enable a pause before the SMTP greeting to detect violation of the SMTP protocol:
If the remote system tries to send SMTP commands prior to the SMTP greeting the
connection is terminated.

This patch is specifically for netqmail-1.06 with the qmail-errmsg logging patch.

Please see http://free.acrconsulting.co.uk/email/other.html for more information.

Andrew Richards, November 2008.

diff -N -u netqmail-1.06.errmsg-v1.1/qmail-smtpd.8 netqmail-1.06.errmsg-v1.1.with.earlytalker/qmail-smtpd.8
--- netqmail-1.06.errmsg-v1.1/qmail-smtpd.8	1998-06-15 11:53:16.000000000 +0100
+++ netqmail-1.06.errmsg-v1.1.with.earlytalker/qmail-smtpd.8	2008-11-04 11:33:32.000000000 +0000
@@ -77,6 +77,17 @@
 is set, it overrides
 .IR databytes .
 .TP 5
+.I earlytalkerdroptime
+Number of seconds to wait before issuing the welcome prompt.
+Default: 0. If any input is received before the welcome prompt the
+session is terminated.  This can be helpful to trap junk SMTP traffic
+(well-behaved MTAs will wait for the welcome prompt before sending).
+
+If the environment variable
+.B EARLYTALKERDROPTIME
+is set, it overrides
+.IR earlytalkerdroptime .
+.TP 5
 .I localiphost
 Replacement host name for local IP addresses.
 Default:
diff -N -u netqmail-1.06.errmsg-v1.1/qmail-smtpd.c netqmail-1.06.errmsg-v1.1.with.earlytalker/qmail-smtpd.c
--- netqmail-1.06.errmsg-v1.1/qmail-smtpd.c	2008-11-02 19:13:06.000000000 +0000
+++ netqmail-1.06.errmsg-v1.1.with.earlytalker/qmail-smtpd.c	2008-11-04 14:08:42.000000000 +0000
@@ -179,6 +179,7 @@
 int bmfok = 0;
 stralloc bmf = {0};
 struct constmap mapbmf;
+unsigned int earlytalkerdroptime = 0;
 
 void setup()
 {
@@ -207,6 +208,9 @@
  
   remoteip = env_get("TCPREMOTEIP");
   if (!remoteip) remoteip = "unknown";
+  if (control_readint(&earlytalkerdroptime,"control/earlytalkerdroptime") == -1) die_control();
+  x = env_get("EARLYTALKERDROPTIME");
+  if (x) { scan_ulong(x,&u); earlytalkerdroptime = u; }
   local = env_get("TCPLOCALHOST");
   if (!local) local = env_get("TCPLOCALIP");
   if (!local) local = "unknown";
@@ -369,6 +373,28 @@
 unsigned int bytestooverflow = 0;
 unsigned int messagebytes = 0;
 
+void earlytalkercheck(delay)
+unsigned int delay;
+{
+  int r;
+  r = timeoutread(delay,0,ssinbuf,sizeof ssinbuf);
+  if (r == -1) if (errno == error_timeout) return; /* Timeout ==> No early talking */
+
+  /* Explain result of timeoutread and exit */
+  enew();
+  if      (r<0) eout3("Error before greeting (",error_str(errno),")");
+  else if (r==0) eout("Disconnect before greeting");
+  else /* Earlytalker */
+  {
+    eout("Data sent before greeting");
+    out("554 SMTP protocol violation\r\n"); flush();
+  }
+
+  eout(": quitting\n");
+  eflush();
+  _exit(1);
+}
+
 void put(ch)
 char *ch;
 {
@@ -514,6 +540,7 @@
   if (chdir(auto_qmail) == -1) die_control();
   setup();
   if (ipme_init() != 1) die_ipme();
+  if (earlytalkerdroptime) earlytalkercheck(earlytalkerdroptime);
   smtp_greet("220 ");
   out(" ESMTP\r\n");
   if (commands(&ssin,&smtpcommands) == 0) die_read();
