source: trunk/src/sh_log_correlate.c@ 435

Last change on this file since 435 was 358, checked in by katerina, 13 years ago

Patch for ticket #264 (Add a deadtime for correlate rules to avoid multiple reports).

File size: 7.6 KB
Line 
1#include "config_xor.h"
2
3#ifdef USE_LOGFILE_MONITOR
4
5#undef FIL__
6#define FIL__ _("sh_log_correlate.c")
7
8#include <string.h>
9#include <time.h>
10
11/* Debian/Ubuntu: libpcre3-dev */
12#ifdef HAVE_PCRE_PCRE_H
13#include <pcre/pcre.h>
14#else
15#include <pcre.h>
16#endif
17
18#ifndef PCRE_NO_AUTO_CAPTURE
19#define PCRE_NO_AUTO_CAPTURE 0
20#endif
21
22#include "samhain.h"
23#include "sh_pthread.h"
24#include "sh_utils.h"
25#include "sh_string.h"
26#include "sh_log_check.h"
27#include "sh_log_evalrule.h"
28
29extern int flag_err_debug;
30
31/*--------------------------------------------------------------
32 *
33 * Event correlation
34 *
35 *--------------------------------------------------------------*/
36
37/* For each even to be correlated, we keep a label in a list. We
38 * then build a string from the (time-sorted) list of labels, and
39 * match this string against a regular expression.
40 */
41
42/* -- The list of labels kept in memory ----------------------- */
43
44struct sh_keep
45{
46 sh_string * label; /* label of keep rule */
47 unsigned long delay; /* valid delay */
48 time_t last; /* seen at */
49 struct sh_keep * next;
50};
51
52static struct sh_keep * keeplist = NULL;
53static struct sh_keep * keeplast = NULL;
54static unsigned long keepcount = 0;
55
56static void sh_keep_free(void * item)
57{
58 struct sh_keep * keep = (struct sh_keep *) item;
59
60 if (!keep)
61 return;
62 sh_string_destroy(&(keep->label));
63 SH_FREE(keep);
64}
65
66void sh_keep_destroy()
67{
68 struct sh_keep * keep;
69
70 while (keeplist)
71 {
72 keep = keeplist;
73 keeplist = keep->next;
74 sh_keep_free(keep);
75 --keepcount;
76 }
77 keeplist = NULL;
78 keeplast = NULL;
79 keepcount = 0;
80}
81
82int sh_keep_add(sh_string * label, unsigned long delay, time_t last)
83{
84 struct sh_keep * keep = SH_ALLOC(sizeof(struct sh_keep));
85
86 keep->label = sh_string_copy(label);
87 keep->delay = delay;
88 keep->last = last;
89 keep->next = NULL;
90
91 if (keeplast && keeplist)
92 {
93 keeplast->next = keep;
94 keeplast = keep;
95 }
96 else
97 {
98 keeplist = keep;
99 keeplast = keeplist;
100 }
101 ++keepcount;
102 return 0;
103}
104
105int sh_keep_comp(const void * a, const void * b)
106{
107 return ( (int)(((struct sh_keep *)a)->last) -
108 (int)(((struct sh_keep *)b)->last) );
109}
110
111/* -- Sort the kept labels and build a string ----------------- */
112
113static sh_string * sh_keep_eval()
114{
115 unsigned long count = 0;
116 sh_string * res = NULL;
117 time_t now = time(NULL);
118 struct sh_keep * keep = keeplist;
119 struct sh_keep * prev = keeplist;
120 struct sh_keep * arr;
121
122 if (keepcount > 0)
123 {
124 arr = SH_ALLOC (keepcount * sizeof(struct sh_keep));
125
126 while (count < keepcount && keep)
127 {
128 if ((now >= keep->last) &&
129 ((unsigned long)(now - keep->last) <= keep->delay))
130 {
131 memcpy(&(arr[count]), keep, sizeof(struct sh_keep));
132 ++count;
133 prev = keep;
134 keep = keep->next;
135 }
136 else /* Too old or in future, delete it */
137 {
138 if (keep != keeplist)
139 {
140 prev->next = keep->next;
141 sh_keep_free(keep);
142 keep = prev->next;
143 --keepcount;
144 }
145 else /* list head */
146 {
147 keeplist = keep->next;
148 prev = keeplist;
149 sh_keep_free(keep);
150 keep = keeplist;
151 --keepcount;
152 }
153 }
154 }
155
156 if (count > 0)
157 {
158 unsigned long i;
159 qsort(arr, count, sizeof(struct sh_keep), sh_keep_comp);
160 res = sh_string_copy(arr[0].label);
161 for (i = 1; i < count; ++i)
162 res = sh_string_add(res, arr[i].label);
163 }
164 SH_FREE(arr);
165 }
166
167 return res;
168}
169
170/* -- Match the string against correlation rules -------------- */
171
172struct sh_mkeep
173{
174 sh_string * label; /* label of match rule */
175 pcre * rule; /* compiled regex for rule */
176 time_t reported; /* last reported */
177 struct sh_qeval * queue; /* assigned queue */
178 struct sh_mkeep * next;
179};
180
181struct sh_mkeep * mkeep_list = NULL;
182unsigned long mkeep_deadtime = 60;
183
184int sh_keep_deadtime (const char * str)
185{
186 unsigned long value;
187 char * foo;
188
189 value = (size_t) strtoul(str, &foo, 0);
190
191 if (*foo == '\0') {
192 mkeep_deadtime = value;
193 return 0;
194 }
195 return -1;
196}
197
198int sh_keep_match_add(const char * str, const char * queue,
199 const char * pattern)
200{
201 unsigned int nfields = 1; /* seconds:label */
202 size_t lengths[1];
203 char * new = sh_util_strdup(str);
204 char ** splits = split_array_braced(new, _("CORRELATE"),
205 &nfields, lengths);
206
207 if (nfields == 1 && lengths[0] > 0)
208 {
209 struct sh_mkeep * mkeep = SH_ALLOC(sizeof(struct sh_mkeep));
210 const char * error;
211 int erroffset;
212 struct sh_qeval * rqueue = NULL;
213
214 mkeep->rule = pcre_compile(pattern, PCRE_NO_AUTO_CAPTURE,
215 &error, &erroffset, NULL);
216 if (!(mkeep->rule))
217 {
218 sh_string * msg = sh_string_new(0);
219 sh_string_add_from_char(msg, _("Bad regex: "));
220 sh_string_add_from_char(msg, pattern);
221
222 SH_MUTEX_LOCK(mutex_thread_nolog);
223 sh_error_handle(SH_ERR_ERR, FIL__, __LINE__, 0, MSG_E_SUBGEN,
224 sh_string_str(msg),
225 _("sh_keep_match_add"));
226 SH_MUTEX_UNLOCK(mutex_thread_nolog);
227 sh_string_destroy(&msg);
228
229 SH_FREE(splits);
230 SH_FREE(mkeep);
231 SH_FREE(new);
232 return -1;
233 }
234
235 if (0 != strcmp(queue, _("trash")))
236 {
237
238 rqueue = sh_log_find_queue(queue);
239 if (!rqueue)
240 {
241 pcre_free(mkeep->rule);
242 SH_FREE(splits);
243 SH_FREE(mkeep);
244 SH_FREE(new);
245 return -1;
246 }
247 }
248
249 mkeep->queue = rqueue;
250 mkeep->label = sh_string_new_from_lchar(splits[0], strlen(splits[0]));
251 mkeep->reported = 0;
252 mkeep->next = mkeep_list;
253 mkeep_list = mkeep;
254 }
255 SH_FREE(new);
256 return 0;
257}
258
259void sh_keep_match_del()
260{
261 struct sh_mkeep * mkeep = mkeep_list;
262 while (mkeep)
263 {
264 mkeep_list = mkeep->next;
265 sh_string_destroy(&(mkeep->label));
266 pcre_free(mkeep->rule);
267 mkeep = mkeep_list;
268 }
269 mkeep_list = NULL;
270}
271
272static struct sh_mkeep ** dummy_mkeep;
273
274void sh_keep_match()
275{
276 if (mkeep_list)
277 {
278 sh_string * res = sh_keep_eval();
279
280 if (res)
281 {
282 struct sh_mkeep * mkeep = mkeep_list;
283
284 dummy_mkeep = &mkeep;
285
286 while (mkeep)
287 {
288 /* Use pcre_dfa_exec() to obtain number of matches. Needs ovector
289 * array, otherwise number of matches is not returned.
290 */
291#if defined(HAVE_PCRE_DFA_EXEC)
292 int ovector[SH_MINIBUF];
293 int wspace[SH_MINIBUF];
294#endif
295
296#if defined(HAVE_PCRE_DFA_EXEC)
297 int val = pcre_dfa_exec(mkeep->rule, NULL,
298 sh_string_str(res),
299 (int)sh_string_len(res),
300 0, /* start at offset 0 in the subject */
301 0,
302 ovector, SH_MINIBUF,
303 wspace, SH_MINIBUF);
304#else
305 int val = pcre_exec(mkeep->rule, NULL,
306 sh_string_str(res),
307 (int)sh_string_len(res),
308 0, /* start at offset 0 in the subject */
309 0,
310 NULL, 0);
311 val = (val >= 0) ? 1 : val;
312#endif
313
314 if (val >= 0)
315 {
316 sh_string * alias;
317 time_t now = time(NULL);
318
319 if ((mkeep->reported < now) &&
320 (mkeep_deadtime < (unsigned int)(now - mkeep->reported)))
321 {
322 mkeep->reported = now;
323
324 SH_MUTEX_LOCK(mutex_thread_nolog);
325 sh_error_handle (mkeep->queue->severity, FIL__, __LINE__, 0,
326 MSG_LOGMON_COR, sh_string_str(mkeep->label),
327 val);
328
329 alias = mkeep->queue->alias;
330 if (alias)
331 {
332 sh_error_mail (sh_string_str(alias),
333 mkeep->queue->severity, FIL__, __LINE__, 0,
334 MSG_LOGMON_COR, sh_string_str(mkeep->label),
335 val);
336 }
337
338 SH_MUTEX_UNLOCK(mutex_thread_nolog);
339 }
340 }
341 mkeep = mkeep->next;
342 }
343 sh_string_destroy(&res);
344 }
345 }
346 return;
347}
348
349#endif
Note: See TracBrowser for help on using the repository browser.