snort3: update to 3.6.2.0
authorJohn Audia <therealgraysky@proton.me>
Tue, 28 Jan 2025 23:38:28 +0000 (18:38 -0500)
committerHannu Nyman <hannu.nyman@iki.fi>
Thu, 30 Jan 2025 17:19:00 +0000 (19:19 +0200)
Changelog: https://github.com/snort3/snort3/releases/tag/3.6.2.0

% snort --version

   ,,_     -*> Snort++ <*-
  o"  )~   Version 3.6.2.0
   ''''    By Martin Roesch & The Snort Team
           http://snort.org/contact#team
           Copyright (C) 2014-2024 Cisco and/or its affiliates. All rights reserved.
           Copyright (C) 1998-2013 Sourcefire, Inc., et al.
           Using DAQ version 3.0.18
           Using Hyperscan version 5.4.2 2025-01-28
           Using libpcap version 1.10.5 (with TPACKET_V3)
           Using LuaJIT version 2.1.0-beta3
           Using LZMA version 5.6.2
           Using OpenSSL 3.0.15 3 Sep 2024
           Using PCRE2 version 10.42 2022-12-11
           Using ZLIB version 1.3.1

Signed-off-by: John Audia <therealgraysky@proton.me>
net/snort3/Makefile
net/snort3/patches/100-remove-HAVE_HS_COMPILE_LIT-to-work-around-upstream-b.patch
net/snort3/patches/110-packet_capture-Fix-compilation-with-GCC-13.patch
net/snort3/patches/900-core-convert-project-to-PCRE2.patch [deleted file]

index c4c98fed05251612d23c744383ee3980f9d6fe87..334338933e696e053475e6d07520271abba13cd0 100644 (file)
@@ -6,13 +6,13 @@
 include $(TOPDIR)/rules.mk
 
 PKG_NAME:=snort3
-PKG_VERSION:=3.1.84.0
-PKG_RELEASE:=4
+PKG_VERSION:=3.6.2.0
+PKG_RELEASE:=1
 
 PKG_SOURCE_PROTO:=git
 PKG_SOURCE_VERSION:=$(PKG_VERSION)
 PKG_SOURCE_URL:=https://github.com/snort3/snort3
-PKG_MIRROR_HASH:=ffa69fdd95c55a943ab4dd782923caf31937dd8ad29e202d7fe781373ed84444
+PKG_MIRROR_HASH:=961649f0ea661b6454c9c056a789708a601dcd367515e506ada5d86fea9cee18
 
 PKG_MAINTAINER:=W. Michael Petullo <mike@flyn.org>, John Audia <therealgraysky@proton.me>
 PKG_LICENSE:=GPL-2.0-only
index 629e8d698f97c81743c3db04bb73e2c281d5af48..23b8e20cffee60ddba956fb6f35257060a53c0bf 100644 (file)
@@ -24,7 +24,7 @@ Workaround to build until upstream bug is fixed[1].
  endif()
 --- a/config.cmake.h.in
 +++ b/config.cmake.h.in
-@@ -124,7 +124,6 @@
+@@ -127,7 +127,6 @@
  
  /* hyperscan available */
  #cmakedefine HAVE_HYPERSCAN 1
index 5d6fb79e34597dd4d7e9bd8cc145873a26565865..8dfd723ee2b51e1b8230da2f25318c1d8f4866f1 100644 (file)
@@ -18,5 +18,5 @@ src/network_inspectors/packet_capture/packet_capture.h:25:54: error: 'int16_t' d
  #include <string>
 +#include <cstdint>
  
- void packet_capture_enable(const std::string&, const int16_t g = -1, const std::string& t = "");
+ void packet_capture_enable(const std::string&, const int16_t g = -1, const std::string& t = "", const bool ci = true);
  void packet_capture_disable();
diff --git a/net/snort3/patches/900-core-convert-project-to-PCRE2.patch b/net/snort3/patches/900-core-convert-project-to-PCRE2.patch
deleted file mode 100644 (file)
index 01199f8..0000000
+++ /dev/null
@@ -1,2052 +0,0 @@
-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;