]> git.ipfire.org Git - thirdparty/snort3.git/commitdiff
Pull request #3176: US 684353: http_inspect: number of header lines rule option
authorTom Peters (thopeter) <thopeter@cisco.com>
Tue, 30 Nov 2021 17:29:53 +0000 (17:29 +0000)
committerTom Peters (thopeter) <thopeter@cisco.com>
Tue, 30 Nov 2021 17:29:53 +0000 (17:29 +0000)
Merge in SNORT/snort3 from ~MDAGON/snort3:hdrs_num2 to master

Squashed commit of the following:

commit 6e4ab5896b6911913dfff1a681516f90938f5326
Author: Maya Dagon <mdagon@cisco.com>
Date:   Tue Aug 3 15:55:26 2021 -0400

    http_inspect: new rule options num_headers, num_trailers

34 files changed:
doc/user/http_inspect.txt
src/framework/range.cc
src/framework/range.h
src/ips_options/ips_ack.cc
src/ips_options/ips_bufferlen.cc
src/ips_options/ips_dsize.cc
src/ips_options/ips_fragoffset.cc
src/ips_options/ips_icmp_id.cc
src/ips_options/ips_icmp_seq.cc
src/ips_options/ips_icode.cc
src/ips_options/ips_id.cc
src/ips_options/ips_itype.cc
src/ips_options/ips_seq.cc
src/ips_options/ips_tos.cc
src/ips_options/ips_ttl.cc
src/ips_options/ips_window.cc
src/service_inspectors/cip/ips_cip_attribute.cc
src/service_inspectors/cip/ips_cip_class.cc
src/service_inspectors/cip/ips_cip_connpathclass.cc
src/service_inspectors/cip/ips_cip_enipcommand.cc
src/service_inspectors/cip/ips_cip_instance.cc
src/service_inspectors/cip/ips_cip_service.cc
src/service_inspectors/cip/ips_cip_status.cc
src/service_inspectors/dce_rpc/ips_dce_iface.cc
src/service_inspectors/http_inspect/http_api.cc
src/service_inspectors/http_inspect/http_enum.h
src/service_inspectors/http_inspect/http_inspect.cc
src/service_inspectors/http_inspect/http_inspect.h
src/service_inspectors/http_inspect/http_msg_head_shared.h
src/service_inspectors/http_inspect/http_msg_section.cc
src/service_inspectors/http_inspect/http_msg_section.h
src/service_inspectors/http_inspect/ips_http.cc
src/service_inspectors/http_inspect/ips_http.h
src/stream/tcp/ips_stream_size.cc

index 54a7150f9de0578ff65fe54344ca132e0d824cf8..c2d848c5ca8d8d85d651095d538d374fddbc71cb 100755 (executable)
@@ -667,6 +667,13 @@ 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
+
+These rule options are used to check the number of headers and
+trailers, respectively. Checks available: equal to "=" or just value,
+not "!" or "!=",  less than "<", greater than ">", less or equal to "<=",
+less or greater than ">=", in range "<>", in range or equal to "<=>".
+
 ==== Timing issues and combining rule options
 
 HTTP inspector is stateful. That means it is aware of a bigger picture than
index 275a6221f335a3d85e4acbf95d66fcb7ea652407..66d356b4bb0caad1f7c81bcade254e56ede94e09 100644 (file)
@@ -28,6 +28,8 @@
 #include <cstring>
 #include <string>
 
+#include "hash/hash_key_operations.h"
+
 using namespace snort;
 using namespace std;
 
@@ -308,6 +310,16 @@ bool RangeCheck::validate(const char* s, const char* r)
     return true;
 }
 
+uint32_t RangeCheck::hash() const
+{
+    uint32_t a = op;
+    uint32_t b = min;
+    uint32_t c = max;
+    mix(a,b,c);
+    finalize(a,b,c);
+    return a;
+}
+
 //--------------------------------------------------------------------------
 // unit tests: EQ, NOT, LT, LE, GT, GE, LG, LEG
 //--------------------------------------------------------------------------
index 7f8324c19f4a18bf504ed843f27cf4d42dff0b2e..4b53a1593c639de1b5fc03340f8df4baa1012398 100644 (file)
@@ -43,8 +43,6 @@ public:
         EQ, NOT, LT, LE, GT, GE, LG, LEG, MAX
     };
 
-    // Warning: FragOffsetOption computes its hash function using all the data members of
-    // RangeCheck. Any change to the following may require changes in ips_fragoffset.cc.
     Op op = MAX;
     long min = 0;
     long max = 0;
@@ -57,6 +55,7 @@ public:
     bool parse(const char* s);
     bool eval(long) const;
     bool validate(const char* s, const char* r);
+    uint32_t hash() const;
 };
 }
 #endif
index 3f4d92a079b0fa40b87d72eedbc6a4d343de366d..dcf3df4760b16c278cc345fbc82c4190152b8780 100644 (file)
@@ -60,13 +60,11 @@ private:
 
 uint32_t TcpAckOption::hash() const
 {
-    uint32_t a = config.op;
-    uint32_t b = config.min;
-    uint32_t c = config.max;
+    uint32_t a = config.hash();
+    uint32_t b = IpsOption::hash();
+    uint32_t c = 0;
 
     mix(a,b,c);
-    a += IpsOption::hash();
-
     finalize(a,b,c);
     return c;
 }
index 21ee5870d7c11ffb0bca6f1079fe38058fdc070c..d7bedd6658271c27f9b3d14f0bf6a8574f2b46f1 100644 (file)
@@ -60,13 +60,11 @@ private:
 
 uint32_t LenOption::hash() const
 {
-    uint32_t a = config.op;
-    uint32_t b = config.min;
-    uint32_t c = config.max;
+    uint32_t a = config.hash();
+    uint32_t b = IpsOption::hash();
+    uint32_t c = 0;
 
     mix(a,b,c);
-    a += IpsOption::hash();
-
     finalize(a,b,c);
     return c;
 }
index 2c59e3def4041ced8becec5a99b1786af17ebd72..93b1151ed4b85095b8cac38df045d1994c95f3ce 100644 (file)
@@ -57,13 +57,11 @@ private:
 
 uint32_t DsizeOption::hash() const
 {
-    uint32_t a = config.min;
-    uint32_t b = config.max;
-    uint32_t c = config.op;
+    uint32_t a = config.hash();
+    uint32_t b = IpsOption::hash();
+    uint32_t c = 0;
 
     mix(a,b,c);
-    a += IpsOption::hash();
-
     finalize(a,b,c);
     return c;
 }
index fbae6b56fae5b42903c84fdd541030b6d04dfc7a..7efcfcef6da39dba9b0499f686df2c5e17ed435b 100644 (file)
@@ -56,13 +56,11 @@ private:
 
 uint32_t FragOffsetOption::hash() const
 {
-    uint32_t a = config.op;
-    uint32_t b = (uint32_t)config.min;
-    uint32_t c = (uint32_t)config.max;
+    uint32_t a = config.hash();
+    uint32_t b = IpsOption::hash();
+    uint32_t c = 0;
 
     mix(a,b,c);
-    a += IpsOption::hash();
-
     finalize(a,b,c);
     return c;
 }
index 12f9d22bbf7330fcb6e74ca6a831afb640ec8369..e89bde3ae45a6896e68d47a43365c5b15c5bbe3a 100644 (file)
@@ -80,13 +80,11 @@ private:
 
 uint32_t IcmpIdOption::hash() const
 {
-    uint32_t a = config.op;
-    uint32_t b = config.min;
-    uint32_t c = config.max;
+    uint32_t a = config.hash();
+    uint32_t b = IpsOption::hash();
+    uint32_t c = 0;
 
     mix(a,b,c);
-    a += IpsOption::hash();
-
     finalize(a,b,c);
     return c;
 }
index 147cbc2dabec6b48e30fb865af280e38b7f861bf..fff474c9c96f50d28e8c626a2f3578b28485331d 100644 (file)
@@ -80,13 +80,11 @@ private:
 
 uint32_t IcmpSeqOption::hash() const
 {
-    uint32_t a = config.op;
-    uint32_t b = config.min;
-    uint32_t c = config.max;
+    uint32_t a = config.hash();
+    uint32_t b = IpsOption::hash();
+    uint32_t c = 0;
 
     mix(a,b,c);
-    a += IpsOption::hash();
-
     finalize(a,b,c);
     return c;
 }
index 947cab3212018ba9898ee8bea51f2808fdbb952c..ddf2d94e701ea525b30692aa0869ef2318951f3f 100644 (file)
@@ -57,13 +57,11 @@ private:
 
 uint32_t IcodeOption::hash() const
 {
-    uint32_t a = config.op;
-    uint32_t b = config.min;
-    uint32_t c = config.max;
+    uint32_t a = config.hash();
+    uint32_t b = IpsOption::hash();
+    uint32_t c = 0;
 
     mix(a,b,c);
-    a += IpsOption::hash();
-
     finalize(a,b,c);
     return c;
 }
index b59cfd52ce34e2ab66aeaed71299ef3bc454e8b2..b4f83a81a5a846ab32e3235279ceb0badb3cd88f 100644 (file)
@@ -56,13 +56,11 @@ private:
 
 uint32_t IpIdOption::hash() const
 {
-    uint32_t a = config.op;
-    uint32_t b = config.min;
-    uint32_t c = config.max;
+    uint32_t a = config.hash();
+    uint32_t b = IpsOption::hash();
+    uint32_t c = 0;
 
     mix(a,b,c);
-    a += IpsOption::hash();
-
     finalize(a,b,c);
     return c;
 }
index 89b7040ce05d6afdc6236a9da47b8b0297162d9a..9fc4de5f3f3aff86918ed25fc5740119d5e690ea 100644 (file)
@@ -57,13 +57,11 @@ private:
 
 uint32_t IcmpTypeOption::hash() const
 {
-    uint32_t a = config.op;
-    uint32_t b = config.min;
-    uint32_t c = config.max;
+    uint32_t a = config.hash();
+    uint32_t b = IpsOption::hash();
+    uint32_t c = 0;
 
     mix(a,b,c);
-    a += IpsOption::hash();
-
     finalize(a,b,c);
     return c;
 }
index 9376aa9813a705ef15a734b020dbe40a5c73df00..771e9c5e5c61c43ad2b4ae3deb49c29b5587566a 100644 (file)
@@ -57,13 +57,11 @@ private:
 
 uint32_t TcpSeqOption::hash() const
 {
-    uint32_t a = config.op;
-    uint32_t b = config.min;
-    uint32_t c = config.max;
+    uint32_t a = config.hash();
+    uint32_t b = IpsOption::hash();
+    uint32_t c = 0;
 
     mix(a,b,c);
-    a += IpsOption::hash();
-
     finalize(a,b,c);
     return c;
 }
index c8a7d6d7a93a71f2ad614360baa7abd42a449f8a..46b995c0568bea1ea51c9fd93382fbeddc7e9c49 100644 (file)
@@ -56,13 +56,11 @@ public:
 
 uint32_t IpTosOption::hash() const
 {
-    uint32_t a = config.op;
-    uint32_t b = config.min;
-    uint32_t c = config.max;
+    uint32_t a = config.hash();
+    uint32_t b = IpsOption::hash();
+    uint32_t c = 0;
 
     mix(a,b,c);
-    a += IpsOption::hash();
-
     finalize(a,b,c);
     return c;
 }
index 2f1fddf5fb14988ab75173845a26c8d87cd7a7ba..b88146999e033a76df1513e544666dd5f19ae3e4 100644 (file)
@@ -56,12 +56,9 @@ private:
 
 uint32_t TtlOption::hash() const
 {
-    uint32_t a = config.op;
-    uint32_t b = config.min;
-    uint32_t c = config.max;
-
-    mix(a,b,c);
-    a += IpsOption::hash();
+    uint32_t a = config.hash();
+    uint32_t b = IpsOption::hash();
+    uint32_t c = 0;
 
     mix(a,b,c);
     finalize(a,b,c);
index 0c57d8132a3696c6e45792426695fc274c9eaf99..c176ac7aa123fecf86461fd88be57a1b69a9b157 100644 (file)
@@ -57,13 +57,11 @@ private:
 
 uint32_t TcpWinOption::hash() const
 {
-    uint32_t a = config.op;
-    uint32_t b = config.min;
-    uint32_t c = config.max;
+    uint32_t a = config.hash();
+    uint32_t b = IpsOption::hash();
+    uint32_t c = 0;
 
     mix(a,b,c);
-    a += IpsOption::hash();
-
     finalize(a,b,c);
     return c;
 }
index a3bd448d61fb1f3daf266424948121d6d2bd6793..a2e76ce1bb7a51e9f051ce685fe604d30aff1e13 100644 (file)
@@ -62,13 +62,11 @@ private:
 
 uint32_t CipAttributeOption::hash() const
 {
-    uint32_t a = cip_attr.op;
-    uint32_t b = cip_attr.min;
-    uint32_t c = cip_attr.max;
+    uint32_t a = cip_attr.hash();
+    uint32_t b = IpsOption::hash();
+    uint32_t c = 0;
 
     mix(a, b, c);
-    a += IpsOption::hash();
-
     finalize(a,b,c);
     return c;
 }
index a0384593d0a79298ee75f00c0daa43641d886713..c57965e81b59b538d6e22a802ef93b05c6a6686b 100644 (file)
@@ -63,13 +63,11 @@ private:
 
 uint32_t CipClassOption::hash() const
 {
-    uint32_t a = cip_class.op;
-    uint32_t b = cip_class.min;
-    uint32_t c = cip_class.max;
+    uint32_t a = cip_class.hash();
+    uint32_t b = IpsOption::hash();
+    uint32_t c = 0;
 
     mix(a, b, c);
-    a += IpsOption::hash();
-
     finalize(a,b,c);
     return c;
 }
index b1da5a54566916c84f3131113f6e71d82fb5b129..a8feb6584e67a9557fa6732b01f3486da4626a85 100644 (file)
@@ -62,13 +62,11 @@ private:
 
 uint32_t CipConnpathclassOption::hash() const
 {
-    uint32_t a = cip_cpc.op;
-    uint32_t b = cip_cpc.min;
-    uint32_t c = cip_cpc.max;
+    uint32_t a = cip_cpc.hash();
+    uint32_t b = IpsOption::hash();
+    uint32_t c = 0;
 
     mix(a, b, c);
-    a += IpsOption::hash();
-
     finalize(a,b,c);
     return c;
 }
index 467ee8c477df315b94c3635162f1248aa10edf15..89420483dd2cabddf4005314fd6b2acdc463d884 100644 (file)
@@ -62,13 +62,11 @@ private:
 
 uint32_t CipEnipCommandOption::hash() const
 {
-    uint32_t a = cip_enip_cmd.op;
-    uint32_t b = cip_enip_cmd.min;
-    uint32_t c = cip_enip_cmd.max;
+    uint32_t a = cip_enip_cmd.hash();
+    uint32_t b = IpsOption::hash();
+    uint32_t c = 0;
 
     mix(a, b, c);
-    a += IpsOption::hash();
-
     finalize(a,b,c);
     return c;
 }
index 224a364d6a59c0dc876610b250b4b3d53550f20f..66538f1bd0aa81836b2580f4cc6775c4f1ffc15e 100644 (file)
@@ -62,13 +62,11 @@ private:
 
 uint32_t CipInstanceOption::hash() const
 {
-    uint32_t a = cip_inst.op;
-    uint32_t b = cip_inst.min;
-    uint32_t c = cip_inst.max;
+    uint32_t a = cip_inst.hash();
+    uint32_t b = IpsOption::hash();
+    uint32_t c = 0;
 
     mix(a, b, c);
-    a += IpsOption::hash();
-
     finalize(a,b,c);
     return c;
 }
index 97af706ad6156fe2d43d1984d691138c887396a6..53cb5d214f5b6a26f504d32a0a6d63d76d7e7b78 100644 (file)
@@ -62,13 +62,11 @@ private:
 
 uint32_t CipServiceOption::hash() const
 {
-    uint32_t a = cip_serv.op;
-    uint32_t b = cip_serv.min;
-    uint32_t c = cip_serv.max;
+    uint32_t a = cip_serv.hash();
+    uint32_t b = IpsOption::hash();
+    uint32_t c = 0;
 
     mix(a, b, c);
-    a += IpsOption::hash();
-
     finalize(a,b,c);
     return c;
 }
index c4dcd021b20b0b92d3f55419831b3663f8eb2c12..f11873dbd2567ece014ea628c1d55ce285476a15 100644 (file)
@@ -62,13 +62,11 @@ private:
 
 uint32_t CipStatusOption::hash() const
 {
-    uint32_t a = cip_status.op;
-    uint32_t b = cip_status.min;
-    uint32_t c = cip_status.max;
+    uint32_t a = cip_status.hash();
+    uint32_t b = IpsOption::hash();
+    uint32_t c = 0;
 
     mix(a, b, c);
-    a += IpsOption::hash();
-
     finalize(a,b,c);
     return c;
 }
index bd70959c9729340583b643476b182ccebbc55a2e..fee3d4ba6e2a08139c0f7240f76718ad7fe0ac86 100644 (file)
@@ -342,13 +342,11 @@ uint32_t Dce2IfaceOption::hash() const
         (uuid.node[3] << 16) |
         (uuid.node[4] << 8) |
         (uuid.node[5]);
-    b += version.max;
-    c += version.min;
+    b += version.hash();
+    c += any_frag;
 
     mix(a, b, c);
 
-    a += version.op;
-    b += any_frag;
     c += IpsOption::hash();
 
     finalize(a, b, c);
index bf1d47f14ecc42c6a8aed76ba42e3e35db0d925a..91c1327b96fba161fced1d861195efe8ba82b2e9 100644 (file)
@@ -104,6 +104,8 @@ extern const BaseApi* ips_http_client_body;
 extern const BaseApi* ips_http_cookie;
 extern const BaseApi* ips_http_header;
 extern const BaseApi* ips_http_method;
+extern const BaseApi* ips_http_num_headers;
+extern const BaseApi* ips_http_num_trailers;
 extern const BaseApi* ips_http_param;
 extern const BaseApi* ips_http_raw_body;
 extern const BaseApi* ips_http_raw_cookie;
@@ -131,6 +133,8 @@ const BaseApi* sin_http[] =
     ips_http_cookie,
     ips_http_header,
     ips_http_method,
+    ips_http_num_headers,
+    ips_http_num_trailers,
     ips_http_param,
     ips_http_raw_body,
     ips_http_raw_cookie,
index 9dfdf66eb1861ef770d3073293ffe5feee1fd228..065339076f6a2af8922a622ca66371c2614efa03 100755 (executable)
@@ -53,14 +53,16 @@ enum SectionType { SEC_DISCARD = -19, SEC_ABORT = -18, SEC__NOT_COMPUTE=-14, SEC
 
 enum DetectionStatus { DET_REACTIVATING = 1, DET_ON, DET_DEACTIVATING, DET_OFF };
 
-// Message buffers available to clients
-// This enum must remain synchronized with HttpApi::classic_buffer_names[]
-enum HTTP_BUFFER { HTTP_BUFFER_CLIENT_BODY = 1, HTTP_BUFFER_COOKIE, HTTP_BUFFER_HEADER,
+// HTTP rule options.
+// Lower portion is message buffers available to clients.
+// That part must remain synchronized with HttpApi::classic_buffer_names[]
+enum HTTP_RULE_OPT { HTTP_BUFFER_CLIENT_BODY = 1, HTTP_BUFFER_COOKIE, HTTP_BUFFER_HEADER,
     HTTP_BUFFER_METHOD, HTTP_BUFFER_PARAM, HTTP_BUFFER_RAW_BODY, HTTP_BUFFER_RAW_COOKIE,
     HTTP_BUFFER_RAW_HEADER, HTTP_BUFFER_RAW_REQUEST, HTTP_BUFFER_RAW_STATUS,
     HTTP_BUFFER_RAW_TRAILER, HTTP_BUFFER_RAW_URI, HTTP_BUFFER_STAT_CODE, HTTP_BUFFER_STAT_MSG,
     HTTP_BUFFER_TRAILER, HTTP_BUFFER_TRUE_IP, HTTP_BUFFER_URI, HTTP_BUFFER_VERSION,
-    BUFFER_JS_DATA, BUFFER_VBA_DATA, HTTP_BUFFER_MAX };
+    BUFFER_JS_DATA, BUFFER_VBA_DATA , HTTP_BUFFER_MAX = BUFFER_VBA_DATA,
+    HTTP_RANGE_NUM_HDRS, HTTP_RANGE_NUM_TRAILERS, HTTP_MAX_RULE_OPTION };
 
 // Peg counts
 // This enum must remain synchronized with HttpModule::peg_names[] in http_tables.cc
index 57d805821be6f1b7685eea390fad9cc61e553161..ddf444ca0480a8dd094dee79a8709e335f79e138 100755 (executable)
@@ -274,9 +274,9 @@ bool HttpInspect::get_buf(unsigned id, Packet* p, InspectionBuffer& b)
 }
 
 const Field& HttpInspect::http_get_buf(Cursor& c, Packet* p,
-    const HttpBufferInfo& buffer_info)
+    const HttpBufferInfo& buffer_info) const
 {
-    HttpMsgSection* current_section = HttpContextData::get_snapshot(p);
+    HttpMsgSection* const current_section = HttpContextData::get_snapshot(p);
 
     if (current_section == nullptr)
         return Field::FIELD_NULL;
@@ -284,6 +284,17 @@ const Field& HttpInspect::http_get_buf(Cursor& c, Packet* p,
     return current_section->get_classic_buffer(c, buffer_info);
 }
 
+int32_t HttpInspect::http_get_num_headers(Packet* p,
+    const HttpBufferInfo& buffer_info) const
+{
+    const HttpMsgSection* const current_section = HttpContextData::get_snapshot(p);
+
+    if (current_section == nullptr)
+        return STAT_NOT_COMPUTE;
+
+    return current_section->get_num_headers(buffer_info);
+}
+
 bool HttpInspect::get_fp_buf(InspectionBuffer::Type ibt, Packet* p, InspectionBuffer& b)
 {
     if (get_latest_is(p) == IS_NONE)
index b61e742fe887c4d562a1ae1545b6960f02ffecb8..49d508006737d49bde136ef55845c7c20f2b9cf2 100644 (file)
@@ -48,7 +48,8 @@ public:
         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 HttpBufferInfo& buffer_info) const;
+    int32_t http_get_num_headers(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 b51bd4d9688785cc5e63b504c357fd32a4995a2d..f0f791a68ce12bfc36df506c4cf14abf457681bb 100755 (executable)
@@ -59,7 +59,9 @@ public:
     uint64_t get_file_cache_index();
     const Field& get_content_disposition_filename();
     bool is_external_js();
+    int32_t get_num_headers() const { return num_headers; }
 
+    static const int MAX_HEADERS = 200;  // I'm an arbitrary number. FIXIT-RC
 protected:
     HttpMsgHeadShared(const uint8_t* buffer, const uint16_t buf_size,
         HttpFlowData* session_data_, HttpCommon::SourceId source_id_, bool buf_owner, snort::Flow* flow_,
@@ -78,7 +80,6 @@ private:
     static const int MAX = HttpEnums::HEAD__MAX_VALUE + HttpEnums::MAX_CUSTOM_HEADERS;
 
     // All of these are indexed by the relative position of the header field in the message
-    static const int MAX_HEADERS = 200;  // I'm an arbitrary number. FIXIT-RC
     static const int MAX_HEADER_LENGTH = 4096; // Based on max cookie size of some browsers
 
     void parse_header_block();
index e115e8409f72fcbf08d740426f30d29e56163175..6e16ae044fdeb541103c497d1bfc2c8123e63a2b 100644 (file)
@@ -404,6 +404,20 @@ const Field& HttpMsgSection::get_classic_buffer(Cursor& c, const HttpBufferInfo&
     }
 }
 
+int32_t HttpMsgSection::get_num_headers(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;
+
+    const HttpMsgHeadShared* const head = (buf.type == HTTP_RANGE_NUM_TRAILERS) ?
+        (HttpMsgHeadShared*)trailer[buffer_side]:
+        (HttpMsgHeadShared*)header[buffer_side] ;
+    if (head == nullptr)
+        return HttpCommon::STAT_NOT_COMPUTE;
+
+    return head->get_num_headers();
+}
+
 void HttpMsgSection::get_related_sections()
 {
     // When a message section is created these relationships become fixed so we make copies for
index 8f41965c958ce305450c009f576a90e562639931..eb5f53ace5f060d37ccb674db89d448d9f4976fb 100644 (file)
@@ -80,6 +80,7 @@ public:
     bool is_clear() { return cleared; }
 
     uint64_t get_transaction_id() { return trans_num; }
+    int32_t get_num_headers(const HttpBufferInfo& buf) const;
 
     HttpMsgSection* next = nullptr;
 
index 067d17209c57a5b9958fbb6d9d2783c4f792f368..5603318bf4b10d1374f28f44e4200e2885c6b8bc 100644 (file)
@@ -41,14 +41,16 @@ using namespace snort;
 using namespace HttpCommon;
 using namespace HttpEnums;
 
-THREAD_LOCAL std::array<ProfileStats, PSI_MAX> HttpCursorModule::http_ps;
+THREAD_LOCAL std::array<ProfileStats, PSI_MAX> HttpRuleOptModule::http_ps;
 
-bool HttpCursorModule::begin(const char*, int, SnortConfig*)
+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 (buffer_index)
+    switch (rule_opt_index)
     {
     case HTTP_BUFFER_RAW_STATUS:
     case HTTP_BUFFER_STAT_CODE:
@@ -66,6 +68,7 @@ bool HttpCursorModule::begin(const char*, int, SnortConfig*)
     case HTTP_BUFFER_TRUE_IP:
     case HTTP_BUFFER_URI:
     case HTTP_BUFFER_VERSION:
+    case HTTP_RANGE_NUM_HDRS:
         inspect_section = IS_FLEX_HEADER;
         break;
     case HTTP_BUFFER_CLIENT_BODY:
@@ -75,6 +78,7 @@ bool HttpCursorModule::begin(const char*, int, SnortConfig*)
         break;
     case HTTP_BUFFER_RAW_TRAILER:
     case HTTP_BUFFER_TRAILER:
+    case HTTP_RANGE_NUM_TRAILERS:
         inspect_section = IS_TRAILER;
         break;
     default:
@@ -83,7 +87,7 @@ bool HttpCursorModule::begin(const char*, int, SnortConfig*)
     return true;
 }
 
-bool HttpCursorModule::set(const char*, Value& v, SnortConfig*)
+bool HttpRuleOptModule::set(const char*, Value& v, SnortConfig*)
 {
     if (v.is("field"))
     {
@@ -163,27 +167,31 @@ bool HttpCursorModule::set(const char*, Value& v, SnortConfig*)
         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());
+    }
     return true;
 }
 
-bool HttpCursorModule::end(const char*, int, SnortConfig*)
+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 (((buffer_index == HTTP_BUFFER_TRAILER) || (buffer_index == HTTP_BUFFER_RAW_TRAILER)) &&
+    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) &&
         !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 (buffer_index == HTTP_BUFFER_PARAM && para_list.param.length() == 0)
+    if (rule_opt_index == HTTP_BUFFER_PARAM && para_list.param.length() == 0)
         ParseError("Specify parameter name");
     return true;
 }
 
-void HttpCursorModule::HttpRuleParaList::reset()
+void HttpRuleOptModule::HttpRuleParaList::reset()
 {
     field.clear();
     param.clear();
@@ -198,6 +206,7 @@ void HttpCursorModule::HttpRuleParaList::reset()
     path = false;
     query = false;
     fragment = false;
+    range.init();
 }
 
 uint32_t HttpIpsOption::hash() const
@@ -206,6 +215,7 @@ 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();
     finalize(a,b,c);
     return c;
 }
@@ -215,7 +225,8 @@ 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;
+           buffer_info == hio.buffer_info &&
+           range == hio.range;
 }
 
 bool HttpIpsOption::retry(Cursor& current_cursor, const Cursor&)
@@ -232,7 +243,7 @@ bool HttpIpsOption::retry(Cursor& current_cursor, const Cursor&)
 
 IpsOption::EvalStatus HttpIpsOption::eval(Cursor& c, Packet* p)
 {
-    RuleProfile profile(HttpCursorModule::http_ps[psi]);
+    RuleProfile profile(HttpRuleOptModule::http_ps[psi]);
 
     if (!p->flow || !p->flow->gadget || (HttpInspect::get_latest_is(p) == IS_NONE))
         return NO_MATCH;
@@ -248,17 +259,28 @@ IpsOption::EvalStatus HttpIpsOption::eval(Cursor& c, Packet* p)
     const Http2FlowData* const h2i_flow_data =
         (Http2FlowData*)p->flow->get_flow_data(Http2FlowData::inspector_id);
 
-    HttpInspect* const hi = (h2i_flow_data != nullptr) ?
+    const HttpInspect* const hi = (h2i_flow_data != nullptr) ?
         (HttpInspect*)(p->flow->assistant_gadget) : (HttpInspect*)(p->flow->gadget);
 
-    const Field& http_buffer = hi->http_get_buf(c, p, buffer_info);
+    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;
+        if (http_buffer.length() <= 0)
+            return NO_MATCH;
 
-    c.set(key, http_buffer.start(), http_buffer.length());
+        c.set(key, http_buffer.start(), http_buffer.length());
 
-    return MATCH;
+        return MATCH;
+    }
+    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;
+    }
 }
 
 //-------------------------------------------------------------------------
@@ -272,7 +294,7 @@ IpsOption::EvalStatus HttpIpsOption::eval(Cursor& c, Packet* p)
 
 static Module* client_body_mod_ctor()
 {
-    return new HttpCursorModule(IPS_OPT, IPS_HELP, HTTP_BUFFER_CLIENT_BODY, CAT_SET_BODY,
+    return new HttpRuleOptModule(IPS_OPT, IPS_HELP, HTTP_BUFFER_CLIENT_BODY, CAT_SET_BODY,
         PSI_CLIENT_BODY);
 }
 
@@ -288,7 +310,7 @@ static const IpsApi client_body_api =
         IPS_OPT,
         IPS_HELP,
         client_body_mod_ctor,
-        HttpCursorModule::mod_dtor
+        HttpRuleOptModule::mod_dtor
     },
     OPT_TYPE_DETECTION,
     0, PROTO_BIT__TCP,
@@ -325,7 +347,7 @@ static const Parameter http_cookie_params[] =
 
 static Module* cookie_mod_ctor()
 {
-    return new HttpCursorModule(IPS_OPT, IPS_HELP, HTTP_BUFFER_COOKIE, CAT_SET_COOKIE, PSI_COOKIE,
+    return new HttpRuleOptModule(IPS_OPT, IPS_HELP, HTTP_BUFFER_COOKIE, CAT_SET_COOKIE, PSI_COOKIE,
         http_cookie_params);
 }
 
@@ -341,7 +363,7 @@ static const IpsApi cookie_api =
         IPS_OPT,
         IPS_HELP,
         cookie_mod_ctor,
-        HttpCursorModule::mod_dtor
+        HttpRuleOptModule::mod_dtor
     },
     OPT_TYPE_DETECTION,
     0, PROTO_BIT__TCP,
@@ -386,7 +408,7 @@ static const Parameter http_header_params[] =
 
 static Module* header_mod_ctor()
 {
-    return new HttpCursorModule(IPS_OPT, IPS_HELP, HTTP_BUFFER_HEADER, CAT_SET_HEADER,
+    return new HttpRuleOptModule(IPS_OPT, IPS_HELP, HTTP_BUFFER_HEADER, CAT_SET_HEADER,
         PSI_HEADER, http_header_params);
 }
 
@@ -402,7 +424,7 @@ static const IpsApi header_api =
         IPS_OPT,
         IPS_HELP,
         header_mod_ctor,
-        HttpCursorModule::mod_dtor
+        HttpRuleOptModule::mod_dtor
     },
     OPT_TYPE_DETECTION,
     0, PROTO_BIT__TCP,
@@ -437,7 +459,7 @@ static const Parameter http_method_params[] =
 
 static Module* method_mod_ctor()
 {
-    return new HttpCursorModule(IPS_OPT, IPS_HELP, HTTP_BUFFER_METHOD, CAT_SET_METHOD, PSI_METHOD,
+    return new HttpRuleOptModule(IPS_OPT, IPS_HELP, HTTP_BUFFER_METHOD, CAT_SET_METHOD, PSI_METHOD,
         http_method_params);
 }
 
@@ -453,7 +475,7 @@ static const IpsApi method_api =
         IPS_OPT,
         IPS_HELP,
         method_mod_ctor,
-        HttpCursorModule::mod_dtor
+        HttpRuleOptModule::mod_dtor
     },
     OPT_TYPE_DETECTION,
     0, PROTO_BIT__TCP,
@@ -486,7 +508,7 @@ static const Parameter http_param_params[] =
 
 static Module* param_mod_ctor()
 {
-    return new HttpCursorModule(IPS_OPT, IPS_HELP, HTTP_BUFFER_PARAM, CAT_SET_OTHER, PSI_PARAM,
+    return new HttpRuleOptModule(IPS_OPT, IPS_HELP, HTTP_BUFFER_PARAM, CAT_SET_OTHER, PSI_PARAM,
         http_param_params);
 }
 
@@ -502,7 +524,7 @@ static const IpsApi param_api =
         IPS_OPT,
         IPS_HELP,
         param_mod_ctor,
-        HttpCursorModule::mod_dtor
+        HttpRuleOptModule::mod_dtor
     },
     OPT_TYPE_DETECTION,
     0, PROTO_BIT__TCP,
@@ -526,7 +548,7 @@ static const IpsApi param_api =
 
 static Module* raw_body_mod_ctor()
 {
-    return new HttpCursorModule(IPS_OPT, IPS_HELP, HTTP_BUFFER_RAW_BODY, CAT_SET_OTHER,
+    return new HttpRuleOptModule(IPS_OPT, IPS_HELP, HTTP_BUFFER_RAW_BODY, CAT_SET_OTHER,
         PSI_RAW_BODY);
 }
 
@@ -542,7 +564,7 @@ static const IpsApi raw_body_api =
         IPS_OPT,
         IPS_HELP,
         raw_body_mod_ctor,
-        HttpCursorModule::mod_dtor
+        HttpRuleOptModule::mod_dtor
     },
     OPT_TYPE_DETECTION,
     0, PROTO_BIT__TCP,
@@ -579,7 +601,7 @@ static const Parameter http_raw_cookie_params[] =
 
 static Module* raw_cookie_mod_ctor()
 {
-    return new HttpCursorModule(IPS_OPT, IPS_HELP, HTTP_BUFFER_RAW_COOKIE, CAT_SET_OTHER,
+    return new HttpRuleOptModule(IPS_OPT, IPS_HELP, HTTP_BUFFER_RAW_COOKIE, CAT_SET_OTHER,
         PSI_RAW_COOKIE, http_raw_cookie_params);
 }
 
@@ -595,7 +617,7 @@ static const IpsApi raw_cookie_api =
         IPS_OPT,
         IPS_HELP,
         raw_cookie_mod_ctor,
-        HttpCursorModule::mod_dtor
+        HttpRuleOptModule::mod_dtor
     },
     OPT_TYPE_DETECTION,
     0, PROTO_BIT__TCP,
@@ -634,7 +656,7 @@ static const Parameter http_raw_header_params[] =
 
 static Module* raw_header_mod_ctor()
 {
-    return new HttpCursorModule(IPS_OPT, IPS_HELP, HTTP_BUFFER_RAW_HEADER, CAT_SET_RAW_HEADER,
+    return new HttpRuleOptModule(IPS_OPT, IPS_HELP, HTTP_BUFFER_RAW_HEADER, CAT_SET_RAW_HEADER,
         PSI_RAW_HEADER, http_raw_header_params);
 }
 
@@ -650,7 +672,7 @@ static const IpsApi raw_header_api =
         IPS_OPT,
         IPS_HELP,
         raw_header_mod_ctor,
-        HttpCursorModule::mod_dtor
+        HttpRuleOptModule::mod_dtor
     },
     OPT_TYPE_DETECTION,
     0, PROTO_BIT__TCP,
@@ -685,7 +707,7 @@ static const Parameter http_raw_request_params[] =
 
 static Module* raw_request_mod_ctor()
 {
-    return new HttpCursorModule(IPS_OPT, IPS_HELP, HTTP_BUFFER_RAW_REQUEST, CAT_SET_OTHER,
+    return new HttpRuleOptModule(IPS_OPT, IPS_HELP, HTTP_BUFFER_RAW_REQUEST, CAT_SET_OTHER,
         PSI_RAW_REQUEST, http_raw_request_params);
 }
 
@@ -701,7 +723,7 @@ static const IpsApi raw_request_api =
         IPS_OPT,
         IPS_HELP,
         raw_request_mod_ctor,
-        HttpCursorModule::mod_dtor
+        HttpRuleOptModule::mod_dtor
     },
     OPT_TYPE_DETECTION,
     0, PROTO_BIT__TCP,
@@ -734,7 +756,7 @@ static const Parameter http_raw_status_params[] =
 
 static Module* raw_status_mod_ctor()
 {
-    return new HttpCursorModule(IPS_OPT, IPS_HELP, HTTP_BUFFER_RAW_STATUS, CAT_SET_OTHER,
+    return new HttpRuleOptModule(IPS_OPT, IPS_HELP, HTTP_BUFFER_RAW_STATUS, CAT_SET_OTHER,
         PSI_RAW_STATUS, http_raw_status_params);
 }
 
@@ -750,7 +772,7 @@ static const IpsApi raw_status_api =
         IPS_OPT,
         IPS_HELP,
         raw_status_mod_ctor,
-        HttpCursorModule::mod_dtor
+        HttpRuleOptModule::mod_dtor
     },
     OPT_TYPE_DETECTION,
     0, PROTO_BIT__TCP,
@@ -788,7 +810,7 @@ static const Parameter http_raw_trailer_params[] =
 
 static Module* raw_trailer_mod_ctor()
 {
-    return new HttpCursorModule(IPS_OPT, IPS_HELP, HTTP_BUFFER_RAW_TRAILER, CAT_SET_RAW_HEADER,
+    return new HttpRuleOptModule(IPS_OPT, IPS_HELP, HTTP_BUFFER_RAW_TRAILER, CAT_SET_RAW_HEADER,
         PSI_RAW_TRAILER, http_raw_trailer_params);
 }
 
@@ -804,7 +826,7 @@ static const IpsApi raw_trailer_api =
         IPS_OPT,
         IPS_HELP,
         raw_trailer_mod_ctor,
-        HttpCursorModule::mod_dtor
+        HttpRuleOptModule::mod_dtor
     },
     OPT_TYPE_DETECTION,
     0, PROTO_BIT__TCP,
@@ -851,7 +873,7 @@ static const Parameter http_raw_uri_params[] =
 
 static Module* raw_uri_mod_ctor()
 {
-    return new HttpCursorModule(IPS_OPT, IPS_HELP, HTTP_BUFFER_RAW_URI, CAT_SET_RAW_KEY,
+    return new HttpRuleOptModule(IPS_OPT, IPS_HELP, HTTP_BUFFER_RAW_URI, CAT_SET_RAW_KEY,
         PSI_RAW_URI, http_raw_uri_params);
 }
 
@@ -867,7 +889,7 @@ static const IpsApi raw_uri_api =
         IPS_OPT,
         IPS_HELP,
         raw_uri_mod_ctor,
-        HttpCursorModule::mod_dtor
+        HttpRuleOptModule::mod_dtor
     },
     OPT_TYPE_DETECTION,
     0, PROTO_BIT__TCP,
@@ -900,7 +922,7 @@ static const Parameter http_stat_code_params[] =
 
 static Module* stat_code_mod_ctor()
 {
-    return new HttpCursorModule(IPS_OPT, IPS_HELP, HTTP_BUFFER_STAT_CODE, CAT_SET_STAT_CODE,
+    return new HttpRuleOptModule(IPS_OPT, IPS_HELP, HTTP_BUFFER_STAT_CODE, CAT_SET_STAT_CODE,
         PSI_STAT_CODE, http_stat_code_params);
 }
 
@@ -916,7 +938,7 @@ static const IpsApi stat_code_api =
         IPS_OPT,
         IPS_HELP,
         stat_code_mod_ctor,
-        HttpCursorModule::mod_dtor
+        HttpRuleOptModule::mod_dtor
     },
     OPT_TYPE_DETECTION,
     0, PROTO_BIT__TCP,
@@ -949,7 +971,7 @@ static const Parameter http_stat_msg_params[] =
 
 static Module* stat_msg_mod_ctor()
 {
-    return new HttpCursorModule(IPS_OPT, IPS_HELP, HTTP_BUFFER_STAT_MSG, CAT_SET_STAT_MSG,
+    return new HttpRuleOptModule(IPS_OPT, IPS_HELP, HTTP_BUFFER_STAT_MSG, CAT_SET_STAT_MSG,
         PSI_STAT_MSG, http_stat_msg_params);
 }
 
@@ -965,7 +987,7 @@ static const IpsApi stat_msg_api =
         IPS_OPT,
         IPS_HELP,
         stat_msg_mod_ctor,
-        HttpCursorModule::mod_dtor
+        HttpRuleOptModule::mod_dtor
     },
     OPT_TYPE_DETECTION,
     0, PROTO_BIT__TCP,
@@ -1002,7 +1024,7 @@ static const Parameter http_trailer_params[] =
 
 static Module* trailer_mod_ctor()
 {
-    return new HttpCursorModule(IPS_OPT, IPS_HELP, HTTP_BUFFER_TRAILER, CAT_SET_HEADER,
+    return new HttpRuleOptModule(IPS_OPT, IPS_HELP, HTTP_BUFFER_TRAILER, CAT_SET_HEADER,
         PSI_TRAILER, http_trailer_params);
 }
 
@@ -1018,7 +1040,7 @@ static const IpsApi trailer_api =
         IPS_OPT,
         IPS_HELP,
         trailer_mod_ctor,
-        HttpCursorModule::mod_dtor
+        HttpRuleOptModule::mod_dtor
     },
     OPT_TYPE_DETECTION,
     0, PROTO_BIT__TCP,
@@ -1053,7 +1075,7 @@ static const Parameter http_true_ip_params[] =
 
 static Module* true_ip_mod_ctor()
 {
-    return new HttpCursorModule(IPS_OPT, IPS_HELP, HTTP_BUFFER_TRUE_IP, CAT_SET_OTHER,
+    return new HttpRuleOptModule(IPS_OPT, IPS_HELP, HTTP_BUFFER_TRUE_IP, CAT_SET_OTHER,
         PSI_TRUE_IP, http_true_ip_params);
 }
 
@@ -1069,7 +1091,7 @@ static const IpsApi true_ip_api =
         IPS_OPT,
         IPS_HELP,
         true_ip_mod_ctor,
-        HttpCursorModule::mod_dtor
+        HttpRuleOptModule::mod_dtor
     },
     OPT_TYPE_DETECTION,
     0, PROTO_BIT__TCP,
@@ -1116,7 +1138,7 @@ static const Parameter http_uri_params[] =
 
 static Module* uri_mod_ctor()
 {
-    return new HttpCursorModule(IPS_OPT, IPS_HELP, HTTP_BUFFER_URI, CAT_SET_KEY, PSI_URI,
+    return new HttpRuleOptModule(IPS_OPT, IPS_HELP, HTTP_BUFFER_URI, CAT_SET_KEY, PSI_URI,
         http_uri_params);
 }
 
@@ -1132,7 +1154,7 @@ static const IpsApi uri_api =
         IPS_OPT,
         IPS_HELP,
         uri_mod_ctor,
-        HttpCursorModule::mod_dtor
+        HttpRuleOptModule::mod_dtor
     },
     OPT_TYPE_DETECTION,
     0, PROTO_BIT__TCP,
@@ -1169,7 +1191,7 @@ static const Parameter http_version_params[] =
 
 static Module* version_mod_ctor()
 {
-    return new HttpCursorModule(IPS_OPT, IPS_HELP, HTTP_BUFFER_VERSION, CAT_SET_OTHER,
+    return new HttpRuleOptModule(IPS_OPT, IPS_HELP, HTTP_BUFFER_VERSION, CAT_SET_OTHER,
         PSI_VERSION, http_version_params);
 }
 
@@ -1185,7 +1207,7 @@ static const IpsApi version_api =
         IPS_OPT,
         IPS_HELP,
         version_mod_ctor,
-        HttpCursorModule::mod_dtor
+        HttpRuleOptModule::mod_dtor
     },
     OPT_TYPE_DETECTION,
     0, PROTO_BIT__TCP,
@@ -1209,7 +1231,7 @@ static const IpsApi version_api =
 #define IPS_HELP "rule option to set detection cursor to normalized JavaScript data"
 static Module* js_data_mod_ctor()
 {
-    return new HttpCursorModule(IPS_OPT, IPS_HELP, BUFFER_JS_DATA, CAT_SET_JS_DATA,
+    return new HttpRuleOptModule(IPS_OPT, IPS_HELP, BUFFER_JS_DATA, CAT_SET_JS_DATA,
         PSI_JS_DATA);
 }
 
@@ -1225,7 +1247,100 @@ static const IpsApi js_data_api =
         IPS_OPT,
         IPS_HELP,
         js_data_mod_ctor,
-        HttpCursorModule::mod_dtor
+        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,
@@ -1246,6 +1361,8 @@ 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;
index c97b42506e0e4db33973ea2f8357691ae0c8c830..46e30e16f8799559ce468177ed4f60753618ec38 100644 (file)
 #include "profiler/profiler.h"
 #include "framework/ips_option.h"
 #include "framework/module.h"
+#include "framework/range.h"
 
 #include "http_buffer_info.h"
 #include "http_enum.h"
 
+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_MAX };
+    PSI_TRUE_IP, PSI_URI, PSI_VERSION, PSI_JS_DATA, PSI_VBA_DATA,
+    PSI_RANGE_NUM_HDRS, PSI_RANGE_NUM_TRAILERS, PSI_MAX };
 
-class HttpCursorModule : public snort::Module
+class HttpRuleOptModule : public snort::Module
 {
 public:
-    HttpCursorModule(const char* key_, const char* help, HttpEnums::HTTP_BUFFER buffer_index_,
+    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_), buffer_index(buffer_index_),
+        : snort::Module(key_, help), key(key_), rule_opt_index(rule_opt_index_),
           cat(cat_), psi(psi_) {}
-    HttpCursorModule(const char* key_, const char* help, HttpEnums::HTTP_BUFFER buffer_index_,
+    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_), buffer_index(buffer_index_),
-          cat(cat_), psi(psi_) {}
+        : 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]; }
     static void mod_dtor(snort::Module* m) { delete m; }
     bool begin(const char*, int, snort::SnortConfig*) override;
@@ -74,12 +78,13 @@ private:
         bool path;
         bool query;
         bool fragment;
+        snort::RangeCheck range;
 
         void reset();
     };
 
     const char* const key;
-    const HttpEnums::HTTP_BUFFER buffer_index;
+    const HttpEnums::HTTP_RULE_OPT rule_opt_index;
     const snort::CursorActionType cat;
     const PsIdx psi;
 
@@ -92,26 +97,28 @@ private:
 class HttpIpsOption : public snort::IpsOption
 {
 public:
-    HttpIpsOption(const HttpCursorModule* cm) :
+    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->buffer_index, cm->sub_id, cm->form,
-            cm->para_list.param, cm->para_list.nocase) {}
+        buffer_info(cm->rule_opt_index, cm->sub_id, cm->form,
+        cm->para_list.param, cm->para_list.nocase), range(cm->para_list.range){}
     snort::CursorActionType get_cursor_type() const override { return cat; }
     EvalStatus eval(Cursor&, snort::Packet*) override;
     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((HttpCursorModule*)m); }
+        { return new HttpIpsOption((HttpRuleOptModule*)m); }
     static void opt_dtor(snort::IpsOption* p) { delete 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;
 };
 
 #endif
index ce3cd5f5a67e0cf47a29585a1a2743a2aed08d7b..dff965734cdd8ed9c6b411c716f9ee5b63e8a9a1 100644 (file)
@@ -64,18 +64,12 @@ private:
 
 uint32_t SizeOption::hash() const
 {
-    uint32_t a = ssod.op;
-    uint32_t b = ssod.min;
-    uint32_t c = ssod.max;
-
-    mix(a,b,c);
-
-    a = direction;
-    b += IpsOption::hash();
+    uint32_t a = ssod.hash();
+    uint32_t b = direction;
+    uint32_t c = IpsOption::hash();
 
     mix(a,b,c);
     finalize(a,b,c);
-
     return c;
 }