ze-filter  (ze-filter-0.8.0-develop-180218)
ze-throttle.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 #define LOG_LEVEL 11
34 
35 typedef struct HStat_T {
36  time_t date;
37  int nb;
38 } HStat_T;
39 
40 
41 
42 /*
43  DIM_HI number of seconds of connection counting
44  DIM_SHFT log2(DIM_RAP)
45  DIM_LO number of normalised minutes of counting
46  DIM_RAP number of seconds in a normalised minute
47 */
48 #define DIM_HI 1024
49 #define DIM_SHFT 6
50 #define DIM_LO (DIM_HI >> DIM_SHFT)
51 #define DIM_RAP (DIM_HI / DIM_LO)
52 
53 
54 struct ThrottleData {
55  bool ok;
56 
57  pthread_mutex_t mutex;
58 
61 };
62 
63 typedef struct ThrottleData ThrottleData;
64 
65 static ThrottleData hdata = { FALSE, PTHREAD_MUTEX_INITIALIZER };
66 
67 #define THROTTLE_LOCK() \
68  if (pthread_mutex_lock(&hdata.mutex) != 0) { \
69  ZE_LogSysError("pthread_mutex_lock"); \
70  }
71 
72 #define THROTTLE_UNLOCK() \
73  if (pthread_mutex_unlock(&hdata.mutex) != 0) { \
74  ZE_LogSysError("pthread_mutex_unlock"); \
75  }
76 
77 
78 
79 /* ****************************************************************************
80  * *
81  * *
82  **************************************************************************** */
83 void add_throttle_entry(time_t);
84 void update_throttle(time_t);
85 
86 double poisson_upper_bound(double, double);
87 
88 /* ****************************************************************************
89  * *
90  * *
91  **************************************************************************** */
92 static bool
93 throttle_init()
94 {
95  if (hdata.ok)
96  return TRUE;
97 
98  THROTTLE_LOCK();
99 
100  if (!hdata.ok) {
101  /*
102  * Initialisation of connection rate statistics
103  */
104  memset(hdata.sec, 0, sizeof (hdata.sec));
105  memset(hdata.min, 0, sizeof (hdata.min));
106  hdata.ok = TRUE;
107  }
108 
109  THROTTLE_UNLOCK();
110 
111  return TRUE;
112 }
113 
114 /* ****************************************************************************
115  * *
116  * *
117  **************************************************************************** */
118 void
120 {
121  THROTTLE_LOCK();
122 
123 
124  THROTTLE_UNLOCK();
125 }
126 
127 /* ****************************************************************************
128  * *
129  * *
130  **************************************************************************** */
131 int
133  size_t sza;
134  size_t szb;
135 {
136  throttle_free();
137  return throttle_init();
138 }
139 
140 
141 
142 /* ****************************************************************************
143  * *
144  * *
145  **************************************************************************** */
146 
147 void
149  time_t t;
150 {
151  int i;
152 
153  throttle_init();
154 
155  THROTTLE_LOCK();
156 
157  i = t % DIM_HI;
158 
159  if (hdata.sec[i].date != t) {
160  hdata.sec[i].date = t;
161  hdata.sec[i].nb = 0;
162  }
163  hdata.sec[i].nb++;
164 
165  t >>= DIM_SHFT;
166  i = t % DIM_LO;
167 
168  if (hdata.min[i].date != t) {
169  hdata.min[i].date = t;
170  hdata.min[i].nb = 0;
171  }
172  hdata.min[i].nb++;
173 
174  THROTTLE_UNLOCK();
175 }
176 
177 /* ****************************************************************************
178  * *
179  * *
180  **************************************************************************** */
181 static kstats_T st_sec;
182 static kstats_T st_min;
183 static time_t st_last = 0;
184 
185 void
187  time_t t;
188 {
189  int i, j;
190  time_t t0, ti;
191 
192  if (t < DIM_HI)
193  return;
194 
195  THROTTLE_LOCK();
196 
197  st_last = t;
198 
199  memset(hdata.min, 0, sizeof (hdata.min));
200 
201  t0 = t + 1 - DIM_HI;
202 
203  for (ti = t0; ti < t + 1; ti++) {
204  i = ti % DIM_HI;
205  if (hdata.sec[i].date != ti) {
206  hdata.sec[i].date = ti;
207  hdata.sec[i].nb = 0;
208  }
209  j = ((ti - t0) >> DIM_SHFT);
210 
211  hdata.min[j].nb += hdata.sec[i].nb;
212  }
213  zeKStatsReset(&st_sec);
214  zeKStatsReset(&st_min);
215 
216  for (i = 0; i < DIM_HI; i++)
217  zeKStatsUpdate(&st_sec, (double) hdata.sec[i].nb);
218 
219  for (i = 0; i < DIM_LO; i++)
220  zeKStatsUpdate(&st_min, (double) hdata.min[i].nb);
221 
222  ZE_MessageInfo(12,
223  "THROTTLE : short=[%7.3f/%7.3f] long=[%7.3f/%7.3f] (mean/std dev)",
224  zeKMean(&st_sec), zeKStdDev(&st_sec), zeKMean(&st_min),
225  zeKStdDev(&st_min));
226 
227  THROTTLE_UNLOCK();
228 
230 }
231 
232 /* ****************************************************************************
233  * *
234  * *
235  **************************************************************************** */
236 static bool dos_current = FALSE;
237 
238 bool
240 {
241  return dos_current;
242 }
243 
244 /* ****************************************************************************
245  * *
246  * *
247  **************************************************************************** */
248 #define HOLD_TIME 120
249 
250 static time_t dos_start_time = 0;
251 static time_t dos_last_log = 0;
252 
253 #define DOS_COEF 5.0
254 
255 bool
257 {
258  double mean, gmean;
259  double stddev;
260  double last_mean = (double) hdata.min[DIM_LO - 1].nb;
261  int i;
262  kstats_T stats;
263 
264  zeKStatsReset(&stats);
265 
266  THROTTLE_LOCK();
267  for (i = 0; i < (DIM_LO - 1); i++)
268  zeKStatsUpdate(&stats, (double) hdata.min[i].nb);
269  last_mean = (double) hdata.min[DIM_LO - 1].nb;
270  THROTTLE_UNLOCK();
271 
272  gmean = mean = zeKMean(&stats);
273  stddev = zeKStdDev(&stats);
274 
275  /*
276  * shall see this again later
277  */
278  dos_current = FALSE;
279 
280  if (gmean < 10)
281  gmean = 10;
282 
283  if (last_mean > gmean + DOS_COEF * sqrt(gmean)) {
284  time_t now = time(NULL);
285 
286  if (!dos_current)
287  dos_start_time = now;
288 
289  if ((dos_last_log == (time_t) 0) && (dos_last_log + HOLD_TIME < now)) {
290  ZE_MessageInfo(LOG_LEVEL, "*** DoS - THROTTLE : %7.3f %7.3f %7.3f",
291  mean, stddev, last_mean);
292  dos_last_log = now;
293  }
294  dos_current = TRUE;
295  return TRUE;
296  } else {
297  if (dos_last_log != (time_t) 0) {
298  ZE_MessageInfo(LOG_LEVEL, "*** DoS - THROTTLE : END");
299  dos_last_log = (time_t) 0;
300  }
301  dos_start_time = (time_t) 0;
302  }
303 
304  return FALSE;
305 }
306 
307 
308 /* ****************************************************************************
309  * *
310  * *
311  **************************************************************************** */
312 void
314 {
315  double mean = zeKMean(&st_min);
316  double stddev = zeKStdDev(&st_min);
317 
318  double last_mean = (double) hdata.min[DIM_LO - 1].nb;
319 
321  ZE_MessageInfo(9, "THROTTLE STAT : %7.3f %7.3f %7.3f", mean, stddev,
322  last_mean);
323 }
324 
325 /* ****************************************************************************
326  * *
327  * *
328  **************************************************************************** */
329 double
330 poisson_upper_bound(lambda, prob)
331  double lambda;
332  double prob;
333 {
334  double sum, tmp;
335  int i = 0;
336 
337  sum = tmp = exp(-lambda);
338 
339  while (sum < prob) {
340  i++;
341  tmp *= lambda / i;
342  sum += tmp;
343  }
344  printf(" i : %3d - sum : %7.5f\n", i, sum);
345  return i;
346 }
#define LOG_LEVEL
Definition: ze-throttle.c:33
HStat_T sec[DIM_HI]
Definition: ze-throttle.c:59
void add_throttle_entry(time_t)
Definition: ze-throttle.c:148
void zeKStatsReset(kstats_T *)
Definition: zeKStats.c:92
#define DIM_HI
Definition: ze-throttle.c:48
#define HOLD_TIME
Definition: ze-throttle.c:248
#define FALSE
Definition: macros.h:160
void throttle_free()
Definition: ze-throttle.c:119
struct HStat_T HStat_T
#define OPT_YES
Definition: ze-cf.h:45
void update_throttle(time_t)
Definition: ze-throttle.c:186
int cf_get_int(int id)
Definition: ze-cf.c:803
#define DOS_COEF
Definition: ze-throttle.c:253
time_t date
Definition: ze-throttle.c:36
#define CF_LOG_THROTTLE
Definition: cfh-defs.h:60
#define THROTTLE_UNLOCK()
Definition: ze-throttle.c:72
HStat_T min[DIM_LO]
Definition: ze-throttle.c:60
#define THROTTLE_LOCK()
Definition: ze-throttle.c:67
void zeKStatsUpdate(kstats_T *, double)
Definition: zeKStats.c:101
pthread_mutex_t mutex
Definition: ze-throttle.c:57
#define ZE_MessageInfo(level,...)
Definition: zeSyslog.h:90
#define TRUE
Definition: macros.h:157
void log_throttle_stats()
Definition: ze-throttle.c:313
bool check_throttle_dos()
Definition: ze-throttle.c:239
#define DIM_LO
Definition: ze-throttle.c:50
#define min(a, b)
Definition: macros.h:128
int throttle_resize(size_t sza, size_t szb)
Definition: ze-throttle.c:132
double poisson_upper_bound(double, double)
Definition: ze-throttle.c:330
int nb
Definition: ze-throttle.c:37
double zeKMean(kstats_T *s)
Definition: zeKStats.c:43
double zeKStdDev(kstats_T *s)
Definition: zeKStats.c:53
#define DIM_SHFT
Definition: ze-throttle.c:49
bool update_throttle_dos()
Definition: ze-throttle.c:256