ze-filter  (ze-filter-0.8.0-develop-180218)
ze-livehistory.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 /* ****************************************************************************
31  * *
32  * *
33  **************************************************************************** */
34 
35 #ifndef DTCLEANUP
36 #define DTCLEANUP 600
37 #endif
38 
39 
40 #define K_MIN 16
41 #define K_SHF 10
42 
43 /*
44 ** Window width = K_MIN * (2 ** K_SHF) seconds
45 **
46 ** K_MIN K_SHF Window (sec)
47 ** 16 8 4096 (~ 1 h)
48 ** 16 10 16384 (~ 4.5 h)
49 ** 16 12 65536 (~ 18 h)
50 **
51 */
52 
53 #define NB_MAJOR(i) ((i) >> K_SHF)
54 #define NB_MINOR(i) (((i) >> K_SHF) & (K_MIN - 1))
55 
56 typedef struct Bucket_T {
57  long count[LH_MAX];
58 
59 #if 0
60  int NbBadRcpt;
61  int NbEmpty;
62  int NbSpamTrap;
63  int NbEmptyMsgs;
64  int NbBadMX;
65  int NbBadResolve;
66 #endif
67 
68  time_t dtms;
69  time_t t;
70 } Bucket_T;
71 
72 
73 typedef struct ShortHist_T {
75  char ip[SZ_IP];
77  time_t update;
78 } ShortHist_T;
79 
80 
81 /* ****************************************************************************
82  * *
83  * *
84  **************************************************************************** */
85 
86 static struct {
87  bool ok;
88  time_t last;
89  int nb;
90 
91  pthread_mutex_t mutex;
92 
94 
96 } hdata = {
97 FALSE, (time_t) 0, 0, PTHREAD_MUTEX_INITIALIZER, JBT_INITIALIZER};
98 
99 
100 #define DATA_LOCK() \
101  if (pthread_mutex_lock(&hdata.mutex) != 0) { \
102  ZE_LogSysError("pthread_mutex_lock"); \
103  }
104 
105 #define DATA_UNLOCK() \
106  if (pthread_mutex_unlock(&hdata.mutex) != 0) { \
107  ZE_LogSysError("pthread_mutex_unlock"); \
108  }
109 
110 /* ****************************************************************************
111  * *
112  * *
113  **************************************************************************** */
114 static int
115 livehistory_cmp(a, b)
116  void *a;
117  void *b;
118 {
119  ShortHist_T *ta = (ShortHist_T *) a;
120  ShortHist_T *tb = (ShortHist_T *) b;
121 
122  if (ta == NULL)
123  return -1;
124  if (tb == NULL)
125  return 1;
126  if ((ta == NULL) && (tb == NULL))
127  return 0;
128 
129  return ip_strcmp(ta->ip, tb->ip);
130 }
131 
132 /* ****************************************************************************
133  * *
134  * *
135  **************************************************************************** */
136 static bool
137 livehistory_init()
138 {
139  if (hdata.ok)
140  return TRUE;
141 
142  DATA_LOCK();
143  if (!hdata.ok) {
144  if (!zeBTree_Init(&hdata.db_empty, sizeof (ShortHist_T), livehistory_cmp))
145  ZE_LogMsgError(0, "Can't initialize db_empty");
146 
147  hdata.ok = TRUE;
148  hdata.last = time(NULL);
149  memset(hdata.bucket, 0, sizeof (hdata.bucket));
150  }
151  DATA_UNLOCK();
152 
153  return TRUE;
154 }
155 
156 /* ****************************************************************************
157  * *
158  * *
159  **************************************************************************** */
160 void
162 {
163  DATA_LOCK();
164 
165  zeBTree_Destroy(&hdata.db_empty);
166  hdata.nb = 0;
167 
168  DATA_UNLOCK();
169 }
170 
171 
172 /* ****************************************************************************
173  * *
174  * *
175  **************************************************************************** */
176 static bool
177 select_function(vp, arg)
178  void *vp;
179  void *arg;
180 {
181  ShortHist_T *p = (ShortHist_T *) vp;
182  time_t now, *tnow;
183  int tr, ti, i;
184 
185  tnow = (time_t *) arg;
186 
187  if (p == NULL)
188  return FALSE;
189 
190  if (tnow != NULL)
191  now = (*tnow);
192  else
193  now = time(NULL);
194 
195  tr = NB_MAJOR(now);
196  ti = NB_MINOR(now);
197 
198  if (p->update + 3600 > now)
199  return TRUE;
200 
201  for (i = 0; i < K_MIN; i++) {
202  if (p->bucket[i].t + K_MIN >= tr)
203  return TRUE;
204  }
205  return FALSE;
206 }
207 
208 /* ****************************************************************************
209  * *
210  * *
211  **************************************************************************** */
212 
213 bool
215 {
216  time_t now = time(NULL);
217 
218  if (!livehistory_init())
219  return FALSE;
220 
221  DATA_LOCK();
222 
223  if ((hdata.last + DTCLEANUP / 2 < now) && ((hdata.last + DTCLEANUP < now)
224  || (zeBTree_Count(&hdata.db_empty) >
225  NB_BTCLEANUP))) {
226  ZEBT_T tmp = JBT_INITIALIZER;
227 
228  if (zeBTree_Init(&tmp, sizeof (ShortHist_T), livehistory_cmp)) {
229  if (zeBTree_Cpy(&tmp, &hdata.db_empty, select_function, (void *) &now)) {
230  zeBTree_Destroy(&hdata.db_empty);
231  hdata.db_empty = tmp;
232  } else
233  ZE_LogMsgError(0, "Can't copy btrees...");
234  } else
235  ZE_LogMsgError(0, "Can't initialize temporary btree");
236 
237  hdata.last = now;
238  }
239  DATA_UNLOCK();
240 
241 #if 0
243 #endif
244 
245  return TRUE;
246 }
247 
248 /* ****************************************************************************
249  * *
250  * *
251  **************************************************************************** */
252 int
253 livehistory_add_entry(ip, now, n, what)
254  char *ip;
255  time_t now;
256  int n;
257  int what;
258 {
259  ShortHist_T p;
260  ShortHist_T *ptr = NULL;
261  int res = 0;
262  int tr, ti, i;
263 
264  if (ip == NULL)
265  return 0;
266 
267  if (now == (time_t) 0)
268  now = time(NULL);
269 
270  tr = NB_MAJOR(now);
271  ti = NB_MINOR(now);
272 
273  if (!livehistory_init())
274  return res;
275 
276  if (what < 0 || what >= LH_MAX)
277  return 0;
278 
279  DATA_LOCK();
280 
281  /*
282  * update throttle table...
283  */
284  memset(&p, 0, sizeof (p));
285  strlcpy(p.ip, ip, sizeof (p.ip));
286 
287  ptr = zeBTree_Get(&hdata.db_empty, &p);
288 
289  if (ptr != NULL) {
290  if (ptr->bucket[ti].t != tr) {
291  memset(&ptr->bucket[ti], 0, sizeof (Bucket_T));
292  ptr->bucket[ti].t = tr;
293  }
294  ptr->bucket[ti].count[what] += n;
295 
296  ptr->update = now;
297  for (i = 0; i < K_MIN; i++) {
298  if (ptr->bucket[i].t + K_MIN >= tr)
299  res += ptr->bucket[ti].count[what];
300  }
301  } else {
302  memset(&p, 0, sizeof (p));
303  strlcpy(p.ip, ip, sizeof (p.ip));
304  p.update = now;
305  memset(&p.bucket[ti], 0, sizeof (Bucket_T));
306  p.bucket[ti].t = tr;
307 
308  p.bucket[ti].count[what] = n;
309 
310  if (!zeBTree_Add(&hdata.db_empty, &p))
311  ZE_LogMsgError(0, "Error adding new leaf to db");
312 
313  res = n;
314  }
315 
316  if (hdata.bucket[ti].t != tr) {
317  memset(&hdata.bucket[ti], 0, sizeof (hdata.bucket[ti]));
318  hdata.bucket[ti].t = tr;
319  }
320 
321  hdata.bucket[ti].count[what] += n;
322 
323  DATA_UNLOCK();
324 
325  if ((hdata.last + DTCLEANUP / 2 < now) && ((hdata.last + DTCLEANUP < now)
326  || (zeBTree_Count(&hdata.db_empty) >
327  NB_BTCLEANUP)))
329 
330  return res;
331 }
332 
333 /* ****************************************************************************
334  * *
335  * *
336  **************************************************************************** */
337 int
339  char *ip;
340  time_t win;
341  int what;
342 {
343  ShortHist_T *ptr = NULL, p;
344  int res = 0;
345  time_t now = time(NULL);
346  int tr, ti, i;
347 
348  if (ip == NULL)
349  return 0;
350 
351 #if 1
352  tr = NB_MAJOR(now);
353  ti = NB_MINOR(now);
354 #else
355  tr = NB_MAJOR(win);
356  ti = NB_MINOR(win);
357 #endif
358 
359  if (!livehistory_init())
360  return res;
361 
362  if (what < 0 || what >= LH_MAX)
363  return 0;
364 
365  DATA_LOCK();
366 
367  /*
368  * update throttle table...
369  */
370  memset(&p, 0, sizeof (p));
371  strlcpy(p.ip, ip, sizeof (p.ip));
372 
373  ptr = zeBTree_Get(&hdata.db_empty, &p);
374 
375  if (ptr != NULL) {
376  for (i = 0; i < K_MIN; i++) {
377  if (ptr->bucket[i].t + K_MIN >= tr)
378  res += ptr->bucket[ti].count[what];
379  }
380  }
381 
382  DATA_UNLOCK();
383 
384  return res;
385 }
386 
387 
388 
389 /* ****************************************************************************
390  * *
391  * *
392  **************************************************************************** */
393 typedef struct browse_T browse_T;
394 
395 struct browse_T {
396  int fd;
397 
398  int nrec;
399  int nok;
400  int count[LH_MAX];
401 
402  time_t now;
403 
405 };
406 
407 static int
408 log_rec(void *data, void *arg)
409 {
410  ShortHist_T *p = (ShortHist_T *) data;
411  time_t now = time(NULL);
412  int tr, ti, i, j;
413  int fd;
414  int count[LH_MAX];
415  bool ok = FALSE;
416  browse_T *results = (browse_T *) arg;
417 
418  if (data == NULL)
419  return 0;
420 
421  if (results == NULL)
422  return 0;
423 
424  fd = results->fd;
425 #if 0
426  now = results->now;
427 #endif
428 
429  tr = NB_MAJOR(now);
430  ti = NB_MINOR(now);
431 
432  results->nrec++;
433 
434  memset(count, 0, sizeof (count));
435  for (i = 0; i < K_MIN; i++) {
436  if (p->bucket[i].t + K_MIN >= tr) {
437  for (j = 0; j < LH_MAX; j++) {
438  count[j] += p->bucket[i].count[j];
439  results->count[j] += p->bucket[i].count[j];
440  }
441  }
442  }
443  for (j = 0; j < LH_MAX; j++)
444  if (count[j] > 0)
445  ok = TRUE;
446 
447  if (ok) {
448  char *s = "", nodename[128];
449 
450  FD_PRINTF(fd, " %-17s :", p->ip);
451  for (j = 1; j < LH_MAX; j++)
452  FD_PRINTF(fd, " %9d", count[j]);
453 
454  if (results->ip_resolve) {
455  s = nodename;
456  *s = '\0';
457  CACHE_GETHOSTNAMEBYADDR(p->ip, nodename, sizeof (nodename), FALSE);
458  }
459 
460  FD_PRINTF(fd, " : %s\n", s);
461 
462  results->nok++;
463  }
464 
465  return ok;
466 }
467 
468 void
470  int fd;
471  bool resolve;
472 {
473  int nb = 0, nbt = 0;
474  time_t now = time(NULL);
475  char buf[256];
476 
477  browse_T results;
478 
479  if (!livehistory_init())
480  return;
481 
482  if (fd < 0)
483  fd = STDOUT_FILENO;
484 
485  DATA_LOCK();
486 
487  memset(&results, 0, sizeof (results));
488 
489  results.fd = fd;
490  results.now = now;
491  results.ip_resolve = resolve;
492 
493  FD_PRINTF(fd, "%-20s : %s\n", "Version", PACKAGE);
494  ctime_r(&now, buf);
495  FD_PRINTF(fd, "*** LIVE HISTORY %s\n", buf);
496  FD_PRINTF(fd, " %-17s : %s\n", "HOST IP",
497  "..BADRCPT .SPAMTRAP EMPTYCONN EMPTYMSGS ....BADMX .LONGCONN");
498 
499  nb = zeBTree_Browse(&hdata.db_empty, log_rec, &results);
500 
501  {
502  int i;
503  char buf[256];
504 
505  zeStrSet(buf, '-', (LH_MAX - 1) * 10);
506  FD_PRINTF(fd, " %-17s %s\n", "", buf);
507  FD_PRINTF(fd, " %-17s :", "");
508 
509  for (i = 1; i < LH_MAX; i++)
510  FD_PRINTF(fd, " %9d", results.count[i]);
511  FD_PRINTF(fd, "\n");
512  FD_PRINTF(fd, " %-17s : %s\n", "",
513  "..BADRCPT .SPAMTRAP EMPTYCONN EMPTYMSGS ....BADMX .LONGCONN");
514  }
515 
516  nbt = results.nrec;
517 
518  DATA_UNLOCK();
519 
520  FD_PRINTF(fd, "\n %d/%d entries on database\n", nb, nbt);
521 }
522 
523 
524 /* ****************************************************************************
525  * *
526  * *
527  **************************************************************************** */
#define K_MIN
void livehistory_log_table(int fd, bool resolve)
struct Bucket_T bucket[K_MIN]
#define DATA_LOCK()
long count[LH_MAX]
#define CACHE_GETHOSTNAMEBYADDR(ip, name, size, query)
Definition: ze-filter.h:186
void * zeBTree_Get(ZEBT_T *, void *)
Definition: zeBTree.c:281
#define DTCLEANUP
char ip[SZ_IP]
#define JBT_INITIALIZER
Definition: zeBTree.h:85
bool zeBTree_Init(ZEBT_T *, size_t, ZEBT_CMP_F)
Definition: zeBTree.c:96
#define NB_BTCLEANUP
Definition: zeBTree.h:70
bool livehistory_clean_table()
int livehistory_add_entry(char *ip, time_t now, int n, int what)
int livehistory_check_host(char *ip, time_t win, int what)
bool zeBTree_Add(ZEBT_T *, void *)
Definition: zeBTree.c:309
pthread_mutex_t mutex
#define FALSE
Definition: macros.h:160
#define strlcpy
Definition: zeString.h:32
#define ZE_LogMsgError(level,...)
Definition: zeSyslog.h:113
struct Bucket_T bucket[K_MIN]
int ip_strcmp(char *, char *)
Definition: ze-inet.c:141
#define LH_MAX
bool zeBTree_Destroy(ZEBT_T *)
Definition: zeBTree.c:192
#define FD_PRINTF(fdp,...)
Definition: macros.h:45
#define SZ_IP
Definition: ze-libjc.h:77
int nb[RATE_DIM]
Definition: ze-smtprate.c:100
time_t t
#define NB_MINOR(i)
int zeBTree_Count(ZEBT_T *)
Definition: zeBTree.c:245
char * zeStrSet(char *, int, int)
Definition: zeStrings.c:330
struct Bucket_T Bucket_T
time_t now
bool zeBTree_Cpy(ZEBT_T *, ZEBT_T *, ZEBT_SEL_F, void *)
Definition: zeBTree.c:515
ZEBT_T db_empty
#define TRUE
Definition: macros.h:157
time_t last
Definition: ze-smtprate.c:101
JSOCKADDR_T addr
bool ip_resolve
int count[LH_MAX]
#define NB_MAJOR(i)
#define PACKAGE
Definition: version.h:28
#define DATA_UNLOCK()
void livehistory_reset()
struct ShortHist_T ShortHist_T
bool ok
time_t dtms
int zeBTree_Browse(ZEBT_T *, ZEBT_BROWSE_F, void *)
Definition: zeBTree.c:262
Definition: zeBTree.h:73