]> git.ipfire.org Git - thirdparty/snort3.git/commitdiff
Pull request #3582: Header length rule options
authorTom Peters (thopeter) <thopeter@cisco.com>
Wed, 14 Sep 2022 22:13:11 +0000 (22:13 +0000)
committerTom Peters (thopeter) <thopeter@cisco.com>
Wed, 14 Sep 2022 22:13:11 +0000 (22:13 +0000)
Merge in SNORT/snort3 from ~ADMAMOLE/snort3:header_length to master

Squashed commit of the following:

commit 95bfb786b9c1cc5912a90e0aeaf1ea57f1532b4b
Author: Adrian Mamolea <admamole@cisco.com>
Date:   Wed Aug 31 12:16:43 2022 -0400

    http_inspect: http_max_header_line and http_max_trailer_line rule options

doc/user/http_inspect.txt
src/service_inspectors/http_inspect/http_api.cc
src/service_inspectors/http_inspect/http_enum.h
src/service_inspectors/http_inspect/http_inspect.cc
src/service_inspectors/http_inspect/http_inspect.h
src/service_inspectors/http_inspect/http_msg_head_shared.cc
src/service_inspectors/http_inspect/http_msg_head_shared.h
src/service_inspectors/http_inspect/http_msg_section.cc
src/service_inspectors/http_inspect/http_msg_section.h
src/service_inspectors/http_inspect/ips_http_num_hdrs.cc

index 298bedec0760ca03a42abf6a6d0ff1086cce1361..b0f07f9946c397a47a31ed157d8d5702a2618849 100755 (executable)
@@ -780,6 +780,11 @@ and decompress_vba options enabled.
 These are range-based rule options used to check the number of headers and
 trailers, respectively.
 
+===== http_max_header_line and http_max_trailer_line
+
+These are range-based rule options used to check the longest line in
+request and response headers and trailers, respectively.
+
 ===== http_num_cookies
 
 This is a range-based rule option that checks the number of cookies. In a
index 5d1e59a3ff046458845b492e5e3733432b796884..93064df4cbe9220950710d2acc517d9736beec59 100644 (file)
@@ -104,6 +104,8 @@ extern const BaseApi* ips_http_client_body;
 extern const BaseApi* ips_http_cookie;
 extern const BaseApi* ips_http_header;
 extern const BaseApi* ips_http_header_test;
+extern const BaseApi* ips_http_max_header_line;
+extern const BaseApi* ips_http_max_trailer_line;
 extern const BaseApi* ips_http_method;
 extern const BaseApi* ips_http_num_cookies;
 extern const BaseApi* ips_http_num_headers;
@@ -137,6 +139,8 @@ const BaseApi* sin_http[] =
     ips_http_cookie,
     ips_http_header,
     ips_http_header_test,
+    ips_http_max_header_line,
+    ips_http_max_trailer_line,
     ips_http_method,
     ips_http_num_cookies,
     ips_http_num_headers,
index 0af7b2823d9304819ae0cf4492c8f1311341c510..b4acfaec4f6c507e675789373a26c2cdbd979c42 100755 (executable)
@@ -58,7 +58,8 @@ enum HTTP_RULE_OPT { HTTP_BUFFER_CLIENT_BODY = 1, HTTP_BUFFER_COOKIE, HTTP_BUFFE
     HTTP_BUFFER_TRAILER, HTTP_BUFFER_TRUE_IP, HTTP_BUFFER_URI, HTTP_BUFFER_VERSION,
     BUFFER_JS_DATA, BUFFER_VBA_DATA , HTTP__BUFFER_MAX = BUFFER_VBA_DATA,
     HTTP_RANGE_NUM_HDRS, HTTP_RANGE_NUM_TRAILERS, HTTP_VERSION_MATCH,
-    HTTP_HEADER_TEST, HTTP_TRAILER_TEST, HTTP_RANGE_NUM_COOKIES, HTTP__MAX_RULE_OPTION };
+    HTTP_HEADER_TEST, HTTP_TRAILER_TEST, HTTP_RANGE_NUM_COOKIES, HTTP_RANGE_MAX_HEADER_LINE,
+    HTTP_RANGE_MAX_TRAILER_LINE, HTTP__MAX_RULE_OPTION };
 
 // Peg counts
 // This enum must remain synchronized with HttpModule::peg_names[] in http_tables.cc
index 71f9cba4a66f4042fbeaaf82791b6c8af83c998e..433525f11a83832403334beeb9226421f30ffbf0 100755 (executable)
@@ -319,6 +319,17 @@ int32_t HttpInspect::http_get_num_headers(Packet* p,
     return current_section->get_num_headers(buffer_info);
 }
 
+int32_t HttpInspect::http_get_max_header_line(Packet* p,
+    const HttpBufferInfo& buffer_info) const
+{
+    const HttpMsgSection* const current_section = HttpContextData::get_snapshot(p);
+
+    if (current_section == nullptr)
+        return STAT_NOT_PRESENT;
+
+    return current_section->get_max_header_line(buffer_info);
+}
+
 int32_t HttpInspect::http_get_num_cookies(Packet* p,
     const HttpBufferInfo& buffer_info) const
 {
index 10f4772b4c665ce4257b472a1c63e9e3d1e68744..93790e178a9ff244c8cf3cc8e0e329f40d7aac15 100644 (file)
@@ -52,6 +52,7 @@ public:
     const Field& http_get_param_buf(Cursor& c, snort::Packet* p,
         const HttpParam& param) const;
     int32_t http_get_num_headers(snort::Packet* p, const HttpBufferInfo& buffer_info) const;
+    int32_t http_get_max_header_line(snort::Packet* p, const HttpBufferInfo& buffer_info) const;
     int32_t http_get_num_cookies(snort::Packet* p, const HttpBufferInfo& buffer_info) const;
     HttpEnums::VersionId http_get_version_id(snort::Packet* p,
         const HttpBufferInfo& buffer_info) const;
index ee3ea1b2ebedf6a8dcedc464f761e11561f11b70..dcc689cd4a55bba2c60d2efa0e584e838e9f143a 100755 (executable)
@@ -117,6 +117,7 @@ void HttpMsgHeadShared::parse_header_block()
 {
     int32_t bytes_used = 0;
     num_headers = 0;
+    max_header_line = 0;
     int32_t num_seps;
 
     // The number of header lines in a message may be zero
@@ -131,6 +132,10 @@ void HttpMsgHeadShared::parse_header_block()
         assert(num_headers < session_data->num_head_lines[source_id]);
         const int32_t header_length = find_next_header(msg_text.start() + bytes_used,
             msg_text.length() - bytes_used, num_seps);
+        if (header_length >  max_header_line)
+        {
+            max_header_line = header_length;
+        }
         header_line[num_headers].set(header_length, msg_text.start() + bytes_used + num_seps);
         if (header_line[num_headers].length() > params->maximum_header_length)
         {
index 144aa97610e493e26d38d1502d2bc956a8284aac..d7ea2da2c093793685f615b05444cf61eb1448d2 100755 (executable)
@@ -60,6 +60,7 @@ public:
     uint64_t get_file_cache_index();
     const Field& get_content_disposition_filename();
     int32_t get_num_headers() const { return num_headers; }
+    int32_t get_max_header_line() const { return max_header_line; }
     int32_t get_content_type();
 
 protected:
@@ -77,6 +78,7 @@ protected:
     Field* header_line = nullptr;
     HttpEnums::HeaderId* header_name_id = nullptr;
     int32_t num_headers = HttpCommon::STAT_NOT_COMPUTE;
+    int32_t max_header_line = HttpCommon::STAT_NOT_COMPUTE;
 
 #ifdef REG_TEST
     void print_headers(FILE* output);
index 71afc0a294eaff8a66780b4e7a9eb995961a8a08..842c87eb7e79e0e175fae270826ea74090a38717 100644 (file)
@@ -163,7 +163,7 @@ const Field& HttpMsgSection::get_classic_buffer(unsigned id, uint64_t sub_id, ui
 
 const Field& HttpMsgSection::get_classic_buffer(const HttpBufferInfo& buf)
 {
-    // buffer_side replaces source_id for buffers that support the request option
+    // buffer_side replaces source_id for rule options that support the request option
     const SourceId buffer_side = (buf.form & FORM_REQUEST) ? SRC_CLIENT : source_id;
 
     switch (buf.type)
@@ -408,7 +408,7 @@ const Field& HttpMsgSection::get_param_buffer(Cursor& c, const HttpParam& param)
 
 int32_t HttpMsgSection::get_num_headers(const HttpBufferInfo& buf) const
 {
-    // buffer_side replaces source_id for buffers that support the request option
+    // buffer_side replaces source_id for rule options that support the request option
     const SourceId buffer_side = (buf.form & FORM_REQUEST) ? SRC_CLIENT : source_id;
 
     const HttpMsgHeadShared* const head = (buf.type == HTTP_RANGE_NUM_TRAILERS) ?
@@ -420,6 +420,20 @@ int32_t HttpMsgSection::get_num_headers(const HttpBufferInfo& buf) const
     return head->get_num_headers();
 }
 
+int32_t HttpMsgSection::get_max_header_line(const HttpBufferInfo& buf) const
+{
+    // buffer_side replaces source_id for rule options that support the request option
+    const SourceId buffer_side = (buf.form & FORM_REQUEST) ? SRC_CLIENT : source_id;
+
+    const HttpMsgHeadShared* const head = (buf.type == HTTP_RANGE_MAX_TRAILER_LINE) ?
+        (HttpMsgHeadShared*)trailer[buffer_side]:
+        (HttpMsgHeadShared*)header[buffer_side] ;
+    if (head == nullptr)
+        return HttpCommon::STAT_NO_SOURCE;
+
+    return head->get_max_header_line();
+}
+
 int32_t HttpMsgSection::get_num_cookies(const HttpBufferInfo& buf) const
 {
     // buffer_side replaces source_id for rule options that support the request option
@@ -434,7 +448,7 @@ int32_t HttpMsgSection::get_num_cookies(const HttpBufferInfo& buf) const
 
 VersionId HttpMsgSection::get_version_id(const HttpBufferInfo& buf) const
 {
-    // buffer_side replaces source_id for buffers that support the request option
+    // buffer_side replaces source_id for rule options that support the request option
     const SourceId buffer_side = (buf.form & FORM_REQUEST) ? SRC_CLIENT : source_id;
     HttpMsgStart* start = (buffer_side == SRC_CLIENT) ?
         (HttpMsgStart*)request : (HttpMsgStart*)status;
index 0c029062273298ad1aee0c84292322a543cfe108..bd34c9db7b6c36ae3b2233645595a5f3195b3400 100644 (file)
@@ -87,6 +87,7 @@ public:
 
     uint64_t get_transaction_id() { return trans_num; }
     int32_t get_num_headers(const HttpBufferInfo& buf) const;
+    int32_t get_max_header_line(const HttpBufferInfo& buf) const;
     int32_t get_num_cookies(const HttpBufferInfo& buf) const;
     HttpEnums::VersionId get_version_id(const HttpBufferInfo& buf) const;
 
index 5d2632a4693e82ff825ba47aaaf78a731e235b85..90d0e07f5c96b42f68d97f5c9cdff66d8f6b8a41 100644 (file)
@@ -101,35 +101,29 @@ IpsOption::EvalStatus HttpRangeIpsOption::eval(Cursor&, Packet* p)
 }
 
 //-------------------------------------------------------------------------
-// num_header_lines
+// max_header_line
 //-------------------------------------------------------------------------
 #undef IPS_OPT
-#define IPS_OPT "http_num_headers"
+#define IPS_OPT "http_max_header_line"
 #undef IPS_HELP
-#define IPS_HELP "rule option to perform range check on number of headers"
+#define IPS_HELP "rule option to perform range check on longest header line"
 
-static const Parameter http_num_hdrs_params[] =
+static const Parameter http_max_header_line_params[] =
 {
     { "~range", Parameter::PT_INTERVAL, "0:65535", nullptr,
-        "check that number of headers of current buffer are in given range" },
+        "check that longest line of current header is in given range" },
     { "request", Parameter::PT_IMPLIED, nullptr, nullptr,
         "match against the version from the request message even when examining the response" },
-    { "with_header", Parameter::PT_IMPLIED, nullptr, nullptr,
-        "this rule is limited to examining HTTP message headers" },
-    { "with_body", Parameter::PT_IMPLIED, nullptr, nullptr,
-        "parts of this rule examine HTTP message body" },
-    { "with_trailer", Parameter::PT_IMPLIED, nullptr, nullptr,
-        "parts of this rule examine HTTP message trailers" },
     { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
 };
 
-static Module* num_hdrs_mod_ctor()
+static Module* max_header_line_mod_ctor()
 {
-    return new HttpNumRuleOptModule<HTTP_RANGE_NUM_HDRS, IS_FLEX_HEADER>(IPS_OPT, IPS_HELP,
-        http_num_hdrs_params);
+    return new HttpNumRuleOptModule<HTTP_RANGE_MAX_HEADER_LINE, IS_FLEX_HEADER>(IPS_OPT, IPS_HELP,
+        http_max_header_line_params);
 }
 
-static const IpsApi num_headers_api =
+static const IpsApi max_header_line_api =
 {
     {
         PT_IPS_OPTION,
@@ -140,7 +134,7 @@ static const IpsApi num_headers_api =
         API_OPTIONS,
         IPS_OPT,
         IPS_HELP,
-        num_hdrs_mod_ctor,
+        max_header_line_mod_ctor,
         HttpRangeRuleOptModule::mod_dtor
     },
     OPT_TYPE_DETECTION,
@@ -149,26 +143,35 @@ static const IpsApi num_headers_api =
     nullptr,
     nullptr,
     nullptr,
-    HttpNumIpsOption<&HttpInspect::http_get_num_headers>::opt_ctor,
+    HttpNumIpsOption<&HttpInspect::http_get_max_header_line>::opt_ctor,
     HttpRangeIpsOption::opt_dtor,
     nullptr
 };
 
 //-------------------------------------------------------------------------
-// num_trailer_lines
+// max_trailer_line
 //-------------------------------------------------------------------------
 #undef IPS_OPT
-#define IPS_OPT "http_num_trailers"
+#define IPS_OPT "http_max_trailer_line"
 #undef IPS_HELP
-#define IPS_HELP "rule option to perform range check on number of trailers"
+#define IPS_HELP "rule option to perform range check on longest trailer line"
 
-static Module* num_trailers_mod_ctor()
+static const Parameter http_max_trailer_line_params[] =
 {
-    return new HttpNumRuleOptModule<HTTP_RANGE_NUM_TRAILERS, IS_TRAILER>(IPS_OPT, IPS_HELP,
-        http_num_hdrs_params);
+    { "~range", Parameter::PT_INTERVAL, "0:65535", nullptr,
+        "check that longest line of current trailer is in given range" },
+    { "request", Parameter::PT_IMPLIED, nullptr, nullptr,
+        "match against the version from the request message even when examining the response" },
+    { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
+};
+
+static Module* max_trailer_line_mod_ctor()
+{
+    return new HttpNumRuleOptModule<HTTP_RANGE_MAX_TRAILER_LINE, IS_TRAILER>(IPS_OPT, IPS_HELP,
+        http_max_trailer_line_params);
 }
 
-static const IpsApi num_trailers_api =
+static const IpsApi max_trailer_line_api =
 {
     {
         PT_IPS_OPTION,
@@ -179,7 +182,7 @@ static const IpsApi num_trailers_api =
         API_OPTIONS,
         IPS_OPT,
         IPS_HELP,
-        num_trailers_mod_ctor,
+        max_trailer_line_mod_ctor,
         HttpRangeRuleOptModule::mod_dtor
     },
     OPT_TYPE_DETECTION,
@@ -188,7 +191,7 @@ static const IpsApi num_trailers_api =
     nullptr,
     nullptr,
     nullptr,
-    HttpNumIpsOption<&HttpInspect::http_get_num_headers>::opt_ctor,
+    HttpNumIpsOption<&HttpInspect::http_get_max_header_line>::opt_ctor,
     HttpRangeIpsOption::opt_dtor,
     nullptr
 };
@@ -241,9 +244,104 @@ static const IpsApi num_cookies_api =
     nullptr
 };
 
+//-------------------------------------------------------------------------
+// num_header_lines
+//-------------------------------------------------------------------------
+#undef IPS_OPT
+#define IPS_OPT "http_num_headers"
+#undef IPS_HELP
+#define IPS_HELP "rule option to perform range check on number of headers"
+
+static const Parameter http_num_hdrs_params[] =
+{
+    { "~range", Parameter::PT_INTERVAL, "0:65535", nullptr,
+        "check that number of headers of current buffer are in given range" },
+    { "request", Parameter::PT_IMPLIED, nullptr, nullptr,
+        "match against the version from the request message even when examining the response" },
+    { "with_header", Parameter::PT_IMPLIED, nullptr, nullptr,
+        "this rule is limited to examining HTTP message headers" },
+    { "with_body", Parameter::PT_IMPLIED, nullptr, nullptr,
+        "parts of this rule examine HTTP message body" },
+    { "with_trailer", Parameter::PT_IMPLIED, nullptr, nullptr,
+        "parts of this rule examine HTTP message trailers" },
+    { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
+};
+
+static Module* num_hdrs_mod_ctor()
+{
+    return new HttpNumRuleOptModule<HTTP_RANGE_NUM_HDRS, IS_FLEX_HEADER>(IPS_OPT, IPS_HELP,
+        http_num_hdrs_params);
+}
+
+static const IpsApi num_headers_api =
+{
+    {
+        PT_IPS_OPTION,
+        sizeof(IpsApi),
+        IPSAPI_VERSION,
+        1,
+        API_RESERVED,
+        API_OPTIONS,
+        IPS_OPT,
+        IPS_HELP,
+        num_hdrs_mod_ctor,
+        HttpRangeRuleOptModule::mod_dtor
+    },
+    OPT_TYPE_DETECTION,
+    0, PROTO_BIT__TCP,
+    nullptr,
+    nullptr,
+    nullptr,
+    nullptr,
+    HttpNumIpsOption<&HttpInspect::http_get_num_headers>::opt_ctor,
+    HttpRangeIpsOption::opt_dtor,
+    nullptr
+};
+
+//-------------------------------------------------------------------------
+// num_trailer_lines
+//-------------------------------------------------------------------------
+#undef IPS_OPT
+#define IPS_OPT "http_num_trailers"
+#undef IPS_HELP
+#define IPS_HELP "rule option to perform range check on number of trailers"
+
+static Module* num_trailers_mod_ctor()
+{
+    return new HttpNumRuleOptModule<HTTP_RANGE_NUM_TRAILERS, IS_TRAILER>(IPS_OPT, IPS_HELP,
+        http_num_hdrs_params);
+}
+
+static const IpsApi num_trailers_api =
+{
+    {
+        PT_IPS_OPTION,
+        sizeof(IpsApi),
+        IPSAPI_VERSION,
+        1,
+        API_RESERVED,
+        API_OPTIONS,
+        IPS_OPT,
+        IPS_HELP,
+        num_trailers_mod_ctor,
+        HttpRangeRuleOptModule::mod_dtor
+    },
+    OPT_TYPE_DETECTION,
+    0, PROTO_BIT__TCP,
+    nullptr,
+    nullptr,
+    nullptr,
+    nullptr,
+    HttpNumIpsOption<&HttpInspect::http_get_num_headers>::opt_ctor,
+    HttpRangeIpsOption::opt_dtor,
+    nullptr
+};
+
 //-------------------------------------------------------------------------
 // plugins
 //-------------------------------------------------------------------------
+const BaseApi* ips_http_max_header_line = &max_header_line_api.base;
+const BaseApi* ips_http_max_trailer_line = &max_trailer_line_api.base;
+const BaseApi* ips_http_num_cookies = &num_cookies_api.base;
 const BaseApi* ips_http_num_headers = &num_headers_api.base;
 const BaseApi* ips_http_num_trailers = &num_trailers_api.base;
-const BaseApi* ips_http_num_cookies = &num_cookies_api.base;