README.st-patch http://toribio.apollinare.org/qmail (c) 2003-2007 Salvatore Toribio for this combo-patch (toribio - pusc.it) This cumulative patch for ucspi comes with NO WARRANTY, you can redistribute and modify it freely, just put a link to this page. Original ucspi from Daniel J. Bernstein could be download from: ucspi-tcp-0.88.tar.gz . TO APPLY THE PATCH Download it (ucspi.st-combo.09.patch) or: wget http://cr.yp.to/ucspi-tcp/ucspi-tcp-0.88.tar.gz wget http://toribio.apollinare.org/qmail/ucspi.st-combo.09.patch tar xzf ucspi-tcp-0.88.tar.gz -C /var/tmp cp ucspi.st-combo.09.patch /var/tmp/ cd /var/tmp patch -p0 < ucspi.st-combo.09.patch PATCHES INCLUDED rblsmtpd-nodefaultrbl.patch from Charles Cazabon (http://pyropus.ca/software/misc/rblsmtpd-nodefaultrbl.patch) ucspi-tcp-0.88.a_record.patch from Mate Wierdl (http://djbware.csi.hu/patches/ucspi-tcp-0.88.a_record.patch) ucspi-tcp-0.88.errno.patch from Mate Wierdl (http://djbware.csi.hu/patches/ucspi-tcp-0.88.errno.patch) ucspi-tcp-0.88-periplimit.7.patch from Balazs Nagy Concurrent IP connection limiter for ucspi-tcp. It is possible to run the tcpserver with the option '-s number' in order to limit the connections from the same ip. I have added a workaround to avoid a memory problem... (http://js.hu/package/ucspi-tcp/) Added option '-L' to the tcpseerver If tcpserve is invoked with this option the logs will change format to be compatibile with qmail-scanner log format (pid program: log_message). This option will also set the QSLOG environment variable, so qmail-smtpd-st (from qmail.st-combo.14.patch ) will log with the same format. ----------------- Salvatore Toribio 20070712 diff -Naur ucspi-tcp-0.88.orig/Makefile ucspi-tcp-0.88/Makefile --- ucspi-tcp-0.88.orig/Makefile 2000-03-18 15:18:42.000000000 +0000 +++ ucspi-tcp-0.88/Makefile 2007-07-11 15:43:22.000000000 +0000 @@ -753,7 +753,7 @@ alloc.h buffer.h error.h strerr.h sgetopt.h subgetopt.h pathexec.h \ socket.h uint16.h ndelay.h remoteinfo.h stralloc.h uint16.h rules.h \ stralloc.h sig.h dns.h stralloc.h iopause.h taia.h tai.h uint64.h \ -taia.h +taia.h uint32.h ./compile tcpserver.c time.a: \ diff -Naur ucspi-tcp-0.88.orig/README.st-patch ucspi-tcp-0.88/README.st-patch --- ucspi-tcp-0.88.orig/README.st-patch 1970-01-01 00:00:00.000000000 +0000 +++ ucspi-tcp-0.88/README.st-patch 2007-07-11 15:43:22.000000000 +0000 @@ -0,0 +1,69 @@ + README.st-patch + +http://toribio.apollinare.org/qmail + +(c) 2003-2007 Salvatore Toribio for this combo-patch (toribio - pusc.it) + +This cumulative patch for ucspi comes +with NO WARRANTY, you can redistribute and modify it freely, just put a +link to this /page/. + +Original ucspi from Daniel J. +Bernstein could be download from: ucspi-tcp-0.88.tar.gz +. + + + TO APPLY THE PATCH + +Download it (ucspi.st-combo.09.patch) or: + +wget http://cr.yp.to/ucspi-tcp/ucspi-tcp-0.88.tar.gz +wget http://toribio.apollinare.org/qmail/ucspi.st-combo.09.patch + +tar xzf ucspi-tcp-0.88.tar.gz -C /var/tmp +cp ucspi.st-combo.09.patch /var/tmp/ + +cd /var/tmp + +patch -p0 < ucspi.st-combo.09.patch + +You will get this output: + +patching file ucspi-tcp-0.88/Makefile +patching file ucspi-tcp-0.88/README.st-patch +patching file ucspi-tcp-0.88/error.h +patching file ucspi-tcp-0.88/rblsmtpd.c +patching file ucspi-tcp-0.88/tcpserver.c + + + PATCHES INCLUDED + +rblsmtpd-nodefaultrbl.patch from Charles Cazabon +(http://pyropus.ca/software/misc/rblsmtpd-nodefaultrbl.patch) + +ucspi-tcp-0.88.a_record.patch from Mate Wierdl +(http://djbware.csi.hu/patches/ucspi-tcp-0.88.a_record.patch) + +ucspi-tcp-0.88.errno.patch from Mate Wierdl +(http://djbware.csi.hu/patches/ucspi-tcp-0.88.errno.patch) + +ucspi-tcp-0.88-periplimit.7.patch from Balazs Nagy +Concurrent IP connection limiter for ucspi-tcp. +It is possible to run the tcpserver with the option '-s number' in +order to limit the connections from the same ip. +I have added a workaround to avoid a memory problem... +(http://js.hu/package/ucspi-tcp/) + +Added option '-L' to the tcpseerver +If tcpserve is invoked with this option the logs will change format +to be compatibile with qmail-scanner log format +(pid program: log_message). +This option will also set the QSLOG environment variable, so +qmail-smtpd-st (from qmail.st-combo.14.patch +) will +log with the same format. + + +----------------- +Salvatore Toribio +20070712 diff -Naur ucspi-tcp-0.88.orig/error.h ucspi-tcp-0.88/error.h --- ucspi-tcp-0.88.orig/error.h 2000-03-18 15:18:42.000000000 +0000 +++ ucspi-tcp-0.88/error.h 2007-07-11 15:43:22.000000000 +0000 @@ -1,7 +1,7 @@ #ifndef ERROR_H #define ERROR_H -extern int errno; +#include extern int error_intr; extern int error_nomem; diff -Naur ucspi-tcp-0.88.orig/rblsmtpd.c ucspi-tcp-0.88/rblsmtpd.c --- ucspi-tcp-0.88.orig/rblsmtpd.c 2000-03-18 15:18:42.000000000 +0000 +++ ucspi-tcp-0.88/rblsmtpd.c 2007-07-11 15:43:22.000000000 +0000 @@ -60,16 +60,54 @@ void rbl(char *base) { + int i; + char *altreply = 0; if (decision) return; if (!stralloc_copy(&tmp,&ip_reverse)) nomem(); + i = str_chr(base, ':'); + if (base[i]) { + base[i] = 0; + altreply = base+i+1; + } if (!stralloc_cats(&tmp,base)) nomem(); - if (dns_txt(&text,&tmp) == -1) { - flagmustnotbounce = 1; - if (flagfailclosed) { - if (!stralloc_copys(&text,"temporary RBL lookup error")) nomem(); - decision = 2; + if (altreply) { + if (dns_ip4(&text,&tmp) == -1) { + flagmustnotbounce = 1; + if (flagfailclosed) { + if (!stralloc_copys(&text,"temporary RBL lookup error")) nomem(); + decision = 2; + } + return; + } + if (text.len) { + if(!stralloc_copys(&text, "")) nomem(); + while(*altreply) { + char *x; + i = str_chr(altreply, '%'); + if(!stralloc_catb(&text, altreply, i)) nomem(); + if(altreply[i] && + altreply[i+1]=='I' && + altreply[i+2]=='P' && + altreply[i+3]=='%') { + if(!stralloc_catb(&text, ip_env, str_len(ip_env))) nomem(); + altreply+=i+4; + } else if(altreply[i]) { + if(!stralloc_cats(&text, "%")) nomem(); + altreply+=i+1; + } else { + altreply+=i; + } + } + } + } else { + if (dns_txt(&text,&tmp) == -1) { + flagmustnotbounce = 1; + if (flagfailclosed) { + if (!stralloc_copys(&text,"temporary RBL lookup error")) nomem(); + decision = 2; + } + return; } - return; } if (text.len) if (flagrblbounce) @@ -118,6 +156,12 @@ void rblsmtpd(void) { int i; + char *x; + unsigned long u; + unsigned int qslog = 0; + + x = env_get("QSLOG"); + if (x) { scan_ulong(x,&u); qslog = u; } if (flagmustnotbounce || (decision == 2)) { if (!stralloc_copys(&message,"451 ")) nomem(); @@ -131,10 +175,16 @@ if ((message.s[i] < 32) || (message.s[i] > 126)) message.s[i] = '?'; - buffer_puts(buffer_2,"rblsmtpd: "); - buffer_puts(buffer_2,ip_env); - buffer_puts(buffer_2," pid "); - buffer_put(buffer_2,strnum,fmt_ulong(strnum,getpid())); + if (qslog) { + buffer_put(buffer_2,strnum,fmt_ulong(strnum,getpid())); + buffer_puts(buffer_2," rblsmtpd: ip "); + buffer_puts(buffer_2,ip_env); + } else { + buffer_puts(buffer_2,"rblsmtpd: "); + buffer_puts(buffer_2,ip_env); + buffer_puts(buffer_2," pid "); + buffer_put(buffer_2,strnum,fmt_ulong(strnum,getpid())); + } buffer_puts(buffer_2,": "); buffer_put(buffer_2,message.s,message.len); buffer_puts(buffer_2,"\n"); @@ -155,7 +205,6 @@ main(int argc,char **argv,char **envp) { - int flagwantdefaultrbl = 1; char *x; int opt; @@ -182,7 +231,7 @@ case 'c': flagfailclosed = 1; break; case 'C': flagfailclosed = 0; break; case 't': scan_ulong(optarg,&timeout); break; - case 'r': rbl(optarg); flagwantdefaultrbl = 0; break; + case 'r': rbl(optarg); break; case 'a': antirbl(optarg); break; default: usage(); } @@ -190,7 +239,6 @@ argv += optind; if (!*argv) usage(); - if (flagwantdefaultrbl) rbl("rbl.maps.vix.com"); if (decision >= 2) rblsmtpd(); pathexec_run(*argv,argv,envp); diff -Naur ucspi-tcp-0.88.orig/tcpserver.c ucspi-tcp-0.88/tcpserver.c --- ucspi-tcp-0.88.orig/tcpserver.c 2000-03-18 15:18:42.000000000 +0000 +++ ucspi-tcp-0.88/tcpserver.c 2007-07-11 15:43:22.000000000 +0000 @@ -2,6 +2,7 @@ #include #include #include "uint16.h" +#include "uint32.h" #include "str.h" #include "byte.h" #include "fmt.h" @@ -35,6 +36,7 @@ int flagremoteinfo = 1; int flagremotehost = 1; int flagparanoid = 0; +int qslog = 0; unsigned long timeout = 26; static stralloc tcpremoteinfo; @@ -141,7 +143,11 @@ if (verbosity >= 2) { strnum[fmt_ulong(strnum,getpid())] = 0; - strerr_warn4("tcpserver: pid ",strnum," from ",remoteipstr,0); + if (qslog) { + strerr_warn3(strnum," tcpserver: from ",remoteipstr,0); + } else{ + strerr_warn4("tcpserver: pid ",strnum," from ",remoteipstr,0); + } } if (flagkillopts) @@ -213,9 +219,15 @@ if (verbosity >= 2) { strnum[fmt_ulong(strnum,getpid())] = 0; - if (!stralloc_copys(&tmp,"tcpserver: ")) drop_nomem(); - safecats(flagdeny ? "deny" : "ok"); - cats(" "); safecats(strnum); + if (qslog) { + if (!stralloc_copys(&tmp,strnum)) drop_nomem(); + cats(" tcpserver: "); + safecats(flagdeny ? "deny" : "ok"); + } else { + if (!stralloc_copys(&tmp,"tcpserver: ")) drop_nomem(); + safecats(flagdeny ? "deny" : "ok"); + cats(" "); safecats(strnum); + } cats(" "); if (localhost) safecats(localhost); cats(":"); safecats(localipstr); cats(":"); safecats(localportstr); @@ -240,8 +252,9 @@ { strerr_warn1("\ tcpserver: usage: tcpserver \ -[ -1UXpPhHrRoOdDqQv ] \ +[ -1UXpPhHrRoOdDqQvL ] \ [ -c limit ] \ +[ -s perip limit ] \ [ -x rules.cdb ] \ [ -B banner ] \ [ -g gid ] \ @@ -254,19 +267,39 @@ } unsigned long limit = 40; +unsigned long periplimit = 0; unsigned long numchildren = 0; +typedef struct +{ + pid_t pid; + int offset; +} connections; + +typedef struct +{ + uint32 ipaddr; + unsigned long num; +} ipchildren; + +connections *children; +ipchildren *numipchildren; + int flag1 = 0; unsigned long backlog = 20; unsigned long uid = 0; unsigned long gid = 0; -void printstatus(void) +void printstatus(char *s) { if (verbosity < 2) return; strnum[fmt_ulong(strnum,numchildren)] = 0; - strnum2[fmt_ulong(strnum2,limit)] = 0; - strerr_warn4("tcpserver: status: ",strnum,"/",strnum2,0); + strnum2[fmt_ulong(strnum2,limit-1)] = 0; + if (qslog) { + strerr_warn5("tcpserver-st09: ",s,strnum,"/",strnum2,0); + } else { + strerr_warn4("tcpserver: status: ",strnum,"/",strnum2,0); + } } void sigterm() @@ -278,14 +311,25 @@ { int wstat; int pid; + int i; while ((pid = wait_nohang(&wstat)) > 0) { if (verbosity >= 2) { strnum[fmt_ulong(strnum,pid)] = 0; strnum2[fmt_ulong(strnum2,wstat)] = 0; - strerr_warn4("tcpserver: end ",strnum," status ",strnum2,0); + if (qslog) { + strerr_warn3(strnum," tcpserver: end status ",strnum2,0); + } else { + strerr_warn4("tcpserver: end ",strnum," status ",strnum2,0); + } } - if (numchildren) --numchildren; printstatus(); + if (numchildren) --numchildren; printstatus("status-close: "); + for (i=0;ifd = -1; - + + if (!periplimit) + periplimit = limit; + if (limit= limit) sig_pause(); + uint32 ipaddr; + pid_t pid; + int i; + int lastempty = 0; + int freechild = 0; + ipchildren *ipcount; + + while (numchildren >= limit - 1) sig_pause(); sig_unblock(sig_child); t = socket_accept4(s,remoteip,&remoteport); sig_block(sig_child); if (t == -1) continue; - ++numchildren; printstatus(); + + for (i=0;iipaddr || !ipcount->num) + lastempty = i; + else if (ipcount->ipaddr == ipaddr) { + ++ipcount->num; + break; + } + } + if (i == limit) { + if (lastempty) { + i = lastempty; + ipcount = &numipchildren[i]; + ipcount->ipaddr = ipaddr; + ipcount->num = 1; + } else { + /* never reached */ + close(t); + strerr_die2x(111,DROP,"internal problem"); + } + } + if (ipcount->num > periplimit) { + remoteipstr[ip4_fmt(remoteipstr,remoteip)] = 0; + strerr_warn3(DROP, "per ip limit reached for ", remoteipstr, 0); + close(t); + --ipcount->num; + continue; + } + ++numchildren; printstatus("status-open: "); - switch(fork()) { + switch(pid = fork()) { case 0: close(s); doit(t); @@ -419,7 +523,11 @@ strerr_die4sys(111,DROP,"unable to run ",*argv,": "); case -1: strerr_warn2(DROP,"unable to fork: ",&strerr_sys); - --numchildren; printstatus(); + --numchildren; printstatus("status-close: "); + break; + default: + children[freechild].pid = pid; + children[freechild].offset = i; } close(t); }