From: Raza Shafiq (rshafiq) Date: Mon, 4 Mar 2024 21:21:51 +0000 (+0000) Subject: Pull request #4174: filters: updated dyn array with vector X-Git-Tag: 3.1.82.0~8 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=d5c9523ae60ac6ef668b6dba2a8cd0ed1635f174;p=thirdparty%2Fsnort3.git Pull request #4174: filters: updated dyn array with vector Merge in SNORT/snort3 from ~RSHAFIQ/snort3:dyn_vector to master Squashed commit of the following: commit ebf9adff7693f9073fe08e63862779e9722232c4 Author: rshafiq Date: Wed Jan 24 19:11:05 2024 -0500 filters: updated dyn array with vector --- diff --git a/src/detection/signature.cc b/src/detection/signature.cc index 8207a3dd8..f7c4f4ff2 100644 --- a/src/detection/signature.cc +++ b/src/detection/signature.cc @@ -30,6 +30,7 @@ #include "actions/actions.h" #include "framework/decode_data.h" +#include "filters/sfthd.h" #include "hash/hash_defs.h" #include "hash/ghash.h" #include "helpers/json_stream.h" @@ -162,7 +163,7 @@ OptTreeNode::~OptTreeNode() snort_free(proto_nodes); if (detection_filter) - snort_free(detection_filter); + sfthd_node_free(detection_filter); delete sigInfo.body; delete[] buffer_setters; diff --git a/src/filters/sfthd.cc b/src/filters/sfthd.cc index cf8fe221c..c0bdcafe4 100644 --- a/src/filters/sfthd.cc +++ b/src/filters/sfthd.cc @@ -21,10 +21,7 @@ * sfthd.cc author Marc Norton * * An Abstracted Event Thresholding System - * - * 3/5/07 - man - fixed memory leak in global config to limit - * of one gid=0, or multiple gid!=0 but not both. - * Boris Lytochkin found it. + * 01/24/2024 - updated the arrays with STL containers (Raza Shafiq: rshafiq@cisco.com) */ #ifdef HAVE_CONFIG_H @@ -34,21 +31,18 @@ #include "sfthd.h" #include +#include #include "hash/ghash.h" #include "hash/hash_defs.h" #include "hash/xhash.h" #include "main/thread.h" #include "sfip/sf_ipvar.h" -#include "utils/dyn_array.h" #include "utils/sflsq.h" #include "utils/util.h" using namespace snort; -// Debug Printing -//#define THD_DEBUG - THREAD_LOCAL EventFilterStats event_filter_stats; XHash* sfthd_new_hash(unsigned nbytes, size_t key, size_t data) @@ -82,11 +76,6 @@ XHash* sfthd_local_new(unsigned bytes) sizeof(THD_IP_NODE_KEY), sizeof(THD_IP_NODE)); -#ifdef THD_DEBUG - if ( !local_hash ) - printf("Could not allocate the sfxhash table\n"); -#endif - return local_hash; } @@ -97,11 +86,6 @@ XHash* sfthd_global_new(unsigned bytes) sizeof(THD_IP_GNODE_KEY), sizeof(THD_IP_NODE)); -#ifdef THD_DEBUG - if ( !global_hash ) - printf("Could not allocate the sfxhash table\n"); -#endif - return global_hash; } @@ -116,9 +100,6 @@ THD_STRUCT* sfthd_new(unsigned lbytes, unsigned gbytes) thd->ip_nodes = sfthd_local_new(lbytes); if ( !thd->ip_nodes ) { -#ifdef THD_DEBUG - printf("Could not allocate the sfxhash table\n"); -#endif snort_free(thd); return nullptr; } @@ -130,9 +111,6 @@ THD_STRUCT* sfthd_new(unsigned lbytes, unsigned gbytes) thd->ip_gnodes = sfthd_global_new(gbytes); if ( !thd->ip_gnodes ) { -#ifdef THD_DEBUG - printf("Could not allocate the sfxhash table\n"); -#endif delete thd->ip_nodes; snort_free(thd); return nullptr; @@ -143,7 +121,7 @@ THD_STRUCT* sfthd_new(unsigned lbytes, unsigned gbytes) ThresholdObjects* sfthd_objs_new() { - return (ThresholdObjects*)snort_calloc(sizeof(ThresholdObjects)); + return new ThresholdObjects; } void sfthd_node_free(THD_NODE* sfthd_node) @@ -152,9 +130,11 @@ void sfthd_node_free(THD_NODE* sfthd_node) return; if ( sfthd_node->ip_address ) + { sfvar_free(sfthd_node->ip_address); - - snort_free(sfthd_node); + sfthd_node->ip_address = nullptr; + } + delete sfthd_node; } static void sfthd_node_free(void* node) @@ -162,63 +142,49 @@ static void sfthd_node_free(void* node) void sfthd_objs_free(ThresholdObjects* thd_objs) { - if (thd_objs == nullptr) + if ( thd_objs == nullptr ) return; - for (int i = 0; i < THD_MAX_GENID; i++) + for ( const auto* hash : thd_objs->sfthd_vector ) { - if ( thd_objs->sfthd_array[i] ) - delete thd_objs->sfthd_array[i]; + if ( hash ) + delete hash; } - for (PolicyId policy_id = 0; policy_id < thd_objs->numPoliciesAllocated; policy_id++) + std::set deleted_ip_vars; + for (auto& policy_map : thd_objs->sfthd_gvector) { - if ( !thd_objs->sfthd_garray[policy_id] ) - continue; - - if ( thd_objs->sfthd_garray[policy_id][0] ) - { - sfthd_node_free(thd_objs->sfthd_garray[policy_id][0]); - - /* Free any individuals */ - for (int i = 0; i < THD_MAX_GENID; i++) - { - if ( thd_objs->sfthd_garray[policy_id][i] != - thd_objs->sfthd_garray[policy_id][0] ) - { - sfthd_node_free(thd_objs->sfthd_garray[policy_id][i]); - } - } - } - else + for (auto& gen_id_and_node : policy_map) { - /* Anything other GID will be allocated individually */ - for (int i = 1; i < THD_MAX_GENID; i++) + THD_NODE* node = gen_id_and_node.second.get(); + if ( node ) { - if ( thd_objs->sfthd_garray[policy_id][i] ) - sfthd_node_free(thd_objs->sfthd_garray[policy_id][i]); + auto ip_deleted = deleted_ip_vars.insert(node->ip_address); + if ( ip_deleted.second ) + sfvar_free(node->ip_address); } } - - snort_free(thd_objs->sfthd_garray[policy_id]); + // Clear the map after handling ip_address in all nodes. + policy_map.clear(); } - if ( thd_objs->sfthd_garray ) - snort_free(thd_objs->sfthd_garray); + // If there's anything else in thd_objs that needs manual deletion or cleanup, do it here. - snort_free(thd_objs); + delete thd_objs; // Finally, delete the container itself if necessary. } + + static void sfthd_item_free(void* item) { THD_ITEM* sfthd_item = (THD_ITEM*)item; sflist_free_all(sfthd_item->sfthd_node_list, sfthd_node_free); - snort_free(sfthd_item); + delete sfthd_item; } void sfthd_free(THD_STRUCT* thd) { - if (thd == nullptr) + if ( thd == nullptr ) return; if ( thd->ip_nodes ) @@ -236,8 +202,8 @@ THD_NODE* sfthd_create_rule_threshold(int id, int count, unsigned int seconds) { - THD_NODE* sfthd_node = (THD_NODE*)snort_calloc(sizeof(THD_NODE)); - + THD_NODE* sfthd_node = new THD_NODE(); + sfthd_node->thd_id = id; sfthd_node->tracking = tracking; sfthd_node->type = type; @@ -272,190 +238,100 @@ the current event should be logged or dropped. @return integer @retval 0 successfully added the thresholding object @retval !0 failed - */ static int sfthd_create_threshold_local( SnortConfig*, ThresholdObjects* thd_objs, THD_NODE* config, PolicyId policy_id) { - GHash* sfthd_hash; - THD_ITEM* sfthd_item; - THD_NODE* sfthd_node; - tThdItemKey key; - - if (thd_objs == nullptr ) + + if ( thd_objs == nullptr or config == nullptr ) return -1; - + if ( config->gen_id >= THD_MAX_GENID ) return -1; - - /* Check for an existing 'gen_id' entry, if none found create one. */ - if (thd_objs->sfthd_array[config->gen_id] == nullptr) - { - int nrows; - - if ( config->gen_id == 1 ) /* patmatch rules gen_id, many rules */ - { - nrows= THD_GEN_ID_1_ROWS; - } - else /* other gen_id's */ - { - nrows= THD_GEN_ID_ROWS; - } - - /* Create the hash table for this gen_id */ + + if ( thd_objs->sfthd_vector.size() <= config->gen_id ) + thd_objs->sfthd_vector.resize(config->gen_id + 1, nullptr); + + auto& sfthd_hash = thd_objs->sfthd_vector[config->gen_id]; + if ( sfthd_hash == nullptr ) + { + int nrows = (config->gen_id == 1) ? THD_GEN_ID_1_ROWS : THD_GEN_ID_ROWS; sfthd_hash = new GHash(nrows, sizeof(tThdItemKey), false, sfthd_item_free); - thd_objs->sfthd_array[config->gen_id] = sfthd_hash; - } - else - { - /* Get the hash table for this gen_id */ - sfthd_hash = thd_objs->sfthd_array[config->gen_id]; } - if (sfthd_hash == nullptr) - return -2; - + tThdItemKey key; key.sig_id = config->sig_id; key.policyId = policy_id; - /* Check if sig_id is already in the table - if not allocate and add it */ - sfthd_item = (THD_ITEM*)sfthd_hash->find((void*)&key); + + THD_ITEM* sfthd_item = static_cast(sfthd_hash->find(&key)); if ( !sfthd_item ) { - /* Create the sfthd_item hash node data */ - sfthd_item = (THD_ITEM*)snort_calloc(sizeof(THD_ITEM)); - - sfthd_item->gen_id = config->gen_id; - sfthd_item->sig_id = config->sig_id; - sfthd_item->policyId = policy_id; - sfthd_item->sfthd_node_list = sflist_new(); - - if (!sfthd_item->sfthd_node_list) + sfthd_item = new THD_ITEM{ policy_id, config->gen_id, config->sig_id, sflist_new() }; + if ( sfthd_item->sfthd_node_list == nullptr ) { - snort_free(sfthd_item); + delete sfthd_item; return -4; } - /* Add the sfthd_item to the hash table */ - if ( sfthd_hash->insert((void*)&key, sfthd_item) ) + if ( sfthd_hash->insert(&key, sfthd_item) != HASH_OK ) { - sflist_free(sfthd_item->sfthd_node_list); - snort_free(sfthd_item); + sflist_free_all(sfthd_item->sfthd_node_list, sfthd_node_free); + delete sfthd_item; return -5; } } - /* * Test that we only have one Limit/Threshold/Both Object at the tail, * we can have multiple suppression nodes at the head */ - if ( sfthd_item->sfthd_node_list->count > 0 ) + if ( sfthd_item->sfthd_node_list->count > 0 ) { THD_NODE* p; - if ( !sfthd_item->sfthd_node_list->tail) + if ( !sfthd_item->sfthd_node_list->tail ) { - /* can you say paranoid- if there is a count, there should be a tail */ + // Paranoid check: if there is a count, there should be a tail return -10; } - p = (THD_NODE*)sfthd_item->sfthd_node_list->tail->ndata; - if (p) /* just to be safe- if there is a tail, there is is node data */ + p = static_cast(sfthd_item->sfthd_node_list->tail->ndata); + if ( p ) // Ensure there is node data if there is a tail { - if ( p->type != THD_TYPE_SUPPRESS && config->type != THD_TYPE_SUPPRESS ) + if ( p->type != THD_TYPE_SUPPRESS and config->type != THD_TYPE_SUPPRESS ) { -#ifdef THD_DEBUG - printf("THD_DEBUG: Could not add a 2nd Threshold object, " - "you can only have 1 per sid: gid=%u, sid=%u\n", - config->gen_id, config->sig_id); -#endif - /* cannot add more than one threshold per sid in - version 3.0, wait for 3.2 and CIDR blocks */ + // Cannot add more than one threshold per sid in version 3.0 return THD_TOO_MANY_THDOBJ; } } } - /* Create a THD_NODE for this THD_ITEM (Object) */ - sfthd_node = (THD_NODE*)snort_calloc(sizeof(THD_NODE)); - - /* Limit priorities to force suppression nodes to highest priority */ + THD_NODE* sfthd_node = new THD_NODE(*config); // Copy the node parameters if ( config->priority >= THD_PRIORITY_SUPPRESS ) - { - config->priority = THD_PRIORITY_SUPPRESS - 1; - } - - /* Copy the node parameters */ - sfthd_node->thd_id = config->thd_id; - sfthd_node->gen_id = config->gen_id; - sfthd_node->sig_id = config->sig_id; - sfthd_node->tracking = config->tracking; /* by_src, by_dst */ - sfthd_node->type = config->type; - sfthd_node->priority = config->priority; - sfthd_node->count = config->count; - sfthd_node->seconds = config->seconds; - sfthd_node->ip_address= config->ip_address; - - if ( config->type == THD_TYPE_SUPPRESS ) - { - sfthd_node->priority = THD_PRIORITY_SUPPRESS; - } - - /* - add the sfthd_node using priority to determine where in the list - it belongs - - 3.0 we can have only 1 threshold object but several suppression objects - plus a single threshold object is ok. Blocking multiple threshold - objects is done above. + sfthd_node->priority = THD_PRIORITY_SUPPRESS - 1; - Suppressions have the highest priority and are at the front of the - list, the tail node is either a suppression node or the only pure - thresholding node. - */ + if ( sfthd_item->sfthd_node_list->count > 0 ) { SF_LNODE* lnode; - NODE_DATA ndata; - - /* Walk the list and insert based on priorities if suppress */ - for ( ndata = sflist_first(sfthd_item->sfthd_node_list, &lnode); - ndata; - ndata = sflist_next(&lnode) ) + for ( auto ndata = sflist_first(sfthd_item->sfthd_node_list, &lnode); + ndata != nullptr; ndata = sflist_next(&lnode) ) { - THD_NODE* sfthd_n = (THD_NODE*)ndata; - - /* check if the new node is higher priority */ - if ( sfthd_node->priority > sfthd_n->priority ) + THD_NODE* sfthd_n = static_cast(ndata); + if ( sfthd_node->priority > sfthd_n->priority ) { - /* insert before current node */ -#ifdef THD_DEBUG - printf("Threshold node added after based on priority\n"); fflush(stdout); -#endif - sflist_add_before(sfthd_item->sfthd_node_list,lnode,sfthd_node); + sflist_add_before(sfthd_item->sfthd_node_list, lnode, sfthd_node); return 0; } - /* last node, just insert it here */ - if ( !lnode->next ) + if ( lnode->next == nullptr ) { - /* if last node, insert at end of list */ -#ifdef THD_DEBUG - printf("Threshold node added to tail\n"); fflush(stdout); -#endif - sflist_add_tail(sfthd_item->sfthd_node_list,sfthd_node); + sflist_add_tail(sfthd_item->sfthd_node_list, sfthd_node); return 0; } } + delete sfthd_node; + return -11; } - - /* - sfthd_node list is empty - add as head node - */ - assert(!sfthd_item->sfthd_node_list->count); - { -#ifdef THD_DEBUG - printf("Threshold node added to head of list\n"); fflush(stdout); -#endif - sflist_add_head(sfthd_item->sfthd_node_list,sfthd_node); - } + else + sflist_add_head(sfthd_item->sfthd_node_list, sfthd_node); return 0; } @@ -465,80 +341,27 @@ static int sfthd_create_threshold_local( static int sfthd_create_threshold_global( SnortConfig*, ThresholdObjects* thd_objs, THD_NODE* config, PolicyId policy_id) { - THD_NODE* sfthd_node; - - if (thd_objs == nullptr) + if ( thd_objs == nullptr or config == nullptr or config->gen_id >= THD_MAX_GENID ) return -1; - if (config->gen_id >= THD_MAX_GENID) - return -1; + if ( thd_objs->sfthd_gvector.size() <= policy_id ) + thd_objs->sfthd_gvector.resize(policy_id + 1); - if (thd_objs->sfthd_garray[policy_id] == nullptr) - { - thd_objs->sfthd_garray[policy_id] = - (THD_NODE**)(snort_calloc(THD_MAX_GENID, sizeof(THD_NODE*))); - } + auto& map = thd_objs->sfthd_gvector[policy_id]; - if ((config->gen_id == 0) && - (thd_objs->sfthd_garray[policy_id][config->gen_id] != nullptr)) - { - return THD_TOO_MANY_THDOBJ; - } - /* Reset the current threshold */ - if (thd_objs->sfthd_garray[policy_id][config->gen_id] == - thd_objs->sfthd_garray[policy_id][0]) - { - thd_objs->sfthd_garray[policy_id][config->gen_id] = nullptr; - } - else if (thd_objs->sfthd_garray[policy_id][config->gen_id]) - { - return THD_TOO_MANY_THDOBJ; - } + // Check if there is an existing entry for config->gen_id + if ( config->gen_id == 0 and map.find(0) != map.end() ) + map.erase(config->gen_id); - sfthd_node = (THD_NODE*)snort_calloc(sizeof(THD_NODE)); - - /* Copy the node parameters */ - sfthd_node->thd_id = config->thd_id; - sfthd_node->gen_id = config->gen_id; - sfthd_node->sig_id = config->sig_id; /* -1 for global thresholds */ - sfthd_node->tracking = config->tracking; /* by_src, by_dst */ - sfthd_node->type = config->type; - sfthd_node->priority = config->priority; - sfthd_node->count = config->count; - sfthd_node->seconds = config->seconds; - sfthd_node->ip_address = config->ip_address; - - /* need a hash of these where - * key=[gen_id,sig_id] => THD_GNODE_KEY - * data = THD_NODE's - */ - if (config->gen_id == 0) /* do em all */ - { - int i; + if ( map.find(config->gen_id) != map.end() ) + return THD_TOO_MANY_THDOBJ; - for (i = 0; i < THD_MAX_GENID; i++) - { - /* only assign if there wasn't a value */ - if (thd_objs->sfthd_garray[policy_id][i] == nullptr) - { - thd_objs->sfthd_garray[policy_id][i] = sfthd_node; - } - } - } - else - { - thd_objs->sfthd_garray[policy_id][config->gen_id] = sfthd_node; - } - -#ifdef THD_DEBUG - printf("THD_DEBUG-GLOBAL: created global threshold object " - "for gen_id=%u\n",config->gen_id); - fflush(stdout); -#endif + map.emplace(config->gen_id, std::make_unique(*config)); return 0; } + /*! Add a permanent threshold object to the threshold table. Multiple objects may be defined for each gen_id and sig_id pair. Internally @@ -577,63 +400,40 @@ int sfthd_create_threshold( int type, int priority, int count, - int seconds, + unsigned seconds, sfip_var_t* ip_address, PolicyId policy_id) { - //allocate memory fpr sfthd_array if needed. - THD_NODE sfthd_node; - memset(&sfthd_node, 0, sizeof(sfthd_node)); - - thd_objs->count++; - - sfthd_node.thd_id = thd_objs->count; /* produce a unique thd_id for this node */ - sfthd_node.gen_id = gen_id; - sfthd_node.sig_id = sig_id; - sfthd_node.tracking = tracking; /* by_src, by_dst */ - sfthd_node.type = type; - sfthd_node.priority = priority; - sfthd_node.count = count; - sfthd_node.seconds = seconds; - sfthd_node.ip_address= ip_address; - - // FIXIT-L convert to std::vector - sfDynArrayCheckBounds ((void**)&thd_objs->sfthd_garray, policy_id, - &thd_objs->numPoliciesAllocated); - - if (thd_objs->sfthd_garray[policy_id] == nullptr) - { - thd_objs->sfthd_garray[policy_id] = - (THD_NODE**)snort_calloc(THD_MAX_GENID, sizeof(THD_NODE*)); - } + + if ( thd_objs == nullptr ) + return -1; + + if ( thd_objs->sfthd_gvector.size() <= policy_id ) + thd_objs->sfthd_gvector.resize(policy_id + 1); + if ( thd_objs->sfthd_vector.size() <= gen_id ) + thd_objs->sfthd_vector.resize(gen_id + 1, nullptr); + + THD_NODE sfthd_node { thd_objs->count++, // Increment count and use it as thd_id + gen_id, sig_id, tracking, // by_src, by_dst + type, priority, count, seconds, ip_address }; + if ( sig_id == 0 ) - { return sfthd_create_threshold_global(sc, thd_objs, &sfthd_node, policy_id); - } - if ( gen_id == 0 ) + if ( gen_id == 0 ) return -1; return sfthd_create_threshold_local(sc, thd_objs, &sfthd_node, policy_id); } -#ifdef THD_DEBUG -static char* printIP(unsigned u, char* buf, unsigned len) -{ - SnortSnprintf(buf, len, "%d.%d.%d.%d", (u>>24)&0xff, (u>>16)&0xff, (u>>8)&0xff, u&0xff); - return s; -} - -#endif int sfthd_test_rule(XHash* rule_hash, THD_NODE* sfthd_node, const SfIp* sip, const SfIp* dip, long curtime, PolicyId policy_id) { - if ((rule_hash == nullptr) || (sfthd_node == nullptr)) + if ( rule_hash == nullptr or sfthd_node == nullptr ) return 0; int status = sfthd_test_local(rule_hash, sfthd_node, sip, dip, curtime, policy_id); - return (status < -1) ? 1 : status; } @@ -641,13 +441,9 @@ static inline int sfthd_test_suppress( THD_NODE* sfthd_node, const SfIp* ip) { - if ( !sfthd_node->ip_address || + if ( !sfthd_node->ip_address or sfvar_ip_in(sfthd_node->ip_address, ip) ) { -#ifdef THD_DEBUG - printf("THD_DEBUG: SUPPRESS NODE, do not log events with this IP\n"); - fflush(stdout); -#endif /* Don't log, and stop looking( event's to this address * for this gen_id+sig_id) */ return -1; @@ -667,10 +463,6 @@ static inline int sfthd_test_non_suppress( if ( sfthd_node->type == THD_TYPE_DETECT ) { -#ifdef THD_DEBUG - printf("\n...Detect Test\n"); - fflush(stdout); -#endif dt = (unsigned)(curtime - sfthd_ip_node->tstart); if ( dt >= sfthd_node->seconds ) @@ -684,13 +476,7 @@ static inline int sfthd_test_non_suppress( } sfthd_ip_node->tlast = curtime; -#ifdef THD_DEBUG - printf("...dt=%u, sfthd_node->seconds=%u\n",dt, sfthd_node->seconds); - printf("...sfthd_ip_node->count=%u, sfthd_node->count=%d\n", - sfthd_ip_node->count,sfthd_node->count); - fflush(stdout); -#endif - if ( (int)sfthd_ip_node->count > sfthd_node->count || + if ( (int)sfthd_ip_node->count > sfthd_node->count or (int)sfthd_ip_node->prev > sfthd_node->count ) { return 0; /* Log it, stop looking: log all > 'count' events */ @@ -702,10 +488,6 @@ static inline int sfthd_test_non_suppress( } if ( sfthd_node->type == THD_TYPE_LIMIT ) { -#ifdef THD_DEBUG - printf("\n...Limit Test\n"); - fflush(stdout); -#endif dt = (unsigned)(curtime - sfthd_ip_node->tstart); if ( dt >= sfthd_node->seconds ) @@ -714,12 +496,6 @@ static inline int sfthd_test_non_suppress( sfthd_ip_node->count = 1; } -#ifdef THD_DEBUG - printf("...dt=%u, sfthd_node->seconds=%u\n",dt, sfthd_node->seconds); - printf("...sfthd_ip_node->count=%u, sfthd_node->count=%d\n", - sfthd_ip_node->count,sfthd_node->count); - fflush(stdout); -#endif if ( (int)sfthd_ip_node->count <= sfthd_node->count ) { return 0; /* Log it, stop looking: only log the 1st 'count' events */ @@ -731,10 +507,6 @@ static inline int sfthd_test_non_suppress( } else if ( sfthd_node->type == THD_TYPE_THRESHOLD ) { -#ifdef THD_DEBUG - printf("\n...Threshold Test\n"); - fflush(stdout); -#endif dt = (unsigned)(curtime - sfthd_ip_node->tstart); if ( dt >= sfthd_node->seconds ) { @@ -752,10 +524,6 @@ static inline int sfthd_test_non_suppress( } else if ( sfthd_node->type == THD_TYPE_BOTH ) { -#ifdef THD_DEBUG - printf("\n...Threshold+Limit Test\n"); - fflush(stdout); -#endif dt = (unsigned)(curtime - sfthd_ip_node->tstart); if ( dt >= sfthd_node->seconds ) { @@ -789,11 +557,6 @@ static inline int sfthd_test_non_suppress( } } -#ifdef THD_DEBUG - printf("THD_DEBUG: You should not be here...\n"); - fflush(stdout); -#endif - return 0; /* should not get here, so log it just to be safe */ } @@ -826,50 +589,23 @@ int sfthd_test_local( THD_IP_NODE data,* sfthd_ip_node; const SfIp* ip; -#ifdef THD_DEBUG - char buf[24]; - printf("THD_DEBUG: Key THD_NODE IP=%s,", - printIP((unsigned)sfthd_node->ip_address, buf, sizeof(buf)) ); - printf(" MASK=%s\n", printIP((unsigned)sfthd_node->ip_mask, buf, sizeof(buf)) ); - printf("THD_DEBUG: PKT SIP=%s\n", printIP((unsigned)sip, buf, sizeof(buf)) ); - printf("THD_DEBUG: PKT DIP=%s\n", printIP((unsigned)dip, buf, sizeof(buf)) ); - fflush(stdout); -#endif - - /* -1 means don't do any limit or thresholding */ - if ( sfthd_node->count == THD_NO_THRESHOLD) - { -#ifdef THD_DEBUG - printf("\n...No Threshold applied for this object\n"); - fflush(stdout); -#endif + // -1 means don't do any limit or thresholding + if ( sfthd_node->count == THD_NO_THRESHOLD ) return 0; - } - /* - * Get The correct IP - */ - if (sfthd_node->tracking == THD_TRK_SRC) + // Get The correct IP + if ( sfthd_node->tracking == THD_TRK_SRC ) ip = sip; else ip = dip; - /* - * Check for and test Suppression of this event to this IP - */ + // Check for and test Suppression of this event to this IP if ( sfthd_node->type == THD_TYPE_SUPPRESS ) - { -#ifdef THD_DEBUG - printf("THD_DEBUG: SUPPRESS NODE Testing...\n"); fflush(stdout); -#endif return sfthd_test_suppress(sfthd_node, ip); - } - - /* - * Go on and do standard thresholding - */ + + // Go on and do standard thresholding - /* Set up the key */ + // Set up the key key.policyId = policy_id; key.ip = *ip; key.thd_id = sfthd_node->thd_id; @@ -880,10 +616,8 @@ int sfthd_test_local( data.prev = 0; data.tstart = data.tlast = curtime; /* Event time */ - /* - * Check for any Permanent sig_id objects for this gen_id or add this one ... - */ - + // Check for any Permanent sig_id objects for this gen_id or add this one ... + std::lock_guard lock(sfthd_hash_mutex); int status = local_hash->insert((void*)&key, &data); @@ -931,26 +665,10 @@ static inline int sfthd_test_global( THD_IP_NODE* sfthd_ip_node; const SfIp* ip; -#ifdef THD_DEBUG - char buf[24]; - printf("THD_DEBUG: Global THD_NODE IP=%s,", - printIP((unsigned)sfthd_node->ip_address, buf, sizeof(buf)) ); - printf(" MASK=%s\n", printIP((unsigned)sfthd_node->ip_mask, buf, sizeof(buf)) ); - printf("THD_DEBUG: PKT SIP=%s\n", printIP((unsigned)sip, buf, sizeof(buf)) ); - printf("THD_DEBUG: PKT DIP=%s\n", printIP((unsigned)dip, buf, sizeof(buf)) ); - fflush(stdout); -#endif - /* -1 means don't do any limit or thresholding */ if ( sfthd_node->count == THD_NO_THRESHOLD) - { -#ifdef THD_DEBUG - printf("\n...No Threshold applied for this object\n"); - fflush(stdout); -#endif return 0; - } - + /* Get The correct IP */ if (sfthd_node->tracking == THD_TRK_SRC) ip = sip; @@ -959,13 +677,8 @@ static inline int sfthd_test_global( /* Check for and test Suppression of this event to this IP */ if ( sfthd_node->type == THD_TYPE_SUPPRESS ) - { -#ifdef THD_DEBUG - printf("THD_DEBUG: G-SUPPRESS NODE Testing...\n"); fflush(stdout); -#endif return sfthd_test_suppress(sfthd_node, ip); - } - + /* * Go on and do standard thresholding */ @@ -984,7 +697,7 @@ static inline int sfthd_test_global( /* Check for any Permanent sig_id objects for this gen_id or add this one ... */ int status = global_hash->insert((void*)&key, &data); - if (status == HASH_INTABLE) + if ( status == HASH_INTABLE ) { /* Already in the table */ sfthd_ip_node = (THD_IP_NODE*)global_hash->get_user_data(); @@ -992,12 +705,12 @@ static inline int sfthd_test_global( /* Increment the event count */ sfthd_ip_node->count++; } - else if (status == HASH_NOMEM) + else if ( status == HASH_NOMEM ) { event_filter_stats.xhash_nomem_peg_global++; return 1; } - else if (status != HASH_OK) + else if ( status != HASH_OK ) { /* hash error */ return 1; /* check the next threshold object */ @@ -1039,163 +752,67 @@ int sfthd_test_threshold( long curtime, PolicyId policy_id) { - tThdItemKey key; - GHash* sfthd_hash; - THD_ITEM* sfthd_item; - THD_NODE* sfthd_node; - THD_NODE* g_thd_node = nullptr; -#ifdef THD_DEBUG - int cnt; -#endif - - if ((thd_objs == nullptr) || (thd == nullptr)) - return 0; + if ( thd_objs == nullptr or thd == nullptr or gen_id >= THD_MAX_GENID ) + return 0; // Invalid parameters or gen_id -#ifdef THD_DEBUG - printf("sfthd_test_threshold...\n"); fflush(stdout); -#endif - - if ( gen_id >= THD_MAX_GENID ) + // Check if the gen_id exists in sfthd_vector + if ( gen_id < thd_objs->sfthd_vector.size() ) { -#ifdef THD_DEBUG - printf("THD_DEBUG: invalid gen_id=%u\n",gen_id); - fflush(stdout); -#endif - return 0; /* bogus gen_id */ - } + GHash* sfthd_hash = thd_objs->sfthd_vector[gen_id]; - /* - * Get the hash table for this gen_id - */ - sfthd_hash = thd_objs->sfthd_array[gen_id]; - if (sfthd_hash == nullptr) - { -#ifdef THD_DEBUG - printf("THD_DEBUG: no hash table entry for gen_id=%u\n",gen_id); - fflush(stdout); -#endif - goto global_test; - /* return 0; */ /* no threshold objects for this gen_id, log it ! */ - } + if ( sfthd_hash != nullptr ) + { + tThdItemKey key = { policy_id, sig_id }; + THD_ITEM* sfthd_item = static_cast(sfthd_hash->find(&key)); - key.sig_id = sig_id; - key.policyId = policy_id; - /* - * Check for any Permanent sig_id objects for this gen_id - */ - sfthd_item = (THD_ITEM*)sfthd_hash->find((void*)&key); - if (sfthd_item == nullptr) - { -#ifdef THD_DEBUG - printf("THD_DEBUG: no THD objects for gen_id=%u, sig_id=%u\n",gen_id,sig_id); - fflush(stdout); -#endif - /* no matching permanent sig_id objects so, log it ! */ - goto global_test; + if ( sfthd_item != nullptr and sfthd_item->sfthd_node_list != nullptr ) + { + SF_LNODE* cursor; + for ( THD_NODE* sfthd_node = static_cast(sflist_first(sfthd_item->sfthd_node_list, &cursor)); + sfthd_node != nullptr; + sfthd_node = static_cast(sflist_next(&cursor)) ) + { + int status = sfthd_test_local(thd->ip_nodes, sfthd_node, sip, dip, curtime, policy_id); + if ( status <= 0 ) + return (status < -1) ? 1 : status; + } + } + } } - /* No List of Threshold objects - bail and log it */ - if (sfthd_item->sfthd_node_list == nullptr) + // Global threshold test + if (policy_id < thd_objs->sfthd_gvector.size()) { - goto global_test; - } - - /* For each permanent thresholding object, test/add/update the thd object - We maintain a list of thd objects for each gen_id+sig_id - each object has it's own unique thd_id - Suppression nodes have a very high priority, so they are tested 1st */ -#ifdef THD_DEBUG - cnt=0; -#endif - SF_LNODE* cursor; + auto& g_thd_map = thd_objs->sfthd_gvector[policy_id]; - for (sfthd_node = (THD_NODE*)sflist_first(sfthd_item->sfthd_node_list, &cursor); - sfthd_node != nullptr; - sfthd_node = (THD_NODE*)sflist_next(&cursor)) - { -#ifdef THD_DEBUG - cnt++; - printf("THD_DEBUG: gen_id=%u sig_id=%u testing thd_id=%d thd_type=%d\n", - gen_id, sig_id, sfthd_node->thd_id, sfthd_node->type); - fflush(stdout); -#endif - /* - * Test SUPPRESSION and THRESHOLDING - */ - int status = sfthd_test_local(thd->ip_nodes, sfthd_node, sip, dip, curtime, policy_id); + auto it = g_thd_map.find(gen_id); + if ( gen_id != 0 and it == g_thd_map.end() ) + it = g_thd_map.find(0); - if ( status < 0 ) /* -1 == Don't log and stop looking */ - { -#ifdef THD_DEBUG - printf("THD_DEBUG: gen_id=%u sig_id=%u, UnLoggable %d\n\n",gen_id, sig_id,cnt); - fflush(stdout); -#endif - return (status < -1) ? 1 : -1; /* !0 == Don't log it*/ - } - else if ( status == 0 ) /* Log it and stop looking */ + if ( it != g_thd_map.end() ) { -#ifdef THD_DEBUG - printf("THD_DEBUG: gen_id=%u sig_id=%u tested %d THD_NODE's, " - "Loggable\n\n",sfthd_item->gen_id, sfthd_item->sig_id,cnt); - fflush(stdout); -#endif - return 0; /* 0 == Log the event */ + THD_NODE* g_thd_node = it->second.get(); // Get the raw pointer from the unique_ptr + if ( g_thd_node != nullptr ) + { + int status = sfthd_test_global(thd->ip_gnodes, g_thd_node, sig_id, sip, dip, curtime, policy_id); + if ( status <= 0 ) + return (status < -1) ? 1 : status; + } } - /* status > 0 : Log it later but Keep looking - * check the next threshold object for a blocking action ... - */ } - /* - * Test for a global threshold object - * we're here cause there were no threshold objects for this gen_id/sig_id pair - */ -global_test: - -#ifdef THD_DEBUG - printf("THD_DEBUG-GLOBAL: doing global object test\n"); -#endif - if (thd_objs->sfthd_garray && thd_objs->sfthd_garray[policy_id]) - { - g_thd_node = thd_objs->sfthd_garray[policy_id][gen_id]; - } + return 0; // Default to loggable if no blocking action is found +} - if ( g_thd_node ) - { - int status = sfthd_test_global(thd->ip_gnodes, g_thd_node, sig_id, - sip, dip, curtime, policy_id); - if ( status < 0 ) /* -1 == Don't log and stop looking */ - { #ifdef THD_DEBUG - printf("THD_DEBUG-GLOBAL: gen_id=%u sig_id=%u THD_NODE's, " - "UnLoggable\n\n",gen_id, sig_id); - fflush(stdout); -#endif - return (status < -1) ? 1 : -1; /* !0 == Don't log it*/ - } - /* Log it ! */ -#ifdef THD_DEBUG - printf("THD_DEBUG-GLOBAL: gen_id=%u sig_id=%u THD_NODE's, " - "Loggable\n\n",gen_id, sig_id); - fflush(stdout); -#endif - } - else - { -#ifdef THD_DEBUG - printf("THD_DEBUG-GLOBAL: no Global THD Object for gen_id=%u, " - "sig_id=%u\n\n",gen_id, sig_id); - fflush(stdout); -#endif - } - - return 0; /* Default: Log it if we did not block the logging action */ +static char* printIP(unsigned u, char* buf, unsigned len) +{ + SnortSnprintf(buf, len, "%d.%d.%d.%d", (u>>24)&0xff, (u>>16)&0xff, (u>>8)&0xff, u&0xff); + return s; } - -#ifdef THD_DEBUG /*! * A function to print the thresholding objects to stdout. * diff --git a/src/filters/sfthd.h b/src/filters/sfthd.h index 0e3d8368a..f28316f8a 100644 --- a/src/filters/sfthd.h +++ b/src/filters/sfthd.h @@ -29,6 +29,7 @@ #include "utils/cpp_macros.h" #include +#include namespace snort { @@ -129,15 +130,15 @@ PADDING_GUARD_END */ struct THD_NODE { - int thd_id; /* Id of this node */ - unsigned gen_id; /* Keep these around if needed */ - unsigned sig_id; - int tracking; /* by_src, by_dst */ - int type; - int priority; - int count; - unsigned seconds; - sfip_var_t* ip_address; + int thd_id = 0; /* Id of this node */ + unsigned gen_id = 0; /* Keep these around if needed */ + unsigned sig_id = 0; + int tracking = 0; /* by_src, by_dst */ + int type = 0; + int priority = 0; + int count = 0; + unsigned seconds = 0; + sfip_var_t* ip_address = nullptr; }; /*! @@ -198,19 +199,19 @@ struct THD_STRUCT struct ThresholdObjects { - int count; /* Total number of thresholding/suppression objects */ - snort::GHash* sfthd_array[THD_MAX_GENID]; /* Local Hash of THD_ITEM nodes, lookup by key=sig_id - */ - - /* Double array of THD_NODE pointers. First index is policyId and therefore variable length. - * Second index is genId and of fixed length, A simpler definition could be - * THD_NODE * sfthd_garray[0][THD_MAX_GENID] and we could intentionally overflow first index, - * but we may have to deal with compiler warnings if the array is indexed by value known at - * compile time. - */ - //THD_NODE * (*sfthd_garray)[THD_MAX_GENID]; - THD_NODE*** sfthd_garray; - PolicyId numPoliciesAllocated; + int count = 0; /* Total number of thresholding/suppression objects */ + std::vector sfthd_vector; /* Local Hash of THD_ITEM nodes, lookup by key=sig_id */ + /* + * Vector of unordered maps, each map indexed by generator ID (genId) and containing + * unique pointers to THD_NODE structures. The outer vector is indexed by policyId + * and can dynamically vary in size. Each map represents THD_NODE structures for a specific + * policyId, with the key being the genId. This allows direct access to THD_NODE structures + * by their generator ID within a given policy context, optimizing lookup and management + * of thresholding nodes. + */ + std::vector>> sfthd_gvector; + + PolicyId numPoliciesAllocated = 0; }; struct EventFilterStats @@ -245,7 +246,7 @@ void sfthd_node_free(THD_NODE*); int sfthd_create_threshold(snort::SnortConfig*, ThresholdObjects*, unsigned gen_id, unsigned sig_id, int tracking, int type, int priority, int count, - int seconds, sfip_var_t* ip_address, PolicyId policy_id); + unsigned seconds, sfip_var_t* ip_address, PolicyId policy_id); // 1: don't log due to event_filter // 0: log diff --git a/src/utils/CMakeLists.txt b/src/utils/CMakeLists.txt index 9973a56c2..8e9766f73 100644 --- a/src/utils/CMakeLists.txt +++ b/src/utils/CMakeLists.txt @@ -24,8 +24,6 @@ add_library ( utils OBJECT ${SNPRINTF_SOURCES} boyer_moore.cc dnet_header.h - dyn_array.cc - dyn_array.h kmap.cc sflsq.cc snort_bounds.h diff --git a/src/utils/dyn_array.cc b/src/utils/dyn_array.cc deleted file mode 100644 index 1253ce33c..000000000 --- a/src/utils/dyn_array.cc +++ /dev/null @@ -1,56 +0,0 @@ -//-------------------------------------------------------------------------- -// Copyright (C) 2014-2024 Cisco and/or its affiliates. All rights reserved. -// Copyright (C) 2008-2013 Sourcefire, Inc. -// -// This program is free software; you can redistribute it and/or modify it -// under the terms of the GNU General Public License Version 2 as published -// by the Free Software Foundation. You may not use, modify or distribute -// this program under any other version of the GNU General Public License. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// General Public License for more details. -// -// You should have received a copy of the GNU General Public License along -// with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -//-------------------------------------------------------------------------- - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "dyn_array.h" - -#include "util.h" - -// number of additional policies allocated with each re-alloc operation -#define POLICY_ALLOCATION_CHUNK 10 - -int sfDynArrayCheckBounds( // FIXIT-L replace with vector - void** dynArray, - unsigned int index, - unsigned int* maxElements - ) -{ - void* ppTmp = nullptr; - - if (index >= *maxElements) - { - //expand the array - ppTmp = snort_calloc(index+POLICY_ALLOCATION_CHUNK, sizeof(void*)); - - if (*maxElements) - { - memcpy(ppTmp, *dynArray, sizeof(void*)*(*maxElements)); - snort_free(*dynArray); - } - - *dynArray = ppTmp; - *maxElements = index + POLICY_ALLOCATION_CHUNK; - } - - return 0; -} - diff --git a/src/utils/dyn_array.h b/src/utils/dyn_array.h deleted file mode 100644 index e38756ae7..000000000 --- a/src/utils/dyn_array.h +++ /dev/null @@ -1,27 +0,0 @@ -//-------------------------------------------------------------------------- -// Copyright (C) 2014-2024 Cisco and/or its affiliates. All rights reserved. -// Copyright (C) 2008-2013 Sourcefire, Inc. -// -// This program is free software; you can redistribute it and/or modify it -// under the terms of the GNU General Public License Version 2 as published -// by the Free Software Foundation. You may not use, modify or distribute -// this program under any other version of the GNU General Public License. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// General Public License for more details. -// -// You should have received a copy of the GNU General Public License along -// with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -//-------------------------------------------------------------------------- - -#ifndef DYN_ARRAY_H -#define DYN_ARRAY_H - -int sfDynArrayCheckBounds( // FIXIT-L change return type to bool - void** dynArray, unsigned int index, unsigned int* maxElements); - -#endif -