Partial depth detection enables faster threat detection by immediately forwarding
partial message data to the detection engine before the complete message arrives.
This feature can be configured independently for HTTP request bodies
-(partial_depth_body) and headers (partial_depth_header).
+(partial_depth_body) and headers and request line (partial_depth_header).
Configuration options:
0 (default): Feature disabled
partial_depth_body = -1 when early detection is needed beyond this limit. HTTP
headers have no such limitation.
+Partially inspected request lines are not parsed, the raw content is available in the
+http_raw_request buffer. Incomplete lines in partially inspected headers are not parsed.
+The raw content of the partial header is available in the http_raw_header buffer.
+
This feature is turned off by default by setting partial_depth_body = 0
and partial_depth_header = 0. To activate it, set the corresponding parameter to
the desired value.
delete body_params;
}
+bool HttpMsgRequest::detection_required() const
+{
+ if (params->partial_depth_header != 0)
+ return true;
+ return version_id == HttpEnums::VERS_0_9;
+}
+
void HttpMsgRequest::parse_start_line()
{
+ if (session_data->partial_flush[source_id])
+ return;
+
// Version field
if ((start_line.length() < 10) || !is_sp_tab[start_line.start()[start_line.length()-9]] ||
memcmp(start_line.start() + start_line.length() - 8, "HTTP/", 5))
void HttpMsgRequest::gen_events()
{
+ if (session_data->partial_flush[source_id])
+ return;
+
if (*transaction->get_infractions(source_id) & INF_BAD_REQ_LINE)
return;
void HttpMsgRequest::publish(unsigned)
{
+ if (session_data->partial_flush[source_id])
+ return;
+
if (!session_data->ssl_search_abandoned && trans_num > 1 &&
!flow->flags.data_decrypted && get_method_id() != METH_CONNECT)
{
HttpCommon::SourceId source_id_, bool buf_owner, snort::Flow* flow_,
const HttpParaList* params_);
~HttpMsgRequest() override;
- bool detection_required() const override
- { return version_id == HttpEnums::VERS_0_9; }
+ bool detection_required() const override;
snort::PduSection get_inspection_section() const override
{ return snort::PS_HEADER; }
void gen_events() override;
int64_t partial_depth = 0;
auto params = my_inspector->params;
- if (type == SEC_HEADER)
+ if (type == SEC_HEADER || type == SEC_REQUEST)
{
if (params->partial_depth_header != 0 && !session_data->for_httpx)
partial_depth = params->partial_depth_header;
// 4. returns the current transaction
// Request section: replace the old request transaction with a new transaction.
- if (session_data->section_type[source_id] == SEC_REQUEST)
+ if (session_data->section_type[source_id] == SEC_REQUEST &&
+ session_data->infractions[SRC_CLIENT] != nullptr)
{
// If the HTTP request and response messages are alternating (usual situation) the old
// request transaction will have been moved to the server side when the last response
}
}
+void HttpTransaction::set_request(HttpMsgRequest* request_)
+{
+ // section is already cleared
+ // check when clear_section() needs to be called
+ delete request;
+ request = request_;
+}
+
void HttpTransaction::set_header(HttpMsgHeader* header_, HttpCommon::SourceId source_id)
{
delete (header[source_id]);
static void delete_transaction(HttpTransaction*, HttpFlowData*);
HttpMsgRequest* get_request() const { return request; }
- void set_request(HttpMsgRequest* request_) { request = request_; }
+ void set_request(HttpMsgRequest* request);
HttpMsgStatus* get_status() const { return status; }
void set_status(HttpMsgStatus* status_) { status = status_; }
type_expected[SRC_CLIENT] = SEC_HEADER;
section_type[SRC_CLIENT] = SEC_HEADER;
CHECK(trans[k] == HttpTransaction::attach_my_transaction(flow_data, SRC_CLIENT, flow));
+ HttpUnitTestSetup::half_reset(flow_data, SRC_CLIENT);
for (unsigned j=0; j < k; j++)
{
CHECK(trans[k] != trans[j]);
type_expected[SRC_CLIENT] = SEC_HEADER;
section_type[SRC_CLIENT] = SEC_HEADER;
CHECK(trans == HttpTransaction::attach_my_transaction(flow_data, SRC_CLIENT, flow));
+ HttpUnitTestSetup::half_reset(flow_data, SRC_CLIENT);
type_expected[SRC_CLIENT] = SEC_REQUEST;
section_type[SRC_SERVER] = SEC_STATUS;
type_expected[SRC_CLIENT] = SEC_HEADER;
section_type[SRC_CLIENT] = SEC_HEADER;
CHECK(trans2 == HttpTransaction::attach_my_transaction(flow_data, SRC_CLIENT, flow));
+ HttpUnitTestSetup::half_reset(flow_data, SRC_CLIENT);
type_expected[SRC_CLIENT] = SEC_REQUEST;
section_type[SRC_SERVER] = SEC_STATUS;
type_expected[SRC_CLIENT] = SEC_HEADER;
section_type[SRC_CLIENT] = SEC_HEADER;
CHECK(trans[k] == HttpTransaction::attach_my_transaction(flow_data, SRC_CLIENT, flow));
+ HttpUnitTestSetup::half_reset(flow_data, SRC_CLIENT);
for (unsigned j=0; j < k; j++)
{
CHECK(trans[k] != trans[j]);
type_expected[SRC_CLIENT] = SEC_HEADER;
section_type[SRC_CLIENT] = SEC_HEADER;
CHECK(trans[k] == HttpTransaction::attach_my_transaction(flow_data, SRC_CLIENT, flow));
+ HttpUnitTestSetup::half_reset(flow_data, SRC_CLIENT);
for (unsigned j=5; j < k; j++)
{
CHECK(trans[k] != trans[j]);
{ assert(flow_data!=nullptr); return flow_data->section_type; }
static HttpCommon::SectionType* get_type_expected(HttpFlowData* flow_data)
{ assert(flow_data!=nullptr); return flow_data->type_expected; }
+ static void half_reset(HttpFlowData* flow_data, HttpCommon::SourceId source_id)
+ { assert(flow_data!=nullptr); flow_data->half_reset(source_id); }
};
#endif