doc/signals.txt
doc/snort2lua_cmds.txt
doc/snort_manual.chunked/
+doc/snort_manual.chunked.tgz
doc/snort_manual.html
doc/snort_manual.pdf
doc/snort_manual.text
Inspector* NHttpApi::nhttp_ctor(Module* mod)
{
const NHttpModule* const nhttp_mod = (NHttpModule*)mod;
- return new NHttpInspect(nhttp_mod->get_test_input(), nhttp_mod->get_test_output());
+ return new NHttpInspect(nhttp_mod->get_params());
}
static const char* legacy_buffers[] =
return SCAN_NOTFOUND;
}
-ScanResult NHttpBodyCutter::cut(const uint8_t*, uint32_t, NHttpInfractions&, NHttpEventGen&,
- uint32_t flow_target, uint32_t flow_max)
+ScanResult NHttpBodyCutter::cut(const uint8_t*, uint32_t length, NHttpInfractions&,
+ NHttpEventGen&, uint32_t flow_target, uint32_t flow_max)
{
assert(remaining > 0);
+ // Are we skipping to the next message?
+ if (flow_target == 0)
+ {
+ if (remaining <= length)
+ {
+ num_flush = remaining;
+ remaining = 0;
+ return SCAN_DISCARD;
+ }
+ else
+ {
+ num_flush = length;
+ remaining -= num_flush;
+ return SCAN_DISCARD_PIECE;
+ }
+ }
+
// The normal body section size is flow_target. But if there are only flow_max or less
// remaining we take the whole thing rather than leave a small final section.
if (remaining <= flow_max)
ScanResult NHttpChunkCutter::cut(const uint8_t* buffer, uint32_t length,
NHttpInfractions& infractions, NHttpEventGen& events, uint32_t flow_target, uint32_t)
{
+ // Are we skipping through the rest of this chunked body to the trailers and the next message?
+ const bool discard_mode = (flow_target == 0);
+
if (new_section)
{
new_section = false;
num_good_chunks = 0;
}
- // FIXIT-M there are examples of chunk lengths with trailing white space, need to address that
-
for (uint32_t k=0; k < length; k++)
{
switch (curr_state)
// Terminating zero-length chunk
num_good_chunks++;
num_flush = k+1;
- return SCAN_FOUND;
+ return !discard_mode ? SCAN_FOUND : SCAN_DISCARD;
}
else
{
case CHUNK_DATA:
{
uint32_t skip_amount = (length-k <= expected) ? length-k : expected;
- skip_amount = (skip_amount <= flow_target-data_seen) ? skip_amount :
- flow_target-data_seen;
+ if (!discard_mode && (skip_amount > flow_target-data_seen))
+ { // Do not exceed requested section size
+ skip_amount = flow_target-data_seen;
+ }
k += skip_amount - 1;
if ((expected -= skip_amount) == 0)
{
digits_seen = 0;
break;
case CHUNK_BAD:
+ // If we are skipping to the trailers and next message the broken chunk thwarts us
+ if (discard_mode)
+ {
+ return SCAN_ABORT;
+ }
uint32_t skip_amount = length-k;
skip_amount = (skip_amount <= flow_target-data_seen) ? skip_amount :
flow_target-data_seen;
}
}
octets_seen += length;
+ if (discard_mode)
+ {
+ num_flush = length;
+ return SCAN_DISCARD_PIECE;
+ }
return SCAN_NOTFOUND;
}
public:
explicit NHttpBodyCutter(int64_t expected_length) : remaining(expected_length)
{ assert(remaining > 0); }
- NHttpEnums::ScanResult cut(const uint8_t*, uint32_t, NHttpInfractions&, NHttpEventGen&,
+ NHttpEnums::ScanResult cut(const uint8_t*, uint32_t length, NHttpInfractions&, NHttpEventGen&,
uint32_t flow_target, uint32_t flow_max) override;
private:
static const int MAX_OCTETS = 65535;
static const int DATA_BLOCK_SIZE = 16384;
static const int FINAL_BLOCK_SIZE = 24576;
+static const int GZIP_BLOCK_SIZE = 4096;
static const uint32_t NHTTP_GID = 219;
// Field status codes for when no valid value is present in length or integer value. Positive
SEC_REQUEST = 2, SEC_STATUS, SEC_HEADER, SEC_BODY, SEC_CHUNK, SEC_TRAILER };
// Result of scanning by splitter
-enum ScanResult { SCAN_NOTFOUND, SCAN_FOUND, SCAN_FOUND_PIECE, SCAN_DISCARD, SCAN_ABORT };
+enum ScanResult { SCAN_NOTFOUND, SCAN_FOUND, SCAN_FOUND_PIECE, SCAN_DISCARD, SCAN_DISCARD_PIECE,
+ SCAN_ABORT };
// State machine for chunk parsing
enum ChunkState { CHUNK_ZEROS, CHUNK_NUMBER, CHUNK_WHITESPACE, CHUNK_OPTIONS, CHUNK_HCRLF,
NHttpFlowData::NHttpFlowData() : FlowData(nhttp_flow_id)
{
- /* FIXIT-L Temporary printf while we shake out stream interface */
if (!NHttpTestManager::use_test_input() && NHttpTestManager::use_test_output())
{
seq_num = ++instance_count;
NHttpFlowData::~NHttpFlowData()
{
- /* FIXIT-L Temporary printf while we shake out stream interface */
if (!NHttpTestManager::use_test_input() && NHttpTestManager::use_test_output())
{
printf("Flow Data destruct %" PRIu64 "\n", seq_num);
section_size_target[source_id] = 0;
section_size_max[source_id] = 0;
file_depth_remaining[source_id] = STAT_NOTPRESENT;
+ detect_depth_remaining[source_id] = STAT_NOTPRESENT;
infractions[source_id].reset();
events[source_id].reset();
+ chunk_offset[source_id] = 0;
+ chunk_state[source_id] = CHUNK_NUMBER;
+ chunk_expected_length[source_id] = 0;
if (source_id == SRC_CLIENT)
{
NHttpEnums::MethodId method_id = NHttpEnums::METH__NOTPRESENT;
int32_t status_code_num = NHttpEnums::STAT_NOTPRESENT;
int64_t file_depth_remaining[2] = { NHttpEnums::STAT_NOTPRESENT, NHttpEnums::STAT_NOTPRESENT };
+ int64_t detect_depth_remaining[2] = { NHttpEnums::STAT_NOTPRESENT,
+ NHttpEnums::STAT_NOTPRESENT };
MimeState* mime_state = nullptr; // SRC_CLIENT only
// number of user data octets seen so far (regular body or chunks)
using namespace NHttpEnums;
-NHttpInspect::NHttpInspect(bool test_input, bool test_output)
+NHttpInspect::NHttpInspect(NHttpParaList params_) : params(params_)
{
- if (test_input)
+ if (params.test_input)
{
NHttpTestManager::activate_test_input();
}
- if (test_output)
+ if (params.test_output)
{
NHttpTestManager::activate_test_output();
}
{
case SEC_REQUEST:
latest_section = new NHttpMsgRequest(data, dsize, session_data, source_id, buf_owner,
- flow);
+ flow, ¶ms);
break;
case SEC_STATUS:
- latest_section = new NHttpMsgStatus(data, dsize, session_data, source_id, buf_owner, flow);
+ latest_section = new NHttpMsgStatus(data, dsize, session_data, source_id, buf_owner, flow,
+ ¶ms);
break;
case SEC_HEADER:
- latest_section = new NHttpMsgHeader(data, dsize, session_data, source_id, buf_owner, flow);
+ latest_section = new NHttpMsgHeader(data, dsize, session_data, source_id, buf_owner, flow,
+ ¶ms);
break;
case SEC_BODY:
- latest_section = new NHttpMsgBody(data, dsize, session_data, source_id, buf_owner, flow);
+ latest_section = new NHttpMsgBody(data, dsize, session_data, source_id, buf_owner, flow,
+ ¶ms);
break;
case SEC_CHUNK:
- latest_section = new NHttpMsgChunk(data, dsize, session_data, source_id, buf_owner, flow);
+ latest_section = new NHttpMsgChunk(data, dsize, session_data, source_id, buf_owner, flow,
+ ¶ms);
break;
case SEC_TRAILER:
latest_section = new NHttpMsgTrailer(data, dsize, session_data, source_id, buf_owner,
- flow);
+ flow, ¶ms);
break;
default:
assert(0);
#include "log/messages.h"
#include "nhttp_enum.h"
+#include "nhttp_module.h"
#include "nhttp_stream_splitter.h"
class NHttpApi;
public:
static THREAD_LOCAL uint8_t body_buffer[NHttpEnums::MAX_OCTETS];
- NHttpInspect(bool test_input, bool test_output);
+ NHttpInspect(NHttpParaList params_);
bool get_buf(InspectionBuffer::Type, Packet*, InspectionBuffer&) override;
bool get_buf(unsigned, Packet*, InspectionBuffer&) override;
NHttpEnums::SourceId source_id_, bool buf_owner) const;
static THREAD_LOCAL NHttpMsgSection* latest_section;
+
+ const NHttpParaList params;
};
#endif
{
{ "test_input", Parameter::PT_BOOL, nullptr, "false", "read HTTP messages from text file" },
{ "test_output", Parameter::PT_BOOL, nullptr, "false", "print out HTTP section data" },
+ { "request_depth", Parameter::PT_INT, "-1:", "-1",
+ "maximum request message body bytes to examine (-1 no limit)" },
+ { "response_depth", Parameter::PT_INT, "-1:", "-1",
+ "maximum response message body bytes to examine (-1 no limit)" },
{ nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
};
bool NHttpModule::begin(const char*, int, SnortConfig*)
{
- test_input = false;
- test_output = false;
return true;
}
{
if (val.is("test_input"))
{
- test_input = val.get_bool();
+ params.test_input = val.get_bool();
}
else if (val.is("test_output"))
{
- test_output = val.get_bool();
+ params.test_output = val.get_bool();
+ }
+ else if (val.is("request_depth"))
+ {
+ params.request_depth = val.get_long();
+ }
+ else if (val.is("response_depth"))
+ {
+ params.response_depth = val.get_long();
}
else
{
#define NHTTP_NAME "new_http_inspect"
#define NHTTP_HELP "new HTTP inspector"
+struct NHttpParaList
+{
+public:
+ bool test_input;
+ bool test_output;
+ long request_depth;
+ long response_depth;
+};
+
class NHttpModule : public Module
{
public:
bool set(const char*, Value&, SnortConfig*) override;
unsigned get_gid() const override { return NHttpEnums::NHTTP_GID; }
const RuleMap* get_rules() const override { return nhttp_events; }
- bool get_test_input() const { return test_input; }
- bool get_test_output() const { return test_output; }
+ NHttpParaList get_params() const { return params; }
private:
static const Parameter nhttp_params[];
static const RuleMap nhttp_events[];
- bool test_input = false;
- bool test_output = false;
+ NHttpParaList params;
};
#endif
using namespace NHttpEnums;
NHttpMsgBody::NHttpMsgBody(const uint8_t* buffer, const uint16_t buf_size,
- NHttpFlowData* session_data_, SourceId source_id_, bool buf_owner, Flow* flow_) :
- NHttpMsgSection(buffer, buf_size, session_data_, source_id_, buf_owner, flow_),
+ NHttpFlowData* session_data_, SourceId source_id_, bool buf_owner, Flow* flow_,
+ const NHttpParaList* params_) :
+ NHttpMsgSection(buffer, buf_size, session_data_, source_id_, buf_owner, flow_, params_),
data_length(session_data->data_length[source_id]),
body_octets(session_data->body_octets[source_id])
{
void NHttpMsgBody::analyze()
{
- data.start = msg_text.start;
- data.length = msg_text.length;
+ detect_data.length = (msg_text.length <= session_data->detect_depth_remaining[source_id]) ?
+ msg_text.length : session_data->detect_depth_remaining[source_id];
+ detect_data.start = msg_text.start;
+ session_data->detect_depth_remaining[source_id] -= detect_data.length;
// Always set file data. File processing will later set a new value in some cases.
- if (data.length > 0)
+ // FIXIT-M should file data length here be independent of file_depth_remaining?
+ file_data.length = msg_text.length;
+ if (file_data.length > 0)
{
- set_file_data(const_cast<uint8_t*>(data.start), (unsigned)data.length);
+ file_data.start = msg_text.start;
+ set_file_data(const_cast<uint8_t*>(file_data.start), (unsigned)file_data.length);
}
if (session_data->file_depth_remaining[source_id] > 0)
else file_position = SNORT_FILE_MIDDLE;
// Chunked body with nothing but the zero length chunk?
- if (front && (data.length == 0))
+ if (front && (file_data.length == 0))
{
return;
}
- const int32_t fp_length = (data.length <= session_data->file_depth_remaining[source_id]) ?
- data.length : session_data->file_depth_remaining[source_id];
+ const int32_t fp_length = (file_data.length <= session_data->file_depth_remaining[source_id]) ?
+ file_data.length : session_data->file_depth_remaining[source_id];
if (source_id == SRC_SERVER)
{
- if (file_api->file_process(flow, const_cast<uint8_t*>(data.start), fp_length,
+ if (file_api->file_process(flow, const_cast<uint8_t*>(file_data.start), fp_length,
file_position, false, false))
{
session_data->file_depth_remaining[source_id] -= fp_length;
}
else
{
- file_api->process_mime_data(flow, data.start, data.start + fp_length,
+ file_api->process_mime_data(flow, file_data.start, file_data.start + fp_length,
session_data->mime_state, true, file_position);
session_data->file_depth_remaining[source_id] -= fp_length;
NHttpMsgSection::print_message_title(output, "body");
fprintf(output, "Expected data length %" PRIi64 ", octets seen %" PRIi64 "\n", data_length,
body_octets);
- data.print(output, "Data");
+ detect_data.print(output, "Detect data");
+ file_data.print(output, "File data");
NHttpMsgSection::print_message_wrapup(output);
}
{
// More body coming
session_data->body_octets[source_id] = body_octets;
- session_data->section_size_target[source_id] = DATA_BLOCK_SIZE;
- session_data->section_size_max[source_id] = FINAL_BLOCK_SIZE;
+ update_depth();
session_data->infractions[source_id] = infractions;
session_data->events[source_id] = events;
}
{
public:
NHttpMsgBody(const uint8_t* buffer, const uint16_t buf_size, NHttpFlowData* session_data_,
- NHttpEnums::SourceId source_id_, bool buf_owner, Flow* flow_);
+ NHttpEnums::SourceId source_id_, bool buf_owner, Flow* flow_,
+ const NHttpParaList* params_);
void analyze() override;
void print_section(FILE* output) override;
void gen_events() override;
void update_flow() override;
- Field& get_data() { return data; }
+ Field& get_detect_data() { return detect_data; }
+ bool worth_detection() const override { return (detect_data.length > 0); }
protected:
- int64_t data_length; // FIXIT-M this has no meaning in chunk subclass. Potential source of errors.
+ int64_t data_length; // FIXIT-M this has no meaning in chunk subclass. Potential source of
+ // errors.
int64_t body_octets;
- Field data;
+ Field detect_data;
+ Field file_data;
void do_file_processing();
};
using namespace NHttpEnums;
NHttpMsgChunk::NHttpMsgChunk(const uint8_t* buffer, const uint16_t buf_size,
- NHttpFlowData* session_data_, SourceId source_id_, bool buf_owner, Flow* flow_) :
- NHttpMsgBody(buffer, buf_size, session_data_, source_id_, buf_owner, flow_)
+ NHttpFlowData* session_data_, SourceId source_id_, bool buf_owner, Flow* flow_,
+ const NHttpParaList* params_) :
+ NHttpMsgBody(buffer, buf_size, session_data_, source_id_, buf_owner, flow_, params_)
{
transaction->set_body(this);
}
{
NHttpMsgSection::print_message_title(output, "chunked body");
fprintf(output, "Cumulative octets %" PRIi64 "\n", body_octets);
- data.print(output, "Data");
+ detect_data.print(output, "Detect data");
+ file_data.print(output, "File data");
NHttpMsgSection::print_message_wrapup(output);
}
else
{
session_data->body_octets[source_id] = body_octets;
- session_data->section_size_target[source_id] = DATA_BLOCK_SIZE;
+ update_depth();
session_data->infractions[source_id] = infractions;
session_data->events[source_id] = events;
}
{
public:
NHttpMsgChunk(const uint8_t* buffer, const uint16_t buf_size, NHttpFlowData* session_data_,
- NHttpEnums::SourceId source_id_, bool buf_owner, Flow* flow_);
+ NHttpEnums::SourceId source_id_, bool buf_owner, Flow* flow_,
+ const NHttpParaList* params_);
void print_section(FILE* output) override;
void gen_events() override;
void update_flow() override;
protected:
NHttpMsgHeadShared(const uint8_t* buffer, const uint16_t buf_size,
- NHttpFlowData* session_data_, NHttpEnums::SourceId source_id_, bool buf_owner, Flow* flow_)
- : NHttpMsgSection(buffer, buf_size, session_data_, source_id_, buf_owner, flow_) { }
+ NHttpFlowData* session_data_, NHttpEnums::SourceId source_id_, bool buf_owner, Flow* flow_,
+ const NHttpParaList* params_)
+ : NHttpMsgSection(buffer, buf_size, session_data_, source_id_, buf_owner, flow_, params_)
+ { }
// Header normalization strategies. There should be one defined for every different way we can
// process a header field value.
using namespace NHttpEnums;
NHttpMsgHeader::NHttpMsgHeader(const uint8_t* buffer, const uint16_t buf_size,
- NHttpFlowData* session_data_, SourceId source_id_, bool buf_owner, Flow* flow_) :
- NHttpMsgHeadShared(buffer, buf_size, session_data_, source_id_, buf_owner, flow_)
+ NHttpFlowData* session_data_, SourceId source_id_, bool buf_owner, Flow* flow_,
+ const NHttpParaList* params_) :
+ NHttpMsgHeadShared(buffer, buf_size, session_data_, source_id_, buf_owner, flow_, params_)
{
transaction->set_header(this, source_id);
}
// FIXIT-M inspect for Content-Length header which should not be present
// Chunked body
session_data->type_expected[source_id] = SEC_CHUNK;
- session_data->body_octets[source_id] = 0;
- session_data->section_size_target[source_id] = DATA_BLOCK_SIZE;
- if (session_data->file_depth_remaining[1-source_id] <= 0)
- { // Bidirectional file processing is problematic FIXIT-M
- session_data->file_depth_remaining[source_id] = file_api->get_max_file_depth();
- }
- session_data->infractions[source_id].reset();
- session_data->events[source_id].reset();
+ prepare_body();
}
else if ((get_header_value_norm(HEAD_CONTENT_LENGTH).length > 0) &&
(*(int64_t*)get_header_value_norm(HEAD_CONTENT_LENGTH).start > 0))
session_data->type_expected[source_id] = SEC_BODY;
session_data->data_length[source_id] = *(int64_t*)get_header_value_norm(
HEAD_CONTENT_LENGTH).start;
- session_data->body_octets[source_id] = 0;
- session_data->section_size_target[source_id] = DATA_BLOCK_SIZE;
- session_data->section_size_max[source_id] = FINAL_BLOCK_SIZE;
- if (session_data->file_depth_remaining[1-source_id] <= 0)
- { // Bidirectional file processing is problematic FIXIT-M
- session_data->file_depth_remaining[source_id] = file_api->get_max_file_depth();
- if (source_id == SRC_CLIENT)
- {
- // FIXIT-L Cannot use new because file_api insists on freeing the mime_state using
- // free().
- session_data->mime_state = (MimeState*) new_calloc(1, sizeof(MimeState));
- file_api->set_mime_log_config_defauts(&mime_conf);
- session_data->mime_state->log_config = &mime_conf;
- file_api->set_mime_decode_config_defauts(&decode_conf);
- session_data->mime_state->decode_conf = &decode_conf;
- file_api->set_log_buffers(&session_data->mime_state->log_state,
- session_data->mime_state->log_config);
- }
- }
- session_data->infractions[source_id].reset();
- session_data->events[source_id].reset();
+ prepare_body();
}
else
{
session_data->section_type[source_id] = SEC__NOTCOMPUTE;
}
+// Common activities of preparing for upcoming regular body or chunked body
+void NHttpMsgHeader::prepare_body()
+{
+ session_data->body_octets[source_id] = 0;
+ const int64_t& depth = (source_id == SRC_CLIENT) ? params->request_depth :
+ params->response_depth;
+ session_data->detect_depth_remaining[source_id] = (depth != -1) ? depth : INT64_MAX;
+ setup_file_processing();
+ setup_decompression();
+ update_depth();
+ session_data->infractions[source_id].reset();
+ session_data->events[source_id].reset();
+}
+
+void NHttpMsgHeader::setup_file_processing()
+{
+ // FIXIT-M Bidirectional file processing is problematic so we don't do it. When the library
+ // fully supports it remove the outer if statement that prevents it from being done.
+ if (session_data->file_depth_remaining[1-source_id] == 0)
+ {
+ if ((session_data->file_depth_remaining[source_id] = file_api->get_max_file_depth()) < 0)
+ {
+ session_data->file_depth_remaining[source_id] = 0;
+ }
+ if (source_id == SRC_CLIENT)
+ {
+ // FIXIT-L Cannot use new because file_api insists on freeing the mime_state using
+ // free().
+ session_data->mime_state = (MimeState*) new_calloc(1, sizeof(MimeState));
+ file_api->set_mime_log_config_defauts(&mime_conf);
+ session_data->mime_state->log_config = &mime_conf;
+ file_api->set_mime_decode_config_defauts(&decode_conf);
+ session_data->mime_state->decode_conf = &decode_conf;
+ file_api->set_log_buffers(&session_data->mime_state->log_state,
+ session_data->mime_state->log_config);
+ }
+ }
+}
+
+void NHttpMsgHeader::setup_decompression()
+{
+}
+
{
public:
NHttpMsgHeader(const uint8_t* buffer, const uint16_t buf_size, NHttpFlowData* session_data_,
- NHttpEnums::SourceId source_id_, bool buf_owner, Flow* flow_);
+ NHttpEnums::SourceId source_id_, bool buf_owner, Flow* flow_,
+ const NHttpParaList* params_);
void print_section(FILE* output) override;
void gen_events() override;
void update_flow() override;
// Dummy configurations to support MIME processing
MAIL_LogConfig mime_conf;
DecodeConfig decode_conf;
+
+ void prepare_body();
+ void setup_file_processing();
+ void setup_decompression();
};
#endif
using namespace NHttpEnums;
NHttpMsgRequest::NHttpMsgRequest(const uint8_t* buffer, const uint16_t buf_size,
- NHttpFlowData* session_data_, SourceId source_id_, bool buf_owner, Flow* flow_) :
- NHttpMsgStart(buffer, buf_size, session_data_, source_id_, buf_owner, flow_)
+ NHttpFlowData* session_data_, SourceId source_id_, bool buf_owner, Flow* flow_,
+ const NHttpParaList* params_) :
+ NHttpMsgStart(buffer, buf_size, session_data_, source_id_, buf_owner, flow_, params_)
{
transaction->set_request(this);
}
{
public:
NHttpMsgRequest(const uint8_t* buffer, const uint16_t buf_size, NHttpFlowData* session_data_,
- NHttpEnums::SourceId source_id_, bool buf_owner, Flow* flow_);
+ NHttpEnums::SourceId source_id_, bool buf_owner, Flow* flow_,
+ const NHttpParaList* params_);
~NHttpMsgRequest() { delete uri; }
void print_section(FILE* output) override;
void gen_events() override;
using namespace NHttpEnums;
NHttpMsgSection::NHttpMsgSection(const uint8_t* buffer, const uint16_t buf_size,
- NHttpFlowData* session_data_, SourceId source_id_, bool buf_owner, Flow* flow_) :
+ NHttpFlowData* session_data_, SourceId source_id_, bool buf_owner, Flow* flow_,
+ const NHttpParaList* params_) :
msg_text(buf_size, buffer),
session_data(session_data_),
source_id(source_id_),
flow(flow_),
+ params(params_),
transaction(NHttpTransaction::attach_my_transaction(session_data, source_id)),
tcp_close(session_data->tcp_close[source_id]),
scratch_pad(2*buf_size+500),
fprintf(output, "\n");
}
+void NHttpMsgSection::update_depth() const
+{
+ const int64_t& depth = (session_data->file_depth_remaining[source_id] >=
+ session_data->detect_depth_remaining[source_id]) ?
+ session_data->file_depth_remaining[source_id] :
+ session_data->detect_depth_remaining[source_id];
+ session_data->section_size_target[source_id] = (depth <= DATA_BLOCK_SIZE) ? depth :
+ DATA_BLOCK_SIZE;
+ session_data->section_size_max[source_id] = (depth <= FINAL_BLOCK_SIZE) ? depth :
+ FINAL_BLOCK_SIZE;
+}
+
const Field& NHttpMsgSection::get_legacy(unsigned buffer_id)
{
// When current section is trailers, that is what will be used for header and cookie buffers.
case HTTP_BUFFER_CLIENT_BODY:
{
NHttpMsgBody* body = transaction->get_body();
- return (body != nullptr) ? body->get_data() : Field::FIELD_NULL;
+ return (body != nullptr) ? body->get_detect_data() : Field::FIELD_NULL;
}
case HTTP_BUFFER_COOKIE:
{
#include "nhttp_scratch_pad.h"
#include "nhttp_field.h"
+#include "nhttp_module.h"
#include "nhttp_flow_data.h"
#include "nhttp_transaction.h"
#include "nhttp_infractions.h"
const Field& get_legacy(unsigned buffer_id);
// Should this section be sent directly to detection after inspection?
- bool worth_detection() { return (msg_text.length > 0); }
+ virtual bool worth_detection() const { return (msg_text.length > 0); }
NHttpEnums::MethodId get_method_id() const { return method_id; }
protected:
NHttpMsgSection(const uint8_t* buffer, const uint16_t buf_size, NHttpFlowData* session_data_,
- NHttpEnums::SourceId source_id_, bool buf_owner, Flow* flow_);
+ NHttpEnums::SourceId source_id_, bool buf_owner, Flow* flow_, const NHttpParaList*
+ params_);
// Convenience methods
void print_message_title(FILE* output, const char* title) const;
void print_message_wrapup(FILE* output);
+ void update_depth() const;
const Field msg_text;
NHttpFlowData* const session_data;
const NHttpEnums::SourceId source_id;
Flow* const flow;
- NHttpTransaction* transaction;
+ const NHttpParaList* const params;
+ NHttpTransaction* const transaction;
const bool tcp_close;
ScratchPad scratch_pad;
protected:
NHttpMsgStart(const uint8_t* buffer, const uint16_t buf_size, NHttpFlowData* session_data_,
- NHttpEnums::SourceId source_id_, bool buf_owner, Flow* flow_) :
- NHttpMsgSection(buffer, buf_size, session_data_, source_id_, buf_owner, flow_) { }
+ NHttpEnums::SourceId source_id_, bool buf_owner, Flow* flow_, const NHttpParaList* params_)
+ : NHttpMsgSection(buffer, buf_size, session_data_, source_id_, buf_owner, flow_, params_)
+ { }
virtual void parse_start_line() = 0;
void derive_version_id();
using namespace NHttpEnums;
NHttpMsgStatus::NHttpMsgStatus(const uint8_t* buffer, const uint16_t buf_size,
- NHttpFlowData* session_data_, SourceId source_id_, bool buf_owner, Flow* flow_) :
- NHttpMsgStart(buffer, buf_size, session_data_, source_id_, buf_owner, flow_)
+ NHttpFlowData* session_data_, SourceId source_id_, bool buf_owner, Flow* flow_,
+ const NHttpParaList* params_) :
+ NHttpMsgStart(buffer, buf_size, session_data_, source_id_, buf_owner, flow_, params_)
{
transaction->set_status(this);
}
{
public:
NHttpMsgStatus(const uint8_t* buffer, const uint16_t buf_size, NHttpFlowData* session_data_,
- NHttpEnums::SourceId source_id_, bool buf_owner, Flow* flow_);
+ NHttpEnums::SourceId source_id_, bool buf_owner, Flow* flow_,
+ const NHttpParaList* params_);
void print_section(FILE* output) override;
void gen_events() override;
void update_flow() override;
using namespace NHttpEnums;
NHttpMsgTrailer::NHttpMsgTrailer(const uint8_t* buffer, const uint16_t buf_size,
- NHttpFlowData* session_data_, SourceId source_id_, bool buf_owner, Flow* flow_) :
- NHttpMsgHeadShared(buffer, buf_size, session_data_, source_id_, buf_owner, flow_)
+ NHttpFlowData* session_data_, SourceId source_id_, bool buf_owner, Flow* flow_,
+ const NHttpParaList* params_) :
+ NHttpMsgHeadShared(buffer, buf_size, session_data_, source_id_, buf_owner, flow_, params_)
{
transaction->set_trailer(this, source_id);
}
{
public:
NHttpMsgTrailer(const uint8_t* buffer, const uint16_t buf_size, NHttpFlowData* session_data_,
- NHttpEnums::SourceId source_id_, bool buf_owner, Flow* flow_);
+ NHttpEnums::SourceId source_id_, bool buf_owner, Flow* flow_,
+ const NHttpParaList* params_);
void print_section(FILE* output) override;
void gen_events() override;
void update_flow() override;
return StreamSplitter::FLUSH;
}
case SCAN_DISCARD:
+ case SCAN_DISCARD_PIECE:
prepare_flush(session_data, flush_offset, SEC_DISCARD, cutter->get_num_flush(),
cutter->get_octets_seen(), 0, 0, false, 0);
- delete cutter;
- cutter = nullptr;
+ if (cut_result == SCAN_DISCARD)
+ {
+ delete cutter;
+ cutter = nullptr;
+ }
return StreamSplitter::FLUSH;
case SCAN_FOUND:
case SCAN_FOUND_PIECE:
fprintf(NHttpTestManager::get_output_file(), "Discarded %u octets\n\n", len);
fflush(NHttpTestManager::get_output_file());
}
- session_data->section_type[source_id] = SEC__NOTCOMPUTE;
+ if (flags & PKT_PDU_TAIL)
+ {
+ session_data->section_type[source_id] = SEC__NOTCOMPUTE;
+
+ // When we are skipping through a message body beyond flow depth this is the end of
+ // the line. Here we do the message section's normal job of updating the flow for the
+ // next stage.
+ if (session_data->cutter[source_id] == nullptr)
+ {
+ if (session_data->type_expected[source_id] == SEC_BODY)
+ {
+ session_data->type_expected[source_id] = (source_id == SRC_CLIENT) ?
+ SEC_REQUEST : SEC_STATUS;
+ session_data->half_reset(source_id);
+ }
+ else if (session_data->type_expected[source_id] == SEC_CHUNK)
+ {
+ session_data->type_expected[source_id] = SEC_TRAILER;
+ session_data->infractions[source_id].reset();
+ session_data->events[source_id].reset();
+ }
+ }
+ }
return nullptr;
}