Ticket #15735: patch-tcpserver.c.diff

File patch-tcpserver.c.diff, 8.1 KB (added by compconsultant@…, 16 years ago)

This goes in the files directory, nowhere to download it as is

  • tcpserver.c

    diff -ruN tcpserver.c.orig tcpserver.c
    old new  
     1#ifdef __dietlibc__
     2#define NO_GETLOADAVG
     3#endif
     4
    15#include <sys/types.h>
    26#include <sys/param.h>
    37#include <netdb.h>
     8#include <stdlib.h>
     9#ifdef NO_GETLOADAVG
     10#include <unistd.h>
     11#endif
    412#include "uint16.h"
    513#include "str.h"
    614#include "byte.h"
     
    2836#include "sig.h"
    2937#include "dns.h"
    3038
     39
     40#ifdef SOLARIS
     41#include <kstat.h>
     42static kstat_ctl_t   *kc;
     43#ifndef FSCALE
     44#define FSHIFT  8               /* bits to right of fixed binary point */
     45#define FSCALE  (1<<FSHIFT)
     46#endif /* FSCALE */
     47
     48#define loaddouble(la) ((double)(la) / FSCALE)
     49#endif
     50
    3151int verbosity = 1;
    3252int flagkillopts = 1;
    3353int flagdelay = 1;
     
    5979static stralloc tmp;
    6080static stralloc fqdn;
    6181static stralloc addresses;
     82static stralloc diemsg_buf;
     83static stralloc diemsg2_buf;
     84static stralloc diemsg3_buf;
     85static stralloc diemsg4_buf;
    6286
    6387char bspace[16];
    6488buffer b;
    6589
    6690
     91typedef struct
     92{
     93  char ip[4];
     94  pid_t pid;
     95} baby;
     96
     97baby *child;
    6798
    6899/* ---------------------------- child */
    69100
     
    72103int flagdeny = 0;
    73104int flagallownorules = 0;
    74105char *fnrules = 0;
     106unsigned long maxload = 0;
     107long maxconnip = -1;
     108long maxconnc = -1;
     109char *diemsg = "";
     110char *diemsg2 = "";
     111char *diemsg3 = "";
     112char *diemsg4 = "";
    75113
    76114void drop_nomem(void)
    77115{
     
    110148  strerr_die4sys(111,DROP,"unable to read ",fnrules,": ");
    111149}
    112150
     151unsigned long limit = 40;
     152
    113153void found(char *data,unsigned int datalen)
    114154{
    115155  unsigned int next0;
     
    125165        if (data[1 + split] == '=') {
    126166          data[1 + split] = 0;
    127167          env(data + 1,data + 1 + split + 1);
     168          if (str_diff(data+1, "MAXLOAD") == 0) scan_ulong(data+1+split+1,&maxload);
     169          if (str_diff(data+1, "MAXCONNIP") == 0) scan_ulong(data+1+split+1,&maxconnip);
     170          if (str_diff(data+1, "MAXCONNC") == 0) scan_ulong(data+1+split+1,&maxconnc);
     171          if (str_diff(data+1, "DIEMSG") == 0) {
     172            if (!stralloc_copys(&diemsg_buf,data+1+split+1)) drop_nomem();
     173            if (!stralloc_0(&diemsg_buf)) drop_nomem();
     174            diemsg = diemsg_buf.s;
     175          }
     176          if (str_diff(data+1, "DIEMSG_MAXLOAD") == 0) {
     177            if (!stralloc_copys(&diemsg2_buf,data+1+split+1)) drop_nomem();
     178            if (!stralloc_0(&diemsg2_buf)) drop_nomem();
     179            diemsg2 = diemsg2_buf.s;
     180          }
     181          if (str_diff(data+1, "DIEMSG_MAXCONNIP") == 0) {
     182            if (!stralloc_copys(&diemsg3_buf,data+1+split+1)) drop_nomem();
     183            if (!stralloc_0(&diemsg3_buf)) drop_nomem();
     184            diemsg3 = diemsg3_buf.s;
     185          }
     186          if (str_diff(data+1, "DIEMSG_MAXCONNC") == 0) {
     187            if (!stralloc_copys(&diemsg4_buf,data+1+split+1)) drop_nomem();
     188            if (!stralloc_0(&diemsg4_buf)) drop_nomem();
     189            diemsg4 = diemsg4_buf.s;
     190          }
    128191        }
    129192        break;
    130193    }
     
    133196  }
    134197}
    135198
     199unsigned long getprocla(void)
     200{
     201#ifdef SOLARIS
     202  kstat_t       *ksp;
     203  kstat_named_t *knp;
     204  double lavg;
     205  kstat_chain_update(kc);
     206  ksp = kstat_lookup(kc, "unix", 0, "system_misc");
     207  kstat_read(kc,ksp,NULL);
     208  knp = kstat_data_lookup(ksp,"avenrun_1min");
     209  lavg = loaddouble(knp->value.ui32);
     210  return (unsigned long)(lavg * 100);
     211#else
     212#ifdef NO_GETLOADAVG
     213  int lret;
     214  int i;
     215  unsigned long u1, u2;
     216  char *s;
     217  static stralloc loadavg_data = {0};
     218
     219  lret = openreadclose("/proc/loadavg", &loadavg_data, 10);
     220  if (lret != -1) {
     221    /* /proc/loadavg format is:
     222     * 13.08 3.04 1.00 34/170 14190 */
     223    s = loadavg_data.s;
     224    i = scan_ulong (s, &u1); s+=i;
     225    if ((i>0) && (i<5) && (*s == '.')) { /* load should be < 10000 */
     226      i = scan_ulong (s+1,&u2);
     227      if (i==2) { /* we require two decimal places */
     228        return (u1 * 100 + u2);
     229      }
     230      return (u1 * 100);
     231    }
     232  }
     233#else
     234  double result;
     235  if (getloadavg(&result, 1) == 1) {
     236    return (result * 100);
     237  }
     238#endif
     239#endif
     240}
     241
    136242void doit(int t)
    137243{
    138244  int j;
     245  unsigned long curload = 0;
    139246
    140247  remoteipstr[ip4_fmt(remoteipstr,remoteip)] = 0;
    141248
     
    211318    }
    212319  }
    213320
     321  if (maxload) {
     322    curload = getprocla();
     323    if (curload > maxload) flagdeny = 2;
     324  }
     325 
     326  if (!flagdeny && (maxconnip != -1 || maxconnc != -1)) {
     327        unsigned long u;
     328        long c1=0, cc=0;
     329        for (u=0; u < limit; u++) if (child[u].pid != 0) {
     330                if ((child[u].ip[0] == remoteip[0]) &&
     331                    (child[u].ip[1] == remoteip[1]) &&
     332                    (child[u].ip[2] == remoteip[2]) ) {
     333                    cc++;
     334                    if (child[u].ip[3] == remoteip[3]) c1++;
     335                }
     336        }
     337        if (maxconnc != -1 && (cc >= maxconnc)) flagdeny = 4;
     338        if (maxconnip != -1 && (c1 >= maxconnip)) flagdeny = 3;
     339  }
     340
    214341  if (verbosity >= 2) {
    215342    strnum[fmt_ulong(strnum,getpid())] = 0;
    216343    if (!stralloc_copys(&tmp,"tcpserver: ")) drop_nomem();
     
    223350    cats(":"); safecats(remoteipstr);
    224351    cats(":"); if (flagremoteinfo) safecats(tcpremoteinfo.s);
    225352    cats(":"); safecats(remoteportstr);
     353    if (flagdeny == 2) {
     354        char curloadstr[FMT_ULONG];
     355        curloadstr[fmt_ulong(curloadstr,curload)] = 0;
     356        cats(" "); safecats ("MAXLOAD"); cats(":"); safecats(curloadstr);
     357    }
     358    if (flagdeny == 3) {
     359        char maxconstr[FMT_ULONG];
     360        maxconstr[fmt_ulong(maxconstr,maxconnip)] = 0;
     361        cats(" "); safecats ("MAXCONNIP"); cats(":"); safecats(maxconstr);
     362    }
     363    if (flagdeny == 4) {
     364        char maxconstr[FMT_ULONG];
     365        maxconstr[fmt_ulong(maxconstr,maxconnc)] = 0;
     366        cats(" "); safecats ("MAXCONNC"); cats(":"); safecats(maxconstr);
     367    }
    226368    cats("\n");
    227369    buffer_putflush(buffer_2,tmp.s,tmp.len);
    228370  }
    229371
    230   if (flagdeny) _exit(100);
     372  if (flagdeny) {
     373    if ((flagdeny==2) && *diemsg2) diemsg = diemsg2;
     374    if ((flagdeny==3) && *diemsg3) diemsg = diemsg3;
     375    if ((flagdeny==4) && *diemsg4) diemsg = diemsg4;
     376    if (*diemsg) {
     377      buffer_init(&b,write,t,bspace,sizeof bspace);
     378      buffer_puts(&b,diemsg);
     379      if (buffer_putsflush(&b,"\r\n") == -1)
     380        strerr_die2sys(111,DROP,"unable to print diemsg: ");
     381    }
     382    sleep(1);
     383    _exit(100);
     384  }
    231385}
    232386
    233387
     
    253407  _exit(100);
    254408}
    255409
    256 unsigned long limit = 40;
    257410unsigned long numchildren = 0;
    258411
    259412int flag1 = 0;
     
    278431{
    279432  int wstat;
    280433  int pid;
     434  unsigned long u;
    281435 
    282436  while ((pid = wait_nohang(&wstat)) > 0) {
    283437    if (verbosity >= 2) {
     
    286440      strerr_warn4("tcpserver: end ",strnum," status ",strnum2,0);
    287441    }
    288442    if (numchildren) --numchildren; printstatus();
     443    for (u=0; u < limit; u++) if (child[u].pid == pid) { child[u].pid = 0; break; }
     444    if (u == limit) strerr_die1x(111,"tcpserver: ERROR: dead child not found?!"); /* never happens */
    289445  }
    290446}
    291447
     
    299455  unsigned long u;
    300456  int s;
    301457  int t;
     458  pid_t pid;
    302459 
    303460  while ((opt = getopt(argc,argv,"dDvqQhHrR1UXx:t:u:g:l:b:B:c:pPoO")) != opteof)
    304461    switch(opt) {
     
    332489  argc -= optind;
    333490  argv += optind;
    334491
     492  x = env_get("MAXLOAD"); if (x) scan_ulong(x,&maxload);
     493  x = env_get("MAXCONNIP"); if (x) scan_ulong(x,&maxconnip);
     494  x = env_get("MAXCONNC"); if (x) scan_ulong(x,&maxconnc);
     495  x = env_get("DIEMSG"); if (x) diemsg = x;
     496  x = env_get("DIEMSG_MAXLOAD"); if (x) diemsg2 = x;
     497  x = env_get("DIEMSG_MAXCONNIP"); if (x) diemsg3 = x;
     498  x = env_get("DIEMSG_MAXCONNC"); if (x) diemsg4 = x;
     499 
    335500  if (!verbosity)
    336501    buffer_2->fd = -1;
    337502 
     
    352517  }
    353518
    354519  if (!*argv) usage();
     520 
     521  child = calloc(sizeof(baby),limit);
     522  if (!child)
     523    strerr_die2x(111,FATAL,"out of memory for MAXCONNIP tracking");
    355524 
    356525  sig_block(sig_child);
    357526  sig_catch(sig_child,sigchld);
     
    393562 
    394563  close(0);
    395564  close(1);
     565  #ifdef SOLARIS
     566  kc = kstat_open();
     567  #endif 
    396568  printstatus();
    397569 
    398570  for (;;) {
     
    405577    if (t == -1) continue;
    406578    ++numchildren; printstatus();
    407579 
    408     switch(fork()) {
     580    switch(pid=fork()) {
    409581      case 0:
    410582        close(s);
    411583        doit(t);
     
    420592      case -1:
    421593        strerr_warn2(DROP,"unable to fork: ",&strerr_sys);
    422594        --numchildren; printstatus();
     595        break;
     596      default:
     597        for (u=0; u < limit; u++) if (child[u].pid == 0) { byte_copy(child[u].ip,4,remoteip); child[u].pid = pid; break; }
     598        if (u == limit) strerr_die1x(111,"tcpserver: ERROR: no empty space for new child?!"); /* never happens */
    423599    }
    424600    close(t);
    425601  }