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