mirror of
https://github.com/owasp-modsecurity/ModSecurity.git
synced 2025-08-14 05:45:59 +03:00
Support PCRE2
This commit is contained in:
parent
5519f6cfae
commit
f84614fe06
2
CHANGES
2
CHANGES
@ -1,6 +1,8 @@
|
|||||||
v3.x.y - YYYY-MMM-DD (to be released)
|
v3.x.y - YYYY-MMM-DD (to be released)
|
||||||
-------------------------------------
|
-------------------------------------
|
||||||
|
|
||||||
|
- Support PCRE2
|
||||||
|
[Issue #2668 - @martinhsv]
|
||||||
- Support SecRequestBodyNoFilesLimit
|
- Support SecRequestBodyNoFilesLimit
|
||||||
[Issue #2670 - @airween, @martinhsv]
|
[Issue #2670 - @airween, @martinhsv]
|
||||||
- Fix misuses of LMDB API
|
- Fix misuses of LMDB API
|
||||||
|
183
build/pcre2.m4
Normal file
183
build/pcre2.m4
Normal file
@ -0,0 +1,183 @@
|
|||||||
|
dnl Check for PCRE2 Libraries
|
||||||
|
dnl CHECK_PCRE2(ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND])
|
||||||
|
|
||||||
|
AC_DEFUN([PROG_PCRE2], [
|
||||||
|
|
||||||
|
# Possible names for the pcre2 library/package (pkg-config)
|
||||||
|
PCRE2_POSSIBLE_LIB_NAMES="pcre2 pcre2-8"
|
||||||
|
|
||||||
|
# Possible extensions for the library
|
||||||
|
PCRE2_POSSIBLE_EXTENSIONS="so so0 la sl dll dylib so.0.0.0"
|
||||||
|
|
||||||
|
# Possible paths (if pkg-config was not found, proceed with the file lookup)
|
||||||
|
PCRE2_POSSIBLE_PATHS="/usr/lib /usr/local/lib /usr/local/libpcre2-8 /usr/local/pcre2 /usr/local /opt/libpcre2-8 /opt/pcre2 /opt /usr /usr/lib64 /opt/local"
|
||||||
|
|
||||||
|
# Variables to be set by this very own script.
|
||||||
|
PCRE2_VERSION=""
|
||||||
|
PCRE2_CFLAGS=""
|
||||||
|
PCRE2_CPPFLAGS=""
|
||||||
|
PCRE2_LDADD=""
|
||||||
|
PCRE2_LDFLAGS=""
|
||||||
|
|
||||||
|
AC_ARG_WITH(
|
||||||
|
pcre2,
|
||||||
|
AC_HELP_STRING(
|
||||||
|
[--with-pcre2=PATH],
|
||||||
|
[Path to pcre2 prefix or config script]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
if test "x${with_pcre2}" == "xno"; then
|
||||||
|
AC_DEFINE(HAVE_PCRE2, 0, [Support for PCRE2 was disabled by the utilization of --without-pcre2 or --with-pcre2=no])
|
||||||
|
AC_MSG_NOTICE([Support for PCRE2 was disabled by the utilization of --without-pcre2 or --with-pcre2=no])
|
||||||
|
PCRE2_DISABLED=yes
|
||||||
|
else
|
||||||
|
if test "x${with_pcre2}" == "xyes"; then
|
||||||
|
PCRE2_MANDATORY=yes
|
||||||
|
AC_MSG_NOTICE([PCRE2 support was marked as mandatory by the utilization of --with-pcre2=yes])
|
||||||
|
fi
|
||||||
|
# for x in ${PCRE2_POSSIBLE_LIB_NAMES}; do
|
||||||
|
# CHECK_FOR_PCRE2_AT(${x})
|
||||||
|
# if test -n "${PCRE2_VERSION}"; then
|
||||||
|
# break
|
||||||
|
# fi
|
||||||
|
# done
|
||||||
|
|
||||||
|
# if test "x${with_pcre2}" != "xyes" or test "x${with_pcre2}" == "xyes"; then
|
||||||
|
if test "x${with_pcre2}" == "x" || test "x${with_pcre2}" == "xyes"; then
|
||||||
|
# Nothing about PCRE2 was informed, using the pkg-config to figure things out.
|
||||||
|
if test -n "${PKG_CONFIG}"; then
|
||||||
|
PCRE2_PKG_NAME=""
|
||||||
|
for x in ${PCRE2_POSSIBLE_LIB_NAMES}; do
|
||||||
|
if ${PKG_CONFIG} --exists ${x}; then
|
||||||
|
PCRE2_PKG_NAME="$x"
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
AC_MSG_NOTICE([Nothing about PCRE2 was informed during the configure phase. Trying to detect it on the platform...])
|
||||||
|
if test -n "${PCRE2_PKG_NAME}"; then
|
||||||
|
# Package was found using the pkg-config scripts
|
||||||
|
PCRE2_VERSION="`${PKG_CONFIG} ${PCRE2_PKG_NAME} --modversion`"
|
||||||
|
PCRE2_CFLAGS="`${PKG_CONFIG} ${PCRE2_PKG_NAME} --cflags`"
|
||||||
|
PCRE2_LDADD="`${PKG_CONFIG} ${PCRE2_PKG_NAME} --libs-only-l`"
|
||||||
|
PCRE2_LDFLAGS="`${PKG_CONFIG} ${PCRE2_PKG_NAME} --libs-only-L --libs-only-other`"
|
||||||
|
PCRE2_DISPLAY="${PCRE2_LDADD}, ${PCRE2_CFLAGS}"
|
||||||
|
else
|
||||||
|
# If pkg-config did not find anything useful, go over file lookup.
|
||||||
|
for x in ${PCRE2_POSSIBLE_PATHS}; do
|
||||||
|
CHECK_FOR_PCRE2_AT(${x})
|
||||||
|
if test -n "${PCRE2_VERSION}"; then
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
if test "x${with_pcre2}" != "x"; then
|
||||||
|
# An specific path was informed, lets check.
|
||||||
|
PCRE2_MANDATORY=yes
|
||||||
|
CHECK_FOR_PCRE2_AT(${with_pcre2})
|
||||||
|
fi
|
||||||
|
# fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if test -z "${PCRE2_LDADD}"; then
|
||||||
|
if test -z "${PCRE2_MANDATORY}"; then
|
||||||
|
if test -z "${PCRE2_DISABLED}"; then
|
||||||
|
AC_MSG_NOTICE([PCRE2 library was not found])
|
||||||
|
PCRE2_FOUND=0
|
||||||
|
else
|
||||||
|
PCRE2_FOUND=2
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
AC_MSG_ERROR([PCRE2 was explicitly referenced but it was not found])
|
||||||
|
PCRE2_FOUND=-1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
if test -z "${PCRE2_MANDATORY}"; then
|
||||||
|
PCRE2_FOUND=2
|
||||||
|
AC_MSG_NOTICE([PCRE2 is disabled by default.])
|
||||||
|
else
|
||||||
|
PCRE2_FOUND=1
|
||||||
|
AC_MSG_NOTICE([using PCRE2 v${PCRE2_VERSION}])
|
||||||
|
PCRE2_CFLAGS="-DWITH_PCRE2 ${PCRE2_CFLAGS}"
|
||||||
|
PCRE2_DISPLAY="${PCRE2_LDADD}, ${PCRE2_CFLAGS}"
|
||||||
|
AC_SUBST(PCRE2_VERSION)
|
||||||
|
AC_SUBST(PCRE2_LDADD)
|
||||||
|
AC_SUBST(PCRE2_LIBS)
|
||||||
|
AC_SUBST(PCRE2_LDFLAGS)
|
||||||
|
AC_SUBST(PCRE2_CFLAGS)
|
||||||
|
AC_SUBST(PCRE2_DISPLAY)
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
AC_SUBST(PCRE2_FOUND)
|
||||||
|
|
||||||
|
]) # AC_DEFUN [PROG_PCRE2]
|
||||||
|
|
||||||
|
|
||||||
|
AC_DEFUN([CHECK_FOR_PCRE2_AT], [
|
||||||
|
path=$1
|
||||||
|
echo "*** LOOKING AT PATH: " ${path}
|
||||||
|
for y in ${PCRE2_POSSIBLE_EXTENSIONS}; do
|
||||||
|
for z in ${PCRE2_POSSIBLE_LIB_NAMES}; do
|
||||||
|
if test -e "${path}/${z}.${y}"; then
|
||||||
|
pcre2_lib_path="${path}/"
|
||||||
|
pcre2_lib_name="${z}"
|
||||||
|
pcre2_lib_file="${pcre2_lib_path}/${z}.${y}"
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
if test -e "${path}/lib${z}.${y}"; then
|
||||||
|
pcre2_lib_path="${path}/"
|
||||||
|
pcre2_lib_name="${z}"
|
||||||
|
pcre2_lib_file="${pcre2_lib_path}/lib${z}.${y}"
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
if test -e "${path}/lib/lib${z}.${y}"; then
|
||||||
|
pcre2_lib_path="${path}/lib/"
|
||||||
|
pcre2_lib_name="${z}"
|
||||||
|
pcre2_lib_file="${pcre2_lib_path}/lib${z}.${y}"
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
if test -e "${path}/lib/x86_64-linux-gnu/lib${z}.${y}"; then
|
||||||
|
pcre2_lib_path="${path}/lib/x86_64-linux-gnu/"
|
||||||
|
pcre2_lib_name="${z}"
|
||||||
|
pcre2_lib_file="${pcre2_lib_path}/lib${z}.${y}"
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
if test -e "${path}/lib/i386-linux-gnu/lib${z}.${y}"; then
|
||||||
|
pcre2_lib_path="${path}/lib/i386-linux-gnu/"
|
||||||
|
pcre2_lib_name="${z}"
|
||||||
|
pcre2_lib_file="${pcre2_lib_path}/lib${z}.${y}"
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
if test -n "$pcre2_lib_path"; then
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
if test -e "${path}/include/pcre2.h"; then
|
||||||
|
pcre2_inc_path="${path}/include"
|
||||||
|
elif test -e "${path}/pcre2.h"; then
|
||||||
|
pcre2_inc_path="${path}"
|
||||||
|
elif test -e "${path}/include/pcre2/pcre2.h"; then
|
||||||
|
pcre2_inc_path="${path}/include"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if test -n "${pcre2_lib_path}"; then
|
||||||
|
AC_MSG_NOTICE([PCRE2 library found at: ${pcre2_lib_file}])
|
||||||
|
fi
|
||||||
|
|
||||||
|
if test -n "${pcre2_inc_path}"; then
|
||||||
|
AC_MSG_NOTICE([PCRE2 headers found at: ${pcre2_inc_path}])
|
||||||
|
fi
|
||||||
|
|
||||||
|
if test -n "${pcre2_lib_path}" -a -n "${pcre2_inc_path}"; then
|
||||||
|
# TODO: Compile a piece of code to check the version.
|
||||||
|
PCRE2_CFLAGS="-I${pcre2_inc_path}"
|
||||||
|
PCRE2_LDADD="-l${pcre2_lib_name}"
|
||||||
|
PCRE2_LDFLAGS="-L${pcre2_lib_path}"
|
||||||
|
PCRE2_DISPLAY="${pcre2_lib_file}, ${pcre2_inc_path}"
|
||||||
|
fi
|
||||||
|
]) # AC_DEFUN [CHECK_FOR_PCRE2_AT]
|
24
configure.ac
24
configure.ac
@ -129,6 +129,13 @@ CHECK_LIBXML2
|
|||||||
CHECK_PCRE
|
CHECK_PCRE
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# Check for pcre2
|
||||||
|
#
|
||||||
|
PROG_PCRE2
|
||||||
|
AM_CONDITIONAL([PCRE2_CFLAGS], [test "PCRE2_CFLAGS" != ""])
|
||||||
|
|
||||||
|
|
||||||
# Checks for header files.
|
# Checks for header files.
|
||||||
AC_HEADER_STDC
|
AC_HEADER_STDC
|
||||||
AC_CHECK_HEADERS([string])
|
AC_CHECK_HEADERS([string])
|
||||||
@ -555,6 +562,23 @@ if test "x$LUA_FOUND" = "x2"; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
## PCRE2
|
||||||
|
if test "x$PCRE2_FOUND" = "x0"; then
|
||||||
|
echo " + PCRE2 ....not found"
|
||||||
|
fi
|
||||||
|
if test "x$PCRE2_FOUND" = "x1"; then
|
||||||
|
echo -n " + PCRE2 ....found "
|
||||||
|
if ! test "x$PCRE2_VERSION" = "x"; then
|
||||||
|
echo "v${PCRE2_VERSION}"
|
||||||
|
else
|
||||||
|
echo ""
|
||||||
|
fi
|
||||||
|
echo " ${PCRE2_DISPLAY}"
|
||||||
|
fi
|
||||||
|
if test "x$PCRE2_FOUND" = "x2"; then
|
||||||
|
echo " + PCRE2 ....disabled"
|
||||||
|
fi
|
||||||
|
|
||||||
echo " "
|
echo " "
|
||||||
echo " Other Options"
|
echo " Other Options"
|
||||||
if test $buildTestUtilities = true; then
|
if test $buildTestUtilities = true; then
|
||||||
|
@ -324,6 +324,7 @@ libmodsecurity_la_CPPFLAGS = \
|
|||||||
$(YAJL_CFLAGS) \
|
$(YAJL_CFLAGS) \
|
||||||
$(LMDB_CFLAGS) \
|
$(LMDB_CFLAGS) \
|
||||||
$(PCRE_CFLAGS) \
|
$(PCRE_CFLAGS) \
|
||||||
|
$(PCRE2_CFLAGS) \
|
||||||
$(SSDEEP_CFLAGS) \
|
$(SSDEEP_CFLAGS) \
|
||||||
$(MAXMIND_CFLAGS) \
|
$(MAXMIND_CFLAGS) \
|
||||||
$(LUA_CFLAGS) \
|
$(LUA_CFLAGS) \
|
||||||
@ -339,6 +340,7 @@ libmodsecurity_la_LDFLAGS = \
|
|||||||
$(LMDB_LDFLAGS) \
|
$(LMDB_LDFLAGS) \
|
||||||
$(LUA_LDFLAGS) \
|
$(LUA_LDFLAGS) \
|
||||||
$(PCRE_LDFLAGS) \
|
$(PCRE_LDFLAGS) \
|
||||||
|
$(PCRE2_LDFLAGS) \
|
||||||
$(SSDEEP_LDFLAGS) \
|
$(SSDEEP_LDFLAGS) \
|
||||||
$(MAXMIND_LDFLAGS) \
|
$(MAXMIND_LDFLAGS) \
|
||||||
$(YAJL_LDFLAGS) \
|
$(YAJL_LDFLAGS) \
|
||||||
@ -355,6 +357,7 @@ libmodsecurity_la_LIBADD = \
|
|||||||
../others/libinjection.la \
|
../others/libinjection.la \
|
||||||
../others/libmbedtls.la \
|
../others/libmbedtls.la \
|
||||||
$(PCRE_LDADD) \
|
$(PCRE_LDADD) \
|
||||||
|
$(PCRE2_LDADD) \
|
||||||
$(MAXMIND_LDADD) \
|
$(MAXMIND_LDADD) \
|
||||||
$(SSDEEP_LDADD) \
|
$(SSDEEP_LDADD) \
|
||||||
$(YAJL_LDADD)
|
$(YAJL_LDADD)
|
||||||
|
@ -15,24 +15,28 @@
|
|||||||
|
|
||||||
#include "src/operators/verify_cc.h"
|
#include "src/operators/verify_cc.h"
|
||||||
|
|
||||||
#include <pcre.h>
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "src/operators/operator.h"
|
#include "src/operators/operator.h"
|
||||||
|
|
||||||
|
#ifndef WITH_PCRE2
|
||||||
#if PCRE_HAVE_JIT
|
#if PCRE_HAVE_JIT
|
||||||
#define pcre_study_opt PCRE_STUDY_JIT_COMPILE
|
#define pcre_study_opt PCRE_STUDY_JIT_COMPILE
|
||||||
#else
|
#else
|
||||||
#define pcre_study_opt 0
|
#define pcre_study_opt 0
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
namespace modsecurity {
|
namespace modsecurity {
|
||||||
namespace operators {
|
namespace operators {
|
||||||
|
|
||||||
VerifyCC::~VerifyCC() {
|
VerifyCC::~VerifyCC() {
|
||||||
|
#if WITH_PCRE2
|
||||||
|
pcre2_code_free(m_pc);
|
||||||
|
#else
|
||||||
if (m_pc != NULL) {
|
if (m_pc != NULL) {
|
||||||
pcre_free(m_pc);
|
pcre_free(m_pc);
|
||||||
m_pc = NULL;
|
m_pc = NULL;
|
||||||
@ -45,6 +49,7 @@ VerifyCC::~VerifyCC() {
|
|||||||
#endif
|
#endif
|
||||||
m_pce = NULL;
|
m_pce = NULL;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -90,6 +95,22 @@ int VerifyCC::luhnVerify(const char *ccnumber, int len) {
|
|||||||
|
|
||||||
|
|
||||||
bool VerifyCC::init(const std::string ¶m2, std::string *error) {
|
bool VerifyCC::init(const std::string ¶m2, std::string *error) {
|
||||||
|
#ifdef WITH_PCRE2
|
||||||
|
PCRE2_SPTR pcre2_pattern = reinterpret_cast<PCRE2_SPTR>(m_param.c_str());
|
||||||
|
uint32_t pcre2_options = (PCRE2_DOTALL|PCRE2_MULTILINE);
|
||||||
|
int errornumber = 0;
|
||||||
|
PCRE2_SIZE erroroffset = 0;
|
||||||
|
m_pc = pcre2_compile(pcre2_pattern, PCRE2_ZERO_TERMINATED,
|
||||||
|
pcre2_options, &errornumber, &erroroffset, NULL);
|
||||||
|
if (m_pc == NULL) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
m_match_data = pcre2_match_data_create_from_pattern(m_pc, NULL);
|
||||||
|
if (m_match_data == NULL) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
const char *errptr = NULL;
|
const char *errptr = NULL;
|
||||||
int erroffset = 0;
|
int erroffset = 0;
|
||||||
|
|
||||||
@ -112,6 +133,7 @@ bool VerifyCC::init(const std::string ¶m2, std::string *error) {
|
|||||||
error->assign(errptr);
|
error->assign(errptr);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -119,11 +141,25 @@ bool VerifyCC::init(const std::string ¶m2, std::string *error) {
|
|||||||
|
|
||||||
bool VerifyCC::evaluate(Transaction *t, RuleWithActions *rule,
|
bool VerifyCC::evaluate(Transaction *t, RuleWithActions *rule,
|
||||||
const std::string& i, std::shared_ptr<RuleMessage> ruleMessage) {
|
const std::string& i, std::shared_ptr<RuleMessage> ruleMessage) {
|
||||||
|
#ifdef WITH_PCRE2
|
||||||
|
PCRE2_SIZE offset = 0;
|
||||||
|
size_t target_length = i.length();
|
||||||
|
PCRE2_SPTR pcre2_i = reinterpret_cast<PCRE2_SPTR>(i.c_str());
|
||||||
|
|
||||||
|
for (offset = 0; offset < target_length; offset++) {
|
||||||
|
int ret = pcre2_match(m_pc, pcre2_i, target_length, offset, 0, m_match_data, NULL);
|
||||||
|
|
||||||
|
/* If there was no match, then we are done. */
|
||||||
|
if (ret < 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
PCRE2_SIZE *ovector = pcre2_get_ovector_pointer(m_match_data);
|
||||||
|
|
||||||
|
#else
|
||||||
int offset = 0;
|
int offset = 0;
|
||||||
int target_length = i.length();
|
int target_length = i.length();
|
||||||
|
|
||||||
for (offset = 0; offset < target_length; offset++) {
|
for (offset = 0; offset < target_length; offset++) {
|
||||||
std::string match;
|
|
||||||
int ovector[33];
|
int ovector[33];
|
||||||
memset(ovector, 0, sizeof(ovector));
|
memset(ovector, 0, sizeof(ovector));
|
||||||
int ret = pcre_exec(m_pc, m_pce, i.c_str(), i.size(), offset,
|
int ret = pcre_exec(m_pc, m_pce, i.c_str(), i.size(), offset,
|
||||||
@ -136,8 +172,9 @@ bool VerifyCC::evaluate(Transaction *t, RuleWithActions *rule,
|
|||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
if (ret > 0) {
|
if (ret > 0) {
|
||||||
match = std::string(i, ovector[0], ovector[1] - ovector[0]);
|
std::string match = std::string(i, ovector[0], ovector[1] - ovector[0]);
|
||||||
int is_cc = luhnVerify(match.c_str(), match.size());
|
int is_cc = luhnVerify(match.c_str(), match.size());
|
||||||
if (is_cc) {
|
if (is_cc) {
|
||||||
if (t) {
|
if (t) {
|
||||||
|
@ -16,7 +16,14 @@
|
|||||||
#ifndef SRC_OPERATORS_VERIFY_CC_H_
|
#ifndef SRC_OPERATORS_VERIFY_CC_H_
|
||||||
#define SRC_OPERATORS_VERIFY_CC_H_
|
#define SRC_OPERATORS_VERIFY_CC_H_
|
||||||
|
|
||||||
|
#if WITH_PCRE2
|
||||||
|
#define PCRE2_CODE_UNIT_WIDTH 8
|
||||||
|
#include <pcre2.h>
|
||||||
|
#else
|
||||||
#include <pcre.h>
|
#include <pcre.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
@ -32,7 +39,11 @@ class VerifyCC : public Operator {
|
|||||||
explicit VerifyCC(std::unique_ptr<RunTimeString> param)
|
explicit VerifyCC(std::unique_ptr<RunTimeString> param)
|
||||||
: Operator("VerifyCC", std::move(param)),
|
: Operator("VerifyCC", std::move(param)),
|
||||||
m_pc(NULL),
|
m_pc(NULL),
|
||||||
|
#if WITH_PCRE2
|
||||||
|
m_match_data(NULL) { }
|
||||||
|
#else
|
||||||
m_pce(NULL) { }
|
m_pce(NULL) { }
|
||||||
|
#endif
|
||||||
~VerifyCC();
|
~VerifyCC();
|
||||||
|
|
||||||
bool evaluate(Transaction *t, RuleWithActions *rule,
|
bool evaluate(Transaction *t, RuleWithActions *rule,
|
||||||
@ -40,8 +51,13 @@ class VerifyCC : public Operator {
|
|||||||
std::shared_ptr<RuleMessage> ruleMessage) override;
|
std::shared_ptr<RuleMessage> ruleMessage) override;
|
||||||
bool init(const std::string ¶m, std::string *error) override;
|
bool init(const std::string ¶m, std::string *error) override;
|
||||||
private:
|
private:
|
||||||
|
#if WITH_PCRE2
|
||||||
|
pcre2_code *m_pc;
|
||||||
|
pcre2_match_data *m_match_data;
|
||||||
|
#else
|
||||||
pcre *m_pc;
|
pcre *m_pc;
|
||||||
pcre_extra *m_pce;
|
pcre_extra *m_pce;
|
||||||
|
#endif
|
||||||
static int luhnVerify(const char *ccnumber, int len);
|
static int luhnVerify(const char *ccnumber, int len);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -15,7 +15,6 @@
|
|||||||
|
|
||||||
#include "src/utils/regex.h"
|
#include "src/utils/regex.h"
|
||||||
|
|
||||||
#include <pcre.h>
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <list>
|
#include <list>
|
||||||
|
|
||||||
@ -24,17 +23,27 @@
|
|||||||
|
|
||||||
#include "src/utils/geo_lookup.h"
|
#include "src/utils/geo_lookup.h"
|
||||||
|
|
||||||
|
#ifndef WITH_PCRE2
|
||||||
#if PCRE_HAVE_JIT
|
#if PCRE_HAVE_JIT
|
||||||
#define pcre_study_opt PCRE_STUDY_JIT_COMPILE
|
#define pcre_study_opt PCRE_STUDY_JIT_COMPILE
|
||||||
#else
|
#else
|
||||||
#define pcre_study_opt 0
|
#define pcre_study_opt 0
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace modsecurity {
|
namespace modsecurity {
|
||||||
namespace Utils {
|
namespace Utils {
|
||||||
|
|
||||||
// Helper function to tell us if the current config indicates CRLF is a valid newline sequence
|
// Helper function to tell us if the current config indicates CRLF is a valid newline sequence
|
||||||
bool crlfIsNewline() {
|
bool crlfIsNewline() {
|
||||||
|
#if WITH_PCRE2
|
||||||
|
uint32_t newline = 0;
|
||||||
|
pcre2_config(PCRE2_CONFIG_NEWLINE, &newline);
|
||||||
|
bool crlf_is_newline =
|
||||||
|
newline == PCRE2_NEWLINE_ANY ||
|
||||||
|
newline == PCRE2_NEWLINE_CRLF ||
|
||||||
|
newline == PCRE2_NEWLINE_ANYCRLF;
|
||||||
|
#else
|
||||||
int d = 0;
|
int d = 0;
|
||||||
pcre_config(PCRE_CONFIG_NEWLINE, &d);
|
pcre_config(PCRE_CONFIG_NEWLINE, &d);
|
||||||
|
|
||||||
@ -48,12 +57,26 @@ bool crlfIsNewline() {
|
|||||||
option_bits == PCRE_NEWLINE_ANY ||
|
option_bits == PCRE_NEWLINE_ANY ||
|
||||||
option_bits == PCRE_NEWLINE_CRLF ||
|
option_bits == PCRE_NEWLINE_CRLF ||
|
||||||
option_bits == PCRE_NEWLINE_ANYCRLF;
|
option_bits == PCRE_NEWLINE_ANYCRLF;
|
||||||
|
#endif
|
||||||
return crlf_is_newline;
|
return crlf_is_newline;
|
||||||
}
|
}
|
||||||
|
|
||||||
Regex::Regex(const std::string& pattern_, bool ignoreCase)
|
Regex::Regex(const std::string& pattern_, bool ignoreCase)
|
||||||
: pattern(pattern_.empty() ? ".*" : pattern_) {
|
: pattern(pattern_.empty() ? ".*" : pattern_) {
|
||||||
|
#if WITH_PCRE2
|
||||||
|
PCRE2_SPTR pcre2_pattern = reinterpret_cast<PCRE2_SPTR>(pattern.c_str());
|
||||||
|
uint32_t pcre2_options = (PCRE2_DOTALL|PCRE2_MULTILINE);
|
||||||
|
if (ignoreCase) {
|
||||||
|
pcre2_options |= PCRE2_CASELESS;
|
||||||
|
}
|
||||||
|
int errornumber = 0;
|
||||||
|
PCRE2_SIZE erroroffset = 0;
|
||||||
|
m_pc = pcre2_compile(pcre2_pattern, PCRE2_ZERO_TERMINATED,
|
||||||
|
pcre2_options, &errornumber, &erroroffset, NULL);
|
||||||
|
if (m_pc != NULL) {
|
||||||
|
m_match_data = pcre2_match_data_create_from_pattern(m_pc, NULL);
|
||||||
|
}
|
||||||
|
#else
|
||||||
const char *errptr = NULL;
|
const char *errptr = NULL;
|
||||||
int erroffset;
|
int erroffset;
|
||||||
int flags = (PCRE_DOTALL|PCRE_MULTILINE);
|
int flags = (PCRE_DOTALL|PCRE_MULTILINE);
|
||||||
@ -65,10 +88,15 @@ Regex::Regex(const std::string& pattern_, bool ignoreCase)
|
|||||||
&errptr, &erroffset, NULL);
|
&errptr, &erroffset, NULL);
|
||||||
|
|
||||||
m_pce = pcre_study(m_pc, pcre_study_opt, &errptr);
|
m_pce = pcre_study(m_pc, pcre_study_opt, &errptr);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Regex::~Regex() {
|
Regex::~Regex() {
|
||||||
|
#if WITH_PCRE2
|
||||||
|
pcre2_match_data_free(m_match_data);
|
||||||
|
pcre2_code_free(m_pc);
|
||||||
|
#else
|
||||||
if (m_pc != NULL) {
|
if (m_pc != NULL) {
|
||||||
pcre_free(m_pc);
|
pcre_free(m_pc);
|
||||||
m_pc = NULL;
|
m_pc = NULL;
|
||||||
@ -81,29 +109,39 @@ Regex::~Regex() {
|
|||||||
#endif
|
#endif
|
||||||
m_pce = NULL;
|
m_pce = NULL;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
std::list<SMatch> Regex::searchAll(const std::string& s) const {
|
std::list<SMatch> Regex::searchAll(const std::string& s) const {
|
||||||
const char *subject = s.c_str();
|
|
||||||
const std::string tmpString = std::string(s.c_str(), s.size());
|
|
||||||
int ovector[OVECCOUNT];
|
|
||||||
int rc, i, offset = 0;
|
|
||||||
std::list<SMatch> retList;
|
std::list<SMatch> retList;
|
||||||
|
int rc;
|
||||||
|
#ifdef WITH_PCRE2
|
||||||
|
PCRE2_SPTR pcre2_s = reinterpret_cast<PCRE2_SPTR>(s.c_str());
|
||||||
|
PCRE2_SIZE offset = 0;
|
||||||
|
|
||||||
|
do {
|
||||||
|
rc = pcre2_match(m_pc, pcre2_s, s.length(),
|
||||||
|
offset, 0, m_match_data, NULL);
|
||||||
|
PCRE2_SIZE *ovector = pcre2_get_ovector_pointer(m_match_data);
|
||||||
|
#else
|
||||||
|
const char *subject = s.c_str();
|
||||||
|
int ovector[OVECCOUNT];
|
||||||
|
int offset = 0;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
rc = pcre_exec(m_pc, m_pce, subject,
|
rc = pcre_exec(m_pc, m_pce, subject,
|
||||||
s.size(), offset, 0, ovector, OVECCOUNT);
|
s.size(), offset, 0, ovector, OVECCOUNT);
|
||||||
|
#endif
|
||||||
for (i = 0; i < rc; i++) {
|
for (int i = 0; i < rc; i++) {
|
||||||
size_t start = ovector[2*i];
|
size_t start = ovector[2*i];
|
||||||
size_t end = ovector[2*i+1];
|
size_t end = ovector[2*i+1];
|
||||||
size_t len = end - start;
|
size_t len = end - start;
|
||||||
if (end > s.size()) {
|
if (end > s.size()) {
|
||||||
rc = 0;
|
rc = -1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
std::string match = std::string(tmpString, start, len);
|
std::string match = std::string(s, start, len);
|
||||||
offset = start + len;
|
offset = start + len;
|
||||||
retList.push_front(SMatch(match, start));
|
retList.push_front(SMatch(match, start));
|
||||||
|
|
||||||
@ -118,10 +156,16 @@ std::list<SMatch> Regex::searchAll(const std::string& s) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool Regex::searchOneMatch(const std::string& s, std::vector<SMatchCapture>& captures) const {
|
bool Regex::searchOneMatch(const std::string& s, std::vector<SMatchCapture>& captures) const {
|
||||||
|
#ifdef WITH_PCRE2
|
||||||
|
PCRE2_SPTR pcre2_s = reinterpret_cast<PCRE2_SPTR>(s.c_str());
|
||||||
|
int rc = pcre2_match(m_pc, pcre2_s, s.length(), 0, 0, m_match_data, NULL);
|
||||||
|
PCRE2_SIZE *ovector = pcre2_get_ovector_pointer(m_match_data);
|
||||||
|
#else
|
||||||
const char *subject = s.c_str();
|
const char *subject = s.c_str();
|
||||||
int ovector[OVECCOUNT];
|
int ovector[OVECCOUNT];
|
||||||
|
|
||||||
int rc = pcre_exec(m_pc, m_pce, subject, s.size(), 0, 0, ovector, OVECCOUNT);
|
int rc = pcre_exec(m_pc, m_pce, subject, s.size(), 0, 0, ovector, OVECCOUNT);
|
||||||
|
#endif
|
||||||
|
|
||||||
for (int i = 0; i < rc; i++) {
|
for (int i = 0; i < rc; i++) {
|
||||||
size_t start = ovector[2*i];
|
size_t start = ovector[2*i];
|
||||||
@ -138,9 +182,22 @@ bool Regex::searchOneMatch(const std::string& s, std::vector<SMatchCapture>& cap
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool Regex::searchGlobal(const std::string& s, std::vector<SMatchCapture>& captures) const {
|
bool Regex::searchGlobal(const std::string& s, std::vector<SMatchCapture>& captures) const {
|
||||||
const char *subject = s.c_str();
|
|
||||||
|
|
||||||
bool prev_match_zero_length = false;
|
bool prev_match_zero_length = false;
|
||||||
|
#ifdef WITH_PCRE2
|
||||||
|
PCRE2_SPTR pcre2_s = reinterpret_cast<PCRE2_SPTR>(s.c_str());
|
||||||
|
PCRE2_SIZE startOffset = 0;
|
||||||
|
|
||||||
|
while (startOffset <= s.length()) {
|
||||||
|
uint32_t pcre2_options = 0;
|
||||||
|
if (prev_match_zero_length) {
|
||||||
|
pcre2_options = PCRE2_NOTEMPTY_ATSTART | PCRE2_ANCHORED;
|
||||||
|
}
|
||||||
|
int rc = pcre2_match(m_pc, pcre2_s, s.length(),
|
||||||
|
startOffset, pcre2_options, m_match_data, NULL);
|
||||||
|
PCRE2_SIZE *ovector = pcre2_get_ovector_pointer(m_match_data);
|
||||||
|
|
||||||
|
#else
|
||||||
|
const char *subject = s.c_str();
|
||||||
int startOffset = 0;
|
int startOffset = 0;
|
||||||
|
|
||||||
while (startOffset <= s.length()) {
|
while (startOffset <= s.length()) {
|
||||||
@ -151,6 +208,7 @@ bool Regex::searchGlobal(const std::string& s, std::vector<SMatchCapture>& captu
|
|||||||
}
|
}
|
||||||
int rc = pcre_exec(m_pc, m_pce, subject, s.length(), startOffset, pcre_options, ovector, OVECCOUNT);
|
int rc = pcre_exec(m_pc, m_pce, subject, s.length(), startOffset, pcre_options, ovector, OVECCOUNT);
|
||||||
|
|
||||||
|
#endif
|
||||||
if (rc > 0) {
|
if (rc > 0) {
|
||||||
size_t firstGroupForThisFullMatch = captures.size();
|
size_t firstGroupForThisFullMatch = captures.size();
|
||||||
for (int i = 0; i < rc; i++) {
|
for (int i = 0; i < rc; i++) {
|
||||||
@ -169,8 +227,13 @@ bool Regex::searchGlobal(const std::string& s, std::vector<SMatchCapture>& captu
|
|||||||
startOffset = end;
|
startOffset = end;
|
||||||
prev_match_zero_length = false;
|
prev_match_zero_length = false;
|
||||||
} else {
|
} else {
|
||||||
// zero-length match; modify next match attempt to avoid infinite loop
|
if ( startOffset == s.length()) {
|
||||||
prev_match_zero_length = true;
|
// zero-length match at end of string; force end of while-loop
|
||||||
|
startOffset++;
|
||||||
|
} else {
|
||||||
|
// zero-length match mid-string; adjust next match attempt
|
||||||
|
prev_match_zero_length = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -196,11 +259,20 @@ bool Regex::searchGlobal(const std::string& s, std::vector<SMatchCapture>& captu
|
|||||||
}
|
}
|
||||||
|
|
||||||
int Regex::search(const std::string& s, SMatch *match) const {
|
int Regex::search(const std::string& s, SMatch *match) const {
|
||||||
|
#ifdef WITH_PCRE2
|
||||||
|
PCRE2_SPTR pcre2_s = reinterpret_cast<PCRE2_SPTR>(s.c_str());
|
||||||
|
int ret = pcre2_match(m_pc, pcre2_s, s.length(),
|
||||||
|
0, 0, m_match_data, NULL) > 0;
|
||||||
|
|
||||||
|
if (ret > 0) { // match
|
||||||
|
PCRE2_SIZE *ovector = pcre2_get_ovector_pointer(m_match_data);
|
||||||
|
#else
|
||||||
int ovector[OVECCOUNT];
|
int ovector[OVECCOUNT];
|
||||||
int ret = pcre_exec(m_pc, m_pce, s.c_str(),
|
int ret = pcre_exec(m_pc, m_pce, s.c_str(),
|
||||||
s.size(), 0, 0, ovector, OVECCOUNT) > 0;
|
s.size(), 0, 0, ovector, OVECCOUNT) > 0;
|
||||||
|
|
||||||
if (ret > 0) {
|
if (ret > 0) {
|
||||||
|
#endif
|
||||||
*match = SMatch(
|
*match = SMatch(
|
||||||
std::string(s, ovector[ret-1], ovector[ret] - ovector[ret-1]),
|
std::string(s, ovector[ret-1], ovector[ret] - ovector[ret-1]),
|
||||||
0);
|
0);
|
||||||
@ -210,9 +282,19 @@ int Regex::search(const std::string& s, SMatch *match) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int Regex::search(const std::string& s) const {
|
int Regex::search(const std::string& s) const {
|
||||||
|
#ifdef WITH_PCRE2
|
||||||
|
PCRE2_SPTR pcre2_s = reinterpret_cast<PCRE2_SPTR>(s.c_str());
|
||||||
|
int rc = pcre2_match(m_pc, pcre2_s, s.length(), 0, 0, m_match_data, NULL);
|
||||||
|
if (rc > 0) {
|
||||||
|
return 1; // match
|
||||||
|
} else {
|
||||||
|
return 0; // no match
|
||||||
|
}
|
||||||
|
#else
|
||||||
int ovector[OVECCOUNT];
|
int ovector[OVECCOUNT];
|
||||||
return pcre_exec(m_pc, m_pce, s.c_str(),
|
return pcre_exec(m_pc, m_pce, s.c_str(),
|
||||||
s.size(), 0, 0, ovector, OVECCOUNT) > 0;
|
s.size(), 0, 0, ovector, OVECCOUNT) > 0;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Utils
|
} // namespace Utils
|
||||||
|
@ -12,8 +12,12 @@
|
|||||||
* directly using the email address security@modsecurity.org.
|
* directly using the email address security@modsecurity.org.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
#if WITH_PCRE2
|
||||||
|
#define PCRE2_CODE_UNIT_WIDTH 8
|
||||||
|
#include <pcre2.h>
|
||||||
|
#else
|
||||||
#include <pcre.h>
|
#include <pcre.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
@ -76,8 +80,13 @@ class Regex {
|
|||||||
|
|
||||||
const std::string pattern;
|
const std::string pattern;
|
||||||
private:
|
private:
|
||||||
|
#if WITH_PCRE2
|
||||||
|
pcre2_code *m_pc;
|
||||||
|
pcre2_match_data *m_match_data;
|
||||||
|
#else
|
||||||
pcre *m_pc = NULL;
|
pcre *m_pc = NULL;
|
||||||
pcre_extra *m_pce = NULL;
|
pcre_extra *m_pce = NULL;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -50,6 +50,7 @@ unit_tests_LDADD = \
|
|||||||
$(LMDB_LDADD) \
|
$(LMDB_LDADD) \
|
||||||
$(LUA_LDADD) \
|
$(LUA_LDADD) \
|
||||||
$(PCRE_LDADD) \
|
$(PCRE_LDADD) \
|
||||||
|
$(PCRE2_LDADD) \
|
||||||
$(SSDEEP_LDADD) \
|
$(SSDEEP_LDADD) \
|
||||||
$(YAJL_LDADD)
|
$(YAJL_LDADD)
|
||||||
|
|
||||||
@ -81,6 +82,7 @@ unit_tests_CPPFLAGS = \
|
|||||||
$(GLOBAL_CPPFLAGS) \
|
$(GLOBAL_CPPFLAGS) \
|
||||||
$(LMDB_CFLAGS) \
|
$(LMDB_CFLAGS) \
|
||||||
$(PCRE_CFLAGS) \
|
$(PCRE_CFLAGS) \
|
||||||
|
$(PCRE2_CFLAGS) \
|
||||||
$(YAJL_CFLAGS) \
|
$(YAJL_CFLAGS) \
|
||||||
$(LUA_CFLAGS) \
|
$(LUA_CFLAGS) \
|
||||||
$(SSDEEP_CFLAGS) \
|
$(SSDEEP_CFLAGS) \
|
||||||
@ -104,6 +106,7 @@ regression_tests_LDADD = \
|
|||||||
$(LMDB_LDADD) \
|
$(LMDB_LDADD) \
|
||||||
$(LUA_LDADD) \
|
$(LUA_LDADD) \
|
||||||
$(PCRE_LDADD) \
|
$(PCRE_LDADD) \
|
||||||
|
$(PCRE2_LDADD) \
|
||||||
$(SSDEEP_LDADD) \
|
$(SSDEEP_LDADD) \
|
||||||
$(YAJL_LDADD)
|
$(YAJL_LDADD)
|
||||||
|
|
||||||
@ -137,6 +140,7 @@ regression_tests_CPPFLAGS = \
|
|||||||
$(LUA_CFLAGS) \
|
$(LUA_CFLAGS) \
|
||||||
$(SSDEEP_CFLAGS) \
|
$(SSDEEP_CFLAGS) \
|
||||||
$(PCRE_CFLAGS) \
|
$(PCRE_CFLAGS) \
|
||||||
|
$(PCRE2_CFLAGS) \
|
||||||
$(YAJL_CFLAGS) \
|
$(YAJL_CFLAGS) \
|
||||||
$(LIBXML2_CFLAGS)
|
$(LIBXML2_CFLAGS)
|
||||||
|
|
||||||
@ -157,6 +161,7 @@ rules_optimization_LDADD = \
|
|||||||
$(LMDB_LDADD) \
|
$(LMDB_LDADD) \
|
||||||
$(LUA_LDADD) \
|
$(LUA_LDADD) \
|
||||||
$(PCRE_LDADD) \
|
$(PCRE_LDADD) \
|
||||||
|
$(PCRE2_LDADD) \
|
||||||
$(SSDEEP_LDADD) \
|
$(SSDEEP_LDADD) \
|
||||||
$(YAJL_LDADD)
|
$(YAJL_LDADD)
|
||||||
|
|
||||||
@ -188,6 +193,7 @@ rules_optimization_CPPFLAGS = \
|
|||||||
$(LUA_CFLAGS) \
|
$(LUA_CFLAGS) \
|
||||||
$(SSDEEP_CFLAGS) \
|
$(SSDEEP_CFLAGS) \
|
||||||
$(PCRE_CFLAGS) \
|
$(PCRE_CFLAGS) \
|
||||||
|
$(PCRE2_CFLAGS) \
|
||||||
$(YAJL_CFLAGS) \
|
$(YAJL_CFLAGS) \
|
||||||
$(LIBXML2_CFLAGS)
|
$(LIBXML2_CFLAGS)
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user