ze-filter  (ze-filter-0.8.0-develop-180218)
ze-smtprate.c
Go to the documentation of this file.
1 
2 /*
3  *
4  * ze-filter - Mail Server Filter for sendmail
5  *
6  * Copyright (c) 2001-2018 - Jose-Marcio Martins da Cruz
7  *
8  * Auteur : Jose Marcio Martins da Cruz
9  * jose.marcio.mc@gmail.org
10  *
11  * Historique :
12  * Creation : janvier 2002
13  *
14  * This program is free software, but with restricted license :
15  *
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
20  *
21  * More details about ze-filter license can be found at ze-filter
22  * web site : http://foss.jose-marcio.org
23  */
24 
25 #include <ze-sys.h>
26 
27 #include "ze-filter.h"
28 
29 
30 #define MINUTE * 60
31 #define HOUR * 60 MINUTE
32 #define DAY * 24 HOUR
33 
34 #define SZ_KEY 80
35 
36 #undef DEBUG_LEVEL
37 #define DEBUG_LEVEL 19
38 
39 /* ****************************************************************************
40  * *
41  * *
42  **************************************************************************** */
43 
44 typedef struct {
45  int which;
46  char *fname;
47  char *name;
48  time_t wsz;
49  char *unit;
50  double coef;
51  char *format;
52 } RATE_DEF_T;
53 
54 static RATE_DEF_T rateDef[] = {
55  {RATE_CONN, "ze-conn.data", "Connection Rate", 10 MINUTE, NULL, 1.0, NULL},
56  {RATE_RCPT, "ze-rcpt.data", "Recipient Rate", 10 MINUTE, NULL, 1.0, NULL},
57  {RATE_BOUNCE, "ze-bounce.data", "Bounce Rate", 10 MINUTE, NULL, 1.0, NULL},
58  {RATE_MSGS, "ze-msgs.data", "Message Rate", 10 MINUTE, NULL, 1.0, NULL},
59  {RATE_HAM, "ze-ham.data", "Ham Rate", 10 MINUTE, NULL, 1.0, NULL},
60  {RATE_SPAM, "ze-spam.data", "Spam Rate", 10 MINUTE, NULL, 1.0, NULL},
61  {RATE_SCORE, "ze-score.data", "Spam Score Rate", 10 MINUTE, NULL, 1.0, NULL},
62  {RATE_XFILES, "ze-xfiles.data", "XFiles Rate", 10 MINUTE, NULL, 1.0, NULL},
63  {RATE_VOLUME, "ze-bytes.data", "Volume Rate", 10 MINUTE, NULL, 1.0, NULL},
64  {RATE_SVCTIME, "ze-svctime.data", "Service Time Rate", 10 MINUTE, NULL, 1.0,
65  NULL},
66  {RATE_FROM_CONN, "ze-fromconn.data", "Connection Rate by sender address",
67  20 MINUTE, NULL, 1.0, NULL},
68  {RATE_FROM_MSGS, "ze-frommsgs.data", "Message Rate by sender address",
69  20 MINUTE, NULL, 1.0, NULL},
70  {RATE_FROM_RCPT, "ze-fromrcpt.data", "Recipient Rate by sender address",
71  20 MINUTE, NULL, 1.0, NULL},
72  {RATE_AUTH_CONN, "ze-authconn.data", "Connection Rate AUTH login",
73  20 MINUTE, NULL, 1.0, NULL},
74  {RATE_AUTH_MSGS, "ze-authmsgs.data", "Message Rate by AUTH login",
75  20 MINUTE, NULL, 1.0, NULL},
76  {RATE_AUTH_RCPT, "ze-authrcpt.data", "Recipient Rate by AUTH login",
77  20 MINUTE, NULL, 1.0, NULL},
78 
79  {-1, NULL, NULL, 0, NULL, 1., NULL}
80 };
81 
82 /* ****************************************************************************
83  * *
84  * *
85  **************************************************************************** */
86 #define SZ_BUCKET 30
87 
88 #if 0
89 static int NB_BUCKET = 128;
90 #else
91 #define NB_BUCKET 128
92 #endif
93 
94 static size_t DIM_HIST = 0x4000;
95 static size_t DIM_RES = 0x1000;
96 
97 
98 typedef struct Bucket_T {
99  time_t date; /* bucket date - minutes since epoch */
100  int nb[RATE_DIM];
101  time_t last;
102 } Bucket_T;
103 
104 typedef struct Res_T {
105  char key[SZ_KEY];
106  int nb[4][RATE_DIM];
107 
108  int rate[RATE_DIM];
110 } Res_T;
111 
112 
113 /* ****************************************************************************
114  * *
115  * *
116  **************************************************************************** */
117 
118 unsigned int smtprate_interval = 60; /* 1 minute */
119 unsigned int smtprate_window = 600; /* 10 minutes */
120 
121 typedef struct HistEvt_T {
123  time_t date; /* date */
124  char key[SZ_KEY]; /* IP address */
125  int nb; /* count */
126 } HistEvt_T;
127 
128 typedef struct {
129  HistEvt_T *data; /* array of events */
130  long ptr; /* pointer to next event */
131  size_t nb; /* used events on the array */
132 } RateHist_T;
133 
134 #define RATEHIST_INITIALIZER {NULL,0,0}
135 
136 typedef struct SmtpRate_T {
137  long signature;
138  bool ok;
139  pthread_mutex_t mutex;
140 
141  ZEBT_T db_rate; /* tree with results per host */
142  time_t last_update; /* results data update */
143  time_t last;
144 
145  RateHist_T hist[RATE_DIM]; /* history array */
146  Res_T gres; /* global results */
147 } SmtpRate_T;
148 
149 static SmtpRate_T hdata = {
150  0, FALSE, PTHREAD_MUTEX_INITIALIZER, JBT_INITIALIZER, (time_t) 0, (time_t) 0
151 };
152 
153 #define DATA_LOCK() MUTEX_LOCK(&hdata.mutex)
154 
155 #define DATA_UNLOCK() MUTEX_UNLOCK(&hdata.mutex)
156 
157 static int res_t_cmp_by_addr(void *, void *);
158 static int res_t_cmp_by_value(void *, void *);
159 static void update_res_t(Res_T *, time_t);
160 
161 /* ****************************************************************************
162  * *
163  * *
164  **************************************************************************** */
165 static int
166 res_t_cmp_by_addr(a, b)
167  void *a;
168  void *b;
169 {
170  Res_T *ta = (Res_T *) a;
171  Res_T *tb = (Res_T *) b;
172 
173  ZE_LogMsgInfo(30, " %s <-> %s", STRNULL(ta->key, ""), STRNULL(tb->key, ""));
174 
175  if (ta == NULL || tb == NULL) {
176  if (tb != NULL)
177  return -1;
178  if (ta != NULL)
179  return 1;
180  return 0;
181  }
182 
183  return (strcmp(ta->key, tb->key));
184 }
185 
186 static int
187 res_t_cmp_by_value(a, b)
188  void *a;
189  void *b;
190 {
191  Res_T *ta = (Res_T *) a;
192  Res_T *tb = (Res_T *) b;
193  int i;
194 
195  if (ta == NULL || tb == NULL) {
196  if (tb != NULL)
197  return -1;
198  if (ta != NULL)
199  return 1;
200  return 0;
201  }
202 
203  for (i = 0; i < RATE_DIM; i++) {
204  if (ta->rate[i] != tb->rate[i])
205  return (tb->rate[i] - ta->rate[i]);
206  }
207 
208  return (strcmp(STRNULL(ta->key, ""), STRNULL(tb->key, "")));
209 }
210 
211 /* ****************************************************************************
212  * *
213  * *
214  **************************************************************************** */
215 static int
216 calc_bucket_rate(bucket, which, now, wsz)
217  Bucket_T *bucket;
218  int which;
219  time_t now;
220  time_t wsz;
221 {
222  int nb, i;
223 
224  if (bucket == NULL)
225  return 0;
226 
227  if (now == 0)
228  now = time(NULL);
229 
230  nb = 0;
231  for (i = 0; i < NB_BUCKET; i++) {
232  if (bucket[i].date * SZ_BUCKET + wsz > now)
233  nb += bucket[i].nb[which];
234  }
235 
236  return nb;
237 }
238 
239 static void
240 update_res_t(res, now)
241  Res_T *res;
242  time_t now;
243 {
244  int which;
245 
246  for (which = 0; which < RATE_DIM; which++) {
247  if (rateDef[which].which < 0)
248  break;
249  res->rate[which] =
250  calc_bucket_rate(res->Srate, which, now, rateDef[which].wsz);
251  res->nb[0][which] = calc_bucket_rate(res->Srate, which, now, 1 MINUTE);
252  res->nb[1][which] = calc_bucket_rate(res->Srate, which, now, 10 MINUTE);
253  res->nb[2][which] = calc_bucket_rate(res->Srate, which, now, 1 HOUR);
254  res->nb[3][which] = calc_bucket_rate(res->Srate, which, now, 2 HOUR);
255  }
256 }
257 
258 /* ****************************************************************************
259  * *
260  * *
261  **************************************************************************** */
262 bool
263 smtprate_init(sza, szb)
264  size_t sza;
265  size_t szb;
266 {
267  int i;
268 
269  if (hdata.ok)
270  return TRUE;
271 
272  DATA_LOCK();
273 
274  if (!hdata.ok) {
275  ZE_LogMsgInfo(DEBUG_LEVEL, " again ??? ");
276  if (hdata.signature != SIGNATURE) {
277  memset(hdata.hist, 0, sizeof (hdata.hist));
278  memset(&hdata.gres, 0, sizeof (hdata.gres));
279  }
280 
281  if ((sza != 0) && (szb != 0)) {
282  DIM_HIST = sza;
283  DIM_RES = szb;
284  }
285 
286  for (i = 0; i < RATE_DIM; i++) {
287  /*
288  * Initialisation of connection data
289  */
290  if (hdata.hist[i].data == NULL)
291  hdata.hist[i].data =
292  (HistEvt_T *) malloc(DIM_HIST * sizeof (HistEvt_T));
293 
294  if (hdata.hist[i].data != NULL) {
295  memset(hdata.hist[i].data, 0, DIM_HIST * sizeof (HistEvt_T));
296  hdata.hist[i].ptr = 0;
297  } else {
298  ZE_LogSysError("malloc conn array");
299  DATA_UNLOCK();
300  return FALSE;
301  }
302  }
303 
304  memset(&hdata.gres, 0, sizeof (hdata.gres));
305 
306  if (!zeBTree_Init(&hdata.db_rate, sizeof (Res_T), res_t_cmp_by_addr))
307  ZE_LogMsgError(0, "Can't initialize db_rate");
308 
310 
311  hdata.last_update = time(NULL);
312 
313  hdata.ok = TRUE;
314  }
315 
316  DATA_UNLOCK();
317 
318  return TRUE;
319 }
320 
321 /* ****************************************************************************
322  * *
323  * *
324  **************************************************************************** */
325 void
327 {
328  int i;
329 
330  DATA_LOCK();
331 
332  for (i = 0; i < RATE_DIM; i++) {
333  FREE(hdata.hist[i].data);
334  memset(&hdata.hist[i], 0, sizeof (hdata.hist[i]));
335  }
336 
337  zeBTree_Destroy(&hdata.db_rate);
338  hdata.ok = FALSE;
339 
340  DATA_UNLOCK();
341 }
342 
343 
344 /* ****************************************************************************
345  * *
346  * *
347  **************************************************************************** */
348 bool
350  size_t sza;
351  size_t szb;
352 {
353  smtprate_free();
354  return smtprate_init(sza, szb);
355 }
356 
357 
358 /* ****************************************************************************
359  * *
360  * *
361  **************************************************************************** */
362 int
363 smtprate_add_entry(which, key, name, nb, t)
364  int which;
365  char *key;
366  char *name;
367  int nb;
368  time_t t;
369 {
370  Res_T p;
371  Res_T *ptr = NULL;
372  int n;
373 
374  RateHist_T *rptr;
375 
376  time_t tbucket;
377  int ibucket;
378 
379  tbucket = t / SZ_BUCKET;
380  ibucket = tbucket % NB_BUCKET;
381 
382  if (key == NULL)
383  return 0;
384 
385  ZE_LogMsgInfo(DEBUG_LEVEL, "Entering : %s", key);
386 
387  if (!smtprate_init(0, 0)) {
388  ZE_LogMsgError(0, "Can't continue : connection cache null ptr");
389  return 0;
390  }
391 
392  if (which < 0 || which >= RATE_DIM)
393  return 0;
394 
395  if (rateDef[which].which < 0)
396  return 0;
397 
398  DATA_LOCK();
399 
400  name = STRNULL(name, "UNKNOWN");
401 
402  rptr = &hdata.hist[which];
403 
404  if (which == RATE_CONN && nb == 0)
405  nb = 1;
406 
407  n = rptr->ptr;
408  rptr->data[n].signature = SIGNATURE;
409  strlcpy(rptr->data[n].key, key, sizeof (rptr->data[n].key));
410  rptr->data[n].date = t;
411  rptr->data[n].nb = nb;
412  rptr->ptr = (n + 1) % DIM_HIST;
413  if (rptr->nb < DIM_HIST)
414  rptr->nb++;
415 
416  /*
417  * global rate update XXX
418  */
419  if (hdata.gres.Srate[ibucket].date != tbucket) {
420  memset(&hdata.gres.Srate[ibucket], 0, sizeof (Bucket_T));
421  hdata.gres.Srate[ibucket].date = tbucket;
422  }
423  hdata.gres.Srate[ibucket].nb[which] += nb;
424  update_res_t(&hdata.gres, t);
425 
426  /*
427  * update throttle table...
428  */
429  memset(&p, 0, sizeof (p));
430  strlcpy(p.key, key, sizeof (p.key));
431 
432  ptr = zeBTree_Get(&hdata.db_rate, &p);
433 
434  if (ptr != NULL) {
435  ZE_LogMsgInfo(DEBUG_LEVEL, "Found in tree : %s", key);
436 
437  if (ptr->Srate[ibucket].date != tbucket) {
438  memset(&ptr->Srate[ibucket], 0, sizeof (Bucket_T));
439  ptr->Srate[ibucket].date = tbucket;
440  }
441  ptr->Srate[ibucket].nb[which] += nb;
442 
443  ptr->rate[which] =
444  calc_bucket_rate(ptr->Srate, which, t, rateDef[which].wsz);
445  } else {
446  ZE_LogMsgInfo(DEBUG_LEVEL, "Adding to tree : %s", key);
447  strlcpy(p.key, key, sizeof (p.key));
448 
449  p.Srate[ibucket].date = tbucket;
450  p.Srate[ibucket].nb[which] = nb;
451 
452  p.rate[which] = calc_bucket_rate(p.Srate, which, t, rateDef[which].wsz);
453 
454  if (!zeBTree_Add(&hdata.db_rate, &p))
455  ZE_LogMsgError(0, "Error adding new leaf to db");
456  }
457 
458  switch (which) {
459  case RATE_CONN:
461  break;
462  }
463 
464  n = calc_bucket_rate(hdata.gres.Srate, which, t, rateDef[which].wsz);
465 
466  ZE_LogMsgInfo(DEBUG_LEVEL, "Global rate : %s : %d %d", key, n,
467  hdata.gres.rate[which]);
468 
469  DATA_UNLOCK();
470 
471  return n;
472 }
473 
474 /* ****************************************************************************
475  * *
476  * *
477  **************************************************************************** */
478 int
479 smtprate_check(which, key, win)
480  int which;
481  char *key;
482  time_t win;
483 {
484  Res_T p;
485  Res_T *t = NULL;
486  int res = 0;
487  time_t now = time(NULL);
488 
489  if (key == NULL)
490  return 0;
491 
492  memset(&p, 0, sizeof (p));
493  strlcpy(p.key, key, sizeof (p.key));
494 
495  if (!smtprate_init(0, 0)) {
496  ZE_LogMsgError(0, "Can't continue : connection cache null ptr");
497  return 0;
498  }
499 
500  if (which < 0 || which >= RATE_DIM)
501  return 0;
502 
503  if (rateDef[which].which < 0)
504  return 0;
505 
506  DATA_LOCK();
507 
508  if (win <= 0)
509  win = rateDef[which].wsz;
510  if (strlen(key) > 0) {
511  if ((t = zeBTree_Get(&hdata.db_rate, &p)) != NULL)
512  res = calc_bucket_rate(t->Srate, which, now, win);
513  } else {
514  res = calc_bucket_rate(hdata.gres.Srate, which, now, win);
515  }
516 
517  DATA_UNLOCK();
518 
519  return res;
520 }
521 
522 
523 /* ****************************************************************************
524  * *
525  * *
526  **************************************************************************** */
527 static time_t cleanuptime = 0;
528 
529 static bool
530 cleanup_select(vp, arg)
531  void *vp;
532  void *arg;
533 {
534  Res_T *p = (Res_T *) vp;
535  int i;
536  time_t *win = (time_t *) arg;
537  time_t nbb = NB_BUCKET * SZ_BUCKET;
538 
539  if (win != NULL && *win > 0)
540  nbb = *win;
541 
542  for (i = 0; i < NB_BUCKET; i++) {
543  if (p->Srate[i].date * SZ_BUCKET + nbb >= cleanuptime)
544  return TRUE;
545  }
546 
547  return FALSE;
548 }
549 
550 
551 bool
553  time_t now;
554  time_t win;
555 {
556  ZE_LogMsgInfo(DEBUG_LEVEL, "Entering ...");
557 
558  if (!smtprate_init(0, 0)) {
559  ZE_LogMsgError(0, "Can't continue : connection cache null ptr");
560  return FALSE;
561  }
562 
563  if (hdata.last_update + 120 > now)
564  return TRUE;
565 
566  ZE_LogMsgInfo(DEBUG_LEVEL, "Updating Connection Rate Results...");
567 
568  DATA_LOCK();
569 
570  cleanuptime = now;
571 
572 #if _PERIODIC_DEBUG
573  ZE_MessageInfo(9, "smtprate_cleanup_table : before : %d nodes",
574  zeBTree_Count(&hdata.db_rate));
575 #endif
576 
577  if (!zeBTree_Cleanup(&hdata.db_rate, cleanup_select, &win))
578  ZE_LogMsgError(0, "Can't initialize temporary btree");
579 
580 #if _PERIODIC_DEBUG
581  ZE_MessageInfo(9, "smtprate_cleanup_table : after : %d nodes",
582  zeBTree_Count(&hdata.db_rate));
583 #endif
584 
585  hdata.last_update = now;
586 
587  DATA_UNLOCK();
588 
589  return TRUE;
590 }
591 
592 
593 /* ****************************************************************************
594  * *
595  * *
596  **************************************************************************** */
597 int
599  time_t w_width;
600 {
601  int i;
602  time_t now = time(NULL);
603  Res_T p;
604  Res_T *t;
605  static bool save_it = FALSE;
606  int which;
607 
608  ZE_LogMsgInfo(DEBUG_LEVEL, "Entering ...");
609 
610  if (!smtprate_init(0, 0)) {
611  ZE_LogMsgError(0, "Can't continue : connection cache null ptr");
612  return 0;
613  }
614 
615  ZE_LogMsgInfo(DEBUG_LEVEL, "Updating Connection Rate Results...");
616 
617  DATA_LOCK();
618 
619 #if _PERIODIC_DEBUG
620  ZE_MessageInfo(9, "smtprate_update_table : before : %d nodes",
621  zeBTree_Count(&hdata.db_rate));
622 #endif
623 
624 #if 0
625  zeBTree_Clear(&hdata.db_rate);
626 #endif
627  memset(&hdata.gres, 0, sizeof (hdata.gres));
628 
629  for (which = 0; which < RATE_DIM; which++) {
630  if (rateDef[which].which < 0)
631  break;
632 
633  if (hdata.hist[which].data == NULL)
634  continue;
635 
636  for (i = 0; i < DIM_HIST; i++) {
637  HistEvt_T *h = &hdata.hist[which].data[i];
638 
639  if (h->date == 0 || h->nb == 0)
640  continue;
641 
642  if (h->date + w_width < now) {
643  ZE_LogMsgInfo(DEBUG_LEVEL, "connection too old...");
644  continue;
645  }
646 
647  if (strlen(h->key) > 0) {
648  time_t tbucket = h->date / SZ_BUCKET;
649  int ibucket = tbucket % NB_BUCKET;
650 
651  ZE_LogMsgInfo(DEBUG_LEVEL, "Updating info for %s...", p.key);
652 
653  if (hdata.gres.Srate[ibucket].date > tbucket)
654  continue;
655 
656  if (h->date + rateDef[which].wsz >= now) {
657  if (hdata.gres.Srate[ibucket].date < tbucket) {
658  memset(&hdata.gres.Srate[ibucket], 0, sizeof (Bucket_T));
659  hdata.gres.Srate[ibucket].date = tbucket;
660  }
661 
662  hdata.gres.Srate[ibucket].nb[which] += h->nb;
663  }
664 
665  memset(&p, 0, sizeof (p));
666  strlcpy(p.key, h->key, sizeof (p.key));
667 
668  if ((t = zeBTree_Get(&hdata.db_rate, &p)) != NULL) {
669  ZE_LogMsgInfo(DEBUG_LEVEL, " %-20s already there...", p.key);
670 
671  if (t->Srate[ibucket].date < tbucket) {
672  memset(&t->Srate[ibucket], 0, sizeof (Bucket_T));
673  t->Srate[ibucket].date = tbucket;
674  }
675  if (t->Srate[ibucket].date == tbucket)
676  t->Srate[ibucket].nb[which] += h->nb;
677  } else {
678  ZE_LogMsgInfo(DEBUG_LEVEL, " %-20s not already there...", p.key);
679  memset(&p, 0, sizeof (p));
680  strlcpy(p.key, h->key, sizeof (p.key));
681 
682  memset(&p.Srate[ibucket], 0, sizeof (Bucket_T));
683  p.Srate[ibucket].date = tbucket;
684  p.Srate[ibucket].nb[which] += h->nb;
685 
686  if (!zeBTree_Add(&hdata.db_rate, &p))
687  ZE_LogMsgError(0, "Error adding new leaf to db");
688  else
689  hdata.hist[which].nb += h->nb;
690  }
691  }
692  }
693  }
694 
695  update_res_t(&hdata.gres, now);
696  for (which = RATE_CONN; which < RATE_DIM; which++) {
697  if (rateDef[which].which < 0)
698  break;
699 
700  if (rateDef[which].name == NULL)
701  continue;
702 
703  ZE_LogMsgInfo(DEBUG_LEVEL, "Global %-16s : %d",
704  rateDef[which].name, hdata.gres.rate[which]);
705  }
706 
707  ZE_LogMsgInfo(DEBUG_LEVEL, "SMTP Rates update OK !");
708 
709 #if _PERIODIC_DEBUG
710  ZE_MessageInfo(9, "smtprate_update_table : after : %d nodes",
711  zeBTree_Count(&hdata.db_rate));
712 #endif
713 
714  hdata.last = now;
715 
716  DATA_UNLOCK();
717 
718  update_throttle(now);
719 
720  if (save_it)
721  smtprate_save_table(NULL);
722  save_it = !save_it;
723 
724  smtprate_cleanup_table(time(NULL), 0);
725 
726  ZE_LogMsgInfo(DEBUG_LEVEL, "Exiting ...");
727 
728  return hdata.gres.rate[RATE_CONN];
729 }
730 
731 /* ****************************************************************************
732  * *
733  * *
734  **************************************************************************** */
735 
736 void
738  char *filename;
739 {
740  char *work_dir = cf_get_str(CF_WORKDIR);
741  char fname[256];
742  int fd;
743  size_t size;
744  int which;
745 
746  if (!smtprate_init(0, 0)) {
747  ZE_LogMsgError(0, "Can't continue : connection cache null ptr");
748  return;
749  }
750 
751  DATA_LOCK();
752  if (work_dir == NULL)
753  work_dir = ZE_WORKDIR;
754 
755  for (which = 0; which < RATE_DIM; which++) {
756  if (rateDef[which].which < 0)
757  break;
758 
759  if (rateDef[which].fname == NULL || hdata.hist[which].data == NULL)
760  continue;
761 
762  ZE_LogMsgInfo(DEBUG_LEVEL, "Saving \"%s\" history file : %s",
763  rateDef[which].name, rateDef[which].fname);
764 
765  snprintf(fname, sizeof (fname), "%s/%s", work_dir, rateDef[which].fname);
766  if ((fd = open(fname, O_WRONLY | O_CREAT | O_TRUNC, 00644)) >= 0) {
767  size = DIM_HIST * sizeof (HistEvt_T);
768  if (write(fd, hdata.hist[which].data, size) != size)
769  ZE_LogMsgWarning(0, "Can't write %s file", fname);
770  close(fd);
771  } else
772  ZE_LogMsgWarning(0, "Can't open %s file", fname);
773  }
774 
775  DATA_UNLOCK();
776 }
777 
778 
779 /* ****************************************************************************
780  * *
781  * *
782  **************************************************************************** */
783 int
785  char *filename;
786 {
787  char *work_dir = cf_get_str(CF_WORKDIR);
788  char fname[256];
789  int fd;
790  int i, imax;
791  time_t tmax;
792  size_t size;
793  int which;
794 
795  if (work_dir == NULL)
796  work_dir = ZE_WORKDIR;
797 
798  ZE_LogMsgInfo(DEBUG_LEVEL, "Entering ...");
799 
800  if (!smtprate_init(0, 0)) {
801  ZE_LogMsgError(0, "Can't continue : connection cache null ptr");
802  return 0;
803  }
804 
805  for (which = 0; which < RATE_DIM; which++) {
806  if (rateDef[which].which < 0)
807  break;
808  if (rateDef[which].fname == NULL)
809  continue;
810  if (rateDef[which].name == NULL)
811  continue;
812  if (hdata.hist[which].data == NULL)
813  continue;
814 
815  ZE_LogMsgInfo(DEBUG_LEVEL, "Reading \"%s\" history file : %s",
816  rateDef[which].name, rateDef[which].fname);
817 
818  snprintf(fname, sizeof (fname), "%s/%s", work_dir, rateDef[which].fname);
819  if ((fd = open(fname, O_RDONLY)) >= 0) {
820  size = DIM_HIST * sizeof (HistEvt_T);
821  if (read(fd, hdata.hist[which].data, size) != size)
822  ZE_LogMsgWarning(0, "Can't read %s file", fname);
823  close(fd);
824  } else
825  ZE_LogMsgWarning(0, "Can't open %s file", fname);
826 
827  for (i = 0, imax = 0, tmax = 0; i < DIM_HIST; i++) {
828  if (tmax == 0)
829  tmax = hdata.hist[which].data[i].date;
830  if (hdata.hist[which].data[i].date > tmax) {
831  tmax = hdata.hist[which].data[i].date;
832  imax = i;
833  }
834  if (which == RATE_CONN && hdata.hist[which].data[i].nb == 0)
835  hdata.hist[which].data[i].nb = 1;
836 
837  if (which == RATE_CONN)
838  add_throttle_entry(hdata.hist[which].data[i].date);
839  }
840  hdata.hist[which].ptr = 0;
841  if (imax > 0)
842  hdata.hist[which].ptr = imax + 1;
843  hdata.hist[which].ptr %= DIM_HIST;
844  }
845 
846 #if 0
848 #endif
849 
850  ZE_LogMsgInfo(DEBUG_LEVEL, "Exiting ...");
851 
852  return 0;
853 }
854 
855 /* ****************************************************************************
856  * *
857  * *
858  **************************************************************************** */
859 void
861 {
862  ZE_MessageInfo(10, "*** THROTTLE TABLE");
863 #if 0
864  for (i = 0; i < hdata.conn_nb; i++) {
865  if (hdata.rate_res[i].nb > 5)
866  ZE_MessageInfo(10, " CONN THROTTLE : %-16s %5d",
867  hdata.rate_res[i].ip, hdata.rate_res[i].nb);
868  }
869 #endif
870 }
871 
872 
873 /* ****************************************************************************
874  * *
875  * *
876  **************************************************************************** */
877 
878 static int outfd = STDOUT_FILENO;
879 static pthread_mutex_t fdmutex = PTHREAD_MUTEX_INITIALIZER;
880 
884  time_t win;
885  time_t now;
886  bool hostnames;
887  int nbrecs;
888  int count;
889 };
890 
891 static int
892 print_node(vp, arg)
893  void *vp;
894  void *arg;
895 {
896  Res_T *p = (Res_T *) vp;
897  smtp_select_T *sel = (smtp_select_T *) arg;
898  char nodename[256], *s;
899  int i;
900  time_t now = time(NULL);
901 
902  s = nodename;
903 
904  if (p == NULL || sel == NULL)
905  return 0;
906 
907  if (sel->nbrecs > 0 && sel->count >= sel->nbrecs)
908  return 1;
909 
910  sel->count++;
911 
912  if (sel->hostnames) {
913  memset(nodename, 0, sizeof (nodename));
914  CACHE_GETHOSTNAMEBYADDR(p->key, nodename, sizeof (nodename), FALSE);
915  } else
916  s = "";
917 
918  FD_PRINTF(outfd, " . %-16s ", p->key);
919 
920  update_res_t(p, now);
921 
922  for (i = 0; i < RATE_DIM; i++) {
923  if (rateDef[i].which < 0)
924  break;
925 
926  if (GET_BIT(sel->flags, i))
927  FD_PRINTF(outfd, "- %4d %4d %4d ", p->nb[0][i], p->nb[1][i], p->nb[2][i]);
928  }
929 
930  FD_PRINTF(outfd, ": %s\n", s);
931 
932  return 1;
933 }
934 
935 static bool
936 select_node(vp, arg)
937  void *vp;
938  void *arg;
939 {
940  Res_T *p = (Res_T *) vp;
941  smtp_select_T *sel = (smtp_select_T *) arg;
942 
943  int i, j;
944  time_t now = time(NULL);
945 
946  if (sel == NULL)
947  return FALSE;
948 
949  for (i = 0; i < NB_BUCKET; i++) {
950  for (j = 0; j < RATE_DIM; j++) {
951  if (rateDef[j].which < 0)
952  break;
953 
954  if (!GET_BIT(sel->flags, j))
955  continue;
956 
957  if (p->Srate[i].nb[j] == 0)
958  continue;
959 
960  if (p->Srate[i].date * SZ_BUCKET + sel->win > now) {
961  update_res_t(p, now);
962  return TRUE;
963  }
964  }
965  }
966  return FALSE;
967 }
968 
969 void
970 smtprate_print_table(fd, allhosts, verbose, hostnames, win, flags, nbrecs)
971  int fd;
972  int allhosts;
973  int verbose;
974  bool hostnames;
975  time_t win;
976  uint32_t flags;
977  int nbrecs;
978 {
979  int i;
980 
981  uint32_t v;
982  time_t tmin = 0, tmax = 0, now;
983  unsigned long hh, mm, ss;
984  char s[256];
985  int which;
986 
987  if (fd < 0)
988  fd = STDOUT_FILENO;
989 
990  ZE_LogMsgInfo(DEBUG_LEVEL, "Entering ...");
991 
992  if (!smtprate_init(0, 0)) {
993  ZE_LogMsgError(0, "Can't continue : connection cache null ptr");
994  return;
995  }
996 
997  FD_PRINTF(fd, "%-30s : %s\n", "Version", PACKAGE);
998  now = time(NULL);
999  ctime_r(&now, s);
1000  FD_PRINTF(fd, "*** THROTTLE TABLE (units each 10 minutes) at %s\n", s);
1001 
1002  for (which = 0; which < RATE_DIM; which++) {
1003  if (rateDef[which].which < 0)
1004  break;
1005 
1006  if (rateDef[which].name == NULL)
1007  continue;
1008 
1009  if (!GET_BIT(flags, which))
1010  continue;
1011 
1012  /*
1013  * Connection cache processing
1014  */
1015  FD_PRINTF(fd, "*** %-18s : %6ld/ 10 min (%ld entries)\n",
1016  rateDef[which].name, (long int ) hdata.gres.nb[1][which],
1017  (long int ) hdata.hist[which].nb);
1018 
1019  tmin = tmax = 0;
1020  for (v = 0, i = 0; i < DIM_HIST; i++) {
1021  if (hdata.hist[which].data[i].date != 0) {
1022  if (tmin == 0)
1023  tmin = hdata.hist[which].data[i].date;
1024  if (tmax == 0)
1025  tmax = hdata.hist[which].data[i].date;
1026  if (hdata.hist[which].data[i].date < tmin)
1027  tmin = hdata.hist[which].data[i].date;
1028  if (hdata.hist[which].data[i].date > tmax)
1029  tmax = hdata.hist[which].data[i].date;
1030  v++;
1031  }
1032  }
1033 
1034  ss = tmax - tmin;
1035  hh = ss / 3600;
1036  ss -= hh * 3600;
1037  mm = ss / 60;
1038  ss -= mm * 60;
1039 
1040  FD_PRINTF(fd, " %-18s : %3ld:%02ld:%02ld (%ld/%ld entries)\n",
1041  "HISTORY", hh, mm, ss, (long int ) v, (long int ) DIM_HIST);
1042  }
1043 
1044  /*
1045  * Let's print data..
1046  */
1047  if (allhosts) {
1048  ZEBT_T db_tmp = JBT_INITIALIZER;
1049 
1050  MUTEX_LOCK(&fdmutex);
1051  outfd = fd;
1052  if (zeBTree_Init(&db_tmp, sizeof (Res_T), res_t_cmp_by_value)) {
1053  smtp_select_T sel;
1054  int i;
1055 
1056  memset(&sel, 0, sizeof (sel));
1057 
1058  sel.flags = flags;
1059  sel.win = win;
1060  sel.now = time(NULL);
1061  sel.hostnames = hostnames;
1062  sel.nbrecs = nbrecs;
1063 
1064  zeBTree_Set_BTree_Size(&db_tmp, FALSE, 0);
1065 
1066  FD_PRINTF(fd, " -");
1067  for (i = 0; i < RATE_DIM; i++) {
1068  if (!GET_BIT(flags, i))
1069  continue;
1070  switch (i) {
1071  case RATE_CONN:
1072  FD_PRINTF(fd, " CONNECT :");
1073  break;
1074  case RATE_RCPT:
1075  FD_PRINTF(fd, " RCPTS :");
1076  break;
1077  case RATE_BOUNCE:
1078  FD_PRINTF(fd, " BOUNCES :");
1079  break;
1080  case RATE_MSGS:
1081  FD_PRINTF(fd, " MSGS :");
1082  break;
1083  case RATE_HAM:
1084  FD_PRINTF(fd, " HAM :");
1085  break;
1086  case RATE_SPAM:
1087  FD_PRINTF(fd, " SPAM :");
1088  break;
1089  case RATE_XFILES:
1090  FD_PRINTF(fd, " XFILES :");
1091  break;
1092  case RATE_VOLUME:
1093  FD_PRINTF(fd, " VOLUME :");
1094  break;
1095  case RATE_SVCTIME:
1096  FD_PRINTF(fd, " SVCTIME :");
1097  break;
1098  case RATE_SCORE:
1099  FD_PRINTF(fd, " SCORE :");
1100  break;
1101  }
1102  }
1103  if (hostnames)
1104  FD_PRINTF(fd, " HOST NAME");
1105  FD_PRINTF(fd, "\n");
1106 
1107  FD_PRINTF(fd, " HOST ADDRESS -");
1108  for (i = 0; i < RATE_DIM; i++) {
1109  if (!GET_BIT(flags, i))
1110  continue;
1111  switch (i) {
1112  case RATE_CONN:
1113  case RATE_RCPT:
1114  case RATE_BOUNCE:
1115  case RATE_MSGS:
1116  case RATE_HAM:
1117  case RATE_SPAM:
1118  case RATE_XFILES:
1119  case RATE_VOLUME:
1120  case RATE_SVCTIME:
1121  case RATE_SCORE:
1122  FD_PRINTF(fd, " 01m 10m 01h :");
1123  break;
1124  }
1125  }
1126  FD_PRINTF(fd, "\n");
1127 
1128  if (zeBTree_Cpy(&db_tmp, &hdata.db_rate, select_node, &sel)) {
1129  int n;
1130 
1131  n = zeBTree_Browse(&db_tmp, print_node, &sel);
1132 
1133  FD_PRINTF(fd, "\n %d records handled \n\n", n);
1134  }
1135  zeBTree_Destroy(&db_tmp);
1136  }
1137 
1138  MUTEX_UNLOCK(&fdmutex);
1139  }
1140 
1141  ZE_LogMsgInfo(DEBUG_LEVEL, "Exiting ...");
1142 }
1143 
1144 
1145 /* ****************************************************************************
1146  * *
1147  * *
1148  **************************************************************************** */
1149 uint32_t
1151  char *str;
1152 {
1153  char *ptr, *s;
1154  char *nstr = NULL;
1155  uint32_t flags = 0;
1156 
1157  nstr = strdup(str);
1158  if (nstr != NULL) {
1159  for (s = strtok_r(nstr, ",", &ptr); s != NULL;
1160  s = strtok_r(NULL, ",", &ptr)) {
1161  char *tag;
1162 
1163  tag = "conn";
1164  if (strncasecmp(s, tag, strlen(tag)) == 0) {
1165  SET_BIT(flags, RATE_CONN);
1166  continue;
1167  }
1168 
1169  tag = "rcpt";
1170  if (strncasecmp(s, tag, strlen(tag)) == 0) {
1171  SET_BIT(flags, RATE_RCPT);
1172  continue;
1173  }
1174 
1175  tag = "bounce";
1176  if (strncasecmp(s, tag, strlen(tag)) == 0) {
1177  SET_BIT(flags, RATE_BOUNCE);
1178  continue;
1179  }
1180 
1181  tag = "msg";
1182  if (strncasecmp(s, tag, strlen(tag)) == 0) {
1183  SET_BIT(flags, RATE_MSGS);
1184  continue;
1185  }
1186 
1187  tag = "ham";
1188  if (strncasecmp(s, tag, strlen(tag)) == 0) {
1189  SET_BIT(flags, RATE_HAM);
1190  continue;
1191  }
1192 
1193  tag = "spam";
1194  if (strncasecmp(s, tag, strlen(tag)) == 0) {
1195  SET_BIT(flags, RATE_SPAM);
1196  continue;
1197  }
1198 
1199  tag = "xfile";
1200  if (strncasecmp(s, tag, strlen(tag)) == 0) {
1201  SET_BIT(flags, RATE_XFILES);
1202  continue;
1203  }
1204 
1205  tag = "vol";
1206  if (strncasecmp(s, tag, strlen(tag)) == 0) {
1207  SET_BIT(flags, RATE_VOLUME);
1208  continue;
1209  }
1210 
1211  tag = "svc";
1212  if (strncasecmp(s, tag, strlen(tag)) == 0) {
1213  SET_BIT(flags, RATE_SVCTIME);
1214  continue;
1215  }
1216 
1217  tag = "score";
1218  if (strncasecmp(s, tag, strlen(tag)) == 0) {
1219  SET_BIT(flags, RATE_SCORE);
1220  continue;
1221  }
1222 
1223  tag = "all";
1224  if (strncasecmp(s, tag, strlen(tag)) == 0) {
1225  int j;
1226 
1227  for (j = 0; j < RATE_DIM; j++)
1228  SET_BIT(flags, j);
1229  continue;
1230  }
1231  break;
1232  }
1233  FREE(nstr);
1234  }
1235  return flags;
1236 }
char key[SZ_KEY]
Definition: ze-smtprate.c:124
bool zeBTree_Set_BTree_Size(ZEBT_T *, bool, int)
Definition: zeBTree.c:170
int smtprate_add_entry(int which, char *key, char *name, int nb, time_t t)
Definition: ze-smtprate.c:363
int smtprate_update_table(time_t w_width)
Definition: ze-smtprate.c:598
uint32_t smtprate_str2flags(char *str)
Definition: ze-smtprate.c:1150
#define CACHE_GETHOSTNAMEBYADDR(ip, name, size, query)
Definition: ze-filter.h:186
void * zeBTree_Get(ZEBT_T *, void *)
Definition: zeBTree.c:281
int rate[RATE_DIM]
Definition: ze-smtprate.c:108
int nb[4][RATE_DIM]
Definition: ze-smtprate.c:106
char * format
Definition: ze-smtprate.c:51
#define ZE_WORKDIR
Definition: defs.h:33
uint32_t flags
Definition: ze-smtprate.c:883
#define FREE(x)
Definition: macros.h:37
#define JBT_INITIALIZER
Definition: zeBTree.h:85
uint32_t signature
Definition: ze-smtprate.c:122
bool zeBTree_Init(ZEBT_T *, size_t, ZEBT_CMP_F)
Definition: zeBTree.c:96
#define MUTEX_UNLOCK(mutex)
Definition: macros.h:101
unsigned int smtprate_window
Definition: ze-smtprate.c:119
#define RATE_AUTH_RCPT
Definition: ze-smtprate.h:68
#define STRNULL(x, r)
Definition: macros.h:81
#define RATE_XFILES
Definition: ze-smtprate.h:58
#define MUTEX_LOCK(mutex)
Definition: macros.h:93
#define ZE_LogMsgInfo(level,...)
Definition: zeSyslog.h:110
bool smtprate_cleanup_table(time_t now, time_t win)
Definition: ze-smtprate.c:552
bool zeBTree_Add(ZEBT_T *, void *)
Definition: zeBTree.c:309
time_t last
Definition: ze-smtprate.c:143
#define FALSE
Definition: macros.h:160
#define strlcpy
Definition: zeString.h:32
#define RATE_SVCTIME
Definition: ze-smtprate.h:60
#define ZE_LogMsgError(level,...)
Definition: zeSyslog.h:113
struct Bucket_T bucket[K_MIN]
#define RATE_VOLUME
Definition: ze-smtprate.h:59
time_t date
Definition: ze-smtprate.c:99
Bucket_T Srate[NB_BUCKET]
Definition: ze-smtprate.c:109
RateHist_T hist[RATE_DIM]
Definition: ze-smtprate.c:145
bool zeBTree_Destroy(ZEBT_T *)
Definition: zeBTree.c:192
#define GET_BIT(p, i)
Definition: macros.h:168
struct Bucket_T Bucket_T
char * name
Definition: ze-smtprate.c:47
#define FD_PRINTF(fdp,...)
Definition: macros.h:45
#define SET_BIT(p, i)
Definition: macros.h:166
int nb[RATE_DIM]
Definition: ze-smtprate.c:100
bool smtprate_resize(size_t sza, size_t szb)
Definition: ze-smtprate.c:349
long signature
Definition: ze-smtprate.c:137
void add_throttle_entry(time_t)
Definition: ze-throttle.c:148
#define RATE_AUTH_MSGS
Definition: ze-smtprate.h:67
int smtprate_read_table(char *filename)
Definition: ze-smtprate.c:784
unsigned int connrate_window
HistEvt_T * data
Definition: ze-smtprate.c:129
#define SZ_BUCKET
Definition: ze-smtprate.c:86
#define RATE_HAM
Definition: ze-smtprate.h:55
time_t date
Definition: ze-smtprate.c:123
char * fname
Definition: ze-smtprate.c:46
#define HOUR
Definition: ze-smtprate.c:31
#define SZ_KEY
Definition: ze-smtprate.c:34
pthread_mutex_t mutex
Definition: ze-smtprate.c:139
int zeBTree_Count(ZEBT_T *)
Definition: zeBTree.c:245
bool zeBTree_Clear(ZEBT_T *)
Definition: zeBTree.c:222
ZEBT_T db_rate
Definition: ze-smtprate.c:141
#define DATA_UNLOCK()
Definition: ze-smtprate.c:155
bool zeBTree_Cpy(ZEBT_T *, ZEBT_T *, ZEBT_SEL_F, void *)
Definition: zeBTree.c:515
#define ZE_MessageInfo(level,...)
Definition: zeSyslog.h:90
int nb
Definition: ze-connopen.c:61
#define RATE_SPAM
Definition: ze-smtprate.h:56
#define DEBUG_LEVEL
Definition: ze-smtprate.c:37
#define RATE_MSGS
Definition: ze-smtprate.h:54
#define TRUE
Definition: macros.h:157
#define RATE_BOUNCE
Definition: ze-smtprate.h:53
#define RATE_DIM
Definition: ze-smtprate.h:70
#define ZE_LogSysError(...)
Definition: zeSyslog.h:129
double coef
Definition: ze-smtprate.c:50
time_t last
Definition: ze-smtprate.c:101
char * cf_get_str(int id)
Definition: ze-cf.c:854
time_t last_update
Definition: ze-smtprate.c:142
#define RATE_RCPT
Definition: ze-smtprate.h:52
#define DATA_LOCK()
Definition: ze-smtprate.c:153
char * unit
Definition: ze-smtprate.c:49
#define ZE_LogMsgWarning(level,...)
Definition: zeSyslog.h:112
int smtprate_check(int which, char *key, time_t win)
Definition: ze-smtprate.c:479
#define RATE_SCORE
Definition: ze-smtprate.h:57
#define MINUTE
Definition: ze-smtprate.c:30
void update_throttle(time_t)
Definition: ze-throttle.c:186
void smtprate_free()
Definition: ze-smtprate.c:326
#define PACKAGE
Definition: version.h:28
void smtprate_save_table(char *filename)
Definition: ze-smtprate.c:737
void smtprate_print_table(int fd, int allhosts, int verbose, bool hostnames, time_t win, uint32_t flags, int nbrecs)
Definition: ze-smtprate.c:970
struct HistEvt_T HistEvt_T
Res_T gres
Definition: ze-smtprate.c:146
bool smtprate_init(size_t sza, size_t szb)
Definition: ze-smtprate.c:263
unsigned int smtprate_interval
Definition: ze-smtprate.c:118
void smtprate_log_table()
Definition: ze-smtprate.c:860
#define RATE_FROM_MSGS
Definition: ze-smtprate.h:63
time_t wsz
Definition: ze-smtprate.c:48
#define RATE_AUTH_CONN
Definition: ze-smtprate.h:66
struct SmtpRate_T SmtpRate_T
size_t nb
Definition: ze-smtprate.c:131
#define SIGNATURE
Definition: ze-libjc.h:75
#define RATE_FROM_RCPT
Definition: ze-smtprate.h:64
#define CF_WORKDIR
Definition: cfh-defs.h:67
struct Res_T Res_T
long uint32_t
Definition: ze-sys.h:489
char key[SZ_KEY]
Definition: ze-smtprate.c:105
bool zeBTree_Cleanup(ZEBT_T *, ZEBT_SEL_F, void *)
Definition: zeBTree.c:564
int zeBTree_Browse(ZEBT_T *, ZEBT_BROWSE_F, void *)
Definition: zeBTree.c:262
#define RATE_FROM_CONN
Definition: ze-smtprate.h:62
#define RATE_CONN
Definition: ze-smtprate.h:51
#define NB_BUCKET
Definition: ze-smtprate.c:91
Definition: zeBTree.h:73