badrcptto v1.02

This is the home of a small patch for qmail called badrcptto, which I thought might be useful for the world. This patch blocks e-mail for specific users in an e-mail domain you accept mail for, before the e-mail even transfers the line.

This patch lets you reject e-mail at the smtp envelope (rcpt) phase, which can produce a considerable bandwidth saving when a lot of e-mail is directed at non-existing users. Instead of recieving the body of the e-mail and then rejecting it in qmail-send, you can reject it before receiving the body. This can be very useful in a setup where you have one qmail box accepting all the e-mail, which then passes it on to another (q)mail box behind it.

With standard qmail, if the user does not exist (anymore) on the second box, the first box will simply accept the mail, and the second will produce a bounce message to the sender. This is not a problem for a small amount of mail, but if massive amounts of email are addressed to this user (bounces from spam that used this user's address as the 'from', e.g.), your line might get filled with unnessary traffic.

Alex Kramarov made an addition to my original patch, which allows turning off the badrcptto check if environment variable RELAYCLIENT is set, so one could use this patch to prevent remote users from sending e-mail to local accounts by listing them in badrcptto, while allowing local users to do so. This addition is now part of this badrcptto patch (v1.01).

And then Andrew McCarthy read my thoughts and reworked Johan Almqvist's patch to log badmailfrom hits to log badrcptto hits. He integrated Johan's work with the badrcptto patch, leading to v1.02 of this badrcptto patch, which you can find below. Note that you will still need to apply the last hunk of Johan's patch if you also want to log badmailfrom hits. Only the last hunk, mind you - the rest is duplicated in this patch.

You can download the v1.02 patch here or just cut and paste below. If you don't want the logging, get the v1.01 patch here. If you run netqmail (and you probably should!), use this slightly modified patch.

Oliver Neubauer built further on this patch and created a 'validrcptto' patch, which acts as an 'allow only' control list. Very handy if non-existing addresses in your domain are being used as the 'from' address in spam...

--- qmail-1.03-clean/Makefile	Mon Jun 15 11:53:16 1998
+++ qmail-1.03/Makefile	Fri Mar 28 13:44:38 2003
@@ -1535,13 +1535,13 @@
 load qmail-smtpd.o rcpthosts.o commands.o timeoutread.o \
 timeoutwrite.o ip.o ipme.o ipalloc.o control.o constmap.o received.o \
 date822fmt.o now.o qmail.o cdb.a fd.a wait.a datetime.a getln.a \
-open.a sig.a case.a env.a stralloc.a alloc.a substdio.a error.a str.a \
+open.a sig.a case.a env.a stralloc.a alloc.a strerr.a substdio.a error.a str.a \
 fs.a auto_qmail.o socket.lib
 	./load qmail-smtpd rcpthosts.o commands.o timeoutread.o \
 	timeoutwrite.o ip.o ipme.o ipalloc.o control.o constmap.o \
 	received.o date822fmt.o now.o qmail.o cdb.a fd.a wait.a \
 	datetime.a getln.a open.a sig.a case.a env.a stralloc.a \
-	alloc.a substdio.a error.a str.a fs.a auto_qmail.o  `cat \
+	alloc.a strerr.a substdio.a error.a str.a fs.a auto_qmail.o  `cat \
 	socket.lib`
 
 qmail-smtpd.0: \
--- qmail-1.03-clean/qmail-smtpd.c	Mon Jun 15 11:53:16 1998
+++ qmail-1.03/qmail-smtpd.c	Fri Mar 28 13:46:05 2003
@@ -23,6 +23,7 @@
 #include "timeoutread.h"
 #include "timeoutwrite.h"
 #include "commands.h"
+#include "strerr.h"
 
 #define MAXHOPS 100
 unsigned int databytes = 0;
@@ -50,6 +51,7 @@
 void straynewline() { out("451 See http://pobox.com/~djb/docs/smtplf.html.\r\n"); flush(); _exit(1); }
 
 void err_bmf() { out("553 sorry, your envelope sender is in my badmailfrom list (#5.7.1)\r\n"); }
+void err_brt() { out("553 sorry, this recipient is in my badrecipientto list (#5.7.1)\r\n"); }
 void err_nogateway() { out("553 sorry, that domain isn't in my list of allowed rcpthosts (#5.7.1)\r\n"); }
 void err_unimpl() { out("502 unimplemented (#5.5.1)\r\n"); }
 void err_syntax() { out("555 syntax error (#5.5.4)\r\n"); }
@@ -96,6 +98,9 @@
 int bmfok = 0;
 stralloc bmf = {0};
 struct constmap mapbmf;
+int brtok = 0;
+stralloc brt = {0};
+struct constmap mapbrt;
 
 void setup()
 {
@@ -116,6 +121,11 @@
   if (bmfok == -1) die_control();
   if (bmfok)
     if (!constmap_init(&mapbmf,bmf.s,bmf.len,0)) die_nomem();
+
+  brtok = control_readfile(&brt,"control/badrcptto",0);
+  if (brtok == -1) die_control();
+  if (brtok)
+    if (!constmap_init(&mapbrt,brt.s,brt.len,0)) die_nomem();
  
   if (control_readint(&databytes,"control/databytes") == -1) die_control();
   x = env_get("DATABYTES");
@@ -208,6 +218,17 @@
   return 0;
 }
 
+int brtcheck()
+{
+  int j;
+  if (!brtok) return 0;
+  if (constmap(&mapbrt,addr.s,addr.len - 1)) return 1;
+  j = byte_rchr(addr.s,addr.len,'@');
+  if (j < addr.len)
+    if (constmap(&mapbrt,addr.s + j,addr.len - j - 1)) return 1;
+  return 0;
+}
+
 int addrallowed()
 {
   int r;
@@ -258,6 +279,11 @@
   }
   else
     if (!addrallowed()) { err_nogateway(); return; }
+  if (!env_get("RELAYCLIENT") && brtcheck()) {
+    strerr_warn4("qmail-smtpd: badrcptto: ",addr.s," at ",remoteip,0);
+    err_brt();
+    return;
+  }
   if (!stralloc_cats(&rcptto,"T")) die_nomem();
   if (!stralloc_cats(&rcptto,addr.s)) die_nomem();
   if (!stralloc_0(&rcptto)) die_nomem();

(c) 2000-2016 Ward Vandewege. This patch is GPL'd.