1 /* $Id$ */
2 /*
3 ** Copyright (C) 2014-2021 Cisco and/or its affiliates. All rights reserved.
4 ** Copyright (C) 2003-2013 Sourcefire, Inc.
5 **
6 ** This program is free software; you can redistribute it and/or modify
7 ** it under the terms of the GNU General Public License Version 2 as
8 ** published by the Free Software Foundation. You may not use, modify or
9 ** distribute this program under any other version of the GNU General
10 ** Public License.
11 **
12 ** This program is distributed in the hope that it will be useful,
13 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
14 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 ** GNU General Public License for more details.
16 **
17 ** You should have received a copy of the GNU General Public License
18 ** along with this program; if not, write to the Free Software
19 ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 */
21 /*
22 sfthreshold.c
23
24 This file contains functions that glue the generic thresholding2 code to
25 snort.
26
27 dependent files: sfthd sfxghash sfghash sflsq
28 util mstring
29
30 Marc Norton
31
32 2003-05-29:
33 cmg: Added s_checked variable --
34 when this is 1, the sfthreshold_test will always return the same
35 answer until
36 sfthreshold_reset is called
37
38 2003-11-3:
39 man: cleaned up and added more startup printout.
40 */
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <string.h>
44
45 #ifdef HAVE_CONFIG_H
46 #include "config.h"
47 #endif
48
49 #include "mstring.h"
50 #include "util.h"
51 #include "parser.h"
52
53 #include "sfthd.h"
54 #include "sfthreshold.h"
55 #include "snort.h"
56
57 #ifndef WIN32
58 #include <sys/socket.h>
59 #include <netinet/in.h>
60 #include <arpa/inet.h>
61 #endif
62
63 #include <errno.h>
64
65 /* Data */
66 THD_STRUCT *thd_runtime = NULL;
67
68 static int thd_checked = 0;
69 static int thd_answer = 0;
70
71 typedef enum { PRINT_GLOBAL, PRINT_LOCAL, PRINT_SUPPRESS } PrintFormat;
72
ThresholdConfigNew(void)73 ThresholdConfig * ThresholdConfigNew(void)
74 {
75 ThresholdConfig *tc =
76 (ThresholdConfig *)SnortAlloc(sizeof(ThresholdConfig));
77
78 /* sfthd_objs_new will handle fatal */
79 tc->thd_objs = sfthd_objs_new();
80 tc->memcap = 1024 * 1024;
81 tc->enabled = 1;
82
83 return tc;
84 }
85
ThresholdConfigFree(ThresholdConfig * tc)86 void ThresholdConfigFree(ThresholdConfig *tc)
87 {
88 if (tc == NULL)
89 return;
90
91 if (tc->thd_objs != NULL)
92 {
93 sfthd_objs_free(tc->thd_objs);
94 tc->thd_objs = NULL;
95 }
96
97 free(tc);
98 }
99
100 // prnMode = 0: init output format
101 // prnMode = 1: term output format (with header and count of filtered events)
102 // prnMode = 2: term output format (count only)
print_thd_node(THD_NODE * p,PrintFormat type,unsigned * prnMode)103 static int print_thd_node( THD_NODE *p , PrintFormat type, unsigned* prnMode )
104 {
105 char buf[STD_BUF+1];
106 memset(buf, 0, STD_BUF+1);
107
108 switch( type )
109 {
110 case PRINT_GLOBAL:
111 if(p->type == THD_TYPE_SUPPRESS ) return 0;
112 if(p->sig_id != 0 ) return 0;
113 break;
114
115 case PRINT_LOCAL:
116 if(p->type == THD_TYPE_SUPPRESS ) return 0;
117 if(p->sig_id == 0 || p->gen_id == 0 ) return 0;
118 break;
119
120 case PRINT_SUPPRESS:
121 if(p->type != THD_TYPE_SUPPRESS ) return 0;
122 break;
123 }
124
125 /* SnortSnprintfAppend(buf, STD_BUF, "| thd-id=%d", p->thd_id ); */
126
127
128 if ( *prnMode && !p->filtered )
129 return 1;
130
131 if( p->gen_id == 0 )
132 {
133 SnortSnprintfAppend(buf, STD_BUF, "| gen-id=global");
134 }
135 else
136 {
137 SnortSnprintfAppend(buf, STD_BUF, "| gen-id=%-6d", p->gen_id );
138 }
139 if( p->sig_id == 0 )
140 {
141 SnortSnprintfAppend(buf, STD_BUF, " sig-id=global" );
142 }
143 else
144 {
145 SnortSnprintfAppend(buf, STD_BUF, " sig-id=%-10d", p->sig_id );
146 }
147
148 switch ( p->type )
149 {
150 case THD_TYPE_LIMIT:
151 SnortSnprintfAppend(buf, STD_BUF, " type=Limit ");
152 break;
153
154 case THD_TYPE_THRESHOLD:
155 SnortSnprintfAppend(buf, STD_BUF, " type=Threshold");
156 break;
157
158 case THD_TYPE_BOTH:
159 SnortSnprintfAppend(buf, STD_BUF, " type=Both ");
160 break;
161
162 case THD_TYPE_SUPPRESS:
163 if ( *prnMode )
164 SnortSnprintfAppend(buf, STD_BUF, " type=Suppress ");
165 break;
166 }
167
168 switch ( p->tracking )
169 {
170 case THD_TRK_NONE:
171 SnortSnprintfAppend(buf, STD_BUF, " tracking=none");
172 break;
173
174 case THD_TRK_SRC:
175 SnortSnprintfAppend(buf, STD_BUF, " tracking=src");
176 break;
177
178 case THD_TRK_DST:
179 SnortSnprintfAppend(buf, STD_BUF, " tracking=dst");
180 break;
181 }
182
183 if( p->type == THD_TYPE_SUPPRESS )
184 {
185 if ( p->tracking != THD_TRK_NONE )
186 {
187 // TBD output suppress node ip addr set
188 SnortSnprintfAppend(buf, STD_BUF, "-ip=%-16s", "<list>");
189 }
190 }
191 else
192 {
193 SnortSnprintfAppend(buf, STD_BUF, " count=%-3d", p->count);
194 SnortSnprintfAppend(buf, STD_BUF, " seconds=%-3d", p->seconds);
195 }
196
197 if ( *prnMode )
198 {
199 if ( *prnMode == 1 )
200 {
201 LogMessage("+-----------------------[filtered events]--------------------------------------\n");
202 *prnMode = 2;
203 }
204 SnortSnprintfAppend(buf, STD_BUF, " filtered=" STDu64, p->filtered);
205 }
206 LogMessage("%s\n", buf);
207
208 return 1;
209 }
210 /*
211 *
212 */
print_thd_local(ThresholdObjects * thd_objs,PrintFormat type,unsigned * prnMode)213 static int print_thd_local(ThresholdObjects *thd_objs, PrintFormat type, unsigned* prnMode)
214 {
215 SFGHASH * sfthd_hash;
216 THD_ITEM * sfthd_item;
217 THD_NODE * sfthd_node;
218 int gen_id;
219 SFGHASH_NODE * item_hash_node;
220 int lcnt=0;
221 tSfPolicyId policyId;
222
223 for (policyId = 0; policyId < thd_objs->numPoliciesAllocated; policyId++)
224 {
225 for(gen_id=0;gen_id < THD_MAX_GENID ; gen_id++ )
226 {
227 sfthd_hash = thd_objs->sfthd_array[gen_id];
228 if( !sfthd_hash )
229 {
230 continue;
231 }
232
233 for(item_hash_node = sfghash_findfirst( sfthd_hash );
234 item_hash_node != 0;
235 item_hash_node = sfghash_findnext( sfthd_hash ) )
236 {
237 /* Check for any Permanent sig_id objects for this gen_id */
238 sfthd_item = (THD_ITEM*)item_hash_node->data;
239
240 if (sfthd_item->policyId != policyId)
241 {
242 continue;
243 }
244
245 for( sfthd_node = (THD_NODE*)sflist_first(sfthd_item->sfthd_node_list);
246 sfthd_node != 0;
247 sfthd_node = (THD_NODE*)sflist_next(sfthd_item->sfthd_node_list) )
248 {
249 if (print_thd_node(sfthd_node, type, prnMode) != 0)
250 lcnt++;
251 }
252 }
253 }
254 }
255
256 if( !lcnt && !*prnMode )
257 LogMessage("| none\n");
258
259 return 0;
260 }
261
262
263 /*
264 * Startup/Shutdown Display Of Thresholding
265 */
print_thresholding(ThresholdConfig * thd_config,unsigned shutdown)266 void print_thresholding(ThresholdConfig *thd_config, unsigned shutdown)
267 {
268 int i;
269 THD_NODE * thd;
270
271 if (thd_config == NULL)
272 return;
273
274 if ( !shutdown )
275 {
276 LogMessage("\n");
277 LogMessage("+-----------------------[event-filter-config]----------------------------------\n");
278 LogMessage("| memory-cap : %d bytes\n",thd_config->memcap);
279 LogMessage("+-----------------------[event-filter-global]----------------------------------\n");
280 }
281
282 if (thd_config->thd_objs == NULL)
283 {
284 if ( !shutdown )
285 LogMessage("| none\n");
286 }
287 else
288 {
289 tSfPolicyId policyId;
290 int gcnt=0;
291
292 for (policyId = 0; policyId < thd_config->thd_objs->numPoliciesAllocated; policyId++)
293 {
294 if (thd_config->thd_objs->sfthd_garray[policyId] == NULL)
295 {
296 continue;
297 }
298
299 for(i=0;i<THD_MAX_GENID;i++)
300 {
301 thd = thd_config->thd_objs->sfthd_garray[policyId][i];
302 if( !thd ) continue;
303 gcnt++;
304 }
305
306 if( !gcnt )
307 {
308 if ( !shutdown )
309 LogMessage("| none\n");
310 }
311 /* display gen_id=global and sig_id=global rules */
312 if( gcnt )
313 {
314 for(i=0;i<THD_MAX_GENID;i++)
315 {
316 thd = thd_config->thd_objs->sfthd_garray[policyId][i];
317 if( !thd ) continue;
318
319 if( thd->gen_id == 0 && thd->sig_id == 0 )
320 {
321 print_thd_node( thd, PRINT_GLOBAL, &shutdown );
322 break;
323 }
324 }
325 }
326
327 /* display gen_id!=global and sig_id=global rules */
328 if( gcnt )
329 {
330 for(i=0;i<THD_MAX_GENID;i++)
331 {
332 thd = thd_config->thd_objs->sfthd_garray[policyId][i];
333 if( !thd ) continue;
334
335 if( thd->gen_id !=0 || thd->sig_id != 0 )
336 {
337 print_thd_node( thd, PRINT_GLOBAL, &shutdown );
338 }
339 }
340 }
341 }
342 }
343
344 if ( !shutdown )
345 LogMessage("+-----------------------[event-filter-local]-----------------------------------\n");
346 if (thd_config->thd_objs == NULL)
347 {
348 if ( !shutdown )
349 LogMessage("| none\n");
350 }
351 else
352 {
353 print_thd_local(thd_config->thd_objs, PRINT_LOCAL, &shutdown);
354 }
355
356 if ( !shutdown )
357 LogMessage("+-----------------------[suppression]------------------------------------------\n");
358 if (thd_config->thd_objs == NULL)
359 {
360 if ( !shutdown )
361 LogMessage("| none\n");
362 }
363 else
364 {
365 print_thd_local(thd_config->thd_objs, PRINT_SUPPRESS, &shutdown);
366 }
367
368 if ( !shutdown )
369 LogMessage("--------------------------------------------"
370 "-----------------------------------\n");
371
372 }
373
sfthreshold_free(void)374 void sfthreshold_free(void)
375 {
376 if (thd_runtime != NULL)
377 sfthd_free(thd_runtime);
378
379 thd_runtime = NULL;
380 }
381
382 /*
383
384 Create and Add a Thresholding Event Object
385
386 */
sfthreshold_create(struct _SnortConfig * sc,ThresholdConfig * thd_config,THDX_STRUCT * thdx)387 int sfthreshold_create(struct _SnortConfig *sc, ThresholdConfig *thd_config, THDX_STRUCT *thdx)
388 {
389 if (thd_config == NULL)
390 return -1;
391
392 if (!thd_config->enabled)
393 return 0;
394
395 /* Auto init - memcap must be set 1st, which is not really a problem */
396 if (thd_runtime == NULL)
397 {
398 thd_runtime = sfthd_new(thd_config->memcap, thd_config->memcap);
399 if (thd_runtime == NULL)
400 return -1;
401 }
402
403 /* print_thdx( thdx ); */
404
405 /* Add the object to the table - */
406 return sfthd_create_threshold(sc,
407 thd_config->thd_objs,
408 thdx->gen_id,
409 thdx->sig_id,
410 thdx->tracking,
411 thdx->type,
412 thdx->priority,
413 thdx->count,
414 thdx->seconds,
415 thdx->ip_address);
416 }
417
418 /*
419 Test an event against the threshold object table
420 to determine if it should be logged.
421
422 It will always return the same answer until sfthreshold_reset is
423 called
424
425 gen_id:
426 sig_id:
427 sip: host ordered sip
428 dip: host ordered dip
429 curtime:
430
431 2003-05-29 cmg:
432
433 This code is in use in fpLogEvent, CallAlertFuncs, CallLogFuncs
434 and the reset function is called in ProcessPacket
435
436
437 returns 0 - log
438 !0 - don't log
439 */
sfthreshold_test(unsigned gen_id,unsigned sig_id,sfaddr_t * sip,sfaddr_t * dip,long curtime)440 int sfthreshold_test(
441 unsigned gen_id, unsigned sig_id,
442 sfaddr_t* sip, sfaddr_t* dip,
443 long curtime )
444 {
445 if ((snort_conf->threshold_config == NULL) ||
446 !snort_conf->threshold_config->enabled)
447 {
448 return 0;
449 }
450
451 if (!thd_checked)
452 {
453 thd_checked = 1;
454 thd_answer = sfthd_test_threshold(snort_conf->threshold_config->thd_objs,
455 thd_runtime, gen_id, sig_id, sip, dip, curtime);
456 }
457
458 return thd_answer;
459 }
460
461 /**
462 * Reset the thresholding system so that subsequent calls to
463 * sfthreshold_test will indeed try to alter the thresholding system
464 *
465 */
sfthreshold_reset(void)466 void sfthreshold_reset(void)
467 {
468 thd_checked = 0;
469 }
470
471 /* empty out active entries */
sfthreshold_reset_active(void)472 void sfthreshold_reset_active(void)
473 {
474 if (thd_runtime == NULL)
475 return;
476
477 if (thd_runtime->ip_nodes != NULL)
478 sfxhash_make_empty(thd_runtime->ip_nodes);
479
480 if (thd_runtime->ip_gnodes != NULL)
481 sfxhash_make_empty(thd_runtime->ip_gnodes);
482 }
483
484