Go to:
Gentoo Home
Documentation
Forums
Lists
Bugs
Planet
Store
Wiki
Get Gentoo!
Gentoo's Bugzilla – Attachment 63174 Details for
Bug 98708
Unable to limit per-ip connections with tcpserver
Home
|
New
–
[Ex]
|
Browse
|
Search
|
Privacy Policy
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
The Limits Patch for tcpserver
tcpserver-limits-2005-01-30.diff (text/plain), 12.68 KB, created by
Fred Dinkler
on 2005-07-11 14:07:38 UTC
(
hide
)
Description:
The Limits Patch for tcpserver
Filename:
MIME Type:
Creator:
Fred Dinkler
Created:
2005-07-11 14:07:38 UTC
Size:
12.68 KB
patch
obsolete
>diff -purN ucspi-tcp-0.88.org/README.tcpserver-limits-patch ucspi-tcp-0.88.my/README.tcpserver-limits-patch >--- ucspi-tcp-0.88.org/README.tcpserver-limits-patch 1970-01-01 01:00:00.000000000 +0100 >+++ ucspi-tcp-0.88.my/README.tcpserver-limits-patch 2005-01-30 18:26:14.000000000 +0100 >@@ -0,0 +1,135 @@ >+20050130 reinstated /proc/loadavg support for those compiling on Linux >+with dietlibc (see #define NO_GETLOADAVG at top of tcpserver.c). >+Also, we now compile on 64bit platforms (we avoid including unistd.h if >+using getloadavg(3), so we don't conflict with readwrite.h header file) >+Needed if your compile was breaking with: >+readwrite.h:4: error: syntax error before "read" >+readwrite.h:4: warning: data definition has no type or storage class >+SUMMARY: If 20040725 worked for you, there is no reason to upgrade >+(no new features of bugfixes) >+ >+20040725 adds a sleep(1) before terminating (to prevent too high load from >+many rapid fork()/exit() calls. It also changes the method for checking >+system load to getloadavg(3) instead of parsing /proc/loadavg, therefore >+making it working on *BSD and other non-Linux systems in addition to Linux. >+It also adds DIEMSG="xxx" support. >+ >+20040327 fixes a bug in 20040124 related to MAXLOAD (it would not work >+correctly when load was higher than 10.00) >+ >+ >+This patch (20040725) makes tcpserver from DJB's ucspi-tcp-0.88 package (see >+http://cr.yp.to/ucspi-tcp.html) to modify its behavior if some environment >+variables are present. >+ >+The variables can be preset before starting tcpserver (thus acting as >+default for all connections), or, if you use 'tcpserver -x xxx.cdb', they >+can be set (or overridden) from xxx.cdb. If none of the variables are set, >+tcpserver behaves same as non patched version (except for negligible >+performance loss). Any or all variables can be set, as soon as first limit >+is reached the connection is dropped. I'd recommend using .cdb files >+exclusively though, as you can then modify configuration without killing >+tcpserver. >+ >+The variables are: >+ >+(1) MAXLOAD >+ maximum 1-minute load average * 100. For example, if you have line >+ :allow,MAXLOAD="350" >+ in your rules file from which you created .cdb, the connection will be >+ accepted only if load average is below 3.50 >+ For this variable to have effect, you have to have working getloadavg(3) >+ (most modern UN*Xoids have, including Linux and FreeBSD) >+ Otherwise, you have to uncomment #define NO_GETLOADAVG in tcpserver.c >+ and have readable '/proc/loadavg' with linux-2.4.x/2.6.x syntax (see >+ the source -- this is needed if you're compiling with dietlibc >+ or such) >+ >+(2) MAXCONNIP >+ maximum connections from one IP address. tcpserver's -c flag defines >+ maximum number of allowed connections, but it can be abused if >+ just one host goes wild and eats all the connections - no other host >+ would be able to connect then. If you created your .cdb with: >+ :allow,MAXCONNIP="5" >+ and run tcpserver -c 50, then each IP address would be able to have at >+ most 5 concurrent connections, while there still could connect 50 >+ clients total >+ >+(3) MAXCONNC >+ >+ maximum connections from whole C-class (256 addresses). Extension of >+ MAXCONNIP, as sometimes the problematic client has a whole farm of >+ client machines with different IP addresses instead of just one IP >+ address, and they all try to connect. It might have been more useful to >+ be able to specify CIDR block than C-class, but I've decided to KISS. >+ >+ for example tcpserver -c 200, and .cdb with: >+ :allow,MAXCONNC="15" >+ will allow at most 15 host from any x.y.z.0/24 address block, while >+ still allowing up to 200 total connections. >+ >+(4) DIEMSG >+ >+ if set and one of the above limits is exceeded, this is the message >+ to be sent to client (CRLF is always added to the text) before terminating >+ connection. If unset, the connection simply terminates (after 1 sec delay) >+ if limit is exceeded. >+ >+ For example: >+ DIEMSG="421 example.com Service temporarily not available, closing >+ transmission channel" >+ >+Notes: >+ >+- if a connection is dropped due to some of those variables set, it will be >+ flagged (if you run tcpserver -v) with "LOAD:", "MAXCONNIP:" or >+ "MAXCONNC:" at the end of the "tcpserver: deny" line. If that bothers you >+ (eg. you have a strict log parsers), don't apply that chunk of the patch. >+ >+- the idea for this patch came from my previous experience with xinetd, and >+ need to limit incoming bursts of virus/spam SMTP connections, since I was >+ running qmail-scanner to scan incoming and outgoing messages for viruses >+ and spam. >+ >+When you make changes, please check that they work as expected. >+ >+Examples (for tcprules created .cdb) >+(a) 192.168.:allow,MAXLOAD="1000" >+ :allow,MAXCONNIP="3" >+ >+ this would allow any connection from your local LAN (192.168.*.* >+ addresses) if system load is less than 10.00. non-LAN connections would >+ be accepted only if clients from that IP address have not already opened >+ more than 2 connections (as your connection would be last allowed -- 3rd) >+ >+(b) 192.168.:allow >+ 5.6.7.8:allow,MAXCONNIP="3" >+ 1.2.:allow,MAXLOAD="500",MAXCONNIP="1",MAXCONNC="5" >+ :allow,MAXLOAD="1000",MAXCONNIP="3",DIEMSG="421 example.com unavailable" >+ >+ if client connects from 192.168.*.* (ex: your LAN), it is allowed. >+ if it connects from 5.6.7.8 (ex: little abusive customer of yours), >+ it is allowed unless there are already 3active connections from 5.6.7.8 >+ to this service >+ if it connects from 1.2.*.* (ex: some problematic networks which caused >+ you grief in the past) it will connect only if load is less than 5.0, >+ there is less than 5 active connections from whole C class >+ (1.2.*.0/24), and if that specific IP address does not already have >+ connection open. >+ in all other cases, the client will be permitted to connect if load is >+ less than 10.00 and client has 2 or less connections open. If load is >+ higher than 10.00 or there are 3 or more connections open from this >+ client, the message "421 example.com unavailable" will be returned to >+ the client and connection terminated. >+ >+ >+Any bugs introduced are my own, do not bother DJB with them. >+If you find any, or have neat ideas, or better documentation, or whatever, >+contact me. >+ >+the latest version of the patch can be found at: >+http://linux.voyager.hr/ucspi-tcp/ >+ >+Enjoy, >+Matija Nalis, >+mnalis-tcpserver _at_ voyager.hr >diff -purN ucspi-tcp-0.88.org/tcpserver.c ucspi-tcp-0.88.my/tcpserver.c >--- ucspi-tcp-0.88.org/tcpserver.c 2000-03-18 16:18:42.000000000 +0100 >+++ ucspi-tcp-0.88.my/tcpserver.c 2005-01-30 18:18:04.000000000 +0100 >@@ -1,6 +1,14 @@ >+#ifdef __dietlibc__ >+#define NO_GETLOADAVG >+#endif >+ > #include <sys/types.h> > #include <sys/param.h> > #include <netdb.h> >+#include <stdlib.h> >+#ifdef NO_GETLOADAVG >+#include <unistd.h> >+#endif > #include "uint16.h" > #include "str.h" > #include "byte.h" >@@ -64,6 +72,13 @@ char bspace[16]; > buffer b; > > >+typedef struct >+{ >+ char ip[4]; >+ pid_t pid; >+} baby; >+ >+baby *child; > > /* ---------------------------- child */ > >@@ -72,6 +87,10 @@ buffer b; > int flagdeny = 0; > int flagallownorules = 0; > char *fnrules = 0; >+unsigned long maxload = 0; >+unsigned long maxconnip = 0; >+unsigned long maxconnc = 0; >+char *diemsg = ""; > > void drop_nomem(void) > { >@@ -110,6 +129,8 @@ void drop_rules(void) > strerr_die4sys(111,DROP,"unable to read ",fnrules,": "); > } > >+unsigned long limit = 40; >+ > void found(char *data,unsigned int datalen) > { > unsigned int next0; >@@ -125,6 +146,10 @@ void found(char *data,unsigned int datal > if (data[1 + split] == '=') { > data[1 + split] = 0; > env(data + 1,data + 1 + split + 1); >+ if (str_diff(data+1, "MAXLOAD") == 0) scan_ulong(data+1+split+1,&maxload); >+ 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, "DIEMSG") == 0) diemsg = data+1+split+1; > } > break; > } >@@ -136,6 +161,7 @@ void found(char *data,unsigned int datal > void doit(int t) > { > int j; >+ unsigned long curload; > > remoteipstr[ip4_fmt(remoteipstr,remoteip)] = 0; > >@@ -211,6 +237,51 @@ void doit(int t) > } > } > >+ if (maxload) { >+#ifdef NO_GETLOADAVG >+ int lret; >+ int i; >+ unsigned long u1, u2; >+ char *s; >+ static stralloc loadavg_data = {0}; >+ >+ lret = openreadclose("/proc/loadavg", &loadavg_data, 10); >+ if (lret != -1) { >+ /* /proc/loadavg format is: >+ 13.08 3.04 1.00 34/170 14190 */ >+ s = loadavg_data.s; >+ i = scan_ulong (s, &u1); s+=i; >+ if ((i>0) && (i<5) && (*s == '.')) { /* load should be < 10000 */ >+ i = scan_ulong (s+1,&u2); >+ if (i==2) { /* we require two decimal places */ >+ curload = u1 * 100 + u2; >+ if (curload > maxload) flagdeny = 2; >+ } >+ } >+ } >+#else >+ double result; >+ if (getloadavg(&result, 1) == 1) { >+ curload = result * 100; >+ if (curload > maxload) flagdeny = 2; >+ } >+#endif >+ } >+ >+ if (!flagdeny && (maxconnip || maxconnc)) { >+ unsigned long u, 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 && (cc >= maxconnc)) flagdeny = 4; >+ if (maxconnip && (c1 >= maxconnip)) flagdeny = 3; >+ } >+ > if (verbosity >= 2) { > strnum[fmt_ulong(strnum,getpid())] = 0; > if (!stralloc_copys(&tmp,"tcpserver: ")) drop_nomem(); >@@ -223,11 +294,35 @@ void doit(int t) > cats(":"); safecats(remoteipstr); > cats(":"); if (flagremoteinfo) safecats(tcpremoteinfo.s); > cats(":"); safecats(remoteportstr); >+ if (flagdeny == 2) { >+ char curloadstr[FMT_ULONG]; >+ curloadstr[fmt_ulong(curloadstr,curload)] = 0; >+ cats(" "); safecats ("LOAD"); cats(":"); safecats(curloadstr); >+ } >+ 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 (*diemsg) { >+ buffer_init(&b,write,t,bspace,sizeof bspace); >+ buffer_puts(&b,diemsg); >+ if (buffer_putsflush(&b,"\r\n") == -1) >+ strerr_die2sys(111,DROP,"unable to print diemsg: "); >+ } >+ sleep(1); >+ _exit(100); >+ } > } > > >@@ -253,7 +348,6 @@ host port program",0); > _exit(100); > } > >-unsigned long limit = 40; > unsigned long numchildren = 0; > > int flag1 = 0; >@@ -278,6 +372,7 @@ void sigchld() > { > int wstat; > int pid; >+ unsigned long u; > > while ((pid = wait_nohang(&wstat)) > 0) { > if (verbosity >= 2) { >@@ -286,6 +381,8 @@ void sigchld() > 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 +396,7 @@ main(int argc,char **argv) > 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 +430,11 @@ main(int argc,char **argv) > argc -= optind; > argv += optind; > >+ x = env_get("MAXLOAD"); if (x) scan_ulong(x,&maxload); >+ x = env_get("MAXCONNIP"); if (x) scan_ulong(x,&maxconnip); >+ x = env_get("MAXCONNC"); if (x) scan_ulong(x,&maxconnc); >+ x = env_get("DIEMSG"); if (x) diemsg = x; >+ > if (!verbosity) > buffer_2->fd = -1; > >@@ -352,6 +455,10 @@ main(int argc,char **argv) > } > > 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 +512,7 @@ main(int argc,char **argv) > if (t == -1) continue; > ++numchildren; printstatus(); > >- switch(fork()) { >+ switch(pid=fork()) { > case 0: > close(s); > doit(t); >@@ -420,6 +527,10 @@ main(int argc,char **argv) > 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); > }
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 98708
: 63174