if ( p->packet_flags & PKT_STREAM_UNEST_UNI )
p->packet_flags ^= PKT_STREAM_UNEST_UNI;
}
- if ( ssn_state.session_flags & SSNFLAG_STREAM_ORDER_BAD )
- p->packet_flags |= PKT_STREAM_ORDER_BAD;
}
void Flow::set_direction(Packet* p)
bool ProfilerModule::end(const char*, int, SnortConfig* sc)
{
TimeProfilerStats::set_enabled(sc->profiler->time.show);
+ RuleContext::set_enabled(sc->profiler->rule.show);
return true;
}
"body",
};
-#ifdef APPID_DEEP_PERF_PROFILING
static THREAD_LOCAL snort::ProfileStats process_http_perf_stats;
static ProfileStats* get_profile(const char*)
{
{
Profiler::register_module("http_process", "appid", get_profile);
}
-#else
-void appid_http_profiler_init() { return; }
-#endif
AppIdHttpSession::AppIdHttpSession(AppIdSession& asd)
: asd(asd)
int AppIdHttpSession::process_http_packet(AppidSessionDirection direction,
AppidChangeBits& change_bits)
{
-#ifdef APPID_DEEP_PERF_PROFILING
- snort::Profile profile(process_http_perf_stats);
-#endif
+ DeepProfile profile(process_http_perf_stats);
AppId service_id = APP_ID_NONE;
AppId client_id = APP_ID_NONE;
AppId payload_id = APP_ID_NONE;
#define MAX_CANDIDATE_CLIENTS 10
-#ifdef APPID_DEEP_PERF_PROFILING
static THREAD_LOCAL ProfileStats client_disco_perf_stats;
static ProfileStats* get_profile(const char*)
{
return &client_disco_perf_stats;
}
-#endif
ClientDiscovery* ClientDiscovery::discovery_manager = nullptr;
THREAD_LOCAL ClientAppMatch* match_free_list = nullptr;
for ( auto kv : udp_detectors )
kv.second->initialize();
-#ifdef APPID_DEEP_PERF_PROFILING
Profiler::register_module("client_discovery", "appid", get_profile);
-#endif
}
void ClientDiscovery::finalize_client_plugins()
bool ClientDiscovery::do_client_discovery(AppIdSession& asd, Packet* p,
AppidSessionDirection direction, AppidChangeBits& change_bits)
{
-#ifdef APPID_DEEP_PERF_PROFILING
- Profile profile(client_disco_perf_stats);
-#endif
+ DeepProfile profile(client_disco_perf_stats);
bool isTpAppidDiscoveryDone = false;
AppInfoTableEntry* entry;
uint32_t prevRnaClientState = asd.client_disco_state;
if ( !p->flow )
return NO_MATCH;
-#ifdef APPID_DEEP_PERF_PROFILING
- Profile profile(ips_appid_perf_stats);
-#endif
-
+ DeepProfile profile(ips_appid_perf_stats);
AppIdSession* session = appid_api.get_appid_session(*(p->flow));
+
if ( !session )
return NO_MATCH;
LUA_LOG_TRACE = 5,
};
-#ifdef APPID_DEEP_PERF_PROFILING
// FIXIT-L: Add separate perf stats for ODP detectors and custom
// detectors if more granularity is desired
static THREAD_LOCAL ProfileStats lua_validate_perf_stats;
{
Profiler::register_module("lua_validate", "appid", get_profile);
}
-#else
-void lua_detector_profiler_init() { return; }
-#endif
static std::unordered_map<AppId, CHPApp*>* CHP_glossary = nullptr; // tracks http multipatterns
int LuaServiceDetector::validate(AppIdDiscoveryArgs& args)
{
-#ifdef APPID_DEEP_PERF_PROFILING
- Profile profile(lua_validate_perf_stats);
-#endif
+ DeepProfile profile(lua_validate_perf_stats);
//FIXIT-M: RELOAD - use lua references to get user data object from stack
auto my_lua_state = lua_detector_mgr? lua_detector_mgr->L : nullptr;
lua_settop(my_lua_state,0);
int LuaClientDetector::validate(AppIdDiscoveryArgs& args)
{
-#ifdef APPID_DEEP_PERF_PROFILING
- Profile profile(lua_validate_perf_stats);
-#endif
+ DeepProfile profile(lua_validate_perf_stats);
//FIXIT-M: RELOAD - use lua references to get user data object from stack
auto my_lua_state = lua_detector_mgr? lua_detector_mgr->L : nullptr;
std::string name = this->name + "_";
using namespace snort;
-#ifdef APPID_DEEP_PERF_PROFILING
static THREAD_LOCAL ProfileStats service_disco_perf_stats;
static ProfileStats* get_profile(const char*)
{
return &service_disco_perf_stats;
}
-#endif
static ServiceDetector* ftp_service;
ServiceDiscovery* ServiceDiscovery::discovery_manager = nullptr;
service_detector_list.emplace_back(kv.second);
}
-#ifdef APPID_DEEP_PERF_PROFILING
Profiler::register_module("service_discovery", "appid", get_profile);
-#endif
}
void ServiceDiscovery::finalize_service_patterns()
bool ServiceDiscovery::do_service_discovery(AppIdSession& asd, Packet* p,
AppidSessionDirection direction, AppidChangeBits& change_bits)
{
-#ifdef APPID_DEEP_PERF_PROFILING
- Profile profile(service_disco_perf_stats);
-#endif
+ DeepProfile profile(service_disco_perf_stats);
bool isTpAppidDiscoveryDone = false;
uint32_t prevRnaServiceState = asd.service_disco_state;
AppId tp_app_id = asd.get_tp_app_id();
typedef AppIdHttpSession::pair_t pair_t;
static THREAD_LOCAL ProfileStats tp_lib_perf_stats;
-#ifdef APPID_DEEP_PERF_PROFILING
static THREAD_LOCAL ProfileStats tp_disco_perf_stats;
+
static ProfileStats* get_profile(const char* key)
{
if ( !strcmp(key, "tp_discovery") )
return &tp_lib_perf_stats;
return nullptr;
}
+
void tp_appid_profiler_init()
{
Profiler::register_module("tp_discovery", "appid", get_profile);
Profiler::register_module("tp_library", "tp_discovery", get_profile);
}
-#else
-static ProfileStats* get_profile(const char*)
-{
- return &tp_lib_perf_stats;
-}
-void tp_appid_profiler_init()
-{
- Profiler::register_module("tp_library", "appid", get_profile);
-}
-#endif
static inline bool contains(const vector<AppId>& vec, const AppId val)
{
bool do_tp_discovery(AppIdSession& asd, IpProtocol protocol,
Packet* p, AppidSessionDirection& direction, AppidChangeBits& change_bits)
{
-#ifdef APPID_DEEP_PERF_PROFILING
- Profile tp_disco_profile(tp_disco_perf_stats);
-#endif
-
+ DeepProfile tp_disco_profile(tp_disco_perf_stats);
AppId tp_app_id = asd.get_tp_app_id();
if (tp_app_id == APP_ID_SSH && asd.payload.get_id() != APP_ID_SFTP &&
if (protocol != IpProtocol::TCP || (p->packet_flags & PKT_STREAM_ORDER_OK)
|| asd.config->mod_config->tp_allow_probes)
{
- Profile tp_lib_profile(tp_lib_perf_stats);
+ DeepProfile tp_lib_profile(tp_lib_perf_stats);
int tp_confidence;
ThirdPartyAppIDAttributeData tp_attribute_data;
vector<AppId> tp_proto_list;
+
if (!asd.tpsession)
{
const TPLibHandler* tph = TPLibHandler::get();
ParseAbort("ParseRulesFile otn_map ghash_new failed.");
}
-#define IFACE_VARS_MAX 128
-typedef struct iface_var
-{
- char name[128];
- uint32_t net;
- uint32_t netmask;
-} iface_var_t;
-
-/****************************************************************************
- *
- * Function : DefineIfaceVar()
- * Purpose : Assign network address and network mask to IFACE_ADDR_VARNAME
- * variable.
- * Arguments : interface name (string) netaddress and netmask (4 octets each)
- * Returns : void function
- *
- ****************************************************************************/
-static void DefineIfaceVar(SnortConfig* sc, char* iname, const uint8_t* network, const uint8_t* netmask)
-{
- char valbuf[32];
- char varbuf[BUFSIZ];
-
- if ((network == nullptr) || (*network == 0))
- return;
-
- SnortSnprintf(varbuf, BUFSIZ, "%s_ADDRESS", iname);
-
- SnortSnprintf(valbuf, 32, "%d.%d.%d.%d/%d.%d.%d.%d",
- network[0] & 0xff, network[1] & 0xff, network[2] & 0xff,
- network[3] & 0xff, netmask[0] & 0xff, netmask[1] & 0xff,
- netmask[2] & 0xff, netmask[3] & 0xff);
-
- VarDefine(sc, varbuf, valbuf);
-}
-
-// Find all up interfaces and define iface_ADDRESS vars for them
-static void DefineAllIfaceVars(SnortConfig* sc)
-{
- // FIXIT-L don't come back here on reload unless we are going to find
- // new ifaces. Cache retrieved devs so if user is running with dropped
- // privs and does a reload, we can use previous values
- static int num_vars = 0;
-
- // should be more than enough to cover the number of interfaces on a machine
- static iface_var_t iface_vars[IFACE_VARS_MAX];
-
- if (num_vars > 0)
- {
- int i;
-
- for (i = 0; i < num_vars; i++)
- {
- DefineIfaceVar(sc, iface_vars[i].name,
- (uint8_t*)&iface_vars[i].net,
- (uint8_t*)&iface_vars[i].netmask);
- }
- }
- else
- {
- char errbuf[PCAP_ERRBUF_SIZE];
- pcap_if_t* alldevs;
- pcap_if_t* dev;
- bpf_u_int32 net, netmask;
-
- if (pcap_findalldevs(&alldevs, errbuf) == -1)
- return;
-
- for (dev = alldevs; dev != nullptr; dev = dev->next)
- {
- if (pcap_lookupnet(dev->name, &net, &netmask, errbuf) == 0)
- {
- /* We've hit the maximum variables we can cache */
- if (num_vars >= IFACE_VARS_MAX)
- break;
-
- SnortSnprintf(iface_vars[num_vars].name,
- sizeof(iface_vars[num_vars].name), "%s", dev->name);
-
- DefineIfaceVar(sc, iface_vars[num_vars].name,
- (uint8_t*)&net,
- (uint8_t*)&netmask);
-
- iface_vars[num_vars].net = net;
- iface_vars[num_vars].netmask = netmask;
- num_vars++;
- }
- }
-
- pcap_freealldevs(alldevs);
- }
-}
-
static RuleListNode* addNodeToOrderedList(RuleListNode* ordered_list,
RuleListNode* node, int evalIndex)
{
sc->rate_filter_config = RateFilter_ConfigNew();
sc->detection_filter_config = DetectionFilterConfigNew();
- /* If snort is not run with root privileges, no interfaces will be defined,
- * so user beware if an iface_ADDRESS variable is used in snort.conf and
- * snort is not run as root (even if just in read mode) */
- DefineAllIfaceVars(sc);
-
/* Add command line defined variables - duplicates will already
* have been resolved */
while (tmp != nullptr)
#define s_rule_table_title "rule profile"
+bool RuleContext::enabled = false;
+
static inline OtnState& operator+=(OtnState& lhs, const OtnState& rhs)
{
lhs.elapsed += rhs.elapsed;
void RuleContext::stop(bool match)
{
- if ( finished )
+ if ( !enabled or finished )
return;
finished = true;
TEST_CASE( "rule profiler time context", "[profiler][rule_profiler]" )
{
dot_node_state_t stats;
+ RuleContext::set_enabled(true);
stats.elapsed = 0_ticks;
stats.checks = 0;
CHECK( stats.elapsed_match == save.elapsed_match );
CHECK( stats.checks == save.checks );
}
+ RuleContext::set_enabled(false);
}
TEST_CASE( "rule pause", "[profiler][rule_profiler]" )
{
dot_node_state_t stats;
RuleContext ctx(stats);
+ RuleContext::set_enabled(true);
{
RulePause pause(ctx);
}
CHECK( ctx.active() );
+ RuleContext::set_enabled(false);
}
#endif
{ stop(); }
void start()
- { sw.start(); }
+ { if ( enabled ) sw.start(); }
void pause()
- { sw.stop(); }
+ { if ( enabled ) sw.stop(); }
void stop(bool = false);
bool active() const
- { return sw.active(); }
+ { return enabled and sw.active(); }
+
+ static void set_enabled(bool b)
+ { enabled = b; }
private:
dot_node_state_t& stats;
Stopwatch<SnortClock> sw;
bool finished = false;
+ static bool enabled;
};
class RulePause
else if ( !p->test_session_flags(SSNFLAG_MIDSTREAM)
&& !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)
- {
- /* revert back to command state - assume server didn't accept STARTTLS */
- smtp_ssn->state = STATE_COMMAND;
- }
- else
- return;
+ smtp_ssn->state = STATE_COMMAND;
}
}
{
smtp_ssn->state = STATE_TLS_SERVER_PEND;
}
- else if (p->packet_flags & PKT_STREAM_ORDER_OK)
+ else
{
/* reset state - server may have rejected STARTTLS command */
smtp_ssn->state = STATE_COMMAND;
};
TcpStreamTracker::TcpStreamTracker(bool client) :
- client_tracker(client), tcp_state(client ? TCP_STATE_NONE : TCP_LISTEN)
+ tcp_state(client ? TCP_STATE_NONE : TCP_LISTEN), client_tracker(client)
{ }
TcpStreamTracker::~TcpStreamTracker()
fin_seq_status = TcpStreamTracker::FIN_NOT_SEEN;
fin_seq_set = false;
rst_pkt_sent = false;
+ order = 0;
}
//-------------------------------------------------------------------------
class TcpStreamTracker
{
public:
- enum TcpState
+ enum TcpState : uint8_t
{
TCP_LISTEN,
TCP_SYN_SENT,
TCP_MAX_STATES
};
- enum TcpEvent
+ enum TcpEvent : uint8_t
{
TCP_SYN_SENT_EVENT,
TCP_SYN_RECV_EVENT,
TCP_MAX_EVENTS
};
- enum FinSeqNumStatus { FIN_NOT_SEEN, FIN_WITH_SEQ_SEEN, FIN_WITH_SEQ_ACKED };
+ enum FinSeqNumStatus : uint8_t { FIN_NOT_SEEN, FIN_WITH_SEQ_SEEN, FIN_WITH_SEQ_ACKED };
TcpStreamTracker(bool client);
virtual ~TcpStreamTracker();
virtual bool is_segment_seq_valid(TcpSegmentDescriptor&);
virtual void flush_data_on_fin_recv(TcpSegmentDescriptor&);
- bool client_tracker;
- TcpState tcp_state;
- TcpEvent tcp_event = TCP_MAX_EVENTS;
- bool require_3whs = false;
-
+public:
uint32_t snd_una = 0; // SND.UNA - send unacknowledged
uint32_t snd_nxt = 0; // SND.NXT - send next
uint32_t snd_wnd = 0; // SND.WND - send window
- uint16_t snd_up = 0; // SND.UP - send urgent pointer
uint32_t snd_wl1 = 0; // SND.WL1 - segment sequence number used for last window update
uint32_t snd_wl2 = 0; // SND.WL2 - segment acknowledgment number used for last window update
uint32_t iss = 0; // ISS - initial send sequence number
uint32_t rcv_nxt = 0; // RCV.NXT - receive next
uint32_t rcv_wnd = 0; // RCV.WND - receive window
- uint16_t rcv_up = 0; // RCV.UP - receive urgent pointer
uint32_t irs = 0; // IRS - initial receive sequence number
+ uint16_t snd_up = 0; // SND.UP - send urgent pointer
+ uint16_t rcv_up = 0; // RCV.UP - receive urgent pointer
+
+ TcpState tcp_state;
+ TcpEvent tcp_event = TCP_MAX_EVENTS;
+
+ bool client_tracker;
+ bool require_3whs = false;
bool rst_pkt_sent = false;
// FIXIT-L make these non-public
public:
- uint32_t r_win_base = 0; /* remote side window base sequence number
- * (i.e. the last ack we got) */
-
- TcpSession* session = nullptr;
TcpNormalizerPolicy normalizer;
TcpReassemblerPolicy reassembler;
- snort::StreamSplitter* splitter = nullptr;
- uint32_t small_seg_count = 0;
- uint8_t alert_count = 0;
StreamAlertInfo alerts[MAX_SESSION_ALERTS];
- FlushPolicy flush_policy = STREAM_FLPOLICY_IGNORE;
+
// this is intended to be private to paf but is included
// directly to avoid the need for allocation; do not directly
// manipulate within this module.
PAF_State paf_state; // for tracking protocol aware flushing
+ TcpSession* session = nullptr;
+ snort::StreamSplitter* splitter = nullptr;
+
+ FlushPolicy flush_policy = STREAM_FLPOLICY_IGNORE;
+
+ uint32_t r_win_base = 0; // remote side window base sequence number (the last ack we got)
+ uint32_t small_seg_count = 0;
+
+ uint16_t wscale = 0; /* window scale setting */
+ uint16_t mss = 0; /* max segment size */
+
+ uint8_t alert_count = 0;
+ uint8_t order = 0;
+
+ FinSeqNumStatus fin_seq_status = TcpStreamTracker::FIN_NOT_SEEN;
+
protected:
// FIXIT-H reorganize per-flow structs to minimize padding
uint32_t ts_last_packet = 0;
uint32_t ts_last = 0; /* last timestamp (for PAWS) */
- uint16_t tf_flags = 0;
- uint8_t mac_addr[6] = { };
- bool mac_addr_valid = false;
uint32_t fin_final_seq = 0;
uint32_t fin_seq_adjust = 0;
- bool fin_seq_set = false; // FIXIT-M should be obviated by tcp state
+
+ uint16_t tf_flags = 0;
+
+ uint8_t mac_addr[6] = { };
uint8_t tcp_options_len = 0;
- // FIXIT-L make this protected...
-public:
- uint16_t wscale = 0; /* window scale setting */
- uint16_t mss = 0; /* max segment size */
- FinSeqNumStatus fin_seq_status = TcpStreamTracker::FIN_NOT_SEEN;
+ bool mac_addr_valid = false;
+ bool fin_seq_set = false; // FIXIT-M should be obviated by tcp state
};
// <--- note -- the 'state' parameter must be a reference
{ "session_timeout", Parameter::PT_INT, "1:max31", "30",
"session tracking timeout" },
+ { "track_only", Parameter::PT_BOOL, nullptr, "false",
+ "disable reassembly if true" },
+
{ nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
};
else
config->flags &= ~STREAM_CONFIG_SHOW_PACKETS;
}
+ else if ( v.is("track_only") )
+ {
+ if ( v.get_bool() )
+ config->flags |= STREAM_CONFIG_NO_REASSEMBLY;
+ else
+ config->flags &= ~STREAM_CONFIG_NO_REASSEMBLY;
+ }
else
return false;
}
}
+void TcpSession::update_stream_order(TcpSegmentDescriptor& tsd, bool aligned)
+{
+ switch ( listener->order )
+ {
+ case 0:
+ if ( aligned )
+ tsd.get_pkt()->packet_flags |= PKT_STREAM_ORDER_OK;
+ else
+ listener->order = 1;
+ break;
+ case 1:
+ if ( aligned )
+ {
+ tsd.get_pkt()->packet_flags |= PKT_STREAM_ORDER_OK;
+ listener->order = 2;
+ }
+ break;
+ default:
+ if ( !(flow->get_session_flags() & SSNFLAG_STREAM_ORDER_BAD) )
+ flow->set_session_flags(SSNFLAG_STREAM_ORDER_BAD);
+ tsd.get_pkt()->packet_flags |= PKT_STREAM_ORDER_BAD;
+ }
+}
+
int TcpSession::process_tcp_data(TcpSegmentDescriptor& tsd)
{
DeepProfile profile(s5TcpDataPerfStats);
if (tsd.get_seg_len() != 0)
{
- if (!( flow->get_session_flags() & SSNFLAG_STREAM_ORDER_BAD))
- tsd.get_pkt()->packet_flags |= PKT_STREAM_ORDER_OK;
-
+ update_stream_order(tsd, true);
process_tcp_stream(tsd);
- /* set flags to session flags */
-
return STREAM_ALIGNED;
}
}
listener->normalizer.trim_win_payload(tsd);
return STREAM_UNALIGNED;
}
-
- if ((listener->get_tcp_state() == TcpStreamTracker::TCP_ESTABLISHED)
- && (listener->flush_policy == STREAM_FLPOLICY_IGNORE))
- {
- if (SEQ_GT(tsd.get_end_seq(), listener->rcv_nxt))
- {
- // set next ack so we are within the window going forward on this side.
- // FIXIT-L for ips, must move all the way to first hole or right end
- listener->rcv_nxt = tsd.get_end_seq();
- }
- }
-
if (tsd.get_seg_len() != 0)
{
- if (!( flow->get_session_flags() & SSNFLAG_STREAM_ORDER_BAD))
- {
- if (!SEQ_LEQ((tsd.get_seg_seq() + tsd.get_seg_len()), listener->rcv_nxt))
- flow->set_session_flags(SSNFLAG_STREAM_ORDER_BAD);
- }
+ update_stream_order(tsd, false);
process_tcp_stream(tsd);
}
}
if ( !splitter_init and tsd.get_seg_len() > 0 )
{
- client.set_splitter(tsd.get_flow());
- server.set_splitter(tsd.get_flow());
-
- client.init_flush_policy();
- server.init_flush_policy();
+ if ( !(config->flags & STREAM_CONFIG_NO_REASSEMBLY) )
+ {
+ client.set_splitter(tsd.get_flow());
+ server.set_splitter(tsd.get_flow());
+ client.init_flush_policy();
+ server.init_flush_policy();
+ }
splitter_init = true;
}
private:
void set_os_policy() override;
bool flow_exceeds_config_thresholds(TcpSegmentDescriptor&);
+ void update_stream_order(TcpSegmentDescriptor&, bool aligned);
void process_tcp_stream(TcpSegmentDescriptor&);
int process_tcp_data(TcpSegmentDescriptor&);
void swap_trackers();
#define STREAM_CONFIG_SHOW_PACKETS 0x00000001
#define STREAM_CONFIG_NO_ASYNC_REASSEMBLY 0x00000002
+#define STREAM_CONFIG_NO_REASSEMBLY 0x00000004
#define STREAM_DEFAULT_SSN_TIMEOUT 30