From: John Audia Date: Tue, 28 Jan 2025 23:38:28 +0000 (-0500) Subject: snort3: update to 3.6.2.0 X-Git-Url: http://git.lede-project.org./?a=commitdiff_plain;h=21c63a67e32c701da6221726ec2d4e717bc7bc03;p=feed%2Fpackages.git snort3: update to 3.6.2.0 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 --- diff --git a/net/snort3/Makefile b/net/snort3/Makefile index c4c98fed05..334338933e 100644 --- a/net/snort3/Makefile +++ b/net/snort3/Makefile @@ -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 , John Audia PKG_LICENSE:=GPL-2.0-only diff --git a/net/snort3/patches/100-remove-HAVE_HS_COMPILE_LIT-to-work-around-upstream-b.patch b/net/snort3/patches/100-remove-HAVE_HS_COMPILE_LIT-to-work-around-upstream-b.patch index 629e8d698f..23b8e20cff 100644 --- a/net/snort3/patches/100-remove-HAVE_HS_COMPILE_LIT-to-work-around-upstream-b.patch +++ b/net/snort3/patches/100-remove-HAVE_HS_COMPILE_LIT-to-work-around-upstream-b.patch @@ -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 diff --git a/net/snort3/patches/110-packet_capture-Fix-compilation-with-GCC-13.patch b/net/snort3/patches/110-packet_capture-Fix-compilation-with-GCC-13.patch index 5d6fb79e34..8dfd723ee2 100644 --- a/net/snort3/patches/110-packet_capture-Fix-compilation-with-GCC-13.patch +++ b/net/snort3/patches/110-packet_capture-Fix-compilation-with-GCC-13.patch @@ -18,5 +18,5 @@ src/network_inspectors/packet_capture/packet_capture.h:25:54: error: 'int16_t' d #include +#include - 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 index 01199f87cd..0000000000 --- a/net/snort3/patches/900-core-convert-project-to-PCRE2.patch +++ /dev/null @@ -1,2052 +0,0 @@ -From a71cca137eb33f659354ce0ebda4951cb26485df Mon Sep 17 00:00:00 2001 -From: Christian Marangi -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 ---- - 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 -+#define PCRE2_CODE_UNIT_WIDTH 8 -+#include - - #include - -@@ -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 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& 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& 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 - #include - #include --#include -+#define PCRE2_CODE_UNIT_WIDTH 8 -+#include - #include - #include - #include -@@ -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 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 --#include -+#define PCRE2_CODE_UNIT_WIDTH 8 -+#include - #include - - #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::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 - #include - #include --#include -+#define PCRE2_CODE_UNIT_WIDTH 8 -+#include - #include - #include - #include -@@ -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 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 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 -- --#include --#include -- --#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 -+ -+#include -+#include -+ -+#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;