max_packet_service_fail_ignore_bytes;
}
}
+ else if (!(strcasecmp(conf_key, "failed_state_expiration_secs")))
+ {
+ int32_t brute_force_failed_state_expiration_secs = atoi(conf_val);
+ if (brute_force_failed_state_expiration_secs < MIN_BRUTE_FORCE_FAILED_EXPIRATION_SECS)
+ {
+ appid_log(nullptr, TRACE_WARNING_LEVEL, "appid: invalid "
+ "failed_state_expiration_secs %" PRIi32 ", must be greater than "
+ "%u.\n", brute_force_failed_state_expiration_secs,
+ MIN_BRUTE_FORCE_FAILED_EXPIRATION_SECS);
+ }
+ else if (brute_force_failed_state_expiration_secs > MAX_BRUTE_FORCE_FAILED_EXPIRATION_SECS)
+ {
+ appid_log(nullptr, TRACE_WARNING_LEVEL, "appid: invalid "
+ "failed_state_expiration_secs %" PRIi32 ", must be less than "
+ "%u.\n", brute_force_failed_state_expiration_secs,
+ MAX_BRUTE_FORCE_FAILED_EXPIRATION_SECS);
+ }
+ else
+ {
+ odp_ctxt.failed_state_expiration_secs = brute_force_failed_state_expiration_secs;
+ }
+ }
+ else if (!(strcasecmp(conf_key, "brute_force_inprocess_threshold")))
+ {
+ int32_t brute_force_inprocess_threshold = atoi(conf_val);
+ if (brute_force_inprocess_threshold < MIN_BRUTE_FORCE_INPROCESS_STATE_THRESHOLD)
+ {
+ appid_log(nullptr, TRACE_WARNING_LEVEL, "appid: invalid "
+ "brute_force_inprocess_state_threshold %" PRIi32 ", must be greater than "
+ "%u.\n", brute_force_inprocess_threshold,
+ MIN_BRUTE_FORCE_INPROCESS_STATE_THRESHOLD);
+ }
+ else if (brute_force_inprocess_threshold > MAX_BRUTE_FORCE_INPROCESS_STATE_THRESHOLD)
+ {
+ appid_log(nullptr, TRACE_WARNING_LEVEL, "appid: invalid "
+ "brute_force_inprocess_state_threshold %" PRIi32 ", must be less than "
+ "%u.\n", brute_force_inprocess_threshold,
+ MAX_BRUTE_FORCE_INPROCESS_STATE_THRESHOLD);
+ }
+ else
+ {
+ odp_ctxt.brute_force_inprocess_threshold = brute_force_inprocess_threshold;
+ }
+ }
/* App Priority bit set*/
else if (!(strcasecmp(conf_key, "app_priority")))
{
appid_log(nullptr, TRACE_INFO_LEVEL, "Appid Config: max_packet_service_fail_ignore_bytes %" PRIu16" \n", max_packet_service_fail_ignore_bytes);
appid_log(nullptr, TRACE_INFO_LEVEL, "Appid Config: eve_http_client %s\n", (eve_http_client ? "True" : "False"));
appid_log(nullptr, TRACE_INFO_LEVEL, "Appid Config: appid_cpu_profiler %s\n", (appid_cpu_profiler ? "True" : "False"));
+ appid_log(nullptr, TRACE_INFO_LEVEL, "Appid Config: brute_force_inprocess_threshold %" PRId8" \n", brute_force_inprocess_threshold);
+ appid_log(nullptr, TRACE_INFO_LEVEL, "Appid Config: failed_state_expiration_secs %" PRId32" \n", failed_state_expiration_secs);
}
bool OdpContext::is_appid_cpu_profiler_running()
#define DEFAULT_MAX_BYTES_BEFORE_SERVICE_FAIL 4096
#define DEFAULT_MAX_PKTS_BEFORE_SERVICE_FAIL 5
#define DEFAULT_MAX_PKT_BEFORE_SERVICE_FAIL_IGNORE_BYTES 10
+
+#define DEFAULT_FAILED_STATE_EXPIRATION_SECS 7200
+#define MIN_BRUTE_FORCE_FAILED_EXPIRATION_SECS 0
+#define MAX_BRUTE_FORCE_FAILED_EXPIRATION_SECS 86400
+
+#define DEFAULT_BRUTE_FORCE_INPROCESS_STATE_THRESHOLD 5
+#define MIN_BRUTE_FORCE_INPROCESS_STATE_THRESHOLD 1
+#define MAX_BRUTE_FORCE_INPROCESS_STATE_THRESHOLD 50
enum SnortProtoIdIndex
bool ftp_userid_disabled = false;
bool chp_body_collection_disabled = false;
bool need_reinspection = false;
+ bool tp_allow_probes = false;
+ bool allow_port_wildcard_host_cache = false;
+ bool recheck_for_portservice_appid = false;
+ bool eve_http_client = true;
+ bool appid_cpu_profiler = true;
+ uint8_t brute_force_inprocess_threshold = DEFAULT_BRUTE_FORCE_INPROCESS_STATE_THRESHOLD;
+ uint16_t max_packet_before_service_fail = DEFAULT_MAX_PKTS_BEFORE_SERVICE_FAIL;
+ uint16_t max_packet_service_fail_ignore_bytes = DEFAULT_MAX_PKT_BEFORE_SERVICE_FAIL_IGNORE_BYTES;
AppId first_pkt_service_id = 0;
AppId first_pkt_payload_id = 0;
AppId first_pkt_client_id = 0;
uint32_t chp_body_collection_max = 0;
uint32_t rtmp_max_packets = 15;
uint32_t max_tp_flow_depth = 5;
- bool tp_allow_probes = false;
+ uint32_t failed_state_expiration_secs = DEFAULT_FAILED_STATE_EXPIRATION_SECS;
uint32_t host_port_app_cache_lookup_interval = 10;
uint32_t host_port_app_cache_lookup_range = 100000;
- bool allow_port_wildcard_host_cache = false;
- bool recheck_for_portservice_appid = false;
uint64_t max_bytes_before_service_fail = DEFAULT_MAX_BYTES_BEFORE_SERVICE_FAIL;
- uint16_t max_packet_before_service_fail = DEFAULT_MAX_PKTS_BEFORE_SERVICE_FAIL;
- uint16_t max_packet_service_fail_ignore_bytes = DEFAULT_MAX_PKT_BEFORE_SERVICE_FAIL_IGNORE_BYTES;
FirstPktAppIdDiscovered first_pkt_appid_prefix = NO_APPID_FOUND;
- bool eve_http_client = true;
- bool appid_cpu_profiler = true;
OdpContext(const AppIdConfig&, snort::SnortConfig*);
void initialize(AppIdInspector& inspector);
odp_thread_local_ctxt->initialize(SnortConfig::get_conf());
AppIdServiceState::initialize(config->memcap);
+ AppIdServiceState::set_service_thresholds(pkt_thread_odp_ctxt->failed_state_expiration_secs, pkt_thread_odp_ctxt->brute_force_inprocess_threshold);
assert(!pkt_thread_tp_appid_ctxt);
pkt_thread_tp_appid_ctxt = ctxt.get_tp_appid_ctxt();
if (pkt_thread_tp_appid_ctxt)
ServiceDiscovery::set_thread_local_ftp_service();
AppIdContext& ctxt = inspector.get_ctxt();
OdpContext& current_odp_ctxt = ctxt.get_odp_ctxt();
+ AppIdServiceState::set_service_thresholds(current_odp_ctxt.failed_state_expiration_secs, current_odp_ctxt.brute_force_inprocess_threshold);
assert(pkt_thread_odp_ctxt != ¤t_odp_ctxt);
pkt_thread_odp_ctxt = ¤t_odp_ctxt;
sds->set_reset_time(0);
ServiceState sds_state = sds->get_state();
- if ( ((sds_state == ServiceState::FAILED) or (sds_state == ServiceState::SEARCHING_BRUTE_FORCE)) and
- asd.get_session_flags(APPID_SESSION_WAIT_FOR_EXTERNAL))
+ if ( ((sds_state == ServiceState::FAILED) or (sds_state == ServiceState::SEARCHING_BRUTE_FORCE)) )
{
- if (appidDebug->is_active())
- LogMessage("AppIdDbg %s No service match, waiting for external detection\n", appidDebug->get_debug_session());
- return APPID_INPROCESS;
+ if ( asd.get_session_flags(APPID_SESSION_WAIT_FOR_EXTERNAL) )
+ {
+ if ( appidDebug->is_active() )
+ LogMessage("AppIdDbg %s No service match, waiting for external detection\n", appidDebug->get_debug_session());
+ return APPID_INPROCESS;
+ }
+
+ if ( sds->check_and_expire_failed_state() )
+ sds_state = sds->get_state();
}
if ( sds_state == ServiceState::FAILED )
}
}
+ /*Move brute force iterator if provided detector failed*/
+ if ( ret > APPID_INPROCESS )
+ {
+ if ( !sds )
+ sds = AppIdServiceState::add(ip, proto, port, group, asd.asid, asd.is_decrypted(), true);
+
+ if ( sds->get_state() == ServiceState::SEARCHING_BRUTE_FORCE )
+ sds->next_brute_force(proto);
+ }
+
/* Failed all candidates, or no detector identified after seeing bidirectional exchange */
if ( got_fail_service or ( ( ret != APPID_INPROCESS ) and
!asd.service_detector and ( dir == APP_ID_FROM_RESPONDER ) ) )
using namespace snort;
static THREAD_LOCAL MapList* service_state_cache = nullptr;
+static THREAD_LOCAL uint32_t failed_state_expiration_threshold_secs = 0;
+static THREAD_LOCAL uint8_t brute_force_inprocess_threshold = 0;
const size_t MapList::sz = sizeof(ServiceDiscoveryState) +
sizeof(Map_t::value_type) + sizeof(Queue_t::value_type);
last_detract.clear();
last_invalid_client.clear();
reset_time = 0;
+ failed_timestamp = TIME_POINT_ZERO;
+ brute_force_inprocess_count = 0;
}
ServiceDiscoveryState::~ServiceDiscoveryState()
{
if ( !tcp_brute_force_mgr )
tcp_brute_force_mgr = new AppIdDetectorList(IpProtocol::TCP, sd);
- service = tcp_brute_force_mgr->next();
+
+ if ( ++brute_force_inprocess_count >= brute_force_inprocess_threshold )
+ {
+ service = tcp_brute_force_mgr->next();
+ brute_force_inprocess_count = 0;
+ }
+ else
+ {
+ service = tcp_brute_force_mgr->current();
+ }
+
appid_log(CURRENT_PACKET, TRACE_DEBUG_LEVEL, "Brute-force state %s\n", service? "" : "failed - no more TCP detectors");
}
else if (proto == IpProtocol::UDP)
{
if ( !udp_brute_force_mgr )
udp_brute_force_mgr = new AppIdDetectorList(IpProtocol::UDP, sd);
- service = udp_brute_force_mgr->next();
+
+ if ( ++brute_force_inprocess_count > brute_force_inprocess_threshold )
+ {
+ service = udp_brute_force_mgr->next();
+ brute_force_inprocess_count = 0;
+ }
+ else
+ {
+ service = udp_brute_force_mgr->current();
+ }
+
appid_log(CURRENT_PACKET, TRACE_DEBUG_LEVEL, "Brute-force state %s\n", service? "" : "failed - no more UDP detectors");
}
else
{
service = sd;
reset_time = 0;
+ failed_timestamp = TIME_POINT_ZERO;
+ brute_force_inprocess_count = 0;
if ( state != ServiceState::VALID )
{
state = ServiceState::VALID;
state = SEARCHING_BRUTE_FORCE;
else
state = FAILED;
+
+ failed_timestamp = SnortClock::now();
}
}
}
}
+bool ServiceDiscoveryState::check_and_expire_failed_state()
+{
+ if ( failed_timestamp == TIME_POINT_ZERO or !failed_state_expiration_threshold_secs )
+ return false;
+
+ if ( clock_usecs(TO_USECS(SnortClock::now() - failed_timestamp)) > (failed_state_expiration_threshold_secs * 1000000) )
+ {
+ reset();
+ return true;
+ }
+
+ return false;
+}
+
+void ServiceDiscoveryState::reset()
+{
+ state = ServiceState::SEARCHING_PORT_PATTERN;
+ last_detract.clear();
+ last_invalid_client.clear();
+ reset_time = 0;
+ failed_timestamp = TIME_POINT_ZERO;
+ invalid_client_count = 0;
+ valid_count = 0;
+ detract_count = 0;
+ service = nullptr;
+ brute_force_inprocess_count = 0;
+
+ if ( tcp_brute_force_mgr )
+ delete tcp_brute_force_mgr;
+ if ( udp_brute_force_mgr )
+ delete udp_brute_force_mgr;
+
+ tcp_brute_force_mgr = nullptr;
+ udp_brute_force_mgr = nullptr;
+}
+
bool AppIdServiceState::initialize(size_t memcap)
{
if ( !service_state_cache )
return false;
}
+void AppIdServiceState::set_service_thresholds(uint32_t _failed_state_expiration_threshold_secs, uint8_t _brute_force_inprocess_threshold)
+{
+ failed_state_expiration_threshold_secs = _failed_state_expiration_threshold_secs;
+ brute_force_inprocess_threshold = _brute_force_inprocess_threshold;
+}
+
void AppIdServiceState::clean()
{
delete service_state_cache;
service_state_cache = nullptr;
+ failed_state_expiration_threshold_secs = 0;
+ brute_force_inprocess_threshold = 0;
}
ServiceDiscoveryState* AppIdServiceState::add(const SfIp* ip, IpProtocol proto, uint16_t port,
#include "protocols/protocol_ids.h"
#include "sfip/sf_ip.h"
+#include "time/clock_defs.h"
#include "utils/cpp_macros.h"
#include "utils/util.h"
{
ServiceDetector* detector = nullptr;
- if ( dit != detectors->end())
+ if ( dit != detectors->end() )
detector = (ServiceDetector*)(dit++)->second;
return detector;
}
+ ServiceDetector* current()
+ {
+ ServiceDetector* detector = nullptr;
+
+ if ( dit != detectors->end() )
+ detector = (ServiceDetector*)(dit)->second;
+ return detector;
+ }
+
void reset()
{
dit = detectors->begin();
void set_service_id_failed(AppIdSession& asd, const snort::SfIp* client_ip,
unsigned invalid_delta = 0);
void update_service_incompatible(const snort::SfIp* ip);
+ bool check_and_expire_failed_state();
ServiceState get_state() const
{
reset_time = resetTime;
}
+ void next_brute_force(IpProtocol proto)
+ {
+ if ( proto == IpProtocol::TCP )
+ tcp_brute_force_mgr->next();
+ else if (proto == IpProtocol::UDP )
+ udp_brute_force_mgr->next();
+ brute_force_inprocess_count = 0;
+ }
+
Queue_t::iterator qptr; // Our place in service_state_queue
private:
+ void reset();
+
ServiceState state;
ServiceDetector* service = nullptr;
AppIdDetectorList* tcp_brute_force_mgr = nullptr;
*/
snort::SfIp last_invalid_client;
time_t reset_time;
+ SnortClock::time_point failed_timestamp;
+ uint8_t brute_force_inprocess_count;
};
class AppIdServiceState
{
public:
static bool initialize(size_t memcap);
+ static void set_service_thresholds(uint32_t _failed_state_expiration_threshold_secs, uint8_t _brute_force_inprocess_threshold);
static void clean();
static ServiceDiscoveryState* add(const snort::SfIp*, IpProtocol, uint16_t port,
int16_t group, uint32_t asid, bool decrypted, bool do_touch = false);
{
appidDebug = new AppIdDebug();
appidDebug->activate(nullptr, nullptr, false);
+ AppIdServiceState::set_service_thresholds(0, 1);
}
void teardown() override
{
delete appidDebug;
+ AppIdServiceState::clean();
}
};
#ifdef USE_TSC_CLOCK
#include "time/tsc_clock.h"
using SnortClock = TscClock;
+#define TIME_POINT_ZERO 0
#define CLOCK_ZERO 0
#define DURA_ZERO 0
#define TO_TICKS(t) (t)
using hr_clock = std::chrono::high_resolution_clock;
using SnortClock = hr_clock;
inline long clock_scale() { return 1; }
+#define TIME_POINT_ZERO SnortClock::time_point::min()
#define CLOCK_ZERO 0_ticks
#define DURA_ZERO Clock::duration::zero()
#define TO_TICKS(t) (t.count())