1 /****************************************************************************
2 *
3 * Copyright (C) 2014-2021 Cisco and/or its affiliates. All rights reserved.
4 * Copyright (C) 2009-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
23 /* @file sfrf.c
24 * @brief rate filter implementation for Snort
25 * @ingroup rate_filter
26 * @author Dilbagh Chahal
27 */
28 /* @ingroup rate_filter
29 * @{
30 */
31
32 #include <stdlib.h>
33 #include <stdio.h>
34 #include <string.h>
35
36 #ifndef WIN32
37 #include <netinet/in.h>
38 #include <arpa/inet.h>
39
40 #endif /* !WIN32 */
41
42 #ifdef HAVE_CONFIG_H
43 #include "config.h"
44 #endif
45
46 #include "snort.h"
47 #include "parser/IpAddrSet.h"
48 #include "generators.h"
49 #include "rules.h"
50 #include "treenodes.h"
51 #include "sfrf.h"
52 #include "util.h"
53 #include "sfPolicyData.h"
54 #include "sfPolicyUserData.h"
55 #include "session_common.h"
56
57 // Number of hash rows for gid 1 (rules)
58 #define SFRF_GEN_ID_1_ROWS 4096
59 // Number of hash rows for non-zero gid
60 #define SFRF_GEN_ID_ROWS 512
61
62 // maximum number of norevert rate_filter configuration allowed.
63 #define SFRF_NO_REVERT_LIMIT 1000
64
65 // private data ...
66 /* Key to find tracking nodes in trackingHash.
67 */
68 typedef struct
69 {
70 ///policy identifier.
71 tSfPolicyId policyId;
72
73 /* Internally generated threshold identity for a configured threshold.
74 */
75 int tid;
76
77 /* Stores either source or destination IP address on a matching packet, depending on
78 * whether dos threshold is tracking by source or destination IP address. For tracking
79 * by rule, it is cleared out (all 0s).
80 */
81 struct in6_addr ip;
82
83 } tSFRFTrackingNodeKey ;
84
85 /* Tracking node for rate_filter. One node is created on fly, in tracking
86 * hash for each threshold configure (identified by Tid) and source or
87 * destination IP address. For rule based tracking, IP is cleared in the
88 * created node. Nodes are deleted when hash performs ANR on hash.
89 */
90 typedef struct
91 {
92 // automatically initialized to FS_NEW when allocated
93 FilterState filterState;
94
95 #ifdef SFRF_OVER_RATE
96 int overRate; // 0 = count not exceeded in prior seconds
97 time_t tlast; // time of most recent event
98 #endif
99
100 /* number of packets counted against a specific IP address or threshold.
101 */
102 unsigned count;
103
104 /* time when this sampling period started.
105 */
106 time_t tstart;
107
108 /* time when new action was activated due to rate limit exceeding.
109 */
110 time_t revertTime;
111
112 } tSFRFTrackingNode;
113
114 SFXHASH *rf_hash = NULL;
115
116 static int internal_syn_rate_limit_act;
117
118 // private methods ...
119 static int _checkThreshold(
120 tSFRFConfigNode*,
121 tSFRFTrackingNode*,
122 time_t curTime
123 );
124
125 static int _checkSamplingPeriod(
126 tSFRFConfigNode*,
127 tSFRFTrackingNode*,
128 time_t curTime
129 );
130
131 static tSFRFTrackingNode *_getSFRFTrackingNode(
132 sfaddr_t*,
133 unsigned tid,
134 time_t curTime
135 );
136
137 static void _updateDependentThresholds(
138 RateFilterConfig *config,
139 unsigned gid,
140 unsigned sid,
141 sfaddr_t* sip,
142 sfaddr_t* dip,
143 time_t curTime
144 );
145
146 // public methods ...
147 /* Create a new threshold global context
148 *
149 * Create a threshold table, initialize the threshold system, and optionally
150 * limit it's memory usage.
151 *
152 * @param nbytes maximum memory to use for thresholding objects, in bytes.
153 * @return pointer to newly created tSFRFContext
154 */
155 #define SFRF_BYTES (sizeof(tSFRFTrackingNodeKey) + sizeof(tSFRFTrackingNode))
156
SFRF_New(unsigned nbytes)157 static void SFRF_New( unsigned nbytes )
158 {
159 int nrows;
160
161 /* Calc max ip nodes for this memory */
162 if ( nbytes < SFRF_BYTES )
163 {
164 nbytes = SFRF_BYTES;
165 }
166 nrows = nbytes / (SFRF_BYTES);
167
168 /* Create global hash table for all of the IP Nodes */
169 rf_hash = sfxhash_new(
170 nrows, /* try one node per row - for speed */
171 sizeof(tSFRFTrackingNodeKey), /* keys size */
172 sizeof(tSFRFTrackingNode), /* data size */
173 nbytes, /* memcap **/
174 1, /* ANR flag - true ?- Automatic Node Recovery=ANR */
175 0, /* ANR callback - none */
176 0, /* user freemem callback - none */
177 1) ; /* Recycle nodes ?*/
178 }
179
SFRF_Delete(void)180 void SFRF_Delete (void)
181 {
182 if ( !rf_hash )
183 return;
184
185 sfxhash_delete(rf_hash);
186 rf_hash = NULL;
187 }
188
SFRF_Flush(void)189 void SFRF_Flush (void)
190 {
191 if ( rf_hash )
192 sfxhash_make_empty(rf_hash);
193 }
194
SFRF_ConfigNodeFree(void * item)195 static void SFRF_ConfigNodeFree(void *item)
196 {
197 tSFRFConfigNode *node = (tSFRFConfigNode *)item;
198
199 if (node == NULL)
200 return;
201
202 if (node->applyTo != NULL)
203 {
204 IpAddrSetDestroy(node->applyTo);
205 }
206
207 free(node);
208 }
209
210 /* free tSFRFSidNode and related buffers.
211 *
212 * @param item - pointer to tSFRFSidNode to be freed.
213 * @returns void
214 */
SFRF_SidNodeFree(void * item)215 static void SFRF_SidNodeFree(void* item)
216 {
217 tSFRFSidNode* pSidnode = (tSFRFSidNode*)item;
218 sflist_free_all(pSidnode->configNodeList, SFRF_ConfigNodeFree);
219 free(pSidnode);
220 }
221
222 /* Add a permanent threshold object to the threshold table. Multiple
223 * objects may be defined for each gid and sid pair. Internally
224 * a unique threshold id is generated for each pair.
225 *
226 * Threshold objects track the number of events seen during the time
227 * interval specified by seconds. Depending on the type of threshold
228 * object and the count value, the thresholding object determines if
229 * the current event should be logged or dropped.
230 *
231 * @param pContext Threshold object from SFRF_ContextNew()
232 * @param cfgNode Permanent Thresholding Object
233 *
234 * @return @retval 0 successfully added the thresholding object, !0 otherwise
235 */
SFRF_ConfigAdd(SnortConfig * sc,RateFilterConfig * rf_config,tSFRFConfigNode * cfgNode)236 int SFRF_ConfigAdd(SnortConfig *sc, RateFilterConfig *rf_config, tSFRFConfigNode *cfgNode)
237 {
238 SFGHASH* genHash;
239 int nrows;
240 int hstatus;
241 tSFRFSidNode* pSidNode;
242 tSFRFConfigNode* pNewConfigNode;
243 tSFRFGenHashKey key = {0,0};
244 tSfPolicyId policy_id = getParserPolicy(sc);
245
246 // Auto init - memcap must be set 1st, which is not really a problem
247 if ( rf_hash == NULL )
248 {
249 SFRF_New(rf_config->memcap);
250
251 if ( rf_hash == NULL )
252 return -1;
253 }
254
255 if ((rf_config == NULL) || (cfgNode == NULL))
256 return -1;
257
258 if ( (cfgNode->sid == 0 ) || (cfgNode->gid == 0) )
259 return -1;
260
261 if ( cfgNode->gid >= SFRF_MAX_GENID )
262 return -1;
263
264 if ( cfgNode->count < 1 )
265 return -1;
266
267 if ( cfgNode->timeout == 0 )
268 {
269 if ( rf_config->noRevertCount >= SFRF_NO_REVERT_LIMIT )
270 return -1;
271
272 rf_config->noRevertCount++;
273 }
274
275 /* Check for an existing 'gid' entry, if none found then create one. */
276 /* Get the hash table for this gid */
277 genHash = rf_config->genHash[cfgNode->gid];
278
279 if ( !genHash )
280 {
281 if ( cfgNode->gid == 1 )/* patmatch rules gid, many rules */
282 {
283 nrows= SFRF_GEN_ID_1_ROWS;
284 }
285 else /* other gid's */
286 {
287 nrows= SFRF_GEN_ID_ROWS;
288 }
289
290 /* Create the hash table for this gid */
291 genHash = sfghash_new( nrows, sizeof(tSFRFGenHashKey), 0, SFRF_SidNodeFree );
292 if ( !genHash )
293 return -2;
294
295 rf_config->genHash[cfgNode->gid] = genHash;
296 }
297
298 key.sid = cfgNode->sid;
299 key.policyId = policy_id;
300
301 /* Check if sid is already in the table - if not allocate and add it */
302 pSidNode = (tSFRFSidNode*)sfghash_find( genHash, (void*)&key );
303 if ( !pSidNode )
304 {
305 /* Create the pSidNode hash node data */
306 pSidNode = (tSFRFSidNode*)calloc(1,sizeof(tSFRFSidNode));
307 if ( !pSidNode )
308 return -3;
309
310 pSidNode->gid = cfgNode->gid;
311 pSidNode->sid = cfgNode->sid;
312 pSidNode->configNodeList = sflist_new();
313
314 if ( !pSidNode->configNodeList )
315 {
316 free(pSidNode);
317 return -4;
318 }
319
320 /* Add the pSidNode to the hash table */
321 hstatus = sfghash_add( genHash, (void*)&key, pSidNode );
322 if ( hstatus )
323 {
324 sflist_free(pSidNode->configNodeList);
325 free(pSidNode);
326 return -5;
327 }
328 }
329
330 /* Create a tSFRFConfigNode for this tSFRFSidNode (Object) */
331 pNewConfigNode = (tSFRFConfigNode*)calloc(1,sizeof(tSFRFConfigNode));
332 if ( !pNewConfigNode )
333 {
334 sflist_free(pSidNode->configNodeList);
335 free(pSidNode);
336 return -6;
337 }
338
339 *pNewConfigNode = *cfgNode;
340
341 rf_config->count++;
342
343 /* Copy the node parameters, with unique internally assigned tid */
344 pNewConfigNode->tid = rf_config->count;
345 if ( pNewConfigNode->tid == 0 )
346 {
347 // tid overflow. rare but possible
348 free(pNewConfigNode);
349 sflist_free(pSidNode->configNodeList);
350 free(pSidNode);
351 return -6;
352 }
353
354
355 #ifdef SFRF_DEBUG
356 printf("--%d-%d-%d: Threshold node added to tail of list\n",
357 pNewConfigNode->tid,
358 pNewConfigNode->gid,
359 pNewConfigNode->sid);
360 fflush(stdout);
361 #endif
362 sflist_add_tail(pSidNode->configNodeList,pNewConfigNode);
363
364 return 0;
365 }
366
367
368 #ifdef SFRF_DEBUG
get_netip(sfaddr_t * ip)369 static char* get_netip(sfaddr_t* ip)
370 {
371 return sfip_ntoa(ip);
372 }
373
374 #endif // SFRF_DEBUG
375
376 /*
377 *
378 * Find/Test/Add an event against a single threshold object.
379 * Events without thresholding objects are automatically loggable.
380 *
381 * @param pContext Threshold table pointer
382 * @param cfgNode Permanent Thresholding Object
383 * @param ip Event/Packet Src IP address- should be host ordered for comparison
384 * @param curTime Current Event/Packet time in seconds
385 * @param op operation of type SFRF_COUNT_OPERATION
386 *
387 * @return integer
388 * @retval !0 : rate limit is reached. Return value contains new action.
389 * @retval 0 : Otherwise
390 */
SFRF_TestObject(tSFRFConfigNode * cfgNode,sfaddr_t * ip,time_t curTime,SFRF_COUNT_OPERATION op)391 static int SFRF_TestObject(
392 tSFRFConfigNode* cfgNode,
393 sfaddr_t* ip,
394 time_t curTime,
395 SFRF_COUNT_OPERATION op
396 ) {
397 tSFRFTrackingNode* dynNode;
398 int retValue = -1;
399
400 dynNode = _getSFRFTrackingNode(ip, cfgNode->tid, curTime);
401
402 if ( dynNode == NULL )
403 return retValue;
404
405 if ( _checkSamplingPeriod(cfgNode, dynNode, curTime) != 0 )
406 {
407 #ifdef SFRF_DEBUG
408 printf("...Sampling period reset\n");
409 fflush(stdout);
410 #endif
411 }
412
413 switch (op)
414 {
415 case SFRF_COUNT_INCREMENT:
416 if ( (dynNode->count+1) != 0 )
417 {
418 dynNode->count++;
419 }
420 break;
421 case SFRF_COUNT_DECREMENT:
422 if ( cfgNode->seconds == 0 )
423 {
424 // count can be decremented only for total count, and not for rate
425 if ( dynNode->count != 0 )
426 {
427 dynNode->count--;
428 }
429 }
430 break;
431 case SFRF_COUNT_RESET:
432 dynNode->count = 0;
433 break;
434 default:
435 break;
436 }
437
438 retValue = _checkThreshold(cfgNode, dynNode, curTime);
439
440 // we drop after the session count has been incremented
441 // but the decrement will never come so we "fix" it here
442 // if the count were not incremented in such cases, the
443 // threshold would never be exceeded.
444 if ( !cfgNode->seconds && dynNode->count > cfgNode->count )
445 if ( cfgNode->newAction == RULE_TYPE__DROP )
446 dynNode->count--;
447
448 #ifdef SFRF_DEBUG
449 printf("--SFRF_DEBUG: %d-%d-%d: %d Packet IP %s, op: %d, count %d, action %d\n",
450 cfgNode->tid, cfgNode->gid,
451 cfgNode->sid, (unsigned) curTime, get_netip(ip), op,
452 dynNode->count, retValue);
453 fflush(stdout);
454 #endif
455 return retValue;
456 }
457
SFRF_AppliesTo(tSFRFConfigNode * pCfg,sfaddr_t * ip)458 static inline int SFRF_AppliesTo(tSFRFConfigNode* pCfg, sfaddr_t* ip)
459 {
460 return ( !pCfg->applyTo || IpAddrSetContains(pCfg->applyTo, ip) );
461 }
462
463 /* Test a an event against the threshold database. Events without thresholding
464 * objects are automatically loggable.
465 *
466 * @param pContext Threshold table pointer
467 * @param gid Generator Id from the event
468 * @param sid Signature Id from the event
469 * @param sip Event/Packet Src IP address
470 * @param dip Event/Packet Dst IP address
471 * @param curTime Current Event/Packet time
472 * @param op operation of type SFRF_COUNT_OPERATION
473 *
474 * @return -1 if packet is within dos_threshold and therefore action is allowed.
475 * >=0 if packet violates a dos_threshold and therefore new_action should
476 * replace rule action. new_action value is returned.
477 */
SFRF_TestThreshold(RateFilterConfig * config,unsigned gid,unsigned sid,sfaddr_t * sip,sfaddr_t * dip,time_t curTime,SFRF_COUNT_OPERATION op)478 int SFRF_TestThreshold(
479 RateFilterConfig *config,
480 unsigned gid,
481 unsigned sid,
482 sfaddr_t* sip,
483 sfaddr_t* dip,
484 time_t curTime,
485 SFRF_COUNT_OPERATION op
486 ) {
487 SFGHASH *genHash;
488 tSFRFSidNode* pSidNode;
489 tSFRFConfigNode* cfgNode;
490 int newStatus = -1;
491 int status = -1;
492 tSFRFGenHashKey key;
493
494 #ifdef SFRF_DEBUG
495 printf("--%d-%d-%d: %s() entering\n", 0, gid, sid, __func__);
496 fflush(stdout);
497 #endif
498
499 if ( gid >= SFRF_MAX_GENID )
500 return status; /* bogus gid */
501
502 if(EventIsInternal(gid) &&
503 sid == INTERNAL_EVENT_SYN_RECEIVED )
504 {
505 if( internal_syn_rate_limit_act >= -1 )
506 return internal_syn_rate_limit_act;
507 }
508 // Some events (like 'TCP connection closed' raised by preprocessor may
509 // not have any configured threshold but may impact thresholds for other
510 // events (like 'TCP connection opened'
511 _updateDependentThresholds(config, gid, sid, sip, dip, curTime);
512
513 /*
514 * Get the hash table for this gid
515 */
516 genHash = config->genHash [ gid ];
517 if ( !genHash )
518 {
519 #ifdef SFRF_DEBUG
520 printf("--SFRF_DEBUG: %d-%d-%d: no hash table entry for gid\n", 0, gid, sid);
521 fflush(stdout);
522 #endif
523 return status;
524 }
525
526 /*
527 * Check for any Permanent sid objects for this gid
528 */
529 key.sid = sid;
530 key.policyId = getApplicableRuntimePolicy(gid);
531
532 pSidNode = (tSFRFSidNode*)sfghash_find( genHash, (void*)&key );
533 if ( !pSidNode )
534 {
535 #ifdef SFRF_DEBUG
536 printf("--SFRF_DEBUG: %d-%d-%d: no DOS THD object\n", 0, gid, sid);
537 fflush(stdout);
538 #endif
539 return status;
540 }
541
542 /* No List of Threshold objects - bail and log it */
543 if ( !pSidNode->configNodeList )
544 {
545 #ifdef SFRF_DEBUG
546 printf("--SFRF_DEBUG: %d-%d-%d: No user configuration\n",
547 0, gid, sid);
548 fflush(stdout);
549 #endif
550 return status;
551 }
552
553 /* For each permanent thresholding object, test/add/update the config object */
554 /* We maintain a list of thd objects for each gid+sid */
555 /* each object has it's own unique thd_id */
556 for ( cfgNode = (tSFRFConfigNode*)sflist_first(pSidNode->configNodeList);
557 cfgNode != 0;
558 cfgNode = (tSFRFConfigNode*)sflist_next(pSidNode->configNodeList) )
559 {
560 switch (cfgNode->tracking)
561 {
562 case SFRF_TRACK_BY_SRC:
563 if ( SFRF_AppliesTo(cfgNode, sip) )
564 {
565 newStatus = SFRF_TestObject(cfgNode, sip, curTime, op);
566 }
567 break;
568
569 case SFRF_TRACK_BY_DST:
570 if ( SFRF_AppliesTo(cfgNode, dip) )
571 {
572 newStatus = SFRF_TestObject(cfgNode, dip, curTime, op);
573 }
574 break;
575
576 case SFRF_TRACK_BY_RULE:
577 {
578 sfaddr_t cleared;
579 IP_CLEAR(cleared);
580 newStatus = SFRF_TestObject(cfgNode, IP_ARG(cleared), curTime, op);
581 }
582 break;
583
584 default:
585 // error case
586 break;
587 }
588
589 #ifdef SFRF_DEBUG
590 printf("--SFRF_DEBUG: %d-%d-%d: Time %d, rate limit blocked: %d\n",
591 cfgNode->tid, gid, sid, (unsigned)curTime, newStatus);
592 fflush(stdout);
593 #endif
594
595 // rate limit is reached
596 if ( newStatus >= 0 && (status == -1) )
597 {
598 status = newStatus;
599 }
600 }
601
602 // rate limit not reached
603 return status;
604 }
605
606 /* A function to print the thresholding objects to stdout.
607 *
608 * @param pContext pointer to global threshold context
609 * @return
610 */
SFRF_ShowObjects(RateFilterConfig * config)611 void SFRF_ShowObjects(RateFilterConfig *config)
612 {
613 SFGHASH* genHash;
614 tSFRFSidNode* pSidnode;
615 tSFRFConfigNode* cfgNode;
616 int gid;
617 SFGHASH_NODE* sidHashNode;
618
619 for ( gid=0;gid < SFRF_MAX_GENID ; gid++ )
620 {
621 genHash = config->genHash [ gid ];
622 if ( !genHash )
623 {
624 continue;
625 }
626
627 printf("...GEN_ID = %u\n",gid);
628
629 for ( sidHashNode = sfghash_findfirst( genHash );
630 sidHashNode != 0;
631 sidHashNode = sfghash_findnext( genHash ) )
632 {
633 /* Check for any Permanent sid objects for this gid */
634 pSidnode = (tSFRFSidNode*)sidHashNode->data;
635
636 printf(".....GEN_ID = %u, SIG_ID = %u, PolicyId = %u\n",gid, pSidnode->sid, pSidnode->policyId);
637
638 /* For each permanent thresholding object, test/add/update the thd object */
639 /* We maintain a list of thd objects for each gid+sid */
640 /* each object has it's own unique thd_id */
641
642 for ( cfgNode = (tSFRFConfigNode*)sflist_first(pSidnode->configNodeList);
643 cfgNode != 0;
644 cfgNode = (tSFRFConfigNode*)sflist_next(pSidnode->configNodeList) )
645 {
646 printf(".........SFRF_ID =%d\n",cfgNode->tid );
647 printf(".........tracking =%d\n",cfgNode->tracking);
648 printf(".........count =%u\n",cfgNode->count);
649 printf(".........seconds =%u\n",cfgNode->seconds);
650 }
651 }
652 }
653 }
654
655 /* Set sampling period rate limit
656 *
657 * @param cfgNode threshold configuration node
658 * @param dynNode tracking node for a configured node
659 * @param curTime for packet timestamp
660 *
661 * @returns 0 if continuing with old sampling period.
662 * 1 if new sampling period is started.
663 */
_checkSamplingPeriod(tSFRFConfigNode * cfgNode,tSFRFTrackingNode * dynNode,time_t curTime)664 static int _checkSamplingPeriod(
665 tSFRFConfigNode* cfgNode,
666 tSFRFTrackingNode* dynNode,
667 time_t curTime
668 ) {
669 unsigned dt;
670
671 if ( cfgNode->seconds )
672 {
673 dt = (unsigned)(curTime - dynNode->tstart);
674 if ( dt >= cfgNode->seconds )
675 { // observation period is over, start a new one
676 dynNode->tstart = curTime;
677
678 #ifdef SFRF_OVER_RATE
679 dt = (unsigned)(curTime - dynNode->tlast);
680 if ( dt > cfgNode->seconds ) dynNode->overRate = 0;
681 else dynNode->overRate = (dynNode->count > cfgNode->count);
682 dynNode->tlast = curTime;
683 #endif
684 dynNode->count = 0;
685 return 1;
686 }
687 }
688 #ifdef SFRF_OVER_RATE
689 else
690 {
691 dynNode->overRate = (dynNode->count > cfgNode->count);
692 }
693 dynNode->tlast = curTime;
694 #endif
695 return 0;
696 }
697
698 /* Checks if rate limit is reached for a configured threshold.
699 *
700 * DOS Threshold monitoring is done is discrete time intervals specified by
701 * 'cfgNode->seconds'. Once threshold action is activated, it stays active
702 * for the revert timeout. Counters and seconds is maintained current at all
703 * times. This may cause threshold action to be reactivated immediately if counter
704 * is above threshold.
705 * Threshold is tracked using a hash with ANR. This could cause some tracking nodes
706 * to disappear when memory is low. Node deletion and subsequent creation will cause
707 * rate limiting to start afresh for a specific stream.
708 *
709 * @param cfgNode threshold configuration node
710 * @param dynNode tracking node for a configured node
711 * @param curTime for packet timestamp
712 *
713 * @returns 0 if threshold is not reached
714 * 1 otherwise
715 */
_checkThreshold(tSFRFConfigNode * cfgNode,tSFRFTrackingNode * dynNode,time_t curTime)716 static int _checkThreshold(
717 tSFRFConfigNode* cfgNode,
718 tSFRFTrackingNode* dynNode,
719 time_t curTime
720 ) {
721 /* Once newAction is activated, it stays active for the revert timeout, unless ANR
722 * causes the node itself to disappear.
723 * Also note that we want to maintain the counters and rates update so that we reblock
724 * offending traffic again quickly if it has not subsided.
725 */
726 if ( dynNode->filterState == FS_ON )
727 {
728 if ( (cfgNode->timeout != 0 )
729 && ((unsigned)(curTime - dynNode->revertTime) >= cfgNode->timeout))
730 {
731 #ifdef SFRF_OVER_RATE
732 if ( dynNode->count > cfgNode->count || dynNode->overRate )
733 {
734 #ifdef SFRF_DEBUG
735 printf("...dos action continued, count %u\n", dynnode->count);
736 fflush(stdout);
737 #endif
738 dynNode->revertTime = curTime;
739 return cfgNode->newAction;
740 }
741 #endif
742 #ifdef SFRF_DEBUG
743 printf("...dos action stopped, count %u\n", dynnode->count);
744 fflush(stdout);
745 #endif
746 dynNode->filterState = FS_OFF;
747 }
748 else
749 {
750 #ifdef SFRF_DEBUG
751 printf("...DOS action continued, count %u\n", dynNode->count);
752 fflush(stdout);
753 #endif
754 return cfgNode->newAction;
755 }
756 }
757
758 #ifdef SFRF_OVER_RATE
759 if ( dynNode->count <= cfgNode->count && !dynNode->overRate )
760 #else
761 if ( dynNode->count <= cfgNode->count )
762 #endif
763 {
764 // rate limit not reached.
765 #ifdef SFRF_DEBUG
766 printf("...DOS action nop, count %u\n", dynNode->count);
767 fflush(stdout);
768 #endif
769 return -1;
770 }
771
772 // rate limit reached.
773 dynNode->revertTime = curTime;
774 dynNode->filterState = FS_ON;
775 #ifdef SFRF_OVER_RATE
776 dynNode->overRate = 1;
777 #endif
778 #ifdef SFRF_DEBUG
779 printf("...DOS action started, count %u\n", dynNode->count);
780 fflush(stdout);
781 #endif
782
783 return RULE_TYPE__MAX + cfgNode->newAction;
784 }
785
786
_updateDependentThresholds(RateFilterConfig * config,unsigned gid,unsigned sid,sfaddr_t * sip,sfaddr_t * dip,time_t curTime)787 static void _updateDependentThresholds(
788 RateFilterConfig *config,
789 unsigned gid,
790 unsigned sid,
791 sfaddr_t* sip,
792 sfaddr_t* dip,
793 time_t curTime
794 ) {
795 if ( gid == GENERATOR_INTERNAL &&
796 sid == INTERNAL_EVENT_SESSION_DEL )
797 {
798 // decrementing counters - this results in the following sequence:
799 // 1. sfdos_thd_test_threshold(gid internal, sid DEL)
800 // 2. _updateDependentThresholds(gid internal, sid DEL)
801 // 3. | sfdos_thd_test_threshold(gid internal, sid ADD)
802 // 4. | _updateDependentThresholds(gid internal, sid ADD)
803 // 5. continue with regularly scheduled programming (ie step 1)
804
805 SFRF_TestThreshold(config, gid, INTERNAL_EVENT_SESSION_ADD,
806 sip, dip, curTime, SFRF_COUNT_DECREMENT);
807 return;
808 }
809 }
810
_getSFRFTrackingNode(sfaddr_t * ip,unsigned tid,time_t curTime)811 static tSFRFTrackingNode* _getSFRFTrackingNode(
812 sfaddr_t* ip,
813 unsigned tid,
814 time_t curTime
815 ) {
816 tSFRFTrackingNode* dynNode = NULL;
817 tSFRFTrackingNodeKey key;
818 SFXHASH_NODE * hnode = NULL;
819
820 /* Setup key */
821 sfaddr_copy_to_raw(&key.ip, ip);
822 key.tid = tid;
823 key.policyId = getNapRuntimePolicy(); // TBD-EDM should this be NAP or IPS?
824
825 /*
826 * Check for any Permanent sid objects for this gid or add this one ...
827 */
828 hnode = sfxhash_get_node(rf_hash, (void*)&key);
829 if ( hnode && hnode->data )
830 {
831 dynNode = (tSFRFTrackingNode*)hnode->data;
832
833 if ( dynNode->filterState == FS_NEW )
834 {
835 // first time initialization
836 dynNode->tstart = curTime;
837 #ifdef SFRF_OVER_RATE
838 dynNode->tlast = curTime;
839 #endif
840 dynNode->filterState = FS_OFF;
841 }
842 }
843 return dynNode;
844 }
SFRF_InternalSynRecdEvent(Packet * p)845 int SFRF_InternalSynRecdEvent(Packet* p)
846 {
847 sfaddr_t* sip = NULL, *dip = NULL;
848 internal_syn_rate_limit_act = -2;
849
850 if ( IPH_IS_VALID(p) )
851 {
852 sip = GET_SRC_IP(p);
853 dip = GET_DST_IP(p);
854
855 getSessionPlugins()->select_session_nap( p, true );
856
857 internal_syn_rate_limit_act = SFRF_TestThreshold(
858 snort_conf->rate_filter_config,
859 GENERATOR_INTERNAL,
860 INTERNAL_EVENT_SYN_RECEIVED,
861 sip, dip,
862 p->pkth->ts.tv_sec,
863 SFRF_COUNT_INCREMENT);
864
865 if(internal_syn_rate_limit_act > 0)
866 {
867 SnortEventqAdd(
868 GENERATOR_INTERNAL, /* GID */
869 INTERNAL_EVENT_SYN_RECEIVED, /* SID */
870 1, /* rev */
871 0, /* class */
872 3, /* priority */
873 "", /* event msg*/
874 NULL /* rule info ptr */
875 );
876 pc.syn_rate_limit_events++;
877 }
878
879 if( ScNapInlineMode() &&
880 ( DAQ_GetInterfaceMode(p->pkth) == DAQ_MODE_INLINE ))
881 {
882 int action = internal_syn_rate_limit_act;
883 if (internal_syn_rate_limit_act >= RULE_TYPE__MAX)
884 action = internal_syn_rate_limit_act - RULE_TYPE__MAX;
885 if( (action == RULE_TYPE__DROP) ||
886 (action == RULE_TYPE__SDROP) ||
887 (action == RULE_TYPE__REJECT) )
888 {
889 p->error_flags |= PKT_ERR_SYN_RL_DROP;
890 }
891 }
892 }
893
894 return 1;
895 }
896
897 /*@}*/
898
899