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