]> git.ipfire.org Git - thirdparty/snort3.git/commitdiff
Pull request #3270: US 727968: http_inspect: refactor HttpIpsOption
authorTom Peters (thopeter) <thopeter@cisco.com>
Tue, 22 Feb 2022 23:04:21 +0000 (23:04 +0000)
committerTom Peters (thopeter) <thopeter@cisco.com>
Tue, 22 Feb 2022 23:04:21 +0000 (23:04 +0000)
Merge in SNORT/snort3 from ~MDAGON/snort3:refactor_ips to master

Squashed commit of the following:

commit 2791042eff639fe3d50139a9b63396841ee1a862
Author: Maya Dagon <mdagon@cisco.com>
Date:   Thu Feb 10 17:26:51 2022 -0500

    http_inspect: refactor rule options

20 files changed:
doc/user/http_inspect.txt
src/service_inspectors/http_inspect/CMakeLists.txt
src/service_inspectors/http_inspect/dev_notes.txt
src/service_inspectors/http_inspect/http_buffer_info.cc
src/service_inspectors/http_inspect/http_buffer_info.h
src/service_inspectors/http_inspect/http_inspect.cc
src/service_inspectors/http_inspect/http_inspect.h
src/service_inspectors/http_inspect/http_msg_section.cc
src/service_inspectors/http_inspect/http_msg_section.h
src/service_inspectors/http_inspect/http_msg_start.h
src/service_inspectors/http_inspect/ips_http.cc
src/service_inspectors/http_inspect/ips_http.h
src/service_inspectors/http_inspect/ips_http_buffer.cc [new file with mode: 0644]
src/service_inspectors/http_inspect/ips_http_buffer.h [new file with mode: 0644]
src/service_inspectors/http_inspect/ips_http_num_hdrs.cc [new file with mode: 0644]
src/service_inspectors/http_inspect/ips_http_num_hdrs.h [new file with mode: 0644]
src/service_inspectors/http_inspect/ips_http_param.cc [new file with mode: 0644]
src/service_inspectors/http_inspect/ips_http_param.h [new file with mode: 0644]
src/service_inspectors/http_inspect/ips_http_version.cc [new file with mode: 0644]
src/service_inspectors/http_inspect/ips_http_version.h [new file with mode: 0644]

index d47ed264101aa413bea80033c28d0ab48cbf82b1..107e26029d5f58c8f210bb2c4df397e0a8ad6b6f 100755 (executable)
@@ -685,7 +685,7 @@ The vba_data will contain the decompressed Visual Basic for Applications
 (vba) macro data embedded in MS office files. It requires decompress_zip
 and decompress_vba options enabled.
 
-===== num_headers and num_trailers
+===== http_num_headers and http_num_trailers
 
 These rule options are used to check the number of headers and
 trailers, respectively. Checks available: equal to "=" or just value,
index d4972a0010e675aa9f695eb8f80e59439e794075..0a151aac056a8d6aa56069a29a2b7c00f8135f3d 100644 (file)
@@ -72,6 +72,14 @@ set (FILE_LIST
     http_event.h
     http_js_norm.cc
     http_js_norm.h
+    ips_http_buffer.cc
+    ips_http_buffer.h
+    ips_http_num_hdrs.cc
+    ips_http_num_hdrs.h
+    ips_http_param.cc
+    ips_http_param.h
+    ips_http_version.cc
+    ips_http_version.h
 )
 
 #if (STATIC_INSPECTORS)
index 802f258265275867acd2ee5fd029c3f67a1472f2..aa451bae39da7d60b47dfea56967fd7eccf66cf9 100755 (executable)
@@ -336,6 +336,12 @@ generated and processing continues normally. If there is no separator at all tha
 Then we return to #1 as the next chunk begins. In particular extra separators beyond the two
 expected are attributed to the beginning of the next chunk.
 
+Rule options:
+
+HttpIpsOption is the base class for http rule options. It supports the commonly used parameters: 
+field, request, with_body, with_header and with_trailer. HttpBufferIpsOption is a rule option that 
+sets a buffer. It implements most of the rule options.
+
 Test tool usage instructions:
 
 The HI test tool consists of two features. test_output provides extensive information about the
index fdb5f97cb36959aa29440d9d8d11c08d288b2e40..c8443981c79c1be6e806f00dbc42e7a2ae3fb7c3 100644 (file)
@@ -33,37 +33,16 @@ uint32_t HttpBufferInfo::hash() const
     uint32_t c = sub_id & 0xFFFFFFFF;
     uint32_t d = form >> 32;
     uint32_t e = form & 0xFFFFFFFF;
-    uint32_t f = 0;
     mix(a,b,c);
-    if (param)
-        f = param->is_nocase() ? 1 : 0;
-    mix(d,e,f);
-    mix(a,c,f);
-    if (param)
-        mix_str(a,c,f,param->c_str(),param->length());
-    finalize(a,c,f);
-    return f;
+    mix(d,e,a);
+    finalize(d,e,a);
+    return d;
 }
 
 bool HttpBufferInfo::operator==(const HttpBufferInfo& rhs) const
 {
-    bool param_match = false;
-
-    if (param && rhs.param)
-    {
-        HttpParam& lhs_param = *param;
-        HttpParam& rhs_param = *rhs.param;
-
-        param_match = (lhs_param == rhs_param);
-    }
-    else if (!param && !rhs.param)
-    {
-        param_match = true;
-    }
-
-    return type == rhs.type &&
-        sub_id == rhs.sub_id &&
-        form == rhs.form &&
-        param_match;
+    return (type == rhs.type &&
+         sub_id == rhs.sub_id &&
+         form == rhs.form);
 }
 
index df7df05256484eb1c3b7bf8dafe82fd48f7dfa9c..cda4a2823a127ae9d992a10c1f9287678de3a59f 100644 (file)
 #ifndef HTTP_BUFFER_INFO_H
 #define HTTP_BUFFER_INFO_H
 
-#include <string>
-
-#include "http_enum.h"
-#include "http_param.h"
-
 class HttpBufferInfo
 {
 public:
     HttpBufferInfo(unsigned type_, uint64_t sub_id_ = 0, uint64_t form_ = 0)
         : type(type_), sub_id(sub_id_), form(form_) {}
 
-    HttpBufferInfo(unsigned type_, uint64_t sub_id_, uint64_t form_,
-        const std::string& param_str, bool nocase)
-        : type(type_), sub_id(sub_id_), form(form_)
-    {
-        if (param_str.length() > 0)
-            param = new HttpParam(param_str, nocase);
-    }
-
-    ~HttpBufferInfo()
-    { delete param; }
-
     uint32_t hash() const;
 
     bool operator==(const HttpBufferInfo& rhs) const;
 
 public:
-    unsigned type;
-    uint64_t sub_id;
-    uint64_t form;
-    HttpParam* param = nullptr;
+    const unsigned type;
+    const uint64_t sub_id;
+    const uint64_t form;
 };
 
 #endif
index 6cbde96c96533cf7ec9e0910b6989bfb56f82f2a..fbb373d333690dbb88f196a42ac1e608786e2b6a 100755 (executable)
@@ -48,6 +48,7 @@
 #include "http_msg_request.h"
 #include "http_msg_status.h"
 #include "http_msg_trailer.h"
+#include "http_param.h"
 #include "http_test_manager.h"
 
 using namespace snort;
@@ -261,10 +262,9 @@ bool HttpInspect::get_buf(InspectionBuffer::Type ibt, Packet* p, InspectionBuffe
 
 bool HttpInspect::get_buf(unsigned id, Packet* p, InspectionBuffer& b)
 {
-    Cursor c;
     HttpBufferInfo buffer_info(id);
 
-    const Field& http_buffer = http_get_buf(c, p, buffer_info);
+    const Field& http_buffer = http_get_buf(p, buffer_info);
 
     if (http_buffer.length() <= 0)
         return false;
@@ -274,15 +274,25 @@ bool HttpInspect::get_buf(unsigned id, Packet* p, InspectionBuffer& b)
     return true;
 }
 
-const Field& HttpInspect::http_get_buf(Cursor& c, Packet* p,
-    const HttpBufferInfo& buffer_info) const
+const Field& HttpInspect::http_get_buf(Packet* p, const HttpBufferInfo& buffer_info) const
+{
+    HttpMsgSection* const current_section = HttpContextData::get_snapshot(p);
+
+    if (current_section == nullptr)
+        return Field::FIELD_NULL;
+
+    return current_section->get_classic_buffer(buffer_info);
+}
+
+const Field& HttpInspect::http_get_param_buf(Cursor& c, Packet* p,
+    const HttpParam& param) const
 {
     HttpMsgSection* const current_section = HttpContextData::get_snapshot(p);
 
     if (current_section == nullptr)
         return Field::FIELD_NULL;
 
-    return current_section->get_classic_buffer(c, buffer_info);
+    return current_section->get_param_buffer(c, param);
 }
 
 int32_t HttpInspect::http_get_num_headers(Packet* p,
@@ -296,14 +306,15 @@ int32_t HttpInspect::http_get_num_headers(Packet* p,
     return current_section->get_num_headers(buffer_info);
 }
 
-VersionId HttpInspect::http_get_version_id(Packet* p) const
+VersionId HttpInspect::http_get_version_id(Packet* p,
+    const HttpBufferInfo& buffer_info) const
 {
     const HttpMsgSection* const current_section = HttpContextData::get_snapshot(p);
 
     if (current_section == nullptr)
         return VERS__NOT_PRESENT;
 
-    return current_section->get_version_id();
+    return current_section->get_version_id(buffer_info);
 }
 
 bool HttpInspect::get_fp_buf(InspectionBuffer::Type ibt, Packet* p, InspectionBuffer& b)
index 0f80b421fdeff89394385429e99092fbdb358cd1..44021533a30fad79642ab01c2405ea0fe37f0c11 100644 (file)
@@ -37,6 +37,7 @@
 #include "http_stream_splitter.h"
 
 class HttpApi;
+class HttpParam;
 
 class HttpInspect : public snort::Inspector
 {
@@ -47,10 +48,12 @@ public:
     bool get_buf(snort::InspectionBuffer::Type ibt, snort::Packet* p,
         snort::InspectionBuffer& b) override;
     bool get_buf(unsigned id, snort::Packet* p, snort::InspectionBuffer& b) override;
-    const Field& http_get_buf(Cursor& c, snort::Packet* p,
-        const HttpBufferInfo& buffer_info) const;
+    const Field& http_get_buf(snort::Packet* p, const HttpBufferInfo& buffer_info) const;
+    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;
-    HttpEnums::VersionId http_get_version_id(snort::Packet* p) const;
+    HttpEnums::VersionId http_get_version_id(snort::Packet* p,
+        const HttpBufferInfo& buffer_info) const;
     bool get_fp_buf(snort::InspectionBuffer::Type ibt, snort::Packet* p,
         snort::InspectionBuffer& b) override;
     bool configure(snort::SnortConfig*) override;
index 0599c8043036b115f23e547a7af4886f31acde87..486539b8ba3e99324055155e8734c164f03c212a 100644 (file)
@@ -155,13 +155,12 @@ const Field& HttpMsgSection::classic_normalize(const Field& raw, Field& norm,
 
 const Field& HttpMsgSection::get_classic_buffer(unsigned id, uint64_t sub_id, uint64_t form)
 {
-    Cursor c;
     HttpBufferInfo buffer_info(id, sub_id, form);
 
-    return get_classic_buffer(c, buffer_info);
+    return get_classic_buffer(buffer_info);
 }
 
-const Field& HttpMsgSection::get_classic_buffer(Cursor& c, const HttpBufferInfo& buf)
+const Field& HttpMsgSection::get_classic_buffer(const HttpBufferInfo& buf)
 {
     // buffer_side replaces source_id for buffers that support the request option
     const SourceId buffer_side = (buf.form & FORM_REQUEST) ? SRC_CLIENT : source_id;
@@ -197,120 +196,6 @@ const Field& HttpMsgSection::get_classic_buffer(Cursor& c, const HttpBufferInfo&
       {
         return (request != nullptr) ? request->get_method() : Field::FIELD_NULL;
       }
-    case HTTP_BUFFER_PARAM:
-      {
-        if (buf.param == nullptr || request == nullptr)
-            return Field::FIELD_NULL;
-
-        HttpUri* query = request->get_http_uri();
-        HttpMsgBody* body = (source_id == SRC_CLIENT) ? get_body() : nullptr;
-
-        if (query == nullptr && body == nullptr)
-            return Field::FIELD_NULL;
-
-        const HttpParaList::UriParam& uri_config = params->uri_param;
-
-        ParameterMap& query_params = request->get_query_params();
-        ParameterMap& body_params = request->get_body_params();
-
-        // cache lookup
-        HttpParam& param = *buf.param;
-        ParameterData& query_data = query_params[param.str_upper()];
-        ParameterData& body_data = body_params[param.str_upper()];
-
-        if (!query_data.parsed && query != nullptr)
-        {
-            // query has not been parsed for this parameter
-            const Field& rq = query->get_query();
-            const Field& nq = query->get_norm_query();
-
-            if (rq.length() > 0 && nq.length() > 0)
-            {
-                HttpQueryParser parser(rq.start(), rq.length(),
-                    nq.start(), nq.length(), uri_config,
-                    session_data, source_id);
-
-                parser.parse(param, query_data);
-                query_data.parsed = true;
-            }
-        }
-
-        if (!body_data.parsed && body != nullptr)
-        {
-            // body has not been parsed for this parameter
-            const Field& rb = body->get_detect_data();
-            const Field& nb = body->get_classic_client_body();
-
-            if (rb.length() > 0 && nb.length() > 0 && body->is_first())
-            {
-                HttpQueryParser parser(rb.start(), rb.length(),
-                    nb.start(), nb.length(), uri_config,
-                    session_data, source_id);
-
-                parser.parse(param, body_data);
-                body_data.parsed = true;
-            }
-        }
-
-        KeyValueVec& query_kv = query_data.kv_vec;
-        KeyValueVec& body_kv = body_data.kv_vec;
-
-        unsigned num_query_params = query_kv.size();
-        unsigned num_body_params = body_kv.size();
-
-        if (num_query_params == 0 && num_body_params == 0)
-            return Field::FIELD_NULL;
-
-        // get data stored on the cursor
-        HttpCursorData* cd = (HttpCursorData*)c.get_data(HttpCursorData::id);
-
-        if (!cd)
-        {
-            cd = new HttpCursorData();
-            c.set_data(cd);
-        }
-
-        // save the parameter count on the cursor
-        cd->num_query_params = num_query_params;
-        cd->num_body_params = num_body_params;
-
-        unsigned& query_index = cd->query_index;
-        unsigned& body_index = cd->body_index;
-
-        while (query_index < num_query_params)
-        {
-            KeyValue* fields = query_kv[query_index];
-
-            Field& key = fields->key;
-            Field& value = fields->value;
-
-            ++query_index;
-
-            if (param.is_nocase())
-                return value;
-
-            if (!memcmp(key.start(), param.c_str(), key.length()))
-                return value;
-        }
-
-        while (body_index < num_body_params)
-        {
-            KeyValue* fields = body_kv[body_index];
-
-            Field& key = fields->key;
-            Field& value = fields->value;
-
-            ++body_index;
-
-            if (param.is_nocase())
-                return value;
-
-            if (!memcmp(key.start(), param.c_str(), key.length()))
-                return value;
-        }
-
-        return Field::FIELD_NULL;
-      }
     case HTTP_BUFFER_RAW_BODY:
       {
         return (get_body() != nullptr) ? get_body()->msg_text : Field::FIELD_NULL;
@@ -404,6 +289,120 @@ const Field& HttpMsgSection::get_classic_buffer(Cursor& c, const HttpBufferInfo&
     }
 }
 
+const Field& HttpMsgSection::get_param_buffer(Cursor& c, const HttpParam& param)
+{
+    if (request == nullptr)
+        return Field::FIELD_NULL;
+
+    HttpUri* query = request->get_http_uri();
+    HttpMsgBody* body = (source_id == SRC_CLIENT) ? get_body() : nullptr;
+
+    if (query == nullptr && body == nullptr)
+        return Field::FIELD_NULL;
+
+    const HttpParaList::UriParam& uri_config = params->uri_param;
+
+    ParameterMap& query_params = request->get_query_params();
+    ParameterMap& body_params = request->get_body_params();
+
+    // cache lookup
+    ParameterData& query_data = query_params[param.str_upper()];
+    ParameterData& body_data = body_params[param.str_upper()];
+
+    if (!query_data.parsed && query != nullptr)
+    {
+        // query has not been parsed for this parameter
+        const Field& rq = query->get_query();
+        const Field& nq = query->get_norm_query();
+
+        if (rq.length() > 0 && nq.length() > 0)
+        {
+            HttpQueryParser parser(rq.start(), rq.length(),
+                nq.start(), nq.length(), uri_config,
+                session_data, source_id);
+
+            parser.parse(param, query_data);
+            query_data.parsed = true;
+        }
+    }
+
+    if (!body_data.parsed && body != nullptr)
+    {
+        // body has not been parsed for this parameter
+        const Field& rb = body->get_detect_data();
+        const Field& nb = body->get_classic_client_body();
+
+        if (rb.length() > 0 && nb.length() > 0 && body->is_first())
+        {
+            HttpQueryParser parser(rb.start(), rb.length(),
+                nb.start(), nb.length(), uri_config,
+                session_data, source_id);
+
+            parser.parse(param, body_data);
+            body_data.parsed = true;
+        }
+    }
+
+    KeyValueVec& query_kv = query_data.kv_vec;
+    KeyValueVec& body_kv = body_data.kv_vec;
+
+    unsigned num_query_params = query_kv.size();
+    unsigned num_body_params = body_kv.size();
+
+    if (num_query_params == 0 && num_body_params == 0)
+        return Field::FIELD_NULL;
+
+    // get data stored on the cursor
+    HttpCursorData* cd = (HttpCursorData*)c.get_data(HttpCursorData::id);
+
+    if (!cd)
+    {
+        cd = new HttpCursorData();
+        c.set_data(cd);
+    }
+
+    // save the parameter count on the cursor
+    cd->num_query_params = num_query_params;
+    cd->num_body_params = num_body_params;
+
+    unsigned& query_index = cd->query_index;
+    unsigned& body_index = cd->body_index;
+
+    while (query_index < num_query_params)
+    {
+        KeyValue* fields = query_kv[query_index];
+
+        Field& key = fields->key;
+        Field& value = fields->value;
+
+        ++query_index;
+
+        if (param.is_nocase())
+            return value;
+
+        if (!memcmp(key.start(), param.c_str(), key.length()))
+            return value;
+    }
+
+    while (body_index < num_body_params)
+    {
+        KeyValue* fields = body_kv[body_index];
+
+        Field& key = fields->key;
+        Field& value = fields->value;
+
+        ++body_index;
+
+        if (param.is_nocase())
+            return value;
+
+        if (!memcmp(key.start(), param.c_str(), key.length()))
+            return value;
+    }
+
+    return Field::FIELD_NULL;
+}
+
 int32_t HttpMsgSection::get_num_headers(const HttpBufferInfo& buf) const
 {
     // buffer_side replaces source_id for buffers that support the request option
@@ -418,6 +417,16 @@ int32_t HttpMsgSection::get_num_headers(const HttpBufferInfo& buf) const
     return head->get_num_headers();
 }
 
+VersionId HttpMsgSection::get_version_id(const HttpBufferInfo& buf) const
+{
+    // buffer_side replaces source_id for buffers 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;
+
+    return (start != nullptr) ? start->get_version_id() : VERS__NOT_PRESENT;
+}
+
 void HttpMsgSection::get_related_sections()
 {
     // When a message section is created these relationships become fixed so we make copies for
index 838ff75b50921ef091b8ff98f485e4fd350cb604..58d6c39f7f25192d509e9b129e81c1208405027b 100644 (file)
@@ -30,6 +30,7 @@
 #include "http_field.h"
 #include "http_flow_data.h"
 #include "http_module.h"
+#include "http_param.h"
 #include "http_transaction.h"
 
 //-------------------------------------------------------------------------
@@ -67,7 +68,8 @@ public:
     virtual void update_flow() = 0;
 
     const Field& get_classic_buffer(unsigned id, uint64_t sub_id, uint64_t form);
-    const Field& get_classic_buffer(Cursor& c, const HttpBufferInfo& buf);
+    const Field& get_classic_buffer(const HttpBufferInfo& buf);
+    const Field& get_param_buffer(Cursor& c, const HttpParam& param);
 
     HttpEnums::MethodId get_method_id() const { return method_id; }
 
@@ -81,7 +83,7 @@ public:
 
     uint64_t get_transaction_id() { return trans_num; }
     int32_t get_num_headers(const HttpBufferInfo& buf) const;
-    HttpEnums::VersionId get_version_id() const { return version_id; }
+    HttpEnums::VersionId get_version_id(const HttpBufferInfo& buf) const;
 
     HttpMsgSection* next = nullptr;
 
index ceabd6a633d749be4d2b3e8def782e6e5dff57ac..6d046292faa349ce5f4db102f858abc09fdecc93 100644 (file)
@@ -34,6 +34,7 @@ public:
     void analyze() override;
     bool detection_required() const override { return false; }
     const Field& get_version() const { return version; }
+    HttpEnums::VersionId get_version_id() const { return version_id; }
 
 protected:
     HttpMsgStart(const uint8_t* buffer, const uint16_t buf_size, HttpFlowData* session_data_,
index 49898ab542f36c27c706e4903c926168571e63f3..7408ad05efd6291d4fadc42b2d3747bfa2af458e 100644 (file)
 #include "http_flow_data.h"
 #include "http_inspect.h"
 #include "http_msg_head_shared.h"
-#include "http_param.h"
 
 using namespace snort;
 using namespace HttpCommon;
 using namespace HttpEnums;
 
-THREAD_LOCAL std::array<ProfileStats, PSI_MAX> HttpRuleOptModule::http_ps;
-
-const std::string hdrs_num_range = "0:" + std::to_string(HttpMsgHeadShared::MAX_HEADERS);
 
 bool HttpRuleOptModule::begin(const char*, int, SnortConfig*)
 {
     para_list.reset();
     sub_id = 0;
     form = 0;
-    switch (rule_opt_index)
-    {
-    case HTTP_BUFFER_RAW_STATUS:
-    case HTTP_BUFFER_STAT_CODE:
-    case HTTP_BUFFER_STAT_MSG:
-        inspect_section = IS_HEADER;
-        break;
-    case HTTP_BUFFER_COOKIE:
-    case HTTP_BUFFER_HEADER:
-    case HTTP_BUFFER_METHOD:
-    case HTTP_BUFFER_PARAM:
-    case HTTP_BUFFER_RAW_COOKIE:
-    case HTTP_BUFFER_RAW_HEADER:
-    case HTTP_BUFFER_RAW_REQUEST:
-    case HTTP_BUFFER_RAW_URI:
-    case HTTP_BUFFER_TRUE_IP:
-    case HTTP_BUFFER_URI:
-    case HTTP_BUFFER_VERSION:
-    case HTTP_RANGE_NUM_HDRS:
-    case HTTP_VERSION_MATCH:
-        inspect_section = IS_FLEX_HEADER;
-        break;
-    case HTTP_BUFFER_CLIENT_BODY:
-    case HTTP_BUFFER_RAW_BODY:
-    case BUFFER_JS_DATA:
-        inspect_section = IS_BODY;
-        break;
-    case HTTP_BUFFER_RAW_TRAILER:
-    case HTTP_BUFFER_TRAILER:
-    case HTTP_RANGE_NUM_TRAILERS:
-        inspect_section = IS_TRAILER;
-        break;
-    default:
-        assert(false);
-    }
-    return true;
-}
-
-static const std::map <std::string, VersionId> VersionStrToEnum =
-{
-    { "malformed", VERS__PROBLEMATIC },
-    { "other", VERS__OTHER },
-    { "1.0", VERS_1_0 },
-    { "1.1", VERS_1_1 },
-    { "2.0", VERS_2_0 },
-    { "0.9", VERS_0_9 }
-};
-
-bool HttpRuleOptModule::parse_version_list(Value& v)
-{
-    v.set_first_token();
-    std::string tok;
-
-    while ( v.get_next_token(tok) )
-    {
-        if (tok[0] == '"')
-            tok.erase(0, 1);
-
-        if (tok.length() == 0)
-            continue;
-
-        if (tok[tok.length()-1] == '"')
-            tok.erase(tok.length()-1, 1);
-
-        auto iter = VersionStrToEnum.find(tok);
-        if (iter == VersionStrToEnum.end())
-        {
-            ParseError("Unrecognized version %s\n", tok.c_str());
-            return false;
-        }
-
-        para_list.version_flags[iter->second - VERS__MIN] = true;
-    }
+    is_trailer_opt = false;
     return true;
 }
 
@@ -145,17 +69,6 @@ bool HttpRuleOptModule::set(const char*, Value& v, SnortConfig*)
         if (sub_id == STAT_OTHER)
             ParseError("Unrecognized header field name");
     }
-    else if (v.is("~param"))
-    {
-        std::string bc = v.get_string();
-        bool negated = false;
-        if (!parse_byte_code(bc.c_str(), negated, para_list.param) or negated)
-            ParseError("Invalid http_param");
-    }
-    else if (v.is("nocase"))
-    {
-        para_list.nocase = true;
-    }
     else if (v.is("request"))
     {
         para_list.request = true;
@@ -176,44 +89,6 @@ bool HttpRuleOptModule::set(const char*, Value& v, SnortConfig*)
         para_list.with_trailer = true;
         inspect_section = IS_TRAILER;
     }
-    else if (v.is("scheme"))
-    {
-        para_list.scheme = true;
-        sub_id = UC_SCHEME;
-    }
-    else if (v.is("host"))
-    {
-        para_list.host = true;
-        sub_id = UC_HOST;
-    }
-    else if (v.is("port"))
-    {
-        para_list.port = true;
-        sub_id = UC_PORT;
-    }
-    else if (v.is("path"))
-    {
-        para_list.path = true;
-        sub_id = UC_PATH;
-    }
-    else if (v.is("query"))
-    {
-        para_list.query = true;
-        sub_id = UC_QUERY;
-    }
-    else if (v.is("fragment"))
-    {
-        para_list.fragment = true;
-        sub_id = UC_FRAGMENT;
-    }
-    else if (v.is("~range"))
-    {
-        return para_list.range.validate(v.get_string(), hdrs_num_range.c_str());
-    }
-    else if (v.is("~version_list"))
-    {
-        return parse_version_list(v);
-    }
     return true;
 }
 
@@ -222,35 +97,19 @@ bool HttpRuleOptModule::end(const char*, int, SnortConfig*)
     // Check for option conflicts
     if (para_list.with_header + para_list.with_body + para_list.with_trailer > 1)
         ParseError("Only specify one with_ option. Use the one that happens last.");
-    if (((rule_opt_index == HTTP_BUFFER_TRAILER) || (rule_opt_index == HTTP_BUFFER_RAW_TRAILER) || (rule_opt_index == HTTP_RANGE_NUM_TRAILERS)) &&
-        (para_list.with_header || para_list.with_body) &&
+    if ( is_trailer_opt && (para_list.with_header || para_list.with_body) &&
         !para_list.request)
         ParseError("Trailers with with_ option must also specify request");
-    if (para_list.scheme + para_list.host + para_list.port + para_list.path + para_list.query +
-          para_list.fragment > 1)
-        ParseError("Only specify one part of the URI");
-    if (rule_opt_index == HTTP_BUFFER_PARAM && para_list.param.length() == 0)
-        ParseError("Specify parameter name");
     return true;
 }
 
 void HttpRuleOptModule::HttpRuleParaList::reset()
 {
     field.clear();
-    param.clear();
-    nocase = false;
     request = false;
     with_header = false;
     with_body = false;
     with_trailer = false;
-    scheme = false;
-    host = false;
-    port = false;
-    path = false;
-    query = false;
-    fragment = false;
-    range.init();
-    version_flags = 0;
 }
 
 uint32_t HttpIpsOption::hash() const
@@ -259,8 +118,6 @@ uint32_t HttpIpsOption::hash() const
     uint32_t b = (uint32_t)inspect_section;
     uint32_t c = buffer_info.hash();
     mix(a,b,c);
-    a += range.hash();
-    b += (uint32_t)version_flags.to_ulong();
     finalize(a,b,c);
     return c;
 }
@@ -270,39 +127,14 @@ bool HttpIpsOption::operator==(const IpsOption& ips) const
     const HttpIpsOption& hio = static_cast<const HttpIpsOption&>(ips);
     return IpsOption::operator==(ips) &&
            inspect_section == hio.inspect_section &&
-           buffer_info == hio.buffer_info &&
-           range == hio.range &&
-           version_flags == hio.version_flags;
-}
-
-bool HttpIpsOption::retry(Cursor& current_cursor, const Cursor&)
-{
-    if (buffer_info.type == HTTP_BUFFER_PARAM)
-    {
-        HttpCursorData* cd = (HttpCursorData*)current_cursor.get_data(HttpCursorData::id);
-
-        if (cd)
-            return cd->retry();
-    }
-    return false;
-}
-
-IpsOption::EvalStatus HttpIpsOption::eval_version_match(Packet* p, const HttpInspect* hi)
-{
-    const VersionId version = hi->http_get_version_id(p);
-
-    if (version_flags[version - HttpEnums::VERS__MIN])
-        return MATCH;
-
-    return NO_MATCH;
+           buffer_info == hio.buffer_info;
 }
 
-IpsOption::EvalStatus HttpIpsOption::eval(Cursor& c, Packet* p)
+// Verify inspect_section matches. If it does get inspector pointer.
+HttpInspect const* HttpIpsOption::eval_helper(Packet* p)
 {
-    RuleProfile profile(HttpRuleOptModule::http_ps[psi]);
-
     if (!p->flow || !p->flow->gadget || (HttpInspect::get_latest_is(p) == IS_NONE))
-        return NO_MATCH;
+        return nullptr;
 
     const bool section_match =
         (HttpInspect::get_latest_is(p) == inspect_section) ||
@@ -310,7 +142,7 @@ IpsOption::EvalStatus HttpIpsOption::eval(Cursor& c, Packet* p)
         ((HttpInspect::get_latest_is(p) == IS_FIRST_BODY) && (inspect_section == IS_BODY)) ||
         ((HttpInspect::get_latest_src(p) == SRC_CLIENT) && (inspect_section == IS_FLEX_HEADER));
     if (!section_match)
-        return NO_MATCH;
+        return nullptr;
 
     const Http2FlowData* const h2i_flow_data =
         (Http2FlowData*)p->flow->get_flow_data(Http2FlowData::inspector_id);
@@ -318,1170 +150,6 @@ IpsOption::EvalStatus HttpIpsOption::eval(Cursor& c, Packet* p)
     const HttpInspect* const hi = (h2i_flow_data != nullptr) ?
         (HttpInspect*)(p->flow->assistant_gadget) : (HttpInspect*)(p->flow->gadget);
 
-    if (buffer_info.type <= HTTP__BUFFER_MAX)
-    {
-        const Field& http_buffer = hi->http_get_buf(c, p, buffer_info);
-
-        if (http_buffer.length() <= 0)
-            return NO_MATCH;
-
-        c.set(key, http_buffer.start(), http_buffer.length());
-
-        return MATCH;
-    }
-    else if (buffer_info.type == HTTP_VERSION_MATCH)
-    {
-        return eval_version_match(p, hi);
-    }
-    else
-    {
-        const int32_t num_lines = hi->http_get_num_headers(p, buffer_info);
-        if (num_lines != HttpCommon::STAT_NOT_PRESENT && range.eval(num_lines))
-            return MATCH;
-
-        return NO_MATCH;
-    }
-}
-
-//-------------------------------------------------------------------------
-// http_client_body
-//-------------------------------------------------------------------------
-
-#undef IPS_OPT
-#define IPS_OPT "http_client_body"
-#undef IPS_HELP
-#define IPS_HELP "rule option to set the detection cursor to the request body"
-
-static Module* client_body_mod_ctor()
-{
-    return new HttpRuleOptModule(IPS_OPT, IPS_HELP, HTTP_BUFFER_CLIENT_BODY, CAT_SET_BODY,
-        PSI_CLIENT_BODY);
-}
-
-static const IpsApi client_body_api =
-{
-    {
-        PT_IPS_OPTION,
-        sizeof(IpsApi),
-        IPSAPI_VERSION,
-        1,
-        API_RESERVED,
-        API_OPTIONS,
-        IPS_OPT,
-        IPS_HELP,
-        client_body_mod_ctor,
-        HttpRuleOptModule::mod_dtor
-    },
-    OPT_TYPE_DETECTION,
-    0, PROTO_BIT__TCP,
-    nullptr,
-    nullptr,
-    nullptr,
-    nullptr,
-    HttpIpsOption::opt_ctor,
-    HttpIpsOption::opt_dtor,
-    nullptr
-};
-
-//-------------------------------------------------------------------------
-// http_cookie
-//-------------------------------------------------------------------------
-
-static const Parameter http_cookie_params[] =
-{
-    { "request", Parameter::PT_IMPLIED, nullptr, nullptr,
-        "match against the cookie 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 }
-};
-
-#undef IPS_OPT
-#define IPS_OPT "http_cookie"
-#undef IPS_HELP
-#define IPS_HELP "rule option to set the detection cursor to the HTTP cookie"
-
-static Module* cookie_mod_ctor()
-{
-    return new HttpRuleOptModule(IPS_OPT, IPS_HELP, HTTP_BUFFER_COOKIE, CAT_SET_COOKIE, PSI_COOKIE,
-        http_cookie_params);
-}
-
-static const IpsApi cookie_api =
-{
-    {
-        PT_IPS_OPTION,
-        sizeof(IpsApi),
-        IPSAPI_VERSION,
-        1,
-        API_RESERVED,
-        API_OPTIONS,
-        IPS_OPT,
-        IPS_HELP,
-        cookie_mod_ctor,
-        HttpRuleOptModule::mod_dtor
-    },
-    OPT_TYPE_DETECTION,
-    0, PROTO_BIT__TCP,
-    nullptr,
-    nullptr,
-    nullptr,
-    nullptr,
-    HttpIpsOption::opt_ctor,
-    HttpIpsOption::opt_dtor,
-    nullptr
-};
-
-//-------------------------------------------------------------------------
-// http_header
-//-------------------------------------------------------------------------
-
-// FIXIT-M add match_unknown option to look at HEAD__UNKNOWN.
-
-// FIXIT-M if http_header is the fast pattern buffer and the content to be
-// matched appears in the normalized field but not in the raw field
-// detection will fail.
-
-static const Parameter http_header_params[] =
-{
-    { "field", Parameter::PT_STRING, nullptr, nullptr,
-        "restrict to given header. Header name is case insensitive." },
-    { "request", Parameter::PT_IMPLIED, nullptr, nullptr,
-        "match against the headers 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 }
-};
-
-#undef IPS_OPT
-#define IPS_OPT "http_header"
-#undef IPS_HELP
-#define IPS_HELP "rule option to set the detection cursor to the normalized headers"
-
-static Module* header_mod_ctor()
-{
-    return new HttpRuleOptModule(IPS_OPT, IPS_HELP, HTTP_BUFFER_HEADER, CAT_SET_HEADER,
-        PSI_HEADER, http_header_params);
-}
-
-static const IpsApi header_api =
-{
-    {
-        PT_IPS_OPTION,
-        sizeof(IpsApi),
-        IPSAPI_VERSION,
-        1,
-        API_RESERVED,
-        API_OPTIONS,
-        IPS_OPT,
-        IPS_HELP,
-        header_mod_ctor,
-        HttpRuleOptModule::mod_dtor
-    },
-    OPT_TYPE_DETECTION,
-    0, PROTO_BIT__TCP,
-    nullptr,
-    nullptr,
-    nullptr,
-    nullptr,
-    HttpIpsOption::opt_ctor,
-    HttpIpsOption::opt_dtor,
-    nullptr
-};
-
-//-------------------------------------------------------------------------
-// http_method
-//-------------------------------------------------------------------------
-
-static const Parameter http_method_params[] =
-{
-    { "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 }
-};
-
-#undef IPS_OPT
-#define IPS_OPT "http_method"
-#undef IPS_HELP
-#define IPS_HELP "rule option to set the detection cursor to the HTTP request method"
-
-static Module* method_mod_ctor()
-{
-    return new HttpRuleOptModule(IPS_OPT, IPS_HELP, HTTP_BUFFER_METHOD, CAT_SET_METHOD, PSI_METHOD,
-        http_method_params);
-}
-
-static const IpsApi method_api =
-{
-    {
-        PT_IPS_OPTION,
-        sizeof(IpsApi),
-        IPSAPI_VERSION,
-        1,
-        API_RESERVED,
-        API_OPTIONS,
-        IPS_OPT,
-        IPS_HELP,
-        method_mod_ctor,
-        HttpRuleOptModule::mod_dtor
-    },
-    OPT_TYPE_DETECTION,
-    0, PROTO_BIT__TCP,
-    nullptr,
-    nullptr,
-    nullptr,
-    nullptr,
-    HttpIpsOption::opt_ctor,
-    HttpIpsOption::opt_dtor,
-    nullptr
-};
-
-//-------------------------------------------------------------------------
-// http_param
-//-------------------------------------------------------------------------
-
-static const Parameter http_param_params[] =
-{
-    { "~param", Parameter::PT_STRING, nullptr, nullptr,
-        "parameter to match" },
-    { "nocase", Parameter::PT_IMPLIED, nullptr, nullptr,
-        "case insensitive match" },
-    { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
-};
-
-#undef IPS_OPT
-#define IPS_OPT "http_param"
-#undef IPS_HELP
-#define IPS_HELP "rule option to set the detection cursor to the value of the specified HTTP parameter key which may be in the query or body"
-
-static Module* param_mod_ctor()
-{
-    return new HttpRuleOptModule(IPS_OPT, IPS_HELP, HTTP_BUFFER_PARAM, CAT_SET_OTHER, PSI_PARAM,
-        http_param_params);
-}
-
-static const IpsApi param_api =
-{
-    {
-        PT_IPS_OPTION,
-        sizeof(IpsApi),
-        IPSAPI_VERSION,
-        1,
-        API_RESERVED,
-        API_OPTIONS,
-        IPS_OPT,
-        IPS_HELP,
-        param_mod_ctor,
-        HttpRuleOptModule::mod_dtor
-    },
-    OPT_TYPE_DETECTION,
-    0, PROTO_BIT__TCP,
-    nullptr,
-    nullptr,
-    nullptr,
-    nullptr,
-    HttpIpsOption::opt_ctor,
-    HttpIpsOption::opt_dtor,
-    nullptr
-};
-
-//-------------------------------------------------------------------------
-// http_raw_body
-//-------------------------------------------------------------------------
-
-#undef IPS_OPT
-#define IPS_OPT "http_raw_body"
-#undef IPS_HELP
-#define IPS_HELP "rule option to set the detection cursor to the unnormalized message body"
-
-static Module* raw_body_mod_ctor()
-{
-    return new HttpRuleOptModule(IPS_OPT, IPS_HELP, HTTP_BUFFER_RAW_BODY, CAT_SET_OTHER,
-        PSI_RAW_BODY);
-}
-
-static const IpsApi raw_body_api =
-{
-    {
-        PT_IPS_OPTION,
-        sizeof(IpsApi),
-        IPSAPI_VERSION,
-        1,
-        API_RESERVED,
-        API_OPTIONS,
-        IPS_OPT,
-        IPS_HELP,
-        raw_body_mod_ctor,
-        HttpRuleOptModule::mod_dtor
-    },
-    OPT_TYPE_DETECTION,
-    0, PROTO_BIT__TCP,
-    nullptr,
-    nullptr,
-    nullptr,
-    nullptr,
-    HttpIpsOption::opt_ctor,
-    HttpIpsOption::opt_dtor,
-    nullptr
-};
-
-//-------------------------------------------------------------------------
-// http_raw_cookie
-//-------------------------------------------------------------------------
-
-static const Parameter http_raw_cookie_params[] =
-{
-    { "request", Parameter::PT_IMPLIED, nullptr, nullptr,
-        "match against the cookie 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 }
-};
-
-#undef IPS_OPT
-#define IPS_OPT "http_raw_cookie"
-#undef IPS_HELP
-#define IPS_HELP "rule option to set the detection cursor to the unnormalized cookie"
-
-static Module* raw_cookie_mod_ctor()
-{
-    return new HttpRuleOptModule(IPS_OPT, IPS_HELP, HTTP_BUFFER_RAW_COOKIE, CAT_SET_OTHER,
-        PSI_RAW_COOKIE, http_raw_cookie_params);
-}
-
-static const IpsApi raw_cookie_api =
-{
-    {
-        PT_IPS_OPTION,
-        sizeof(IpsApi),
-        IPSAPI_VERSION,
-        1,
-        API_RESERVED,
-        API_OPTIONS,
-        IPS_OPT,
-        IPS_HELP,
-        raw_cookie_mod_ctor,
-        HttpRuleOptModule::mod_dtor
-    },
-    OPT_TYPE_DETECTION,
-    0, PROTO_BIT__TCP,
-    nullptr,
-    nullptr,
-    nullptr,
-    nullptr,
-    HttpIpsOption::opt_ctor,
-    HttpIpsOption::opt_dtor,
-    nullptr
-};
-
-//-------------------------------------------------------------------------
-// http_raw_header
-//-------------------------------------------------------------------------
-
-static const Parameter http_raw_header_params[] =
-{
-    { "field", Parameter::PT_STRING, nullptr, nullptr,
-        "restrict to given header. Header name is case insensitive." },
-    { "request", Parameter::PT_IMPLIED, nullptr, nullptr,
-        "match against the headers 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 }
-};
-
-#undef IPS_OPT
-#define IPS_OPT "http_raw_header"
-#undef IPS_HELP
-#define IPS_HELP "rule option to set the detection cursor to the unnormalized headers"
-
-static Module* raw_header_mod_ctor()
-{
-    return new HttpRuleOptModule(IPS_OPT, IPS_HELP, HTTP_BUFFER_RAW_HEADER, CAT_SET_RAW_HEADER,
-        PSI_RAW_HEADER, http_raw_header_params);
+    return hi;
 }
 
-static const IpsApi raw_header_api =
-{
-    {
-        PT_IPS_OPTION,
-        sizeof(IpsApi),
-        IPSAPI_VERSION,
-        1,
-        API_RESERVED,
-        API_OPTIONS,
-        IPS_OPT,
-        IPS_HELP,
-        raw_header_mod_ctor,
-        HttpRuleOptModule::mod_dtor
-    },
-    OPT_TYPE_DETECTION,
-    0, PROTO_BIT__TCP,
-    nullptr,
-    nullptr,
-    nullptr,
-    nullptr,
-    HttpIpsOption::opt_ctor,
-    HttpIpsOption::opt_dtor,
-    nullptr
-};
-
-//-------------------------------------------------------------------------
-// http_raw_request
-//-------------------------------------------------------------------------
-
-static const Parameter http_raw_request_params[] =
-{
-    { "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 }
-};
-
-#undef IPS_OPT
-#define IPS_OPT "http_raw_request"
-#undef IPS_HELP
-#define IPS_HELP "rule option to set the detection cursor to the unnormalized request line"
-
-static Module* raw_request_mod_ctor()
-{
-    return new HttpRuleOptModule(IPS_OPT, IPS_HELP, HTTP_BUFFER_RAW_REQUEST, CAT_SET_OTHER,
-        PSI_RAW_REQUEST, http_raw_request_params);
-}
-
-static const IpsApi raw_request_api =
-{
-    {
-        PT_IPS_OPTION,
-        sizeof(IpsApi),
-        IPSAPI_VERSION,
-        1,
-        API_RESERVED,
-        API_OPTIONS,
-        IPS_OPT,
-        IPS_HELP,
-        raw_request_mod_ctor,
-        HttpRuleOptModule::mod_dtor
-    },
-    OPT_TYPE_DETECTION,
-    0, PROTO_BIT__TCP,
-    nullptr,
-    nullptr,
-    nullptr,
-    nullptr,
-    HttpIpsOption::opt_ctor,
-    HttpIpsOption::opt_dtor,
-    nullptr
-};
-
-//-------------------------------------------------------------------------
-// http_raw_status
-//-------------------------------------------------------------------------
-
-static const Parameter http_raw_status_params[] =
-{
-    { "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 }
-};
-
-#undef IPS_OPT
-#define IPS_OPT "http_raw_status"
-#undef IPS_HELP
-#define IPS_HELP "rule option to set the detection cursor to the unnormalized status line"
-
-static Module* raw_status_mod_ctor()
-{
-    return new HttpRuleOptModule(IPS_OPT, IPS_HELP, HTTP_BUFFER_RAW_STATUS, CAT_SET_OTHER,
-        PSI_RAW_STATUS, http_raw_status_params);
-}
-
-static const IpsApi raw_status_api =
-{
-    {
-        PT_IPS_OPTION,
-        sizeof(IpsApi),
-        IPSAPI_VERSION,
-        1,
-        API_RESERVED,
-        API_OPTIONS,
-        IPS_OPT,
-        IPS_HELP,
-        raw_status_mod_ctor,
-        HttpRuleOptModule::mod_dtor
-    },
-    OPT_TYPE_DETECTION,
-    0, PROTO_BIT__TCP,
-    nullptr,
-    nullptr,
-    nullptr,
-    nullptr,
-    HttpIpsOption::opt_ctor,
-    HttpIpsOption::opt_dtor,
-    nullptr
-};
-
-//-------------------------------------------------------------------------
-// http_raw_trailer
-//-------------------------------------------------------------------------
-
-static const Parameter http_raw_trailer_params[] =
-{
-    { "field", Parameter::PT_STRING, nullptr, nullptr,
-        "restrict to given trailer. Trailer name is case insensitive." },
-    { "request", Parameter::PT_IMPLIED, nullptr, nullptr,
-        "match against the trailers from the request message even when examining the response" },
-    { "with_header", Parameter::PT_IMPLIED, nullptr, nullptr,
-        "parts of this rule examine HTTP response message headers (must be combined with request)"
-        },
-    { "with_body", Parameter::PT_IMPLIED, nullptr, nullptr,
-        "parts of this rule examine HTTP response message body (must be combined with request)" },
-    { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
-};
-
-#undef IPS_OPT
-#define IPS_OPT "http_raw_trailer"
-#undef IPS_HELP
-#define IPS_HELP "rule option to set the detection cursor to the unnormalized trailers"
-
-static Module* raw_trailer_mod_ctor()
-{
-    return new HttpRuleOptModule(IPS_OPT, IPS_HELP, HTTP_BUFFER_RAW_TRAILER, CAT_SET_RAW_HEADER,
-        PSI_RAW_TRAILER, http_raw_trailer_params);
-}
-
-static const IpsApi raw_trailer_api =
-{
-    {
-        PT_IPS_OPTION,
-        sizeof(IpsApi),
-        IPSAPI_VERSION,
-        1,
-        API_RESERVED,
-        API_OPTIONS,
-        IPS_OPT,
-        IPS_HELP,
-        raw_trailer_mod_ctor,
-        HttpRuleOptModule::mod_dtor
-    },
-    OPT_TYPE_DETECTION,
-    0, PROTO_BIT__TCP,
-    nullptr,
-    nullptr,
-    nullptr,
-    nullptr,
-    HttpIpsOption::opt_ctor,
-    HttpIpsOption::opt_dtor,
-    nullptr
-};
-
-//-------------------------------------------------------------------------
-// http_raw_uri
-//-------------------------------------------------------------------------
-
-static const Parameter http_raw_uri_params[] =
-{
-    { "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" },
-    { "scheme", Parameter::PT_IMPLIED, nullptr, nullptr,
-        "match against scheme section of URI only" },
-    { "host", Parameter::PT_IMPLIED, nullptr, nullptr,
-        "match against host section of URI only" },
-    { "port", Parameter::PT_IMPLIED, nullptr, nullptr,
-        "match against port section of URI only" },
-    { "path", Parameter::PT_IMPLIED, nullptr, nullptr,
-        "match against path section of URI only" },
-    { "query", Parameter::PT_IMPLIED, nullptr, nullptr,
-        "match against query section of URI only" },
-    { "fragment", Parameter::PT_IMPLIED, nullptr, nullptr,
-        "match against fragment section of URI only" },
-    { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
-};
-
-#undef IPS_OPT
-#define IPS_OPT "http_raw_uri"
-#undef IPS_HELP
-#define IPS_HELP "rule option to set the detection cursor to the unnormalized URI"
-
-static Module* raw_uri_mod_ctor()
-{
-    return new HttpRuleOptModule(IPS_OPT, IPS_HELP, HTTP_BUFFER_RAW_URI, CAT_SET_RAW_KEY,
-        PSI_RAW_URI, http_raw_uri_params);
-}
-
-static const IpsApi raw_uri_api =
-{
-    {
-        PT_IPS_OPTION,
-        sizeof(IpsApi),
-        IPSAPI_VERSION,
-        1,
-        API_RESERVED,
-        API_OPTIONS,
-        IPS_OPT,
-        IPS_HELP,
-        raw_uri_mod_ctor,
-        HttpRuleOptModule::mod_dtor
-    },
-    OPT_TYPE_DETECTION,
-    0, PROTO_BIT__TCP,
-    nullptr,
-    nullptr,
-    nullptr,
-    nullptr,
-    HttpIpsOption::opt_ctor,
-    HttpIpsOption::opt_dtor,
-    nullptr
-};
-
-//-------------------------------------------------------------------------
-// http_stat_code
-//-------------------------------------------------------------------------
-
-static const Parameter http_stat_code_params[] =
-{
-    { "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 }
-};
-
-#undef IPS_OPT
-#define IPS_OPT "http_stat_code"
-#undef IPS_HELP
-#define IPS_HELP "rule option to set the detection cursor to the HTTP status code"
-
-static Module* stat_code_mod_ctor()
-{
-    return new HttpRuleOptModule(IPS_OPT, IPS_HELP, HTTP_BUFFER_STAT_CODE, CAT_SET_STAT_CODE,
-        PSI_STAT_CODE, http_stat_code_params);
-}
-
-static const IpsApi stat_code_api =
-{
-    {
-        PT_IPS_OPTION,
-        sizeof(IpsApi),
-        IPSAPI_VERSION,
-        1,
-        API_RESERVED,
-        API_OPTIONS,
-        IPS_OPT,
-        IPS_HELP,
-        stat_code_mod_ctor,
-        HttpRuleOptModule::mod_dtor
-    },
-    OPT_TYPE_DETECTION,
-    0, PROTO_BIT__TCP,
-    nullptr,
-    nullptr,
-    nullptr,
-    nullptr,
-    HttpIpsOption::opt_ctor,
-    HttpIpsOption::opt_dtor,
-    nullptr
-};
-
-//-------------------------------------------------------------------------
-// http_stat_msg
-//-------------------------------------------------------------------------
-
-static const Parameter http_stat_msg_params[] =
-{
-    { "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 }
-};
-
-#undef IPS_OPT
-#define IPS_OPT "http_stat_msg"
-#undef IPS_HELP
-#define IPS_HELP "rule option to set the detection cursor to the HTTP status message"
-
-static Module* stat_msg_mod_ctor()
-{
-    return new HttpRuleOptModule(IPS_OPT, IPS_HELP, HTTP_BUFFER_STAT_MSG, CAT_SET_STAT_MSG,
-        PSI_STAT_MSG, http_stat_msg_params);
-}
-
-static const IpsApi stat_msg_api =
-{
-    {
-        PT_IPS_OPTION,
-        sizeof(IpsApi),
-        IPSAPI_VERSION,
-        1,
-        API_RESERVED,
-        API_OPTIONS,
-        IPS_OPT,
-        IPS_HELP,
-        stat_msg_mod_ctor,
-        HttpRuleOptModule::mod_dtor
-    },
-    OPT_TYPE_DETECTION,
-    0, PROTO_BIT__TCP,
-    nullptr,
-    nullptr,
-    nullptr,
-    nullptr,
-    HttpIpsOption::opt_ctor,
-    HttpIpsOption::opt_dtor,
-    nullptr
-};
-
-//-------------------------------------------------------------------------
-// http_trailer
-//-------------------------------------------------------------------------
-
-static const Parameter http_trailer_params[] =
-{
-    { "field", Parameter::PT_STRING, nullptr, nullptr, "restrict to given trailer" },
-    { "request", Parameter::PT_IMPLIED, nullptr, nullptr,
-        "match against the trailers from the request message even when examining the response" },
-    { "with_header", Parameter::PT_IMPLIED, nullptr, nullptr,
-        "parts of this rule examine HTTP response message headers (must be combined with request)"
-        },
-    { "with_body", Parameter::PT_IMPLIED, nullptr, nullptr,
-        "parts of this rule examine HTTP message body (must be combined with request)" },
-    { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
-};
-
-#undef IPS_OPT
-#define IPS_OPT "http_trailer"
-#undef IPS_HELP
-#define IPS_HELP "rule option to set the detection cursor to the normalized trailers"
-
-static Module* trailer_mod_ctor()
-{
-    return new HttpRuleOptModule(IPS_OPT, IPS_HELP, HTTP_BUFFER_TRAILER, CAT_SET_HEADER,
-        PSI_TRAILER, http_trailer_params);
-}
-
-static const IpsApi trailer_api =
-{
-    {
-        PT_IPS_OPTION,
-        sizeof(IpsApi),
-        IPSAPI_VERSION,
-        1,
-        API_RESERVED,
-        API_OPTIONS,
-        IPS_OPT,
-        IPS_HELP,
-        trailer_mod_ctor,
-        HttpRuleOptModule::mod_dtor
-    },
-    OPT_TYPE_DETECTION,
-    0, PROTO_BIT__TCP,
-    nullptr,
-    nullptr,
-    nullptr,
-    nullptr,
-    HttpIpsOption::opt_ctor,
-    HttpIpsOption::opt_dtor,
-    nullptr
-};
-
-//-------------------------------------------------------------------------
-// http_true_ip
-//-------------------------------------------------------------------------
-
-static const Parameter http_true_ip_params[] =
-{
-    { "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 }
-};
-
-#undef IPS_OPT
-#define IPS_OPT "http_true_ip"
-#undef IPS_HELP
-#define IPS_HELP "rule option to set the detection cursor to the final client IP address"
-
-static Module* true_ip_mod_ctor()
-{
-    return new HttpRuleOptModule(IPS_OPT, IPS_HELP, HTTP_BUFFER_TRUE_IP, CAT_SET_OTHER,
-        PSI_TRUE_IP, http_true_ip_params);
-}
-
-static const IpsApi true_ip_api =
-{
-    {
-        PT_IPS_OPTION,
-        sizeof(IpsApi),
-        IPSAPI_VERSION,
-        1,
-        API_RESERVED,
-        API_OPTIONS,
-        IPS_OPT,
-        IPS_HELP,
-        true_ip_mod_ctor,
-        HttpRuleOptModule::mod_dtor
-    },
-    OPT_TYPE_DETECTION,
-    0, PROTO_BIT__TCP,
-    nullptr,
-    nullptr,
-    nullptr,
-    nullptr,
-    HttpIpsOption::opt_ctor,
-    HttpIpsOption::opt_dtor,
-    nullptr
-};
-
-//-------------------------------------------------------------------------
-// http_uri
-//-------------------------------------------------------------------------
-
-static const Parameter http_uri_params[] =
-{
-    { "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" },
-    { "scheme", Parameter::PT_IMPLIED, nullptr, nullptr,
-        "match against scheme section of URI only" },
-    { "host", Parameter::PT_IMPLIED, nullptr, nullptr,
-        "match against host section of URI only" },
-    { "port", Parameter::PT_IMPLIED, nullptr, nullptr,
-        "match against port section of URI only" },
-    { "path", Parameter::PT_IMPLIED, nullptr, nullptr,
-        "match against path section of URI only" },
-    { "query", Parameter::PT_IMPLIED, nullptr, nullptr,
-        "match against query section of URI only" },
-    { "fragment", Parameter::PT_IMPLIED, nullptr, nullptr,
-        "match against fragment section of URI only" },
-    { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
-};
-
-#undef IPS_OPT
-#define IPS_OPT "http_uri"
-#undef IPS_HELP
-#define IPS_HELP "rule option to set the detection cursor to the normalized URI buffer"
-
-static Module* uri_mod_ctor()
-{
-    return new HttpRuleOptModule(IPS_OPT, IPS_HELP, HTTP_BUFFER_URI, CAT_SET_KEY, PSI_URI,
-        http_uri_params);
-}
-
-static const IpsApi uri_api =
-{
-    {
-        PT_IPS_OPTION,
-        sizeof(IpsApi),
-        IPSAPI_VERSION,
-        1,
-        API_RESERVED,
-        API_OPTIONS,
-        IPS_OPT,
-        IPS_HELP,
-        uri_mod_ctor,
-        HttpRuleOptModule::mod_dtor
-    },
-    OPT_TYPE_DETECTION,
-    0, PROTO_BIT__TCP,
-    nullptr,
-    nullptr,
-    nullptr,
-    nullptr,
-    HttpIpsOption::opt_ctor,
-    HttpIpsOption::opt_dtor,
-    nullptr
-};
-
-//-------------------------------------------------------------------------
-// http_version
-//-------------------------------------------------------------------------
-
-static const Parameter http_version_params[] =
-{
-    { "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 }
-};
-
-#undef IPS_OPT
-#define IPS_OPT "http_version"
-#undef IPS_HELP
-#define IPS_HELP "rule option to set the detection cursor to the version buffer"
-
-static Module* version_mod_ctor()
-{
-    return new HttpRuleOptModule(IPS_OPT, IPS_HELP, HTTP_BUFFER_VERSION, CAT_SET_OTHER,
-        PSI_VERSION, http_version_params);
-}
-
-static const IpsApi version_api =
-{
-    {
-        PT_IPS_OPTION,
-        sizeof(IpsApi),
-        IPSAPI_VERSION,
-        1,
-        API_RESERVED,
-        API_OPTIONS,
-        IPS_OPT,
-        IPS_HELP,
-        version_mod_ctor,
-        HttpRuleOptModule::mod_dtor
-    },
-    OPT_TYPE_DETECTION,
-    0, PROTO_BIT__TCP,
-    nullptr,
-    nullptr,
-    nullptr,
-    nullptr,
-    HttpIpsOption::opt_ctor,
-    HttpIpsOption::opt_dtor,
-    nullptr
-};
-
-//-------------------------------------------------------------------------
-// js_data
-//-------------------------------------------------------------------------
-//
-
-#undef IPS_OPT
-#define IPS_OPT "js_data"
-#undef IPS_HELP
-#define IPS_HELP "rule option to set detection cursor to normalized JavaScript data"
-static Module* js_data_mod_ctor()
-{
-    return new HttpRuleOptModule(IPS_OPT, IPS_HELP, BUFFER_JS_DATA, CAT_SET_JS_DATA,
-        PSI_JS_DATA);
-}
-
-static const IpsApi js_data_api =
-{
-    {
-        PT_IPS_OPTION,
-        sizeof(IpsApi),
-        IPSAPI_VERSION,
-        1,
-        API_RESERVED,
-        API_OPTIONS,
-        IPS_OPT,
-        IPS_HELP,
-        js_data_mod_ctor,
-        HttpRuleOptModule::mod_dtor
-    },
-    OPT_TYPE_DETECTION,
-    0, PROTO_BIT__TCP,
-    nullptr,
-    nullptr,
-    nullptr,
-    nullptr,
-    HttpIpsOption::opt_ctor,
-    HttpIpsOption::opt_dtor,
-    nullptr
-};
-
-//-------------------------------------------------------------------------
-// num_header_lines
-//-------------------------------------------------------------------------
-#undef IPS_OPT
-#define IPS_OPT "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, hdrs_num_range.c_str(), 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 HttpRuleOptModule(IPS_OPT, IPS_HELP, HTTP_RANGE_NUM_HDRS, CAT_SET_OTHER,
-       PSI_RANGE_NUM_HDRS, 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,
-        HttpRuleOptModule::mod_dtor
-    },
-    OPT_TYPE_DETECTION,
-    0, PROTO_BIT__TCP,
-    nullptr,
-    nullptr,
-    nullptr,
-    nullptr,
-    HttpIpsOption::opt_ctor,
-    HttpIpsOption::opt_dtor,
-    nullptr
-};
-
-//-------------------------------------------------------------------------
-// num_trailer_lines
-//-------------------------------------------------------------------------
-#undef IPS_OPT
-#define IPS_OPT "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 HttpRuleOptModule(IPS_OPT, IPS_HELP, HTTP_RANGE_NUM_TRAILERS, CAT_SET_OTHER,
-       PSI_RANGE_NUM_TRAILERS, 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,
-        HttpRuleOptModule::mod_dtor
-    },
-    OPT_TYPE_DETECTION,
-    0, PROTO_BIT__TCP,
-    nullptr,
-    nullptr,
-    nullptr,
-    nullptr,
-    HttpIpsOption::opt_ctor,
-    HttpIpsOption::opt_dtor,
-    nullptr
-};
-
-//-------------------------------------------------------------------------
-// http_version_match
-//-------------------------------------------------------------------------
-#undef IPS_OPT
-#define IPS_OPT "http_version_match"
-#undef IPS_HELP
-#define IPS_HELP "rule option to match version to listed values"
-
-static const Parameter version_match_params[] =
-{
-    { "~version_list", Parameter::PT_STRING, nullptr, nullptr,
-        "space-separated list of versions to match" },
-    { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
-};
-
-static Module* version_match_mod_ctor()
-{
-    return new HttpRuleOptModule(IPS_OPT, IPS_HELP, HTTP_VERSION_MATCH, CAT_SET_OTHER,
-        PSI_VERSION_MATCH, version_match_params);
-}
-
-static const IpsApi version_match_api =
-{
-    {
-        PT_IPS_OPTION,
-        sizeof(IpsApi),
-        IPSAPI_VERSION,
-        1,
-        API_RESERVED,
-        API_OPTIONS,
-        IPS_OPT,
-        IPS_HELP,
-        version_match_mod_ctor,
-        HttpRuleOptModule::mod_dtor
-    },
-    OPT_TYPE_DETECTION,
-    0, PROTO_BIT__TCP,
-    nullptr,
-    nullptr,
-    nullptr,
-    nullptr,
-    HttpIpsOption::opt_ctor,
-    HttpIpsOption::opt_dtor,
-    nullptr
-};
-
-//-------------------------------------------------------------------------
-// plugins
-//-------------------------------------------------------------------------
-
-const BaseApi* ips_http_client_body = &client_body_api.base;
-const BaseApi* ips_http_cookie = &cookie_api.base;
-const BaseApi* ips_http_header = &header_api.base;
-const BaseApi* ips_http_method = &method_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_param = &param_api.base;
-const BaseApi* ips_http_raw_body = &raw_body_api.base;
-const BaseApi* ips_http_raw_cookie = &raw_cookie_api.base;
-const BaseApi* ips_http_raw_header = &raw_header_api.base;
-const BaseApi* ips_http_raw_request = &raw_request_api.base;
-const BaseApi* ips_http_raw_status = &raw_status_api.base;
-const BaseApi* ips_http_raw_trailer = &raw_trailer_api.base;
-const BaseApi* ips_http_raw_uri = &raw_uri_api.base;
-const BaseApi* ips_http_stat_code = &stat_code_api.base;
-const BaseApi* ips_http_stat_msg = &stat_msg_api.base;
-const BaseApi* ips_http_trailer = &trailer_api.base;
-const BaseApi* ips_http_true_ip = &true_ip_api.base;
-const BaseApi* ips_http_uri = &uri_api.base;
-const BaseApi* ips_http_version = &version_api.base;
-const BaseApi* ips_http_version_match = &version_match_api.base;
-const BaseApi* ips_js_data = &js_data_api.base;
index 2d49b122e0067e49fc73a9f2fee1eb2bc2ca0718..b9e6d36a3f978d166e125441ebc0958fe6ed555e 100644 (file)
 
 class HttpInspect;
 
-enum PsIdx { PSI_CLIENT_BODY, PSI_COOKIE, PSI_HEADER, PSI_METHOD, PSI_PARAM,
-    PSI_RAW_BODY, PSI_RAW_COOKIE, PSI_RAW_HEADER, PSI_RAW_REQUEST, PSI_RAW_STATUS,
-    PSI_RAW_TRAILER, PSI_RAW_URI, PSI_STAT_CODE, PSI_STAT_MSG, PSI_TRAILER,
-    PSI_TRUE_IP, PSI_URI, PSI_VERSION, PSI_JS_DATA, PSI_VBA_DATA,
-    PSI_RANGE_NUM_HDRS, PSI_RANGE_NUM_TRAILERS, PSI_VERSION_MATCH, PSI_MAX };
-
 class HttpRuleOptModule : public snort::Module
 {
 public:
     HttpRuleOptModule(const char* key_, const char* help, HttpEnums::HTTP_RULE_OPT rule_opt_index_,
-        snort::CursorActionType cat_, PsIdx psi_)
-        : snort::Module(key_, help), key(key_), rule_opt_index(rule_opt_index_),
-          cat(cat_), psi(psi_) {}
+        snort::CursorActionType cat_)
+        : snort::Module(key_, help), rule_opt_index(rule_opt_index_), key(key_),
+          cat(cat_) {}
     HttpRuleOptModule(const char* key_, const char* help, HttpEnums::HTTP_RULE_OPT rule_opt_index_,
-        snort::CursorActionType cat_, PsIdx psi_, const snort::Parameter params[])
-        : snort::Module(key_, help, params), key(key_), rule_opt_index(rule_opt_index_),
-        cat(cat_), psi(psi_) {}
-    snort::ProfileStats* get_profile() const override { return &http_ps[psi]; }
+        snort::CursorActionType cat_, const snort::Parameter params[])
+        : snort::Module(key_, help, params), rule_opt_index(rule_opt_index_),
+        key(key_), cat(cat_) {}
+    snort::ProfileStats* get_profile() const = 0;
     static void mod_dtor(snort::Module* m) { delete m; }
     bool begin(const char*, int, snort::SnortConfig*) override;
     bool set(const char*, snort::Value&, snort::SnortConfig*) override;
@@ -58,75 +52,53 @@ public:
     Usage get_usage() const override
     { return DETECT; }
 
+protected:
+    HttpEnums::InspectSection inspect_section;
+    const HttpEnums::HTTP_RULE_OPT rule_opt_index;
+    const char* const key;
+    uint64_t sub_id;
+    bool is_trailer_opt;          // used by ::end for with_* validation
+
 private:
     friend class HttpIpsOption;
-    static THREAD_LOCAL std::array<snort::ProfileStats, PsIdx::PSI_MAX> http_ps;
-    static const int version_size = HttpEnums::VERS__MAX - HttpEnums::VERS__MIN + 1;
 
     struct HttpRuleParaList
     {
     public:
         std::string field;        // provide buffer containing specific header field
-        std::string param;        // provide buffer containing specific parameter
-        bool nocase;              // case insensitive match
         bool request;             // provide buffer from request not response
         bool with_header;         // provide buffer with a later section than it appears in
         bool with_body;
         bool with_trailer;
-        bool scheme;              // provide buffer with one of the six URI subcomponents
-        bool host;
-        bool port;
-        bool path;
-        bool query;
-        bool fragment;
-        snort::RangeCheck range;
-        std::bitset<version_size> version_flags;
 
         void reset();
     };
 
-    const char* const key;
-    const HttpEnums::HTTP_RULE_OPT rule_opt_index;
     const snort::CursorActionType cat;
-    const PsIdx psi;
-
     HttpRuleParaList para_list;
-    HttpEnums::InspectSection inspect_section;
-    uint64_t sub_id;
     uint64_t form;
-
-    bool parse_version_list(snort::Value& v);
 };
 
 class HttpIpsOption : public snort::IpsOption
 {
 public:
-    HttpIpsOption(const HttpRuleOptModule* cm) :
-        snort::IpsOption(cm->key, RULE_OPTION_TYPE_BUFFER_SET),
-        key(cm->key), cat(cm->cat), psi(cm->psi),
-        inspect_section(cm->inspect_section),
-        buffer_info(cm->rule_opt_index, cm->sub_id, cm->form,
-        cm->para_list.param, cm->para_list.nocase), range(cm->para_list.range),
-        version_flags(cm->para_list.version_flags){}
+    HttpIpsOption(const HttpRuleOptModule* cm, option_type_t type) :
+        snort::IpsOption(cm->key, type),
+        buffer_info(cm->rule_opt_index, cm->sub_id, cm->form),
+        cat(cm->cat), inspect_section(cm->inspect_section) {}
     snort::CursorActionType get_cursor_type() const override { return cat; }
-    EvalStatus eval(Cursor&, snort::Packet*) override;
+    EvalStatus eval(Cursor&, snort::Packet*) = 0;
     uint32_t hash() const override;
     bool operator==(const snort::IpsOption& ips) const override;
-    bool retry(Cursor&, const Cursor&) override;
-    static IpsOption* opt_ctor(snort::Module* m, OptTreeNode*)
-        { return new HttpIpsOption((HttpRuleOptModule*)m); }
-    static void opt_dtor(snort::IpsOption* p) { delete p; }
+
+protected:
+    const HttpBufferInfo buffer_info;
+  
+    HttpInspect const* eval_helper(snort::Packet* p);
 
 private:
-    const char* const key;
     const snort::CursorActionType cat;
-    const PsIdx psi;
     const HttpEnums::InspectSection inspect_section;
-    HttpBufferInfo buffer_info;
-    const snort::RangeCheck range;
-    const std::bitset<HttpRuleOptModule::version_size> version_flags;
-
-    IpsOption::EvalStatus eval_version_match(snort::Packet* p, const HttpInspect* hi);
 };
 
 #endif
diff --git a/src/service_inspectors/http_inspect/ips_http_buffer.cc b/src/service_inspectors/http_inspect/ips_http_buffer.cc
new file mode 100644 (file)
index 0000000..9326dfd
--- /dev/null
@@ -0,0 +1,1104 @@
+//--------------------------------------------------------------------------
+// Copyright (C) 2022-2022 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation.  You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//--------------------------------------------------------------------------
+// ips_http_buffer.cc author Maya Dagon <mdagon@cisco.com>
+// Refactored from ips_http.cc author Tom Peters <thopeter@cisco.com>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "ips_http_buffer.h"
+
+#include "framework/cursor.h"
+#include "hash/hash_key_operations.h"
+#include "log/messages.h"
+#include "parser/parse_utils.h"
+#include "protocols/packet.h"
+
+#include "http_common.h"
+#include "http_enum.h"
+#include "http_inspect.h"
+
+using namespace snort;
+using namespace HttpCommon;
+using namespace HttpEnums;
+
+THREAD_LOCAL std::array<ProfileStats, BUFFER_PSI_MAX> HttpBufferRuleOptModule::http_buffer_ps;
+
+bool HttpBufferRuleOptModule::begin(const char*, int, SnortConfig*)
+{
+    HttpRuleOptModule::begin(nullptr, 0, nullptr);
+    scheme = false;
+    host = false;
+    port = false;
+    path = false;
+    query = false;
+    fragment = false;
+
+    switch (rule_opt_index)
+    {
+    case HTTP_BUFFER_RAW_STATUS:
+    case HTTP_BUFFER_STAT_CODE:
+    case HTTP_BUFFER_STAT_MSG:
+        inspect_section = IS_HEADER;
+        break;
+    case HTTP_BUFFER_COOKIE:
+    case HTTP_BUFFER_HEADER:
+    case HTTP_BUFFER_METHOD:
+    case HTTP_BUFFER_RAW_COOKIE:
+    case HTTP_BUFFER_RAW_HEADER:
+    case HTTP_BUFFER_RAW_REQUEST:
+    case HTTP_BUFFER_RAW_URI:
+    case HTTP_BUFFER_TRUE_IP:
+    case HTTP_BUFFER_URI:
+    case HTTP_BUFFER_VERSION:
+        inspect_section = IS_FLEX_HEADER;
+        break;
+    case HTTP_BUFFER_CLIENT_BODY:
+    case HTTP_BUFFER_RAW_BODY:
+    case BUFFER_JS_DATA:
+        inspect_section = IS_BODY;
+        break;
+    case HTTP_BUFFER_RAW_TRAILER:
+    case HTTP_BUFFER_TRAILER:
+        inspect_section = IS_TRAILER;
+        is_trailer_opt = true;
+        break;
+    default:
+        assert(false);
+    }
+    return true;
+}
+
+
+bool HttpBufferRuleOptModule::set(const char*, Value& v, SnortConfig*)
+{
+    if (v.is("scheme"))
+    {
+        scheme = true;
+        sub_id = UC_SCHEME;
+    }
+    else if (v.is("host"))
+    {
+        host = true;
+        sub_id = UC_HOST;
+    }
+    else if (v.is("port"))
+    {
+        port = true;
+        sub_id = UC_PORT;
+    }
+    else if (v.is("path"))
+    {
+        path = true;
+        sub_id = UC_PATH;
+    }
+    else if (v.is("query"))
+    {
+        query = true;
+        sub_id = UC_QUERY;
+    }
+    else if (v.is("fragment"))
+    {
+        fragment = true;
+        sub_id = UC_FRAGMENT;
+    }
+    else
+        HttpRuleOptModule::set(nullptr, v, nullptr);
+
+    return true;
+}
+
+
+bool HttpBufferRuleOptModule::end(const char*, int, SnortConfig*)
+{
+    // Check for option conflicts
+    if (scheme + host + port + path + query + fragment > 1)
+        ParseError("Only specify one part of the URI");
+    return HttpRuleOptModule::end(nullptr, 0, nullptr);
+}
+
+
+IpsOption::EvalStatus HttpBufferIpsOption::eval(Cursor& c, Packet* p)
+{
+    RuleProfile profile(HttpBufferRuleOptModule::http_buffer_ps[idx]);
+
+    const HttpInspect* const hi = eval_helper(p);
+    if (hi == nullptr)
+        return NO_MATCH;
+    
+    const Field& http_buffer = hi->http_get_buf(p, buffer_info);
+    if (http_buffer.length() <= 0)
+        return NO_MATCH;
+
+    c.set(key, http_buffer.start(), http_buffer.length());
+
+    return MATCH;
+}
+
+
+//-------------------------------------------------------------------------
+// http_client_body
+//-------------------------------------------------------------------------
+
+#undef IPS_OPT
+#define IPS_OPT "http_client_body"
+#undef IPS_HELP
+#define IPS_HELP "rule option to set the detection cursor to the request body"
+
+static Module* client_body_mod_ctor()
+{
+    return new HttpBufferRuleOptModule(IPS_OPT, IPS_HELP, HTTP_BUFFER_CLIENT_BODY, CAT_SET_BODY,
+        BUFFER_PSI_CLIENT_BODY);
+}
+
+static const IpsApi client_body_api =
+{
+    {
+        PT_IPS_OPTION,
+        sizeof(IpsApi),
+        IPSAPI_VERSION,
+        1,
+        API_RESERVED,
+        API_OPTIONS,
+        IPS_OPT,
+        IPS_HELP,
+        client_body_mod_ctor,
+        HttpBufferRuleOptModule::mod_dtor
+    },
+    OPT_TYPE_DETECTION,
+    0, PROTO_BIT__TCP,
+    nullptr,
+    nullptr,
+    nullptr,
+    nullptr,
+    HttpBufferIpsOption::opt_ctor,
+    HttpBufferIpsOption::opt_dtor,
+    nullptr
+};
+
+//-------------------------------------------------------------------------
+// http_cookie
+//-------------------------------------------------------------------------
+
+static const Parameter http_cookie_params[] =
+{
+    { "request", Parameter::PT_IMPLIED, nullptr, nullptr,
+        "match against the cookie 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 }
+};
+
+#undef IPS_OPT
+#define IPS_OPT "http_cookie"
+#undef IPS_HELP
+#define IPS_HELP "rule option to set the detection cursor to the HTTP cookie"
+
+static Module* cookie_mod_ctor()
+{
+    return new HttpBufferRuleOptModule(IPS_OPT, IPS_HELP, HTTP_BUFFER_COOKIE, CAT_SET_COOKIE, BUFFER_PSI_COOKIE,
+        http_cookie_params);
+}
+
+static const IpsApi cookie_api =
+{
+    {
+        PT_IPS_OPTION,
+        sizeof(IpsApi),
+        IPSAPI_VERSION,
+        1,
+        API_RESERVED,
+        API_OPTIONS,
+        IPS_OPT,
+        IPS_HELP,
+        cookie_mod_ctor,
+        HttpBufferRuleOptModule::mod_dtor
+    },
+    OPT_TYPE_DETECTION,
+    0, PROTO_BIT__TCP,
+    nullptr,
+    nullptr,
+    nullptr,
+    nullptr,
+    HttpBufferIpsOption::opt_ctor,
+    HttpBufferIpsOption::opt_dtor,
+    nullptr
+};
+
+//-------------------------------------------------------------------------
+// http_header
+//-------------------------------------------------------------------------
+
+// FIXIT-M add match_unknown option to look at HEAD__UNKNOWN.
+
+// FIXIT-M if http_header is the fast pattern buffer and the content to be
+// matched appears in the normalized field but not in the raw field
+// detection will fail.
+
+static const Parameter http_header_params[] =
+{
+    { "field", Parameter::PT_STRING, nullptr, nullptr,
+        "restrict to given header. Header name is case insensitive." },
+    { "request", Parameter::PT_IMPLIED, nullptr, nullptr,
+        "match against the headers 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 }
+};
+
+#undef IPS_OPT
+#define IPS_OPT "http_header"
+#undef IPS_HELP
+#define IPS_HELP "rule option to set the detection cursor to the normalized headers"
+
+static Module* header_mod_ctor()
+{
+    return new HttpBufferRuleOptModule(IPS_OPT, IPS_HELP, HTTP_BUFFER_HEADER, CAT_SET_HEADER,
+        BUFFER_PSI_HEADER, http_header_params);
+}
+
+static const IpsApi header_api =
+{
+    {
+        PT_IPS_OPTION,
+        sizeof(IpsApi),
+        IPSAPI_VERSION,
+        1,
+        API_RESERVED,
+        API_OPTIONS,
+        IPS_OPT,
+        IPS_HELP,
+        header_mod_ctor,
+        HttpBufferRuleOptModule::mod_dtor
+    },
+    OPT_TYPE_DETECTION,
+    0, PROTO_BIT__TCP,
+    nullptr,
+    nullptr,
+    nullptr,
+    nullptr,
+    HttpBufferIpsOption::opt_ctor,
+    HttpBufferIpsOption::opt_dtor,
+    nullptr
+};
+
+//-------------------------------------------------------------------------
+// http_method
+//-------------------------------------------------------------------------
+
+static const Parameter http_method_params[] =
+{
+    { "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 }
+};
+
+#undef IPS_OPT
+#define IPS_OPT "http_method"
+#undef IPS_HELP
+#define IPS_HELP "rule option to set the detection cursor to the HTTP request method"
+
+static Module* method_mod_ctor()
+{
+    return new HttpBufferRuleOptModule(IPS_OPT, IPS_HELP, HTTP_BUFFER_METHOD, CAT_SET_METHOD, BUFFER_PSI_METHOD,
+        http_method_params);
+}
+
+static const IpsApi method_api =
+{
+    {
+        PT_IPS_OPTION,
+        sizeof(IpsApi),
+        IPSAPI_VERSION,
+        1,
+        API_RESERVED,
+        API_OPTIONS,
+        IPS_OPT,
+        IPS_HELP,
+        method_mod_ctor,
+        HttpBufferRuleOptModule::mod_dtor
+    },
+    OPT_TYPE_DETECTION,
+    0, PROTO_BIT__TCP,
+    nullptr,
+    nullptr,
+    nullptr,
+    nullptr,
+    HttpBufferIpsOption::opt_ctor,
+    HttpBufferIpsOption::opt_dtor,
+    nullptr
+};
+
+//-------------------------------------------------------------------------
+// http_raw_body
+//-------------------------------------------------------------------------
+
+#undef IPS_OPT
+#define IPS_OPT "http_raw_body"
+#undef IPS_HELP
+#define IPS_HELP "rule option to set the detection cursor to the unnormalized message body"
+
+static Module* raw_body_mod_ctor()
+{
+    return new HttpBufferRuleOptModule(IPS_OPT, IPS_HELP, HTTP_BUFFER_RAW_BODY, CAT_SET_OTHER,
+        BUFFER_PSI_RAW_BODY);
+}
+
+static const IpsApi raw_body_api =
+{
+    {
+        PT_IPS_OPTION,
+        sizeof(IpsApi),
+        IPSAPI_VERSION,
+        1,
+        API_RESERVED,
+        API_OPTIONS,
+        IPS_OPT,
+        IPS_HELP,
+        raw_body_mod_ctor,
+        HttpBufferRuleOptModule::mod_dtor
+    },
+    OPT_TYPE_DETECTION,
+    0, PROTO_BIT__TCP,
+    nullptr,
+    nullptr,
+    nullptr,
+    nullptr,
+    HttpBufferIpsOption::opt_ctor,
+    HttpBufferIpsOption::opt_dtor,
+    nullptr
+};
+
+//-------------------------------------------------------------------------
+// http_raw_cookie
+//-------------------------------------------------------------------------
+
+static const Parameter http_raw_cookie_params[] =
+{
+    { "request", Parameter::PT_IMPLIED, nullptr, nullptr,
+        "match against the cookie 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 }
+};
+
+#undef IPS_OPT
+#define IPS_OPT "http_raw_cookie"
+#undef IPS_HELP
+#define IPS_HELP "rule option to set the detection cursor to the unnormalized cookie"
+
+static Module* raw_cookie_mod_ctor()
+{
+    return new HttpBufferRuleOptModule(IPS_OPT, IPS_HELP, HTTP_BUFFER_RAW_COOKIE, CAT_SET_OTHER,
+        BUFFER_PSI_RAW_COOKIE, http_raw_cookie_params);
+}
+
+static const IpsApi raw_cookie_api =
+{
+    {
+        PT_IPS_OPTION,
+        sizeof(IpsApi),
+        IPSAPI_VERSION,
+        1,
+        API_RESERVED,
+        API_OPTIONS,
+        IPS_OPT,
+        IPS_HELP,
+        raw_cookie_mod_ctor,
+        HttpBufferRuleOptModule::mod_dtor
+    },
+    OPT_TYPE_DETECTION,
+    0, PROTO_BIT__TCP,
+    nullptr,
+    nullptr,
+    nullptr,
+    nullptr,
+    HttpBufferIpsOption::opt_ctor,
+    HttpBufferIpsOption::opt_dtor,
+    nullptr
+};
+
+//-------------------------------------------------------------------------
+// http_raw_header
+//-------------------------------------------------------------------------
+
+static const Parameter http_raw_header_params[] =
+{
+    { "field", Parameter::PT_STRING, nullptr, nullptr,
+        "restrict to given header. Header name is case insensitive." },
+    { "request", Parameter::PT_IMPLIED, nullptr, nullptr,
+        "match against the headers 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 }
+};
+
+#undef IPS_OPT
+#define IPS_OPT "http_raw_header"
+#undef IPS_HELP
+#define IPS_HELP "rule option to set the detection cursor to the unnormalized headers"
+
+static Module* raw_header_mod_ctor()
+{
+    return new HttpBufferRuleOptModule(IPS_OPT, IPS_HELP, HTTP_BUFFER_RAW_HEADER, CAT_SET_RAW_HEADER,
+        BUFFER_PSI_RAW_HEADER, http_raw_header_params);
+}
+
+static const IpsApi raw_header_api =
+{
+    {
+        PT_IPS_OPTION,
+        sizeof(IpsApi),
+        IPSAPI_VERSION,
+        1,
+        API_RESERVED,
+        API_OPTIONS,
+        IPS_OPT,
+        IPS_HELP,
+        raw_header_mod_ctor,
+        HttpBufferRuleOptModule::mod_dtor
+    },
+    OPT_TYPE_DETECTION,
+    0, PROTO_BIT__TCP,
+    nullptr,
+    nullptr,
+    nullptr,
+    nullptr,
+    HttpBufferIpsOption::opt_ctor,
+    HttpBufferIpsOption::opt_dtor,
+    nullptr
+};
+
+//-------------------------------------------------------------------------
+// http_raw_request
+//-------------------------------------------------------------------------
+
+static const Parameter http_raw_request_params[] =
+{
+    { "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 }
+};
+
+#undef IPS_OPT
+#define IPS_OPT "http_raw_request"
+#undef IPS_HELP
+#define IPS_HELP "rule option to set the detection cursor to the unnormalized request line"
+
+static Module* raw_request_mod_ctor()
+{
+    return new HttpBufferRuleOptModule(IPS_OPT, IPS_HELP, HTTP_BUFFER_RAW_REQUEST, CAT_SET_OTHER,
+        BUFFER_PSI_RAW_REQUEST, http_raw_request_params);
+}
+
+static const IpsApi raw_request_api =
+{
+    {
+        PT_IPS_OPTION,
+        sizeof(IpsApi),
+        IPSAPI_VERSION,
+        1,
+        API_RESERVED,
+        API_OPTIONS,
+        IPS_OPT,
+        IPS_HELP,
+        raw_request_mod_ctor,
+        HttpBufferRuleOptModule::mod_dtor
+    },
+    OPT_TYPE_DETECTION,
+    0, PROTO_BIT__TCP,
+    nullptr,
+    nullptr,
+    nullptr,
+    nullptr,
+    HttpBufferIpsOption::opt_ctor,
+    HttpBufferIpsOption::opt_dtor,
+    nullptr
+};
+
+//-------------------------------------------------------------------------
+// http_raw_status
+//-------------------------------------------------------------------------
+
+static const Parameter http_raw_status_params[] =
+{
+    { "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 }
+};
+
+#undef IPS_OPT
+#define IPS_OPT "http_raw_status"
+#undef IPS_HELP
+#define IPS_HELP "rule option to set the detection cursor to the unnormalized status line"
+
+static Module* raw_status_mod_ctor()
+{
+    return new HttpBufferRuleOptModule(IPS_OPT, IPS_HELP, HTTP_BUFFER_RAW_STATUS, CAT_SET_OTHER,
+        BUFFER_PSI_RAW_STATUS, http_raw_status_params);
+}
+
+static const IpsApi raw_status_api =
+{
+    {
+        PT_IPS_OPTION,
+        sizeof(IpsApi),
+        IPSAPI_VERSION,
+        1,
+        API_RESERVED,
+        API_OPTIONS,
+        IPS_OPT,
+        IPS_HELP,
+        raw_status_mod_ctor,
+        HttpBufferRuleOptModule::mod_dtor
+    },
+    OPT_TYPE_DETECTION,
+    0, PROTO_BIT__TCP,
+    nullptr,
+    nullptr,
+    nullptr,
+    nullptr,
+    HttpBufferIpsOption::opt_ctor,
+    HttpBufferIpsOption::opt_dtor,
+    nullptr
+};
+
+//-------------------------------------------------------------------------
+// http_raw_trailer
+//-------------------------------------------------------------------------
+
+static const Parameter http_raw_trailer_params[] =
+{
+    { "field", Parameter::PT_STRING, nullptr, nullptr,
+        "restrict to given trailer. Trailer name is case insensitive." },
+    { "request", Parameter::PT_IMPLIED, nullptr, nullptr,
+        "match against the trailers from the request message even when examining the response" },
+    { "with_header", Parameter::PT_IMPLIED, nullptr, nullptr,
+        "parts of this rule examine HTTP response message headers (must be combined with request)"
+        },
+    { "with_body", Parameter::PT_IMPLIED, nullptr, nullptr,
+        "parts of this rule examine HTTP response message body (must be combined with request)" },
+    { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
+};
+
+#undef IPS_OPT
+#define IPS_OPT "http_raw_trailer"
+#undef IPS_HELP
+#define IPS_HELP "rule option to set the detection cursor to the unnormalized trailers"
+
+static Module* raw_trailer_mod_ctor()
+{
+    return new HttpBufferRuleOptModule(IPS_OPT, IPS_HELP, HTTP_BUFFER_RAW_TRAILER, CAT_SET_RAW_HEADER,
+        BUFFER_PSI_RAW_TRAILER, http_raw_trailer_params);
+}
+
+static const IpsApi raw_trailer_api =
+{
+    {
+        PT_IPS_OPTION,
+        sizeof(IpsApi),
+        IPSAPI_VERSION,
+        1,
+        API_RESERVED,
+        API_OPTIONS,
+        IPS_OPT,
+        IPS_HELP,
+        raw_trailer_mod_ctor,
+        HttpBufferRuleOptModule::mod_dtor
+    },
+    OPT_TYPE_DETECTION,
+    0, PROTO_BIT__TCP,
+    nullptr,
+    nullptr,
+    nullptr,
+    nullptr,
+    HttpBufferIpsOption::opt_ctor,
+    HttpBufferIpsOption::opt_dtor,
+    nullptr
+};
+
+//-------------------------------------------------------------------------
+// http_raw_uri
+//-------------------------------------------------------------------------
+
+static const Parameter http_raw_uri_params[] =
+{
+    { "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" },
+    { "scheme", Parameter::PT_IMPLIED, nullptr, nullptr,
+        "match against scheme section of URI only" },
+    { "host", Parameter::PT_IMPLIED, nullptr, nullptr,
+        "match against host section of URI only" },
+    { "port", Parameter::PT_IMPLIED, nullptr, nullptr,
+        "match against port section of URI only" },
+    { "path", Parameter::PT_IMPLIED, nullptr, nullptr,
+        "match against path section of URI only" },
+    { "query", Parameter::PT_IMPLIED, nullptr, nullptr,
+        "match against query section of URI only" },
+    { "fragment", Parameter::PT_IMPLIED, nullptr, nullptr,
+        "match against fragment section of URI only" },
+    { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
+};
+
+#undef IPS_OPT
+#define IPS_OPT "http_raw_uri"
+#undef IPS_HELP
+#define IPS_HELP "rule option to set the detection cursor to the unnormalized URI"
+
+static Module* raw_uri_mod_ctor()
+{
+    return new HttpBufferRuleOptModule(IPS_OPT, IPS_HELP, HTTP_BUFFER_RAW_URI, CAT_SET_RAW_KEY,
+        BUFFER_PSI_RAW_URI, http_raw_uri_params);
+}
+
+static const IpsApi raw_uri_api =
+{
+    {
+        PT_IPS_OPTION,
+        sizeof(IpsApi),
+        IPSAPI_VERSION,
+        1,
+        API_RESERVED,
+        API_OPTIONS,
+        IPS_OPT,
+        IPS_HELP,
+        raw_uri_mod_ctor,
+        HttpBufferRuleOptModule::mod_dtor
+    },
+    OPT_TYPE_DETECTION,
+    0, PROTO_BIT__TCP,
+    nullptr,
+    nullptr,
+    nullptr,
+    nullptr,
+    HttpBufferIpsOption::opt_ctor,
+    HttpBufferIpsOption::opt_dtor,
+    nullptr
+};
+
+//-------------------------------------------------------------------------
+// http_stat_code
+//-------------------------------------------------------------------------
+
+static const Parameter http_stat_code_params[] =
+{
+    { "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 }
+};
+
+#undef IPS_OPT
+#define IPS_OPT "http_stat_code"
+#undef IPS_HELP
+#define IPS_HELP "rule option to set the detection cursor to the HTTP status code"
+
+static Module* stat_code_mod_ctor()
+{
+    return new HttpBufferRuleOptModule(IPS_OPT, IPS_HELP, HTTP_BUFFER_STAT_CODE, CAT_SET_STAT_CODE,
+        BUFFER_PSI_STAT_CODE, http_stat_code_params);
+}
+
+static const IpsApi stat_code_api =
+{
+    {
+        PT_IPS_OPTION,
+        sizeof(IpsApi),
+        IPSAPI_VERSION,
+        1,
+        API_RESERVED,
+        API_OPTIONS,
+        IPS_OPT,
+        IPS_HELP,
+        stat_code_mod_ctor,
+        HttpBufferRuleOptModule::mod_dtor
+    },
+    OPT_TYPE_DETECTION,
+    0, PROTO_BIT__TCP,
+    nullptr,
+    nullptr,
+    nullptr,
+    nullptr,
+    HttpBufferIpsOption::opt_ctor,
+    HttpBufferIpsOption::opt_dtor,
+    nullptr
+};
+
+//-------------------------------------------------------------------------
+// http_stat_msg
+//-------------------------------------------------------------------------
+
+static const Parameter http_stat_msg_params[] =
+{
+    { "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 }
+};
+
+#undef IPS_OPT
+#define IPS_OPT "http_stat_msg"
+#undef IPS_HELP
+#define IPS_HELP "rule option to set the detection cursor to the HTTP status message"
+
+static Module* stat_msg_mod_ctor()
+{
+    return new HttpBufferRuleOptModule(IPS_OPT, IPS_HELP, HTTP_BUFFER_STAT_MSG, CAT_SET_STAT_MSG,
+        BUFFER_PSI_STAT_MSG, http_stat_msg_params);
+}
+
+static const IpsApi stat_msg_api =
+{
+    {
+        PT_IPS_OPTION,
+        sizeof(IpsApi),
+        IPSAPI_VERSION,
+        1,
+        API_RESERVED,
+        API_OPTIONS,
+        IPS_OPT,
+        IPS_HELP,
+        stat_msg_mod_ctor,
+        HttpBufferRuleOptModule::mod_dtor
+    },
+    OPT_TYPE_DETECTION,
+    0, PROTO_BIT__TCP,
+    nullptr,
+    nullptr,
+    nullptr,
+    nullptr,
+    HttpBufferIpsOption::opt_ctor,
+    HttpBufferIpsOption::opt_dtor,
+    nullptr
+};
+
+//-------------------------------------------------------------------------
+// http_trailer
+//-------------------------------------------------------------------------
+
+static const Parameter http_trailer_params[] =
+{
+    { "field", Parameter::PT_STRING, nullptr, nullptr, "restrict to given trailer" },
+    { "request", Parameter::PT_IMPLIED, nullptr, nullptr,
+        "match against the trailers from the request message even when examining the response" },
+    { "with_header", Parameter::PT_IMPLIED, nullptr, nullptr,
+        "parts of this rule examine HTTP response message headers (must be combined with request)"
+        },
+    { "with_body", Parameter::PT_IMPLIED, nullptr, nullptr,
+        "parts of this rule examine HTTP message body (must be combined with request)" },
+    { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
+};
+
+#undef IPS_OPT
+#define IPS_OPT "http_trailer"
+#undef IPS_HELP
+#define IPS_HELP "rule option to set the detection cursor to the normalized trailers"
+
+static Module* trailer_mod_ctor()
+{
+    return new HttpBufferRuleOptModule(IPS_OPT, IPS_HELP, HTTP_BUFFER_TRAILER, CAT_SET_HEADER,
+        BUFFER_PSI_TRAILER, http_trailer_params);
+}
+
+static const IpsApi trailer_api =
+{
+    {
+        PT_IPS_OPTION,
+        sizeof(IpsApi),
+        IPSAPI_VERSION,
+        1,
+        API_RESERVED,
+        API_OPTIONS,
+        IPS_OPT,
+        IPS_HELP,
+        trailer_mod_ctor,
+        HttpBufferRuleOptModule::mod_dtor
+    },
+    OPT_TYPE_DETECTION,
+    0, PROTO_BIT__TCP,
+    nullptr,
+    nullptr,
+    nullptr,
+    nullptr,
+    HttpBufferIpsOption::opt_ctor,
+    HttpBufferIpsOption::opt_dtor,
+    nullptr
+};
+
+//-------------------------------------------------------------------------
+// http_true_ip
+//-------------------------------------------------------------------------
+
+static const Parameter http_true_ip_params[] =
+{
+    { "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 }
+};
+
+#undef IPS_OPT
+#define IPS_OPT "http_true_ip"
+#undef IPS_HELP
+#define IPS_HELP "rule option to set the detection cursor to the final client IP address"
+
+static Module* true_ip_mod_ctor()
+{
+    return new HttpBufferRuleOptModule(IPS_OPT, IPS_HELP, HTTP_BUFFER_TRUE_IP, CAT_SET_OTHER,
+        BUFFER_PSI_TRUE_IP, http_true_ip_params);
+}
+
+static const IpsApi true_ip_api =
+{
+    {
+        PT_IPS_OPTION,
+        sizeof(IpsApi),
+        IPSAPI_VERSION,
+        1,
+        API_RESERVED,
+        API_OPTIONS,
+        IPS_OPT,
+        IPS_HELP,
+        true_ip_mod_ctor,
+        HttpBufferRuleOptModule::mod_dtor
+    },
+    OPT_TYPE_DETECTION,
+    0, PROTO_BIT__TCP,
+    nullptr,
+    nullptr,
+    nullptr,
+    nullptr,
+    HttpBufferIpsOption::opt_ctor,
+    HttpBufferIpsOption::opt_dtor,
+    nullptr
+};
+
+//-------------------------------------------------------------------------
+// http_uri
+//-------------------------------------------------------------------------
+
+static const Parameter http_uri_params[] =
+{
+    { "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" },
+    { "scheme", Parameter::PT_IMPLIED, nullptr, nullptr,
+        "match against scheme section of URI only" },
+    { "host", Parameter::PT_IMPLIED, nullptr, nullptr,
+        "match against host section of URI only" },
+    { "port", Parameter::PT_IMPLIED, nullptr, nullptr,
+        "match against port section of URI only" },
+    { "path", Parameter::PT_IMPLIED, nullptr, nullptr,
+        "match against path section of URI only" },
+    { "query", Parameter::PT_IMPLIED, nullptr, nullptr,
+        "match against query section of URI only" },
+    { "fragment", Parameter::PT_IMPLIED, nullptr, nullptr,
+        "match against fragment section of URI only" },
+    { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
+};
+
+#undef IPS_OPT
+#define IPS_OPT "http_uri"
+#undef IPS_HELP
+#define IPS_HELP "rule option to set the detection cursor to the normalized URI buffer"
+
+static Module* uri_mod_ctor()
+{
+    return new HttpBufferRuleOptModule(IPS_OPT, IPS_HELP, HTTP_BUFFER_URI, CAT_SET_KEY, BUFFER_PSI_URI,
+        http_uri_params);
+}
+
+static const IpsApi uri_api =
+{
+    {
+        PT_IPS_OPTION,
+        sizeof(IpsApi),
+        IPSAPI_VERSION,
+        1,
+        API_RESERVED,
+        API_OPTIONS,
+        IPS_OPT,
+        IPS_HELP,
+        uri_mod_ctor,
+        HttpBufferRuleOptModule::mod_dtor
+    },
+    OPT_TYPE_DETECTION,
+    0, PROTO_BIT__TCP,
+    nullptr,
+    nullptr,
+    nullptr,
+    nullptr,
+    HttpBufferIpsOption::opt_ctor,
+    HttpBufferIpsOption::opt_dtor,
+    nullptr
+};
+
+//-------------------------------------------------------------------------
+// http_version
+//-------------------------------------------------------------------------
+
+static const Parameter http_version_params[] =
+{
+    { "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 }
+};
+
+#undef IPS_OPT
+#define IPS_OPT "http_version"
+#undef IPS_HELP
+#define IPS_HELP "rule option to set the detection cursor to the version buffer"
+
+static Module* version_mod_ctor()
+{
+    return new HttpBufferRuleOptModule(IPS_OPT, IPS_HELP, HTTP_BUFFER_VERSION, CAT_SET_OTHER,
+        BUFFER_PSI_VERSION, http_version_params);
+}
+
+static const IpsApi version_api =
+{
+    {
+        PT_IPS_OPTION,
+        sizeof(IpsApi),
+        IPSAPI_VERSION,
+        1,
+        API_RESERVED,
+        API_OPTIONS,
+        IPS_OPT,
+        IPS_HELP,
+        version_mod_ctor,
+        HttpBufferRuleOptModule::mod_dtor
+    },
+    OPT_TYPE_DETECTION,
+    0, PROTO_BIT__TCP,
+    nullptr,
+    nullptr,
+    nullptr,
+    nullptr,
+    HttpBufferIpsOption::opt_ctor,
+    HttpBufferIpsOption::opt_dtor,
+    nullptr
+};
+
+//-------------------------------------------------------------------------
+// js_data
+//-------------------------------------------------------------------------
+//
+
+#undef IPS_OPT
+#define IPS_OPT "js_data"
+#undef IPS_HELP
+#define IPS_HELP "rule option to set detection cursor to normalized JavaScript data"
+static Module* js_data_mod_ctor()
+{
+    return new HttpBufferRuleOptModule(IPS_OPT, IPS_HELP, BUFFER_JS_DATA, CAT_SET_JS_DATA,
+        BUFFER_PSI_JS_DATA);
+}
+
+static const IpsApi js_data_api =
+{
+    {
+        PT_IPS_OPTION,
+        sizeof(IpsApi),
+        IPSAPI_VERSION,
+        1,
+        API_RESERVED,
+        API_OPTIONS,
+        IPS_OPT,
+        IPS_HELP,
+        js_data_mod_ctor,
+        HttpBufferRuleOptModule::mod_dtor
+    },
+    OPT_TYPE_DETECTION,
+    0, PROTO_BIT__TCP,
+    nullptr,
+    nullptr,
+    nullptr,
+    nullptr,
+    HttpBufferIpsOption::opt_ctor,
+    HttpBufferIpsOption::opt_dtor,
+    nullptr
+};
+
+//-------------------------------------------------------------------------
+// plugins
+//-------------------------------------------------------------------------
+
+const BaseApi* ips_http_client_body = &client_body_api.base;
+const BaseApi* ips_http_cookie = &cookie_api.base;
+const BaseApi* ips_http_header = &header_api.base;
+const BaseApi* ips_http_method = &method_api.base;
+const BaseApi* ips_http_raw_body = &raw_body_api.base;
+const BaseApi* ips_http_raw_cookie = &raw_cookie_api.base;
+const BaseApi* ips_http_raw_header = &raw_header_api.base;
+const BaseApi* ips_http_raw_request = &raw_request_api.base;
+const BaseApi* ips_http_raw_status = &raw_status_api.base;
+const BaseApi* ips_http_raw_trailer = &raw_trailer_api.base;
+const BaseApi* ips_http_raw_uri = &raw_uri_api.base;
+const BaseApi* ips_http_stat_code = &stat_code_api.base;
+const BaseApi* ips_http_stat_msg = &stat_msg_api.base;
+const BaseApi* ips_http_trailer = &trailer_api.base;
+const BaseApi* ips_http_true_ip = &true_ip_api.base;
+const BaseApi* ips_http_uri = &uri_api.base;
+const BaseApi* ips_http_version = &version_api.base;
+const BaseApi* ips_js_data = &js_data_api.base;
diff --git a/src/service_inspectors/http_inspect/ips_http_buffer.h b/src/service_inspectors/http_inspect/ips_http_buffer.h
new file mode 100644 (file)
index 0000000..cd568db
--- /dev/null
@@ -0,0 +1,86 @@
+//--------------------------------------------------------------------------
+// Copyright (C) 2022-2022 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation.  You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//--------------------------------------------------------------------------
+// ips_http_buffer.h author Maya Dagon <mdagon@cisco.com>
+// Refactored from ips_http.h author Tom Peters <thopeter@cisco.com>
+
+#ifndef IPS_HTTP_BUFFER_H
+#define IPS_HTTP_BUFFER_H
+
+#include <array>
+
+#include "profiler/profiler.h"
+#include "framework/ips_option.h"
+#include "framework/module.h"
+
+#include "ips_http.h"
+
+enum BufferPsIdx { BUFFER_PSI_CLIENT_BODY, BUFFER_PSI_COOKIE, BUFFER_PSI_HEADER, BUFFER_PSI_METHOD,
+    BUFFER_PSI_RAW_BODY, BUFFER_PSI_RAW_COOKIE, BUFFER_PSI_RAW_HEADER, BUFFER_PSI_RAW_REQUEST,
+    BUFFER_PSI_RAW_STATUS, BUFFER_PSI_RAW_TRAILER, BUFFER_PSI_RAW_URI, BUFFER_PSI_STAT_CODE,
+    BUFFER_PSI_STAT_MSG, BUFFER_PSI_TRAILER, BUFFER_PSI_TRUE_IP, BUFFER_PSI_URI, BUFFER_PSI_VERSION,
+    BUFFER_PSI_JS_DATA, BUFFER_PSI_VBA_DATA, BUFFER_PSI_MAX };
+
+class HttpBufferRuleOptModule : public HttpRuleOptModule
+{
+public:
+    HttpBufferRuleOptModule(const char* key_, const char* help, HttpEnums::HTTP_RULE_OPT rule_opt_index_,
+        snort::CursorActionType cat_, BufferPsIdx idx_)
+        : HttpRuleOptModule(key_, help, rule_opt_index_, cat_), idx(idx_) {}
+    HttpBufferRuleOptModule(const char* key_, const char* help, HttpEnums::HTTP_RULE_OPT rule_opt_index_,
+        snort::CursorActionType cat_, BufferPsIdx idx_, const snort::Parameter params[])
+        : HttpRuleOptModule(key_, help, rule_opt_index_, cat_, params), idx(idx_) {}
+    snort::ProfileStats* get_profile() const override { return &http_buffer_ps[idx]; }
+    static void mod_dtor(snort::Module* m) { delete m; }
+    bool begin(const char*, int, snort::SnortConfig*) override;
+    bool set(const char*, snort::Value&, snort::SnortConfig*) override;
+    bool end(const char*, int, snort::SnortConfig*) override;
+
+private:
+    friend class HttpBufferIpsOption;
+    static THREAD_LOCAL std::array<snort::ProfileStats, BUFFER_PSI_MAX> http_buffer_ps;
+    const BufferPsIdx idx;
+
+    // URI related params. These affect the sub_id while parsed.
+    // These values are saved to alert on conflicts, only used by ::end
+    bool scheme;
+    bool host;
+    bool port;
+    bool path;
+    bool query;
+    bool fragment;
+};
+
+class HttpBufferIpsOption : public HttpIpsOption
+{
+public:
+    HttpBufferIpsOption(const HttpBufferRuleOptModule* cm) :
+        HttpIpsOption(cm, RULE_OPTION_TYPE_BUFFER_SET), idx(cm->idx),
+        key(cm->key) {}
+    EvalStatus eval(Cursor&, snort::Packet*) override;
+
+    static IpsOption* opt_ctor(snort::Module* m, OptTreeNode*)
+    { return new HttpBufferIpsOption((HttpBufferRuleOptModule*)m); }
+
+    static void opt_dtor(snort::IpsOption* p) { delete p; }
+
+private:
+    const BufferPsIdx idx;
+    const char* const key;
+};
+
+#endif
diff --git a/src/service_inspectors/http_inspect/ips_http_num_hdrs.cc b/src/service_inspectors/http_inspect/ips_http_num_hdrs.cc
new file mode 100644 (file)
index 0000000..545167d
--- /dev/null
@@ -0,0 +1,202 @@
+//--------------------------------------------------------------------------
+// Copyright (C) 2022-2022 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation.  You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//--------------------------------------------------------------------------
+// ips_http_num_hdrs.cc author Maya Dagon <mdagon@cisco.com>
+// Refactored from ips_http.cc author Tom Peters <thopeter@cisco.com>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "ips_http_num_hdrs.h"
+
+#include "framework/cursor.h"
+#include "hash/hash_key_operations.h"
+#include "log/messages.h"
+#include "parser/parse_utils.h"
+#include "protocols/packet.h"
+#include "service_inspectors/http2_inspect/http2_flow_data.h"
+
+#include "http_common.h"
+#include "http_enum.h"
+#include "http_flow_data.h"
+#include "http_inspect.h"
+#include "http_msg_head_shared.h"
+
+using namespace snort;
+using namespace HttpCommon;
+using namespace HttpEnums;
+
+THREAD_LOCAL std::array<ProfileStats, NUM_HDRS_PSI_MAX> HttpNumHdrsRuleOptModule::http_num_hdrs_ps;
+
+const std::string hdrs_num_range = "0:" + std::to_string(HttpMsgHeadShared::MAX_HEADERS);
+
+bool HttpNumHdrsRuleOptModule::begin(const char*, int, SnortConfig*)
+{
+    HttpRuleOptModule::begin(nullptr, 0, nullptr);
+    range.init();
+    if (rule_opt_index == HTTP_RANGE_NUM_HDRS)
+        inspect_section = IS_FLEX_HEADER;
+    else
+    {
+        inspect_section = IS_TRAILER;
+        is_trailer_opt = true;
+    }
+
+    return true;
+}
+
+bool HttpNumHdrsRuleOptModule::set(const char*, Value& v, SnortConfig*)
+{
+    if (v.is("~range"))
+        return range.validate(v.get_string(), hdrs_num_range.c_str());
+    
+    return HttpRuleOptModule::set(nullptr, v, nullptr);
+}
+
+
+uint32_t HttpNumHdrsIpsOption::hash() const
+{
+    uint32_t a = HttpIpsOption::hash();
+    uint32_t b = range.hash();
+    uint32_t c = 0;
+    mix(a,b,c);
+    finalize(a,b,c);
+    return c;
+}
+
+bool HttpNumHdrsIpsOption::operator==(const IpsOption& ips) const
+{
+    const HttpNumHdrsIpsOption& hio = static_cast<const HttpNumHdrsIpsOption&>(ips);
+    return HttpIpsOption::operator==(static_cast<const HttpIpsOption&>(ips)) &&
+           range == hio.range;
+}
+
+IpsOption::EvalStatus HttpNumHdrsIpsOption::eval(Cursor&, Packet* p)
+{
+    RuleProfile profile(HttpNumHdrsRuleOptModule::http_num_hdrs_ps[idx]);
+
+    const HttpInspect* const hi = eval_helper(p);
+    if (hi == nullptr)
+        return NO_MATCH;
+
+    const int32_t num_lines = hi->http_get_num_headers(p, buffer_info);
+    if (num_lines != HttpCommon::STAT_NOT_PRESENT && range.eval(num_lines))
+        return MATCH;
+
+    return NO_MATCH;
+}
+
+//-------------------------------------------------------------------------
+// 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, hdrs_num_range.c_str(), 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 HttpNumHdrsRuleOptModule(IPS_OPT, IPS_HELP, HTTP_RANGE_NUM_HDRS, CAT_SET_OTHER,
+       NUM_HDRS_PSI_HDRS, 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,
+        HttpNumHdrsRuleOptModule::mod_dtor
+    },
+    OPT_TYPE_DETECTION,
+    0, PROTO_BIT__TCP,
+    nullptr,
+    nullptr,
+    nullptr,
+    nullptr,
+    HttpNumHdrsIpsOption::opt_ctor,
+    HttpNumHdrsIpsOption::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 HttpNumHdrsRuleOptModule(IPS_OPT, IPS_HELP, HTTP_RANGE_NUM_TRAILERS, CAT_SET_OTHER,
+        NUM_HDRS_PSI_TRAILERS, 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,
+        HttpNumHdrsRuleOptModule::mod_dtor
+    },
+    OPT_TYPE_DETECTION,
+    0, PROTO_BIT__TCP,
+    nullptr,
+    nullptr,
+    nullptr,
+    nullptr,
+    HttpNumHdrsIpsOption::opt_ctor,
+    HttpNumHdrsIpsOption::opt_dtor,
+    nullptr
+};
+
+//-------------------------------------------------------------------------
+// plugins
+//-------------------------------------------------------------------------
+const BaseApi* ips_http_num_headers = &num_headers_api.base;
+const BaseApi* ips_http_num_trailers = &num_trailers_api.base;
+
diff --git a/src/service_inspectors/http_inspect/ips_http_num_hdrs.h b/src/service_inspectors/http_inspect/ips_http_num_hdrs.h
new file mode 100644 (file)
index 0000000..54a8da2
--- /dev/null
@@ -0,0 +1,77 @@
+//--------------------------------------------------------------------------
+// Copyright (C) 2022-2022 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation.  You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//--------------------------------------------------------------------------
+// ips_http_num_hdrs.h author Maya Dagon <mdagon@cisco.com>
+// Refactored from ips_http.h author Tom Peters <thopeter@cisco.com>
+
+#ifndef IPS_HTTP_NUM_HDRS_H
+#define IPS_HTTP_NUM_HDRS_H
+
+#include <array>
+
+#include "profiler/profiler.h"
+#include "framework/ips_option.h"
+#include "framework/module.h"
+#include "framework/range.h"
+
+#include "http_enum.h"
+#include "ips_http.h"
+
+enum NumHdrsPsIdx { NUM_HDRS_PSI_HDRS, NUM_HDRS_PSI_TRAILERS, NUM_HDRS_PSI_MAX };
+
+class HttpNumHdrsRuleOptModule : public HttpRuleOptModule
+{
+public:
+    HttpNumHdrsRuleOptModule(const char* key_, const char* help, HttpEnums::HTTP_RULE_OPT rule_opt_index_,
+        snort::CursorActionType cat_, NumHdrsPsIdx idx_, const snort::Parameter params[])
+        : HttpRuleOptModule(key_, help, rule_opt_index_, cat_, params), idx(idx_) {}
+
+    snort::ProfileStats* get_profile() const override
+    { return &http_num_hdrs_ps[idx]; }
+  
+    static void mod_dtor(snort::Module* m) { delete m; }
+    bool begin(const char*, int, snort::SnortConfig*) override;
+    bool set(const char*, snort::Value&, snort::SnortConfig*) override;
+
+private:
+    friend class HttpNumHdrsIpsOption;
+    static THREAD_LOCAL std::array<snort::ProfileStats, NUM_HDRS_PSI_MAX> http_num_hdrs_ps;
+    const NumHdrsPsIdx idx;
+    snort::RangeCheck range;
+};
+
+class HttpNumHdrsIpsOption : public HttpIpsOption
+{
+public:
+    HttpNumHdrsIpsOption(const HttpNumHdrsRuleOptModule* cm) :
+        HttpIpsOption(cm, RULE_OPTION_TYPE_OTHER), idx(cm->idx), range(cm->range) {}
+    EvalStatus eval(Cursor&, snort::Packet*) override;
+    uint32_t hash() const override;
+    bool operator==(const snort::IpsOption& ips) const override;
+
+    static IpsOption* opt_ctor(snort::Module* m, OptTreeNode*)
+    { return new HttpNumHdrsIpsOption((HttpNumHdrsRuleOptModule*)m); }
+
+    static void opt_dtor(snort::IpsOption* p) { delete p; }
+
+private:
+    const NumHdrsPsIdx idx;
+    const snort::RangeCheck range;
+};
+
+#endif
+
diff --git a/src/service_inspectors/http_inspect/ips_http_param.cc b/src/service_inspectors/http_inspect/ips_http_param.cc
new file mode 100644 (file)
index 0000000..17bc528
--- /dev/null
@@ -0,0 +1,174 @@
+//--------------------------------------------------------------------------
+// Copyright (C) 2022-2022 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation.  You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//--------------------------------------------------------------------------
+// ips_http_param.cc author Maya Dagon <mdagon@cisco.com>
+// Refactored from ips_http.cc author Tom Peters <thopeter@cisco.com>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "ips_http_param.h"
+
+#include "framework/cursor.h"
+#include "hash/hash_key_operations.h"
+#include "log/messages.h"
+#include "parser/parse_utils.h"
+#include "protocols/packet.h"
+
+#include "http_common.h"
+#include "http_enum.h"
+#include "http_inspect.h"
+#include "http_param.h"
+
+using namespace snort;
+using namespace HttpCommon;
+using namespace HttpEnums;
+
+THREAD_LOCAL ProfileStats HttpParamRuleOptModule::http_param_ps;
+
+bool HttpParamRuleOptModule::begin(const char*, int, SnortConfig*)
+{
+    HttpRuleOptModule::begin(nullptr, 0, nullptr);
+    param.clear();
+    nocase = false;
+    inspect_section = IS_FLEX_HEADER;
+    return true;
+}
+
+bool HttpParamRuleOptModule::set(const char*, Value& v, SnortConfig*)
+{
+    if (v.is("~param"))
+    {
+        std::string bc = v.get_string();
+        bool negated = false;
+        if (!parse_byte_code(bc.c_str(), negated, param) or negated)
+            ParseError("Invalid http_param");
+    }
+    else if (v.is("nocase"))
+    {
+        nocase = true;
+    }
+    return true;
+}
+
+uint32_t HttpParamIpsOption::hash() const
+{
+    uint32_t a = HttpIpsOption::hash();
+    uint32_t b = http_param.is_nocase() ? 1 : 0;
+    uint32_t c = 0;
+    mix_str(a,b,c,http_param.c_str(),http_param.length());
+    finalize(a,b,c);
+    return a;
+}
+
+bool HttpParamRuleOptModule::end(const char*, int, SnortConfig*)
+{
+    if (param.length() == 0)
+        ParseError("Specify parameter name");
+    return true;
+}
+
+bool HttpParamIpsOption::operator==(const IpsOption& ips) const
+{
+    const HttpParamIpsOption& hio = static_cast<const HttpParamIpsOption&>(ips);
+
+    return HttpIpsOption::operator==(static_cast<const HttpIpsOption&>(ips)) &&
+           http_param == hio.http_param;
+}
+
+bool HttpParamIpsOption::retry(Cursor& current_cursor, const Cursor&)
+{
+    HttpCursorData* cd = (HttpCursorData*)current_cursor.get_data(HttpCursorData::id);
+
+    if (cd)
+        return cd->retry();
+
+    return false;
+}
+
+IpsOption::EvalStatus HttpParamIpsOption::eval(Cursor& c, Packet* p)
+{
+    RuleProfile profile(HttpParamRuleOptModule::http_param_ps);
+
+    const HttpInspect* const hi = eval_helper(p);
+    if (hi == nullptr)
+        return NO_MATCH;
+    
+    const Field& http_buffer = hi->http_get_param_buf(c, p, http_param);
+    if (http_buffer.length() <= 0)
+        return NO_MATCH;
+
+    c.set(key, http_buffer.start(), http_buffer.length());
+
+    return MATCH;
+}
+
+//-------------------------------------------------------------------------
+// http_param
+//-------------------------------------------------------------------------
+
+static const Parameter http_param_params[] =
+{
+    { "~param", Parameter::PT_STRING, nullptr, nullptr,
+        "parameter to match" },
+    { "nocase", Parameter::PT_IMPLIED, nullptr, nullptr,
+        "case insensitive match" },
+    { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
+};
+
+#undef IPS_OPT
+#define IPS_OPT "http_param"
+#undef IPS_HELP
+#define IPS_HELP "rule option to set the detection cursor to the value of the specified HTTP parameter key which may be in the query or body"
+
+static Module* param_mod_ctor()
+{
+    return new HttpParamRuleOptModule(IPS_OPT, IPS_HELP, HTTP_BUFFER_PARAM, CAT_SET_OTHER,
+        http_param_params);
+}
+
+static const IpsApi param_api =
+{
+    {
+        PT_IPS_OPTION,
+        sizeof(IpsApi),
+        IPSAPI_VERSION,
+        1,
+        API_RESERVED,
+        API_OPTIONS,
+        IPS_OPT,
+        IPS_HELP,
+        param_mod_ctor,
+        HttpParamRuleOptModule::mod_dtor
+    },
+    OPT_TYPE_DETECTION,
+    0, PROTO_BIT__TCP,
+    nullptr,
+    nullptr,
+    nullptr,
+    nullptr,
+    HttpParamIpsOption::opt_ctor,
+    HttpParamIpsOption::opt_dtor,
+    nullptr
+};
+
+//-------------------------------------------------------------------------
+// plugins
+//-------------------------------------------------------------------------
+
+const BaseApi* ips_http_param = &param_api.base;
diff --git a/src/service_inspectors/http_inspect/ips_http_param.h b/src/service_inspectors/http_inspect/ips_http_param.h
new file mode 100644 (file)
index 0000000..40cf593
--- /dev/null
@@ -0,0 +1,73 @@
+//--------------------------------------------------------------------------
+// Copyright (C) 2022-2022 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation.  You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//--------------------------------------------------------------------------
+// ips_http_param.h author Maya Dagon <mdagon@cisco.com>
+// Refactored from ips_http.h author Tom Peters <thopeter@cisco.com>
+
+#ifndef IPS_HTTP_PARAM_H
+#define IPS_HTTP_PARAM_H
+
+#include "profiler/profiler.h"
+#include "framework/ips_option.h"
+#include "framework/module.h"
+
+#include "http_param.h"
+#include "ips_http.h"
+
+
+class HttpParamRuleOptModule : public HttpRuleOptModule
+{
+public:
+    HttpParamRuleOptModule(const char* key_, const char* help, HttpEnums::HTTP_RULE_OPT rule_opt_index_,
+        snort::CursorActionType cat_, const snort::Parameter params[])
+        : HttpRuleOptModule(key_, help, rule_opt_index_, cat_, params) {}
+    snort::ProfileStats* get_profile() const override { return &http_param_ps; }
+    static void mod_dtor(snort::Module* m) { delete m; }
+    bool begin(const char*, int, snort::SnortConfig*) override;
+    bool set(const char*, snort::Value&, snort::SnortConfig*) override;
+    bool end(const char*, int, snort::SnortConfig*) override;
+
+private:
+    friend class HttpParamIpsOption;
+    static THREAD_LOCAL snort::ProfileStats http_param_ps;
+  
+    std::string param;        // provide buffer containing specific parameter
+    bool nocase;             // case insensitive match
+};
+
+class HttpParamIpsOption : public HttpIpsOption
+{
+public:
+    HttpParamIpsOption(const HttpParamRuleOptModule* cm) :
+        HttpIpsOption(cm, RULE_OPTION_TYPE_BUFFER_SET),
+        key(cm->key), http_param(cm->param, cm->nocase) {}
+    EvalStatus eval(Cursor&, snort::Packet*) override;
+    uint32_t hash() const override;
+    bool operator==(const snort::IpsOption& ips) const override;
+
+    static IpsOption* opt_ctor(snort::Module* m, OptTreeNode*)
+    { return new HttpParamIpsOption((HttpParamRuleOptModule*)m); }
+
+    static void opt_dtor(snort::IpsOption* p) { delete p; }
+    bool retry(Cursor& , const Cursor&) override;
+
+private:
+    const char* const key;
+    const HttpParam http_param; 
+};
+
+#endif
diff --git a/src/service_inspectors/http_inspect/ips_http_version.cc b/src/service_inspectors/http_inspect/ips_http_version.cc
new file mode 100644 (file)
index 0000000..7a60c31
--- /dev/null
@@ -0,0 +1,188 @@
+//--------------------------------------------------------------------------
+// Copyright (C) 2022-2022 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation.  You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//--------------------------------------------------------------------------
+// ips_http_version.cc author Maya Dagon <mdagon@cisco.com>
+// Refactored from ips_http.cc author Tom Peters <thopeter@cisco.com>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "ips_http_version.h"
+
+#include "framework/cursor.h"
+#include "hash/hash_key_operations.h"
+#include "log/messages.h"
+#include "parser/parse_utils.h"
+#include "protocols/packet.h"
+
+#include "http_common.h"
+#include "http_enum.h"
+#include "http_inspect.h"
+
+using namespace snort;
+using namespace HttpCommon;
+using namespace HttpEnums;
+
+THREAD_LOCAL ProfileStats HttpVersionRuleOptModule::http_version_ps;
+
+bool HttpVersionRuleOptModule::begin(const char*, int, SnortConfig*)
+{
+    HttpRuleOptModule::begin(nullptr, 0, nullptr);
+    inspect_section = IS_FLEX_HEADER;
+    version_flags = 0;
+    return true;
+}
+
+static const std::map <std::string, VersionId> VersionStrToEnum =
+{
+    { "malformed", VERS__PROBLEMATIC },
+    { "other", VERS__OTHER },
+    { "1.0", VERS_1_0 },
+    { "1.1", VERS_1_1 },
+    { "2.0", VERS_2_0 },
+    { "0.9", VERS_0_9 }
+};
+
+bool HttpVersionRuleOptModule::parse_version_list(Value& v)
+{
+    v.set_first_token();
+    std::string tok;
+
+    while ( v.get_next_token(tok) )
+    {
+        if (tok[0] == '"')
+            tok.erase(0, 1);
+
+        if (tok.length() == 0)
+            continue;
+
+        if (tok[tok.length()-1] == '"')
+            tok.erase(tok.length()-1, 1);
+
+        auto iter = VersionStrToEnum.find(tok);
+        if (iter == VersionStrToEnum.end())
+        {
+            ParseError("Unrecognized version %s\n", tok.c_str());
+            return false;
+        }
+
+        version_flags[iter->second - VERS__MIN] = true;
+    }
+    return true;
+}
+
+bool HttpVersionRuleOptModule::set(const char*, Value& v, SnortConfig*)
+{
+    if (v.is("~version_list"))
+    {
+        return parse_version_list(v);
+    }
+    return HttpRuleOptModule::set(nullptr, v, nullptr);
+}
+
+uint32_t HttpVersionIpsOption::hash() const
+{
+    uint32_t a = HttpIpsOption::hash();
+    uint32_t b = (uint32_t)version_flags.to_ulong();
+    uint32_t c = 0;
+    mix(a,b,c);
+    finalize(a,b,c);
+    return c;
+}
+
+bool HttpVersionIpsOption::operator==(const IpsOption& ips) const
+{
+    const HttpVersionIpsOption& hio = static_cast<const HttpVersionIpsOption&>(ips);
+    return HttpIpsOption::operator==(static_cast<const HttpIpsOption&>(ips)) &&
+           version_flags == hio.version_flags;
+}
+
+IpsOption::EvalStatus HttpVersionIpsOption::eval(Cursor&, Packet* p)
+{
+    RuleProfile profile(HttpVersionRuleOptModule::http_version_ps);
+
+    const HttpInspect* const hi = eval_helper(p);
+    if (hi == nullptr)
+        return NO_MATCH;
+
+    const VersionId version = hi->http_get_version_id(p, buffer_info);
+
+    if (version_flags[version - HttpEnums::VERS__MIN])
+        return MATCH;
+
+    return NO_MATCH;
+}
+
+//-------------------------------------------------------------------------
+// http_version_match
+//-------------------------------------------------------------------------
+#undef IPS_OPT
+#define IPS_OPT "http_version_match"
+#undef IPS_HELP
+#define IPS_HELP "rule option to match version to listed values"
+
+static const Parameter version_match_params[] =
+{
+    { "~version_list", Parameter::PT_STRING, nullptr, nullptr,
+        "space-separated list of versions to match" },
+    { "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* version_match_mod_ctor()
+{
+    return new HttpVersionRuleOptModule(IPS_OPT, IPS_HELP, HTTP_VERSION_MATCH, CAT_SET_OTHER,
+        version_match_params);
+}
+
+static const IpsApi version_match_api =
+{
+    {
+        PT_IPS_OPTION,
+        sizeof(IpsApi),
+        IPSAPI_VERSION,
+        1,
+        API_RESERVED,
+        API_OPTIONS,
+        IPS_OPT,
+        IPS_HELP,
+        version_match_mod_ctor,
+        HttpVersionRuleOptModule::mod_dtor
+    },
+    OPT_TYPE_DETECTION,
+    0, PROTO_BIT__TCP,
+    nullptr,
+    nullptr,
+    nullptr,
+    nullptr,
+    HttpVersionIpsOption::opt_ctor,
+    HttpVersionIpsOption::opt_dtor,
+    nullptr
+};
+
+//-------------------------------------------------------------------------
+// plugins
+//-------------------------------------------------------------------------
+const BaseApi* ips_http_version_match = &version_match_api.base;
diff --git a/src/service_inspectors/http_inspect/ips_http_version.h b/src/service_inspectors/http_inspect/ips_http_version.h
new file mode 100644 (file)
index 0000000..2a89c62
--- /dev/null
@@ -0,0 +1,70 @@
+//--------------------------------------------------------------------------
+// Copyright (C) 2022-2022 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation.  You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//--------------------------------------------------------------------------
+// ips_http_version.h author Maya Dagon <mdagon@cisco.com>
+// Refactored from ips_http.h author Tom Peters <thopeter@cisco.com>
+
+#ifndef IPS_HTTP_VERSION_H
+#define IPS_HTTP_VERSION_H
+
+#include "profiler/profiler.h"
+#include "framework/ips_option.h"
+#include "framework/module.h"
+
+#include "http_enum.h"
+#include "ips_http.h"
+
+class HttpVersionRuleOptModule : public HttpRuleOptModule
+{
+public:
+    HttpVersionRuleOptModule(const char* key_, const char* help, HttpEnums::HTTP_RULE_OPT rule_opt_index_,
+        snort::CursorActionType cat_, const snort::Parameter params[])
+        : HttpRuleOptModule(key_, help, rule_opt_index_, cat_, params){}
+    snort::ProfileStats* get_profile() const override { return &http_version_ps; }
+    static void mod_dtor(snort::Module* m) { delete m; }
+    bool begin(const char*, int, snort::SnortConfig*) override;
+    bool set(const char*, snort::Value&, snort::SnortConfig*) override;
+
+private:
+    friend class HttpVersionIpsOption;
+    static THREAD_LOCAL snort::ProfileStats http_version_ps;
+    static const int version_size = HttpEnums::VERS__MAX - HttpEnums::VERS__MIN + 1;
+
+    std::bitset<version_size> version_flags;
+
+    bool parse_version_list(snort::Value& v);
+};
+
+class HttpVersionIpsOption : public HttpIpsOption
+{
+public:
+    HttpVersionIpsOption(const HttpVersionRuleOptModule* cm) :
+        HttpIpsOption(cm, RULE_OPTION_TYPE_OTHER), version_flags(cm->version_flags) {}
+    EvalStatus eval(Cursor&, snort::Packet*) override;
+    uint32_t hash() const override;
+    bool operator==(const snort::IpsOption& ips) const override;
+
+    static IpsOption* opt_ctor(snort::Module* m, OptTreeNode*)
+    { return new HttpVersionIpsOption((HttpVersionRuleOptModule*)m); }
+
+    static void opt_dtor(snort::IpsOption* p) { delete p; }
+
+private:
+    const std::bitset<HttpVersionRuleOptModule::version_size> version_flags;
+};
+
+#endif