--- ../ucspi-tcp-0.88.orig/00README.isp.patch 1969-12-31 19:00:00.000000000 -0500 +++ 00README.isp.patch 2006-12-23 00:04:41.722776000 -0500 @@ -0,0 +1,47 @@ +This is the ucspi-tcp-0.88.isp-2006122301.patch. This patch includes +the following patch(es): + rblsmtpd-nodefaultrbl.patch + rblsmtpd-nonrecursive-v4.patch + +and a more lightweight version of the IP limiting patch: + ucspi-tcp-0.88-periplimit.7.patch + +When a host goes over it's MAXCONNIP or MAXCONNC, RBLSMTPD is set with +DROPMSG. This requires you to have rblsmtpd before qmail-smtpd in +your /service/qmail-smtpd/run. + +This patch adds the following functionality: +tcpserver: + * Per IP limiting via MAXCONNIP environment variable + * Per "ClassC" limiting via MAXCONNC environment variable + + * If either MAXCONNIP or MAXCONNC is reached, RBLSMTPD is set with + the contents of the DROPMSG environment variable. DROPMSG defaults + to "Please try later." (which rblsmtpd changes into + "451 Please try later.". + +rblsmtpd: + * Removes the default rbl query to rbl.maps.vix.com. + * Terminates a socket after printing RBLSMTPD, if RBLSMTPD begins with + a "+" character. + * adds a "-R base:dns_server_ip" option to send non-recursive DNS + queries directly to the RBL content server + +to patch, simply: + wget http://cr.yp.to/ucspi-tcp/ucspi-tcp-0.88.tar.gz + tar -zxvf ucspi-tcp-0.88.tar.gz + patch -d ucspi-tcp-0.88/ < ucspi-tcp-0.88.isp.patch + +then just follow djb's installation instructions + +The latest version of this patch is available at: +http://jeremy.kister.net./code/ucspi-tcp-0.88.isp.patch + +Example documentation for MAXCONNIP and MAXCONNC can be found at the +original author's website at: http://linux.voyager.hr/ucspi-tcp/ + +-- + +Jeremy Kister +http://jeremy.kister.net./ + --- ../ucspi-tcp-0.88.orig/dns.h 2000-03-18 10:18:42.000000000 -0500 +++ dns.h 2006-12-23 00:07:32.623657000 -0500 @@ -64,6 +64,7 @@ extern int dns_resolvconfip(char *); extern int dns_resolve(char *,char *); +extern int dns_query(char *,char *,char *); extern struct dns_transmit dns_resolve_tx; extern int dns_ip4_packet(stralloc *,char *,unsigned int); @@ -74,6 +75,7 @@ extern int dns_name4(stralloc *,char *); extern int dns_txt_packet(stralloc *,char *,unsigned int); extern int dns_txt(stralloc *,stralloc *); +extern int dns_txt_q(stralloc *,stralloc *,char *); extern int dns_mx_packet(stralloc *,char *,unsigned int); extern int dns_mx(stralloc *,stralloc *); --- ../ucspi-tcp-0.88.orig/dns_resolve.c 2000-03-18 10:18:42.000000000 -0500 +++ dns_resolve.c 2006-12-23 00:08:05.453838000 -0500 @@ -27,3 +27,24 @@ if (r == 1) return 0; } } + +int dns_query(char *q,char qtype[2],char *servers) +{ + struct taia stamp; + struct taia deadline; + iopause_fd x[1]; + int r; + + if (dns_transmit_start(&dns_resolve_tx,servers,0,q,qtype,"\0\0\0\0") == -1) return -1; + + for (;;) { + taia_now(&stamp); + taia_uint(&deadline,120); + taia_add(&deadline,&deadline,&stamp); + dns_transmit_io(&dns_resolve_tx,x,&deadline); + iopause(x,1,&deadline,&stamp); + r = dns_transmit_get(&dns_resolve_tx,x,&stamp); + if (r == -1) return -1; + if (r == 1) return 0; + } +} --- ../ucspi-tcp-0.88.orig/dns_txt.c 2000-03-18 10:18:42.000000000 -0500 +++ dns_txt.c 2006-12-23 00:09:07.974175000 -0500 @@ -47,6 +47,7 @@ } static char *q = 0; +static char *q2 = 0; int dns_txt(stralloc *out,stralloc *fqdn) { @@ -57,3 +58,15 @@ dns_domain_free(&q); return 0; } + +int dns_txt_q(stralloc *out,stralloc *fqdn, char *servers) +{ + int i; + + if (!dns_domain_fromdot(&q2,fqdn->s,fqdn->len)) return -1; + if (dns_query(q2,DNS_T_TXT,servers) == -1) return -1; + if (dns_txt_packet(out,dns_resolve_tx.packet,dns_resolve_tx.packetlen) == -1) return -1; + dns_transmit_free(&dns_resolve_tx); + dns_domain_free(&q2); + return 0; +} --- ../ucspi-tcp-0.88.orig/error.h 2000-03-18 10:18:42.000000000 -0500 +++ error.h 2006-12-23 00:09:29.784303000 -0500 @@ -1,7 +1,7 @@ #ifndef ERROR_H #define ERROR_H -extern int errno; +#include extern int error_intr; extern int error_nomem; --- ../ucspi-tcp-0.88.orig/rblsmtpd.c 2000-03-18 10:18:42.000000000 -0500 +++ rblsmtpd.c 2006-12-23 00:13:41.705562000 -0500 @@ -22,7 +22,7 @@ } void usage(void) { - strerr_die1x(100,"rblsmtpd: usage: rblsmtpd [ -b ] [ -R ] [ -t timeout ] [ -r base ] [ -a base ] smtpd [ arg ... ]"); + strerr_die1x(100,"rblsmtpd: usage: rblsmtpd [ -b ] [ -t timeout ] [ -r base ] [ -R base:ip ] [ -a base ] smtpd [ arg ... ]"); } char *ip_env; @@ -78,6 +78,47 @@ decision = 2; } +void rbl_ip(char *base_and_ip) +{ + stralloc base = {0}; + char servers[64]; + int i = -1; + int j; + int k; + + if (decision) return; + + /* base_and_ip is base:dotted_quad */ + if (!stralloc_copys(&base,base_and_ip)) nomem(); + for (j=0;j= 2) rblsmtpd(); pathexec_run(*argv,argv,envp); --- ../ucspi-tcp-0.88.orig/tcpserver.c 2000-03-18 10:18:42.000000000 -0500 +++ tcpserver.c 2006-12-23 00:01:32.871552000 -0500 @@ -59,11 +59,19 @@ static stralloc tmp; static stralloc fqdn; static stralloc addresses; +static stralloc dropmsg_buf; char bspace[16]; buffer b; +typedef struct +{ + char ip[4]; + pid_t pid; +} baby; + +baby *child; /* ---------------------------- child */ @@ -72,6 +80,10 @@ int flagdeny = 0; int flagallownorules = 0; char *fnrules = 0; +unsigned long maxload = 0; +long maxconnip = -1; +long maxconnc = -1; +char *dropmsg = "+Please try later."; void drop_nomem(void) { @@ -110,6 +122,8 @@ strerr_die4sys(111,DROP,"unable to read ",fnrules,": "); } +unsigned long limit = 40; + void found(char *data,unsigned int datalen) { unsigned int next0; @@ -125,6 +139,13 @@ if (data[1 + split] == '=') { data[1 + split] = 0; env(data + 1,data + 1 + split + 1); + if (str_diff(data+1, "MAXCONNIP") == 0) scan_ulong(data+1+split+1,&maxconnip); + if (str_diff(data+1, "MAXCONNC") == 0) scan_ulong(data+1+split+1,&maxconnc); + if (str_diff(data+1, "DROPMSG") == 0) { + if (!stralloc_copys(&dropmsg_buf,data+1+split+1)) drop_nomem(); + if (!stralloc_0(&dropmsg_buf)) drop_nomem(); + dropmsg = dropmsg_buf.s; + } } break; } @@ -211,6 +232,21 @@ } } + if (!flagdeny && (maxconnip != -1 || maxconnc != -1)) { + unsigned long u; + long c1=0, cc=0; + for (u=0; u < limit; u++) if (child[u].pid != 0) { + if ((child[u].ip[0] == remoteip[0]) && + (child[u].ip[1] == remoteip[1]) && + (child[u].ip[2] == remoteip[2]) ) { + cc++; + if (child[u].ip[3] == remoteip[3]) c1++; + } + } + if (maxconnc != -1 && (cc >= maxconnc)) flagdeny = 4; + if (maxconnip != -1 && (c1 >= maxconnip)) flagdeny = 3; + } + if (verbosity >= 2) { strnum[fmt_ulong(strnum,getpid())] = 0; if (!stralloc_copys(&tmp,"tcpserver: ")) drop_nomem(); @@ -223,11 +259,25 @@ cats(":"); safecats(remoteipstr); cats(":"); if (flagremoteinfo) safecats(tcpremoteinfo.s); cats(":"); safecats(remoteportstr); + if (flagdeny == 3) { + char maxconstr[FMT_ULONG]; + maxconstr[fmt_ulong(maxconstr,maxconnip)] = 0; + cats(" "); safecats ("MAXCONNIP"); cats(":"); safecats(maxconstr); + } + if (flagdeny == 4) { + char maxconstr[FMT_ULONG]; + maxconstr[fmt_ulong(maxconstr,maxconnc)] = 0; + cats(" "); safecats ("MAXCONNC"); cats(":"); safecats(maxconstr); + } cats("\n"); buffer_putflush(buffer_2,tmp.s,tmp.len); } - if (flagdeny) _exit(100); + if (flagdeny) { + if (*dropmsg) { + env("RBLSMTPD",dropmsg); + } + } } @@ -253,7 +303,6 @@ _exit(100); } -unsigned long limit = 40; unsigned long numchildren = 0; int flag1 = 0; @@ -278,6 +327,7 @@ { int wstat; int pid; + unsigned long u; while ((pid = wait_nohang(&wstat)) > 0) { if (verbosity >= 2) { @@ -286,6 +336,8 @@ strerr_warn4("tcpserver: end ",strnum," status ",strnum2,0); } if (numchildren) --numchildren; printstatus(); + for (u=0; u < limit; u++) if (child[u].pid == pid) { child[u].pid = 0; break; } + if (u == limit) strerr_die1x(111,"tcpserver: ERROR: dead child not found?!"); /* never happens */ } } @@ -299,6 +351,7 @@ unsigned long u; int s; int t; + pid_t pid; while ((opt = getopt(argc,argv,"dDvqQhHrR1UXx:t:u:g:l:b:B:c:pPoO")) != opteof) switch(opt) { @@ -332,6 +385,10 @@ argc -= optind; argv += optind; + x = env_get("MAXCONNIP"); if (x) scan_ulong(x,&maxconnip); + x = env_get("MAXCONNC"); if (x) scan_ulong(x,&maxconnc); + x = env_get("DROPMSG"); if (x) dropmsg = x; + if (!verbosity) buffer_2->fd = -1; @@ -352,6 +409,10 @@ } if (!*argv) usage(); + + child = calloc(sizeof(baby),limit); + if (!child) + strerr_die2x(111,FATAL,"out of memory for MAXCONNIP tracking"); sig_block(sig_child); sig_catch(sig_child,sigchld); @@ -405,7 +466,7 @@ if (t == -1) continue; ++numchildren; printstatus(); - switch(fork()) { + switch(pid=fork()) { case 0: close(s); doit(t); @@ -420,6 +481,10 @@ case -1: strerr_warn2(DROP,"unable to fork: ",&strerr_sys); --numchildren; printstatus(); + break; + default: + for (u=0; u < limit; u++) if (child[u].pid == 0) { byte_copy(child[u].ip,4,remoteip); child[u].pid = pid; break; } + if (u == limit) strerr_die1x(111,"tcpserver: ERROR: no empty space for new child?!"); /* never happens */ } close(t); }