Download | Plain Text | No Line Numbers
- diff -Naur ucspi-tcp6-1.00.orig/src/CHANGES.tcpserver-limits-patch ucspi-tcp6-1.00/src/CHANGES.tcpserver-limits-patch
- --- ucspi-tcp6-1.00.orig/src/CHANGES.tcpserver-limits-patch 1970-01-01 01:00:00.000000000 +0100
- +++ ucspi-tcp6-1.00/src/CHANGES.tcpserver-limits-patch 2014-05-18 16:01:53.991206542 +0200
- @@ -0,0 +1,28 @@
- +20060126 Added support for "always reject" (setting MAXCONNIP and/or
- +MAXCONNC to 0) and fixing a bug when sometimes DIEMSG would not be
- +shown (by Mark Powell)
- +
- +20050903 Added support for Solaris (by Jorge Valdes).
- +Moved MAXLOAD code to getprocla().
- +Modified documentation a little to accommodate recent changes.
- +
- +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)
- +
- +
- diff -Naur ucspi-tcp6-1.00.orig/src/README.tcpserver-limits-patch ucspi-tcp6-1.00/src/README.tcpserver-limits-patch
- --- ucspi-tcp6-1.00.orig/src/README.tcpserver-limits-patch 1970-01-01 01:00:00.000000000 +0100
- +++ ucspi-tcp6-1.00/src/README.tcpserver-limits-patch 2014-05-18 20:26:06.659001385 +0200
- @@ -0,0 +1,122 @@
- +See CHANGES.tcpserver-limits-patch for changes summary.
- +
- +:::COMPILING:::
- +
- + For MAXLOAD variable to have effect, you have 3 options:
- +
- +(1) By default the patch assumes that you have working getloadavg(3)
- + (most modern UN*Xoids have, including Linux and FreeBSD). No changes
- + are needed to standard ucspi-tcp compilation procedures.
- +
- +(2) If you have a non-Solaris system without getloadavg(3), but with
- + readable '/proc/loadavg' (in linux-2.4.x/2.6.x syntax); for example
- + if you're compiling on Linux system with dietlibc:
- + - conf-cc needs to be modified to include "-DNO_GETLOADAVG"
- +
- +
- +:::USING:::
- +
- +This patch makes tcpserver from Dr. Erwin Hoffmann's ucspi-tcp6 1.00a package
- +(see http://www.fehcom.de/ipnet/ucspi-tcp6.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
- +
- + See COMPILING instructions above for info on supported systems.
- +
- +(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.
- + 0 is valid value and means 'always reject'
- +
- +(3) MAXCONNC
- +
- + maximum connections from whole /24 (IPv4) or /64 (IPv6). 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.
- + 0 is valid value and means 'always reject'
- +
- +(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.
- +
- +
- +The origin patch is from Matija Nalis, http://linux.voyager.hr/ucspi-tcp/
- diff -Naur ucspi-tcp6-1.00.orig/src/tcpserver.c ucspi-tcp6-1.00/src/tcpserver.c
- --- ucspi-tcp6-1.00.orig/src/tcpserver.c 2014-01-08 13:05:43.000000000 +0100
- +++ ucspi-tcp6-1.00/src/tcpserver.c 2014-05-18 20:29:12.437079915 +0200
- @@ -1,3 +1,11 @@
- +#ifdef __dietlibc__
- +#define NO_GETLOADAVG
- +#endif
- +
- +#include <stdlib.h>
- +#ifdef NO_GETLOADAVG
- +#include <unistd.h>
- +#endif
- #include <sys/types.h>
- #include <unistd.h>
- #include <sys/param.h>
- @@ -64,11 +72,20 @@
- static stralloc tmp;
- static stralloc fqdn;
- static stralloc addresses;
- +static stralloc diemsg_buf;
- +
- +#define loaddouble(la) ((double)(la) / FSCALE)
-
- char bspace[16];
- buffer b;
-
- +typedef struct
- +{
- + char ip[16];
- + pid_t pid;
- +} baby;
-
- +baby *child;
-
- /* ---------------------------- child */
-
- @@ -77,6 +94,10 @@
- int flagdeny = 0;
- int flagallownorules = 0;
- char *fnrules = 0;
- +unsigned long maxload = 0;
- +long maxconnip = -1;
- +long maxconnc = -1;
- +char *diemsg = "";
-
- void drop_nomem(void)
- {
- @@ -114,6 +135,8 @@
- strerr_die4sys(111,DROP,"unable to read ",fnrules,": ");
- }
-
- +unsigned long limit = 40;
- +
- void found(char *data,unsigned int datalen)
- {
- unsigned int next0;
- @@ -129,6 +152,14 @@
- 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) {
- + if (!stralloc_copys(&diemsg_buf,data+1+split+1)) drop_nomem();
- + if (!stralloc_0(&diemsg_buf)) drop_nomem();
- + diemsg = diemsg_buf.s;
- + }
- }
- break;
- }
- @@ -137,6 +168,37 @@
- }
- }
-
- +unsigned long getprocla(void)
- +{
- +#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 */
- + return (u1 * 100 + u2);
- + }
- + return (u1 * 100);
- + }
- + }
- +#else
- + double result;
- + if (getloadavg(&result, 1) == 1) {
- + return (result * 100);
- + }
- +#endif
- +}
- +
- void doit(int t)
- {
- int mappedv4 = 0;
- @@ -254,6 +316,29 @@
- }
- }
-
- + unsigned long curload = 0;
- + if (maxload) {
- + curload = getprocla();
- + if (curload > maxload) flagdeny = 2;
- + }
- +
- + 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 (ipv4 || mappedv4 || ip6_isv4mapped(remoteip)) {
- + if (byte_equal(child[u].ip, 15, remoteip)) cc++;
- + }
- + else {
- + if (byte_equal(child[u].ip, 8, remoteip)) cc++;
- + }
- + if (byte_equal(child[u].ip, 16, remoteip)) 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();
- @@ -266,11 +351,35 @@
- cats(":"); safecats(stripaddr);
- 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);
- + }
- }
-
-
- @@ -297,7 +406,6 @@
- _exit(100);
- }
-
- -unsigned long limit = 40;
- unsigned long numchildren = 0;
-
- int flag1 = 0;
- @@ -322,6 +430,7 @@
- {
- int wstat;
- int pid;
- + unsigned long u;
-
- while ((pid = wait_nohang(&wstat)) > 0) {
- if (verbosity >= 2) {
- @@ -330,11 +439,14 @@
- 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 */
- }
- }
-
- int main(int argc,char **argv)
- {
- + pid_t pid;
- char *hostname;
- int opt;
- struct servent *se;
- @@ -377,6 +489,10 @@
- }
- 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;
- @@ -397,6 +513,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);
- @@ -459,7 +579,7 @@
- if (t == -1) continue;
- ++numchildren; printstatus();
-
- - switch(fork()) {
- + switch(pid=fork()) {
- case 0:
- close(s);
- doit(t);
- @@ -474,6 +594,16 @@
- 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,16,remoteip);
- + child[u].pid = pid;
- + break;
- + }
- + if (u == limit)
- + strerr_die1x(111,"tcpserver: ERROR: no empty space for new child?!"); /* never happens */
- }
- close(t);
- }
-