const uint8_t* hdr_start = raw_in;
if (pflow)
{
- Layer mpls_lyr = pflow->get_mpls_layer_per_dir(enc.forward());
+ Layer* mpls_lyr = pflow->get_mpls_layer_per_dir(enc.forward());
- if (mpls_lyr.length)
+ if (mpls_lyr && mpls_lyr->length)
{
- hdr_len = mpls_lyr.length;
- hdr_start = mpls_lyr.start;
+ hdr_len = mpls_lyr->length;
+ hdr_start = mpls_lyr->start;
+ assert(hdr_start);
}
}
flow_stash.h
ha.h
session.h
- stash_item.h
stream_flow.h
)
ha_module.cc
ha_module.h
prune_stats.h
- stash_item.h
filter_flow_critera.h
)
information.
- FlowHAClient - All HA coordination is managed via a set of FlowHAClient's.
Every function that desires to use HA capabilities defines one FlowHAClient
- object within the packet processing thread. Each client is provided a
+ object within the packet processing thread. Each client is provided a
handle bit-mask as part of the pending logic. The client may set the
pending bit to indicate the desire to add content to the HA message.
A maximum of 17 clients may existing (numbers 1-16, corresponding to the
09/25/2023
-In response to the need for more nuanced management of different protocol
-types within the `flow_cache`, we've leveraged the newly added feature in
-xhash. This enhancement includes the introduction of Protocol-Based
-Least Recently Used (LRU) caches, which substantially improves the handling
+In response to the need for more nuanced management of different protocol
+types within the `flow_cache`, we've leveraged the newly added feature in
+xhash. This enhancement includes the introduction of Protocol-Based
+Least Recently Used (LRU) caches, which substantially improves the handling
of multiple protocol types in the cache.
-With this implementation, during various pruning sessions (idle,
-excess, and timeout etc), we've adopted a round-robin method to cycle through
-the LRU lists designated for each protocol type. This methodology ensures
-that every protocol, irrespective of its inherent timeout characteristics,
+With this implementation, during various pruning sessions (idle,
+excess, and timeout etc), we've adopted a round-robin method to cycle through
+the LRU lists designated for each protocol type. This methodology ensures
+that every protocol, irrespective of its inherent timeout characteristics,
is given an equal opportunity for pruning and retirement from the cache.
-This adjustment to `flow_cache` not only addresses the previously observed
-bias during pruning sessions, especially concerning UDP flows,
-but lays down a framework for more advanced and controlled data management
+This adjustment to `flow_cache` not only addresses the previously observed
+bias during pruning sessions, especially concerning UDP flows,
+but lays down a framework for more advanced and controlled data management
within the cache moving forward.
10/25/2024
Allowlist LRU
-To address the need for preserving flows that have been allowlisted and are
-at risk of timing out, we've introduced a configurable Allowlist LRU cache
-within the flow_cache. This enhancement enables the retention of flows marked
-with a whitelist verdict, preventing them from being prematurely pruned due
-to inactivity timeouts. This is particularly beneficial in scenarios where
-Snort ceases to observe traffic for a flow after the whitelist decision,
-especially if that flow is long-lived. Without this adjustment,
-such flows may be pruned by the cache upon timeout, potentially impacting
-event logging at the flow’s end-of-life (EOF) due to missing
+To address the need for preserving flows that have been allowlisted and are
+at risk of timing out, we've introduced a configurable Allowlist LRU cache
+within the flow_cache. This enhancement enables the retention of flows marked
+with a whitelist verdict, preventing them from being prematurely pruned due
+to inactivity timeouts. This is particularly beneficial in scenarios where
+Snort ceases to observe traffic for a flow after the whitelist decision,
+especially if that flow is long-lived. Without this adjustment,
+such flows may be pruned by the cache upon timeout, potentially impacting
+event logging at the flow’s end-of-life (EOF) due to missing
pruned flow information.
The Allowlist LRU cache is disabled by default but can be enabled by adding
-allowlist_cache = { enable = true } in the stream configuration.
-Like the protocol-based LRUs, this allowlist functionality is an
-additional LRU rather than a new hash_table, thereby maintaining
-consistent performance with previous configurations.
\ No newline at end of file
+allowlist_cache = { enable = true } in the stream configuration.
+Like the protocol-based LRUs, this allowlist functionality is an
+additional LRU rather than a new hash_table, thereby maintaining
+consistent performance with previous configurations.
+
+04/07/2025
+Changed the flow data hash to start with 7 hash buckets. This is trying to balance
+between memory usage and speed.
+The flow data hash load factor controls the when a hash table rebalance happens. We
+don't ever want a hash rebalance to happen for flow data as that would mean allocating
+a new bigger bucket array and rehashing all of the elements in the hash. So, a max
+load factor of 5.0 was chosen. This means that the average depth for all buckets in
+the hash would need to be 5 or more before a rebalance would happen. This is very
+unlikely to happen.
#include "expect_cache.h"
#include "expect_flow.h"
+#include <algorithm>
+
#include "detection/ips_context.h"
#include "hash/zhash.h"
#include "packet_io/packet_tracer.h"
static THREAD_LOCAL std::vector<ExpectFlow*>* packet_expect_flows = nullptr;
ExpectFlow::~ExpectFlow()
-{
- clear();
-}
+{ clear(); }
void ExpectFlow::clear()
{
- while (data)
- {
- FlowData* fd = data;
- data = data->next;
- delete fd;
- }
- data = nullptr;
+ std::for_each(std::begin(data), std::end(data),
+ [](FlowData* f)
+ { delete f; }
+ );
+ data.clear();
}
-int ExpectFlow::add_flow_data(FlowData* fd)
+void ExpectFlow::add_flow_data(FlowData* fd)
{
- if (data)
+ unsigned id = fd->get_id();
+ if (data.size() == data.capacity())
+ data.reserve(data.size() + FlowDataStore::FLOW_DATA_INCREMENTS);
+ auto lower = std::lower_bound(data.begin(), data.end(), id,
+ [](const FlowData* the_fd, unsigned id)
+ { return the_fd->get_id() < id; });
+ if (lower == data.end())
+ data.emplace_back(fd);
+ else
{
- FlowData* prev_fd;
- for (prev_fd = data; prev_fd && prev_fd->next; prev_fd = prev_fd->next);
-
- prev_fd->next = fd;
+ FlowData* lower_fd = *lower;
+ if (lower_fd->get_id() == id)
+ {
+ delete lower_fd;
+ *lower = fd;
+ }
+ else
+ data.emplace(lower, fd);
}
- else
- data = fd;
- return 0;
}
std::vector<ExpectFlow*>* ExpectFlow::get_expect_flows()
FlowData* ExpectFlow::get_flow_data(unsigned id)
{
- for (FlowData* p = data; p; p = p->next)
- {
- if (p->get_id() == id)
- return p;
- }
- return nullptr;
+ auto lower = std::lower_bound(data.begin(), data.end(), id,
+ [](const FlowData* the_fd, unsigned id)
+ { return the_fd->get_id() < id; });
+ if (lower == data.end())
+ return nullptr;
+ FlowData* fd = *lower;
+ return (fd->get_id() == id) ? fd : nullptr;
}
struct ExpectNode
bool ExpectCache::process_expected(ExpectNode* node, FlowKey& key, Packet* p, Flow* lws)
{
- ExpectFlow* head;
- FlowData* fd;
- bool ignoring = false;
-
assert(node->count && node->head);
/* Pull the first set of expected flow data off of the Expect node and apply it
in its entirety to the target flow. Discard the set (and potentially the
entire node, it empty) after this is done. */
node->count--;
- head = node->head;
+ ExpectFlow* head = node->head;
node->head = head->next;
- while ((fd = head->data))
- {
- head->data = fd->next;
- lws->set_flow_data(fd);
- ++realized;
- fd->handle_expected(p);
- }
+ std::for_each(std::begin(head->data), std::end(head->data),
+ [this, p, lws](FlowData* fd)
+ {
+ lws->set_flow_data(fd);
+ ++realized;
+ fd->handle_expected(p);
+ }
+ );
+ head->data.clear();
head->next = free_list;
free_list = head;
/* If this is 0, we're ignoring, otherwise setting id of new session */
+ bool ignoring = false;
if (!node->snort_protocol_id)
ignoring = node->direction != 0;
else
for (unsigned i = 0; i < max; ++i)
{
ExpectFlow* p = pool + i;
- p->data = nullptr;
p->next = free_list;
free_list = p;
}
int16_t expected_ingress_group = ctrlPkt->pkth->egress_group;
int16_t expected_egress_group = ctrlPkt->pkth->ingress_group;
bool reversed_key = key.init(ctrlPkt->context->conf, type, ip_proto, cliIP, cliPort,
- srvIP, srvPort, vlanId, mplsId, ctrlPkt->pkth->address_space_id,
+ srvIP, srvPort, vlanId, mplsId, ctrlPkt->pkth->address_space_id,
#ifndef DISABLE_TENANT_ID
ctrlPkt->pkth->tenant_id,
#endif
last = node->tail;
if ( last )
{
- FlowData* lfd = last->data;
- while ( lfd )
- {
- if ( lfd->get_id() == fd->get_id() )
- {
- last = nullptr;
- break;
- }
- lfd = lfd->next;
- }
+ if ( last->get_flow_data(fd->get_id()) )
+ last = nullptr;
}
}
else
// a la FlowCache)
//-------------------------------------------------------------------------
+#include <memory>
+#include <unordered_map>
#include <vector>
+#include "flow/flow_data.h"
#include "main/snort_types.h"
struct ExpectNode;
namespace snort
{
-class FlowData;
struct Packet;
struct SO_PUBLIC ExpectFlow
{
- struct ExpectFlow* next;
- snort::FlowData* data;
+ ExpectFlow* next = nullptr;
+ // This cannot use a unique_ptr because we need to move to a real flow during realization
+ std::vector<FlowData*> data;
+ ExpectFlow() = default;
~ExpectFlow();
void clear();
- int add_flow_data(snort::FlowData*);
- snort::FlowData* get_flow_data(unsigned);
+ void add_flow_data(FlowData*);
+ FlowData* get_flow_data(unsigned);
static std::vector<ExpectFlow*>* get_expect_flows();
static void reset_expect_flows();
- static void handle_expected_flows(const snort::Packet*);
+ static void handle_expected_flows(const Packet*);
};
}
free_flow_data();
delete session;
- if ( mpls_client.length )
- delete[] mpls_client.start;
- if ( mpls_server.length )
- delete[] mpls_server.start;
+ delete_mpls_layer(mpls_client);
+ delete_mpls_layer(mpls_server);
delete bitop;
if ( ssn_client )
clear_data();
delete ha_state;
- delete stash;
delete ips_cont;
}
ha_state = new FlowHAState;
previous_ssn_state = ssn_state;
}
- mpls_client.length = 0;
- mpls_server.length = 0;
-
- stash = new FlowStash;
+ assert(!mpls_client);
+ assert(!mpls_server);
}
inline void Flow::clean()
{
- if ( mpls_client.length )
- {
- delete[] mpls_client.start;
- mpls_client.length = 0;
- }
- if ( mpls_server.length )
- {
- delete[] mpls_server.start;
- mpls_server.length = 0;
- }
+ delete_mpls_layer(mpls_client);
+ mpls_client = nullptr;
+ delete_mpls_layer(mpls_server);
+ mpls_server = nullptr;
delete bitop;
bitop = nullptr;
filtering_state.clear();
return get_inspection_duration();
}
-int Flow::set_flow_data(FlowData* fd)
-{
- if ( !fd ) return -1;
-
- current_flow_data = fd;
- uint32_t id = fd->get_id();
- // operator[] will create a new entry if it does not exist
- // or replace the existing one if it does
- // when replacing, the old entry is deleted
- flow_data[id] = std::unique_ptr<FlowData>(fd);
- return 0;
-}
-
-
-FlowData* Flow::get_flow_data(unsigned id) const
-{
- auto it = flow_data.find(id);
- if ( it != flow_data.end() )
- return it->second.get();
- return nullptr;
-}
-
-void Flow::free_flow_data(FlowData* fd)
-{
- if ( fd )
- flow_data.erase(fd->get_id());
-}
-
-void Flow::free_flow_data(uint32_t proto)
-{
- flow_data.erase(proto);
-}
-
void Flow::free_flow_data()
{
if ( flow_data.empty() )
{
- if (stash)
- stash->reset();
+ stash.reset();
return;
}
const SnortConfig* sc = SnortConfig::get_conf();
}
flow_data.clear();
- if (stash)
- stash->reset();
+ stash.reset();
if (ps)
{
}
}
-void Flow::call_handlers(Packet* p, bool eof)
-{
- for (auto& fd_pair : flow_data)
- {
- FlowData* fd = fd_pair.second.get();
- if ( eof )
- fd->handle_eof(p);
- else
- fd->handle_retransmit(p);
- }
-}
-
void Flow::markup_packet_flags(Packet* p)
{
if ( (ssn_state.session_flags & SSNFLAG_ESTABLISHED) != SSNFLAG_ESTABLISHED )
if ( !mpls_lyr || !(mpls_lyr->start) )
return;
- if ( p->packet_flags & PKT_FROM_CLIENT )
+ Layer*& mpls_layer = ( p->packet_flags & PKT_FROM_CLIENT ) ? mpls_client : mpls_server;
+ if ( !mpls_layer )
{
- if ( !mpls_client.length )
- {
- mpls_client.length = mpls_lyr->length;
- mpls_client.prot_id = mpls_lyr->prot_id;
- mpls_client.start = new uint8_t[mpls_lyr->length];
- memcpy((void *)mpls_client.start, mpls_lyr->start, mpls_lyr->length);
- }
- }
- else
- {
- if ( !mpls_server.length )
- {
- mpls_server.length = mpls_lyr->length;
- mpls_server.prot_id = mpls_lyr->prot_id;
- mpls_server.start = new uint8_t[mpls_lyr->length];
- memcpy((void *)mpls_server.start, mpls_lyr->start, mpls_lyr->length);
- }
+ mpls_layer = new Layer;
+ mpls_layer->length = mpls_lyr->length;
+ mpls_layer->prot_id = mpls_lyr->prot_id;
+ mpls_layer->start = new uint8_t[mpls_lyr->length];
+ memcpy((void *)mpls_layer->start, mpls_lyr->start, mpls_lyr->length);
}
}
-Layer Flow::get_mpls_layer_per_dir(bool client)
+Layer* Flow::get_mpls_layer_per_dir(bool client)
{
if ( client )
return mpls_client;
// state. Inspector state is stored in FlowData, and Flow manages a list
// of FlowData items.
+#include <atomic>
#include <bitset>
+#include <list>
+#include <memory>
#include <string>
#include <sys/time.h>
+#include <unordered_map>
#include <daq_common.h>
void restart(bool dump_flow_data = true);
void clear(bool dump_flow_data = true);
- int set_flow_data(FlowData*);
- FlowData* get_flow_data(uint32_t proto) const;
- void free_flow_data(uint32_t proto);
- void free_flow_data(FlowData*);
+ void set_flow_data(FlowData* fd)
+ {
+ assert(fd);
+ flow_data.set(fd);
+ }
+ FlowData* get_flow_data(unsigned id) const
+ { return flow_data.get(id); }
+ void free_flow_data(unsigned id)
+ { flow_data.erase(id); }
+ void free_flow_data(FlowData* fd)
+ {
+ if ( fd )
+ flow_data.erase(fd->get_id());
+ }
void free_flow_data();
+ void call_handlers(Packet* p,
+ FlowDataStore::FlowDataHandlerType handler_type = FlowDataStore::HANDLER_RETRANSMIT) const
+ {
+ flow_data.call_handlers(p, handler_type);
+ }
- void call_handlers(Packet* p, bool eof = false);
void markup_packet_flags(Packet*);
void set_client_initiate(Packet*);
void set_direction(Packet*);
bool expired(const Packet*) const;
void set_ttl(Packet*, bool client);
void set_mpls_layer_per_dir(Packet*);
- Layer get_mpls_layer_per_dir(bool);
+ Layer* get_mpls_layer_per_dir(bool);
void swap_roles();
void set_service(Packet*, const char* new_service);
- bool get_attr(const std::string& key, int32_t& val) const;
- bool get_attr(const std::string& key, std::string& val) const;
- void set_attr(const std::string& key, const int32_t& val);
- void set_attr(const std::string& key, const std::string& val);
- // Use this API when the publisher of the attribute allocated memory for it and can give up its
- // ownership after the call.
- void set_attr(const std::string& key, std::string* val)
- {
- assert(stash);
- stash->store(key, val);
- }
template<typename T>
bool get_attr(const std::string& key, T& val) const
- {
- assert(stash);
- return stash->get(key, val);
- }
-
+ { return stash.get(key, val); }
template<typename T>
- void set_attr(const std::string& key, const T& val)
- {
- assert(stash);
- stash->store(key, val);
- }
+ void set_attr(const std::string& key, T& val)
+ { stash.store(key, val); }
+ void set_attr(const std::string& key, const std::string& val)
+ { stash.store(key, val); }
+ void set_attr(const std::string& key, StashGenericObject* val)
+ { stash.store(key, val); }
+ bool set_attr(const snort::SfIp& ip, const SnortConfig* sc = nullptr)
+ { return stash.store(ip, sc); }
+ const std::list<SfIp>* get_aux_ip_list() const
+ { return stash.get_aux_ip_list(); }
uint32_t update_session_flags(uint32_t ssn_flags)
{ return ssn_state.session_flags = ssn_flags; }
{ return (flow_state <= FlowState::INSPECT) and !is_inspection_disabled(); }
void set_state(FlowState fs)
- {
+ {
flow_state = fs;
if (fs > FlowState::INSPECT)
{
void set_clouseau(Inspector* ins)
{
+ if (clouseau)
+ clouseau->rem_ref();
clouseau = ins;
clouseau->add_ref();
}
void set_gadget(Inspector* ins)
{
+ if (gadget)
+ gadget->rem_ref();
gadget = ins;
gadget->add_ref();
}
void set_assistant_gadget(Inspector* ins)
{
+ if (assistant_gadget)
+ assistant_gadget->rem_ref();
assistant_gadget = ins;
assistant_gadget->add_ref();
}
void set_data(Inspector* pd)
{
+ if (data)
+ data->rem_ref();
data = pd;
data->add_ref();
}
bool handle_allowlist();
+protected:
+ static void delete_mpls_layer(Layer* mpls_layer)
+ {
+ if ( mpls_layer )
+ {
+ if ( mpls_layer->length )
+ delete[] mpls_layer->start;
+ delete mpls_layer;
+ }
+ }
+ DeferredTrust deferred_trust;
+ FlowStash stash;
+ FlowDataStore flow_data;
+
public: // FIXIT-M privatize if possible
// fields are organized by initialization and size to minimize
// void space
- std::unordered_map<uint32_t, std::unique_ptr<FlowData>> flow_data;
-
- DeferredTrust deferred_trust;
-
const FlowKey* key = nullptr;
BitOp* bitop = nullptr;
FlowHAState* ha_state = nullptr;
- FlowStash* stash = nullptr;
-
- uint8_t ip_proto = 0;
- PktType pkt_type = PktType::NONE; // ^^
// these fields are always set; not zeroed
Flow* prev = nullptr;
Continuation* ips_cont = nullptr;
long last_data_seen = 0;
- Layer mpls_client = {};
- Layer mpls_server = {};
+ Layer* mpls_client = nullptr;
+ Layer* mpls_server = nullptr;
IpsContextChain context_chain;
- FlowData* current_flow_data = nullptr;
FlowStats flowstats = {};
class StreamFlowIntf* stream_intf = nullptr;
uint64_t expire_time = 0;
+ std::bitset<64> data_log_filtering_state;
+
+ FilteringState filtering_state;
+
+ DAQ_Verdict last_verdict = MAX_DAQ_VERDICT;
+
unsigned network_policy_id = 0;
struct timeval prev_packet_time = {0, 0};
unsigned reload_id = 0;
uint32_t default_session_timeout = 0;
uint32_t idle_timeout = 0;
- int32_t client_intf = 0;
- int32_t server_intf = 0;
-
- int16_t client_group = 0;
- int16_t server_group = 0;
-
- uint16_t client_port = 0;
- uint16_t server_port = 0;
-
- uint16_t ssn_policy = 0;
- uint16_t session_state = 0;
-
- uint8_t inner_client_ttl = 0;
- uint8_t inner_server_ttl = 0;
- uint8_t outer_client_ttl = 0;
- uint8_t outer_server_ttl = 0;
-
- uint8_t response_count = 0;
- uint8_t dump_code = 0;
struct
{
bool allowed_on_excess : 1; // Set if the flow is allowed on excess
} flags = {};
- FlowState flow_state = FlowState::SETUP;
+ int32_t client_intf = 0;
+ int32_t server_intf = 0;
- FilteringState filtering_state;
+ int16_t client_group = 0;
+ int16_t server_group = 0;
- DAQ_Verdict last_verdict = MAX_DAQ_VERDICT;
+ uint16_t client_port = 0;
+ uint16_t server_port = 0;
- std::bitset<64> data_log_filtering_state;
+ uint16_t ssn_policy = 0;
+ uint16_t session_state = 0;
+
+ uint8_t ip_proto = 0;
+ PktType pkt_type = PktType::NONE; // ^^
+
+ uint8_t inner_client_ttl = 0;
+ uint8_t inner_server_ttl = 0;
+ uint8_t outer_client_ttl = 0;
+ uint8_t outer_server_ttl = 0;
+
+ uint8_t response_count = 0;
+ uint8_t dump_code = 0;
+
+ FlowState flow_state = FlowState::SETUP;
private:
void clean();
#include "flow_data.h"
+#include <algorithm>
#include <cassert>
#include "framework/inspector.h"
unsigned FlowData::flow_data_id = 0;
+FlowDataStore::~FlowDataStore()
+{ clear(); }
+
+void FlowDataStore::set(FlowData* fd)
+{
+ assert(fd);
+ unsigned id = fd->get_id();
+ if (flow_data.size() == flow_data.capacity())
+ flow_data.reserve(flow_data.size() + FLOW_DATA_INCREMENTS);
+ const auto lower = std::lower_bound(flow_data.begin(), flow_data.end(), id,
+ [](const FlowData* the_fd, unsigned id)
+ { return the_fd->get_id() < id; });
+ if (lower == flow_data.end())
+ flow_data.emplace_back(fd);
+ else
+ {
+ FlowData* lower_fd = *lower;
+ if (lower_fd->get_id() == id)
+ {
+ delete lower_fd;
+ *lower = fd;
+ }
+ else
+ flow_data.emplace(lower, fd);
+ }
+}
+
+void FlowDataStore::erase(unsigned id)
+{
+ const auto lower = std::lower_bound(flow_data.begin(), flow_data.end(), id,
+ [](const FlowData* the_fd, unsigned id)
+ { return the_fd->get_id() < id; });
+ if (lower != flow_data.end() && (*lower)->get_id() == id)
+ {
+ FlowData* lower_fd = *lower;
+ flow_data.erase(lower);
+ delete lower_fd;
+ }
+}
+
+void FlowDataStore::clear()
+{
+ // Cannot use unique_ptr because resize and pop_back leave the flow_data element in
+ // the vector. This can lead to crashes if the vector is used during the flow data destruction.
+ while (!flow_data.empty())
+ {
+ FlowData* fd = flow_data.back();
+ flow_data.pop_back();
+ delete fd;
+ }
+}
+
+FlowData* FlowDataStore::get(unsigned id) const
+{
+ const auto lower = std::lower_bound(flow_data.begin(), flow_data.end(), id,
+ [](const FlowData* the_fd, unsigned id)
+ { return the_fd->get_id() < id; });
+ if (lower == flow_data.end())
+ return nullptr;
+ FlowData* lower_fd = *lower;
+ return (lower_fd->get_id() == id) ? lower_fd : nullptr;
+}
+
+bool FlowDataStore::empty() const
+{ return flow_data.empty(); }
+
+void FlowDataStore::call_handlers(Packet* p, FlowDataHandlerType handler_type) const
+{
+ // handle_eof modifies flow_data, so we must make a temporary vector to be walked
+ std::vector<FlowData*> fd_ptrs;
+ fd_ptrs.reserve(flow_data.size());
+ for (FlowData* fd : flow_data)
+ {
+ assert(fd);
+ fd_ptrs.push_back(fd);
+ }
+
+ for (FlowData* fd : fd_ptrs)
+ {
+ switch (handler_type)
+ {
+ case HANDLER_RETRANSMIT:
+ fd->handle_retransmit(p);
+ break;
+ case HANDLER_EOF:
+ fd->handle_eof(p);
+ break;
+ default:
+ assert(!"Invalid handler type");
+ }
+ }
+}
+
FlowData::FlowData(unsigned u, Inspector* ph)
{
assert(u > 0);
id = u;
handler = ph;
- prev = next = nullptr;
if ( handler )
handler->add_ref();
}
handler->rem_ref();
}
+void FlowData::set_handler(Inspector* h)
+{
+ if (handler != h)
+ {
+ if (handler)
+ handler->rem_ref();
+ handler = h;
+ if (handler)
+ handler->add_ref();
+ }
+}
+
RuleFlowData::RuleFlowData(unsigned u) :
FlowData(u, SnortConfig::get_conf()->so_rules->proxy)
{ }
-
#ifndef FLOW_DATA_H
#define FLOW_DATA_H
+#include <vector>
+
// FlowData is how inspectors maintain flow state
// use Flow::set/get_flow_data() to attach to a flow
public:
virtual ~FlowData();
- unsigned get_id()
+ unsigned get_id() const
{ return id; }
static unsigned create_flow_data_id()
{ return ++flow_data_id; }
- Inspector* get_handler() { return handler; }
+ Inspector* get_handler() const
+ { return handler; }
+
+ void set_handler(Inspector*);
- virtual void handle_expected(Packet*) { }
- virtual void handle_retransmit(Packet*) { }
- virtual void handle_eof(Packet*) { }
+ virtual void handle_expected(Packet*)
+ { }
+ virtual void handle_retransmit(Packet*)
+ { }
+ virtual void handle_eof(Packet*)
+ { }
protected:
FlowData(unsigned u, Inspector* = nullptr);
-public: // FIXIT-L privatize
- FlowData* next;
- FlowData* prev;
-
private:
static unsigned flow_data_id;
Inspector* handler;
~RuleFlowData() override = default;
};
+class SO_PUBLIC FlowDataStore
+{
+public:
+ FlowDataStore() = default;
+ ~FlowDataStore();
+
+ void set(FlowData*);
+ FlowData* get(unsigned) const;
+
+ void erase(unsigned);
+ void erase(FlowData*);
+ void clear();
+
+ bool empty() const;
+
+ enum FlowDataHandlerType
+ {
+ HANDLER_RETRANSMIT,
+ HANDLER_EOF,
+ };
+
+ void call_handlers(Packet*, FlowDataHandlerType) const;
+
+ static constexpr unsigned FLOW_DATA_INCREMENTS = 7;
+
+private:
+ std::vector<FlowData*> flow_data;
+};
+
}
#endif
#include <cassert>
+#include "framework/data_bus.h"
#include "main/snort_config.h"
#include "pub_sub/auxiliary_ip_event.h"
-#include "pub_sub/stash_events.h"
using namespace snort;
using namespace std;
-FlowStash::~FlowStash()
-{
- reset();
-}
-
-void FlowStash::reset()
-{
- for(auto it = container.begin(); it != container.end(); ++it)
- {
- delete it->second;
- }
- container.clear();
-}
-
-bool FlowStash::get(const string& key, int32_t& val)
+bool FlowStash::get(const string& key, int32_t& val) const
{
return get(key, val, STASH_ITEM_TYPE_INT32);
}
-bool FlowStash::get(const string& key, uint32_t& val)
+bool FlowStash::get(const string& key, uint32_t& val) const
{
return get(key, val, STASH_ITEM_TYPE_UINT32);
}
-bool FlowStash::get(const string& key, string& val)
+bool FlowStash::get(const string& key, string& val) const
{
return get(key, val, STASH_ITEM_TYPE_STRING);
}
-bool FlowStash::get(const string& key, StashGenericObject* &val)
+bool FlowStash::get(const string& key, StashGenericObject* &val) const
{
return get(key, val, STASH_ITEM_TYPE_GENERIC_OBJECT);
}
-void FlowStash::store(const string& key, int32_t val, unsigned pubid, unsigned evid)
+void FlowStash::store(const string& key, int32_t val)
{
- store(key, val, STASH_ITEM_TYPE_INT32, pubid, evid);
+ internal_store(key, val);
}
-void FlowStash::store(const string& key, uint32_t val, unsigned pubid, unsigned evid)
+void FlowStash::store(const string& key, uint32_t val)
{
- store(key, val, STASH_ITEM_TYPE_UINT32, pubid, evid);
+ internal_store(key, val);
}
-void FlowStash::store(const string& key, const string& val, unsigned pubid, unsigned evid)
+void FlowStash::store(const string& key, const string& val)
{
- store(key, val, STASH_ITEM_TYPE_STRING, pubid, evid);
+ internal_store(key, val);
}
-void FlowStash::store(const string& key, string* val, unsigned pubid, unsigned evid)
+void FlowStash::store(const string& key, string* val)
{
- store(key, val, STASH_ITEM_TYPE_STRING, pubid, evid);
+ internal_store(key, val);
}
-void FlowStash::store(const string& key, StashGenericObject* val, unsigned pubid, unsigned evid)
+void FlowStash::store(const string& key, StashGenericObject* val)
{
- store(key, val, STASH_ITEM_TYPE_GENERIC_OBJECT, pubid, evid);
+ internal_store(key, val);
}
-void FlowStash::store(const string& key, StashGenericObject* &val, StashItemType type, unsigned pubid, unsigned evid)
+template<typename T>
+bool FlowStash::get(const string& key, T& val, StashItemType type) const
{
-#ifdef NDEBUG
- UNUSED(type);
-#endif
- auto item = new StashItem(val);
- auto it_and_status = container.emplace(key, item);
-
- if (!it_and_status.second)
- {
- StashGenericObject* stored_object;
- assert(it_and_status.first->second->get_type() == type);
- it_and_status.first->second->get_val(stored_object);
- assert(stored_object->get_object_type() == val->get_object_type());
- delete it_and_status.first->second;
- it_and_status.first->second = item;
- }
-
- if (DataBus::valid(pubid))
+ auto lower = lower_bound(container.begin(), container.end(), key,
+ [](const unique_ptr<StashItem>& item, const string& key)
+ { return 0 > item->get_key().compare(key); });
+ if (lower == container.end())
+ return false;
+ StashItem* item = lower->get();
+ if (item->get_key() == key)
{
- StashEvent e(item);
- DataBus::publish(pubid, evid, e);
+ if (item->get_type() == type)
+ {
+ item->get_val(val);
+ return true;
+ }
+ assert(item->get_type() == type);
}
+ return false;
}
template<typename T>
-bool FlowStash::get(const string& key, T& val, StashItemType type)
+void FlowStash::internal_store(const string& key, T& val)
{
-#ifdef NDEBUG
- UNUSED(type);
-#endif
- auto it = container.find(key);
-
- if (it != container.end())
+ if (container.size() == container.capacity())
+ container.reserve(container.size() + FLOW_STASH_INCREMENTS);
+ StashItem* new_item = new StashItem(key, val);
+ auto lower = lower_bound(container.begin(), container.end(), key,
+ [](const unique_ptr<StashItem>& item, const string& key)
+ { return 0 > item->get_key().compare(key); });
+ if (lower == container.end())
+ container.emplace_back(new_item);
+ else
{
- assert(it->second->get_type() == type);
- it->second->get_val(val);
- return true;
+ unique_ptr<StashItem>& lower_item = *lower;
+ if (lower_item->get_key() == key)
+ lower_item.reset(new_item);
+ else
+ container.emplace(lower, new_item);
}
- return false;
}
-template<typename T>
-void FlowStash::store(const string& key, T& val, StashItemType type, unsigned pubid, unsigned evid)
-{
-#ifdef NDEBUG
- UNUSED(type);
-#endif
- auto item = new StashItem(val);
- auto it_and_status = container.emplace(key, item);
+#define STASH_AUX_IP "aux_ip"
- if (!it_and_status.second)
+class AuxIPStashItem : public StashGenericObject
+{
+public:
+ AuxIPStashItem() = default;
+ ~AuxIPStashItem() override = default;
+ bool update(const SfIp& ip, const SnortConfig* sc)
{
- assert(it_and_status.first->second->get_type() == type);
- delete it_and_status.first->second;
- it_and_status.first->second = item;
+ if ( any_of(aux_ip_fifo.cbegin(), aux_ip_fifo.cend(),
+ [ip](const snort::SfIp& aip)
+ { return aip == ip; }) )
+ return false;
+
+ while ( aux_ip_fifo.size() >= (unsigned)sc->max_aux_ip )
+ aux_ip_fifo.pop_back();
+
+ aux_ip_fifo.emplace_front(ip);
+ return true;
}
- StashEvent e(item);
- DataBus::publish(pubid, evid, e);
-}
+ const list<snort::SfIp>& get_aux_ip_list() const
+ { return aux_ip_fifo; }
+
+protected:
+ list<snort::SfIp> aux_ip_fifo;
+};
bool FlowStash::store(const SfIp& ip, const SnortConfig* sc)
{
if ( sc->max_aux_ip > 0 )
{
- if ( std::any_of(aux_ip_fifo.cbegin(), aux_ip_fifo.cend(),
- [ip](const snort::SfIp& aip){ return aip == ip; }) )
+ AuxIPStashItem* item;
+ StashGenericObject* stash_value;
+ if (!get(STASH_AUX_IP, stash_value))
+ {
+ item = new AuxIPStashItem;
+ store(STASH_AUX_IP, item);
+ }
+ else
+ item = static_cast<AuxIPStashItem*>(stash_value);
+
+ if (!item->update(ip, sc))
return false;
-
- if ( aux_ip_fifo.size() == (unsigned)sc->max_aux_ip )
- aux_ip_fifo.pop_back();
-
- aux_ip_fifo.emplace_front(ip);
}
AuxiliaryIpEvent event(ip);
DataBus::publish(intrinsic_pub_id, IntrinsicEventIds::AUXILIARY_IP, event);
return true;
}
+
+const list<snort::SfIp>* FlowStash::get_aux_ip_list() const
+{
+ StashGenericObject* stash_value;
+ if (!get(STASH_AUX_IP, stash_value))
+ return nullptr;
+ AuxIPStashItem* item = static_cast<AuxIPStashItem*>(stash_value);
+ return &item->get_aux_ip_list();
+}
// a generic store for shared flow data
+#include <algorithm>
#include <list>
-#include <map>
+#include <memory>
#include <string>
-#include <unordered_map>
+#include <vector>
#include "main/snort_types.h"
#include "sfip/sf_ip.h"
-#include "stash_item.h"
-
namespace snort
{
+class StashItem;
+struct SnortConfig;
+
+class StashGenericObject
+{
+public:
+ StashGenericObject() = default;
+ virtual ~StashGenericObject() = default;
+};
+
+enum StashItemType
+{
+ STASH_ITEM_TYPE_INT32,
+ STASH_ITEM_TYPE_UINT32,
+ STASH_ITEM_TYPE_STRING,
+ STASH_ITEM_TYPE_GENERIC_OBJECT
+};
+
+union StashItemVal
+{
+ int32_t int32_val;
+ uint32_t uint32_val;
+ std::string* str_val;
+ StashGenericObject* generic_obj_val;
+};
+
+class StashItem
+{
+public:
+ StashItem(const std::string& the_key, int32_t int32_val) : key(the_key)
+ {
+ type = STASH_ITEM_TYPE_INT32;
+ val.int32_val = int32_val;
+ }
+
+ StashItem(const std::string& the_key, uint32_t uint32_val) : key(the_key)
+ {
+ type = STASH_ITEM_TYPE_UINT32;
+ val.uint32_val = uint32_val;
+ }
+
+ StashItem(const std::string& the_key, const std::string& str_val) : key(the_key)
+ {
+ type = STASH_ITEM_TYPE_STRING;
+ val.str_val = new std::string(str_val);
+ }
+
+ StashItem(const std::string& the_key, std::string* str_val) : key(the_key)
+ {
+ type = STASH_ITEM_TYPE_STRING;
+ val.str_val = str_val;
+ }
+
+ StashItem(const std::string& the_key, StashGenericObject* obj) : key(the_key)
+ {
+ type = STASH_ITEM_TYPE_GENERIC_OBJECT;
+ val.generic_obj_val = obj;
+ }
+
+ ~StashItem()
+ {
+ switch (type)
+ {
+ case STASH_ITEM_TYPE_STRING:
+ delete val.str_val;
+ break;
+ case STASH_ITEM_TYPE_GENERIC_OBJECT:
+ delete val.generic_obj_val;
+ default:
+ break;
+ }
+ }
+
+ const std::string& get_key() const
+ { return key; }
+
+ StashItemType get_type() const
+ { return type; }
+
+ void get_val(int32_t& int32_val) const
+ { int32_val = val.int32_val; }
+
+ void get_val(uint32_t& uint32_val) const
+ { uint32_val = val.uint32_val; }
+
+ void get_val(std::string& str_val) const
+ { str_val = *(val.str_val); }
+
+ void get_val(StashGenericObject* &obj_val) const
+ { obj_val = val.generic_obj_val; }
+
+private:
+ std::string key;
+ StashItemType type;
+ StashItemVal val;
+};
class SO_PUBLIC FlowStash
{
public:
- ~FlowStash();
- void reset();
+ FlowStash() = default;
+ ~FlowStash()
+ { reset(); }
- bool get(const std::string& key, int32_t& val);
- bool get(const std::string& key, uint32_t& val);
- bool get(const std::string& key, std::string& val);
- bool get(const std::string& key, StashGenericObject* &val);
+ void reset()
+ { container.clear(); }
- void store(const std::string& key, int32_t val, unsigned pubid = 0, unsigned evid = 0);
- void store(const std::string& key, uint32_t val, unsigned pubid = 0, unsigned evid = 0);
- void store(const std::string& key, const std::string& val, unsigned pubid = 0, unsigned evid = 0);
- void store(const std::string& key, std::string* val, unsigned pubid = 0, unsigned evid = 0);
- void store(const std::string& key, StashGenericObject* val, unsigned pubid = 0, unsigned evid = 0);
+ bool get(const std::string& key, int32_t& val) const;
+ bool get(const std::string& key, uint32_t& val) const;
+ bool get(const std::string& key, std::string& val) const;
+ bool get(const std::string& key, StashGenericObject* &val) const;
- bool store(const snort::SfIp&, const struct SnortConfig* = nullptr);
+ void store(const std::string& key, int32_t val);
+ void store(const std::string& key, uint32_t val);
+ void store(const std::string& key, const std::string& val);
+ void store(const std::string& key, std::string* val);
+ void store(const std::string& key, StashGenericObject* val);
- std::list<snort::SfIp>& get_aux_ip_list()
- { return aux_ip_fifo; }
+ bool store(const snort::SfIp&, const SnortConfig*);
+
+ const std::list<snort::SfIp>* get_aux_ip_list() const;
private:
- std::list<snort::SfIp> aux_ip_fifo;
- std::unordered_map<std::string, StashItem*> container;
+ static constexpr unsigned FLOW_STASH_INCREMENTS = 7;
+
+ std::vector<std::unique_ptr<StashItem>> container;
template<typename T>
- bool get(const std::string& key, T& val, StashItemType type);
+ bool get(const std::string& key, T& val, StashItemType type) const;
template<typename T>
- void store(const std::string& key, T& val, StashItemType type, unsigned = 0, unsigned = 0);
- void store(const std::string& key, StashGenericObject* &val, StashItemType type, unsigned, unsigned);
+ void internal_store(const std::string& key, T& val);
};
}
+++ /dev/null
-//--------------------------------------------------------------------------
-// Copyright (C) 2019-2025 Cisco and/or its affiliates. All rights reserved.
-//
-// 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.
-//--------------------------------------------------------------------------
-
-// stash_item.h author Shravan Rangaraju <shrarang@cisco.com>
-
-#ifndef STASH_ITEM_H
-#define STASH_ITEM_H
-
-// stored in the FlowStash
-
-#include <cstdint>
-#include <string>
-
-#define STASH_APPID_DATA "appid_data"
-
-#define STASH_GENERIC_OBJECT_APPID 1
-#define STASH_GENERIC_OBJECT_MIME 2
-
-namespace snort
-{
-
-class StashGenericObject
-{
-public:
- StashGenericObject(int type) : object_type(type)
- { }
-
- virtual ~StashGenericObject() = default;
-
- int get_object_type() const
- { return object_type; }
-
-private:
- int object_type;
-};
-
-enum StashItemType
-{
- STASH_ITEM_TYPE_INT32,
- STASH_ITEM_TYPE_UINT32,
- STASH_ITEM_TYPE_STRING,
- STASH_ITEM_TYPE_GENERIC_OBJECT
-};
-
-union StashItemVal
-{
- int32_t int32_val;
- uint32_t uint32_val;
- std::string* str_val;
- StashGenericObject* generic_obj_val;
-};
-
-class StashItem
-{
-public:
- StashItem(int32_t int32_val)
- {
- type = STASH_ITEM_TYPE_INT32;
- val.int32_val = int32_val;
- }
-
- StashItem(uint32_t uint32_val)
- {
- type = STASH_ITEM_TYPE_UINT32;
- val.uint32_val = uint32_val;
- }
-
- StashItem(const std::string& str_val)
- {
- type = STASH_ITEM_TYPE_STRING;
- val.str_val = new std::string(str_val);
- }
-
- StashItem(std::string* str_val)
- {
- type = STASH_ITEM_TYPE_STRING;
- val.str_val = str_val;
- }
-
- StashItem(StashGenericObject* obj)
- {
- type = STASH_ITEM_TYPE_GENERIC_OBJECT;
- val.generic_obj_val = obj;
- }
-
- ~StashItem()
- {
- switch (type)
- {
- case STASH_ITEM_TYPE_STRING:
- delete val.str_val;
- break;
- case STASH_ITEM_TYPE_GENERIC_OBJECT:
- delete val.generic_obj_val;
- default:
- break;
- }
- }
-
- StashItemType get_type() const
- { return type; }
-
- void get_val(int32_t& int32_val) const
- { int32_val = val.int32_val; }
-
- void get_val(uint32_t& uint32_val) const
- { uint32_val = val.uint32_val; }
-
- void get_val(std::string& str_val) const
- { str_val = *(val.str_val); }
-
- void get_val(StashGenericObject* &obj_val) const
- { obj_val = val.generic_obj_val; }
-
-private:
- StashItemType type;
- StashItemVal val;
-};
-
-}
-
-#endif
void Flow::set_client_initiate(Packet*) { }
void Flow::set_direction(Packet*) { }
void Flow::set_mpls_layer_per_dir(Packet*) { }
+FlowDataStore::~FlowDataStore() = default;
void packet_gettimeofday(struct timeval* ) { }
SO_PUBLIC void ts_print(const struct timeval*, char*, bool) { }
FlowKey flow_key;
flow_key.port_l = port++;
flow_key.pkt_type = PktType::UDP;
-
+
Flow* flow = cache->allocate(&flow_key);
CHECK(cache->move_to_allowlist(flow) == true); // Move flow to allow list
FlowKey flow_key;
flow_key.port_l = port++;
flow_key.pkt_type = PktType::TCP;
-
+
Flow* flow = cache->allocate(&flow_key);
CHECK(cache->move_to_allowlist(flow) == true);
}
// Ensure pruning doesn't occur because all flows are allow listed
for (uint8_t i = 0; i < total_lru_count; ++i)
CHECK(cache->prune_one(PruneReason::IDLE_PROTOCOL_TIMEOUT, true, i) == false);
-
+
CHECK_EQUAL(2, cache->get_count());
CHECK_EQUAL(2, cache->get_lru_flow_count(allowlist_lru_index));
FlowKey flow_key;
flow_key.port_l = port++;
flow_key.pkt_type = PktType::TCP;
-
+
Flow* flow = cache->allocate(&flow_key);
CHECK(cache->move_to_allowlist(flow) == true);
}
fcg.max_flows = 10;
fcg.prune_flows = 10;
- for (uint8_t i = to_utype(PktType::NONE); i <= to_utype(PktType::MAX); ++i)
+ for (uint8_t i = to_utype(PktType::NONE); i <= to_utype(PktType::MAX); ++i)
fcg.proto[i].nominal_timeout = 5;
-
+
FlowCache* cache = new FlowCache(fcg);
int port = 1;
- for (unsigned i = 0; i < 2; ++i)
+ for (unsigned i = 0; i < 2; ++i)
{
FlowKey flow_key;
flow_key.port_l = port++;
flow_key.pkt_type = PktType::UDP;
-
+
Flow* flow = cache->allocate(&flow_key);
CHECK(cache->move_to_allowlist(flow) == true); // Move flow to allow list
CHECK_EQUAL(2, cache->get_count());
// Ensure pruning doesn't occur because all flows are allow listed
- for (uint8_t i = 0; i < to_utype(PktType::MAX) - 1; ++i)
+ for (uint8_t i = 0; i < to_utype(PktType::MAX) - 1; ++i)
CHECK(cache->prune_one(PruneReason::NONE, true, i) == false);
-
+
CHECK_EQUAL(2, cache->get_count()); // Ensure no flows were pruned
// Add a new ICMP flow
// we can't prune to 0 so 1 flow will be pruned
CHECK_EQUAL(1, cache->prune_multiple(PruneReason::MEMCAP, true));
- CHECK_EQUAL(1, cache->get_count());
+ CHECK_EQUAL(1, cache->get_count());
CHECK_EQUAL(1, cache->get_lru_flow_count(allowlist_lru_index));
// Adding five UDP flows, these will become the LRU flows
- for (unsigned i = 0; i < 5; ++i)
+ for (unsigned i = 0; i < 5; ++i)
{
FlowKey flow_key;
flow_key.port_l = port++;
flow_key.pkt_type = PktType::UDP;
-
+
Flow* flow = cache->allocate(&flow_key);
flow->last_data_seen = 2 + i;
}
CHECK_EQUAL(6, cache->get_count());
// Adding three TCP flows, move two to allow list, making them MRU
- for (unsigned i = 0; i < 3; ++i)
+ for (unsigned i = 0; i < 3; ++i)
{
FlowKey flow_key;
flow_key.port_l = port++;
flow_key.pkt_type = PktType::TCP;
-
+
Flow* flow = cache->allocate(&flow_key);
flow->last_data_seen = 4 + i; // Set TCP flows to have later timeout
- if (i > 0)
+ if (i > 0)
{
CHECK(cache->move_to_allowlist(flow) == true);
FlowKey flow_key;
flow_key.port_l = port++;
flow_key.pkt_type = PktType::TCP;
-
+
Flow* flow = cache->allocate(&flow_key);
CHECK(cache->move_to_allowlist(flow) == true);
}
DummyCache* cache = new DummyCache(fcg);
CHECK(cache->dump_flows(dump_stream, 100, ffc, true, 1) == true);
- delete cache;
+ delete cache;
}
TEST_GROUP(dump_flows_summary) { };
std::vector<PktType> types = {PktType::IP, PktType::ICMP, PktType::TCP, PktType::UDP};
- for (const auto& type : types)
+ for (const auto& type : types)
{
for (unsigned i = 0; i < 5; i++)
{
CHECK(cache->dump_flows_summary(flows_summary, ffc) == true);
FlowsTypeSummary expected_type{};
- for (const auto& type : types)
+ for (const auto& type : types)
expected_type[to_utype(type)] = 5;
CHECK(expected_type == flows_summary.type_summary);
std::vector<snort::Flow::FlowState> types = {snort::Flow::FlowState::BLOCK, snort::Flow::FlowState::ALLOW, snort::Flow::FlowState::SETUP};
- for (const auto& type : types)
+ for (const auto& type : types)
{
for (unsigned i = 0; i < 5; i++)
{
CHECK(expected_type == flows_summary.type_summary);
FlowsStateSummary expected_state{};
- for (const auto& type : types)
+ for (const auto& type : types)
{
expected_state[to_utype(type)] = flows_number;
}
std::vector<PktType> types = {PktType::IP, PktType::ICMP, PktType::TCP, PktType::UDP};
- for (const auto& type : types)
+ for (const auto& type : types)
{
int port = 1;
for (unsigned i = 0; i < 5; i++)
CHECK(cache->dump_flows_summary(flows_summary, ffc) == true);
expected_type = {};
- for (const auto& type : types)
+ for (const auto& type : types)
expected_type[to_utype(type)] = 1;
CHECK(expected_type == flows_summary.type_summary);
-TEST_GROUP(flow_cache_lrus)
-{
+TEST_GROUP(flow_cache_lrus)
+{
FlowCacheConfig fcg;
DummyCache* cache;
CHECK(flow != nullptr);
}
- CHECK_EQUAL(10, cache->get_count()); // Verify 10 flows in
+ CHECK_EQUAL(10, cache->get_count()); // Verify 10 flows in
CHECK_EQUAL(4, cache->count_flows_in_lru(to_utype(PktType::TCP))); // 4 TCP flows
CHECK_EQUAL(1, cache->count_flows_in_lru(to_utype(PktType::UDP))); // 1 UDP flow
CHECK_EQUAL(1, cache->count_flows_in_lru(to_utype(PktType::USER))); // 1 USER flow
FlowCache::FlowCache(const FlowCacheConfig& cfg) : config(cfg) { }
FlowCache::~FlowCache() = default;
Flow::~Flow() = default;
+FlowDataStore::~FlowDataStore() = default;
DetectionEngine::DetectionEngine() { context = nullptr; }
DetectionEngine::~DetectionEngine() = default;
unsigned FlowCache::purge() { return 1; }
#include "flow/flow_stash.h"
#include "main/snort_config.h"
-#include "pub_sub/stash_events.h"
#include "utils/util.h"
#include <CppUTest/CommandLineTestRunner.h>
using namespace snort;
using namespace std;
-template<class Type>
-class DBConsumer : public DataHandler
-{
-public:
-
- static const char* STASH_EVENT;
-
- DBConsumer(const char* mod_name) : DataHandler(mod_name) {}
-
- void handle(DataEvent& e, Flow*) override
- {
- const StashEvent* se = static_cast<const StashEvent*>(&e);
- se->get_item()->get_val(value);
- }
-
- Type get_from_stash(FlowStash& stash)
- {
- stash.get(STASH_EVENT, value);
- return value;
- }
-
- Type get_value() const { return value; }
-
-private:
- Type value;
-};
-
-template<class Type>
-const char* DBConsumer<Type>::STASH_EVENT = "foo.stash.event";
-
static DataHandler* s_handler = nullptr;
void DataBus::subscribe(const PubKey&, unsigned, snort::DataHandler* h)
TEST_GROUP(stash_tests)
{ };
-// DataBus tests
-TEST(stash_tests, data_bus_publish_test)
-{
- typedef int32_t value_t;
-
- DBConsumer<value_t> c("foo");
- PubKey pub_key { };
-
- DataBus::subscribe(pub_key, 0, &c);
-
- FlowStash stash;
- value_t vin, vout;
-
- // stash/publish 10
- vin = 10;
- stash.store(DBConsumer<value_t>::STASH_EVENT, vin, 1, 1);
- vout = c.get_value();
- CHECK_EQUAL(vin, vout);
-
- // stash/publish 20, with the same key as before
- vin = 20;
- stash.store(DBConsumer<value_t>::STASH_EVENT, vin, 1, 1);
- vout = c.get_value();
- CHECK_EQUAL(vin, vout);
-
- // do we get some event that we're not listening to?
- value_t before = c.get_value();
- stash.store("bar.stash.event", 30);
- value_t after = c.get_value();
- CHECK_EQUAL(before, after);
-
- // do we still get our own STASH_EVENT from the stash, at a later time?
- vout = c.get_from_stash(stash);
- CHECK_EQUAL(vin, vout);
-}
-
// Stash tests
TEST(stash_tests, new_int32_item)
{
TEST(stash_tests, new_generic_object)
{
FlowStash stash;
- StashGenericObject *test_object = new StashGenericObject(111);
+ StashGenericObject *test_object = new StashGenericObject;
stash.store("item_1", test_object);
StashGenericObject *retrieved_object;
CHECK(stash.get("item_1", retrieved_object));
POINTERS_EQUAL(test_object, retrieved_object);
- CHECK_EQUAL(test_object->get_object_type(), ((StashGenericObject*)retrieved_object)->get_object_type());
}
TEST(stash_tests, update_generic_object)
{
FlowStash stash;
- StashGenericObject *test_object = new StashGenericObject(111);
+ StashGenericObject *test_object = new StashGenericObject;
stash.store("item_1", test_object);
- StashGenericObject *new_test_object = new StashGenericObject(111);
+ StashGenericObject *new_test_object = new StashGenericObject;
stash.store("item_1", new_test_object);
StashGenericObject *retrieved_object;
TEST(stash_tests, mixed_items)
{
FlowStash stash;
- StashGenericObject *test_object = new StashGenericObject(111);
+ StashGenericObject *test_object = new StashGenericObject;
stash.store("item_1", 10);
stash.store("item_2", "value_2");
StashGenericObject *retrieved_object;
CHECK(stash.get("item_4", retrieved_object));
POINTERS_EQUAL(test_object, retrieved_object);
- CHECK_EQUAL(test_object->get_object_type(), ((StashGenericObject*)retrieved_object)->get_object_type());
}
TEST(stash_tests, store_ip)
// Disabled
snort_conf.max_aux_ip = -1;
- CHECK_FALSE(stash.store(ip));
+ CHECK_FALSE(stash.store(ip, nullptr));
// Enabled without stashing, no duplicate IP checking
snort_conf.max_aux_ip = 0;
- CHECK_TRUE(stash.store(ip));
- CHECK_TRUE(stash.store(ip));
+ CHECK_TRUE(stash.store(ip, nullptr));
+ CHECK_TRUE(stash.store(ip, nullptr));
// Enabled with FIFO stashing, duplicate IP checking
snort_conf.max_aux_ip = 2;
- CHECK_TRUE(stash.store(ip));
- CHECK_FALSE(stash.store(ip));
+ CHECK_TRUE(stash.store(ip, nullptr));
+ CHECK_FALSE(stash.store(ip, nullptr));
SfIp ip2;
CHECK(ip2.set("1.1.1.2") == SFIP_SUCCESS);
- CHECK_TRUE(stash.store(ip2));
- CHECK_FALSE(stash.store(ip2));
+ CHECK_TRUE(stash.store(ip2, nullptr));
+ CHECK_FALSE(stash.store(ip2, nullptr));
SfIp ip3;
CHECK(ip3.set("1111::8888") == SFIP_SUCCESS);
- CHECK_TRUE(stash.store(ip3));
- CHECK_FALSE(stash.store(ip3));
- CHECK_FALSE(stash.store(ip2));
- CHECK_TRUE(stash.store(ip));
- CHECK_FALSE(stash.store(ip));
- CHECK_FALSE(stash.store(ip3));
+ CHECK_TRUE(stash.store(ip3, nullptr));
+ CHECK_FALSE(stash.store(ip3, nullptr));
+ CHECK_FALSE(stash.store(ip2, nullptr));
+ CHECK_TRUE(stash.store(ip, nullptr));
+ CHECK_FALSE(stash.store(ip, nullptr));
+ CHECK_FALSE(stash.store(ip3, nullptr));
}
int main(int argc, char** argv)
void FlowHAState::reset() {}
-FlowStash::~FlowStash() = default;
-
-void FlowStash::reset() {}
-
void DetectionEngine::onload(Flow*) {}
Packet* DetectionEngine::set_next_packet(const Packet*, Flow*) { return nullptr; }
delete flow;
}
+class TestFlowData : public FlowData
+{
+public:
+ explicit TestFlowData(unsigned v) : FlowData(module_id), version(v)
+ { }
+ ~TestFlowData() override = default;
+
+ unsigned get_version() const
+ { return version; }
+
+ static unsigned module_id;
+
+ static void init()
+ { module_id = FlowData::create_flow_data_id(); }
+
+protected:
+ unsigned version;
+};
+
+unsigned TestFlowData::module_id = 0;
+
+class HigherIdFlowData : public FlowData
+{
+public:
+ HigherIdFlowData() : FlowData(module_id)
+ { }
+ ~HigherIdFlowData() override = default;
+
+ static unsigned module_id;
+
+ static void init()
+ { module_id = FlowData::create_flow_data_id(); }
+};
+
+unsigned HigherIdFlowData::module_id = 0;
+
+TEST_GROUP(flow_data_test)
+{
+};
+
+TEST(flow_data_test, flow_data_access)
+{
+ unsigned lower_module_id = FlowData::create_flow_data_id();
+ TestFlowData::init();
+ HigherIdFlowData::init();
+ unsigned higher_module_id = FlowData::create_flow_data_id();
+
+ Flow *flow = new Flow;
+
+ TestFlowData* existing_fd = static_cast<TestFlowData*>(flow->get_flow_data(TestFlowData::module_id));
+ CHECK_TEXT(!existing_fd, "FlowData should not exist");
+
+ // new
+ TestFlowData* fd = new TestFlowData(1);
+ flow->set_flow_data(fd);
+ existing_fd = static_cast<TestFlowData*>(flow->get_flow_data(TestFlowData::module_id));
+ CHECK_TEXT(existing_fd, "FlowData should exist");
+ UNSIGNED_LONGS_EQUAL_TEXT(1, existing_fd->get_version(), "FlowData version should be 1");
+
+ // overwrite
+ fd = new TestFlowData(2);
+ flow->set_flow_data(fd);
+ existing_fd = static_cast<TestFlowData*>(flow->get_flow_data(TestFlowData::module_id));
+ CHECK_TEXT(existing_fd, "FlowData should exist");
+ UNSIGNED_LONGS_EQUAL_TEXT(2, existing_fd->get_version(), "FlowData version should be 2");
+
+ // free by object
+ flow->free_flow_data(fd);
+ existing_fd = static_cast<TestFlowData*>(flow->get_flow_data(TestFlowData::module_id));
+ CHECK_TEXT(!existing_fd, "FlowData should not exist");
+
+ HigherIdFlowData* hid_fd = new HigherIdFlowData;
+ flow->set_flow_data(hid_fd);
+ HigherIdFlowData* hid_existing_fd =
+ static_cast<HigherIdFlowData*>(flow->get_flow_data(HigherIdFlowData::module_id));
+ CHECK_TEXT(hid_existing_fd, "HigherIdFlowData should exist");
+
+ fd = new TestFlowData(3);
+ flow->set_flow_data(fd);
+ existing_fd = static_cast<TestFlowData*>(flow->get_flow_data(TestFlowData::module_id));
+ CHECK_TEXT(existing_fd, "FlowData should exist");
+ UNSIGNED_LONGS_EQUAL_TEXT(3, existing_fd->get_version(), "FlowData version should be 3");
+
+ // free by id not found lower
+ flow->free_flow_data(lower_module_id);
+ existing_fd = static_cast<TestFlowData*>(flow->get_flow_data(TestFlowData::module_id));
+ CHECK_TEXT(existing_fd, "FlowData should exist");
+ UNSIGNED_LONGS_EQUAL_TEXT(3, existing_fd->get_version(), "FlowData version should be 3");
+ hid_existing_fd = static_cast<HigherIdFlowData*>(flow->get_flow_data(HigherIdFlowData::module_id));
+ CHECK_TEXT(hid_existing_fd, "HigherIdFlowData should exist");
+
+ // free by id not found higher
+ flow->free_flow_data(higher_module_id);
+ existing_fd = static_cast<TestFlowData*>(flow->get_flow_data(TestFlowData::module_id));
+ CHECK_TEXT(existing_fd, "FlowData should exist");
+ UNSIGNED_LONGS_EQUAL_TEXT(3, existing_fd->get_version(), "FlowData version should be 3");
+ hid_existing_fd = static_cast<HigherIdFlowData*>(flow->get_flow_data(HigherIdFlowData::module_id));
+ CHECK_TEXT(hid_existing_fd, "HigherIdFlowData should exist");
+
+ // free by id
+ flow->free_flow_data(TestFlowData::module_id);
+ existing_fd = static_cast<TestFlowData*>(flow->get_flow_data(TestFlowData::module_id));
+ CHECK_TEXT(!existing_fd, "FlowData should not exist");
+ hid_existing_fd = static_cast<HigherIdFlowData*>(flow->get_flow_data(HigherIdFlowData::module_id));
+ CHECK_TEXT(hid_existing_fd, "HigherIdFlowData should exist");
+ flow->free_flow_data(hid_existing_fd);
+ hid_existing_fd = static_cast<HigherIdFlowData*>(flow->get_flow_data(HigherIdFlowData::module_id));
+ CHECK_TEXT(!hid_existing_fd, "HigherIdFlowData should not exist");
+
+ delete flow;
+}
+
int main(int argc, char** argv)
{
int return_value = CommandLineTestRunner::RunAllTests(argc, argv);
Flow::~Flow() = default;
void Flow::set_client_initiate(Packet*) { }
void Flow::set_direction(Packet*) { }
+FlowDataStore::~FlowDataStore() = default;
void packet_gettimeofday(struct timeval* tv)
{
int SFDAQInstance::ioctl(DAQ_IoctlCmd, void*, size_t) { return DAQ_SUCCESS; }
-FlowStash::~FlowStash() = default;
-
-
SideChannel::SideChannel(ScMsgFormat)
{ }
// depends on includes installed in framework/snort_api.h
// see framework/plugins.h
-#define BASE_API_VERSION 21
+#define BASE_API_VERSION 22
// set the reserved field to this to be future proof
#define API_RESERVED 0
InspectionPolicy* get_inspection_policy() { return nullptr; }
Flow::~Flow() = default;
bool Flow::handle_allowlist() { return true; }
+FlowDataStore::~FlowDataStore() = default;
void ThreadConfig::implement_thread_affinity(SThreadType, unsigned) { }
void ThreadConfig::apply_thread_policy(SThreadType , unsigned ) { }
void ThreadConfig::set_instance_tid(int) { }
(*ofn)->outputs.emplace_back(eh);
}
-void EventManager::copy_outputs(OutputSet* dst, OutputSet* src)
+void EventManager::copy_outputs(OutputSet* dst, const OutputSet* src)
{
- dst->outputs = src->outputs;
+ if (dst && src && src->outputs.size())
+ dst->outputs = src->outputs;
}
//-------------------------------------------------------------------------
static unsigned get_output_type_flags(char*);
static void add_output(OutputSet**, snort::Logger*);
- static void copy_outputs(OutputSet* dst, OutputSet* src);
+ static void copy_outputs(OutputSet* dst, const OutputSet* src);
static void release_outputs(OutputSet*);
static void open_outputs();
return log_flags & MIME_FLAG_RCPT_TO_PRESENT;
}
-MailLogState::MailLogState(MailLogConfig* conf) : StashGenericObject(STASH_GENERIC_OBJECT_MIME)
+MailLogState::MailLogState(MailLogConfig* conf)
{
if (conf && (conf->log_email_hdrs || conf->log_filename
|| conf->log_mailfrom || conf->log_rcptto))
uri(uri),
uri_length(uri_length)
{
- p->flow->stash->store(STASH_EXTRADATA_MIME, log_state);
+ p->flow->set_attr(STASH_EXTRADATA_MIME, log_state);
reset_mime_paf_state(&mime_boundary);
}
char src_ip[INET6_ADDRSTRLEN];
char dst_ip[INET6_ADDRSTRLEN];
- AppIdInspector* inspector = (AppIdInspector*)ctrlPkt->flow->current_flow_data->get_handler();
- if ((inspector == nullptr) or strcmp(inspector->get_name(), MOD_NAME))
- inspector = (AppIdInspector*)InspectorManager::get_inspector(MOD_NAME, true);
+ AppIdInspector* inspector =
+ static_cast<AppIdInspector*>(
+ InspectorManager::get_inspector(MOD_NAME, MOD_USAGE, appid_inspector_api.type));
+ assert(inspector);
// FIXIT-RC - port parameter passed in as 0 since we may not know client port, verify
{
if (!api.flags.stored_in_stash)
{
- assert(p.flow and p.flow->stash);
- p.flow->stash->store(STASH_APPID_DATA, &api, false);
+ assert(p.flow);
+ p.flow->set_attr(STASH_APPID_DATA, &api);
api.flags.stored_in_stash = true;
}
#include <unordered_map>
#include <daq_common.h>
+#include "flow/flow_data.h"
#include "pub_sub/appid_events.h"
#include "app_info_table.h"
#include "pub_sub/shadowtraffic_aggregator.h"
#include "service_state.h"
+#define STASH_APPID_DATA "appid_data"
+
namespace snort
{
class AppIdSessionApi;
static unsigned inspector_id;
static std::mutex inferred_svcs_lock;
- static void init() { inspector_id = FlowData::create_flow_data_id(); }
+ static void init() { inspector_id = snort::FlowData::create_flow_data_id(); }
void set_session_flags(uint64_t set_flags) { flags |= set_flags; }
void clear_session_flags(uint64_t clear_flags) { flags &= ~clear_flags; }
void set_shadow_traffic_publishing_appid(AppId id)
{
- shadow_traffic_appid = id;
+ shadow_traffic_appid = id;
}
AppId get_shadow_traffic_publishing_appid() const
{
return shadow_traffic_appid;
}
-
- inline void change_shadow_traffic_bits_to_string (const uint32_t& st_bits,std::string& str) const
- {
+
+ inline void change_shadow_traffic_bits_to_string (const uint32_t& st_bits,std::string& str) const
+ {
std::string tempStr;
if (st_bits & ShadowTraffic_Type_Encrypted_DNS) {
if (!tempStr.empty()) {
tempStr.pop_back();
}
-
- str.append(tempStr);
- }
-
+
+ str.append(tempStr);
+ }
+
void set_cert_key (const std::string& key)
{
ssl_cert_key = key;
static THREAD_LOCAL uint32_t appid_flow_data_id = 0;
AppIdSessionApi::AppIdSessionApi(const AppIdSession* asd, const SfIp& ip) :
- StashGenericObject(STASH_GENERIC_OBJECT_APPID), asd(asd), initiator_ip(ip),
+ asd(asd), initiator_ip(ip),
session_id(std::to_string(get_instance_id()) + "." + std::to_string(++appid_flow_data_id))
{ }
#define APPID_SESSION_API_H
#include "flow/flow.h"
-#include "flow/stash_item.h"
#include "main/snort_types.h"
#include "pub_sub/appid_events.h"
#include "sfip/sf_ip.h"
// LCOV_EXCL_STOP
// Stubs for appid sessions
-FlowData::FlowData(unsigned, Inspector*) : next(nullptr), prev(nullptr), handler(nullptr), id(0)
+FlowData::FlowData(unsigned, Inspector*) : handler(nullptr), id(0)
{ }
FlowData::~FlowData() = default;
+FlowDataStore::~FlowDataStore() = default;
// Stubs for packet
Packet::Packet(bool) { }
namespace snort
{
AppIdApi appid_api;
-AppIdSessionApi::AppIdSessionApi(const AppIdSession*, const SfIp&) :
- StashGenericObject(STASH_GENERIC_OBJECT_APPID) { }
+AppIdSessionApi::AppIdSessionApi(const AppIdSession*, const SfIp&)
+{ }
Flow::~Flow() = default;
AppIdSession* AppIdApi::get_appid_session(snort::Flow const&) { return nullptr; }
namespace snort
{
-AppIdSessionApi::AppIdSessionApi(const AppIdSession*, const SfIp&) :
- StashGenericObject(STASH_GENERIC_OBJECT_APPID) {}
+AppIdSessionApi::AppIdSessionApi(const AppIdSession*, const SfIp&)
+{ }
SearchTool::SearchTool(bool, const char*) { }
void SearchTool::reload() { }
static bool test_find_all_done = false;
void ParseWarning(WarningGroup, const char*, ...) { }
// Stubs for appid sessions
-FlowData::FlowData(unsigned, Inspector*) : next(nullptr), prev(nullptr), handler(nullptr), id(0)
+FlowData::FlowData(unsigned, Inspector*) : handler(nullptr), id(0)
{ }
FlowData::~FlowData() = default;
void Module::main_accumulate_stats(){}
void Module::reset_stats() {}
-AppIdSessionApi::AppIdSessionApi(const AppIdSession*, const SfIp&) :
- StashGenericObject(STASH_GENERIC_OBJECT_APPID) {}
+AppIdSessionApi::AppIdSessionApi(const AppIdSession*, const SfIp&)
+{ }
}
AlpnPatternMatchers::~AlpnPatternMatchers() {}
return &p;
}
-AppIdSessionApi::AppIdSessionApi(const AppIdSession*, const SfIp&) :
- StashGenericObject(STASH_GENERIC_OBJECT_APPID) {}
+AppIdSessionApi::AppIdSessionApi(const AppIdSession*, const SfIp&)
+{ }
}
void appid_log(const snort::Packet*, unsigned char, char const*, ...) { }
appid_api.set_ssl_certificate_key(*flow, cert_key);
asd.set_cert_key(cert_key);
CHECK_EQUAL(asd.get_cert_key(), cert_key);
- delete &asd.get_api();
+ delete &asd.get_api();
}
TEST(appid_api, ssl_app_group_id_lookup)
// When appid session is not existing
// 1. Match based on server name
Flow* f = new Flow;
- flow->set_flow_data(nullptr);
+ // This call just sets mock_flow_data pointer to nullptr, so mocks work correctly for the test.
+ flow->free_flow_data(1);
service = APP_ID_NONE;
client = APP_ID_NONE;
payload = APP_ID_NONE;
Packet::~Packet() = default;
FlowData::FlowData(unsigned, Inspector*) { }
FlowData::~FlowData() = default;
-AppIdSessionApi::AppIdSessionApi(const AppIdSession* asd, const SfIp& ip) :
- StashGenericObject(STASH_GENERIC_OBJECT_APPID), asd(asd), initiator_ip(ip) {}
+AppIdSessionApi::AppIdSessionApi(const AppIdSession* asd, const SfIp& ip) : asd(asd), initiator_ip(ip) { }
[[noreturn]] void FatalError(const char*,...) { exit(-1); }
void ErrorMessage(const char*, va_list&) { }
void WarningMessage(const char*, va_list&) { }
namespace snort
{
-AppIdSessionApi::AppIdSessionApi(const AppIdSession*, const SfIp&) :
- StashGenericObject(STASH_GENERIC_OBJECT_APPID) {}
+AppIdSessionApi::AppIdSessionApi(const AppIdSession*, const SfIp&)
+{ }
}
void ApplicationDescriptor::set_id(
}
} // namespace ip
-AppIdSessionApi::AppIdSessionApi(const AppIdSession*, const SfIp&) :
- StashGenericObject(STASH_GENERIC_OBJECT_APPID) {}
+AppIdSessionApi::AppIdSessionApi(const AppIdSession*, const SfIp&)
+{ }
void AppIdSessionApi::get_first_stream_app_ids(AppId&, AppId&, AppId&, AppId&) const { }
// Mocks for publish
uint32_t AppInfoManager::getAttributeBits(AppId)
{
return 0;
-}
+}
// Stubs for AppIdSession
void AppIdSession::sync_with_snort_protocol_id(AppId, Packet*) {}
namespace snort
{
AppIdApi appid_api;
-AppIdSessionApi::AppIdSessionApi(const AppIdSession*, const SfIp&) :
- StashGenericObject(STASH_GENERIC_OBJECT_APPID) { }
+AppIdSessionApi::AppIdSessionApi(const AppIdSession*, const SfIp&)
+{ }
AppIdSession* AppIdApi::get_appid_session(Flow const&) { return session; }
Packet::Packet(bool) { }
return &p;
}
-AppIdSessionApi::AppIdSessionApi(const AppIdSession*, const SfIp&) :
- StashGenericObject(STASH_GENERIC_OBJECT_APPID) {}
+AppIdSessionApi::AppIdSessionApi(const AppIdSession*, const SfIp&)
+{ }
}
void appid_log(const snort::Packet*, unsigned char, char const*, ...) { }
Packet::Packet(bool) {}
Packet::~Packet() = default;
Packet* DetectionEngine::get_current_packet() { return nullptr; }
-AppIdSessionApi::AppIdSessionApi(const AppIdSession*, const SfIp&) :
- StashGenericObject(STASH_GENERIC_OBJECT_APPID) {}
+AppIdSessionApi::AppIdSessionApi(const AppIdSession*, const SfIp&)
+{ }
}
void FlowHAState::add(uint8_t) { }
FlowData::FlowData(unsigned, Inspector*)
{
- next = prev = nullptr;
handler = nullptr;
id = 222;
}
typedef int32_t AppId;
Flow::~Flow() = default;
+FlowDataStore::~FlowDataStore() = default;
class FakeFlow : public Flow
{
};
-FlowData* Flow::get_flow_data(unsigned) const
+FlowData* FlowDataStore::get(unsigned) const
{
return mock_flow_data;
}
-int Flow::set_flow_data(FlowData* fd)
+void FlowDataStore::set(FlowData* fd)
{
mock_flow_data = fd;
- return 0;
}
-bool FlowStash::get(const std::string &, StashGenericObject*&) { return false; }
+void FlowDataStore::erase(unsigned)
+{
+ mock_flow_data = nullptr;
+}
+
+bool FlowStash::get(const std::string &, StashGenericObject*&) const
+{ return false; }
#endif
}
time_t packet_time() { return std::time(nullptr); }
-AppIdSessionApi::AppIdSessionApi(const AppIdSession*, const SfIp&) :
- StashGenericObject(STASH_GENERIC_OBJECT_APPID) {}
+AppIdSessionApi::AppIdSessionApi(const AppIdSession*, const SfIp&)
+{ }
}
DiscoveryFilter::~DiscoveryFilter(){}
// Stubs for appid classes
class AppIdInspector{};
-FlowData::FlowData(unsigned, Inspector*) : next(nullptr), prev(nullptr), handler(nullptr), id(0)
+FlowData::FlowData(unsigned, Inspector*) : handler(nullptr), id(0)
{ }
FlowData::~FlowData() = default;
{
SfIp aux_ip;
if (parse_ip_from_uri(*uri, aux_ip))
- p.flow->stash->store(aux_ip);
+ p.flow->set_attr(aux_ip);
}
}
}
#ifndef EXTRACTORS_H
#define EXTRACTORS_H
+#include <map>
#include <sys/time.h>
#include <vector>
static bool open_pcap_dumper()
{
string fname;
- if ( config.capture_path.empty() )
+ if ( config.capture_path.empty() )
get_instance_file(fname, FILE_NAME);
else
{
}
// for unit test
-static void _packet_capture_enable(const string& f, const int16_t g = -1, const string& t = "",
+static void _packet_capture_enable(const string& f, const int16_t g = -1, const string& t = "",
const bool ci = true, const string& path = "", const unsigned max = 0)
{
if ( !config.enabled )
// non-static functions
// -----------------------------------------------------------------------------
-void packet_capture_enable(const string& f, const int16_t g, const string& t, const bool ci,
+void packet_capture_enable(const string& f, const int16_t g, const string& t, const bool ci,
const string& p, const unsigned max)
{
void PacketCapture::show(const SnortConfig*) const
{
ConfigLogger::log_flag("enable", config.enabled);
- if (config.enabled)
+ if (config.enabled)
{
ConfigLogger::log_value("filter", config.filter.c_str());
ConfigLogger::log_value("tenants", int_vector_to_str(config.tenants).c_str());
if (!config.tenants.empty())
{
- if (!std::any_of(config.tenants.begin(), config.tenants.end(),[&p](uint32_t tenant_id){
- return p->pkth->tenant_id == tenant_id;
- }))
+ uint32_t packet_tenant_id = p->pkth->tenant_id;
+ if (std::none_of(config.tenants.cbegin(), config.tenants.cend(),
+ [packet_tenant_id](uint32_t tenant_id)
+ {
+ return packet_tenant_id == tenant_id;
+ }))
{
cap_count_stats.checked++;
return;
"\x0a\x96";
Packet p_match(false), p_non_match(false);
- DAQ_PktHdr_t daq_hdr;
+ DAQ_PktHdr_t daq_hdr = {};
p_match.pkth = &daq_hdr;
p_non_match.pkth = &daq_hdr;
&stats.state_changes[SFS_STATE_TCP_CLOSED]);
formatter->register_field("udp_created", (PegCount*)
&stats.state_changes[SFS_STATE_UDP_CREATED]);
- formatter->register_field("app_id", appid_name);
+ formatter->register_field("app_id", appid_name);
formatter->register_field("port_a", port_a);
formatter->register_field("port_b", port_b);
formatter->register_field("protocol", protocol);
if ( p->flow and p->flow->reload_id > 0 )
{
- const auto& aux_ip_list = p->flow->stash->get_aux_ip_list();
- for ( const auto& ip : aux_ip_list )
+ const auto* aux_ip_list = p->flow->get_aux_ip_list();
+ if (aux_ip_list)
{
- if ( BLOCKED == snort_reputation_aux_ip(config, data, p, &ip) )
- return;
+ for ( const auto& ip : *aux_ip_list )
+ {
+ if ( BLOCKED == snort_reputation_aux_ip(config, data, p, &ip) )
+ return;
+ }
}
}
if ( is_new )
{
if ( proto == IpProtocol::TCP )
- logger.log(RNA_EVENT_NEW, NEW_TCP_SERVICE, p, &htp,
+ logger.log(RNA_EVENT_NEW, NEW_TCP_SERVICE, p, htp,
(const struct in6_addr*) ip.get_ip6_ptr(), htp->get_last_seen_mac(mac_addr), &ha);
else
- logger.log(RNA_EVENT_NEW, NEW_UDP_SERVICE, p, &htp,
+ logger.log(RNA_EVENT_NEW, NEW_UDP_SERVICE, p, htp,
(const struct in6_addr*) ip.get_ip6_ptr(), htp->get_last_seen_mac(mac_addr), &ha);
ha.hits = 0; // hit count is reset after logs are written
if ( new_pld )
{
if ( proto == IpProtocol::TCP )
- logger.log(RNA_EVENT_CHANGE, CHANGE_TCP_SERVICE_INFO, p, &srt,
+ logger.log(RNA_EVENT_CHANGE, CHANGE_TCP_SERVICE_INFO, p, srt,
(const struct in6_addr*) p->flow->server_ip.get_ip6_ptr(),
srt->get_last_seen_mac(mac_addr), &local_ha);
else
- logger.log(RNA_EVENT_CHANGE, CHANGE_UDP_SERVICE_INFO, p, &srt,
+ logger.log(RNA_EVENT_CHANGE, CHANGE_UDP_SERVICE_INFO, p, srt,
(const struct in6_addr*) p->flow->server_ip.get_ip6_ptr(),
srt->get_last_seen_mac(mac_addr), &local_ha);
}
new_client_payload = crt->add_client_payload(hc, payload, max_payloads);
if ( new_client_payload )
- logger.log(RNA_EVENT_CHANGE, CHANGE_CLIENT_APP_UPDATE, p, &crt,
+ logger.log(RNA_EVENT_CHANGE, CHANGE_CLIENT_APP_UPDATE, p, crt,
(const struct in6_addr*) p->flow->client_ip.get_ip6_ptr(),
crt->get_last_seen_mac(mac_addr), &hc);
}
ha.last_seen = (uint32_t) packet_time();
if ( proto == IpProtocol::TCP )
- logger.log(RNA_EVENT_CHANGE, CHANGE_TCP_SERVICE_INFO, p, &htp,
+ logger.log(RNA_EVENT_CHANGE, CHANGE_TCP_SERVICE_INFO, p, htp,
(const struct in6_addr*) ip.get_ip6_ptr(), htp->get_last_seen_mac(mac_addr), &ha);
else
- logger.log(RNA_EVENT_CHANGE, CHANGE_UDP_SERVICE_INFO, p, &htp,
+ logger.log(RNA_EVENT_CHANGE, CHANGE_UDP_SERVICE_INFO, p, htp,
(const struct in6_addr*) ip.get_ip6_ptr(), htp->get_last_seen_mac(mac_addr), &ha);
ha.hits = 0;
HostApplication ha(p->flow->server_port, proto, service, false);
//coverity[y2k38_safety]
ha.last_seen = (uint32_t) packet_time();
- logger.log(RNA_EVENT_CHANGE, CHANGE_BANNER_UPDATE, p, &rt,
+ logger.log(RNA_EVENT_CHANGE, CHANGE_BANNER_UPDATE, p, rt,
(const struct in6_addr*) p->flow->server_ip.get_ip6_ptr(),
rt->get_last_seen_mac(mac_addr), &ha);
}
bool is_new = false;
auto hc = rt->find_or_add_client(client, version, service, is_new);
if ( is_new )
- logger.log(RNA_EVENT_NEW, NEW_CLIENT_APP, p, &rt,
+ logger.log(RNA_EVENT_NEW, NEW_CLIENT_APP, p, rt,
(const struct in6_addr*) p->flow->client_ip.get_ip6_ptr(), mac, &hc);
}
conf ? conf->max_host_services : 0, login_success) )
{
logger.log(RUA_EVENT, login_success ? CHANGE_USER_LOGIN : FAILED_USER_LOGIN,
- p, &rt, (const struct in6_addr*) p->ptrs.ip_api.get_dst()->get_ip6_ptr(),
+ p, rt, (const struct in6_addr*) p->ptrs.ip_api.get_dst()->get_ip6_ptr(),
username, service, packet_time());
}
}
const uint8_t* src_mac = layer::get_eth_layer(p)->ether_src;
logger.log(RNA_EVENT_CHANGE, CHANGE_NETBIOS_NAME, src_ip_ptr, src_mac,
- &rt, p, packet_time(), 0, nullptr, nullptr, nullptr, nullptr, nullptr,
+ rt, p, packet_time(), 0, nullptr, nullptr, nullptr, nullptr, nullptr,
nullptr, APP_ID_NONE, nullptr, false, 0, 0, nullptr, nb_name);
}
}
if ( uafp and rt->add_ua_fingerprint(uafp->fpid, uafp->fp_type, jail_broken,
device_info, MAX_USER_AGENT_DEVICES) )
{
- logger.log(RNA_EVENT_NEW, NEW_OS, p, &rt,
+ logger.log(RNA_EVENT_NEW, NEW_OS, p, rt,
(const struct in6_addr*)p->flow->client_ip.get_ip6_ptr(),
rt->get_last_seen_mac(mac_addr), (FpFingerprint*)uafp, packet_time(),
device_info, jail_broken);
}
#endif
-void RnaLogger::log(uint16_t type, uint16_t subtype, const Packet* p, RnaTracker* ht,
+void RnaLogger::log(uint16_t type, uint16_t subtype, const Packet* p, RnaTracker& ht,
const struct in6_addr* src_ip, const uint8_t* src_mac, const HostApplication* ha)
{
log(type, subtype, src_ip, src_mac, ht, p, 0, 0,
nullptr, ha);
}
-void RnaLogger::log(uint16_t type, uint16_t subtype, const Packet* p, RnaTracker* ht,
+void RnaLogger::log(uint16_t type, uint16_t subtype, const Packet* p, RnaTracker& ht,
const struct in6_addr* ip, const char* user, AppId appid, time_t event_time)
{
log(type, subtype, ip, nullptr, ht, p, event_time, 0,
nullptr, nullptr, nullptr, nullptr, nullptr, user, appid);
}
-void RnaLogger::log(uint16_t type, uint16_t subtype, const Packet* p, RnaTracker* ht,
+void RnaLogger::log(uint16_t type, uint16_t subtype, const Packet* p, RnaTracker& ht,
const struct in6_addr* src_ip, const uint8_t* src_mac, const HostClient* hc)
{
log(type, subtype, src_ip, src_mac, ht, p, 0, 0,
nullptr, nullptr, nullptr, nullptr, hc);
}
-void RnaLogger::log(uint16_t type, uint16_t subtype, const Packet* p, RnaTracker* ht,
+void RnaLogger::log(uint16_t type, uint16_t subtype, const Packet* p, RnaTracker& ht,
const struct in6_addr* src_ip, const uint8_t* src_mac, const FpFingerprint* fp,
time_t event_time, const char* device_info, bool jail_broken)
{
fp, nullptr, nullptr, nullptr, APP_ID_NONE, device_info, jail_broken);
}
-void RnaLogger::log(uint16_t type, uint16_t subtype, const Packet* p, RnaTracker* ht,
+void RnaLogger::log(uint16_t type, uint16_t subtype, const Packet* p, RnaTracker& ht,
const struct in6_addr* src_ip, const uint8_t* src_mac, time_t event_time)
{
log(type, subtype, src_ip, src_mac, ht, p, event_time);
}
-void RnaLogger::log(uint16_t type, uint16_t subtype, const Packet* p, RnaTracker* ht,
+void RnaLogger::log(uint16_t type, uint16_t subtype, const Packet* p, RnaTracker& ht,
const struct in6_addr* src_ip, const uint8_t* src_mac, const HostMac* hm, time_t event_time)
{
log(type, subtype, src_ip, src_mac, ht, p, event_time, 0, hm);
}
-void RnaLogger::log(uint16_t type, uint16_t subtype, const Packet* p, RnaTracker* ht,
+void RnaLogger::log(uint16_t type, uint16_t subtype, const Packet* p, RnaTracker& ht,
uint16_t proto, const uint8_t* src_mac, const struct in6_addr* src_ip, time_t event_time)
{
log(type, subtype, src_ip, src_mac, ht, p, event_time, proto);
}
void RnaLogger::log(uint16_t type, uint16_t subtype, const Packet* p, const uint8_t* src_mac,
- const struct in6_addr* src_ip, RnaTracker* ht, time_t event_time, void* cond_var)
+ const struct in6_addr* src_ip, RnaTracker& ht, time_t event_time, void* cond_var)
{
log(type, subtype, src_ip, src_mac, ht, p, event_time, 0,
nullptr, nullptr, nullptr, cond_var);
}
-void RnaLogger::log(uint16_t type, uint16_t subtype, const snort::Packet* p, RnaTracker* ht,
+void RnaLogger::log(uint16_t type, uint16_t subtype, const snort::Packet* p, RnaTracker& ht,
const struct in6_addr* src_ip, const uint8_t* src_mac, uint32_t lease, uint32_t netmask,
const struct in6_addr* router)
{
nullptr, nullptr, APP_ID_NONE, nullptr, false, lease, netmask, router);
}
-void RnaLogger::log(uint16_t type, uint16_t subtype, const snort::Packet* p, RnaTracker* ht,
+void RnaLogger::log(uint16_t type, uint16_t subtype, const snort::Packet* p, RnaTracker& ht,
const struct in6_addr* src_ip, const uint8_t* src_mac, const FpFingerprint* fp,
const vector<const char*>* cpeos, time_t event_time)
{
}
bool RnaLogger::log(uint16_t type, uint16_t subtype, const struct in6_addr* src_ip,
- const uint8_t* src_mac, RnaTracker* ht, const Packet* p, time_t event_time,
+ const uint8_t* src_mac, RnaTracker& ht, const Packet* p, time_t event_time,
uint16_t proto, const HostMac* hm, const HostApplication* ha,
const FpFingerprint* fp, void* cond_var, const HostClient* hc,
const char* user, AppId appid, const char* di, bool jb, uint32_t lease,
if ( !enabled )
return false;
- assert(ht);
-
RnaLoggerEvent rle(type, subtype, src_mac, ht, hm, proto, cond_var,
ha, fp, hc, user, appid, di, jb, lease, netmask, router, p, nb_name, cpeos);
if ( src_ip and (!IN6_IS_ADDR_V4MAPPED(src_ip) or src_ip->s6_addr32[3]) )
//coverity[y2k38_safety]
rle.event_time = (uint32_t)event_time;
//coverity[y2k38_safety]
- (*ht)->update_last_event(event_time);
+ ht->update_last_event(event_time);
}
EventManager::call_loggers(nullptr, const_cast<Packet*>(p), "RNA", &rle);
RnaTracker ht;
uint8_t mac[6] = {0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6};
RnaLogger logger1(false);
- CHECK(false == logger1.log(0, 0, nullptr, mac, &ht, nullptr, 0, 0,
+ CHECK(false == logger1.log(0, 0, nullptr, mac, ht, nullptr, 0, 0,
nullptr, nullptr, nullptr, nullptr, nullptr));
RnaLogger logger2(true);
- CHECK(true == logger2.log(0, 0, nullptr, mac, &ht, nullptr, 0, 0,
+ CHECK(true == logger2.log(0, 0, nullptr, mac, ht, nullptr, 0, 0,
nullptr, nullptr, nullptr, nullptr, nullptr));
}
}
RnaLogger(const bool enable) : enabled(enable) { }
// for host application
- void log(uint16_t type, uint16_t subtype, const snort::Packet* p, RnaTracker* ht,
+ void log(uint16_t type, uint16_t subtype, const snort::Packet* p, RnaTracker& ht,
const struct in6_addr* src_ip, const uint8_t* src_mac, const snort::HostApplication* ha);
// for host client
- void log(uint16_t type, uint16_t subtype, const snort::Packet* p, RnaTracker* ht,
+ void log(uint16_t type, uint16_t subtype, const snort::Packet* p, RnaTracker& ht,
const struct in6_addr* src_ip, const uint8_t* src_mac, const snort::HostClient* hcp);
// for host user
- void log(uint16_t type, uint16_t subtype, const snort::Packet*, RnaTracker*,
+ void log(uint16_t type, uint16_t subtype, const snort::Packet*, RnaTracker&,
const struct in6_addr*, const char* user, AppId appid, time_t event_time);
// for cpe os info event
- void log(uint16_t type, uint16_t subtype, const snort::Packet* p, RnaTracker* ht,
+ void log(uint16_t type, uint16_t subtype, const snort::Packet* p, RnaTracker& ht,
const struct in6_addr* src_ip, const uint8_t* src_mac, const snort::FpFingerprint* fp,
const std::vector<const char*>* cpeos, time_t event_time);
// for fingerprint
- void log(uint16_t type, uint16_t subtype, const snort::Packet* p, RnaTracker* ht,
+ void log(uint16_t type, uint16_t subtype, const snort::Packet* p, RnaTracker& ht,
const struct in6_addr* src_ip, const uint8_t* src_mac, const snort::FpFingerprint* fp,
time_t event_time, const char* device_info = nullptr, bool jail_broken = false);
// for event time
- void log(uint16_t type, uint16_t subtype, const snort::Packet* p, RnaTracker* ht,
+ void log(uint16_t type, uint16_t subtype, const snort::Packet* p, RnaTracker& ht,
const struct in6_addr* src_ip, const uint8_t* src_mac, time_t event_time);
// for mac event
- void log(uint16_t type, uint16_t subtype, const snort::Packet* p, RnaTracker* ht,
+ void log(uint16_t type, uint16_t subtype, const snort::Packet* p, RnaTracker& ht,
const struct in6_addr* src_ip, const uint8_t* src_mac,
const snort::HostMac* hm = nullptr, time_t event_time = 0);
// for protocol event
- void log(uint16_t type, uint16_t subtype, const snort::Packet* p, RnaTracker* ht,
+ void log(uint16_t type, uint16_t subtype, const snort::Packet* p, RnaTracker& ht,
uint16_t proto, const uint8_t* mac, const struct in6_addr* ip = nullptr,
time_t event_time = 0);
// for timeout update
void log(uint16_t type, uint16_t subtype, const snort::Packet* p, const uint8_t* src_mac,
- const struct in6_addr* src_ip, RnaTracker* ht, time_t event_time, void* cond_var);
+ const struct in6_addr* src_ip, RnaTracker& ht, time_t event_time, void* cond_var);
// for dhcp info event
- void log(uint16_t type, uint16_t subtype, const snort::Packet* p, RnaTracker* ht,
+ void log(uint16_t type, uint16_t subtype, const snort::Packet* p, RnaTracker& ht,
const struct in6_addr* src_ip, const uint8_t* src_mac, uint32_t lease, uint32_t netmask,
const struct in6_addr* router);
// for all
bool log(uint16_t type, uint16_t subtype, const struct in6_addr* src_ip,
- const uint8_t* src_mac, RnaTracker* ht, const snort::Packet* p = nullptr,
+ const uint8_t* src_mac, RnaTracker& ht, const snort::Packet* p = nullptr,
time_t event_time = 0, uint16_t proto = 0, const snort::HostMac* hm = nullptr,
const snort::HostApplication* ha = nullptr, const snort::FpFingerprint* fp = nullptr,
void* cond_var = nullptr, const snort::HostClient* hc = nullptr,
struct RnaLoggerEvent : public Event
{
- RnaLoggerEvent (uint16_t t, uint16_t st, const uint8_t* mc, const RnaTracker* rt,
+ RnaLoggerEvent (uint16_t t, uint16_t st, const uint8_t* mc, const RnaTracker& rt,
const snort::HostMac* hmp, uint16_t pr, void* cv, const snort::HostApplication* hap,
const snort::FpFingerprint* fpr, const snort::HostClient* hcp, const char* u,
int32_t app, const char* di, bool jb, uint32_t ls, uint32_t nm,
uint16_t subtype;
const struct in6_addr* ip = nullptr;
const uint8_t* mac;
- const RnaTracker* ht;
+ const RnaTracker& ht;
const snort::HostMac* hm;
uint16_t proto;
void* cond_var;
rt->update_last_seen();
FpFingerprint fp = FpFingerprint();
fp.fp_type = FpFingerprint::FpType::FP_TYPE_CPE;
- logger.log(RNA_EVENT_NEW, NEW_OS, p, &rt, src_ip_ptr, src_mac, &fp,
+ logger.log(RNA_EVENT_NEW, NEW_OS, p, rt, src_ip_ptr, src_mac, &fp,
cpeos_event.get_os_names(), packet_time());
return true;
if ( new_host )
{
if ( nfe->get_create_host() )
- logger.log(RNA_EVENT_NEW, NEW_HOST, p, &ht, src_ip_ptr, src_mac);
+ logger.log(RNA_EVENT_NEW, NEW_HOST, p, ht, src_ip_ptr, src_mac);
else
return;
}
if ( ptype > to_utype(ProtocolId::ETHERTYPE_MINIMUM) )
{
if ( ht->add_network_proto(ptype) )
- logger.log(RNA_EVENT_NEW, NEW_NET_PROTOCOL, p, &ht, ptype, src_mac, src_ip_ptr,
+ logger.log(RNA_EVENT_NEW, NEW_NET_PROTOCOL, p, ht, ptype, src_mac, src_ip_ptr,
packet_time());
}
// Remaining fields (port, proto, etc.) are parsed from the NetFlow record
ptype = nfe->get_record()->proto;
if ( ht->add_xport_proto(ptype) )
- logger.log(RNA_EVENT_NEW, NEW_XPORT_PROTOCOL, p, &ht, ptype, src_mac, src_ip_ptr,
+ logger.log(RNA_EVENT_NEW, NEW_XPORT_PROTOCOL, p, ht, ptype, src_mac, src_ip_ptr,
packet_time());
if ( !new_host )
- generate_change_host_update(&ht, p, &src_ip, src_mac, packet_time());
+ generate_change_host_update(ht, p, &src_ip, src_mac, packet_time());
}
void RnaPnd::analyze_netflow_service(NetFlowEvent* nfe)
if ( is_new )
{
if ( proto == IpProtocol::TCP )
- logger.log(RNA_EVENT_NEW, NEW_TCP_SERVICE, p, &ht,
+ logger.log(RNA_EVENT_NEW, NEW_TCP_SERVICE, p, ht,
(const struct in6_addr*) src_ip.get_ip6_ptr(), mac_addr, &ha);
else if ( proto == IpProtocol::UDP )
- logger.log(RNA_EVENT_NEW, NEW_UDP_SERVICE, p, &ht,
+ logger.log(RNA_EVENT_NEW, NEW_UDP_SERVICE, p, ht,
(const struct in6_addr*) src_ip.get_ip6_ptr(), mac_addr, &ha);
ha.hits = 0;
}
if ( new_host )
- logger.log(RNA_EVENT_NEW, NEW_HOST, p, &ht, src_ip_ptr, src_mac);
+ logger.log(RNA_EVENT_NEW, NEW_HOST, p, ht, src_ip_ptr, src_mac);
if ( new_mac and !new_host )
{
HostMac hm;
- logger.log(RNA_EVENT_CHANGE, CHANGE_MAC_ADD, p, &ht, src_ip_ptr, src_mac,
+ logger.log(RNA_EVENT_CHANGE, CHANGE_MAC_ADD, p, ht, src_ip_ptr, src_mac,
ht->get_hostmac(src_mac, hm) ? &hm : nullptr, packet_time());
}
if ( ht->update_mac_ttl(src_mac, ttl) )
{
HostMac hm;
- logger.log(RNA_EVENT_CHANGE, CHANGE_MAC_INFO, p, &ht, src_ip_ptr, src_mac,
+ logger.log(RNA_EVENT_CHANGE, CHANGE_MAC_INFO, p, ht, src_ip_ptr, src_mac,
ht->get_hostmac(src_mac, hm) ? &hm : nullptr, packet_time());
if ( ht->reset_hops_if_primary() )
- logger.log(RNA_EVENT_CHANGE, CHANGE_HOPS, p, &ht, src_ip_ptr, src_mac, packet_time());
+ logger.log(RNA_EVENT_CHANGE, CHANGE_HOPS, p, ht, src_ip_ptr, src_mac, packet_time());
}
if ( p->is_tcp() and ht->get_host_type() == HOST_TYPE_HOST )
if ( ptype > to_utype(ProtocolId::ETHERTYPE_MINIMUM) )
{
if ( ht->add_network_proto(ptype) )
- logger.log(RNA_EVENT_NEW, NEW_NET_PROTOCOL, p, &ht, ptype, src_mac, src_ip_ptr,
+ logger.log(RNA_EVENT_NEW, NEW_NET_PROTOCOL, p, ht, ptype, src_mac, src_ip_ptr,
packet_time());
}
ptype = to_utype(p->get_ip_proto_next());
if ( ht->add_xport_proto(ptype) )
- logger.log(RNA_EVENT_NEW, NEW_XPORT_PROTOCOL, p, &ht, ptype, src_mac, src_ip_ptr,
+ logger.log(RNA_EVENT_NEW, NEW_XPORT_PROTOCOL, p, ht, ptype, src_mac, src_ip_ptr,
packet_time());
if ( !new_host )
- generate_change_host_update(&ht, p, src_ip, src_mac, packet_time());
+ generate_change_host_update(ht, p, src_ip, src_mac, packet_time());
discover_host_types_icmpv6_ndp(ht, p, last_seen, src_ip_ptr, src_mac);
const TcpFingerprint* tfp = processor->get(p, rna_flow);
if ( tfp and ht->add_tcp_fingerprint(tfp->fpid) )
- logger.log(RNA_EVENT_NEW, NEW_OS, p, &ht, src_ip_ptr, src_mac, tfp, packet_time());
+ logger.log(RNA_EVENT_NEW, NEW_OS, p, ht, src_ip_ptr, src_mac, tfp, packet_time());
}
}
if (new_mac)
{
ht->add_mac(mk.mac_addr, p->ptrs.ip_api.ttl(), 0);
- logger.log(RNA_EVENT_NEW, NEW_HOST, p, &ht, nullptr, mk.mac_addr);
+ logger.log(RNA_EVENT_NEW, NEW_HOST, p, ht, nullptr, mk.mac_addr);
hm_ptr->update_last_event(p->pkth->ts.tv_sec);
}
else
if (dhcp_fp and ht->add_udp_fingerprint(dhcp_fp->fpid))
{
const auto& src_ip_ptr = (const struct in6_addr*) src_ip->get_ip6_ptr();
- logger.log(RNA_EVENT_NEW, NEW_OS, p, &ht, src_ip_ptr, src_mac, dhcp_fp, packet_time());
+ logger.log(RNA_EVENT_NEW, NEW_OS, p, ht, src_ip_ptr, src_mac, dhcp_fp, packet_time());
}
}
if (new_mac)
{
ht->add_mac(mk.mac_addr, p->ptrs.ip_api.ttl(), 0);
- logger.log(RNA_EVENT_NEW, NEW_HOST, p, &ht, nullptr, mk.mac_addr);
+ logger.log(RNA_EVENT_NEW, NEW_HOST, p, ht, nullptr, mk.mac_addr);
hm_ptr->update_last_event(p->pkth->ts.tv_sec);
}
else
hm_ptr->update_last_seen(p->pkth->ts.tv_sec);
- logger.log(RNA_EVENT_CHANGE, CHANGE_FULL_DHCP_INFO, p, &ht,
+ logger.log(RNA_EVENT_CHANGE, CHANGE_FULL_DHCP_INFO, p, ht,
(const struct in6_addr*) leased_ip.get_ip6_ptr(), src_mac,
lease, net_mask, (const struct in6_addr*) router_ip.get_ip6_ptr());
}
const auto& src_ip_ptr = (const struct in6_addr*) src_ip->get_ip6_ptr();
const auto& src_mac = layer::get_eth_layer(p)->ether_src;
- logger.log(RNA_EVENT_NEW, NEW_OS, p, &rt, src_ip_ptr, src_mac, fp, packet_time());
+ logger.log(RNA_EVENT_NEW, NEW_OS, p, rt, src_ip_ptr, src_mac, fp, packet_time());
}
}
hm.update_vlan(vh->vth_pri_cfi_vlan, vh->vth_proto);
}
-void RnaPnd::generate_change_vlan_update(RnaTracker *rt, const Packet* p,
+void RnaPnd::generate_change_vlan_update(RnaTracker& rt, const Packet* p,
const uint8_t* src_mac, HostTrackerMac& hm, bool isnew)
{
if ( !(p->proto_bits & PROTO_BIT__VLAN) )
if ( !isnew )
update_vlan(p, hm);
- rt->get()->update_vlan(vh->vth_pri_cfi_vlan, vh->vth_proto);
+ rt->update_vlan(vh->vth_pri_cfi_vlan, vh->vth_proto);
logger.log(RNA_EVENT_CHANGE, CHANGE_VLAN_TAG, p, rt, nullptr, src_mac, packet_time());
}
}
-void RnaPnd::generate_change_vlan_update(RnaTracker *rt, const Packet* p,
+void RnaPnd::generate_change_vlan_update(RnaTracker& rt, const Packet* p,
const uint8_t* src_mac, const SfIp* src_ip, bool isnew)
{
if ( !(p->proto_bits & PROTO_BIT__VLAN) )
if ( !vh )
return;
- if ( isnew or !rt->get()->has_same_vlan(vh->vth_pri_cfi_vlan) )
+ if ( isnew or !rt->has_same_vlan(vh->vth_pri_cfi_vlan) )
{
- rt->get()->update_vlan(vh->vth_pri_cfi_vlan, vh->vth_proto);
+ rt->update_vlan(vh->vth_pri_cfi_vlan, vh->vth_proto);
logger.log(RNA_EVENT_CHANGE, CHANGE_VLAN_TAG, p, rt,
(const struct in6_addr*) src_ip->get_ip6_ptr(), src_mac, packet_time());
}
}
-void RnaPnd::generate_change_host_update(RnaTracker* ht, const Packet* p,
+void RnaPnd::generate_change_host_update(RnaTracker& ht, const Packet* p,
const SfIp* src_ip, const uint8_t* src_mac, const time_t& sec)
{
if ( !ht or !update_timeout )
return;
- uint32_t last_seen = (*ht)->get_last_seen();
- uint32_t last_event = (*ht)->get_last_event();
+ uint32_t last_seen = ht->get_last_seen();
+ uint32_t last_event = ht->get_last_event();
time_t timestamp = sec - update_timeout;
if ( last_seen > last_event and (time_t) last_event + update_timeout <= sec )
logger.log(RNA_EVENT_CHANGE, CHANGE_HOST_UPDATE, p, src_mac,
if ( last_seen > last_event and (time_t) last_event + update_timeout <= sec )
{
logger.log(RNA_EVENT_CHANGE, CHANGE_HOST_UPDATE, p, src_mac, nullptr,
- &rt, last_seen, (void*) ×tamp);
+ rt, last_seen, (void*) ×tamp);
+
//coverity[y2k38_safety]
mt->update_last_event(sec);
}
auto sec = time(nullptr);
for ( auto & h : hosts )
- generate_change_host_update(&h.second, nullptr, &h.first, nullptr, sec);
+ generate_change_host_update(h.second, nullptr, &h.first, nullptr, sec);
for ( auto & m : mac_hosts)
generate_change_host_update_eth(m.second.get(), nullptr,
ht.get()->update_last_seen();
ht.get()->add_mac(mk.mac_addr, 0, 0);
- logger.log(RNA_EVENT_NEW, NEW_HOST, p, &ht, nullptr, mk.mac_addr);
+ logger.log(RNA_EVENT_NEW, NEW_HOST, p, ht, nullptr, mk.mac_addr);
hm_ptr->update_last_event(p->pkth->ts.tv_sec);
- generate_change_vlan_update(&ht, p, mk.mac_addr, *hm_ptr, true);
+ generate_change_vlan_update(ht, p, mk.mac_addr, *hm_ptr, true);
}
else
{
generate_change_host_update_eth(hm_ptr.get(), p, mk.mac_addr, packet_time());
hm_ptr->update_last_seen(p->pkth->ts.tv_sec);
- generate_change_vlan_update(&ht, p, mk.mac_addr, *hm_ptr, false);
+ generate_change_vlan_update(ht, p, mk.mac_addr, *hm_ptr, false);
}
if ( discover_proto )
{
if ( hm_ptr->add_network_proto(ntype) )
{
- logger.log(RNA_EVENT_NEW, NEW_NET_PROTOCOL, p, &ht, ntype, mk.mac_addr);
+ logger.log(RNA_EVENT_NEW, NEW_NET_PROTOCOL, p, ht, ntype, mk.mac_addr);
hm_ptr->update_last_event(p->pkth->ts.tv_sec);
}
}
ntype = ((const RNA_LLC*) lyr.start)->s.proto;
if ( hm_ptr->add_network_proto(ntype) )
{
- logger.log(RNA_EVENT_NEW, NEW_NET_PROTOCOL, p, &ht, ntype, mk.mac_addr);
+ logger.log(RNA_EVENT_NEW, NEW_NET_PROTOCOL, p, ht, ntype, mk.mac_addr);
hm_ptr->update_last_event(p->pkth->ts.tv_sec);
}
}
RnaTracker rt = std::make_shared<snort::HostTracker>();
if ( layer::get_arp_layer(p) )
- retval = discover_network_arp(p, &rt);
+ retval = discover_network_arp(p, rt);
else
{
// If we have an inner LLC layer, grab it
return;
}
-int RnaPnd::discover_network_arp(const Packet* p, RnaTracker* ht_ref)
+int RnaPnd::discover_network_arp(const Packet* p, RnaTracker& ht_ref)
{
MacKey mk(layer::get_eth_layer(p)->ether_src);
const auto& src_mac = mk.mac_addr;
if ( !new_host_mac )
hm_ptr->update_last_seen(p->pkth->ts.tv_sec);
- *ht_ref = ht;
+ ht_ref = ht;
if( new_host )
{
ht->update_hops(255);
ht->add_mac(src_mac, 0, 0);
- logger.log(RNA_EVENT_NEW, NEW_HOST, p, &ht,
+ logger.log(RNA_EVENT_NEW, NEW_HOST, p, ht,
(const struct in6_addr*) spa.get_ip6_ptr(), src_mac);
hm_ptr->update_last_event(p->pkth->ts.tv_sec);
}
hm_ptr->update_last_event(p->pkth->ts.tv_sec);
}
- generate_change_vlan_update(&ht, p, src_mac, &spa, true);
+ generate_change_vlan_update(ht, p, src_mac, &spa, true);
auto ntype = to_utype(ProtocolId::ETHERTYPE_ARP);
if ( hm_ptr->add_network_proto(ntype) )
{
- logger.log(RNA_EVENT_NEW, NEW_NET_PROTOCOL, p, &ht, ntype, src_mac);
+ logger.log(RNA_EVENT_NEW, NEW_NET_PROTOCOL, p, ht, ntype, src_mac);
hm_ptr->update_last_event(p->pkth->ts.tv_sec);
}
hm_ptr->update_last_event(p->pkth->ts.tv_sec);
- ht_ref.get()->update_last_seen();
- ht_ref.get()->add_mac(mk.mac_addr, 0, 1);
+ ht_ref->update_last_seen();
+ ht_ref->add_mac(mk.mac_addr, 0, 1);
- logger.log(RNA_EVENT_NEW, NEW_HOST, p, &ht_ref,
+ logger.log(RNA_EVENT_NEW, NEW_HOST, p, ht_ref,
(const struct in6_addr*) nullptr, mk.mac_addr);
- generate_change_vlan_update(&ht_ref, p, mk.mac_addr, *hm_ptr, true);
+ generate_change_vlan_update(ht_ref, p, mk.mac_addr, *hm_ptr, true);
}
else
{
hm_ptr->update_last_seen(p->pkth->ts.tv_sec);
generate_change_host_update_eth(hm_ptr.get(), p, mk.mac_addr, packet_time());
- generate_change_vlan_update(&ht_ref, p, mk.mac_addr, *hm_ptr, false);
+ generate_change_vlan_update(ht_ref, p, mk.mac_addr, *hm_ptr, false);
}
return 0;
if ( ht_last_seen - ht->get_nat_count_start() <= RNA_NAT_TIMEOUT_THRESHOLD )
{
ht->set_host_type(p->is_from_application_client() ? HOST_TYPE_NAT : HOST_TYPE_LB);
- logger.log(RNA_EVENT_CHANGE, CHANGE_HOST_TYPE, p, &ht, src_ip, src_mac);
+ logger.log(RNA_EVENT_CHANGE, CHANGE_HOST_TYPE, p, ht, src_ip, src_mac);
}
ht->set_nat_count_start(ht_last_seen);
else
ht->set_host_type(HOST_TYPE_BRIDGE);
- logger.log(RNA_EVENT_CHANGE, CHANGE_HOST_TYPE, p, &ht,
+ logger.log(RNA_EVENT_CHANGE, CHANGE_HOST_TYPE, p, ht,
(const struct in6_addr*)cdp_ip.get_ip6_ptr(), layer::get_eth_layer(p)->ether_src);
}
}
if ( host_type != HOST_TYPE_ROUTER and host_type != HOST_TYPE_BRIDGE )
{
ht->set_host_type(HOST_TYPE_ROUTER);
- logger.log(RNA_EVENT_CHANGE, CHANGE_HOST_TYPE, p, &ht, src_ip, neighbor_src_mac);
+ logger.log(RNA_EVENT_CHANGE, CHANGE_HOST_TYPE, p, ht, src_ip, neighbor_src_mac);
}
}
if ( ht->make_primary(src_mac) )
{
HostMac hm;
- logger.log(RNA_EVENT_CHANGE, CHANGE_MAC_INFO, p, &ht,
+ logger.log(RNA_EVENT_CHANGE, CHANGE_MAC_INFO, p, ht,
src_ip, src_mac, ht->get_hostmac(src_mac, hm) ? &hm : nullptr, last_seen);
}
private:
// generate change event for single host
- void generate_change_host_update(RnaTracker*, const snort::Packet*,
+ void generate_change_host_update(RnaTracker&, const snort::Packet*,
const snort::SfIp*, const uint8_t* src_mac, const time_t&);
void generate_change_host_update_eth(HostTrackerMac*, const snort::Packet*,
const uint8_t* src_mac, const time_t&);
// Change vlan event related utilities
inline void update_vlan(const snort::Packet*, HostTrackerMac&);
- void generate_change_vlan_update(RnaTracker*, const snort::Packet*,
+ void generate_change_vlan_update(RnaTracker&, const snort::Packet*,
const uint8_t* src_mac, HostTrackerMac&, bool isnew);
- void generate_change_vlan_update(RnaTracker*, const snort::Packet*,
+ void generate_change_vlan_update(RnaTracker&, const snort::Packet*,
const uint8_t* src_mac, const snort::SfIp*, bool isnew);
void generate_new_host_mac(const snort::Packet*, RnaTracker, bool discover_proto = false);
// RNA utilities for non-IP packets
void discover_network_ethernet(const snort::Packet*);
- int discover_network_arp(const snort::Packet*, RnaTracker*);
+ int discover_network_arp(const snort::Packet*, RnaTracker&);
int discover_network_bpdu(const snort::Packet*, const uint8_t* data, RnaTracker&);
int discover_network_cdp(const snort::Packet*, const uint8_t* data, uint16_t rlen,
RnaTracker&);
NetworkPolicy* get_network_policy() { return nullptr; }
InspectionPolicy* get_inspection_policy() { return nullptr; }
Flow::~Flow() = default;
+FlowDataStore::~FlowDataStore() = default;
bool Flow::handle_allowlist() { return true; }
void ThreadConfig::implement_thread_affinity(SThreadType, unsigned) { }
void ThreadConfig::apply_thread_policy(SThreadType , unsigned ) { }
//--------------------------------------------------------------------------
#ifdef UNIT_TEST
-struct TestCase
+struct ParseSOTestCase
{
const char* rule;
const char* expect;
bool result;
};
-static const TestCase syntax_tests[] =
+static const ParseSOTestCase syntax_tests[] =
{
{ "alert()", "alert()", true },
{ " alert() ", "alert()", true },
{ nullptr, nullptr, false }
};
-static const TestCase basic_tests[] =
+static const ParseSOTestCase basic_tests[] =
{
{ "alert( sid:1; )", "alert( sid:1; )", true },
};
// __STRDUMP_DISABLE__
-static const TestCase stub_tests[] =
+static const ParseSOTestCase stub_tests[] =
{
{ "alert( id:0; )", "alert( )", true },
{ "alert( sid:1; id:0; )", "alert( sid:1; )", true },
TEST_CASE("parse_so_rule.syntax", "[parser]")
{
- const TestCase* tc = syntax_tests;
+ const ParseSOTestCase* tc = syntax_tests;
while ( tc->rule )
{
TEST_CASE("parse_so_rule.basic", "[parser]")
{
- const TestCase* tc = basic_tests;
+ const ParseSOTestCase* tc = basic_tests;
while ( tc->rule )
{
TEST_CASE("get_so_stub", "[parser]")
{
- const TestCase* tc = stub_tests;
+ const ParseSOTestCase* tc = stub_tests;
while ( tc->rule )
{
int DetectionEngine::queue_event(unsigned int, unsigned int) { return 0; }
FlowData::~FlowData() = default;
FlowData::FlowData(unsigned int, snort::Inspector*) { }
+FlowDataStore::~FlowDataStore() = default;
// Inspector mocks, used by MockInspector class
InspectApi mock_api;
return translation_status;
}
-// Mocks for snort::Flow::get_flow_data
+// Mocks for snort::FlowDataStore::get
unsigned Http2FlowData::inspector_id = 0;
Http2Stream::~Http2Stream() = default;
Http2FlowData http2_flow_data(nullptr);
void Http2FlowData::set_mid_frame(bool val) { continuation_expected[SRC_SERVER] = val; }
bool Http2FlowData::is_mid_frame() const { return continuation_expected[SRC_SERVER]; }
-FlowData* snort::Flow::get_flow_data(unsigned int) const { return &http2_flow_data; }
+FlowData* FlowDataStore::get(unsigned) const
+{ return &http2_flow_data; }
TEST_GROUP(payload_injector_test)
{
{
"allocations",
[](const View& lhs, const View& rhs)
- { return lhs.allocs() >= rhs.allocs(); }
+ { return lhs.allocs() > rhs.allocs(); }
},
{
"total_used",
[](const View& lhs, const View& rhs)
- { return lhs.total() >= rhs.total(); }
+ { return lhs.total() > rhs.total(); }
},
{
"avg_allocation",
[](const View& lhs, const View& rhs)
- { return lhs.avg_alloc() >= rhs.avg_alloc(); }
+ { return lhs.avg_alloc() > rhs.avg_alloc(); }
},
};
{
"checks",
[](const View& lhs, const View& rhs)
- { return lhs.checks() >= rhs.checks(); }
+ { return lhs.checks() > rhs.checks(); }
},
{
"avg_check",
[](const View& lhs, const View& rhs)
- { return lhs.avg_check() >= rhs.avg_check(); }
+ { return lhs.avg_check() > rhs.avg_check(); }
},
{
"total_time",
[](const View& lhs, const View& rhs)
- { return TO_TICKS(lhs.elapsed()) >= TO_TICKS(rhs.elapsed()); }
+ { return TO_TICKS(lhs.elapsed()) > TO_TICKS(rhs.elapsed()); }
},
{
"matches",
[](const View& lhs, const View& rhs)
- { return lhs.matches() >= rhs.matches(); }
+ { return lhs.matches() > rhs.matches(); }
},
{
"no_matches",
[](const View& lhs, const View& rhs)
- { return lhs.no_matches() >= rhs.no_matches(); }
+ { return lhs.no_matches() > rhs.no_matches(); }
},
{
"avg_match",
[](const View& lhs, const View& rhs)
- { return lhs.avg_match() >= rhs.avg_match(); }
+ { return lhs.avg_match() > rhs.avg_match(); }
},
{
"avg_no_match",
[](const View& lhs, const View& rhs)
- { return lhs.avg_no_match() >= rhs.avg_no_match(); }
+ { return lhs.avg_no_match() > rhs.avg_no_match(); }
}
};
{
"checks",
[](const View& lhs, const View& rhs)
- { return lhs.checks() >= rhs.checks(); }
+ { return lhs.checks() > rhs.checks(); }
},
{
"avg_check",
[](const View& lhs, const View& rhs)
- { return lhs.avg_check() >= rhs.avg_check(); }
+ { return lhs.avg_check() > rhs.avg_check(); }
},
{
"total_time",
[](const View& lhs, const View& rhs)
- { return lhs.elapsed() >= rhs.elapsed(); }
+ { return lhs.elapsed() > rhs.elapsed(); }
}
};
+++ /dev/null
-//--------------------------------------------------------------------------
-// Copyright (C) 2019-2025 Cisco and/or its affiliates. All rights reserved.
-//
-// 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.
-//--------------------------------------------------------------------------
-// stash_events.h author Silviu Minut <sminut@cisco.com>
-
-#ifndef STASH_EVENTS_H
-#define STASH_EVENTS_H
-
-#include "framework/data_bus.h"
-
-using snort::StashItem;
-
-class StashEvent : public snort::DataEvent
-{
-public:
- StashEvent(const StashItem* it = nullptr) : item(it) {}
- const StashItem* get_item() const { return item; }
-private:
- const StashItem* item;
-};
-
-#endif
namespace snort
{
unsigned FlowData::flow_data_id = 0;
-FlowData::FlowData(unsigned, Inspector*) : next(nullptr), prev(nullptr), handler(nullptr), id(0)
+FlowData::FlowData(unsigned, Inspector*) : handler(nullptr), id(0)
{ }
FlowData::~FlowData() = default;
-FlowData* Flow::get_flow_data(uint32_t) const { return nullptr; }
-int Flow::set_flow_data(FlowData*) { return 0; }
+FlowData* FlowDataStore::get(uint32_t) const { return nullptr; }
+void FlowDataStore::set(FlowData*) { }
Flow::~Flow() = default;
+FlowDataStore::~FlowDataStore() = default;
unsigned DataBus::get_id(PubKey const&) { return 0; }
void DataBus::publish(unsigned int, unsigned int, DataEvent&, Flow*) { }
int DetectionEngine::queue_event(unsigned int, unsigned int) { return 0; }
CipFlowData::CipFlowData() : FlowData(inspector_id)
{
- memset(&session, 0, sizeof(session));
cip_stats.sessions++;
cip_stats.concurrent_sessions++;
if (cip_stats.max_concurrent_sessions < cip_stats.concurrent_sessions)
public:
static unsigned inspector_id;
- CipSessionData session;
+ CipSessionData session = {};
};
CipSessionData* get_cip_session_data(const snort::Flow*);
#include "dns.h"
#include <iomanip>
+#include <map>
#include <sstream>
#include <string>
#include "sfip/sf_ip.h"
GtpFlowData::GtpFlowData() : FlowData(inspector_id)
{
- memset(&ropts, 0, sizeof(ropts));
gtp_stats.concurrent_sessions++;
if(gtp_stats.max_concurrent_sessions < gtp_stats.concurrent_sessions)
gtp_stats.max_concurrent_sessions = gtp_stats.concurrent_sessions;
public:
static unsigned inspector_id;
- GTP_Roptions ropts;
+ GTP_Roptions ropts = {};
};
namespace snort
// Publish entire request/response body limited dynamically
int32_t should_publish_body = 0;
if (is_request)
- flow->stash->get(STASH_PUBLISH_REQUEST_BODY, should_publish_body);
+ flow->get_attr(STASH_PUBLISH_REQUEST_BODY, should_publish_body);
else
- flow->stash->get(STASH_PUBLISH_RESPONSE_BODY, should_publish_body);
+ flow->get_attr(STASH_PUBLISH_RESPONSE_BODY, should_publish_body);
if (should_publish_body)
{
{
fprintf(HttpTestManager::get_output_file(),
"Published %" PRId32 " bytes of body. Originated from %s. last: %s\n",
- publish_length, (is_request ? "client" : "server"),
+ publish_length, (is_request ? "client" : "server"),
(last_piece ? "true" : "false"));
fflush(HttpTestManager::get_output_file());
}
// If it is not the last piece of the request, it should be marked as such because of REQUEST_PUBLISH_DEPTH limit:
// if sum of already published octets (publish_octets) and current publishing length (request_publish_length)
- // is greater than the request publish depth.
- auto request_last_piece = last_piece ?
+ // is greater than the request publish depth.
+ auto request_last_piece = last_piece ?
true : (publish_octets + request_publish_length >= REQUEST_PUBLISH_DEPTH);
HttpRequestBodyEvent http_request_body_event(this, request_publish_length, publish_octets, request_last_piece, session_data);
DataBus::publish(DataBus::get_id(http_pub_key), HttpEventIds::HTTP_PUBLISH_LENGTH, http_publish_length_event, flow);
int32_t new_depth = http_publish_length_event.get_publish_length();
+ int32_t should_publish = (int32_t)http_publish_length_event.should_publish_body();
if (is_request)
- flow->stash->store(STASH_PUBLISH_REQUEST_BODY, http_publish_length_event.should_publish_body());
+ flow->set_attr(STASH_PUBLISH_REQUEST_BODY, should_publish);
else
- flow->stash->store(STASH_PUBLISH_RESPONSE_BODY, http_publish_length_event.should_publish_body());
+ flow->set_attr(STASH_PUBLISH_RESPONSE_BODY, should_publish);
if (new_depth > session_data->publish_depth_remaining[source_id])
{
{
SfIp aux_ip;
if (parse_ip_from_uri(aux_ip_str, aux_ip))
- flow->stash->store(aux_ip);
+ flow->set_attr(aux_ip);
}
}
}
{
int32_t should_publish_body = 0;
if (source_id == SRC_CLIENT)
- flow->stash->get(STASH_PUBLISH_REQUEST_BODY, should_publish_body);
+ flow->get_attr(STASH_PUBLISH_REQUEST_BODY, should_publish_body);
else
- flow->stash->get(STASH_PUBLISH_RESPONSE_BODY, should_publish_body);
+ flow->get_attr(STASH_PUBLISH_RESPONSE_BODY, should_publish_body);
if (should_publish_body)
{
{
// Stubs whose sole purpose is to make the test code link
unsigned FlowData::flow_data_id = 0;
-FlowData::FlowData(unsigned, Inspector*) : next(nullptr), prev(nullptr), handler(nullptr), id(0)
+FlowData::FlowData(unsigned, Inspector*) : handler(nullptr), id(0)
{}
FlowData::~FlowData() = default;
+FlowDataStore::~FlowDataStore() = default;
int DetectionEngine::queue_event(unsigned int, unsigned int) { return 0; }
fd_status_t File_Decomp_StopFree(fd_session_t*) { return File_Decomp_OK; }
uint32_t str_to_hash(const uint8_t *, size_t) { return 0; }
-FlowData* Flow::get_flow_data(uint32_t) const { return nullptr; }
-int Flow::set_flow_data(FlowData*) { return 0;}
+FlowData* FlowDataStore::get(unsigned) const { return nullptr; }
+void FlowDataStore::set(FlowData*) { }
Flow::~Flow() = default;
unsigned DataBus::get_id(PubKey const&) { return 0; }
void DataBus::publish(unsigned int, unsigned int, DataEvent&, Flow*) {}
ImapFlowData::ImapFlowData() : FlowData(inspector_id)
{
- memset(&session, 0, sizeof(session));
imapstats.concurrent_sessions++;
if(imapstats.max_concurrent_sessions < imapstats.concurrent_sessions)
imapstats.max_concurrent_sessions = imapstats.concurrent_sessions;
public:
static unsigned inspector_id;
- IMAPData session;
+ IMAPData session = {};
};
#endif
PopFlowData::PopFlowData() : FlowData(inspector_id)
{
- memset(&session, 0, sizeof(session));
popstats.concurrent_sessions++;
if(popstats.max_concurrent_sessions < popstats.concurrent_sessions)
popstats.max_concurrent_sessions = popstats.concurrent_sessions;
public:
static unsigned inspector_id;
- POPData session;
+ POPData session = {};
};
#endif
SipFlowData::SipFlowData() : FlowData(inspector_id)
{
- memset(&session, 0, sizeof(session));
sip_stats.sessions++;
sip_stats.concurrent_sessions++;
if(sip_stats.max_concurrent_sessions < sip_stats.concurrent_sessions)
public:
static unsigned inspector_id;
- SIPData session;
+ SIPData session = {};
};
SIPData* get_sip_session_data(const snort::Flow*);
Packet p;
Flow flow;
p.flow = &flow;
- FlowStash stash;
- p.flow->stash = &stash;
p.context = new IpsContext(1);
SmtpMime mime_ssn(&p, &decode_conf, &log_config);
smtp_normalizing = true;
// Cleanup
delete p.context;
- p.flow->stash = nullptr;
}
TEST_CASE("normalize_data", "[smtp]")
Packet p;
Flow flow;
p.flow =& flow;
- FlowStash stash;
- p.flow->stash = &stash;
p.context = new IpsContext(1);
SmtpMime mime_ssn(&p, &decode_conf, &log_config);
smtp_normalizing = true;
// Cleanup
delete p.context;
- p.flow->stash = nullptr;
}
#endif
: daq_msg(msg), seq_num(seq), expiration(exp), tracker(trk), expired(false)
{ }
-HeldPacketQueue::iter_t HeldPacketQueue::append(DAQ_Msg_h msg, uint32_t seq,
+const HeldPacketQueue::iter_t HeldPacketQueue::append(DAQ_Msg_h msg, uint32_t seq,
TcpStreamTracker& trk)
{
timeval now, expiration;
return --q.end();
}
-void HeldPacketQueue::erase(iter_t it)
+void HeldPacketQueue::erase(const iter_t it)
{
q.erase(it);
}
return expired;
}
- bool has_expired()
+ bool has_expired() const
{ return expired; }
TcpStreamTracker& get_tracker() const { return tracker; }
public:
using list_t = std::list<HeldPacket>;
- using iter_t = list_t::iterator;
+ using iter_t = list_t::const_iterator;
- iter_t append(DAQ_Msg_h msg, uint32_t seq, TcpStreamTracker& trk);
- void erase(iter_t it);
+ const iter_t append(DAQ_Msg_h msg, uint32_t seq, TcpStreamTracker& trk);
+ void erase(const iter_t it);
// Return whether there still are expired packets in the queue.
bool execute(const timeval& cur_time, int max_remove);
bool empty() const
{ return q.empty(); }
+ auto end() const
+ { return q.end(); }
+
// This must be called at reload time only, with now = reload time.
// Return true if, upon exit, there are expired packets in the queue.
bool adjust_expiration(uint32_t new_timeout_ms, const timeval& now);
// Treat sequence number overlap as a retransmission,
// only check right side since left side happens rarely
- tos.seglist.session->flow->call_handlers(tos.tsd->get_pkt(), false);
+ tos.seglist.session->flow->call_handlers(tos.tsd->get_pkt());
if ( tos.overlap < tos.right->length )
{
if ( tos.right->is_retransmit(tos.rdata, tos.rsize,
// Don't need to process a retry packet through stream again,
// just make sure the retransmit handler is called so that
// we do things like update file inspection.
- flow->call_handlers(p, false);
+ flow->call_handlers(p);
return true;
}
bool TcpStateEstablished::fin_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk)
{
trk.update_on_fin_sent(tsd);
- trk.session->flow->call_handlers(tsd.get_pkt(), true);
+ trk.session->flow->call_handlers(tsd.get_pkt(), FlowDataStore::HANDLER_EOF);
trk.set_tcp_state(TcpStreamTracker::TCP_FIN_WAIT1);
return true;
}
}
trk.update_on_fin_sent(tsd);
- trk.session->flow->call_handlers(tsd.get_pkt(), true);
+ trk.session->flow->call_handlers(tsd.get_pkt(), FlowDataStore::HANDLER_EOF);
TcpStreamTracker::TcpState listener_state = tsd.get_listener()->get_tcp_state();
// If one sided has sent a FIN
if ( TcpStreamTracker::TCP_FIN_WAIT1 == listener_state )
bool TcpStateSynSent::fin_sent(TcpSegmentDescriptor& tsd, TcpStreamTracker& trk)
{
trk.update_on_fin_sent(tsd);
- trk.session->flow->call_handlers(tsd.get_pkt(), true);
+ trk.session->flow->call_handlers(tsd.get_pkt(), FlowDataStore::HANDLER_EOF);
trk.session->update_timestamp_tracking(tsd);
if ( trk.session->flow->two_way_traffic() )
{
THREAD_LOCAL HeldPacketQueue* hpq = nullptr;
-const std::list<HeldPacket>::iterator TcpStreamTracker::null_iterator { };
-
const char* tcp_state_names[] =
{
"TCP_LISTEN", "TCP_SYN_SENT", "TCP_SYN_RECV",
};
TcpStreamTracker::TcpStreamTracker(bool client) :
- client_tracker(client), tcp_state(client ? TCP_STATE_NONE : TCP_LISTEN),
- held_packet(null_iterator)
+ client_tracker(client), tcp_state(client ? TCP_STATE_NONE : TCP_LISTEN)
{
flush_policy = STREAM_FLPOLICY_IGNORE;
update_flush_policy(nullptr);
+ if (hpq)
+ held_packet = hpq->end();
}
TcpStreamTracker::~TcpStreamTracker()
fin_seq_set = false;
rst_pkt_sent = false;
order = TcpStreamTracker::IN_SEQUENCE;
- held_packet = null_iterator;
+ if (hpq)
+ held_packet = hpq->end();
+ else
+ held_packet = {};
flush_policy = STREAM_FLPOLICY_IGNORE;
update_flush_policy(nullptr);
return valid_seq;
}
+bool TcpStreamTracker::is_holding_packet() const
+{
+ assert(hpq);
+ return held_packet != hpq->end();
+}
+
bool TcpStreamTracker::set_held_packet(Packet* p)
{
- if ( held_packet != null_iterator )
+ if ( is_holding_packet() )
return false;
held_packet = hpq->append(p->daq_msg, p->ptrs.tcph->seq(), *this);
uint32_t TcpStreamTracker::perform_partial_flush()
{
uint32_t flushed = 0;
- if ( held_packet != null_iterator )
+ if ( is_holding_packet() )
{
Packet* p;
flushed = reassembler->perform_partial_flush(session->flow, p);
bool TcpStreamTracker::is_retransmit_of_held_packet(Packet* cp)
{
- if ( (held_packet == null_iterator) or ( cp->daq_msg == held_packet->get_daq_msg() ) )
+ if ( !is_holding_packet() )
+ return false;
+
+ if ( cp->daq_msg == held_packet->get_daq_msg() )
return false;
uint32_t next_send_seq = cp->ptrs.tcph->seq() + (uint32_t)cp->dsize;
void TcpStreamTracker::finalize_held_packet(Packet* cp)
{
- if ( held_packet != null_iterator )
+ if ( is_holding_packet() )
{
DAQ_Msg_h msg = held_packet->get_daq_msg();
}
hpq->erase(held_packet);
- held_packet = null_iterator;
+ held_packet = hpq->end();
tcpStats.current_packets_held--;
}
void TcpStreamTracker::finalize_held_packet(Flow* flow)
{
- if ( held_packet != null_iterator )
+ if ( is_holding_packet() )
{
DAQ_Msg_h msg = held_packet->get_daq_msg();
}
hpq->erase(held_packet);
- held_packet = null_iterator;
+ held_packet = hpq->end();
tcpStats.current_packets_held--;
}
}
void perform_fin_recv_flush(TcpSegmentDescriptor&);
int32_t kickstart_asymmetric_flow(const TcpSegmentDescriptor& tsd, uint32_t max_queued_bytes);
uint32_t perform_partial_flush();
- bool is_holding_packet() const
- { return held_packet != null_iterator; }
+ bool is_holding_packet() const;
// max_remove < 0 means time out all eligible packets.
// Return whether there are more packets that need to be released.
TcpEvent tcp_event = TCP_MAX_EVENTS;
snort::StreamSplitter* splitter = nullptr;
- static const std::list<HeldPacket>::iterator null_iterator;
- std::list<HeldPacket>::iterator held_packet;
+ std::list<HeldPacket>::const_iterator held_packet;
uint32_t ts_last_packet = 0;
uint32_t ts_last = 0; // last timestamp (for PAWS)
uint32_t fin_final_seq = 0;
static StreamSplitter* next_splitter = nullptr;
Flow::~Flow() = default;
+FlowDataStore::~FlowDataStore() = default;
Packet::Packet(bool) { }
Packet::~Packet() = default;
//stringify the macro
#define sm(code) #code
-struct TestCase
+struct TraceTestCase
{
const char* test;
const char* expected;
TEST_CASE("macros", "[trace]")
{
- TestCase cases[] =
+ TraceTestCase cases[] =
{
{
sx(debug_log(1, test_trace, "my message")),