+++ /dev/null
-From a71cca137eb33f659354ce0ebda4951cb26485df Mon Sep 17 00:00:00 2001
-From: Christian Marangi <ansuelsmth@gmail.com>
-Date: Mon, 6 Nov 2023 22:43:59 +0100
-Subject: [PATCH] core: convert project to PCRE2
-
-Convert project to PCRE2 as PCRE is EOL and won't receive any security
-updates anymore.
-
-PCRE2 changed some API and concept. Mainly there isn't the concept of
-study anymore, replaced by match_context concept and match_data is used
-instead of ovector to handle results. Because of this the scratcher is
-not needed anymore and is replaced by a simple function to setup the max
-ovector size on end module init.
-
-Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
----
- README.md | 17 +-
- cmake/FindPCRE.cmake | 32 --
- cmake/FindPCRE2.cmake | 32 ++
- cmake/create_pkg_config.cmake | 4 +-
- cmake/include_libraries.cmake | 2 +-
- configure_cmake.sh | 16 +-
- lua/balanced.lua | 2 +-
- lua/max_detect.lua | 6 +-
- lua/security.lua | 4 +-
- snort.pc.in | 4 +-
- src/CMakeLists.txt | 4 +-
- src/detection/detection_module.cc | 48 +--
- src/detection/detection_options.cc | 6 +-
- src/ips_options/ips_options.cc | 4 +-
- src/ips_options/ips_pcre.cc | 391 ++++++++----------
- src/main/shell.cc | 9 +-
- src/main/snort_config.h | 26 +-
- .../appid/lua_detector_api.cc | 62 +--
- src/parser/parse_rule.cc | 4 +-
- src/parser/parse_stream.cc | 2 +-
- src/search_engines/test/hyperscan_test.cc | 2 +-
- src/utils/stats.cc | 6 +-
- src/utils/stats.h | 6 +-
- src/utils/util.cc | 8 +-
- tools/snort2lua/config_states/config_api.cc | 12 +-
- .../config_states/config_no_option.cc | 14 +-
- .../config_states/config_one_int_option.cc | 24 +-
- tools/snort2lua/rule_states/CMakeLists.txt | 2 +-
- tools/snort2lua/rule_states/rule_api.cc | 4 +-
- .../{rule_pcre.cc => rule_pcre2.cc} | 40 +-
- .../snort2lua/rule_states/rule_sd_pattern.cc | 4 +-
- 31 files changed, 393 insertions(+), 404 deletions(-)
- delete mode 100644 cmake/FindPCRE.cmake
- create mode 100644 cmake/FindPCRE2.cmake
- rename tools/snort2lua/rule_states/{rule_pcre.cc => rule_pcre2.cc} (80%)
-
---- a/README.md
-+++ b/README.md
-@@ -8,13 +8,14 @@ topics:
-
- ---
-
--* [Overview](#overview)
--* [Dependencies](#dependencies)
--* [Download](#download)
--* [Build Snort](#build-snort)
--* [Run Snort](#run-snort)
--* [Documentation](#documentation)
--* [Squeal](#squeal)
-+- [Snort++](#snort)
-+- [OVERVIEW](#overview)
-+- [DEPENDENCIES](#dependencies)
-+- [DOWNLOAD](#download)
-+- [BUILD SNORT](#build-snort)
-+- [RUN SNORT](#run-snort)
-+- [DOCUMENTATION](#documentation)
-+- [SQUEAL](#squeal)
-
- # OVERVIEW
-
-@@ -61,7 +62,7 @@ the latest:
- * OpenSSL from https://www.openssl.org/source/ for SHA and MD5 file signatures,
- the protected_content rule option, and SSL service detection
- * pcap from http://www.tcpdump.org for tcpdump style logging
--* pcre from http://www.pcre.org for regular expression pattern matching
-+* pcre2 from http://www.pcre.org for regular expression pattern matching
- * pkgconfig from https://www.freedesktop.org/wiki/Software/pkg-config/ to locate build dependencies
- * zlib from http://www.zlib.net for decompression
-
---- a/cmake/FindPCRE.cmake
-+++ /dev/null
-@@ -1,32 +0,0 @@
--# - Find pcre
--# Find the native PCRE includes and library
--#
--# PCRE_INCLUDE_DIR - where to find pcre.h, etc.
--# PCRE_LIBRARIES - List of libraries when using pcre.
--# PCRE_FOUND - True if pcre found.
--
--set(ERROR_MESSAGE
-- "\n\tERROR! Libpcre library not found.
-- \tGet it from http://www.pcre.org\n"
--)
--
--find_package(PkgConfig)
--pkg_check_modules(PC_PCRE libpcre)
--
--# Use PCRE_INCLUDE_DIR_HINT and PCRE_LIBRARIES_DIR_HINT from configure_cmake.sh as primary hints
--# and then package config information after that.
--find_path(PCRE_INCLUDE_DIR pcre.h
-- HINTS ${PCRE_INCLUDE_DIR_HINT} ${PC_PCRE_INCLUDEDIR} ${PC_PCRE_INCLUDE_DIRS})
--find_library(PCRE_LIBRARIES NAMES pcre
-- HINTS ${PCRE_LIBRARIES_DIR_HINT} ${PC_PCRE_LIBDIR} ${PC_PCRE_LIBRARY_DIRS})
--
--include(FindPackageHandleStandardArgs)
--find_package_handle_standard_args(PCRE
-- REQUIRED_VARS PCRE_INCLUDE_DIR PCRE_LIBRARIES
-- FAIL_MESSAGE "${ERROR_MESSAGE}"
--)
--
--mark_as_advanced(
-- PCRE_LIBRARIES
-- PCRE_INCLUDE_DIR
--)
---- /dev/null
-+++ b/cmake/FindPCRE2.cmake
-@@ -0,0 +1,32 @@
-+# - Find pcre2
-+# Find the native PCRE2 includes and library
-+#
-+# PCRE2_INCLUDE_DIR - where to find pcre2.h, etc.
-+# PCRE2_LIBRARIES - List of libraries when using pcre2.
-+# PCRE2_FOUND - True if pcre2 found.
-+
-+set(ERROR_MESSAGE
-+ "\n\tERROR! Libpcre2 library not found.
-+ \tGet it from http://www.pcre.org\n"
-+)
-+
-+find_package(PkgConfig)
-+pkg_check_modules(PC_PCRE2 libpcre2-8)
-+
-+# Use PCRE2_INCLUDE_DIR_HINT and PCRE_LIBRARIES_DIR_HINT from configure_cmake.sh as primary hints
-+# and then package config information after that.
-+find_path(PCRE2_INCLUDE_DIR pcre2.h
-+ HINTS ${PCRE2_INCLUDE_DIR_HINT} ${PC_PCRE2_INCLUDEDIR} ${PC_PCRE2_INCLUDE_DIRS})
-+find_library(PCRE2_LIBRARIES NAMES pcre2-8
-+ HINTS ${PCRE2_LIBRARIES_DIR_HINT} ${PC_PCRE2_LIBDIR} ${PC_PCRE2_LIBRARY_DIRS})
-+
-+include(FindPackageHandleStandardArgs)
-+find_package_handle_standard_args(PCRE2-8
-+ REQUIRED_VARS PCRE2_INCLUDE_DIR PCRE2_LIBRARIES
-+ FAIL_MESSAGE "${ERROR_MESSAGE}"
-+)
-+
-+mark_as_advanced(
-+ PCRE2_LIBRARIES
-+ PCRE2_INCLUDE_DIR
-+)
---- a/cmake/create_pkg_config.cmake
-+++ b/cmake/create_pkg_config.cmake
-@@ -72,8 +72,8 @@ if(PCAP_INCLUDE_DIR)
- set(PCAP_CPPFLAGS "-I${PCAP_INCLUDE_DIR}")
- endif()
-
--if(PCRE_INCLUDE_DIR)
-- set(PCRE_CPPFLAGS "-I${PCRE_INCLUDE_DIR}")
-+if(PCRE2_INCLUDE_DIR)
-+ set(PCRE2_CPPFLAGS "-I${PCRE2_INCLUDE_DIR}")
- endif()
-
- if(UUID_INCLUDE_DIR)
---- a/cmake/include_libraries.cmake
-+++ b/cmake/include_libraries.cmake
-@@ -8,7 +8,7 @@ find_package(HWLOC REQUIRED)
- find_package(LuaJIT REQUIRED)
- find_package(OpenSSL 1.1.1 REQUIRED)
- find_package(PCAP REQUIRED)
--find_package(PCRE REQUIRED)
-+find_package(PCRE2 REQUIRED)
- find_package(ZLIB REQUIRED)
- if (ENABLE_UNIT_TESTS)
- find_package(CppUTest REQUIRED)
---- a/configure_cmake.sh
-+++ b/configure_cmake.sh
-@@ -90,10 +90,10 @@ Optional Packages:
- luajit include directory
- --with-luajit-libraries=DIR
- luajit library directory
-- --with-pcre-includes=DIR
-- libpcre include directory
-- --with-pcre-libraries=DIR
-- libpcre library directory
-+ --with-pcre2-includes=DIR
-+ libpcre2 include directory
-+ --with-pcre2-libraries=DIR
-+ libpcre2 library directory
- --with-dnet-includes=DIR
- libdnet include directory
- --with-dnet-libraries=DIR
-@@ -417,11 +417,11 @@ while [ $# -ne 0 ]; do
- --with-luajit-libraries=*)
- append_cache_entry LUAJIT_LIBRARIES_DIR_HINT PATH $optarg
- ;;
-- --with-pcre-includes=*)
-- append_cache_entry PCRE_INCLUDE_DIR_HINT PATH $optarg
-+ --with-pcre2-includes=*)
-+ append_cache_entry PCRE2_INCLUDE_DIR_HINT PATH $optarg
- ;;
-- --with-pcre-libraries=*)
-- append_cache_entry PCRE_LIBRARIES_DIR_HINT PATH $optarg
-+ --with-pcre2-libraries=*)
-+ append_cache_entry PCRE2_LIBRARIES_DIR_HINT PATH $optarg
- ;;
- --with-dnet-includes=*)
- append_cache_entry DNET_INCLUDE_DIR_HINT PATH $optarg
---- a/lua/balanced.lua
-+++ b/lua/balanced.lua
-@@ -5,7 +5,7 @@
-
- arp_spoof = nil
-
--detection = { pcre_override = false }
-+detection = { pcre2_override = false }
-
- http_inspect.request_depth = 300
- http_inspect.response_depth = 500
---- a/lua/max_detect.lua
-+++ b/lua/max_detect.lua
-@@ -10,13 +10,13 @@ ftp_server.check_encrypted = true
-
- detection =
- {
-- pcre_match_limit = 3500,
-- pcre_match_limit_recursion = 3500,
-+ pcre2_match_limit = 3500,
-+ pcre2_match_limit_recursion = 3500,
-
- -- enable for hyperscan for best throughput
- -- use multiple packet threads for fast startup
- --hyperscan_literals = true,
-- --pcre_to_regex = true
-+ --pcre2_to_regex = true
- }
-
- http_inspect.decompress_pdf = true
---- a/lua/security.lua
-+++ b/lua/security.lua
-@@ -9,8 +9,8 @@ ftp_server.check_encrypted = true
-
- detection =
- {
-- pcre_match_limit = 3500,
-- pcre_match_limit_recursion = 3500
-+ pcre2_match_limit = 3500,
-+ pcre2_match_limit_recursion = 3500
- }
-
- http_inspect.decompress_pdf = true
---- a/snort.pc.in
-+++ b/snort.pc.in
-@@ -9,7 +9,7 @@ mandir=@mandir@
- infodir=@infodir@
-
- cpp_opts=DAQ LUAJIT
--cpp_opts_other=DNET HWLOC HYPERSCAN LZMA OPENSSL PCAP PCRE UUID
-+cpp_opts_other=DNET HWLOC HYPERSCAN LZMA OPENSSL PCAP PCRE2 UUID
-
- PCAP_CPPFLAGS=@PCAP_CPPFLAGS@
- LUAJIT_CPPFLAGS=@LUAJIT_CPPFLAGS@
-@@ -18,7 +18,7 @@ DAQ_CPPFLAGS=@DAQ_CPPFLAGS@
- FLEX_CPPFLAGS=@FLEX_CPPFLAGS@
- OPENSSL_CPPFLAGS=@OPENSSL_CPPFLAGS@
- HWLOC_CPPFLAGS=@HWLOC_CPPFLAGS@
--PCRE_CPPFLAGS=@PCRE_CPPFLAGS@
-+PCRE2_CPPFLAGS=@PCRE2_CPPFLAGS@
- LZMA_CPPFLAGS=@LZMA_CPPFLAGS@
- HYPERSCAN_CPPFLAGS=@HYPERSCAN_CPPFLAGS@
- UUID_CPPFLAGS=@UUID_CPPFLAGS@
---- a/src/CMakeLists.txt
-+++ b/src/CMakeLists.txt
-@@ -10,7 +10,7 @@ set(EXTERNAL_LIBRARIES
- ${LUAJIT_LIBRARIES}
- ${OPENSSL_CRYPTO_LIBRARY}
- ${PCAP_LIBRARIES}
-- ${PCRE_LIBRARIES}
-+ ${PCRE2_LIBRARIES}
- ${ZLIB_LIBRARIES}
- )
-
-@@ -21,7 +21,7 @@ set(EXTERNAL_INCLUDES
- ${HWLOC_INCLUDE_DIRS}
- ${OPENSSL_INCLUDE_DIR}
- ${PCAP_INCLUDE_DIR}
-- ${PCRE_INCLUDE_DIR}
-+ ${PCRE2_INCLUDE_DIR}
- ${ZLIB_INCLUDE_DIRS}
- )
-
---- a/src/detection/detection_module.cc
-+++ b/src/detection/detection_module.cc
-@@ -96,21 +96,21 @@ static const Parameter detection_params[
- { "offload_threads", Parameter::PT_INT, "0:max32", "0",
- "maximum number of simultaneous offloads (defaults to disabled)" },
-
-- { "pcre_enable", Parameter::PT_BOOL, nullptr, "true",
-- "enable pcre pattern matching" },
-+ { "pcre2_enable", Parameter::PT_BOOL, nullptr, "true",
-+ "enable pcre2 pattern matching" },
-
-- { "pcre_match_limit", Parameter::PT_INT, "0:max32", "1500",
-- "limit pcre backtracking, 0 = off" },
-+ { "pcre2_match_limit", Parameter::PT_INT, "0:max32", "1500",
-+ "limit pcre2 backtracking, 0 = off" },
-
-- { "pcre_match_limit_recursion", Parameter::PT_INT, "0:max32", "1500",
-- "limit pcre stack consumption, 0 = off" },
-+ { "pcre2_match_limit_recursion", Parameter::PT_INT, "0:max32", "1500",
-+ "limit pcre2 stack consumption, 0 = off" },
-
-- { "pcre_override", Parameter::PT_BOOL, nullptr, "true",
-- "enable pcre match limit overrides when pattern matching (ie ignore /O)" },
-+ { "pcre2_override", Parameter::PT_BOOL, nullptr, "true",
-+ "enable pcre2 match limit overrides when pattern matching (ie ignore /O)" },
-
- #ifdef HAVE_HYPERSCAN
-- { "pcre_to_regex", Parameter::PT_BOOL, nullptr, "false",
-- "enable the use of regex instead of pcre for compatible expressions" },
-+ { "pcre2_to_regex", Parameter::PT_BOOL, nullptr, "false",
-+ "enable the use of regex instead of pcre2 for compatible expressions" },
- #endif
-
- { "enable_address_anomaly_checks", Parameter::PT_BOOL, nullptr, "false",
-@@ -221,13 +221,13 @@ bool DetectionModule::set(const char*, V
- else if ( v.is("offload_threads") )
- sc->offload_threads = v.get_uint32();
-
-- else if ( v.is("pcre_enable") )
-- v.update_mask(sc->run_flags, RUN_FLAG__NO_PCRE, true);
-+ else if ( v.is("pcre2_enable") )
-+ v.update_mask(sc->run_flags, RUN_FLAG__NO_PCRE2, true);
-
-- else if ( v.is("pcre_match_limit") )
-- sc->pcre_match_limit = v.get_uint32();
-+ else if ( v.is("pcre2_match_limit") )
-+ sc->pcre2_match_limit = v.get_uint32();
-
-- else if ( v.is("pcre_match_limit_recursion") )
-+ else if ( v.is("pcre2_match_limit_recursion") )
- {
- // Cap the pcre recursion limit to not exceed the stack size.
- //
-@@ -252,21 +252,21 @@ bool DetectionModule::set(const char*, V
- if (max_rec < 0)
- max_rec = 0;
-
-- sc->pcre_match_limit_recursion = v.get_uint32();
-- if (sc->pcre_match_limit_recursion > max_rec)
-+ sc->pcre2_match_limit_recursion = v.get_uint32();
-+ if (sc->pcre2_match_limit_recursion > max_rec)
- {
-- sc->pcre_match_limit_recursion = max_rec;
-- LogMessage("Capping pcre_match_limit_recursion to %ld, thread stack_size %ld.\n",
-- sc->pcre_match_limit_recursion, thread_stack_size);
-+ sc->pcre2_match_limit_recursion = max_rec;
-+ LogMessage("Capping pcre2_match_limit_recursion to %ld, thread stack_size %llu.\n",
-+ sc->pcre2_match_limit_recursion, thread_stack_size);
- }
- }
-
-- else if ( v.is("pcre_override") )
-- sc->pcre_override = v.get_bool();
-+ else if ( v.is("pcre2_override") )
-+ sc->pcre2_override = v.get_bool();
-
- #ifdef HAVE_HYPERSCAN
-- else if ( v.is("pcre_to_regex") )
-- sc->pcre_to_regex = v.get_bool();
-+ else if ( v.is("pcre2_to_regex") )
-+ sc->pcre2_to_regex = v.get_bool();
- #endif
-
- else if ( v.is("enable_address_anomaly_checks") )
---- a/src/detection/detection_options.cc
-+++ b/src/detection/detection_options.cc
-@@ -595,7 +595,7 @@ int detection_option_node_evaluate(
- {
- if ( !child_node->is_relative )
- {
-- // If it's a non-relative content or pcre, no reason
-+ // If it's a non-relative content or pcre2, no reason
- // to check again. Only increment result once.
- // Should hit this condition on first loop iteration.
- if ( loop_count == 1 )
-@@ -661,10 +661,10 @@ int detection_option_node_evaluate(
- }
-
- // If all children branches matched, we don't need to reeval any of
-- // the children so don't need to reeval this content/pcre rule
-+ // the children so don't need to reeval this content/pcre2 rule
- // option at a new offset.
- // Else, reset the DOE ptr to last eval for offset/depth,
-- // distance/within adjustments for this same content/pcre rule option.
-+ // distance/within adjustments for this same content/pcre2 rule option.
- // If the node and its sub-tree propagate MATCH back,
- // then all its continuations are recalled.
- if ( result == node->num_children )
---- a/src/ips_options/ips_options.cc
-+++ b/src/ips_options/ips_options.cc
-@@ -72,7 +72,7 @@ extern const BaseApi* ips_ip_proto[];
- extern const BaseApi* ips_isdataat[];
- extern const BaseApi* ips_itype[];
- extern const BaseApi* ips_msg[];
--extern const BaseApi* ips_pcre[];
-+extern const BaseApi* ips_pcre2[];
- extern const BaseApi* ips_priority[];
- extern const BaseApi* ips_raw_data[];
- extern const BaseApi* ips_rem[];
-@@ -146,7 +146,7 @@ void load_ips_options()
- PluginManager::load_plugins(ips_isdataat);
- PluginManager::load_plugins(ips_itype);
- PluginManager::load_plugins(ips_msg);
-- PluginManager::load_plugins(ips_pcre);
-+ PluginManager::load_plugins(ips_pcre2);
- PluginManager::load_plugins(ips_priority);
- PluginManager::load_plugins(ips_raw_data);
- PluginManager::load_plugins(ips_rem);
---- a/src/ips_options/ips_pcre.cc
-+++ b/src/ips_options/ips_pcre.cc
-@@ -23,7 +23,8 @@
- #include "config.h"
- #endif
-
--#include <pcre.h>
-+#define PCRE2_CODE_UNIT_WIDTH 8
-+#include <pcre2.h>
-
- #include <cassert>
-
-@@ -43,33 +44,31 @@
-
- using namespace snort;
-
--#ifndef PCRE_STUDY_JIT_COMPILE
--#define PCRE_STUDY_JIT_COMPILE 0
-+#ifndef PCRE2_STUDY_JIT_COMPILE
-+#define PCRE2_STUDY_JIT_COMPILE 0
- #endif
-
- //#define NO_JIT // uncomment to disable JIT for Xcode
-
- #ifdef NO_JIT
--#define PCRE_STUDY_FLAGS 0
--#define pcre_release(x) pcre_free(x)
-+#define PCRE2_JIT 0
- #else
--#define PCRE_STUDY_FLAGS PCRE_STUDY_JIT_COMPILE
--#define pcre_release(x) pcre_free_study(x)
-+#define PCRE2_JIT PCRE2_STUDY_JIT_COMPILE
- #endif
-+#define pcre2_release(x) pcre2_code_free(x)
-
- #define SNORT_PCRE_RELATIVE 0x00010 // relative to the end of the last match
- #define SNORT_PCRE_INVERT 0x00020 // invert detect
- #define SNORT_PCRE_ANCHORED 0x00040
- #define SNORT_OVERRIDE_MATCH_LIMIT 0x00080 // Override default limits on match & match recursion
-
--#define s_name "pcre"
-+#define s_name "pcre2"
- #define mod_regex_name "regex"
-
--struct PcreData
-+struct Pcre2Data
- {
-- pcre* re; /* compiled regex */
-- pcre_extra* pe; /* studied regex foo */
-- bool free_pe;
-+ pcre2_code* re; /* compiled regex */
-+ pcre2_match_context* match_context; /* match_context for limits */
- int options; /* sp_pcre specific options (relative & inverse) */
- char* expression;
- };
-@@ -83,36 +82,32 @@ struct PcreData
- // by verify; search uses the value in snort conf
- static int s_ovector_max = -1;
-
--static unsigned scratch_index;
--static ScratchAllocator* scratcher = nullptr;
--
--static THREAD_LOCAL ProfileStats pcrePerfStats;
-+static THREAD_LOCAL ProfileStats pcre2PerfStats;
-
- //-------------------------------------------------------------------------
- // implementation foo
- //-------------------------------------------------------------------------
-
--static void pcre_capture(
-- const void* code, const void* extra)
-+static void pcre2_capture(const void* code)
- {
- int tmp_ovector_size = 0;
-
-- pcre_fullinfo((const pcre*)code, (const pcre_extra*)extra,
-- PCRE_INFO_CAPTURECOUNT, &tmp_ovector_size);
-+ pcre2_pattern_info((const pcre2_code *)code,
-+ PCRE2_INFO_CAPTURECOUNT, &tmp_ovector_size);
-
- if (tmp_ovector_size > s_ovector_max)
- s_ovector_max = tmp_ovector_size;
- }
-
--static void pcre_check_anchored(PcreData* pcre_data)
-+static void pcre2_check_anchored(Pcre2Data* pcre2_data)
- {
- int rc;
- unsigned long int options = 0;
-
-- if ((pcre_data == nullptr) || (pcre_data->re == nullptr) || (pcre_data->pe == nullptr))
-+ if ((pcre2_data == nullptr) || (pcre2_data->re == nullptr))
- return;
-
-- rc = pcre_fullinfo(pcre_data->re, pcre_data->pe, PCRE_INFO_OPTIONS, (void*)&options);
-+ rc = pcre2_pattern_info(pcre2_data->re, PCRE2_INFO_ARGOPTIONS, (void*)&options);
- switch (rc)
- {
- /* pcre_fullinfo fails for the following:
-@@ -127,40 +122,41 @@ static void pcre_check_anchored(PcreData
- /* This is the success code */
- break;
-
-- case PCRE_ERROR_NULL:
-- ParseError("pcre_fullinfo: code and/or where were null.");
-+ case PCRE2_ERROR_NULL:
-+ ParseError("pcre2_fullinfo: code and/or where were null.");
- return;
-
-- case PCRE_ERROR_BADMAGIC:
-- ParseError("pcre_fullinfo: compiled code didn't have correct magic.");
-+ case PCRE2_ERROR_BADMAGIC:
-+ ParseError("pcre2_fullinfo: compiled code didn't have correct magic.");
- return;
-
-- case PCRE_ERROR_BADOPTION:
-- ParseError("pcre_fullinfo: option type is invalid.");
-+ case PCRE2_ERROR_BADOPTION:
-+ ParseError("pcre2_fullinfo: option type is invalid.");
- return;
-
- default:
-- ParseError("pcre_fullinfo: Unknown error code.");
-+ ParseError("pcre2_fullinfo: Unknown error code.");
- return;
- }
-
-- if ((options & PCRE_ANCHORED) && !(options & PCRE_MULTILINE))
-+ if ((options & PCRE2_ANCHORED) && !(options & PCRE2_MULTILINE))
- {
- /* This means that this pcre rule option shouldn't be EvalStatus
- * even if any of it's relative children should fail to match.
- * It is anchored to the cursor set by the previous cursor setting
- * rule option */
-- pcre_data->options |= SNORT_PCRE_ANCHORED;
-+ pcre2_data->options |= SNORT_PCRE_ANCHORED;
- }
- }
-
--static void pcre_parse(const SnortConfig* sc, const char* data, PcreData* pcre_data)
-+static void pcre2_parse(const SnortConfig* sc, const char* data, Pcre2Data* pcre2_data)
- {
-- const char* error;
-+ PCRE2_UCHAR error[128];
- char* re, * free_me;
- char* opts;
- char delimit = '/';
-- int erroffset;
-+ int errorcode;
-+ PCRE2_SIZE erroffset;
- int compile_flags = 0;
-
- if (data == nullptr)
-@@ -180,7 +176,7 @@ static void pcre_parse(const SnortConfig
-
- if (*re == '!')
- {
-- pcre_data->options |= SNORT_PCRE_INVERT;
-+ pcre2_data->options |= SNORT_PCRE_INVERT;
- re++;
- while (isspace((int)*re))
- re++;
-@@ -212,7 +208,7 @@ static void pcre_parse(const SnortConfig
- else if (*re != delimit)
- goto syntax;
-
-- pcre_data->expression = snort_strdup(re);
-+ pcre2_data->expression = snort_strdup(re);
-
- /* find ending delimiter, trim delimit chars */
- opts = strrchr(re, delimit);
-@@ -230,25 +226,25 @@ static void pcre_parse(const SnortConfig
- {
- switch (*opts)
- {
-- case 'i': compile_flags |= PCRE_CASELESS; break;
-- case 's': compile_flags |= PCRE_DOTALL; break;
-- case 'm': compile_flags |= PCRE_MULTILINE; break;
-- case 'x': compile_flags |= PCRE_EXTENDED; break;
-+ case 'i': compile_flags |= PCRE2_CASELESS; break;
-+ case 's': compile_flags |= PCRE2_DOTALL; break;
-+ case 'm': compile_flags |= PCRE2_MULTILINE; break;
-+ case 'x': compile_flags |= PCRE2_EXTENDED; break;
-
- /*
- * these are pcre specific... don't work with perl
- */
-- case 'A': compile_flags |= PCRE_ANCHORED; break;
-- case 'E': compile_flags |= PCRE_DOLLAR_ENDONLY; break;
-- case 'G': compile_flags |= PCRE_UNGREEDY; break;
-+ case 'A': compile_flags |= PCRE2_ANCHORED; break;
-+ case 'E': compile_flags |= PCRE2_DOLLAR_ENDONLY; break;
-+ case 'G': compile_flags |= PCRE2_UNGREEDY; break;
-
- /*
-- * these are snort specific don't work with pcre or perl
-+ * these are snort specific don't work with pcre2 or perl
- */
-- case 'R': pcre_data->options |= SNORT_PCRE_RELATIVE; break;
-+ case 'R': pcre2_data->options |= SNORT_PCRE_RELATIVE; break;
- case 'O':
-- if ( sc->pcre_override )
-- pcre_data->options |= SNORT_OVERRIDE_MATCH_LIMIT;
-+ if ( sc->pcre2_override )
-+ pcre2_data->options |= SNORT_OVERRIDE_MATCH_LIMIT;
- break;
-
- default:
-@@ -259,71 +255,68 @@ static void pcre_parse(const SnortConfig
- }
-
- /* now compile the re */
-- pcre_data->re = pcre_compile(re, compile_flags, &error, &erroffset, nullptr);
-+ pcre2_data->re = pcre2_compile((PCRE2_SPTR)re, PCRE2_ZERO_TERMINATED, compile_flags, &errorcode, &erroffset, nullptr);
-+
-+ if (pcre2_data->re == nullptr)
-+ {
-+ pcre2_get_error_message(errorcode, error, 128);
-+ ParseError(": pcre2 compile of '%s' failed at offset "
-+ "%zu : %s", re, erroffset, error);
-+ return;
-+ }
-
-- if (pcre_data->re == nullptr)
-+ /* now create match context */
-+ pcre2_data->match_context = pcre2_match_context_create(NULL);
-+ if(pcre2_data->match_context == NULL)
- {
-- ParseError(": pcre compile of '%s' failed at offset "
-- "%d : %s", re, erroffset, error);
-+ ParseError(": failed to allocate memory for match context");
- return;
- }
-
- /* now study it... */
-- pcre_data->pe = pcre_study(pcre_data->re, PCRE_STUDY_FLAGS, &error);
-+ if (PCRE2_JIT)
-+ errorcode = pcre2_jit_compile(pcre2_data->re, PCRE2_JIT_COMPLETE);
-
-- if (pcre_data->pe)
-+ if (PCRE2_JIT || errorcode)
- {
-- if ((sc->get_pcre_match_limit() != 0) &&
-- !(pcre_data->options & SNORT_OVERRIDE_MATCH_LIMIT))
-+ if ((sc->get_pcre2_match_limit() != 0) &&
-+ !(pcre2_data->options & SNORT_OVERRIDE_MATCH_LIMIT))
- {
-- if ( !(pcre_data->pe->flags & PCRE_EXTRA_MATCH_LIMIT) )
-- pcre_data->pe->flags |= PCRE_EXTRA_MATCH_LIMIT;
--
-- pcre_data->pe->match_limit = sc->get_pcre_match_limit();
-+ pcre2_set_match_limit(pcre2_data->match_context, sc->get_pcre2_match_limit());
- }
-
-- if ((sc->get_pcre_match_limit_recursion() != 0) &&
-- !(pcre_data->options & SNORT_OVERRIDE_MATCH_LIMIT))
-+ if ((sc->get_pcre2_match_limit_recursion() != 0) &&
-+ !(pcre2_data->options & SNORT_OVERRIDE_MATCH_LIMIT))
- {
-- if ( !(pcre_data->pe->flags & PCRE_EXTRA_MATCH_LIMIT_RECURSION) )
-- pcre_data->pe->flags |= PCRE_EXTRA_MATCH_LIMIT_RECURSION;
--
-- pcre_data->pe->match_limit_recursion =
-- sc->get_pcre_match_limit_recursion();
-+ pcre2_set_match_limit(pcre2_data->match_context, sc->get_pcre2_match_limit_recursion());
- }
- }
- else
- {
-- if (!(pcre_data->options & SNORT_OVERRIDE_MATCH_LIMIT) &&
-- ((sc->get_pcre_match_limit() != 0) ||
-- (sc->get_pcre_match_limit_recursion() != 0)))
-+ if (!(pcre2_data->options & SNORT_OVERRIDE_MATCH_LIMIT) &&
-+ ((sc->get_pcre2_match_limit() != 0) ||
-+ (sc->get_pcre2_match_limit_recursion() != 0)))
- {
-- pcre_data->pe = (pcre_extra*)snort_calloc(sizeof(pcre_extra));
-- pcre_data->free_pe = true;
--
-- if (sc->get_pcre_match_limit() != 0)
-+ if (sc->get_pcre2_match_limit() != 0)
- {
-- pcre_data->pe->flags |= PCRE_EXTRA_MATCH_LIMIT;
-- pcre_data->pe->match_limit = sc->get_pcre_match_limit();
-+ pcre2_set_match_limit(pcre2_data->match_context, sc->get_pcre2_match_limit());
- }
-
-- if (sc->get_pcre_match_limit_recursion() != 0)
-+ if (sc->get_pcre2_match_limit_recursion() != 0)
- {
-- pcre_data->pe->flags |= PCRE_EXTRA_MATCH_LIMIT_RECURSION;
-- pcre_data->pe->match_limit_recursion =
-- sc->get_pcre_match_limit_recursion();
-+ pcre2_set_match_limit(pcre2_data->match_context, sc->get_pcre2_match_limit_recursion());
- }
- }
- }
-
-- if (error != nullptr)
-+ if (PCRE2_JIT && errorcode)
- {
-- ParseError("pcre study failed : %s", error);
-+ ParseError("pcre2 JIT failed : %s", error);
- return;
- }
-
-- pcre_capture(pcre_data->re, pcre_data->pe);
-- pcre_check_anchored(pcre_data);
-+ pcre2_capture(pcre2_data->re);
-+ pcre2_check_anchored(pcre2_data);
-
- snort_free(free_me);
- return;
-@@ -332,40 +325,44 @@ syntax:
- snort_free(free_me);
-
- // ensure integrity from parse error to fatal error
-- if ( !pcre_data->expression )
-- pcre_data->expression = snort_strdup("");
-+ if ( !pcre2_data->expression )
-+ pcre2_data->expression = snort_strdup("");
-
-- ParseError("unable to parse pcre %s", data);
-+ ParseError("unable to parse pcre2 %s", data);
- }
-
- /*
-- * Perform a search of the PCRE data.
-+ * Perform a search of the PCRE2 data.
- * found_offset will be set to -1 when the find is unsuccessful OR the routine is inverted
- */
--static bool pcre_search(
-+static bool pcre2_search(
- Packet* p,
-- const PcreData* pcre_data,
-+ const Pcre2Data* pcre2_data,
- const uint8_t* buf,
- unsigned len,
- unsigned start_offset,
- int& found_offset)
- {
-+ pcre2_match_data *match_data;
-+ PCRE2_SIZE *ovector;
- bool matched;
-
- found_offset = -1;
-
-- std::vector<void *> ss = p->context->conf->state[get_instance_id()];
-- assert(ss[scratch_index]);
-+ match_data = pcre2_match_data_create(p->context->conf->pcre2_ovector_size, NULL);
-+ if (match_data == nullptr) {
-+ pc.pcre2_error++;
-+ return false;
-+ }
-
-- int result = pcre_exec(
-- pcre_data->re, /* result of pcre_compile() */
-- pcre_data->pe, /* result of pcre_study() */
-- (const char*)buf, /* the subject string */
-- len, /* the length of the subject string */
-- start_offset, /* start at offset 0 in the subject */
-- 0, /* options(handled at compile time */
-- (int*)ss[scratch_index], /* vector for substring information */
-- p->context->conf->pcre_ovector_size); /* number of elements in the vector */
-+ int result = pcre2_match(
-+ pcre2_data->re, /* result of pcre_compile() */
-+ (PCRE2_SPTR)buf, /* the subject string */
-+ (PCRE2_SIZE)len, /* the length of the subject string */
-+ (PCRE2_SIZE)start_offset, /* start at offset 0 in the subject */
-+ 0, /* options(handled at compile time */
-+ match_data, /* match data to store the match results */
-+ pcre2_data->match_context); /* match context for limits */
-
- if (result >= 0)
- {
-@@ -390,34 +387,37 @@ static bool pcre_search(
- * and a single int for scratch space.
- */
-
-- found_offset = ((int*)ss[scratch_index])[1];
-+ ovector = pcre2_get_ovector_pointer(match_data);
-+ found_offset = ovector[1];
- }
-- else if (result == PCRE_ERROR_NOMATCH)
-+ else if (result == PCRE2_ERROR_NOMATCH)
- {
- matched = false;
- }
-- else if (result == PCRE_ERROR_MATCHLIMIT)
-+ else if (result == PCRE2_ERROR_MATCHLIMIT)
- {
-- pc.pcre_match_limit++;
-+ pc.pcre2_match_limit++;
- matched = false;
- }
-- else if (result == PCRE_ERROR_RECURSIONLIMIT)
-+ else if (result == PCRE2_ERROR_RECURSIONLIMIT)
- {
-- pc.pcre_recursion_limit++;
-+ pc.pcre2_recursion_limit++;
- matched = false;
- }
- else
- {
-- pc.pcre_error++;
-+ pc.pcre2_error++;
- return false;
- }
-
- /* invert sense of match */
-- if (pcre_data->options & SNORT_PCRE_INVERT)
-+ if (pcre2_data->options & SNORT_PCRE_INVERT)
- {
- matched = !matched;
- }
-
-+ pcre2_match_data_free(match_data);
-+
- return matched;
- }
-
-@@ -425,14 +425,14 @@ static bool pcre_search(
- // class methods
- //-------------------------------------------------------------------------
-
--class PcreOption : public IpsOption
-+class Pcre2Option : public IpsOption
- {
- public:
-- PcreOption(PcreData* c) :
-+ Pcre2Option(Pcre2Data* c) :
- IpsOption(s_name, RULE_OPTION_TYPE_CONTENT)
- { config = c; }
-
-- ~PcreOption() override;
-+ ~Pcre2Option() override;
-
- uint32_t hash() const override;
- bool operator==(const IpsOption&) const override;
-@@ -446,17 +446,17 @@ public:
- EvalStatus eval(Cursor&, Packet*) override;
- bool retry(Cursor&, const Cursor&) override;
-
-- PcreData* get_data()
-+ Pcre2Data* get_data()
- { return config; }
-
-- void set_data(PcreData* pcre)
-+ void set_data(Pcre2Data* pcre)
- { config = pcre; }
-
- private:
-- PcreData* config;
-+ Pcre2Data* config;
- };
-
--PcreOption::~PcreOption()
-+Pcre2Option::~Pcre2Option()
- {
- if ( !config )
- return;
-@@ -464,21 +464,16 @@ PcreOption::~PcreOption()
- if ( config->expression )
- snort_free(config->expression);
-
-- if ( config->pe )
-- {
-- if ( config->free_pe )
-- snort_free(config->pe);
-- else
-- pcre_release(config->pe);
-- }
-+ if ( config->match_context )
-+ pcre2_match_context_free(config->match_context);
-
- if ( config->re )
-- free(config->re); // external allocation
-+ pcre2_code_free(config->re); // external allocation
-
- snort_free(config);
- }
-
--uint32_t PcreOption::hash() const
-+uint32_t Pcre2Option::hash() const
- {
- uint32_t a = 0, b = 0, c = 0;
- int expression_len = strlen(config->expression);
-@@ -532,14 +527,14 @@ uint32_t PcreOption::hash() const
- return c;
- }
-
--bool PcreOption::operator==(const IpsOption& ips) const
-+bool Pcre2Option::operator==(const IpsOption& ips) const
- {
- if ( !IpsOption::operator==(ips) )
- return false;
-
-- const PcreOption& rhs = (const PcreOption&)ips;
-- PcreData* left = config;
-- PcreData* right = rhs.config;
-+ const Pcre2Option& rhs = (const Pcre2Option&)ips;
-+ Pcre2Data* left = config;
-+ Pcre2Data* right = rhs.config;
-
- if (( strcmp(left->expression, right->expression) == 0) &&
- ( left->options == right->options))
-@@ -550,13 +545,13 @@ bool PcreOption::operator==(const IpsOpt
- return false;
- }
-
--IpsOption::EvalStatus PcreOption::eval(Cursor& c, Packet* p)
-+IpsOption::EvalStatus Pcre2Option::eval(Cursor& c, Packet* p)
- {
- // cppcheck-suppress unreadVariable
-- RuleProfile profile(pcrePerfStats);
-+ RuleProfile profile(pcre2PerfStats);
-
-- // short circuit this for testing pcre performance impact
-- if ( p->context->conf->no_pcre() )
-+ // short circuit this for testing pcre2 performance impact
-+ if ( p->context->conf->no_pcre2() )
- return NO_MATCH;
-
- unsigned pos = c.get_delta();
-@@ -570,7 +565,7 @@ IpsOption::EvalStatus PcreOption::eval(C
-
- int found_offset = -1; // where is the ending location of the pattern
-
-- if ( pcre_search(p, config, c.buffer()+adj, c.size()-adj, pos, found_offset) )
-+ if ( pcre2_search(p, config, c.buffer()+adj, c.size()-adj, pos, found_offset) )
- {
- if ( found_offset > 0 )
- {
-@@ -585,17 +580,17 @@ IpsOption::EvalStatus PcreOption::eval(C
- }
-
- // we always advance by found_offset so no adjustments to cursor are done
--// here; note also that this means relative pcre matches on overlapping
-+// here; note also that this means relative pcre2 matches on overlapping
- // patterns won't work. given the test pattern "ABABACD":
- //
- // ( sid:1; content:"ABA"; content:"C"; within:1; )
--// ( sid:2; pcre:"/ABA/"; content:"C"; within:1; )
-+// ( sid:2; pcre2:"/ABA/"; content:"C"; within:1; )
- //
- // sid 1 will fire but sid 2 will NOT. this example is easily fixed by
--// using content, but more advanced pcre won't work for the relative /
-+// using content, but more advanced pcre2 won't work for the relative /
- // overlap case.
-
--bool PcreOption::retry(Cursor&, const Cursor&)
-+bool Pcre2Option::retry(Cursor&, const Cursor&)
- {
- if ((config->options & (SNORT_PCRE_INVERT | SNORT_PCRE_ANCHORED)))
- {
-@@ -616,46 +611,43 @@ static const Parameter s_params[] =
- { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
- };
-
--struct PcreStats
-+struct Pcre2Stats
- {
-- PegCount pcre_rules;
-+ PegCount pcre2_rules;
- #ifdef HAVE_HYPERSCAN
-- PegCount pcre_to_hyper;
-+ PegCount pcre2_to_hyper;
- #endif
-- PegCount pcre_native;
-- PegCount pcre_negated;
-+ PegCount pcre2_native;
-+ PegCount pcre2_negated;
- };
-
- const PegInfo pcre_pegs[] =
- {
-- { CountType::SUM, "pcre_rules", "total rules processed with pcre option" },
-+ { CountType::SUM, "pcre2_rules", "total rules processed with pcre2 option" },
- #ifdef HAVE_HYPERSCAN
-- { CountType::SUM, "pcre_to_hyper", "total pcre rules by hyperscan engine" },
-+ { CountType::SUM, "pcre2_to_hyper", "total pcre2 rules by hyperscan engine" },
- #endif
-- { CountType::SUM, "pcre_native", "total pcre rules compiled by pcre engine" },
-- { CountType::SUM, "pcre_negated", "total pcre rules using negation syntax" },
-+ { CountType::SUM, "pcre2_native", "total pcre2 rules compiled by pcre engine" },
-+ { CountType::SUM, "pcre2_negated", "total pcre2 rules using negation syntax" },
- { CountType::END, nullptr, nullptr }
- };
-
--PcreStats pcre_stats;
-+Pcre2Stats pcre2_stats;
-
- #define s_help \
-- "rule option for matching payload data with pcre"
-+ "rule option for matching payload data with pcre2"
-
--class PcreModule : public Module
-+class Pcre2Module : public Module
- {
- public:
-- PcreModule() : Module(s_name, s_help, s_params)
-+ Pcre2Module() : Module(s_name, s_help, s_params)
- {
- data = nullptr;
-- scratcher = new SimpleScratchAllocator(scratch_setup, scratch_cleanup);
-- scratch_index = scratcher->get_id();
- }
-
-- ~PcreModule() override
-+ ~Pcre2Module() override
- {
- delete data;
-- delete scratcher;
- }
-
- #ifdef HAVE_HYPERSCAN
-@@ -665,12 +657,12 @@ public:
- bool end(const char*, int, SnortConfig*) override;
-
- ProfileStats* get_profile() const override
-- { return &pcrePerfStats; }
-+ { return &pcre2PerfStats; }
-
- const PegInfo* get_pegs() const override;
- PegCount* get_counts() const override;
-
-- PcreData* get_data();
-+ Pcre2Data* get_data();
-
- bool global_stats() const override
- { return true; }
-@@ -682,31 +674,28 @@ public:
- { return mod_regex; }
-
- private:
-- PcreData* data;
-+ Pcre2Data* data;
- Module* mod_regex = nullptr;
- std::string re;
--
-- static bool scratch_setup(SnortConfig*);
-- static void scratch_cleanup(SnortConfig*);
- };
-
--PcreData* PcreModule::get_data()
-+Pcre2Data* Pcre2Module::get_data()
- {
-- PcreData* tmp = data;
-+ Pcre2Data* tmp = data;
- data = nullptr;
- return tmp;
- }
-
--const PegInfo* PcreModule::get_pegs() const
-+const PegInfo* Pcre2Module::get_pegs() const
- { return pcre_pegs; }
-
--PegCount* PcreModule::get_counts() const
--{ return (PegCount*)&pcre_stats; }
-+PegCount* Pcre2Module::get_counts() const
-+{ return (PegCount*)&pcre2_stats; }
-
- #ifdef HAVE_HYPERSCAN
--bool PcreModule::begin(const char* name, int v, SnortConfig* sc)
-+bool Pcre2Module::begin(const char* name, int v, SnortConfig* sc)
- {
-- if ( sc->pcre_to_regex )
-+ if ( sc->pcre2_to_regex )
- {
- if ( !mod_regex )
- mod_regex = ModuleManager::get_module(mod_regex_name);
-@@ -718,7 +707,7 @@ bool PcreModule::begin(const char* name,
- }
- #endif
-
--bool PcreModule::set(const char* name, Value& v, SnortConfig* sc)
-+bool Pcre2Module::set(const char* name, Value& v, SnortConfig* sc)
- {
- assert(v.is("~re"));
- re = v.get_string();
-@@ -729,50 +718,28 @@ bool PcreModule::set(const char* name, V
- return true;
- }
-
--bool PcreModule::end(const char* name, int v, SnortConfig* sc)
-+bool Pcre2Module::end(const char* name, int v, SnortConfig* sc)
- {
- if( mod_regex )
- mod_regex = mod_regex->end(name, v, sc) ? mod_regex : nullptr;
-
- if ( !mod_regex )
- {
-- data = (PcreData*)snort_calloc(sizeof(*data));
-- pcre_parse(sc, re.c_str(), data);
-+ data = (Pcre2Data*)snort_calloc(sizeof(*data));
-+ pcre2_parse(sc, re.c_str(), data);
- }
-
-- return true;
--}
--
--bool PcreModule::scratch_setup(SnortConfig* sc)
--{
-- if ( s_ovector_max < 0 )
-- return false;
--
- // The pcre_fullinfo() function can be used to find out how many
- // capturing subpatterns there are in a compiled pattern. The
- // smallest size for ovector that will allow for n captured
- // substrings, in addition to the offsets of the substring matched
- // by the whole pattern is 3(n+1).
--
-- sc->pcre_ovector_size = 3 * (s_ovector_max + 1);
-- s_ovector_max = -1;
--
-- for ( unsigned i = 0; i < sc->num_slots; ++i )
-- {
-- std::vector<void *>& ss = sc->state[i];
-- ss[scratch_index] = snort_calloc(sc->pcre_ovector_size, sizeof(int));
-+ if ( s_ovector_max >= 0 ) {
-+ sc->pcre2_ovector_size = 3 * (s_ovector_max + 1);
-+ s_ovector_max = -1;
- }
-- return true;
--}
-
--void PcreModule::scratch_cleanup(SnortConfig* sc)
--{
-- for ( unsigned i = 0; i < sc->num_slots; ++i )
-- {
-- std::vector<void *>& ss = sc->state[i];
-- snort_free(ss[scratch_index]);
-- ss[scratch_index] = nullptr;
-- }
-+ return true;
- }
-
- //-------------------------------------------------------------------------
-@@ -780,21 +747,21 @@ void PcreModule::scratch_cleanup(SnortCo
- //-------------------------------------------------------------------------
-
- static Module* mod_ctor()
--{ return new PcreModule; }
-+{ return new Pcre2Module; }
-
- static void mod_dtor(Module* m)
- { delete m; }
-
--static IpsOption* pcre_ctor(Module* p, OptTreeNode* otn)
-+static IpsOption* pcre2_ctor(Module* p, OptTreeNode* otn)
- {
-- pcre_stats.pcre_rules++;
-- PcreModule* m = (PcreModule*)p;
-+ pcre2_stats.pcre2_rules++;
-+ Pcre2Module* m = (Pcre2Module*)p;
-
- #ifdef HAVE_HYPERSCAN
- Module* mod_regex = m->get_mod_regex();
- if ( mod_regex )
- {
-- pcre_stats.pcre_to_hyper++;
-+ pcre2_stats.pcre2_to_hyper++;
- const IpsApi* opt_api = IpsManager::get_option_api(mod_regex_name);
- return opt_api->ctor(mod_regex, otn);
- }
-@@ -803,16 +770,16 @@ static IpsOption* pcre_ctor(Module* p, O
- UNUSED(otn);
- #endif
- {
-- pcre_stats.pcre_native++;
-- PcreData* d = m->get_data();
-- return new PcreOption(d);
-+ pcre2_stats.pcre2_native++;
-+ Pcre2Data* d = m->get_data();
-+ return new Pcre2Option(d);
- }
- }
-
--static void pcre_dtor(IpsOption* p)
-+static void pcre2_dtor(IpsOption* p)
- { delete p; }
-
--static const IpsApi pcre_api =
-+static const IpsApi pcre2_api =
- {
- {
- PT_IPS_OPTION,
-@@ -832,17 +799,17 @@ static const IpsApi pcre_api =
- nullptr,
- nullptr,
- nullptr,
-- pcre_ctor,
-- pcre_dtor,
-+ pcre2_ctor,
-+ pcre2_dtor,
- nullptr
- };
-
- #ifdef BUILDING_SO
- SO_PUBLIC const BaseApi* snort_plugins[] =
- #else
--const BaseApi* ips_pcre[] =
-+const BaseApi* ips_pcre2[] =
- #endif
- {
-- &pcre_api.base,
-+ &pcre2_api.base,
- nullptr
- };
---- a/src/main/shell.cc
-+++ b/src/main/shell.cc
-@@ -29,7 +29,8 @@
- #include <fstream>
- #include <openssl/crypto.h>
- #include <pcap.h>
--#include <pcre.h>
-+#define PCRE2_CODE_UNIT_WIDTH 8
-+#include <pcre2.h>
- #include <stdexcept>
- #include <vector>
- #include <zlib.h>
-@@ -138,13 +139,17 @@ static void install_version_strings(lua_
-
- static void install_dependencies_strings(Shell* sh, lua_State* L)
- {
-+
- assert(dep_versions[0]);
-
-+ const char pcre2_version[32] = { 0 };
- std::vector<const char*> vs;
- const char* ljv = LUAJIT_VERSION;
- const char* osv = OpenSSL_version(SSLEAY_VERSION);
- const char* lpv = pcap_lib_version();
-
-+ pcre2_config(PCRE2_CONFIG_VERSION, (PCRE2_UCHAR8 *)pcre2_version);
-+
- while (*ljv and !isdigit(*ljv))
- ++ljv;
- while (*osv and !isdigit(*osv))
-@@ -156,7 +161,7 @@ static void install_dependencies_strings
- vs.push_back(ljv);
- vs.push_back(osv);
- vs.push_back(lpv);
-- vs.push_back(pcre_version());
-+ vs.push_back(pcre2_version);
- vs.push_back(zlib_version);
- #ifdef HAVE_HYPERSCAN
- vs.push_back(hs_version());
---- a/src/main/snort_config.h
-+++ b/src/main/snort_config.h
-@@ -60,7 +60,7 @@ enum RunFlag
- RUN_FLAG__PCAP_SHOW = 0x00001000,
- RUN_FLAG__SHOW_FILE_CODES = 0x00002000,
- RUN_FLAG__PAUSE = 0x00004000,
-- RUN_FLAG__NO_PCRE = 0x00008000,
-+ RUN_FLAG__NO_PCRE2 = 0x00008000,
-
- RUN_FLAG__DUMP_RULE_STATE = 0x00010000,
- RUN_FLAG__DUMP_RULE_DEPS = 0x00020000,
-@@ -214,13 +214,13 @@ public:
-
- //------------------------------------------------------
- // detection module stuff
-- // FIXIT-L pcre_match_limit* are interdependent
-+ // FIXIT-L pcre2_match_limit* are interdependent
- // somehow a packet thread needs a much lower setting
-- long int pcre_match_limit = 1500;
-- long int pcre_match_limit_recursion = 1500;
-+ long int pcre2_match_limit = 1500;
-+ long int pcre2_match_limit_recursion = 1500;
-
-- int pcre_ovector_size = 0;
-- bool pcre_override = true;
-+ int pcre2_ovector_size = 0;
-+ bool pcre2_override = true;
-
- uint32_t run_flags = 0;
-
-@@ -228,7 +228,7 @@ public:
- unsigned offload_threads = 0; // disabled
-
- bool hyperscan_literals = false;
-- bool pcre_to_regex = false;
-+ bool pcre2_to_regex = false;
-
- bool global_rule_state = false;
- bool global_default_rule_state = true;
-@@ -600,8 +600,8 @@ public:
- bool alert_before_pass() const
- { return run_flags & RUN_FLAG__ALERT_BEFORE_PASS; }
-
-- bool no_pcre() const
-- { return run_flags & RUN_FLAG__NO_PCRE; }
-+ bool no_pcre2() const
-+ { return run_flags & RUN_FLAG__NO_PCRE2; }
-
- bool conf_error_out() const
- { return run_flags & RUN_FLAG__CONF_ERROR_OUT; }
-@@ -616,11 +616,11 @@ public:
- uint8_t new_ttl() const
- { return get_network_policy()->new_ttl; }
-
-- long int get_pcre_match_limit() const
-- { return pcre_match_limit; }
-+ long int get_pcre2_match_limit() const
-+ { return pcre2_match_limit; }
-
-- long int get_pcre_match_limit_recursion() const
-- { return pcre_match_limit_recursion; }
-+ long int get_pcre2_match_limit_recursion() const
-+ { return pcre2_match_limit_recursion; }
-
- const ProfilerConfig* get_profiler() const
- { return profiler; }
---- a/src/network_inspectors/appid/lua_detector_api.cc
-+++ b/src/network_inspectors/appid/lua_detector_api.cc
-@@ -25,7 +25,8 @@
-
- #include "lua_detector_api.h"
- #include <lua.hpp>
--#include <pcre.h>
-+#define PCRE2_CODE_UNIT_WIDTH 8
-+#include <pcre2.h>
- #include <unordered_map>
-
- #include "detection/fp_config.h"
-@@ -714,7 +715,7 @@ static int detector_get_packet_direction
- return 1;
- }
-
--/**Perform a pcre match with grouping. A simple regular expression match with no grouping
-+/**Perform a pcre2 match with grouping. A simple regular expression match with no grouping
- * can also be performed.
- *
- * @param Lua_State* - Lua state variable.
-@@ -723,41 +724,50 @@ static int detector_get_packet_direction
- * @return matchedStrings/stack - matched strings are pushed on stack starting with group 0.
- * There may be 0 or more strings.
- */
--static int detector_get_pcre_groups(lua_State* L)
-+static int detector_get_pcre2_groups(lua_State* L)
- {
- auto& ud = *UserData<LuaObject>::check(L, DETECTOR, 1);
- // Verify detector user data and that we are in packet context
- LuaStateDescriptor* lsd = ud->validate_lua_state(true);
-
-- int ovector[OVECCOUNT];
-- const char* error;
-- int erroffset;
-+ PCRE2_SIZE* ovector;
-+ pcre2_match_data* match_data;
-+ PCRE2_UCHAR error[128];
-+ PCRE2_SIZE erroffset;
-+ int errorcode;
-
- const char* pattern = lua_tostring(L, 2);
- unsigned int offset = lua_tonumber(L, 3); /*offset can be zero, no check necessary. */
-
- /*compile the regular expression pattern, and handle errors */
-- pcre* re = pcre_compile(pattern, // the pattern
-- PCRE_DOTALL, // default options - dot matches all inc \n
-- &error, // for error message
-- &erroffset, // for error offset
-- nullptr); // use default character tables
-+ pcre2_code* re = pcre2_compile((PCRE2_SPTR)pattern, // the pattern
-+ PCRE2_ZERO_TERMINATED, // assume zero terminated strings
-+ PCRE2_DOTALL, // default options - dot matches all inc \n
-+ &errorcode, // for error message
-+ &erroffset, // for error offset
-+ nullptr); // use default character tables
-
- if (re == nullptr)
- {
-- appid_log(lsd->ldp.pkt, TRACE_ERROR_LEVEL, "PCRE compilation failed at offset %d: %s\n", erroffset, error);
-+ pcre2_get_error_message(errorcode, error, 128);
-+ appid_log(lsd->ldp.pkt, TRACE_ERROR_LEVEL, "PCRE2 compilation failed at offset %d: %s\n", erroffset, error);
-+ return 0;
-+ }
-+
-+ match_data = pcre2_match_data_create(OVECCOUNT, NULL);
-+ if (match_data == nullptr) {
-+ appid_log(lsd->ldp.pkt, TRACE_ERROR_LEVEL, "PCRE2 failed to allocate mem for match_data\n");
- return 0;
- }
-
- /*pattern match against the subject string. */
-- int rc = pcre_exec(re, // compiled pattern
-- nullptr, // no extra data
-- (const char*)lsd->ldp.data, // subject string
-- lsd->ldp.size, // length of the subject
-- offset, // offset 0
-- 0, // default options
-- ovector, // output vector for substring information
-- OVECCOUNT); // number of elements in the output vector
-+ int rc = pcre2_match(re, // compiled pattern
-+ (PCRE2_SPTR)lsd->ldp.data, // subject string
-+ (PCRE2_SIZE)lsd->ldp.size, // length of the subject
-+ (PCRE2_SIZE)offset, // offset 0
-+ 0, // default options
-+ match_data, // match data for match results
-+ NULL); // no match context
-
- if (rc >= 0)
- {
-@@ -771,10 +781,11 @@ static int detector_get_pcre_groups(lua_
- if (!lua_checkstack(L, rc))
- {
- appid_log(lsd->ldp.pkt, TRACE_WARNING_LEVEL, "Cannot grow Lua stack by %d slots to hold "
-- "PCRE matches\n", rc);
-+ "PCRE2 matches\n", rc);
- return 0;
- }
-
-+ ovector = pcre2_get_ovector_pointer(match_data);
- for (int i = 0; i < rc; i++)
- {
- lua_pushlstring(L, (const char*)lsd->ldp.data + ovector[2*i], ovector[2*i+1] -
-@@ -784,12 +795,13 @@ static int detector_get_pcre_groups(lua_
- else
- {
- // log errors except no matches
-- if (rc != PCRE_ERROR_NOMATCH)
-- appid_log(lsd->ldp.pkt, TRACE_WARNING_LEVEL, "PCRE regular expression group match failed. rc: %d\n", rc);
-+ if (rc != PCRE2_ERROR_NOMATCH)
-+ appid_log(lsd->ldp.pkt, TRACE_WARNING_LEVEL, "PCRE2 regular expression group match failed. rc: %d\n", rc);
- rc = 0;
- }
-
-- pcre_free(re);
-+ pcre2_match_data_free(match_data);
-+ pcre2_code_free(re);
- return rc;
- }
-
-@@ -3229,7 +3241,7 @@ static const luaL_Reg detector_methods[]
- { "getPacketSize", detector_get_packet_size },
- { "getPacketDir", detector_get_packet_direction },
- { "matchSimplePattern", detector_memcmp },
-- { "getPcreGroups", detector_get_pcre_groups },
-+ { "getPcreGroups", detector_get_pcre2_groups },
- { "getL4Protocol", detector_get_protocol_type },
- { "getPktSrcAddr", detector_get_packet_src_addr },
- { "getPktDstAddr", detector_get_packet_dst_addr },
---- a/src/parser/parse_rule.cc
-+++ b/src/parser/parse_rule.cc
-@@ -911,10 +911,10 @@ void parse_rule_dir(SnortConfig*, const
- ParseError("illegal direction specifier: %s", s);
- }
-
--// Values of the rule options "pcre", "regex" and "sd_pattern" are already escaped
-+// Values of the rule options "pcre2", "regex" and "sd_pattern" are already escaped
- // They are not unescaped during the rule parsing
- static bool is_already_escaped(const std::string& opt_key)
--{ return opt_key == "pcre" or opt_key == "regex" or opt_key == "sd_pattern"; }
-+{ return opt_key == "pcre2" or opt_key == "regex" or opt_key == "sd_pattern"; }
-
- static std::string escape(const std::string& s)
- {
---- a/src/parser/parse_stream.cc
-+++ b/src/parser/parse_stream.cc
-@@ -603,7 +603,7 @@ static bool exec(
- // that individual rule options can do whatever
- static int get_escape(const string& s)
- {
-- if ( s == "pcre" )
-+ if ( s == "pcre2" )
- return 0; // no escape, option goes to ;
-
- else if ( s == "regex" || s == "sd_pattern" )
---- a/src/search_engines/test/hyperscan_test.cc
-+++ b/src/search_engines/test/hyperscan_test.cc
-@@ -223,7 +223,7 @@ TEST(mpse_hs_match, regex)
- CHECK(hits == 3);
- }
-
--TEST(mpse_hs_match, pcre)
-+TEST(mpse_hs_match, pcre2)
- {
- Mpse::PatternDescriptor desc;
-
---- a/src/utils/stats.cc
-+++ b/src/utils/stats.cc
-@@ -227,9 +227,9 @@ const PegInfo pc_names[] =
- { CountType::SUM, "offload_fallback", "fast pattern offload search fallback attempts" },
- { CountType::SUM, "offload_failures", "fast pattern offload search failures" },
- { CountType::SUM, "offload_suspends", "fast pattern search suspends due to offload context chains" },
-- { CountType::SUM, "pcre_match_limit", "total number of times pcre hit the match limit" },
-- { CountType::SUM, "pcre_recursion_limit", "total number of times pcre hit the recursion limit" },
-- { CountType::SUM, "pcre_error", "total number of times pcre returns error" },
-+ { CountType::SUM, "pcre2_match_limit", "total number of times pcre2 hit the match limit" },
-+ { CountType::SUM, "pcre2_recursion_limit", "total number of times pcre2 hit the recursion limit" },
-+ { CountType::SUM, "pcre2_error", "total number of times pcre2 returns error" },
- { CountType::SUM, "cont_creations", "total number of continuations created" },
- { CountType::SUM, "cont_recalls", "total number of continuations recalled" },
- { CountType::SUM, "cont_flows", "total number of flows using continuation" },
---- a/src/utils/stats.h
-+++ b/src/utils/stats.h
-@@ -60,9 +60,9 @@ struct PacketCount
- PegCount offload_fallback;
- PegCount offload_failures;
- PegCount offload_suspends;
-- PegCount pcre_match_limit;
-- PegCount pcre_recursion_limit;
-- PegCount pcre_error;
-+ PegCount pcre2_match_limit;
-+ PegCount pcre2_recursion_limit;
-+ PegCount pcre2_error;
- PegCount cont_creations;
- PegCount cont_recalls;
- PegCount cont_flows;
---- a/src/utils/util.cc
-+++ b/src/utils/util.cc
-@@ -30,7 +30,8 @@
- #include <netdb.h>
- #include <openssl/crypto.h>
- #include <pcap.h>
--#include <pcre.h>
-+#define PCRE2_CODE_UNIT_WIDTH 8
-+#include <pcre2.h>
- #include <pwd.h>
- #include <sys/file.h>
- #include <sys/resource.h>
-@@ -105,10 +106,13 @@ void StoreSnortInfoStrings()
-
- int DisplayBanner()
- {
-+ PCRE2_UCHAR pcre2_version[32];
- const char* ljv = LUAJIT_VERSION;
- while ( *ljv && !isdigit(*ljv) )
- ++ljv;
-
-+ pcre2_config(PCRE2_CONFIG_VERSION, pcre2_version);
-+
- LogMessage("\n");
- LogMessage(" ,,_ -*> Snort++ <*-\n");
- #ifdef BUILD
-@@ -125,7 +129,7 @@ int DisplayBanner()
- LogMessage(" Using LuaJIT version %s\n", ljv);
- LogMessage(" Using %s\n", OpenSSL_version(SSLEAY_VERSION));
- LogMessage(" Using %s\n", pcap_lib_version());
-- LogMessage(" Using PCRE version %s\n", pcre_version());
-+ LogMessage(" Using PCRE version %s\n", pcre2_version);
- LogMessage(" Using ZLIB version %s\n", zlib_version);
- #ifdef HAVE_HYPERSCAN
- LogMessage(" Using Hyperscan version %s\n", hs_version());
---- a/tools/snort2lua/config_states/config_api.cc
-+++ b/tools/snort2lua/config_states/config_api.cc
-@@ -105,13 +105,13 @@ extern const ConvertMap* min_ttl_map;
- extern const ConvertMap* na_policy_mode_map;
- extern const ConvertMap* new_ttl_map;
- extern const ConvertMap* nolog_map;
--extern const ConvertMap* nopcre_map;
-+extern const ConvertMap* nopcre2_map;
- extern const ConvertMap* no_promisc_map;
- extern const ConvertMap* obfuscate_map;
- extern const ConvertMap* order_map;
- extern const ConvertMap* paf_max_map;
--extern const ConvertMap* pcre_match_limit_map;
--extern const ConvertMap* pcre_match_limit_recursion_map;
-+extern const ConvertMap* pcre2_match_limit_map;
-+extern const ConvertMap* pcre2_match_limit_recursion_map;
- extern const ConvertMap* pkt_count_map;
- extern const ConvertMap* ppm_map;
- extern const ConvertMap* policy_id_map;
-@@ -224,13 +224,13 @@ const std::vector<const ConvertMap*> con
- na_policy_mode_map,
- new_ttl_map,
- nolog_map,
-- nopcre_map,
-+ nopcre2_map,
- no_promisc_map,
- obfuscate_map,
- order_map,
- paf_max_map,
-- pcre_match_limit_map,
-- pcre_match_limit_recursion_map,
-+ pcre2_match_limit_map,
-+ pcre2_match_limit_recursion_map,
- pkt_count_map,
- ppm_map,
- policy_id_map,
---- a/tools/snort2lua/config_states/config_no_option.cc
-+++ b/tools/snort2lua/config_states/config_no_option.cc
-@@ -250,18 +250,18 @@ static const ConvertMap enable_mpls_over
- const ConvertMap* enable_mpls_overlapping_ip_map = &enable_mpls_overlapping_ip_api;
-
- /*************************************************
-- ******************** nopcre *******************
-+ ******************** nopcre2 *******************
- *************************************************/
-
--static const std::string nopcre = "nopcre";
--static const std::string pcre_enable = "pcre_enable";
--static const ConvertMap nopcre_api =
-+static const std::string nopcre2 = "nopcre2";
-+static const std::string pcre2_enable = "pcre2_enable";
-+static const ConvertMap nopcre2_api =
- {
-- nopcre,
-- config_false_no_opt_ctor<& nopcre, & detection, & pcre_enable>
-+ nopcre2,
-+ config_false_no_opt_ctor<& nopcre2, & detection, & pcre2_enable>
- };
-
--const ConvertMap* nopcre_map = &nopcre_api;
-+const ConvertMap* nopcre2_map = &nopcre2_api;
-
- /*************************************************
- ****************** obfuscate ******************
---- a/tools/snort2lua/config_states/config_one_int_option.cc
-+++ b/tools/snort2lua/config_states/config_one_int_option.cc
-@@ -217,30 +217,30 @@ static const ConvertMap new_ttl_api =
- const ConvertMap* new_ttl_map = &new_ttl_api;
-
- /*************************************************
-- ************** pcre_match_limit **************
-+ ************** pcre2_match_limit **************
- *************************************************/
-
--static const std::string pcre_match_limit = "pcre_match_limit";
--static const ConvertMap pcre_match_limit_api =
-+static const std::string pcre2_match_limit = "pcre2_match_limit";
-+static const ConvertMap pcre2_match_limit_api =
- {
-- pcre_match_limit,
-- config_int_ctor<& pcre_match_limit, & detection>,
-+ pcre2_match_limit,
-+ config_int_ctor<& pcre2_match_limit, & detection>,
- };
-
--const ConvertMap* pcre_match_limit_map = &pcre_match_limit_api;
-+const ConvertMap* pcre2_match_limit_map = &pcre2_match_limit_api;
-
- /**************************************************
-- ********** pcre_match_limit_recursion **********
-+ ********** pcre2_match_limit_recursion **********
- **************************************************/
-
--static const std::string pcre_match_limit_recursion = "pcre_match_limit_recursion";
--static const ConvertMap pcre_match_limit_recursion_api =
-+static const std::string pcre2_match_limit_recursion = "pcre_match_limit_recursion";
-+static const ConvertMap pcre2_match_limit_recursion_api =
- {
-- pcre_match_limit_recursion,
-- config_int_ctor<& pcre_match_limit_recursion, & detection>,
-+ pcre2_match_limit_recursion,
-+ config_int_ctor<& pcre2_match_limit_recursion, & detection>,
- };
-
--const ConvertMap* pcre_match_limit_recursion_map = &pcre_match_limit_recursion_api;
-+const ConvertMap* pcre2_match_limit_recursion_map = &pcre2_match_limit_recursion_api;
-
- /*************************************************
- ****************** pkt_count *****************
---- a/tools/snort2lua/rule_states/CMakeLists.txt
-+++ b/tools/snort2lua/rule_states/CMakeLists.txt
-@@ -12,7 +12,7 @@ add_library( rule_states OBJECT
- rule_http_encode.cc
- rule_isdataat.cc
- rule_metadata.cc
-- rule_pcre.cc
-+ rule_pcre2.cc
- rule_react.cc
- rule_reference.cc
- rule_replace.cc
---- a/tools/snort2lua/rule_states/rule_api.cc
-+++ b/tools/snort2lua/rule_states/rule_api.cc
-@@ -75,7 +75,7 @@ extern const ConvertMap* modbus_data_map
- extern const ConvertMap* modbus_func_map;
- extern const ConvertMap* modbus_unit_map;
- extern const ConvertMap* msg_map;
--extern const ConvertMap* pcre_map;
-+extern const ConvertMap* pcre2_map;
- extern const ConvertMap* pkt_data_map;
- extern const ConvertMap* priority_map;
- extern const ConvertMap* protected_content_map;
-@@ -159,7 +159,7 @@ const std::vector<const ConvertMap*> rul
- modbus_func_map,
- modbus_unit_map,
- msg_map,
-- pcre_map,
-+ pcre2_map,
- pkt_data_map,
- priority_map,
- protected_content_map,
---- a/tools/snort2lua/rule_states/rule_pcre.cc
-+++ /dev/null
-@@ -1,159 +0,0 @@
--//--------------------------------------------------------------------------
--// Copyright (C) 2014-2024 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.
--//--------------------------------------------------------------------------
--// rule_pcre.cc author Josh Rosenbaum <jrosenba@cisco.com>
--
--#include <sstream>
--#include <vector>
--
--#include "conversion_state.h"
--#include "helpers/converter.h"
--#include "helpers/s2l_util.h"
--#include "rule_api.h"
--
--namespace rules
--{
--namespace
--{
--class Pcre : public ConversionState
--{
--public:
-- Pcre(Converter& c) : ConversionState(c) { }
-- bool convert(std::istringstream& data) override;
--};
--} // namespace
--
--bool Pcre::convert(std::istringstream& data_stream)
--{
-- bool sticky_buffer_set = false;
-- std::string buffer = "pkt_data";
--
-- char delim = '/';
-- std::string pcre_str = util::get_rule_option_args(data_stream);
-- std::string pattern;
-- std::string new_opts;
-- std::string options;
--
-- if (pcre_str.front() == '!')
-- {
-- pattern += "!";
-- pcre_str.erase(pcre_str.begin());
-- }
--
-- if (pcre_str.front() != '"' || pcre_str.back() != '"')
-- {
-- rule_api.bad_rule(data_stream, "pattern must be enclosed in \"");
-- return set_next_rule_state(data_stream);
-- }
--
-- pcre_str.erase(pcre_str.begin());
-- pattern += '"';
--
-- if (pcre_str.front() == 'm')
-- {
-- pcre_str.erase(pcre_str.begin());
-- pattern += 'm';
-- delim = pcre_str.front();
-- }
--
-- const std::size_t pattern_end = pcre_str.rfind(delim);
-- if ((pcre_str.front() != delim) || (pattern_end == 0))
-- {
-- std::string tmp = "Regex must be enclosed in delim '";
-- tmp.append(delim, 1);
-- rule_api.bad_rule(data_stream, tmp + "'");
-- return set_next_rule_state(data_stream);
-- }
--
-- pattern += pcre_str.substr(0, pattern_end + 1);
-- options = pcre_str.substr(pattern_end + 1, std::string::npos);
-- new_opts = "";
--
-- for (char c : options )
-- {
-- std::string sticky_buffer = std::string(); // empty string
--
-- switch (c)
-- {
-- case 'B': sticky_buffer = "raw_data"; break;
-- case 'U': sticky_buffer = "http_uri"; break;
-- case 'P': sticky_buffer = "pcre_P_option_body"; break;
-- case 'H': sticky_buffer = "pcre_H_option_header"; break;
-- case 'M': sticky_buffer = "http_method"; break;
-- case 'C': sticky_buffer = "http_cookie"; break;
-- case 'I': sticky_buffer = "http_raw_uri"; break;
-- case 'D': sticky_buffer = "http_raw_header"; break;
-- case 'K': sticky_buffer = "http_raw_cookie"; break;
-- case 'S': sticky_buffer = "http_stat_code"; break;
-- case 'Y': sticky_buffer = "http_stat_msg"; break;
-- case 'i':
-- case 's':
-- case 'm':
-- case 'x':
-- case 'A':
-- case 'E':
-- case 'G':
-- case 'O':
-- case 'R':
-- case '"': // end of reg_ex
-- new_opts += c;
-- break;
-- default:
-- {
-- std::string dlt_opt = "unknown option - '";
-- dlt_opt.append(1, c);
-- dlt_opt += "'";
-- rule_api.bad_rule(data_stream, dlt_opt);
-- break;
-- }
-- }
--
-- if (!sticky_buffer.empty())
-- {
-- buffer = sticky_buffer;
--
-- if (sticky_buffer_set)
-- rule_api.bad_rule(data_stream,
-- "Two sticky buffers set for this regular expression!");
-- else
-- sticky_buffer_set = true;
-- }
-- }
--
-- rule_api.add_option("pcre", pattern + new_opts);
--
-- rule_api.set_curr_options_buffer(buffer);
--
-- return set_next_rule_state(data_stream);
--}
--
--/**************************
-- ******* A P I ***********
-- **************************/
--
--static ConversionState* ctor(Converter& c)
--{ return new Pcre(c); }
--
--static const ConvertMap pcre_api =
--{
-- "pcre",
-- ctor,
--};
--
--const ConvertMap* pcre_map = &pcre_api;
--} // namespace rules
--
---- /dev/null
-+++ b/tools/snort2lua/rule_states/rule_pcre2.cc
-@@ -0,0 +1,159 @@
-+//--------------------------------------------------------------------------
-+// Copyright (C) 2014-2024 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.
-+//--------------------------------------------------------------------------
-+// rule_pcre2.cc author Josh Rosenbaum <jrosenba@cisco.com>
-+
-+#include <sstream>
-+#include <vector>
-+
-+#include "conversion_state.h"
-+#include "helpers/converter.h"
-+#include "helpers/s2l_util.h"
-+#include "rule_api.h"
-+
-+namespace rules
-+{
-+namespace
-+{
-+class Pcre2 : public ConversionState
-+{
-+public:
-+ Pcre2(Converter& c) : ConversionState(c) { }
-+ bool convert(std::istringstream& data) override;
-+};
-+} // namespace
-+
-+bool Pcre2::convert(std::istringstream& data_stream)
-+{
-+ bool sticky_buffer_set = false;
-+ std::string buffer = "pkt_data";
-+
-+ char delim = '/';
-+ std::string pcre2_str = util::get_rule_option_args(data_stream);
-+ std::string pattern;
-+ std::string new_opts;
-+ std::string options;
-+
-+ if (pcre2_str.front() == '!')
-+ {
-+ pattern += "!";
-+ pcre2_str.erase(pcre2_str.begin());
-+ }
-+
-+ if (pcre2_str.front() != '"' || pcre2_str.back() != '"')
-+ {
-+ rule_api.bad_rule(data_stream, "pattern must be enclosed in \"");
-+ return set_next_rule_state(data_stream);
-+ }
-+
-+ pcre2_str.erase(pcre2_str.begin());
-+ pattern += '"';
-+
-+ if (pcre2_str.front() == 'm')
-+ {
-+ pcre2_str.erase(pcre2_str.begin());
-+ pattern += 'm';
-+ delim = pcre2_str.front();
-+ }
-+
-+ const std::size_t pattern_end = pcre2_str.rfind(delim);
-+ if ((pcre2_str.front() != delim) || (pattern_end == 0))
-+ {
-+ std::string tmp = "Regex must be enclosed in delim '";
-+ tmp.append(delim, 1);
-+ rule_api.bad_rule(data_stream, tmp + "'");
-+ return set_next_rule_state(data_stream);
-+ }
-+
-+ pattern += pcre2_str.substr(0, pattern_end + 1);
-+ options = pcre2_str.substr(pattern_end + 1, std::string::npos);
-+ new_opts = "";
-+
-+ for (char c : options )
-+ {
-+ std::string sticky_buffer = std::string(); // empty string
-+
-+ switch (c)
-+ {
-+ case 'B': sticky_buffer = "raw_data"; break;
-+ case 'U': sticky_buffer = "http_uri"; break;
-+ case 'P': sticky_buffer = "pcre_P_option_body"; break;
-+ case 'H': sticky_buffer = "pcre_H_option_header"; break;
-+ case 'M': sticky_buffer = "http_method"; break;
-+ case 'C': sticky_buffer = "http_cookie"; break;
-+ case 'I': sticky_buffer = "http_raw_uri"; break;
-+ case 'D': sticky_buffer = "http_raw_header"; break;
-+ case 'K': sticky_buffer = "http_raw_cookie"; break;
-+ case 'S': sticky_buffer = "http_stat_code"; break;
-+ case 'Y': sticky_buffer = "http_stat_msg"; break;
-+ case 'i':
-+ case 's':
-+ case 'm':
-+ case 'x':
-+ case 'A':
-+ case 'E':
-+ case 'G':
-+ case 'O':
-+ case 'R':
-+ case '"': // end of reg_ex
-+ new_opts += c;
-+ break;
-+ default:
-+ {
-+ std::string dlt_opt = "unknown option - '";
-+ dlt_opt.append(1, c);
-+ dlt_opt += "'";
-+ rule_api.bad_rule(data_stream, dlt_opt);
-+ break;
-+ }
-+ }
-+
-+ if (!sticky_buffer.empty())
-+ {
-+ buffer = sticky_buffer;
-+
-+ if (sticky_buffer_set)
-+ rule_api.bad_rule(data_stream,
-+ "Two sticky buffers set for this regular expression!");
-+ else
-+ sticky_buffer_set = true;
-+ }
-+ }
-+
-+ rule_api.add_option("pcre", pattern + new_opts);
-+
-+ rule_api.set_curr_options_buffer(buffer);
-+
-+ return set_next_rule_state(data_stream);
-+}
-+
-+/**************************
-+ ******* A P I ***********
-+ **************************/
-+
-+static ConversionState* ctor(Converter& c)
-+{ return new Pcre2(c); }
-+
-+static const ConvertMap pcre2_api =
-+{
-+ "pcre2",
-+ ctor,
-+};
-+
-+const ConvertMap* pcre2_map = &pcre2_api;
-+} // namespace rules
-+
---- a/tools/snort2lua/rule_states/rule_sd_pattern.cc
-+++ b/tools/snort2lua/rule_states/rule_sd_pattern.cc
-@@ -41,7 +41,7 @@ private:
-
- std::string SDPattern::convert_pattern(const std::string& pattern)
- {
-- const std::string unused_pcre_tokens("()[].+*^$|");
-+ const std::string unused_pcre2_tokens("()[].+*^$|");
-
- std::string s3_pattern;
-
-@@ -100,7 +100,7 @@ std::string SDPattern::convert_pattern(c
- break;
-
- default:
-- if (unused_pcre_tokens.find(sym) != std::string::npos)
-+ if (unused_pcre2_tokens.find(sym) != std::string::npos)
- s3_pattern.push_back('\\');
- s3_pattern.push_back(sym);
- break;