Skip to content

Commit 71a786b

Browse files
authored
Merge pull request #3132 from eduar-hte/windows-port
Add support to build libModSecurity v3 on Windows
2 parents c805648 + 1b2de5a commit 71a786b

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

64 files changed

+1333
-662
lines changed

.github/workflows/ci.yml

+52
Original file line numberDiff line numberDiff line change
@@ -72,3 +72,55 @@ jobs:
7272
run: make -j `sysctl -n hw.logicalcpu`
7373
- name: check
7474
run: make check
75+
76+
build-windows:
77+
runs-on: ${{ matrix.os }}
78+
strategy:
79+
matrix:
80+
os: [windows-2022]
81+
platform: [x86_64]
82+
configuration: [Release]
83+
configure:
84+
- {label: "full", opt: "" }
85+
- {label: "wo lmdb", opt: "-DWITHOUT_LMDB=ON" }
86+
- {label: "wo lua", opt: "-DWITHOUT_LUA=ON" }
87+
- {label: "wo maxmind", opt: "-DWITHOUT_MAXMIND=ON" }
88+
- {label: "wo curl", opt: "-DWITHOUT_CURL=ON" }
89+
steps:
90+
- uses: actions/checkout@v4
91+
with:
92+
submodules: true
93+
- name: Install Conan
94+
run: |
95+
pip3 install conan --upgrade
96+
conan profile detect
97+
- uses: ammaraskar/msvc-problem-matcher@master
98+
- name: Build ${{ matrix.configuration }} ${{ matrix.platform }} ${{ matrix.configure.label }}
99+
shell: cmd
100+
run: vcbuild.bat ${{ matrix.configuration }} ${{ matrix.platform }} NO_ASAN "${{ matrix.configure.opt }}"
101+
- name: Set up test environment
102+
working-directory: build\win32\build\${{ matrix.configuration }}
103+
env:
104+
BASE_DIR: ..\..\..\..
105+
shell: cmd
106+
run: |
107+
copy unit_tests.exe %BASE_DIR%\test
108+
copy regression_tests.exe %BASE_DIR%\test
109+
copy libModSecurity.dll %BASE_DIR%\test
110+
copy %BASE_DIR%\unicode.mapping %BASE_DIR%\test
111+
md \tmp
112+
md \bin
113+
copy "C:\Program Files\Git\usr\bin\echo.exe" \bin
114+
copy "C:\Program Files\Git\usr\bin\echo.exe" \bin\echo
115+
- name: Disable tests that don't work on Windows
116+
working-directory: test\test-cases\regression
117+
shell: cmd
118+
run: |
119+
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
120+
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
121+
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
122+
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
123+
- name: Run tests
124+
working-directory: build\win32\build
125+
run: |
126+
ctest -C ${{ matrix.configuration }} --output-on-failure

Makefile.am

+1-256
Large diffs are not rendered by default.

build/win32/CMakeLists.txt

+244
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,244 @@
1+
cmake_minimum_required(VERSION 3.24)
2+
3+
set(BASE_DIR ${CMAKE_CURRENT_LIST_DIR}/../..)
4+
5+
option(WITHOUT_LMDB "Include LMDB support" OFF)
6+
option(WITHOUT_LUA "Include LUA support" OFF)
7+
option(WITHOUT_LIBXML2 "Include LibXML2 support" OFF)
8+
option(WITHOUT_MAXMIND "Include MaxMind support" OFF)
9+
option(WITHOUT_CURL "Include CURL support" OFF)
10+
11+
option(USE_ASAN "Build with Address Sanitizer" OFF)
12+
13+
# common compiler settings
14+
15+
# NOTE: MBEDTLS_CONFIG_FILE is not only required to compile the mbedtls subset in others, but also
16+
# when their headers are included while compiling libModSecurity
17+
add_compile_definitions(WIN32 _CRT_SECURE_NO_WARNINGS MBEDTLS_CONFIG_FILE="mbed-tls-config.h")
18+
19+
# set standards conformance preprocessor & compiler to align with cross-compiled codebase
20+
# NOTE: otherwise visual c++'s default compiler/preprocessor behaviour generates C4067 warnings
21+
# (unexpected tokens following preprocessor directive - expected a newline)
22+
add_compile_options(/Zc:preprocessor /permissive-)
23+
24+
if(USE_ASAN)
25+
add_compile_options(/fsanitize=address)
26+
add_link_options(/INFERASANLIBS /INCREMENTAL:no)
27+
endif()
28+
29+
# libinjection
30+
31+
project(libinjection C)
32+
33+
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)
34+
35+
# mbedtls
36+
37+
project(mbedtls C)
38+
39+
add_library(mbedtls STATIC ${BASE_DIR}/others/mbedtls/base64.c ${BASE_DIR}/others/mbedtls/sha1.c ${BASE_DIR}/others/mbedtls/md5.c)
40+
41+
target_include_directories(mbedtls PRIVATE ${BASE_DIR}/others)
42+
43+
#
44+
# libModSecurity
45+
#
46+
47+
project(libModSecurity
48+
VERSION
49+
3.0.12
50+
LANGUAGES
51+
CXX
52+
)
53+
54+
set(CMAKE_CXX_STANDARD 17)
55+
set(CMAKE_CXX_STANDARD_REQUIRED On)
56+
set(CMAKE_CXX_EXTENSIONS Off)
57+
58+
set(PACKAGE_BUGREPORT "[email protected]")
59+
set(PACKAGE_NAME "modsecurity")
60+
set(PACKAGE_VERSION "${PROJECT_VERSION}")
61+
set(PACKAGE_STRING "${PACKAGE_NAME} ${PACKAGE_VERSION}")
62+
set(PACKAGE_TARNAME "${PACKAGE_NAME}")
63+
64+
set(HAVE_YAJL 1) # should always be one, mandatory dependency
65+
set(HAVE_GEOIP 0) # should always be zero, no conan package available
66+
set(HAVE_SSDEEP 0) # should always be zero, no conan package available
67+
68+
macro(enable_feature flag option)
69+
if(${option})
70+
set(${flag} 0)
71+
else()
72+
set(${flag} 1)
73+
endif()
74+
endmacro()
75+
76+
enable_feature(HAVE_LMDB ${WITHOUT_LMDB})
77+
enable_feature(HAVE_LUA ${WITHOUT_LUA})
78+
enable_feature(HAVE_LIBXML2 ${WITHOUT_LIBXML2})
79+
enable_feature(HAVE_MAXMIND ${WITHOUT_MAXMIND})
80+
enable_feature(HAVE_CURL ${WITHOUT_CURL})
81+
82+
include(${CMAKE_CURRENT_LIST_DIR}/ConfigureChecks.cmake)
83+
84+
configure_file(config.h.cmake ${BASE_DIR}/src/config.h)
85+
86+
find_package(PCRE2 REQUIRED)
87+
find_package(PThreads4W REQUIRED)
88+
find_package(Poco REQUIRED)
89+
find_package(dirent REQUIRED) # used only by tests (check dirent::dirent refernces)
90+
91+
macro(include_package package flag)
92+
if(${flag})
93+
find_package(${package} REQUIRED)
94+
endif()
95+
endmacro()
96+
97+
include_package(yajl HAVE_YAJL)
98+
include_package(libxml2 HAVE_LIBXML2)
99+
include_package(lua HAVE_LUA)
100+
include_package(CURL HAVE_CURL)
101+
include_package(lmdb HAVE_LMDB)
102+
include_package(maxminddb HAVE_MAXMIND)
103+
104+
# library
105+
#
106+
107+
# NOTE: required to generate libModSecurity's import library (libModSecurity.lib), used by tests to link with shared library
108+
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
109+
110+
file(GLOB_RECURSE libModSecuritySources ${BASE_DIR}/src/*.cc)
111+
112+
add_library(libModSecurity SHARED ${libModSecuritySources})
113+
114+
target_compile_definitions(libModSecurity PRIVATE WITH_PCRE2)
115+
target_include_directories(libModSecurity PRIVATE ${BASE_DIR} ${BASE_DIR}/headers ${BASE_DIR}/others)
116+
target_link_libraries(libModSecurity PRIVATE pcre2::pcre2 pthreads4w::pthreads4w libinjection mbedtls Poco::Poco Iphlpapi.lib)
117+
118+
macro(add_package_dependency project compile_definition link_library flag)
119+
if(${flag})
120+
target_compile_definitions(${project} PRIVATE ${compile_definition})
121+
target_link_libraries(${project} PRIVATE ${link_library})
122+
endif()
123+
endmacro()
124+
125+
add_package_dependency(libModSecurity WITH_YAJL yajl::yajl HAVE_YAJL)
126+
add_package_dependency(libModSecurity WITH_LIBXML2 LibXml2::LibXml2 HAVE_LIBXML2)
127+
add_package_dependency(libModSecurity WITH_LUA lua::lua HAVE_LUA)
128+
if(HAVE_LUA)
129+
target_compile_definitions(libModSecurity PRIVATE WITH_LUA_5_4)
130+
endif()
131+
add_package_dependency(libModSecurity MSC_WITH_CURL CURL::libcurl HAVE_CURL)
132+
add_package_dependency(libModSecurity WITH_LMDB lmdb::lmdb HAVE_LMDB)
133+
add_package_dependency(libModSecurity WITH_MAXMIND maxminddb::maxminddb HAVE_MAXMIND)
134+
135+
# tests
136+
#
137+
138+
project(libModSecurityTests)
139+
140+
function(setTestTargetProperties executable)
141+
target_compile_definitions(${executable} PRIVATE WITH_PCRE2)
142+
target_include_directories(${executable} PRIVATE ${BASE_DIR} ${BASE_DIR}/headers)
143+
target_link_libraries(${executable} PRIVATE libModSecurity pcre2::pcre2 dirent::dirent)
144+
add_package_dependency(${executable} WITH_YAJL yajl::yajl HAVE_YAJL)
145+
endfunction()
146+
147+
# unit tests
148+
file(GLOB unitTestSources ${BASE_DIR}/test/unit/*.cc)
149+
add_executable(unit_tests ${unitTestSources})
150+
setTestTargetProperties(unit_tests)
151+
target_compile_options(unit_tests PRIVATE /wd4805)
152+
153+
# regression tests
154+
file(GLOB regressionTestsSources ${BASE_DIR}/test/regression/*.cc)
155+
add_executable(regression_tests ${regressionTestsSources})
156+
setTestTargetProperties(regression_tests)
157+
158+
macro(add_regression_test_capability compile_definition flag)
159+
if(${flag})
160+
target_compile_definitions(regression_tests PRIVATE ${compile_definition})
161+
endif()
162+
endmacro()
163+
164+
add_regression_test_capability(WITH_LUA HAVE_LUA)
165+
add_regression_test_capability(WITH_CURL HAVE_CURL)
166+
add_regression_test_capability(WITH_LMDB HAVE_LMDB)
167+
add_regression_test_capability(WITH_MAXMIND HAVE_MAXMIND)
168+
169+
enable_testing()
170+
171+
file(READ ${BASE_DIR}/test/test-suite.in TEST_FILES_RAW)
172+
string(REPLACE "\n" ";" TEST_FILES ${TEST_FILES_RAW})
173+
174+
foreach(TEST_FILE ${TEST_FILES})
175+
# ignore comment lines
176+
string(FIND ${TEST_FILE} "#" is_comment)
177+
if(NOT is_comment EQUAL 0)
178+
string(FIND ${TEST_FILE} "TESTS+=" is_valid_prefix)
179+
if(NOT is_valid_prefix EQUAL 0)
180+
message(FATAL_ERROR "Invalid prefix in line: ${TEST_FILE}")
181+
endif()
182+
183+
# remove 'TESTS+=' prefix and 'test/' too because tests are launched
184+
# from that directory
185+
string(SUBSTRING ${TEST_FILE} 12 -1 TEST_FILE)
186+
187+
# test name
188+
get_filename_component(TEST_NAME ${TEST_FILE} NAME_WE)
189+
190+
# determine test runner based on test path prefix
191+
string(FIND ${TEST_FILE} "test-cases/regression/" is_regression_test)
192+
if(is_regression_test EQUAL 0)
193+
set(TEST_RUNNER "regression_tests")
194+
else()
195+
set(TEST_RUNNER "unit_tests")
196+
endif()
197+
198+
add_test(NAME ${TEST_NAME} COMMAND ${TEST_RUNNER} ${TEST_FILE} WORKING_DIRECTORY ${BASE_DIR}/test)
199+
endif()
200+
endforeach()
201+
202+
# benchmark
203+
add_executable(benchmark ${BASE_DIR}/test/benchmark/benchmark.cc)
204+
setTestTargetProperties(benchmark)
205+
206+
# rules_optimization
207+
add_executable(rules_optimization ${BASE_DIR}/test/optimization/optimization.cc)
208+
setTestTargetProperties(rules_optimization)
209+
210+
211+
# examples
212+
#
213+
214+
project(libModSecurityExamples)
215+
216+
function(setExampleTargetProperties executable)
217+
target_include_directories(${executable} PRIVATE ${BASE_DIR} ${BASE_DIR}/headers)
218+
target_link_libraries(${executable} PRIVATE libModSecurity)
219+
endfunction()
220+
221+
# simple_example_using_c
222+
add_executable(simple_example_using_c ${BASE_DIR}/examples/simple_example_using_c/test.c)
223+
setExampleTargetProperties(simple_example_using_c)
224+
225+
# using_bodies_in_chunks
226+
add_executable(using_bodies_in_chunks ${BASE_DIR}/examples/using_bodies_in_chunks/simple_request.cc)
227+
setExampleTargetProperties(using_bodies_in_chunks)
228+
229+
# reading_logs_via_rule_message
230+
add_executable(reading_logs_via_rule_message ${BASE_DIR}/examples/reading_logs_via_rule_message/simple_request.cc)
231+
setExampleTargetProperties(reading_logs_via_rule_message)
232+
target_link_libraries(reading_logs_via_rule_message PRIVATE libModSecurity pthreads4w::pthreads4w)
233+
234+
# reading_logs_with_offset
235+
add_executable(reading_logs_with_offset ${BASE_DIR}/examples/reading_logs_with_offset/read.cc)
236+
setExampleTargetProperties(reading_logs_with_offset)
237+
238+
# tools
239+
#
240+
241+
# rules_check
242+
add_executable(rules_check ${BASE_DIR}/tools/rules-check/rules-check.cc)
243+
target_include_directories(rules_check PRIVATE ${BASE_DIR} ${BASE_DIR}/headers)
244+
target_link_libraries(rules_check PRIVATE libModSecurity)

build/win32/ConfigureChecks.cmake

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
include(CheckIncludeFile)
2+
include(CheckIncludeFiles)
3+
4+
check_include_file("dlfcn.h" HAVE_DLFCN_H)
5+
check_include_file("inttypes.h" HAVE_INTTYPES_H)
6+
check_include_file("stdint.h" HAVE_STDINT_H)
7+
check_include_file("stdio.h" HAVE_STDIO_H)
8+
check_include_file("stdlib.h" HAVE_STDLIB_H)
9+
check_include_file("string" HAVE_STRING)
10+
check_include_file("strings.h" HAVE_STRINGS_H)
11+
check_include_file("string.h" HAVE_STRING_H)
12+
check_include_file("sys/stat.h" HAVE_SYS_STAT_H)
13+
check_include_file("sys/types.h" HAVE_SYS_TYPES_H)
14+
check_include_file("sys/utsname.h" HAVE_SYS_UTSNAME_H)
15+
check_include_file("unistd.h" HAVE_UNISTD_H)
16+
17+
#/* Define to 1 if you have the ANSI C header files. */
18+
check_include_files("stdlib.h;stdarg.h;string.h;float.h" STDC_HEADERS)

0 commit comments

Comments
 (0)