source: trunk/src/sh_log_repeat.c@ 340

Last change on this file since 340 was 272, checked in by katerina, 15 years ago

Fixes tickets #190, #191, #192, #193, and #194.

File size: 13.4 KB
Line 
1#include "config_xor.h"
2
3#ifdef USE_LOGFILE_MONITOR
4
5#include <string.h>
6#include <ctype.h>
7
8#undef FIL__
9#define FIL__ _("sh_log_repeat.c")
10
11#include "samhain.h"
12#include "sh_pthread.h"
13#include "sh_utils.h"
14#include "sh_string.h"
15#include "sh_log_check.h"
16#include "sh_log_evalrule.h"
17
18#define SH_NHIST 12
19#define SH_NFINT 5
20#define SH_NFIELDS 5*sizeof(SINT32) /* 16 */
21#define SH_NBLOCK 63
22
23typedef enum
24{
25 SH_GFLAG_EMAIL = 1 << 0,
26 SH_GFLAG_PATH = 1 << 1,
27 SH_GFLAG_IP = 1 << 2,
28 SH_GFLAG_FQDN = 1 << 3,
29 SH_GFLAG_NUM = 1 << 4,
30 SH_GFLAG_ELSE = 1 << 5,
31
32 SH_GFLAG_XNUM = 1 << 6,
33 SH_GFLAG_CHAR = 1 << 7,
34 SH_GFLAG_USC = 1 << 8
35} SH_GFlags;
36
37
38/* 64 bytes
39 */
40struct gestalt {
41 unsigned char hist[SH_NHIST]; /* time histogram 12 minutes */
42 union {
43 unsigned char flags[SH_NFIELDS]; /* flags indicating field type */
44 SINT32 flint[SH_NFINT];
45 } f;
46 UINT16 sum[SH_NFIELDS]; /* checksum of field */
47 UINT16 ltime; /* last time, in minutes */
48 UINT16 total; /* seen how often? */
49};
50
51static unsigned int nrec = 0; /* size of array */
52static unsigned int urec = 0; /* in use thereof */
53static struct gestalt * arec = NULL; /* array */
54
55static int repeat_count = 24; /* triggers report */
56static int clean_counter = 0; /* cleanup after N inserts */
57static int free_slots = 0; /* free slots available */
58
59#define SH_CLEANUP 256
60
61static struct gestalt * add_entry (unsigned char * flags, UINT16 * sum,
62 time_t ltime)
63{
64 struct gestalt * array = NULL;
65
66 start:
67 if (urec < nrec)
68 {
69 if (free_slots)
70 {
71 unsigned int i;
72 for (i = 0; i < urec; ++i)
73 {
74 if (arec[i].total == 0)
75 {
76 array = &arec[i];
77 --free_slots;
78 break;
79 }
80 }
81 }
82
83 if (!array)
84 {
85 array = &arec[urec];
86 ++urec;
87 }
88
89 memcpy(array->sum, sum, sizeof(UINT16) * SH_NFIELDS);
90 memcpy(array->f.flags, flags, sizeof(unsigned char) * SH_NFIELDS);
91 memset(array->hist, 0, sizeof(unsigned char) * SH_NHIST);
92
93 array->ltime = (UINT16)(ltime % 60);
94 array->hist[SH_NHIST-1] = 1;
95 array->total = 1;
96
97 ++clean_counter;
98 return array;
99 }
100
101 array = SH_ALLOC(sizeof(struct gestalt) * (nrec + SH_NBLOCK + 1));
102 memset(array, 0, sizeof(struct gestalt) * (nrec + SH_NBLOCK + 1));
103 memcpy(array, arec, sizeof(struct gestalt) * (nrec));
104
105 nrec += (SH_NBLOCK + 1);
106 goto start;
107}
108
109static UINT16 shift_history(unsigned char * hist, unsigned int shift,
110 UINT16 total)
111{
112 unsigned int i, j = 0;
113
114 if (shift >= SH_NHIST)
115 {
116 memset(hist, 0, sizeof(unsigned char) * SH_NHIST);
117 return 0;
118 }
119
120 for (i = shift; i < SH_NHIST; ++i)
121 {
122 if (j < shift)
123 total -= hist[j];
124 hist[j] = hist[i];
125 ++j;
126 }
127 for (i = (SH_NHIST-shift); i < SH_NHIST; ++i)
128 {
129 hist[i] = 0;
130 }
131 return total;
132}
133
134static void update_entry (struct gestalt * array, time_t ltime)
135{
136 UINT16 ntime = (UINT16)(ltime % 60);
137
138 if (array->ltime == ntime)
139 {
140 if (array->hist[SH_NHIST-1] < 255)
141 {
142 ++(array->hist[SH_NHIST-1]);
143 ++(array->total);
144 }
145 }
146 else if (array->ltime < ntime)
147 {
148 unsigned int shift = ntime - array->ltime;
149 array->total = shift_history(array->hist, shift, array->total);
150 array->hist[SH_NHIST-1] = 1;
151 array->ltime = ntime;
152 ++(array->total);
153 }
154}
155
156static struct gestalt * update_or_add (unsigned char * flags, UINT16 * sum,
157 time_t ltime)
158{
159 SINT32 flint[SH_NFINT];
160 start:
161
162 if (arec)
163 {
164 unsigned int i;
165 struct gestalt * array = arec;
166
167 memcpy(flint, flags, SH_NFIELDS);
168
169 for (i = 0; i < urec; ++i)
170 {
171 /* Check whether field types match. Integer
172 * comparison is much faster than memcmp() [tested].
173 */
174 if (flint[0] == array->f.flint[0] &&
175 flint[1] == array->f.flint[1] &&
176 flint[2] == array->f.flint[2] &&
177 flint[3] == array->f.flint[3] &&
178 flint[4] == array->f.flint[4])
179 {
180 unsigned int j;
181 int c1 = 0, c2 = 0;
182 UINT16 * asum = array->sum;
183
184 for (j = 0; j < SH_NFIELDS; ++j)
185 {
186 if (flags[j] == SH_GFLAG_ELSE)
187 {
188 ++c1;
189 if (asum[j] == sum[j])
190 ++c2;
191 }
192 }
193
194 if (c1 == c2)
195 {
196 /* Found a matching entry, update time histogram
197 */
198 update_entry (array, ltime);
199 return array;
200 }
201 }
202 ++array;
203 }
204
205 /* No match found, create a new entry
206 */
207 array = add_entry (flags, sum, ltime);
208 return array;
209 }
210
211 arec = SH_ALLOC(sizeof(struct gestalt) * SH_NBLOCK);
212 nrec = SH_NBLOCK;
213 urec = 0;
214
215 goto start;
216}
217
218/* --------------------------------------------------------------------
219 *
220 * crc16 checksum from the linux kernel.
221 * This source code is licensed under the GNU General Public License,
222 * Version 2.
223 */
224
225/** CRC table for the CRC-16. The poly is 0x8005 (x^16 + x^15 + x^2 + 1) */
226UINT16 const crc16_table[256] = {
227 0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241,
228 0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440,
229 0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40,
230 0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841,
231 0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40,
232 0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41,
233 0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641,
234 0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040,
235 0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240,
236 0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441,
237 0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41,
238 0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840,
239 0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41,
240 0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40,
241 0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640,
242 0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041,
243 0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240,
244 0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441,
245 0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41,
246 0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840,
247 0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41,
248 0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40,
249 0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640,
250 0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041,
251 0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241,
252 0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440,
253 0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40,
254 0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841,
255 0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40,
256 0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41,
257 0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641,
258 0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040
259};
260
261static inline UINT16 crc16_byte(UINT16 crc, const unsigned char data)
262{
263 return (crc >> 8) ^ crc16_table[(crc ^ data) & 0xff];
264}
265
266/**
267 * crc16 - compute the CRC-16 for the data buffer
268 * @crc: previous CRC value
269 * @buffer: data pointer
270 * @len: number of bytes in the buffer
271 *
272 * Returns the updated CRC value.
273 */
274static inline UINT16 crc16(UINT16 crc, const unsigned char * buffer,
275 size_t len)
276{
277 while (len--)
278 crc = crc16_byte(crc, *buffer++);
279 return crc;
280}
281
282
283/* end crc16 code
284 *
285 * -------------------------------------------------------------------- */
286
287static void classify(char ** splits, size_t * lengths, unsigned int nfields,
288 unsigned char * flags, UINT16 * sums)
289{
290 unsigned int i;
291 unsigned int flag;
292
293 /* flags we don't want to see in XYZ
294 */
295 static int m_ip = SH_GFLAG_PATH|SH_GFLAG_EMAIL|SH_GFLAG_USC|SH_GFLAG_ELSE|SH_GFLAG_CHAR|SH_GFLAG_XNUM;
296 static int m_num = SH_GFLAG_PATH|SH_GFLAG_EMAIL|SH_GFLAG_USC|SH_GFLAG_ELSE|SH_GFLAG_CHAR;
297 static int m_fqdn = SH_GFLAG_PATH|SH_GFLAG_EMAIL|SH_GFLAG_USC|SH_GFLAG_ELSE;
298 static int m_email = SH_GFLAG_PATH;
299
300 nfields = (nfields > SH_NFIELDS) ? SH_NFIELDS : nfields;
301
302 for (i = 0; i < nfields; ++i)
303 {
304 char *p = splits[i];
305 unsigned int np = 0;
306 unsigned int fqdn = 0;
307
308 flag = 0;
309
310 while (*p)
311 {
312 if (isxdigit((unsigned int)*p))
313 {
314 if (isdigit((unsigned int)*p))
315 {
316 flag |= SH_GFLAG_NUM;
317 }
318 else
319 {
320 flag |= SH_GFLAG_XNUM;
321 }
322 }
323 else if (*p == '.')
324 {
325 flag |= SH_GFLAG_IP;
326 ++np;
327 }
328 else if (*p == '/')
329 {
330 flag |= SH_GFLAG_PATH;
331 }
332 else if (*p == '@')
333 {
334 flag |= SH_GFLAG_EMAIL;
335 }
336 else if (*p == '-')
337 {
338 flag |= SH_GFLAG_FQDN;
339 }
340 else if (*p == '_')
341 {
342 flag |= SH_GFLAG_USC;
343 }
344 else if (isalpha((unsigned int)*p))
345 {
346 if (flag & SH_GFLAG_IP)
347 ++fqdn;
348 flag |= SH_GFLAG_CHAR;
349 }
350 else if (!isascii((unsigned int)*p))
351 {
352 flags[i] = SH_GFLAG_ELSE;
353 break;
354 }
355 else
356 {
357 flag |= SH_GFLAG_ELSE;
358 }
359 ++p;
360 }
361
362 if (flags[i] == 0)
363 {
364 if (0 == (flag & m_ip) &&
365 0 != (flag & SH_GFLAG_IP) &&
366 0 != (flag & SH_GFLAG_NUM) &&
367 np > 2)
368 {
369 flags[i] = SH_GFLAG_IP;
370 }
371 else if (0 == (flag & m_num) &&
372 (0 != (flag & SH_GFLAG_NUM) || 0 != (flag & SH_GFLAG_XNUM)))
373 {
374 flags[i] = SH_GFLAG_NUM;
375 }
376 else if (0 == (flag & m_fqdn) &&
377 0 != (flag & SH_GFLAG_IP) &&
378 0 != (flag & SH_GFLAG_CHAR) &&
379 fqdn)
380 {
381 flags[i] = SH_GFLAG_FQDN;
382 }
383 else if ('/' == splits[i][0])
384 {
385 flags[i] = SH_GFLAG_PATH;
386 }
387 else if (0 == (flag & m_email) &&
388 0 != (flag & SH_GFLAG_EMAIL) &&
389 0 != (flag & SH_GFLAG_CHAR))
390 {
391 flags[i] = SH_GFLAG_EMAIL;
392 }
393 else
394 {
395 flags[i] = SH_GFLAG_ELSE;
396 }
397 }
398
399 /* CRC-16 checksum
400 */
401 sums[i] = crc16(0, (unsigned char *) splits[i], lengths[i]);
402 }
403
404 return;
405}
406
407static void cleanup_array (time_t ltime)
408{
409 UINT16 ntime = (UINT16)(ltime % 60);
410
411 if (ntime > 12) ntime -= 12;
412
413 if (arec && urec > 0)
414 {
415 struct gestalt * array;
416 unsigned int i, last, urec_orig = urec;
417
418 last = urec-1;
419 array = &arec[0];
420
421 for (i = 0; i < urec_orig; ++i)
422 {
423 if (array->ltime < ntime)
424 {
425 memset(array, 0, sizeof(struct gestalt));
426 if (i != last)
427 ++free_slots;
428 else
429 --urec;
430 }
431 }
432 ++array;
433 }
434 clean_counter = 0;
435 return;
436}
437
438/* ----------------------------------------------------------------------
439 *
440 * Public functions
441 */
442
443int sh_repeat_set_trigger (const char * str)
444{
445 unsigned long value;
446 char * foo;
447
448 value = (size_t) strtoul(str, &foo, 0);
449
450 if (*foo == '\0' && value < 65535) {
451 repeat_count = value;
452 return 0;
453 }
454 return -1;
455}
456
457static char * sh_repeat_queue = NULL;
458
459int sh_repeat_set_queue (const char * str)
460{
461 if (!str)
462 return -1;
463 if (sh_repeat_queue)
464 SH_FREE(sh_repeat_queue);
465 sh_repeat_queue = sh_util_strdup(str);
466 return 0;
467}
468
469static int sh_repeat_cron = S_FALSE;
470
471int sh_repeat_set_cron (const char * str)
472{
473 return sh_util_flagval(str, &sh_repeat_cron);
474}
475
476int sh_repeat_message_check (const sh_string * host,
477 const sh_string * msg,
478 time_t ltime)
479{
480 struct gestalt * array;
481
482 UINT16 sums[SH_NFIELDS] = { 0 };
483 unsigned char flags[SH_NFIELDS] = { 0 };
484
485 /* split message into SH_NFIELDS+1, discard last */
486
487 unsigned int nfields = SH_NFIELDS+1;
488 size_t lengths[SH_NFIELDS+1];
489 char * new;
490 char ** splits;
491
492 if (repeat_count == 0)
493 return 0;
494
495 if (sh_repeat_cron == S_FALSE)
496 {
497 char * s = sh_string_str(msg);
498
499 if (0 == strcmp(s, _("cron")) || 0 == strcmp(s, _("CRON")))
500 return 0;
501 }
502
503 new = sh_util_strdup_l(sh_string_str(msg), sh_string_len(msg));
504
505 splits = split_array_token (new, &nfields, lengths,
506 " :,()='[]<>\t\n");
507
508 /* classify fields */
509
510 classify (splits, lengths, nfields, flags, sums);
511
512 /* compare */
513
514 array = update_or_add (flags, sums, ltime);
515
516 /* report */
517
518 if (array->total > repeat_count)
519 {
520 volatile int repeat = array->total;
521 char * tmpmsg;
522 char * tmphost;
523 sh_string * alias;
524
525 /* issue report */
526
527 SH_MUTEX_LOCK(mutex_thread_nolog);
528 tmphost = sh_util_safe_name (sh_string_str(host));
529 tmpmsg = sh_util_safe_name_keepspace (sh_string_str(msg));
530 sh_error_handle (sh_log_lookup_severity(sh_repeat_queue),
531 FIL__, __LINE__, 0, MSG_LOGMON_BURST,
532 repeat, tmpmsg, tmphost);
533 alias = sh_log_lookup_alias(sh_repeat_queue);
534 if (alias)
535 {
536 sh_error_mail (sh_string_str(alias),
537 sh_log_lookup_severity(sh_repeat_queue),
538 FIL__, __LINE__, 0, MSG_LOGMON_BURST,
539 repeat, tmpmsg, tmphost);
540 }
541 SH_FREE(tmpmsg);
542 SH_FREE(tmphost);
543 SH_MUTEX_UNLOCK(mutex_thread_nolog);
544
545 /* mark slot as free */
546
547 memset(array, 0, sizeof(struct gestalt));
548 if (array != &arec[urec-1])
549 ++free_slots;
550 else
551 urec -= 1;
552 }
553
554 SH_FREE(new);
555
556 /* run cleanup routine */
557
558 if (clean_counter >= SH_CLEANUP)
559 {
560 cleanup_array(ltime);
561 }
562
563 return 0;
564}
565
566#endif
Note: See TracBrowser for help on using the repository browser.