]> git.ipfire.org Git - thirdparty/snort3.git/commitdiff
Pull request #4477: Extractor - HTTP fields support: add support for body length...
authorMaya Dagon (mdagon) <mdagon@cisco.com>
Fri, 11 Oct 2024 11:28:41 +0000 (11:28 +0000)
committerMaya Dagon (mdagon) <mdagon@cisco.com>
Fri, 11 Oct 2024 11:28:41 +0000 (11:28 +0000)
Merge in SNORT/snort3 from ~MDAGON/snort3:http_fields to master

Squashed commit of the following:

commit 1fc153936a564191ae716130d477859198d12e2a
Author: maya dagon <mdagon@cisco.com>
Date:   Tue Jul 2 11:02:28 2024 -0400

    extractor: add support for body length, info_code/msg, filename, proxied

15 files changed:
src/network_inspectors/extractor/dev_notes.txt
src/network_inspectors/extractor/extractor_http_event_handler.cc
src/network_inspectors/extractor/extractor_service.cc
src/pub_sub/http_transaction_end_event.cc
src/pub_sub/http_transaction_end_event.h
src/pub_sub/test/CMakeLists.txt
src/pub_sub/test/pub_sub_http_transaction_end_event_test.cc
src/service_inspectors/http_inspect/http_enum.h
src/service_inspectors/http_inspect/http_msg_body.cc
src/service_inspectors/http_inspect/http_msg_status.h
src/service_inspectors/http_inspect/http_normalized_header.cc
src/service_inspectors/http_inspect/http_tables.cc
src/service_inspectors/http_inspect/http_transaction.cc
src/service_inspectors/http_inspect/http_transaction.h
src/service_inspectors/http_inspect/test/http_transaction_test.cc

index 2878b160f5fc1e5dd8a910dd50440e9fe414c661..d3acffaa388b59c26bd2f309cb4114c7f8c0d69a 100644 (file)
@@ -49,4 +49,11 @@ The following fields are supported for HTTP:
  * status_code
  * status_msg
  * trans_depth
+ * request_body_len
+ * response_body_len
+ * info_code
+ * info_msg
+ * proxied
+ * orig_filenames
+ * resp_filenames
 
index 0d489e8cbe08c6291fa82aceaa06e70d7099a768..46482a732fcfaf9abd829e0676d604a849dee821 100644 (file)
@@ -88,6 +88,41 @@ static uint64_t get_trans_depth(const DataEvent* event, const Packet*, const Flo
     return ((const HttpTransactionEndEvent*)event)->get_trans_depth();
 }
 
+static uint64_t get_request_body_len(const DataEvent* event, const Packet*, const Flow*)
+{
+    return ((const HttpTransactionEndEvent*)event)->get_request_body_len();
+}
+
+static uint64_t get_response_body_len(const DataEvent* event, const Packet*, const Flow*)
+{
+    return ((const HttpTransactionEndEvent*)event)->get_response_body_len();
+}
+
+static uint64_t get_info_code(const DataEvent* event, const Packet*, const Flow*)
+{
+    return ((const HttpTransactionEndEvent*)event)->get_info_code();
+}
+
+static const Field& get_info_msg(const DataEvent* event, const Packet*, const Flow*)
+{
+    return ((const HttpTransactionEndEvent*)event)->get_info_msg();
+}
+
+static const char* get_proxied(const DataEvent* event, const Packet*, const Flow*)
+{
+    return ((const HttpTransactionEndEvent*)event)->get_proxied().c_str();
+}
+
+static const char* get_orig_filenames(const DataEvent* event, const Packet*, const Flow*)
+{
+    return ((const HttpTransactionEndEvent*)event)->get_filename(HttpCommon::SRC_CLIENT).c_str();
+}
+
+static const char* get_resp_filenames(const DataEvent* event, const Packet*, const Flow*)
+{
+    return ((const HttpTransactionEndEvent*)event)->get_filename(HttpCommon::SRC_SERVER).c_str();
+}
+
 static struct timeval get_timestamp(const DataEvent*, const Packet* p, const Flow*)
 {
     return p->pkth->ts;
@@ -136,7 +171,10 @@ static const map<string, ExtractorEvent::SipGetFn> sip_getters =
 
 static const map<string, ExtractorEvent::StrGetFn> str_getters =
 {
-    {"version", get_version}
+    {"version", get_version},
+    {"proxied", get_proxied},
+    {"orig_filenames", get_orig_filenames},
+    {"resp_filenames", get_resp_filenames}
 };
 
 static const map<string, ExtractorEvent::NumGetFn> num_getters =
@@ -145,7 +183,10 @@ static const map<string, ExtractorEvent::NumGetFn> num_getters =
     {"id.resp_p", get_ip_dst_port},
     {"uid", get_uid},
     {"pkt_num", get_pkt_num},
-    {"trans_depth", get_trans_depth}
+    {"trans_depth", get_trans_depth},
+    {"request_body_len", get_request_body_len},
+    {"response_body_len", get_response_body_len},
+    {"info_code", get_info_code}
 };
 
 static const map<string, HttpExtractorEventHandler::SubGetFn> sub_getters =
@@ -157,7 +198,8 @@ static const map<string, HttpExtractorEventHandler::SubGetFn> sub_getters =
     {"referrer", get_referrer},
     {"origin", get_origin},
     {"status_code", get_stat_code},
-    {"status_msg", get_stat_msg}
+    {"status_msg", get_stat_msg},
+    {"info_msg", get_info_msg}
 };
 
 template<class T, class U, class V>
index e7cacb0d1410c8510b6a8f7e46dc5ecfe8cf7cca..bfe3b04566ca89cc615a934987f76035654050e6 100644 (file)
@@ -159,7 +159,14 @@ ServiceBlueprint HttpExtractorService::blueprint =
       "version",
       "status_code",
       "status_msg",
-      "trans_depth"
+      "trans_depth",
+      "request_body_len",
+      "response_body_len",
+      "info_code",
+      "info_msg",
+      "proxied",
+      "orig_filenames",
+      "resp_filenames"
     },
 };
 
index 0aa8e6829658f4791f25a269edf7a6e4fc53c238..be35661cd2afd24f36c7f7cf3b8cb1444b8d56b5 100644 (file)
@@ -31,6 +31,7 @@
 #include "service_inspectors/http_inspect/http_transaction.h"
 
 using namespace snort;
+using namespace HttpEnums;
 
 HttpTransactionEndEvent::HttpTransactionEndEvent(const HttpTransaction* const trans)
     : transaction(trans) { }
@@ -113,3 +114,61 @@ uint64_t HttpTransactionEndEvent::get_trans_depth() const
 
     return 0;
 }
+
+uint64_t HttpTransactionEndEvent::get_request_body_len() const
+{
+    return transaction->get_body_len(HttpCommon::SRC_CLIENT);
+}
+
+uint64_t HttpTransactionEndEvent::get_response_body_len() const
+{
+    return transaction->get_body_len(HttpCommon::SRC_SERVER);
+}
+
+uint8_t HttpTransactionEndEvent::get_info_code() const
+{
+    return transaction->get_info_code();
+}
+
+const Field& HttpTransactionEndEvent::get_info_msg() const
+{
+    return transaction->get_info_msg();
+}
+
+const std::string& HttpTransactionEndEvent::get_filename(HttpCommon::SourceId src_id) const
+{
+    return transaction->get_filename(src_id);
+}
+
+const std::string& HttpTransactionEndEvent::get_proxied() const
+{
+    if (proxies != nullptr)
+        return *proxies;
+
+    const std::pair<HeaderId, const char*> proxy_headers[] =
+    {
+        { HEAD_FORWARDED, "FORWARDED" },
+        { HEAD_X_FORWARDED_FOR, "X-FORWARDED-FOR" },
+        { HEAD_X_FORWARDED_FROM, "X-FORWARDED-FROM" },
+        { HEAD_CLIENT_IP, "CLIENT-IP" },
+        { HEAD_VIA, "VIA" },
+        { HEAD_XROXY_CONNECTION, "XROXY-CONNECTION" },
+        { HEAD_PROXY_CONNECTION, "PROXY-CONNECTION" }
+    };
+
+    proxies = new std::string();
+    for (auto& hdr: proxy_headers)
+    {
+        const Field& val = get_client_header(hdr.first);
+        if (val.length() > 0)
+        {
+            if (!proxies->empty())
+                proxies->append(",");
+            proxies->append(hdr.second);
+            proxies->append(" -> ");
+            proxies->append((const char*)val.start(), val.length());
+        }
+    }
+
+    return *proxies;
+}
index 9fe6d4bc61e365d84639bda2fc1e9c76be62b118..7fda6f0dd975afae754d89b1b17c260ba5c706a6 100644 (file)
@@ -38,6 +38,8 @@ class SO_PUBLIC HttpTransactionEndEvent : public snort::DataEvent
 {
 public:
     HttpTransactionEndEvent(const HttpTransaction* const);
+    ~HttpTransactionEndEvent() override
+    { delete proxies; }
 
     const Field& get_host_hdr() const;
     const Field& get_uri() const;
@@ -49,11 +51,18 @@ public:
     const Field& get_origin_hdr() const;
     HttpEnums::VersionId get_version() const;
     uint64_t get_trans_depth() const;
+    uint64_t get_request_body_len() const;
+    uint64_t get_response_body_len() const;
+    uint8_t get_info_code() const;
+    const Field& get_info_msg() const;
+    const std::string& get_filename(HttpCommon::SourceId) const;
+    const std::string& get_proxied() const;
 
 private:
     const Field& get_client_header(uint64_t sub_id) const;
 
     const HttpTransaction* const transaction;
+    mutable std::string* proxies = nullptr;
 };
 }
 #endif
index f2a21d8aa29141abce751c4f4dd987bd14b9889c..00dddc52e8461c9ee1bb1a5af880a03316ec9df3 100644 (file)
@@ -24,6 +24,7 @@ add_cpputest( pub_sub_http_transaction_end_event_test
         ../../service_inspectors/http_inspect/http_flow_data.cc
         ../../service_inspectors/http_inspect/http_test_manager.cc
         ../../service_inspectors/http_inspect/http_test_input.cc
+        ../../service_inspectors/http_inspect/http_field.cc
     LIBS ${ZLIB_LIBRARIES}
 )
 add_cpputest( pub_sub_ftp_events_test
index 0ba37bda65ca20947e226d6d5ca9d3adc0a4f8e3..8762cc6fb302c016e99b0652ebd509d68d563ea4 100644 (file)
@@ -28,6 +28,7 @@
 #include "service_inspectors/http_inspect/http_flow_data.h"
 #include "service_inspectors/http_inspect/http_inspect.h"
 #include "service_inspectors/http_inspect/http_module.h"
+#include "service_inspectors/http_inspect/http_msg_header.h"
 #include "service_inspectors/http_inspect/http_msg_section.h"
 #include "service_inspectors/http_inspect/http_transaction.h"
 #include "service_inspectors/http_inspect/test/http_unit_test_helpers.h"
@@ -70,9 +71,6 @@ unsigned StreamSplitter::max(snort::Flow*) { return 0; }
 HttpParaList::UriParam::UriParam() { }
 HttpParaList::JsNormParam::~JsNormParam() { }
 HttpParaList::~HttpParaList() { }
-const Field Field::FIELD_NULL { STAT_NO_SOURCE };
-const Field& HttpMsgSection::get_classic_buffer(unsigned, uint64_t, uint64_t)
-{ return Field::FIELD_NULL; }
 HttpInspect::HttpInspect(const HttpParaList* para) :
     params(para), xtra_trueip_id(0), xtra_uri_id(0),
     xtra_host_id(0), xtra_jsnorm_id(0)
@@ -106,8 +104,56 @@ const snort::StreamBuffer HttpStreamSplitter::reassemble(snort::Flow*, unsigned,
 bool HttpStreamSplitter::finish(snort::Flow*) { return false; }
 void HttpStreamSplitter::prep_partial_flush(snort::Flow*, uint32_t) { }
 
+HttpMsgHeader::HttpMsgHeader(const uint8_t* buffer, const uint16_t buf_size,
+    HttpFlowData* session_data_, SourceId source_id_, bool buf_owner, Flow* flow_,
+    const HttpParaList* params_) :
+    HttpMsgHeadShared(buffer, buf_size, session_data_, source_id_, buf_owner, flow_, params_)
+{}
+void HttpMsgHeader::publish(unsigned){}
+void HttpMsgHeader::gen_events() {}
+void HttpMsgHeader::update_flow() {}
+void HttpMsgHeader::prepare_body() {}
+#ifdef REG_TEST
+void HttpMsgHeader::print_section(FILE*) {}
+#endif
+HttpMsgHeadShared::HttpMsgHeadShared(const uint8_t* buffer, const uint16_t buf_size,
+    HttpFlowData* session_data_, HttpCommon::SourceId source_id_, bool buf_owner,
+    snort::Flow* flow_, const HttpParaList* params_): HttpMsgSection(buffer, buf_size,
+    session_data_, source_id_, buf_owner, flow_, params_), own_msg_buffer(buf_owner)
+{}
+HttpMsgHeadShared::~HttpMsgHeadShared() {}
+HttpMsgSection::HttpMsgSection(const uint8_t* buffer, const uint16_t buf_size,
+       HttpFlowData* session_data_, SourceId source_id_, bool buf_owner, Flow* flow_,
+       const HttpParaList* params_) :
+    msg_text(buf_size, buffer, buf_owner),
+    session_data(session_data_),
+    flow(flow_),
+    params(params_),
+    transaction(nullptr),
+    trans_num(0),
+    status_code_num(STAT_NOT_PRESENT),
+    source_id(source_id_),
+    version_id(VERS__NOT_PRESENT),
+    method_id(METH__NOT_PRESENT),
+    tcp_close(false)
+{}
+void HttpMsgSection::clear(){}
+bool HttpMsgSection::run_detection(snort::Packet*) { return false; }
+void HttpMsgHeadShared::analyze() {}
+
 THREAD_LOCAL PegCount HttpModule::peg_counts[PEG_COUNT_MAX] = { };
 
+//
+// get_classic_buffer mock
+//
+Field odd (3, (const uint8_t *)"odd", false);
+Field even (4, (const uint8_t *)"even", false);
+static uint32_t test_number = 0;
+const Field& HttpMsgSection::get_classic_buffer(unsigned, uint64_t, uint64_t)
+{
+    return ((test_number % 2) == 0) ? even : odd;
+}
+
 TEST_GROUP(pub_sub_http_transaction_end_event_test)
 {
     Flow* const flow = new Flow;
@@ -127,17 +173,36 @@ TEST_GROUP(pub_sub_http_transaction_end_event_test)
     }
 };
 
-TEST(pub_sub_http_transaction_end_event_test, version_no_req_no_status)
+TEST(pub_sub_http_transaction_end_event_test, no_req_no_status)
 {
     section_type[SRC_CLIENT] = SEC_REQUEST;
     HttpTransaction* trans = HttpTransaction::attach_my_transaction(flow_data, SRC_CLIENT, flow);
     HttpTransactionEndEvent event(trans);
     HttpEnums::VersionId version = event.get_version();
     CHECK(version == HttpEnums::VERS__NOT_PRESENT);
+    uint64_t trans_depth = event.get_trans_depth();
+    CHECK(trans_depth == 0);
+}
+
+TEST(pub_sub_http_transaction_end_event_test, proxied_str_exists)
+{
+    section_type[SRC_CLIENT] = SEC_REQUEST;
+    HttpTransaction* trans = HttpTransaction::attach_my_transaction(flow_data, SRC_CLIENT, flow);
+    char buf[] = "something";
+    HttpMsgHeader* hdr = new HttpMsgHeader((uint8_t*)buf, sizeof(buf), flow_data, SRC_CLIENT, false, flow, &params);
+    trans->set_header(hdr, SRC_CLIENT);
+    HttpTransactionEndEvent event(trans);
+    const std::string result = "FORWARDED -> odd,X-FORWARDED-FOR -> odd,X-FORWARDED-FROM -> odd,"
+        "CLIENT-IP -> odd,VIA -> odd,XROXY-CONNECTION -> odd,PROXY-CONNECTION -> odd";
+    test_number = 1;
+    std::string proxied = event.get_proxied();
+    CHECK(proxied == result);
+    test_number = 2;
+    proxied = event.get_proxied();
+    CHECK(proxied == result);
 }
 
 int main(int argc, char** argv)
 {
     return CommandLineTestRunner::RunAllTests(argc, argv);
 }
-
index 4c5be4a888b759b4dad9688524cce179c71e8d1c..19c9eaed7032948dbcf1f8ae587091bf98567205 100755 (executable)
@@ -156,7 +156,8 @@ enum HeaderId { HEAD__NOT_COMPUTE=-14, HEAD__PROBLEMATIC=-12, HEAD__NOT_PRESENT=
     HEAD_CONTENT_TYPE, HEAD_EXPIRES, HEAD_LAST_MODIFIED, HEAD_X_FORWARDED_FOR, HEAD_TRUE_CLIENT_IP,
     HEAD_X_WORKING_WITH, HEAD_CONTENT_TRANSFER_ENCODING, HEAD_MIME_VERSION, HEAD_PROXY_AGENT,
     HEAD_CONTENT_DISPOSITION, HEAD_HTTP2_SETTINGS, HEAD_RESTRICT_ACCESS_TO_TENANTS,
-    HEAD_RESTRICT_ACCESS_CONTEXT, HEAD_ORIGIN, HEAD__MAX_VALUE };
+    HEAD_RESTRICT_ACCESS_CONTEXT, HEAD_ORIGIN, HEAD_FORWARDED, HEAD_X_FORWARDED_FROM,
+    HEAD_CLIENT_IP, HEAD_XROXY_CONNECTION, HEAD_PROXY_CONNECTION, HEAD__MAX_VALUE };
 
 // All the infractions we might find while parsing and analyzing a message
 enum Infraction
index 80b46815871759639665e42f6f9ca2eded578e5f..1599e9d06abef90bb6994b16f63758da27a1dd5c 100644 (file)
@@ -324,6 +324,8 @@ void HttpMsgBody::analyze()
         }
     }
     body_octets += msg_text.length();
+    if (!session_data->partial_flush[source_id])
+        transaction->add_body_len(source_id, detect_data.length());
     partial_inspected_octets = session_data->partial_flush[source_id] ? msg_text.length() : 0;
 }
 
@@ -715,6 +717,7 @@ void HttpMsgBody::do_file_processing(const Field& file_data)
                     filename_length, 0,
                     get_header(source_id)->get_multi_file_processing_id(), uri_buffer,
                     uri_length);
+                transaction->set_filename(source_id, (const char*) filename_buffer, filename_length);
             }
         }
     }
index 1d40763a61312a6bcc8ab62224936555b34a37ba..a68103dccfc2ef78bc29e80d5ddc1a3e838055c2 100644 (file)
@@ -37,8 +37,8 @@ public:
     void gen_events() override;
     void update_flow() override;
 
-    const Field& get_status_code() { return status_code; }
-    const Field& get_reason_phrase() { return reason_phrase; }
+    const Field& get_status_code() const { return status_code; }
+    const Field& get_reason_phrase() const { return reason_phrase; }
 
 #ifdef REG_TEST
     void print_section(FILE* output) override;
index 37d2c5321d109f3e57c7f8d925b74b9c58347ca0..a4c40e34ebdc5e0075ea2624db1fd9d2a42adf36 100644 (file)
@@ -166,6 +166,11 @@ const NormalizedHeader::HeaderNormalizer* const NormalizedHeader::header_norms[H
     &NORMALIZER_BASIC,      // HEAD_RESTRICT_ACCESS_TO_TENANTS
     &NORMALIZER_BASIC,      // HEAD_RESTRICT_ACCESS_CONTEXT
     &NORMALIZER_URI,        // HEAD_ORIGIN
+    &NORMALIZER_BASIC,      // HEAD_FORWARDED
+    &NORMALIZER_BASIC,      // HEAD_X_FORWARDED_FROM
+    &NORMALIZER_BASIC,      // HEAD_CLIENT_IP
+    &NORMALIZER_BASIC,      // HEAD_XROXY_CONNECTION
+    &NORMALIZER_BASIC,      // HEAD_PROXY_CONNECTION
     &NORMALIZER_BASIC,      // HEAD__MAX_VALUE
     &NORMALIZER_BASIC,      // HEAD_CUSTOM_XFF_HEADER
     &NORMALIZER_BASIC,      // HEAD_CUSTOM_XFF_HEADER
index 5cc31714d98ff9e1edc730ce20b7e83412f74f61..0b2e7c50549f1e49572599a042a9ec2dd06bda73 100755 (executable)
@@ -143,6 +143,11 @@ const StrCode HttpMsgHeadShared::header_list[] =
     { HEAD_RESTRICT_ACCESS_TO_TENANTS, "restrict-access-to-tenants" },
     { HEAD_RESTRICT_ACCESS_CONTEXT,    "restrict-access-context" },
     { HEAD_ORIGIN,                     "origin" },
+    { HEAD_FORWARDED,                  "forwarded" },
+    { HEAD_X_FORWARDED_FROM,           "x-forwarded-from" },
+    { HEAD_CLIENT_IP,                  "client-ip" },
+    { HEAD_XROXY_CONNECTION,           "xroxy-connection" },
+    { HEAD_PROXY_CONNECTION,           "proxy-connection" },
     { 0,                               nullptr }
 };
 
index 71e040adce59b8bc71602c409a08de11039b3ccd..3846065eb69a0bd370da742d39a94e8a46a6b733 100644 (file)
@@ -81,7 +81,8 @@ HttpTransaction::~HttpTransaction()
         delete infractions[k];
     }
     delete_section_list(body_list);
-    delete_section_list(discard_list);
+    delete_section_list(archive_hdr_list);
+    delete_section_list(archive_status_list);
 }
 
 HttpTransaction* HttpTransaction::attach_my_transaction(HttpFlowData* session_data, SourceId
@@ -155,10 +156,10 @@ HttpTransaction* HttpTransaction::attach_my_transaction(HttpFlowData* session_da
               session_data->transaction[SRC_SERVER]->second_response_expected)
     {
         session_data->transaction[SRC_SERVER]->second_response_expected = false;
-        session_data->transaction[SRC_SERVER]->discard_section(
+        session_data->transaction[SRC_SERVER]->archive_status(
             session_data->transaction[SRC_SERVER]->status);
         session_data->transaction[SRC_SERVER]->status = nullptr;
-        session_data->transaction[SRC_SERVER]->discard_section(
+        session_data->transaction[SRC_SERVER]->archive_header(
             session_data->transaction[SRC_SERVER]->header[SRC_SERVER]);
         session_data->transaction[SRC_SERVER]->header[SRC_SERVER] = nullptr;
     }
@@ -217,15 +218,25 @@ HttpTransaction* HttpTransaction::attach_my_transaction(HttpFlowData* session_da
     return session_data->transaction[source_id];
 }
 
-void HttpTransaction::discard_section(HttpMsgSection* section)
+void HttpTransaction::archive_section(HttpMsgSection* section, HttpMsgSection** archive_list)
 {
     if (section != nullptr)
     {
-        section->next = discard_list;
-        discard_list = section;
+        section->next = *archive_list;
+        *archive_list = section;
     }
 }
 
+void HttpTransaction::archive_status(HttpMsgStatus* status)
+{
+    archive_section(status, &archive_status_list); 
+}
+
+void HttpTransaction::archive_header(HttpMsgHeader* hdr)
+{
+    archive_section(hdr, &archive_hdr_list); 
+}
+
 void HttpTransaction::clear_section()
 {
     assert(active_sections > 0);
@@ -289,3 +300,50 @@ void HttpTransaction::set_one_hundred_response()
     one_hundred_response = true;
     second_response_expected = true;
 }
+
+inline bool is_info_code(int32_t code) 
+{
+    return ((99 < code) and (code < 200));
+}
+
+uint8_t HttpTransaction::get_info_code() const
+{     
+     if (status)
+     {
+         const int32_t code = status->get_status_code_num();
+         if (is_info_code(code))
+             return code;
+     }
+
+     const HttpMsgStatus* arch_status = (HttpMsgStatus*) archive_status_list;
+     while (arch_status)
+     {
+         const int32_t code = arch_status->get_status_code_num();
+         if (is_info_code(code))
+             return code;
+         arch_status = (HttpMsgStatus*)(arch_status->next);
+     }
+
+     return 0;
+}
+
+const Field& HttpTransaction::get_info_msg() const
+{     
+     if (status)
+     {
+         const int32_t code = status->get_status_code_num();
+         if (is_info_code(code))
+             return status->get_reason_phrase();
+     }
+
+     const HttpMsgStatus* arch_status = (HttpMsgStatus*) archive_status_list;
+     while (arch_status)
+     {
+         const int32_t code = arch_status->get_status_code_num();
+         if (is_info_code(code))
+             return arch_status->get_reason_phrase();
+         arch_status = (HttpMsgStatus*)(arch_status->next);
+     }
+
+     return Field::FIELD_NULL;
+}
index c3981da211a21765cf32b34daf29ec39b1de79ce..d64a6e817544edf1c81c03b694470b8872f4d2e8 100644 (file)
@@ -62,6 +62,17 @@ public:
     void set_one_hundred_response();
     bool final_response() const { return !second_response_expected; }
 
+    void add_body_len(HttpCommon::SourceId source_id, uint64_t len)
+        { body_len[source_id] += len; }
+    uint64_t get_body_len(HttpCommon::SourceId source_id) const
+        { return body_len[source_id]; }
+    uint8_t get_info_code() const;
+    const Field& get_info_msg() const;
+    void set_filename(HttpCommon::SourceId source_id, const char* fname, uint32_t len)
+        { filename[source_id].assign(fname, len);}
+    const std::string& get_filename(HttpCommon::SourceId source_id) const
+        { return filename[source_id]; }
+  
     void clear_section();
     bool is_clear() const { return active_sections == 0; }
     void garbage_collect();
@@ -70,7 +81,9 @@ public:
 
 private:
     HttpTransaction(HttpFlowData*, snort::Flow* const);
-    void discard_section(HttpMsgSection*);
+    void archive_section(HttpMsgSection*, HttpMsgSection**);
+    void archive_status(HttpMsgStatus*);
+    void archive_header(HttpMsgHeader*);
     void publish_end_of_transaction();
 
     HttpFlowData* const session_data;
@@ -82,7 +95,8 @@ private:
     HttpMsgHeader* header[2] = { nullptr, nullptr };
     HttpMsgTrailer* trailer[2] = { nullptr, nullptr };
     HttpMsgBody* body_list = nullptr;
-    HttpMsgSection* discard_list = nullptr;
+    HttpMsgSection* archive_status_list = nullptr;
+    HttpMsgSection* archive_hdr_list = nullptr;
     HttpInfractions* infractions[2];
 
     bool response_seen = false;
@@ -97,6 +111,9 @@ private:
     unsigned pub_id;
     snort::Flow* const flow;
 
+    uint64_t body_len[2] = { 0, 0 };
+    std::string filename[2]; 
+
     // Estimates of how much memory http_inspect uses to process a transaction
     static const uint16_t small_things = 400; // minor memory costs not otherwise accounted for
     static const uint16_t transaction_memory_usage_estimate;
index aba0218e77b1e0ae139568fe72c9ba203fc6ecb1..e643557b0e412aeadfca1d24dcb638e6239e2987 100644 (file)
@@ -113,6 +113,7 @@ bool HttpStreamSplitter::finish(snort::Flow*) { return false; }
 void HttpStreamSplitter::prep_partial_flush(snort::Flow*, uint32_t) { }
 
 THREAD_LOCAL PegCount HttpModule::peg_counts[PEG_COUNT_MAX] = { };
+const Field Field::FIELD_NULL { STAT_NO_SOURCE };
 
 TEST_GROUP(http_transaction_test)
 {