Merge pull request #3132 from eduar-hte/windows-port

Add support to build libModSecurity v3 on Windows
This commit is contained in:
Ervin Hegedus 2024-05-15 15:00:16 +02:00 committed by GitHub
commit 71a786b1e5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
64 changed files with 1331 additions and 660 deletions

View File

@ -72,3 +72,55 @@ jobs:
run: make -j `sysctl -n hw.logicalcpu`
- name: check
run: make check
build-windows:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [windows-2022]
platform: [x86_64]
configuration: [Release]
configure:
- {label: "full", opt: "" }
- {label: "wo lmdb", opt: "-DWITHOUT_LMDB=ON" }
- {label: "wo lua", opt: "-DWITHOUT_LUA=ON" }
- {label: "wo maxmind", opt: "-DWITHOUT_MAXMIND=ON" }
- {label: "wo curl", opt: "-DWITHOUT_CURL=ON" }
steps:
- uses: actions/checkout@v4
with:
submodules: true
- name: Install Conan
run: |
pip3 install conan --upgrade
conan profile detect
- uses: ammaraskar/msvc-problem-matcher@master
- name: Build ${{ matrix.configuration }} ${{ matrix.platform }} ${{ matrix.configure.label }}
shell: cmd
run: vcbuild.bat ${{ matrix.configuration }} ${{ matrix.platform }} NO_ASAN "${{ matrix.configure.opt }}"
- name: Set up test environment
working-directory: build\win32\build\${{ matrix.configuration }}
env:
BASE_DIR: ..\..\..\..
shell: cmd
run: |
copy unit_tests.exe %BASE_DIR%\test
copy regression_tests.exe %BASE_DIR%\test
copy libModSecurity.dll %BASE_DIR%\test
copy %BASE_DIR%\unicode.mapping %BASE_DIR%\test
md \tmp
md \bin
copy "C:\Program Files\Git\usr\bin\echo.exe" \bin
copy "C:\Program Files\Git\usr\bin\echo.exe" \bin\echo
- name: Disable tests that don't work on Windows
working-directory: test\test-cases\regression
shell: cmd
run: |
jq "map(if .title == \"Test match variable (1/n)\" then .enabled = 0 else . end)" issue-2423-msg-in-chain.json > tmp.json && move /Y tmp.json issue-2423-msg-in-chain.json
jq "map(if .title == \"Test match variable (2/n)\" then .enabled = 0 else . end)" issue-2423-msg-in-chain.json > tmp.json && move /Y tmp.json issue-2423-msg-in-chain.json
jq "map(if .title == \"Test match variable (3/n)\" then .enabled = 0 else . end)" issue-2423-msg-in-chain.json > tmp.json && move /Y tmp.json issue-2423-msg-in-chain.json
jq "map(if .title == \"Variable offset - FILES_NAMES\" then .enabled = 0 else . end)" offset-variable.json > tmp.json && move /Y tmp.json offset-variable.json
- name: Run tests
working-directory: build\win32\build
run: |
ctest -C ${{ matrix.configuration }} --output-on-failure

View File

@ -89,263 +89,8 @@ LOG_DRIVER = env $(SHELL) $(top_srcdir)/test/custom-test-driver
AM_TESTS_ENVIRONMENT=AUTOMAKE_TESTS=true; export AUTOMAKE_TESTS;
LOG_COMPILER=test/test-suite.sh
# for i in `find test/test-cases -iname *.json`; do echo TESTS+=$i; done
TESTS=
TESTS+=test/test-cases/regression/action-allow.json
TESTS+=test/test-cases/regression/action-block.json
TESTS+=test/test-cases/regression/action-ctl_request_body_access.json
TESTS+=test/test-cases/regression/action-ctl_request_body_processor.json
TESTS+=test/test-cases/regression/action-ctl_request_body_processor_urlencoded.json
TESTS+=test/test-cases/regression/action-ctl_rule_engine.json
TESTS+=test/test-cases/regression/action-ctl_audit_engine.json
TESTS+=test/test-cases/regression/action-ctl_rule_remove_by_id.json
TESTS+=test/test-cases/regression/action-ctl_rule_remove_by_tag.json
TESTS+=test/test-cases/regression/action-ctl_rule_remove_target_by_id.json
TESTS+=test/test-cases/regression/action-ctl_rule_remove_target_by_tag.json
TESTS+=test/test-cases/regression/action-disruptive.json
TESTS+=test/test-cases/regression/action-exec.json
TESTS+=test/test-cases/regression/action-expirevar.json
TESTS+=test/test-cases/regression/action-id.json
TESTS+=test/test-cases/regression/action-initcol.json
TESTS+=test/test-cases/regression/action-msg.json
TESTS+=test/test-cases/regression/action-setenv.json
TESTS+=test/test-cases/regression/action-setrsc.json
TESTS+=test/test-cases/regression/action-setsid.json
TESTS+=test/test-cases/regression/action-setuid.json
TESTS+=test/test-cases/regression/actions.json
TESTS+=test/test-cases/regression/action-skip.json
TESTS+=test/test-cases/regression/action-tag.json
TESTS+=test/test-cases/regression/action-tnf-base64.json
TESTS+=test/test-cases/regression/action-xmlns.json
TESTS+=test/test-cases/regression/auditlog.json
TESTS+=test/test-cases/regression/collection-case-insensitive.json
TESTS+=test/test-cases/regression/collection-lua.json
TESTS+=test/test-cases/regression/collection-regular_expression_selection.json
TESTS+=test/test-cases/regression/collection-resource.json
TESTS+=test/test-cases/regression/collection-tx.json
TESTS+=test/test-cases/regression/collection-tx-with-macro.json
TESTS+=test/test-cases/regression/config-body_limits.json
TESTS+=test/test-cases/regression/config-calling_phases_by_name.json
TESTS+=test/test-cases/regression/config-include-bad.json
TESTS+=test/test-cases/regression/config-include.json
TESTS+=test/test-cases/regression/config-remove_by_id.json
TESTS+=test/test-cases/regression/config-remove_by_msg.json
TESTS+=test/test-cases/regression/config-remove_by_tag.json
TESTS+=test/test-cases/regression/config-response_type.json
TESTS+=test/test-cases/regression/config-secdefaultaction.json
TESTS+=test/test-cases/regression/config-secremoterules.json
TESTS+=test/test-cases/regression/config-update-action-by-id.json
TESTS+=test/test-cases/regression/config-update-target-by-id.json
TESTS+=test/test-cases/regression/config-update-target-by-msg.json
TESTS+=test/test-cases/regression/config-update-target-by-tag.json
TESTS+=test/test-cases/regression/config-xml_external_entity.json
TESTS+=test/test-cases/regression/debug_log.json
TESTS+=test/test-cases/regression/directive-sec_rule_script.json
TESTS+=test/test-cases/regression/issue-1152.json
TESTS+=test/test-cases/regression/issue-1528.json
TESTS+=test/test-cases/regression/issue-1565.json
TESTS+=test/test-cases/regression/issue-1576.json
TESTS+=test/test-cases/regression/issue-1591.json
TESTS+=test/test-cases/regression/issue-1725.json
TESTS+=test/test-cases/regression/issue-1743.json
TESTS+=test/test-cases/regression/issue-1785.json
TESTS+=test/test-cases/regression/issue-1812.json
TESTS+=test/test-cases/regression/issue-1831.json
TESTS+=test/test-cases/regression/issue-1844.json
TESTS+=test/test-cases/regression/issue-1850.json
TESTS+=test/test-cases/regression/issue-1941.json
TESTS+=test/test-cases/regression/issue-1943.json
TESTS+=test/test-cases/regression/issue-1956.json
TESTS+=test/test-cases/regression/issue-1960.json
TESTS+=test/test-cases/regression/issue-2099.json
TESTS+=test/test-cases/regression/issue-2000.json
TESTS+=test/test-cases/regression/issue-2111.json
TESTS+=test/test-cases/regression/issue-2196.json
TESTS+=test/test-cases/regression/issue-2423-msg-in-chain.json
TESTS+=test/test-cases/regression/issue-2427.json
TESTS+=test/test-cases/regression/issue-2296.json
TESTS+=test/test-cases/regression/issue-394.json
TESTS+=test/test-cases/regression/issue-849.json
TESTS+=test/test-cases/regression/issue-960.json
TESTS+=test/test-cases/regression/misc.json
TESTS+=test/test-cases/regression/misc-variable-under-quotes.json
TESTS+=test/test-cases/regression/offset-variable.json
TESTS+=test/test-cases/regression/operator-detectsqli.json
TESTS+=test/test-cases/regression/operator-detectxss.json
TESTS+=test/test-cases/regression/operator-fuzzyhash.json
TESTS+=test/test-cases/regression/operator-inpectFile.json
TESTS+=test/test-cases/regression/operator-ipMatchFromFile.json
TESTS+=test/test-cases/regression/operator-pm.json
TESTS+=test/test-cases/regression/operator-rx.json
TESTS+=test/test-cases/regression/operator-rxGlobal.json
TESTS+=test/test-cases/regression/operator-UnconditionalMatch.json
TESTS+=test/test-cases/regression/operator-validate-byte-range.json
TESTS+=test/test-cases/regression/operator-verifycc.json
TESTS+=test/test-cases/regression/operator-verifycpf.json
TESTS+=test/test-cases/regression/operator-verifyssn.json
TESTS+=test/test-cases/regression/operator-verifysvnr.json
TESTS+=test/test-cases/regression/request-body-parser-json.json
TESTS+=test/test-cases/regression/request-body-parser-multipart-crlf.json
TESTS+=test/test-cases/regression/request-body-parser-multipart.json
TESTS+=test/test-cases/regression/request-body-parser-xml.json
TESTS+=test/test-cases/regression/request-body-parser-xml-validade-dtd.json
TESTS+=test/test-cases/regression/rule-920120.json
TESTS+=test/test-cases/regression/rule-920200.json
TESTS+=test/test-cases/regression/rule-920274.json
TESTS+=test/test-cases/regression/secaction.json
TESTS+=test/test-cases/regression/secargumentslimit.json
TESTS+=test/test-cases/regression/sec_component_signature.json
TESTS+=test/test-cases/regression/secmarker.json
TESTS+=test/test-cases/regression/secruleengine.json
TESTS+=test/test-cases/regression/transformation-none.json
TESTS+=test/test-cases/regression/transformations.json
TESTS+=test/test-cases/regression/variable-ARGS_COMBINED_SIZE.json
TESTS+=test/test-cases/regression/variable-ARGS_GET.json
TESTS+=test/test-cases/regression/variable-ARGS_GET_NAMES.json
TESTS+=test/test-cases/regression/variable-ARGS.json
TESTS+=test/test-cases/regression/variable-ARGS_NAMES.json
TESTS+=test/test-cases/regression/variable-ARGS_POST.json
TESTS+=test/test-cases/regression/variable-ARGS_POST_NAMES.json
TESTS+=test/test-cases/regression/variable-AUTH_TYPE.json
TESTS+=test/test-cases/regression/variable-DURATION.json
TESTS+=test/test-cases/regression/variable-ENV.json
TESTS+=test/test-cases/regression/variable-FILES_COMBINED_SIZE.json
TESTS+=test/test-cases/regression/variable-FILES.json
TESTS+=test/test-cases/regression/variable-FILES_NAMES.json
TESTS+=test/test-cases/regression/variable-FILES_SIZES.json
TESTS+=test/test-cases/regression/variable-FULL_REQUEST.json
TESTS+=test/test-cases/regression/variable-FULL_REQUEST_LENGTH.json
TESTS+=test/test-cases/regression/variable-GEO.json
TESTS+=test/test-cases/regression/variable-HIGHEST_SEVERITY.json
TESTS+=test/test-cases/regression/variable-INBOUND_DATA_ERROR.json
TESTS+=test/test-cases/regression/variable-MATCHED_VAR.json
TESTS+=test/test-cases/regression/variable-MATCHED_VAR_NAME.json
TESTS+=test/test-cases/regression/variable-MATCHED_VARS.json
TESTS+=test/test-cases/regression/variable-MATCHED_VARS_NAMES.json
TESTS+=test/test-cases/regression/variable-MODSEC_BUILD.json
TESTS+=test/test-cases/regression/variable-MULTIPART_CRLF_LF_LINES.json
TESTS+=test/test-cases/regression/variable-MULTIPART_FILENAME.json
TESTS+=test/test-cases/regression/variable-MULTIPART_INVALID_HEADER_FOLDING.json
TESTS+=test/test-cases/regression/variable-MULTIPART_NAME.json
TESTS+=test/test-cases/regression/variable-MULTIPART_PART_HEADERS.json
TESTS+=test/test-cases/regression/variable-MULTIPART_STRICT_ERROR.json
TESTS+=test/test-cases/regression/variable-MULTIPART_UNMATCHED_BOUNDARY.json
TESTS+=test/test-cases/regression/variable-OUTBOUND_DATA_ERROR.json
TESTS+=test/test-cases/regression/variable-PATH_INFO.json
TESTS+=test/test-cases/regression/variable-QUERY_STRING.json
TESTS+=test/test-cases/regression/variable-REMOTE_ADDR.json
TESTS+=test/test-cases/regression/variable-REMOTE_HOST.json
TESTS+=test/test-cases/regression/variable-REMOTE_PORT.json
TESTS+=test/test-cases/regression/variable-REMOTE_USER.json
TESTS+=test/test-cases/regression/variable-REQBODY_PROCESSOR_ERROR.json
TESTS+=test/test-cases/regression/variable-REQBODY_PROCESSOR.json
TESTS+=test/test-cases/regression/variable-REQUEST_BASENAME.json
TESTS+=test/test-cases/regression/variable-REQUEST_BODY.json
TESTS+=test/test-cases/regression/variable-REQUEST_BODY_LENGTH.json
TESTS+=test/test-cases/regression/variable-REQUEST_COOKIES.json
TESTS+=test/test-cases/regression/variable-REQUEST_COOKIES_NAMES.json
TESTS+=test/test-cases/regression/variable-REQUEST_FILENAME.json
TESTS+=test/test-cases/regression/variable-REQUEST_HEADERS.json
TESTS+=test/test-cases/regression/variable-REQUEST_HEADERS_NAMES.json
TESTS+=test/test-cases/regression/variable-REQUEST_LINE.json
TESTS+=test/test-cases/regression/variable-REQUEST_METHOD.json
TESTS+=test/test-cases/regression/variable-REQUEST_PROTOCOL.json
TESTS+=test/test-cases/regression/variable-REQUEST_URI.json
TESTS+=test/test-cases/regression/variable-REQUEST_URI_RAW.json
TESTS+=test/test-cases/regression/variable-RESPONSE_BODY.json
TESTS+=test/test-cases/regression/variable-RESPONSE_CONTENT_LENGTH.json
TESTS+=test/test-cases/regression/variable-RESPONSE_CONTENT_TYPE.json
TESTS+=test/test-cases/regression/variable-RESPONSE_HEADERS.json
TESTS+=test/test-cases/regression/variable-RESPONSE_HEADERS_NAMES.json
TESTS+=test/test-cases/regression/variable-RESPONSE_PROTOCOL.json
TESTS+=test/test-cases/regression/variable-RULE.json
TESTS+=test/test-cases/regression/variable-SERVER_ADDR.json
TESTS+=test/test-cases/regression/variable-SERVER_NAME.json
TESTS+=test/test-cases/regression/variable-SERVER_PORT.json
TESTS+=test/test-cases/regression/variable-SESSIONID.json
TESTS+=test/test-cases/regression/variable-STATUS.json
TESTS+=test/test-cases/regression/variable-TIME_DAY.json
TESTS+=test/test-cases/regression/variable-TIME_EPOCH.json
TESTS+=test/test-cases/regression/variable-TIME_HOUR.json
TESTS+=test/test-cases/regression/variable-TIME.json
TESTS+=test/test-cases/regression/variable-TIME_MIN.json
TESTS+=test/test-cases/regression/variable-TIME_MON.json
TESTS+=test/test-cases/regression/variable-TIME_SEC.json
TESTS+=test/test-cases/regression/variable-TIME_WDAY.json
TESTS+=test/test-cases/regression/variable-TIME_YEAR.json
TESTS+=test/test-cases/regression/variable-TX.json
TESTS+=test/test-cases/regression/variable-UNIQUE_ID.json
TESTS+=test/test-cases/regression/variable-URLENCODED_ERROR.json
TESTS+=test/test-cases/regression/variable-USERID.json
TESTS+=test/test-cases/regression/variable-variation-count.json
TESTS+=test/test-cases/regression/variable-variation-exclusion.json
TESTS+=test/test-cases/regression/variable-WEBAPPID.json
TESTS+=test/test-cases/regression/variable-WEBSERVER_ERROR_LOG.json
TESTS+=test/test-cases/regression/variable-XML.json
TESTS+=test/test-cases/secrules-language-tests/operators/beginsWith.json
TESTS+=test/test-cases/secrules-language-tests/operators/contains.json
TESTS+=test/test-cases/secrules-language-tests/operators/containsWord.json
TESTS+=test/test-cases/secrules-language-tests/operators/detectSQLi.json
TESTS+=test/test-cases/secrules-language-tests/operators/detectXSS.json
TESTS+=test/test-cases/secrules-language-tests/operators/endsWith.json
TESTS+=test/test-cases/secrules-language-tests/operators/eq.json
TESTS+=test/test-cases/secrules-language-tests/operators/ge.json
TESTS+=test/test-cases/secrules-language-tests/operators/geoLookup.json
TESTS+=test/test-cases/secrules-language-tests/operators/gt.json
TESTS+=test/test-cases/secrules-language-tests/operators/ipMatch.json
TESTS+=test/test-cases/secrules-language-tests/operators/le.json
TESTS+=test/test-cases/secrules-language-tests/operators/lt.json
TESTS+=test/test-cases/secrules-language-tests/operators/noMatch.json
TESTS+=test/test-cases/secrules-language-tests/operators/pmFromFile.json
TESTS+=test/test-cases/secrules-language-tests/operators/pm.json
TESTS+=test/test-cases/secrules-language-tests/operators/rx.json
TESTS+=test/test-cases/secrules-language-tests/operators/rxGlobal.json
TESTS+=test/test-cases/secrules-language-tests/operators/streq.json
TESTS+=test/test-cases/secrules-language-tests/operators/strmatch.json
TESTS+=test/test-cases/secrules-language-tests/operators/unconditionalMatch.json
TESTS+=test/test-cases/secrules-language-tests/operators/validateByteRange.json
TESTS+=test/test-cases/secrules-language-tests/operators/validateUrlEncoding.json
TESTS+=test/test-cases/secrules-language-tests/operators/validateUtf8Encoding.json
TESTS+=test/test-cases/secrules-language-tests/operators/verifyCC.json
TESTS+=test/test-cases/secrules-language-tests/operators/verifycpf.json
TESTS+=test/test-cases/secrules-language-tests/operators/verifyssn.json
TESTS+=test/test-cases/secrules-language-tests/operators/verifysvnr.json
TESTS+=test/test-cases/secrules-language-tests/operators/within.json
TESTS+=test/test-cases/secrules-language-tests/transformations/base64DecodeExt.json
TESTS+=test/test-cases/secrules-language-tests/transformations/base64Decode.json
TESTS+=test/test-cases/secrules-language-tests/transformations/base64Encode.json
TESTS+=test/test-cases/secrules-language-tests/transformations/cmdLine.json
TESTS+=test/test-cases/secrules-language-tests/transformations/compressWhitespace.json
TESTS+=test/test-cases/secrules-language-tests/transformations/cssDecode.json
TESTS+=test/test-cases/secrules-language-tests/transformations/escapeSeqDecode.json
TESTS+=test/test-cases/secrules-language-tests/transformations/hexDecode.json
TESTS+=test/test-cases/secrules-language-tests/transformations/hexEncode.json
TESTS+=test/test-cases/secrules-language-tests/transformations/htmlEntityDecode.json
TESTS+=test/test-cases/secrules-language-tests/transformations/jsDecode.json
TESTS+=test/test-cases/secrules-language-tests/transformations/length.json
TESTS+=test/test-cases/secrules-language-tests/transformations/lowercase.json
TESTS+=test/test-cases/secrules-language-tests/transformations/md5.json
TESTS+=test/test-cases/secrules-language-tests/transformations/normalisePath.json
TESTS+=test/test-cases/secrules-language-tests/transformations/normalisePathWin.json
TESTS+=test/test-cases/secrules-language-tests/transformations/parityEven7bit.json
TESTS+=test/test-cases/secrules-language-tests/transformations/parityOdd7bit.json
TESTS+=test/test-cases/secrules-language-tests/transformations/parityZero7bit.json
TESTS+=test/test-cases/secrules-language-tests/transformations/removeCommentsChar.json
TESTS+=test/test-cases/secrules-language-tests/transformations/removeComments.json
TESTS+=test/test-cases/secrules-language-tests/transformations/removeNulls.json
TESTS+=test/test-cases/secrules-language-tests/transformations/removeWhitespace.json
TESTS+=test/test-cases/secrules-language-tests/transformations/replaceComments.json
TESTS+=test/test-cases/secrules-language-tests/transformations/replaceNulls.json
TESTS+=test/test-cases/secrules-language-tests/transformations/sha1.json
TESTS+=test/test-cases/secrules-language-tests/transformations/sqlHexDecode.json
TESTS+=test/test-cases/secrules-language-tests/transformations/trim.json
TESTS+=test/test-cases/secrules-language-tests/transformations/trimLeft.json
TESTS+=test/test-cases/secrules-language-tests/transformations/trimRight.json
TESTS+=test/test-cases/secrules-language-tests/transformations/urlDecode.json
TESTS+=test/test-cases/secrules-language-tests/transformations/urlDecodeUni.json
TESTS+=test/test-cases/secrules-language-tests/transformations/urlEncode.json
TESTS+=test/test-cases/secrules-language-tests/transformations/utf8toUnicode.json
include test/test-suite.in
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = modsecurity.pc

244
build/win32/CMakeLists.txt Normal file
View File

@ -0,0 +1,244 @@
cmake_minimum_required(VERSION 3.24)
set(BASE_DIR ${CMAKE_CURRENT_LIST_DIR}/../..)
option(WITHOUT_LMDB "Include LMDB support" OFF)
option(WITHOUT_LUA "Include LUA support" OFF)
option(WITHOUT_LIBXML2 "Include LibXML2 support" OFF)
option(WITHOUT_MAXMIND "Include MaxMind support" OFF)
option(WITHOUT_CURL "Include CURL support" OFF)
option(USE_ASAN "Build with Address Sanitizer" OFF)
# common compiler settings
# NOTE: MBEDTLS_CONFIG_FILE is not only required to compile the mbedtls subset in others, but also
# when their headers are included while compiling libModSecurity
add_compile_definitions(WIN32 _CRT_SECURE_NO_WARNINGS MBEDTLS_CONFIG_FILE="mbed-tls-config.h")
# set standards conformance preprocessor & compiler to align with cross-compiled codebase
# NOTE: otherwise visual c++'s default compiler/preprocessor behaviour generates C4067 warnings
# (unexpected tokens following preprocessor directive - expected a newline)
add_compile_options(/Zc:preprocessor /permissive-)
if(USE_ASAN)
add_compile_options(/fsanitize=address)
add_link_options(/INFERASANLIBS /INCREMENTAL:no)
endif()
# libinjection
project(libinjection C)
add_library(libinjection STATIC ${BASE_DIR}/others/libinjection/src/libinjection_sqli.c ${BASE_DIR}/others/libinjection/src/libinjection_xss.c ${BASE_DIR}/others/libinjection/src/libinjection_html5.c)
# mbedtls
project(mbedtls C)
add_library(mbedtls STATIC ${BASE_DIR}/others/mbedtls/base64.c ${BASE_DIR}/others/mbedtls/sha1.c ${BASE_DIR}/others/mbedtls/md5.c)
target_include_directories(mbedtls PRIVATE ${BASE_DIR}/others)
#
# libModSecurity
#
project(libModSecurity
VERSION
3.0.12
LANGUAGES
CXX
)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED On)
set(CMAKE_CXX_EXTENSIONS Off)
set(PACKAGE_BUGREPORT "security@modsecurity.org")
set(PACKAGE_NAME "modsecurity")
set(PACKAGE_VERSION "${PROJECT_VERSION}")
set(PACKAGE_STRING "${PACKAGE_NAME} ${PACKAGE_VERSION}")
set(PACKAGE_TARNAME "${PACKAGE_NAME}")
set(HAVE_YAJL 1) # should always be one, mandatory dependency
set(HAVE_GEOIP 0) # should always be zero, no conan package available
set(HAVE_SSDEEP 0) # should always be zero, no conan package available
macro(enable_feature flag option)
if(${option})
set(${flag} 0)
else()
set(${flag} 1)
endif()
endmacro()
enable_feature(HAVE_LMDB ${WITHOUT_LMDB})
enable_feature(HAVE_LUA ${WITHOUT_LUA})
enable_feature(HAVE_LIBXML2 ${WITHOUT_LIBXML2})
enable_feature(HAVE_MAXMIND ${WITHOUT_MAXMIND})
enable_feature(HAVE_CURL ${WITHOUT_CURL})
include(${CMAKE_CURRENT_LIST_DIR}/ConfigureChecks.cmake)
configure_file(config.h.cmake ${BASE_DIR}/src/config.h)
find_package(PCRE2 REQUIRED)
find_package(PThreads4W REQUIRED)
find_package(Poco REQUIRED)
find_package(dirent REQUIRED) # used only by tests (check dirent::dirent refernces)
macro(include_package package flag)
if(${flag})
find_package(${package} REQUIRED)
endif()
endmacro()
include_package(yajl HAVE_YAJL)
include_package(libxml2 HAVE_LIBXML2)
include_package(lua HAVE_LUA)
include_package(CURL HAVE_CURL)
include_package(lmdb HAVE_LMDB)
include_package(maxminddb HAVE_MAXMIND)
# library
#
# NOTE: required to generate libModSecurity's import library (libModSecurity.lib), used by tests to link with shared library
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
file(GLOB_RECURSE libModSecuritySources ${BASE_DIR}/src/*.cc)
add_library(libModSecurity SHARED ${libModSecuritySources})
target_compile_definitions(libModSecurity PRIVATE WITH_PCRE2)
target_include_directories(libModSecurity PRIVATE ${BASE_DIR} ${BASE_DIR}/headers ${BASE_DIR}/others)
target_link_libraries(libModSecurity PRIVATE pcre2::pcre2 pthreads4w::pthreads4w libinjection mbedtls Poco::Poco Iphlpapi.lib)
macro(add_package_dependency project compile_definition link_library flag)
if(${flag})
target_compile_definitions(${project} PRIVATE ${compile_definition})
target_link_libraries(${project} PRIVATE ${link_library})
endif()
endmacro()
add_package_dependency(libModSecurity WITH_YAJL yajl::yajl HAVE_YAJL)
add_package_dependency(libModSecurity WITH_LIBXML2 LibXml2::LibXml2 HAVE_LIBXML2)
add_package_dependency(libModSecurity WITH_LUA lua::lua HAVE_LUA)
if(HAVE_LUA)
target_compile_definitions(libModSecurity PRIVATE WITH_LUA_5_4)
endif()
add_package_dependency(libModSecurity MSC_WITH_CURL CURL::libcurl HAVE_CURL)
add_package_dependency(libModSecurity WITH_LMDB lmdb::lmdb HAVE_LMDB)
add_package_dependency(libModSecurity WITH_MAXMIND maxminddb::maxminddb HAVE_MAXMIND)
# tests
#
project(libModSecurityTests)
function(setTestTargetProperties executable)
target_compile_definitions(${executable} PRIVATE WITH_PCRE2)
target_include_directories(${executable} PRIVATE ${BASE_DIR} ${BASE_DIR}/headers)
target_link_libraries(${executable} PRIVATE libModSecurity pcre2::pcre2 dirent::dirent)
add_package_dependency(${executable} WITH_YAJL yajl::yajl HAVE_YAJL)
endfunction()
# unit tests
file(GLOB unitTestSources ${BASE_DIR}/test/unit/*.cc)
add_executable(unit_tests ${unitTestSources})
setTestTargetProperties(unit_tests)
target_compile_options(unit_tests PRIVATE /wd4805)
# regression tests
file(GLOB regressionTestsSources ${BASE_DIR}/test/regression/*.cc)
add_executable(regression_tests ${regressionTestsSources})
setTestTargetProperties(regression_tests)
macro(add_regression_test_capability compile_definition flag)
if(${flag})
target_compile_definitions(regression_tests PRIVATE ${compile_definition})
endif()
endmacro()
add_regression_test_capability(WITH_LUA HAVE_LUA)
add_regression_test_capability(WITH_CURL HAVE_CURL)
add_regression_test_capability(WITH_LMDB HAVE_LMDB)
add_regression_test_capability(WITH_MAXMIND HAVE_MAXMIND)
enable_testing()
file(READ ${BASE_DIR}/test/test-suite.in TEST_FILES_RAW)
string(REPLACE "\n" ";" TEST_FILES ${TEST_FILES_RAW})
foreach(TEST_FILE ${TEST_FILES})
# ignore comment lines
string(FIND ${TEST_FILE} "#" is_comment)
if(NOT is_comment EQUAL 0)
string(FIND ${TEST_FILE} "TESTS+=" is_valid_prefix)
if(NOT is_valid_prefix EQUAL 0)
message(FATAL_ERROR "Invalid prefix in line: ${TEST_FILE}")
endif()
# remove 'TESTS+=' prefix and 'test/' too because tests are launched
# from that directory
string(SUBSTRING ${TEST_FILE} 12 -1 TEST_FILE)
# test name
get_filename_component(TEST_NAME ${TEST_FILE} NAME_WE)
# determine test runner based on test path prefix
string(FIND ${TEST_FILE} "test-cases/regression/" is_regression_test)
if(is_regression_test EQUAL 0)
set(TEST_RUNNER "regression_tests")
else()
set(TEST_RUNNER "unit_tests")
endif()
add_test(NAME ${TEST_NAME} COMMAND ${TEST_RUNNER} ${TEST_FILE} WORKING_DIRECTORY ${BASE_DIR}/test)
endif()
endforeach()
# benchmark
add_executable(benchmark ${BASE_DIR}/test/benchmark/benchmark.cc)
setTestTargetProperties(benchmark)
# rules_optimization
add_executable(rules_optimization ${BASE_DIR}/test/optimization/optimization.cc)
setTestTargetProperties(rules_optimization)
# examples
#
project(libModSecurityExamples)
function(setExampleTargetProperties executable)
target_include_directories(${executable} PRIVATE ${BASE_DIR} ${BASE_DIR}/headers)
target_link_libraries(${executable} PRIVATE libModSecurity)
endfunction()
# simple_example_using_c
add_executable(simple_example_using_c ${BASE_DIR}/examples/simple_example_using_c/test.c)
setExampleTargetProperties(simple_example_using_c)
# using_bodies_in_chunks
add_executable(using_bodies_in_chunks ${BASE_DIR}/examples/using_bodies_in_chunks/simple_request.cc)
setExampleTargetProperties(using_bodies_in_chunks)
# reading_logs_via_rule_message
add_executable(reading_logs_via_rule_message ${BASE_DIR}/examples/reading_logs_via_rule_message/simple_request.cc)
setExampleTargetProperties(reading_logs_via_rule_message)
target_link_libraries(reading_logs_via_rule_message PRIVATE libModSecurity pthreads4w::pthreads4w)
# reading_logs_with_offset
add_executable(reading_logs_with_offset ${BASE_DIR}/examples/reading_logs_with_offset/read.cc)
setExampleTargetProperties(reading_logs_with_offset)
# tools
#
# rules_check
add_executable(rules_check ${BASE_DIR}/tools/rules-check/rules-check.cc)
target_include_directories(rules_check PRIVATE ${BASE_DIR} ${BASE_DIR}/headers)
target_link_libraries(rules_check PRIVATE libModSecurity)

View File

@ -0,0 +1,18 @@
include(CheckIncludeFile)
include(CheckIncludeFiles)
check_include_file("dlfcn.h" HAVE_DLFCN_H)
check_include_file("inttypes.h" HAVE_INTTYPES_H)
check_include_file("stdint.h" HAVE_STDINT_H)
check_include_file("stdio.h" HAVE_STDIO_H)
check_include_file("stdlib.h" HAVE_STDLIB_H)
check_include_file("string" HAVE_STRING)
check_include_file("strings.h" HAVE_STRINGS_H)
check_include_file("string.h" HAVE_STRING_H)
check_include_file("sys/stat.h" HAVE_SYS_STAT_H)
check_include_file("sys/types.h" HAVE_SYS_TYPES_H)
check_include_file("sys/utsname.h" HAVE_SYS_UTSNAME_H)
check_include_file("unistd.h" HAVE_UNISTD_H)
#/* Define to 1 if you have the ANSI C header files. */
check_include_files("stdlib.h;stdarg.h;string.h;float.h" STDC_HEADERS)

111
build/win32/README.md Normal file
View File

@ -0,0 +1,111 @@
# libModSecurity Windows build information <!-- omit from toc -->
The Windows build of libModSecurity uses Build Tools for Visual Studio 2022 (for Visual C++ & CMake) and Conan package manager.
## Contents <!-- omit from toc -->
- [Prerequisites](#prerequisites)
- [Build](#build)
- [Optional features](#optional-features)
- [Address Sanitizer](#address-sanitizer)
- [Docker container](#docker-container)
## Prerequisites
* [Build Tools for Visual Studio 2022](https://aka.ms/vs/17/release/vs_buildtools.exe)
* Install *Desktop development with C++* workload, which includes:
* MSVC C++ compiler
* Windows SDK
* CMake
* Address Sanitizer
* [Conan package manager 2.2.2](https://github.com/conan-io/conan/releases/download/2.2.2/conan-2.2.2-windows-x86_64-installer.exe)
* Install and then setup the default Conan profile to use the MSVC C++ compiler:
1. Open a command-prompt and set the MSVC C++ compiler environment by executing: `C:\BuildTools\VC\Auxiliary\Build\vcvars64.bat`
2. Execute: `conan profile detect --force`
* [Git for Windows 2.44.0](https://github.com/git-for-windows/git/releases/download/v2.44.0.windows.1/Git-2.44.0-64-bit.exe)
* To clone the libModSecurity repository.
* NOTE: Make sure to initialize and update submodules (to get `libinjection` and regression tests)
* `git submodule init`
* `git submodule update`
## Build
Install the prerequisites listsed in the previous section, checkout libModSecurity and from the directory where it's located execute:
```
vcbuild.bat [build_configuration] [arch] [USE_ASAN]
```
where `[build_configuration]` can be: `Release` (default), `RelWithDebInfo`, `MinSizeRel` or `Debug`, and `[arch]` can be: `x86_64` (default) or `x86`.
Built files will be located in the directory: `build\win32\build\[build_configuration]` and include:
* `libModSecurity.dll`
* Executable files for test projects
* `unit_tests.exe`
* `regression_tests.exe`
* `benchmark.exe`
* `rules_optimization.exe`
* Executable files for examples
* `simple_example_using_c.exe`
* `using_bodies_in_chunks.exe`
* `reading_logs_via_rule_message.exe`
* `reading_logs_with_offset.exe`
* Executable files for tools
* `rules_check.exe`
NOTE: When building a different configuration, it's recommended to reset:
* the build directory: `build\win32\build`
* previously built conan packages executing the command:
* `conan remove * -c`
### Optional features
By default the following all the following features are enabled by including the associated third-party library through a Conan package:
* libxml2 2.12.6 for XML processing support
* libcurl 8.6.0 to support http requests from rules
* libmaxminddb 1.9.1 to support reading MaxMind DB files.
* LUA 5.4.6 to enable rules to run scripts in this language for extensibility
* lmdb 0.9.31 in-memory database
Each of these can be turned off by updating the associated `HAVE_xxx` variable (setting it to zero) in the beginning of the libModSecurity section of `CMakeLists.txt`.
### Address Sanitizer
[AddressSanitizer](https://github.com/google/sanitizers/wiki/AddressSanitizer) (aka ASan) is a memory error detector for C/C++.
To generate a build with *Address Sanitizer*, add the `USE_ASAN` optional third argument to `vcbuild.bat`. For example:
* `vcbuild.bat Debug x86_64 USE_ASAN`
NOTE: `USE_ASAN` does not work with `Release` & `MinSizeRel` configurations because they do not include debug info (it is only compatible with `Debug` & `RelWithDebInfo` builds).
* References
* [AddressSanitizer | Microsoft Learn](https://learn.microsoft.com/en-us/cpp/sanitizers/asan?view=msvc-170)
* [AddressSanitizer for Windows: x64 and Debug Build Support - C++ Team Blog (microsoft.com)](https://devblogs.microsoft.com/cppblog/asan-for-windows-x64-and-debug-build-support/)
* [AddressSanitizer language, build, and debugging reference | Microsoft Learn](https://learn.microsoft.com/en-us/cpp/sanitizers/asan-building?view=msvc-170)
### Docker container
A `Dockerfile` configuration file is provided in the `docker` subdir that creates a Windows container image which installs the [prerequisites](#prerequisites) and builds libModSecurity and other binaries.
NOTE: Windows containers are supported in Docker Desktop for Windows, using the *Switch to Windows containers...* option on the context menu of the system tray icon.
To build the docker image, execute the following command (from the `build\win32\docker` directory):
* `docker build -t libmodsecurity:latest -m 4GB .`
* Build type, architecture and build with Address Sanitizer can be configured through build arguments (`BUILD_TYPE`, `ARCH` & `USE_ASAN` respectively). For example, to generate a debug build, add the following argument:
* `--build-arg BUILD_TYPE=Debug`
Once the image is generated, the library and associated binaries (tests & examples) are located in the `C:\src\ModSecurity\build\win32\build\[build_type]` directory.
To extract the library (`libModSecurity.dll`) from the image, you can execute the following commands:
* `docker container create --name [container_name] libmodsecurity`
* `docker cp [container_name]:C:\src\ModSecurity\build\win32\build\[build_type]\libModSecurity.dll .`
* NOTE: If you leave out the `libModSecurity.dll` filename out, you can copy all the built binaries (including examples & tests).
Additionally, the image can be used interactively for additional development work by executing:
* `docker run -it libmodsecurity`

15
build/win32/conanfile.txt Normal file
View File

@ -0,0 +1,15 @@
[requires]
yajl/2.1.0
pcre2/10.42
pthreads4w/3.0.0
libxml2/2.12.6
lua/5.4.6
libcurl/8.6.0
lmdb/0.9.31
libmaxminddb/1.9.1
dirent/1.24
poco/1.13.3
[generators]
CMakeDeps
CMakeToolchain

View File

@ -0,0 +1,92 @@
/* config.h.cmake. Based upon generated config.h.in. */
#ifndef MODSECURITY_CONFIG_H
#define MODSECURITY_CONFIG_H 1
/* Define to 1 if you have the <dlfcn.h> header file. */
#cmakedefine HAVE_DLFCN_H
/* Define to 1 if you have the <inttypes.h> header file. */
#cmakedefine HAVE_INTTYPES_H
/* Define to 1 if you have the <iostream> header file. */
#cmakedefine HAVE_IOSTREAM
/* Define to 1 if you have the <stdint.h> header file. */
#cmakedefine HAVE_STDINT_H
/* Define to 1 if you have the <stdio.h> header file. */
#cmakedefine HAVE_STDIO_H
/* Define to 1 if you have the <stdlib.h> header file. */
#cmakedefine HAVE_STDLIB_H
/* Define to 1 if you have the <string> header file. */
#cmakedefine HAVE_STRING
/* Define to 1 if you have the <strings.h> header file. */
#cmakedefine HAVE_STRINGS_H
/* Define to 1 if you have the <string.h> header file. */
#cmakedefine HAVE_STRING_H
/* Define to 1 if you have the <sys/stat.h> header file. */
#cmakedefine HAVE_SYS_STAT_H
/* Define to 1 if you have the <sys/types.h> header file. */
#cmakedefine HAVE_SYS_TYPES_H
/* Define to 1 if you have the <sys/utsname.h> header file. */
#cmakedefine HAVE_SYS_UTSNAME_H
/* Define to 1 if you have the <unistd.h> header file. */
#cmakedefine HAVE_UNISTD_H
/* Define if GeoIP is available */
#cmakedefine HAVE_GEOIP
/* Define if LMDB is available */
#cmakedefine HAVE_LMDB
/* Define if LUA is available */
#cmakedefine HAVE_LUA
/* Define if MaxMind is available */
#cmakedefine HAVE_MAXMIND
/* Define if SSDEEP is available */
#cmakedefine HAVE_SSDEEP
/* Define if YAJL is available */
#cmakedefine HAVE_YAJL
/* Define if libcurl is available */
#cmakedefine HAVE_CURL
/* Name of package */
#define PACKAGE "@PACKAGE_NAME@"
/* Define to the address where bug reports for this package should be sent. */
#cmakedefine PACKAGE_BUGREPORT "@PACKAGE_BUGREPORT@"
/* Define to the full name of this package. */
#cmakedefine PACKAGE_NAME "@PACKAGE_NAME@"
/* Define to the full name and version of this package. */
#cmakedefine PACKAGE_STRING "@PACKAGE_STRING@"
/* Define to the one symbol short name of this package. */
#cmakedefine PACKAGE_TARNAME "@PACKAGE_TARNAME@"
/* Define to the home page for this package. */
#define PACKAGE_URL ""
/* Define to the version of this package. */
#cmakedefine PACKAGE_VERSION "@PACKAGE_VERSION@"
/* Define to 1 if you have the ANSI C header files. */
#ifndef STDC_HEADERS
#cmakedefine STDC_HEADERS
#endif
#endif // ndef MODSECURITY_CONFIG_H

View File

@ -0,0 +1,115 @@
# escape=`
ARG FROM_IMAGE=mcr.microsoft.com/windows/servercore:ltsc2022
FROM ${FROM_IMAGE}
# reset the shell.
SHELL ["cmd", "/S", "/C"]
# set up environment to collect install errors.
COPY InstallBuildTools.cmd C:\TEMP\
ADD https://aka.ms/vscollect.exe C:\TEMP\collect.exe
# download channel for fixed install.
ARG CHANNEL_URL=https://aka.ms/vs/17/release/channel
ADD ${CHANNEL_URL} C:\TEMP\VisualStudio.chman
# download and install Build Tools for Visual Studio 2022 for native desktop workload.
ADD https://aka.ms/vs/17/release/vs_buildtools.exe C:\TEMP\vs_buildtools.exe
RUN C:\TEMP\InstallBuildTools.cmd C:\TEMP\vs_buildtools.exe --quiet --wait --norestart --nocache `
--channelUri C:\TEMP\VisualStudio.chman `
--installChannelUri C:\TEMP\VisualStudio.chman `
--add Microsoft.VisualStudio.Workload.VCTools `
--includeRecommended `
--installPath C:\BuildTools
# download & install GIT
ARG GIT_VERSION=2.44.0
ARG GIT_BINARY=Git-${GIT_VERSION}-64-bit.exe
ARG GIT_URL=https://github.com/git-for-windows/git/releases/download/v${GIT_VERSION}.windows.1/${GIT_BINARY}
COPY git.inf C:\TEMP\
ARG INSTALLER=C:\TEMP\${GIT_BINARY}
ADD ${GIT_URL} ${INSTALLER}
RUN %INSTALLER% /SP- /VERYSILENT /SUPPRESSMSGBOXES /NOCANCEL `
/NORESTART /CLOSEAPPLICATIONS /RESTARTAPPLICATIONS /LOADINF=git.inf
# download & setup conan
ARG CONAN_VERSION=2.2.2
ARG CONAN_BINARY=conan-${CONAN_VERSION}-windows-x86_64-installer.exe
ARG CONAN_URL=https://github.com/conan-io/conan/releases/download/${CONAN_VERSION}/${CONAN_BINARY}
ARG INSTALLER=C:\TEMP\${CONAN_BINARY}
ADD ${CONAN_URL} ${INSTALLER}
RUN %INSTALLER% /SP- /VERYSILENT /SUPPRESSMSGBOXES
# setup conan profile
RUN C:\BuildTools\VC\Auxiliary\Build\vcvars64.bat && conan profile detect --force
# download libModSecurity
#
# create src dir
ARG SRC_DIR=C:\src
WORKDIR C:\
RUN cmd.exe /C md %SRC_DIR%
# libModSecurity
WORKDIR C:\src
ARG MOD_SECURITY_TAG=v3/master
RUN git clone -c advice.detachedHead=false --depth 1 --branch %MOD_SECURITY_TAG% https://github.com/owasp-modsecurity/ModSecurity.git
ARG MOD_SECURITY_DIR=${SRC_DIR}\ModSecurity
WORKDIR ${MOD_SECURITY_DIR}
# fetch submodules (bindings/python, others/libinjection, test/test-cases/secrules-language-tests)
RUN git submodule init
RUN git submodule update
# build libraries
#
ARG BUILD_TYPE=Release
ARG ARCH=x86_64
ARG USE_ASAN=
RUN C:\BuildTools\VC\Auxiliary\Build\vcvars64.bat && vcbuild.bat %BUILD_TYPE% %ARCH% %USE_ASAN%
# test suite
#
# setup test environment
RUN cmd.exe /C md \tmp
RUN cmd.exe /C md \bin
RUN cmd.exe /C copy "C:\Program Files\GIT\usr\bin" \bin > NUL
RUN cmd.exe /C copy "C:\Program Files\GIT\usr\bin\echo.exe" \bin\echo > NUL
# disable tests that don't work on windows
ARG JQ_VERSION=1.7.1
ARG JQ_BINARY=jq-windows-amd64.exe
ARG JQ_URL=https://github.com/jqlang/jq/releases/download/jq-${JQ_VERSION}/${JQ_BINARY}
ARG JQ_BIN=C:\TEMP\jq.exe
ADD ${JQ_URL} ${JQ_BIN}
WORKDIR ${MOD_SECURITY_DIR}\test\test-cases\regression
RUN %JQ_BIN% "map(if .title == \"Test match variable (1/n)\" then .enabled = 0 else . end)" issue-2423-msg-in-chain.json > tmp.json && move /Y tmp.json issue-2423-msg-in-chain.json
RUN %JQ_BIN% "map(if .title == \"Test match variable (2/n)\" then .enabled = 0 else . end)" issue-2423-msg-in-chain.json > tmp.json && move /Y tmp.json issue-2423-msg-in-chain.json
RUN %JQ_BIN% "map(if .title == \"Test match variable (3/n)\" then .enabled = 0 else . end)" issue-2423-msg-in-chain.json > tmp.json && move /Y tmp.json issue-2423-msg-in-chain.json
RUN %JQ_BIN% "map(if .title == \"Variable offset - FILES_NAMES\" then .enabled = 0 else . end)" offset-variable.json > tmp.json && move /Y tmp.json offset-variable.json
# run tests
WORKDIR ${MOD_SECURITY_DIR}\build\win32\build
RUN C:\BuildTools\VC\Auxiliary\Build\vcvars64.bat && ctest -C %BUILD_TYPE% --output-on-failure
# setup container's entrypoint
#
WORKDIR C:\
# Use developer command prompt and start PowerShell if no other command specified.
ENTRYPOINT ["C:\\BuildTools\\VC\\Auxiliary\\Build\\vcvars64.bat", "&&", "powershell.exe", "-NoLogo", "-ExecutionPolicy", "Bypass"]

View File

@ -0,0 +1,17 @@
@rem Copyright (C) Microsoft Corporation. All rights reserved.
@rem Licensed under the MIT license. See LICENSE.txt in the project root for license information.
@if not defined _echo echo off
setlocal enabledelayedexpansion
call %*
if "%ERRORLEVEL%"=="3010" (
exit /b 0
) else (
if not "%ERRORLEVEL%"=="0" (
set ERR=%ERRORLEVEL%
call C:\TEMP\collect.exe -zip:C:\vslogs.zip
exit /b !ERR!
)
)

View File

@ -0,0 +1,20 @@
[Setup]
Lang=default
Dir=C:\Program Files\Git
Group=Git
NoIcons=0
SetupType=default
Components=ext,ext\shellhere,ext\guihere,gitlfs,assoc,autoupdate
Tasks=
EditorOption=VIM
CustomEditorPath=
PathOption=Cmd
SSHOption=OpenSSH
TortoiseOption=false
CURLOption=WinSSL
CRLFOption=LFOnly
BashTerminalOption=ConHost
PerformanceTweaksFSCache=Enabled
UseCredentialManager=Enabled
EnableSymlinks=Disabled
EnableBuiltinInteractiveAdd=Disabled

View File

@ -19,7 +19,11 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifndef WIN32
#include <unistd.h>
#else
#include <io.h>
#endif
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/time.h>

View File

@ -13,10 +13,11 @@
*
*/
#include <unistd.h>
#include <string>
#include <memory>
#include <thread>
#include <chrono>
#include <pthread.h>
#define NUM_THREADS 100
@ -72,6 +73,11 @@ struct data_ms {
modsecurity::RulesSet *rules;
};
#if defined _MSC_VER
#pragma warning(push)
#pragma warning(disable:4716) // avoid error C4716: 'process_request': must return a value, as MSVC C++ compiler doesn't support [[noreturn]]
#pragma warning(disable:4715) // avoid warning c4715: 'process_request' : not all control paths return a value
#endif
[[noreturn]] static void *process_request(void *data) {
struct data_ms *a = (struct data_ms *)data;
@ -85,7 +91,7 @@ struct data_ms {
modsecTransaction->processConnection(ip, 12345, "127.0.0.1", 80);
modsecTransaction->processURI(request_uri, "GET", "1.1");
usleep(10);
std::this_thread::sleep_for(std::chrono::microseconds(10));
modsecTransaction->addRequestHeader("Host",
"net.tutsplus.com");
modsecTransaction->processRequestHeaders();
@ -105,6 +111,9 @@ struct data_ms {
pthread_exit(nullptr);
}
#if defined _MSC_VER
#pragma warning(pop)
#endif
class ReadingLogsViaRuleMessage {
public:
@ -151,7 +160,7 @@ class ReadingLogsViaRuleMessage {
reinterpret_cast<void *>(&dms));
}
usleep(10000);
std::this_thread::sleep_for(std::chrono::microseconds(10000));
for (i=0; i < NUM_THREADS; i++) {
pthread_join(threads[i], &status);

View File

@ -13,7 +13,11 @@
*
*/
#ifndef WIN32
#include <unistd.h>
#else
#include <io.h>
#endif
#include <stdio.h>
#include <string.h>

View File

@ -37,7 +37,11 @@ bool SetENV::evaluate(RuleWithActions *rule, Transaction *t) {
auto pair = utils::string::ssplit_pair(colNameExpanded, '=');
ms_dbg_a(t, 8, "Setting environment variable: "
+ pair.first + " to " + pair.second);
#ifndef WIN32
setenv(pair.first.c_str(), pair.second.c_str(), /*overwrite*/ 1);
#else
_putenv_s(pair.first.c_str(), pair.second.c_str());
#endif
return true;
}

View File

@ -27,6 +27,10 @@
#include "modsecurity/transaction.h"
#include "src/actions/transformations/transformation.h"
#ifdef WIN32
#include "src/compat/msvc.h"
#endif
namespace modsecurity {
namespace actions {

View File

@ -17,6 +17,7 @@
#include <algorithm>
#include <string>
#include <locale>
#include "modsecurity/transaction.h"
#include "src/actions/transformations/transformation.h"

View File

@ -17,6 +17,7 @@
#include <algorithm>
#include <string>
#include <locale>
#include "modsecurity/transaction.h"
#include "src/actions/transformations/transformation.h"

View File

@ -21,7 +21,12 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#ifndef WIN32
#include <unistd.h>
#else
#include <io.h>
#include "src/compat/msvc.h"
#endif
#include <stdlib.h>
#include <fstream>

View File

@ -18,8 +18,10 @@
#include <stdio.h>
#ifndef WIN32
#include <sys/ipc.h>
#include <sys/shm.h>
#endif
#include <sys/types.h>
#include <iostream>

View File

@ -12,6 +12,7 @@
* directly using the email address security@modsecurity.org.
*
*/
#include <pthread.h>
#ifdef __cplusplus

View File

@ -18,7 +18,11 @@
#include "src/collection/backend/collection_data.h"
#include <sys/types.h>
#ifndef WIN32
#include <unistd.h>
#else
#include <io.h>
#endif
#include <string>
#include <memory>

22
src/compat/msvc.h Normal file
View File

@ -0,0 +1,22 @@
#ifndef __COMPAT_MSVC
#define __COMPAT_MSVC
#include <time.h>
#if !defined(S_ISREG) && defined(S_IFMT) && defined(S_IFREG)
#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
#endif
#define strcasecmp _stricmp
#define strncasecmp _strnicmp
#define strtok_r strtok_s
#define popen _popen
#define pclose _pclose
inline tm* localtime_r(const time_t* tin, tm* tout) {
if (!localtime_s(tout, tin)) return tout;
return nullptr;
}
#endif

View File

@ -15,10 +15,6 @@
#include "modsecurity/debug_log.h"
#include <stddef.h>
#include <fstream>
#include "src/debug_log/debug_log_writer.h"
#include "src/debug_log_writer_agent.h"

View File

@ -15,18 +15,6 @@
#include "src/debug_log/debug_log_writer.h"
#include <errno.h>
#include <fcntl.h>
#include <pthread.h>
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <fstream>
#include "src/utils/shared_files.h"
namespace modsecurity {

View File

@ -13,15 +13,7 @@
*
*/
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <iostream>
#include <map>
#include <string>
#include <cstring>
#ifndef SRC_DEBUG_LOG_DEBUG_LOG_WRITER_H_
@ -45,18 +37,16 @@ class DebugLogWriter {
static int open(const std::string& m_fileName, std::string *error);
private:
DebugLogWriter() : m_first(NULL) { }
~DebugLogWriter() { }
DebugLogWriter() = default;
~DebugLogWriter() = default;
// C++ 03
// ========
// Dont forget to declare these two. You want to make sure they
// are unacceptable otherwise you may accidentally get copies of
// your singleton appearing.
DebugLogWriter(DebugLogWriter const&);
void operator=(DebugLogWriter const&);
struct debug_log_file_handler *m_first;
DebugLogWriter(DebugLogWriter const&) = delete;
void operator=(DebugLogWriter const&) = delete;
};

View File

@ -258,14 +258,11 @@ int ModSecurity::processContentOffset(const char *content, size_t len,
strlen("highlight"));
yajl_gen_array_open(g);
while (vars.size() > 3) {
std::string value;
for(auto [it, pending] = std::tuple{vars.rbegin(), vars.size()}; pending > 3; pending -= 3) {
yajl_gen_map_open(g);
vars.pop_back();
const std::string &startingAt = vars.back().str();
vars.pop_back();
const std::string &size = vars.back().str();
vars.pop_back();
it++;
const std::string &startingAt = it->str(); it++;
const std::string &size = it->str(); it++;
yajl_gen_string(g,
reinterpret_cast<const unsigned char*>("startingAt"),
strlen("startingAt"));
@ -284,7 +281,7 @@ int ModSecurity::processContentOffset(const char *content, size_t len,
return -1;
}
value = std::string(content, stoi(startingAt), stoi(size));
const auto value = std::string(content, stoi(startingAt), stoi(size));
if (varValue.size() > 0) {
varValue.append(" " + value);
} else {
@ -340,16 +337,13 @@ int ModSecurity::processContentOffset(const char *content, size_t len,
yajl_gen_map_open(g);
while (ops.size() > 3) {
std::string value;
for(auto [it, pending] = std::tuple{ops.rbegin(), ops.size()}; pending > 3; pending -= 3) {
yajl_gen_string(g, reinterpret_cast<const unsigned char*>("highlight"),
strlen("highlight"));
yajl_gen_map_open(g);
ops.pop_back();
std::string startingAt = ops.back().str();
ops.pop_back();
std::string size = ops.back().str();
ops.pop_back();
it++;
const std::string &startingAt = it->str(); it++;
const std::string &size = ops.back().str(); it++;
yajl_gen_string(g,
reinterpret_cast<const unsigned char*>("startingAt"),
strlen("startingAt"));
@ -371,7 +365,7 @@ int ModSecurity::processContentOffset(const char *content, size_t len,
reinterpret_cast<const unsigned char*>("value"),
strlen("value"));
value = std::string(varValue, stoi(startingAt), stoi(size));
const auto value = std::string(varValue, stoi(startingAt), stoi(size));
yajl_gen_string(g,
reinterpret_cast<const unsigned char*>(value.c_str()),

View File

@ -23,6 +23,10 @@
#include "src/operators/operator.h"
#include "src/utils/system.h"
#ifdef WIN32
#include "src/compat/msvc.h"
#endif
namespace modsecurity {
namespace operators {

View File

@ -16,10 +16,15 @@
#include "src/operators/rbl.h"
#include <sys/types.h>
#ifndef WIN32
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#else
#include <WinSock2.h>
#include <WS2tcpip.h>
#endif
#include <string>

View File

@ -17,10 +17,14 @@
#define SRC_OPERATORS_RBL_H_
#include <sys/types.h>
#ifndef WIN32
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#else
#include <WinSock2.h>
#endif
#include <string>
#include <memory>

View File

@ -4952,7 +4952,11 @@ static std::stack<int> YY_PREVIOUS_STATE;
* The user has a chance to override it with an option.
*/
/* %if-c-only */
#ifndef WIN32
#include <unistd.h>
#else
#include <io.h>
#endif
/* %endif */
/* %if-c++-only */
/* %endif */

View File

@ -21,7 +21,12 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#ifndef WIN32
#include <unistd.h>
#else
#include <io.h>
#include "src/compat/msvc.h"
#endif
#include <list>
#include <iostream>
#include <string>
@ -61,12 +66,11 @@ MultipartPartTmpFile::~MultipartPartTmpFile() {
void MultipartPartTmpFile::Open() {
struct tm timeinfo;
char tstr[300];
time_t tt = time(NULL);
localtime_r(&tt, &timeinfo);
memset(tstr, '\0', 300);
char tstr[300] {};
strftime(tstr, 299, "/%Y%m%d-%H%M%S", &timeinfo);
std::string path = m_transaction->m_rules->m_uploadDirectory.m_value;
@ -74,14 +78,23 @@ void MultipartPartTmpFile::Open() {
path += "-file-XXXXXX";
char* tmp = strdup(path.c_str());
#ifndef WIN32
m_tmp_file_fd = mkstemp(tmp);
#else
_mktemp_s(tmp, path.length()+1);
m_tmp_file_fd = _open(tmp, _O_CREAT | _O_EXCL | _O_RDWR);
#endif
m_tmp_file_name.assign(tmp);
free(tmp);
ms_dbg_a(m_transaction, 4, "MultipartPartTmpFile: Create filename= " + m_tmp_file_name);
int mode = m_transaction->m_rules->m_uploadFileMode.m_value;
if ((m_tmp_file_fd != -1) && (mode != 0)) {
#ifndef WIN32
if (fchmod(m_tmp_file_fd, mode) == -1) {
#else
if (_chmod(m_tmp_file_name.c_str(), mode) == -1) {
#endif
m_tmp_file_fd = -1;
}
}

View File

@ -172,9 +172,7 @@ RuleWithActions::~RuleWithActions() {
bool RuleWithActions::evaluate(Transaction *transaction) {
RuleMessage rm(this, transaction);
std::shared_ptr<RuleMessage> rm2 = std::make_shared<RuleMessage>(&rm);
return evaluate(transaction, rm2);
return evaluate(transaction, std::make_shared<RuleMessage>(this, transaction));
}
@ -330,7 +328,7 @@ inline void RuleWithActions::executeTransformation(
std::string newValue = a->evaluate(*oldValue, trans);
if (newValue != *oldValue) {
std::shared_ptr<std::string> u(new std::string(newValue));
auto u = std::make_shared<std::string>(newValue);
if (m_containsMultiMatchAction) {
ret->push_back(std::make_pair(u, a->m_name));
(*nth)++;
@ -355,14 +353,13 @@ void RuleWithActions::executeTransformations(
int none = 0;
int transformations = 0;
std::string path("");
std::shared_ptr<std::string> value =
std::shared_ptr<std::string>(new std::string(in));
auto value = std::make_shared<std::string>(in);
if (m_containsMultiMatchAction == true) {
/* keep the original value */
ret.push_back(std::make_pair(
std::shared_ptr<std::string>(new std::string(*value)),
std::shared_ptr<std::string>(new std::string(path))));
std::make_shared<std::string>(*value),
std::make_shared<std::string>(path)));
}
for (Action *a : m_transformations) {
@ -436,8 +433,8 @@ void RuleWithActions::executeTransformations(
if (!m_containsMultiMatchAction) {
ret.push_back(std::make_pair(
std::shared_ptr<std::string>(new std::string(*value)),
std::shared_ptr<std::string>(new std::string(path))));
std::make_shared<std::string>(*value),
std::make_shared<std::string>(path)));
}
}

View File

@ -19,6 +19,10 @@
#include "src/utils/string.h"
#include "src/variables/variable.h"
#ifdef WIN32
#include "src/compat/msvc.h"
#endif
namespace modsecurity {

View File

@ -53,6 +53,9 @@
#include "src/actions/disruptive/allow.h"
#include "src/variables/remote_user.h"
#ifdef WIN32
#include "src/compat/msvc.h"
#endif
using modsecurity::actions::Action;

View File

@ -17,7 +17,8 @@
#include "src/config.h"
#ifdef WIN32
#include <winsock2.h>
#include "src/compat/msvc.h"
#include <WinSock2.h>
#include <iphlpapi.h>
#endif
@ -48,7 +49,11 @@
#endif
#include <stdio.h>
#ifndef WIN32
#include <unistd.h>
#else
#include <io.h>
#endif
#include <string.h>
#include "src/utils/sha1.h"
@ -207,7 +212,7 @@ std::string UniqueId::ethernetMacAddress() {
pAdapter = pAdapterInfo;
while (pAdapter && !mac[0] && !mac[1] && !mac[2]) {
if (pAdapter->AddressLength > 4) {
apr_snprintf(mac, MAC_ADDRESS_SIZE, "%02x:%02x:%02x:%02x:%02x:%02x",
snprintf(mac, MAC_ADDRESS_SIZE, "%02x:%02x:%02x:%02x:%02x:%02x",
(unsigned char)pAdapter->Address[0],
(unsigned char)pAdapter->Address[1],
(unsigned char)pAdapter->Address[2],

View File

@ -13,10 +13,13 @@
*
*/
#ifndef WIN32
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#else
#include <WinSock2.h>
#endif
#include <string>
#include <fstream>

View File

@ -20,10 +20,14 @@
#include <curl/curl.h>
#endif
#ifndef WIN32
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#else
#include <WinSock2.h>
#endif
#include <string>
#include <fstream>
@ -94,6 +98,11 @@ bool HttpsClient::download(const std::string &uri) {
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 1);
#ifdef WIN32
/* use the operating system's native CA store for certificate verification.*/
curl_easy_setopt(curl, CURLOPT_SSL_OPTIONS, (long)CURLSSLOPT_NATIVE_CA);
#endif
/* send all data to this function */
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &HttpsClient::handle);

View File

@ -15,10 +15,14 @@
#include "src/utils/ip_tree.h"
#ifndef WIN32
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#else
#include <WinSock2.h>
#endif
#include <string>
#include <fstream>

View File

@ -15,9 +15,15 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifndef WIN32
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#else
#include "src/compat/msvc.h"
#include <WinSock2.h>
#include <WS2tcpip.h>
#endif
#include "src/utils/msc_tree.h"

View File

@ -15,236 +15,103 @@
#include "src/utils/shared_files.h"
#include <errno.h>
#include <fcntl.h>
#include <pthread.h>
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#ifdef WIN32
#include <windows.h>
#include <io.h>
#endif
#include <utility>
#include <fstream>
#include <string>
namespace modsecurity {
namespace utils {
std::pair<msc_file_handler *, FILE *> SharedFiles::find_handler(
const std::string &fileName) {
for (const auto &i : m_handlers) {
if (i.first == fileName) {
return i.second;
}
}
return std::pair<modsecurity::utils::msc_file_handler *,
FILE *>(NULL, NULL);
}
std::pair<msc_file_handler *, FILE *> SharedFiles::add_new_handler(
SharedFiles::handlers_map::iterator SharedFiles::add_new_handler(
const std::string &fileName, std::string *error) {
int shm_id;
int ret;
key_t mem_key_structure;
msc_file_handler_t *new_debug_log = NULL;
struct shmid_ds shared_mem_info;
FILE *fp;
bool toBeCreated = true;
fp = fopen(fileName.c_str(), "a");
FILE *fp = fopen(fileName.c_str(), "a");
if (fp == 0) {
error->assign("Failed to open file: " + fileName);
goto err_fh;
return m_handlers.end();
}
mem_key_structure = ftok(fileName.c_str(), 1);
if (mem_key_structure < 0) {
error->assign("Failed to select key for the shared memory (1): ");
error->append(strerror(errno));
goto err_mem_key;
}
shm_id = shmget(mem_key_structure, sizeof (msc_file_handler_t) \
+ fileName.size() + 1, IPC_CREAT | IPC_EXCL | 0666);
if (shm_id < 0) {
shm_id = shmget(mem_key_structure, sizeof (msc_file_handler_t)
+ fileName.size() + 1, IPC_CREAT | 0666);
toBeCreated = false;
if (shm_id < 0) {
error->assign("Failed to allocate shared memory (1): ");
error->append(strerror(errno));
goto err_shmget1;
}
}
ret = shmctl(shm_id, IPC_STAT, &shared_mem_info);
if (ret < 0) {
error->assign("Failed to get information on shared memory (1): ");
error->append(strerror(errno));
goto err_shmctl1;
}
new_debug_log = reinterpret_cast<msc_file_handler_t *>(
shmat(shm_id, NULL, 0));
if ((reinterpret_cast<char *>(new_debug_log)[0]) == -1) {
error->assign("Failed to attach shared memory (1): ");
error->append(strerror(errno));
goto err_shmat1;
}
if (toBeCreated == false && shared_mem_info.shm_nattch == 0) {
toBeCreated = true;
}
if (toBeCreated) {
memset(new_debug_log, '\0', sizeof(msc_file_handler_t));
new_debug_log->shm_id_structure = shm_id;
memcpy(new_debug_log->file_name, fileName.c_str(), fileName.size());
new_debug_log->file_name[fileName.size()] = '\0';
}
m_handlers.push_back(std::make_pair(fileName,
std::make_pair(new_debug_log, fp)));
return std::make_pair(new_debug_log, fp);
err_shmat1:
shmdt(new_debug_log);
err_shmctl1:
err_shmget1:
err_mem_key:
fclose(fp);
err_fh:
return std::pair<modsecurity::utils::msc_file_handler *,
FILE *>(NULL, NULL);
return m_handlers.insert({ fileName, {fp, 0} }).first;
}
bool SharedFiles::open(const std::string& fileName, std::string *error) {
std::pair<msc_file_handler *, FILE *> a;
bool ret = true;
#if MODSEC_USE_GENERAL_LOCK
pthread_mutex_lock(m_generalLock);
#endif
a = find_handler(fileName);
if (a.first == NULL) {
a = add_new_handler(fileName, error);
if (error->size() > 0) {
ret = false;
goto out;
}
auto it = m_handlers.find(fileName);
if (it == m_handlers.end()) {
it = add_new_handler(fileName, error);
if (error->size() > 0)
return false;
}
if (a.first == NULL) {
if (it == m_handlers.end()) {
error->assign("Not able to open: " + fileName);
ret = false;
goto out;
return false;
}
out:
#if MODSEC_USE_GENERAL_LOCK
pthread_mutex_unlock(m_generalLock);
#endif
it->second.cnt++;
return ret;
return true;
}
void SharedFiles::close(const std::string& fileName) {
std::pair<msc_file_handler *, FILE *> a;
/* int ret; */
/* int shm_id; */
/* struct shmid_ds shared_mem_info; */
/* int j = 0; */
if (fileName.empty())
return;
#if MODSEC_USE_GENERAL_LOCK
pthread_mutex_lock(m_generalLock);
#endif
auto it = m_handlers.find(fileName);
if (it == m_handlers.end())
return;
if (fileName.empty()) {
goto out;
it->second.cnt--;
if (it->second.cnt == 0)
{
fclose(it->second.fp);
m_handlers.erase(it);
}
a = find_handler(fileName);
if (a.first == NULL || a.second == NULL) {
goto out;
}
/* fclose(a.second); */
a.second = 0;
/*
* Delete the file structure will be welcomed, but we cannot delay
* while the process is being killed.
*
for (std::pair<std::string,
std::pair<msc_file_handler *, FILE *>> i : m_handlers) {
if (i.first == fileName) {
j++;
}
}
m_handlers.erase(m_handlers.begin()+j);
*/
/* hmdt(a.second); */
shmctl(a.first->shm_id_structure, IPC_RMID, NULL);
/*
*
* We could check to see how many process attached to the shared memory
* we have, prior to the deletion of the shared memory.
*
ret = shmctl(a.first->shm_id_structure, IPC_STAT, &shared_mem_info);
if (ret < 0) {
goto out;
}
ret = shared_mem_info.shm_nattch;
shm_id = a.first->shm_id_structure;
*/
out:
#if MODSEC_USE_GENERAL_LOCK
pthread_mutex_unlock(m_generalLock);
#endif
return;
}
bool SharedFiles::write(const std::string& fileName,
const std::string &msg, std::string *error) {
std::pair<msc_file_handler *, FILE *> a;
std::string lmsg = msg;
size_t wrote;
struct flock lock{};
bool ret = true;
a = find_handler(fileName);
if (a.first == NULL) {
auto it = m_handlers.find(fileName);
if (it == m_handlers.end()) {
error->assign("file is not open: " + fileName);
return false;
}
//Exclusively lock whole file
#ifndef WIN32
struct flock lock {};
lock.l_start = lock.l_len = lock.l_whence = 0;
lock.l_type = F_WRLCK;
fcntl(fileno(a.second), F_SETLKW, &lock);
fcntl(fileno(it->second.fp), F_SETLKW, &lock);
#else
auto handle = reinterpret_cast<HANDLE>(_get_osfhandle(fileno(it->second.fp)));
OVERLAPPED overlapped = { 0 };
::LockFileEx(handle, LOCKFILE_EXCLUSIVE_LOCK, 0, MAXDWORD, MAXDWORD, &overlapped);
#endif
wrote = fwrite(lmsg.c_str(), 1, lmsg.size(), a.second);
auto wrote = fwrite(msg.c_str(), 1, msg.size(), it->second.fp);
if (wrote < msg.size()) {
error->assign("failed to write: " + fileName);
ret = false;
}
fflush(a.second);
fflush(it->second.fp);
//Remove exclusive lock
#ifndef WIN32
lock.l_type = F_UNLCK;
fcntl(fileno(a.second), F_SETLKW, &lock);
fcntl(fileno(it->second.fp), F_SETLKW, &lock);
#else
overlapped = { 0 };
::UnlockFileEx(handle, 0, MAXDWORD, MAXDWORD, &overlapped);
#endif
return ret;
}

View File

@ -17,45 +17,18 @@
#define SRC_UTILS_SHARED_FILES_H_
#include <errno.h>
#include <fcntl.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <utility>
#include <vector>
#include <fstream>
#include <unordered_map>
#include <string>
#include "modsecurity/transaction.h"
#include "modsecurity/audit_log.h"
/**
* Not using this critical section yet.
*
*/
/* #define MODSEC_USE_GENERAL_LOCK */
namespace modsecurity {
namespace utils {
typedef struct msc_file_handler {
int shm_id_structure;
char file_name[];
} msc_file_handler_t;
class SharedFiles {
public:
public:
bool open(const std::string& fileName, std::string *error);
void close(const std::string& fileName);
bool write(const std::string& fileName, const std::string &msg,
@ -66,86 +39,28 @@ class SharedFiles {
return instance;
}
protected:
std::pair<msc_file_handler *, FILE *> find_handler(
const std::string &fileName);
std::pair<msc_file_handler *, FILE *> add_new_handler(
const std::string &fileName, std::string *error);
private:
SharedFiles()
#ifdef MODSEC_USE_GENERAL_LOCK
: m_generalLock(NULL),
m_memKeyStructure(0)
#endif
{
#ifdef MODSEC_USE_GENERAL_LOCK
int shm_id;
bool toBeCreated(false);
bool err = false;
m_memKeyStructure = ftok(".", 1); // cppcheck-suppress useInitializationList
if (m_memKeyStructure < 0) {
err = true;
goto err_mem_key;
}
shm_id = shmget(m_memKeyStructure, sizeof(pthread_mutex_t),
IPC_CREAT | IPC_EXCL | 0666);
if (shm_id < 0) {
shm_id = shmget(m_memKeyStructure, sizeof(pthread_mutex_t),
IPC_CREAT | 0666);
toBeCreated = false;
if (shm_id < 0) {
err = true;
goto err_shmget1;
}
}
m_generalLock = reinterpret_cast<pthread_mutex_t *>(
shmat(shm_id, NULL, 0));
if ((reinterpret_cast<char *>(m_generalLock)[0]) == -1) {
err = true;
goto err_shmat1;
}
if (toBeCreated) {
memset(m_generalLock, '\0', sizeof(pthread_mutex_t));
pthread_mutex_init(m_generalLock, NULL);
pthread_mutex_unlock(m_generalLock);
}
if (err) {
err_mem_key:
std::cerr << strerror(errno) << std::endl;
err_shmget1:
std::cerr << "err_shmget1" << std::endl;
err_shmat1:
std::cerr << "err_shmat1" << std::endl;
}
#endif
}
~SharedFiles() {
#if MODSEC_USE_GENERAL_LOCK
shmdt(m_generalLock);
shmctl(m_memKeyStructure, IPC_RMID, NULL);
#endif
}
private:
SharedFiles() = default;
~SharedFiles() = default;
// C++ 03
// ========
// Dont forget to declare these two. You want to make sure they
// are unacceptable otherwise you may accidentally get copies of
// your singleton appearing.
SharedFiles(SharedFiles const&);
void operator=(SharedFiles const&);
SharedFiles(SharedFiles const&) = delete;
void operator=(SharedFiles const&) = delete;
std::vector<std::pair<std::string,
std::pair<msc_file_handler *, FILE *>>> m_handlers;
#if MODSEC_USE_GENERAL_LOCK
pthread_mutex_t *m_generalLock;
key_t m_memKeyStructure;
#endif
struct handler_info {
FILE* fp;
unsigned int cnt;
};
using handlers_map = std::unordered_map<std::string, handler_info>;
handlers_map m_handlers;
handlers_map::iterator add_new_handler(
const std::string &fileName, std::string *error);
};

View File

@ -17,11 +17,6 @@
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#ifdef __OpenBSD__
#include <glob.h>
#else
#include <wordexp.h>
#endif
#include <stdint.h>
#include <inttypes.h>

View File

@ -19,6 +19,9 @@
#include <string.h>
#ifdef __OpenBSD__
#include <glob.h>
#elif defined(WIN32)
#include "Poco/Glob.h"
#include <algorithm>
#else
#include <wordexp.h>
#endif
@ -31,6 +34,7 @@
#include <vector>
#if defined _MSC_VER
#include "src/compat/msvc.h"
#include <direct.h>
#elif defined __GNUC__
#include <sys/types.h>
@ -40,6 +44,36 @@
#include "src/utils/system.h"
#include "src/config.h"
#ifdef WIN32
// Public domain code from mingw-w64's winpthreads
// https://sourceforge.net/p/mingw-w64/code/HEAD/tree/trunk/mingw-w64-libraries/winpthreads/src/clock.c
//
#define CLOCK_PROCESS_CPUTIME_ID 2
#define POW10_7 10000000
// NOTE: includes only CLOCK_PROCESS_CPUTIME_ID implementation, ignores clock_id argument
static int clock_gettime(int clock_id, struct timespec *tp)
{
unsigned __int64 t;
LARGE_INTEGER pf, pc;
union {
unsigned __int64 u64;
FILETIME ft;
} ct, et, kt, ut;
if(0 == GetProcessTimes(GetCurrentProcess(), &ct.ft, &et.ft, &kt.ft, &ut.ft))
return -1;
t = kt.u64 + ut.u64;
tp->tv_sec = t / POW10_7;
tp->tv_nsec = ((int) (t % POW10_7)) * 100;
return 0;
}
#endif
namespace modsecurity {
namespace utils {
@ -64,19 +98,15 @@ double cpu_seconds(void) {
std::string find_resource(const std::string& resource,
const std::string& config, std::string *err) {
std::ifstream *iss;
err->assign("Looking at: ");
// Trying absolute or relative to the current dir.
iss = new std::ifstream(resource, std::ios::in);
if (iss->is_open()) {
iss->close();
delete iss;
auto iss = std::ifstream(resource, std::ios::in);
if (iss.is_open()) {
return resource;
} else {
err->append("'" + resource + "', ");
}
delete iss;
// What about `*' ?
if (utils::expandEnv(resource, 0).size() > 0) {
@ -87,15 +117,12 @@ std::string find_resource(const std::string& resource,
// Trying the same path of the configuration file.
std::string f = get_path(config) + "/" + resource;
iss = new std::ifstream(f, std::ios::in);
if (iss->is_open()) {
iss->close();
delete iss;
iss = std::ifstream(f, std::ios::in);
if (iss.is_open()) {
return f;
} else {
err->append("'" + f + "', ");
}
delete iss;
// What about `*' ?
if (utils::expandEnv(f, 0).size() > 0) {
@ -122,8 +149,16 @@ std::string get_path(const std::string& file) {
std::list<std::string> expandEnv(const std::string& var, int flags) {
std::list<std::string> vars;
#ifdef __OpenBSD__
#ifdef WIN32
// NOTE: align scopes with if & if in other versions
{
{
std::set<std::string> files;
Poco::Glob::glob(var, files);
for(auto file : files) {
std::replace(file.begin(), file.end(), '\\', '/'); // preserve unix-like paths
const char* exp[] = { file.c_str() };
#elif defined(__OpenBSD__)
glob_t p;
if (glob(var.c_str(), flags, NULL, &p) == false) {
if (p.gl_pathc) {
@ -135,15 +170,13 @@ std::list<std::string> expandEnv(const std::string& var, int flags) {
if (p.we_wordc) {
for (char** exp = p.we_wordv; *exp; ++exp) {
#endif
std::ifstream *iss = new std::ifstream(exp[0], std::ios::in);
if (iss->is_open()) {
iss->close();
auto iss = std::ifstream(exp[0], std::ios::in);
if (iss.is_open())
vars.push_back(exp[0]);
}
delete iss;
}
}
#ifdef __OpenBSD__
#ifdef WIN32
#elif defined(__OpenBSD__)
globfree(&p);
#else
wordfree(&p);
@ -153,7 +186,13 @@ std::list<std::string> expandEnv(const std::string& var, int flags) {
}
bool createDir(const std::string& dir, int mode, std::string *error) {
#ifndef WIN32
int ret = mkdir(dir.data(), mode);
#else
if (dir == ".")
return true;
int ret = _mkdir(dir.c_str());
#endif
if (ret != 0 && errno != EEXIST) {
error->assign("Not able to create directory: " + dir + ": " \
+ strerror(errno) + ".");

View File

@ -13,8 +13,6 @@
*
*/
#include <ctime>
#include <iostream>
#include <string>
#include <list>

View File

@ -25,9 +25,15 @@
#include <utility>
#include <map>
#ifdef WIN32
#include "src/compat/msvc.h"
#endif
#include "modsecurity/transaction.h"
#ifndef WIN32
extern char **environ;
#endif
namespace modsecurity {
namespace variables {
@ -47,12 +53,20 @@ void Env::evaluate(Transaction *transaction,
transaction->m_variableEnvs.insert(a);
}
const auto hasName = m_name.length() > 0;
for (auto& x : transaction->m_variableEnvs) {
if (x.first != m_name && m_name.length() > 0) {
#ifndef WIN32
if (hasName && x.first != m_name) {
#else
if (hasName && strcasecmp(x.first.c_str(), m_name.c_str()) != 0) {
#endif
continue;
}
if (!m_keyExclusion.toOmit(x.first)) {
l->push_back(new VariableValue(&m_collectionName, &x.first,
// (Windows) we need to keep the case from the rule in case that from
// the environment differs.
const auto &key = hasName ? m_name : x.first;
if (!m_keyExclusion.toOmit(key)) {
l->push_back(new VariableValue(&m_collectionName, &key,
&x.second));
}
}

View File

@ -30,6 +30,10 @@
#include "modsecurity/transaction.h"
#ifdef WIN32
#include "src/compat/msvc.h"
#endif
namespace modsecurity {
namespace variables {

View File

@ -30,6 +30,10 @@
#include "modsecurity/transaction.h"
#ifdef WIN32
#include "src/compat/msvc.h"
#endif
namespace modsecurity {
namespace variables {

View File

@ -30,6 +30,10 @@
#include "modsecurity/transaction.h"
#ifdef WIN32
#include "src/compat/msvc.h"
#endif
namespace modsecurity {
namespace variables {

View File

@ -30,6 +30,10 @@
#include "modsecurity/transaction.h"
#ifdef WIN32
#include "src/compat/msvc.h"
#endif
namespace modsecurity {
namespace variables {

View File

@ -30,6 +30,10 @@
#include "modsecurity/transaction.h"
#ifdef WIN32
#include "src/compat/msvc.h"
#endif
namespace modsecurity {
namespace variables {

View File

@ -30,6 +30,10 @@
#include "modsecurity/transaction.h"
#ifdef WIN32
#include "src/compat/msvc.h"
#endif
namespace modsecurity {
namespace variables {

View File

@ -30,6 +30,10 @@
#include "modsecurity/transaction.h"
#ifdef WIN32
#include "src/compat/msvc.h"
#endif
namespace modsecurity {
namespace variables {

View File

@ -30,6 +30,10 @@
#include "modsecurity/transaction.h"
#ifdef WIN32
#include "src/compat/msvc.h"
#endif
namespace modsecurity {
namespace variables {

View File

@ -2,7 +2,10 @@
#
#
git clone https://github.com/SpiderLabs/owasp-modsecurity-crs.git owasp-v2
git clone https://github.com/coreruleset/coreruleset.git owasp-v2
cd owasp-v2
git checkout 2.2.9 -b tag2.2.9
cd -
echo 'Include "owasp-v2/base_rules/*.conf"' >> basic_rules.conf
echo 'Include "owasp-v2/optional_rules/*.conf"' >> basic_rules.conf

View File

@ -1,7 +1,7 @@
#!/bin/bash
git clone https://github.com/SpiderLabs/owasp-modsecurity-crs.git owasp-v3
git clone https://github.com/coreruleset/coreruleset.git owasp-v3
cd owasp-v3
git checkout v3.0.2 -b tag3.0.2
cd -

View File

@ -42,9 +42,9 @@ print_usage ()
{
cat <<END
Usage:
test-driver --test-name=NAME --log-file=PATH --trs-file=PATH
[--expect-failure={yes|no}] [--color-tests={yes|no}]
[--enable-hard-errors={yes|no}] [--]
test-driver --test-name NAME --log-file PATH --trs-file PATH
[--expect-failure {yes|no}] [--color-tests {yes|no}]
[--enable-hard-errors {yes|no}] [--]
TEST-SCRIPT [TEST-SCRIPT-ARGUMENTS]
The '--test-name', '--log-file' and '--trs-file' options are mandatory.
END

View File

@ -114,7 +114,11 @@ using namespace modsecurity;
#include <stdio.h>
#include <stdlib.h>
#ifndef WIN32
#include <unistd.h>
#else
#include <io.h>
#endif
#include <signal.h>
#include <string.h>

View File

@ -15,7 +15,11 @@
#include <string.h>
#ifndef WIN32
#include <unistd.h>
#else
#include <io.h>
#endif
#include <ctime>
#include <iostream>
@ -60,13 +64,11 @@ bool contains(const std::string &s, const std::string &pattern) {
void clearAuditLog(const std::string &filename) {
if (!filename.empty()) {
std::ifstream file;
file.open(filename.c_str(), std::ifstream::out | std::ifstream::trunc);
std::ofstream file{filename.c_str(), std::ofstream::out | std::ofstream::trunc};
if (!file.is_open() || file.fail()) {
std::cout << std::endl << "Failed to clear previous contents of audit log: " \
<< filename << std::endl;
}
file.close();
}
}
std::string getAuditLogContent(const std::string &filename) {
@ -506,6 +508,7 @@ int main(int argc, char **argv) {
#ifdef NO_LOGS
std::cout << "Test utility cannot work without logging support." \
<< std::endl;
return 0;
#else
test.cmd_options(argc, argv);
if (!test.m_automake_output && !test.m_count_all) {
@ -605,6 +608,6 @@ int main(int argc, char **argv) {
delete vec;
}
return failed;
#endif
return 0;
}

View File

@ -215,7 +215,6 @@
]
},
"expected":{
// should not match
},
"rules":[
"SecRequestBodyAccess On",
@ -248,7 +247,6 @@
]
},
"expected":{
// should not match
},
"rules":[
"SecRequestBodyAccess On",

255
test/test-suite.in Normal file
View File

@ -0,0 +1,255 @@
# for i in `find test/test-cases -iname *.json`; do echo TESTS+=$i; done
TESTS+=test/test-cases/regression/action-allow.json
TESTS+=test/test-cases/regression/action-block.json
TESTS+=test/test-cases/regression/action-ctl_request_body_access.json
TESTS+=test/test-cases/regression/action-ctl_request_body_processor.json
TESTS+=test/test-cases/regression/action-ctl_request_body_processor_urlencoded.json
TESTS+=test/test-cases/regression/action-ctl_rule_engine.json
TESTS+=test/test-cases/regression/action-ctl_audit_engine.json
TESTS+=test/test-cases/regression/action-ctl_rule_remove_by_id.json
TESTS+=test/test-cases/regression/action-ctl_rule_remove_by_tag.json
TESTS+=test/test-cases/regression/action-ctl_rule_remove_target_by_id.json
TESTS+=test/test-cases/regression/action-ctl_rule_remove_target_by_tag.json
TESTS+=test/test-cases/regression/action-disruptive.json
TESTS+=test/test-cases/regression/action-exec.json
TESTS+=test/test-cases/regression/action-expirevar.json
TESTS+=test/test-cases/regression/action-id.json
TESTS+=test/test-cases/regression/action-initcol.json
TESTS+=test/test-cases/regression/action-msg.json
TESTS+=test/test-cases/regression/action-setenv.json
TESTS+=test/test-cases/regression/action-setrsc.json
TESTS+=test/test-cases/regression/action-setsid.json
TESTS+=test/test-cases/regression/action-setuid.json
TESTS+=test/test-cases/regression/actions.json
TESTS+=test/test-cases/regression/action-skip.json
TESTS+=test/test-cases/regression/action-tag.json
TESTS+=test/test-cases/regression/action-tnf-base64.json
TESTS+=test/test-cases/regression/action-xmlns.json
TESTS+=test/test-cases/regression/auditlog.json
TESTS+=test/test-cases/regression/collection-case-insensitive.json
TESTS+=test/test-cases/regression/collection-lua.json
TESTS+=test/test-cases/regression/collection-regular_expression_selection.json
TESTS+=test/test-cases/regression/collection-resource.json
TESTS+=test/test-cases/regression/collection-tx.json
TESTS+=test/test-cases/regression/collection-tx-with-macro.json
TESTS+=test/test-cases/regression/config-body_limits.json
TESTS+=test/test-cases/regression/config-calling_phases_by_name.json
TESTS+=test/test-cases/regression/config-include-bad.json
TESTS+=test/test-cases/regression/config-include.json
TESTS+=test/test-cases/regression/config-remove_by_id.json
TESTS+=test/test-cases/regression/config-remove_by_msg.json
TESTS+=test/test-cases/regression/config-remove_by_tag.json
TESTS+=test/test-cases/regression/config-response_type.json
TESTS+=test/test-cases/regression/config-secdefaultaction.json
TESTS+=test/test-cases/regression/config-secremoterules.json
TESTS+=test/test-cases/regression/config-update-action-by-id.json
TESTS+=test/test-cases/regression/config-update-target-by-id.json
TESTS+=test/test-cases/regression/config-update-target-by-msg.json
TESTS+=test/test-cases/regression/config-update-target-by-tag.json
TESTS+=test/test-cases/regression/config-xml_external_entity.json
TESTS+=test/test-cases/regression/debug_log.json
TESTS+=test/test-cases/regression/directive-sec_rule_script.json
TESTS+=test/test-cases/regression/issue-1152.json
TESTS+=test/test-cases/regression/issue-1528.json
TESTS+=test/test-cases/regression/issue-1565.json
TESTS+=test/test-cases/regression/issue-1576.json
TESTS+=test/test-cases/regression/issue-1591.json
TESTS+=test/test-cases/regression/issue-1725.json
TESTS+=test/test-cases/regression/issue-1743.json
TESTS+=test/test-cases/regression/issue-1785.json
TESTS+=test/test-cases/regression/issue-1812.json
TESTS+=test/test-cases/regression/issue-1831.json
TESTS+=test/test-cases/regression/issue-1844.json
TESTS+=test/test-cases/regression/issue-1850.json
TESTS+=test/test-cases/regression/issue-1941.json
TESTS+=test/test-cases/regression/issue-1943.json
TESTS+=test/test-cases/regression/issue-1956.json
TESTS+=test/test-cases/regression/issue-1960.json
TESTS+=test/test-cases/regression/issue-2099.json
TESTS+=test/test-cases/regression/issue-2000.json
TESTS+=test/test-cases/regression/issue-2111.json
TESTS+=test/test-cases/regression/issue-2196.json
TESTS+=test/test-cases/regression/issue-2423-msg-in-chain.json
TESTS+=test/test-cases/regression/issue-2427.json
TESTS+=test/test-cases/regression/issue-2296.json
TESTS+=test/test-cases/regression/issue-394.json
TESTS+=test/test-cases/regression/issue-849.json
TESTS+=test/test-cases/regression/issue-960.json
TESTS+=test/test-cases/regression/misc.json
TESTS+=test/test-cases/regression/misc-variable-under-quotes.json
TESTS+=test/test-cases/regression/offset-variable.json
TESTS+=test/test-cases/regression/operator-detectsqli.json
TESTS+=test/test-cases/regression/operator-detectxss.json
TESTS+=test/test-cases/regression/operator-fuzzyhash.json
TESTS+=test/test-cases/regression/operator-inpectFile.json
TESTS+=test/test-cases/regression/operator-ipMatchFromFile.json
TESTS+=test/test-cases/regression/operator-pm.json
TESTS+=test/test-cases/regression/operator-rx.json
TESTS+=test/test-cases/regression/operator-rxGlobal.json
TESTS+=test/test-cases/regression/operator-UnconditionalMatch.json
TESTS+=test/test-cases/regression/operator-validate-byte-range.json
TESTS+=test/test-cases/regression/operator-verifycc.json
TESTS+=test/test-cases/regression/operator-verifycpf.json
TESTS+=test/test-cases/regression/operator-verifyssn.json
TESTS+=test/test-cases/regression/operator-verifysvnr.json
TESTS+=test/test-cases/regression/request-body-parser-json.json
TESTS+=test/test-cases/regression/request-body-parser-multipart-crlf.json
TESTS+=test/test-cases/regression/request-body-parser-multipart.json
TESTS+=test/test-cases/regression/request-body-parser-xml.json
TESTS+=test/test-cases/regression/request-body-parser-xml-validade-dtd.json
TESTS+=test/test-cases/regression/rule-920120.json
TESTS+=test/test-cases/regression/rule-920200.json
TESTS+=test/test-cases/regression/rule-920274.json
TESTS+=test/test-cases/regression/secaction.json
TESTS+=test/test-cases/regression/secargumentslimit.json
TESTS+=test/test-cases/regression/sec_component_signature.json
TESTS+=test/test-cases/regression/secmarker.json
TESTS+=test/test-cases/regression/secruleengine.json
TESTS+=test/test-cases/regression/transformation-none.json
TESTS+=test/test-cases/regression/transformations.json
TESTS+=test/test-cases/regression/variable-ARGS_COMBINED_SIZE.json
TESTS+=test/test-cases/regression/variable-ARGS_GET.json
TESTS+=test/test-cases/regression/variable-ARGS_GET_NAMES.json
TESTS+=test/test-cases/regression/variable-ARGS.json
TESTS+=test/test-cases/regression/variable-ARGS_NAMES.json
TESTS+=test/test-cases/regression/variable-ARGS_POST.json
TESTS+=test/test-cases/regression/variable-ARGS_POST_NAMES.json
TESTS+=test/test-cases/regression/variable-AUTH_TYPE.json
TESTS+=test/test-cases/regression/variable-DURATION.json
TESTS+=test/test-cases/regression/variable-ENV.json
TESTS+=test/test-cases/regression/variable-FILES_COMBINED_SIZE.json
TESTS+=test/test-cases/regression/variable-FILES.json
TESTS+=test/test-cases/regression/variable-FILES_NAMES.json
TESTS+=test/test-cases/regression/variable-FILES_SIZES.json
TESTS+=test/test-cases/regression/variable-FULL_REQUEST.json
TESTS+=test/test-cases/regression/variable-FULL_REQUEST_LENGTH.json
TESTS+=test/test-cases/regression/variable-GEO.json
TESTS+=test/test-cases/regression/variable-HIGHEST_SEVERITY.json
TESTS+=test/test-cases/regression/variable-INBOUND_DATA_ERROR.json
TESTS+=test/test-cases/regression/variable-MATCHED_VAR.json
TESTS+=test/test-cases/regression/variable-MATCHED_VAR_NAME.json
TESTS+=test/test-cases/regression/variable-MATCHED_VARS.json
TESTS+=test/test-cases/regression/variable-MATCHED_VARS_NAMES.json
TESTS+=test/test-cases/regression/variable-MODSEC_BUILD.json
TESTS+=test/test-cases/regression/variable-MULTIPART_CRLF_LF_LINES.json
TESTS+=test/test-cases/regression/variable-MULTIPART_FILENAME.json
TESTS+=test/test-cases/regression/variable-MULTIPART_INVALID_HEADER_FOLDING.json
TESTS+=test/test-cases/regression/variable-MULTIPART_NAME.json
TESTS+=test/test-cases/regression/variable-MULTIPART_PART_HEADERS.json
TESTS+=test/test-cases/regression/variable-MULTIPART_STRICT_ERROR.json
TESTS+=test/test-cases/regression/variable-MULTIPART_UNMATCHED_BOUNDARY.json
TESTS+=test/test-cases/regression/variable-OUTBOUND_DATA_ERROR.json
TESTS+=test/test-cases/regression/variable-PATH_INFO.json
TESTS+=test/test-cases/regression/variable-QUERY_STRING.json
TESTS+=test/test-cases/regression/variable-REMOTE_ADDR.json
TESTS+=test/test-cases/regression/variable-REMOTE_HOST.json
TESTS+=test/test-cases/regression/variable-REMOTE_PORT.json
TESTS+=test/test-cases/regression/variable-REMOTE_USER.json
TESTS+=test/test-cases/regression/variable-REQBODY_PROCESSOR_ERROR.json
TESTS+=test/test-cases/regression/variable-REQBODY_PROCESSOR.json
TESTS+=test/test-cases/regression/variable-REQUEST_BASENAME.json
TESTS+=test/test-cases/regression/variable-REQUEST_BODY.json
TESTS+=test/test-cases/regression/variable-REQUEST_BODY_LENGTH.json
TESTS+=test/test-cases/regression/variable-REQUEST_COOKIES.json
TESTS+=test/test-cases/regression/variable-REQUEST_COOKIES_NAMES.json
TESTS+=test/test-cases/regression/variable-REQUEST_FILENAME.json
TESTS+=test/test-cases/regression/variable-REQUEST_HEADERS.json
TESTS+=test/test-cases/regression/variable-REQUEST_HEADERS_NAMES.json
TESTS+=test/test-cases/regression/variable-REQUEST_LINE.json
TESTS+=test/test-cases/regression/variable-REQUEST_METHOD.json
TESTS+=test/test-cases/regression/variable-REQUEST_PROTOCOL.json
TESTS+=test/test-cases/regression/variable-REQUEST_URI.json
TESTS+=test/test-cases/regression/variable-REQUEST_URI_RAW.json
TESTS+=test/test-cases/regression/variable-RESPONSE_BODY.json
TESTS+=test/test-cases/regression/variable-RESPONSE_CONTENT_LENGTH.json
TESTS+=test/test-cases/regression/variable-RESPONSE_CONTENT_TYPE.json
TESTS+=test/test-cases/regression/variable-RESPONSE_HEADERS.json
TESTS+=test/test-cases/regression/variable-RESPONSE_HEADERS_NAMES.json
TESTS+=test/test-cases/regression/variable-RESPONSE_PROTOCOL.json
TESTS+=test/test-cases/regression/variable-RULE.json
TESTS+=test/test-cases/regression/variable-SERVER_ADDR.json
TESTS+=test/test-cases/regression/variable-SERVER_NAME.json
TESTS+=test/test-cases/regression/variable-SERVER_PORT.json
TESTS+=test/test-cases/regression/variable-SESSIONID.json
TESTS+=test/test-cases/regression/variable-STATUS.json
TESTS+=test/test-cases/regression/variable-TIME_DAY.json
TESTS+=test/test-cases/regression/variable-TIME_EPOCH.json
TESTS+=test/test-cases/regression/variable-TIME_HOUR.json
TESTS+=test/test-cases/regression/variable-TIME.json
TESTS+=test/test-cases/regression/variable-TIME_MIN.json
TESTS+=test/test-cases/regression/variable-TIME_MON.json
TESTS+=test/test-cases/regression/variable-TIME_SEC.json
TESTS+=test/test-cases/regression/variable-TIME_WDAY.json
TESTS+=test/test-cases/regression/variable-TIME_YEAR.json
TESTS+=test/test-cases/regression/variable-TX.json
TESTS+=test/test-cases/regression/variable-UNIQUE_ID.json
TESTS+=test/test-cases/regression/variable-URLENCODED_ERROR.json
TESTS+=test/test-cases/regression/variable-USERID.json
TESTS+=test/test-cases/regression/variable-variation-count.json
TESTS+=test/test-cases/regression/variable-variation-exclusion.json
TESTS+=test/test-cases/regression/variable-WEBAPPID.json
TESTS+=test/test-cases/regression/variable-WEBSERVER_ERROR_LOG.json
TESTS+=test/test-cases/regression/variable-XML.json
TESTS+=test/test-cases/secrules-language-tests/operators/beginsWith.json
TESTS+=test/test-cases/secrules-language-tests/operators/contains.json
TESTS+=test/test-cases/secrules-language-tests/operators/containsWord.json
TESTS+=test/test-cases/secrules-language-tests/operators/detectSQLi.json
TESTS+=test/test-cases/secrules-language-tests/operators/detectXSS.json
TESTS+=test/test-cases/secrules-language-tests/operators/endsWith.json
TESTS+=test/test-cases/secrules-language-tests/operators/eq.json
TESTS+=test/test-cases/secrules-language-tests/operators/ge.json
TESTS+=test/test-cases/secrules-language-tests/operators/geoLookup.json
TESTS+=test/test-cases/secrules-language-tests/operators/gt.json
TESTS+=test/test-cases/secrules-language-tests/operators/ipMatch.json
TESTS+=test/test-cases/secrules-language-tests/operators/le.json
TESTS+=test/test-cases/secrules-language-tests/operators/lt.json
TESTS+=test/test-cases/secrules-language-tests/operators/noMatch.json
TESTS+=test/test-cases/secrules-language-tests/operators/pmFromFile.json
TESTS+=test/test-cases/secrules-language-tests/operators/pm.json
TESTS+=test/test-cases/secrules-language-tests/operators/rx.json
TESTS+=test/test-cases/secrules-language-tests/operators/rxGlobal.json
TESTS+=test/test-cases/secrules-language-tests/operators/streq.json
TESTS+=test/test-cases/secrules-language-tests/operators/strmatch.json
TESTS+=test/test-cases/secrules-language-tests/operators/unconditionalMatch.json
TESTS+=test/test-cases/secrules-language-tests/operators/validateByteRange.json
TESTS+=test/test-cases/secrules-language-tests/operators/validateUrlEncoding.json
TESTS+=test/test-cases/secrules-language-tests/operators/validateUtf8Encoding.json
TESTS+=test/test-cases/secrules-language-tests/operators/verifyCC.json
TESTS+=test/test-cases/secrules-language-tests/operators/verifycpf.json
TESTS+=test/test-cases/secrules-language-tests/operators/verifyssn.json
TESTS+=test/test-cases/secrules-language-tests/operators/verifysvnr.json
TESTS+=test/test-cases/secrules-language-tests/operators/within.json
TESTS+=test/test-cases/secrules-language-tests/transformations/base64DecodeExt.json
TESTS+=test/test-cases/secrules-language-tests/transformations/base64Decode.json
TESTS+=test/test-cases/secrules-language-tests/transformations/base64Encode.json
TESTS+=test/test-cases/secrules-language-tests/transformations/cmdLine.json
TESTS+=test/test-cases/secrules-language-tests/transformations/compressWhitespace.json
TESTS+=test/test-cases/secrules-language-tests/transformations/cssDecode.json
TESTS+=test/test-cases/secrules-language-tests/transformations/escapeSeqDecode.json
TESTS+=test/test-cases/secrules-language-tests/transformations/hexDecode.json
TESTS+=test/test-cases/secrules-language-tests/transformations/hexEncode.json
TESTS+=test/test-cases/secrules-language-tests/transformations/htmlEntityDecode.json
TESTS+=test/test-cases/secrules-language-tests/transformations/jsDecode.json
TESTS+=test/test-cases/secrules-language-tests/transformations/length.json
TESTS+=test/test-cases/secrules-language-tests/transformations/lowercase.json
TESTS+=test/test-cases/secrules-language-tests/transformations/md5.json
TESTS+=test/test-cases/secrules-language-tests/transformations/normalisePath.json
TESTS+=test/test-cases/secrules-language-tests/transformations/normalisePathWin.json
TESTS+=test/test-cases/secrules-language-tests/transformations/parityEven7bit.json
TESTS+=test/test-cases/secrules-language-tests/transformations/parityOdd7bit.json
TESTS+=test/test-cases/secrules-language-tests/transformations/parityZero7bit.json
TESTS+=test/test-cases/secrules-language-tests/transformations/removeCommentsChar.json
TESTS+=test/test-cases/secrules-language-tests/transformations/removeComments.json
TESTS+=test/test-cases/secrules-language-tests/transformations/removeNulls.json
TESTS+=test/test-cases/secrules-language-tests/transformations/removeWhitespace.json
TESTS+=test/test-cases/secrules-language-tests/transformations/replaceComments.json
TESTS+=test/test-cases/secrules-language-tests/transformations/replaceNulls.json
TESTS+=test/test-cases/secrules-language-tests/transformations/sha1.json
TESTS+=test/test-cases/secrules-language-tests/transformations/sqlHexDecode.json
TESTS+=test/test-cases/secrules-language-tests/transformations/trim.json
TESTS+=test/test-cases/secrules-language-tests/transformations/trimLeft.json
TESTS+=test/test-cases/secrules-language-tests/transformations/trimRight.json
TESTS+=test/test-cases/secrules-language-tests/transformations/urlDecode.json
TESTS+=test/test-cases/secrules-language-tests/transformations/urlDecodeUni.json
TESTS+=test/test-cases/secrules-language-tests/transformations/urlEncode.json
TESTS+=test/test-cases/secrules-language-tests/transformations/utf8toUnicode.json

View File

@ -13,7 +13,7 @@ then
AMOUNT=$(./regression_tests countall ../$FILE)
RET=$?
if [ $RET -ne 0 ]; then
echo ":test-result: SKIP: json is not enabled. (regression/$RET) ../$FILE:$i"
echo ":test-result: SKIP: json is not enabled. (regression/$RET) ../$FILE"
exit 0
fi
@ -30,10 +30,10 @@ else
RET=$?
if [ $RET -eq 127 ]
then
echo ":test-result: SKIP: json is not enabled. (unit/$RET) ../$FILE:$i"
echo ":test-result: SKIP: json is not enabled. (unit/$RET) ../$FILE"
elif [ $RET -ne 0 ]
then
echo ":test-result: FAIL possible segfault: (unit/$RET) ../$FILE:$i"
echo ":test-result: FAIL possible segfault: (unit/$RET) ../$FILE"
fi
fi

View File

@ -195,6 +195,10 @@ int main(int argc, char **argv) {
std::cout << t->print() << std::endl;
}
const int skp = std::count_if(results.cbegin(), results.cend(), [](const auto &i)
{ return i->skipped; });
const int failed = results.size() - skp;
if (!test.m_automake_output) {
std::cout << std::endl;
@ -202,13 +206,7 @@ int main(int argc, char **argv) {
if (results.size() == 0) {
std::cout << KGRN << "All tests passed" << RESET << std::endl;
} else {
int skp = 0;
for (const auto &i : results) {
if (i->skipped == true) {
skp++;
}
}
std::cout << KRED << results.size()-skp << " failed.";
std::cout << KRED << failed << " failed.";
std::cout << RESET << std::endl;
if (skp > 0) {
std::cout << " " << std::to_string(skp) << " ";
@ -217,13 +215,12 @@ int main(int argc, char **argv) {
}
}
for (std::pair<std::string, std::vector<UnitTest *> *> a : test) {
std::vector<UnitTest *> *vec = a.second;
for (int i = 0; i < vec->size(); i++) {
delete vec->at(i);
}
for (auto a : test) {
auto *vec = a.second;
for(auto *t : *vec)
delete t;
delete vec;
}
return failed;
}

View File

@ -15,7 +15,11 @@
#include <string.h>
#include <sys/stat.h>
#ifndef WIN32
#include <unistd.h>
#else
#include <io.h>
#endif
#include <ctime>
#include <iostream>

28
vcbuild.bat Normal file
View File

@ -0,0 +1,28 @@
@rem For Windows build information, see build\win32\README.md
@echo off
pushd %CD%
if not "%1"=="" (set build_type=%1) else (set build_type=Release)
echo Build type: %build_type%
if not "%2"=="" (set arch=%2) else (set arch=x86_64)
echo Arch: %arch%
if "%3"=="USE_ASAN" (
echo Address Sanitizer: Enabled
set CI_ASAN=-c tools.build:cxxflags="[""/fsanitize=address""]"
set ASAN_FLAG=ON
) else (
echo Address Sanitizer: Disabled
set CI_ASAN=
set ASAN_FLAG=OFF
)
cd build\win32
conan install . -s compiler.cppstd=17 %CI_ASAN% --output-folder=build --build=missing --settings=build_type=%build_type% --settings=arch=%arch%
cd build
cmake --fresh .. -G "Visual Studio 17 2022" -DCMAKE_TOOLCHAIN_FILE=conan_toolchain.cmake -DUSE_ASAN=%ASAN_FLAG% %4 %5 %6 %7 %8 %9
cmake --build . --config %build_type%
popd