+16/09/22 - build 211
+
+-- fix hyperscan detection with nocase
+-- fix shutdown sequence
+-- fix --dirty-pig
+-- fix FreeBSD build re appid / service_rpc
+
+16/09/20 - build 210
+
+-- started dce_udp porting
+-- added HA details to stream/* dev_notes
+-- added stream.ip_frag_only to avoid tracking unwanted flows
+-- updated default stream cache sizes to match 2.X
+-- fixed tcp_connector_test for OSX build
+-- fixed binder make files to include binder.h
+-- fixed double counting of ip and udp timeouts and prunes
+-- fixed clearing of SYN - RST flows
+
+16/09/14 - build 209
+
+-- add dce iface fast pattern for tcp
+-- add --enable-tsc-clock to build/use TSC register (on x86)
+-- update latency to use ticks during runtime
+-- tcp stream reassembly tweaks
+-- fix inverted detection_filter logic
+-- fix stream profile stats parents
+-- fix most bogus gap counts
+-- unit test fixes for high availability, hyperscan, and regex
+
16/09/09 - build 208
-- fixed for TCP high availability
endif ( NOT ENABLE_COREFILES )
set ( _LARGEFILE_SOURCE ${ENABLE_LARGE_PCAP} )
+set ( USE_TSC_CLOCK ${ENABLE_TSC_CLOCK} )
if ( ENABLE_LARGE_PCAP )
set ( _FILE_OFFSET_BITS 64 )
option ( ENABLE_COREFILES "Prevent Snort from generating core files" ON )
option ( ENABLE_INTEL_SOFT_CPM "Enable Intel Soft CPM support" OFF )
option ( ENABLE_LARGE_PCAP "Enable support for pcaps larger than 2 GB" OFF )
+option ( ENABLE_TSC_CLOCK "Use timestamp counter register clock (x86 only)" OFF )
# documentation
option ( MAKE_HTML_DOC "Create the HTML documentation" ON )
#cmakedefine _LARGEFILE_SOURCE 1
#cmakedefine _FILE_OFFSET_BITS @_FILE_OFFSET_BITS@
+/* enable ha capable build */
+#cmakedefine USE_TSC_CLOCK 1
/* platforms */
AC_DEFINE(SHELL, [1], [enable shell support])
fi
+AC_ARG_ENABLE(tsc-clock,
+ AS_HELP_STRING([--enable-tsc-clock],[use timestamp counter register clock (x86 only)]),
+ enable_tsc_clock="$enableval", enable_tsc_clock="no")
+
+if test "x$enable_tsc_clock" = "xyes"; then
+ AC_DEFINE(USE_TSC_CLOCK, [1], [enable tsc clock])
+fi
+
AC_ARG_ENABLE(large-pcap,
AS_HELP_STRING([--enable-large-pcap],[enable support for pcaps larger than 2 GB]),
enable_large_pcap="$enableval", enable_large_pcap="no")
--disable-static-codecs do not include codecs in binary
--enable-shell enable command line shell support
--enable-large-pcap enable support for pcaps larger than 2 GB
+ --enable-tsc-clock use timestamp counter register clock (x86 only)
--enable-debug-msgs enable debug printing options (bugreports and
developers only)
--enable-debug enable debugging options (bugreports and developers
--enable-large-pcap)
append_cache_entry ENABLE_LARGE_PCAP BOOL true
;;
+ --enable-tsc-clock)
+ append_cache_entry ENABLE_TSC_CLOCK BOOL true
+ ;;
--disable-large-pcap)
append_cache_entry ENABLE_LARGE_PCAP BOOL false
;;
#include "protocols/packet.h"
#include "protocols/tcp.h"
#include "search_engines/search_tool.h"
-#include "stream/stream_api.h"
+#include "stream/stream.h"
#include "utils/util.h"
#include "utils/util_utf.h"
#include "utils/sfsnprintfappend.h"
HttpSessionData* SetNewHttpSessionData(Packet* p, void*)
{
HttpFlowData* fd = new HttpFlowData;
- p->flow->set_application_data(fd);
+ p->flow->set_flow_data(fd);
return &fd->session;
}
static HttpSessionData* get_session_data(Flow* flow)
{
- HttpFlowData* fd = (HttpFlowData*)flow->get_application_data(
- HttpFlowData::flow_id);
-
+ HttpFlowData* fd = (HttpFlowData*)flow->get_flow_data(HttpFlowData::flow_id);
return fd ? &fd->session : NULL;
}
void HttpInspectRegisterXtraDataFuncs()
{
- xtra_trueip_id = stream.reg_xtra_data_cb(GetHttpTrueIP);
- xtra_uri_id = stream.reg_xtra_data_cb(GetHttpUriData);
- xtra_hname_id = stream.reg_xtra_data_cb(GetHttpHostnameData);
- xtra_gzip_id = stream.reg_xtra_data_cb(GetHttpGzipData);
- xtra_jsnorm_id = stream.reg_xtra_data_cb(GetHttpJSNormData);
+ xtra_trueip_id = Stream::reg_xtra_data_cb(GetHttpTrueIP);
+ xtra_uri_id = Stream::reg_xtra_data_cb(GetHttpUriData);
+ xtra_hname_id = Stream::reg_xtra_data_cb(GetHttpHostnameData);
+ xtra_gzip_id = Stream::reg_xtra_data_cb(GetHttpGzipData);
+ xtra_jsnorm_id = Stream::reg_xtra_data_cb(GetHttpJSNormData);
}
static void PrintFileDecompOpt(HTTPINSPECT_CONF* ServerConf)
/*
** We now set the packet direction
*/
- if (p->flow && stream.is_midstream(p->flow))
+ if (p->flow && Stream::is_midstream(p->flow))
{
SiInput->pdir = HI_SI_NO_MODE;
}
/* for pipelined HTTP requests */
if ( !iCallDetect )
- stream.clear_extra_data(p->flow, p, 0);
+ Stream::clear_extra_data(p->flow, p, 0);
if (hsd->true_ip)
{
if (!(p->packet_flags & PKT_STREAM_INSERT) && !(p->packet_flags & PKT_REBUILT_STREAM))
SetExtraData(p, xtra_trueip_id);
else
- stream.set_extra_data(p->flow, p, xtra_trueip_id);
+ Stream::set_extra_data(p->flow, p, xtra_trueip_id);
}
if (hsd->log_flags & HTTP_LOG_URI)
{
- stream.set_extra_data(p->flow, p, xtra_uri_id);
+ Stream::set_extra_data(p->flow, p, xtra_uri_id);
}
if (hsd->log_flags & HTTP_LOG_HOSTNAME)
{
- stream.set_extra_data(p->flow, p, xtra_hname_id);
+ Stream::set_extra_data(p->flow, p, xtra_hname_id);
}
if (hsd->log_flags & HTTP_LOG_JSNORM_DATA)
#include "detection/detection_util.h"
#include "protocols/packet.h"
-#include "stream/stream_api.h"
#include "utils/util_jsnorm.h"
#include "utils/util_utf.h"
#include "hi_ui_config.h"
#include "hi_ui_config.h"
#include "hi_ad.h"
#include "hi_main.h"
-#include "stream/stream_api.h"
/*
** NAME
#include "main/snort_debug.h"
#include "events/event_queue.h"
#include "protocols/packet.h"
-#include "stream/stream_api.h"
+#include "stream/stream.h"
#include "utils/util.h"
#ifdef DEBUG_MSGS
if ( !flow )
return nullptr;
- HttpSplitter* s = (HttpSplitter*)stream.get_splitter(flow, c2s);
+ HttpSplitter* s = (HttpSplitter*)Stream::get_splitter(flow, c2s);
return s ? &s->state : nullptr;
}
if ( nreq == MAX_PIPELINE )
{
- if ( stream.is_paf_active(ssn, 0) )
+ if ( Stream::is_paf_active(ssn, 0) )
hi_paf_event_pipe();
}
else if ( nreq < MAX_PIPELINE )
#define HI_STREAM_SPLITTER_H
#include "main/snort_types.h"
-#include "stream/stream_api.h"
#include "stream/stream_splitter.h"
bool hi_paf_init(uint32_t cap);
#ifndef HI_UTIL_H
#define HI_UTIL_H
+#include <strings.h>
#include "hi_include.h"
/*
#include "main/snort_debug.h"
#include "decompress/file_decomp.h"
#include "profiler/profiler.h"
-#include "stream/stream_api.h"
#include "file_api/file_api.h"
#include "file_api/file_service.h"
#include "mime/decode_base.h"
dnp3 = { }
dns = { }
gtp_inspect = default_gtp
+http_inspect = { }
imap = { }
smtp = { }
pop = { }
ssl = { }
telnet = { }
--- use http_inspect or new_http_inspect (incomplete)
-http_inspect = { }
---new_http_inspect = { }
-
ftp_server = default_ftp_server
ftp_client = { }
ftp_data = { }
detection
framework
file_api
- time
latency
profiler
+ time
ips_actions
events
hash
detection/libdetection.a \
framework/libframework.a \
file_api/libfile_api.a \
-time/libtime.a \
latency/liblatency.a \
profiler/libprofiler.a \
+time/libtime.a \
actions/libips_actions.a \
events/libevents.a \
hash/libhash.a \
#include "packet_io/active.h"
#include "codecs/ip/checksum.h"
#include "main/thread.h"
-#include "stream/stream_api.h"
#include "codecs/codec_module.h"
#include "protocols/ip.h"
#include "protocols/ipv4_options.h"
#include "protocols/ipv6.h"
#include "codecs/codec_module.h"
#include "framework/codec.h"
-#include "stream/stream_api.h"
#include "main/snort_config.h"
#include "packet_io/active.h"
#include "protocols/protocol_ids.h"
}
if ( sfvar_ip_in(SynToMulticastDstIp, snort.ip_api.get_dst()) )
- {
codec_event(codec, DECODE_SYN_TO_MULTICAST);
- }
+
if ( (tcph->th_flags & TH_RST) )
codec_event(codec, DECODE_TCP_SYN_RST);
#include <CppUTest/CommandLineTestRunner.h>
#include <CppUTest/TestHarness.h>
+#ifdef MACOS
+#define __THROW
+#define __SOCKADDR_ARG struct sockaddr*
+#define __CONST_SOCKADDR_ARG const struct sockaddr*
+#endif
+
extern const BaseApi* tcp_connector;
ConnectorApi* tcpc_api = nullptr;
if ( s_poll_undesirable )
{
- fds[0].revents |= POLLRDHUP;
+ fds[0].revents |= POLLHUP;
return 1;
}
#include "ports/port_object.h"
#include "profiler/profiler_defs.h"
#include "sfip/sf_ipvar.h"
+#include "stream/stream.h"
#include "utils/stats.h"
#define CHECK_SRC_IP 0x01
{
{
PacketLatency::Context pkt_latency_ctx { p };
-
bool inspected = false;
// If the packet has errors, we won't analyze it.
check_tags_flag = 1;
- /* Check for normally closed session */
- stream.check_session_closed(p);
+ // clear closed sessions here after inspection since non-stream
+ // inspectors may depend on flow information
+ // FIXIT-H but this result in double clearing? should normal
+ // clear_session() calls be deleted from stream? this is a
+ // performance hit on short-lived flows
+ Stream::check_flow_closed(p);
/*
** By checking tagging here, we make sure that we log the
DEBUG_WRAP(
DebugFormat(DEBUG_DETECT, "%d%*s%*d 0x%x\n",
- level, indent - offset, option_type_str[node->option_type],
- 54 - indent, node->num_children, node->option_data);
+ level, indent - offset, option_type_str[node->option_type],
+ 54 - indent, node->num_children, node->option_data);
for (i=0; i<node->num_children; i++)
print_option_tree(node->children[i], level+1);
);
}
+
#endif
void* add_detection_option_tree(
auto last_check = state.last_check;
if ( last_check.ts == p->pkth->ts &&
- last_check.packet_number == cur_eval_pkt_count &&
- last_check.rebuild_flag == (p->packet_flags & PKT_REBUILT_STREAM) &&
- !(p->packet_flags & PKT_ALLOW_MULTIPLE_DETECT) )
+ last_check.packet_number == cur_eval_pkt_count &&
+ last_check.rebuild_flag == (p->packet_flags & PKT_REBUILT_STREAM) &&
+ !(p->packet_flags & PKT_ALLOW_MULTIPLE_DETECT) )
{
if ( !last_check.flowbit_failed &&
- !(p->packet_flags & PKT_IP_RULE_2ND) &&
- !(p->proto_bits & (PROTO_BIT__TEREDO|PROTO_BIT__GTP)) )
+ !(p->packet_flags & PKT_IP_RULE_2ND) &&
+ !(p->proto_bits & (PROTO_BIT__TEREDO|PROTO_BIT__GTP)) )
{
return last_check.result;
}
IpsOption* opt = (IpsOption*)node->option_data;
try_again = opt->retry();
- PatternMatchData* pmd = opt->get_pattern();
+ PatternMatchData* pmd = opt->get_pattern(0, RULE_WO_DIR);
if ( pmd and pmd->last_check )
content_last = pmd->last_check + get_instance_id();
switch ( node->option_type )
{
case RULE_OPTION_TYPE_LEAF_NODE:
- // Add the match for this otn to the queue.
+ // Add the match for this otn to the queue.
{
OptTreeNode* otn = (OptTreeNode*)node->option_data;
int16_t app_proto = p->get_application_protocol();
bool f_result = true;
if ( otn->detection_filter )
- f_result = detection_filter_test(otn->detection_filter,
+ f_result = !detection_filter_test(otn->detection_filter,
p->ptrs.ip_api.get_src(), p->ptrs.ip_api.get_dst(),
p->pkth->ts.tv_sec);
if ( content_last )
{
if ( content_last->ts == p->pkth->ts &&
- content_last->packet_number == cur_eval_pkt_count &&
- content_last->rebuild_flag == (p->packet_flags & PKT_REBUILT_STREAM) )
+ content_last->packet_number == cur_eval_pkt_count &&
+ content_last->rebuild_flag == (p->packet_flags & PKT_REBUILT_STREAM) )
{
rval = DETECTION_OPTION_NO_MATCH;
break;
rval = node->evaluate(node->option_data, cursor, p);
break;
-
}
if ( rval == DETECTION_OPTION_NO_MATCH )
state.last_check.result = result;
return result;
}
-
else if ( rval == DETECTION_OPTION_FAILED_BIT )
{
eval_data->flowbit_failed = 1;
state.last_check.result = result;
return 0;
}
-
else if ( rval == DETECTION_OPTION_NO_ALERT )
{
// Cache the current flowbit_noalert flag, and set it
continue;
}
}
-
else if ( child_node->option_type == RULE_OPTION_TYPE_CONTENT )
{
// Check for an unbounded relative search. If this
// failed before, it's going to fail again so don't
// go down this path again
IpsOption* opt = (IpsOption*)node->option_data;
- PatternMatchData* pmd = opt->get_pattern();
+ PatternMatchData* pmd = opt->get_pattern(0, RULE_WO_DIR);
if ( pmd->unbounded() )
{
}
}
}
-
else if ( child_node->option_type == RULE_OPTION_TYPE_LEAF_NODE )
// Leaf node matched, don't eval again
continue;
}
if ( continue_loop &&
- rval == DETECTION_OPTION_MATCH &&
- node->relative_children )
+ rval == DETECTION_OPTION_MATCH &&
+ node->relative_children )
{
continue_loop = try_again;
}
-
else
continue_loop = false;
local_stats.latency_timeouts = timeouts;
local_stats.latency_suspends = suspends;
}
-
else
{
local_stats.elapsed = node_stats.elapsed;
}
}
-
detection_option_tree_root_t* new_root()
{
detection_option_tree_root_t* p = (detection_option_tree_root_t*)
fp_only = !ofl->ips_opt->fp_research();
}
- PatternMatchData* tmp = get_pmd(ofl);
+ // Set rule direction
+ RuleDirection dir = RULE_WO_DIR;
+ if (OtnFlowFromServer(otn))
+ dir = RULE_FROM_SERVER;
+ else if (OtnFlowFromClient(otn))
+ dir = RULE_FROM_CLIENT;
+
+ PatternMatchData* tmp = get_pmd(ofl, otn->proto, dir);
if ( !tmp )
continue;
if ( !ofl->ips_opt )
continue;
- PatternMatchData* pmd = get_pmd(ofl);
+ PatternMatchData* pmd = get_pmd(ofl, 0, RULE_WO_DIR);
if ( !pmd )
continue;
{
static MpseAgent agent =
{
- pmx_create_tree, add_patrn_to_neg_list,
- fpDeletePMX, free_detection_option_root, neg_list_free
+ pmx_create_tree, add_patrn_to_neg_list,
+ fpDeletePMX, free_detection_option_root, neg_list_free
};
pg->mpse[pmd->pm_type] = MpseManager::get_search_engine(
snprintf(buf, sizeof(buf), "%2.02X ", (uint8_t)pattern[i]);
hex += buf;
txt += isprint(pattern[i]) ? pattern[i] : '.';
-
}
printf("fast pattern[%d] = x%s '%s'\n", pattern_length, hex.c_str(), txt.c_str());
#else
#include "events/event_wrapper.h"
#include "packet_io/active.h"
#include "parser/parser.h"
-#include "stream/stream_api.h"
#include "utils/sflsq.h"
#include "utils/util.h"
#include "profiler/profiler.h"
#include "protocols/udp.h"
#include "protocols/icmp4.h"
#include "search_engines/pat_stats.h"
+#include "stream/stream.h"
#include "utils/stats.h"
THREAD_LOCAL ProfileStats rulePerfStats;
THREAD_LOCAL uint64_t rule_eval_pkt_count = 0;
-THREAD_LOCAL OTNX_MATCH_DATA t_omd;
+static THREAD_LOCAL OTNX_MATCH_DATA t_omd;
/* initialize the global OTNX_MATCH_DATA variable */
void otnx_match_data_init(int num_rule_types)
static inline void InitMatchInfo(OTNX_MATCH_DATA* o)
{
- int i = 0;
+ for ( int i = 0; i < o->iMatchInfoArraySize; i++ )
+ o->matchInfo[i].iMatchCount = 0;
- for (i = 0; i < o->iMatchInfoArraySize; i++)
- {
- o->matchInfo[i].iMatchCount = 0;
- o->matchInfo[i].iMatchIndex = 0;
- o->matchInfo[i].iMatchMaxLen = 0;
- }
+ o->have_match = false;
}
// called by fpLogEvent(), which does the filtering etc.
** int - 1 max_events variable hit, 0 successful.
**
*/
-int fpAddMatch(OTNX_MATCH_DATA* omd_local, int pLen, const OptTreeNode* otn)
+int fpAddMatch(OTNX_MATCH_DATA* omd_local, int /*pLen*/, const OptTreeNode* otn)
{
- MATCH_INFO* pmi;
- int evalIndex;
- int i;
RuleTreeNode* rtn = getRuntimeRtnFromOtn(otn);
-
- evalIndex = rtn->listhead->ruleListNode->evalIndex;
+ int evalIndex = rtn->listhead->ruleListNode->evalIndex;
/* bounds check index */
if ( evalIndex >= omd_local->iMatchInfoArraySize )
pc.match_limit++;
return 1;
}
- pmi = &omd_local->matchInfo[evalIndex];
+ MATCH_INFO* pmi = &omd_local->matchInfo[evalIndex];
/*
** If we hit the max number of unique events for any rule type alert,
return 1;
}
- /* Check that we are not storing the same otn again */
- for ( i=0; i< pmi->iMatchCount; i++ )
+ // don't store the same otn again
+ for ( int i=0; i< pmi->iMatchCount; i++ )
{
if ( pmi->MatchArray[ i ] == otn )
- {
- //LogMessage("fpAddMatch: storing the same otn...\n");
return 0;
- }
}
- /*
- ** Add the event to the appropriate list
- */
+ // add the event to the appropriate list
pmi->MatchArray[ pmi->iMatchCount ] = otn;
- /*
- ** This means that we are adding a NC rule
- ** and we only set the index to this rule
- ** if there is no content rules in the
- ** same array.
- */
- if (pLen > 0)
- {
- /*
- ** Event Comparison Function
- ** Here the largest content match is the
- ** priority
- */
- if ( pmi->iMatchMaxLen < pLen )
- {
- pmi->iMatchMaxLen = pLen;
- pmi->iMatchIndex = pmi->iMatchCount;
- }
- }
-
pmi->iMatchCount++;
-
+ omd_local->have_match = true;
return 0;
}
if ( !otn )
return 0;
- return !stream.add_session_alert(
+ return !Stream::add_flow_alert(
p->flow, p, otn->sigInfo.generator, otn->sigInfo.id);
}
{
const SigInfo* si = &otn->sigInfo;
- if (!stream.check_session_alerted(p->flow, p, si->generator, si->id))
+ if (!Stream::check_flow_alerted(p->flow, p, si->generator, si->id))
return 0;
else
return 1;
*/
static inline int fpFinalSelectEvent(OTNX_MATCH_DATA* o, Packet* p)
{
+ if ( !o->have_match )
+ return 0;
+
int i;
int j;
int k;
unsigned size;
int check_ports;
+ bool have_match;
MATCH_INFO* matchInfo;
int iMatchInfoArraySize;
set( FILE_API_INCLUDES
file_api.h
- file_config.h
+ file_config.h
+ file_cache.h
file_flows.h
file_identifier.h
file_lib.h
file_policy.h
+ file_segment.h
file_service.h
)
circular_buffer.h
file_capture.cc
file_capture.h
+ file_cache.cc
+ file_cache.h
file_config.cc
file_enforcer.cc
file_enforcer.h
file_mempool.h
file_module.cc
file_module.h
- file_policy.cc
+ file_policy.cc
+ file_segment.cc
+ file_segment.h
file_service.cc
file_stats.cc
file_stats.h
file_identifier.h \
file_lib.h \
file_policy.h \
+file_segment.h \
file_service.h
libfile_api_a_SOURCES = \
circular_buffer.cc circular_buffer.h \
file_capture.cc file_capture.h \
+file_cache.cc file_cache.h \
file_config.cc \
file_flows.cc \
file_enforcer.cc file_enforcer.h \
file_mempool.cc file_mempool.h \
file_module.cc file_module.h \
file_policy.cc \
+file_segment.cc file_segment.h \
file_service.cc \
file_stats.cc file_stats.h
uint64_t size; /* maximum number of elements */
uint64_t start; /* index of oldest element, reader update only */
uint64_t end; /* index to write new element, writer update only*/
- uint64_t under_run;
- uint64_t over_run;
ElemType* elems; /* vector of elements */
- uint64_t total_write;
- uint64_t total_read;
};
/* This approach adds one byte to end and start pointers */
}
}
-/* Returns number of free elements*/
-uint64_t cbuffer_available(CircularBuffer* cb)
-{
- return (cbuffer_size(cb) - cbuffer_used(cb));
-}
-
/* Returns total number of elements*/
uint64_t cbuffer_size(CircularBuffer* cb)
{
if ( cbuffer_is_full (cb)) /* full, return error */
{
- cb->over_run++;
return CB_FAIL;
}
w = 0;
cb->end = w;
- cb->total_write++;
return CB_SUCCESS;
}
if (cbuffer_is_empty(cb)) /* Empty, return error */
{
- cb->under_run++;
return CB_FAIL;
}
r = 0;
cb->start = r;
- cb->total_read++;
-
- return CB_SUCCESS;
-}
-
-/*
- * Read one element from the buffer and no change on buffer
- *
- * Args:
- * CircularBuffer *: buffer
- * ElemType *elem: the element pointer to be stored
- * Return:
- * CB_FAIL
- * CB_SUCCESS
- */
-int cbuffer_peek(CircularBuffer* cb, ElemType* elem)
-{
- if (cbuffer_is_empty(cb)) /* Empty, return error */
- return CB_FAIL;
-
- *elem = cb->elems[cb->start];
return CB_SUCCESS;
}
-/* Returns total number of reads*/
-uint64_t cbuffer_num_reads(CircularBuffer* cb)
-{
- return (cb->total_read);
-}
-
-/* Returns total number of writes*/
-uint64_t cbuffer_num_writes(CircularBuffer* cb)
-{
- return (cb->total_write);
-}
-
-/* Returns total number of writer overruns*/
-uint64_t cbuffer_num_over_runs(CircularBuffer* cb)
-{
- return (cb->over_run);
-}
-
-/* Returns total number of reader overruns*/
-uint64_t cbuffer_num_under_runs(CircularBuffer* cb)
-{
- return (cb->under_run);
-}
-
// Returns number of elements in use
uint64_t cbuffer_used(CircularBuffer* cb);
-// Returns number of free elements
-uint64_t cbuffer_available(CircularBuffer* cb);
-
// Returns total number of elements
uint64_t cbuffer_size(CircularBuffer* cb);
// Returns CB_SUCCESS or CB_FAIL
int cbuffer_read(CircularBuffer* cb, ElemType* elem);
-// Read one element from the buffer and no change on buffer
-// Returns CB_SUCCESS or CB_FAIL
-int cbuffer_peek(CircularBuffer* cb, ElemType* elem);
-
-uint64_t cbuffer_num_reads(CircularBuffer* cb);
-
-uint64_t cbuffer_num_writes(CircularBuffer* cb);
-
-/* Returns total number of writer overruns*/
-uint64_t cbuffer_num_over_runs(CircularBuffer* cb);
-
-/* Returns total number of reader overruns*/
-uint64_t cbuffer_num_under_runs(CircularBuffer* cb);
-
#endif
// and configurations.
#include <sys/types.h>
+#include <string>
-#include "stream/stream_api.h"
#include "main/snort_types.h"
#define ENABLE_FILE_TYPE_IDENTIFICATION 0x1
enum FileDirection
{
- DIRECTION_UNKNOWN,
FILE_DOWNLOAD,
FILE_UPLOAD
};
return ((position == SNORT_FILE_END) || (position == SNORT_FILE_FULL));
}
-SO_PUBLIC uint64_t get_file_processed_size(Flow* flow);
-FilePosition get_file_position(Packet* pkt);
+SO_PUBLIC uint64_t get_file_processed_size(class Flow* flow);
+FilePosition get_file_position(struct Packet* pkt);
#endif
--- /dev/null
+//--------------------------------------------------------------------------
+// Copyright (C) 2016-2016 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.
+//--------------------------------------------------------------------------
+// file_cache.cc author Hui Cao <huica@cisco.com>
+
+#include "file_cache.h"
+#include "file_service.h"
+
+#include "sfip/sfip_t.h"
+#include "sfip/sf_ip.h"
+#include "time/packet_time.h"
+#include "utils/util.h"
+#include "utils/snort_bounds.h"
+#include "main/snort_config.h"
+
+uint64_t FileCache::num_add_fails = 0;
+
+static int file_cache_free_func(void*, void* data)
+{
+ FileCache::FileNode* node = (FileCache::FileNode*)data;
+ if (node)
+ {
+ delete node->file;
+ node->file = nullptr;
+ }
+ return 0;
+}
+
+FileCache::FileCache()
+{
+ int max_files = snort_conf->file_config.max_files_cached;
+ fileHash = sfxhash_new(max_files, sizeof(FileHashKey), sizeof(FileNode),
+ 0, 1, nullptr, file_cache_free_func, 1);
+ if (!fileHash)
+ FatalError("Failed to create the expected channel hash table.\n");
+ sfxhash_set_max_nodes(fileHash, max_files);
+}
+
+FileCache::~FileCache()
+{
+ if (fileHash)
+ {
+ sfxhash_delete(fileHash);
+ }
+}
+
+FileContext* FileCache::add(const FileHashKey& hashKey)
+{
+ FileNode new_node;
+ /*
+ * use the time that we keep files around
+ * since this info would effectively be invalid
+ * after that anyway because the file that
+ * caused this will be gone.
+ */
+ time_t now = packet_time();
+ new_node.expires = now + timeout;
+ new_node.file = new FileContext;
+
+ std::lock_guard<std::mutex> lock(cache_mutex);
+
+ if (sfxhash_add(fileHash, (void*)&hashKey, &new_node) != SFXHASH_OK)
+ {
+ /* Uh, shouldn't get here...
+ * There is already a node or couldn't alloc space
+ * for key. This means bigger problems, but fail
+ * gracefully.
+ */
+ FileCache::num_add_fails++;
+ delete new_node.file;
+ return nullptr;
+ }
+
+ return new_node.file;
+}
+
+FileContext* FileCache::find(const FileHashKey& hashKey)
+{
+ std::lock_guard<std::mutex> lock(cache_mutex);
+
+ // No hash table, or its empty? Get out of dodge.
+ if ((!fileHash) || (!sfxhash_count(fileHash)))
+ {
+ DebugMessage(DEBUG_FILE, "No expected sessions\n");
+ return nullptr;
+ }
+
+ SFXHASH_NODE* hash_node = sfxhash_find_node(fileHash, &hashKey);
+
+ if (!hash_node)
+ return nullptr;
+
+ FileNode* node = (FileNode*)hash_node->data;
+ if (!node)
+ {
+ sfxhash_free_node(fileHash, hash_node);
+ return nullptr;
+ }
+
+ DebugMessage(DEBUG_FILE, "Found resumed file\n");
+ time_t now = packet_time();
+ if (node->expires && now > node->expires)
+ {
+ DebugMessage(DEBUG_FILE, "File expired\n");
+ sfxhash_free_node(fileHash, hash_node);
+ return nullptr;
+ }
+
+ node->expires = now + timeout;
+ return node->file;
+}
+
--- /dev/null
+//--------------------------------------------------------------------------
+// Copyright (C) 2016-2016 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.
+//--------------------------------------------------------------------------
+
+// file_cache.h author Hui Cao <huica@cisco.com>
+
+#ifndef FILE_CACHE_H
+#define FILE_CACHE_H
+
+#include <mutex>
+
+#include "file_api.h"
+#include "file_lib.h"
+#include "file_config.h"
+
+#include "protocols/packet.h"
+#include "hash/sfxhash.h"
+#include "hash/hashes.h"
+
+class FileCache
+{
+public:
+
+ struct FileHashKey
+ {
+ sfip_t sip;
+ sfip_t dip;
+ uint64_t file_sig;
+ };
+
+ struct FileNode
+ {
+ time_t expires;
+ FileContext* file;
+ };
+
+ FileCache();
+ ~FileCache();
+ FileContext* add(const FileHashKey&);
+ FileContext* find(const FileHashKey&);
+
+ static uint64_t num_add_fails;
+
+private:
+
+ /* The hash table of expected files */
+ SFXHASH* fileHash = nullptr;
+ uint32_t timeout = DEFAULT_FILE_BLOCK_TIMEOUT;
+ std::mutex cache_mutex;
+
+};
+
+#endif
+
#include "main/snort_config.h"
#include "main/snort_types.h"
-bool FileConfig::process_file_magic(FileMagicData &magic)
+bool FileConfig::process_file_magic(FileMagicData& magic)
{
bool negated = false;
std::string str = '"' + magic.content_str + '"';
}
/*The main function for parsing rule option*/
-void FileConfig::process_file_rule(FileMagicRule &rule)
+void FileConfig::process_file_rule(FileMagicRule& rule)
{
fileIdentifier.insert_file_rule(rule);
}
-void FileConfig::process_file_policy_rule(FileRule &rule)
+void FileConfig::process_file_policy_rule(FileRule& rule)
{
filePolicy.insert_file_rule(rule);
}
-FileMagicRule* FileConfig::get_rule_from_id(uint32_t id)
+FileMagicRule* FileConfig::get_rule_from_id(uint32_t id)
{
return fileIdentifier.get_rule_from_id(id);
}
-std::string FileConfig::file_type_name( uint32_t id)
+std::string FileConfig::file_type_name(uint32_t id)
{
if (SNORT_FILE_TYPE_UNKNOWN == id)
return "Unknown file type, done";
{
return snort_conf->file_config.file_type_name(id);
}
+
#define DEFAULT_FILE_CAPTURE_MAX_SIZE 1048576 // 1 MiB
#define DEFAULT_FILE_CAPTURE_MIN_SIZE 0 // 0
#define DEFAULT_FILE_CAPTURE_BLOCK_SIZE 32768 // 32 KiB
+#define DEFAULT_MAX_FILES_CACHED 65536
+
class FileConfig
{
public:
void process_file_policy_rule(FileRule&);
bool process_file_magic(FileMagicData&);
uint32_t find_file_type_id(const uint8_t* buf, int len, uint64_t file_offset, void** context);
- FilePolicy& get_file_policy() {return filePolicy;}
- std::string file_type_name( uint32_t id);
+ FilePolicy& get_file_policy() { return filePolicy; }
+ std::string file_type_name(uint32_t id);
int64_t file_type_depth = DEFAULT_FILE_TYPE_DEPTH;
int64_t file_signature_depth = DEFAULT_FILE_SIGNATURE_DEPTH;
int64_t capture_min_size = DEFAULT_FILE_CAPTURE_MIN_SIZE;
int64_t capture_block_size = DEFAULT_FILE_CAPTURE_BLOCK_SIZE;
int64_t file_depth = 0;
+ int64_t max_files_cached = DEFAULT_MAX_FILES_CACHED;
static int64_t show_data_depth;
static bool trace_type;
return false;
}
-FileVerdict FileEnforcer::cached_verdict_lookup(Flow* flow, FileInfo* file)
+FileVerdict FileEnforcer::cached_verdict_lookup(Flow* flow, FileInfo* file)
{
FileVerdict verdict = FILE_VERDICT_UNKNOWN;
SFXHASH_NODE* hash_node;
class FileEnforcer
{
-
struct FileHashKey
{
sfip_t sip;
sfip_t dip;
size_t file_sig;
- } ;
+ };
struct FileNode
{
#include "file_api.h"
#include "file_stats.h"
#include "file_capture.h"
+#include "file_cache.h"
#include "file_enforcer.h"
#include "file_policy.h"
#include "file_lib.h"
#include "file_config.h"
#include "main/snort_types.h"
-#include "stream/stream_api.h"
#include "packet_io/active.h"
+#include "sfip/sfip_t.h"
+#include "sfip/sf_ip.h"
int64_t FileConfig::show_data_depth = DEFAULT_FILE_SHOW_DATA_DEPTH;
bool FileConfig::trace_type = false;
FileFlows* FileFlows::get_file_flows(Flow* flow)
{
- FileFlows* fd = (FileFlows*) flow->get_application_data(FileFlows::flow_id);
+ FileFlows* fd = (FileFlows*)flow->get_flow_data(FileFlows::flow_id);
if (fd)
return fd;
if (FileService::is_file_service_enabled())
{
fd = new FileFlows(flow);
- flow->set_application_data(fd);
+ flow->set_flow_data(fd);
}
return fd;
current_context = ctx;
}
+FileContext* FileFlows::get_current_file_context()
+{
+ if (current_file_id)
+ {
+ return get_file_context(current_file_id, false);
+ }
+ return current_context;
+}
+
uint32_t FileFlows::get_new_file_instance()
{
return max_file_id++;
delete(main_context);
}
-void FileFlows::init_file_context(FileDirection direction, FileContext* context)
-{
- FilePolicy& inspect = FileService::get_inspect();
- inspect.policy_check(flow, context);
- context->set_file_direction(direction);
-}
-
FileContext* FileFlows::find_main_file_context(FilePosition pos, FileDirection dir, size_t index)
{
/* Attempt to get a previously allocated context. */
if (context)
{
- if ((pos == SNORT_FILE_MIDDLE) or (pos == SNORT_FILE_END))
+ if ((pos == SNORT_FILE_MIDDLE)or (pos == SNORT_FILE_END))
return context;
else
delete context;
}
context = new FileContext;
- file_stats.files_total++;
main_context = context;
- init_file_context(dir, context);
+ context->check_policy(flow, dir);
if (!index)
- context->set_file_id(max_file_id++);
+ context->set_file_id(get_new_file_instance());
else
context->set_file_id(index);
return context;
}
-void FileFlows::finish_signature_lookup(FileContext* context)
+FileContext* FileFlows::get_file_context(uint64_t file_id, bool to_create)
{
- if (context->get_file_sig_sha256())
- {
- //Check file type based on file policy
- FilePolicy& inspect = FileService::get_inspect();
- inspect.signature_lookup(flow, context);
- log_file_event(context, flow);
- context->config_file_signature(false);
- file_stats.signatures_processed[context->get_file_type()][context->get_file_direction()]++;
- }
+ // search for file based on id to support multiple files
+ FileCache* file_cache = FileService::get_file_cache();
+ assert(file_cache);
+
+ FileCache::FileHashKey key;
+ sfip_copy(key.dip, &(flow->client_ip));
+ sfip_copy(key.sip, &(flow->server_ip));
+ key.file_sig = file_id;
+
+ FileContext* context = file_cache->find(key);
+
+ if (!context && to_create)
+ context = file_cache->add(key);
+
+ current_file_id = file_id;
+ return context;
}
-/*
+/* This function is used to process file that is sent in pieces
+ *
* Return:
* true: continue processing/log/block this file
* false: ignore this file
*/
-bool FileFlows::file_process(FileContext* context, const uint8_t* file_data,
- int data_size, FilePosition position)
+bool FileFlows::file_process(uint64_t file_id, const uint8_t* file_data,
+ int data_size, uint64_t offset, FileDirection dir)
{
- if ( FileConfig::trace_stream )
- {
- FileContext::print_file_data(stdout, file_data, data_size,
- snort_conf->file_config.show_data_depth);
- }
+ int ret = 0;
- if (!context)
- return false;
+ int64_t file_depth = FileService::get_max_file_depth();
- set_current_file_context(context);
- file_stats.file_data_total += data_size;
-
- if ((!context->is_file_type_enabled()) and (!context->is_file_signature_enabled()))
+ if ((file_depth < 0)or (offset > (uint64_t)file_depth))
{
- context->update_file_size(data_size, position);
- return false;
+ return 0;
}
- context->set_file_config(&(snort_conf->file_config));
-
- if((FileService::get_file_enforcer()->cached_verdict_lookup(flow, context)
- != FILE_VERDICT_UNKNOWN))
- return true;
-
- /*file type id*/
- if (context->is_file_type_enabled())
- {
- context->process_file_type(file_data, data_size, position);
+ FileContext* context = get_file_context(file_id, true);
- /*Don't care unknown file type*/
- if (context->get_file_type()== SNORT_FILE_TYPE_UNKNOWN)
- {
- context->config_file_type(false);
- context->config_file_signature(false);
- context->update_file_size(data_size, position);
- context->stop_file_capture();
- return false;
- }
+ if (!context)
+ return 0;
- if (context->get_file_type() != SNORT_FILE_TYPE_CONTINUE)
- {
- context->config_file_type(false);
- file_stats.files_processed[context->get_file_type()][context->get_file_direction()]++;
- //Check file type based on file policy
- FilePolicy& inspect = FileService::get_inspect();
- inspect.type_lookup(flow, context);
- log_file_event(context, flow);
- }
- }
+ context->check_policy(flow, dir);
+ context->set_file_id(file_id);
- /* file signature calculation */
- if (context->is_file_signature_enabled())
+ if (context->verdict != FILE_VERDICT_UNKNOWN)
{
- context->process_file_signature_sha256(file_data, data_size, position);
-
- file_stats.data_processed[context->get_file_type()][context->get_file_direction()]
- += data_size;
+ /*A new file session, but policy might be different*/
+ context->check_policy(flow, dir);
- context->update_file_size(data_size, position);
-
- if ( FileConfig::trace_signature )
- context->print_file_sha256(std::cout);
-
- /*Fails to capture, when out of memory or size limit, need lookup*/
- if (context->is_file_capture_enabled())
+ if ((context->get_file_sig_sha256())
+ || !context->is_file_signature_enabled())
{
- context->process_file_capture(file_data, data_size, position);
+ /* Just check file type and signature */
+ FilePosition position = SNORT_FILE_FULL;
+ ret = context->process(flow, file_data, data_size, position);
+ return ret;
}
-
- finish_signature_lookup(context);
- }
- else
- {
- context->update_file_size(data_size, position);
}
- return true;
+ return context->process(flow, file_data, data_size, offset);
}
/*
FilePosition position, bool upload, size_t file_index)
{
FileContext* context;
- FileDirection direction = upload ? FILE_UPLOAD:FILE_DOWNLOAD;
+ FileDirection direction = upload ? FILE_UPLOAD : FILE_DOWNLOAD;
/* if both disabled, return immediately*/
if (!FileService::is_file_service_enabled())
return false;
context = find_main_file_context(position, direction, file_index);
- return file_process(context, file_data, data_size, position);
+ set_current_file_context(context);
+
+ return context->process(flow, file_data, data_size, position);
}
void FileFlows::set_file_name(const uint8_t* fname, uint32_t name_size)
if ( !context )
return;
- if ( !context->get_file_name().length() )
+ if ( !context->is_file_name_set() )
{
if (fname and name_size)
context->set_file_name((const char*)fname, name_size);
- else
- context->set_file_name(".", 1);
-
- log_file_event(context, flow);
- }
-
- if ( FileConfig::trace_type )
- context->print(std::cout);
-}
-void FileFlows::log_file_event(FileContext* context, Flow* flow)
-{
- if ( context->get_file_name().length() )
- {
- switch (context->verdict)
- {
- case FILE_VERDICT_LOG:
- // Log file event through data bus
- get_data_bus().publish("file_event", (const uint8_t*)"LOG", 3, flow);
- break;
-
- case FILE_VERDICT_BLOCK:
- // can't block session inside a session
- get_data_bus().publish( "file_event", (const uint8_t*)"BLOCK", 5, flow);
- break;
-
- case FILE_VERDICT_REJECT:
- get_data_bus().publish( "file_event", (const uint8_t*)"RESET", 5, flow);
- break;
- default:
- break;
- }
+ context->log_file_event(flow);
}
}
return position;
}
-
{
public:
- FileFlows(Flow* f) : FlowData(flow_id), flow(f) {}
+ FileFlows(Flow* f) : FlowData(flow_id), flow(f) { }
~FileFlows();
static void init()
{ flow_id = FlowData::get_flow_id(); }
// Factory method to get file flows
static FileFlows* get_file_flows(Flow*);
- FileContext* get_current_file_context() {return current_context; }
+ FileContext* get_current_file_context();
+
void set_current_file_context(FileContext*);
+ // Get file context based on file id, create it if not existed
+ FileContext* get_file_context(uint64_t file_id, bool to_create);
+
uint32_t get_new_file_instance();
void set_file_name(const uint8_t* fname, uint32_t name_size);
bool upload, size_t file_index = 0);
// This is used for each file context. Support multiple files per session
- bool file_process(FileContext*, const uint8_t* file_data, int data_size, FilePosition);
+ bool file_process(uint64_t file_id, const uint8_t* file_data,
+ int data_size, uint64_t offset, FileDirection);
//void handle_retransmit(Packet*) override;
static unsigned flow_id;
private:
void save_to_pending_context();
- void finish_signature_lookup(FileContext*);
void init_file_context(FileDirection, FileContext*);
FileContext* find_main_file_context(FilePosition, FileDirection, size_t id = 0);
- void log_file_event(FileContext*, Flow*);
FileContext* main_context = nullptr;
FileContext* pending_context = nullptr;
FileContext* current_context = nullptr;
uint32_t max_file_id = 0;
+ uint64_t current_file_id = 0;
Flow* flow = nullptr;
};
#endif
#include "catch/catch.hpp"
#endif
-typedef struct _IdentifierSharedNode
+struct MergeNode
{
IdentifierNode* shared_node; /*the node that is shared*/
IdentifierNode* append_node; /*the node that is added*/
-} IdentifierSharedNode;
+} ;
void FileMagicData::clear()
{
void FileIdentifier::init_merge_hash()
{
- identifier_merge_hash = sfghash_new(1000, sizeof(IdentifierSharedNode), 0, NULL);
- if (identifier_merge_hash == NULL)
+ identifier_merge_hash = sfghash_new(1000, sizeof(MergeNode), 0, nullptr);
+ if (identifier_merge_hash == nullptr)
{
FatalError("%s(%d) Could not create identifier merge hash.\n",
__FILE__, __LINE__);
FileIdentifier::~FileIdentifier()
{
/*Release memory used for identifiers*/
- for (IDMemoryBlocks::iterator idMem = idMemoryBlocks.begin();
- idMem != idMemoryBlocks.end(); idMem++)
+ for (auto mem_block:id_memory_blocks)
{
- snort_free(idMem->mem);
+ snort_free(mem_block);
}
- if (identifier_merge_hash != NULL)
+ if (identifier_merge_hash != nullptr)
{
sfghash_delete(identifier_merge_hash);
}
void* FileIdentifier::calloc_mem(size_t size)
{
- void* ret;
- IDMemoryBlock memblock;
- ret = snort_calloc(size);
+ void* ret = snort_calloc(size);
memory_used += size;
/*For memory management*/
- memblock.mem = ret;
- idMemoryBlocks.push_back(memblock);
+ id_memory_blocks.push_back(ret);
return ret;
}
if (start->state == ID_NODE_USED)
start->state = ID_NODE_SHARED;
else
- start->state = ID_NODE_USED;
+ start->state = ID_NODE_USED;
for (i = 0; i < MAX_BRANCH; i++)
- set_node_state_shared(start->next[i]);
+ set_node_state_shared(start->next[i]);
}
/*Clone a trie*/
int index;
IdentifierNode* node;
if (!start)
- return NULL;
+ return nullptr;
node = (IdentifierNode*)calloc_mem(sizeof(*node));
IdentifierNode* FileIdentifier::create_trie_from_magic(FileMagicRule& rule, uint32_t type_id)
{
IdentifierNode* current;
- IdentifierNode* root = NULL;
+ IdentifierNode* root = nullptr;
if (!rule.file_magics.size() || !type_id)
- return NULL;
+ return nullptr;
/* Content magics are sorted based on offset, this
* will help compile the file magic trio
current->state = ID_NODE_NEW;
root = current;
- for(FileMagics::iterator magic = rule.file_magics.begin();
- magic !=rule.file_magics.end(); magic++)
+ for (auto magic:rule.file_magics)
{
unsigned int i;
- current->offset = magic->offset;
- for (i = 0; i < magic->content.size(); i++)
+ current->offset = magic.offset;
+ for (i = 0; i < magic.content.size(); i++)
{
IdentifierNode* node = (IdentifierNode*)calloc_mem(sizeof(*node));
- uint8_t index = magic->content[i];
- node->offset = magic->offset + i + 1;
+ uint8_t index = magic.content[i];
+ node->offset = magic.offset + i + 1;
node->state = ID_NODE_NEW;
current->next[index] = node;
current = node;
IdentifierNode* append)
{
IdentifierNode* next = (*next_ptr);
- IdentifierSharedNode sharedIdentifier;
+ MergeNode merge_node;
IdentifierNode* result;
if (!append || (next == append))
return false;
- sharedIdentifier.append_node = append;
- sharedIdentifier.shared_node = next;
+ merge_node.append_node = append;
+ merge_node.shared_node = next;
if (!next)
{
/*reuse the append*/
set_node_state_shared(append);
return false;
}
- else if ((result = (IdentifierNode*)sfghash_find(identifier_merge_hash, &sharedIdentifier)))
+ else if ((result = (IdentifierNode*)sfghash_find(identifier_merge_hash, &merge_node)))
{
/*the same pointer has been processed, reuse it*/
*next_ptr = result;
/*offset could have gap when non 0 offset is allowed */
int index;
IdentifierNode* node = (IdentifierNode*)calloc_mem(sizeof(*node));
- sharedIdentifier.shared_node = next;
- sharedIdentifier.append_node = append;
+ merge_node.shared_node = next;
+ merge_node.append_node = append;
node->offset = append->offset;
for (index = 0; index < MAX_BRANCH; index++)
set_node_state_shared(next);
next = node;
- sfghash_add(identifier_merge_hash, &sharedIdentifier, next);
+ sfghash_add(identifier_merge_hash, &merge_node, next);
}
else if (next->state == ID_NODE_SHARED)
{
/*shared, need to clone one*/
IdentifierNode* current_next = next;
- sharedIdentifier.shared_node = current_next;
- sharedIdentifier.append_node = append;
+ merge_node.shared_node = current_next;
+ merge_node.append_node = append;
next = clone_node(current_next);
set_node_state_shared(next);
- sfghash_add(identifier_merge_hash, &sharedIdentifier, next);
+ sfghash_add(identifier_merge_hash, &merge_node, next);
}
*next_ptr = next;
if (!identifier_root)
{
- identifier_root = (IdentifierNode *)calloc_mem(sizeof(*identifier_root));
+ identifier_root = (IdentifierNode*)calloc_mem(sizeof(*identifier_root));
init_merge_hash();
}
return;
}
-
file_magic_rules[rule.id] = rule;
node = create_trie_from_magic(rule, rule.id);
}
/*Either end of magics or passed the current offset*/
- *context = NULL;
+ *context = nullptr;
if ( file_type_id == SNORT_FILE_TYPE_CONTINUE )
file_type_id = SNORT_FILE_TYPE_UNKNOWN;
return file_type_id;
}
-FileMagicRule* FileIdentifier::get_rule_from_id(uint32_t id)
+FileMagicRule* FileIdentifier::get_rule_from_id(uint32_t id)
{
if ((id < FILE_ID_MAX) && (file_magic_rules[id].id > 0))
{
return (&(file_magic_rules[id]));
}
else
- return NULL;
+ return nullptr;
}
//--------------------------------------------------------------------------
const char* data = "PDF";
- void *context = NULL;
-
- CHECK(rc.find_file_type_id((const uint8_t *)data, strlen(data), 0, &context) == 1);
+ void* context = nullptr;
+ CHECK(rc.find_file_type_id((const uint8_t*)data, strlen(data), 0, &context) == 1);
}
TEST_CASE ("FileIdRuleUnknow", "[FileMagic]")
const char* data = "DDF";
- void *context = NULL;
+ void* context = nullptr;
- CHECK(rc.find_file_type_id((const uint8_t *)data, strlen(data), 0, &context) ==
+ CHECK(rc.find_file_type_id((const uint8_t*)data, strlen(data), 0, &context) ==
SNORT_FILE_TYPE_UNKNOWN);
-
}
TEST_CASE ("FileIdRuleEXE", "[FileMagic]")
rc.insert_file_rule(rule);
const char* data = "PDFooo";
- void *context = NULL;
+ void* context = nullptr;
- CHECK(rc.find_file_type_id((const uint8_t *)data, strlen(data), 0, &context) == 1);
+ CHECK(rc.find_file_type_id((const uint8_t*)data, strlen(data), 0, &context) == 1);
}
TEST_CASE ("FileIdRulePDFEXE", "[FileMagic]")
rc.insert_file_rule(rule);
const char* data = "PDFEXE";
- void *context = NULL;
+ void* context = nullptr;
// Match the last one
- CHECK(rc.find_file_type_id((const uint8_t *)data, strlen(data), 0, &context) == 3);
+ CHECK(rc.find_file_type_id((const uint8_t*)data, strlen(data), 0, &context) == 3);
}
TEST_CASE ("FileIdRuleFirst", "[FileMagic]")
rc.insert_file_rule(rule);
const char* data = "PDF";
- void *context = NULL;
+ void* context = nullptr;
- CHECK(rc.find_file_type_id((const uint8_t *)data, strlen(data), 0, &context) == 1);
+ CHECK(rc.find_file_type_id((const uint8_t*)data, strlen(data), 0, &context) == 1);
}
#endif
+
ID_NODE_NEW,
ID_NODE_USED,
ID_NODE_SHARED
-} ;
+};
class FileMagicData
{
std::string content_str; /* magic content to match*/
std::string content; /* magic content raw values*/
uint32_t offset; /* pattern search start offset */
- bool operator < (const FileMagicData& magic) const
+ bool operator <(const FileMagicData& magic) const
{
return (offset < magic.offset);
}
FileMagics file_magics;
};
-typedef struct _IdentifierNode
+struct IdentifierNode
{
uint32_t type_id; /* magic content to match*/
IdNodeState state;
uint32_t offset; /* offset from file start */
- struct _IdentifierNode* next[MAX_BRANCH]; /* pointer to an array of 256 identifiers pointers*/
-} IdentifierNode;
-
-struct IDMemoryBlock
-{
- void *mem;
+ struct IdentifierNode* next[MAX_BRANCH]; /* pointer to an array of 256 identifiers pointers*/
};
-typedef std::list<IDMemoryBlock > IDMemoryBlocks;
+typedef std::list<void* > IDMemoryBlocks;
class FileIdentifier
{
-public:
- ~FileIdentifier();
- uint32_t memory_usage() {return memory_used;}
+public: ~FileIdentifier();
+ uint32_t memory_usage() { return memory_used; }
void insert_file_rule(FileMagicRule& rule);
uint32_t find_file_type_id(const uint8_t* buf, int len, uint64_t offset, void** context);
FileMagicRule* get_rule_from_id(uint32_t);
+
private:
void init_merge_hash();
void* calloc_mem(size_t size);
uint32_t memory_used = 0; /*Track memory usage*/
SFGHASH* identifier_merge_hash = nullptr;
FileMagicRule file_magic_rules[FILE_ID_MAX + 1];
- IDMemoryBlocks idMemoryBlocks;
+ IDMemoryBlocks id_memory_blocks;
};
#endif
#include <iostream>
#include <iomanip>
-#include "file_identifier.h"
+#include "file_capture.h"
#include "file_config.h"
+#include "file_enforcer.h"
+#include "file_identifier.h"
+#include "file_service.h"
+#include "file_segment.h"
+#include "file_stats.h"
+
#include "hash/hashes.h"
#include "utils/util.h"
-#include "file_api/file_capture.h"
+#include "main/snort_config.h"
+#include "framework/data_bus.h"
FileInfo::~FileInfo ()
{
- if(sha256)
+ if (sha256)
delete[] sha256;
}
if (other.sha256)
{
sha256 = new uint8_t[SHA256_HASH_SIZE];
- memcpy( (char *)sha256, (const char *)other.sha256, SHA256_HASH_SIZE);
+ memcpy( (char*)sha256, (const char*)other.sha256, SHA256_HASH_SIZE);
}
file_size = other.file_size;
FileInfo& FileInfo::operator=(const FileInfo& other)
{
// check for self-assignment
- if(&other == this)
+ if (&other == this)
return *this;
copy(other);
/*File properties*/
-void FileInfo::set_file_name (const char *name, uint32_t name_size)
+void FileInfo::set_file_name(const char* name, uint32_t name_size)
{
if (name and name_size)
{
file_name.assign(name, name_size);
}
+
+ file_name_set = true;
}
std::string& FileInfo::get_file_name()
return file_id;
}
-
void FileInfo::set_file_direction(FileDirection dir)
{
direction = dir;
FileDirection FileInfo::get_file_direction() const
{
- return (direction);
+ return direction;
}
void FileInfo::set_file_sig_sha256(uint8_t* signature)
return (sha256);
}
-std::string FileInfo::sha_to_string (const uint8_t *sha256)
+std::string FileInfo::sha_to_string(const uint8_t* sha256)
{
uint8_t conv[] = "0123456789ABCDEF";
- const uint8_t *index;
- const uint8_t *end;
+ const uint8_t* index;
+ const uint8_t* end;
std::string sha_out;
index = sha256;
end = index + SHA256_HASH_SIZE;
- while(index < end)
+ while (index < end)
{
sha_out.push_back(conv[((*index & 0xFF)>>4)]);
sha_out.push_back(conv[((*index & 0xFF)&0x0F)]);
{
file_type_context = nullptr;
file_signature_context = nullptr;
- file_config = nullptr;
+ file_config = &(snort_conf->file_config);
file_capture = nullptr;
+ file_segments = nullptr;
}
FileContext::~FileContext ()
{
if (file_signature_context)
snort_free(file_signature_context);
- if(file_capture)
+ if (file_capture)
stop_file_capture();
+ if (file_segments)
+ delete file_segments;
}
inline int FileContext::get_data_size_from_depth_limit(FileProcessType type, int
}
/* stop file type identification */
-inline void FileContext::finalize_file_type ()
+inline void FileContext::finalize_file_type()
{
if (SNORT_FILE_TYPE_CONTINUE == file_type_id)
file_type_id = SNORT_FILE_TYPE_UNKNOWN;
file_type_context = nullptr;
}
+
+void FileContext::log_file_event(Flow* flow)
+{
+ // wait for file name is set to log file event
+ if ( is_file_name_set() )
+ {
+ switch (verdict)
+ {
+ case FILE_VERDICT_LOG:
+ // Log file event through data bus
+ get_data_bus().publish("file_event", (const uint8_t*)"LOG", 3, flow);
+ break;
+
+ case FILE_VERDICT_BLOCK:
+ // can't block session inside a session
+ get_data_bus().publish("file_event", (const uint8_t*)"BLOCK", 5, flow);
+ break;
+
+ case FILE_VERDICT_REJECT:
+ get_data_bus().publish("file_event", (const uint8_t*)"RESET", 5, flow);
+ break;
+ default:
+ break;
+ }
+ if ( FileConfig::trace_type )
+ print(std::cout);
+ }
+}
+
+void FileContext::finish_signature_lookup(Flow* flow)
+{
+ if (get_file_sig_sha256())
+ {
+ //Check file type based on file policy
+ FilePolicy& inspect = FileService::get_inspect();
+ inspect.signature_lookup(flow, this);
+ log_file_event(flow);
+ config_file_signature(false);
+ file_stats.signatures_processed[get_file_type()][get_file_direction()]++;
+ }
+}
+
+void FileContext::check_policy(Flow* flow, FileDirection dir)
+{
+ file_stats.files_total++;
+ set_file_direction(dir);
+ FilePolicy& inspect = FileService::get_inspect();
+ inspect.policy_check(flow, this);
+}
+
+/*
+ * Return:
+ * true: continue processing/log/block this file
+ * false: ignore this file
+ */
+bool FileContext::process(Flow* flow, const uint8_t* file_data, int data_size,
+ FilePosition position)
+{
+ if ( FileConfig::trace_stream )
+ {
+ FileContext::print_file_data(stdout, file_data, data_size,
+ snort_conf->file_config.show_data_depth);
+ }
+
+ //set_current_file_context(context);
+ file_stats.file_data_total += data_size;
+
+ if ((!is_file_type_enabled())and (!is_file_signature_enabled()))
+ {
+ update_file_size(data_size, position);
+ return false;
+ }
+
+ if ((FileService::get_file_enforcer()->cached_verdict_lookup(flow, this)
+ != FILE_VERDICT_UNKNOWN))
+ return true;
+
+ /*file type id*/
+ if (is_file_type_enabled())
+ {
+ process_file_type(file_data, data_size, position);
+
+ /*Don't care unknown file type*/
+ if (get_file_type()== SNORT_FILE_TYPE_UNKNOWN)
+ {
+ config_file_type(false);
+ config_file_signature(false);
+ update_file_size(data_size, position);
+ stop_file_capture();
+ return false;
+ }
+
+ if (get_file_type() != SNORT_FILE_TYPE_CONTINUE)
+ {
+ config_file_type(false);
+ file_stats.files_processed[get_file_type()][get_file_direction()]++;
+ //Check file type based on file policy
+ FilePolicy& inspect = FileService::get_inspect();
+ inspect.type_lookup(flow, this);
+ log_file_event(flow);
+ }
+ }
+
+ /* file signature calculation */
+ if (is_file_signature_enabled())
+ {
+ process_file_signature_sha256(file_data, data_size, position);
+
+ file_stats.data_processed[get_file_type()][get_file_direction()]
+ += data_size;
+
+ update_file_size(data_size, position);
+
+ if ( FileConfig::trace_signature )
+ print_file_sha256(std::cout);
+
+ /*Fails to capture, when out of memory or size limit, need lookup*/
+ if (is_file_capture_enabled())
+ {
+ process_file_capture(file_data, data_size, position);
+ }
+
+ finish_signature_lookup(flow);
+ }
+ else
+ {
+ update_file_size(data_size, position);
+ }
+
+ return true;
+}
+
+bool FileContext::process(Flow* flow, const uint8_t* file_data, int data_size,
+ uint64_t offset)
+{
+ if (!file_segments)
+ file_segments = new FileSegments(this);
+ return file_segments->process(flow, file_data, data_size, offset);
+}
+
/*
* Main File type processing function
* We use file type context to decide file type across packets
return processed_bytes;
}
-
-void FileContext::set_file_config(FileConfig* config)
-{
- file_config = config;
-}
-
-FileConfig* FileContext::get_file_config()
-{
- return file_config;
-}
-
void FileContext::print_file_data(FILE* fp, const uint8_t* data, int len, int max_depth)
{
char str[18];
*/
void FileContext::print_file_sha256(std::ostream& log)
{
-
unsigned char* hash = sha256;
if (!sha256)
log.flags(f);
}
-void FileContext::print( std::ostream& log)
+void FileContext::print(std::ostream& log)
{
log << "File name: " << file_name << std::endl;
log << "File type: " << file_config->file_type_name(file_type_id)
return get_ids_from_group(conf, group, ids, count);
}
**/
+
class FileCapture;
class FileConfig;
+class FileSegments;
+class Flow;
class SO_PUBLIC FileInfo
{
public:
virtual ~FileInfo();
- FileInfo(){}
+ FileInfo() { }
FileInfo(const FileInfo& other);
FileInfo& operator=(const FileInfo& other);
uint32_t get_file_type() const;
void set_file_name(const char* file_name, uint32_t name_size);
std::string& get_file_name();
+ // Whether file name has been set (could be empty file name)
+ bool is_file_name_set() const { return file_name_set; }
+
void set_file_size(uint64_t size);
uint64_t get_file_size() const;
void set_file_direction(FileDirection dir);
FileDirection get_file_direction() const;
void set_file_sig_sha256(uint8_t* signature);
uint8_t* get_file_sig_sha256() const;
- std::string sha_to_string(const uint8_t *sha256);
+ std::string sha_to_string(const uint8_t* sha256);
void set_file_id(size_t index);
size_t get_file_id() const;
FileVerdict verdict = FILE_VERDICT_UNKNOWN;
protected:
std::string file_name;
+ bool file_name_set = false;
uint64_t file_size = 0;
- FileDirection direction = DIRECTION_UNKNOWN;
+ FileDirection direction = FILE_DOWNLOAD;
uint32_t file_type_id = SNORT_FILE_TYPE_CONTINUE;
uint8_t* sha256 = nullptr;
size_t file_id = 0;
void copy(const FileInfo& other);
};
-class SO_PUBLIC FileContext: public FileInfo
+class SO_PUBLIC FileContext : public FileInfo
{
public:
FileContext();
~FileContext();
+ void check_policy(Flow*, FileDirection);
+
// main processing functions
+
+ // Return:
+ // true: continue processing/log/block this file
+ // false: ignore this file
+ bool process(Flow*, const uint8_t* file_data, int data_size, FilePosition);
+ bool process(Flow*, const uint8_t* file_data, int data_size, uint64_t offset);
void process_file_type(const uint8_t* file_data, int data_size, FilePosition position);
void process_file_signature_sha256(const uint8_t* file_data, int data_size, FilePosition pos);
void update_file_size(int data_size, FilePosition position);
void stop_file_capture();
- FileCaptureState process_file_capture(const uint8_t* file_data, int data_size, FilePosition pos);
+ FileCaptureState process_file_capture(const uint8_t* file_data, int data_size,
+ FilePosition pos);
+ void log_file_event(Flow*);
// Preserve the file in memory until it is released
// The file reserved will be returned and it will be detached from file context/session
- FileCaptureState reserve_file(FileCapture* &dest);
+ FileCaptureState reserve_file(FileCapture*& dest);
// Configuration functions
void config_file_type(bool enabled);
//File properties
uint64_t get_processed_bytes();
- void set_file_config(FileConfig* file_config);
- FileConfig* get_file_config();
-
void print_file_sha256(std::ostream&);
static void print_file_data(FILE* fp, const uint8_t* data, int len, int max_depth);
void print(std::ostream&);
void* file_type_context;
void* file_signature_context;
FileConfig* file_config;
- FileCapture *file_capture;
- FileState file_state = {FILE_CAPTURE_SUCCESS, FILE_SIG_PROCESSING};
+ FileCapture* file_capture;
+ FileSegments* file_segments;
+ FileState file_state = { FILE_CAPTURE_SUCCESS, FILE_SIG_PROCESSING };
inline int get_data_size_from_depth_limit(FileProcessType type, int data_size);
- inline void finalize_file_type ();
+ inline void finalize_file_type();
+ inline void finish_signature_lookup(Flow*);
};
#endif
for (size_t i = start; i < name.length(); i++)
{
- if ( name[i] > 0x1F && name[i] < 0x7F)
- { /* printable */
+ if ( name[i] > 0x1F && name[i] < 0x7F) /* printable */
+ {
TextLog_Putc(log, name[i]);
}
- else
- { /* not printable */
+ else /* not printable */
+ {
TextLog_Putc(log, '.');
}
}
TextLog_Puts(log, "\"] ");
}
-void LogHandler::handle(DataEvent& , Flow* f)
+void LogHandler::handle(DataEvent&, Flow* f)
{
if (config.log_sys_time)
{
void FileLog::show(SnortConfig*)
{
LogMessage("%s config:\n", s_name);
- LogMessage(" Log system time: %s\n", config.log_sys_time? "true" : "false");
- LogMessage(" Log packet time: %s\n", config.log_pkt_time? "true" : "false");
+ LogMessage(" Log system time: %s\n", config.log_sys_time ? "true" : "false");
+ LogMessage(" Log packet time: %s\n", config.log_pkt_time ? "true" : "false");
}
//-------------------------------------------------------------------------
static Inspector* fl_ctor(Module* m)
{
- FileLogModule* fl_module = (FileLogModule *)m;
+ FileLogModule* fl_module = (FileLogModule*)m;
return new FileLog(fl_module->config);
}
mod_dtor
},
IT_PASSIVE,
- (uint16_t)PktType::NONE,
+ (uint16_t) PktType::NONE,
nullptr, // buffers
nullptr, // service
nullptr, // pinit
else if ( v.is("capture_block_size") )
fc.capture_block_size = v.get_long();
+ else if ( v.is("max_files_cached") )
+ fc.max_files_cached = v.get_long();
+
else if ( v.is("enable_type") )
{
if ( v.get_bool() )
return true;
}
+
{ "capture_block_size", Parameter::PT_INT, "8:", "32768",
"file capture block size in bytes" },
+ { "max_files_cached", Parameter::PT_INT, "8:", "65536",
+ "maximal number of files cached in memory" },
+
{ "enable_type", Parameter::PT_BOOL, nullptr, "false",
"enable type ID" },
{ nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
};
-
#define file_id_help \
"configure file identification"
capture_enabled = enabled;
}
-void FilePolicy::insert_file_rule(FileRule &rule)
+void FilePolicy::insert_file_rule(FileRule& rule)
{
file_rules.push_back(rule);
while (offset < hex.size())
{
- int buffer = std::stoi( hex.substr(offset, 2), nullptr, 16);
+ int buffer = std::stoi(hex.substr(offset, 2), nullptr, 16);
bytes.push_back(static_cast<unsigned char>(buffer));
offset += 2;
}
emptyRule.use.type_enabled = type_enabled;
emptyRule.use.signature_enabled = signature_enabled;
emptyRule.use.capture_enabled = capture_enabled;
-
}
FileRule& FilePolicy::match_file_rule(Flow*, FileInfo* file)
{
- for(unsigned i = 0; i < file_rules.size(); i++)
+ for (unsigned i = 0; i < file_rules.size(); i++)
{
if (file_rules[i].when.sha256.size())
continue;
// No file type specified in rule or file type is matched
- if ((file_rules[i].when.type_id == 0) or
- (file_rules[i].when.type_id == file->get_file_type()))
+ if ((file_rules[i].when.type_id == 0)or
+ (file_rules[i].when.type_id == file->get_file_type()))
return file_rules[i];
}
// No file type specified in rule or file type is matched
if (file->get_file_sig_sha256())
{
- std::string sha((const char *)file->get_file_sig_sha256(), SHA256_HASH_SIZE);
-
- std::map<std::string, FileVerdict>::iterator it;
+ std::string sha((const char*)file->get_file_sig_sha256(), SHA256_HASH_SIZE);
- return file_shas[sha];
+ auto search = file_shas.find(sha);
+ if (search != file_shas.end())
+ return search->second;
}
return FILE_VERDICT_UNKNOWN;
FileVerdict FilePolicy::type_lookup(Flow* flow, FileContext* file)
{
- type_lookup(flow, (FileInfo *)file);
+ type_lookup(flow, (FileInfo*)file);
FileRule rule = match_file_rule(nullptr, file);
file->config_file_signature(rule.use.signature_enabled);
file->config_file_capture(rule.use.capture_enabled);
return verdict;
}
-FileVerdict FilePolicy::signature_lookup(Flow* flow, FileContext* file )
+FileVerdict FilePolicy::signature_lookup(Flow* flow, FileContext* file)
{
FileRule& rule = match_file_rule(nullptr, file);
if (rule.use.capture_enabled)
{
- FileCapture *captured = nullptr;
+ FileCapture* captured = nullptr;
if (file->reserve_file(captured) == FILE_CAPTURE_SUCCESS)
- {
- captured->store_file_async();
- }
+ captured->store_file_async();
}
- return (signature_lookup(flow, (FileInfo *)file));
+ return (signature_lookup(flow, (FileInfo*)file));
}
#ifndef FILE_POLICY_H
#define FILE_POLICY_H
-#include "file_api.h"
#include <map>
+#include <vector>
+
+#include "file_api.h"
struct FileVerdictWhen
{
FileVerdictUse use;
FileRule();
- ~FileRule() {}
+ ~FileRule() { }
void clear();
};
class FilePolicy
{
-
public:
- FilePolicy() {}
- ~FilePolicy() {}
+ FilePolicy() { }
+ ~FilePolicy() { }
// This is called when a new flow is queried for the first time
// Check & update what file policy is enabled on this flow/file
// This is called after file signature is complete
virtual FileVerdict signature_lookup(Flow* flow, FileInfo* file);
- void insert_file_rule(FileRule &);
+ void insert_file_rule(FileRule&);
void set_file_type(bool enabled);
void set_file_signature(bool enabled);
void set_file_capture(bool enabled);
- bool is_type_id_enabled() {return type_enabled;}
- bool is_signature_enabled() {return signature_enabled;}
- bool is_capture_enabled() {return capture_enabled;}
+ bool is_type_id_enabled() { return type_enabled; }
+ bool is_signature_enabled() { return signature_enabled; }
+ bool is_capture_enabled() { return capture_enabled; }
void load();
private:
};
#endif
+
--- /dev/null
+//--------------------------------------------------------------------------
+// Copyright (C) 2015-2016 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.
+//--------------------------------------------------------------------------
+// file_segment.cc author Hui Cao <huica@cisco.com>
+
+#include "file_segment.h"
+
+#include "log/messages.h"
+#include "file_flows.h"
+#include "file_service.h"
+
+FileSegment::~FileSegment ()
+{
+ if (data)
+ delete data;
+}
+
+FileSegments::FileSegments (FileContext* ctx)
+{
+ head = nullptr;
+ current_offset = 0;
+ context = ctx;
+}
+
+FileSegments::~FileSegments ()
+{
+ clear();
+}
+
+void FileSegments::clear()
+{
+ FileSegment* current_segment = head;
+
+ while (current_segment)
+ {
+ FileSegment* previous_segment = current_segment;
+ current_segment = current_segment->next;
+ delete previous_segment;
+ }
+
+ head = nullptr;
+ current_offset = 0;
+}
+
+// Update the segment list based on new data
+void FileSegments::add(const uint8_t* file_data, uint64_t data_size, uint64_t offset)
+{
+ FileSegment* new_segment = new FileSegment();
+ new_segment->offset = offset;
+ new_segment->data = new std::string((const char*)file_data, data_size);
+
+ if (!head)
+ {
+ head = new_segment;
+ return;
+ }
+
+ FileSegment* current_segment = head;
+ uint64_t start = offset;
+ uint64_t end = offset + data_size;
+ // left points to segment that "next" pointer needs to be updated
+ FileSegment* left = nullptr;
+ FileSegment* previous = nullptr;
+ bool find_left = false;
+ bool is_overlap = false;
+
+ // Find left boundary, left points to segment that needs update
+ while (current_segment)
+ {
+ if (current_segment->offset > start)
+ {
+ find_left = true;
+ left = previous;
+ break;
+ }
+
+ previous = current_segment;
+ current_segment = current_segment->next;
+ }
+
+ // New segment should be at the end of link list
+ if (!find_left)
+ {
+ previous->next = new_segment;
+ }
+ // New segment should be at the start of link list
+ else if (!left)
+ {
+ if (end <= head->offset)
+ {
+ new_segment->next = head;
+ head = new_segment;
+ }
+ else
+ {
+ is_overlap = true;
+ }
+ }
+ else
+ {
+ if ((left->offset + left->data->size() > start) ||
+ (left->next->offset < end))
+ {
+ is_overlap = true;
+ }
+ else
+ {
+ new_segment->next = left->next;
+ left->next = new_segment;
+ }
+ }
+
+ // ignore overlap case
+ if (is_overlap)
+ {
+ delete new_segment;
+ return;
+ }
+}
+
+FilePosition FileSegments::get_file_position(uint64_t data_size, uint64_t file_size)
+{
+ if (current_offset == 0)
+ {
+ if (file_size == data_size)
+ return SNORT_FILE_FULL;
+ else
+ return SNORT_FILE_START;
+ }
+
+ if (file_size <= data_size + current_offset)
+ return SNORT_FILE_END;
+
+ return SNORT_FILE_MIDDLE;
+}
+
+int FileSegments::process_one(Flow* flow, const uint8_t* file_data, int data_size)
+{
+ FilePosition position = get_file_position(data_size, context->get_file_size());
+
+ return context->process(flow, file_data, data_size, position);
+}
+
+int FileSegments::process_all(Flow* flow)
+{
+ int ret = 1;
+
+ FileSegment* current_segment = head;
+ while (current_segment && (current_offset == current_segment->offset))
+ {
+ ret = process_one(flow, (uint8_t* )current_segment->data->data(),
+ current_segment->data->size());
+
+ if (!ret)
+ {
+ clear();
+ break;
+ }
+
+ current_offset += current_segment->data->size();
+ head = current_segment->next;
+ delete(current_segment);
+ current_segment = head;
+ }
+
+ return ret;
+}
+
+/*
+ * Process file segment, do file segment reassemble if the file segment is
+ * out of order.
+ * Return:
+ * 1: continue processing/log/block this file
+ * 0: ignore this file
+ */
+int FileSegments::process(Flow* flow, const uint8_t* file_data, uint64_t data_size,
+ uint64_t offset)
+{
+ int ret = 0;
+
+ if (offset == 0)
+ {
+ current_offset = 0;
+ }
+
+ // Walk through the segments that can be flushed
+ if (current_offset == offset)
+ {
+ ret = process_one(flow, file_data, data_size);
+ current_offset += data_size;
+ if (!ret)
+ {
+ clear();
+ return 0;
+ }
+
+ ret = process_all(flow);
+ }
+ else if ((current_offset < context->get_file_size()) && (current_offset < offset))
+ {
+ add(file_data, data_size, offset);
+ }
+
+ return ret;
+}
+
--- /dev/null
+//--------------------------------------------------------------------------
+// Copyright (C) 2015-2016 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.
+//--------------------------------------------------------------------------
+// file_segment.h author Hui Cao <huica@cisco.com>
+
+#ifndef FILE_SEGMENT_H
+#define FILE_SEGMENT_H
+
+//Segmented file data reassemble and processing
+
+#include <sys/types.h>
+#include <string>
+
+#include "file_lib.h"
+#include "file_api.h"
+
+class FileSegment
+{
+public:
+ FileSegment() { }
+ ~FileSegment();
+
+ // Use single list for simplicity
+ FileSegment* next = nullptr;
+ uint32_t offset = 0;
+ std::string* data = nullptr;
+};
+
+class FileSegments
+{
+public:
+ FileSegments(FileContext*);
+ ~FileSegments();
+
+ void clear();
+
+ // Process file segments with current_offset specified. If file segment is out of order,
+ // it will be put into the file segments queue.
+ int process(Flow*, const uint8_t* file_data, uint64_t data_size, uint64_t offset);
+
+private:
+ FileSegment* head = nullptr;
+ uint64_t current_offset;
+ FileContext* context = nullptr;
+
+ void add(const uint8_t* file_data, uint64_t data_size, uint64_t offset);
+ FilePosition get_file_position(uint64_t data_size, uint64_t file_size);
+ int process_one(Flow*, const uint8_t* file_data, int data_size);
+ int process_all(Flow*);
+};
+
+#endif
+
#include <stdlib.h>
#include "file_api.h"
-#include "file_stats.h"
#include "file_capture.h"
+#include "file_cache.h"
+#include "file_config.h"
#include "file_flows.h"
#include "file_enforcer.h"
#include "file_lib.h"
-#include "file_config.h"
+#include "file_stats.h"
#include "mime/file_mime_config.h"
#include "mime/file_mime_process.h"
#include "main/snort_types.h"
#include "managers/action_manager.h"
-#include "stream/stream_api.h"
#include "detection/detect.h"
#include "detection/detection_util.h"
#include "packet_io/active.h"
bool FileService::file_capture_enabled = false;
bool FileService::file_processing_initiated = false;
FileEnforcer* FileService::file_enforcer = nullptr;
+FileCache* FileService::file_cache = nullptr;
void FileService::init()
{
{
if (file_enforcer)
delete file_enforcer;
+ if (file_cache)
+ delete file_cache;
MimeSession::exit();
FileCapture::exit();
if (!file_processing_initiated)
{
file_enforcer = new FileEnforcer;
+ file_cache = new FileCache;
//RegisterProfileStats("file", print_file_stats); FIXIT-M put in module
file_processing_initiated = true;
}
return context->get_processed_bytes();
}
+
#include "file_api/file_policy.h"
class FileEnforcer;
+class FileCache;
class SO_PUBLIC FileService
{
static void close();
static void enable_file_type();
- static void enable_file_signature ();
+ static void enable_file_signature();
static void enable_file_capture();
- static bool is_file_type_id_enabled() {return file_type_id_enabled;}
- static bool is_file_signature_enabled() {return file_signature_enabled;}
- static bool is_file_capture_enabled() {return file_capture_enabled;}
+ static bool is_file_type_id_enabled() { return file_type_id_enabled; }
+ static bool is_file_signature_enabled() { return file_signature_enabled; }
+ static bool is_file_capture_enabled() { return file_capture_enabled; }
static bool is_file_service_enabled();
static int64_t get_max_file_depth();
static FilePolicy& get_inspect();
- static FileEnforcer* get_file_enforcer() {return file_enforcer;}
+ static FileEnforcer* get_file_enforcer() { return file_enforcer; }
+ static FileCache* get_file_cache() { return file_cache; }
private:
static void start_file_processing();
static bool file_capture_enabled;
static bool file_processing_initiated;
static FileEnforcer* file_enforcer;
+ static FileCache* file_cache;
};
extern const struct BaseApi* file_inspectors[];
#include "file_stats.h"
#include "file_capture.h"
+#include "file_cache.h"
#include "file_config.h"
#include "main/snort_types.h"
#if 0
LogLabel("file type verdicts");
- uint64_t verdicts_total = 0;
+ uint64_t verdicts_total = 0;#include "file_capture.h"
for (i = 0; i < FILE_VERDICT_MAX; i++)
{
verdicts_total+=file_stats.verdicts_type[i];
LogLabel("file stats summary");
LogCount("Files processed",file_stats.files_total);
LogCount("Files data processed", file_stats.file_data_total);
-
+ if(FileCache::num_add_fails)
+ LogCount("Fails to add to cache", FileCache::num_add_fails);
}
#define MAX_PROTOCOL_ORDINAL 8192 // FIXIT-L use std::vector and get_protocol_count()
-typedef struct _File_Stats
+struct FileStats
{
uint64_t files_total;
uint64_t files_processed[FILE_ID_MAX + 1][2];
uint64_t data_processed[FILE_ID_MAX + 1][2];
uint64_t file_data_total;
uint64_t files_sig_depth;
-} FileStats;
+};
extern FileStats file_stats;
#include <assert.h>
#include "time/packet_time.h"
-#include "stream/stream_api.h" // FIXIT-M bad dependency
#include "hash/zhash.h"
+#include "protocols/packet.h"
+#include "stream/stream.h"
#include "sfip/sf_ip.h"
/* Reasonably small, and prime */
while ((fd = head->data))
{
head->data = fd->next;
- lws->set_application_data(fd);
+ lws->set_flow_data(fd);
++realized;
fd->handle_expected(p);
}
#include "flow/ha.h"
#include "flow/session.h"
#include "ips_options/ips_flowbits.h"
-#include "utils/bitop.h"
-#include "utils/util.h"
#include "protocols/packet.h"
#include "sfip/sf_ip.h"
+#include "utils/bitop.h"
+#include "utils/util.h"
unsigned FlowData::flow_id = 0;
void Flow::init(PktType type)
{
pkt_type = type;
-
- // FIXIT-M getFlowbitSizeInBytes() should be attribute of ??? (or eliminate)
- bitop = new BitOp(getFlowbitSizeInBytes());
+ bitop = nullptr;
if ( HighAvailabilityManager::active() )
{
ha_state = new FlowHAState;
previous_ssn_state = ssn_state;
}
+ mpls_client.length = 0;
+ mpls_server.length = 0;
}
void Flow::term()
if ( session )
delete session;
- free_application_data();
+ free_flow_data();
+
+ if ( mpls_client.length )
+ delete[] mpls_client.start;
+
+ if ( mpls_server.length )
+ delete[] mpls_server.start;
+
+ if ( bitop )
+ delete bitop;
if ( ssn_client )
ssn_client->rem_ref();
if ( gadget )
gadget->rem_ref();
- if ( bitop )
- delete bitop;
-
if ( ha_state )
delete ha_state;
+}
- if ( clientMplsLyr.length )
+inline void Flow::clean()
+{
+ if ( mpls_client.length )
{
- delete[] clientMplsLyr.start;
- clientMplsLyr.length = 0;
+ delete[] mpls_client.start;
+ mpls_client.length = 0;
}
- if ( serverMplsLyr.length )
+ if ( mpls_server.length )
{
- delete[] serverMplsLyr.start;
- serverMplsLyr.length = 0;
+ delete[] mpls_server.start;
+ mpls_server.length = 0;
+ }
+ if ( bitop )
+ {
+ delete bitop;
+ bitop = nullptr;
}
}
session->clear();
}
- free_application_data();
-
- if ( clientMplsLyr.length )
- {
- delete[] clientMplsLyr.start;
- clientMplsLyr.length = 0;
- }
- if ( serverMplsLyr.length )
- {
- delete[] serverMplsLyr.start;
- serverMplsLyr.length = 0;
- }
+ free_flow_data();
+ clean();
// FIXIT-M cleanup() winds up calling clear()
if ( ssn_client )
if ( data )
clear_data();
- constexpr size_t offset = offsetof(Flow, appDataList);
- // FIXIT-L need a struct to zero here to make future proof
- memset((uint8_t*)this+offset, 0, sizeof(Flow)-offset);
-
- bitop->reset();
-
if ( ha_state )
ha_state->reset();
+
+ constexpr size_t offset = offsetof(Flow, flow_data);
+ // FIXIT-L need a struct to zero here to make future proof
+ memset((uint8_t*)this+offset, 0, sizeof(Flow)-offset);
}
-void Flow::restart(bool free_flow_data)
+void Flow::restart(bool dump_flow_data)
{
- if ( free_flow_data )
- free_application_data();
+ if ( dump_flow_data )
+ free_flow_data();
- if ( clientMplsLyr.length )
- {
- delete[] clientMplsLyr.start;
- clientMplsLyr.length = 0;
- }
- if ( serverMplsLyr.length )
- {
- delete[] serverMplsLyr.start;
- serverMplsLyr.length = 0;
- }
-
- bitop->reset();
+ clean();
ssn_state.ignore_direction = 0;
ssn_state.session_flags = SSNFLAG_NONE;
previous_ssn_state = ssn_state;
}
-void Flow::clear(bool free_flow_data)
+void Flow::clear(bool dump_flow_data)
{
- restart(free_flow_data);
+ restart(dump_flow_data);
set_state(FlowState::SETUP);
if ( ssn_client )
clear_gadget();
}
-int Flow::set_application_data(FlowData* fd)
+int Flow::set_flow_data(FlowData* fd)
{
- FlowData* appData = get_application_data(fd->get_id());
- assert(appData != fd);
+ FlowData* old = get_flow_data(fd->get_id());
+ assert(old != fd);
- if (appData)
- free_application_data(appData);
+ if (old)
+ free_flow_data(old);
fd->prev = nullptr;
- fd->next = appDataList;
+ fd->next = flow_data;
- if ( appDataList )
- appDataList->prev = fd;
+ if ( flow_data )
+ flow_data->prev = fd;
- appDataList = fd;
+ flow_data = fd;
return 0;
}
-FlowData* Flow::get_application_data(unsigned id)
+FlowData* Flow::get_flow_data(unsigned id)
{
- FlowData* appData = appDataList;
+ FlowData* fd = flow_data;
- while (appData)
+ while (fd)
{
- if (appData->get_id() == id)
- return appData;
+ if (fd->get_id() == id)
+ return fd;
- appData = appData->next;
+ fd = fd->next;
}
return nullptr;
}
-void Flow::free_application_data(FlowData* fd)
+void Flow::free_flow_data(FlowData* fd)
{
- if ( fd == appDataList )
+ if ( fd == flow_data )
{
- appDataList = fd->next;
- if ( appDataList )
- appDataList->prev = nullptr;
+ flow_data = fd->next;
+ if ( flow_data )
+ flow_data->prev = nullptr;
}
else if ( !fd->next )
{
delete fd;
}
-void Flow::free_application_data(uint32_t proto)
+void Flow::free_flow_data(uint32_t proto)
{
- FlowData* fd = get_application_data(proto);
+ FlowData* fd = get_flow_data(proto);
if ( fd )
- free_application_data(fd);
+ free_flow_data(fd);
}
-void Flow::free_application_data()
+void Flow::free_flow_data()
{
- FlowData* appData = appDataList;
+ FlowData* fd = flow_data;
- while (appData)
+ while (fd)
{
- FlowData* tmp = appData;
- appData = appData->next;
+ FlowData* tmp = fd;
+ fd = fd->next;
delete tmp;
}
- appDataList = nullptr;
+ flow_data = nullptr;
}
void Flow::call_handlers(Packet* p, bool eof)
{
- FlowData* appData = appDataList;
+ FlowData* fd = flow_data;
- while (appData)
+ while (fd)
{
if ( eof )
- appData->handle_eof(p);
+ fd->handle_eof(p);
else
- appData->handle_retransmit(p);
+ fd->handle_retransmit(p);
- appData = appData->next;
+ fd = fd->next;
}
}
}
}
-static constexpr int TCP_HZ = 100;
-
-static inline uint64_t CalcJiffies(const Packet* p)
-{
- uint64_t ret = 0;
- uint64_t sec = (uint64_t)p->pkth->ts.tv_sec * TCP_HZ;
- uint64_t usec = (p->pkth->ts.tv_usec / (1000000UL/TCP_HZ));
-
- ret = sec + usec;
-
- return ret;
-}
-
void Flow::set_expire(const Packet* p, uint32_t timeout)
{
- expire_time = CalcJiffies(p) + (timeout * TCP_HZ);
-}
-
-int Flow::get_expire(const Packet* p)
-{
- return ( CalcJiffies(p) > expire_time );
+ expire_time = (uint64_t)p->pkth->ts.tv_sec + timeout;
}
bool Flow::expired(const Packet* p)
if ( !expire_time )
return false;
- uint64_t pkttime = CalcJiffies(p);
-
- if ( (int)(pkttime - expire_time) > 0 )
+ if ( (uint64_t)p->pkth->ts.tv_sec > expire_time )
return true;
return false;
if ( p->packet_flags & PKT_FROM_CLIENT )
{
- if ( !clientMplsLyr.length )
+ if ( !mpls_client.length )
{
- clientMplsLyr.length = mpls_lyr->length;
- clientMplsLyr.prot_id = mpls_lyr->prot_id;
- clientMplsLyr.start = new uint8_t[mpls_lyr->length];
- memcpy((void *)clientMplsLyr.start, mpls_lyr->start, mpls_lyr->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 ( !serverMplsLyr.length )
+ if ( !mpls_server.length )
{
- serverMplsLyr.length = mpls_lyr->length;
- serverMplsLyr.prot_id = mpls_lyr->prot_id;
- serverMplsLyr.start = new uint8_t[mpls_lyr->length];
- memcpy((void *)serverMplsLyr.start, mpls_lyr->start, mpls_lyr->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);
}
}
}
Layer Flow::get_mpls_layer_per_dir(bool client)
{
if ( client )
- return clientMplsLyr;
+ return mpls_client;
else
- return serverMplsLyr;
+ return mpls_server;
}
#include <assert.h>
-#include "utils/bitop.h"
#include "sfip/sfip_t.h"
#include "flow/flow_key.h"
#include "framework/inspector.h"
void term();
void reset(bool do_cleanup = true);
- void restart(bool free_flow_data = true);
- void clear(bool free_flow_data = true);
-
- int set_application_data(FlowData*);
- FlowData* get_application_data(uint32_t proto);
- void free_application_data(uint32_t proto);
- void free_application_data(FlowData*);
- void free_application_data();
- void set_application_ids(AppId serviceAppId, AppId clientAppId,
- AppId payloadAppId, AppId miscAppId);
- void get_application_ids(AppId& serviceAppId, AppId& clientAppId,
- AppId& payloadAppId, AppId& miscAppId);
+ 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);
+ void free_flow_data(uint32_t proto);
+ void free_flow_data(FlowData*);
+ void free_flow_data();
+
+ void set_application_ids(AppId service, AppId client, AppId payload, AppId misc);
+ void get_application_ids(AppId& service, AppId& client, AppId& payload, AppId& misc);
+
void call_handlers(Packet* p, bool eof = false);
void markup_packet_flags(Packet*);
void set_direction(Packet*);
void set_expire(const Packet*, uint32_t timeout);
- int get_expire(const Packet*);
bool expired(const Packet*);
void set_ttl(Packet*, bool client);
void set_mpls_layer_per_dir(Packet*);
}
public: // FIXIT-M privatize if possible
+ // fields are organized by initialization and size to minimize
+ // void space and allow for memset of tail end of struct
+
// these fields are const after initialization
const FlowKey* key;
class Session* session;
class BitOp* bitop;
class FlowHAState* ha_state;
+
uint8_t ip_proto; // FIXIT-M do we need both of these?
PktType pkt_type; // ^^
Flow* prev, * next;
Inspector* ssn_client;
Inspector* ssn_server;
+
long last_data_seen;
+ Layer mpls_client, mpls_server;
// everything from here down is zeroed
- FlowData* appDataList;
+ FlowData* flow_data;
Inspector* clouseau; // service identifier
Inspector* gadget; // service handler
Inspector* data;
const char* service;
- Layer clientMplsLyr, serverMplsLyr;
- unsigned policy_id;
-
- FlowState flow_state;
+ uint64_t expire_time;
sfip_t client_ip; // FIXIT-L family and bits should be changed to uint16_t
sfip_t server_ip; // or uint8_t to reduce sizeof from 24 to 20
- uint64_t expire_time;
+ LwState ssn_state;
+ LwState previous_ssn_state;
+
+ // FIXIT-L: if appid is only consumer of this move to appid
+ AppId application_ids[APP_PROTOID_MAX];
+
+ FlowState flow_state;
+ unsigned policy_id;
int32_t iface_in;
int32_t iface_out;
uint8_t response_count;
bool disable_inspect;
- // FIXIT-L: if appid is only consumer of this move to appid
- AppId application_ids[APP_PROTOID_MAX];
-
-public:
- LwState ssn_state;
- LwState previous_ssn_state;
+private:
+ void clean();
};
#endif
#include "main/snort_debug.h"
#include "packet_io/active.h"
#include "time/packet_time.h"
+#include "utils/stats.h"
#define SESSION_CACHE_FLAG_PURGING 0x01
FlowCache::FlowCache (const FlowConfig& cfg) : config(cfg)
{
- cleanup_flows = cfg.max_sessions * cfg.cleanup_pct / 100;
- if ( cleanup_flows == 0 )
- cleanup_flows = 1;
-
- assert(cleanup_flows <= cfg.max_sessions);
- assert(cleanup_flows > 0);
-
hash_table = new ZHash(config.max_sessions, sizeof(FlowKey));
hash_table->set_keyops(FlowKey::hash, FlowKey::compare);
if ( !flow )
flow = static_cast<Flow*>(hash_table->first());
- while ( flow and retired < num_flows )
+ while ( flow and (retired < num_flows) )
{
if ( flow->last_data_seen + config.nominal_timeout > thetime )
break;
while ( auto flow = static_cast<Flow*>(hash_table->first()) )
{
- flow->ssn_state.session_flags |= SSNFLAG_PRUNED;
release(flow, PruneReason::PURGE);
++retired;
}
int remove(Flow*);
private:
+ const unsigned cleanup_flows = 1;
const FlowConfig& config;
- unsigned cleanup_flows;
unsigned uni_count;
uint32_t flags;
unsigned max_sessions = 0;
unsigned pruning_timeout = 0;
unsigned nominal_timeout = 0;
- unsigned cleanup_pct = 0;
};
#endif
#include "protocols/udp.h"
#include "protocols/vlan.h"
#include "sfip/sf_ip.h"
+#include "stream/stream.h"
#include "expect_cache.h"
#include "flow_cache.h"
#include "session.h"
FlowControl::FlowControl()
-{
- ip_cache = nullptr;
- icmp_cache = nullptr;
- tcp_cache = nullptr;
- udp_cache = nullptr;
- user_cache = nullptr;
- file_cache = nullptr;
- exp_cache = nullptr;
-
- ip_mem = icmp_mem = nullptr;
- tcp_mem = udp_mem = nullptr;
- user_mem = file_mem = nullptr;
-
- get_ip = get_icmp = nullptr;
- get_tcp = get_udp = nullptr;
- get_user = get_file = nullptr;
-
- last_pkt_type = PktType::NONE;
-}
+{ }
FlowControl::~FlowControl()
{
static THREAD_LOCAL PegCount user_count = 0;
static THREAD_LOCAL PegCount file_count = 0;
-uint32_t FlowControl::max_flows(PktType type)
-{
- FlowCache* cache = get_cache(type);
-
- if ( cache )
- return cache->get_max_flows();
-
- return 0;
-}
-
PegCount FlowControl::get_flows(PktType type)
{
switch ( type )
case PktType::ICMP: return icmp_count;
case PktType::TCP: return tcp_count;
case PktType::UDP: return udp_count;
- case PktType::PDU: return user_count;
+ case PktType::PDU: return user_count;
case PktType::FILE: return file_count;
default: return 0;
}
cache->purge();
}
-void FlowControl::prune_flows(PktType type, const Packet* p)
-{
- if ( !p )
- return;
-
- FlowCache* cache = get_cache(type);
-
- if ( !cache )
- return;
-
- // smack the older timed out flows
- if ( !cache->prune_stale(p->pkth->ts.tv_sec, p->flow) )
- {
- // if no luck, try the memcap
- cache->prune_excess(p->flow);
- }
-}
-
// hole for memory manager/prune handler
bool FlowControl::prune_one(PruneReason reason, bool do_cleanup)
{
return cache ? cache->prune_one(reason, do_cleanup) : false;
}
-void FlowControl::timeout_flows(uint32_t flowCount, time_t cur_time)
+void FlowControl::timeout_flows(time_t cur_time)
{
- Active::suspend();
-
- if ( ip_cache )
- ip_cache->timeout(flowCount, cur_time);
-
- //if ( icmp_cache )
- //icmp_cache does not need cleaning
-
- if ( tcp_cache )
- tcp_cache->timeout(flowCount, cur_time);
+ if ( !types.size() )
+ return;
- if ( udp_cache )
- udp_cache->timeout(flowCount, cur_time);
+ Active::suspend();
+ FlowCache* fc = get_cache(types[next]);
- if ( user_cache )
- user_cache->timeout(flowCount, cur_time);
+ if ( ++next >= types.size() )
+ next = 0;
- if ( file_cache )
- file_cache->timeout(flowCount, cur_time);
+ if ( fc )
+ fc->timeout(1, cur_time);
Active::resume();
}
case Flow::FlowState::ALLOW:
if ( news )
- stream.stop_inspection(flow, p, SSN_DIR_BOTH, -1, 0);
+ Stream::stop_inspection(flow, p, SSN_DIR_BOTH, -1, 0);
else
DisableInspection();
case Flow::FlowState::BLOCK:
if ( news )
- stream.drop_traffic(flow, SSN_DIR_BOTH);
+ Stream::drop_traffic(flow, SSN_DIR_BOTH);
else
Active::block_again();
case Flow::FlowState::RESET:
if ( news )
- stream.drop_traffic(flow, SSN_DIR_BOTH);
+ Stream::drop_traffic(flow, SSN_DIR_BOTH);
else
Active::reset_again();
- stream.blocked_session(flow, p);
+ Stream::blocked_flow(flow, p);
DisableInspection();
break;
}
ip_cache->push(ip_mem + i);
get_ip = get_ssn;
+ types.push_back(PktType::IP);
}
void FlowControl::process_ip(Packet* p)
icmp_cache->push(icmp_mem + i);
get_icmp = get_ssn;
+ types.push_back(PktType::ICMP);
}
void FlowControl::process_icmp(Packet* p)
tcp_cache->push(tcp_mem + i);
get_tcp = get_ssn;
+ types.push_back(PktType::TCP);
}
void FlowControl::process_tcp(Packet* p)
udp_cache->push(udp_mem + i);
get_udp = get_ssn;
+ types.push_back(PktType::UDP);
}
void FlowControl::process_udp(Packet* p)
user_cache->push(user_mem + i);
get_user = get_ssn;
+ types.push_back(PktType::PDU);
}
void FlowControl::process_user(Packet* p)
file_cache->push(file_mem + i);
get_file = get_ssn;
+ types.push_back(PktType::FILE);
}
void FlowControl::process_file(Packet* p)
// processed. flows are pruned as needed to process new flows.
#include <cstdint>
+#include <vector>
#include "flow/flow_config.h"
#include "framework/counts.h"
void delete_flow(const FlowKey*);
void delete_flow(Flow*, PruneReason);
void purge_flows(PktType);
- void prune_flows(PktType, const Packet*);
bool prune_one(PruneReason, bool do_cleanup);
- void timeout_flows(uint32_t flowCount, time_t cur_time);
+
+ void timeout_flows(time_t cur_time);
char expected_flow(Flow*, Packet*);
bool is_expected(Packet*);
const sfip_t *dstIP, uint16_t dstPort,
PktType, int16_t appId, FlowData*);
- uint32_t max_flows(PktType);
-
PegCount get_flows(PktType);
PegCount get_total_prunes(PktType) const;
PegCount get_prunes(PktType, PruneReason) const;
void preemptive_cleanup();
private:
- FlowCache* ip_cache;
- FlowCache* icmp_cache;
- FlowCache* tcp_cache;
- FlowCache* udp_cache;
- FlowCache* user_cache;
- FlowCache* file_cache;
+ FlowCache* ip_cache = nullptr;
+ FlowCache* icmp_cache = nullptr;
+ FlowCache* tcp_cache = nullptr;
+ FlowCache* udp_cache = nullptr;
+ FlowCache* user_cache = nullptr;
+ FlowCache* file_cache = nullptr;
// preallocated arrays
- Flow* ip_mem;
- Flow* icmp_mem;
- Flow* tcp_mem;
- Flow* udp_mem;
- Flow* user_mem;
- Flow* file_mem;
-
- InspectSsnFunc get_ip;
- InspectSsnFunc get_icmp;
- InspectSsnFunc get_tcp;
- InspectSsnFunc get_udp;
- InspectSsnFunc get_user;
- InspectSsnFunc get_file;
-
- class ExpectCache* exp_cache;
- PktType last_pkt_type;
+ Flow* ip_mem = nullptr;
+ Flow* icmp_mem = nullptr;
+ Flow* tcp_mem = nullptr;
+ Flow* udp_mem = nullptr;
+ Flow* user_mem = nullptr;
+ Flow* file_mem = nullptr;
+
+ InspectSsnFunc get_ip = nullptr;
+ InspectSsnFunc get_icmp = nullptr;
+ InspectSsnFunc get_tcp = nullptr;
+ InspectSsnFunc get_udp = nullptr;
+ InspectSsnFunc get_user = nullptr;
+ InspectSsnFunc get_file = nullptr;
+
+ class ExpectCache* exp_cache = nullptr;
+ PktType last_pkt_type = PktType::NONE;
+
+ std::vector<PktType> types;
+ unsigned next = 0;
};
#endif
#include "packet_io/sfdaq.h"
#include "profiler/profiler.h"
#include "side_channel/side_channel.h"
-#include "stream/stream_api.h"
+#include "stream/stream.h"
#include "time/packet_time.h"
static const uint8_t HA_MESSAGE_VERSION = 3;
{
FlowKey key;
(void)read_flow_key(&key, msg);
- stream.delete_session(&key);
+ Stream::delete_flow(&key);
}
static void consume_receive_update_message(HAMessage* msg)
FlowKey key;
(void)read_flow_key(&key, msg);
// flow will be nullptr if/when the session does not exist in the caches
- Flow* flow = stream.get_session(&key);
+ Flow* flow = Stream::get_flow(&key);
assert(s_client_map);
// the subclasses do the actual work of tracking, reassembly, etc.
#include "sfip/sfip_t.h"
-#include "stream/stream_api.h"
+#include "stream/stream.h"
struct Packet;
class Flow;
#include "flow/flow.h"
#include "main/snort_debug.h"
-#include "stream/stream_api.h"
+#include "stream/stream.h"
#include <CppUTest/CommandLineTestRunner.h>
#include <CppUTest/TestHarness.h>
private:
};
-Flow* Stream::get_session(const FlowKey* flowkey)
+Flow* Stream::get_flow(const FlowKey* flowkey)
{
s_flowkey = *flowkey;
s_get_session_called = true;
return &s_flow;
}
-void Stream::delete_session(const FlowKey* flowkey)
+void Stream::delete_flow(const FlowKey* flowkey)
{
s_flowkey = *flowkey;
s_delete_session_called = true;
CAT_SET_KEY,
};
+enum RuleDirection
+{
+ RULE_FROM_CLIENT,
+ RULE_FROM_SERVER,
+ RULE_WO_DIR
+};
+
class SO_PUBLIC IpsOption
{
public:
{ return CAT_NONE; }
// for fast-pattern options like content
- virtual struct PatternMatchData* get_pattern()
+ virtual struct PatternMatchData* get_pattern(int /*proto*/, RuleDirection)
{ return nullptr; }
static int eval(void* v, Cursor& c, Packet* p)
min = max = 0;
}
-bool RangeCheck::is_set()
+bool RangeCheck::is_set() const
{
return (op != MAX);
}
return true;
}
-bool RangeCheck::eval(long c)
+bool RangeCheck::eval(long c) const
{
switch ( op )
{
bool operator==(const RangeCheck&) const;
void init();
- bool is_set();
+ bool is_set() const;
// FIXIT-L add ttl style syntax
bool parse(const char* s);
- bool eval(long);
+ bool eval(long) const;
};
#endif
// host_tracker_module.cc author Steve Chew <stechew@cisco.com>
-#include "host_tracker/host_tracker_module.h"
+#include "host_tracker_module.h"
-#include "host_tracker/host_cache.h"
-#include "stream/stream_api.h"
+#include "stream/stream.h"
#include "target_based/snort_protocols.h"
+#include "host_cache.h"
const PegInfo host_tracker_pegs[] =
{
int eval(Cursor& c, Packet*) override
{ return CheckANDPatternMatch(config, c); }
- PatternMatchData* get_pattern() override
+ PatternMatchData* get_pattern(int, RuleDirection) override
{ return &config->pmd; }
protected:
}
return true;
}
+
#endif
// FIXIT-P fp, fp_only are set after hash table comparisons so this must
-// return false to avoid unnecessary reevaluation and false positives.
+// return this == &ips to avoid unnecessary reevaluation and false positives.
// when this is fixed, add PatternMatchData::operator==().
bool ContentOption::operator==(const IpsOption& ips) const
{
{
return true;
}
-#else
- UNUSED(ips);
#endif
- return false;
+ return this == &ips;
}
//-------------------------------------------------------------------------
DebugMessage(DEBUG_PATTERN_MATCH, "Pattern match found\n");
return DETECTION_OPTION_MATCH;
}
-
else
{
DebugMessage(DEBUG_PATTERN_MATCH, "Pattern match failed\n");
#include <bitset>
-#include "profiler/profiler.h"
#include "detection/detection_defines.h"
#include "framework/ips_option.h"
#include "framework/module.h"
#include "file_api/file_identifier.h"
#include "file_api/file_flows.h"
+#include "profiler/profiler.h"
+#include "protocols/packet.h"
typedef std::bitset<FILE_ID_MAX> TypeBitSet;
#include "parser/parser.h"
#include "utils/util.h"
#include "hash/sfhashfcn.h"
-#include "stream/stream_api.h"
#include "profiler/profiler.h"
#include "detection/detection_defines.h"
#include "framework/ips_option.h"
#include "utils/bitop.h"
#include "hash/sfghash.h"
#include "parser/mstring.h"
-#include "stream/stream_api.h"
#include "profiler/profiler.h"
#include "hash/sfhashfcn.h"
#include "detection/detection_defines.h"
BitOp* GrpBitOp;
} FLOWBITS_GRP;
+static std::forward_list<const FLOWBITS_OP*> op_list;
+
+static SFGHASH* flowbits_hash = NULL;
static SFGHASH* flowbits_grp_hash = NULL;
+static SF_QUEUE* flowbits_bit_queue = NULL;
-static std::forward_list<const FLOWBITS_OP*> op_list;
+static unsigned flowbits_count = 0;
+static unsigned flowbits_grp_count = 0;
+static int flowbits_toggle = 1;
static int check_flowbits(
uint8_t type, uint8_t evalType, uint16_t* ids, uint16_t num_ids,
// helper methods
//-------------------------------------------------------------------------
+static inline BitOp* get_flow_bitop(const Packet* p)
+{
+ Flow* flow = p->flow;
+
+ if (!flow)
+ return NULL;
+
+ if ( !flow->bitop )
+ flow->bitop = new BitOp(flowbits_count);
+
+ return flow->bitop;
+}
+
static inline int clear_group_bit(BitOp* bitop, char* group)
{
if ( !group )
uint8_t type, uint8_t evalType, uint16_t* ids, uint16_t num_ids, char* group, Packet* p)
{
int rval = DETECTION_OPTION_NO_MATCH;
- BitOp* bitop;
Flowbits_eval eval = (Flowbits_eval)evalType;
int result = 0;
int i;
- bitop = stream.get_flow_bitop(p);
+ BitOp* bitop = get_flow_bitop(p);
+
if (!bitop)
{
- DebugMessage(DEBUG_FLOWBITS, "No FLOWBITS_DATA");
+ assert(false);
return rval;
}
// public methods
//-------------------------------------------------------------------------
-static SFGHASH* flowbits_hash = NULL;
-static SF_QUEUE* flowbits_bit_queue = NULL;
-static uint16_t flowbits_count = 0;
-static uint16_t flowbits_grp_count = 0;
-static int flowbits_toggle = 1;
-
-// FIXIT-P consider allocating flowbits on session on demand instead of
-// preallocating.
-
-unsigned int getFlowbitSize()
-{
- return flowbits_count;
-}
-
-unsigned int getFlowbitSizeInBytes()
-{
- return flowbits_count ? (flowbits_count + 7) >> 3 : 1;
-}
-
void FlowbitResetCounts()
{
SFGHASH_NODE* n;
if ( !flowbits_count )
{
ParseError("The number of flowbit IDs in the current ruleset exceeds "
- "the maximum number of IDs that are allowed (65535).");
+ "the maximum number of IDs that are allowed (%u).", flowbits_count-1);
}
}
if ( !flowbits_hash or !flowbits_grp_hash )
return;
- unsigned size = getFlowbitSizeInBytes();
-
for ( SFGHASH_NODE* n = sfghash_findfirst(flowbits_grp_hash);
n != NULL;
n= sfghash_findnext(flowbits_grp_hash) )
{
FLOWBITS_GRP* fbg = (FLOWBITS_GRP*)n->data;
- fbg->GrpBitOp = new BitOp(size);
+ fbg->GrpBitOp = new BitOp(flowbits_count);
fbg->GrpBitOp->reset();
}
void FlowbitResetCounts();
int FlowBits_SetOperation(void*);
-void setFlowbitSize(unsigned);
-unsigned int getFlowbitSize();
-unsigned int getFlowbitSizeInBytes();
-
#endif
bool retry() override;
- PatternMatchData* get_pattern() override
+ PatternMatchData* get_pattern(int, RuleDirection) override
{ return &config.pmd; }
int eval(Cursor&, Packet*) override;
return c;
}
-// see ContentOption::operator==() for why this is always false
+// see ContentOption::operator==()
bool RegexOption::operator==(const IpsOption& ips) const
{
#if 0
RegexOption& rhs = (RegexOption&)ips;
- if ( config.re == rhs.config.re and
- config.pmd.flags == rhs.config.pmd.flags and
- config.pmd.relative == rhs.config.pmd.relative )
+ if ( config.re == rhs.config.re and
+ config.pmd.flags == rhs.config.pmd.flags and
+ config.pmd.relative == rhs.config.pmd.relative )
return true;
-
-#else
- UNUSED(ips);
#endif
- return false;
+ return this == &ips;
}
static int hs_match(
bool RegexModule::begin(const char*, int, SnortConfig*)
{
config.reset();
+ config.pmd.flags |= HS_FLAG_SINGLEMATCH;
return true;
}
config.re.erase(0, 1);
config.re.erase(config.re.length()-1, 1);
}
-
else if ( v.is("nocase") )
{
config.pmd.flags |= HS_FLAG_CASELESS;
std::string pii;
unsigned threshold = 1;
bool obfuscate_pii = false;
- int (*validate)(const uint8_t* buf, unsigned long long buflen) = nullptr;
+ int (* validate)(const uint8_t* buf, unsigned long long buflen) = nullptr;
inline bool operator==(const SdPatternConfig& rhs) const
{
uint32_t hash() const override;
bool operator==(const IpsOption&) const override;
- PatternMatchData* get_pattern() override
+ PatternMatchData* get_pattern(int, RuleDirection) override
{ return &config.pmd; }
int eval(Cursor&, Packet* p) override;
{
// FIXIT-L why is this failing but everything is working?
ParseError("can't initialize sd_pattern for %s (%d) %p",
- config.pii.c_str(), err, (void*)s_scratch);
+ config.pii.c_str(), err, (void*)s_scratch);
}
config.pmd.pattern_buf = config.pii.c_str();
}
SdPatternOption::~SdPatternOption()
-{
+{
if ( config.db )
hs_free_database(config.db);
}
return false;
}
-struct hsContext
+struct hsContext
{
- hsContext(const SdPatternConfig &c_, Packet* p_, const uint8_t* const start_)
- : config(c_), packet(p_), start(start_) {}
+ hsContext(const SdPatternConfig& c_, Packet* p_, const uint8_t* const start_)
+ : config(c_), packet(p_), start(start_) { }
unsigned int count = 0;
ctx->packet->obfuscator = new Obfuscator();
uint32_t off = ctx->buf - ctx->start;
- // FIXIT-L Make configurable or don't show any PII partials (0 for user defined??)
+ // FIXIT-L Make configurable or don't show any PII partials (0 for user defined??)
len = len > 4 ? len - 4 : len;
ctx->packet->obfuscator->push(off, len);
}
config.validate = SdLuhnAlgorithm;
config.obfuscate_pii = sc->obfuscate_pii;
}
-
else if (config.pii == "us_social")
{
config.pii = SD_SOCIAL_PATTERN;
config.obfuscate_pii = sc->obfuscate_pii;
}
-
else if (config.pii == "us_social_nodashes")
{
config.pii = SD_SOCIAL_NODASHES_PATTERN;
{
hs_compile_error_t* err = nullptr;
- if ( hs_compile(config.pii.c_str(), HS_FLAG_DOTALL|HS_FLAG_SOM_LEFTMOST, HS_MODE_BLOCK, nullptr, &config.db, &err)
+ if ( hs_compile(config.pii.c_str(), HS_FLAG_DOTALL|HS_FLAG_SOM_LEFTMOST, HS_MODE_BLOCK,
+ nullptr, &config.db, &err)
or !config.db )
{
ParseError("can't compile regex '%s'", config.pii.c_str());
}
static void sd_pattern_dtor(IpsOption* p)
-{
+{
delete p;
}
void setup()
{
+ // FIXIT-L cpputest hangs or crashes in the leak detector
+ MemoryLeakWarningPlugin::turnOffNewDeleteOverloads();
opt = get_option(" foo ");
regex_setup(snort_conf);
}
api->dtor(opt);
regex_cleanup(snort_conf);
api->pterm(snort_conf);
+ MemoryLeakWarningPlugin::turnOnNewDeleteOverloads();
}
};
void setup()
{
+ // FIXIT-L cpputest hangs or crashes in the leak detector
+ MemoryLeakWarningPlugin::turnOffNewDeleteOverloads();
opt = get_option("\\bfoo", true);
regex_setup(snort_conf);
}
IpsApi* api = (IpsApi*)ips_regex;
api->dtor(opt);
regex_cleanup(snort_conf);
+ MemoryLeakWarningPlugin::turnOnNewDeleteOverloads();
}
};
static const PegInfo latency_pegs[] =
{
- { "total_packets", "total packets monitored" },
- { "packet_timeouts", "packets that timed out" },
- { "total_rule_evals", "total rule evals monitored" },
- { "rule_eval_timeouts", "rule evals that timed out" },
- { "rule_tree_enables", "rule tree re-enables" },
+ { "total packets", "total packets monitored" },
+ { "total usecs", "total usecs elapsed" },
+ { "max usecs", "maximum usecs elapsed" },
+ { "packet timeouts", "packets that timed out" },
+ { "total rule evals", "total rule evals monitored" },
+ { "rule eval timeouts", "rule evals that timed out" },
+ { "rule tree enables", "rule tree re-enables" },
{ nullptr, nullptr }
};
using std::chrono::microseconds;
if ( v.is("max_time") )
- config.max_time =
- duration_cast<decltype(config.max_time)>(microseconds(v.get_long()));
+ {
+ long t = clock_ticks(v.get_long());
+ config.max_time = duration_cast<decltype(config.max_time)>(microseconds(t));
+ }
else if ( v.is("fastpath") )
config.fastpath = v.get_bool();
using std::chrono::milliseconds;
if ( v.is("max_time") )
- config.max_time =
- duration_cast<decltype(config.max_time)>(microseconds(v.get_long()));
-
+ {
+ long t = clock_ticks(v.get_long());
+ config.max_time = duration_cast<decltype(config.max_time)>(microseconds(t));
+ }
else if ( v.is("suspend") )
config.suspend = v.get_bool();
config.suspend_threshold = v.get_long();
else if ( v.is("max_suspend_time") )
- config.max_suspend_time =
- duration_cast<decltype(config.max_time)>(milliseconds(v.get_long()));
-
+ {
+ long t = clock_ticks(v.get_long());
+ config.max_suspend_time = duration_cast<decltype(config.max_time)>(milliseconds(t));
+ }
else if ( v.is("action") )
config.action =
static_cast<decltype(config.action)>(v.get_long());
struct LatencyStats
{
PegCount total_packets;
+ PegCount total_usecs;
+ PegCount max_usecs;
PegCount packet_timeouts;
PegCount total_rule_evals;
PegCount rule_eval_timeouts;
#include "protocols/packet.h"
#include "sfip/sf_ip.h"
#include "time/clock_defs.h"
+#include "utils/stats.h"
+
#include "latency_config.h"
#include "latency_timer.h"
#include "latency_util.h"
#include "catch/catch.hpp"
#endif
+static THREAD_LOCAL uint64_t elapsed = 0;
+
namespace packet_latency
{
// -----------------------------------------------------------------------------
// helpers
// -----------------------------------------------------------------------------
-using DefaultClock = hr_clock;
-
struct Event
{
const Packet* packet;
bool fastpathed;
- typename DefaultClock::duration elapsed;
+ typename SnortClock::duration elapsed;
};
template<typename Clock>
using std::chrono::duration_cast;
using std::chrono::microseconds;
- os << "latency: packet timed out";
+ os << "latency: packet " << pc.total_from_daq << " timed out";
if ( e.fastpathed )
os << " (fastpathed)";
os << ": ";
- os << duration_cast<microseconds>(e.elapsed).count() << " usec, [";
+ os << clock_usecs(duration_cast<microseconds>(e.elapsed).count()) << " usec, [";
os << e.packet->ptrs.ip_api.get_src() << " -> " <<
e.packet->ptrs.ip_api.get_dst() << "]";
// implementation
// -----------------------------------------------------------------------------
-template<typename Clock = DefaultClock>
+template<typename Clock = SnortClock>
class Impl
{
public:
if ( config->action & PacketLatencyConfig::LOG )
log_handler.handle(e);
- if ( timer.marked_as_fastpathed and (config->action & PacketLatencyConfig::ALERT) )
+ if ( config->action & PacketLatencyConfig::ALERT )
event_handler.handle(e);
}
+ // FIXIT-H this is fugly and inefficient
+ using std::chrono::duration_cast;
+ using std::chrono::microseconds;
+ elapsed = clock_usecs(duration_cast<microseconds>(timer.elapsed()).count());
+
timers.pop_back();
return timed_out;
}
{
if ( packet_latency::get_impl().pop(p) )
++latency_stats.packet_timeouts;
+
+ // FIXIT-L the timer is still running so this max is slightly larger than logged
+ if ( elapsed > latency_stats.max_usecs )
+ latency_stats.max_usecs = elapsed;
+
+ latency_stats.total_usecs += elapsed;
}
}
CHECK_FALSE( impl.fastpath() );
CHECK( impl.pop(nullptr) );
- CHECK( event_handler.count == 0 );
+ CHECK( event_handler.count == 1 );
CHECK( log_handler.count == 1 );
}
#include "events/event_queue.h"
#include "log/messages.h"
#include "main/snort_config.h"
+
#include "latency_config.h"
#include "latency_rules.h"
#include "latency_stats.h"
// helpers
// -----------------------------------------------------------------------------
-using DefaultClock = hr_clock;
-
struct Event
{
enum Type
};
Type type;
- typename DefaultClock::duration elapsed;
+ typename SnortClock::duration elapsed;
detection_option_tree_root_t* root;
};
os << ": ";
- os << duration_cast<microseconds>(e.elapsed).count() << " usec, ";
+ os << clock_usecs(duration_cast<microseconds>(e.elapsed).count()) << " usec, ";
}
// FIXIT-L clean up rule latency logging; delete or make useful
// implementation
// -----------------------------------------------------------------------------
-template<typename Clock = DefaultClock, typename RuleTree = DefaultRuleInterface>
+template<typename Clock = SnortClock, typename RuleTree = DefaultRuleInterface>
class Impl
{
public:
#include "events/event.h"
#include "parser/parser.h"
#include "packet_io/sfdaq.h"
-#include "stream/stream_api.h"
#include "utils/util.h"
#include "utils/stats.h"
#include "detection/detect.h"
#include "parser/parser.h"
#include "events/event.h"
-#include "utils/util.h"
+#include "log/obfuscator.h"
#include "packet_io/active.h"
#include "packet_io/sfdaq.h"
-#include "stream/stream_api.h"
#include "protocols/layer.h"
#include "protocols/vlan.h"
#include "protocols/icmp4.h"
-#include "log/obfuscator.h"
+#include "stream/stream.h"
#include "utils/safec.h"
+#include "utils/util.h"
using namespace std;
Unified2InitFile(&config);
- stream.reg_xtra_data_log(AlertExtraData, &config);
+ Stream::reg_xtra_data_log(AlertExtraData, &config);
}
void U2Logger::close()
}
if ( p->flow )
- stream.update_session_alert(
+ Stream::update_flow_alert(
p->flow, p, event->sig_info->generator, event->sig_info->id,
event->event_id, event->ref_time.tv_sec);
if ( p->xtradata_mask )
{
LogFunction* log_funcs;
- uint32_t max_count = stream.get_xtra_data_map(&log_funcs);
+ uint32_t max_count = Stream::get_xtra_data_map(&log_funcs);
if ( max_count > 0 )
AlertExtraData(
// //
//-----------------------------------------------//
-#define BUILD "208"
+#define BUILD "211"
#endif
#include "side_channel/side_channel_module.h"
#include "sfip/sf_ip.h"
#include "sfip/sf_ipvar.h"
+#include "stream/stream.h"
#include "target_based/sftarget_data.h"
#include "target_based/snort_protocols.h"
#include "filters/detection_filter.h"
#include "filters/rate_filter.h"
#include "filters/sfthreshold.h"
-#include "flow/flow_control.h"
#include "flow/ha.h"
#include "framework/mpse.h"
#include "helpers/process.h"
void Snort::thread_idle()
{
- if ( flow_con )
- flow_con->timeout_flows(16384, time(NULL));
+ Stream::timeout_flows(time(nullptr));
perf_monitor_idle_process();
aux_counts.idle++;
HighAvailabilityManager::process_receive();
void Snort::thread_term()
{
HighAvailabilityManager::thread_term_beginning();
+
if ( !snort_conf->dirty_pig )
- InspectorManager::thread_stop(snort_conf);
+ Stream::purge_flows();
+ InspectorManager::thread_stop(snort_conf);
ModuleManager::accumulate(snort_conf);
InspectorManager::thread_term(snort_conf);
ActionManager::thread_term(snort_conf);
Active::reset();
PacketManager::encode_reset();
-
- if ( flow_con ) // FIXIT-M always instantiate
- {
- flow_con->timeout_flows(4, pkthdr->ts.tv_sec);
- }
-
+ Stream::timeout_flows(pkthdr->ts.tv_sec);
HighAvailabilityManager::process_receive();
s_packet->pkth = nullptr; // no longer avail upon sig segv
// prune_handler.cc author Joel Cornett <jocornet@cisco.com>
#include "prune_handler.h"
-
-#include "flow/flow_cache.h"
-#include "flow/flow_control.h"
#include "stream/stream.h"
namespace memory
void prune_handler()
{
- // assert(flow_con);
- if ( flow_con )
- flow_con->prune_one(PruneReason::MEMCAP, false);
+ Stream::prune_flows();
}
} // namespace memory
AppIdSession* AppIdApi::get_appid_data(Flow* flow)
{
- AppIdSession* session = (AppIdSession*) flow->get_application_data(AppIdSession::flow_id);
+ AppIdSession* session = (AppIdSession*) flow->get_flow_data(AppIdSession::flow_id);
return (session && session->common.fsf_type.flow_type == APPID_SESSION_TYPE_NORMAL) ?
session : nullptr;
uint32_t AppIdApi::produce_ha_state(void* lwssn, uint8_t* buf)
{
AppIdSessionHA* appHA = (AppIdSessionHA*)buf;
- AppIdSession* session = (AppIdSession*)(((Flow*)lwssn)->get_application_data(AppIdSession::flow_id));
+ AppIdSession* session = (AppIdSession*)(((Flow*)lwssn)->get_flow_data(AppIdSession::flow_id));
// FIXIT - getFlowType should be a class member
if (session && get_flow_type(session) != APPID_FLOW_TYPE_NORMAL)
AppIdSessionHA* appHA = (AppIdSessionHA*)buf;
if (appHA->flags & APPID_HA_FLAGS_APP)
{
- AppIdSession* session = (AppIdSession*)(((Flow*)lwssn)->get_application_data(
+ AppIdSession* session = (AppIdSession*)(((Flow*)lwssn)->get_flow_data(
AppIdSession::flow_id));
if (!session)
{
session = new AppIdSession(proto, ip);
- ((Flow*)lwssn)->set_application_data(session);
+ ((Flow*)lwssn)->set_flow_data(session);
if (session->serviceAppId == APP_ID_FTP_CONTROL)
{
session->setAppIdFlag(APPID_SESSION_CLIENT_DETECTED |
// appid_flow_data.cc author Sourcefire Inc.
+#include "log/messages.h"
#include "protocols/tcp.h"
#include "profiler/profiler.h"
#include "target_based/snort_protocols.h"
+#include "sfip/sf_ip.h"
+#include "stream/stream.h"
+#include "time/packet_time.h"
+#include "utils/util.h"
-#include "appid_session.h"
-#include "appid_module.h"
-#include "fw_appid.h"
-#include "appid_stats.h"
-#include "app_forecast.h"
-#include "host_port_app_cache.h"
-#include "lua_detector_module.h"
+#include "appid_utils/ip_funcs.h"
#include "client_plugins/client_app_base.h"
#include "detector_plugins/detector_http.h"
#include "detector_plugins/detector_dns.h"
#include "service_plugins/service_ssl.h"
#include "service_plugins/service_util.h"
-#include "log/messages.h"
-#include "stream/stream_api.h"
-#include "sfip/sf_ip.h"
-#include "utils/util.h"
-#include "appid_utils/ip_funcs.h"
-#include "time/packet_time.h"
+#include "appid_session.h"
+#include "appid_module.h"
+#include "fw_appid.h"
+#include "appid_stats.h"
+#include "app_forecast.h"
+#include "host_port_app_cache.h"
+#include "lua_detector_module.h"
ProfileStats tpPerfStats;
ProfileStats tpLibPerfStats;
data->flow = p->flow;
data->stats.firstPktsecond = p->pkth->ts.tv_sec;
- p->flow->set_application_data(data);
+ p->flow->set_flow_data(data);
return data;
}
// FIXIT - 2.9.x set_application_protocol_id_expected has several new parameters, need to look
// into what is required to support those here.
- if (stream.set_application_protocol_id_expected(/*crtlPkt,*/ cliIp, cliPort, srvIp, srvPort,
- protocol, app_id, session) )
+ if ( Stream::set_application_protocol_id_expected(
+ /*crtlPkt,*/ cliIp, cliPort, srvIp, srvPort, protocol, app_id, session) )
{
if (app_id_debug_session_flag)
LogMessage("AppIdDbg %s failed to create a related flow for %s-%u -> %s-%u %u\n",
thirdparty_appid_module->disable_flags(tpsession,
TP_SESSION_FLAG_ATTRIBUTE | TP_SESSION_FLAG_TUNNELING | TP_SESSION_FLAG_FUTUREFLOW);
}
- if (tp_app_id == APP_ID_SSL && (stream.get_application_protocol_id(p->flow) == snortId_for_ftp_data))
+ if (tp_app_id == APP_ID_SSL &&
+ (Stream::get_application_protocol_id(p->flow) == snortId_for_ftp_data))
{
// If we see SSL on an FTP data channel set tpAppId back
// to APP_ID_NONE so the FTP preprocessor picks up the flow.
if( is_packet_ignored(p) )
return;
- AppIdSession* session = (AppIdSession*) p->flow->get_application_data(AppIdSession::flow_id);
+ AppIdSession* session = (AppIdSession*) p->flow->get_flow_data(AppIdSession::flow_id);
if (session)
{
if (session->common.fsf_type.flow_type == APPID_SESSION_TYPE_IGNORE)
APPID_SESSION_BIDIRECTIONAL_CHECKED)
{
// FIXIT-M: This _dpd call needs to be convert to correct snort++ call
- // static THREAD_LOCAL APPID_SESSION_STRUCT_FLAG ignore_fsf {
- // APPID_SESSION_TYPE_IGNORE };
+ // static THREAD_LOCAL APPID_SESSION_STRUCT_FLAG ignore_fsf
+ // { APPID_SESSION_TYPE_IGNORE };
+
+ // p->flow->set_flow_data(PP_APP_ID, &ignore_fsf, nullptr);
- // _dpd.sessionAPI->set_application_data(p->flow, PP_APP_ID, &ignore_fsf,
- // nullptr);
if (app_id_debug_session_flag)
LogMessage("AppIdDbg %s not monitored\n", app_id_debug_session);
}
else
tmp_session->common.initiator_port = 0;
tmp_session->common.policyId = appIdPolicyId;
- p->flow->set_application_data(tmp_session);
+ p->flow->set_flow_data(tmp_session);
if (app_id_debug_session_flag)
LogMessage("AppIdDbg %s unknown monitoring\n", app_id_debug_session);
}
(SearchTool*)( ( AppIdConfig*)pConfig)->find_generic_config_element(client_app_mod.name);
#ifdef APP_ID_USES_REASSEMBLED
- stream.flush_response_flush(pkt);
+ Stream::flush_response_flush(pkt);
#endif
if (!size)
goto inprocess;
#ifdef APP_ID_USES_REASSEMBLED
- stream.flush_response_flush(pkt);
+ Stream::flush_response_flush(pkt);
#endif
if (!size)
#endif
#ifdef APP_ID_USES_REASSEMBLED
- stream.flush_response_flush(pkt);
+ Stream::flush_response_flush(pkt);
#endif
if (!size)
goto inprocess;
#ifdef APP_ID_USES_REASSEMBLED
- stream.flush_response_flush(pkt);
+ Stream::flush_response_flush(pkt);
#endif
if (!size)
return CLIENT_APP_INPROCESS;
#ifdef APP_ID_USES_REASSEMBLED
- stream.flush_response_flush(pkt);
+ Stream::flush_response_flush(pkt);
#endif
dd = (POP3DetectorData*)pop3_detector_mod.api->data_get(flowp,
goto inprocess;
#ifdef APP_ID_USES_REASSEMBLED
- stream.flush_response_flush(pkt);
+ Stream::flush_response_flush(pkt);
#endif
if (dir != APP_ID_FROM_RESPONDER)
#include "appid_utils/network_set.h"
#include "time/packet_time.h"
#include "sfip/sf_ip.h"
-#include "stream/stream_api.h"
#define HTTP_PATTERN_MAX_LEN 1024
#define PORT_MAX 65535
#include "hash/sfhashfcn.h"
#include "log/messages.h"
#include "profiler/profiler.h"
+#include "stream/stream.h"
#include "utils/util.h"
-#include "stream/stream_api.h"
//-------------------------------------------------------------------------
// appid option
#include "service_rpc.h"
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
#include <netdb.h>
#if defined(FREEBSD) || defined(OPENBSD)
-#include "rpc/rpc.h"
+#include <rpc/rpc.h>
#endif
#include "service_api.h"
{
}
-void* get_application_data(void*, uint32_t)
+void* get_flow_data(void*, uint32_t)
{
return pAppIdData;
}
-int set_application_data(void*, uint32_t, AppIdSession* data, StreamAppDataFree)
+int set_flow_data(void*, uint32_t, AppIdSession* data, StreamAppDataFree)
{
pAppIdData = data;
// Session APIs
void enable_preproc_all_ports(SnortConfig*, uint32_t appId, uint32_t flags);
-void* get_application_data(void* stream_session, uint32_t protocol);
-int set_application_data(void* scbptr, uint32_t protocol, void* data, StreamAppDataFree);
+void* get_flow_data(void* stream_session, uint32_t protocol);
+int set_flow_data(void* scbptr, uint32_t protocol, void* data, StreamAppDataFree);
uint32_t get_packet_direction(Packet*);
uint32_t get_session_flags(void* ssnptr);
sfaddr_t* get_session_ip_address(void* scbptr, uint32_t direction);
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
-#include "bitop.h"
#include "bnfa_search.h"
#include "acsmx.h"
#include "acsmx2.h"
return retv;
}
-void mpseSetRuleMask(void* pvoid, BITOP* rm)
-{
- MPSE* p = (MPSE*)pvoid;
-
- switch ( p->method )
- {
- default:
- return;
- }
-}
-
int mpsePrintInfo(void* pvoid)
{
MPSE* p = (MPSE*)pvoid;
set(FILE_LIST
binder.cc
+ binder.h
binding.h
bind_module.cc
bind_module.h
file_list = \
binder.cc \
+binder.h \
binding.h \
bind_module.cc \
bind_module.h
#include "protocols/packet.h"
#include "protocols/vlan.h"
#include "protocols/layer.h"
-#include "stream/stream_api.h"
#include "stream/stream_splitter.h"
#include "profiler/profiler.h"
#include "utils/stats.h"
static void set_service(Flow* flow, const HostAttributeEntry* host)
{
- stream.set_application_protocol_id_from_host_entry(flow, host, FROM_SERVER);
+ Stream::set_application_protocol_id(flow, host, FROM_SERVER);
}
static Inspector* get_gadget(Flow* flow)
if ( ins )
{
- stream.set_splitter(flow, true, ins->get_splitter(true));
- stream.set_splitter(flow, false, ins->get_splitter(false));
+ Stream::set_splitter(flow, true, ins->get_splitter(true));
+ Stream::set_splitter(flow, false, ins->get_splitter(false));
}
else
{
- stream.set_splitter(flow, true, new AtomSplitter(true));
- stream.set_splitter(flow, false, new AtomSplitter(false));
+ Stream::set_splitter(flow, true, new AtomSplitter(true));
+ Stream::set_splitter(flow, false, new AtomSplitter(false));
}
return 0;
#include "managers/inspector_manager.h"
#include "main/policy.h"
#include "profiler/profiler.h"
-#include "stream/stream_api.h"
#include "stream/stream_splitter.h"
#include "utils/stats.h"
void ParseError(const char*, ...) { }
void LogMessage(const char*,...) { }
-void Stream::set_application_protocol_id_from_host_entry(Flow*, HostAttributeEntry const*, int) { }
+void Stream::set_application_protocol_id(Flow*, HostAttributeEntry const*, int) { }
void Stream::set_splitter(Flow*, bool, class StreamSplitter*) { }
const char* get_protocol_name(uint16_t) { return ""; }
int16_t FindProtocolReference(const char*) { return 0; }
memset(conf,0,sizeof(SnortConfig));
snort_conf = (SnortConfig*)conf;
Flow* flow = new Flow;
- constexpr size_t offset = offsetof(Flow, appDataList);
+ constexpr size_t offset = offsetof(Flow, flow_data);
memset((uint8_t*)flow+offset, 0, sizeof(Flow)-offset);
s_inspector = new MyInspector();
#include "protocols/tcp_options.h"
#include "protocols/icmp4.h"
#include "protocols/icmp6.h"
-#include "stream/stream.h"
#include "stream/tcp/tcp_normalizer.h"
#include "utils/stats.h"
#include <sstream>
#include <vector>
-#include "stream/stream.h"
#include "stream/tcp/tcp_normalizer.h"
using namespace std;
#include "protocols/packet.h"
#include "time/packet_time.h"
#include "hash/sfxhash.h"
-#include "stream/stream_api.h"
-#include "sfip/sf_ip.h"
#include "protocols/tcp.h"
#include "protocols/udp.h"
#include "protocols/icmp4.h"
#include "protocols/icmp6.h"
#include "protocols/eth.h"
+#include "sfip/sf_ip.h"
+#include "stream/stream.h"
typedef struct s_PS_HASH_KEY
{
}
else if (p->ptrs.udph && p->flow)
{
- if (stream.get_packet_direction(p) & PKT_FROM_SERVER)
+ if (Stream::get_packet_direction(p) & PKT_FROM_SERVER)
reverse_pkt = 1;
}
{
if ( p->flow )
{
- uint32_t direction = stream.get_packet_direction(p);
+ uint32_t direction = Stream::get_packet_direction(p);
if (direction == PKT_FROM_CLIENT)
{
#include "main/snort_types.h"
#include "main/snort_debug.h"
#include "profiler/profiler.h"
-#include "stream/stream_api.h"
#include "file_api/file_api.h"
#include "parser/parser.h"
#include "framework/inspector.h"
static ReputationData* SetNewReputationData(Flow* flow)
{
ReputationFlowData* fd = new ReputationFlowData;
- flow->set_application_data(fd);
+ flow->set_flow_data(fd);
return &fd->session;
}
static ReputationData* get_session_data(Flow* flow)
{
- ReputationFlowData* fd = (ReputationFlowData*)flow->get_application_data(
+ ReputationFlowData* fd = (ReputationFlowData*)flow->get_flow_data(
ReputationFlowData::flow_id);
return fd ? &fd->session : nullptr;
#define REPUTATION_INSPECT_H
#include "protocols/packet.h"
-#include "stream/stream_api.h"
// Per-session data block containing current state
// of the Reputation preprocessor for the session.
#include "managers/action_manager.h"
#include "packet_io/sfdaq.h"
#include "protocols/tcp.h"
+#include "stream/stream.h"
#include "utils/dnet_header.h"
#define MAX_ATTEMPTS 20
THREAD_LOCAL Active::ActiveAction Active::delayed_active_action = Active::ACT_PASS;
THREAD_LOCAL int Active::active_tunnel_bypass = 0;
-THREAD_LOCAL bool Active::active_suspend = 0;
+THREAD_LOCAL bool Active::active_suspend = false;
THREAD_LOCAL uint8_t Active::s_attempts = 0;
THREAD_LOCAL uint64_t Active::s_injects = 0;
active_action = ACT_BLOCK;
if ( force or SnortConfig::inline_mode() or SnortConfig::treat_drop_as_ignore() )
- stream.drop_session(p);
+ Stream::drop_flow(p);
}
void Active::reset_session(const Packet* p, bool force)
active_action = ACT_RESET;
if ( force or SnortConfig::inline_mode() or SnortConfig::treat_drop_as_ignore() )
- stream.drop_session(p);
+ Stream::drop_flow(p);
if ( s_enabled and snort_conf->max_responses )
{
if ( p->flow )
{
- stream.init_active_response(p, p->flow);
+ Stream::init_active_response(p, p->flow);
p->flow->set_state(Flow::FlowState::RESET);
}
}
*
***************************************************************************/
static void AddRuleFuncToList(
- int (* rfunc) (Packet*, RuleTreeNode*, struct RuleFpList*, int),
+ int (* rfunc)(Packet*, RuleTreeNode*, struct RuleFpList*, int),
RuleTreeNode* rtn)
{
RuleFpList* idx;
return 1;
}
-PatternMatchData* get_pmd(OptFpList* ofl)
+PatternMatchData* get_pmd(OptFpList* ofl, int proto, RuleDirection direction)
{
if ( !ofl->ips_opt )
return nullptr;
- return ofl->ips_opt->get_pattern();
+ return ofl->ips_opt->get_pattern(proto, direction);
}
static void finalize_content(OptFpList* ofl)
{
- PatternMatchData* pmd = get_pmd(ofl);
+ PatternMatchData* pmd = get_pmd(ofl, 0, RULE_WO_DIR);
if ( !pmd )
return;
bool is_fast_pattern_only(OptFpList* ofl)
{
- PatternMatchData* pmd = get_pmd(ofl);
+ PatternMatchData* pmd = get_pmd(ofl, 0, RULE_WO_DIR);
if ( !pmd )
return false;
static void clear_fast_pattern_only(OptFpList* ofl)
{
- PatternMatchData* pmd = get_pmd(ofl);
+ PatternMatchData* pmd = get_pmd(ofl, 0, RULE_WO_DIR);
if ( pmd && pmd->fp_only > 0 )
pmd->fp_only = 0;
}
// reset the check if one of these are present.
- if ( fpl->ips_opt and !fpl->ips_opt->get_pattern() )
+ if ( fpl->ips_opt and !fpl->ips_opt->get_pattern(0, RULE_WO_DIR))
{
if ( fpl->ips_opt->get_cursor_type() > CAT_NONE )
relative_is_bad_mkay = false;
* After otn processing we can finalize port object processing for this rule
*/
if ( FinishPortListRule(
- sc->port_tables, new_rtn, otn, rtn.proto, has_fp, sc->fast_pattern_config) )
+ sc->port_tables, new_rtn, otn, rtn.proto, has_fp, sc->fast_pattern_config) )
ParseError("Failed to finish a port list rule.");
return nullptr;
#define PARSE_RULE_H
#include "detection/rules.h"
+#include "framework/ips_option.h"
struct OptFpList;
struct OptTreeNode;
const char* parse_rule_close(SnortConfig*, RuleTreeNode&, OptTreeNode*);
bool is_fast_pattern_only(OptFpList*);
-struct PatternMatchData* get_pmd(OptFpList*);
+struct PatternMatchData* get_pmd(OptFpList*, int proto, RuleDirection);
int get_rule_count();
// show statistics
// -----------------------------------------------------------------------------
-#define s_memory_table_title "Memory Profile Statistics"
+#define s_memory_table_title "memory profile"
namespace memory_stats
{
#include "catch/catch.hpp"
#endif
-static constexpr unsigned WIDTH = 40;
+static constexpr unsigned WIDTH = 50;
static constexpr char ENDL = '\n';
const StatsTable::Header StatsTable::HEADER { '=' };
#include "catch/catch.hpp"
#endif
-#define s_rule_table_title "Rule Profile Statistics"
+#define s_rule_table_title "rule profile"
static inline OtnState& operator+=(OtnState& lhs, const OtnState& rhs)
{
table << n; // #
table << v.sig_info.generator; // gid
- table << v.sig_info.id; // sid
- table << v.sig_info.rev; // rev
+ table << v.sig_info.id; // sid
+ table << v.sig_info.rev;
- table << v.checks(); // checks
- table << v.matches(); // matches
- table << v.alerts(); // alerts
+ table << v.checks();
+ table << v.matches();
+ table << v.alerts();
- table << duration_cast<microseconds>(v.elapsed()).count(); // time
- table << duration_cast<microseconds>(v.avg_check()).count(); // avg/check
- table << duration_cast<microseconds>(v.avg_match()).count(); // avg/match
- table << duration_cast<microseconds>(v.avg_no_match()).count(); // avg/non-match
+ table << clock_usecs(duration_cast<microseconds>(v.elapsed()).count());
+ table << clock_usecs(duration_cast<microseconds>(v.avg_check()).count());
+ table << clock_usecs(duration_cast<microseconds>(v.avg_match()).count());
+ table << clock_usecs(duration_cast<microseconds>(v.avg_no_match()).count());
table << v.timeouts();
table << v.suspends();
private:
dot_node_state_t& stats;
- Stopwatch<hr_clock> sw;
+ Stopwatch<SnortClock> sw;
bool finished = false;
};
#include "catch/catch.hpp"
#endif
-#define s_time_table_title "Module Profile Statistics"
+#define s_time_table_title "module profile"
namespace time_stats
{
t << v.checks();
// total time
- t << duration_cast<microseconds>(v.elapsed()).count();
+ t << clock_usecs(duration_cast<microseconds>(v.elapsed()).count());
// avg/check
- t << duration_cast<microseconds>(v.avg_check()).count();
+ t << clock_usecs(duration_cast<microseconds>(v.avg_check()).count());
}
} // namespace time_stats
private:
TimeProfilerStats& stats;
- Stopwatch<hr_clock> sw;
+ Stopwatch<SnortClock> sw;
bool stopped_once = false;
};
#include "utils/stats.h"
#include "log/text_log.h"
#include "main/snort_debug.h"
-#include "stream/stream_api.h"
#include "packet_io/sfdaq.h"
#include "packet_io/active.h"
+#include "stream/stream.h"
THREAD_LOCAL ProfileStats decodePerfStats;
// outermost ip is considered to be outer here,
// even if it is the only ip layer ...
- ttl = stream.get_session_ttl(p->flow, dir, outer);
+ ttl = Stream::get_flow_ttl(p->flow, dir, outer);
// if we don't get outer, we use inner
if ( 0 == ttl && outer )
- ttl = stream.get_session_ttl(p->flow, dir, false);
+ ttl = Stream::get_flow_ttl(p->flow, dir, false);
return ttl;
}
flags = d.flags;
user = u;
user_tree = user_list = nullptr;
+
+ if ( no_case )
+ flags |= HS_FLAG_CASELESS;
+
+ flags |= HS_FLAG_SINGLEMATCH;
}
void Pattern::escape(const uint8_t* s, unsigned n, bool literal)
void setup()
{
+ // FIXIT-L cpputest hangs or crashes in the leak detector
+ MemoryLeakWarningPlugin::turnOffNewDeleteOverloads();
CHECK(se_hyperscan);
hs = mpse_api->ctor(snort_conf, nullptr, false, &s_agent);
CHECK(hs);
{
mpse_api->dtor(hs);
hyperscan_cleanup(snort_conf);
+ MemoryLeakWarningPlugin::turnOnNewDeleteOverloads();
}
};
CHECK(hits == 1);
}
+TEST(mpse_hs_match, nocase)
+{
+ Mpse::PatternDescriptor desc(true, true, false);
+
+ CHECK(hs->add_pattern(nullptr, (uint8_t*)"foo", 3, desc, s_user) == 0);
+ CHECK(hs->prep_patterns(snort_conf) == 0);
+ CHECK(hs->get_pattern_count() == 1);
+
+ hyperscan_setup(snort_conf);
+
+ int state = 0;
+ CHECK(hs->search((uint8_t*)"foo", 3, match, nullptr, &state) == 0);
+ CHECK(hs->search((uint8_t*)"fOo", 3, match, nullptr, &state) == 0);
+ CHECK(hits == 2);
+}
+
TEST(mpse_hs_match, other)
{
Mpse::PatternDescriptor desc(false, true, false);
CHECK(hs->add_pattern(nullptr, (uint8_t*)"foo", 3, desc, s_user) == 0);
- CHECK(hs->add_pattern(nullptr, (uint8_t*)"\rbar\n", 3, desc, s_user) == 0);
- CHECK(hs->add_pattern(nullptr, (uint8_t*)"\\(baz\\)", 3, desc, s_user) == 0);
-
CHECK(hs->prep_patterns(snort_conf) == 0);
- CHECK(hs->get_pattern_count() == 3);
+ CHECK(hs->get_pattern_count() == 1);
hyperscan_setup(snort_conf);
int state = 0;
CHECK(hs->search((uint8_t*)"foo", 3, match, nullptr, &state) == 0);
+ CHECK(hs->search((uint8_t*)"fOo", 3, match, nullptr, &state) == 0);
CHECK(hits == 1);
}
void setup()
{
+ // FIXIT-L cpputest hangs or crashes in the leak detector
+ MemoryLeakWarningPlugin::turnOffNewDeleteOverloads();
CHECK(se_hyperscan);
hs1 = mpse_api->ctor(snort_conf, nullptr, false, &s_agent);
mpse_api->dtor(hs1);
mpse_api->dtor(hs2);
hyperscan_cleanup(snort_conf);
+ MemoryLeakWarningPlugin::turnOnNewDeleteOverloads();
}
};
dce_tcp_module.cc
dce_tcp_module.h
dce_tcp_paf.cc
- dce_tcp_paf.h
+ dce_tcp_paf.h
+ dce_udp.cc
+ dce_udp.h
+ dce_udp_module.cc
+ dce_udp_module.h
dce_utils.cc
dce_utils.h
ips_dce_iface.cc
dce_tcp_module.h \
dce_tcp_paf.cc \
dce_tcp_paf.h \
+dce_udp.cc\
+dce_udp.h \
+dce_udp_module.cc \
+dce_udp_module.h \
dce_utils.cc \
dce_utils.h \
ips_dce_iface.cc \
void* config = sd->config;
if (sd->trans == DCE2_TRANS_TYPE__TCP)
{
- if (((dce2TcpProtoConf*)config)->co_reassemble_threshold > 0)
+ if (((dce2TcpProtoConf*)config)->common.co_reassemble_threshold > 0)
return true;
}
else
{
- if (((dce2SmbProtoConf*)config)->co_reassemble_threshold > 0)
+ if (((dce2SmbProtoConf*)config)->common.co_reassemble_threshold > 0)
return true;
}
return false;
{
if (sd->trans == DCE2_TRANS_TYPE__TCP)
{
- return ((dce2TcpProtoConf*)config)->co_reassemble_threshold;
+ return ((dce2TcpProtoConf*)config)->common.co_reassemble_threshold;
}
else
{
- return ((dce2SmbProtoConf*)config)->co_reassemble_threshold;
+ return ((dce2SmbProtoConf*)config)->common.co_reassemble_threshold;
}
}
return UINT16_MAX;
else if ( v.is("max_frag_len") )
common.max_frag_len = v.get_long();
+ else
+ return false;
+ return true;
+}
+bool dce2_set_co_config(Value& v, dce2CoProtoConf& co)
+{
+ if (dce2_set_common_config(v, co.common))
+ return true;
else if ( v.is("policy") )
- common.policy = (DCE2_Policy)v.get_long();
+ co.policy = (DCE2_Policy)v.get_long();
+ else if ( v.is("reassemble_threshold") )
+ co.co_reassemble_threshold = v.get_long();
else
return false;
return true;
"DISABLED" : "ENABLED");
LogMessage(" Max Fragment length: %d\n",
common.max_frag_len);
+}
+
+void print_dce2_co_config(dce2CoProtoConf& co)
+{
+ print_dce2_common_config(co.common);
+
LogMessage(" Policy : %s\n",
- dce2_get_policy_name(common.policy));
+ dce2_get_policy_name(co.policy));
+ LogMessage(" Reassemble Threshold : %d\n",
+ co.co_reassemble_threshold);
}
bool dce2_paf_abort(Flow* flow, DCE2_SsnData* sd)
{
&dce2_tcp_api.base,
&dce2_smb_api.base,
+ &dce2_udp_api.base,
ips_dce_iface,
ips_dce_opnum,
ips_dce_stub_data,
const BaseApi* sin_dce_tcp = &dce2_tcp_api.base;
const BaseApi* sin_dce_smb = &dce2_smb_api.base;
+const BaseApi* sin_dce_udp = &dce2_udp_api.base;
#endif
extern const InspectApi dce2_smb_api;
extern const InspectApi dce2_tcp_api;
+extern const InspectApi dce2_udp_api;
extern THREAD_LOCAL int dce2_detected;
extern THREAD_LOCAL int dce2_inspector_instances;
extern THREAD_LOCAL DCE2_CStack* dce2_pkt_stack;
{
bool disable_defrag;
int max_frag_len;
+};
+
+struct dce2CoProtoConf
+{
+ dce2CommonProtoConf common;
DCE2_Policy policy;
+ uint16_t co_reassemble_threshold;
};
#define DCE2_DEBUG__PAF_END_MSG "=========================================================="
bool dce2_set_common_config(Value&, dce2CommonProtoConf&);
void print_dce2_common_config(dce2CommonProtoConf&);
+bool dce2_set_co_config(Value&, dce2CoProtoConf&);
+void print_dce2_co_config(dce2CoProtoConf&);
bool dce2_paf_abort(Flow*, DCE2_SsnData*);
void DCE2_Detect(DCE2_SsnData*);
Packet* DCE2_GetRpkt(Packet*, DCE2_RpktType,
DCE2_SmbSsnData* get_dce2_smb_session_data(Flow* flow)
{
- Dce2SmbFlowData* fd = (Dce2SmbFlowData*)flow->get_application_data(
- Dce2SmbFlowData::flow_id);
-
+ Dce2SmbFlowData* fd = (Dce2SmbFlowData*)flow->get_flow_data(Dce2SmbFlowData::flow_id);
return fd ? &fd->dce2_smb_session : nullptr;
}
static DCE2_SmbSsnData* set_new_dce2_smb_session(Packet* p)
{
Dce2SmbFlowData* fd = new Dce2SmbFlowData;
-
memset(&fd->dce2_smb_session,0,sizeof(DCE2_SmbSsnData));
- p->flow->set_application_data(fd);
+ p->flow->set_flow_data(fd);
return(&fd->dce2_smb_session);
}
#include "dce_smb_utils.h"
#include "detection/detection_util.h"
#include "main/snort_debug.h"
+#include "file_api/file_flows.h"
#define UNKNOWN_FILE_SIZE ~0
ftracker->file_name_size = 0;
}
+static inline FileContext* get_file_context(DCE2_SmbSsnData* ssd, uint64_t file_id)
+{
+ assert(ssd->sd.wire_pkt);
+ FileFlows* file_flows = FileFlows::get_file_flows((ssd->sd.wire_pkt)->flow);
+ assert(file_flows);
+ return file_flows->get_file_context(file_id, true);
+}
+
static inline void DCE2_Smb2ProcessFileData(DCE2_SmbSsnData* ssd, const uint8_t* file_data,
- uint32_t data_size, bool)
+ uint32_t data_size, FileDirection dir)
{
int64_t file_detection_depth = DCE2_ScSmbFileDepth((dce2SmbProtoConf*)ssd->sd.config);
int64_t detection_size = 0;
DCE2_FileDetect();
}
-// FIXIT-L port file processing
-/*
- _dpd.fileAPI->file_segment_process(fileCache, (void *)ssd->sd.wire_pkt,
- ssd->ftracker.fid_v2, ssd->ftracker.tracker.file.file_size,
- file_data, data_size, ssd->ftracker.tracker.file.file_offset,
- upload);
-*/
+ assert(ssd->sd.wire_pkt);
+ FileFlows* file_flows = FileFlows::get_file_flows((ssd->sd.wire_pkt)->flow);
+
+ file_flows->file_process(ssd->ftracker.fid_v2, file_data, data_size,
+ ssd->ftracker.tracker.file.file_offset, dir);
}
/********************************************************************
if (ssd->ftracker.file_name && ssd->ftracker.file_name_size)
{
-// FIXIT-L port file processing
-/*
- _dpd.fileAPI->file_cache_update_entry(fileCache, (void *)ssd->sd.wire_pkt, ssd->ftracker.fid_v2,
- (uint8_t *) ssd->ftracker.file_name, ssd->ftracker.file_name_size, file_size);
-*/
+ FileContext* file = get_file_context(ssd, ssd->ftracker.fid_v2);
+ if (file)
+ {
+ file->set_file_size(file_size);
+ file->set_file_name(ssd->ftracker.file_name, ssd->ftracker.file_name_size);
+ }
}
DCE2_Smb2ResetFileName(&(ssd->ftracker));
}
!ssd->ftracker.tracker.file.file_size
&& ssd->ftracker.tracker.file.file_offset)
{
- bool upload = DCE2_SsnFromClient(ssd->sd.wire_pkt) ? true : false;
+ FileDirection dir = DCE2_SsnFromClient(ssd->sd.wire_pkt) ? FILE_UPLOAD : FILE_DOWNLOAD;
ssd->ftracker.tracker.file.file_size = ssd->ftracker.tracker.file.file_offset;
-// FIXIT-L port file processing
-/*
- uint64_t fileId_persistent = alignedNtohq((const uint64_t *)(&(smb_close_hdr->fileId_persistent)));
- _dpd.fileAPI->file_cache_update_entry(fileCache, (void *)ssd->sd.wire_pkt,
- fileId_persistent, nullptr, 0, ssd->ftracker.tracker.file.file_size);
-*/
- DCE2_Smb2ProcessFileData(ssd, nullptr, 0, upload);
+ uint64_t fileId_persistent = alignedNtohq(&(smb_close_hdr->fileId_persistent));
+ FileContext* file = get_file_context(ssd, fileId_persistent);
+ if (file)
+ {
+ file->set_file_size(ssd->ftracker.tracker.file.file_size);
+ }
+
+ DCE2_Smb2ProcessFileData(ssd, nullptr, 0, dir);
}
}
uint64_t file_size = alignedNtohq((const uint64_t*)file_data);
DebugFormat(DEBUG_DCE_SMB, "Get file size %lu!\n", file_size);
ssd->ftracker.tracker.file.file_size = file_size;
-//FIXIT-L port file processing
-/*
- uint64_t fileId_persistent = alignedNtohq((const uint64_t *)(&(smb_set_info_hdr->fileId_persistent)));
- _dpd.fileAPI->file_cache_update_entry(fileCache, (void *)ssd->sd.wire_pkt,
- fileId_persistent, nullptr, 0, file_size);
-*/
+ uint64_t fileId_persistent = alignedNtohq(&(smb_set_info_hdr->fileId_persistent));
+ FileContext* file = get_file_context(ssd, fileId_persistent);
+ if (file)
+ {
+ file->set_file_size(ssd->ftracker.tracker.file.file_size);
+ }
}
}
}
DCE2_Smb2RemoveRequest(ssd, request);
- DCE2_Smb2ProcessFileData(ssd, file_data, data_size, false);
+ DCE2_Smb2ProcessFileData(ssd, file_data, data_size, FILE_DOWNLOAD);
ssd->ftracker.tracker.file.file_offset += data_size;
total_data_length = alignedNtohl((const uint32_t*)&(smb_read_hdr->length));
if (total_data_length > (uint32_t)data_size)
ssd->ftracker.tracker.file.file_direction = DCE2_SMB_FILE_DIRECTION__UPLOAD;
ssd->ftracker.tracker.file.file_offset = offset;
- DCE2_Smb2ProcessFileData(ssd, file_data, data_size, true);
+ DCE2_Smb2ProcessFileData(ssd, file_data, data_size, FILE_UPLOAD);
ssd->ftracker.tracker.file.file_offset += data_size;
total_data_length = alignedNtohl((const uint32_t*)&(smb_write_hdr->length));
if (total_data_length > (uint32_t)data_size)
else if (ssd->pdu_state == DCE2_SMB_PDU_STATE__RAW_DATA)
{
/*continue processing raw data*/
- bool upload = DCE2_SsnFromClient(ssd->sd.wire_pkt) ? true : false;
- DCE2_Smb2ProcessFileData(ssd, data_ptr, data_len, upload);
+ FileDirection dir = DCE2_SsnFromClient(ssd->sd.wire_pkt) ? FILE_UPLOAD : FILE_DOWNLOAD;
+ DCE2_Smb2ProcessFileData(ssd, data_ptr, data_len, dir);
ssd->ftracker.tracker.file.file_offset += data_len;
}
}
bool Dce2SmbModule::set(const char*, Value& v, SnortConfig*)
{
- if (dce2_set_common_config(v,config.common))
+ if (dce2_set_co_config(v,config.common))
return true;
- else if ( v.is("reassemble_threshold") )
- config.co_reassemble_threshold = v.get_long();
else if ( v.is("smb_fingerprint_policy") )
config.smb_fingerprint_policy = (dce2SmbFingerprintPolicy)v.get_long();
else if ( v.is("smb_max_chain") )
{
LogMessage("DCE SMB config: \n");
- print_dce2_common_config(config.common);
- LogMessage(" Reassemble Threshold : %d\n",
- config.co_reassemble_threshold);
+ print_dce2_co_config(config.common);
LogMessage(" SMB fingerprint policy : %s\n",
dce2SmbFingerprintPolicyStrings[config.smb_fingerprint_policy]);
struct dce2SmbProtoConf
{
- dce2CommonProtoConf common;
- uint16_t co_reassemble_threshold;
+ dce2CoProtoConf common;
dce2SmbFingerprintPolicy smb_fingerprint_policy;
uint8_t smb_max_chain;
uint8_t smb_max_compound;
#define DCE_SMB_PAF_H
#include "main/snort_types.h"
-#include "stream/stream_api.h"
#include "stream/stream_splitter.h"
#define DCE2_SMB_PAF_SHIFT(x64, x8) { x64 <<= 8; x64 |= (uint64_t)x8; }
DCE2_TcpSsnData* get_dce2_tcp_session_data(Flow* flow)
{
- Dce2TcpFlowData* fd = (Dce2TcpFlowData*)flow->get_application_data(
- Dce2TcpFlowData::flow_id);
-
+ Dce2TcpFlowData* fd = (Dce2TcpFlowData*)flow->get_flow_data(Dce2TcpFlowData::flow_id);
return fd ? &fd->dce2_tcp_session : nullptr;
}
Dce2TcpFlowData* fd = new Dce2TcpFlowData;
memset(&fd->dce2_tcp_session,0,sizeof(DCE2_TcpSsnData));
- p->flow->set_application_data(fd);
+ p->flow->set_flow_data(fd);
return(&fd->dce2_tcp_session);
}
bool Dce2TcpModule::set(const char*, Value& v, SnortConfig*)
{
- if (dce2_set_common_config(v,config.common))
+ if (dce2_set_co_config(v,config.common))
return true;
- else if ( v.is("reassemble_threshold") )
- config.co_reassemble_threshold = v.get_long();
- else
- return false;
- return true;
+
+ return false;
}
void Dce2TcpModule::get_data(dce2TcpProtoConf& dce2_tcp_config)
void print_dce2_tcp_conf(dce2TcpProtoConf& config)
{
LogMessage("DCE TCP config: \n");
-
- print_dce2_common_config(config.common);
- LogMessage(" Reassemble Threshold : %d\n",
- config.co_reassemble_threshold);
+ print_dce2_co_config(config.common);
}
struct dce2TcpProtoConf
{
- dce2CommonProtoConf common;
- uint16_t co_reassemble_threshold;
+ dce2CoProtoConf common;
};
class Dce2TcpModule : public Module
#include "dce_common.h"
#include "main/snort_types.h"
-#include "stream/stream_api.h"
#include "stream/stream_splitter.h"
#define DCE2_DEBUG__PAF_START_MSG_TCP "DCE/RPC over TCP PAF ====================================="
--- /dev/null
+//--------------------------------------------------------------------------
+// Copyright (C) 2016-2016 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.
+//--------------------------------------------------------------------------
+
+// dce_udp.cc author Maya Dagon <mdagon@cisco.com>
+// based on work by Todd Wease
+
+#include "dce_udp.h"
+#include "dce_udp_module.h"
+#include "main/snort_debug.h"
+#include "detection/detect.h"
+#include "log/messages.h"
+#include "protocols/packet_manager.h"
+#include "utils/util.h"
+
+THREAD_LOCAL int dce2_udp_inspector_instances = 0;
+
+THREAD_LOCAL dce2UdpStats dce2_udp_stats;
+
+THREAD_LOCAL ProfileStats dce2_udp_pstat_main;
+THREAD_LOCAL ProfileStats dce2_udp_pstat_session;
+THREAD_LOCAL ProfileStats dce2_udp_pstat_new_session;
+THREAD_LOCAL ProfileStats dce2_udp_pstat_detect;
+THREAD_LOCAL ProfileStats dce2_udp_pstat_log;
+THREAD_LOCAL ProfileStats dce2_udp_pstat_cl_acts;
+THREAD_LOCAL ProfileStats dce2_udp_pstat_cl_frag;
+THREAD_LOCAL ProfileStats dce2_udp_pstat_cl_reass;
+
+//-------------------------------------------------------------------------
+// class stuff
+//-------------------------------------------------------------------------
+Dce2UdpFlowData::Dce2UdpFlowData() : FlowData(flow_id)
+{
+}
+
+Dce2UdpFlowData::~Dce2UdpFlowData()
+{
+ // FIXIT-M add cl_tracker cleanup
+}
+
+unsigned Dce2UdpFlowData::flow_id = 0;
+
+class Dce2Udp : public Inspector
+{
+public:
+ Dce2Udp(dce2UdpProtoConf&);
+ void show(SnortConfig*) override;
+ void eval(Packet*) override;
+
+private:
+ dce2UdpProtoConf config;
+};
+
+Dce2Udp::Dce2Udp(dce2UdpProtoConf& pc)
+{
+ config = pc;
+}
+
+void Dce2Udp::show(SnortConfig*)
+{
+ print_dce2_udp_conf(config);
+}
+
+void Dce2Udp::eval(Packet*)
+{
+}
+
+//-------------------------------------------------------------------------
+// api stuff
+//-------------------------------------------------------------------------
+
+static Module* mod_ctor()
+{
+ return new Dce2UdpModule;
+}
+
+static void mod_dtor(Module* m)
+{
+ delete m;
+}
+
+static Inspector* dce2_udp_ctor(Module* m)
+{
+ Dce2UdpModule* mod = (Dce2UdpModule*)m;
+ dce2UdpProtoConf config;
+ mod->get_data(config);
+ return new Dce2Udp(config);
+}
+
+static void dce2_udp_dtor(Inspector* p)
+{
+ delete p;
+}
+
+static void dce2_udp_init()
+{
+ Dce2UdpFlowData::init();
+}
+
+static void dce2_udp_thread_init()
+{
+ dce2_udp_inspector_instances++;
+}
+
+static void dce2_udp_thread_term()
+{
+ dce2_udp_inspector_instances--;
+}
+
+const InspectApi dce2_udp_api =
+{
+ {
+ PT_INSPECTOR,
+ sizeof(InspectApi),
+ INSAPI_VERSION,
+ 0,
+ API_RESERVED,
+ API_OPTIONS,
+ DCE2_UDP_NAME,
+ DCE2_UDP_HELP,
+ mod_ctor,
+ mod_dtor
+ },
+ IT_SERVICE,
+ (uint16_t)PktType::UDP,
+ nullptr, // buffers
+ "dce_udp",
+ dce2_udp_init,
+ nullptr, // pterm
+ dce2_udp_thread_init, // tinit
+ dce2_udp_thread_term, // tterm
+ dce2_udp_ctor,
+ dce2_udp_dtor,
+ nullptr, // ssn
+ nullptr // reset
+};
+
--- /dev/null
+//--------------------------------------------------------------------------
+// Copyright (C) 2016-2016 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.
+//--------------------------------------------------------------------------
+
+//dce_tcp.h author Maya Dagon <mdagon@cisco.com>
+// based on work by Todd Wease
+
+#ifndef DCE_UDP_H
+#define DCE_UDP_H
+
+#include "dce_common.h"
+#include "dce_list.h"
+#include "protocols/packet.h"
+#include "profiler/profiler.h"
+#include "framework/counts.h"
+
+#define DCE2_UDP_NAME "dce_udp"
+#define DCE2_UDP_HELP "dce over udp inspection"
+
+struct dce2UdpStats
+{
+ /* The common stats block has to be at the beginning followed
+ by the protocol specific stats */
+
+ /*common stats -defined in common.h*/
+ PegCount events;
+ PegCount sessions_aborted;
+ PegCount bad_autodetects;
+
+ /*DCE UDP specific*/
+ PegCount udp_sessions;
+ PegCount udp_pkts;
+ PegCount cl_pkts;
+ PegCount cl_request;
+ PegCount cl_ack;
+ PegCount cl_cancel;
+ PegCount cl_cli_fack;
+ PegCount cl_ping;
+ PegCount cl_response;
+ PegCount cl_reject;
+ PegCount cl_cancel_ack;
+ PegCount cl_srv_fack;
+ PegCount cl_fault;
+ PegCount cl_nocall;
+ PegCount cl_working;
+ PegCount cl_other_req;
+ PegCount cl_other_resp;
+ PegCount cl_fragments;
+ PegCount cl_max_frag_size;
+ PegCount cl_frag_reassembled;
+ PegCount cl_max_seqnum;
+};
+
+extern THREAD_LOCAL dce2UdpStats dce2_udp_stats;
+extern THREAD_LOCAL ProfileStats dce2_udp_pstat_main;
+extern THREAD_LOCAL ProfileStats dce2_udp_pstat_session;
+extern THREAD_LOCAL ProfileStats dce2_udp_pstat_new_session;
+extern THREAD_LOCAL ProfileStats dce2_udp_pstat_detect;
+extern THREAD_LOCAL ProfileStats dce2_udp_pstat_log;
+extern THREAD_LOCAL ProfileStats dce2_udp_pstat_cl_acts;
+extern THREAD_LOCAL ProfileStats dce2_udp_pstat_cl_frag;
+extern THREAD_LOCAL ProfileStats dce2_udp_pstat_cl_reass;
+
+struct DCE2_ClTracker
+{
+ DCE2_List* act_trackers; /* List of activity trackers */
+};
+
+struct DCE2_UdpSsnData
+{
+ DCE2_SsnData sd; // This member must be first
+ DCE2_ClTracker cl_tracker;
+};
+
+class Dce2UdpFlowData : public FlowData
+{
+public:
+ Dce2UdpFlowData();
+ ~Dce2UdpFlowData();
+
+ static void init()
+ {
+ flow_id = FlowData::get_flow_id();
+ }
+
+public:
+ static unsigned flow_id;
+ DCE2_UdpSsnData dce2_udp_session;
+};
+
+#endif
+
--- /dev/null
+//--------------------------------------------------------------------------
+// Copyright (C) 2016-2016 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.
+//--------------------------------------------------------------------------
+
+// dce_udp_module.cc author Maya Dagon <mdagon@cisco.com>
+
+#include "dce_udp_module.h"
+#include "dce_udp.h"
+#include "dce_common.h"
+#include "main/snort_config.h"
+
+using namespace std;
+
+static const Parameter s_params[] =
+{
+ { "disable_defrag", Parameter::PT_BOOL, nullptr, "false",
+ " Disable DCE/RPC defragmentation" },
+ { "max_frag_len", Parameter::PT_INT, "1514:65535", "65535",
+ " Maximum fragment size for defragmentation" },
+ { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
+};
+
+static const RuleMap dce2_udp_rules[] =
+{
+ { DCE2_CL_BAD_MAJOR_VERSION, DCE2_CL_BAD_MAJOR_VERSION_STR },
+ { DCE2_CL_BAD_PDU_TYPE, DCE2_CL_BAD_PDU_TYPE_STR },
+ { DCE2_CL_DATA_LT_HDR, DCE2_CL_DATA_LT_HDR_STR },
+ { DCE2_CL_BAD_SEQ_NUM, DCE2_CL_BAD_SEQ_NUM_STR },
+ { 0, nullptr }
+};
+
+static const PegInfo dce2_udp_pegs[] =
+{
+ { "events", "total events" },
+ { "aborted sessions", "total aborted sessions" },
+ { "bad autodetects", "total bad autodetects" },
+ { "udp sessions", "total udp sessions" },
+ { "udp packets", "total udp packets" },
+ { "Requests", "total connection-less requests" },
+ { "Acks", "total connection-less acks" },
+ { "Cancels", "total connection-less cancels" },
+ { "Client facks", "total connection-less client facks" },
+ { "Ping", "total connection-less ping" },
+ { "Responses", "total connection-less responses" },
+ { "Rejects", "total connection-less rejects" },
+ { "Cancel acks", "total connection-less cancel acks" },
+ { "Server facks", "total connection-less server facks" },
+ { "Faults", "total connection-less faults" },
+ { "No calls", "total connection-less no calls" },
+ { "Working", "total connection-less working" },
+ { "Other requests", "total connection-less other requests" },
+ { "Other responses", "total connection-less other responses" },
+ { "Fragments", "total connection-less fragments" },
+ { "Max fragment size",
+ "connection-less maximum fragment size" },
+ { "Frags reassembled",
+ "total connection-less fragments reassembled" },
+ { "Max seqnum",
+ "max connection-less seqnum" },
+ { nullptr, nullptr }
+};
+
+Dce2UdpModule::Dce2UdpModule() : Module(DCE2_UDP_NAME, DCE2_UDP_HELP, s_params)
+{
+}
+
+const RuleMap* Dce2UdpModule::get_rules() const
+{
+ return dce2_udp_rules;
+}
+
+const PegInfo* Dce2UdpModule::get_pegs() const
+{
+ return dce2_udp_pegs;
+}
+
+PegCount* Dce2UdpModule::get_counts() const
+{
+ return (PegCount*)&dce2_udp_stats;
+}
+
+ProfileStats* Dce2UdpModule::get_profile(
+ unsigned index, const char*& name, const char*& parent) const
+{
+ switch ( index )
+ {
+ case 0:
+ name = "dce_udp_main";
+ parent = nullptr;
+ return &dce2_udp_pstat_main;
+
+ case 1:
+ name = "dce_udp_session";
+ parent = "dce_udp_main";
+ return &dce2_udp_pstat_session;
+
+ case 2:
+ name = "dce_udp_new_session";
+ parent = "dce_udp_session";
+ return &dce2_udp_pstat_new_session;
+
+ case 3:
+ name = "dce_udp_detect";
+ parent = "dce_udp_main";
+ return &dce2_udp_pstat_detect;
+
+ case 4:
+ name = "dce_udp_log";
+ parent = "dce_udp_main";
+ return &dce2_udp_pstat_log;
+
+ case 5:
+ name = "dce_udp_cl_acts";
+ parent = "dce_udp_main";
+ return &dce2_udp_pstat_cl_acts;
+
+ case 6:
+ name = "dce_udp_cl_frag";
+ parent = "dce_udp_main";
+ return &dce2_udp_pstat_cl_frag;
+
+ case 7:
+ name = "dce_udp_cl_reass";
+ parent = "dce_udp_main";
+ return &dce2_udp_pstat_cl_reass;
+ }
+ return nullptr;
+}
+
+bool Dce2UdpModule::set(const char*, Value& v, SnortConfig*)
+{
+ if (dce2_set_common_config(v,config.common))
+ return true;
+ else
+ return false;
+}
+
+void Dce2UdpModule::get_data(dce2UdpProtoConf& dce2_udp_config)
+{
+ dce2_udp_config = config;
+}
+
+void print_dce2_udp_conf(dce2UdpProtoConf& config)
+{
+ LogMessage("DCE UDP config: \n");
+ print_dce2_common_config(config.common);
+}
+
--- /dev/null
+//--------------------------------------------------------------------------
+// Copyright (C) 2016-2016 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.
+//--------------------------------------------------------------------------
+//
+// dce_udp_module.h author Maya Dagon <mdagon@cisco.com>
+
+#ifndef DCE2_UDP_MODULE_H
+#define DCE2_UDP_MODULE_H
+
+#include "dce_common.h"
+#include "framework/module.h"
+
+#define DCE2_CL_BAD_MAJOR_VERSION 40
+#define DCE2_CL_BAD_PDU_TYPE 41
+#define DCE2_CL_DATA_LT_HDR 42
+#define DCE2_CL_BAD_SEQ_NUM 43
+
+#define DCE2_CL_BAD_MAJOR_VERSION_STR "Connection-less DCE/RPC - Invalid major version."
+#define DCE2_CL_BAD_PDU_TYPE_STR "Connection-less DCE/RPC - Invalid pdu type."
+#define DCE2_CL_DATA_LT_HDR_STR \
+ "Connection-less DCE/RPC - Data length less than header size."
+#define DCE2_CL_BAD_SEQ_NUM_STR \
+ "Connection-less DCE/RPC - Bad sequence number."
+
+struct SnortConfig;
+
+struct dce2UdpProtoConf
+{
+ dce2CommonProtoConf common;
+};
+
+class Dce2UdpModule : public Module
+{
+public:
+ Dce2UdpModule();
+
+ bool set(const char*, Value&, SnortConfig*) override;
+
+ unsigned get_gid() const override
+ {
+ return GID_DCE2;
+ }
+
+ const RuleMap* get_rules() const override;
+ const PegInfo* get_pegs() const override;
+ PegCount* get_counts() const override;
+ ProfileStats* get_profile(unsigned, const char*&, const char*&) const override;
+ void get_data(dce2UdpProtoConf&);
+
+private:
+ dce2UdpProtoConf config;
+};
+
+void print_dce2_udp_conf(dce2UdpProtoConf& config);
+
+#endif
+
#include "framework/range.h"
#include "detection/detect.h"
#include "detection/detection_defines.h"
+#include "detection/pattern_match_data.h"
#include "hash/sfhashfcn.h"
#include "profiler/profiler.h"
+#include "target_based/snort_protocols.h"
+#include "main/snort_debug.h"
//-------------------------------------------------------------------------
// dcerpc2 interface rule options
{
public:
Dce2IfaceOption(RangeCheck iface_version, bool iface_any_frag, Uuid iface_uuid) :
- IpsOption(s_name)
- { version = iface_version; any_frag = iface_any_frag; uuid = iface_uuid; }
+ IpsOption(s_name), version(iface_version), any_frag(iface_any_frag), uuid(iface_uuid)
+ {
+ memset(&pmd, 0, sizeof(pmd));
+ }
uint32_t hash() const override;
bool operator==(const IpsOption&) const override;
int eval(Cursor&, Packet*) override;
+ PatternMatchData* get_pattern(int proto, RuleDirection direction) override;
+ ~Dce2IfaceOption();
private:
- RangeCheck version;
- bool any_frag;
- Uuid uuid;
+ const RangeCheck version;
+ const bool any_frag;
+ const Uuid uuid;
+ PatternMatchData pmd;
};
+Dce2IfaceOption::~Dce2IfaceOption()
+{
+ if ( pmd.pattern_buf)
+ {
+ snort_free((char*)pmd.pattern_buf);
+ }
+}
+
+PatternMatchData* Dce2IfaceOption::get_pattern(int proto, RuleDirection direction)
+{
+ if (pmd.pattern_buf)
+ {
+ return &pmd;
+ }
+
+ if (proto == SNORT_PROTO_TCP)
+ {
+ const char client_fp[] = "\x05\x00\x00";
+ const char server_fp[] = "\x05\x00\x02";
+ const char no_dir_fp[] = "\x05\x00";
+
+ switch (direction)
+ {
+ case RULE_FROM_CLIENT:
+ pmd.pattern_size = 3;
+ pmd.pattern_buf = (char*)snort_alloc(pmd.pattern_size);
+ memcpy((void*)pmd.pattern_buf, client_fp, pmd.pattern_size);
+ break;
+
+ case RULE_FROM_SERVER:
+ pmd.pattern_size = 3;
+ pmd.pattern_buf = (char*)snort_alloc(pmd.pattern_size);
+ memcpy((void*)pmd.pattern_buf, server_fp, pmd.pattern_size);
+ break;
+
+ default:
+ pmd.pattern_size = 2;
+ pmd.pattern_buf = (char*)snort_alloc(pmd.pattern_size);
+ memcpy((void*)pmd.pattern_buf, no_dir_fp, pmd.pattern_size);
+ break;
+ }
+ return &pmd;
+ }
+ // FIXIT-L add udp fast pattern
+
+ return nullptr;
+}
+
uint32_t Dce2IfaceOption::hash() const
{
uint32_t a, b, c;
bool Dce2IfaceOption::operator==(const IpsOption& ips) const
{
- if ( strcmp(get_name(), ips.get_name()) )
- return false;
-
- const Dce2IfaceOption& rhs = (Dce2IfaceOption&)ips;
-
- if ((DCE2_UuidCompare(&uuid, &rhs.uuid) == 0) &&
- (version == rhs.version) &&
- (any_frag == rhs.any_frag))
- {
- return true;
- }
-
- return false;
+ // FIXIT-L
+ // Fast pattern is calculated only after the entire rule is parsed.
+ // The rule option can be mistaken as a duplicate because we don't take the fast pattern into
+ // account. Instead of comparing values, make sure it is the same object.
+ return this == &ips;
}
int Dce2IfaceOption::eval(Cursor&, Packet* p)
static dnp3_session_data_t* get_session_data(Flow* flow)
{
- Dnp3FlowData* fd = (Dnp3FlowData*)flow->get_application_data(
- Dnp3FlowData::flow_id);
-
+ Dnp3FlowData* fd = (Dnp3FlowData*)flow->get_flow_data(Dnp3FlowData::flow_id);
return fd ? &fd->dnp3_session : nullptr;
}
static dnp3_session_data_t* set_new_dnp3_session(Packet* p)
{
Dnp3FlowData* fd = new Dnp3FlowData;
-
- p->flow->set_application_data(fd);
+ p->flow->set_flow_data(fd);
return(&fd->dnp3_session);
}
// Protocol aware flushing for DNP3.
#include "main/snort_types.h"
-#include "stream/stream_api.h"
#include "stream/stream_splitter.h"
enum dnp3_paf_state
if ((p->has_tcp_data() && !p->is_full_pdu()) || !p->flow || !p->dsize)
return DETECTION_OPTION_NO_MATCH;
- Dnp3FlowData* fd = (Dnp3FlowData*)p->flow->get_application_data(
- Dnp3FlowData::flow_id);
+ Dnp3FlowData* fd = (Dnp3FlowData*)p->flow->get_flow_data(Dnp3FlowData::flow_id);
if (!fd)
return DETECTION_OPTION_NO_MATCH;
if ((p->has_tcp_data() && !p->is_full_pdu()) || !p->flow || !p->dsize)
return DETECTION_OPTION_NO_MATCH;
- Dnp3FlowData* fd = (Dnp3FlowData*)p->flow->get_application_data(
- Dnp3FlowData::flow_id);
+ Dnp3FlowData* fd = (Dnp3FlowData*)p->flow->get_flow_data(Dnp3FlowData::flow_id);
if (!fd)
return DETECTION_OPTION_NO_MATCH;
if ((p->has_tcp_data() && !p->is_full_pdu()) || !p->flow || !p->dsize)
return DETECTION_OPTION_NO_MATCH;
- Dnp3FlowData* fd = (Dnp3FlowData*)p->flow->get_application_data(
- Dnp3FlowData::flow_id);
+ Dnp3FlowData* fd = (Dnp3FlowData*)p->flow->get_flow_data(Dnp3FlowData::flow_id);
if (!fd)
return DETECTION_OPTION_NO_MATCH;
if ((p->has_tcp_data() && !p->is_full_pdu()) || !p->flow || !p->dsize)
return DETECTION_OPTION_NO_MATCH;
- Dnp3FlowData* fd = (Dnp3FlowData*)p->flow->get_application_data(
- Dnp3FlowData::flow_id);
+ Dnp3FlowData* fd = (Dnp3FlowData*)p->flow->get_flow_data(Dnp3FlowData::flow_id);
if (!fd)
return DETECTION_OPTION_NO_MATCH;
#include "main/snort_types.h"
#include "main/snort_debug.h"
#include "profiler/profiler.h"
-#include "stream/stream_api.h"
#include "parser/parser.h"
#include "framework/inspector.h"
+#include "stream/stream.h"
#include "utils/sfsnprintfappend.h"
#include "dns_module.h"
fd = new DnsFlowData;
- p->flow->set_application_data(fd);
+ p->flow->set_flow_data(fd);
return &fd->session;
}
return &udpSessionData;
}
- fd = (DnsFlowData*)((p->flow)->get_application_data(
- DnsFlowData::flow_id));
-
+ fd = (DnsFlowData*)((p->flow)->get_flow_data(DnsFlowData::flow_id));
return fd ? &fd->session : NULL;
}
return;
}
- if ( !stream.is_stream_sequenced(p->flow, SSN_DIR_FROM_CLIENT) )
+ if ( !Stream::is_stream_sequenced(p->flow, SSN_DIR_FROM_CLIENT) )
{
return;
}
#define DNS_H
#include "protocols/packet.h"
-#include "stream/stream_api.h"
// Implementation header with definitions, datatypes and flowdata class for
// DNS service inspector.
// FIXIT-L breaks target-based non-standard ports
//if ( !ScPafEnabled() )
/* Force flush of client side of stream */
- stream.flush_response(p);
+ Stream::flush_response(p);
}
else
{
if (p->flow)
{
- FtpFlowData* fd = (FtpFlowData*)p->flow->get_application_data(FtpFlowData::flow_id);
+ FtpFlowData* fd = (FtpFlowData*)p->flow->get_flow_data(FtpFlowData::flow_id);
ft_ssn = fd ? &fd->session.ft_ssn : nullptr;
if (ft_ssn != NULL)
{
/* XXX - Not FTP or Telnet */
assert(false);
- p->flow->free_application_data(FtpFlowData::flow_id);
+ p->flow->free_flow_data(FtpFlowData::flow_id);
return 0;
}
}
return -1;
FtpDataFlowData* fd = (FtpDataFlowData*)
- p->flow->get_application_data(FtpFlowData::flow_id);
+ p->flow->get_flow_data(FtpFlowData::flow_id);
FTP_DATA_SESSION* data_ssn = fd ? &fd->session : nullptr;
/* FTP-Data session is in limbo, we need to lookup the control session
* to figure out what to do. */
- FtpFlowData* fd = (FtpFlowData*)stream.get_application_data_from_key(
+ FtpFlowData* fd = (FtpFlowData*)Stream::get_flow_data(
&data_ssn->ftp_key, FtpFlowData::flow_id);
FTP_SESSION* ftp_ssn = fd ? &fd->session : NULL;
memset(&session, 0, sizeof(session));
session.ft_ssn.proto = FTPP_SI_PROTO_FTP_DATA;
- stream.populate_session_key(p, &session.ftp_key);
+ Stream::populate_flow_key(p, &session.ftp_key);
}
FtpDataFlowData::~FtpDataFlowData()
initFilePosition(&data_ssn->position, get_file_processed_size(p->flow));
finalFilePosition(&data_ssn->position);
- stream.flush_request(p);
+ Stream::flush_request(p);
if (!(data_ssn->packet_flags & FTPDATA_FLG_STOP))
{
#include "ftpp_return_codes.h"
#include "sfip/sf_ip.h"
+#include "stream/stream.h"
#include "utils/util.h"
unsigned FtpFlowData::flow_id = 0;
SiInput->pproto = FTPP_SI_PROTO_TELNET;
- p->flow->set_application_data(fd);
+ p->flow->set_flow_data(fd);
*Telnetsession = Newsession;
return FTPP_SUCCESS;
bool FTPDataDirection(Packet* p, FTP_DATA_SESSION* ftpdata)
{
uint32_t direction;
- uint32_t pktdir = stream.get_packet_direction(p);
+ uint32_t pktdir = Stream::get_packet_direction(p);
if (ftpdata->mode == FTPP_XFER_ACTIVE)
direction = ftpdata->direction ? PKT_FROM_SERVER : PKT_FROM_CLIENT;
Newsession->client_conf = ClientConf;
Newsession->server_conf = ServerConf;
- p->flow->set_application_data(fd);
+ p->flow->set_flow_data(fd);
*Ftpsession = Newsession;
SiInput->pproto = FTPP_SI_PROTO_FTP;
/*
* We now set the packet direction
*/
- if (p->flow && stream.is_midstream(p->flow))
+ if (p->flow && Stream::is_midstream(p->flow))
{
SiInput->pdir = FTPP_SI_NO_MODE;
}
#include "ftp_server.h"
#include "protocols/packet.h"
#include "file_api/file_api.h"
-#include "stream/stream_api.h"
#include "flow/flow.h"
+#include "stream/stream.h"
/*
* These are the defines for the different types of
ftpdata->data_chan = session->server_conf->data_chan;
/* Call into Streams to mark data channel as ftp-data */
- result = stream.set_application_protocol_id_expected(
+ result = Stream::set_application_protocol_id_expected(
&session->clientIP, session->clientPort,
&session->serverIP, session->serverPort,
p->type(), ftp_data_app_id, fd);
{
/* Call into Streams to mark data channel as something
* to ignore. */
- stream.ignore_session(
+ Stream::ignore_flow(
&session->clientIP, session->clientPort,
&session->serverIP, session->serverPort,
p->type(), SSN_DIR_BOTH,
ftpdata->data_chan = session->server_conf->data_chan;
/* Call into Streams to mark data channel as ftp-data */
- result = stream.set_application_protocol_id_expected(
+ result = Stream::set_application_protocol_id_expected(
&session->clientIP, session->clientPort,
&session->serverIP, session->serverPort,
p->type(), ftp_data_app_id, fd);
{
/* Call into Streams to mark data channel as something
* to ignore. */
- stream.ignore_session(
+ Stream::ignore_flow(
&session->clientIP, session->clientPort,
&session->serverIP, session->serverPort,
p->type(), SSN_DIR_BOTH,
if (!ftpssn->server_conf->check_encrypted_data)
{
/* Mark this session & packet as one to ignore */
- stream.stop_inspection(p->flow, p, SSN_DIR_BOTH, -1, 0);
+ Stream::stop_inspection(p->flow, p, SSN_DIR_BOTH, -1, 0);
}
DebugMessage(DEBUG_FTPTELNET,
"FTP client stream is now encrypted\n");
if (!ftpssn->server_conf->check_encrypted_data)
{
/* Mark this session & packet as one to ignore */
- stream.stop_inspection(p->flow, p, SSN_DIR_BOTH, -1, 0);
+ Stream::stop_inspection(p->flow, p, SSN_DIR_BOTH, -1, 0);
}
DebugMessage(DEBUG_FTPTELNET,
"FTP server stream is now encrypted\n");
else
{
/* Okay, it wasn't an IAC also its a midstream pickup */
- if (*read_ptr > 0x7F && stream.is_midstream(p->flow))
+ if (*read_ptr > 0x7F && Stream::is_midstream(p->flow))
{
consec_8bit_chars++;
if (consec_8bit_chars > CONSECUTIVE_8BIT_THRESHOLD)
if (!tnssn->telnet_conf->check_encrypted_data)
{
/* Mark this session & packet as one to ignore */
- stream.stop_inspection(p->flow, p, SSN_DIR_BOTH, -1, 0);
+ Stream::stop_inspection(p->flow, p, SSN_DIR_BOTH, -1, 0);
/* No point to do further normalization */
return FTPP_ALERT;
}
if (!tnssn->telnet_conf->check_encrypted_data)
{
/* Mark this session & packet as one to ignore */
- stream.stop_inspection(p->flow, p, SSN_DIR_BOTH, -1, 0);
+ Stream::stop_inspection(p->flow, p, SSN_DIR_BOTH, -1, 0);
/* No point to do further normalization */
return FTPP_ALERT;
}
if (p->flow)
{
TelnetFlowData* fd = (TelnetFlowData*)
- p->flow->get_application_data(FtpFlowData::flow_id);
+ p->flow->get_flow_data(FtpFlowData::flow_id);
ft_ssn = fd ? &fd->session.ft_ssn : nullptr;
else
{
assert(false);
- p->flow->free_application_data(FtpFlowData::flow_id);
+ p->flow->free_flow_data(FtpFlowData::flow_id);
return 0;
}
}
static GTP_Roptions* GTPGetNewSession(Packet* packetp)
{
GtpFlowData* gfd = new GtpFlowData;
- packetp->flow->set_application_data(gfd);
+ packetp->flow->set_flow_data(gfd);
GTP_Roptions* pRopts = &gfd->ropts;
gtp_stats.sessions++;
void GTPmain(Packet* packetp)
{
/* Attempt to get a previously allocated GTP block. */
- GtpFlowData* gfd = (GtpFlowData*)packetp->flow->get_application_data(GtpFlowData::flow_id);
+ GtpFlowData* gfd = (GtpFlowData*)packetp->flow->get_flow_data(GtpFlowData::flow_id);
GTP_Roptions* pRopts = gfd ? &gfd->ropts : nullptr;
if ( !pRopts )
if ( !p or !p->flow )
return DETECTION_OPTION_NO_MATCH;
- GtpFlowData* gfd = (GtpFlowData*)p->flow->get_application_data(GtpFlowData::flow_id);
+ GtpFlowData* gfd = (GtpFlowData*)p->flow->get_flow_data(GtpFlowData::flow_id);
if ( !gfd or !gfd->ropts.gtp_infoElements )
return DETECTION_OPTION_NO_MATCH;
if ( !p or !p->flow )
return DETECTION_OPTION_NO_MATCH;
- GtpFlowData* gfd = (GtpFlowData*)p->flow->get_application_data(GtpFlowData::flow_id);
+ GtpFlowData* gfd = (GtpFlowData*)p->flow->get_flow_data(GtpFlowData::flow_id);
if ( !gfd )
return DETECTION_OPTION_NO_MATCH;
if ( !p or !p->flow )
return DETECTION_OPTION_NO_MATCH;
- GtpFlowData* gfd = (GtpFlowData*)p->flow->get_application_data(GtpFlowData::flow_id);
+ GtpFlowData* gfd = (GtpFlowData*)p->flow->get_flow_data(GtpFlowData::flow_id);
if ( gfd and version == gfd->ropts.gtp_version )
return DETECTION_OPTION_MATCH;
#include <stdio.h>
#include <zlib.h>
-#include "stream/stream_api.h"
+#include "flow/flow.h"
#include "mime/file_mime_process.h"
#include "utils/util_utf.h"
#include <stdio.h>
#include "main/snort_types.h"
-#include "stream/stream_api.h"
#include "http_enum.h"
#include "http_msg_request.h"
const Field& HttpInspect::process(const uint8_t* data, const uint16_t dsize, Flow* const flow,
SourceId source_id, bool buf_owner) const
{
- HttpFlowData* session_data = (HttpFlowData*)flow->get_application_data(
- HttpFlowData::http_flow_id);
+ HttpFlowData* session_data = (HttpFlowData*)flow->get_flow_data(HttpFlowData::http_flow_id);
assert(session_data != nullptr);
HttpModule::increment_peg_counts(PEG_INSPECT);
latest_section = nullptr;
HttpFlowData* session_data =
- (HttpFlowData*)p->flow->get_application_data(HttpFlowData::http_flow_id);
+ (HttpFlowData*)p->flow->get_flow_data(HttpFlowData::http_flow_id);
if (session_data == nullptr)
return;
#ifndef HTTP_MSG_SECTION_H
#define HTTP_MSG_SECTION_H
-#include "stream/stream_api.h"
#include "detection/detection_util.h"
#include "http_field.h"
assert(total <= MAX_OCTETS);
- HttpFlowData* session_data = (HttpFlowData*)flow->get_application_data(
- HttpFlowData::http_flow_id);
+ HttpFlowData* session_data = (HttpFlowData*)flow->get_flow_data(HttpFlowData::http_flow_id);
assert(session_data != nullptr);
#ifdef REG_TEST
// This is the session state information we share with HttpInspect and store with stream. A
// session is defined by a TCP connection. Since scan() is the first to see a new TCP
// connection the new flow data object is created here.
- HttpFlowData* session_data = (HttpFlowData*)flow->get_application_data(
- HttpFlowData::http_flow_id);
+ HttpFlowData* session_data = (HttpFlowData*)flow->get_flow_data(HttpFlowData::http_flow_id);
+
if (session_data == nullptr)
{
- flow->set_application_data(session_data = new HttpFlowData);
+ flow->set_flow_data(session_data = new HttpFlowData);
HttpModule::increment_peg_counts(PEG_FLOW);
}
bool HttpStreamSplitter::finish(Flow* flow)
{
- HttpFlowData* session_data = (HttpFlowData*)flow->get_application_data(
- HttpFlowData::http_flow_id);
-
+ HttpFlowData* session_data = (HttpFlowData*)flow->get_flow_data(HttpFlowData::http_flow_id);
assert(session_data != nullptr);
#ifdef REG_TEST
#include "main/snort_types.h"
#include "main/snort_debug.h"
#include "profiler/profiler.h"
-#include "stream/stream_api.h"
#include "file_api/file_api.h"
#include "parser/parser.h"
#include "framework/inspector.h"
#include "utils/util.h"
#include "protocols/ssl.h"
#include "mime/file_mime_process.h"
+#include "stream/stream.h"
#include "imap_paf.h"
#include "imap_module.h"
unsigned ImapFlowData::flow_id = 0;
static IMAPData* get_session_data(Flow* flow)
{
- ImapFlowData* fd = (ImapFlowData*)flow->get_application_data(
- ImapFlowData::flow_id);
-
+ ImapFlowData* fd = (ImapFlowData*)flow->get_flow_data(ImapFlowData::flow_id);
return fd ? &fd->session : NULL;
}
IMAPData* imap_ssn;
ImapFlowData* fd = new ImapFlowData;
- p->flow->set_application_data(fd);
+ p->flow->set_flow_data(fd);
imap_ssn = &fd->session;
imapstats.sessions++;
(p->packet_flags & PKT_REBUILT_STREAM))
{
int missing_in_rebuilt =
- stream.missing_in_reassembled(p->flow, SSN_DIR_FROM_CLIENT);
+ Stream::missing_in_reassembled(p->flow, SSN_DIR_FROM_CLIENT);
if (ssn->session_flags & IMAP_FLAG_NEXT_STATE_UNKNOWN)
{
imap_ssn->state = STATE_TLS_DATA;
}
else if (!(p->flow->get_session_flags() & SSNFLAG_MIDSTREAM)
- && !stream.missed_packets(p->flow, SSN_DIR_BOTH))
+ && !Stream::missed_packets(p->flow, SSN_DIR_BOTH))
{
/* revert back to command state - assume server didn't accept STARTTLS */
imap_ssn->state = STATE_UNKNOWN;
// IMAP service inspector.
#include "protocols/packet.h"
-#include "stream/stream_api.h"
+#include "stream/stream.h"
#include "imap_config.h"
// Direction packet is coming from, if we can figure it out
if ( !flow )
return nullptr;
- ImapSplitter* s = (ImapSplitter*)stream.get_splitter(flow, c2s);
+ ImapSplitter* s = (ImapSplitter*)Stream::get_splitter(flow, c2s);
return s ? &s->state : nullptr;
}
// Protocol aware flushing for IMAP
#include "main/snort_types.h"
-#include "stream/stream_api.h"
#include "stream/stream_splitter.h"
#include "mime/file_mime_paf.h"
return DETECTION_OPTION_NO_MATCH;
ModbusFlowData* mfd =
- (ModbusFlowData*)p->flow->get_application_data(ModbusFlowData::flow_id);
+ (ModbusFlowData*)p->flow->get_flow_data(ModbusFlowData::flow_id);
if ( mfd and func == mfd->ssn_data.func )
return DETECTION_OPTION_MATCH;
return DETECTION_OPTION_NO_MATCH;
ModbusFlowData* mfd =
- (ModbusFlowData*)p->flow->get_application_data(ModbusFlowData::flow_id);
+ (ModbusFlowData*)p->flow->get_flow_data(ModbusFlowData::flow_id);
if ( mfd and unit == mfd->ssn_data.unit )
return DETECTION_OPTION_MATCH;
assert(p->has_tcp_data());
ModbusFlowData* mfd =
- (ModbusFlowData*)p->flow->get_application_data(ModbusFlowData::flow_id);
+ (ModbusFlowData*)p->flow->get_flow_data(ModbusFlowData::flow_id);
if ( !p->is_full_pdu() )
{
if ( !mfd )
{
mfd = new ModbusFlowData;
- p->flow->set_application_data(mfd);
+ p->flow->set_flow_data(mfd);
modbus_stats.sessions++;
}
#include "modbus.h"
#include "modbus_module.h"
#include "protocols/packet.h"
-#include "stream/stream_api.h"
#include "events/event_queue.h"
// FIXIT-L convert this stuff to a table and make configurable
return false;
ModbusFlowData* mfd =
- (ModbusFlowData*)p->flow->get_application_data(ModbusFlowData::flow_id);
+ (ModbusFlowData*)p->flow->get_flow_data(ModbusFlowData::flow_id);
/* Lay the header struct over the payload */
header = (modbus_header_t*)p->data;
#include "main/snort_types.h"
#include "main/snort_debug.h"
#include "profiler/profiler.h"
-#include "stream/stream_api.h"
#include "parser/parser.h"
#include "framework/inspector.h"
#include "target_based/snort_protocols.h"
unsigned PopFlowData::flow_id = 0;
static POPData* get_session_data(Flow* flow)
{
- PopFlowData* fd = (PopFlowData*)flow->get_application_data(
- PopFlowData::flow_id);
-
+ PopFlowData* fd = (PopFlowData*)flow->get_flow_data(PopFlowData::flow_id);
return fd ? &fd->session : NULL;
}
POPData* pop_ssn;
PopFlowData* fd = new PopFlowData;
- p->flow->set_application_data(fd);
+ p->flow->set_flow_data(fd);
pop_ssn = &fd->session;
popstats.sessions++;
(p->packet_flags & PKT_REBUILT_STREAM))
{
int missing_in_rebuilt =
- stream.missing_in_reassembled(p->flow, SSN_DIR_FROM_CLIENT);
+ Stream::missing_in_reassembled(p->flow, SSN_DIR_FROM_CLIENT);
if (ssn->session_flags & POP_FLAG_NEXT_STATE_UNKNOWN)
{
pop_ssn->state = STATE_TLS_DATA;
}
else if (!(p->flow->get_session_flags() & SSNFLAG_MIDSTREAM)
- && !stream.missed_packets(p->flow, SSN_DIR_BOTH))
+ && !Stream::missed_packets(p->flow, SSN_DIR_BOTH))
{
/* revert back to command state - assume server didn't accept STARTTLS */
pop_ssn->state = STATE_UNKNOWN;
// POP service inspector.
#include "protocols/packet.h"
-#include "stream/stream_api.h"
+#include "stream/stream.h"
#include "pop_config.h"
// Direction packet is coming from, if we can figure it out
if ( !flow )
return nullptr;
- PopSplitter* s = (PopSplitter*)stream.get_splitter(flow, c2s);
+ PopSplitter* s = (PopSplitter*)Stream::get_splitter(flow, c2s);
return s ? &s->state : nullptr;
}
// Protocol aware flushing for POP.
#include "main/snort_types.h"
-#include "stream/stream_api.h"
#include "stream/stream_splitter.h"
#include "mime/file_mime_paf.h"
#include "profiler/profiler.h"
#include "utils/util.h"
#include "detection/detection_util.h"
-#include "stream/stream_api.h"
#include "stream/stream_splitter.h"
#include "target_based/snort_protocols.h"
#include "protocols/tcp.h"
#include "protocols/packet.h"
#include "framework/data_bus.h"
#include "framework/inspector.h"
+#include "stream/stream.h"
#include "utils/safec.h"
#include "rpc_module.h"
RpcSsnData* rsdata = &fd->session;
rsdata->active = 1;
- p->flow->set_application_data(fd);
+ p->flow->set_flow_data(fd);
DebugFormat(DEBUG_RPC, "STATEFUL: Created new session: " "%p\n", (void*) rsdata);
return rsdata;
if ( p->flow )
{
- RpcFlowData* fd = (RpcFlowData*)p->flow->get_application_data(
- RpcFlowData::flow_id);
+ RpcFlowData* fd = (RpcFlowData*)p->flow->get_flow_data(RpcFlowData::flow_id);
if ( fd )
rsdata = &fd->session;
++rdstats.total_packets;
- if ( !rsdata && p->flow && !stream.is_midstream(p->flow) )
+ if ( !rsdata && p->flow && !Stream::is_midstream(p->flow) )
rsdata = RpcSsnDataNew(p);
if ( RpcSsnIsActive(rsdata) and (p->packet_flags & PKT_REBUILT_STREAM) )
extern const BaseApi* sin_bo;
extern const BaseApi* sin_dce_smb;
extern const BaseApi* sin_dce_tcp;
+extern const BaseApi* sin_dce_udp;
extern const BaseApi* sin_dnp3;
extern const BaseApi* sin_dns;
extern const BaseApi* sin_ftp_client;
sin_bo,
sin_dce_smb,
sin_dce_tcp,
+ sin_dce_udp,
sin_dnp3,
sin_dns,
sin_ftp_client,
#include "main/snort_debug.h"
#include "main/snort_config.h"
#include "profiler/profiler.h"
-#include "stream/stream_api.h"
#include "file_api/file_api.h"
#include "parser/parser.h"
#include "framework/inspector.h"
MaxSessionsAlerted = 0;
}
SipFlowData* fd = new SipFlowData;
- p->flow->set_application_data(fd);
+ p->flow->set_flow_data(fd);
numSessions++;
return &fd->session;
}
SIPData* get_sip_session_data(Flow* flow)
{
- SipFlowData* fd = (SipFlowData*)flow->get_application_data(
- SipFlowData::flow_id);
-
+ SipFlowData* fd = (SipFlowData*)flow->get_flow_data(SipFlowData::flow_id);
return fd ? &fd->session : NULL;
}
// Implementation header with definitions, datatypes and flowdata class for SIP service inspector.
#include "protocols/packet.h"
-#include "stream/stream_api.h"
#include "sip_config.h"
#include "sip_dialog.h"
#include "sip_parser.h"
#include <assert.h>
+#include "framework/data_bus.h"
#include "main/snort_types.h"
#include "main/snort_debug.h"
#include "main/snort_config.h"
+#include "stream/stream.h"
#include "sfip/sf_ip.h"
-#include "stream/stream_api.h"
-#include "framework/data_bus.h"
#include "sip_module.h"
#include "sip.h"
sfip_to_str(&mdataB->maddress), mdataB->mport);
/* Call into Streams to mark data channel as something to ignore. */
- FlowData* fd = stream.get_application_data_from_ip_port(
+ FlowData* fd = Stream::get_flow_data(
PktType::UDP, IpProtocol::UDP, &mdataA->maddress,mdataA->mport,
&mdataB->maddress, mdataB->mport, 0, 0, p->pkth->address_space_id,
SipFlowData::flow_id);
}
else
{
- stream.ignore_session(&mdataA->maddress, mdataA->mport, &mdataB->maddress,
+ Stream::ignore_flow(&mdataA->maddress, mdataA->mport, &mdataB->maddress,
mdataB->mport, p->type(), SSN_DIR_BOTH, SipFlowData::flow_id);
}
sip_stats.ignoreChannels++;
sipEventData.packet = p;
- if (stream.service_event_publish(PP_SIP, p->flow, SIP_EVENT_TYPE_SIP_DIALOG, &sipEventData)
+ if (Stream::service_event_publish(PP_SIP, p->flow, SIP_EVENT_TYPE_SIP_DIALOG, &sipEventData)
== false)
ErrorMessage("failed to publish to SIP_DIALOG\n");
}
#include "main/snort_types.h"
#include "main/snort_debug.h"
#include "profiler/profiler.h"
-#include "stream/stream_api.h"
#include "file_api/file_api.h"
#include "mime/file_mime_process.h"
#include "parser/parser.h"
unsigned SmtpFlowData::flow_id = 0;
static SMTPData* get_session_data(Flow* flow)
{
- SmtpFlowData* fd = (SmtpFlowData*)flow->get_application_data(
- SmtpFlowData::flow_id);
-
+ SmtpFlowData* fd = (SmtpFlowData*)flow->get_flow_data(SmtpFlowData::flow_id);
return fd ? &fd->session : NULL;
}
SMTPData* smtp_ssn;
SmtpFlowData* fd = new SmtpFlowData;
- p->flow->set_application_data(fd);
+ p->flow->set_flow_data(fd);
smtp_ssn = &fd->session;
smtpstats.sessions++;
smtp_ssn->mime_ssn->config = config;
smtp_ssn->mime_ssn->set_mime_stats(&(smtpstats.mime_stats));
- if(stream.is_midstream(p->flow))
+ if(Stream::is_midstream(p->flow))
{
DebugMessage(DEBUG_SMTP, "Got midstream packet - "
"setting state to unknown\n");
(p->packet_flags & PKT_REBUILT_STREAM))
{
int missing_in_rebuilt =
- stream.missing_in_reassembled(p->flow, SSN_DIR_FROM_CLIENT);
+ Stream::missing_in_reassembled(p->flow, SSN_DIR_FROM_CLIENT);
if (ssn->session_flags & SMTP_FLAG_NEXT_STATE_UNKNOWN)
{
smtp_ssn->state = STATE_TLS_DATA;
}
else if (!(p->flow->get_session_flags() & SSNFLAG_MIDSTREAM)
- && !stream.missed_packets(p->flow, SSN_DIR_BOTH))
+ && !Stream::missed_packets(p->flow, SSN_DIR_BOTH))
{
/* Check to see if the raw packet is in order */
if (p->packet_flags & PKT_STREAM_ORDER_OK)
/* if we're ignoring tls data, set a zero length alt buffer */
if (config->ignore_tls_data)
{
- stream.stop_inspection(p->flow, p, SSN_DIR_BOTH, -1, 0);
+ Stream::stop_inspection(p->flow, p, SSN_DIR_BOTH, -1, 0);
return;
}
}
static void SMTP_RegXtraDataFuncs(SMTP_PROTO_CONF* config)
{
- config->xtra_filename_id = stream.reg_xtra_data_cb(SMTP_GetFilename);
- config->xtra_mfrom_id = stream.reg_xtra_data_cb(SMTP_GetMailFrom);
- config->xtra_rcptto_id = stream.reg_xtra_data_cb(SMTP_GetRcptTo);
- config->xtra_ehdrs_id = stream.reg_xtra_data_cb(SMTP_GetEmailHdrs);
+ config->xtra_filename_id = Stream::reg_xtra_data_cb(SMTP_GetFilename);
+ config->xtra_mfrom_id = Stream::reg_xtra_data_cb(SMTP_GetMailFrom);
+ config->xtra_rcptto_id = Stream::reg_xtra_data_cb(SMTP_GetRcptTo);
+ config->xtra_ehdrs_id = Stream::reg_xtra_data_cb(SMTP_GetEmailHdrs);
}
int SmtpMime::handle_header_line(const uint8_t* ptr, const uint8_t* eol,
// Implementation header with definitions, datatypes and flowdata class for
// SMTP service inspector.
-#include "protocols/packet.h"
-#include "stream/stream_api.h"
#include "main/thread.h"
+#include "protocols/packet.h"
+#include "stream/stream.h"
#include "smtp_config.h"
// Direction packet is coming from, if we can figure it out
if ( !flow )
return nullptr;
- SmtpSplitter* s = (SmtpSplitter*)stream.get_splitter(flow, c2s);
+ SmtpSplitter* s = (SmtpSplitter*)Stream::get_splitter(flow, c2s);
return s ? &s->state : nullptr;
}
// Protocol aware flushing for SMTP
#include "main/snort_types.h"
-#include "stream/stream_api.h"
#include "stream/stream_splitter.h"
#include "mime/file_mime_paf.h"
#include "smtp.h"
#include "smtp_config.h"
-#include "stream/stream_api.h"
#include "detection/detection_util.h"
#include "utils/safec.h"
if (log->is_file_name_present())
{
- stream.set_extra_data(p->flow, p, config->xtra_filename_id);
+ Stream::set_extra_data(p->flow, p, config->xtra_filename_id);
}
if (log->is_email_from_present())
{
- stream.set_extra_data(p->flow, p, config->xtra_mfrom_id);
+ Stream::set_extra_data(p->flow, p, config->xtra_mfrom_id);
}
if (log->is_email_to_present())
{
- stream.set_extra_data(p->flow, p, config->xtra_rcptto_id);
+ Stream::set_extra_data(p->flow, p, config->xtra_rcptto_id);
}
if (log->is_email_hdrs_present())
{
- stream.set_extra_data(p->flow, p, config->xtra_ehdrs_id);
+ Stream::set_extra_data(p->flow, p, config->xtra_ehdrs_id);
}
}
#include <sys/types.h>
#include "events/event_queue.h"
+#include "file_api/file_api.h"
+#include "framework/inspector.h"
#include "log/messages.h"
#include "main/snort_types.h"
#include "main/snort_debug.h"
-#include "profiler/profiler.h"
-#include "stream/stream_api.h"
-#include "file_api/file_api.h"
#include "parser/parser.h"
-#include "framework/inspector.h"
+#include "profiler/profiler.h"
#include "utils/sfsnprintfappend.h"
#include "target_based/snort_protocols.h"
static SSHData* SetNewSSHData(Packet* p)
{
SshFlowData* fd = new SshFlowData;
- p->flow->set_application_data(fd);
+ p->flow->set_flow_data(fd);
return &fd->session;
}
static SSHData* get_session_data(Flow* flow)
{
- SshFlowData* fd = (SshFlowData*)flow->get_application_data(
- SshFlowData::flow_id);
-
+ SshFlowData* fd = (SshFlowData*)flow->get_flow_data(SshFlowData::flow_id);
return fd ? &fd->session : NULL;
}
// means we've already missed packets) set missed packets flag and make
// sure we don't do any more reassembly on this session
if ((p->flow->get_session_flags() & SSNFLAG_MIDSTREAM)
- || stream.missed_packets(p->flow, SSN_DIR_BOTH))
+ || Stream::missed_packets(p->flow, SSN_DIR_BOTH))
{
// Order only matters if the packets are not encrypted
if ( !(sessp->state_flags & SSH_FLG_SESS_ENCRYPTED ))
else
SnortEventqAdd(GID_SSH, SSH_EVENT_RESPOVERFLOW);
- stream.stop_inspection(p->flow, p, SSN_DIR_BOTH, -1, 0);
+ Stream::stop_inspection(p->flow, p, SSN_DIR_BOTH, -1, 0);
}
}
// and therefore cannot be used late in an
// encrypted session. For performance purposes,
// stop examining this session.
- stream.stop_inspection(p->flow, p, SSN_DIR_BOTH, -1, 0);
+ Stream::stop_inspection(p->flow, p, SSN_DIR_BOTH, -1, 0);
}
}
}
// packets appear malformed/spoofed.
#include "protocols/packet.h"
-#include "stream/stream_api.h"
+#include "stream/stream.h"
#include "ssh_config.h"
// Per-session data block containing current state
#include "main/snort_types.h"
#include "main/snort_debug.h"
#include "profiler/profiler.h"
-#include "stream/stream_api.h"
#include "parser/parser.h"
#include "framework/inspector.h"
#include "utils/sfsnprintfappend.h"
#include "target_based/snort_protocols.h"
#include "detection/detect.h"
#include "protocols/ssl.h"
+#include "stream/stream.h"
#include "ssl_module.h"
static SSLData* SetNewSSLData(Packet* p)
{
SslFlowData* fd = new SslFlowData;
- p->flow->set_application_data(fd);
+ p->flow->set_flow_data(fd);
return &fd->session;
}
SSLData* get_ssl_session_data(Flow* flow)
{
- SslFlowData* fd = (SslFlowData*)flow->get_application_data(
- SslFlowData::flow_id);
-
+ SslFlowData* fd = (SslFlowData*)flow->get_flow_data(SslFlowData::flow_id);
return fd ? &fd->session : NULL;
}
/* Check if we're either midstream or if packets were missed after the
* * connection was established */
else if ((packet->flow->get_session_flags() & SSNFLAG_MIDSTREAM) ||
- (stream.missed_packets(packet->flow, SSN_DIR_BOTH)))
+ (Stream::missed_packets(packet->flow, SSN_DIR_BOTH)))
{
if ((ssl_flags & (SSL_CAPP_FLAG | SSL_SAPP_FLAG)) == (SSL_CAPP_FLAG | SSL_SAPP_FLAG))
{
if (!config->max_heartbeat_len)
{
DebugMessage(DEBUG_SSL, "STOPPING INSPECTION (process_app)\n");
- stream.stop_inspection(packet->flow, packet, SSN_DIR_BOTH, -1, 0);
+ Stream::stop_inspection(packet->flow, packet, SSN_DIR_BOTH, -1, 0);
sslstats.stopped++;
}
else if (!(new_flags & SSL_HEARTBEAT_SEEN))
if (!config->max_heartbeat_len)
{
DebugMessage(DEBUG_SSL, "STOPPING INSPECTION (process_other)\n");
- stream.stop_inspection(packet->flow, packet, SSN_DIR_BOTH, -1, 0);
+ Stream::stop_inspection(packet->flow, packet, SSN_DIR_BOTH, -1, 0);
}
else if (!(new_flags & SSL_HEARTBEAT_SEEN))
{
{
if ( (SSL_IS_SHELLO(new_flags) && !SSL_IS_CHELLO(sd->ssn_flags) ))
{
- if (!(stream.missed_packets(p->flow, SSN_DIR_FROM_CLIENT)))
+ if (!(Stream::missed_packets(p->flow, SSN_DIR_FROM_CLIENT)))
SnortEventqAdd(GID_SSL, SSL_INVALID_SERVER_HELLO);
}
}
// Implementation header with definitions, datatypes and flowdata class for SSL service inspector.
#include "protocols/packet.h"
-#include "stream/stream_api.h"
#include "ssl_config.h"
#define SSLPP_ENCRYPTED_FLAGS \
set (STREAM_INCLUDES
paf.h
- stream_api.h
+ stream.h
stream_splitter.h
)
add_library( stream STATIC
- stream.h
- stream_api.cc
+ stream.cc
stream_inspectors.cc
stream_inspectors.h
stream_splitter.cc
x_include_HEADERS = \
paf.h \
-stream_api.h \
+stream.h \
stream_splitter.h
libstream_a_SOURCES = \
-stream.h \
-stream_api.cc \
+stream.cc \
stream_inspectors.cc \
stream_inspectors.h \
stream_splitter.cc
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//--------------------------------------------------------------------------
-#include "stream/stream.h"
-
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <assert.h>
-#include "stream_module.h"
-#include "stream_ha.h"
-#include "main/snort_debug.h"
-#include "managers/inspector_manager.h"
#include "flow/flow_control.h"
#include "flow/prune_stats.h"
-#include "stream/stream_api.h"
+#include "main/snort_debug.h"
+#include "managers/inspector_manager.h"
#include "profiler/profiler.h"
+
#include "stream/tcp/tcp_session.h"
+#include "stream_module.h"
+#include "stream_ha.h"
//-------------------------------------------------------------------------
// stats
void StreamBase::tterm()
{
- flow_con->purge_flows(PktType::IP);
- flow_con->purge_flows(PktType::ICMP);
- flow_con->purge_flows(PktType::TCP);
- flow_con->purge_flows(PktType::UDP);
- flow_con->purge_flows(PktType::PDU);
- flow_con->purge_flows(PktType::FILE);
-
StreamHAManager::tterm();
}
switch ( p->type() )
{
case PktType::IP:
- if ( p->has_ip() )
+ if ( p->has_ip() and
+ ((p->ptrs.decode_flags & DECODE_FRAG) or !config->ip_frags_only) )
flow_con->process_ip(p);
break;
#include "binder/binder.h"
#include "main/snort_debug.h"
#include "managers/inspector_manager.h"
+#include "stream/stream.h"
#include "sfip/sf_ip.h"
-#include "stream/stream_api.h"
// HA Session flags helper macros
#define HA_IGNORED_SESSION_FLAGS \
#include "stream_module.h"
-#include "stream/stream.h"
-
#include <string>
using namespace std;
{ "idle_timeout", Parameter::PT_INT, "1:", idle, \
"maximum inactive time before retiring session tracker" }, \
\
- { "cleanup_pct", Parameter::PT_INT, "1:100", cleanup, \
- "percent of cache to clean when max_sessions is reached" }, \
-\
{ nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr } \
}
CACHE_PARAMS(ip_params, "16384", "30", "180", "5");
-CACHE_PARAMS(icmp_params, "32768", "30", "180", "5");
-CACHE_PARAMS(tcp_params, "131072", "30", "180", "5");
-CACHE_PARAMS(udp_params, "65536", "30", "180", "5");
+CACHE_PARAMS(icmp_params, "65536", "30", "180", "5");
+CACHE_PARAMS(tcp_params, "262144", "30", "180", "5");
+CACHE_PARAMS(udp_params, "131072", "30", "180", "5");
CACHE_PARAMS(user_params, "1024", "30", "180", "5");
CACHE_PARAMS(file_params, "128", "30", "180", "5");
static const Parameter s_params[] =
{
+ { "ip_frags_only", Parameter::PT_BOOL, nullptr, "false",
+ "don't process non-frag flows" },
+
CACHE_TABLE("ip_cache", "ip", ip_params),
CACHE_TABLE("icmp_cache", "icmp", icmp_params),
CACHE_TABLE("tcp_cache", "tcp", tcp_params),
{
FlowConfig* fc = nullptr;
- if ( strstr(fqn, "ip_cache") )
+ if ( v.is("ip_frags_only") )
+ {
+ config.ip_frags_only = v.get_bool();
+ return true;
+ }
+ else if ( strstr(fqn, "ip_cache") )
fc = &config.ip_cfg;
else if ( strstr(fqn, "icmp_cache") )
else if ( v.is("idle_timeout") )
fc->nominal_timeout = v.get_long();
- else if ( v.is("cleanup_pct") )
- fc->cleanup_pct = v.get_long();
-
else
return false;
PROTO_FIELDS(file);
};
+extern const PegInfo base_pegs[];
+
extern THREAD_LOCAL BaseStats stream_base_stats;
struct StreamModuleConfig
FlowConfig udp_cfg;
FlowConfig user_cfg;
FlowConfig file_cfg;
+ bool ip_frags_only;
};
class StreamModule : public Module
#include "stream_file.h"
#include "main/snort_config.h"
-#include "stream/stream.h"
//-------------------------------------------------------------------------
// stream_file module
#include "main/snort_types.h"
#include "main/thread.h"
#include "framework/module.h"
-#include "stream/stream.h"
struct SnortConfig;
Currently only the ICMP Unreachable message is handled by the ICMP session
module.
+The module icmp_ha.cc (and icmp_ha.h) implements the per-protocol hooks into
+the stream logic for HA. IcmpHAManager is a static class that interfaces
+to a per-packet thread instance of the class IcmpHA. IcmpHA is sub-class
+of ProtocolHA, declared in the stream/base area. Thus each protocol
+within 'stream' can have specific HA logic and interfaces.
+
+IcmpHAManager::process_deletion() is called when an ICMP stream is being
+destroyed and indicates to the stream & flow HA logic that a flow
+deletion HA message needs to be emitted for the flow in question.
+Icmp streams are closed due to timeout or puning actions which lead
+to the invocation of process_deletion().
+
+IcmpHA::create_session() is called from the stream & flow HA logic and
+handles the creation of new flow upon receiving an HA update message.
Flow* IcmpHA::create_session(FlowKey* key)
{
- DebugMessage(DEBUG_HA,"IcmpHA::create_session\n");
-
- assert ( key );
-
- Flow* flow = flow_con->new_flow(key);
+ assert(key);
+ Flow* flow = Stream::new_flow(key);
if ( (flow != nullptr ) && (flow->session == nullptr) )
{
config = nullptr;
}
-ProfileStats* StreamIcmpModule::get_profile() const
-{ return &icmp_perf_stats; }
+ProfileStats* StreamIcmpModule::get_profile(
+ unsigned index, const char*& name, const char*& parent) const
+{
+ if ( index )
+ return nullptr;
+
+ name = MOD_NAME;
+ parent = "stream";
+ return &icmp_perf_stats;
+}
StreamIcmpConfig* StreamIcmpModule::get_data()
{
#include "main/snort_types.h"
#include "main/thread.h"
+#include "flow/session.h"
#include "framework/module.h"
-#include "stream/stream.h"
extern const PegInfo icmp_pegs[];
extern THREAD_LOCAL struct IcmpStats icmpStats;
bool begin(const char*, int, SnortConfig*) override;
bool end(const char*, int, SnortConfig*) override;
- ProfileStats* get_profile() const override;
+ ProfileStats* get_profile(unsigned, const char*&, const char*&) const override;
const PegInfo* get_pegs() const override;
PegCount* get_counts() const override;
{
if (ssn->ssn_state.session_flags & SSNFLAG_PRUNED)
icmpStats.prunes++;
+
else if (ssn->ssn_state.session_flags & SSNFLAG_TIMEDOUT)
icmpStats.timeouts++;
{
case PktType::TCP:
/* Lookup a TCP session */
- ssn = Stream::get_session(&skey);
+ ssn = Stream::get_flow(&skey);
break;
case PktType::UDP:
/* Lookup a UDP session */
- ssn = Stream::get_session(&skey);
+ ssn = Stream::get_flow(&skey);
break;
case PktType::ICMP:
/* Lookup a ICMP session */
- ssn = Stream::get_session(&skey);
+ ssn = Stream::get_flow(&skey);
break;
default:
break;
packet eval method is not used as the base Stream Inspector delegates
packets directly to the IP session packet processing method.
+The module ip_ha.cc (and ip_ha.h) implements the per-protocol hooks into
+the stream logic for HA. IpHAManager is a static class that interfaces
+to a per-packet thread instance of the class IpHA. IpHA is sub-class
+of ProtocolHA, declared in the stream/base area. Thus each protocol
+within 'stream' can have specific HA logic and interfaces.
+
+IpHAManager::process_deletion() is called when an IP stream is being
+destroyed and indicates to the stream & flow HA logic that a flow
+deletion HA message needs to be emitted for the flow in question.
+Ip streams are closed due to timeout or puning actions which lead
+to the invocation of process_deletion().
+
+IpHA::create_session() is called from the stream & flow HA logic and
+handles the creation of new flow upon receiving an HA update message.
#include "ip_ha.h"
-#include "flow/flow_control.h"
#include "main/snort_debug.h"
-#include "stream/ip/ip_session.h"
+#include "stream/stream.h"
+#include "ip_session.h"
Flow* IpHA::create_session(FlowKey* key)
{
- DebugMessage(DEBUG_HA,"IpHA::create_session\n");
+ assert(key);
- assert ( key );
-
- Flow* flow = flow_con->new_flow(key);
+ Flow* flow = Stream::new_flow(key);
if ( (flow != nullptr ) && (flow->session == nullptr) )
{
{
case 0:
name = "stream_ip";
- parent = nullptr;
+ parent = "stream";
return &ip_perf_stats;
case 1:
#include "main/snort_types.h"
#include "main/thread.h"
+#include "flow/session.h"
#include "framework/module.h"
-#include "stream/stream.h"
struct SnortConfig;
#include "ip_defrag.h"
#include "ip_ha.h"
#include "stream/stream.h"
-#include "flow/flow_control.h"
#include "sfip/sf_ip.h"
#include "profiler/profiler.h"
if ( lws->ssn_state.session_flags & SSNFLAG_TIMEDOUT )
ip_stats.timeouts++;
- else if ( lws->ssn_state.session_flags & SSNFLAG_PRUNED )
- ip_stats.prunes++;
- if ( lws->ssn_state.session_flags & SSNFLAG_TIMEDOUT )
- ip_stats.timeouts++;
else if ( lws->ssn_state.session_flags & SSNFLAG_PRUNED )
ip_stats.prunes++;
ip_stats.current++;
#ifdef ENABLE_EXPECTED_IP
- if ( flow_con->expected_session(flow, p))
+ if ( Stream::expected_flow(flow, p) )
{
ip_stats.sessions--; // Incremented in SESSION_STATS_ADD
MODULE_PROFILE_END(ip_perf_stats);
{
Profile profile(ip_perf_stats);
- if ( stream.expired_session(flow, p) )
+ if ( Stream::expired_flow(flow, p) )
{
IpSessionCleanup(flow, &tracker);
#ifdef ENABLE_EXPECTED_IP
- if ( flow_con->expected_session(flow, p))
+ if ( Stream::expected_flow(flow, p) )
return 0;
#endif
IpHAManager::process_deletion(flow);
}
- if ( stream.blocked_session(flow, p) || stream.ignored_session(flow, p) )
+ if ( Stream::blocked_flow(flow, p) || Stream::ignored_flow(flow, p) )
return 0;
if ( p->ptrs.decode_flags & DECODE_FRAG )
#include "flow/flow.h"
/* engine-based defragmentation policy enums */
-// must update stream_api.h::IP_POLICIES if this changes
+// must update stream.h::IP_POLICIES if this changes
enum
{
FRAG_POLICY_FIRST = 1,
* TCP State Machine - this class is the engine that dispatches processing to the correct
event handling method of the handler for the current TCP state of the flow.
+Most of the TCP HA processing is contained in the ../tcp area and one needed to refer
+to ../tcp/dev_notes.txt for a description.
+
+One HA state transition is implemented within this TCP library. In
+TcpStreamSession::clear(), TcpHAManager::process_deletion() is invoked to
+cause HA to generate a Deletion message for the target flow. This handles
+the case where a TCP session is being removed from from the flow cache due
+to a timeout or pruning function. Other normal TCP stream closure actions
+are handled in the ../tcp/tcp_session.cc module.
void SwapPacketHeaderFoo();
virtual void update_perf_base_state(char) { }
- virtual void clear_session(bool free_flow_data, bool flush_segments, bool restart, Packet* p = nullptr) = 0;
+ virtual void clear_session(
+ bool free_flow_data, bool flush_segments, bool restart, Packet* p = nullptr) = 0;
// FIXIT-L these 2 function names convey no meaning afaict... figure out
// why are they called and name appropriately...
virtual void flush() { }
- virtual TcpStreamTracker::TcpState get_talker_state() { return TcpStreamTracker::TCP_MAX_STATES; }
- virtual TcpStreamTracker::TcpState get_listener_state() { return TcpStreamTracker::TCP_MAX_STATES; }
+ virtual TcpStreamTracker::TcpState get_talker_state()
+ { return TcpStreamTracker::TCP_MAX_STATES; }
+
+ virtual TcpStreamTracker::TcpState get_listener_state()
+ { return TcpStreamTracker::TCP_MAX_STATES; }
+
virtual void init_new_tcp_session(TcpSegmentDescriptor&);
virtual void update_timestamp_tracking(TcpSegmentDescriptor&) { }
virtual void update_session_on_syn_ack();
}
void set_pkt_action_flag(uint32_t flag)
- {
- pkt_action_mask |= flag;
- }
+ { pkt_action_mask |= flag; }
virtual void update_paws_timestamps(TcpSegmentDescriptor&) { }
virtual void check_for_repeated_syn(TcpSegmentDescriptor&) { }
// tcp_stream_tracker.cpp author davis mcpherson <davmcphe@@cisco.com>
// Created on: Jun 24, 2015
-#include "protocols/tcp_options.h"
-#include "protocols/tcp.h"
-#include "protocols/eth.h"
-#include "profiler/profiler.h"
+#include "tcp_stream_tracker.h"
+#include "profiler/profiler.h"
+#include "protocols/eth.h"
+#include "protocols/tcp.h"
+#include "protocols/tcp_options.h"
#include "stream/stream.h"
-#include "tcp_stream_tracker.h"
const char* tcp_state_names[] =
-{ "TCP_LISTEN", "TCP_SYN_SENT", "TCP_SYN_RECV", "TCP_ESTABLISHED","TCP_FIN_WAIT1",
- "TCP_FIN_WAIT2", "TCP_CLOSE_WAIT", "TCP_CLOSING", "TCP_LAST_ACK",
- "TCP_TIME_WAIT", "TCP_CLOSED", "TCP_STATE_NONE",};
-
-const char* tcp_event_names[] = { "TCP_SYN_SENT_EVENT", "TCP_SYN_RECV_EVENT",
- "TCP_SYN_ACK_SENT_EVENT", "TCP_SYN_ACK_RECV_EVENT",
- "TCP_ACK_SENT_EVENT",
- "TCP_ACK_RECV_EVENT", "TCP_DATA_SEG_SENT_EVENT",
- "TCP_DATA_SEG_RECV_EVENT",
- "TCP_FIN_SENT_EVENT", "TCP_FIN_RECV_EVENT", "TCP_RST_SENT_EVENT",
- "TCP_RST_RECV_EVENT" };
+{
+ "TCP_LISTEN", "TCP_SYN_SENT", "TCP_SYN_RECV",
+ "TCP_ESTABLISHED",
+ "TCP_FIN_WAIT1", "TCP_FIN_WAIT2", "TCP_CLOSE_WAIT", "TCP_CLOSING",
+ "TCP_LAST_ACK", "TCP_TIME_WAIT", "TCP_CLOSED",
+ "TCP_STATE_NONE"
+};
+
+const char* tcp_event_names[] = {
+ "TCP_SYN_SENT_EVENT", "TCP_SYN_RECV_EVENT",
+ "TCP_SYN_ACK_SENT_EVENT", "TCP_SYN_ACK_RECV_EVENT",
+ "TCP_ACK_SENT_EVENT", "TCP_ACK_RECV_EVENT",
+ "TCP_DATA_SEG_SENT_EVENT", "TCP_DATA_SEG_RECV_EVENT",
+ "TCP_FIN_SENT_EVENT", "TCP_FIN_RECV_EVENT",
+ "TCP_RST_SENT_EVENT", "TCP_RST_RECV_EVENT"
+};
TcpStreamTracker::TcpStreamTracker(bool client) :
client_tracker(client), tcp_state(client ? TCP_STATE_NONE : TCP_LISTEN)
this->fin_final_seq = fin_final_seq;
}
+ // FIXIT-M fin_final_seq can be zero so need to use current state
+ // or other flag to know when it is actually set
+ bool fin_set() { return fin_final_seq != 0; }
+
uint32_t get_ts_last_packet() const
{
return ts_last_packet;
#include "main/snort_types.h"
#include "main/snort_debug.h"
-#include "stream/stream.h"
-#include "stream/stream_api.h"
+#include "protocols/packet.h"
//--------------------------------------------------------------------
// private state
#include <stdint.h>
#include "main/snort_types.h"
-#include "stream/stream_api.h"
#include "stream/stream_splitter.h"
struct SnortConfig;
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//--------------------------------------------------------------------------
-#include "stream_api.h"
+#include "stream.h"
#ifdef HAVE_CONFIG_H
#include "config.h"
#include "main/snort_config.h"
#include "main/snort_debug.h"
#include "main/snort_debug.h"
-#include "utils/util.h"
#include "flow/flow_control.h"
#include "flow/flow_cache.h"
#include "flow/ha.h"
+#include "flow/prune_stats.h"
#include "flow/session.h"
#include "stream/stream.h"
#include "stream/paf.h"
#include "protocols/vlan.h"
#include "target_based/snort_protocols.h"
#include "target_based/sftarget_hostentry.h"
+#include "utils/bitop.h"
+#include "utils/util.h"
#ifdef UNIT_TEST
#include "catch/catch.hpp"
#include "stream/libtcp/stream_tcp_unit_test.h"
#endif
-Stream stream; // FIXIT-L global for SnortContext
+// this should not be publicly accessible
+extern THREAD_LOCAL class FlowControl* flow_con;
-Stream::Stream()
+struct StreamImpl
{
- xtradata_func_count = 0;
- extra_data_log = NULL;
- extra_data_config = NULL;
-}
+public:
+ uint32_t xtradata_func_count = 0;
+ LogFunction xtradata_map[MAX_LOG_FN];
+ LogExtraData extra_data_log = nullptr;
+ void* extra_data_config = nullptr;
+};
-Stream::~Stream() { }
+static StreamImpl stream;
//-------------------------------------------------------------------------
// session foo
//-------------------------------------------------------------------------
-Flow* Stream::get_session(const FlowKey* key)
+Flow* Stream::get_flow(const FlowKey* key)
{ return flow_con->find_flow(key); }
-Flow* Stream::new_session(const FlowKey* key)
+Flow* Stream::new_flow(const FlowKey* key)
{ return flow_con->new_flow(key); }
-void Stream::delete_session(const FlowKey* key)
+Flow* Stream::new_flow(FlowKey* key)
+{
+ return flow_con ? flow_con->new_flow(key) : nullptr;
+}
+
+void Stream::delete_flow(const FlowKey* key)
{ flow_con->delete_flow(key); }
//-------------------------------------------------------------------------
// key foo
//-------------------------------------------------------------------------
-Flow* Stream::get_session_ptr_from_ip_port(
+Flow* Stream::get_flow(
PktType type, IpProtocol proto,
const sfip_t* srcIP, uint16_t srcPort,
const sfip_t* dstIP, uint16_t dstPort,
uint16_t vlan, uint32_t mplsId, uint16_t addressSpaceId)
{
FlowKey key;
-
key.init(type, proto, srcIP, srcPort, dstIP, dstPort, vlan, mplsId, addressSpaceId);
-
- return get_session(&key);
+ return get_flow(&key);
}
-void Stream::populate_session_key(Packet* p, FlowKey* key)
+void Stream::populate_flow_key(Packet* p, FlowKey* key)
{
if (!key || !p)
return;
p->pkth->address_space_id);
}
-FlowKey* Stream::get_session_key(Packet* p)
+FlowKey* Stream::get_flow_key(Packet* p)
{
FlowKey* key = (FlowKey*)snort_calloc(sizeof(*key));
- populate_session_key(p, key);
+ populate_flow_key(p, key);
return key;
}
// app data foo
//-------------------------------------------------------------------------
-FlowData* Stream::get_application_data_from_key(
+FlowData* Stream::get_flow_data(
const FlowKey* key, unsigned flow_id)
{
- Flow* flow = get_session(key);
- return flow->get_application_data(flow_id);
+ Flow* flow = get_flow(key);
+ return flow->get_flow_data(flow_id);
}
-FlowData* Stream::get_application_data_from_ip_port(
+FlowData* Stream::get_flow_data(
PktType type, IpProtocol proto,
const sfip_t* srcIP, uint16_t srcPort,
const sfip_t* dstIP, uint16_t dstPort,
uint16_t vlan, uint32_t mplsId,
uint16_t addressSpaceID, unsigned flow_id)
{
- Flow* flow;
-
- flow = get_session_ptr_from_ip_port(
+ Flow* flow = get_flow(
type, proto,
srcIP, srcPort, dstIP, dstPort,
vlan, mplsId, addressSpaceID);
if (!flow)
return NULL;
- return flow->get_application_data(flow_id);
+ return flow->get_flow_data(flow_id);
}
//-------------------------------------------------------------------------
// session status
//-------------------------------------------------------------------------
-void Stream::check_session_closed(Packet* p)
+void Stream::check_flow_closed(Packet* p)
{
Flow* flow = p->flow;
- if (!p || !flow)
+ if ( !flow )
return;
if (flow->session_state & STREAM_STATE_CLOSED)
}
}
-int Stream::ignore_session(
+int Stream::ignore_flow(
const sfip_t* srcIP, uint16_t srcPort,
const sfip_t* dstIP, uint16_t dstPort,
PktType protocol, char direction,
uint32_t flow_id)
{
assert(flow_con);
-
FlowData* fd = new FlowData(flow_id);
-
- return flow_con->add_expected(
- srcIP, srcPort, dstIP, dstPort, protocol, direction, fd);
+ return flow_con->add_expected(srcIP, srcPort, dstIP, dstPort, protocol, direction, fd);
}
void Stream::proxy_started(Flow* flow, unsigned dir)
tcpssn->flush();
if ( dir & SSN_DIR_FROM_SERVER )
- stream.set_splitter(flow, true, new LogSplitter(true));
+ set_splitter(flow, true, new LogSplitter(true));
if ( dir & SSN_DIR_FROM_CLIENT )
- stream.set_splitter(flow, false, new LogSplitter(false));
+ set_splitter(flow, false, new LogSplitter(false));
tcpssn->start_proxy();
flow->set_proxied();
}
}
-void Stream::drop_session(const Packet* p)
+void Stream::drop_flow(const Packet* p)
{
Flow* flow = p->flow;
flow->session->clear();
flow->set_state(Flow::FlowState::BLOCK);
- if (!(p->packet_flags & PKT_STATELESS))
+ if ( !(p->packet_flags & PKT_STATELESS) )
drop_traffic(flow, SSN_DIR_BOTH);
}
// misc support
//-------------------------------------------------------------------------
-BitOp* Stream::get_flow_bitop(const Packet* p)
-{
- Flow* flow = p->flow;
-
- if (!flow)
- return NULL;
-
- return flow->bitop;
-}
-
void Stream::init_active_response(const Packet* p, Flow* flow)
{
if ( !flow )
flow->set_expire(p, snort_conf->min_interval);
}
+void Stream::purge_flows()
+{
+ if ( !flow_con )
+ return;
+
+ flow_con->purge_flows(PktType::IP);
+ flow_con->purge_flows(PktType::ICMP);
+ flow_con->purge_flows(PktType::TCP);
+ flow_con->purge_flows(PktType::UDP);
+ flow_con->purge_flows(PktType::PDU);
+ flow_con->purge_flows(PktType::FILE);
+}
+
+void Stream::timeout_flows(time_t cur_time)
+{
+ if ( flow_con )
+ // FIXIT-M batch here or loop vs looping over idle?
+ flow_con->timeout_flows(cur_time);
+}
+
+void Stream::prune_flows()
+{
+ if ( flow_con )
+ flow_con->prune_one(PruneReason::MEMCAP, false);
+}
+
+bool Stream::expected_flow(Flow* f, Packet* p)
+{
+ return flow_con->expected_flow(f, p) != SSN_DIR_NONE;
+}
+
//-------------------------------------------------------------------------
// app proto id foo
//-------------------------------------------------------------------------
srcIP, srcPort, dstIP, dstPort, protocol, appId, fd);
}
-void Stream::set_application_protocol_id_from_host_entry(
+void Stream::set_application_protocol_id(
Flow* flow, const HostAttributeEntry* host_entry, int /*direction*/)
{
int16_t application_protocol;
/* Not caching the source and dest host_entry in the session so we can
* swap the table out after processing this packet if we need
* to. */
- HostAttributeEntry* host_entry = NULL;
int16_t protocol = 0;
if (!flow)
set_ip_protocol(flow);
}
- host_entry = SFAT_LookupHostEntryByIP(&flow->server_ip);
- if (host_entry)
+ if ( HostAttributeEntry* host_entry = SFAT_LookupHostEntryByIP(&flow->server_ip) )
{
- set_application_protocol_id_from_host_entry(flow, host_entry, FROM_SERVER);
+ set_application_protocol_id(flow, host_entry, FROM_SERVER);
if (flow->ssn_state.application_protocol != 0)
- {
return flow->ssn_state.application_protocol;
- }
}
- host_entry = SFAT_LookupHostEntryByIP(&flow->client_ip);
- if (host_entry)
+ if ( HostAttributeEntry* host_entry = SFAT_LookupHostEntryByIP(&flow->client_ip) )
{
- set_application_protocol_id_from_host_entry(flow, host_entry, FROM_CLIENT);
+ set_application_protocol_id(flow, host_entry, FROM_CLIENT);
if (flow->ssn_state.application_protocol != 0)
- {
return flow->ssn_state.application_protocol;
- }
}
flow->ssn_state.application_protocol = -1;
-
return 0;
}
void Stream::log_extra_data(
Flow* flow, uint32_t mask, uint32_t id, uint32_t sec)
{
- if ( mask && extra_data_log )
+ if ( mask && stream.extra_data_log )
{
- extra_data_log(
- flow, extra_data_config, xtradata_map,
- xtradata_func_count, mask, id, sec);
+ stream.extra_data_log(
+ flow, stream.extra_data_config, stream.xtradata_map,
+ stream.xtradata_func_count, mask, id, sec);
}
}
uint32_t Stream::reg_xtra_data_cb(LogFunction f)
{
uint32_t i = 0;
- while (i < xtradata_func_count)
+ while (i < stream.xtradata_func_count)
{
- if (xtradata_map[i++] == f)
- {
+ if (stream.xtradata_map[i++] == f)
return i;
- }
}
- if ( xtradata_func_count == MAX_LOG_FN)
+ if ( stream.xtradata_func_count == MAX_LOG_FN)
return 0;
- xtradata_map[xtradata_func_count++] = f;
- return xtradata_func_count;
+
+ stream.xtradata_map[stream.xtradata_func_count++] = f;
+ return stream.xtradata_func_count;
}
uint32_t Stream::get_xtra_data_map(LogFunction** f)
{
if (f)
{
- *f = xtradata_map;
- return xtradata_func_count;
+ *f = stream.xtradata_map;
+ return stream.xtradata_func_count;
}
- else
- return 0;
+ return 0;
}
void Stream::reg_xtra_data_log(LogExtraData f, void* config)
{
- extra_data_log = f;
- extra_data_config = config;
+ stream.extra_data_log = f;
+ stream.extra_data_config = config;
}
//-------------------------------------------------------------------------
// other foo
//-------------------------------------------------------------------------
-uint8_t Stream::get_session_ttl(Flow* flow, char dir, bool outer)
+uint8_t Stream::get_flow_ttl(Flow* flow, char dir, bool outer)
{
if ( !flow )
return 0;
else
lwssn->session_state |= STREAM_STATE_DROP_SERVER;
- if ( (lwssn->response_count < max) && lwssn->get_expire(p) )
+ if ( (lwssn->response_count < max) && lwssn->expired(p) )
{
uint32_t delay = snort_conf->min_interval;
EncodeFlags flags =
}
}
-bool Stream::blocked_session(Flow* flow, Packet* p)
+bool Stream::blocked_flow(Flow* flow, Packet* p)
{
if ( !(flow->ssn_state.session_flags & (SSNFLAG_DROP_CLIENT|SSNFLAG_DROP_SERVER)) )
return false;
return false;
}
-bool Stream::ignored_session(Flow* flow, Packet* p)
+bool Stream::ignored_flow(Flow* flow, Packet* p)
{
if (((p->is_from_server()) &&
(flow->ssn_state.ignore_direction & SSN_DIR_FROM_CLIENT)) ||
return false;
}
-static int StreamExpireSession(Flow* lwssn)
+static int StreamExpire(Packet* p, Flow* lwssn)
{
+ if ( !lwssn->expired(p) )
+ return 0;
+
if ( HighAvailabilityManager::in_standby(lwssn) )
return 1;
return 1;
}
-static int StreamExpire(Packet* p, Flow* lwssn)
-{
- if ( lwssn->expired(p) )
- {
- /* Expiration time has passed. */
- return StreamExpireSession(lwssn);
- }
-
- return 0;
-}
-
-bool Stream::expired_session(Flow* flow, Packet* p)
+bool Stream::expired_flow(Flow* flow, Packet* p)
{
if ( (flow->session_state & STREAM_STATE_TIMEDOUT)
|| StreamExpire(p, flow) )
}
// return true if added
-bool Stream::add_session_alert(
+bool Stream::add_flow_alert(
Flow* flow, Packet* p, uint32_t gid, uint32_t sid)
{
if ( !flow )
}
// return true if gid/sid have already been seen
-bool Stream::check_session_alerted(
+bool Stream::check_flow_alerted(
Flow* flow, Packet* p, uint32_t gid, uint32_t sid)
{
if ( !flow )
return flow->session->check_alerted(p, gid, sid);
}
-int Stream::update_session_alert(
+int Stream::update_flow_alert(
Flow* flow, Packet* p,
uint32_t gid, uint32_t sid,
uint32_t event_id, uint32_t event_second)
#ifdef UNIT_TEST
-#include "framework/cursor.h"
-
TEST_CASE("Stream API", "[stream_api][stream]")
{
// initialization code here
pkt->flow->session = new TcpSession(flow);
Stream::stop_inspection(flow, pkt, SSN_DIR_FROM_SERVER, 0, 0);
- bool ignored = Stream::ignored_session(flow, pkt);
+ bool ignored = Stream::ignored_flow(flow, pkt);
CHECK(ignored);
delete pkt->flow->session;
pkt->flow->session = new TcpSession(flow);
Stream::stop_inspection(flow, pkt, SSN_DIR_FROM_SERVER, 0, 0);
- bool ignored = Stream::ignored_session(flow, pkt);
+ bool ignored = Stream::ignored_flow(flow, pkt);
CHECK(!ignored);
delete pkt->flow->session;
delete pkt;
pkt->flow->session = new TcpSession(flow);
Stream::stop_inspection(flow, pkt, SSN_DIR_FROM_CLIENT, 0, 0);
- bool ignored = Stream::ignored_session(flow, pkt);
+ bool ignored = Stream::ignored_flow(flow, pkt);
CHECK(!ignored);
delete pkt->flow->session;
pkt->flow->session = new TcpSession(flow);
Stream::stop_inspection(flow, pkt, SSN_DIR_FROM_CLIENT, 0, 0);
- bool ignored = Stream::ignored_session(flow, pkt);
+ bool ignored = Stream::ignored_flow(flow, pkt);
CHECK(ignored);
delete pkt->flow->session;
delete pkt;
pkt->flow->session = new TcpSession(flow);
Stream::stop_inspection(flow, pkt, SSN_DIR_BOTH, 0, 0);
- bool ignored = Stream::ignored_session(flow, pkt);
+ bool ignored = Stream::ignored_flow(flow, pkt);
CHECK(ignored);
delete pkt->flow->session;
pkt->flow->session = new TcpSession(flow);
Stream::stop_inspection(flow, pkt, SSN_DIR_BOTH, 0, 0);
- bool ignored = Stream::ignored_session(flow, pkt);
+ bool ignored = Stream::ignored_flow(flow, pkt);
CHECK(ignored);
delete pkt->flow->session;
delete pkt;
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//--------------------------------------------------------------------------
+// stream.h author Steven Sturges
+
#ifndef STREAM_H
#define STREAM_H
+// provides a common flow management interface
+
#include <sys/types.h>
-#include <netinet/in.h>
+#include "sfip/sfip_t.h"
+#include "protocols/packet.h"
+#include "flow/flow.h"
#include "main/snort_types.h"
-#include "stream/stream_api.h"
-#include "network_inspectors/normalize/norm.h"
-#include "flow/session.h"
-
-#define STREAM_DEFAULT_SSN_TIMEOUT 30 /* seconds to timeout a session */
-#define STREAM_MAX_SSN_TIMEOUT 3600*24 /* max timeout (approx 1 day) */
-#define STREAM_MIN_SSN_TIMEOUT 1 /* min timeout (1 second) */
-
-#define STREAM_TRACK_YES 1
-#define STREAM_TRACK_NO 0
-
-// FIXIT-L move to proto specific where possible
-#define STREAM_CONFIG_STATEFUL_INSPECTION 0x00000001
-#define STREAM_CONFIG_LOG_STREAMS 0x00000004
-#define STREAM_CONFIG_REASS_CLIENT 0x00000008
-#define STREAM_CONFIG_REASS_SERVER 0x00000010
-#define STREAM_CONFIG_ASYNC 0x00000020
-#define STREAM_CONFIG_SHOW_PACKETS 0x00000040
-#define STREAM_CONFIG_MIDSTREAM_DROP_NOALERT 0x00000080
-#define STREAM_CONFIG_IGNORE_ANY 0x00000100
-#define STREAM_CONFIG_STATIC_FLUSHPOINTS 0x00000200
-#define STREAM_CONFIG_IPS 0x00000400
-#define STREAM_CONFIG_NO_ASYNC_REASSEMBLY 0x00000800
-
-// shared stream state
-extern THREAD_LOCAL class FlowControl* flow_con;
-extern const PegInfo base_pegs[];
-
-const PegInfo* Stream_GetNormPegs();
-NormPegs Stream_GetNormCounts(unsigned&);
+
+/* traffic direction identification */
+#define FROM_SERVER 0
+#define FROM_CLIENT 1
+
+#define SSN_MISSING_NONE 0x00
+#define SSN_MISSING_BEFORE 0x01
+#define SSN_MISSING_AFTER 0x02
+#define SSN_MISSING_BOTH (SSN_MISSING_BEFORE | SSN_MISSING_AFTER)
+
+#define SSN_DIR_NONE 0x00
+#define SSN_DIR_FROM_CLIENT 0x01
+#define SSN_DIR_FROM_SERVER 0x02
+#define SSN_DIR_BOTH 0x03
+
+// sequence must match FRAG_POLICY_* enum in stream_ip.h (1-based)
+#define IP_POLICIES \
+ "first | linux | bsd | bsd_right | last | windows | solaris"
+
+// sequence must match STREAM_POLICY_* defines in tcp_session.cc (1-based)
+#define TCP_POLICIES \
+ "first | last | linux | old_linux | bsd | macos | solaris | irix | " \
+ "hpux11 | hpux10 | windows | win_2003 | vista | proxy"
+
+class Flow;
+
+typedef int (* LogFunction)(Flow*, uint8_t** buf, uint32_t* len, uint32_t* type);
+typedef void (* LogExtraData)(Flow*, void* config, LogFunction* funcs,
+ uint32_t max_count, uint32_t xtradata_mask, uint32_t id, uint32_t sec);
+
+#define MAX_LOG_FN 32
+
+//-------------------------------------------------------------------------
+
+class SO_PUBLIC Stream
+{
+public:
+ // for shutdown only
+ static void purge_flows();
+
+ static void timeout_flows(time_t cur_time);
+ static void prune_flows();
+ static bool expected_flow(Flow*, Packet*);
+ static Flow* new_flow(FlowKey*);
+
+ // Looks in the flow cache for flow session with specified key and returns
+ // pointer to flow session oject if found, otherwise null.
+ static Flow* get_flow(const FlowKey*);
+
+ // Allocates a flow session object from the flow cache table for the protocol
+ // type of the specified key. If no cache exists for that protocol type null is
+ // returned. If a flow already exists for the key a pointer to that session
+ // object is returned.
+ // If a new session object can not be allocated the program is terminated.
+ static Flow* new_flow(const FlowKey*);
+
+ // Removes the flow session object from the flow cache table and returns
+ // the resources allocated to that flow to the free list.
+ static void delete_flow(const FlowKey*);
+
+ // Examines the source and destination ip addresses and ports to determine if the
+ // packet is from the client or server side of the flow and sets bits in the
+ // packet_flags field of the Packet struct to indicate the direction determined.
+ static uint32_t get_packet_direction(Packet*);
+
+ // Sets the stream session into proxy mode.
+ static void proxy_started(Flow*, unsigned dir); // FIXIT-L method name is misleading
+
+ // Stop inspection on a flow for up to count bytes (-1 to ignore for life or until resume).
+ // If response flag is set, automatically resume inspection up to count bytes when a data
+ // packet in the other direction is seen. Also marks the packet to be ignored
+ // FIXIT-L stop_inspection() does not currently support the bytes/response parameters
+ static void stop_inspection(Flow*, Packet*, char dir, int32_t bytes, int rspFlag);
+
+ // Adds entry to the expected session cache with a flow key generated from the network
+ // n-tuple parameters specified. Inspection will be turned off for this expected session
+ // when it arrives.
+ static int ignore_flow(
+ const sfip_t *addr1, uint16_t p1, const sfip_t *addr2, uint16_t p2,
+ PktType, char dir, uint32_t ppId);
+
+ // Resume inspection for flow.
+ // FIXIT-L does resume work only for a flow that has been stopped by call to stop_inspection?
+ static void resume_inspection(Flow*, char dir);
+
+ // Set Active status to force drop the current packet and set flow state to drop
+ // subsequent packets arriving from the direction specified.
+ static void drop_traffic(Flow*, char dir);
+
+ // Mark a flow as dropped, release allocated resources, and set flow state such that any
+ // subsequent packets received on this flow are dropped.
+ static void drop_flow(const Packet*);
+
+ // FIXIT-L flush_request() / flush_response() are misnomers in ips mode and may cause errors
+
+ // Flush queued data on the listener side of a stream flow. The listener is the side of the
+ // connection the packet is destined, so if the Packet is from the client, then the
+ // server side tracker is flushed.
+ static void flush_request(Packet*); // flush listener
+
+ // Flush queued data on the talker side of a stream flow. The talker is the side of the
+ // connection the packet originated from, so if the Packet is from the client, then the
+ // client side tracker is flushed.
+ static void flush_response(Packet*); // flush talker
+
+ // Add session alert - true if added
+ static bool add_flow_alert(Flow*, Packet*, uint32_t gid, uint32_t sid);
+
+ // Check session alert - true if previously alerted
+ static bool check_flow_alerted(Flow*, Packet* p, uint32_t gid, uint32_t sid);
+
+ // Set Extra Data Logging
+ static int update_flow_alert(
+ Flow*, Packet* p, uint32_t gid, uint32_t sid,
+ uint32_t eventId, uint32_t eventSecond);
+
+ // Get reassembly direction for given session
+ static char get_reassembly_direction(Flow*);
+
+ // Returns true if stream data for the flow is in sequence, otherwise return false.
+ static bool is_stream_sequenced(Flow*, uint8_t dir);
+
+ // Get state of missing packets for the flow.
+ // SSN_MISSING_BOTH if missing before and after
+ // SSN_MISSING_BEFORE if missing before
+ // SSN_MISSING_AFTER if missing after
+ // SSN_MISSING_NONE if none missing
+ static int missing_in_reassembled(Flow*, uint8_t dir);
+
+ // Returns true if packets were missed on the stream, otherwise returns false.
+ static bool missed_packets(Flow*, uint8_t dir);
+
+ // Get the protocol identifier from a stream
+ static int16_t get_application_protocol_id(Flow*);
+
+ // Set the protocol identifier for a stream
+ static int16_t set_application_protocol_id(Flow*, int16_t appId);
+
+ // initialize response count and expiration time
+ static void init_active_response(const Packet*, Flow*);
+
+ static void set_splitter(Flow*, bool toServer, class StreamSplitter* = nullptr);
+ static StreamSplitter* get_splitter(Flow*, bool toServer);
+ static bool is_paf_active(Flow*, bool toServer);
+
+ // Turn off inspection for potential session. Adds session identifiers to a hash table.
+ // TCP only.
+ static int set_application_protocol_id_expected(
+ const sfip_t *a1, uint16_t p1, const sfip_t *a2, uint16_t p2, PktType,
+ int16_t appId, FlowData*);
+
+ // Get pointer to application data for a flow based on the lookup tuples for cases where
+ // Snort does not have an active packet that is relevant.
+ static FlowData* get_flow_data(
+ PktType type, IpProtocol proto,
+ const sfip_t *a1, uint16_t p1, const sfip_t *a2, uint16_t p2,
+ uint16_t vlanId, uint32_t mplsId, uint16_t addrSpaceId, unsigned flow_id);
+
+ // Get pointer to application data for a flow using the FlowKey as the lookup criteria
+ static FlowData* get_flow_data(const FlowKey*, unsigned flow_id);
+
+ // Get pointer to a session flow instance for a flow based on the lookup tuples for
+ // cases where Snort does not have an active packet that is relevant.
+ static Flow* get_flow(
+ PktType type, IpProtocol proto,
+ const sfip_t *a1, uint16_t p1, const sfip_t *a2, uint16_t p2,
+ uint16_t vlanId, uint32_t mplsId, uint16_t addrSpaceId);
+
+ // Delete the session if it is in the closed session state.
+ static void check_flow_closed(Packet*);
+
+ // Create a session key from the Packet
+ static FlowKey* get_flow_key(Packet*);
+
+ // Populate a session key from the Packet
+ static void populate_flow_key(Packet*, FlowKey*);
+
+ static void update_direction(Flow*, char dir, const sfip_t* ip, uint16_t port);
+
+ static void set_application_protocol_id(
+ Flow*, const struct HostAttributeEntry*, int direction);
+
+ static bool is_midstream(Flow* flow)
+ { return flow->ssn_state.session_flags & SSNFLAG_MIDSTREAM; }
+
+ // Get the TTL value used at session setup
+ // Set outer=false to get inner ip ttl for ip in ip; else outer=true
+ static uint8_t get_flow_ttl(Flow*, char dir, bool outer);
+
+ static bool expired_flow(Flow*, Packet*);
+ static bool ignored_flow(Flow*, Packet*);
+ static bool blocked_flow(Flow*, Packet*);
+
+ // extra data methods
+ static void set_extra_data(Flow*, Packet*, uint32_t);
+ static void clear_extra_data(Flow*, Packet*, uint32_t);
+ static void log_extra_data(Flow*, uint32_t mask, uint32_t id, uint32_t sec);
+
+ static uint32_t reg_xtra_data_cb(LogFunction);
+ static void reg_xtra_data_log(LogExtraData, void*);
+ static uint32_t get_xtra_data_map(LogFunction**);
+
+private:
+ static void set_ip_protocol(Flow*);
+};
#endif
+++ /dev/null
-//--------------------------------------------------------------------------
-// Copyright (C) 2014-2016 Cisco and/or its affiliates. All rights reserved.
-// Copyright (C) 2005-2013 Sourcefire, Inc.
-//
-// This program is free software; you can redistribute it and/or modify it
-// under the terms of the GNU General Public License Version 2 as published
-// by the Free Software Foundation. You may not use, modify or distribute
-// this program under any other version of the GNU General Public License.
-//
-// This program is distributed in the hope that it will be useful, but
-// WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-// General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License along
-// with this program; if not, write to the Free Software Foundation, Inc.,
-// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-//--------------------------------------------------------------------------
-
-// stream_api.h author Steven Sturges
-
-#ifndef STREAM_API_H
-#define STREAM_API_H
-
-/*
- * Purpose: Definition of the StreamAPI. To be used as a common interface
- * for TCP (and later UDP & ICMP) Stream access for other
- * preprocessors and detection plugins.
- */
-
-#include <sys/types.h>
-
-#include "sfip/sfip_t.h"
-#include "protocols/packet.h"
-#include "flow/flow.h"
-#include "main/snort_types.h"
-
-/* traffic direction identification */
-#define FROM_SERVER 0
-#define FROM_CLIENT 1
-
-#define SSN_MISSING_NONE 0x00
-#define SSN_MISSING_BEFORE 0x01
-#define SSN_MISSING_AFTER 0x02
-#define SSN_MISSING_BOTH (SSN_MISSING_BEFORE | SSN_MISSING_AFTER)
-
-#define SSN_DIR_NONE 0x00
-#define SSN_DIR_FROM_CLIENT 0x01
-#define SSN_DIR_FROM_SERVER 0x02
-#define SSN_DIR_BOTH 0x03
-
-// sequence must match FRAG_POLICY_* enum in stream_ip.h (1-based)
-#define IP_POLICIES \
- "first | linux | bsd | bsd_right | last | windows | solaris"
-
-// sequence must match STREAM_POLICY_* defines in tcp_session.cc (1-based)
-#define TCP_POLICIES \
- "first | last | linux | old_linux | bsd | macos | solaris | irix | " \
- "hpux11 | hpux10 | windows | win_2003 | vista | proxy"
-
-class Flow;
-
-typedef int (* LogFunction)(Flow*, uint8_t** buf, uint32_t* len, uint32_t* type);
-typedef void (* LogExtraData)(Flow*, void* config, LogFunction* funcs,
- uint32_t max_count, uint32_t xtradata_mask, uint32_t id, uint32_t sec);
-
-typedef int (* PacketIterator)
-(
- DAQ_PktHdr_t*,
- uint8_t*, /* pkt pointer */
- void* /* user-defined data pointer */
-);
-
-typedef int (* StreamSegmentIterator)
-(
- DAQ_PktHdr_t*,
- uint8_t*, /* pkt pointer */
- uint8_t*, /* payload pointer */
- uint32_t, /* sequence number */
- void* /* user-defined data pointer */
-);
-
-#define MAX_LOG_FN 32
-
-//-------------------------------------------------------------------------
-// public methods other than ctor / dtor must all be declared SO_PUBLIC
-//-------------------------------------------------------------------------
-
-class SO_PUBLIC Stream
-{
-public:
- SO_PRIVATE Stream();
- SO_PRIVATE ~Stream();
-
- // Looks in the flow cache for flow session with specified key and returns
- // pointer to flow session oject if found, otherwise null.
- static Flow* get_session(const FlowKey*);
-
- // Allocates a flow session object from the flow cache table for the protocol
- // type of the specified key. If no cache exists for that protocol type null is
- // returned. If a flow already exists for the key a pointer to that session
- // object is returned.
- // If a new session object can not be allocated the program is terminated.
- static Flow* new_session(const FlowKey*);
-
- // Removes the flow session object from the flow cache table and returns
- // the resources allocated to that flow to the free list.
- static void delete_session(const FlowKey*);
-
- // Examines the source and destination ip addresses and ports to determine if the
- // packet is from the client or server side of the flow and sets bits in the
- // packet_flags field of the Packet struct to indicate the direction determined.
- static uint32_t get_packet_direction(Packet*);
-
- // Sets the stream session into proxy mode.
- static void proxy_started(Flow*, unsigned dir); // FIXIT-L method name is misleading
-
- // Stop inspection on a flow for up to count bytes (-1 to ignore for life or until resume).
- // If response flag is set, automatically resume inspection up to count bytes when a data
- // packet in the other direction is seen. Also marks the packet to be ignored
- // FIXIT-L stop_inspection() does not currently support the bytes/response parameters
- static void stop_inspection(Flow*, Packet*, char dir, int32_t bytes, int rspFlag);
-
- // Adds entry to the expected session cache with a flow key generated from the network
- // n-tuple parameters specified. Inspection will be turned off for this expected session
- // when it arrives.
- int ignore_session( const sfip_t *addr1, uint16_t p1, const sfip_t *addr2, uint16_t p2,
- PktType, char dir, uint32_t ppId);
-
- // Resume inspection for flow.
- // FIXIT-L does resume work only for a flow that has been stopped by call to stop_inspection?
- static void resume_inspection(Flow*, char dir);
-
- // Set Active status to force drop the current packet and set flow state to drop
- // subsequent packets arriving from the direction specified.
- static void drop_traffic(Flow*, char dir);
-
- // Mark a flow as dropped, release allocated resources, and set flow state such that any
- // subsequent packets received on this flow are dropped.
- static void drop_session(const Packet*);
-
- // FIXIT-L flush_request() / flush_response() are misnomers in ips mode and may cause errors
-
- // Flush queued data on the listener side of a stream flow. The listener is the side of the
- // connection the packet is destined, so if the Packet is from the client, then the
- // server side tracker is flushed.
- static void flush_request(Packet*); // flush listener
-
- // Flush queued data on the talker side of a stream flow. The talker is the side of the
- // connection the packet originated from, so if the Packet is from the client, then the
- // client side tracker is flushed.
- static void flush_response(Packet*); // flush talker
-
- // Add session alert - true if added
- static bool add_session_alert(Flow*, Packet*, uint32_t gid, uint32_t sid);
-
- // Check session alert - true if previously alerted
- static bool check_session_alerted(Flow*, Packet* p, uint32_t gid, uint32_t sid);
-
- // Set Extra Data Logging
- static int update_session_alert(
- Flow*, Packet* p, uint32_t gid, uint32_t sid,
- uint32_t eventId, uint32_t eventSecond);
-
- // Get pointer to Flowbits data
- static BitOp* get_flow_bitop(const Packet*);
-
- // Get reassembly direction for given session
- static char get_reassembly_direction(Flow*);
-
- // Returns true if stream data for the flow is in sequence, otherwise return false.
- static bool is_stream_sequenced(Flow*, uint8_t dir);
-
- // Get state of missing packets for the flow.
- // SSN_MISSING_BOTH if missing before and after
- // SSN_MISSING_BEFORE if missing before
- // SSN_MISSING_AFTER if missing after
- // SSN_MISSING_NONE if none missing
- static int missing_in_reassembled(Flow*, uint8_t dir);
-
- // Returns true if packets were missed on the stream, otherwise returns false.
- static bool missed_packets(Flow*, uint8_t dir);
-
- // Get the protocol identifier from a stream
- static int16_t get_application_protocol_id(Flow*);
-
- // Set the protocol identifier for a stream
- static int16_t set_application_protocol_id(Flow*, int16_t appId);
-
- // initialize response count and expiration time
- static void init_active_response(const Packet*, Flow*);
-
- static void set_splitter(Flow*, bool toServer, class StreamSplitter* = nullptr);
- static StreamSplitter* get_splitter(Flow*, bool toServer);
- static bool is_paf_active(Flow*, bool toServer);
-
- // Turn off inspection for potential session. Adds session identifiers to a hash table.
- // TCP only.
- int set_application_protocol_id_expected(
- const sfip_t *a1, uint16_t p1, const sfip_t *a2, uint16_t p2, PktType,
- int16_t appId, FlowData*);
-
- // Get pointer to application data for a flow based on the lookup tuples for cases where
- // Snort does not have an active packet that is relevant.
- static FlowData* get_application_data_from_ip_port(
- PktType type, IpProtocol proto,
- const sfip_t *a1, uint16_t p1, const sfip_t *a2, uint16_t p2,
- uint16_t vlanId, uint32_t mplsId, uint16_t addrSpaceId, unsigned flow_id);
-
- // Get pointer to application data for a flow using the FlowKey as the lookup criteria
- static FlowData* get_application_data_from_key(const FlowKey*, unsigned flow_id);
-
- // -- extra data methods
- uint32_t reg_xtra_data_cb(LogFunction);
- void reg_xtra_data_log(LogExtraData, void*);
- uint32_t get_xtra_data_map(LogFunction**);
-
- static void set_extra_data(Flow*, Packet*, uint32_t);
- static void clear_extra_data(Flow*, Packet*, uint32_t);
- void log_extra_data(Flow*, uint32_t mask, uint32_t id, uint32_t sec);
-
- // Get pointer to a session flow instance for a flow based on the lookup tuples for
- // cases where Snort does not have an active packet that is relevant.
- static Flow* get_session_ptr_from_ip_port(
- PktType type, IpProtocol proto,
- const sfip_t *a1, uint16_t p1, const sfip_t *a2, uint16_t p2,
- uint16_t vlanId, uint32_t mplsId, uint16_t addrSpaceId);
-
- // Delete the session if it is in the closed session state.
- void check_session_closed(Packet*);
-
- // Create a session key from the Packet
- static FlowKey* get_session_key(Packet*);
-
- // Populate a session key from the Packet
- static void populate_session_key(Packet*, FlowKey*);
-
- void update_direction(Flow*, char dir, const sfip_t* ip, uint16_t port);
-
- static void set_application_protocol_id_from_host_entry(
- Flow*, const struct HostAttributeEntry*, int direction);
-
- static bool is_midstream(Flow* flow)
- { return flow->ssn_state.session_flags & SSNFLAG_MIDSTREAM; }
-
- // Get the TTL value used at session setup
- // Set outer=false to get inner ip ttl for ip in ip; else outer=true
- static uint8_t get_session_ttl(Flow*, char dir, bool outer);
-
- static bool expired_session(Flow*, Packet*);
- static bool ignored_session(Flow*, Packet*);
- static bool blocked_session(Flow*, Packet*);
-
-private:
- static void set_ip_protocol(Flow*);
-
-private:
- uint32_t xtradata_func_count = 0;
- LogFunction xtradata_map[MAX_LOG_FN];
- LogExtraData extra_data_log = NULL;
- void* extra_data_config = NULL;
-};
-
-SO_PUBLIC extern Stream stream;
-
-#endif
-
#include "flush_bucket.h"
#include "protocols/packet.h"
-static THREAD_LOCAL uint8_t pdu_buf[65536];
+static THREAD_LOCAL uint8_t pdu_buf[StreamSplitter::max_buf];
static THREAD_LOCAL StreamBuffer str_buf;
unsigned StreamSplitter::max_pdu = 16384;
// paf_max; the HI splitter should pull from there
static void set_max(unsigned);
+ // FIXIT-L max_pdu should suffice
+ static const unsigned max_buf = 65536;
+
virtual void reset() { }
virtual void update() { }
An instance of this data structure is allocated and managed for each end of
the connection.
-
+The module tcp_ha.cc (and tcp_ha.h) implements the per-protocol hooks into
+the stream logic for HA. TcpHAManager is a static class that interfaces
+to a per-packet thread instance of the class TcpHA. TcpHA is sub-class
+of ProtocolHA, declared in the stream/base area. Thus each protocol
+within 'stream' can have specific HA logic and interfaces.
+
+TcpHAManager::process_deletion() is called when an TCP stream is being
+destroyed and indicates to the stream & flow HA logic that a flow
+deletion HA message needs to be emitted for the flow in question.
+Tcp streams are both closed internally (e.g. FIN) and externally due
+to cache timeout or pruning. The calls to TcpHAManager::process_deletion()
+in tcp/tcp_session.cc indicate a normal closure of a stream/flow.
+
+TcpHA::create_session() is called from the stream & flow HA logic and
+handles the creation of new flow upon receiving an HA update message.
+
+TcpHA::deactivate_session() is called from the stream & flow HA logic to
+place a session into standby mode. Upon receiving an HA Update message,
+the flow is first created if necessary, and is then placed into Standby
+state. deactivate_session() sets the TCP specific state for Standy mode.
if ( srod.direction & SSN_DIR_FROM_SERVER )
{
tcpssn->server->flush_policy = STREAM_FLPOLICY_IGNORE;
- stream.set_splitter(lwssn, true);
+ Stream::set_splitter(lwssn, true);
}
if ( srod.direction & SSN_DIR_FROM_CLIENT )
{
tcpssn->client->flush_policy = STREAM_FLPOLICY_IGNORE;
- stream.set_splitter(lwssn, false);
+ Stream::set_splitter(lwssn, false);
}
}
else
if ( srod.direction & SSN_DIR_FROM_SERVER )
{
tcpssn->server->flush_policy = STREAM_FLPOLICY_ON_ACK;
- stream.set_splitter(lwssn, true, new AtomSplitter(true));
+ Stream::set_splitter(lwssn, true, new AtomSplitter(true));
}
if ( srod.direction & SSN_DIR_FROM_CLIENT )
{
tcpssn->client->flush_policy = STREAM_FLPOLICY_ON_ACK;
- stream.set_splitter(lwssn, false, new AtomSplitter(false));
+ Stream::set_splitter(lwssn, false, new AtomSplitter(false));
}
}
IpsOption* ropt = reassemble_api.ctor(reassembler, nullptr);
int rc = ropt->eval(cursor, pkt);
CHECK( ( rc == DETECTION_OPTION_MATCH ) );
- StreamSplitter* ss = stream.get_splitter(flow, true);
+ StreamSplitter* ss = Stream::get_splitter(flow, true);
CHECK( ( ss != nullptr ) );
CHECK( ( !ss->is_paf() ) );
CHECK( ( ( ( TcpSession* )pkt->flow->session)->server.flush_policy
#ifndef SEGMENT_OVERLAP_EDITOR_H
#define SEGMENT_OVERLAP_EDITOR_H
+#include "normalize/normalize.h"
#include "tcp_defs.h"
#include "tcp_segment_node.h"
#include "tcp_session.h"
#define STREAM_TCP_H
#include "flow/flow.h"
-#include "stream/stream_api.h"
#include "protocols/packet.h"
#include "tcp_defs.h"
#define SLAM_MAX 4
-// target-based policy types - changes to this enum require changes to stream_api.h::TCP_POLICIES
+// target-based policy types - changes to this enum require changes to stream.h::TCP_POLICIES
enum class StreamPolicy
{
OS_INVALID = 0,
#include "tcp_ha.h"
-#include "flow/flow_control.h"
#include "main/snort_debug.h"
-#include "stream/tcp/tcp_session.h"
+#include "stream/stream.h"
+#include "tcp_session.h"
Flow* TcpHA::create_session(FlowKey* key)
{
- DebugMessage(DEBUG_HA,"TcpHA::create_session)\n");
+ assert(key);
- assert ( key );
-
- Flow* flow = flow_con->new_flow(key);
+ Flow* flow = Stream::new_flow(key);
if ( (flow != nullptr ) && (flow->session == nullptr) )
{
#include <string>
#include "profiler/profiler.h"
-#include "stream_tcp.h"
#include "stream/stream.h"
+#include "stream_tcp.h"
using namespace std;
switch ( index )
{
case 0:
- name = "stream_tcp";
- parent = nullptr;
+ name = MOD_NAME;
+ parent = "stream";
return &s5TcpPerfStats;
case 1:
#include "main/snort_types.h"
#include "main/thread.h"
+#include "flow/session.h"
#include "framework/module.h"
-#include "stream/stream.h"
#include "tcp_stream_config.h"
#define GID_STREAM_TCP 129
#include "main/snort.h"
#include "protocols/packet.h"
-#include "stream/stream.h"
+#include "protocols/packet_manager.h"
#include "profiler/profiler.h"
#include "flow/flow_control.h"
//if (SEQ_LT(ai->seq, flush_seq) )
{
- stream.log_extra_data(flow, xtradata_mask, ai->event_id, ai->event_second);
+ Stream::log_extra_data(flow, xtradata_mask, ai->event_id, ai->event_second);
memset(ai, 0, sizeof(*ai));
}
#if 0
}
}
-uint32_t TcpReassembler::get_flush_data_len(TcpSegmentNode* tsn, uint32_t to_seq,
- uint32_t flushBufSize)
+uint32_t TcpReassembler::get_flush_data_len(TcpSegmentNode* tsn, uint32_t to_seq, unsigned max)
{
unsigned int flushSize = tsn->payload_size;
- // copy only till flush buffer gets full
- if ( flushSize > flushBufSize )
- flushSize = flushBufSize;
+ if ( flushSize > max )
+ flushSize = max;
// copy only to flush point
if ( paf_active(&tracker->paf_state) && SEQ_GT(tsn->seq + flushSize, to_seq) )
}
// flush the client seglist up to the most recently acked segment
-int TcpReassembler::flush_data_segments(Packet* p, uint32_t toSeq, uint8_t* flushbuf,
- const uint8_t* flushbuf_end)
+int TcpReassembler::flush_data_segments(Packet* p, uint32_t toSeq)
{
- uint16_t bytes_flushed = 0;
+ uint32_t bytes_flushed = 0;
uint32_t segs = 0;
uint32_t flags = PKT_PDU_HEAD;
DEBUG_WRAP(uint32_t bytes_queued = seg_bytes_logical; );
while ( SEQ_LT(seglist.next->seq, toSeq) )
{
TcpSegmentNode* tsn = seglist.next, * sr = nullptr;
- unsigned flushbuf_size = flushbuf_end - flushbuf;
- unsigned bytes_to_copy = get_flush_data_len(tsn, toSeq, flushbuf_size);
+ unsigned bytes_to_copy = get_flush_data_len(tsn, toSeq, tracker->splitter->max(p->flow));
unsigned bytes_copied = 0;
assert(bytes_to_copy);
|| SEQ_EQ(tsn->seq + bytes_to_copy, toSeq) )
flags |= PKT_PDU_TAIL;
- const StreamBuffer* sb = tracker->splitter->reassemble(p->flow, total, bytes_flushed,
- tsn->payload,
- bytes_to_copy, flags, bytes_copied);
+ const StreamBuffer* sb = tracker->splitter->reassemble(
+ p->flow, total, bytes_flushed, tsn->payload, bytes_to_copy, flags, bytes_copied);
+
flags = 0;
+
if ( sb )
{
s5_pkt->data = sb->data;
s5_pkt->dsize = sb->length;
assert(sb->length <= s5_pkt->max_dsize);
- // FIXIT-M flushbuf should be eliminated from this function
- // since we are actually using the stream splitter buffer
- flushbuf = ( uint8_t* )s5_pkt->data;
- // ensure we stop here
bytes_to_copy = bytes_copied;
}
assert(bytes_to_copy == bytes_copied);
-
- flushbuf += bytes_to_copy;
bytes_flushed += bytes_to_copy;
if ( bytes_to_copy < tsn->payload_size
flush_count++;
segs++;
- if ( flushbuf >= flushbuf_end )
- break;
-
if ( SEQ_EQ(tsn->seq + bytes_to_copy, toSeq) )
break;
if ( tsn->next )
seglist.next = tsn->next;
- tracker->set_tf_flags(TF_MISSING_PKT);
+ // FIXIT-L this is suboptimal - better to exclude fin from toSeq
+ if ( !tracker->fin_set() or SEQ_LT(toSeq, tracker->fin_final_seq) )
+ tracker->set_tf_flags(TF_MISSING_PKT);
+
break;
}
seglist.next = tsn->next;
if ( sb || !seglist.next )
break;
+
+ if ( bytes_flushed + seglist.next->payload_size >= StreamSplitter::max_buf )
+ break;
}
DEBUG_WRAP(bytes_queued -= bytes_flushed; );
prep_s5_pkt(session->flow, p, pkt_flags);
- // if not specified, set bytes to flush to what was acked
- if (!bytes && SEQ_GT(tracker->r_win_base, seglist_base_seq))
- bytes = tracker->r_win_base - seglist_base_seq;
-
// FIXIT-L this should not be necessary here
seglist_base_seq = seglist.next->seq;
stop_seq = seglist_base_seq + bytes;
/* setup the pseudopacket payload */
s5_pkt->dsize = 0;
- s5_pkt->data = s5_pkt->pkt;
- const uint8_t* s5_pkt_end = s5_pkt->data + s5_pkt->max_dsize;
- flushed_bytes = flush_data_segments(p, stop_seq, (uint8_t*)s5_pkt->data, s5_pkt_end);
+ s5_pkt->data = nullptr;
+ flushed_bytes = flush_data_segments(p, stop_seq);
if ( flushed_bytes == 0 )
break; /* No more data... bail */
return _flush_to_seq(bytes, p, pkt_flags);
}
-// FIXIT-H the seq number math in the following 2 funcs does not handle
-// wrapping get the footprint for the current seglist, the difference
+// get the footprint for the current seglist, the difference
// between our base sequence and the last ack'd sequence we received
uint32_t TcpReassembler::get_q_footprint()
{
- int32_t fp;
-
- if ( tracker == nullptr )
- return 0;
-
- fp = tracker->r_win_base - seglist_base_seq;
- if ( fp <= 0 )
+ if ( !tracker )
return 0;
seglist.next = seglist.head;
+ uint32_t fp = tracker->r_win_base - seglist_base_seq;
+
+ // FIXIT-M ideally would exclude fin here
+
return fp;
}
// FIXIT-P get_q_sequenced() performance could possibly be
// boosted by tracking sequenced bytes as seglist is updated
// to avoid the while loop, etc. below.
+
uint32_t TcpReassembler::get_q_sequenced()
{
int32_t len;
#include "framework/counts.h"
#include "detection/detect.h"
#include "normalize/normalize.h"
-#include "stream/stream_api.h"
#include "segment_overlap_editor.h"
#include "tcp_defs.h"
bool is_segment_fasttrack(TcpSegmentNode* tail, TcpSegmentDescriptor&);
int purge_alerts(uint32_t /*flush_seq*/, Flow* flow);
void show_rebuilt_packet(Packet* pkt);
- uint32_t get_flush_data_len(TcpSegmentNode* ss, uint32_t to_seq, uint32_t flushBufSize);
- int flush_data_segments(Packet* p, uint32_t toSeq, uint8_t* flushbuf,
- const uint8_t* flushbuf_end);
+ uint32_t get_flush_data_len(TcpSegmentNode* ss, uint32_t to_seq, unsigned max);
+ int flush_data_segments(Packet* p, uint32_t toSeq);
void prep_s5_pkt(Flow* flow, Packet* p, uint32_t pkt_flags);
int _flush_to_seq(uint32_t bytes, Packet* p, uint32_t pkt_flags);
int flush_to_seq(uint32_t bytes, Packet* p, uint32_t pkt_flags);
#include "log/log_text.h"
#include "stream/stream.h"
#include "stream/stream_splitter.h"
-#include "flow/flow_control.h"
#include "flow/session.h"
#include "profiler/profiler.h"
#include "file_api/file_api.h"
-#include "normalize/normalize.h"
#include "perf_monitor/flow_tracker.h"
#include "filters/sfrf.h"
{
if ( client->reassembler )
{
- if( flush_segments )
+ if ( flush_segments )
client->reassembler->flush_queued_segments(flow, true, p);
client->reassembler->purge_segment_list();
}
if ( server->reassembler )
{
- if( flush_segments )
+ if ( flush_segments )
server->reassembler->flush_queued_segments(flow, true, p);
server->reassembler->purge_segment_list();
}
else
return;
- if (flow->get_session_flags() & SSNFLAG_PRUNED)
+ if ( flow->get_session_flags() & SSNFLAG_PRUNED )
tcpStats.prunes++;
- else if (flow->get_session_flags() & SSNFLAG_TIMEDOUT)
+
+ else if ( flow->get_session_flags() & SSNFLAG_TIMEDOUT )
tcpStats.timeouts++;
update_perf_base_state(TcpStreamTracker::TCP_CLOSED);
- if( restart )
+ if ( restart )
{
flow->restart(free_flow_data);
paf_reset(&client->paf_state);
if ( ( session_flags & SSNFLAG_COUNTED_INITIALIZE )
&& !( session_flags & SSNFLAG_COUNTED_CLOSING ) )
{
- assert(tcpStats.sessions_initializing);
- tcpStats.sessions_initializing--;
+ //assert(tcpStats.sessions_initializing);
+ if ( tcpStats.sessions_initializing ) // FIXIT-L eliminate / fix underflow
+ tcpStats.sessions_initializing--;
}
}
break;
if ( session_flags & SSNFLAG_COUNTED_ESTABLISH )
{
- assert(tcpStats.sessions_established);
+ //assert(tcpStats.sessions_established);
tcpStats.sessions_established--;
if (perfmon_config && (perfmon_config->perf_flags & PERF_FLOWIP))
}
else if ( session_flags & SSNFLAG_COUNTED_INITIALIZE )
{
- assert(tcpStats.sessions_initializing);
- tcpStats.sessions_initializing--;
+ //assert(tcpStats.sessions_initializing);
+ if ( tcpStats.sessions_initializing ) // FIXIT-L eliminate / fix underflow
+ tcpStats.sessions_initializing--;
}
}
break;
case TcpStreamTracker::TCP_CLOSED:
if ( session_flags & SSNFLAG_COUNTED_CLOSING )
{
- assert(tcpStats.sessions_closing);
+ //assert(tcpStats.sessions_closing);
tcpStats.sessions_closing--;
}
else if ( session_flags & SSNFLAG_COUNTED_ESTABLISH )
{
- assert(tcpStats.sessions_established);
- tcpStats.sessions_established--;
+ //assert(tcpStats.sessions_established);
+ if ( tcpStats.sessions_established ) // FIXIT-L eliminate / fix underflow
+ tcpStats.sessions_established--;
if ( perfmon_config && ( perfmon_config->perf_flags & PERF_FLOWIP ) )
perf_flow_ip->update_state(&flow->client_ip,
}
else if ( session_flags & SSNFLAG_COUNTED_INITIALIZE )
{
- assert(tcpStats.sessions_initializing);
- tcpStats.sessions_initializing--;
+ //assert(tcpStats.sessions_initializing);
+ if ( tcpStats.sessions_initializing ) // FIXIT-L eliminate / fix underflow
+ tcpStats.sessions_initializing--;
}
break;
{
// FIXIT-L why flush here instead of just purge?
// s5_ignored_session() may be disabling detection too soon if we really want to flush
- if (stream.ignored_session(flow, tsd.get_pkt()))
+ if (Stream::ignored_flow(flow, tsd.get_pkt()))
{
if ( talker && ( talker->get_tf_flags() & TF_FORCE_FLUSH ) )
{
flush_talker(tsd.get_pkt());
set_splitter(true, nullptr);
set_splitter(false, nullptr);
- flow->free_application_data();
+ flow->free_flow_data();
}
talker->update_on_rst_sent( );
void TcpSession::check_for_repeated_syn(TcpSegmentDescriptor& tsd)
{
uint32_t action = ACTION_NOTHING;
- if (!SEQ_EQ(tsd.get_seg_seq(), talker->get_iss())
- && listener->normalizer->packet_dropper(tsd, NORM_TCP_BLOCK))
+
+ if ( !SEQ_EQ(tsd.get_seg_seq(), talker->get_iss()) and
+ listener->normalizer->packet_dropper(tsd, NORM_TCP_BLOCK) )
+ {
action = ACTION_BAD_PKT;
- else if (talker->get_tcp_state() >= TcpStreamTracker::TCP_ESTABLISHED)
+ }
+ else if ( talker->get_tcp_state() >= TcpStreamTracker::TCP_ESTABLISHED and
+ talker->get_tcp_state() < TcpStreamTracker::TCP_CLOSED )
+ {
action = listener->normalizer->handle_repeated_syn(tsd);
-
+ }
if (action != ACTION_NOTHING)
{
/* got a bad SYN on the session, alert! */
flow_ready = false;
}
- if (stream.blocked_session(flow, p) || (flow->session_state & STREAM_STATE_IGNORE))
+ if (Stream::blocked_flow(flow, p) || (flow->session_state & STREAM_STATE_IGNORE))
flow_ready = false;
- // FIXIT-L expected flow should be checked by flow_con before we get here
+ // FIXIT-L expected flow should be checked by Stream before we get here
// harmonize this with that and the checks above
- char ignore = flow_con->expected_flow(flow, p);
- if (ignore)
+
+ if ( Stream::expected_flow(flow, p) )
{
server->flush_policy = STREAM_FLPOLICY_IGNORE;
client->flush_policy = STREAM_FLPOLICY_IGNORE;
{
// Check if the session is expired. Should be done before we do something with
// the packet...Insert a packet, or handle state change SYN, FIN, RST, etc.
- if (stream.expired_session(flow, p))
+ if (Stream::expired_flow(flow, p))
{
/* Session is timed out, if also reset then restart, otherwise clear */
if (flow->get_session_flags() & SSNFLAG_RESET)
// tcp_state_closed.cc author davis mcpherson <davmcphe@@cisco.com>
// Created on: Jul 30, 2015
-#include "stream/stream.h"
+#include "tcp_state_closed.h"
#include "tcp_module.h"
#include "tcp_tracker.h"
#include "tcp_session.h"
#include "tcp_normalizer.h"
-#include "tcp_state_closed.h"
#ifdef UNIT_TEST
#include "catch/catch.hpp"
// tcp_state_none.cc author davis mcpherson <davmcphe@@cisco.com>
// Created on: Jul 30, 2015
-#include "stream/stream.h"
+#include "tcp_state_none.h"
#include "tcp_module.h"
#include "tcp_tracker.h"
#include "tcp_session.h"
#include "tcp_normalizer.h"
-#include "tcp_state_none.h"
#ifdef UNIT_TEST
#include "catch/catch.hpp"
if ( trk.update_on_rst_recv(tsd) )
{
trk.session->update_session_on_rst(tsd, false);
- trk.session->update_perf_base_state(TcpStreamTracker::TCP_CLOSING);
+ trk.set_tcp_state(TcpStreamTracker::TCP_CLOSED);
+ trk.session->update_perf_base_state(TcpStreamTracker::TCP_CLOSED);
trk.session->set_pkt_action_flag(ACTION_RST);
+ tsd.get_pkt()->flow->session_state |= STREAM_STATE_CLOSED;
}
else
{
#define TCP_STREAM_CONFIG_H
#include "time/packet_time.h"
-#include "stream/stream.h"
-
#include "tcp_defs.h"
+#define STREAM_CONFIG_STATEFUL_INSPECTION 0x00000001
+#define STREAM_CONFIG_LOG_STREAMS 0x00000004
+#define STREAM_CONFIG_REASS_CLIENT 0x00000008
+#define STREAM_CONFIG_REASS_SERVER 0x00000010
+#define STREAM_CONFIG_ASYNC 0x00000020
+#define STREAM_CONFIG_SHOW_PACKETS 0x00000040
+#define STREAM_CONFIG_MIDSTREAM_DROP_NOALERT 0x00000080
+#define STREAM_CONFIG_IGNORE_ANY 0x00000100
+#define STREAM_CONFIG_STATIC_FLUSHPOINTS 0x00000200
+#define STREAM_CONFIG_IPS 0x00000400
+#define STREAM_CONFIG_NO_ASYNC_REASSEMBLY 0x00000800
+
+#define STREAM_DEFAULT_SSN_TIMEOUT 30
+
class TcpStreamConfig
{
public:
r_nxt_ack++;
// set final seq # any packet rx'ed with seq > is bad
- if ( fin_final_seq == 0 )
+ if ( !fin_set() )
fin_final_seq = tsd.get_end_seq() + 1;
return true;
void flush_data_on_fin_recv(TcpSegmentDescriptor& tsd) override;
void init_toolbox() override;
-
};
#endif
packet eval method is not used as the base Stream Inspector delegates
packets directly to the UDP session packet processing method.
+The module udp_ha.cc (and udp_ha.h) implements the per-protocol hooks into
+the stream logic for HA. UdpHAManager is a static class that interfaces
+to a per-packet thread instance of the class UdpHA. UdpHA is sub-class
+of ProtocolHA, declared in the stream/base area. Thus each protocol
+within 'stream' can have specific HA logic and interfaces.
+
+UdpHAManager::process_deletion() is called when an UDP stream is being
+destroyed and indicates to the stream & flow HA logic that a flow
+deletion HA message needs to be emitted for the flow in question.
+Udp streams are closed due to timeout or puning actions which lead
+to the invocation of process_deletion().
+
+UdpHA::create_session() is called from the stream & flow HA logic and
+handles the creation of new flow upon receiving an HA update message.
#include "udp_ha.h"
-#include "flow/flow_control.h"
#include "main/snort_debug.h"
-#include "stream/udp/udp_session.h"
-
-extern THREAD_LOCAL class FlowControl* flow_con;
+#include "stream/stream.h"
+#include "udp_session.h"
Flow* UdpHA::create_session(FlowKey* key)
{
- DebugMessage(DEBUG_HA,"UdpHA::create_session\n");
-
- assert ( key );
+ assert(key);
- Flow* flow = flow_con->new_flow(key);
+ Flow* flow = Stream::new_flow(key);
if ( (flow != nullptr ) && (flow->session == nullptr) )
{
config = nullptr;
}
-ProfileStats* StreamUdpModule::get_profile() const
+ProfileStats* StreamUdpModule::get_profile(
+ unsigned index, const char*& name, const char*& parent) const
{
+ if ( index )
+ return nullptr;
+
+ name = MOD_NAME;
+ parent = "stream";
return &udp_perf_stats;
}
#include "main/snort_types.h"
#include "main/thread.h"
+#include "flow/session.h"
#include "framework/module.h"
-#include "stream/stream.h"
struct SnortConfig;
bool begin(const char*, int, SnortConfig*) override;
bool end(const char*, int, SnortConfig*) override;
- ProfileStats* get_profile() const override;
+ ProfileStats* get_profile(unsigned, const char*&, const char*&) const override;
const PegInfo* get_pegs() const override;
PegCount* get_counts() const override;
StreamUdpConfig* get_data();
#include "config.h"
#endif
-#include "stream_udp.h"
-#include "udp_module.h"
-#include "udp_ha.h"
-
#include "stream/stream.h"
#include "main/snort_types.h"
#include "main/snort_debug.h"
#include "hash/sfxhash.h"
#include "utils/util.h"
#include "protocols/packet.h"
-#include "flow/flow_control.h"
#include "flow/session.h"
#include "packet_io/active.h"
+#include "perf_monitor/flow_ip_tracker.h"
#include "profiler/profiler.h"
#include "sfip/sf_ip.h"
-#include "perf_monitor/flow_ip_tracker.h"
+#include "stream/stream.h"
+
+#include "stream_udp.h"
+#include "udp_module.h"
+#include "udp_ha.h"
// NOTE: sender is assumed to be client
// responder is assumed to be server
{
if (lwssn->ssn_state.session_flags & SSNFLAG_PRUNED)
udpStats.prunes++;
+
else if (lwssn->ssn_state.session_flags & SSNFLAG_TIMEDOUT)
udpStats.timeouts++;
{
assert(lwssn->pkt_type == PktType::UDP);
- if ( stream.blocked_session(lwssn, p) )
+ if ( Stream::blocked_flow(lwssn, p) )
return 0;
- if ( stream.ignored_session(lwssn, p) )
+ if ( Stream::ignored_flow(lwssn, p) )
return 0;
/* if both seen, mark established */
&flow->server_ip, SFS_STATE_UDP_CREATED);
}
- if ( flow_con->expected_flow(flow, p) )
+ if ( Stream::expected_flow(flow, p) )
{
udpStats.sessions--; // incremented in SESSIONS_STATS_ADD
return false;
StreamUdpConfig* pc = get_udp_cfg(flow->ssn_server);
// Check if the session is expired.
// Should be done before we do something with the packet...
- if ( stream.expired_session(flow, p) )
+ if ( Stream::expired_flow(flow, p) )
{
UdpSessionCleanup(flow);
flow->restart();
flow->ssn_state.session_flags |= SSNFLAG_SEEN_SENDER;
- udpStats.created++; // FIXIT-M is this correct? will mess with calc of current sessions
- udpStats.timeouts++;
+ udpStats.created++;
UdpHAManager::process_deletion(flow);
}
#include "stream_user.h"
#include "main/snort_config.h"
-#include "stream/stream.h"
//-------------------------------------------------------------------------
// stream_user module
#include "config.h"
#endif
-#include "stream_user.h"
-#include "user_module.h"
-
-#include "stream/stream.h"
-#include "stream/stream_splitter.h"
-#include "stream/paf.h"
-
-#include "flow/flow_control.h"
#include "main/snort.h"
#include "perf_monitor/perf_monitor.h"
#include "profiler/profiler.h"
#include "sfip/sf_ip.h"
#include "utils/util.h"
+#include "stream/stream.h"
+#include "stream/stream_splitter.h"
+#include "stream/paf.h"
+
+#include "stream_user.h"
+#include "user_module.h"
+
THREAD_LOCAL ProfileStats user_perf_stats;
// we always get exactly one copy of user data in order
server.init();
#ifdef ENABLE_EXPECTED_USER
- if ( flow_con->expected_session(flow, p))
+ if ( Stream::expected_flow(flow, p) )
return false;
#endif
return true;
{
Profile profile(user_perf_stats);
- if ( stream.expired_session(flow, p) )
+ if ( Stream::expired_flow(flow, p) )
{
flow->restart();
// FIXIT-M count user session timeouts here
#ifdef ENABLE_EXPECTED_USER
- if ( flow_con->expected_session(flow, p))
+ if ( Stream::expected_flow(flow, p))
return 0;
#endif
}
flow->set_direction(p);
- if ( stream.blocked_session(flow, p) || stream.ignored_session(flow, p) )
+ if ( Stream::blocked_flow(flow, p) || Stream::ignored_flow(flow, p) )
return 0;
update(p, flow);
#include <vector>
using namespace std;
+#include "hash/sfghash.h"
+#include "main/snort_debug.h"
+#include "utils/util.h"
+#include "stream/stream.h"
+
#include "sftarget_reader.h"
#include "sftarget_hostentry.h"
#include "sftarget_data.h"
-#include "hash/sfghash.h"
-#include "utils/util.h"
-#include "main/snort_debug.h"
-#include "stream/stream_api.h"
-
struct SFTargetProtocolReference
{
char name[SFAT_BUFSZ];
if ( p->flow )
{
/* Use session information via Stream API */
- protocol = stream.get_application_protocol_id(p->flow);
+ protocol = Stream::get_application_protocol_id(p->flow);
if ( protocol )
break;
periodic.cc
periodic.h
timersub.h
+ tsc_clock.cc
)
if ( ENABLE_UNIT_TESTS )
endif ( ENABLE_UNIT_TESTS )
set ( TIME_INCLUDES
- cpuclock.h
clock_defs.h
stopwatch.h
+ tsc_clock.h
)
add_library ( time STATIC
x_includedir = $(pkgincludedir)/time
x_include_HEADERS = \
-cpuclock.h \
clock_defs.h \
-stopwatch.h
+stopwatch.h \
+tsc_clock.h
libtime_a_SOURCES = \
+clock_defs.h \
packet_time.cc \
packet_time.h \
periodic.cc \
periodic.h \
-timersub.h \
-clock_defs.h \
-stopwatch.h
+stopwatch.h \
+timersub.h \
+tsc_clock.cc
if ENABLE_UNIT_TESTS
libtime_a_SOURCES += stopwatch_test.cc
#ifndef CLOCK_DEFS_H
#define CLOCK_DEFS_H
-#include <chrono>
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef USE_TSC_CLOCK
+#include "time/tsc_clock.h"
+using SnortClock = TscClock;
+#else
+#include <chrono>
using hr_clock = std::chrono::high_resolution_clock;
-using hr_duration = hr_clock::duration;
-using hr_time = hr_clock::time_point;
+using SnortClock = hr_clock;
+inline long clock_scale() { return 1.0; }
+#endif
+
+using hr_duration = SnortClock::duration;
+using hr_time = SnortClock::time_point;
inline constexpr hr_duration operator "" _ticks (unsigned long long int v)
{ return hr_duration(v); }
using time_point = TimePoint;
using rep = Rep;
};
+
+inline long clock_usecs(long ticks)
+{ return ticks / clock_scale(); }
+
+inline long clock_ticks(long usecs)
+{ return usecs * clock_scale(); }
+
#endif
+++ /dev/null
-//--------------------------------------------------------------------------
-// Copyright (C) 2014-2016 Cisco and/or its affiliates. All rights reserved.
-// Copyright (C) 2006-2013 Sourcefire, Inc.
-//
-// This program is free software; you can redistribute it and/or modify it
-// under the terms of the GNU General Public License Version 2 as published
-// by the Free Software Foundation. You may not use, modify or distribute
-// this program under any other version of the GNU General Public License.
-//
-// This program is distributed in the hope that it will be useful, but
-// WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-// General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License along
-// with this program; if not, write to the Free Software Foundation, Inc.,
-// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-//--------------------------------------------------------------------------
-
-#ifndef CPUCLOCK_H
-#define CPUCLOCK_H
-
-// Assembly to find clock ticks
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <unistd.h>
-
-// INTEL LINUX/BSD/..
-#if (defined(__i386) || defined(__amd64) || defined(__x86_64__))
-#define get_clockticks(val) \
-{ \
- uint32_t a, d; \
- __asm__ __volatile__ ("rdtsc" : "=a" (a), "=d" (d)); \
- val = ((uint64_t)a) | (((uint64_t)d) << 32); \
-}
-#else
-#if (defined(__ia64) && defined(__GNUC__) )
-#define get_clockticks(val) \
-{ \
- __asm__ __volatile__ ("mov %0=ar.itc" : "=r" (val)); \
-}
-#else
-#if (defined(__ia64) && defined(__hpux))
-#include <machine/sys/inline.h>
-#define get_clockticks(val) \
-{ \
- val = _Asm_mov_from_ar (_AREG_ITC); \
-}
-#else
-// POWER PC
-#if (defined(__GNUC__) && (defined(__powerpc__) || (defined(__ppc__))))
-#define get_clockticks(val) \
-{ \
- uint32_t tbu0, tbu1, tbl; \
- do \
- { \
- __asm__ __volatile__ ("mftbu %0" : "=r" (tbu0)); \
- __asm__ __volatile__ ("mftb %0" : "=r" (tbl)); \
- __asm__ __volatile__ ("mftbu %0" : "=r" (tbu1)); \
- } while (tbu0 != tbu1); \
- val = ((uint64_t)tbl) | (((uint64_t)tbu0) << 32); \
-}
-#else
-// SPARC
-#ifdef SPARCV9
-#ifdef _LP64
-#define get_clockticks(val) \
-{ \
- __asm__ __volatile__ ("rd %%tick, %0" : "=r" (val)); \
-}
-#else
-#define get_clockticks(val) \
-{ \
- uint32_t a, b; \
- __asm__ __volatile__ ("rd %%tick, %0\n" \
- "srlx %0, 32, %1" \
- : "=r" (a), "=r" (b)); \
- val = ((uint64_t)a) | (((uint64_t)b) << 32); \
-}
-#endif // _LP64
-#else
-#define get_clockticks(val)
-#endif // SPARCV9
-#endif // __GNUC__ && __powerpc__ || __ppc__
-#endif // __ia64 && __hpux
-#endif // __ia64 && __GNUC__
-#endif // __i386 || __amd64 || __x86_64__
-
-inline double get_ticks_per_usec()
-{
- uint64_t start = 0, end = 0;
- get_clockticks(start);
-
- sleep(1);
- get_clockticks(end);
-
- return (double)(end-start)/1e6;
-}
-
-#endif
-
namespace t_stopwatch
{
-struct Clock : public ClockTraits<hr_clock>
+struct Clock : public ClockTraits<SnortClock>
{
static time_point now()
{ return time; }
--- /dev/null
+//--------------------------------------------------------------------------
+// Copyright (C) 2016-2016 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.
+//--------------------------------------------------------------------------
+// tsc_clock.cc author Russ Combs <rucombs@cisco.com>
+
+#include "tsc_clock.h"
+#include <time.h>
+
+long clock_scale()
+{
+ static long tpus = 0; // ticks / usec
+
+ if ( !tpus )
+ {
+ struct timespec one_sec = { 1, 0 };
+ uint64_t start = TscClock::counter();
+ nanosleep(&one_sec, nullptr);
+ uint64_t end = TscClock::counter();
+ tpus = (long)((end - start)/1e6);
+ }
+ return tpus;
+}
+
--- /dev/null
+//--------------------------------------------------------------------------
+// Copyright (C) 2016-2016 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.
+//--------------------------------------------------------------------------
+// tsc_clock.h author Russ Combs <rucombs@cisco.com>
+
+#ifndef TSC_CLOCK_H
+#define TSC_CLOCK_H
+
+// the STL chrono clocks are kinda heavy so we use the time stamp counter
+// where available (x86 with rdtsc support). this wasn't always a good
+// choice on multi-core systems but most now have rdtscp, constant_tsc,
+// tsc_reliable, and nonstop_tsc. note that we don't worry about exact
+// instruction sequencing.
+//
+// references:
+// http://stackoverflow.com/questions/275004/timer-function-to-provide-time-in-nano-seconds-using-c
+// http://stackoverflow.com/questions/7935518/is-clock-gettime-adequate-for-submicrosecond-timing
+//
+// this clock stores ticks, not actual time values. use ticks during runtime
+// convert from/to usecs at startup/shutdown. see clock_defs.h.
+
+#include <chrono>
+
+struct TscClock
+{
+ // this has to be const so we use a nice round number and scale it later
+ typedef std::ratio<1, 1000000> period;
+
+ typedef uint64_t rep;
+ typedef std::chrono::duration<rep, period> duration;
+ typedef std::chrono::time_point<TscClock> time_point;
+
+ static const bool is_steady = true;
+
+ static uint64_t counter()
+ {
+ uint32_t lo, hi;
+ asm volatile("rdtsc" : "=a" (lo), "=d" (hi));
+ return ((uint64_t)hi << 32) | lo;
+ }
+
+ static time_point now() noexcept
+ {
+ return time_point(duration(counter()));
+ }
+};
+
+long clock_scale();
+
+#endif
+
// -----------------------------------------------------------------------------
inline BitOp::BitOp(size_t len) :
- bit_buf(new uint8_t[len]()), buf_size(len)
-{ }
+ buf_size(len ? (len + 7) >> 3 : 1)
+{
+ bit_buf = new uint8_t[len]();
+}
inline BitOp::~BitOp()
{ delete[] bit_buf; }
inline uint8_t BitOp::mask(size_t bit) const
{ return (uint8_t)(0x80 >> (bit & 7)); }
-// FIXIT-L ops that don't need to be inlined can probably be put into a .cc file
// Reset the bit buffer so that it can be reused
inline void BitOp::reset()
{ memset(bit_buf, 0, buf_size); }
TEST_CASE( "bitop", "[bitop]" )
{
- BitOp bitop(3);
+ BitOp bitop(24);
SECTION( "zero-initialized" )
{
#include "ips_options/ips_pcre.h"
#include "time/packet_time.h"
#include "time/timersub.h"
-#include "stream/stream.h"
#ifdef PATH_MAX
#define PATH_MAX_UTIL PATH_MAX
if ((lua_option != nullptr) && snort_option->compare(*lua_option))
{
retval = parse_int_option(*lua_option, stream, false);
- table_api.add_diff_option_comment("config " + *snort_option +
- ":", *lua_option);
+ table_api.add_diff_option_comment("config " + *snort_option + ":", *lua_option);
}
else
{
const std::string* lua_option = nullptr>
static ConversionState* config_int_ctor(Converter& c)
{
- return new ConfigIntOption(c,
- snort_option,
- lua_table,
- lua_option);
+ return new ConfigIntOption(c, snort_option, lua_table, lua_option);
}
} // namespace
bool use_string_array = false>
static ConversionState* config_string_ctor(Converter& c)
{
- return new ConfigStringOption(c,
- snort_option,
- lua_table,
- lua_option,
- use_string_array);
+ return new ConfigStringOption(c, snort_option, lua_table, lua_option, use_string_array);
}
} // namespace