03-Jun-2005 qmail notes on cdb and the moresmtproutes patch I wanted to be able to use smtproutes-like functionality on a per-user basis. This qmail setup scans e-mail & forwards it into the 'main' mail server. It has an entry in /var/qmail/control/smtproutes like "ourdomain.com:192.168.7.6". So all e-mail for anybody @ ourdomain.com gets sent along to 192.168.7.6. But I have some users who I need to send along to a different address, and would like per-user smtproutes-like functionality. For instance, I'd like all mail for 'clyde@ourdomain.com' to go to 192.168.7.90 instead. Googling, I found this page with a patch: http://marc.theaimsgroup.com/?l=qmail&m=108986091011169&w=2 It has a patch (listed at the end) for qmail which allows for a moresmtproutes.cdb file which can define per-user smtproutes. I applied the patch to my netqmail-1.05 install. I had a hard time creating a cdb file. I downloaded the cdb program from Dan Bernstein's site at http://cr.yp.to/cdb.html and it built w/o any problems. But no matter what syntax I tried, I could not figure out what kind of input file cdbmake wants. I still don't know. Where is the documentation on the input file syntax requirements for cdbmake? I did find that the cdb package also installs cdbmake-12, so I tried that. Voila. Here is the file format (a plain text file) you need to create: , e.g.: joe_special@domain.com 192.168.5.16 After you have the file made, do this to create the cdb file: qmail# cdbmake-12 test_moresmtproutes.cdb moresmtproutes.tmp < moresmtproutes No errors, so I checked the new .cdb file with cdbdump: qmail# cdbdump < test_moresmtproutes.cdb +22,12:joe_special@domain.com->192.168.5.16 I then restarted qmail and it worked. Messages for my special user get sent along to his specific ip, and the rest go to the one in /var/qmail/control/smtproutes. ...Then I read the next message in the thread, which states that while the patch works, it is case sensitive, and it obviously shouldn't be. ** DISCLAIMER ** ** I am terrible at C. This works for me, but use it at your own risk. ** If the lines I added below are a huge mistake, please let me know ** via e-mail to: ape@apecity.com **************** So after some trial and error, I modified qmail-remote.c (one of the files patched by the above patch) to make it do this great per-user smtproutes business, case-insensitively. This ASSUMES that when you create your moresmtproutes.cdb file, you do it all in lower case. Go to line 334 of qmail-remote.c, which should be the start of the lookup_host function. Add three lines near the start of the function, and modify the next line so it looks like this: 334 lookup_host(char *s, int len) 335 { 336 static stralloc morerelayhost = {0}; 337 uint32 dlen; 338 stralloc abuffer = {0}; 339 if (!stralloc_copys(&abuffer,s)) return -1; 340 case_lowerb(abuffer.s,abuffer.len); 341 if (fdmoreroutes != -1 && cdb_seek(fdmoreroutes, abuffer.s, abuffer.len, &dlen) == 1) { The lines I added are #338-340. Line 341 differs from the original in that instead of reading 'abuffer.s' and 'abuffer.len' as shown above, the original has 's' and 'len' instead. Stop qmail, do 'make setup check', restart it, and you should be good to go. To test it, send an email to youruser@domain.com and YOURUSER@Domain.Com and they should both go to him. ---------------------------------------------------------- Here's the patch in case the link to it above is no more. I am not the author of this patch. The author appears to be Richard Lyons. Thanks to the author! diff -ur qmail-1.03.orig/Makefile qmail-1.03/Makefile --- qmail-1.03.orig/Makefile Mon Jun 15 20:53:16 1998 +++ qmail-1.03/Makefile Thu Jul 15 12:13:23 2004 @@ -1441,12 +1441,12 @@ load qmail-remote.o control.o constmap.o timeoutread.o timeoutwrite.o \ timeoutconn.o tcpto.o now.o dns.o ip.o ipalloc.o ipme.o quote.o \ ndelay.a case.a sig.a open.a lock.a seek.a getln.a stralloc.a alloc.a \ -substdio.a error.a str.a fs.a auto_qmail.o dns.lib socket.lib +substdio.a error.a str.a fs.a auto_qmail.o cdb.a dns.lib socket.lib ./load qmail-remote control.o constmap.o timeoutread.o \ timeoutwrite.o timeoutconn.o tcpto.o now.o dns.o ip.o \ ipalloc.o ipme.o quote.o ndelay.a case.a sig.a open.a \ lock.a seek.a getln.a stralloc.a alloc.a substdio.a error.a \ - str.a fs.a auto_qmail.o `cat dns.lib` `cat socket.lib` + str.a fs.a auto_qmail.o cdb.a `cat dns.lib` `cat socket.lib` qmail-remote.0: \ qmail-remote.8 @@ -1457,7 +1457,7 @@ subfd.h substdio.h scan.h case.h error.h auto_qmail.h control.h dns.h \ alloc.h quote.h ip.h ipalloc.h ip.h gen_alloc.h ipme.h ip.h ipalloc.h \ gen_alloc.h gen_allocdefs.h str.h now.h datetime.h exit.h constmap.h \ -tcpto.h readwrite.h timeoutconn.h timeoutread.h timeoutwrite.h +tcpto.h readwrite.h timeoutconn.h timeoutread.h timeoutwrite.h cdb.h open.h ./compile qmail-remote.c qmail-rspawn: \ diff -ur qmail-1.03.orig/qmail-remote.c qmail-1.03/qmail-remote.c --- qmail-1.03.orig/qmail-remote.c Mon Jun 15 20:53:16 1998 +++ qmail-1.03/qmail-remote.c Thu Jul 15 12:38:33 2004 @@ -28,6 +28,8 @@ #include "timeoutconn.h" #include "timeoutread.h" #include "timeoutwrite.h" +#include "cdb.h" +#include "open.h" #define HUGESMTPTEXT 5000 @@ -43,6 +45,7 @@ struct constmap maproutes; stralloc host = {0}; stralloc sender = {0}; +int fdmoreroutes; saa reciplist = {0}; @@ -324,6 +327,23 @@ case 1: if (!constmap_init(&maproutes,routes.s,routes.len,1)) temp_nomem(); break; } + fdmoreroutes = open_read("control/moresmtproutes.cdb"); +} + +char * +lookup_host(char *s, int len) +{ + static stralloc morerelayhost = {0}; + uint32 dlen; + + if (fdmoreroutes != -1 && cdb_seek(fdmoreroutes, s, len, &dlen) == 1) { + if (!stralloc_ready(&morerelayhost, (unsigned int)(dlen + 1))) temp_nomem(); + morerelayhost.len = dlen; + if (cdb_bread(fdmoreroutes, morerelayhost.s, morerelayhost.len) == -1) temp_control(); + if (!stralloc_0(&morerelayhost)) temp_nomem(); + return morerelayhost.s; + } + return 0; } void main(argc,argv) @@ -347,11 +367,14 @@ if (!stralloc_copys(&host,argv[1])) temp_nomem(); - relayhost = 0; - for (i = 0;i <= host.len;++i) - if ((i == 0) || (i == host.len) || (host.s[i] == '.')) + relayhost = lookup_host(argv[3], str_len(argv[3])); + for (i = 0;!relayhost && i <= host.len;++i) + if ((i == 0) || (i == host.len) || (host.s[i] == '.')) { if (relayhost = constmap(&maproutes,host.s + i,host.len - i)) break; + if (relayhost = lookup_host(host.s + i, host.len - i)) + break; + } if (relayhost && !*relayhost) relayhost = 0; if (relayhost) {