Revert "Add other projects to submodules"

This reverts commit 68bea47edd.
This commit is contained in:
Théophile Diot 2023-06-28 10:09:51 -04:00
parent d9a98c6fa9
commit e2f1aba3cc
No known key found for this signature in database
GPG Key ID: E752C80DB72BB014
2699 changed files with 818161 additions and 71 deletions

58
.gitmodules vendored
View File

@ -1,15 +1,11 @@
[submodule "nginx"]
path = src/deps/src/nginx
url = https://github.com/nginx/nginx.git
# TODO add nginx ?
# TODO add Lua ?
[submodule "LuaJIT"]
path = src/deps/src/luajit2
url = https://github.com/openresty/luajit2.git
[submodule "zlib"]
path = src/deps/src/zlib
url = https://github.com/madler/zlib.git
[submodule "lua-nginx-module"]
path = src/deps/src/lua-nginx-module
url = https://github.com/openresty/lua-nginx-module.git
@ -18,18 +14,6 @@
path = src/deps/src/lua-resty-core
url = https://github.com/openresty/lua-resty-core.git
[submodule "ModSecurity"]
path = src/deps/src/ModSecurity
url = https://github.com/SpiderLabs/ModSecurity.git
[submodule "libinjection"]
path = src/deps/src/libinjection
url = https://github.com/libinjection/libinjection.git
[submodule "ModSecurity-nginx"]
path = src/deps/src/ModSecurity-nginx
url = https://github.com/SpiderLabs/ModSecurity-nginx.git
[submodule "lua-resty-lrucache"]
path = src/deps/src/lua-resty-lrucache
url = https://github.com/openresty/lua-resty-lrucache.git
@ -74,9 +58,7 @@
path = src/deps/src/luasec
url = https://github.com/brunoos/luasec.git
[submodule "lua-resty-ipmatcher"]
path = src/deps/src/lua-resty-ipmatcher
url = https://github.com/api7/lua-resty-ipmatcher.git
# TODO add lua-resty-ipmatcher
[submodule "lua-resty-redis"]
path = src/deps/src/lua-resty-redis
@ -86,9 +68,7 @@
path = src/deps/src/lua-resty-upload
url = https://github.com/openresty/lua-resty-upload.git
[submodule "luajit-geoip"]
path = src/deps/src/luajit-geoip
url = https://github.com/leafo/luajit-geoip.git
# TODO add luajit-geoip
[submodule "lbase64"]
path = src/deps/src/lbase64
@ -110,26 +90,26 @@
path = src/deps/src/lua-resty-lock
url = https://github.com/openresty/lua-resty-lock.git
[submodule "lua-pack"]
path = src/deps/src/lua-pack
url = https://github.com/kong/lua-pack.git
# TODO add lua-pack
[submodule "lua-resty-openssl"]
path = src/deps/src/lua-resty-openssl
url = https://github.com/fffonion/lua-resty-openssl.git
# TODO add lua-resty-openssl
[submodule "lua-ffi-zlib"]
path = src/deps/src/lua-ffi-zlib
url = https://github.com/hamishforbes/lua-ffi-zlib.git
# TODO add lua-ffi-zlib
[submodule "lua-resty-signal"]
path = src/deps/src/lua-resty-signal
url = https://github.com/openresty/lua-resty-signal.git
# TODO add lua-resty-signal
# TODO add libinjection
# TODO add ModSecurity-nginx
[submodule "libmaxminddb"]
path = src/deps/src/libmaxminddb
url = https://github.com/maxmind/libmaxminddb.git
[submodule "zlib"]
path = src/deps/src/zlib
url = https://github.com/madler/zlib.git
[submodule "headers-more-nginx-module"]
path = src/deps/src/headers-more-nginx-module
url = https://github.com/openresty/headers-more-nginx-module.git
@ -149,3 +129,7 @@
[submodule "stream-lua-nginx-module"]
path = src/deps/src/stream-lua-nginx-module
url = https://github.com/openresty/stream-lua-nginx-module.git
[submodule "cpython"]
path = src/deps/src/cpython
url = https://github.com/python/cpython.git

View File

@ -128,6 +128,15 @@ function do_and_check_cmd() {
return 0
}
# nginx 1.24.0
echo " Downloading nginx"
NGINX_VERSION="1.24.0"
secure_download "https://nginx.org/download/nginx-${NGINX_VERSION}.tar.gz" "nginx-${NGINX_VERSION}.tar.gz" "1114e37de5664a8109c99cfb2faa1f42ff8ac63c932bcf3780d645e5ed32c0b2ac446f80305b4465994c8f9430604968e176ae464fd80f632d1cb2c8f6007ff3"
if [ -f "deps/src/nginx-${NGINX_VERSION}.tar.gz" ] ; then
do_and_check_cmd tar -xvzf deps/src/nginx-${NGINX_VERSION}.tar.gz -C deps/src
do_and_check_cmd rm -f deps/src/nginx-${NGINX_VERSION}.tar.gz
fi
# Lua 5.1.5
echo " Downloading Lua"
LUA_VERSION="5.1.5"
@ -138,3 +147,94 @@ if [ -f "deps/src/lua-${LUA_VERSION}.tar.gz" ] ; then
do_and_check_cmd patch deps/src/lua-${LUA_VERSION}/Makefile deps/misc/lua.patch1
do_and_check_cmd patch deps/src/lua-${LUA_VERSION}/src/Makefile deps/misc/lua.patch2
fi
# lua-resty-ipmatcher v0.6.1 (3 commits after just in case)
echo " Downloading lua-resty-ipmatcher"
dopatch="no"
if [ ! -d "deps/src/lua-resty-ipmatcher" ] ; then
dopatch="yes"
fi
git_secure_clone "https://github.com/api7/lua-resty-ipmatcher.git" "7fbb618f7221b1af1451027d3c64e51f3182761c"
if [ "$dopatch" = "yes" ] ; then
do_and_check_cmd patch deps/src/lua-resty-ipmatcher/resty/ipmatcher.lua deps/misc/ipmatcher.patch
fi
# luajit-geoip v2.1.0
echo " Downloading luajit-geoip"
dopatch="no"
if [ ! -d "deps/src/luajit-geoip" ] ; then
dopatch="yes"
fi
git_secure_clone "https://github.com/leafo/luajit-geoip.git" "12a9388207f40c37ad5cf6de2f8e0cc72bf13477"
if [ "$dopatch" = "yes" ] ; then
do_and_check_cmd patch deps/src/luajit-geoip/geoip/mmdb.lua deps/misc/mmdb.patch
fi
# lua-pack v2.0.0
echo " Downloading lua-pack"
dopatch="no"
if [ ! -d "deps/src/lua-pack" ] ; then
dopatch="yes"
fi
git_secure_clone "https://github.com/Kong/lua-pack.git" "495bf30606b9744140258df349862981e3ee7820"
if [ "$dopatch" = "yes" ] ; then
do_and_check_cmd cp deps/misc/lua-pack.Makefile deps/src/lua-pack/Makefile
fi
# lua-resty-openssl v0.8.22
echo " Downloading lua-resty-openssl"
dopatch="no"
if [ ! -d "deps/src/lua-resty-openssl" ] ; then
dopatch="yes"
fi
git_secure_clone "https://github.com/fffonion/lua-resty-openssl.git" "484907935e60273d31626ac849b23a2d218173de"
if [ "$dopatch" == "yes" ] ; then
do_and_check_cmd rm -r deps/src/lua-resty-openssl/t
fi
# lua-ffi-zlib v0.5.0
echo " Downloading lua-ffi-zlib"
dopatch="no"
if [ ! -d "deps/src/lua-ffi-zlib" ] ; then
dopatch="yes"
fi
git_secure_clone "https://github.com/hamishforbes/lua-ffi-zlib.git" "1fb69ca505444097c82d2b72e87904f3ed923ae9"
if [ "$dopatch" = "yes" ] ; then
do_and_check_cmd patch deps/src/lua-ffi-zlib/lib/ffi-zlib.lua deps/misc/lua-ffi-zlib.patch
fi
# lua-resty-signal v0.03
echo " Downloading lua-resty-signal"
git_secure_clone "https://github.com/openresty/lua-resty-signal.git" "d07163e8cfa673900e66048cd2a1f18523aecf16"
# ModSecurity v3.0.9
echo " Downloading ModSecurity"
dopatch="no"
if [ ! -d "deps/src/ModSecurity" ] ; then
dopatch="yes"
fi
git_secure_clone "https://github.com/SpiderLabs/ModSecurity.git" "205dac0e8c675182f96b5c2fb06be7d1cf7af2b2"
if [ "$dopatch" = "yes" ] ; then
do_and_check_cmd patch deps/src/ModSecurity/configure.ac deps/misc/modsecurity.patch
fi
# libinjection v3.10.0+
# TODO: check if the latest commit is fine
echo " Downloading libinjection"
git_secure_clone "https://github.com/libinjection/libinjection.git" "49904c42a6e68dc8f16c022c693e897e4010a06c"
do_and_check_cmd cp -r deps/src/libinjection deps/src/ModSecurity/others
# ModSecurity-nginx v1.0.3
echo " Downloading ModSecurity-nginx"
dopatch="no"
if [ ! -d "deps/src/ModSecurity-nginx" ] ; then
dopatch="yes"
fi
git_secure_clone "https://github.com/SpiderLabs/ModSecurity-nginx.git" "d59e4ad121df702751940fd66bcc0b3ecb51a079"
if [ "$dopatch" = "yes" ] ; then
do_and_check_cmd patch deps/src/ModSecurity-nginx/src/ngx_http_modsecurity_log.c deps/misc/modsecurity-nginx.patch
do_and_check_cmd patch deps/src/ModSecurity-nginx/config deps/misc/config.patch
do_and_check_cmd patch deps/src/ModSecurity-nginx/src/ngx_http_modsecurity_common.h deps/misc/ngx_http_modsecurity_common.h.patch
do_and_check_cmd patch deps/src/ModSecurity-nginx/src/ngx_http_modsecurity_module.c deps/misc/ngx_http_modsecurity_module.c.patch
do_and_check_cmd cp deps/misc/ngx_http_modsecurity_access.c deps/src/ModSecurity-nginx/src
fi

View File

@ -18,10 +18,9 @@ function do_and_check_cmd() {
NTASK=$(nproc)
# Compiling and installing lua
LUA_VERSION="5.1.5"
echo " Compiling and installing lua-${LUA_VERSION}"
CHANGE_DIR="/tmp/bunkerweb/deps/src/lua-${LUA_VERSION}" do_and_check_cmd make -j $NTASK linux
CHANGE_DIR="/tmp/bunkerweb/deps/src/lua-${LUA_VERSION}" do_and_check_cmd make INSTALL_TOP=/usr/share/bunkerweb/deps install
echo " Compiling and installing lua-5.1.5"
CHANGE_DIR="/tmp/bunkerweb/deps/src/lua-5.1.5" do_and_check_cmd make -j $NTASK linux
CHANGE_DIR="/tmp/bunkerweb/deps/src/lua-5.1.5" do_and_check_cmd make INSTALL_TOP=/usr/share/bunkerweb/deps install
# Compiling and installing libmaxminddb
echo " Compiling and installing libmaxminddb"
@ -40,8 +39,8 @@ CHANGE_DIR="/tmp/bunkerweb/deps/src/zlib" do_and_check_cmd make install
# Compiling and installing ModSecurity
echo " Compiling and installing ModSecurity"
do_and_check_cmd patch deps/src/ModSecurity/configure.ac deps/misc/modsecurity.patch
do_and_check_cmd cp -r deps/src/libinjection deps/src/ModSecurity/others
# temp fix : Debian run it twice
# TODO : patch it in clone.sh
cd /tmp/bunkerweb/deps/src/ModSecurity && ./build.sh > /dev/null 2>&1
CHANGE_DIR="/tmp/bunkerweb/deps/src/ModSecurity" do_and_check_cmd sh build.sh
CHANGE_DIR="/tmp/bunkerweb/deps/src/ModSecurity" do_and_check_cmd ./configure --disable-dependency-tracking --disable-static --disable-examples --disable-doxygen-doc --disable-doxygen-html --disable-valgrind-memcheck --disable-valgrind-helgrind --prefix=/usr/share/bunkerweb/deps --with-maxmind=/usr/share/bunkerweb/deps
@ -108,7 +107,6 @@ CHANGE_DIR="/tmp/bunkerweb/deps/src/luasec" do_and_check_cmd make LUACPATH=/usr/
# Installing lua-resty-ipmatcher
echo " Installing lua-resty-ipmatcher"
do_and_check_cmd patch deps/src/lua-resty-ipmatcher/resty/ipmatcher.lua deps/misc/ipmatcher.patch
CHANGE_DIR="/tmp/bunkerweb/deps/src/lua-resty-ipmatcher" do_and_check_cmd make INST_PREFIX=/usr/share/bunkerweb/deps INST_LIBDIR=/usr/share/bunkerweb/deps/lib/lua INST_LUADIR=/usr/share/bunkerweb/deps/lib/lua install
# Installing lua-resty-redis
@ -121,7 +119,6 @@ CHANGE_DIR="/tmp/bunkerweb/deps/src/lua-resty-upload" do_and_check_cmd make PREF
# Installing lujit-geoip
echo " Installing luajit-geoip"
do_and_check_cmd patch deps/src/luajit-geoip/geoip/mmdb.lua deps/misc/mmdb.patch
do_and_check_cmd cp -r /tmp/bunkerweb/deps/src/luajit-geoip/geoip /usr/share/bunkerweb/deps/lib/lua
# Installing lbase64
@ -146,18 +143,15 @@ CHANGE_DIR="/tmp/bunkerweb/deps/src/lua-resty-lock" do_and_check_cmd make PREFIX
# Installing lua-pack
echo " Installing lua-pack"
do_and_check_cmd cp deps/misc/lua-pack.Makefile deps/src/lua-pack/Makefile
CHANGE_DIR="/tmp/bunkerweb/deps/src/lua-pack" do_and_check_cmd make INST_LIBDIR=/usr/share/bunkerweb/deps/lib/lua LUA_LIBDIR=-L/usr/share/bunkerweb/deps/lib LUA_INCDIR=-I/usr/share/bunkerweb/deps/include install
# Installing lua-resty-openssl
echo " Installing lua-resty-openssl"
do_and_check_cmd rm -r deps/src/lua-resty-openssl/t
CHANGE_DIR="/tmp/bunkerweb/deps/src/lua-resty-openssl" do_and_check_cmd make LUA_LIB_DIR=/usr/share/bunkerweb/deps/lib/lua install
do_and_check_cmd cp /tmp/bunkerweb/deps/src/lua-resty-openssl/lib/resty/openssl.lua /usr/share/bunkerweb/deps/lib/lua/resty
# Installing lua-ffi-zlib
echo " Installing lua-ffi-zlib"
do_and_check_cmd patch deps/src/lua-ffi-zlib/lib/ffi-zlib.lua deps/misc/lua-ffi-zlib.patch
do_and_check_cmd cp /tmp/bunkerweb/deps/src/lua-ffi-zlib/lib/ffi-zlib.lua /usr/share/bunkerweb/deps/lib/lua
# Installing lua-resty-signal
@ -174,20 +168,13 @@ CONFARGS="$(echo -n "$CONFARGS" | sed "s/--with-ld-opt='-Wl/--with-ld-opt='-lpcr
if [ "$OS" = "fedora" ] ; then
CONFARGS="$(echo -n "$CONFARGS" | sed "s/--with-ld-opt='.*'/--with-ld-opt=-lpcre/" | sed "s/--with-cc-opt='.*'//")"
fi
do_and_check_cmd patch deps/src/ModSecurity-nginx/src/ngx_http_modsecurity_log.c deps/misc/modsecurity-nginx.patch
do_and_check_cmd patch deps/src/ModSecurity-nginx/config deps/misc/config.patch
do_and_check_cmd patch deps/src/ModSecurity-nginx/src/ngx_http_modsecurity_common.h deps/misc/ngx_http_modsecurity_common.h.patch
do_and_check_cmd patch deps/src/ModSecurity-nginx/src/ngx_http_modsecurity_module.c deps/misc/ngx_http_modsecurity_module.c.patch
do_and_check_cmd cp deps/misc/ngx_http_modsecurity_access.c deps/src/ModSecurity-nginx/src
echo '#!/bin/bash' > "/tmp/bunkerweb/deps/src/nginx/configure-fix.sh"
echo "./configure $CONFARGS --add-dynamic-module=/tmp/bunkerweb/deps/src/headers-more-nginx-module --add-dynamic-module=/tmp/bunkerweb/deps/src/nginx_cookie_flag_module --add-dynamic-module=/tmp/bunkerweb/deps/src/lua-nginx-module --add-dynamic-module=/tmp/bunkerweb/deps/src/ngx_brotli --add-dynamic-module=/tmp/bunkerweb/deps/src/ngx_devel_kit --add-dynamic-module=/tmp/bunkerweb/deps/src/stream-lua-nginx-module" --add-dynamic-module=/tmp/bunkerweb/deps/src/ModSecurity-nginx >> "/tmp/bunkerweb/deps/src/nginx/configure-fix.sh"
do_and_check_cmd chmod +x "/tmp/bunkerweb/deps/src/nginx/configure-fix.sh"
CHANGE_DIR="/tmp/bunkerweb/deps/src/nginx" LUAJIT_LIB="/usr/share/bunkerweb/deps/lib -Wl,-rpath,/usr/share/bunkerweb/deps/lib" LUAJIT_INC="/usr/share/bunkerweb/deps/include/luajit-2.1" MODSECURITY_LIB="/usr/share/bunkerweb/deps/lib" MODSECURITY_INC="/usr/share/bunkerweb/deps/include" do_and_check_cmd ./configure-fix.sh
CHANGE_DIR="/tmp/bunkerweb/deps/src/nginx" do_and_check_cmd make -j $NTASK modules
echo '#!/bin/bash' > "/tmp/bunkerweb/deps/src/nginx-${NGINX_VERSION}/configure-fix.sh"
echo "./configure $CONFARGS --add-dynamic-module=/tmp/bunkerweb/deps/src/headers-more-nginx-module --add-dynamic-module=/tmp/bunkerweb/deps/src/nginx_cookie_flag_module --add-dynamic-module=/tmp/bunkerweb/deps/src/lua-nginx-module --add-dynamic-module=/tmp/bunkerweb/deps/src/ngx_brotli --add-dynamic-module=/tmp/bunkerweb/deps/src/ngx_devel_kit --add-dynamic-module=/tmp/bunkerweb/deps/src/stream-lua-nginx-module" --add-dynamic-module=/tmp/bunkerweb/deps/src/ModSecurity-nginx >> "/tmp/bunkerweb/deps/src/nginx-${NGINX_VERSION}/configure-fix.sh"
do_and_check_cmd chmod +x "/tmp/bunkerweb/deps/src/nginx-${NGINX_VERSION}/configure-fix.sh"
CHANGE_DIR="/tmp/bunkerweb/deps/src/nginx-${NGINX_VERSION}" LUAJIT_LIB="/usr/share/bunkerweb/deps/lib -Wl,-rpath,/usr/share/bunkerweb/deps/lib" LUAJIT_INC="/usr/share/bunkerweb/deps/include/luajit-2.1" MODSECURITY_LIB="/usr/share/bunkerweb/deps/lib" MODSECURITY_INC="/usr/share/bunkerweb/deps/include" do_and_check_cmd ./configure-fix.sh
CHANGE_DIR="/tmp/bunkerweb/deps/src/nginx-${NGINX_VERSION}" do_and_check_cmd make -j $NTASK modules
do_and_check_cmd mkdir /usr/share/bunkerweb/modules
CHANGE_DIR="/tmp/bunkerweb/deps/src/nginx" do_and_check_cmd cp ./objs/*.so /usr/share/bunkerweb/modules
CHANGE_DIR="/tmp/bunkerweb/deps/src/nginx-${NGINX_VERSION}" do_and_check_cmd cp ./objs/*.so /usr/share/bunkerweb/modules
# Dependencies are installed
echo " Dependencies for BunkerWeb successfully compiled and installed !"

@ -1 +0,0 @@
Subproject commit 205dac0e8c675182f96b5c2fb06be7d1cf7af2b2

@ -1 +0,0 @@
Subproject commit d59e4ad121df702751940fd66bcc0b3ecb51a079

View File

@ -0,0 +1,19 @@
#name: "Close stale issues"
#on:
# schedule:
# - cron: "0 0 * * *"
#
#jobs:
# stale:
# runs-on: ubuntu-latest
# steps:
# - uses: actions/stale@v3
# with:
# repo-token: ${{ secrets.GITHUB_TOKEN }}
# stale-issue-message: 'This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 5 days'
# stale-pr-message: 'This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 5 days'
# stale-issue-label: 'no-issue-activity'
# stale-pr-label: 'no-pr-activity'
# exempt-issue-label: 'nostale,work-in-progress'
# days-before-stale: 30
# days-before-close: 5

View File

@ -0,0 +1,47 @@
sudo: required
dist: bionic
os: linux
language: c
compiler:
- gcc
addons:
apt:
packages:
- libyajl-dev
- libgeoip-dev
- liblmdb-dev
env:
- VER_NGINX=1.21.0
- VER_NGINX=1.20.1
before_script:
- cd ..
- git clone https://github.com/SpiderLabs/ModSecurity.git
- cd ModSecurity
- git checkout v3/master
- git submodule init
- git submodule update
- ./build.sh
- ./configure --without-lmdb
- make
- sudo make install
- cd ..
- wget http://nginx.org/download/nginx-${VER_NGINX}.tar.gz && tar -xf nginx-${VER_NGINX}.tar.gz
- cd nginx-${VER_NGINX}
- ./configure --with-http_auth_request_module --with-http_v2_module --add-module=../ModSecurity-nginx
- make
- sudo make install
- cd ..
- wget http://hg.nginx.org/nginx-tests/archive/tip.tar.gz
- tar xvzf tip.tar.gz
- cd nginx-tests-*
- cp ../ModSecurity-nginx/tests/* .
- export TEST_NGINX_BINARY=/usr/local/nginx/sbin/nginx
script:
- prove .

View File

@ -0,0 +1,2 @@
zimmerle = Felipe Zimmerle <felipe@zimmerle.org>
defanator = Andrei Belov <defanator@gmail.com>

View File

@ -0,0 +1,70 @@
v1.0.3 - 2022-May-24
--------------------
- Support http protocol versions besides 0.9, 1.0, 1.1, 2.0
[Issue #224 - @HQuest, @martinhsv]
- Support for building with nginx configured with PCRE2
[Issue #260 - @defanator]
v1.0.2 - 2021-Jun-02
--------------------
- Fix auditlog in case of internal redirect
[Issue #90 - @AirisX, @defanator]
- Fix nginx sends response without headers
[Issue #238 - @airween, @defanator]
- Fix nginx not clearing body cache (caused by incomplete fix for #187)
[Issue #216 - @krewi1, @martinhsv]
- Fix config setting not respected: client_body_in_file_only on
[Issue #187 - @martinhsv]
- Fix audit_log not generated for disruptive actions
[Issue #170, #2220, #2237 - @victorhora]
- Exit more gracefully if uri length is zero
[@martinhsv]
v1.0.1 - 2019-Dec-16
--------------------
- Fixed obtaining of server_addr
[Issue #167, #168 - @defanator]
- Avoid processing of subrequests initiated by the error_page
[Issue #76, #164, #165 - @defanator]
- Tests: extend request body tests
[Issue #142,#143 - @defanator]
- Added basic tests over HTTP/2
[Issue #145 - @defanator]
- Module configuration refactoring
[Issue #139 - @defanator]
- Restore r->write_event_handler after reading request body
[Issue #131 - @defanator]
- Increase log level for disruptive actions to "error"
[Issue #112 - @victorhora]
- Support for generating transaction ID in nginx
[Issue #126 - @defanator]
- Extend request body tests with ARGS_POST case
[Issue #124 - @defanator]
- Fix tests after 42a472a change in library
[Issue #122 - @defanator]
- Fix processing of response body when gzip compression is enabled
[Issue #107 - @turchanov]
- Fixed processing of response body chunks in
ngx_http_modsecurity_body_filter.
[Issue #105 - @turchanov, @defanator]
- Fix incorrect handling of request/response body data chain of ngx_buf_t
buffers
[Issue #104 - @turchanov, @defanator]
- Pool pointer is now handled in ngx_http_modsecurity_config_cleanup
[Issue #87 - @AirisX, @defanator, @zimmerle]
- Fix memory leak in intervention processing
[Issue #100 - @defanator]
- Emit connector version in error log
[Issue #88 - @defanator]
- Fixed memory leak on config cleanup.
[Issue #80 - @AirisX, @defanator]
v1.0.0 - 2017-Dec-20
--------------------
- First version of ModSecurity-nginx connector

View File

@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@ -0,0 +1,266 @@
<img src="https://github.com/SpiderLabs/ModSecurity/raw/v3/master/others/modsec.png" width="50%">
[![Build Status](https://travis-ci.org/SpiderLabs/ModSecurity-nginx.svg?branch=master)](https://travis-ci.org/SpiderLabs/ModSecurity-nginx)
[![](https://raw.githubusercontent.com/ZenHubIO/support/master/zenhub-badge.png)](https://zenhub.com)
The ModSecurity-nginx connector is the connection point between nginx and libmodsecurity (ModSecurity v3). Said another way, this project provides a communication channel between nginx and libmodsecurity. This connector is required to use LibModSecurity with nginx.
The ModSecurity-nginx connector takes the form of an nginx module. The module simply serves as a layer of communication between nginx and ModSecurity.
Notice that this project depends on libmodsecurity rather than ModSecurity (version 2.9 or less).
### What is the difference between this project and the old ModSecurity add-on for nginx?
The old version uses ModSecurity standalone, which is a wrapper for
Apache internals to link ModSecurity to nginx. This current version is closer
to nginx, consuming the new libmodsecurity which is no longer dependent on
Apache. As a result, this current version has less dependencies, fewer bugs, and is faster. In addition, some new functionality is also provided - such as the possibility of use of global rules configuration with per directory/location customizations (e.g. SecRuleRemoveById).
# Compilation
Before compile this software make sure that you have libmodsecurity installed.
You can download it from the [ModSecurity git repository](https://github.com/SpiderLabs/ModSecurity). For information pertaining to the compilation and installation of libmodsecurity please consult the documentation provided along with it.
With libmodsecurity installed, you can proceed with the installation of the ModSecurity-nginx connector, which follows the nginx third-party module installation procedure. From the nginx source directory:
```
./configure --add-module=/path/to/ModSecurity-nginx
```
Or, to build a dynamic module:
```
./configure --add-dynamic-module=/path/to/ModSecurity-nginx --with-compat
```
Note that when building a dynamic module, your nginx source version
needs to match the version of nginx you're compiling this for.
Further information about nginx third-party add-ons support are available here:
http://wiki.nginx.org/3rdPartyModules
# Usage
ModSecurity for nginx extends your nginx configuration directives.
It adds four new directives and they are:
modsecurity
-----------
**syntax:** *modsecurity on | off*
**context:** *http, server, location*
**default:** *off*
Turns on or off ModSecurity functionality.
Note that this configuration directive is no longer related to the SecRule state.
Instead, it now serves solely as an nginx flag to enable or disable the module.
modsecurity_rules_file
----------------------
**syntax:** *modsecurity_rules_file &lt;path to rules file&gt;*
**context:** *http, server, location*
**default:** *no*
Specifies the location of the modsecurity configuration file, e.g.:
```nginx
server {
modsecurity on;
location / {
root /var/www/html;
modsecurity_rules_file /etc/my_modsecurity_rules.conf;
}
}
```
modsecurity_rules_remote
------------------------
**syntax:** *modsecurity_rules_remote &lt;key&gt; &lt;URL to rules&gt;*
**context:** *http, server, location*
**default:** *no*
Specifies from where (on the internet) a modsecurity configuration file will be downloaded.
It also specifies the key that will be used to authenticate to that server:
```nginx
server {
modsecurity on;
location / {
root /var/www/html;
modsecurity_rules_remote my-server-key https://my-own-server/rules/download;
}
}
```
modsecurity_rules
-----------------
**syntax:** *modsecurity_rules &lt;modsecurity rule&gt;*
**context:** *http, server, location*
**default:** *no*
Allows for the direct inclusion of a ModSecurity rule into the nginx configuration.
The following example is loading rules from a file and injecting specific configurations per directory/alias:
```nginx
server {
modsecurity on;
location / {
root /var/www/html;
modsecurity_rules_file /etc/my_modsecurity_rules.conf;
}
location /ops {
root /var/www/html/opts;
modsecurity_rules '
SecRuleEngine On
SecDebugLog /tmp/modsec_debug.log
SecDebugLogLevel 9
SecRuleRemoveById 10
';
}
}
```
modsecurity_transaction_id
--------------------------
**syntax:** *modsecurity_transaction_id string*
**context:** *http, server, location*
**default:** *no*
Allows to pass transaction ID from nginx instead of generating it in the library.
This can be useful for tracing purposes, e.g. consider this configuration:
```nginx
log_format extended '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" $request_id';
server {
server_name host1;
modsecurity on;
modsecurity_transaction_id "host1-$request_id";
access_log logs/host1-access.log extended;
error_log logs/host1-error.log;
location / {
...
}
}
server {
server_name host2;
modsecurity on;
modsecurity_transaction_id "host2-$request_id";
access_log logs/host2-access.log extended;
error_log logs/host2-error.log;
location / {
...
}
}
```
Using a combination of log_format and modsecurity_transaction_id you will
be able to find correlations between access log and error log entries
using the same unique identificator.
String can contain variables.
# Contributing
As an open source project we invite (and encourage) anyone from the community to contribute to our project. This may take the form of: new
functionality, bug fixes, bug reports, beginners user support, and anything else that you
are willing to help with. Thank you.
## Providing Patches
We prefer to have your patch within the GitHub infrastructure to facilitate our
review work, and our QA integration. GitHub provides an excellent
documentation on how to perform “Pull Requests”. More information available
here: https://help.github.com/articles/using-pull-requests/
Please respect the coding style in use. Pull requests can include various commits, so
provide one fix or one functionality per commit. Do not change anything outside
the scope of your target work (e.g. coding style in a function that you have
passed by).
### Dont know where to start?
Within our code there are various items marked as TODO or FIXME that may need
your attention. Check the list of items by performing a grep:
```
$ cd /path/to/modsecurity-nginx
$ egrep -Rin "TODO|FIXME" -R *
```
You may also take a look at recent bug reports and open issues to get an idea of what kind of help we are looking for.
### Testing your patch
Along with the manual testing, we strongly recommend that you to use the nginx test
utility to make sure that you patch does not adversely affect the behavior or performance of nginx.
The nginx tests are available on: http://hg.nginx.org/nginx-tests/
To use those tests, make sure you have the Perl utility prove (part of Perl 5)
and proceed with the following commands:
```
$ cp /path/to/ModSecurity-nginx/tests/* /path/to/nginx/test/repository
$ cd /path/to/nginx/test/repository
$ TEST_NGINX_BINARY=/path/to/your/nginx prove .
```
If you are facing problems getting your added functionality to pass all the nginx tests, feel free to contact us or the nginx mailing list at: http://nginx.org/en/support.html
### Debugging
We respect the nginx debugging schema. By using the configuration option
"--with-debug" during the nginx configuration you will also be enabling the
connector's debug messages. Core dumps and crashes are expected to be debugged
in the same fashion that is used to debug nginx. For further information,
please check the nginx debugging information: http://wiki.nginx.org/Debugging
## Reporting Issues
If you are facing a configuration issue or if something is not working as you
expect it to be, please use ModSecurity users mailing list. Issues on GitHub
are also welcome, but we prefer to have users question on the mailing list first,
where you can reach an entire community. Also dont forget to look for an
existing issue before opening a new one.
Lastly, If you are planning to open an issue on GitHub, please dont forget to tell us the
version of your libmodsecurity and the version of the nginx connector you are running.
### Security issue
Please do not publicly report any security issue. Instead, contact us at:
security@modsecurity.org to report the issue. Once the problem is fixed we will provide you with credit for the discovery.
## Feature Request
We would love to discuss any ideas that you may have for a new feature. Please keep in mind this is a community driven project so be sure to contact the community via the mailing list to get feedback first. Alternatively,
feel free to open GitHub issues requesting for new features. Before opening a new issue, please check if there is an existing feature request for the desired functionality.
## Packaging
Having our packages in distros on time is something we highly desire. Let us know if
there is anything we can do to facilitate your work as a packager.

View File

@ -0,0 +1,192 @@
# vim: filetype=sh
# If $NGX_IGNORE_RPATH is set to "YES", we will ignore explicit
# library path specification on resulting binary, allowing libmodsecurity.so
# to be relocated across configured library pathes (adjust /etc/ld.so.conf
# or set $LD_LIBRARY_PATH environment variable to manage them)
#
# $YAJL_LIB variable may need to be populated in case of non-standard
# path of libyajl.so's installation
ngx_feature_name=
ngx_feature_run=no
ngx_feature_incs="#include <modsecurity/modsecurity.h>"
ngx_feature_libs="-lmodsecurity"
ngx_feature_test='printf("hello");'
ngx_modsecurity_opt_I=
ngx_modsecurity_opt_L=
YAJL_EXTRA=
if test -n "$YAJL_LIB"; then
YAJL_EXTRA="-L$YAJL_LIB -lyajl"
fi
# If $MODSECURITY_INC is specified, lets use it. Otherwise lets try
# the default paths
#
if [ -n "$MODSECURITY_INC" -o -n "$MODSECURITY_LIB" ]; then
# explicitly set ModSecurity lib path
ngx_feature="ModSecurity library in \"$MODSECURITY_LIB\" and \"$MODSECURITY_INC\" (specified by the MODSECURITY_LIB and MODSECURITY_INC env)"
ngx_feature_path="$MODSECURITY_INC"
ngx_modsecurity_opt_I="-I$MODSECURITY_INC"
ngx_modsecurity_opt_L="-L$MODSECURITY_LIB $YAJL_EXTRA"
if [ $NGX_RPATH = YES ]; then
ngx_feature_libs="-R$MODSECURITY_LIB -L$MODSECURITY_LIB -lmodsecurity $YAJL_EXTRA"
elif [ "$NGX_IGNORE_RPATH" != "YES" -a $NGX_SYSTEM = "Linux" ]; then
ngx_feature_libs="-Wl,-rpath,$MODSECURITY_LIB -L$MODSECURITY_LIB -lmodsecurity $YAJL_EXTRA"
else
ngx_feature_libs="-L$MODSECURITY_LIB -lmodsecurity $YAJL_EXTRA"
fi
. auto/feature
if [ $ngx_found = no ]; then
cat << END
$0: error: ngx_http_modsecurity_module requires the ModSecurity library and MODSECURITY_LIB is defined as "$MODSECURITY_LIB" and MODSECURITY_INC (path for modsecurity.h) "$MODSECURITY_INC", but we cannot find ModSecurity there.
END
exit 1
fi
else
# auto-discovery
ngx_feature="ModSecurity library"
ngx_feature_libs="-lmodsecurity"
. auto/feature
if [ $ngx_found = no ]; then
ngx_feature="ModSecurity library in /usr/local/modsecurity"
ngx_feature_path="/usr/local/modsecurity/include"
if [ $NGX_RPATH = YES ]; then
ngx_feature_libs="-R/usr/local/modsecurity/lib -L/usr/local/modsecurity/lib -lmodsecurity"
elif [ "$NGX_IGNORE_RPATH" != "YES" -a $NGX_SYSTEM = "Linux" ]; then
ngx_feature_libs="-Wl,-rpath,/usr/local/modsecurity/lib -L/usr/local/modsecurity/lib -lmodsecurity"
else
ngx_feature_libs="-L/usr/local/modsecurity/lib -lmodsecurity"
fi
. auto/feature
fi
fi
if [ $ngx_found = no ]; then
cat << END
$0: error: ngx_http_modsecurity_module requires the ModSecurity library.
END
exit 1
fi
ngx_addon_name=ngx_http_modsecurity_module
# We must place ngx_http_modsecurity_module after ngx_http_gzip_filter_module
# in load order list to be able to read response body before it gets compressed
# (for filter modules later initialization means earlier execution).
#
# Nginx implements load ordering only for dynamic modules and only a BEFORE part
# of "ngx_module_order". So we list all of the modules that come after
# ngx_http_gzip_filter_module as a BEFORE dependency for
# ngx_http_modsecurity_module.
#
# For static compilation HTTP_FILTER_MODULES will be patched later.
modsecurity_dependency="ngx_http_postpone_filter_module \
ngx_http_ssi_filter_module \
ngx_http_charset_filter_module \
ngx_http_xslt_filter_module \
ngx_http_image_filter_module \
ngx_http_sub_filter_module \
ngx_http_addition_filter_module \
ngx_http_gunzip_filter_module \
ngx_http_userid_filter_module \
ngx_http_headers_filter_module \
ngx_http_copy_filter_module"
if test -n "$ngx_module_link"; then
ngx_module_type=HTTP_FILTER
ngx_module_name="$ngx_addon_name"
ngx_module_srcs="$ngx_addon_dir/src/ngx_http_modsecurity_module.c \
$ngx_addon_dir/src/ngx_http_modsecurity_access.c \
$ngx_addon_dir/src/ngx_http_modsecurity_header_filter.c \
$ngx_addon_dir/src/ngx_http_modsecurity_body_filter.c \
$ngx_addon_dir/src/ngx_http_modsecurity_log.c \
$ngx_addon_dir/src/ngx_http_modsecurity_rewrite.c \
"
ngx_module_deps="$ngx_addon_dir/src/ddebug.h \
$ngx_addon_dir/src/ngx_http_modsecurity_common.h \
"
ngx_module_libs="$ngx_feature_libs"
ngx_module_incs="$ngx_feature_path"
ngx_module_order="ngx_http_chunked_filter_module \
ngx_http_v2_filter_module \
ngx_http_range_header_filter_module \
ngx_http_gzip_filter_module \
$ngx_module_name \
$modsecurity_dependency";
. auto/module
else
CFLAGS="$ngx_modsecurity_opt_I $CFLAGS"
NGX_LD_OPT="$ngx_modsecurity_opt_L $NGX_LD_OPT"
CORE_INCS="$CORE_INCS $ngx_feature_path"
CORE_LIBS="$CORE_LIBS $ngx_feature_libs"
HTTP_FILTER_MODULES="$HTTP_FILTER_MODULES ngx_http_modsecurity_module"
NGX_ADDON_SRCS="\
$NGX_ADDON_SRCS \
$ngx_addon_dir/src/ngx_http_modsecurity_module.c \
$ngx_addon_dir/src/ngx_http_modsecurity_access.c \
$ngx_addon_dir/src/ngx_http_modsecurity_header_filter.c \
$ngx_addon_dir/src/ngx_http_modsecurity_body_filter.c \
$ngx_addon_dir/src/ngx_http_modsecurity_log.c \
$ngx_addon_dir/src/ngx_http_modsecurity_rewrite.c \
"
NGX_ADDON_DEPS="\
$NGX_ADDON_DEPS \
$ngx_addon_dir/src/ddebug.h \
$ngx_addon_dir/src/ngx_http_modsecurity_common.h \
"
fi
#
# Nginx does not provide reliable way to introduce our module into required
# place in static ($ngx_module_link=ADDON) compilation mode, so we must
# explicitly update module "ordering rules".
#
if [ "$ngx_module_link" != DYNAMIC ] ; then
# Reposition modsecurity module to satisfy $modsecurity_dependency
# (this mimics dependency resolution made by ngx_add_module() function
# though less optimal in terms of computational complexity).
modules=
found=
for module in $HTTP_FILTER_MODULES; do
# skip our module name from the original list
if [ "$module" = "$ngx_addon_name" ]; then
continue
fi
if [ -z "${found}" ]; then
for item in $modsecurity_dependency; do
if [ "$module" = "$item" ]; then
modules="${modules} $ngx_addon_name"
found=1
break
fi
done
fi
modules="${modules} $module"
done
if [ -z "${found}" ]; then
# This must never happen since ngx_http_copy_filter_module must be in HTTP_FILTER_MODULES
# and we stated dependency on it in $modsecurity_dependency
echo "$0: error: cannot reposition modsecurity module in HTTP_FILTER_MODULES list"
exit 1
fi
HTTP_FILTER_MODULES="${modules}"
fi

View File

@ -0,0 +1,37 @@
#!/usr/bin/env stap
global begin_rule
global rules
global rules_phase
# Rules
probe process("/usr/local/lib/libmodsecurity.so.3").function("evaluate@rule.cc*")
{
begin_rule = gettimeofday_us();
}
probe process("/usr/local/lib/libmodsecurity.so.3").function("evaluate@rule.cc*").return
{
elapsed_rule = gettimeofday_us() - begin_rule
rules[$this->m_ruleId] <<< elapsed_rule
rules_phase[$this->m_ruleId] = $this->m_phase
}
# Resume
probe end
{
foreach ([rule] in rules)
{
if (@count(rules[rule])) {
p = rules_phase[rule] - 1;
if (p <= 0) {
p = 1
}
printf("Phase %d;Rule ID: %d %u\n", p, rule, @avg(rules[rule]));
}
}
}

View File

@ -0,0 +1,20 @@
#!/bin/bash
git clean -xfdi
git submodule foreach --recursive git clean -xfdi
VERSION=`git describe --tags`
DIR_NAME="modsecurity-nginx-$VERSION"
TAR_NAME="modsecurity-nginx-$VERSION.tar.gz"
MY_DIR=${PWD##*/}
cd ..
tar --transform "s/^$MY_DIR/$DIR_NAME/" -cvzf $TAR_NAME --exclude .git $MY_DIR
sha256sum $TAR_NAME > $TAR_NAME.sha256
gpg --detach-sign -a $TAR_NAME
cd -
echo $TAR_NAME ": done."

View File

@ -0,0 +1,100 @@
// From: https://raw.githubusercontent.com/openresty/lua-nginx-module/master/src/ddebug.h
/*
* Copyright (C) Yichun Zhang (agentzh)
*/
#ifndef _DDEBUG_H_INCLUDED_
#define _DDEBUG_H_INCLUDED_
#include <ngx_core.h>
/*
* #undef MODSECURITY_DDEBUG
* #define MODSECURITY_DDEBUG 1
*/
/*
* Setting MODSECURITY_SANITY_CHECKS will help you in the debug process. By
* defining MODSECURITY_SANITY_CHECKS a set of functions will be executed in
* order to make sure the well behavior of ModSecurity, letting you know (via
* debug_logs) if something unexpected happens.
*
* If performance is not a concern, it is safe to keep it set.
*
*/
#ifndef MODSECURITY_SANITY_CHECKS
#define MODSECURITY_SANITY_CHECKS 0
#endif
#if defined(MODSECURITY_DDEBUG) && (MODSECURITY_DDEBUG)
# if (NGX_HAVE_VARIADIC_MACROS)
# define dd(...) fprintf(stderr, "modsec *** %s: ", __func__); \
fprintf(stderr, __VA_ARGS__); \
fprintf(stderr, " at %s line %d.\n", __FILE__, __LINE__)
# else
#include <stdarg.h>
#include <stdio.h>
#include <stdarg.h>
static void dd(const char *fmt, ...) {
}
# endif
#else
# if (NGX_HAVE_VARIADIC_MACROS)
# define dd(...)
# else
#include <stdarg.h>
static void dd(const char *fmt, ...) {
}
# endif
#endif
#if defined(MODSECURITY_DDEBUG) && (MODSECURITY_DDEBUG)
#define dd_check_read_event_handler(r) \
dd("r->read_event_handler = %s", \
r->read_event_handler == ngx_http_block_reading ? \
"ngx_http_block_reading" : \
r->read_event_handler == ngx_http_test_reading ? \
"ngx_http_test_reading" : \
r->read_event_handler == ngx_http_request_empty_handler ? \
"ngx_http_request_empty_handler" : "UNKNOWN")
#define dd_check_write_event_handler(r) \
dd("r->write_event_handler = %s", \
r->write_event_handler == ngx_http_handler ? \
"ngx_http_handler" : \
r->write_event_handler == ngx_http_core_run_phases ? \
"ngx_http_core_run_phases" : \
r->write_event_handler == ngx_http_request_empty_handler ? \
"ngx_http_request_empty_handler" : "UNKNOWN")
#else
#define dd_check_read_event_handler(r)
#define dd_check_write_event_handler(r)
#endif
#endif /* _DDEBUG_H_INCLUDED_ */
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */

View File

@ -0,0 +1,228 @@
/*
* ModSecurity connector for nginx, http://www.modsecurity.org/
* Copyright (c) 2015 Trustwave Holdings, Inc. (http://www.trustwave.com/)
*
* You may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* If any of the files related to licensing are missing or if you have any
* other questions related to licensing please contact Trustwave Holdings, Inc.
* directly using the email address security@modsecurity.org.
*
*/
#ifndef MODSECURITY_DDEBUG
#define MODSECURITY_DDEBUG 0
#endif
#include "ddebug.h"
#include "ngx_http_modsecurity_common.h"
void
ngx_http_modsecurity_request_read(ngx_http_request_t *r)
{
ngx_http_modsecurity_ctx_t *ctx;
ctx = ngx_http_get_module_ctx(r, ngx_http_modsecurity_module);
#if defined(nginx_version) && nginx_version >= 8011
r->main->count--;
#endif
if (ctx->waiting_more_body)
{
ctx->waiting_more_body = 0;
r->write_event_handler = ngx_http_core_run_phases;
ngx_http_core_run_phases(r);
}
}
ngx_int_t
ngx_http_modsecurity_access_handler(ngx_http_request_t *r)
{
#if 1
ngx_pool_t *old_pool;
ngx_http_modsecurity_ctx_t *ctx;
ngx_http_modsecurity_conf_t *mcf;
dd("catching a new _access_ phase handler");
mcf = ngx_http_get_module_loc_conf(r, ngx_http_modsecurity_module);
if (mcf == NULL || mcf->enable != 1)
{
dd("ModSecurity not enabled... returning");
return NGX_DECLINED;
}
/*
* FIXME:
* In order to perform some tests, let's accept everything.
*
if (r->method != NGX_HTTP_GET &&
r->method != NGX_HTTP_POST && r->method != NGX_HTTP_HEAD) {
dd("ModSecurity is not ready to deal with anything different from " \
"POST, GET or HEAD");
return NGX_DECLINED;
}
*/
ctx = ngx_http_get_module_ctx(r, ngx_http_modsecurity_module);
dd("recovering ctx: %p", ctx);
if (ctx == NULL)
{
dd("ctx is null; Nothing we can do, returning an error.");
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
if (ctx->intervention_triggered) {
return NGX_DECLINED;
}
if (ctx->waiting_more_body == 1)
{
dd("waiting for more data before proceed. / count: %d",
r->main->count);
return NGX_DONE;
}
if (ctx->body_requested == 0)
{
ngx_int_t rc = NGX_OK;
ctx->body_requested = 1;
dd("asking for the request body, if any. Count: %d",
r->main->count);
/**
* TODO: Check if there is any benefit to use request_body_in_single_buf set to 1.
*
* saw some module using this request_body_in_single_buf
* but not sure what exactly it does, same for the others options below.
*
* r->request_body_in_single_buf = 1;
*/
r->request_body_in_single_buf = 1;
r->request_body_in_persistent_file = 1;
if (!r->request_body_in_file_only) {
// If the above condition fails, then the flag below will have been
// set correctly elsewhere. We need to set the flag here for other
// conditions (client_body_in_file_only not used but
// client_body_buffer_size is)
r->request_body_in_clean_file = 1;
}
rc = ngx_http_read_client_request_body(r,
ngx_http_modsecurity_request_read);
if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) {
#if (nginx_version < 1002006) || \
(nginx_version >= 1003000 && nginx_version < 1003009)
r->main->count--;
#endif
return rc;
}
if (rc == NGX_AGAIN)
{
dd("nginx is asking us to wait for more data.");
ctx->waiting_more_body = 1;
return NGX_DONE;
}
}
if (ctx->waiting_more_body == 0)
{
int ret = 0;
int already_inspected = 0;
dd("request body is ready to be processed");
r->write_event_handler = ngx_http_core_run_phases;
ngx_chain_t *chain = r->request_body->bufs;
/**
* TODO: Speed up the analysis by sending chunk while they arrive.
*
* Notice that we are waiting for the full request body to
* start to process it, it may not be necessary. We may send
* the chunks to ModSecurity while nginx keep calling this
* function.
*/
if (r->request_body->temp_file != NULL) {
ngx_str_t file_path = r->request_body->temp_file->file.name;
const char *file_name = ngx_str_to_char(file_path, r->pool);
if (file_name == (char*)-1) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
/*
* Request body was saved to a file, probably we don't have a
* copy of it in memory.
*/
dd("request body inspection: file -- %s", file_name);
msc_request_body_from_file(ctx->modsec_transaction, file_name);
already_inspected = 1;
} else {
dd("inspection request body in memory.");
}
while (chain && !already_inspected)
{
u_char *data = chain->buf->pos;
msc_append_request_body(ctx->modsec_transaction, data,
chain->buf->last - data);
if (chain->buf->last_buf) {
break;
}
chain = chain->next;
/* XXX: chains are processed one-by-one, maybe worth to pass all chains and then call intervention() ? */
/**
* ModSecurity may perform stream inspection on this buffer,
* it may ask for a intervention in consequence of that.
*
*/
ret = ngx_http_modsecurity_process_intervention(ctx->modsec_transaction, r, 0);
if (ret > 0) {
return ret;
}
}
/**
* At this point, all the request body was sent to ModSecurity
* and we want to make sure that all the request body inspection
* happened; consequently we have to check if ModSecurity have
* returned any kind of intervention.
*/
/* XXX: once more -- is body can be modified ? content-length need to be adjusted ? */
old_pool = ngx_http_modsecurity_pcre_malloc_init(r->pool);
msc_process_request_body(ctx->modsec_transaction);
ngx_http_modsecurity_pcre_malloc_done(old_pool);
ret = ngx_http_modsecurity_process_intervention(ctx->modsec_transaction, r, 0);
if (r->error_page) {
return NGX_DECLINED;
}
if (ret > 0) {
return ret;
}
}
dd("Nothing to add on the body inspection, reclaiming a NGX_DECLINED");
#endif
return NGX_DECLINED;
}

View File

@ -0,0 +1,184 @@
/*
* ModSecurity connector for nginx, http://www.modsecurity.org/
* Copyright (c) 2015 Trustwave Holdings, Inc. (http://www.trustwave.com/)
*
* You may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* If any of the files related to licensing are missing or if you have any
* other questions related to licensing please contact Trustwave Holdings, Inc.
* directly using the email address security@modsecurity.org.
*
*/
#ifndef MODSECURITY_DDEBUG
#define MODSECURITY_DDEBUG 0
#endif
#include "ddebug.h"
#include "ngx_http_modsecurity_common.h"
static ngx_http_output_body_filter_pt ngx_http_next_body_filter;
/* XXX: check behaviour on few body filters installed */
ngx_int_t
ngx_http_modsecurity_body_filter_init(void)
{
ngx_http_next_body_filter = ngx_http_top_body_filter;
ngx_http_top_body_filter = ngx_http_modsecurity_body_filter;
return NGX_OK;
}
ngx_int_t
ngx_http_modsecurity_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
{
ngx_chain_t *chain = in;
ngx_http_modsecurity_ctx_t *ctx = NULL;
#if defined(MODSECURITY_SANITY_CHECKS) && (MODSECURITY_SANITY_CHECKS)
ngx_http_modsecurity_conf_t *mcf;
ngx_list_part_t *part = &r->headers_out.headers.part;
ngx_table_elt_t *data = part->elts;
ngx_uint_t i = 0;
#endif
if (in == NULL) {
return ngx_http_next_body_filter(r, in);
}
ctx = ngx_http_get_module_ctx(r, ngx_http_modsecurity_module);
dd("body filter, recovering ctx: %p", ctx);
if (ctx == NULL) {
return ngx_http_next_body_filter(r, in);
}
if (ctx->intervention_triggered) {
return ngx_http_next_body_filter(r, in);
}
#if defined(MODSECURITY_SANITY_CHECKS) && (MODSECURITY_SANITY_CHECKS)
mcf = ngx_http_get_module_loc_conf(r, ngx_http_modsecurity_module);
if (mcf != NULL && mcf->sanity_checks_enabled != NGX_CONF_UNSET)
{
#if 0
dd("dumping stored ctx headers");
for (i = 0; i < ctx->sanity_headers_out->nelts; i++)
{
ngx_http_modsecurity_header_t *vals = ctx->sanity_headers_out->elts;
ngx_str_t *s2 = &vals[i].name, *s3 = &vals[i].value;
dd(" dump[%d]: name = '%.*s', value = '%.*s'", (int)i,
(int)s2->len, (char*)s2->data,
(int)s3->len, (char*)s3->data);
}
#endif
/*
* Identify if there is a header that was not inspected by ModSecurity.
*/
int worth_to_fail = 0;
for (i = 0; ; i++)
{
int found = 0;
ngx_uint_t j = 0;
ngx_table_elt_t *s1;
ngx_http_modsecurity_header_t *vals;
if (i >= part->nelts)
{
if (part->next == NULL) {
break;
}
part = part->next;
data = part->elts;
i = 0;
}
vals = ctx->sanity_headers_out->elts;
s1 = &data[i];
/*
* Headers that were inspected by ModSecurity.
*/
while (j < ctx->sanity_headers_out->nelts)
{
ngx_str_t *s2 = &vals[j].name;
ngx_str_t *s3 = &vals[j].value;
if (s1->key.len == s2->len && ngx_strncmp(s1->key.data, s2->data, s1->key.len) == 0)
{
if (s1->value.len == s3->len && ngx_strncmp(s1->value.data, s3->data, s1->value.len) == 0)
{
found = 1;
break;
}
}
j++;
}
if (!found) {
dd("header: `%.*s' with value: `%.*s' was not inspected by ModSecurity",
(int) s1->key.len,
(const char *) s1->key.data,
(int) s1->value.len,
(const char *) s1->value.data);
worth_to_fail++;
}
}
if (worth_to_fail)
{
dd("%d header(s) were not inspected by ModSecurity, so exiting", worth_to_fail);
return ngx_http_filter_finalize_request(r,
&ngx_http_modsecurity_module, NGX_HTTP_INTERNAL_SERVER_ERROR);
}
}
#endif
int is_request_processed = 0;
for (; chain != NULL; chain = chain->next)
{
u_char *data = chain->buf->pos;
int ret;
msc_append_response_body(ctx->modsec_transaction, data, chain->buf->last - data);
ret = ngx_http_modsecurity_process_intervention(ctx->modsec_transaction, r, 0);
if (ret > 0) {
return ngx_http_filter_finalize_request(r,
&ngx_http_modsecurity_module, ret);
}
/* XXX: chain->buf->last_buf || chain->buf->last_in_chain */
is_request_processed = chain->buf->last_buf;
if (is_request_processed) {
ngx_pool_t *old_pool;
old_pool = ngx_http_modsecurity_pcre_malloc_init(r->pool);
msc_process_response_body(ctx->modsec_transaction);
ngx_http_modsecurity_pcre_malloc_done(old_pool);
/* XXX: I don't get how body from modsec being transferred to nginx's buffer. If so - after adjusting of nginx's
XXX: body we can proceed to adjust body size (content-length). see xslt_body_filter() for example */
ret = ngx_http_modsecurity_process_intervention(ctx->modsec_transaction, r, 0);
if (ret > 0) {
return ret;
}
else if (ret < 0) {
return ngx_http_filter_finalize_request(r,
&ngx_http_modsecurity_module, NGX_HTTP_INTERNAL_SERVER_ERROR);
}
}
}
if (!is_request_processed)
{
dd("buffer was not fully loaded! ctx: %p", ctx);
}
/* XXX: xflt_filter() -- return NGX_OK here */
return ngx_http_next_body_filter(r, in);
}

View File

@ -0,0 +1,173 @@
/*
* ModSecurity connector for nginx, http://www.modsecurity.org/
* Copyright (c) 2015 Trustwave Holdings, Inc. (http://www.trustwave.com/)
*
* You may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* If any of the files related to licensing are missing or if you have any
* other questions related to licensing please contact Trustwave Holdings, Inc.
* directly using the email address security@modsecurity.org.
*
*/
#ifndef _NGX_HTTP_MODSECURITY_COMMON_H_INCLUDED_
#define _NGX_HTTP_MODSECURITY_COMMON_H_INCLUDED_
#include <nginx.h>
#include <ngx_config.h>
#include <ngx_core.h>
#include <ngx_http.h>
#include <modsecurity/modsecurity.h>
#include <modsecurity/transaction.h>
/* #define MSC_USE_RULES_SET 1 */
#if defined(MODSECURITY_CHECK_VERSION)
#if MODSECURITY_VERSION_NUM >= 304010
#define MSC_USE_RULES_SET 1
#endif
#endif
#if defined(MSC_USE_RULES_SET)
#include <modsecurity/rules_set.h>
#else
#include <modsecurity/rules.h>
#endif
/**
* TAG_NUM:
*
* Alpha - 001
* Beta - 002
* Dev - 010
* Rc1 - 051
* Rc2 - 052
* ... - ...
* Release- 100
*
*/
#define MODSECURITY_NGINX_MAJOR "1"
#define MODSECURITY_NGINX_MINOR "0"
#define MODSECURITY_NGINX_PATCHLEVEL "3"
#define MODSECURITY_NGINX_TAG ""
#define MODSECURITY_NGINX_TAG_NUM "100"
#define MODSECURITY_NGINX_VERSION MODSECURITY_NGINX_MAJOR "." \
MODSECURITY_NGINX_MINOR "." MODSECURITY_NGINX_PATCHLEVEL \
MODSECURITY_NGINX_TAG
#define MODSECURITY_NGINX_VERSION_NUM MODSECURITY_NGINX_MAJOR \
MODSECURITY_NGINX_MINOR MODSECURITY_NGINX_PATCHLEVEL \
MODSECURITY_NGINX_TAG_NUM
#define MODSECURITY_NGINX_WHOAMI "ModSecurity-nginx v" \
MODSECURITY_NGINX_VERSION
typedef struct {
ngx_str_t name;
ngx_str_t value;
} ngx_http_modsecurity_header_t;
typedef struct {
ngx_http_request_t *r;
Transaction *modsec_transaction;
ModSecurityIntervention *delayed_intervention;
#if defined(MODSECURITY_SANITY_CHECKS) && (MODSECURITY_SANITY_CHECKS)
/*
* Should be filled with the headers that were sent to ModSecurity.
*
* The idea is to compare this set of headers with the headers that were
* sent to the client. This check was placed because we don't have control
* over other modules, thus, we may partially inspect the headers.
*
*/
ngx_array_t *sanity_headers_out;
#endif
unsigned waiting_more_body:1;
unsigned body_requested:1;
unsigned processed:1;
unsigned logged:1;
unsigned intervention_triggered:1;
} ngx_http_modsecurity_ctx_t;
typedef struct {
void *pool;
ModSecurity *modsec;
ngx_uint_t rules_inline;
ngx_uint_t rules_file;
ngx_uint_t rules_remote;
} ngx_http_modsecurity_main_conf_t;
typedef struct {
void *pool;
/* RulesSet or Rules */
void *rules_set;
ngx_flag_t enable;
#if defined(MODSECURITY_SANITY_CHECKS) && (MODSECURITY_SANITY_CHECKS)
ngx_flag_t sanity_checks_enabled;
#endif
ngx_http_complex_value_t *transaction_id;
} ngx_http_modsecurity_conf_t;
typedef ngx_int_t (*ngx_http_modsecurity_resolv_header_pt)(ngx_http_request_t *r, ngx_str_t name, off_t offset);
typedef struct {
ngx_str_t name;
ngx_uint_t offset;
ngx_http_modsecurity_resolv_header_pt resolver;
} ngx_http_modsecurity_header_out_t;
extern ngx_module_t ngx_http_modsecurity_module;
/* ngx_http_modsecurity_module.c */
int ngx_http_modsecurity_process_intervention (Transaction *transaction, ngx_http_request_t *r, ngx_int_t early_log);
ngx_http_modsecurity_ctx_t *ngx_http_modsecurity_create_ctx(ngx_http_request_t *r);
char *ngx_str_to_char(ngx_str_t a, ngx_pool_t *p);
#if (NGX_PCRE2)
#define ngx_http_modsecurity_pcre_malloc_init(x) NULL
#define ngx_http_modsecurity_pcre_malloc_done(x) (void)x
#else
ngx_pool_t *ngx_http_modsecurity_pcre_malloc_init(ngx_pool_t *pool);
void ngx_http_modsecurity_pcre_malloc_done(ngx_pool_t *old_pool);
#endif
/* ngx_http_modsecurity_body_filter.c */
ngx_int_t ngx_http_modsecurity_body_filter_init(void);
ngx_int_t ngx_http_modsecurity_body_filter(ngx_http_request_t *r, ngx_chain_t *in);
/* ngx_http_modsecurity_header_filter.c */
ngx_int_t ngx_http_modsecurity_header_filter_init(void);
ngx_int_t ngx_http_modsecurity_header_filter(ngx_http_request_t *r);
#if defined(MODSECURITY_SANITY_CHECKS) && (MODSECURITY_SANITY_CHECKS)
int ngx_http_modsecurity_store_ctx_header(ngx_http_request_t *r, ngx_str_t *name, ngx_str_t *value);
#endif
/* ngx_http_modsecurity_log.c */
void ngx_http_modsecurity_log(void *log, const void* data);
ngx_int_t ngx_http_modsecurity_log_handler(ngx_http_request_t *r);
/* ngx_http_modsecurity_access.c */
ngx_int_t ngx_http_modsecurity_access_handler(ngx_http_request_t *r);
/* ngx_http_modsecurity_rewrite.c */
ngx_int_t ngx_http_modsecurity_rewrite_handler(ngx_http_request_t *r);
#endif /* _NGX_HTTP_MODSECURITY_COMMON_H_INCLUDED_ */

View File

@ -0,0 +1,558 @@
/*
* ModSecurity connector for nginx, http://www.modsecurity.org/
* Copyright (c) 2015 Trustwave Holdings, Inc. (http://www.trustwave.com/)
*
* You may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* If any of the files related to licensing are missing or if you have any
* other questions related to licensing please contact Trustwave Holdings, Inc.
* directly using the email address security@modsecurity.org.
*
*/
#ifndef MODSECURITY_DDEBUG
#define MODSECURITY_DDEBUG 0
#endif
#include "ddebug.h"
#include "ngx_http_modsecurity_common.h"
static ngx_http_output_header_filter_pt ngx_http_next_header_filter;
static ngx_int_t ngx_http_modsecurity_resolv_header_server(ngx_http_request_t *r, ngx_str_t name, off_t offset);
static ngx_int_t ngx_http_modsecurity_resolv_header_date(ngx_http_request_t *r, ngx_str_t name, off_t offset);
static ngx_int_t ngx_http_modsecurity_resolv_header_content_length(ngx_http_request_t *r, ngx_str_t name, off_t offset);
static ngx_int_t ngx_http_modsecurity_resolv_header_content_type(ngx_http_request_t *r, ngx_str_t name, off_t offset);
static ngx_int_t ngx_http_modsecurity_resolv_header_last_modified(ngx_http_request_t *r, ngx_str_t name, off_t offset);
static ngx_int_t ngx_http_modsecurity_resolv_header_connection(ngx_http_request_t *r, ngx_str_t name, off_t offset);
static ngx_int_t ngx_http_modsecurity_resolv_header_transfer_encoding(ngx_http_request_t *r, ngx_str_t name, off_t offset);
static ngx_int_t ngx_http_modsecurity_resolv_header_vary(ngx_http_request_t *r, ngx_str_t name, off_t offset);
ngx_http_modsecurity_header_out_t ngx_http_modsecurity_headers_out[] = {
{ ngx_string("Server"),
offsetof(ngx_http_headers_out_t, server),
ngx_http_modsecurity_resolv_header_server },
{ ngx_string("Date"),
offsetof(ngx_http_headers_out_t, date),
ngx_http_modsecurity_resolv_header_date },
{ ngx_string("Content-Length"),
offsetof(ngx_http_headers_out_t, content_length_n),
ngx_http_modsecurity_resolv_header_content_length },
{ ngx_string("Content-Type"),
offsetof(ngx_http_headers_out_t, content_type),
ngx_http_modsecurity_resolv_header_content_type },
{ ngx_string("Last-Modified"),
offsetof(ngx_http_headers_out_t, last_modified),
ngx_http_modsecurity_resolv_header_last_modified },
{ ngx_string("Connection"),
0,
ngx_http_modsecurity_resolv_header_connection },
{ ngx_string("Transfer-Encoding"),
0,
ngx_http_modsecurity_resolv_header_transfer_encoding },
{ ngx_string("Vary"),
0,
ngx_http_modsecurity_resolv_header_vary },
#if 0
{ ngx_string("Content-Encoding"),
offsetof(ngx_http_headers_out_t, content_encoding),
NGX_TABLE },
{ ngx_string("Cache-Control"),
offsetof(ngx_http_headers_out_t, cache_control),
NGX_ARRAY },
{ ngx_string("Location"),
offsetof(ngx_http_headers_out_t, location),
NGX_TABLE },
{ ngx_string("Content-Range"),
offsetof(ngx_http_headers_out_t, content_range),
NGX_TABLE },
{ ngx_string("Accept-Ranges"),
offsetof(ngx_http_headers_out_t, accept_ranges),
NGX_TABLE },
returiders_out[i].name 1;
{ ngx_string("WWW-Authenticate"),
offsetof(ngx_http_headers_out_t, www_authenticate),
NGX_TABLE },
{ ngx_string("Expires"),
offsetof(ngx_http_headers_out_t, expires),
NGX_TABLE },
#endif
{ ngx_null_string, 0, 0 }
};
#if defined(MODSECURITY_SANITY_CHECKS) && (MODSECURITY_SANITY_CHECKS)
int
ngx_http_modsecurity_store_ctx_header(ngx_http_request_t *r, ngx_str_t *name, ngx_str_t *value)
{
ngx_http_modsecurity_ctx_t *ctx;
ngx_http_modsecurity_conf_t *mcf;
ngx_http_modsecurity_header_t *hdr;
ctx = ngx_http_get_module_ctx(r, ngx_http_modsecurity_module);
if (ctx == NULL || ctx->sanity_headers_out == NULL) {
return NGX_ERROR;
}
mcf = ngx_http_get_module_loc_conf(r, ngx_http_modsecurity_module);
if (mcf == NULL || mcf->sanity_checks_enabled == NGX_CONF_UNSET)
{
return NGX_OK;
}
hdr = ngx_array_push(ctx->sanity_headers_out);
if (hdr == NULL) {
return NGX_ERROR;
}
hdr->name.data = ngx_pnalloc(r->pool, name->len);
hdr->value.data = ngx_pnalloc(r->pool, value->len);
if (hdr->name.data == NULL || hdr->value.data == NULL) {
return NGX_ERROR;
}
ngx_memcpy(hdr->name.data, name->data, name->len);
hdr->name.len = name->len;
ngx_memcpy(hdr->value.data, value->data, value->len);
hdr->value.len = value->len;
return NGX_OK;
}
#endif
static ngx_int_t
ngx_http_modsecurity_resolv_header_server(ngx_http_request_t *r, ngx_str_t name, off_t offset)
{
static char ngx_http_server_full_string[] = NGINX_VER;
static char ngx_http_server_string[] = "nginx";
ngx_http_core_loc_conf_t *clcf = NULL;
ngx_http_modsecurity_ctx_t *ctx = NULL;
ngx_str_t value;
clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
ctx = ngx_http_get_module_ctx(r, ngx_http_modsecurity_module);
if (r->headers_out.server == NULL) {
if (clcf->server_tokens) {
value.data = (u_char *)ngx_http_server_full_string;
value.len = sizeof(ngx_http_server_full_string);
} else {
value.data = (u_char *)ngx_http_server_string;
value.len = sizeof(ngx_http_server_string);
}
} else {
ngx_table_elt_t *h = r->headers_out.server;
value.data = h->value.data;
value.len = h->value.len;
}
#if defined(MODSECURITY_SANITY_CHECKS) && (MODSECURITY_SANITY_CHECKS)
ngx_http_modsecurity_store_ctx_header(r, &name, &value);
#endif
return msc_add_n_response_header(ctx->modsec_transaction,
(const unsigned char *) name.data,
name.len,
(const unsigned char *) value.data,
value.len);
}
static ngx_int_t
ngx_http_modsecurity_resolv_header_date(ngx_http_request_t *r, ngx_str_t name, off_t offset)
{
ngx_http_modsecurity_ctx_t *ctx = NULL;
ngx_str_t date;
ctx = ngx_http_get_module_ctx(r, ngx_http_modsecurity_module);
if (r->headers_out.date == NULL) {
date.data = ngx_cached_http_time.data;
date.len = ngx_cached_http_time.len;
} else {
ngx_table_elt_t *h = r->headers_out.date;
date.data = h->value.data;
date.len = h->value.len;
}
#if defined(MODSECURITY_SANITY_CHECKS) && (MODSECURITY_SANITY_CHECKS)
ngx_http_modsecurity_store_ctx_header(r, &name, &date);
#endif
return msc_add_n_response_header(ctx->modsec_transaction,
(const unsigned char *) name.data,
name.len,
(const unsigned char *) date.data,
date.len);
}
static ngx_int_t
ngx_http_modsecurity_resolv_header_content_length(ngx_http_request_t *r, ngx_str_t name, off_t offset)
{
ngx_http_modsecurity_ctx_t *ctx = NULL;
ngx_str_t value;
char buf[NGX_INT64_LEN+2];
ctx = ngx_http_get_module_ctx(r, ngx_http_modsecurity_module);
if (r->headers_out.content_length_n > 0)
{
ngx_sprintf((u_char *)buf, "%O%Z", r->headers_out.content_length_n);
value.data = (unsigned char *)buf;
value.len = strlen(buf);
#if defined(MODSECURITY_SANITY_CHECKS) && (MODSECURITY_SANITY_CHECKS)
ngx_http_modsecurity_store_ctx_header(r, &name, &value);
#endif
return msc_add_n_response_header(ctx->modsec_transaction,
(const unsigned char *) name.data,
name.len,
(const unsigned char *) value.data,
value.len);
}
return 1;
}
static ngx_int_t
ngx_http_modsecurity_resolv_header_content_type(ngx_http_request_t *r, ngx_str_t name, off_t offset)
{
ngx_http_modsecurity_ctx_t *ctx = NULL;
ctx = ngx_http_get_module_ctx(r, ngx_http_modsecurity_module);
if (r->headers_out.content_type.len > 0)
{
#if defined(MODSECURITY_SANITY_CHECKS) && (MODSECURITY_SANITY_CHECKS)
ngx_http_modsecurity_store_ctx_header(r, &name, &r->headers_out.content_type);
#endif
return msc_add_n_response_header(ctx->modsec_transaction,
(const unsigned char *) name.data,
name.len,
(const unsigned char *) r->headers_out.content_type.data,
r->headers_out.content_type.len);
}
return 1;
}
static ngx_int_t
ngx_http_modsecurity_resolv_header_last_modified(ngx_http_request_t *r, ngx_str_t name, off_t offset)
{
ngx_http_modsecurity_ctx_t *ctx = NULL;
u_char buf[1024], *p;
ngx_str_t value;
ctx = ngx_http_get_module_ctx(r, ngx_http_modsecurity_module);
if (r->headers_out.last_modified_time == -1) {
return 1;
}
p = ngx_http_time(buf, r->headers_out.last_modified_time);
value.data = buf;
value.len = (int)(p-buf);
#if defined(MODSECURITY_SANITY_CHECKS) && (MODSECURITY_SANITY_CHECKS)
ngx_http_modsecurity_store_ctx_header(r, &name, &value);
#endif
return msc_add_n_response_header(ctx->modsec_transaction,
(const unsigned char *) name.data,
name.len,
(const unsigned char *) value.data,
value.len);
}
static ngx_int_t
ngx_http_modsecurity_resolv_header_connection(ngx_http_request_t *r, ngx_str_t name, off_t offset)
{
ngx_http_modsecurity_ctx_t *ctx = NULL;
ngx_http_core_loc_conf_t *clcf = NULL;
char *connection = NULL;
ngx_str_t value;
clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
ctx = ngx_http_get_module_ctx(r, ngx_http_modsecurity_module);
if (r->headers_out.status == NGX_HTTP_SWITCHING_PROTOCOLS) {
connection = "upgrade";
} else if (r->keepalive) {
connection = "keep-alive";
if (clcf->keepalive_header)
{
u_char buf[1024];
ngx_sprintf(buf, "timeout=%T%Z", clcf->keepalive_header);
ngx_str_t name2 = ngx_string("Keep-Alive");
value.data = buf;
value.len = strlen((char *)buf);
#if defined(MODSECURITY_SANITY_CHECKS) && (MODSECURITY_SANITY_CHECKS)
ngx_http_modsecurity_store_ctx_header(r, &name2, &value);
#endif
msc_add_n_response_header(ctx->modsec_transaction,
(const unsigned char *) name2.data,
name2.len,
(const unsigned char *) value.data,
value.len);
}
} else {
connection = "close";
}
value.data = (u_char *) connection;
value.len = strlen(connection);
#if defined(MODSECURITY_SANITY_CHECKS) && (MODSECURITY_SANITY_CHECKS)
ngx_http_modsecurity_store_ctx_header(r, &name, &value);
#endif
return msc_add_n_response_header(ctx->modsec_transaction,
(const unsigned char *) name.data,
name.len,
(const unsigned char *) value.data,
value.len);
}
static ngx_int_t
ngx_http_modsecurity_resolv_header_transfer_encoding(ngx_http_request_t *r, ngx_str_t name, off_t offset)
{
ngx_http_modsecurity_ctx_t *ctx = NULL;
if (r->chunked) {
ngx_str_t value = ngx_string("chunked");
ctx = ngx_http_get_module_ctx(r, ngx_http_modsecurity_module);
#if defined(MODSECURITY_SANITY_CHECKS) && (MODSECURITY_SANITY_CHECKS)
ngx_http_modsecurity_store_ctx_header(r, &name, &value);
#endif
return msc_add_n_response_header(ctx->modsec_transaction,
(const unsigned char *) name.data,
name.len,
(const unsigned char *) value.data,
value.len);
}
return 1;
}
static ngx_int_t
ngx_http_modsecurity_resolv_header_vary(ngx_http_request_t *r, ngx_str_t name, off_t offset)
{
#if (NGX_HTTP_GZIP)
ngx_http_modsecurity_ctx_t *ctx = NULL;
ngx_http_core_loc_conf_t *clcf = NULL;
clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
if (r->gzip_vary && clcf->gzip_vary) {
ngx_str_t value = ngx_string("Accept-Encoding");
ctx = ngx_http_get_module_ctx(r, ngx_http_modsecurity_module);
#if defined(MODSECURITY_SANITY_CHECKS) && (MODSECURITY_SANITY_CHECKS)
ngx_http_modsecurity_store_ctx_header(r, &name, &value);
#endif
return msc_add_n_response_header(ctx->modsec_transaction,
(const unsigned char *) name.data,
name.len,
(const unsigned char *) value.data,
value.len);
}
#endif
return 1;
}
ngx_int_t
ngx_http_modsecurity_header_filter_init(void)
{
ngx_http_next_header_filter = ngx_http_top_header_filter;
ngx_http_top_header_filter = ngx_http_modsecurity_header_filter;
return NGX_OK;
}
ngx_int_t
ngx_http_modsecurity_header_filter(ngx_http_request_t *r)
{
ngx_http_modsecurity_ctx_t *ctx;
ngx_list_part_t *part = &r->headers_out.headers.part;
ngx_table_elt_t *data = part->elts;
ngx_uint_t i = 0;
int ret = 0;
ngx_uint_t status;
char *http_response_ver;
ngx_pool_t *old_pool;
/* XXX: if NOT_MODIFIED, do we need to process it at all? see xslt_header_filter() */
ctx = ngx_http_get_module_ctx(r, ngx_http_modsecurity_module);
dd("header filter, recovering ctx: %p", ctx);
if (ctx == NULL)
{
dd("something really bad happened or ModSecurity is disabled. going to the next filter.");
return ngx_http_next_header_filter(r);
}
if (ctx->intervention_triggered) {
return ngx_http_next_header_filter(r);
}
/* XXX: can it happen ? already processed i mean */
/* XXX: check behaviour on 'ModSecurity off' */
if (ctx && ctx->processed)
{
/*
* FIXME: verify if this request is already processed.
*/
dd("Already processed... going to the next header...");
return ngx_http_next_header_filter(r);
}
/*
* Lets ask nginx to keep the response body in memory
*
* FIXME: I don't see a reason to keep it `1' when SecResponseBody is disabled.
*/
r->filter_need_in_memory = 1;
ctx->processed = 1;
/*
*
* Assuming ModSecurity module is running immediately before the
* ngx_http_header_filter, we will be able to populate ModSecurity with
* headers from the headers_out structure.
*
* As ngx_http_header_filter place a direct call to the
* ngx_http_write_filter_module, we cannot hook between those two. In order
* to enumerate all headers, we first look at the headers_out structure,
* and later we look into the ngx_list_part_t. The ngx_list_part_t must be
* checked. Other module(s) in the chain may added some content to it.
*
*/
for (i = 0; ngx_http_modsecurity_headers_out[i].name.len; i++)
{
dd(" Sending header to ModSecurity - header: `%.*s'.",
(int) ngx_http_modsecurity_headers_out[i].name.len,
ngx_http_modsecurity_headers_out[i].name.data);
ngx_http_modsecurity_headers_out[i].resolver(r,
ngx_http_modsecurity_headers_out[i].name,
ngx_http_modsecurity_headers_out[i].offset);
}
for (i = 0 ;; i++)
{
if (i >= part->nelts)
{
if (part->next == NULL) {
break;
}
part = part->next;
data = part->elts;
i = 0;
}
#if defined(MODSECURITY_SANITY_CHECKS) && (MODSECURITY_SANITY_CHECKS)
ngx_http_modsecurity_store_ctx_header(r, &data[i].key, &data[i].value);
#endif
/*
* Doing this ugly cast here, explanation on the request_header
*/
msc_add_n_response_header(ctx->modsec_transaction,
(const unsigned char *) data[i].key.data,
data[i].key.len,
(const unsigned char *) data[i].value.data,
data[i].value.len);
}
/* prepare extra paramters for msc_process_response_headers() */
if (r->err_status) {
status = r->err_status;
} else {
status = r->headers_out.status;
}
/*
* NGINX always sends HTTP response with HTTP/1.1, except cases when
* HTTP V2 module is enabled, and request has been posted with HTTP/2.0.
*/
http_response_ver = "HTTP 1.1";
#if (NGX_HTTP_V2)
if (r->stream) {
http_response_ver = "HTTP 2.0";
}
#endif
old_pool = ngx_http_modsecurity_pcre_malloc_init(r->pool);
msc_process_response_headers(ctx->modsec_transaction, status, http_response_ver);
ngx_http_modsecurity_pcre_malloc_done(old_pool);
ret = ngx_http_modsecurity_process_intervention(ctx->modsec_transaction, r, 0);
if (r->error_page) {
return ngx_http_next_header_filter(r);
}
if (ret > 0) {
return ngx_http_filter_finalize_request(r, &ngx_http_modsecurity_module, ret);
}
/*
* Proxies will not like this... but it is necessary to unset
* the content length in order to manipulate the content of
* response body in ModSecurity.
*
* This header may arrive at the client before ModSecurity had
* a change to make any modification. That is why it is necessary
* to set this to -1 here.
*
* We need to have some kind of flag the decide if ModSecurity
* will make a modification or not. If not, keep the content and
* make the proxy servers happy.
*
*/
/*
* The line below is commented to make the spdy test to work
*/
//r->headers_out.content_length_n = -1;
return ngx_http_next_header_filter(r);
}

View File

@ -0,0 +1,81 @@
/*
* ModSecurity connector for nginx, http://www.modsecurity.org/
* Copyright (c) 2015 Trustwave Holdings, Inc. (http://www.trustwave.com/)
*
* You may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* If any of the files related to licensing are missing or if you have any
* other questions related to licensing please contact Trustwave Holdings, Inc.
* directly using the email address security@modsecurity.org.
*
*/
#ifndef MODSECURITY_DDEBUG
#define MODSECURITY_DDEBUG 0
#endif
#include "ddebug.h"
#include "ngx_http_modsecurity_common.h"
void
ngx_http_modsecurity_log(void *log, const void* data)
{
const char *msg;
if (log == NULL) {
return;
}
msg = (const char *) data;
ngx_log_error(NGX_LOG_WARN, (ngx_log_t *)log, 0, "%s", msg);
}
ngx_int_t
ngx_http_modsecurity_log_handler(ngx_http_request_t *r)
{
ngx_pool_t *old_pool;
ngx_http_modsecurity_ctx_t *ctx;
ngx_http_modsecurity_conf_t *mcf;
dd("catching a new _log_ phase handler");
mcf = ngx_http_get_module_loc_conf(r, ngx_http_modsecurity_module);
if (mcf == NULL || mcf->enable != 1)
{
dd("ModSecurity not enabled... returning");
return NGX_OK;
}
/*
if (r->method != NGX_HTTP_GET &&
r->method != NGX_HTTP_POST && r->method != NGX_HTTP_HEAD) {
dd("ModSecurity is not ready to deal with anything different from " \
"POST, GET or HEAD");
return NGX_OK;
}
*/
ctx = ngx_http_get_module_ctx(r, ngx_http_modsecurity_module);
dd("recovering ctx: %p", ctx);
if (ctx == NULL) {
dd("something really bad happened here. returning NGX_ERROR");
return NGX_ERROR;
}
if (ctx->logged) {
dd("already logged earlier");
return NGX_OK;
}
dd("calling msc_process_logging for %p", ctx);
old_pool = ngx_http_modsecurity_pcre_malloc_init(r->pool);
msc_process_logging(ctx->modsec_transaction);
ngx_http_modsecurity_pcre_malloc_done(old_pool);
return NGX_OK;
}

View File

@ -0,0 +1,793 @@
/*
* ModSecurity connector for nginx, http://www.modsecurity.org/
* Copyright (c) 2015 Trustwave Holdings, Inc. (http://www.trustwave.com/)
*
* You may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* If any of the files related to licensing are missing or if you have any
* other questions related to licensing please contact Trustwave Holdings, Inc.
* directly using the email address security@modsecurity.org.
*
*/
#ifndef MODSECURITY_DDEBUG
#define MODSECURITY_DDEBUG 0
#endif
#include "ddebug.h"
#include "ngx_http_modsecurity_common.h"
#include "stdio.h"
#include <ngx_config.h>
#include <ngx_core.h>
#include <ngx_http.h>
static ngx_int_t ngx_http_modsecurity_init(ngx_conf_t *cf);
static void *ngx_http_modsecurity_create_main_conf(ngx_conf_t *cf);
static char *ngx_http_modsecurity_init_main_conf(ngx_conf_t *cf, void *conf);
static void *ngx_http_modsecurity_create_conf(ngx_conf_t *cf);
static char *ngx_http_modsecurity_merge_conf(ngx_conf_t *cf, void *parent, void *child);
static void ngx_http_modsecurity_cleanup_instance(void *data);
static void ngx_http_modsecurity_cleanup_rules(void *data);
/*
* PCRE malloc/free workaround, based on
* https://github.com/openresty/lua-nginx-module/blob/master/src/ngx_http_lua_pcrefix.c
*/
#if !(NGX_PCRE2)
static void *(*old_pcre_malloc)(size_t);
static void (*old_pcre_free)(void *ptr);
static ngx_pool_t *ngx_http_modsec_pcre_pool = NULL;
static void *
ngx_http_modsec_pcre_malloc(size_t size)
{
if (ngx_http_modsec_pcre_pool) {
return ngx_palloc(ngx_http_modsec_pcre_pool, size);
}
fprintf(stderr, "error: modsec pcre malloc failed due to empty pcre pool");
return NULL;
}
static void
ngx_http_modsec_pcre_free(void *ptr)
{
if (ngx_http_modsec_pcre_pool) {
ngx_pfree(ngx_http_modsec_pcre_pool, ptr);
return;
}
#if 0
/* this may happen when called from cleanup handlers */
fprintf(stderr, "error: modsec pcre free failed due to empty pcre pool");
#endif
return;
}
ngx_pool_t *
ngx_http_modsecurity_pcre_malloc_init(ngx_pool_t *pool)
{
ngx_pool_t *old_pool;
if (pcre_malloc != ngx_http_modsec_pcre_malloc) {
ngx_http_modsec_pcre_pool = pool;
old_pcre_malloc = pcre_malloc;
old_pcre_free = pcre_free;
pcre_malloc = ngx_http_modsec_pcre_malloc;
pcre_free = ngx_http_modsec_pcre_free;
return NULL;
}
old_pool = ngx_http_modsec_pcre_pool;
ngx_http_modsec_pcre_pool = pool;
return old_pool;
}
void
ngx_http_modsecurity_pcre_malloc_done(ngx_pool_t *old_pool)
{
ngx_http_modsec_pcre_pool = old_pool;
if (old_pool == NULL) {
pcre_malloc = old_pcre_malloc;
pcre_free = old_pcre_free;
}
}
#endif
/*
* ngx_string's are not null-terminated in common case, so we need to convert
* them into null-terminated ones before passing to ModSecurity
*/
ngx_inline char *ngx_str_to_char(ngx_str_t a, ngx_pool_t *p)
{
char *str = NULL;
if (a.len == 0) {
return NULL;
}
str = ngx_pnalloc(p, a.len+1);
if (str == NULL) {
dd("failed to allocate memory to convert space ngx_string to C string");
/* We already returned NULL for an empty string, so return -1 here to indicate allocation error */
return (char *)-1;
}
ngx_memcpy(str, a.data, a.len);
str[a.len] = '\0';
return str;
}
ngx_inline int
ngx_http_modsecurity_process_intervention (Transaction *transaction, ngx_http_request_t *r, ngx_int_t early_log)
{
char *log = NULL;
ModSecurityIntervention intervention;
intervention.status = 200;
intervention.url = NULL;
intervention.log = NULL;
intervention.disruptive = 0;
ngx_http_modsecurity_ctx_t *ctx = NULL;
dd("processing intervention");
ctx = ngx_http_get_module_ctx(r, ngx_http_modsecurity_module);
if (ctx == NULL)
{
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
if (msc_intervention(transaction, &intervention) == 0) {
dd("nothing to do");
return 0;
}
log = intervention.log;
if (intervention.log == NULL) {
log = "(no log message was specified)";
}
ngx_log_error(NGX_LOG_ERR, (ngx_log_t *)r->connection->log, 0, "%s", log);
if (intervention.log != NULL) {
free(intervention.log);
}
if (intervention.url != NULL)
{
dd("intervention -- redirecting to: %s with status code: %d", intervention.url, intervention.status);
if (r->header_sent)
{
dd("Headers are already sent. Cannot perform the redirection at this point.");
return -1;
}
/**
* Not sure if it sane to do this indepent of the phase
* but, here we go...
*
* This code cames from: http/ngx_http_special_response.c
* function: ngx_http_send_error_page
* src/http/ngx_http_core_module.c
* From src/http/ngx_http_core_module.c (line 1910) i learnt
* that location->hash should be set to 1.
*
*/
ngx_http_clear_location(r);
ngx_str_t a = ngx_string("");
a.data = (unsigned char *)intervention.url;
a.len = strlen(intervention.url);
ngx_table_elt_t *location = NULL;
location = ngx_list_push(&r->headers_out.headers);
ngx_str_set(&location->key, "Location");
location->value = a;
r->headers_out.location = location;
r->headers_out.location->hash = 1;
#if defined(MODSECURITY_SANITY_CHECKS) && (MODSECURITY_SANITY_CHECKS)
ngx_http_modsecurity_store_ctx_header(r, &location->key, &location->value);
#endif
return intervention.status;
}
if (intervention.status != 200)
{
/**
* FIXME: this will bring proper response code to audit log in case
* when e.g. error_page redirect was triggered, but there still won't be another
* required pieces like response headers etc.
*
*/
msc_update_status_code(ctx->modsec_transaction, intervention.status);
if (early_log) {
dd("intervention -- calling log handler manually with code: %d", intervention.status);
ngx_http_modsecurity_log_handler(r);
ctx->logged = 1;
}
if (r->header_sent)
{
dd("Headers are already sent. Cannot perform the redirection at this point.");
return -1;
}
dd("intervention -- returning code: %d", intervention.status);
return intervention.status;
}
return 0;
}
void
ngx_http_modsecurity_cleanup(void *data)
{
ngx_http_modsecurity_ctx_t *ctx;
ctx = (ngx_http_modsecurity_ctx_t *) data;
msc_transaction_cleanup(ctx->modsec_transaction);
#if defined(MODSECURITY_SANITY_CHECKS) && (MODSECURITY_SANITY_CHECKS)
/*
* Purge stored context headers. Memory allocated for individual stored header
* name/value pair will be freed automatically when r->pool is destroyed.
*/
ngx_array_destroy(ctx->sanity_headers_out);
#endif
}
ngx_inline ngx_http_modsecurity_ctx_t *
ngx_http_modsecurity_create_ctx(ngx_http_request_t *r)
{
ngx_str_t s;
ngx_pool_cleanup_t *cln;
ngx_http_modsecurity_ctx_t *ctx;
ngx_http_modsecurity_conf_t *mcf;
ngx_http_modsecurity_main_conf_t *mmcf;
ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_modsecurity_ctx_t));
if (ctx == NULL)
{
dd("failed to allocate memory for the context.");
return NULL;
}
mmcf = ngx_http_get_module_main_conf(r, ngx_http_modsecurity_module);
mcf = ngx_http_get_module_loc_conf(r, ngx_http_modsecurity_module);
dd("creating transaction with the following rules: '%p' -- ms: '%p'", mcf->rules_set, mmcf->modsec);
if (mcf->transaction_id) {
if (ngx_http_complex_value(r, mcf->transaction_id, &s) != NGX_OK) {
return NGX_CONF_ERROR;
}
ctx->modsec_transaction = msc_new_transaction_with_id(mmcf->modsec, mcf->rules_set, (char *) s.data, r->connection->log);
} else {
ctx->modsec_transaction = msc_new_transaction(mmcf->modsec, mcf->rules_set, r->connection->log);
}
dd("transaction created");
ngx_http_set_ctx(r, ctx, ngx_http_modsecurity_module);
cln = ngx_pool_cleanup_add(r->pool, sizeof(ngx_http_modsecurity_ctx_t));
if (cln == NULL)
{
dd("failed to create the ModSecurity context cleanup");
return NGX_CONF_ERROR;
}
cln->handler = ngx_http_modsecurity_cleanup;
cln->data = ctx;
#if defined(MODSECURITY_SANITY_CHECKS) && (MODSECURITY_SANITY_CHECKS)
ctx->sanity_headers_out = ngx_array_create(r->pool, 12, sizeof(ngx_http_modsecurity_header_t));
if (ctx->sanity_headers_out == NULL) {
return NGX_CONF_ERROR;
}
#endif
return ctx;
}
char *
ngx_conf_set_rules(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
int res;
char *rules;
ngx_str_t *value;
const char *error;
ngx_pool_t *old_pool;
ngx_http_modsecurity_conf_t *mcf = conf;
ngx_http_modsecurity_main_conf_t *mmcf;
value = cf->args->elts;
rules = ngx_str_to_char(value[1], cf->pool);
if (rules == (char *)-1) {
return NGX_CONF_ERROR;
}
old_pool = ngx_http_modsecurity_pcre_malloc_init(cf->pool);
res = msc_rules_add(mcf->rules_set, rules, &error);
ngx_http_modsecurity_pcre_malloc_done(old_pool);
if (res < 0) {
dd("Failed to load the rules: '%s' - reason: '%s'", rules, error);
return strdup(error);
}
mmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_modsecurity_module);
mmcf->rules_inline += res;
return NGX_CONF_OK;
}
char *
ngx_conf_set_rules_file(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
int res;
char *rules_set;
ngx_str_t *value;
const char *error;
ngx_pool_t *old_pool;
ngx_http_modsecurity_conf_t *mcf = conf;
ngx_http_modsecurity_main_conf_t *mmcf;
value = cf->args->elts;
rules_set = ngx_str_to_char(value[1], cf->pool);
if (rules_set == (char *)-1) {
return NGX_CONF_ERROR;
}
old_pool = ngx_http_modsecurity_pcre_malloc_init(cf->pool);
res = msc_rules_add_file(mcf->rules_set, rules_set, &error);
ngx_http_modsecurity_pcre_malloc_done(old_pool);
if (res < 0) {
dd("Failed to load the rules from: '%s' - reason: '%s'", rules_set, error);
return strdup(error);
}
mmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_modsecurity_module);
mmcf->rules_file += res;
return NGX_CONF_OK;
}
char *
ngx_conf_set_rules_remote(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
int res;
ngx_str_t *value;
const char *error;
const char *rules_remote_key, *rules_remote_server;
ngx_pool_t *old_pool;
ngx_http_modsecurity_conf_t *mcf = conf;
ngx_http_modsecurity_main_conf_t *mmcf;
value = cf->args->elts;
rules_remote_key = ngx_str_to_char(value[1], cf->pool);
rules_remote_server = ngx_str_to_char(value[2], cf->pool);
if (rules_remote_server == (char *)-1) {
return NGX_CONF_ERROR;
}
if (rules_remote_key == (char *)-1) {
return NGX_CONF_ERROR;
}
old_pool = ngx_http_modsecurity_pcre_malloc_init(cf->pool);
res = msc_rules_add_remote(mcf->rules_set, rules_remote_key, rules_remote_server, &error);
ngx_http_modsecurity_pcre_malloc_done(old_pool);
if (res < 0) {
dd("Failed to load the rules from: '%s' - reason: '%s'", rules_remote_server, error);
return strdup(error);
}
mmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_modsecurity_module);
mmcf->rules_remote += res;
return NGX_CONF_OK;
}
char *ngx_conf_set_transaction_id(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) {
ngx_str_t *value;
ngx_http_complex_value_t cv;
ngx_http_compile_complex_value_t ccv;
ngx_http_modsecurity_conf_t *mcf = conf;
value = cf->args->elts;
ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
ccv.cf = cf;
ccv.value = &value[1];
ccv.complex_value = &cv;
ccv.zero = 1;
if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
return NGX_CONF_ERROR;
}
mcf->transaction_id = ngx_palloc(cf->pool, sizeof(ngx_http_complex_value_t));
if (mcf->transaction_id == NULL) {
return NGX_CONF_ERROR;
}
*mcf->transaction_id = cv;
return NGX_CONF_OK;
}
static ngx_command_t ngx_http_modsecurity_commands[] = {
{
ngx_string("modsecurity"),
NGX_HTTP_LOC_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_MAIN_CONF|NGX_CONF_FLAG,
ngx_conf_set_flag_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_modsecurity_conf_t, enable),
NULL
},
{
ngx_string("modsecurity_rules"),
NGX_HTTP_LOC_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1,
ngx_conf_set_rules,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_modsecurity_conf_t, enable),
NULL
},
{
ngx_string("modsecurity_rules_file"),
NGX_HTTP_LOC_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1,
ngx_conf_set_rules_file,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_modsecurity_conf_t, enable),
NULL
},
{
ngx_string("modsecurity_rules_remote"),
NGX_HTTP_LOC_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE2,
ngx_conf_set_rules_remote,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_modsecurity_conf_t, enable),
NULL
},
{
ngx_string("modsecurity_transaction_id"),
NGX_HTTP_LOC_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_MAIN_CONF|NGX_CONF_1MORE,
ngx_conf_set_transaction_id,
NGX_HTTP_LOC_CONF_OFFSET,
0,
NULL
},
ngx_null_command
};
static ngx_http_module_t ngx_http_modsecurity_ctx = {
NULL, /* preconfiguration */
ngx_http_modsecurity_init, /* postconfiguration */
ngx_http_modsecurity_create_main_conf, /* create main configuration */
ngx_http_modsecurity_init_main_conf, /* init main configuration */
NULL, /* create server configuration */
NULL, /* merge server configuration */
ngx_http_modsecurity_create_conf, /* create location configuration */
ngx_http_modsecurity_merge_conf /* merge location configuration */
};
ngx_module_t ngx_http_modsecurity_module = {
NGX_MODULE_V1,
&ngx_http_modsecurity_ctx, /* module context */
ngx_http_modsecurity_commands, /* module directives */
NGX_HTTP_MODULE, /* module type */
NULL, /* init master */
NULL, /* init module */
NULL, /* init process */
NULL, /* init thread */
NULL, /* exit thread */
NULL, /* exit process */
NULL, /* exit master */
NGX_MODULE_V1_PADDING
};
static ngx_int_t
ngx_http_modsecurity_init(ngx_conf_t *cf)
{
ngx_http_handler_pt *h_rewrite;
ngx_http_handler_pt *h_access;
ngx_http_handler_pt *h_log;
ngx_http_core_main_conf_t *cmcf;
int rc = 0;
cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
if (cmcf == NULL)
{
dd("We are not sure how this returns, NGINX doesn't seem to think it will ever be null");
return NGX_ERROR;
}
/**
*
* Seems like we cannot do this very same thing with
* NGX_HTTP_FIND_CONFIG_PHASE. it does not seems to
* be an array. Our next option is the REWRITE.
*
* TODO: check if we can hook prior to NGX_HTTP_REWRITE_PHASE phase.
*
*/
h_rewrite = ngx_array_push(&cmcf->phases[NGX_HTTP_REWRITE_PHASE].handlers);
if (h_rewrite == NULL)
{
dd("Not able to create a new NGX_HTTP_REWRITE_PHASE handle");
return NGX_ERROR;
}
*h_rewrite = ngx_http_modsecurity_rewrite_handler;
/**
*
* Processing the request body on the access phase.
*
* TODO: check if hook into separated phases is the best thing to do.
*
*/
h_access = ngx_array_push(&cmcf->phases[NGX_HTTP_ACCESS_PHASE].handlers);
if (h_access == NULL)
{
dd("Not able to create a new NGX_HTTP_ACCESS_PHASE handle");
return NGX_ERROR;
}
*h_access = ngx_http_modsecurity_access_handler;
/**
* Process the log phase.
*
* TODO: check if the log phase happens like it happens on Apache.
* check if last phase will not hold the request.
*
*/
h_log = ngx_array_push(&cmcf->phases[NGX_HTTP_LOG_PHASE].handlers);
if (h_log == NULL)
{
dd("Not able to create a new NGX_HTTP_LOG_PHASE handle");
return NGX_ERROR;
}
*h_log = ngx_http_modsecurity_log_handler;
rc = ngx_http_modsecurity_header_filter_init();
if (rc != NGX_OK) {
return rc;
}
rc = ngx_http_modsecurity_body_filter_init();
if (rc != NGX_OK) {
return rc;
}
return NGX_OK;
}
static void *
ngx_http_modsecurity_create_main_conf(ngx_conf_t *cf)
{
ngx_pool_cleanup_t *cln;
ngx_http_modsecurity_main_conf_t *conf;
conf = (ngx_http_modsecurity_main_conf_t *) ngx_pcalloc(cf->pool,
sizeof(ngx_http_modsecurity_main_conf_t));
if (conf == NULL)
{
return NGX_CONF_ERROR;
}
/*
* set by ngx_pcalloc():
*
* conf->modsec = NULL;
* conf->pool = NULL;
* conf->rules_inline = 0;
* conf->rules_file = 0;
* conf->rules_remote = 0;
*/
cln = ngx_pool_cleanup_add(cf->pool, 0);
if (cln == NULL) {
return NGX_CONF_ERROR;
}
cln->handler = ngx_http_modsecurity_cleanup_instance;
cln->data = conf;
conf->pool = cf->pool;
/* Create our ModSecurity instance */
conf->modsec = msc_init();
if (conf->modsec == NULL)
{
dd("failed to create the ModSecurity instance");
return NGX_CONF_ERROR;
}
/* Provide our connector information to LibModSecurity */
msc_set_connector_info(conf->modsec, MODSECURITY_NGINX_WHOAMI);
msc_set_log_cb(conf->modsec, ngx_http_modsecurity_log);
dd ("main conf created at: '%p', instance is: '%p'", conf, conf->modsec);
return conf;
}
static char *
ngx_http_modsecurity_init_main_conf(ngx_conf_t *cf, void *conf)
{
ngx_http_modsecurity_main_conf_t *mmcf;
mmcf = (ngx_http_modsecurity_main_conf_t *) conf;
ngx_log_error(NGX_LOG_NOTICE, cf->log, 0,
"%s (rules loaded inline/local/remote: %ui/%ui/%ui)",
MODSECURITY_NGINX_WHOAMI, mmcf->rules_inline,
mmcf->rules_file, mmcf->rules_remote);
return NGX_CONF_OK;
}
static void *
ngx_http_modsecurity_create_conf(ngx_conf_t *cf)
{
ngx_pool_cleanup_t *cln;
ngx_http_modsecurity_conf_t *conf;
conf = (ngx_http_modsecurity_conf_t *) ngx_pcalloc(cf->pool,
sizeof(ngx_http_modsecurity_conf_t));
if (conf == NULL)
{
dd("Failed to allocate space for ModSecurity configuration");
return NGX_CONF_ERROR;
}
/*
* set by ngx_pcalloc():
*
* conf->enable = 0;
* conf->sanity_checks_enabled = 0;
* conf->rules_set = NULL;
* conf->pool = NULL;
* conf->transaction_id = NULL;
*/
conf->enable = NGX_CONF_UNSET;
conf->rules_set = msc_create_rules_set();
conf->pool = cf->pool;
conf->transaction_id = NGX_CONF_UNSET_PTR;
#if defined(MODSECURITY_SANITY_CHECKS) && (MODSECURITY_SANITY_CHECKS)
conf->sanity_checks_enabled = NGX_CONF_UNSET;
#endif
cln = ngx_pool_cleanup_add(cf->pool, 0);
if (cln == NULL) {
dd("failed to create the ModSecurity configuration cleanup");
return NGX_CONF_ERROR;
}
cln->handler = ngx_http_modsecurity_cleanup_rules;
cln->data = conf;
dd ("conf created at: '%p'", conf);
return conf;
}
static char *
ngx_http_modsecurity_merge_conf(ngx_conf_t *cf, void *parent, void *child)
{
ngx_http_modsecurity_conf_t *p = parent;
ngx_http_modsecurity_conf_t *c = child;
#if defined(MODSECURITY_DDEBUG) && (MODSECURITY_DDEBUG)
ngx_http_core_loc_conf_t *clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
#endif
int rules;
const char *error = NULL;
dd("merging loc config [%s] - parent: '%p' child: '%p'",
ngx_str_to_char(clcf->name, cf->pool), parent,
child);
dd(" state - parent: '%d' child: '%d'",
(int) c->enable, (int) p->enable);
ngx_conf_merge_value(c->enable, p->enable, 0);
ngx_conf_merge_ptr_value(c->transaction_id, p->transaction_id, NULL);
#if defined(MODSECURITY_SANITY_CHECKS) && (MODSECURITY_SANITY_CHECKS)
ngx_conf_merge_value(c->sanity_checks_enabled, p->sanity_checks_enabled, 0);
#endif
#if defined(MODSECURITY_DDEBUG) && (MODSECURITY_DDEBUG)
dd("PARENT RULES");
msc_rules_dump(p->rules_set);
dd("CHILD RULES");
msc_rules_dump(c->rules_set);
#endif
rules = msc_rules_merge(c->rules_set, p->rules_set, &error);
if (rules < 0) {
return strdup(error);
}
#if defined(MODSECURITY_DDEBUG) && (MODSECURITY_DDEBUG)
dd("NEW CHILD RULES");
msc_rules_dump(c->rules_set);
#endif
return NGX_CONF_OK;
}
static void
ngx_http_modsecurity_cleanup_instance(void *data)
{
ngx_pool_t *old_pool;
ngx_http_modsecurity_main_conf_t *mmcf;
mmcf = (ngx_http_modsecurity_main_conf_t *) data;
dd("deleting a main conf -- instance is: \"%p\"", mmcf->modsec);
old_pool = ngx_http_modsecurity_pcre_malloc_init(mmcf->pool);
msc_cleanup(mmcf->modsec);
ngx_http_modsecurity_pcre_malloc_done(old_pool);
}
static void
ngx_http_modsecurity_cleanup_rules(void *data)
{
ngx_pool_t *old_pool;
ngx_http_modsecurity_conf_t *mcf;
mcf = (ngx_http_modsecurity_conf_t *) data;
dd("deleting a loc conf -- RuleSet is: \"%p\"", mcf->rules_set);
old_pool = ngx_http_modsecurity_pcre_malloc_init(mcf->pool);
msc_rules_cleanup(mcf->rules_set);
ngx_http_modsecurity_pcre_malloc_done(old_pool);
}
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */

View File

@ -0,0 +1,228 @@
/*
* ModSecurity connector for nginx, http://www.modsecurity.org/
* Copyright (c) 2015 Trustwave Holdings, Inc. (http://www.trustwave.com/)
*
* You may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* If any of the files related to licensing are missing or if you have any
* other questions related to licensing please contact Trustwave Holdings, Inc.
* directly using the email address security@modsecurity.org.
*
*/
#ifndef MODSECURITY_DDEBUG
#define MODSECURITY_DDEBUG 0
#endif
#include "ddebug.h"
#include "ngx_http_modsecurity_common.h"
void
ngx_http_modsecurity_request_read(ngx_http_request_t *r)
{
ngx_http_modsecurity_ctx_t *ctx;
ctx = ngx_http_get_module_ctx(r, ngx_http_modsecurity_module);
#if defined(nginx_version) && nginx_version >= 8011
r->main->count--;
#endif
if (ctx->waiting_more_body)
{
ctx->waiting_more_body = 0;
r->write_event_handler = ngx_http_core_run_phases;
ngx_http_core_run_phases(r);
}
}
ngx_int_t
ngx_http_modsecurity_pre_access_handler(ngx_http_request_t *r)
{
#if 1
ngx_pool_t *old_pool;
ngx_http_modsecurity_ctx_t *ctx;
ngx_http_modsecurity_conf_t *mcf;
dd("catching a new _preaccess_ phase handler");
mcf = ngx_http_get_module_loc_conf(r, ngx_http_modsecurity_module);
if (mcf == NULL || mcf->enable != 1)
{
dd("ModSecurity not enabled... returning");
return NGX_DECLINED;
}
/*
* FIXME:
* In order to perform some tests, let's accept everything.
*
if (r->method != NGX_HTTP_GET &&
r->method != NGX_HTTP_POST && r->method != NGX_HTTP_HEAD) {
dd("ModSecurity is not ready to deal with anything different from " \
"POST, GET or HEAD");
return NGX_DECLINED;
}
*/
ctx = ngx_http_get_module_ctx(r, ngx_http_modsecurity_module);
dd("recovering ctx: %p", ctx);
if (ctx == NULL)
{
dd("ctx is null; Nothing we can do, returning an error.");
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
if (ctx->intervention_triggered) {
return NGX_DECLINED;
}
if (ctx->waiting_more_body == 1)
{
dd("waiting for more data before proceed. / count: %d",
r->main->count);
return NGX_DONE;
}
if (ctx->body_requested == 0)
{
ngx_int_t rc = NGX_OK;
ctx->body_requested = 1;
dd("asking for the request body, if any. Count: %d",
r->main->count);
/**
* TODO: Check if there is any benefit to use request_body_in_single_buf set to 1.
*
* saw some module using this request_body_in_single_buf
* but not sure what exactly it does, same for the others options below.
*
* r->request_body_in_single_buf = 1;
*/
r->request_body_in_single_buf = 1;
r->request_body_in_persistent_file = 1;
if (!r->request_body_in_file_only) {
// If the above condition fails, then the flag below will have been
// set correctly elsewhere. We need to set the flag here for other
// conditions (client_body_in_file_only not used but
// client_body_buffer_size is)
r->request_body_in_clean_file = 1;
}
rc = ngx_http_read_client_request_body(r,
ngx_http_modsecurity_request_read);
if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) {
#if (nginx_version < 1002006) || \
(nginx_version >= 1003000 && nginx_version < 1003009)
r->main->count--;
#endif
return rc;
}
if (rc == NGX_AGAIN)
{
dd("nginx is asking us to wait for more data.");
ctx->waiting_more_body = 1;
return NGX_DONE;
}
}
if (ctx->waiting_more_body == 0)
{
int ret = 0;
int already_inspected = 0;
dd("request body is ready to be processed");
r->write_event_handler = ngx_http_core_run_phases;
ngx_chain_t *chain = r->request_body->bufs;
/**
* TODO: Speed up the analysis by sending chunk while they arrive.
*
* Notice that we are waiting for the full request body to
* start to process it, it may not be necessary. We may send
* the chunks to ModSecurity while nginx keep calling this
* function.
*/
if (r->request_body->temp_file != NULL) {
ngx_str_t file_path = r->request_body->temp_file->file.name;
const char *file_name = ngx_str_to_char(file_path, r->pool);
if (file_name == (char*)-1) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
/*
* Request body was saved to a file, probably we don't have a
* copy of it in memory.
*/
dd("request body inspection: file -- %s", file_name);
msc_request_body_from_file(ctx->modsec_transaction, file_name);
already_inspected = 1;
} else {
dd("inspection request body in memory.");
}
while (chain && !already_inspected)
{
u_char *data = chain->buf->pos;
msc_append_request_body(ctx->modsec_transaction, data,
chain->buf->last - data);
if (chain->buf->last_buf) {
break;
}
chain = chain->next;
/* XXX: chains are processed one-by-one, maybe worth to pass all chains and then call intervention() ? */
/**
* ModSecurity may perform stream inspection on this buffer,
* it may ask for a intervention in consequence of that.
*
*/
ret = ngx_http_modsecurity_process_intervention(ctx->modsec_transaction, r, 0);
if (ret > 0) {
return ret;
}
}
/**
* At this point, all the request body was sent to ModSecurity
* and we want to make sure that all the request body inspection
* happened; consequently we have to check if ModSecurity have
* returned any kind of intervention.
*/
/* XXX: once more -- is body can be modified ? content-length need to be adjusted ? */
old_pool = ngx_http_modsecurity_pcre_malloc_init(r->pool);
msc_process_request_body(ctx->modsec_transaction);
ngx_http_modsecurity_pcre_malloc_done(old_pool);
ret = ngx_http_modsecurity_process_intervention(ctx->modsec_transaction, r, 0);
if (r->error_page) {
return NGX_DECLINED;
}
if (ret > 0) {
return ret;
}
}
dd("Nothing to add on the body inspection, reclaiming a NGX_DECLINED");
#endif
return NGX_DECLINED;
}

View File

@ -0,0 +1,228 @@
/*
* ModSecurity connector for nginx, http://www.modsecurity.org/
* Copyright (c) 2015 Trustwave Holdings, Inc. (http://www.trustwave.com/)
*
* You may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* If any of the files related to licensing are missing or if you have any
* other questions related to licensing please contact Trustwave Holdings, Inc.
* directly using the email address security@modsecurity.org.
*
*/
#ifndef MODSECURITY_DDEBUG
#define MODSECURITY_DDEBUG 0
#endif
#include "ddebug.h"
#include "ngx_http_modsecurity_common.h"
ngx_int_t
ngx_http_modsecurity_rewrite_handler(ngx_http_request_t *r)
{
ngx_pool_t *old_pool;
ngx_http_modsecurity_ctx_t *ctx;
ngx_http_modsecurity_conf_t *mcf;
mcf = ngx_http_get_module_loc_conf(r, ngx_http_modsecurity_module);
if (mcf == NULL || mcf->enable != 1) {
dd("ModSecurity not enabled... returning");
return NGX_DECLINED;
}
/*
if (r->method != NGX_HTTP_GET &&
r->method != NGX_HTTP_POST && r->method != NGX_HTTP_HEAD) {
dd("ModSecurity is not ready to deal with anything different from " \
"POST, GET or HEAD");
return NGX_DECLINED;
}
*/
dd("catching a new _rewrite_ phase handler");
ctx = ngx_http_get_module_ctx(r, ngx_http_modsecurity_module);
dd("recovering ctx: %p", ctx);
if (ctx == NULL)
{
int ret = 0;
ngx_connection_t *connection = r->connection;
/**
* FIXME: We may want to use struct sockaddr instead of addr_text.
*
*/
ngx_str_t addr_text = connection->addr_text;
ctx = ngx_http_modsecurity_create_ctx(r);
dd("ctx was NULL, creating new context: %p", ctx);
if (ctx == NULL) {
dd("ctx still null; Nothing we can do, returning an error.");
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
/**
* FIXME: Check if it is possible to hook on nginx on a earlier phase.
*
* At this point we are doing an late connection process. Maybe
* we have to hook into NGX_HTTP_FIND_CONFIG_PHASE, it seems to be the
* erliest phase that nginx allow us to attach those kind of hooks.
*
*/
int client_port = ngx_inet_get_port(connection->sockaddr);
int server_port = ngx_inet_get_port(connection->local_sockaddr);
const char *client_addr = ngx_str_to_char(addr_text, r->pool);
if (client_addr == (char*)-1) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
ngx_str_t s;
u_char addr[NGX_SOCKADDR_STRLEN];
s.len = NGX_SOCKADDR_STRLEN;
s.data = addr;
if (ngx_connection_local_sockaddr(r->connection, &s, 0) != NGX_OK) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
const char *server_addr = ngx_str_to_char(s, r->pool);
if (server_addr == (char*)-1) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
old_pool = ngx_http_modsecurity_pcre_malloc_init(r->pool);
ret = msc_process_connection(ctx->modsec_transaction,
client_addr, client_port,
server_addr, server_port);
ngx_http_modsecurity_pcre_malloc_done(old_pool);
if (ret != 1){
dd("Was not able to extract connection information.");
}
/**
*
* FIXME: Check how we can finalize a request without crash nginx.
*
* I don't think nginx is expecting to finalize a request at that
* point as it seems that it clean the ngx_http_request_t information
* and try to use it later.
*
*/
dd("Processing intervention with the connection information filled in");
ret = ngx_http_modsecurity_process_intervention(ctx->modsec_transaction, r, 1);
if (ret > 0) {
ctx->intervention_triggered = 1;
return ret;
}
const char *http_version;
switch (r->http_version) {
case NGX_HTTP_VERSION_9 :
http_version = "0.9";
break;
case NGX_HTTP_VERSION_10 :
http_version = "1.0";
break;
case NGX_HTTP_VERSION_11 :
http_version = "1.1";
break;
#if defined(nginx_version) && nginx_version >= 1009005
case NGX_HTTP_VERSION_20 :
http_version = "2.0";
break;
#endif
default :
http_version = ngx_str_to_char(r->http_protocol, r->pool);
if (http_version == (char*)-1) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
if ((http_version != NULL) && (strlen(http_version) > 5) && (!strncmp("HTTP/", http_version, 5))) {
http_version += 5;
} else {
http_version = "1.0";
}
break;
}
const char *n_uri = ngx_str_to_char(r->unparsed_uri, r->pool);
const char *n_method = ngx_str_to_char(r->method_name, r->pool);
if (n_uri == (char*)-1 || n_method == (char*)-1) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
if (n_uri == NULL) {
dd("uri is of length zero");
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
old_pool = ngx_http_modsecurity_pcre_malloc_init(r->pool);
msc_process_uri(ctx->modsec_transaction, n_uri, n_method, http_version);
ngx_http_modsecurity_pcre_malloc_done(old_pool);
dd("Processing intervention with the transaction information filled in (uri, method and version)");
ret = ngx_http_modsecurity_process_intervention(ctx->modsec_transaction, r, 1);
if (ret > 0) {
ctx->intervention_triggered = 1;
return ret;
}
/**
* Since incoming request headers are already in place, lets send it to ModSecurity
*
*/
ngx_list_part_t *part = &r->headers_in.headers.part;
ngx_table_elt_t *data = part->elts;
ngx_uint_t i = 0;
for (i = 0 ; /* void */ ; i++) {
if (i >= part->nelts) {
if (part->next == NULL) {
break;
}
part = part->next;
data = part->elts;
i = 0;
}
/**
* By using u_char (utf8_t) I believe nginx is hoping to deal
* with utf8 strings.
* Casting those into to unsigned char * in order to pass
* it to ModSecurity, it will handle with those later.
*
*/
dd("Adding request header: %.*s with value %.*s", (int)data[i].key.len, data[i].key.data, (int) data[i].value.len, data[i].value.data);
msc_add_n_request_header(ctx->modsec_transaction,
(const unsigned char *) data[i].key.data,
data[i].key.len,
(const unsigned char *) data[i].value.data,
data[i].value.len);
}
/**
* Since ModSecurity already knew about all headers, i guess it is safe
* to process this information.
*/
old_pool = ngx_http_modsecurity_pcre_malloc_init(r->pool);
msc_process_request_headers(ctx->modsec_transaction);
ngx_http_modsecurity_pcre_malloc_done(old_pool);
dd("Processing intervention with the request headers information filled in");
ret = ngx_http_modsecurity_process_intervention(ctx->modsec_transaction, r, 1);
if (r->error_page) {
return NGX_DECLINED;
}
if (ret > 0) {
ctx->intervention_triggered = 1;
return ret;
}
}
return NGX_DECLINED;
}

View File

@ -0,0 +1,10 @@
# Tests
Those are nginx test files. You can copy those files into yours nginx test
tree, to perform the tests using the "prove" utility.
For more information about those tests, read the subsection "Testing your
patch" on the project's README file.
For more about nginx tests, check their repository:
http://hg.nginx.org/nginx-tests/

View File

@ -0,0 +1,233 @@
#!/usr/bin/perl
#
# ModSecurity, http://www.modsecurity.org/
# Copyright (c) 2015 Trustwave Holdings, Inc. (http://www.trustwave.com/)
#
# You may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# If any of the files related to licensing are missing or if you have any
# other questions related to licensing please contact Trustwave Holdings, Inc.
# directly using the email address security@modsecurity.org.
#
# Tests for ModSecurity module.
###############################################################################
use warnings;
use strict;
use Test::More;
BEGIN { use FindBin; chdir($FindBin::Bin); }
use lib 'lib';
use Test::Nginx;
###############################################################################
select STDERR; $| = 1;
select STDOUT; $| = 1;
my $t = Test::Nginx->new()->has(qw/http/);
$t->write_file_expand('nginx.conf', <<'EOF');
%%TEST_GLOBALS%%
daemon off;
events {
}
http {
%%TEST_GLOBALS_HTTP%%
server {
listen 127.0.0.1:8080;
server_name localhost;
modsecurity on;
modsecurity_rules '
SecRuleEngine On
SecRule ARGS "@streq whee" "id:10,phase:2"
SecRule ARGS "@streq whee" "id:11,phase:2"
';
location / {
modsecurity_rules '
SecRule ARGS "@streq root" "id:21,phase:1,auditlog,status:302,redirect:http://www.modsecurity.org"
SecDebugLog %%TESTDIR%%/auditlog-debug-root.txt
SecDebugLogLevel 9
SecAuditEngine RelevantOnly
SecAuditLogParts AB
SecAuditLog %%TESTDIR%%/auditlog-root.txt
SecAuditLogType Serial
SecAuditLogStorageDir %%TESTDIR%%/
';
}
location /subfolder1/subfolder2 {
modsecurity_rules '
SecRule ARGS "@streq subfolder2" "id:41,phase:1,status:302,auditlog,redirect:http://www.modsecurity.org"
SecRule ARGS "@streq subfolder1" "id:42,phase:1,status:302,auditlog,redirect:http://www.modsecurity.org"
SecDebugLog %%TESTDIR%%/auditlog-debug-subfolder2.txt
SecDebugLogLevel 9
SecAuditEngine RelevantOnly
SecAuditLogParts AB
SecResponseBodyAccess On
SecAuditLog %%TESTDIR%%/auditlog-subfolder2.txt
SecAuditLogType Serial
SecAuditLogStorageDir %%TESTDIR%%/
';
}
location /subfolder1 {
modsecurity_rules '
SecRule ARGS "@streq subfolder1" "id:31,phase:1,status:302,auditlog,redirect:http://www.modsecurity.org"
SecDebugLog %%TESTDIR%%/auditlog-debug-subfolder1.txt
SecDebugLogLevel 9
SecAuditLogParts AB
SecAuditEngine RelevantOnly
SecAuditLog %%TESTDIR%%/auditlog-subfolder1.txt
SecAuditLogType Serial
SecAuditLogStorageDir %%TESTDIR%%/
';
}
location /subfolder3/subfolder4 {
modsecurity_rules '
SecResponseBodyAccess On
SecRule ARGS "@streq subfolder4" "id:61,phase:1,status:302,auditlog,redirect:http://www.modsecurity.org"
SecRule ARGS "@streq subfolder3" "id:62,phase:1,status:302,auditlog,redirect:http://www.modsecurity.org"
SecRule ARGS "@streq subfolder4withE" "id:63,phase:1,ctl:auditLogParts=+E,auditlog"
SecDebugLog %%TESTDIR%%/auditlog-debug-subfolder4.txt
SecDebugLogLevel 9
SecAuditEngine RelevantOnly
SecAuditLogParts AB
SecAuditLog %%TESTDIR%%/auditlog-subfolder4.txt
SecAuditLogType Serial
SecAuditLogStorageDir %%TESTDIR%%/
';
}
location /subfolder3 {
modsecurity_rules '
SecRule ARGS "@streq subfolder3" "id:51,phase:1,status:302,auditlog,redirect:http://www.modsecurity.org"
SecDebugLog %%TESTDIR%%/auditlog-debug-subfolder3.txt
SecDebugLogLevel 9
SecAuditLogParts AB
SecAuditEngine RelevantOnly
SecAuditLog %%TESTDIR%%/auditlog-subfolder3.txt
SecAuditLogType Serial
SecAuditLogStorageDir %%TESTDIR%%/
';
}
}
}
EOF
$t->write_file("/index.html", "should be moved/blocked before this.");
mkdir($t->testdir() . '/subfolder1');
$t->write_file("/subfolder1/index.html", "should be moved/blocked before this.");
mkdir($t->testdir() . '/subfolder1/subfolder2');
$t->write_file("/subfolder1/subfolder2/index.html", "should be moved/blocked before this.");
mkdir($t->testdir() . '/subfolder3');
$t->write_file("/subfolder3/index.html", "should be moved/blocked before this.");
mkdir($t->testdir() . '/subfolder3/subfolder4');
$t->write_file("/subfolder3/subfolder4/index.html", "should be moved/blocked before this.");
$t->run();
$t->plan(9);
###############################################################################
my $d = $t->testdir();
my $r;
# Performing requests at root
$r = http_get('/index.html?what=root');
$r = http_get('/index.html?what=subfolder1');
$r = http_get('/index.html?what=subfolder2');
$r = http_get('/index.html?what=subfolder3');
$r = http_get('/index.html?what=subfolder4');
# Performing requests at subfolder1
$r = http_get('/subfolder1/index.html?what=root');
$r = http_get('/subfolder1/index.html?what=subfolder1');
$r = http_get('/subfolder1/index.html?what=subfolder2');
$r = http_get('/subfolder1/index.html?what=subfolder3');
$r = http_get('/subfolder1/index.html?what=subfolder4');
# Performing requests at subfolder2
$r = http_get('/subfolder1/subfolder2/index.html?what=root');
$r = http_get('/subfolder1/subfolder2/index.html?what=subfolder1');
$r = http_get('/subfolder1/subfolder2/index.html?what=subfolder2');
$r = http_get('/subfolder1/subfolder2/index.html?what=subfolder3');
$r = http_get('/subfolder1/subfolder2/index.html?what=subfolder4');
# Performing requests at subfolder3
$r = http_get('/subfolder3/index.html?what=root');
$r = http_get('/subfolder3/index.html?what=subfolder1');
$r = http_get('/subfolder3/index.html?what=subfolder2');
$r = http_get('/subfolder3/index.html?what=subfolder3');
$r = http_get('/subfolder3/index.html?what=subfolder4');
# Performing requests at subfolder4
$r = http_get('/subfolder3/subfolder4/index.html?what=root');
$r = http_get('/subfolder3/subfolder4/index.html?what=subfolder1');
$r = http_get('/subfolder3/subfolder4/index.html?what=subfolder2');
$r = http_get('/subfolder3/subfolder4/index.html?what=subfolder3');
$r = http_get('/subfolder3/subfolder4/index.html?what=subfolder4');
$r = http_get('/subfolder3/subfolder4/index.html?what=subfolder4withE');
my $root = do {
local $/ = undef;
open my $fh, "<", "$d/auditlog-root.txt"
or die "could not open: $!";
<$fh>;
};
my $subfolder1 = do {
local $/ = undef;
open my $fh, "<", "$d/auditlog-subfolder1.txt"
or die "could not open: $!";
<$fh>;
};
my $subfolder2 = do {
local $/ = undef;
open my $fh, "<", "$d/auditlog-subfolder2.txt"
or die "could not open: $!";
<$fh>;
};
my $subfolder3 = do {
local $/ = undef;
open my $fh, "<", "$d/auditlog-subfolder3.txt"
or die "could not open: $!";
<$fh>;
};
my $subfolder4 = do {
local $/ = undef;
open my $fh, "<", "$d/auditlog-subfolder4.txt"
or die "could not open: $!";
<$fh>;
};
like($root, qr/what=root/, 'root');
like($subfolder1, qr/what=subfolder1/, 'subfolder1');
like($subfolder2, qr/what=subfolder2/, 'subfolder2');
like($subfolder2, qr/what=subfolder1/, 'subfolder2 / subfolder1');
like($subfolder3, qr/what=subfolder3/, 'subfolder3');
like($subfolder4, qr/what=subfolder4/, 'subfolder4');
like($subfolder4, qr/what=subfolder3/, 'subfolder4 / subfolder3');
like($subfolder4, qr/what=subfolder4withE/, 'subfolder4');
like($subfolder4, qr/---E--/, 'subfolder4');

View File

@ -0,0 +1,174 @@
#!/usr/bin/perl
#
# ModSecurity, http://www.modsecurity.org/
# Copyright (c) 2015 Trustwave Holdings, Inc. (http://www.trustwave.com/)
#
# You may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# If any of the files related to licensing are missing or if you have any
# other questions related to licensing please contact Trustwave Holdings, Inc.
# directly using the email address security@modsecurity.org.
#
# Tests for ModSecurity module.
###############################################################################
use warnings;
use strict;
use Test::More;
BEGIN { use FindBin; chdir($FindBin::Bin); }
use lib 'lib';
use Test::Nginx;
###############################################################################
select STDERR; $| = 1;
select STDOUT; $| = 1;
my $t = Test::Nginx->new()->has(qw/http/);
$t->write_file_expand('nginx.conf', <<'EOF');
%%TEST_GLOBALS%%
daemon off;
events {
}
http {
%%TEST_GLOBALS_HTTP%%
server {
listen 127.0.0.1:8080;
server_name s1;
error_page 403 /403.html;
location /403.html {
root %%TESTDIR%%/http;
internal;
}
location / {
modsecurity on;
modsecurity_rules '
SecRuleEngine On
SecRule ARGS "@streq root" "id:10,phase:1,auditlog,status:403,deny"
SecDebugLog %%TESTDIR%%/auditlog-debug-local.txt
SecDebugLogLevel 9
SecAuditEngine RelevantOnly
SecAuditLogParts ABIJDEFHZ
SecAuditLog %%TESTDIR%%/auditlog-local.txt
SecAuditLogType Serial
SecAuditLogStorageDir %%TESTDIR%%/
';
}
}
server {
listen 127.0.0.1:8080;
server_name s2;
modsecurity on;
modsecurity_rules '
SecRuleEngine On
SecRule ARGS "@streq root" "id:10,phase:1,auditlog,status:403,deny"
SecDebugLog %%TESTDIR%%/auditlog-debug-global.txt
SecDebugLogLevel 9
SecAuditEngine RelevantOnly
SecAuditLogParts ABIJDEFHZ
SecAuditLog %%TESTDIR%%/auditlog-global.txt
SecAuditLogType Serial
SecAuditLogStorageDir %%TESTDIR%%/
';
error_page 403 /403.html;
location /403.html {
modsecurity off;
root %%TESTDIR%%/http;
internal;
}
location / {
}
}
}
EOF
my $index_txt = "This is the index page.";
my $custom_txt = "This is a custom error page.";
$t->write_file("/index.html", $index_txt);
mkdir($t->testdir() . '/http');
$t->write_file("/http/403.html", $custom_txt);
$t->run();
$t->plan(10);
###############################################################################
my $d = $t->testdir();
my $t1;
my $t2;
my $t3;
my $t4;
# Performing requests to a server with ModSecurity enabled at location context
$t1 = http_get_host('s1', '/index.html?what=root');
$t2 = http_get_host('s1', '/index.html?what=other');
# Performing requests to a server with ModSecurity enabled at server context
$t3 = http_get_host('s2', '/index.html?what=root');
$t4 = http_get_host('s2', '/index.html?what=other');
my $local = do {
local $/ = undef;
open my $fh, "<", "$d/auditlog-local.txt"
or die "could not open: $!";
<$fh>;
};
my $global = do {
local $/ = undef;
open my $fh, "<", "$d/auditlog-global.txt"
or die "could not open: $!";
<$fh>;
};
like($t1, qr/$custom_txt/, 'ModSecurity at location / root');
like($t2, qr/$index_txt/, 'ModSecurity at location / other');
like($local, qr/what=root/, 'ModSecurity at location / root present in auditlog');
unlike($local, qr/what=other/, 'ModSecurity at location / other not present in auditlog');
like($t3, qr/$custom_txt/, 'ModSecurity at server / root');
like($t4, qr/$index_txt/, 'ModSecurity at server / other');
like($global, qr/what=root/, 'ModSecurity at server / root present in auditlog');
unlike($global, qr/what=other/, 'ModSecurity at server / other not present in auditlog');
like($local, qr/Access denied with code 403/, 'ModSecurity at location / 403 in auditlog');
like($global, qr/Access denied with code 403/, 'ModSecurity at server / 403 in auditlog');
###############################################################################
sub http_get_host {
my ($host, $url) = @_;
return http(<<EOF);
GET $url HTTP/1.0
Host: $host
EOF
}
###############################################################################

View File

@ -0,0 +1,142 @@
#!/usr/bin/perl
#
# ModSecurity, http://www.modsecurity.org/
# Copyright (c) 2015 Trustwave Holdings, Inc. (http://www.trustwave.com/)
#
# You may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# If any of the files related to licensing are missing or if you have any
# other questions related to licensing please contact Trustwave Holdings, Inc.
# directly using the email address security@modsecurity.org.
#
# Tests for ModSecurity module.
###############################################################################
use warnings;
use strict;
use Test::More;
BEGIN { use FindBin; chdir($FindBin::Bin); }
use lib 'lib';
use Test::Nginx;
###############################################################################
select STDERR; $| = 1;
select STDOUT; $| = 1;
my $t = Test::Nginx->new()->has(qw/http/);
$t->write_file_expand('nginx.conf', <<'EOF');
%%TEST_GLOBALS%%
daemon off;
events {
}
http {
%%TEST_GLOBALS_HTTP%%
server {
listen 127.0.0.1:8080;
server_name localhost;
modsecurity on;
modsecurity_rules '
SecRuleEngine On
SecRule ARGS "@streq whee" "id:10,phase:2"
SecRule ARGS "@streq whee" "id:11,phase:2"
';
location / {
modsecurity_rules '
SecRule ARGS "@streq root" "id:21,phase:1,status:302,redirect:http://www.modsecurity.org"
SecDebugLog %%TESTDIR%%/debuglog-root.txt
SecDebugLogLevel 9
';
}
location /subfolder1 {
modsecurity_rules '
SecRule ARGS "@streq subfolder1" "id:31,phase:1,status:302,redirect:http://www.modsecurity.org"
SecDebugLog %%TESTDIR%%/debuglog-subfolder1.txt
SecDebugLogLevel 9
';
location /subfolder1/subfolder2 {
modsecurity_rules '
SecRule ARGS "@streq subfolder2" "id:41,phase:1,status:302,redirect:http://www.modsecurity.org"
SecDebugLog %%TESTDIR%%/debuglog-subfolder2.txt
SecDebugLogLevel 9
';
}
}
}
}
EOF
$t->write_file("/index.html", "should be moved/blocked before this.");
mkdir($t->testdir() . '/subfolder1');
$t->write_file("/subfolder1/index.html", "should be moved/blocked before this.");
mkdir($t->testdir() . '/subfolder1/subfolder2');
$t->write_file("/subfolder1/subfolder2/index.html", "should be moved/blocked before this.");
$t->run();
$t->plan(3);
###############################################################################
my $d = $t->testdir();
my $r;
# Performing requests at root
$r = http_get('/index.html?what=root');
$r = http_get('/index.html?what=subfolder1');
$r = http_get('/index.html?what=subfolder2');
# Performing requests at subfolder1
$r = http_get('/subfolder1/index.html?what=root');
$r = http_get('/subfolder1/index.html?what=subfolder1');
$r = http_get('/subfolder1/index.html?what=subfolder2');
# Performing requests at subfolder2
$r = http_get('/subfolder1/subfolder2/index.html?what=root');
$r = http_get('/subfolder1/subfolder2/index.html?what=subfolder1');
$r = http_get('/subfolder1/subfolder2/index.html?what=subfolder2');
my $root = do {
local $/ = undef;
open my $fh, "<", "$d/debuglog-root.txt"
or die "could not open: $!";
<$fh>;
};
my $subfolder1 = do {
local $/ = undef;
open my $fh, "<", "$d/debuglog-subfolder1.txt"
or die "could not open: $!";
<$fh>;
};
my $subfolder2 = do {
local $/ = undef;
open my $fh, "<", "$d/debuglog-subfolder2.txt"
or die "could not open: $!";
<$fh>;
};
like($root, qr/"what", value "root"/, 'root');
like($subfolder1, qr/"what", value "subfolder1"/, 'subfolder1');
like($subfolder2, qr/"what", value "subfolder2"/, 'subfolder2');

View File

@ -0,0 +1,231 @@
#!/usr/bin/perl
# (C) Andrei Belov
# Tests for ModSecurity-nginx connector (configuration merge).
###############################################################################
use warnings;
use strict;
use Test::More;
use Socket qw/ CRLF /;
BEGIN { use FindBin; chdir($FindBin::Bin); }
use lib 'lib';
use Test::Nginx;
###############################################################################
select STDERR; $| = 1;
select STDOUT; $| = 1;
my $t = Test::Nginx->new()->has(qw/http proxy/);
$t->write_file_expand('nginx.conf', <<'EOF');
%%TEST_GLOBALS%%
daemon off;
events {
}
http {
%%TEST_GLOBALS_HTTP%%
modsecurity on;
modsecurity_rules '
SecRuleEngine On
SecRequestBodyAccess On
SecRequestBodyLimit 128
SecRequestBodyLimitAction Reject
SecRule REQUEST_BODY "@rx BAD BODY" "id:11,phase:request,deny,log,status:403"
';
server {
listen 127.0.0.1:%%PORT_8080%%;
server_name localhost;
location / {
proxy_pass http://127.0.0.1:%%PORT_8081%%;
}
location /modsec-disabled {
modsecurity_rules '
SecRuleEngine Off
';
proxy_pass http://127.0.0.1:%%PORT_8081%%;
}
location /nobodyaccess {
modsecurity_rules '
SecRequestBodyAccess Off
';
proxy_pass http://127.0.0.1:%%PORT_8081%%;
}
location /bodylimitprocesspartial {
modsecurity_rules '
SecRequestBodyLimitAction ProcessPartial
';
proxy_pass http://127.0.0.1:%%PORT_8081%%;
}
location /bodylimitincreased {
modsecurity_rules '
SecRequestBodyLimit 512
';
proxy_pass http://127.0.0.1:%%PORT_8081%%;
}
location /server {
modsecurity off;
location /server/modsec-disabled {
proxy_pass http://127.0.0.1:%%PORT_8082%%;
}
location /server/nobodyaccess {
proxy_pass http://127.0.0.1:%%PORT_8083%%;
}
location /server/bodylimitprocesspartial {
proxy_pass http://127.0.0.1:%%PORT_8084%%;
}
location /server/bodylimitincreased {
proxy_pass http://127.0.0.1:%%PORT_8085%%;
}
}
}
server {
listen 127.0.0.1:%%PORT_8082%%;
modsecurity_rules '
SecRuleEngine Off
';
location / {
proxy_pass http://127.0.0.1:%%PORT_8081%%;
}
}
server {
listen 127.0.0.1:%%PORT_8083%%;
modsecurity_rules '
SecRequestBodyAccess Off
';
location / {
proxy_pass http://127.0.0.1:%%PORT_8081%%;
}
}
server {
listen 127.0.0.1:%%PORT_8084%%;
modsecurity_rules '
SecRequestBodyLimitAction ProcessPartial
';
location / {
proxy_pass http://127.0.0.1:%%PORT_8081%%;
}
}
server {
listen 127.0.0.1:%%PORT_8085%%;
modsecurity_rules '
SecRequestBodyLimit 512
';
location / {
proxy_pass http://127.0.0.1:%%PORT_8081%%;
}
}
}
EOF
$t->run_daemon(\&http_daemon);
$t->run()->waitforsocket('127.0.0.1:' . port(8081));
$t->plan(10);
###############################################################################
like(http_get_body('/', 'GOOD BODY'), qr/TEST-OK-IF-YOU-SEE-THIS/, "http level defaults, pass");
like(http_get_body('/', 'VERY BAD BODY'), qr/^HTTP.*403/, "http level defaults, block");
like(http_get_body('/modsec-disabled', 'VERY BAD BODY'), qr/TEST-OK-IF-YOU-SEE-THIS/, "location override for SecRuleEngine, pass");
like(http_get_body('/nobodyaccess', 'VERY BAD BODY'), qr/TEST-OK-IF-YOU-SEE-THIS/, "location override for SecRequestBodyAccess, pass");
like(http_get_body('/bodylimitprocesspartial', 'BODY' x 33), qr/TEST-OK-IF-YOU-SEE-THIS/, "location override for SecRequestBodyLimitAction, pass");
like(http_get_body('/bodylimitincreased', 'BODY' x 64), qr/TEST-OK-IF-YOU-SEE-THIS/, "location override for SecRequestBodyLimit, pass");
like(http_get_body('/server/modsec-disabled', 'VERY BAD BODY'), qr/TEST-OK-IF-YOU-SEE-THIS/, "server override for SecRuleEngine, pass");
like(http_get_body('/server/nobodyaccess', 'VERY BAD BODY'), qr/TEST-OK-IF-YOU-SEE-THIS/, "server override for SecRequestBodyAccess, pass");
like(http_get_body('/server/bodylimitprocesspartial', 'BODY' x 33), qr/TEST-OK-IF-YOU-SEE-THIS/, "server override for SecRequestBodyLimitAction, pass");
like(http_get_body('/server/bodylimitincreased', 'BODY' x 64), qr/TEST-OK-IF-YOU-SEE-THIS/, "server override for SecRequestBodyLimit, pass");
###############################################################################
sub http_daemon {
my $server = IO::Socket::INET->new(
Proto => 'tcp',
LocalHost => '127.0.0.1:' . port(8081),
Listen => 5,
Reuse => 1
)
or die "Can't create listening socket: $!\n";
local $SIG{PIPE} = 'IGNORE';
while (my $client = $server->accept()) {
$client->autoflush(1);
my $headers = '';
my $uri = '';
while (<$client>) {
$headers .= $_;
last if (/^\x0d?\x0a?$/);
}
$uri = $1 if $headers =~ /^\S+\s+([^ ]+)\s+HTTP/i;
print $client <<'EOF';
HTTP/1.1 200 OK
Connection: close
EOF
print $client "TEST-OK-IF-YOU-SEE-THIS"
unless $headers =~ /^HEAD/i;
close $client;
}
}
sub http_get_body {
my $uri = shift;
my $last = pop;
return http( join '', (map {
my $body = $_;
"GET $uri HTTP/1.1" . CRLF
. "Host: localhost" . CRLF
. "Content-Length: " . (length $body) . CRLF . CRLF
. $body
} @_),
"GET $uri HTTP/1.1" . CRLF
. "Host: localhost" . CRLF
. "Connection: close" . CRLF
. "Content-Length: " . (length $last) . CRLF . CRLF
. $last
);
}
###############################################################################

View File

@ -0,0 +1,112 @@
#!/usr/bin/perl
#
# ModSecurity, http://www.modsecurity.org/
# Copyright (c) 2015 Trustwave Holdings, Inc. (http://www.trustwave.com/)
#
# You may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# If any of the files related to licensing are missing or if you have any
# other questions related to licensing please contact Trustwave Holdings, Inc.
# directly using the email address security@modsecurity.org.
#
# Tests for ModSecurity module.
###############################################################################
use warnings;
use strict;
use Test::More;
BEGIN { use FindBin; chdir($FindBin::Bin); }
use lib 'lib';
use Test::Nginx;
###############################################################################
select STDERR; $| = 1;
select STDOUT; $| = 1;
my $t = Test::Nginx->new()->has(qw/http/);
$t->write_file_expand('nginx.conf', <<'EOF');
%%TEST_GLOBALS%%
daemon off;
events {
}
http {
%%TEST_GLOBALS_HTTP%%
server {
listen 127.0.0.1:8080;
server_name localhost;
modsecurity on;
modsecurity_rules '
SecRuleEngine On
SecRule ARGS "@streq whee" "id:10,phase:2"
SecRule ARGS "@streq whee" "id:11,phase:2"
';
location / {
modsecurity_rules '
SecRuleEngine On
SecRule ARGS "@streq root" "id:21,phase:1,status:302,redirect:http://www.modsecurity.org"
';
}
location /subfolder1 {
modsecurity_rules '
SecRuleEngine On
SecRule ARGS "@streq subfolder1" "id:31,phase:1,status:302,redirect:http://www.modsecurity.org"
';
location /subfolder1/subfolder2 {
modsecurity_rules '
SecRuleEngine On
SecRule ARGS "@streq subfolder2" "id:41,phase:1,status:302,redirect:http://www.modsecurity.org"
';
}
}
}
}
EOF
$t->write_file("/index.html", "should be moved/blocked before this.");
mkdir($t->testdir() . '/subfolder1');
$t->write_file("/subfolder1/index.html", "should be moved/blocked before this.");
mkdir($t->testdir() . '/subfolder1/subfolder2');
$t->write_file("/subfolder1/subfolder2/index.html", "should be moved/blocked before this.");
$t->run();
$t->plan(9);
###############################################################################
# Performing requests at root
like(http_get('/index.html?what=root'), qr/^HTTP.*302/, 'redirect 302 - root');
like(http_get('/index.html?what=subfolder1'), qr/should be moved\/blocked before this./, 'nothing - requested subfolder1 at root');
like(http_get('/index.html?what=subfolder2'), qr/should be moved\/blocked before this./, 'nothing - requested subfolder2 at root');
# Performing requests at subfolder1
like(http_get('/subfolder1/index.html?what=root'), qr/should be moved\/blocked before this./, 'nothing - requested root at subfolder 1');
like(http_get('/subfolder1/index.html?what=subfolder1'), qr/^HTTP.*302/, 'redirect 302 - subfolder 1');
like(http_get('/subfolder1/index.html?what=subfolder2'), qr/should be moved\/blocked before this./, 'nothing - requested subfolder2 at subfolder1');
# Performing requests at subfolder2
like(http_get('/subfolder1/subfolder2/index.html?what=root'), qr/should be moved\/blocked before this./, 'nothing - requested root at subfolder 2');
like(http_get('/subfolder1/subfolder2/index.html?what=subfolder1'), qr/^HTTP.*302/, 'redirect 302 - subfolder 2');
like(http_get('/subfolder1/subfolder2/index.html?what=subfolder2'), qr/^HTTP.*302/, 'redirect 302 - subfolder 2');

View File

@ -0,0 +1,205 @@
#!/usr/bin/perl
# (C) Andrei Belov
# Tests for ModSecurity module (HTTP/2).
###############################################################################
use warnings;
use strict;
use Test::More;
BEGIN { use FindBin; chdir($FindBin::Bin); }
use lib 'lib';
use Test::Nginx;
use Test::Nginx::HTTP2;
###############################################################################
select STDERR; $| = 1;
select STDOUT; $| = 1;
my $t = Test::Nginx->new()->has(qw/http http_v2/);
$t->write_file_expand('nginx.conf', <<'EOF');
%%TEST_GLOBALS%%
daemon off;
events {
}
http {
%%TEST_GLOBALS_HTTP%%
server {
listen 127.0.0.1:8080 http2;
server_name localhost;
location / {
modsecurity on;
modsecurity_rules '
SecRuleEngine On
SecRule ARGS "@streq whee" "id:10,phase:2"
SecRule ARGS "@streq whee" "id:11,phase:2"
';
}
location /phase1 {
modsecurity on;
modsecurity_rules '
SecRuleEngine On
SecDefaultAction "phase:1,log,deny,status:403"
SecRule ARGS "@streq redirect301" "id:1,phase:1,status:301,redirect:http://www.modsecurity.org"
SecRule ARGS "@streq redirect302" "id:2,phase:1,status:302,redirect:http://www.modsecurity.org"
SecRule ARGS "@streq block401" "id:3,phase:1,status:401,block"
SecRule ARGS "@streq block403" "id:4,phase:1,status:403,block"
';
}
location /phase2 {
modsecurity on;
modsecurity_rules '
SecRuleEngine On
SecDefaultAction "phase:2,log,deny,status:403"
SecRule ARGS "@streq redirect301" "id:1,phase:2,status:301,redirect:http://www.modsecurity.org"
SecRule ARGS "@streq redirect302" "id:2,phase:2,status:302,redirect:http://www.modsecurity.org"
SecRule ARGS "@streq block401" "id:3,phase:2,status:401,block"
SecRule ARGS "@streq block403" "id:4,phase:2,status:403,block"
';
}
location /phase3 {
modsecurity on;
modsecurity_rules '
SecRuleEngine On
SecDefaultAction "phase:3,log,deny,status:403"
SecRule ARGS "@streq redirect301" "id:1,phase:3,status:301,redirect:http://www.modsecurity.org"
SecRule ARGS "@streq redirect302" "id:2,phase:3,status:302,redirect:http://www.modsecurity.org"
SecRule ARGS "@streq block401" "id:3,phase:3,status:401,block"
SecRule ARGS "@streq block403" "id:4,phase:3,status:403,block"
';
}
location /phase4 {
modsecurity on;
modsecurity_rules '
SecRuleEngine On
SecResponseBodyAccess On
SecDefaultAction "phase:4,log,deny,status:403"
SecRule ARGS "@streq redirect301" "id:1,phase:4,status:301,redirect:http://www.modsecurity.org"
SecRule ARGS "@streq redirect302" "id:2,phase:4,status:302,redirect:http://www.modsecurity.org"
SecRule ARGS "@streq block401" "id:3,phase:4,status:401,block"
SecRule ARGS "@streq block403" "id:4,phase:4,status:403,block"
';
}
}
}
EOF
$t->write_file("/phase1", "should be moved/blocked before this.");
$t->write_file("/phase2", "should be moved/blocked before this.");
$t->write_file("/phase3", "should be moved/blocked before this.");
$t->write_file("/phase4", "should not be moved/blocked, headers delivered before phase 4.");
$t->run();
$t->plan(20);
###############################################################################
my ($phase, $s, $sid, $frames, $frame);
# Redirect (302)
for $phase (1 .. 3) {
$s = Test::Nginx::HTTP2->new();
$sid = $s->new_stream({ path => "/phase${phase}?what=redirect302" });
$frames = $s->read(all => [{ sid => $sid, fin => 1 }]);
($frame) = grep { $_->{type} eq "HEADERS" } @$frames;
is($frame->{headers}->{':status'}, 302, "redirect 302 - phase ${phase}");
}
SKIP: {
skip 'long test', 1 unless $ENV{TEST_NGINX_UNSAFE};
$s = Test::Nginx::HTTP2->new();
$sid = $s->new_stream({ path => '/phase4?what=redirect302' });
$frames = $s->read(all => [{ sid => $sid, fin => 1 }]);
($frame) = grep { $_->{type} eq "DATA" } @$frames;
is($frame, undef, 'redirect 302 - phase 4');
}
# Redirect (301)
for $phase (1 .. 3) {
$s = Test::Nginx::HTTP2->new();
$sid = $s->new_stream({ path => "/phase${phase}?what=redirect301" });
$frames = $s->read(all => [{ sid => $sid, fin => 1 }]);
($frame) = grep { $_->{type} eq "HEADERS" } @$frames;
is($frame->{headers}->{':status'}, 301, "redirect 301 - phase ${phase}");
}
SKIP: {
skip 'long test', 1 unless $ENV{TEST_NGINX_UNSAFE};
$s = Test::Nginx::HTTP2->new();
$sid = $s->new_stream({ path => '/phase4?what=redirect301' });
$frames = $s->read(all => [{ sid => $sid, fin => 1 }]);
($frame) = grep { $_->{type} eq "DATA" } @$frames;
is($frame, undef, 'redirect 301 - phase 4');
}
# Block (401)
for $phase (1 .. 3) {
$s = Test::Nginx::HTTP2->new();
$sid = $s->new_stream({ path => "/phase${phase}?what=block401" });
$frames = $s->read(all => [{ sid => $sid, fin => 1 }]);
($frame) = grep { $_->{type} eq "HEADERS" } @$frames;
is($frame->{headers}->{':status'}, 401, "block 401 - phase ${phase}");
}
SKIP: {
skip 'long test', 1 unless $ENV{TEST_NGINX_UNSAFE};
$s = Test::Nginx::HTTP2->new();
$sid = $s->new_stream({ path => '/phase4?what=block401' });
$frames = $s->read(all => [{ sid => $sid, fin => 1 }]);
($frame) = grep { $_->{type} eq "DATA" } @$frames;
is($frame, undef, 'block 401 - phase 4');
}
# Block (403)
for $phase (1 .. 3) {
$s = Test::Nginx::HTTP2->new();
$sid = $s->new_stream({ path => "/phase${phase}?what=block403" });
$frames = $s->read(all => [{ sid => $sid, fin => 1 }]);
($frame) = grep { $_->{type} eq "HEADERS" } @$frames;
is($frame->{headers}->{':status'}, 403, "block 403 - phase ${phase}");
}
SKIP: {
skip 'long test', 1 unless $ENV{TEST_NGINX_UNSAFE};
$s = Test::Nginx::HTTP2->new();
$sid = $s->new_stream({ path => '/phase4?what=block403' });
$frames = $s->read(all => [{ sid => $sid, fin => 1 }]);
($frame) = grep { $_->{type} eq "DATA" } @$frames;
is($frame, undef, 'block 403 - phase 4');
}
# Nothing to detect
for $phase (1 .. 3) {
$s = Test::Nginx::HTTP2->new();
$sid = $s->new_stream({ path => "/phase${phase}?what=nothing" });
$frames = $s->read(all => [{ sid => $sid, fin => 1 }]);
($frame) = grep { $_->{type} eq "DATA" } @$frames;
is($frame->{data}, "should be moved\/blocked before this.", "nothing phase ${phase}");
}
$s = Test::Nginx::HTTP2->new();
$sid = $s->new_stream({ path => "/phase4?what=nothing" });
$frames = $s->read(all => [{ sid => $sid, fin => 1 }]);
($frame) = grep { $_->{type} eq "DATA" } @$frames;
is($frame->{data}, "should not be moved\/blocked, headers delivered before phase 4.", 'nothing phase 4');

View File

@ -0,0 +1,287 @@
#!/usr/bin/perl
# (C) Andrei Belov
# Tests for ModSecurity over the http proxy module (HTTP/2).
###############################################################################
use warnings;
use strict;
use Test::More;
BEGIN { use FindBin; chdir($FindBin::Bin); }
use lib 'lib';
use Test::Nginx;
use Test::Nginx::HTTP2;
###############################################################################
select STDERR; $| = 1;
select STDOUT; $| = 1;
my $t = Test::Nginx->new()->has(qw/http http_v2 proxy/)->plan(23);
$t->write_file_expand('nginx.conf', <<'EOF');
%%TEST_GLOBALS%%
daemon off;
events {
}
http {
%%TEST_GLOBALS_HTTP%%
server {
listen 127.0.0.1:8080 http2;
server_name localhost;
location / {
proxy_pass http://127.0.0.1:8081;
proxy_read_timeout 1s;
}
location /phase1 {
modsecurity on;
modsecurity_rules '
SecRuleEngine On
SecDefaultAction "phase:1,log,deny,status:403"
SecRule ARGS "@streq redirect301" "id:1,phase:1,status:301,redirect:http://www.modsecurity.org"
SecRule ARGS "@streq redirect302" "id:2,phase:1,status:302,redirect:http://www.modsecurity.org"
SecRule ARGS "@streq block401" "id:3,phase:1,status:401,block"
SecRule ARGS "@streq block403" "id:4,phase:1,status:403,block"
';
proxy_pass http://127.0.0.1:8081;
proxy_read_timeout 1s;
}
location /phase2 {
modsecurity on;
modsecurity_rules '
SecRuleEngine On
SecDefaultAction "phase:2,log,deny,status:403"
SecRule ARGS "@streq redirect301" "id:1,phase:2,status:301,redirect:http://www.modsecurity.org"
SecRule ARGS "@streq redirect302" "id:2,phase:2,status:302,redirect:http://www.modsecurity.org"
SecRule ARGS "@streq block401" "id:3,phase:2,status:401,block"
SecRule ARGS "@streq block403" "id:4,phase:2,status:403,block"
';
proxy_pass http://127.0.0.1:8081;
proxy_read_timeout 1s;
}
location /phase3 {
modsecurity on;
modsecurity_rules '
SecRuleEngine On
SecDefaultAction "phase:3,log,deny,status:403"
SecRule ARGS "@streq redirect301" "id:1,phase:3,status:301,redirect:http://www.modsecurity.org"
SecRule ARGS "@streq redirect302" "id:2,phase:3,status:302,redirect:http://www.modsecurity.org"
SecRule ARGS "@streq block401" "id:3,phase:3,status:401,block"
SecRule ARGS "@streq block403" "id:4,phase:3,status:403,block"
';
proxy_pass http://127.0.0.1:8081;
proxy_read_timeout 1s;
}
location /phase4 {
modsecurity on;
modsecurity_rules '
SecRuleEngine On
SecResponseBodyAccess On
SecDefaultAction "phase:4,log,deny,status:403"
SecRule ARGS "@streq redirect301" "id:1,phase:4,status:301,redirect:http://www.modsecurity.org"
SecRule ARGS "@streq redirect302" "id:2,phase:4,status:302,redirect:http://www.modsecurity.org"
SecRule ARGS "@streq block401" "id:3,phase:4,status:401,block"
SecRule ARGS "@streq block403" "id:4,phase:4,status:403,block"
';
proxy_pass http://127.0.0.1:8081;
proxy_read_timeout 1s;
}
}
}
EOF
$t->run_daemon(\&http_daemon);
$t->run()->waitforsocket('127.0.0.1:' . port(8081));
###############################################################################
my ($phase, $s, $sid, $frames, $frame);
$s = Test::Nginx::HTTP2->new();
$sid = $s->new_stream({ path => '/' });
$frames = $s->read(all => [{ sid => $sid, fin => 1 }]);
($frame) = grep { $_->{type} eq "DATA" } @$frames;
like($frame->{data}, qr/SEE-THIS/, "proxy request");
$s = Test::Nginx::HTTP2->new();
$sid = $s->new_stream({ path => '/multi' });
$frames = $s->read(all => [{ sid => $sid, fin => 1 }]);
($frame) = grep { $_->{type} eq "DATA" } @$frames;
like($frame->{data}, qr/AND-THIS/, "proxy request with multiple packets");
$s = Test::Nginx::HTTP2->new();
$sid = $s->new_stream({ path => '/', method => 'HEAD' });
$frames = $s->read(all => [{ sid => $sid, fin => 1 }]);
($frame) = grep { $_->{type} eq "DATA" } @$frames;
unlike($frame->{data}, qr/SEE-THIS/, "proxy head request");
# Redirect (302)
for $phase (1 .. 3) {
$s = Test::Nginx::HTTP2->new();
$sid = $s->new_stream({ path => "/phase${phase}?what=redirect302" });
$frames = $s->read(all => [{ sid => $sid, fin => 1 }]);
($frame) = grep { $_->{type} eq "HEADERS" } @$frames;
is($frame->{headers}->{':status'}, 302, "redirect 302 - phase ${phase}");
}
SKIP: {
skip 'long test', 1 unless $ENV{TEST_NGINX_UNSAFE};
$s = Test::Nginx::HTTP2->new();
$sid = $s->new_stream({ path => '/phase4?what=redirect302' });
$frames = $s->read(all => [{ sid => $sid, fin => 1 }]);
($frame) = grep { $_->{type} eq "DATA" } @$frames;
is($frame, undef, 'redirect 302 - phase 4');
}
# Redirect (301)
for $phase (1 .. 3) {
$s = Test::Nginx::HTTP2->new();
$sid = $s->new_stream({ path => "/phase${phase}?what=redirect301" });
$frames = $s->read(all => [{ sid => $sid, fin => 1 }]);
($frame) = grep { $_->{type} eq "HEADERS" } @$frames;
is($frame->{headers}->{':status'}, 301, "redirect 301 - phase ${phase}");
}
SKIP: {
skip 'long test', 1 unless $ENV{TEST_NGINX_UNSAFE};
$s = Test::Nginx::HTTP2->new();
$sid = $s->new_stream({ path => '/phase4?what=redirect301' });
$frames = $s->read(all => [{ sid => $sid, fin => 1 }]);
($frame) = grep { $_->{type} eq "DATA" } @$frames;
is($frame, undef, 'redirect 301 - phase 4');
}
# Block (401)
for $phase (1 .. 3) {
$s = Test::Nginx::HTTP2->new();
$sid = $s->new_stream({ path => "/phase${phase}?what=block401" });
$frames = $s->read(all => [{ sid => $sid, fin => 1 }]);
($frame) = grep { $_->{type} eq "HEADERS" } @$frames;
is($frame->{headers}->{':status'}, 401, "block 401 - phase ${phase}");
}
SKIP: {
skip 'long test', 1 unless $ENV{TEST_NGINX_UNSAFE};
$s = Test::Nginx::HTTP2->new();
$sid = $s->new_stream({ path => '/phase4?what=block401' });
$frames = $s->read(all => [{ sid => $sid, fin => 1 }]);
($frame) = grep { $_->{type} eq "DATA" } @$frames;
is($frame, undef, 'block 401 - phase 4');
}
# Block (403)
for $phase (1 .. 3) {
$s = Test::Nginx::HTTP2->new();
$sid = $s->new_stream({ path => "/phase${phase}?what=block403" });
$frames = $s->read(all => [{ sid => $sid, fin => 1 }]);
($frame) = grep { $_->{type} eq "HEADERS" } @$frames;
is($frame->{headers}->{':status'}, 403, "block 403 - phase ${phase}");
}
SKIP: {
skip 'long test', 1 unless $ENV{TEST_NGINX_UNSAFE};
$s = Test::Nginx::HTTP2->new();
$sid = $s->new_stream({ path => '/phase4?what=block403' });
$frames = $s->read(all => [{ sid => $sid, fin => 1 }]);
($frame) = grep { $_->{type} eq "DATA" } @$frames;
is($frame, undef, 'block 403 - phase 4');
}
# Nothing to detect
#like(http_get('/phase1?what=nothing'), qr/phase1\?what=nothing\' not found/, 'nothing phase 1');
#like(http_get('/phase2?what=nothing'), qr/phase2\?what=nothing\' not found/, 'nothing phase 2');
#like(http_get('/phase3?what=nothing'), qr/phase3\?what=nothing\' not found/, 'nothing phase 3');
#like(http_get('/phase4?what=nothing'), qr/phase4\?what=nothing\' not found/, 'nothing phase 4');
for $phase (1 .. 4) {
$s = Test::Nginx::HTTP2->new();
$sid = $s->new_stream({ path => "/phase${phase}?what=nothing" });
$frames = $s->read(all => [{ sid => $sid, fin => 1 }]);
($frame) = grep { $_->{type} eq "DATA" } @$frames;
like($frame->{data}, qr/phase${phase}\?what=nothing\' not found/, "nothing phase ${phase}");
}
###############################################################################
sub http_daemon {
my $server = IO::Socket::INET->new(
Proto => 'tcp',
LocalHost => '127.0.0.1:' . port(8081),
Listen => 5,
Reuse => 1
)
or die "Can't create listening socket: $!\n";
local $SIG{PIPE} = 'IGNORE';
while (my $client = $server->accept()) {
$client->autoflush(1);
my $headers = '';
my $uri = '';
while (<$client>) {
$headers .= $_;
last if (/^\x0d?\x0a?$/);
}
$uri = $1 if $headers =~ /^\S+\s+([^ ]+)\s+HTTP/i;
if ($uri eq '/') {
print $client <<'EOF';
HTTP/1.1 200 OK
Connection: close
EOF
print $client "TEST-OK-IF-YOU-SEE-THIS"
unless $headers =~ /^HEAD/i;
} elsif ($uri eq '/multi') {
print $client <<"EOF";
HTTP/1.1 200 OK
Connection: close
TEST-OK-IF-YOU-SEE-THIS
EOF
select undef, undef, undef, 0.1;
print $client 'AND-THIS';
} else {
print $client <<"EOF";
HTTP/1.1 404 Not Found
Connection: close
Oops, '$uri' not found
EOF
}
close $client;
}
}
###############################################################################

View File

@ -0,0 +1,208 @@
#!/usr/bin/perl
# Tests for ModSecurity over the http proxy module.
###############################################################################
use warnings;
use strict;
use Test::More;
BEGIN { use FindBin; chdir($FindBin::Bin); }
use lib 'lib';
use Test::Nginx;
###############################################################################
select STDERR; $| = 1;
select STDOUT; $| = 1;
my $t = Test::Nginx->new()->has(qw/http proxy/)->plan(23);
$t->write_file_expand('nginx.conf', <<'EOF');
%%TEST_GLOBALS%%
daemon off;
events {
}
http {
%%TEST_GLOBALS_HTTP%%
server {
listen 127.0.0.1:8080;
server_name localhost;
location / {
proxy_pass http://127.0.0.1:8081;
proxy_read_timeout 1s;
}
location /phase1 {
modsecurity on;
modsecurity_rules '
SecRuleEngine On
SecDefaultAction "phase:1,log,deny,status:403"
SecRule ARGS "@streq redirect301" "id:1,phase:1,status:301,redirect:http://www.modsecurity.org"
SecRule ARGS "@streq redirect302" "id:2,phase:1,status:302,redirect:http://www.modsecurity.org"
SecRule ARGS "@streq block401" "id:3,phase:1,status:401,block"
SecRule ARGS "@streq block403" "id:4,phase:1,status:403,block"
';
proxy_pass http://127.0.0.1:8081;
proxy_read_timeout 1s;
}
location /phase2 {
modsecurity on;
modsecurity_rules '
SecRuleEngine On
SecDefaultAction "phase:2,log,deny,status:403"
SecRule ARGS "@streq redirect301" "id:1,phase:2,status:301,redirect:http://www.modsecurity.org"
SecRule ARGS "@streq redirect302" "id:2,phase:2,status:302,redirect:http://www.modsecurity.org"
SecRule ARGS "@streq block401" "id:3,phase:2,status:401,block"
SecRule ARGS "@streq block403" "id:4,phase:2,status:403,block"
';
proxy_pass http://127.0.0.1:8081;
proxy_read_timeout 1s;
}
location /phase3 {
modsecurity on;
modsecurity_rules '
SecRuleEngine On
SecDefaultAction "phase:3,log,deny,status:403"
SecRule ARGS "@streq redirect301" "id:1,phase:3,status:301,redirect:http://www.modsecurity.org"
SecRule ARGS "@streq redirect302" "id:2,phase:3,status:302,redirect:http://www.modsecurity.org"
SecRule ARGS "@streq block401" "id:3,phase:3,status:401,block"
SecRule ARGS "@streq block403" "id:4,phase:3,status:403,block"
';
proxy_pass http://127.0.0.1:8081;
proxy_read_timeout 1s;
}
location /phase4 {
modsecurity on;
modsecurity_rules '
SecRuleEngine On
SecResponseBodyAccess On
SecDefaultAction "phase:4,log,deny,status:403"
SecRule ARGS "@streq redirect301" "id:1,phase:4,status:301,redirect:http://www.modsecurity.org"
SecRule ARGS "@streq redirect302" "id:2,phase:4,status:302,redirect:http://www.modsecurity.org"
SecRule ARGS "@streq block401" "id:3,phase:4,status:401,block"
SecRule ARGS "@streq block403" "id:4,phase:4,status:403,block"
';
proxy_pass http://127.0.0.1:8081;
proxy_read_timeout 1s;
}
}
}
EOF
$t->todo_alerts();
$t->run_daemon(\&http_daemon);
$t->run()->waitforsocket('127.0.0.1:' . port(8081));
###############################################################################
like(http_get('/'), qr/SEE-THIS/, 'proxy request');
like(http_get('/multi'), qr/AND-THIS/, 'proxy request with multiple packets');
unlike(http_head('/'), qr/SEE-THIS/, 'proxy head request');
# Redirect (302)
like(http_get('/phase1?what=redirect302'), qr/^HTTP.*302/, 'redirect 302 - phase 1');
like(http_get('/phase2?what=redirect302'), qr/^HTTP.*302/, 'redirect 302 - phase 2');
like(http_get('/phase3?what=redirect302'), qr/^HTTP.*302/, 'redirect 302 - phase 3');
is(http_get('/phase4?what=redirect302'), '', 'redirect 302 - phase 4');
# Redirect (301)
like(http_get('/phase1?what=redirect301'), qr/^HTTP.*301/, 'redirect 301 - phase 1');
like(http_get('/phase2?what=redirect301'), qr/^HTTP.*301/, 'redirect 301 - phase 2');
like(http_get('/phase3?what=redirect301'), qr/^HTTP.*301/, 'redirect 301 - phase 3');
is(http_get('/phase4?what=redirect301'), '', 'redirect 301 - phase 4');
# Block (401)
like(http_get('/phase1?what=block401'), qr/^HTTP.*401/, 'block 401 - phase 1');
like(http_get('/phase2?what=block401'), qr/^HTTP.*401/, 'block 401 - phase 2');
like(http_get('/phase3?what=block401'), qr/^HTTP.*401/, 'block 401 - phase 3');
is(http_get('/phase4?what=block401'), '', 'block 401 - phase 4');
# Block (403)
like(http_get('/phase1?what=block403'), qr/^HTTP.*403/, 'block 403 - phase 1');
like(http_get('/phase2?what=block403'), qr/^HTTP.*403/, 'block 403 - phase 2');
like(http_get('/phase3?what=block403'), qr/^HTTP.*403/, 'block 403 - phase 3');
is(http_get('/phase4?what=block403'), '', 'block 403 - phase 4');
# Nothing to detect
like(http_get('/phase1?what=nothing'), qr/phase1\?what=nothing\' not found/, 'nothing phase 1');
like(http_get('/phase2?what=nothing'), qr/phase2\?what=nothing\' not found/, 'nothing phase 2');
like(http_get('/phase3?what=nothing'), qr/phase3\?what=nothing\' not found/, 'nothing phase 3');
like(http_get('/phase4?what=nothing'), qr/phase4\?what=nothing\' not found/, 'nothing phase 4');
###############################################################################
sub http_daemon {
my $server = IO::Socket::INET->new(
Proto => 'tcp',
LocalHost => '127.0.0.1:' . port(8081),
Listen => 5,
Reuse => 1
)
or die "Can't create listening socket: $!\n";
local $SIG{PIPE} = 'IGNORE';
while (my $client = $server->accept()) {
$client->autoflush(1);
my $headers = '';
my $uri = '';
while (<$client>) {
$headers .= $_;
last if (/^\x0d?\x0a?$/);
}
$uri = $1 if $headers =~ /^\S+\s+([^ ]+)\s+HTTP/i;
if ($uri eq '/') {
print $client <<'EOF';
HTTP/1.1 200 OK
Connection: close
EOF
print $client "TEST-OK-IF-YOU-SEE-THIS"
unless $headers =~ /^HEAD/i;
} elsif ($uri eq '/multi') {
print $client <<"EOF";
HTTP/1.1 200 OK
Connection: close
TEST-OK-IF-YOU-SEE-THIS
EOF
select undef, undef, undef, 0.1;
print $client 'AND-THIS';
} else {
print $client <<"EOF";
HTTP/1.1 404 Not Found
Connection: close
Oops, '$uri' not found
EOF
}
close $client;
}
}
###############################################################################

View File

@ -0,0 +1,224 @@
#!/usr/bin/perl
# (C) Andrei Belov
# Tests for ModSecurity-nginx connector (request body operations, HTTP/2).
###############################################################################
use warnings;
use strict;
use Test::More;
use Socket qw/ CRLF /;
BEGIN { use FindBin; chdir($FindBin::Bin); }
use lib 'lib';
use Test::Nginx;
use Test::Nginx::HTTP2;
###############################################################################
select STDERR; $| = 1;
select STDOUT; $| = 1;
my $t = Test::Nginx->new()->has(qw/http http_v2 proxy auth_request/);
$t->write_file_expand('nginx.conf', <<'EOF');
%%TEST_GLOBALS%%
daemon off;
events {
}
http {
%%TEST_GLOBALS_HTTP%%
server {
listen 127.0.0.1:8081;
location / {
return 200 "TEST-OK-IF-YOU-SEE-THIS";
}
}
server {
listen 127.0.0.1:8080 http2;
server_name localhost;
modsecurity on;
client_header_buffer_size 1024;
location /bodyaccess {
modsecurity_rules '
SecRuleEngine On
SecRequestBodyAccess On
SecRule REQUEST_BODY "@rx BAD BODY" "id:11,phase:request,deny,log,status:403"
';
proxy_pass http://127.0.0.1:8081;
}
location /nobodyaccess {
modsecurity_rules '
SecRuleEngine On
SecRequestBodyAccess Off
SecRule REQUEST_BODY "@rx BAD BODY" "id:21,phase:request,deny,log,status:403"
SecRule ARGS_POST|ARGS_POST_NAMES "@rx BAD ARG" "id:22,phase:request,deny,log,status:403"
';
proxy_pass http://127.0.0.1:8081;
}
location /bodylimitreject {
modsecurity_rules '
SecRuleEngine On
SecRequestBodyAccess On
SecRequestBodyLimit 128
SecRequestBodyLimitAction Reject
SecRule REQUEST_BODY "@rx BAD BODY" "id:31,phase:request,deny,log,status:403"
';
proxy_pass http://127.0.0.1:8081;
}
location /bodylimitprocesspartial {
modsecurity_rules '
SecRuleEngine On
SecRequestBodyAccess On
SecRequestBodyLimit 128
SecRequestBodyLimitAction ProcessPartial
SecRule REQUEST_BODY "@rx BAD BODY" "id:41,phase:request,deny,log,status:403"
';
proxy_pass http://127.0.0.1:8081;
}
location = /auth {
return 200;
}
location = /useauth {
modsecurity on;
modsecurity_rules '
SecRuleEngine On
SecRequestBodyAccess On
';
auth_request /auth;
proxy_pass http://127.0.0.1:8081;
}
}
}
EOF
$t->run();
$t->plan(36);
###############################################################################
my ($s, $sid, $frames, $frame);
foreach my $method (('GET', 'POST', 'PUT', 'DELETE')) {
$s = Test::Nginx::HTTP2->new();
$sid = $s->new_stream({ method => $method, path => '/bodyaccess', 'body_more' => 1 });
$s->h2_body('GOOD BODY');
$frames = $s->read(all => [{ sid => $sid, fin => 1 }]);
($frame) = grep { $_->{type} eq "DATA" } @$frames;
like($frame->{data}, qr/TEST-OK-IF-YOU-SEE-THIS/, "${method} request body access on, pass");
$s = Test::Nginx::HTTP2->new();
$sid = $s->new_stream({ method => $method, path => '/bodyaccess', 'body_more' => 1 });
$s->h2_body('VERY BAD BODY');
$frames = $s->read(all => [{ sid => $sid, fin => 1 }]);
($frame) = grep { $_->{type} eq "HEADERS" } @$frames;
is($frame->{headers}->{':status'}, 403, "${method} request body access on, block");
$s = Test::Nginx::HTTP2->new();
$sid = $s->new_stream({ method => $method, path => '/nobodyaccess', 'body_more' => 1 });
$s->h2_body('VERY BAD BODY');
$frames = $s->read(all => [{ sid => $sid, fin => 1 }]);
($frame) = grep { $_->{type} eq "DATA" } @$frames;
like($frame->{data}, qr/TEST-OK-IF-YOU-SEE-THIS/, "${method} request body access off, pass");
$s = Test::Nginx::HTTP2->new();
$sid = $s->new_stream({ 'body_more' => 1,
headers => [
{name => ':method', value => "${method}" },
{name => ':scheme', value => 'http' },
{name => ':path', value => '/nobodyaccess' },
{name => 'host', value => 'localhost' },
{name => 'content-type', value => 'application/x-www-form-urlencoded' }
] });
$s->h2_body('test=VERY BAD BODY');
$frames = $s->read(all => [{ sid => $sid, fin => 1 }]);
($frame) = grep { $_->{type} eq "DATA" } @$frames;
like($frame->{data}, qr/TEST-OK-IF-YOU-SEE-THIS/, "${method} request body access off (ARGS_POST), pass");
$s = Test::Nginx::HTTP2->new();
$sid = $s->new_stream({ method => $method, path => '/bodylimitreject', 'body_more' => 1 });
$s->h2_body('BODY' x 32);
$frames = $s->read(all => [{ sid => $sid, fin => 1 }]);
($frame) = grep { $_->{type} eq "DATA" } @$frames;
like($frame->{data}, qr/TEST-OK-IF-YOU-SEE-THIS/, "${method} request body limit reject, pass");
$s = Test::Nginx::HTTP2->new();
$sid = $s->new_stream({ method => $method, path => '/bodylimitreject', 'body_more' => 1 });
$s->h2_body('BODY' x 33);
$frames = $s->read(all => [{ sid => $sid, fin => 1 }]);
($frame) = grep { $_->{type} eq "HEADERS" } @$frames;
is($frame->{headers}->{':status'}, 403, "${method} request body limit reject, block");
$s = Test::Nginx::HTTP2->new();
$sid = $s->new_stream({ method => $method, path => '/bodylimitprocesspartial', 'body_more' => 1 });
$s->h2_body('BODY' x 32 . 'BAD BODY');
$frames = $s->read(all => [{ sid => $sid, fin => 1 }]);
($frame) = grep { $_->{type} eq "DATA" } @$frames;
like($frame->{data}, qr/TEST-OK-IF-YOU-SEE-THIS/, "${method} request body limit process partial, pass");
$s = Test::Nginx::HTTP2->new();
$sid = $s->new_stream({ method => $method, path => '/bodylimitprocesspartial', 'body_more' => 1 });
$s->h2_body('BODY' x 30 . 'BAD BODY' x 32);
$frames = $s->read(all => [{ sid => $sid, fin => 1 }]);
($frame) = grep { $_->{type} eq "HEADERS" } @$frames;
is($frame->{headers}->{':status'}, 403, "${method} request body limit process partial, block");
}
TODO: {
# https://github.com/SpiderLabs/ModSecurity-nginx/issues/163
# https://github.com/nginx/nginx/commit/6c89d752c8ab3a3cc0832927484808b68153f8c4
local $TODO = 'not yet' unless $t->has_version('1.19.3');
$s = Test::Nginx::HTTP2->new();
$sid = $s->new_stream({ method => 'POST', path => '/useauth', 'body' => 'BODY' x 16 });
$frames = $s->read(all => [{ sid => $sid, fin => 1 }]);
($frame) = grep { $_->{type} eq "DATA" } @$frames;
like($frame->{data}, qr/TEST-OK-IF-YOU-SEE-THIS/, "POST with auth_request (request size < client_header_buffer_size)");
$s = Test::Nginx::HTTP2->new();
$sid = $s->new_stream({ method => 'POST', path => '/useauth', 'body' => 'BODY' x 257 });
$frames = $s->read(all => [{ sid => $sid, fin => 1 }]);
($frame) = grep { $_->{type} eq "DATA" } @$frames;
like($frame->{data}, qr/TEST-OK-IF-YOU-SEE-THIS/, "POST with auth_request (request size > client_header_buffer_size)");
$s = Test::Nginx::HTTP2->new();
$sid = $s->new_stream({ method => 'POST', path => '/useauth', 'body_more' => 1 });
$s->h2_body('BODY' x 15, { 'body_more' => 1 });
select undef, undef, undef, 0.1;
$s->h2_body('BODY');
$frames = $s->read(all => [{ sid => $sid, fin => 1 }]);
($frame) = grep { $_->{type} eq "DATA" } @$frames;
like($frame->{data}, qr/TEST-OK-IF-YOU-SEE-THIS/, "POST with auth_request (request size < client_header_buffer_size), no preread");
$s = Test::Nginx::HTTP2->new();
$sid = $s->new_stream({ method => 'POST', path => '/useauth', 'body_more' => 1 });
$s->h2_body('BODY' x 256, { 'body_more' => 1 });
select undef, undef, undef, 0.1;
$s->h2_body('BODY');
$frames = $s->read(all => [{ sid => $sid, fin => 1 }]);
($frame) = grep { $_->{type} eq "DATA" } @$frames;
like($frame->{data}, qr/TEST-OK-IF-YOU-SEE-THIS/, "POST with auth_request (request size > client_header_buffer_size), no preread");
}
###############################################################################

View File

@ -0,0 +1,251 @@
#!/usr/bin/perl
# (C) Andrei Belov
# Tests for ModSecurity-nginx connector (request body operations).
###############################################################################
use warnings;
use strict;
use Test::More;
use Socket qw/ CRLF /;
BEGIN { use FindBin; chdir($FindBin::Bin); }
use lib 'lib';
use Test::Nginx;
###############################################################################
select STDERR; $| = 1;
select STDOUT; $| = 1;
my $t = Test::Nginx->new()->has(qw/http proxy auth_request/);
$t->write_file_expand('nginx.conf', <<'EOF');
%%TEST_GLOBALS%%
daemon off;
events {
}
http {
%%TEST_GLOBALS_HTTP%%
server {
listen 127.0.0.1:8080;
server_name localhost;
modsecurity on;
client_header_buffer_size 1024;
location /bodyaccess {
modsecurity_rules '
SecRuleEngine On
SecRequestBodyAccess On
SecRule REQUEST_BODY "@rx BAD BODY" "id:11,phase:request,deny,log,status:403"
';
proxy_pass http://127.0.0.1:%%PORT_8081%%;
}
location /nobodyaccess {
modsecurity_rules '
SecRuleEngine On
SecRequestBodyAccess Off
SecRule REQUEST_BODY "@rx BAD BODY" "id:21,phase:request,deny,log,status:403"
SecRule ARGS_POST|ARGS_POST_NAMES "@rx BAD ARG" "id:22,phase:request,deny,log,status:403"
';
proxy_pass http://127.0.0.1:%%PORT_8081%%;
}
location /bodylimitreject {
modsecurity_rules '
SecRuleEngine On
SecRequestBodyAccess On
SecRequestBodyLimit 128
SecRequestBodyLimitAction Reject
SecRule REQUEST_BODY "@rx BAD BODY" "id:31,phase:request,deny,log,status:403"
';
proxy_pass http://127.0.0.1:%%PORT_8081%%;
}
location /bodylimitrejectserver {
modsecurity off;
proxy_pass http://127.0.0.1:%%PORT_8082%%;
}
location /bodylimitprocesspartial {
modsecurity_rules '
SecRuleEngine On
SecRequestBodyAccess On
SecRequestBodyLimit 128
SecRequestBodyLimitAction ProcessPartial
SecRule REQUEST_BODY "@rx BAD BODY" "id:41,phase:request,deny,log,status:403"
';
proxy_pass http://127.0.0.1:%%PORT_8081%%;
}
location = /auth {
return 200;
}
location = /useauth {
modsecurity on;
modsecurity_rules '
SecRuleEngine On
SecRequestBodyAccess On
';
auth_request /auth;
proxy_pass http://127.0.0.1:%%PORT_8081%%;
}
}
server {
listen 127.0.0.1:%%PORT_8082%%;
modsecurity on;
modsecurity_rules '
SecRuleEngine On
SecRequestBodyAccess On
SecRequestBodyLimit 128
SecRequestBodyLimitAction Reject
SecRule REQUEST_BODY "@rx BAD BODY" "id:31,phase:request,deny,log,status:403"
';
location / {
proxy_pass http://127.0.0.1:%%PORT_8081%%;
}
}
}
EOF
$t->run_daemon(\&http_daemon);
$t->run()->waitforsocket('127.0.0.1:' . port(8081));
$t->plan(40);
###############################################################################
foreach my $method (('GET', 'POST', 'PUT', 'DELETE')) {
like(http_req_body($method, '/bodyaccess', 'GOOD BODY'), qr/TEST-OK-IF-YOU-SEE-THIS/, "$method request body access on, pass");
like(http_req_body($method, '/bodyaccess', 'VERY BAD BODY'), qr/^HTTP.*403/, "$method request body access on, block");
like(http_req_body($method, '/nobodyaccess', 'VERY BAD BODY'), qr/TEST-OK-IF-YOU-SEE-THIS/, "$method request body access off, pass");
like(http_req_body_postargs($method, '/nobodyaccess', 'BAD ARG'), qr/TEST-OK-IF-YOU-SEE-THIS/, "$method request body access off (ARGS_POST), pass");
like(http_req_body($method, '/bodylimitreject', 'BODY' x 32), qr/TEST-OK-IF-YOU-SEE-THIS/, "$method request body limit reject, pass");
like(http_req_body($method, '/bodylimitreject', 'BODY' x 33), qr/^HTTP.*403/, "$method request body limit reject, block");
like(http_req_body($method, '/bodylimitprocesspartial', 'BODY' x 32 . 'BAD BODY'), qr/TEST-OK-IF-YOU-SEE-THIS/, "$method request body limit process partial, pass");
like(http_req_body($method, '/bodylimitprocesspartial', 'BODY' x 30 . 'BAD BODY' x 32), qr/^HTTP.*403/, "$method request body limit process partial, block");
}
like(http_req_body('POST', '/useauth', 'BODY' x 16), qr/TEST-OK-IF-YOU-SEE-THIS/, "POST with auth_request (request size < client_header_buffer_size)");
like(http_req_body('POST', '/useauth', 'BODY' x 257), qr/TEST-OK-IF-YOU-SEE-THIS/, "POST with auth_request (request size > client_header_buffer_size)");
like(
http(
'POST /useauth HTTP/1.0' . CRLF
. 'Content-Length: 1028' . CRLF . CRLF
. 'BODY' x 256,
sleep => 0.1,
body => 'BODY'
),
qr/TEST-OK-IF-YOU-SEE-THIS/,
'POST with auth_request (request size > client_header_buffer_size), no preread'
);
like(
http(
'POST /useauth HTTP/1.0' . CRLF
. 'Content-Length: 64' . CRLF . CRLF
. 'BODY' x 15,
sleep => 0.1,
body => 'BODY'
),
qr/TEST-OK-IF-YOU-SEE-THIS/,
'POST with auth_request (request size < client_header_buffer_size), no preread'
);
foreach my $method (('GET', 'POST', 'PUT', 'DELETE')) {
like(http_req_body($method, '/bodylimitrejectserver', 'BODY' x 33), qr/^HTTP.*403/, "$method request body limit reject, block (inherited SecRequestBodyLimit)");
}
###############################################################################
sub http_daemon {
my $server = IO::Socket::INET->new(
Proto => 'tcp',
LocalHost => '127.0.0.1:' . port(8081),
Listen => 5,
Reuse => 1
)
or die "Can't create listening socket: $!\n";
local $SIG{PIPE} = 'IGNORE';
while (my $client = $server->accept()) {
$client->autoflush(1);
my $headers = '';
my $uri = '';
while (<$client>) {
$headers .= $_;
last if (/^\x0d?\x0a?$/);
}
$uri = $1 if $headers =~ /^\S+\s+([^ ]+)\s+HTTP/i;
print $client <<'EOF';
HTTP/1.1 200 OK
Connection: close
EOF
print $client "TEST-OK-IF-YOU-SEE-THIS"
unless $headers =~ /^HEAD/i;
close $client;
}
}
sub http_req_body {
my $method = shift;
my $uri = shift;
my $last = pop;
return http( join '', (map {
my $body = $_;
"$method $uri HTTP/1.1" . CRLF
. "Host: localhost" . CRLF
. "Content-Length: " . (length $body) . CRLF . CRLF
. $body
} @_),
"$method $uri HTTP/1.1" . CRLF
. "Host: localhost" . CRLF
. "Connection: close" . CRLF
. "Content-Length: " . (length $last) . CRLF . CRLF
. $last
);
}
sub http_req_body_postargs {
my $method = shift;
my $uri = shift;
my $last = pop;
return http( join '', (map {
my $body = $_;
"$method $uri HTTP/1.1" . CRLF
. "Host: localhost" . CRLF
. "Content-Type: application/x-www-form-urlencoded" . CRLF
. "Content-Length: " . (length "test=" . $body) . CRLF . CRLF
. "test=" . $body
} @_),
"$method $uri HTTP/1.1" . CRLF
. "Host: localhost" . CRLF
. "Connection: close" . CRLF
. "Content-Type: application/x-www-form-urlencoded" . CRLF
. "Content-Length: " . (length "test=" . $last) . CRLF . CRLF
. "test=" . $last
);
}
###############################################################################

View File

@ -0,0 +1,69 @@
#!/usr/bin/perl
# (C) Andrei Belov
# Tests for ModSecurity-nginx connector (response body operations).
###############################################################################
use warnings;
use strict;
use Test::More;
BEGIN { use FindBin; chdir($FindBin::Bin); }
use lib 'lib';
use Test::Nginx;
###############################################################################
select STDERR; $| = 1;
select STDOUT; $| = 1;
my $t = Test::Nginx->new()->has(qw/http/);
$t->write_file_expand('nginx.conf', <<'EOF');
%%TEST_GLOBALS%%
daemon off;
events {
}
http {
%%TEST_GLOBALS_HTTP%%
server {
listen 127.0.0.1:8080;
server_name localhost;
modsecurity on;
location /body1 {
default_type text/plain;
modsecurity_rules '
SecRuleEngine On
SecResponseBodyAccess On
SecResponseBodyLimit 128
SecRule RESPONSE_BODY "@rx BAD BODY" "id:11,phase:response,deny,log,status:403"
';
}
}
}
EOF
$t->write_file("/body1", "BAD BODY");
$t->run();
$t->todo_alerts();
$t->plan(1);
###############################################################################
TODO: {
local $TODO = 'not yet';
like(http_get('/body1'), qr/^HTTP.*403/, 'response body (block)');
}

View File

@ -0,0 +1,79 @@
#!/usr/bin/perl
# (C) Andrei Belov
# Tests for ModSecurity-nginx connector (scoring).
###############################################################################
use warnings;
use strict;
use Test::More;
BEGIN { use FindBin; chdir($FindBin::Bin); }
use lib 'lib';
use Test::Nginx;
###############################################################################
select STDERR; $| = 1;
select STDOUT; $| = 1;
my $t = Test::Nginx->new()->has(qw/http/);
$t->write_file_expand('nginx.conf', <<'EOF');
%%TEST_GLOBALS%%
daemon off;
events {
}
http {
%%TEST_GLOBALS_HTTP%%
server {
listen 127.0.0.1:8080;
server_name localhost;
modsecurity on;
location /absolute {
modsecurity_rules '
SecRuleEngine On
SecRule ARGS "@streq badarg1" "id:11,phase:2,setvar:tx.score=1"
SecRule ARGS "@streq badarg2" "id:12,phase:2,setvar:tx.score=2"
SecRule TX:SCORE "@ge 2" "id:199,phase:request,deny,log,status:403"
';
}
location /iterative {
modsecurity_rules '
SecRuleEngine On
SecRule ARGS "@streq badarg1" "id:21,phase:2,setvar:tx.score=+1"
SecRule ARGS "@streq badarg2" "id:22,phase:2,setvar:tx.score=+1"
SecRule ARGS "@streq badarg3" "id:23,phase:2,setvar:tx.score=+1"
SecRule TX:SCORE "@ge 3" "id:299,phase:request,deny,log,status:403"
';
}
}
}
EOF
$t->write_file("/absolute", "should be moved/blocked before this.");
$t->write_file("/iterative", "should be moved/blocked before this.");
$t->run();
$t->plan(5);
###############################################################################
like(http_get('/absolute?what=badarg1'), qr/should be moved\/blocked before this./, 'absolute scoring 1 (pass)');
like(http_get('/absolute?what=badarg2'), qr/^HTTP.*403/, 'absolute scoring 2 (block)');
like(http_get('/iterative?arg1=badarg1'), qr/should be moved\/blocked before this./, 'iterative scoring 1 (pass)');
like(http_get('/iterative?arg1=badarg1&arg2=badarg2'), qr/should be moved\/blocked before this./, 'iterative scoring 2 (pass)');
like(http_get('/iterative?arg1=badarg1&arg2=badarg2&arg3=badarg3'), qr/^HTTP.*403/, 'iterative scoring 3 (block)');

View File

@ -0,0 +1,167 @@
#!/usr/bin/perl
# (C) Andrei Belov
# Tests for ModSecurity-nginx connector (modsecurity_transaction_id).
###############################################################################
use warnings;
use strict;
use Test::More;
BEGIN { use FindBin; chdir($FindBin::Bin); }
use lib 'lib';
use Test::Nginx;
###############################################################################
select STDERR; $| = 1;
select STDOUT; $| = 1;
my $t = Test::Nginx->new()->plan(5)->write_file_expand('nginx.conf', <<'EOF');
%%TEST_GLOBALS%%
daemon off;
events {
}
http {
%%TEST_GLOBALS_HTTP%%
modsecurity_transaction_id "tid-HTTP-DEFAULT-$request_id";
server {
listen 127.0.0.1:8080;
server_name server1;
location / {
error_log %%TESTDIR%%/e_s1l1.log info;
modsecurity on;
modsecurity_rules '
SecRuleEngine On
SecDefaultAction "phase:1,log,deny,status:403"
SecRule ARGS "@streq block403" "id:4,phase:1,status:403,block"
';
}
}
server {
listen 127.0.0.1:8080;
server_name server2;
modsecurity_transaction_id "tid-SERVER-DEFAULT-$request_id";
location / {
error_log %%TESTDIR%%/e_s2l1.log info;
modsecurity on;
modsecurity_rules '
SecRuleEngine On
SecDefaultAction "phase:1,log,deny,status:403"
SecRule ARGS "@streq block403" "id:4,phase:1,status:403,block"
';
}
location /specific {
error_log %%TESTDIR%%/e_s2l2.log info;
modsecurity on;
modsecurity_transaction_id "tid-LOCATION-SPECIFIC-$request_id";
modsecurity_rules '
SecRuleEngine On
SecDefaultAction "phase:1,log,deny,status:403"
SecRule ARGS "@streq block403" "id:4,phase:1,status:403,block"
';
}
location /debuglog {
modsecurity on;
modsecurity_transaction_id "tid-DEBUG-$request_id";
modsecurity_rules '
SecRuleEngine On
SecDebugLog %%TESTDIR%%/modsec_debug.log
SecDebugLogLevel 4
SecDefaultAction "phase:1,log,deny,status:403"
SecRule ARGS "@streq block403" "id:4,phase:1,status:403,block"
';
}
location /auditlog {
modsecurity on;
modsecurity_transaction_id "tid-AUDIT-$request_id";
modsecurity_rules '
SecRuleEngine On
SecDefaultAction "phase:1,log,deny,status:403"
SecAuditEngine On
SecAuditLogParts A
SecAuditLog %%TESTDIR%%/modsec_audit.log
SecAuditLogType Serial
SecAuditLogStorageDir %%TESTDIR%%/
SecRule ARGS "@streq block403" "id:4,phase:1,status:403,block"
';
}
}
}
EOF
$t->run();
###############################################################################
# charge limit_req
http(<<EOF);
GET /?what=block403 HTTP/1.0
Host: server1
EOF
isnt(lines($t, 'e_s1l1.log', 'unique_id "tid-HTTP-DEFAULT-'), 0, 'http default');
http(<<EOF);
GET /?what=block403 HTTP/1.0
Host: server2
EOF
isnt(lines($t, 'e_s2l1.log', 'unique_id "tid-SERVER-DEFAULT-'), 0, 'server default');
http(<<EOF);
GET /specific/?what=block403 HTTP/1.0
Host: server2
EOF
isnt(lines($t, 'e_s2l2.log', 'unique_id "tid-LOCATION-SPECIFIC-'), 0, 'location specific');
http(<<EOF);
GET /debuglog/?what=block403 HTTP/1.0
Host: server2
EOF
isnt(lines($t, 'modsec_debug.log', 'tid-DEBUG-'), 0, 'libmodsecurity debug log');
http(<<EOF);
GET /auditlog/?what=block403 HTTP/1.0
Host: server2
EOF
isnt(lines($t, 'modsec_audit.log', 'tid-AUDIT-'), 0, 'libmodsecurity audit log');
###############################################################################
sub lines {
my ($t, $file, $pattern) = @_;
my $path = $t->testdir() . '/' . $file;
open my $fh, '<', $path or return "$!";
my $value = map { $_ =~ /\Q$pattern\E/ } (<$fh>);
close $fh;
return $value;
}
###############################################################################

View File

@ -0,0 +1,172 @@
#!/usr/bin/perl
#
# ModSecurity, http://www.modsecurity.org/
# Copyright (c) 2015 Trustwave Holdings, Inc. (http://www.trustwave.com/)
#
# You may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# If any of the files related to licensing are missing or if you have any
# other questions related to licensing please contact Trustwave Holdings, Inc.
# directly using the email address security@modsecurity.org.
#
# Tests for ModSecurity module.
###############################################################################
use warnings;
use strict;
use Test::More;
BEGIN { use FindBin; chdir($FindBin::Bin); }
use lib 'lib';
use Test::Nginx;
###############################################################################
select STDERR; $| = 1;
select STDOUT; $| = 1;
my $t = Test::Nginx->new()->has(qw/http/);
$t->write_file_expand('nginx.conf', <<'EOF');
%%TEST_GLOBALS%%
daemon off;
events {
}
http {
%%TEST_GLOBALS_HTTP%%
server {
listen 127.0.0.1:8080;
server_name localhost;
location / {
modsecurity on;
modsecurity_rules '
SecRuleEngine On
SecRule ARGS "@streq whee" "id:10,phase:2"
SecRule ARGS "@streq whee" "id:11,phase:2"
';
}
location /phase1 {
modsecurity on;
modsecurity_rules '
SecRuleEngine On
SecDefaultAction "phase:1,log,deny,status:403"
SecRule ARGS "@streq redirect301" "id:1,phase:1,status:301,redirect:http://www.modsecurity.org"
SecRule ARGS "@streq redirect302" "id:2,phase:1,status:302,redirect:http://www.modsecurity.org"
SecRule ARGS "@streq block401" "id:3,phase:1,status:401,block"
SecRule ARGS "@streq block403" "id:4,phase:1,status:403,block"
';
}
location /phase2 {
modsecurity on;
modsecurity_rules '
SecRuleEngine On
SecDefaultAction "phase:2,log,deny,status:403"
SecRule ARGS "@streq redirect301" "id:1,phase:2,status:301,redirect:http://www.modsecurity.org"
SecRule ARGS "@streq redirect302" "id:2,phase:2,status:302,redirect:http://www.modsecurity.org"
SecRule ARGS "@streq block401" "id:3,phase:2,status:401,block"
SecRule ARGS "@streq block403" "id:4,phase:2,status:403,block"
';
}
location /phase3 {
modsecurity on;
modsecurity_rules '
SecRuleEngine On
SecDefaultAction "phase:3,log,deny,status:403"
SecRule ARGS "@streq redirect301" "id:1,phase:3,status:301,redirect:http://www.modsecurity.org"
SecRule ARGS "@streq redirect302" "id:2,phase:3,status:302,redirect:http://www.modsecurity.org"
SecRule ARGS "@streq block401" "id:3,phase:3,status:401,block"
SecRule ARGS "@streq block403" "id:4,phase:3,status:403,block"
';
}
location /phase4 {
modsecurity on;
modsecurity_rules '
SecRuleEngine On
SecResponseBodyAccess On
SecDefaultAction "phase:4,log,deny,status:403"
SecRule ARGS "@streq redirect301" "id:1,phase:4,status:301,redirect:http://www.modsecurity.org"
SecRule ARGS "@streq redirect302" "id:2,phase:4,status:302,redirect:http://www.modsecurity.org"
SecRule ARGS "@streq block401" "id:3,phase:4,status:401,block"
SecRule ARGS "@streq block403" "id:4,phase:4,status:403,block"
';
}
location /early-block {
modsecurity on;
modsecurity_rules '
SecRuleEngine On
SecResponseBodyAccess On
SecDefaultAction "phase:1,log,auditlog,pass"
SecDefaultAction "phase:2,log,auditlog,pass"
SecAction "id:900101,phase:1,nolog,pass,t:none,setvar:tx.trigger_phase1=1"
SecAction "id:900103,phase:1,nolog,pass,t:none,setvar:tx.trigger_phase3=1"
SecAction "id:900105,phase:1,nolog,pass,t:none,setvar:tx.trigger_phase5=1"
SecRule TX:TRIGGER_PHASE1 "@eq 1" "id:901111,phase:1,t:none,deny,log"
SecRule REQUEST_BODY "@rx attack" "id:901121,phase:2,t:none,deny,log"
SecRule TX:TRIGGER_PHASE3 "@eq 1" "id:901131,phase:3,t:none,deny,log"
SecRule RESPONSE_BODY "@rx ok" "id:901141,phase:4,t:none,deny,log"
SecRule TX:TRIGGER_PHASE5 "@eq 1" "id:901151,phase:5,t:none,pass,log,msg:\'This is the phase 5.\'"
';
}
}
}
EOF
$t->write_file("/phase1", "should be moved/blocked before this.");
$t->write_file("/phase2", "should be moved/blocked before this.");
$t->write_file("/phase3", "should be moved/blocked before this.");
$t->write_file("/phase4", "should not be moved/blocked, headers delivered before phase 4.");
$t->write_file("/early-block", "should be moved/blocked before this.");
$t->run();
$t->todo_alerts();
$t->plan(21);
###############################################################################
# Redirect (302)
like(http_get('/phase1?what=redirect302'), qr/^HTTP.*302/, 'redirect 302 - phase 1');
like(http_get('/phase2?what=redirect302'), qr/^HTTP.*302/, 'redirect 302 - phase 2');
like(http_get('/phase3?what=redirect302'), qr/^HTTP.*302/, 'redirect 302 - phase 3');
is(http_get('/phase4?what=redirect302'), '', 'redirect 302 - phase 4');
# Redirect (301)
like(http_get('/phase1?what=redirect301'), qr/^HTTP.*301/, 'redirect 301 - phase 1');
like(http_get('/phase2?what=redirect301'), qr/^HTTP.*301/, 'redirect 301 - phase 2');
like(http_get('/phase3?what=redirect301'), qr/^HTTP.*301/, 'redirect 301 - phase 3');
is(http_get('/phase4?what=redirect301'), '', 'redirect 301 - phase 4');
# Block (401)
like(http_get('/phase1?what=block401'), qr/^HTTP.*401/, 'block 401 - phase 1');
like(http_get('/phase2?what=block401'), qr/^HTTP.*401/, 'block 401 - phase 2');
like(http_get('/phase3?what=block401'), qr/^HTTP.*401/, 'block 401 - phase 3');
is(http_get('/phase4?what=block401'), '', 'block 401 - phase 4');
# Block (403)
like(http_get('/phase1?what=block403'), qr/^HTTP.*403/, 'block 403 - phase 1');
like(http_get('/phase2?what=block403'), qr/^HTTP.*403/, 'block 403 - phase 2');
like(http_get('/phase3?what=block403'), qr/^HTTP.*403/, 'block 403 - phase 3');
is(http_get('/phase4?what=block403'), '', 'block 403 - phase 4');
# Nothing to detect
like(http_get('/phase1?what=nothing'), qr/should be moved\/blocked before this./, 'nothing phase 1');
like(http_get('/phase2?what=nothing'), qr/should be moved\/blocked before this./, 'nothing phase 2');
like(http_get('/phase3?what=nothing'), qr/should be moved\/blocked before this./, 'nothing phase 3');
like(http_get('/phase4?what=nothing'), qr/should not be moved\/blocked, headers delivered before phase 4./, 'nothing phase 4');
# early block (https://github.com/SpiderLabs/ModSecurity-nginx/issues/238)
like(http_get('/early-block'), qr/^HTTP.*403/, 'early block 403 (https://github.com/SpiderLabs/ModSecurity-nginx/issues/238)');

View File

@ -0,0 +1,39 @@
#!/usr/bin/perl
#
# Script to adjust nginx tests to include ModSecurity directives. It enables
# us to passively test nginx functionality with ModSecurity module enabled.
#
# sh command line variations:
#
# for i in *.t; do cp -n $i $i.orig; perl nginx-tests-cvt.pl < $i.orig > $i; done
# for i in *.t; do perl nginx-tests-cvt.pl < $i.orig > $i; done
# for i in *.t; do cp $i.orig $i; done
my $ignore = 0;
while (<STDIN>) {
print $_;
$ignore = 1 if (/^mail {/); # skip mail_*.t mail blocks
$ignore = 0 if (/^http {/);
next if ($ignore);
if (/^ *server_name .*;$/) {
next if (/^ *server_name *below;/); # skip duplication on refresh.t
next if (/^ *server_name *many4.example.com;/); # skip duplication on http_server_name.t
print "
modsecurity on;
modsecurity_rules '
SecRuleEngine On
SecDebugLogLevel 9
SecRule ARGS \"\@streq whee\" \"id:10,phase:2\"
SecRule ARGS \"\@streq whee\" \"id:11,phase:2\"
';
";
}
}

View File

@ -0,0 +1,49 @@
---
name: Bug report for version 2.x
about: Create a report to help us improve
title: ''
labels: ''
assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is.
**Logs and dumps**
Output of:
1. DebugLogs (level 9)
2. AuditLogs
3. Error logs
4. If there is a crash, the core dump file.
_Notice:_ Be carefully to not leak any confidential information.
**To Reproduce**
Steps to reproduce the behavior:
A **curl** command line that mimics the original request and reproduces the problem. Or a ModSecurity v3 test case.
[e.g: curl "modsec-full/ca/..\\..\\..\\..\\..\\..\\/\\etc/\\passwd" or [issue-394.json](https://github.com/SpiderLabs/ModSecurity/blob/v3/master/test/test-cases/regression/issue-394.json)]
**Expected behavior**
A clear and concise description of what you expected to happen.
**Server (please complete the following information):**
- ModSecurity version (and connector): [e.g. ModSecurity v3.0.1 with nginx-connector v1.0.0]
- WebServer: [e.g. nginx-1.15.5]
- OS (and distro): [e.g. Linux, archlinux]
**Rule Set (please complete the following information):**
- Running any public or commercial rule set? [e.g. SpiderLabs commercial rules]
- What is the version number? [e.g. 2018-08-11]
**Additional context**
Add any other context about the problem here.

View File

@ -0,0 +1,50 @@
---
name: Bug report for version 3.x
about: Create a report to help us improve. If you don't know a specific detail or
piece of information leave it blank, if necessary we will help you to figure out.
title: ''
labels: ''
assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is.
**Logs and dumps**
Output of:
1. DebugLogs (level 9)
2. AuditLogs
3. Error logs
4. If there is a crash, the core dump file.
_Notice:_ Be careful to not leak any confidential information.
**To Reproduce**
Steps to reproduce the behavior:
A **curl** command line that mimics the original request and reproduces the problem. Or a ModSecurity v3 test case.
[e.g: curl "modsec-full/ca/..\\..\\..\\..\\..\\..\\/\\etc/\\passwd" or [issue-394.json](https://github.com/SpiderLabs/ModSecurity/blob/v3/master/test/test-cases/regression/issue-394.json)]
**Expected behavior**
A clear and concise description of what you expected to happen.
**Server (please complete the following information):**
- ModSecurity version (and connector): [e.g. ModSecurity v3.0.8 with nginx-connector v1.0.3]
- WebServer: [e.g. nginx-1.18.0]
- OS (and distro): [e.g. Linux, archlinux]
**Rule Set (please complete the following information):**
- Running any public or commercial rule set? [e.g. SpiderLabs commercial rules]
- What is the version number? [e.g. 2018-08-11]
**Additional context**
Add any other context about the problem here.

View File

@ -0,0 +1,77 @@
name: Quality Assurance
on:
push:
pull_request:
jobs:
build-linux:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-20.04]
platform: [x32, x64]
compiler: [gcc, clang]
configure:
- {label: "with parser generation", opt: "--enable-parser-generation" }
- {label: "wo curl", opt: "--without-curl" }
- {label: "wo yajl", opt: "--without-yajl" }
- {label: "wo geoip", opt: "--without-geoip" }
- {label: "wo lmdb", opt: "--without-lmdb" }
- {label: "wo ssdeep", opt: "--without-ssdeep" }
- {label: "wo lua", opt: "--without-lua" }
- {label: "without maxmind", opt: "--without-maxmind" }
steps:
- name: Setup Dependencies
run: |
sudo add-apt-repository --yes ppa:maxmind/ppa
sudo apt-get update -y -qq
sudo apt-get install -y libfuzzy-dev libyajl-dev libgeoip-dev liblua5.2-dev liblmdb-dev cppcheck libmaxminddb-dev libcurl4-openssl-dev
- uses: actions/checkout@v2
with:
submodules: true
- name: build.sh
run: ./build.sh
- name: configure ${{ matrix.configure.label }}
run: ./configure ${{ matrix.configure.opt }}
- uses: ammaraskar/gcc-problem-matcher@master
- name: make
run: make -j `nproc`
- name: check
run: make check
- name: check-static
run: make check-static
build-macos:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [macos-10.15]
compiler: [clang]
configure:
- {label: "with parser generation", opt: "--enable-parser-generation" }
- {label: "wo curl", opt: "--without-curl" }
- {label: "wo yajl", opt: "--without-yajl" }
- {label: "wo geoip", opt: "--without-geoip" }
- {label: "wo lmdb", opt: "--without-lmdb" }
- {label: "wo ssdeep", opt: "--without-ssdeep" }
- {label: "wo lua", opt: "--without-lua" }
- {label: "wo maxmind", opt: "--without-maxmind" }
steps:
- name: Setup Dependencies
run: |
brew install autoconf automake cppcheck lmdb libyaml lua ssdeep libmaxminddb bison
- uses: actions/checkout@v2
with:
submodules: true
- name: build.sh
run: ./build.sh
- name: configure ${{ matrix.configure.label }}
run: ./configure ${{ matrix.configure.opt }}
- uses: ammaraskar/gcc-problem-matcher@master
- name: make
run: make -j `sysctl -n hw.logicalcpu`
- name: check
run: make check
- name: check-static
run: make check-static

50
src/deps/src/ModSecurity/.gitignore vendored Normal file
View File

@ -0,0 +1,50 @@
*.o
*.lo
*.la
**/Makefile
**/Makefile.in
aclocal.m4
ar-lib
autom4te.cache/
build/libtool.m4
build/ltoptions.m4
build/ltsugar.m4
build/ltversion.m4
build/lt~obsolete.m4
compile
config.guess
config.log
config.status
config.sub
configure
depcomp
.deps
.libs
.dirstamp
src/config.h
src/config.h.in
src/location.hh
src/position.hh
src/stack.hh
src/stamp-h1
/test/rules_optimization
/test/regression_tests
/test/unit_tests
/test-driver
/test/massif.out.*
/test/benchmark/benchmark
/test/benchmark/owasp-v3/
/test/test-cases/regression/*.trs
/test/test-cases/regression/*.log
/test-suite.log
ylwrap
missing
install-sh
libtool
ltmain.sh
examples/simple_example_using_c/test
/tools/rules-check/modsec-rules-check
examples/multiprocess_c/multi
examples/reading_logs_via_rule_message/simple_request
examples/reading_logs_with_offset/read
examples/using_bodies_in_chunks/simple_request

9
src/deps/src/ModSecurity/.gitmodules vendored Normal file
View File

@ -0,0 +1,9 @@
[submodule "test/test-cases/secrules-language-tests"]
path = test/test-cases/secrules-language-tests
url = https://github.com/SpiderLabs/secrules-language-tests
[submodule "others/libinjection"]
path = others/libinjection
url = https://github.com/libinjection/libinjection.git
[submodule "bindings/python"]
path = bindings/python
url = https://github.com/SpiderLabs/ModSecurity-Python-bindings.git

View File

@ -0,0 +1,4 @@
zimmerle = Felipe Zimmerle <felipe@zimmerle.org>
rbarnett = Ryan C. Barnett <rcbarnett@gmail.com>
csanders-git = Chaim Sanders <chaim@chaimsanders.com>
victorhora = Victor Hora <victorminuto@gmail.com>

View File

@ -0,0 +1,552 @@
v3.0.9 - 2023-Apr-12
--------------------
- Fix: possible segfault on reload if duplicate ip+CIDR in ip match list
[Issue #2877, #2890 - @tomsommer, @martinhsv]
- Add some member variable inits in Transaction class (possible segfault)
[Issue #2886 - @GNU-Plus-Windows-User, @airween, @mdounin, @martinhsv]
- Resolve memory leak on reload (bison-generated variable)
[Issue #2876 - @martinhsv]
- Support equals sign in XPath expressions
[Issue #2328 - @dennus, @martinhsv]
- Encode two special chars in error.log output
[Issue #2854 - @airween, @martinhsv]
- Add JIT support for PCRE2
[Issue #2791 - @wfjsw, @airween, @FireBurn, @martinhsv]
- Support comments in ipMatchFromFile file via '#' token
[Issue #2554 - @tomsommer, @martinhsv]
- Use name package name libmaxminddb with pkg-config
[Issue #2595, #2596 - @frankvanbever, @ffontaine, @arnout]
- Fix: FILES_TMP_CONTENT collection key should use part name
[Issue #2831 - @airween]
- Use AS_HELP_STRING instead of obsolete AC_HELP_STRING macro
[Issue #2806 - @hughmcmaster]
- During configure, do not check for pcre if pcre2 specified
[Issue #2750 - @dvershinin, @martinhsv]
- Use pkg-config to find libxml2 first
[Issue #2714 - @hughmcmaster]
- Fix two rule-reload memory leak issues
[Issue #2801 - @Abce, @martinhsv]
- Correct whitespace handling for Include directive
[Issue #2800 - @877509395, @martinhsv]
v3.0.8 - 2022-Sep-07
--------------------
- Adjust parser activation rules in modsecurity.conf-recommended
[Issue #2796 - @terjanq, @martinhsv]
- Multipart parsing fixes and new MULTIPART_PART_HEADERS collection
[Issue #2795 - @terjanq, @martinhsv]
- Prevent LMDB related segfault
[Issue #2755, #2761 - @dvershinin]
- Fix msc_transaction_cleanup function comment typo
[Issue #2788 - @lookat23]
- Fix: MULTIPART_INVALID_PART connected to wrong internal variable
[Issue #2785 - @martinhsv]
- Restore Unique_id to include random portion after timestamp
[Issue #2752, #2758 - @datkps11, @martinhsv]
v3.0.7 - 2022-May-30
--------------------
- Move PCRE2 match block from member variable
[@martinhsv]
- Add SecArgumentsLimit, 200007 to modsecurity.conf-recommended
[Issue #2738 - @jleproust, @martinhsv]
- Fix memory leak when concurrent log includes REMOTE_USER
[Issue #2727 - @liudongmiao]
- Fix LMDB initialization issues
[Issue #2688 - @ziollek, @martinhsv]
- Fix initcol error message wording
[Issue #2732 - @877509395, @martinhsv]
- Tolerate other parameters after boundary in multipart C-T
[Issue #1900 - @martinhsv]
- Add DebugLog message for bad pattern in rx operator
[Issue #2723 - @martinhsv]
- Support PCRE2
[Issue #2668 - @martinhsv]
- Support SecRequestBodyNoFilesLimit
[Issue #2670 - @airween, @martinhsv]
- Fix misuses of LMDB API
[Issue #2601, #2602 - @hyc]
- Fix duplication typo in code comment
[Issue #2677 - @gleydsonsoares]
- Add ctl:auditEngine action support
[Issue #2606 - @alekravch, @martinhsv]
- Fix multiMatch msg, etc, population in audit log
[Issue #2573 - @Sachin-M-Desai, @martinhsv]
- Fix some name handling for ARGS_*NAMES: regex SecRuleUpdateTargetById, etc.
[Issue #2627, #2648 - @lontchianicet, @victorserbu2709, @martinhsv]
- Adjust confusing variable name in setRequestBody method
[Issue #2635 - @Mesar-Ali, @martinhsv]
- Multipart names/filenames may include single quote if double-quote enclosed
[Issue #2352 - @martinhsv]
- Add SecRequestBodyJsonDepthLimit to modsecurity.conf-recommended
[Issue #2647 - @theMiddleBlue, @airween, @877509395 ,@martinhsv]
v3.0.6 - 2021-Nov-19
-------------------------------------
- Support configurable limit on depth of JSON parsing
[@theMiddleBlue, @martinhsv]
v3.0.5 - 2021-Jul-07
--------------------
- Handle URI received with uri-fragment
[@martinhsv]
- Having ARGS_NAMES, variables proxied
[@zimmerle, @martinhsv, @KaNikita]
- Use explicit path for cross-compile environments.
[Issue #2485 - @dtoubelis]
- Fix: FILES variable does not use multipart part name for key
[Issue #2377 - @martinhsv]
- Replaces put with setenv in SetEnv action
[Issue #2469 - @martinhsv, @WGH-, @zimmerle]
- Regression: Mark the test as failed in case of segfault.
[@zimmerle]
- Regex key selection should not be case-sensitive
[Issue #2296, #2107, #2297 - @michaelgranzow-avi, @victorhora,
@airween, @martinhsv, @zimmerle]
- Fix: Only delete Multipart tmp files after rules have run
[Issue #2427 - @martinhsv]
- Fixed MatchedVar on chained rules
[Issue #2423, #2435, #2436 - @michaelgranzow-avi]
- Add support for new operator rxGlobal
[@martinhsv]
- Fix maxminddb link on FreeBSD
[Issue #2131 - @granalberto, @zimmerle]
- Fix IP address logging in Section A
[Issue #2300 - @inaratech, @zavazingo, @martinhsv]
- Adds support to lua 5.4
[@zimmerle]
- GeoIP: switch to GEOIP_MEMORY_CACHE from GEOIP_INDEX_CACHE
[Issues #2378, #2186 - @defanator]
- rx: exit after full match (remove /g emulation); ensure capture
groups occuring after unused groups still populate TX vars
[Issue #2336 - @martinhsv]
- Correct CHANGES file entry for #2234
- Add support to test framework for audit log content verification
and add regression tests for issues #2000, #2196
- Support configurable limit on number of arguments processed
[Issue #2234 - @jleproust, @martinhsv]
- Multipart Content-Dispostion should allow field: filename*=
[@martinhsv]
- Fix rule-update-target for non-regex
[Issue 2251 - @martinhsv]
- Fix configure script when packaging for Buildroot
[Issue 2235 - @frankvanbever]
- modsecurity.pc.in: add Libs.private
[Issue #1918, #2253 - @ffontaine, @Dridi, @victorhora]
v3.0.4 - 2020-Jan-13
--------------------
- Fix: audit log data omitted when nolog,auditlog
[@martinhsv]
- Fix: ModSecurity 3.x inspectFile operator does not pass
FILES_TMPNAMES parameter to lua engine
[Issue #2204, #2205 - @kadirerdogan]
- XML: Remove error messages from stderr
[Issue #2010 - @JaiHarpalani, @zimmerle]
- Filter comment or blank line for pmFromFile operator
[Issue #1645 - @LeeShan87, @victorhora, @tdoubley]
- Additional adjustment to Cookie header parsing
[@martinhsv]
- Restore chained rule part H logging to be more like 2.9 behaviour
[Issue #2196 - @martinhsv]
- Small fixes in log messages to help debugging the file upload
[Issue #2130 - @airween]
- Fix Cookie header parsing issues
[Issue #2201 - @airween, @martinhsv]
- Fix rules with nolog are logging to part H
[Issue #2196 - @martinhsv]
- Fix argument key-value pair parsing cases
[Issue #1904 - @martinhsv]
- Fix: audit log part for response body for JSON format to be E
[Issue #2066 - @martinhsv, @zimmerle]
- Make sure m_rulesMessages is filled after successfull match
[Issue #2000, #2048 - @victorhora, @defanator]
- Fix @pm lookup for possible matches on offset zero.
[@zimmerle, @afoxdavidi, @martinhsv, @marshal09]
- Regex lookup on the key name instead of COLLECTION:key
[@rdiperri-yottaa, @danbiagini-work, @mmelo-yottaa, @zimmerle]
- Missing throw in Operator::instantiate
[Issue #2106 - @marduone]
- Making block action execution dependent of the SecEngine status
[Issue #2113, #2111 - @theMiddleBlue, @airween]
- Making block action execution dependent of the SecEngine status
[Issue #1960 - @theMiddleBlue, @zimmerle, @airween, @victorhora]
- Having body limits to respect the rule engine state
[@zimmerle]
- Fix SecRuleUpdateTargetById does not match regular expressions
[Issue #1872 - @zimmerle, @anush-cr, @victorhora, @j0k2r]
- Adds missing check for runtime ctl:ruleRemoveByTag
[Issue #2102, #2099 - @airween]
- Adds a new operator verifySVNR that checks for Austrian social
security numbers.
[Issue #2063 - @Rufus125]
- Fix variables output in debug logs
[Issue #2057 - @jleproust]
- Correct typo validade in log output
[Issue #2059 - @nerrehmit]
- fix/minor: Error encoding hexa decimal.
[Issue #2068 - @tech-ozon-io]
- Limit more log variables to 200 characters.
[Issue #2073 - @jleproust]
- parser: fix parsed file names
[@zimmerle]
- Allow empty anchored variable
[Issue #2024 - @airween]
- Fixed FILES_NAMES collection after the end of multipart parsing
[Issue #2016 - @airween]
- Fixed validateByteRange parsing method
[Issue #2017 - @airween]
- Removes a memory leak on the JSON parser
[@zimmerle]
- Enables LMDB on the regression tests.
[Issue #2011, #2008 - @WGH-, @mdunc]
- Fix: Extra whitespace in some configuration directives causing error
[Issue #2006 - @porjo, @zimmerle]
- Refactoring on Regex and SMatch classes.
[@WGH-]
- Fixed buffer overflow in Utils::Md5::hexdigest()
[Issue #2002 - @defanator]
- Implemented merge() method for ConfigInt, ConfigDouble, ConfigString
[Issue #1990 - @defanator]
- Adds initially support to the drop action.
[@zimmerle]
- Complete merging of particular rule properties
[Issue #1978 - @defanator]
- Replaces AC_CHECK_FILE with 'test -f'
[Issue #1984 - @chuckwolber]
- Fix inet addr handling on 64 bit big endian systems
[Issue #1980 - @airween]
- Fix tests on FreeBSD
[Issue #1973 - @defanator]
- Changes ENV test case to read the default MODSECURTIY env var
[Issue #1969 - @zimmerle, @airween, @inittab]
- Regression: Sets MODSECURITY env var during the tests execution
[Issue #1969 - @zimmerle, @airween, @inittab]
- Fix setenv action to strdup key=variable
[@zimmerle]
- Allow 0 length JSON requests.
[Issue #1822 - @allanbomsft, @zimmerle, @victorhora, @marcstern]
- Fix "make dist" target to include default configuration
[Issue #1966 - @defanator]
- Replaced log locking using mutex with fcntl lock
[Issue #1949, #1927 - @Cloaked9000]
- Correct the usage of modsecurity::Phases::NUMBER_OF_PHASES
[Issue #1959 - @weliu]
- Adds support to multiple ranges in ctl:ruleRemoveById
[Issue #1956 - @theseion, @victorhora, @zimmerle]
- Rule variable interpolation broken
[Issue #1961 - @soonum, @zimmerle]
- Make the boundary check less strict as per RFC2046
[Issue #1943 - @victorhora, @allanbomsft]
- Fix buffer size for utf8toUnicode transformation
[Issue #1208 - @katef, @victorhora]
v3.0.3 - 2018-Nov-05
--------------------
- Fix double macros bug
[Issue #1943 - @supplient, @zimmerle]
- Override the default status code if not suitable to redirect action
[Issue #1850 - @zimmerle, @victorhora]
- parser: Fix the support for CRLF configuration files
[Issue #1945 - @zimmerle, @defanator, @kjakub]
- Organizes the server logs
[0xb7c36 and 0x5ac20 - @zimmerle, @steven-j-wojcik]
- m_lineNumber in Rule not mapping with the correct line number in file
[Issue #1844 - @zimmerle, @victorhora, @xizeng]
- Using shared_ptr instead of unique_ptr on rules exceptions
[Issue #1697 - @zimmerle, @brianp9906, @victorhora, @LeSwiss, @defanator]
- Changes debuglogs schema to avoid unecessary str allocation
[0xb2840 - @zimmerle]
- Fix the SecUnicodeMapFile and SecUnicodeCodePage
[0x3094d - @zimmerle, @victorhora]
- Changes the timing to save the rule message
[0xca270 - @zimmerle]
- Fix crash in msc_rules_add_file() when using disruptive action in chain
[Issue #1849 - @victorhora, @zimmerle, @rperper]
- Fix memory leak in AuditLog::init()
[Issue #1897 - @weliu]
- Fix RulesProperties::appendRules()
[Issue #1901 - @steven-j-wojcik]
- Fix RULE lookup in chained rules
[0x3077c - @zimmerle]
- @ipMatch "Could not add entry" on slash/32 notation in 2.9.0
[Issue #849 - @zimmerle, @dune73]
- Using values after transformation at MATCHED_VARS
[0x14316 - @zimmerle]
- Adds support to UpdateActionById.
[Issue #1800 - @zimmerle, @victorhora, @NisariAIT]
- Add correct C function prototypes for msc_init and msc_create_rule_set
[Issue #1922 - @steven-j-wojcik]
- Allow LuaJIT 2.1 to be used
[Issue #1909 - @victorhora, @mdunc]
- Match m_id JSON log with RuleMessage and v2 format
[Issue #1185 - @victorhora]
- Adds support to setenv action.
[Issue #1044 - @zimmerle]
- Adds new transaction constructor that accepts the transaction id
as parameter.
[Issue #1627 - @defanator, @zimmerle]
- Adds request IDs and URIs to the debug log
[Issue #1627 - @defanator, @zimmerle]
- Treating variables exception on load-time instead of run time.
[0x028e0 and 0x275a1 - @zimmerle]
- Fix: function m.setvar in Lua scripts and add testcases
[Issue #1859 - @nowaits, @victorhora]
- Fix SecResponseBodyAccess and ctl:requestBodyAccess directives
[Issue #1531 - @victorhora, @defanator]
- Fix OpenBSD build
[Issue #1841 - @victorhora, @zimmerle, @juanfra684]
- Fix parser to support GeoLookup with MaxMind
[Issue #1884, #1895 - @victorhora, @everping]
- parser: Fix simple quote setvar in the end of the line
[Issue #1831 - @zimmerle, @csanders-git]
- Fix pc file
[Issue #1847 - @gquintard]
- modsec_rules_check: uses the gnu `.la' instead of `.a' file
[Issue #1853 - @ste7677, @victorhora, @zimmerle]
- good practices: Initialize variables before use it
[Issue #1889 - Marc Stern]
- Fix utf-8 character encoding conversion
[Issue #1794 - @tinselcity, @zimmerle]
- Adds support for ctl:requestBodyProcessor=URLENCODED
[Issue #1797 - @victorhora]
- Add LUA compatibility for CentOS and try to use LuaJIT first if available
[Issue #1622 - @victorhora, @dmitryzykov]
- Allow LuaJIT to be used
[Issue #1809 - @victorhora, @p0pr0ck5]
- Implement support for Lua 5.1
[Issue #1809 - @p0pr0ck5, @victorhora]
- Variable names must match fully, not partially. Match should be case
insensitive.
[Issue #1818, #1820, #1810, #1808 - @michaelgranzow-avi, @victorhora,
@theMiddleBlue, @airween, @zimmerle,
@LeeShan87]
- Improves the performance while loading the rules
[Issue #1735 - @zimmerle, @p0pr0ck5, @victorhora]
- Allow empty strings to be evaluated by regex::searchAll
[Issue #1799, #1785 - @victorhora, @XuanHuyDuong, @zimmerle]
- Adds basic pkg-config info
[Issue #1790 - @gquintard, @zimmerle]
- Fixed LMDB collection errors
[Issue #1787 - @airween, @zimmerle]
- Fixed false positive MULTIPART_UNMATCHED_BOUNDARY errors
[Issue #1747, #1924 - @airween, @victorhora, @defanator, @zimmerle]
- Fix ip tree lookup on netmask content
[Issue #1793 - @tinselcity, @zimmerle]
- Changes the behavior of the default sec actions
[Issue #1629 - @mirkodziadzka-avi, @zimmerle, @victorhora]
- Refactoring on {global,ip,resources,session,tx,user} collections
[Issue #1754, #1778 - @LeeShan87, @zimmerle, @victorhora, @wwd5613,
@sobigboy]
- Fix race condition in UniqueId::uniqueId()
[Issue #1786 - @weliu]
- Fix memory leak in error message for msc_rules_merge C APIs
[Issue #1765 - @weliu]
- Return false in SharedFiles::open() when an error happens
[Issue #1783 - @weliu]
- Use rvalue reference in ModSecurity::serverLog
[Issue #1769 - @weliu]
- Build System: Fix when multiple lines for curl version.
[Issue #1771 - @Artistan]
- Checks if response body inspection is enabled before process it
[Issue #1643 - @zoltan-fedor, @dennus, @defanator, @zimmerle]
- Code Cleanup.
[Issue #1757, #1755, #1756, #1761 - @p0pr0ck5]
- Fix setvar parsing of quoted data
[Issue #1733, #1759, #1775 - @victorhora, @JaiHarpalani, @defanator]
- Fix LDFLAGS for unit tests.
[Issue #1758 - @smlx]
- Adds time stamp back to the audit logs
[Issue #1762 - @Pjack, @zimmerle]
- Disables skip counter if debug log is disabled
[@zimmerle]
- Cosmetics: Represents amount of skipped rules without decimal
[Issue #1737 - @p0pr0ck5]
- Add missing escapeSeqDecode, urlEncode and trimLeft/Right tfns to parser
[Issue #1752 - @victorhora]
- Fix STATUS var parsing and accept STATUS_LINE var for v2 backward comp.
[Issue #1738 - @victorhora]
- Fix memory leak in modsecurity::utils::expandEnv()
[Issue #1750 - @defanator]
- Initialize m_dtd member in ValidateDTD class as NULL
[Issue #1751 - @airween]
- Fix broken @detectxss operator regression test case
[Issue #1739 - @p0pr0ck5]
- Fix utils::string::ssplit() to handle delimiter in the end of string
[Issue #1743, #1744 - @defanator]
- Fix variable FILES_TMPNAMES
[Issue #1646, #1610 - @victorhora, @zimmerle, @defanator]
- Fix memory leak in Collections
[Issue #1729, #1730 - @defanator]
v3.0.2 - 2018-Apr-03
--------------------
- Fix lib version information while generating the .so file
[@gl1f1v21, @zimmerle]
v3.0.1 - 2018-Apr-02
--------------------
- Adds support for ctl:ruleRemoveByTag
[@zimmerle, @weliu]
- Fix SecUploadDir configuration merge
[Issue #1720 - @zimmerle, @gjvanetten]
- Include all prerequisites for "make check" into dist archive
[Issue #1716 - @defanator]
- Fix: Reverse logic of checking output in @inspectFile
[Issue #1715 - @defanator]
- Adds support to libMaxMind
[Issue #1307 - @zimmerle, @defanator]
- Adds capture action to detectXSS
[Issue #1698 - @victorhora]
- Temporarily accept invalid MULTIPART_SEMICOLON_MISSING operator
[Issue #1701 - @victorhora]
- Adds capture action to detectSQLi
[Issue #1698 - @zimmerle]
- Adds capture action to rbl
[Issue #1698 - @zimmerle]
- Adds capture action to verifyCC
[Issue #1698 - @michaelgranzow-avi, @zimmerle]
- Adds capture action to verifySSN
[Issue #1698 - @zimmerle]
- Adds capture action to verifyCPF
[Issue #1698 - @zimmerle]
- Prettier error messages for unsupported configurations (UX)
[@victorhora]
- Add missing verify*** transformation statements to parser
[Issue #1006 and #1007 - @victorhora]
- Fix a set of compilation warnings
[Issue #1650 - @zimmerle, @JayCase]
- Check for disruptive action on SecDefaultAction.
[Issue #1614 - @zimmerle, @michaelgranzow-avi]
- Fix block-block infinite loop.
[Issue #1614 - @zimmerle, @michaelgranzow-avi]
- Correction remove_by_tag and remove_by_msg logic.
[Issue #1636 - @Minasu]
- Fix LMDB compile error
[Issue #1691 - @airween]
- Fix msc_who_am_i() to return pointer to a valid C string
[Issue #1640 - @defanator]
- Added some cosmetics to autoconf related code
[Issue #1652 - @airween]
- Fix "make dist" target to include necessary headers for Lua
[Issue #1678 - @defanator]
- Fix "include /foo/*.conf" for single matched object in directory
[Issue #1677 - @defanator, @zimmerle]
- Add missing Base64 transformation statements to parser
[Issue #1632 - @victorhora, @zimmerle]
- Fixed resource load on ip match from file
[#1674 - @zimmerle, @StefaanSeys]
- Fixed examples compilation while using disable-shared
[#1670 - @zimmerle, @ivanbaldo]
- Fixed compilation issue while xml is disabled
[0x243028 - @zimmerle]
- Having LDADD and LDFLAGS organized on Makefile.am
[0xd0e85e - @zimmerle]
- Checking std::deque size before use it
[0x217cbf - @zimmerle, Yaron Dayagi]
- perf improvement: Added the concept of RunTimeString and removed
all run time parser.
[0x3eae51 0x0320e0 0xb5688f 0xfe47a9 0xfa9842 0x1affc3 0x079de4
0xc7c04f 0x5262ea 0x01974a 0xd5ee1e - @zimmerle]
- perf improvement: Checks debuglog level before format debug msg
[0x42ee9 - @zimmerle]
- perf. improvement/rx: Only compute dynamic regex in case of macro
[0x91ff3 - @zimmerle]
- Fix uri on the benchmark utility
[0x63bec - @zimmerle]
- disable Lua on systems with liblua5.1
[Issue #1639 - @victorhora, @defanator]
v3.0.0 - 2017-Dec-13
--------------------
- Improvements on LUA build scripts and support for LUA 5.2.
[Issue #1617 and #1622 - @victorhora, @zimmerle]
- Fix compilation error with disable_debug_log flag
[0xfd84e - Izik Abramov]
- Improvements on the benchmark tool.
[Issue #1615 - @zimmerle]
- Fix lua headers on the build scripts
[Issue #1621 - @Minasu]
- Refactoring on the JSON parser.
[Issue #1576, #1577 - Tobias Gutknecht, @zimmerle, @victorhora, @marcstern]
- Adds support to WEBAPPID variable.
[Issue #1027 - @zimmerle, @victorhora]
- Adds support for SecWebAppId.
[Issue #1442 - @zimmerle, @victorhora]
- Adds support for SecRuleRemoveByTag.
[Issue #1476 - @zimmerle, @victorhora]
- Adds support for update target by message.
[Issue #1474 - @zimmerle, @victorhora]
- Adds support to SecRuleScript directive.
[Issue #994 - @zimmerle]
- Adds support for the exec action.
[Issue #1050 - @zimmerle]
- Adds support for transformations inside Lua engine
[Issue #994 - @zimmerle]
- Adds initial support for Lua engine.
[Issue #994 - @zimmerle]
- Adds support for @inspectFile operator.
[Issue #999 - @zimmerle, @victorhora]
- Adds support for RESOURCE variable collection.
[Issue #1014 - @zimmerle, @victorhora]
- Adds support for @fuzzyHash operator.
[Issue #997 - @zimmerle]
- Fix build on non x86 arch build
[Issue #1598 - @athmane]
- Fix memory issue while changing rule target dynamic
[Issue #1590 - @zimmerle, @slabber]
- Fix log while displaying the name of a dict selection by regex.
[@zimmerle]
- Setting http response code on the auditlog.
[Issue #1592 - @zimmerle]
- Refactoring on RuleMessage class, now accepting http code as parameter.
[@zimmerle]
- Having disruptive msgs as disruptive [instead of warnings] on audit log
[Issue #1592 - @zimmerle, @nobodysz]
- Parser: Pipes are no longer welcomed inside regex dict element selection.
[Issue #1591 - @zimmerle, @slabber]
- Avoids unicode initialization on every rules object
[Issue #1563 - @zimmerle, @Tiki-God, @sethinsd, @Cloaked9000, @AnoopAlias,
@intelbg]
- Makes clear to the user whenever the audit log is empty due to missing
JSON support.
[Issue #1585 - @zimmerle]
- Makes auditlog more verbose on debug logs
[Issue: #1559 - @zimmerle]
- Enable support for AuditLogFormat
Issue: #1583, #1493 and #1453 - @victorhora]
- Adds macro expansion for @rx operator
[Issue: #1528, #1536 - @asterite3, @zimmerle]
- Consideres under quoted variable while loading the rules.
[Felipe Zimmerle/@zimmerle, Victor Hora/@victorhora]
- Store the connection and url parameters in std::string
[Issue: #1571 - @majordaw]
- Eliminate some reorder and sign warnings
[Issue: #1572 - Dávid Major/@majordaw]
- Makes parallel logging to work when SELinux is enabled.
[Issue: #1562 - David Buckle/@met3or]
- Adds possibility to run the pm operator inside a mutex to avoid concurrent
access while working on a thread environment. This option is a compilation
flag.
[Felipe Zimmerle/@zimmerle]
v3.0.0-rc1 - 2017-Aug-28
------------------------
Very first public version.

View File

@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@ -0,0 +1,353 @@
if TEST_UTILITIES
export MAYBE_TEST = test
endif
if EXAMPLES
export MAYBE_EXAMPLES = examples
endif
SUBDIRS = \
others \
src \
doc \
tools \
$(MAYBE_EXAMPLES) \
$(MAYBE_TEST)
# make clean
CLEANFILES =
ACLOCAL_AMFLAGS = -I build
# make maintainer-clean
MAINTAINERCLEANFILES = \
aclocal.m4 \
ar-lib \
build/libtool.m4 \
build/lt~obsolete.m4 \
build/ltoptions.m4 \
build/ltsugar.m4 \
build/ltversion.m4 \
coding-style.txt \
compile \
config.guess \
config.sub \
configure \
cppcheck.txt \
depcomp \
install-sh \
ltmain.sh \
Makefile.in \
missing \
test/modsec-shared-collections \
test/modsec-shared-collections-lock \
test-suite-drd.log \
test-suite-helgrind.log \
test-suite-memcheck.log \
ylwrap
parser:
cat src/parser/seclang-parser.hh | sed "s/return \*new (yyas_<T> ()) T (t)/return *new (yyas_<T> ()) T (std::move((T\&)t))/g" > src/parser/seclang-parser.hh.fix && mv src/parser/seclang-parser.hh.fix src/parser/seclang-parser.hh
cppcheck:
@cppcheck -U YYSTYPE -U MBEDTLS_MD5_ALT -U MBEDTLS_SHA1_ALT \
-D MS_CPPCHECK_DISABLED_FOR_PARSER -U YY_USER_INIT \
--suppressions-list=./test/cppcheck_suppressions.txt \
--enable=warning,style,performance,portability,unusedFunction,missingInclude \
--inconclusive \
--template="warning: {file},{line},{severity},{id},{message}" \
-I headers -I . -I others -I src -I others/mbedtls -I src/parser \
--error-exitcode=1 \
-i "src/parser/seclang-parser.cc" -i "src/parser/seclang-scanner.cc" \
--force --verbose .
check-static: cppcheck
check-style: check-coding-style
check-coding-style:
@cpplint.py \
$$(find . -name "*.h" -o -name "*.cc" | xargs) 2>&1 \
| egrep -v $$(echo -n "catchall" ; \
for i in $$(cat test/coding_style_suppressions.txt); do echo -n "|"$$i; done) \
| sed 's/^\./warning: ./g' > coding-style.txt
-cat coding-style.txt
@VALGRIND_CHECK_RULES@
VALGRIND_SUPPRESSIONS_FILES = valgrind_suppressions.txt
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-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
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = modsecurity.pc
EXTRA_DIST = modsecurity.pc.in \
modsecurity.conf-recommended \
unicode.mapping

View File

@ -0,0 +1,276 @@
<img src="https://github.com/SpiderLabs/ModSecurity/raw/v3/master/others/modsec.png" width="50%">
![Quality Assurance](https://github.com/SpiderLabs/ModSecurity/workflows/Quality%20Assurance/badge.svg)
[![Build Status](https://sonarcloud.io/api/project_badges/measure?project=USHvY32Uy62L&metric=alert_status)](https://sonarcloud.io/dashboard?id=USHvY32Uy62L)
[![](https://sonarcloud.io/api/project_badges/measure?project=USHvY32Uy62L&metric=sqale_rating
)](https://sonarcloud.io/dashboard?id=USHvY32Uy62L)
[![](https://sonarcloud.io/api/project_badges/measure?project=USHvY32Uy62L&metric=reliability_rating
)](https://sonarcloud.io/dashboard?id=USHvY32Uy62L)
[![](https://sonarcloud.io/api/project_badges/measure?project=USHvY32Uy62L&metric=security_rating
)](https://sonarcloud.io/dashboard?id=USHvY32Uy62L)
[![](https://sonarcloud.io/api/project_badges/measure?project=USHvY32Uy62L&metric=vulnerabilities
)](https://sonarcloud.io/dashboard?id=USHvY32Uy62L)
Libmodsecurity is one component of the ModSecurity v3 project. The library
codebase serves as an interface to ModSecurity Connectors taking in web traffic
and applying traditional ModSecurity processing. In general, it provides the
capability to load/interpret rules written in the ModSecurity SecRules format
and apply them to HTTP content provided by your application via Connectors.
If you are looking for ModSecurity for Apache (aka ModSecurity v2.x), it is still under maintenance and available:
[here](https://github.com/SpiderLabs/ModSecurity/tree/v2/master).
### What is the difference between this project and the old ModSecurity (v2.x.x)?
* All Apache dependencies have been removed
* Higher performance
* New features
* New architecture
Libmodsecurity is a complete rewrite of the ModSecurity platform. When it was first devised the ModSecurity project started as just an Apache module. Over time the project has been extended, due to popular demand, to support other platforms including (but not limited to) Nginx and IIS. In order to provide for the growing demand for additional platform support, it has became necessary to remove the Apache dependencies underlying this project, making it more platform independent.
As a result of this goal we have rearchitected Libmodsecurity such that it is no longer dependent on the Apache web server (both at compilation and during runtime). One side effect of this is that across all platforms users can expect increased performance. Additionally, we have taken this opportunity to lay the groundwork for some new features that users have been long seeking. For example we are looking to natively support auditlogs in the JSON format, along with a host of other functionality in future versions.
### It is no longer just a module.
The 'ModSecurity' branch no longer contains the traditional module logic (for Nginx, Apache, and IIS) that has traditionally been packaged all together. Instead, this branch only contains the library portion (libmodsecurity) for this project. This library is consumed by what we have termed 'Connectors' these connectors will interface with your webserver and provide the library with a common format that it understands. Each of these connectors is maintained as a separate GitHub project. For instance, the Nginx connector is supplied by the ModSecurity-nginx project (https://github.com/SpiderLabs/ModSecurity-nginx).
Keeping these connectors separated allows each project to have different release cycles, issues and development trees. Additionally, it means that when you install ModSecurity v3 you only get exactly what you need, no extras you won't be using.
# Compilation
Before starting the compilation process, make sure that you have all the
dependencies in place. Read the subsection “Dependencies” for further
information.
After the compilation make sure that there are no issues on your
build/platform. We strongly recommend the utilization of the unit tests and
regression tests. These test utilities are located under the subfolder tests.
As a dynamic library, dont forget that libmodsecurity must be installed to a location (folder) where you OS will be looking for dynamic libraries.
### Unix (Linux, MacOS, FreeBSD, …)
On unix the project uses autotools to help the compilation process.
```shell
$ ./build.sh
$ ./configure
$ make
$ sudo make install
```
Details on distribution specific builds can be found in our Wiki:
[Compilation Recipes](https://github.com/SpiderLabs/ModSecurity/wiki/Compilation-recipes)
### Windows
Windows build is not ready yet.
## Dependencies
This library is written in C++ using the C++11 standards. It also uses Flex
and Yacc to produce the “Sec Rules Language” parser. Other, mandatory dependencies include YAJL, as ModSecurity uses JSON for producing logs and its testing framework, libpcre (not yet mandatory) for processing regular expressions in SecRules, and libXML2 (not yet mandatory) which is used for parsing XML requests.
All others dependencies are related to operators specified within SecRules or configuration directives and may not be required for compilation. A short list of such dependencies is as follows:
* libinjection is needed for the operator @detectXSS and @detectSQL
* curl is needed for the directive SecRemoteRules.
If those libraries are missing ModSecurity will be compiled without the support for the operator @detectXSS and the configuration directive SecRemoteRules.
# Library documentation
The library documentation is written within the code in Doxygen format. To generate this documentation, please use the doxygen utility with the provided configuration file, “doxygen.cfg”, located with the "doc/" subfolder. This will generate HTML formatted documentation including usage examples.
# Library utilization
The library provides a C++ and C interface. Some resources are currently only
available via the C++ interface, for instance, the capability to create custom logging
mechanism (see the regression test to check for how those logging mechanism works).
The objective is to have both APIs (C, C++) providing the same functionality,
if you find an aspect of the API that is missing via a particular interface, please open an issue.
Inside the subfolder examples, there are simple examples on how to use the API.
Below some are illustrated:
### Simple example using C++
```c++
using ModSecurity::ModSecurity;
using ModSecurity::Rules;
using ModSecurity::Transaction;
ModSecurity *modsec;
ModSecurity::Rules *rules;
modsec = new ModSecurity();
rules = new Rules();
rules->loadFromUri(rules_file);
Transaction *modsecTransaction = new Transaction(modsec, rules);
modsecTransaction->processConnection("127.0.0.1");
if (modsecTransaction->intervention()) {
std::cout << "There is an intervention" << std::endl;
}
```
### Simple example using C
```c
#include "modsecurity/modsecurity.h"
#include "modsecurity/transaction.h"
char main_rule_uri[] = "basic_rules.conf";
int main (int argc, char **argv)
{
ModSecurity *modsec = NULL;
Transaction *transaction = NULL;
Rules *rules = NULL;
modsec = msc_init();
rules = msc_create_rules_set();
msc_rules_add_file(rules, main_rule_uri);
transaction = msc_new_transaction(modsec, rules);
msc_process_connection(transaction, "127.0.0.1");
msc_process_uri(transaction, "http://www.modsecurity.org/test?key1=value1&key2=value2&key3=value3&test=args&test=test");
msc_process_request_headers(transaction);
msc_process_request_body(transaction);
msc_process_response_headers(transaction);
msc_process_response_body(transaction);
return 0;
}
```
# Contributing
You are more than welcome to contribute to this project and look forward to growing the community around this new version of ModSecurity. Areas of interest include: New
functionalities, fixes, bug report, support for beginning users, or anything that you
are willing to help with.
## Providing patches
We prefer to have your patch within the GitHub infrastructure to facilitate our
review work, and our Q.A. integration. GitHub provides excellent
documentation on how to perform “Pull Requests”, more information available
here: https://help.github.com/articles/using-pull-requests/
Please respect the coding style. Pull requests can include various commits, so
provide one fix or one piece of functionality per commit. Please do not change anything outside
the scope of your target work (e.g. coding style in a function that you have
passed by). For further information about the coding style used in this
project, please check: https://www.chromium.org/blink/coding-style
Provides explanative commit messages. Your first line should give the highlights of your
patch, 3rd and on give a more detailed explanation/technical details about your
patch. Patch explanation is valuable during the review process.
### Dont know where to start?
Within our code there are various items marked as TODO or FIXME that may need
your attention. Check the list of items by performing a grep:
```
$ cd /path/to/modsecurity-nginx
$ egrep -Rin "TODO|FIXME" -R *
```
A TODO list is also available as part of the Doxygen documentation.
### Testing your patch
Along with the manual testing, we strongly recommend you to use the our
regression tests and unit tests. If you have implemented an operator, dont
forget to create unit tests for it. If you implement anything else, it is encouraged that you develop complimentary regression tests for it.
The regression test and unit test utilities are native and do not demand any
external tool or script, although you need to fetch the test cases from other
repositories, as they are shared with other versions of ModSecurity, those
others repositories git submodules. To fetch the submodules repository and run
the utilities, follow the commands listed below:
```shell
$ cd /path/to/your/ModSecurity
$ git submodule foreach git pull
$ cd test
$ ./regression-tests
$ ./unit-tests
```
### Debugging
Before start the debugging process, make sure of where your bug is. The problem
could be on your connector or in libmodsecurity. In order to identify where the
bug is, it is recommended that you develop a regression test that mimics the
scenario where the bug is happening. If the bug is reproducible with the
regression-test utility, then it will be far simpler to debug and ensure that it never occurs again. On Linux it is
recommended that anyone undertaking debugging utilize gdb and/or valgrind as needed.
During the configuration/compilation time, you may want to disable the compiler
optimization making your “back traces” populated with readable data. Use the
CFLAGS to disable the compilation optimization parameters:
```shell
$ export CFLAGS="-g -O0"
$ ./build.sh
$ ./configure
$ make
$ sudo make install
```
## Reporting Issues
If you are facing a configuration issue or something is not working as you
expected to be, please use the ModSecurity users mailing list. Issues on GitHub
are also welcomed, but we prefer to have user ask questions on the mailing list first so that you can reach an entire community. Also dont forget to look for existing issues before open a new one.
If you are going to open a new issue on GitHub, dont forget to tell us the
version of your libmodsecurity and the version of a specific connector if there
is one.
### Security issue
Please do not make public any security issue. Contact us at:
security@modsecurity.org reporting the issue. Once the problem is fixed your
credit will be given.
## Feature request
We are open to discussing any new feature request with the community via the mailing lists. You can alternativly,
feel free to open GitHub issues requesting new features. Before opening a
new issue, please check if there is one already opened on the same topic.
## Bindings
The libModSecurity design allows the integration with bindings. There is an effort to avoid breaking API [binary] compatibility to make an easy integration with possible bindings. Currently, there are two notable projects maintained by the community:
* Python - https://github.com/actions-security/pymodsecurity
* Varnish - https://github.com/xdecock/vmod-modsecurity
## Packaging
Having our packages in distros on time is a desire that we have, so let us know
if there is anything we can do to facilitate your work as a packager.
## Sponsor Note
Development of ModSecurity is sponsored by Trustwave. Sponsorship will end July 1, 2024. Additional information can be found here https://www.trustwave.com/en-us/resources/security-resources/software-updates/end-of-sale-and-trustwave-support-for-modsecurity-web-application-firewall/

View File

@ -0,0 +1,9 @@
# Security Policy
## Supported Versions
The latest versions of both v2.9.x and v3.0.x are supported.
## Reporting a Vulnerability
For information on how to report a security issue, please see https://github.com/SpiderLabs/ModSecurity#security-issue

View File

@ -0,0 +1,13 @@
#!/bin/sh
rm -rf autom4te.cache
rm -f aclocal.m4
case `uname` in Darwin*) glibtoolize --force --copy ;;
*) libtoolize --force --copy ;; esac
autoreconf --install
autoheader
automake --add-missing --foreign --copy --force-missing
autoconf --force
rm -rf autom4te.cache

View File

View File

@ -0,0 +1,171 @@
# ============================================================================
# http://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx_11.html
# ============================================================================
#
# SYNOPSIS
#
# AX_CXX_COMPILE_STDCXX_11([ext|noext],[mandatory|optional])
#
# DESCRIPTION
#
# Check for baseline language coverage in the compiler for the C++11
# standard; if necessary, add switches to CXXFLAGS to enable support.
#
# The first argument, if specified, indicates whether you insist on an
# extended mode (e.g. -std=gnu++11) or a strict conformance mode (e.g.
# -std=c++11). If neither is specified, you get whatever works, with
# preference for an extended mode.
#
# The second argument, if specified 'mandatory' or if left unspecified,
# indicates that baseline C++11 support is required and that the macro
# should error out if no mode with that support is found. If specified
# 'optional', then configuration proceeds regardless, after defining
# HAVE_CXX11 if and only if a supporting mode is found.
#
# LICENSE
#
# Copyright (c) 2008 Benjamin Kosnik <bkoz@redhat.com>
# Copyright (c) 2012 Zack Weinberg <zackw@panix.com>
# Copyright (c) 2013 Roy Stogner <roystgnr@ices.utexas.edu>
# Copyright (c) 2014, 2015 Google Inc.; contributed by Alexey Sokolov <sokolov@google.com>
# Copyright (c) 2015 Paul Norman <penorman@mac.com>
#
# Copying and distribution of this file, with or without modification, are
# permitted in any medium without royalty provided the copyright notice
# and this notice are preserved. This file is offered as-is, without any
# warranty.
#serial 12
m4_define([_AX_CXX_COMPILE_STDCXX_11_testbody], [[
template <typename T>
struct check
{
static_assert(sizeof(int) <= sizeof(T), "not big enough");
};
struct Base {
virtual void f() {}
};
struct Child : public Base {
virtual void f() override {}
};
typedef check<check<bool>> right_angle_brackets;
int a;
decltype(a) b;
typedef check<int> check_type;
check_type c;
check_type&& cr = static_cast<check_type&&>(c);
auto d = a;
auto l = [](){};
// Prevent Clang error: unused variable 'l' [-Werror,-Wunused-variable]
struct use_l { use_l() { l(); } };
// http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae
// Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function because of this
namespace test_template_alias_sfinae {
struct foo {};
template<typename T>
using member = typename T::member_type;
template<typename T>
void func(...) {}
template<typename T>
void func(member<T>*) {}
void test();
void test() {
func<foo>(0);
}
}
// Check for C++11 attribute support
void noret [[noreturn]] () { throw 0; }
]])
AC_DEFUN([AX_CXX_COMPILE_STDCXX_11], [dnl
m4_if([$1], [], [],
[$1], [ext], [],
[$1], [noext], [],
[m4_fatal([invalid argument `$1' to AX_CXX_COMPILE_STDCXX_11])])dnl
m4_if([$2], [], [ax_cxx_compile_cxx11_required=true],
[$2], [mandatory], [ax_cxx_compile_cxx11_required=true],
[$2], [optional], [ax_cxx_compile_cxx11_required=false],
[m4_fatal([invalid second argument `$2' to AX_CXX_COMPILE_STDCXX_11])])
AC_LANG_PUSH([C++])dnl
ac_success=no
AC_CACHE_CHECK(whether $CXX supports C++11 features by default,
ax_cv_cxx_compile_cxx11,
[AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_11_testbody])],
[ax_cv_cxx_compile_cxx11=yes],
[ax_cv_cxx_compile_cxx11=no])])
if test x$ax_cv_cxx_compile_cxx11 = xyes; then
ac_success=yes
fi
m4_if([$1], [noext], [], [dnl
if test x$ac_success = xno; then
for switch in -std=gnu++11 -std=gnu++0x; do
cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx11_$switch])
AC_CACHE_CHECK(whether $CXX supports C++11 features with $switch,
$cachevar,
[ac_save_CXXFLAGS="$CXXFLAGS"
CXXFLAGS="$CXXFLAGS $switch"
AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_11_testbody])],
[eval $cachevar=yes],
[eval $cachevar=no])
CXXFLAGS="$ac_save_CXXFLAGS"])
if eval test x\$$cachevar = xyes; then
CXXFLAGS="$CXXFLAGS $switch"
ac_success=yes
break
fi
done
fi])
m4_if([$1], [ext], [], [dnl
if test x$ac_success = xno; then
dnl HP's aCC needs +std=c++11 according to:
dnl http://h21007.www2.hp.com/portal/download/files/unprot/aCxx/PDF_Release_Notes/769149-001.pdf
for switch in -std=c++11 -std=c++0x +std=c++11; do
cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx11_$switch])
AC_CACHE_CHECK(whether $CXX supports C++11 features with $switch,
$cachevar,
[ac_save_CXXFLAGS="$CXXFLAGS"
CXXFLAGS="$CXXFLAGS $switch"
AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_11_testbody])],
[eval $cachevar=yes],
[eval $cachevar=no])
CXXFLAGS="$ac_save_CXXFLAGS"])
if eval test x\$$cachevar = xyes; then
CXXFLAGS="$CXXFLAGS $switch"
ac_success=yes
break
fi
done
fi])
AC_LANG_POP([C++])
if test x$ax_cxx_compile_cxx11_required = xtrue; then
if test x$ac_success = xno; then
AC_MSG_ERROR([*** A compiler with support for C++11 language features is required.])
fi
else
if test x$ac_success = xno; then
HAVE_CXX11=0
AC_MSG_NOTICE([No compiler with C++11 support was found])
else
HAVE_CXX11=1
AC_DEFINE(HAVE_CXX11,1,
[define if the compiler supports basic C++11 syntax])
fi
AC_SUBST(HAVE_CXX11)
fi
])

View File

@ -0,0 +1,533 @@
# ===========================================================================
# http://www.gnu.org/software/autoconf-archive/ax_prog_doxygen.html
# ===========================================================================
#
# SYNOPSIS
#
# DX_INIT_DOXYGEN(PROJECT-NAME, DOXYFILE-PATH, [OUTPUT-DIR])
# DX_DOXYGEN_FEATURE(ON|OFF)
# DX_DOT_FEATURE(ON|OFF)
# DX_HTML_FEATURE(ON|OFF)
# DX_CHM_FEATURE(ON|OFF)
# DX_CHI_FEATURE(ON|OFF)
# DX_MAN_FEATURE(ON|OFF)
# DX_RTF_FEATURE(ON|OFF)
# DX_XML_FEATURE(ON|OFF)
# DX_PDF_FEATURE(ON|OFF)
# DX_PS_FEATURE(ON|OFF)
#
# DESCRIPTION
#
# The DX_*_FEATURE macros control the default setting for the given
# Doxygen feature. Supported features are 'DOXYGEN' itself, 'DOT' for
# generating graphics, 'HTML' for plain HTML, 'CHM' for compressed HTML
# help (for MS users), 'CHI' for generating a seperate .chi file by the
# .chm file, and 'MAN', 'RTF', 'XML', 'PDF' and 'PS' for the appropriate
# output formats. The environment variable DOXYGEN_PAPER_SIZE may be
# specified to override the default 'a4wide' paper size.
#
# By default, HTML, PDF and PS documentation is generated as this seems to
# be the most popular and portable combination. MAN pages created by
# Doxygen are usually problematic, though by picking an appropriate subset
# and doing some massaging they might be better than nothing. CHM and RTF
# are specific for MS (note that you can't generate both HTML and CHM at
# the same time). The XML is rather useless unless you apply specialized
# post-processing to it.
#
# The macros mainly control the default state of the feature. The use can
# override the default by specifying --enable or --disable. The macros
# ensure that contradictory flags are not given (e.g.,
# --enable-doxygen-html and --enable-doxygen-chm,
# --enable-doxygen-anything with --disable-doxygen, etc.) Finally, each
# feature will be automatically disabled (with a warning) if the required
# programs are missing.
#
# Once all the feature defaults have been specified, call DX_INIT_DOXYGEN
# with the following parameters: a one-word name for the project for use
# as a filename base etc., an optional configuration file name (the
# default is 'Doxyfile', the same as Doxygen's default), and an optional
# output directory name (the default is 'doxygen-doc').
#
# Automake Support
#
# The following is a template aminclude.am file for use with Automake.
# Make targets and variables values are controlled by the various
# DX_COND_* conditionals set by autoconf.
#
# The provided targets are:
#
# doxygen-doc: Generate all doxygen documentation.
#
# doxygen-run: Run doxygen, which will generate some of the
# documentation (HTML, CHM, CHI, MAN, RTF, XML)
# but will not do the post processing required
# for the rest of it (PS, PDF, and some MAN).
#
# doxygen-man: Rename some doxygen generated man pages.
#
# doxygen-ps: Generate doxygen PostScript documentation.
#
# doxygen-pdf: Generate doxygen PDF documentation.
#
# Note that by default these are not integrated into the automake targets.
# If doxygen is used to generate man pages, you can achieve this
# integration by setting man3_MANS to the list of man pages generated and
# then adding the dependency:
#
# $(man3_MANS): doxygen-doc
#
# This will cause make to run doxygen and generate all the documentation.
#
# The following variable is intended for use in Makefile.am:
#
# DX_CLEANFILES = everything to clean.
#
# Then add this variable to MOSTLYCLEANFILES.
#
# ----- begin aminclude.am -------------------------------------
#
# ## --------------------------------- ##
# ## Format-independent Doxygen rules. ##
# ## --------------------------------- ##
#
# if DX_COND_doc
#
# ## ------------------------------- ##
# ## Rules specific for HTML output. ##
# ## ------------------------------- ##
#
# if DX_COND_html
#
# DX_CLEAN_HTML = @DX_DOCDIR@/html
#
# endif DX_COND_html
#
# ## ------------------------------ ##
# ## Rules specific for CHM output. ##
# ## ------------------------------ ##
#
# if DX_COND_chm
#
# DX_CLEAN_CHM = @DX_DOCDIR@/chm
#
# if DX_COND_chi
#
# DX_CLEAN_CHI = @DX_DOCDIR@/@PACKAGE@.chi
#
# endif DX_COND_chi
#
# endif DX_COND_chm
#
# ## ------------------------------ ##
# ## Rules specific for MAN output. ##
# ## ------------------------------ ##
#
# if DX_COND_man
#
# DX_CLEAN_MAN = @DX_DOCDIR@/man
#
# endif DX_COND_man
#
# ## ------------------------------ ##
# ## Rules specific for RTF output. ##
# ## ------------------------------ ##
#
# if DX_COND_rtf
#
# DX_CLEAN_RTF = @DX_DOCDIR@/rtf
#
# endif DX_COND_rtf
#
# ## ------------------------------ ##
# ## Rules specific for XML output. ##
# ## ------------------------------ ##
#
# if DX_COND_xml
#
# DX_CLEAN_XML = @DX_DOCDIR@/xml
#
# endif DX_COND_xml
#
# ## ----------------------------- ##
# ## Rules specific for PS output. ##
# ## ----------------------------- ##
#
# if DX_COND_ps
#
# DX_CLEAN_PS = @DX_DOCDIR@/@PACKAGE@.ps
#
# DX_PS_GOAL = doxygen-ps
#
# doxygen-ps: @DX_DOCDIR@/@PACKAGE@.ps
#
# @DX_DOCDIR@/@PACKAGE@.ps: @DX_DOCDIR@/@PACKAGE@.tag
# cd @DX_DOCDIR@/latex; \
# rm -f *.aux *.toc *.idx *.ind *.ilg *.log *.out; \
# $(DX_LATEX) refman.tex; \
# $(MAKEINDEX_PATH) refman.idx; \
# $(DX_LATEX) refman.tex; \
# countdown=5; \
# while $(DX_EGREP) 'Rerun (LaTeX|to get cross-references right)' \
# refman.log > /dev/null 2>&1 \
# && test $$countdown -gt 0; do \
# $(DX_LATEX) refman.tex; \
# countdown=`expr $$countdown - 1`; \
# done; \
# $(DX_DVIPS) -o ../@PACKAGE@.ps refman.dvi
#
# endif DX_COND_ps
#
# ## ------------------------------ ##
# ## Rules specific for PDF output. ##
# ## ------------------------------ ##
#
# if DX_COND_pdf
#
# DX_CLEAN_PDF = @DX_DOCDIR@/@PACKAGE@.pdf
#
# DX_PDF_GOAL = doxygen-pdf
#
# doxygen-pdf: @DX_DOCDIR@/@PACKAGE@.pdf
#
# @DX_DOCDIR@/@PACKAGE@.pdf: @DX_DOCDIR@/@PACKAGE@.tag
# cd @DX_DOCDIR@/latex; \
# rm -f *.aux *.toc *.idx *.ind *.ilg *.log *.out; \
# $(DX_PDFLATEX) refman.tex; \
# $(DX_MAKEINDEX) refman.idx; \
# $(DX_PDFLATEX) refman.tex; \
# countdown=5; \
# while $(DX_EGREP) 'Rerun (LaTeX|to get cross-references right)' \
# refman.log > /dev/null 2>&1 \
# && test $$countdown -gt 0; do \
# $(DX_PDFLATEX) refman.tex; \
# countdown=`expr $$countdown - 1`; \
# done; \
# mv refman.pdf ../@PACKAGE@.pdf
#
# endif DX_COND_pdf
#
# ## ------------------------------------------------- ##
# ## Rules specific for LaTeX (shared for PS and PDF). ##
# ## ------------------------------------------------- ##
#
# if DX_COND_latex
#
# DX_CLEAN_LATEX = @DX_DOCDIR@/latex
#
# endif DX_COND_latex
#
# .PHONY: doxygen-run doxygen-doc $(DX_PS_GOAL) $(DX_PDF_GOAL)
#
# .INTERMEDIATE: doxygen-run $(DX_PS_GOAL) $(DX_PDF_GOAL)
#
# doxygen-run: @DX_DOCDIR@/@PACKAGE@.tag
#
# doxygen-doc: doxygen-run $(DX_PS_GOAL) $(DX_PDF_GOAL)
#
# @DX_DOCDIR@/@PACKAGE@.tag: $(DX_CONFIG) $(pkginclude_HEADERS)
# rm -rf @DX_DOCDIR@
# $(DX_ENV) $(DX_DOXYGEN) $(srcdir)/$(DX_CONFIG)
# echo Timestamp >$@
#
# DX_CLEANFILES = \
# @DX_DOCDIR@/@PACKAGE@.tag \
# -r \
# $(DX_CLEAN_HTML) \
# $(DX_CLEAN_CHM) \
# $(DX_CLEAN_CHI) \
# $(DX_CLEAN_MAN) \
# $(DX_CLEAN_RTF) \
# $(DX_CLEAN_XML) \
# $(DX_CLEAN_PS) \
# $(DX_CLEAN_PDF) \
# $(DX_CLEAN_LATEX)
#
# endif DX_COND_doc
#
# ----- end aminclude.am ---------------------------------------
#
# LICENSE
#
# Copyright (c) 2009 Oren Ben-Kiki <oren@ben-kiki.org>
#
# Copying and distribution of this file, with or without modification, are
# permitted in any medium without royalty provided the copyright notice
# and this notice are preserved. This file is offered as-is, without any
# warranty.
#serial 13
## ----------##
## Defaults. ##
## ----------##
DX_ENV=""
AC_DEFUN([DX_FEATURE_doc], ON)
AC_DEFUN([DX_FEATURE_dot], OFF)
AC_DEFUN([DX_FEATURE_man], OFF)
AC_DEFUN([DX_FEATURE_html], ON)
AC_DEFUN([DX_FEATURE_chm], OFF)
AC_DEFUN([DX_FEATURE_chi], OFF)
AC_DEFUN([DX_FEATURE_rtf], OFF)
AC_DEFUN([DX_FEATURE_xml], OFF)
AC_DEFUN([DX_FEATURE_pdf], ON)
AC_DEFUN([DX_FEATURE_ps], ON)
## --------------- ##
## Private macros. ##
## --------------- ##
# DX_ENV_APPEND(VARIABLE, VALUE)
# ------------------------------
# Append VARIABLE="VALUE" to DX_ENV for invoking doxygen.
AC_DEFUN([DX_ENV_APPEND], [AC_SUBST([DX_ENV], ["$DX_ENV $1='$2'"])])
# DX_DIRNAME_EXPR
# ---------------
# Expand into a shell expression prints the directory part of a path.
AC_DEFUN([DX_DIRNAME_EXPR],
[[expr ".$1" : '\(\.\)[^/]*$' \| "x$1" : 'x\(.*\)/[^/]*$']])
# DX_IF_FEATURE(FEATURE, IF-ON, IF-OFF)
# -------------------------------------
# Expands according to the M4 (static) status of the feature.
AC_DEFUN([DX_IF_FEATURE], [ifelse(DX_FEATURE_$1, ON, [$2], [$3])])
# DX_REQUIRE_PROG(VARIABLE, PROGRAM)
# ----------------------------------
# Require the specified program to be found for the DX_CURRENT_FEATURE to work.
AC_DEFUN([DX_REQUIRE_PROG], [
AC_PATH_TOOL([$1], [$2])
if test "$DX_FLAG_[]DX_CURRENT_FEATURE$$1" = 1; then
AC_MSG_WARN([$2 not found - will not DX_CURRENT_DESCRIPTION])
AC_SUBST(DX_FLAG_[]DX_CURRENT_FEATURE, 0)
fi
])
# DX_TEST_FEATURE(FEATURE)
# ------------------------
# Expand to a shell expression testing whether the feature is active.
AC_DEFUN([DX_TEST_FEATURE], [test "$DX_FLAG_$1" = 1])
# DX_CHECK_DEPEND(REQUIRED_FEATURE, REQUIRED_STATE)
# -------------------------------------------------
# Verify that a required features has the right state before trying to turn on
# the DX_CURRENT_FEATURE.
AC_DEFUN([DX_CHECK_DEPEND], [
test "$DX_FLAG_$1" = "$2" \
|| AC_MSG_ERROR([doxygen-DX_CURRENT_FEATURE ifelse([$2], 1,
requires, contradicts) doxygen-DX_CURRENT_FEATURE])
])
# DX_CLEAR_DEPEND(FEATURE, REQUIRED_FEATURE, REQUIRED_STATE)
# ----------------------------------------------------------
# Turn off the DX_CURRENT_FEATURE if the required feature is off.
AC_DEFUN([DX_CLEAR_DEPEND], [
test "$DX_FLAG_$1" = "$2" || AC_SUBST(DX_FLAG_[]DX_CURRENT_FEATURE, 0)
])
# DX_FEATURE_ARG(FEATURE, DESCRIPTION,
# CHECK_DEPEND, CLEAR_DEPEND,
# REQUIRE, DO-IF-ON, DO-IF-OFF)
# --------------------------------------------
# Parse the command-line option controlling a feature. CHECK_DEPEND is called
# if the user explicitly turns the feature on (and invokes DX_CHECK_DEPEND),
# otherwise CLEAR_DEPEND is called to turn off the default state if a required
# feature is disabled (using DX_CLEAR_DEPEND). REQUIRE performs additional
# requirement tests (DX_REQUIRE_PROG). Finally, an automake flag is set and
# DO-IF-ON or DO-IF-OFF are called according to the final state of the feature.
AC_DEFUN([DX_ARG_ABLE], [
AC_DEFUN([DX_CURRENT_FEATURE], [$1])
AC_DEFUN([DX_CURRENT_DESCRIPTION], [$2])
AC_ARG_ENABLE(doxygen-$1,
[AS_HELP_STRING(DX_IF_FEATURE([$1], [--disable-doxygen-$1],
[--enable-doxygen-$1]),
DX_IF_FEATURE([$1], [don't $2], [$2]))],
[
case "$enableval" in
#(
y|Y|yes|Yes|YES)
AC_SUBST([DX_FLAG_$1], 1)
$3
;; #(
n|N|no|No|NO)
AC_SUBST([DX_FLAG_$1], 0)
;; #(
*)
AC_MSG_ERROR([invalid value '$enableval' given to doxygen-$1])
;;
esac
], [
AC_SUBST([DX_FLAG_$1], [DX_IF_FEATURE([$1], 1, 0)])
$4
])
if DX_TEST_FEATURE([$1]); then
$5
:
fi
AM_CONDITIONAL(DX_COND_$1, DX_TEST_FEATURE([$1]))
if DX_TEST_FEATURE([$1]); then
$6
:
else
$7
:
fi
])
## -------------- ##
## Public macros. ##
## -------------- ##
# DX_XXX_FEATURE(DEFAULT_STATE)
# -----------------------------
AC_DEFUN([DX_DOXYGEN_FEATURE], [AC_DEFUN([DX_FEATURE_doc], [$1])])
AC_DEFUN([DX_DOT_FEATURE], [AC_DEFUN([DX_FEATURE_dot], [$1])])
AC_DEFUN([DX_MAN_FEATURE], [AC_DEFUN([DX_FEATURE_man], [$1])])
AC_DEFUN([DX_HTML_FEATURE], [AC_DEFUN([DX_FEATURE_html], [$1])])
AC_DEFUN([DX_CHM_FEATURE], [AC_DEFUN([DX_FEATURE_chm], [$1])])
AC_DEFUN([DX_CHI_FEATURE], [AC_DEFUN([DX_FEATURE_chi], [$1])])
AC_DEFUN([DX_RTF_FEATURE], [AC_DEFUN([DX_FEATURE_rtf], [$1])])
AC_DEFUN([DX_XML_FEATURE], [AC_DEFUN([DX_FEATURE_xml], [$1])])
AC_DEFUN([DX_XML_FEATURE], [AC_DEFUN([DX_FEATURE_xml], [$1])])
AC_DEFUN([DX_PDF_FEATURE], [AC_DEFUN([DX_FEATURE_pdf], [$1])])
AC_DEFUN([DX_PS_FEATURE], [AC_DEFUN([DX_FEATURE_ps], [$1])])
# DX_INIT_DOXYGEN(PROJECT, [CONFIG-FILE], [OUTPUT-DOC-DIR])
# ---------------------------------------------------------
# PROJECT also serves as the base name for the documentation files.
# The default CONFIG-FILE is "Doxyfile" and OUTPUT-DOC-DIR is "doxygen-doc".
AC_DEFUN([DX_INIT_DOXYGEN], [
# Files:
AC_SUBST([DX_PROJECT], [$1])
AC_SUBST([DX_CONFIG], [ifelse([$2], [], Doxyfile, [$2])])
AC_SUBST([DX_DOCDIR], [ifelse([$3], [], doxygen-doc, [$3])])
# Environment variables used inside doxygen.cfg:
DX_ENV_APPEND(SRCDIR, $srcdir)
DX_ENV_APPEND(PROJECT, $DX_PROJECT)
DX_ENV_APPEND(DOCDIR, $DX_DOCDIR)
DX_ENV_APPEND(VERSION, $PACKAGE_VERSION)
# Doxygen itself:
DX_ARG_ABLE(doc, [generate any doxygen documentation],
[],
[],
[DX_REQUIRE_PROG([DX_DOXYGEN], doxygen)
DX_REQUIRE_PROG([DX_PERL], perl)],
[DX_ENV_APPEND(PERL_PATH, $DX_PERL)])
# Dot for graphics:
DX_ARG_ABLE(dot, [generate graphics for doxygen documentation],
[DX_CHECK_DEPEND(doc, 1)],
[DX_CLEAR_DEPEND(doc, 1)],
[DX_REQUIRE_PROG([DX_DOT], dot)],
[DX_ENV_APPEND(HAVE_DOT, YES)
DX_ENV_APPEND(DOT_PATH, [`DX_DIRNAME_EXPR($DX_DOT)`])],
[DX_ENV_APPEND(HAVE_DOT, NO)])
# Man pages generation:
DX_ARG_ABLE(man, [generate doxygen manual pages],
[DX_CHECK_DEPEND(doc, 1)],
[DX_CLEAR_DEPEND(doc, 1)],
[],
[DX_ENV_APPEND(GENERATE_MAN, YES)],
[DX_ENV_APPEND(GENERATE_MAN, NO)])
# RTF file generation:
DX_ARG_ABLE(rtf, [generate doxygen RTF documentation],
[DX_CHECK_DEPEND(doc, 1)],
[DX_CLEAR_DEPEND(doc, 1)],
[],
[DX_ENV_APPEND(GENERATE_RTF, YES)],
[DX_ENV_APPEND(GENERATE_RTF, NO)])
# XML file generation:
DX_ARG_ABLE(xml, [generate doxygen XML documentation],
[DX_CHECK_DEPEND(doc, 1)],
[DX_CLEAR_DEPEND(doc, 1)],
[],
[DX_ENV_APPEND(GENERATE_XML, YES)],
[DX_ENV_APPEND(GENERATE_XML, NO)])
# (Compressed) HTML help generation:
DX_ARG_ABLE(chm, [generate doxygen compressed HTML help documentation],
[DX_CHECK_DEPEND(doc, 1)],
[DX_CLEAR_DEPEND(doc, 1)],
[DX_REQUIRE_PROG([DX_HHC], hhc)],
[DX_ENV_APPEND(HHC_PATH, $DX_HHC)
DX_ENV_APPEND(GENERATE_HTML, YES)
DX_ENV_APPEND(GENERATE_HTMLHELP, YES)],
[DX_ENV_APPEND(GENERATE_HTMLHELP, NO)])
# Seperate CHI file generation.
DX_ARG_ABLE(chi, [generate doxygen seperate compressed HTML help index file],
[DX_CHECK_DEPEND(chm, 1)],
[DX_CLEAR_DEPEND(chm, 1)],
[],
[DX_ENV_APPEND(GENERATE_CHI, YES)],
[DX_ENV_APPEND(GENERATE_CHI, NO)])
# Plain HTML pages generation:
DX_ARG_ABLE(html, [generate doxygen plain HTML documentation],
[DX_CHECK_DEPEND(doc, 1) DX_CHECK_DEPEND(chm, 0)],
[DX_CLEAR_DEPEND(doc, 1) DX_CLEAR_DEPEND(chm, 0)],
[],
[DX_ENV_APPEND(GENERATE_HTML, YES)],
[DX_TEST_FEATURE(chm) || DX_ENV_APPEND(GENERATE_HTML, NO)])
# PostScript file generation:
DX_ARG_ABLE(ps, [generate doxygen PostScript documentation],
[DX_CHECK_DEPEND(doc, 1)],
[DX_CLEAR_DEPEND(doc, 1)],
[DX_REQUIRE_PROG([DX_LATEX], latex)
DX_REQUIRE_PROG([DX_MAKEINDEX], makeindex)
DX_REQUIRE_PROG([DX_DVIPS], dvips)
DX_REQUIRE_PROG([DX_EGREP], egrep)])
# PDF file generation:
DX_ARG_ABLE(pdf, [generate doxygen PDF documentation],
[DX_CHECK_DEPEND(doc, 1)],
[DX_CLEAR_DEPEND(doc, 1)],
[DX_REQUIRE_PROG([DX_PDFLATEX], pdflatex)
DX_REQUIRE_PROG([DX_MAKEINDEX], makeindex)
DX_REQUIRE_PROG([DX_EGREP], egrep)])
# LaTeX generation for PS and/or PDF:
AM_CONDITIONAL(DX_COND_latex, DX_TEST_FEATURE(ps) || DX_TEST_FEATURE(pdf))
if DX_TEST_FEATURE(ps) || DX_TEST_FEATURE(pdf); then
DX_ENV_APPEND(GENERATE_LATEX, YES)
else
DX_ENV_APPEND(GENERATE_LATEX, NO)
fi
# Paper size for PS and/or PDF:
AC_ARG_VAR(DOXYGEN_PAPER_SIZE,
[a4wide (default), a4, letter, legal or executive])
case "$DOXYGEN_PAPER_SIZE" in
#(
"")
AC_SUBST(DOXYGEN_PAPER_SIZE, "")
;; #(
a4wide|a4|letter|legal|executive)
DX_ENV_APPEND(PAPER_SIZE, $DOXYGEN_PAPER_SIZE)
;; #(
*)
AC_MSG_ERROR([unknown DOXYGEN_PAPER_SIZE='$DOXYGEN_PAPER_SIZE'])
;;
esac
#For debugging:
#echo DX_FLAG_doc=$DX_FLAG_doc
#echo DX_FLAG_dot=$DX_FLAG_dot
#echo DX_FLAG_man=$DX_FLAG_man
#echo DX_FLAG_html=$DX_FLAG_html
#echo DX_FLAG_chm=$DX_FLAG_chm
#echo DX_FLAG_chi=$DX_FLAG_chi
#echo DX_FLAG_rtf=$DX_FLAG_rtf
#echo DX_FLAG_xml=$DX_FLAG_xml
#echo DX_FLAG_pdf=$DX_FLAG_pdf
#echo DX_FLAG_ps=$DX_FLAG_ps
#echo DX_ENV=$DX_ENV
])

View File

@ -0,0 +1,236 @@
# ===========================================================================
# http://www.gnu.org/software/autoconf-archive/ax_valgrind_check.html
# ===========================================================================
#
# SYNOPSIS
#
# AX_VALGRIND_DFLT(memcheck|helgrind|drd|sgcheck, on|off)
# AX_VALGRIND_CHECK()
#
# DESCRIPTION
#
# AX_VALGRIND_CHECK checks whether Valgrind is present and, if so, allows
# running `make check` under a variety of Valgrind tools to check for
# memory and threading errors.
#
# Defines VALGRIND_CHECK_RULES which should be substituted in your
# Makefile; and $enable_valgrind which can be used in subsequent configure
# output. VALGRIND_ENABLED is defined and substituted, and corresponds to
# the value of the --enable-valgrind option, which defaults to being
# enabled if Valgrind is installed and disabled otherwise. Individual
# Valgrind tools can be disabled via --disable-valgrind-<tool>, the
# default is configurable via the AX_VALGRIND_DFLT command or is to use
# all commands not disabled via AX_VALGRIND_DFLT. All AX_VALGRIND_DFLT
# calls must be made before the call to AX_VALGRIND_CHECK.
#
# If unit tests are written using a shell script and automake's
# LOG_COMPILER system, the $(VALGRIND) variable can be used within the
# shell scripts to enable Valgrind, as described here:
#
# https://www.gnu.org/software/gnulib/manual/html_node/Running-self_002dtests-under-valgrind.html
#
# Usage example:
#
# configure.ac:
#
# AX_VALGRIND_DFLT([sgcheck], [off])
# AX_VALGRIND_CHECK
#
# Makefile.am:
#
# @VALGRIND_CHECK_RULES@
# VALGRIND_SUPPRESSIONS_FILES = my-project.supp
# EXTRA_DIST = my-project.supp
#
# This results in a "check-valgrind" rule being added to any Makefile.am
# which includes "@VALGRIND_CHECK_RULES@" (assuming the module has been
# configured with --enable-valgrind). Running `make check-valgrind` in
# that directory will run the module's test suite (`make check`) once for
# each of the available Valgrind tools (out of memcheck, helgrind and drd)
# while the sgcheck will be skipped unless enabled again on the
# commandline with --enable-valgrind-sgcheck. The results for each check
# will be output to test-suite-$toolname.log. The target will succeed if
# there are zero errors and fail otherwise.
#
# Alternatively, a "check-valgrind-$TOOL" rule will be added, for $TOOL in
# memcheck, helgrind, drd and sgcheck. These are useful because often only
# some of those tools can be ran cleanly on a codebase.
#
# The macro supports running with and without libtool.
#
# LICENSE
#
# Copyright (c) 2014, 2015, 2016 Philip Withnall <philip.withnall@collabora.co.uk>
#
# Copying and distribution of this file, with or without modification, are
# permitted in any medium without royalty provided the copyright notice
# and this notice are preserved. This file is offered as-is, without any
# warranty.
#serial 13
dnl Configured tools
m4_define([valgrind_tool_list], [[memcheck], [helgrind], [drd], [sgcheck]])
m4_set_add_all([valgrind_exp_tool_set], [sgcheck])
m4_foreach([vgtool], [valgrind_tool_list],
[m4_define([en_dflt_valgrind_]vgtool, [on])])
AC_DEFUN([AX_VALGRIND_DFLT],[
m4_define([en_dflt_valgrind_$1], [$2])
])dnl
AC_DEFUN([AX_VALGRIND_CHECK],[
dnl Check for --enable-valgrind
AC_ARG_ENABLE([valgrind],
[AS_HELP_STRING([--enable-valgrind], [Whether to enable Valgrind on the unit tests])],
[enable_valgrind=$enableval],[enable_valgrind=])
AS_IF([test "$enable_valgrind" != "no"],[
# Check for Valgrind.
AC_CHECK_PROG([VALGRIND],[valgrind],[valgrind])
AS_IF([test "$VALGRIND" = ""],[
AS_IF([test "$enable_valgrind" = "yes"],[
AC_MSG_ERROR([Could not find valgrind; either install it or reconfigure with --disable-valgrind])
],[
enable_valgrind=no
])
],[
enable_valgrind=yes
])
])
AM_CONDITIONAL([VALGRIND_ENABLED],[test "$enable_valgrind" = "yes"])
AC_SUBST([VALGRIND_ENABLED],[$enable_valgrind])
# Check for Valgrind tools we care about.
[valgrind_enabled_tools=]
m4_foreach([vgtool],[valgrind_tool_list],[
AC_ARG_ENABLE([valgrind-]vgtool,
m4_if(m4_defn([en_dflt_valgrind_]vgtool),[off],dnl
[AS_HELP_STRING([--enable-valgrind-]vgtool, [Whether to use ]vgtool[ during the Valgrind tests])],dnl
[AS_HELP_STRING([--disable-valgrind-]vgtool, [Whether to skip ]vgtool[ during the Valgrind tests])]),
[enable_valgrind_]vgtool[=$enableval],
[enable_valgrind_]vgtool[=])
AS_IF([test "$enable_valgrind" = "no"],[
enable_valgrind_]vgtool[=no],
[test "$enable_valgrind_]vgtool[" ]dnl
m4_if(m4_defn([en_dflt_valgrind_]vgtool), [off], [= "yes"], [!= "no"]),[
AC_CACHE_CHECK([for Valgrind tool ]vgtool,
[ax_cv_valgrind_tool_]vgtool,[
ax_cv_valgrind_tool_]vgtool[=no
m4_set_contains([valgrind_exp_tool_set],vgtool,
[m4_define([vgtoolx],[exp-]vgtool)],
[m4_define([vgtoolx],vgtool)])
AS_IF([`$VALGRIND --tool=]vgtoolx[ --help >/dev/null 2>&1`],[
ax_cv_valgrind_tool_]vgtool[=yes
])
])
AS_IF([test "$ax_cv_valgrind_tool_]vgtool[" = "no"],[
AS_IF([test "$enable_valgrind_]vgtool[" = "yes"],[
AC_MSG_ERROR([Valgrind does not support ]vgtool[; reconfigure with --disable-valgrind-]vgtool)
],[
enable_valgrind_]vgtool[=no
])
],[
enable_valgrind_]vgtool[=yes
])
])
AS_IF([test "$enable_valgrind_]vgtool[" = "yes"],[
valgrind_enabled_tools="$valgrind_enabled_tools ]m4_bpatsubst(vgtool,[^exp-])["
])
AC_SUBST([ENABLE_VALGRIND_]vgtool,[$enable_valgrind_]vgtool)
])
AC_SUBST([valgrind_tools],["]m4_join([ ], valgrind_tool_list)["])
AC_SUBST([valgrind_enabled_tools],[$valgrind_enabled_tools])
[VALGRIND_CHECK_RULES='
# Valgrind check
#
# Optional:
# - VALGRIND_SUPPRESSIONS_FILES: Space-separated list of Valgrind suppressions
# files to load. (Default: empty)
# - VALGRIND_FLAGS: General flags to pass to all Valgrind tools.
# (Default: --num-callers=30)
# - VALGRIND_$toolname_FLAGS: Flags to pass to Valgrind $toolname (one of:
# memcheck, helgrind, drd, sgcheck). (Default: various)
# Optional variables
VALGRIND_SUPPRESSIONS ?= $(addprefix --suppressions=,$(VALGRIND_SUPPRESSIONS_FILES))
VALGRIND_FLAGS ?= --num-callers=30
VALGRIND_memcheck_FLAGS ?= --leak-check=full --show-reachable=no
VALGRIND_helgrind_FLAGS ?= --history-level=approx
VALGRIND_drd_FLAGS ?=
VALGRIND_sgcheck_FLAGS ?=
# Internal use
valgrind_log_files = $(addprefix test-suite-,$(addsuffix .log,$(valgrind_tools)))
valgrind_memcheck_flags = --tool=memcheck $(VALGRIND_memcheck_FLAGS)
valgrind_helgrind_flags = --tool=helgrind $(VALGRIND_helgrind_FLAGS)
valgrind_drd_flags = --tool=drd $(VALGRIND_drd_FLAGS)
valgrind_sgcheck_flags = --tool=exp-sgcheck $(VALGRIND_sgcheck_FLAGS)
valgrind_quiet = $(valgrind_quiet_$(V))
valgrind_quiet_ = $(valgrind_quiet_$(AM_DEFAULT_VERBOSITY))
valgrind_quiet_0 = --quiet
valgrind_v_use = $(valgrind_v_use_$(V))
valgrind_v_use_ = $(valgrind_v_use_$(AM_DEFAULT_VERBOSITY))
valgrind_v_use_0 = @echo " USE " $(patsubst check-valgrind-%,%,$''@):;
# Support running with and without libtool.
ifneq ($(LIBTOOL),)
valgrind_lt = $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=execute
else
valgrind_lt =
endif
# Use recursive makes in order to ignore errors during check
check-valgrind:
ifeq ($(VALGRIND_ENABLED),yes)
-$(A''M_V_at)$(foreach tool,$(valgrind_enabled_tools), \
$(MAKE) $(AM_MAKEFLAGS) -k check-valgrind-$(tool); \
)
else
@echo "Need to reconfigure with --enable-valgrind"
endif
# Valgrind running
VALGRIND_TESTS_ENVIRONMENT = \
$(TESTS_ENVIRONMENT) \
env VALGRIND=$(VALGRIND) \
G_SLICE=always-malloc,debug-blocks \
G_DEBUG=fatal-warnings,fatal-criticals,gc-friendly
VALGRIND_LOG_COMPILER = test/test-suite.sh $(VALGRIND_SUPPRESSIONS) $(VALGRIND_FLAGS)
# $(valgrind_lt) \
# $(VALGRIND) $(VALGRIND_SUPPRESSIONS) --error-exitcode=1 $(VALGRIND_FLAGS)
define valgrind_tool_rule =
check-valgrind-$(1):
ifeq ($$(VALGRIND_ENABLED)-$$(ENABLE_VALGRIND_$(1)),yes-yes)
$$(valgrind_v_use)$$(MAKE) check-TESTS \
TESTS_ENVIRONMENT="$$(VALGRIND_TESTS_ENVIRONMENT)" \
LOG_COMPILER="$$(VALGRIND_LOG_COMPILER)" \
LOG_FLAGS="$$(valgrind_$(1)_flags)" \
TEST_SUITE_LOG=test-suite-$(1).log
else ifeq ($$(VALGRIND_ENABLED),yes)
@echo "Need to reconfigure with --enable-valgrind-$(1)"
else
@echo "Need to reconfigure with --enable-valgrind"
endif
endef
$(foreach tool,$(valgrind_tools),$(eval $(call valgrind_tool_rule,$(tool))))
A''M_DISTCHECK_CONFIGURE_FLAGS ?=
A''M_DISTCHECK_CONFIGURE_FLAGS += --disable-valgrind
MOSTLYCLEANFILES ?=
MOSTLYCLEANFILES += $(valgrind_log_files)
.PHONY: check-valgrind $(add-prefix check-valgrind-,$(valgrind_tools))
']
AC_SUBST([VALGRIND_CHECK_RULES])
m4_ifdef([_AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE([VALGRIND_CHECK_RULES])])
])

View File

@ -0,0 +1,131 @@
dnl Check for CURL Libraries
dnl CHECK_CURL(ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND])
dnl Sets:
dnl CURL_CFLAGS
dnl CURL_LIBS
CURL_CONFIG=""
CURL_VERSION=""
CURL_CPPFLAGS=""
CURL_CFLAGS=""
CURL_LDFLAGS=""
CURL_LDADD=""
CURL_MIN_VERSION="7.15.1"
AC_DEFUN([CHECK_CURL], [
AC_ARG_WITH(
curl,
[AS_HELP_STRING([--with-curl=PATH],[Path to curl prefix or config script])],
[test_paths="${with_curl}"],
[test_paths="/usr/local/libcurl /usr/local/curl /usr/local /opt/libcurl /opt/curl /opt /usr"])
AC_MSG_CHECKING([for libcurl config script])
for x in ${test_paths}; do
dnl # Determine if the script was specified and use it directly
if test ! -d "$x" -a -e "$x"; then
CURL_CONFIG=$x
curl_path="no"
break
fi
dnl # Try known config script names/locations
for CURL_CONFIG in curl-config; do
if test -e "${x}/bin/${CURL_CONFIG}"; then
curl_path="${x}/bin"
break
elif test -e "${x}/${CURL_CONFIG}"; then
curl_path="${x}"
break
else
curl_path=""
fi
done
if test -n "$curl_path"; then
break
fi
done
if test -n "${curl_path}"; then
if test "${curl_path}" != "no"; then
CURL_CONFIG="${curl_path}/${CURL_CONFIG}"
fi
AC_MSG_RESULT([${CURL_CONFIG}])
CURL_VERSION=`${CURL_CONFIG} --version | sed 's/^[[^0-9]][[^[:space:]]][[^[:space:]]]*[[[:space:]]]*//' | tr '\r\n' ' '`
if test ! -z "${CURL_VERSION}"; then AC_MSG_NOTICE(curl VERSION: $CURL_VERSION); fi
CURL_CFLAGS="`${CURL_CONFIG} --cflags`"
if test ! -z "${CURL_CFLAGS}"; then AC_MSG_NOTICE(curl CFLAGS: $CURL_CFLAGS); fi
CURL_LDADD="`${CURL_CONFIG} --libs`"
if test ! -z "${CURL_CONFIG}"; then AC_MSG_NOTICE(curl LDADD: $CURL_LIBS); fi
dnl # Check version is ok
AC_MSG_CHECKING([if libcurl is at least v${CURL_MIN_VERSION}])
curl_min_ver=`echo ${CURL_MIN_VERSION} | awk -F. '{print (\$ 1 * 1000000) + (\$ 2 * 1000) + \$ 3}'`
curl_ver=`echo ${CURL_VERSION} | awk -F. '{print (\$ 1 * 1000000) + (\$ 2 * 1000) + \$ 3}'`
if test "$curl_min_ver" -le "$curl_ver"; then
AC_MSG_RESULT([yes, $CURL_VERSION])
curl_tlsv2_ver=`echo 7.34.0 | awk -F. '{print (\$ 1 * 1000000) + (\$ 2 * 1000) + \$ 3}'`
if test "$curl_tlsv2_ver" -le "$curl_ver"; then
CURL_CFLAGS="${CURL_CFLAGS} -DWITH_CURL_SSLVERSION_TLSv1_2"
fi
CURL_CFLAGS="${CURL_CFLAGS} -DWITH_CURL"
else
AC_MSG_RESULT([no, $CURL_VERSION])
AC_MSG_NOTICE([NOTE: curl library may be too old])
fi
dnl # Check/warn if GnuTLS is used
AC_MSG_CHECKING([if libcurl is linked with gnutls])
curl_uses_gnutls=`echo ${CURL_LIBS} | grep gnutls | wc -l`
if test "$curl_uses_gnutls" -ne 0; then
AC_MSG_RESULT([yes])
AC_MSG_NOTICE([NOTE: curl linked with gnutls may be buggy, openssl recommended])
CURL_USES_GNUTLS=yes
else
AC_MSG_RESULT([no])
CURL_USES_GNUTLS=no
fi
else
AC_MSG_RESULT([no])
fi
AC_SUBST(CURL_CONFIG)
AC_SUBST(CURL_VERSION)
AC_SUBST(CURL_CPPFLAGS)
AC_SUBST(CURL_CFLAGS)
AC_SUBST(CURL_LDFLAGS)
AC_SUBST(CURL_LDADD)
AC_SUBST(CURL_USES_GNUTLS)
if test "x${with_curl}" == "xno"; then
CURL_DISABLED=yes
else
if test "x${with_curl}" != "x"; then
CURL_MANDATORY=yes
fi
fi
if test -z "${CURL_VERSION}"; then
AC_MSG_NOTICE([*** curl library not found.])
if test -z "${CURL_MANDATORY}"; then
if test -z "${CURL_DISABLED}"; then
CURL_FOUND=0
else
CURL_FOUND=2
fi
else
AC_MSG_ERROR([Curl was explicitly referenced but it was not found])
CURL_FOUND=-1
fi
else
CURL_FOUND=1
AC_MSG_NOTICE([using curl v${CURL_VERSION}])
CURL_DISPLAY="${CURL_LDADD}, ${CURL_CFLAGS}"
fi
AC_SUBST(CURL_FOUND)
AC_SUBST(CURL_DISPLAY)
])

View File

@ -0,0 +1,186 @@
dnl Check for GEOIP Libraries
dnl CHECK_GEOIP(ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND])
dnl Sets:
dnl GEOIP_CFLAGS
dnl GEOIP_LDADD
dnl GEOIP_LDFLAGS
dnl GEOIP_LIBS
dnl GEOIP_VERSION
AC_DEFUN([PROG_GEOIP], [
# Possible names for the geoip library/package (pkg-config)
GEOIP_POSSIBLE_LIB_NAMES="geoip2 geoip GeoIP"
# Possible extensions for the library
GEOIP_POSSIBLE_EXTENSIONS="so la sl dll dylib"
# Possible paths (if pkg-config was not found, proceed with the file lookup)
GEOIP_POSSIBLE_PATHS="/usr/local/libgeoip /usr/local/geoip /usr/local /opt/libgeoip /opt/geoip /opt /usr /opt/local/include /opt/local /usr/lib /usr/local/lib /usr/lib64 /usr"
# Variables to be set by this very own script.
GEOIP_VERSION=""
GEOIP_CFLAGS=""
GEOIP_CPPFLAGS=""
GEOIP_LDADD=""
GEOIP_LDFLAGS=""
AC_ARG_WITH(
geoip,
AS_HELP_STRING(
[--with-geoip=PATH],
[Path to GeoIP (including headers). Use 'no' to disable GeoIP support.]
)
)
# AS_HELP_STRING(
# [--without-geoip],
# [Complete dsiables GeoIP support]
# )
if test "x${with_geoip}" == "xno"; then
AC_DEFINE(HAVE_GEOIP, 0, [Support for GeoIP was disabled by the utilization of --without-geoip or --with-geoip=no])
AC_MSG_NOTICE([Support for GeoIP was disabled by the utilization of --without-geoip or --with-geoip=no])
GEOIP_DISABLED=yes
else
if test "x${with_geoip}" == "xyes"; then
GEOIP_MANDATORY=yes
AC_MSG_NOTICE([GeoIP support was marked as mandatory by the utilization of --with-geoip=yes])
fi
# for x in ${GEOIP_POSSIBLE_LIB_NAMES}; do
# CHECK_FOR_GEOIP_AT(${x})
# if test -n "${GEOIP_VERSION}"; then
# break
# fi
# done
# if test "x${with_geoip}" != "xyes" or test "x${with_geoip}" == "xyes"; then
if test "x${with_geoip}" == "x" || test "x${with_geoip}" == "xyes"; then
# Nothing about GeoIP was informed, using the pkg-config to figure things out.
if test -n "${PKG_CONFIG}"; then
GEOIP_PKG_NAME=""
for x in ${GEOIP_POSSIBLE_LIB_NAMES}; do
if ${PKG_CONFIG} --exists ${x}; then
GEOIP_PKG_NAME="$x"
break
fi
done
fi
AC_MSG_NOTICE([Nothing about GeoIP was informed during the configure phase. Trying to detect it on the platform...])
if test -n "${GEOIP_PKG_NAME}"; then
# Package was found using the pkg-config scripts
GEOIP_VERSION="`${PKG_CONFIG} ${GEOIP_PKG_NAME} --modversion`"
GEOIP_CFLAGS="`${PKG_CONFIG} ${GEOIP_PKG_NAME} --cflags`"
GEOIP_LDADD="`${PKG_CONFIG} ${GEOIP_PKG_NAME} --libs-only-l`"
GEOIP_LDFLAGS="`${PKG_CONFIG} ${GEOIP_PKG_NAME} --libs-only-L --libs-only-other`"
GEOIP_DISPLAY="${GEOIP_LDADD}, ${GEOIP_CFLAGS}"
else
# If pkg-config did not find anything useful, go over file lookup.
for x in ${GEOIP_POSSIBLE_PATHS}; do
CHECK_FOR_GEOIP_AT(${x})
if test -n "${GEOIP_VERSION}"; then
break
fi
done
fi
fi
if test "x${with_geoip}" != "x"; then
# An specific path was informed, lets check.
GEOIP_MANDATORY=yes
CHECK_FOR_GEOIP_AT(${with_geoip})
fi
# fi
fi
if test -z "${GEOIP_CFLAGS}"; then
if test -z "${GEOIP_MANDATORY}"; then
if test -z "${GEOIP_DISABLED}"; then
AC_MSG_NOTICE([GeoIP library was not found])
GEOIP_FOUND=0
else
GEOIP_FOUND=2
fi
else
AC_MSG_ERROR([GeoIP was explicit requested but it was not found])
GEOIP_FOUND=-1
fi
else
GEOIP_FOUND=1
AC_MSG_NOTICE([using GeoIP v${GEOIP_VERSION}])
GEOIP_CFLAGS="-DWITH_GEOIP ${GEOIP_CFLAGS}"
AC_SUBST(GEOIP_VERSION)
AC_SUBST(GEOIP_LDADD)
AC_SUBST(GEOIP_LIBS)
AC_SUBST(GEOIP_LDFLAGS)
AC_SUBST(GEOIP_CFLAGS)
AC_SUBST(GEOIP_DISPLAY)
fi
AC_SUBST(GEOIP_FOUND)
]) # AC_DEFUN [PROG_GEOIP]
AC_DEFUN([CHECK_FOR_GEOIP_AT], [
path=$1
for y in ${GEOIP_POSSIBLE_EXTENSIONS}; do
for z in ${GEOIP_POSSIBLE_LIB_NAMES}; do
if test -e "${path}/${z}.${y}"; then
geoip_lib_path="${path}/"
geoip_lib_name="${z}"
geoip_lib_file="${geoip_lib_path}/${z}.${y}"
break
fi
if test -e "${path}/lib${z}.${y}"; then
geoip_lib_path="${path}/"
geoip_lib_name="${z}"
geoip_lib_file="${geoip_lib_path}/lib${z}.${y}"
break
fi
if test -e "${path}/lib/lib${z}.${y}"; then
geoip_lib_path="${path}/lib/"
geoip_lib_name="${z}"
geoip_lib_file="${geoip_lib_path}/lib${z}.${y}"
break
fi
if test -e "${path}/lib64/lib${z}.${y}"; then
geoip_lib_path="${path}/lib64/"
geoip_lib_name="${z}"
geoip_lib_file="${geoip_lib_path}/lib${z}.${y}"
break
fi
if test -e "${path}/lib/x86_64-linux-gnu/lib${z}.${y}"; then
geoip_lib_path="${path}/lib/x86_64-linux-gnu/"
geoip_lib_name="${z}"
geoip_lib_file="${geoip_lib_path}/lib${z}.${y}"
break
fi
done
if test -n "$geoip_lib_path"; then
break
fi
done
if test -e "${path}/include/GeoIPCity.h"; then
geoip_inc_path="${path}/include"
elif test -e "${path}/GeoIPCity.h"; then
geoip_inc_path="${path}"
fi
if test -n "${geoip_inc_path}" -a -n "${geoip_lib_path}"; then
AC_MSG_NOTICE([GeoIP headers found at: ${geoip_inc_path}])
AC_MSG_NOTICE([GeoIP library found at: ${geoip_lib_file}])
fi
if test -n "${geoip_lib_path}" -a -n "${geoip_inc_path}"; then
# TODO: Compile a piece of code to check the version.
GEOIP_CFLAGS="-I${geoip_inc_path}"
GEOIP_LDADD="-l${geoip_lib_name}"
GEOIP_LDFLAGS="-L${geoip_lib_path}"
GEOIP_DISPLAY="${geoip_lib_file}, ${geoip_inc_path}"
fi
]) # AC_DEFUN [CHECK_FOR_GEOIP_AT]

View File

@ -0,0 +1,187 @@
dnl Check for MAXMIND Libraries
dnl CHECK_MAXMIND(ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND])
dnl Sets:
dnl MAXMIND_CFLAGS
dnl MAXMIND_LDADD
dnl MAXMIND_LDFLAGS
dnl MAXMIND_LIBS
dnl MAXMIND_VERSION
AC_DEFUN([PROG_MAXMIND], [
# Possible names for the maxmind library/package (pkg-config)
MAXMIND_POSSIBLE_LIB_NAMES="maxminddb maxmind"
# Possible extensions for the library
MAXMIND_POSSIBLE_EXTENSIONS="so la sl dll dylib"
# Possible paths (if pkg-config was not found, proceed with the file lookup)
MAXMIND_POSSIBLE_PATHS="/usr/local/libmaxmind /usr/local/maxmind /usr/local /opt/libmaxmind /opt/maxmind /opt /usr /opt/local/include /opt/local /usr/lib /usr/local/lib /usr/lib64 /usr /usr/include/x86_64-linux-gnu/"
# Variables to be set by this very own script.
MAXMIND_VERSION=""
MAXMIND_CFLAGS=""
MAXMIND_CPPFLAGS=""
MAXMIND_LDADD=""
MAXMIND_LDFLAGS=""
AC_ARG_WITH(
maxmind,
AS_HELP_STRING(
[--with-maxmind=PATH],
[Path to MaxMind (including headers). Use 'no' to disable MaxMind support.]
)
)
# AS_HELP_STRING(
# [--without-maxmind],
# [Complete dsiables MaxMind support]
# )
if test "x${with_maxmind}" == "xno"; then
AC_DEFINE(HAVE_MAXMIND, 0, [Support for MaxMind was disabled by the utilization of --without-maxmind or --with-maxmind=no])
AC_MSG_NOTICE([Support for MaxMind was disabled by the utilization of --without-maxmind or --with-maxmind=no])
MAXMIND_DISABLED=yes
else
if test "x${with_maxmind}" == "xyes"; then
MAXMIND_MANDATORY=yes
AC_MSG_NOTICE([MaxMind support was marked as mandatory by the utilization of --with-maxmind=yes])
fi
# for x in ${MAXMIND_POSSIBLE_LIB_NAMES}; do
# CHECK_FOR_MAXMIND_AT(${x})
# if test -n "${MAXMIND_VERSION}"; then
# break
# fi
# done
# if test "x${with_maxmind}" != "xyes" or test "x${with_maxmind}" == "xyes"; then
if test "x${with_maxmind}" == "x" || test "x${with_maxmind}" == "xyes"; then
# Nothing about MaxMind was informed, using the pkg-config to figure things out.
if test -n "${PKG_CONFIG}"; then
MAXMIND_PKG_NAME=""
if ${PKG_CONFIG} --exists libmaxminddb; then
MAXMIND_PKG_NAME="libmaxminddb"
break
fi
fi
AC_MSG_NOTICE([Nothing about MaxMind was informed during the configure phase. Trying to detect it on the platform...])
if test -n "${MAXMIND_PKG_NAME}"; then
# Package was found using the pkg-config scripts
MAXMIND_VERSION="`${PKG_CONFIG} ${MAXMIND_PKG_NAME} --modversion`"
MAXMIND_CFLAGS="`${PKG_CONFIG} ${MAXMIND_PKG_NAME} --cflags`"
MAXMIND_LDADD="`${PKG_CONFIG} ${MAXMIND_PKG_NAME} --libs-only-l`"
MAXMIND_LDFLAGS="`${PKG_CONFIG} ${MAXMIND_PKG_NAME} --libs-only-L --libs-only-other`"
MAXMIND_DISPLAY="${MAXMIND_LDADD}"
else
# If pkg-config did not find anything useful, go over file lookup.
for x in ${MAXMIND_POSSIBLE_PATHS}; do
CHECK_FOR_MAXMIND_AT(${x})
if test -n "${MAXMIND_VERSION}"; then
break
fi
done
fi
fi
if test "x${with_maxmind}" != "x"; then
# An specific path was informed, lets check.
MAXMIND_MANDATORY=yes
CHECK_FOR_MAXMIND_AT(${with_maxmind})
fi
# fi
fi
if test -z "${MAXMIND_DISPLAY}"; then
if test -z "${MAXMIND_MANDATORY}"; then
if test -z "${MAXMIND_DISABLED}"; then
AC_MSG_NOTICE([MaxMind library was not found])
MAXMIND_FOUND=0
else
MAXMIND_FOUND=2
fi
else
AC_MSG_ERROR([MaxMind was explicit requested but it was not found])
MAXMIND_FOUND=-1
fi
else
MAXMIND_FOUND=1
AC_MSG_NOTICE([using MaxMind v${MAXMIND_VERSION}])
MAXMIND_CFLAGS="-DWITH_MAXMIND ${MAXMIND_CFLAGS}"
if ! test "x$MAXMIND_CFLAGS" = "x"; then
MAXMIND_DISPLAY="${MAXMIND_DISPLAY}, ${MAXMIND_CFLAGS}"
fi
AC_SUBST(MAXMIND_VERSION)
AC_SUBST(MAXMIND_LDADD)
AC_SUBST(MAXMIND_LIBS)
AC_SUBST(MAXMIND_LDFLAGS)
AC_SUBST(MAXMIND_CFLAGS)
AC_SUBST(MAXMIND_DISPLAY)
fi
AC_SUBST(MAXMIND_FOUND)
]) # AC_DEFUN [PROG_MAXMIND]
AC_DEFUN([CHECK_FOR_MAXMIND_AT], [
path=$1
for y in ${MAXMIND_POSSIBLE_EXTENSIONS}; do
for z in ${MAXMIND_POSSIBLE_LIB_NAMES}; do
if test -e "${path}/${z}.${y}"; then
maxmind_lib_path="${path}/"
maxmind_lib_name="${z}"
maxmind_lib_file="${maxmind_lib_path}/${z}.${y}"
break
fi
if test -e "${path}/lib${z}.${y}"; then
maxmind_lib_path="${path}/"
maxmind_lib_name="${z}"
maxmind_lib_file="${maxmind_lib_path}/lib${z}.${y}"
break
fi
if test -e "${path}/lib/lib${z}.${y}"; then
maxmind_lib_path="${path}/lib/"
maxmind_lib_name="${z}"
maxmind_lib_file="${maxmind_lib_path}/lib${z}.${y}"
break
fi
if test -e "${path}/lib64/lib${z}.${y}"; then
maxmind_lib_path="${path}/lib64/"
maxmind_lib_name="${z}"
maxmind_lib_file="${maxmind_lib_path}/lib${z}.${y}"
break
fi
if test -e "${path}/lib/x86_64-linux-gnu/lib${z}.${y}"; then
maxmind_lib_path="${path}/lib/x86_64-linux-gnu/"
maxmind_lib_name="${z}"
maxmind_lib_file="${maxmind_lib_path}/lib${z}.${y}"
break
fi
done
if test -n "$maxmind_lib_path"; then
break
fi
done
if test -e "${path}/include/maxminddb.h"; then
maxmind_inc_path="${path}/include"
elif test -e "${path}/maxminddb.h"; then
maxmind_inc_path="${path}"
fi
if test -n "${maxmind_inc_path}" -a -n "${maxmind_lib_path}"; then
AC_MSG_NOTICE([MaxMind headers found at: ${maxmind_inc_path}])
AC_MSG_NOTICE([MaxMind library found at: ${maxmind_lib_file}])
fi
if test -n "${maxmind_lib_path}" -a -n "${maxmind_inc_path}"; then
# TODO: Compile a piece of code to check the version.
MAXMIND_CFLAGS="-I${maxmind_inc_path}"
MAXMIND_LDADD="-l${maxmind_lib_name}"
MAXMIND_LDFLAGS="-L${maxmind_lib_path}"
MAXMIND_DISPLAY="${maxmind_lib_file}, ${maxmind_inc_path}"
fi
]) # AC_DEFUN [CHECK_FOR_MAXMIND_AT]

View File

@ -0,0 +1,135 @@
dnl Check for LIBXML2 Libraries
dnl CHECK_LIBXML2(ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND])
dnl Sets:
dnl LIBXML2_CFLAGS
dnl LIBXML2_LIBS
AC_DEFUN([CHECK_XML2CONFIG], [
AC_MSG_CHECKING([for libxml2 config script])
for x in ${test_paths}; do
dnl # Determine if the script was specified and use it directly
if test ! -d "$x" -a -e "$x"; then
LIBXML2_CONFIG=$x
libxml2_path="no"
break
fi
dnl # Try known config script names/locations
for LIBXML2_CONFIG in xml2-config xml-2-config xml-config; do
if test -e "${x}/bin/${LIBXML2_CONFIG}"; then
libxml2_path="${x}/bin"
break
elif test -e "${x}/${LIBXML2_CONFIG}"; then
libxml2_path="${x}"
break
else
libxml2_path=""
fi
done
if test -n "$libxml2_path"; then
break
fi
done
if test -n "${libxml2_path}"; then
if test "${libxml2_path}" != "no"; then
LIBXML2_CONFIG="${libxml2_path}/${LIBXML2_CONFIG}"
fi
AC_MSG_RESULT([${LIBXML2_CONFIG}])
LIBXML2_VERSION=`${LIBXML2_CONFIG} --version | sed 's/^[[^0-9]][[^[:space:]]][[^[:space:]]]*[[[:space:]]]*//'`
if test ! -z "${LIBXML2_VERSION}"; then AC_MSG_NOTICE(xml VERSION: $LIBXML2_VERSION); fi
LIBXML2_CFLAGS="`${LIBXML2_CONFIG} --cflags` -DWITH_LIBXML2"
if test ! -z "${LIBXML2_CFLAGS}"; then AC_MSG_NOTICE(xml CFLAGS: $LIBXML2_CFLAGS); fi
LIBXML2_LDADD="`${LIBXML2_CONFIG} --libs`"
if test ! -z "${LIBXML2_LDADD}"; then AC_MSG_NOTICE(xml LDADD: $LIBXML2_LDADD); fi
AC_MSG_CHECKING([if libxml2 is at least v${LIBXML2_MIN_VERSION}])
libxml2_min_ver=`echo ${LIBXML2_MIN_VERSION} | awk -F. '{print (\$ 1 * 1000000) + (\$ 2 * 1000) + \$ 3}'`
libxml2_ver=`echo ${LIBXML2_VERSION} | awk -F. '{print (\$ 1 * 1000000) + (\$ 2 * 1000) + \$ 3}'`
if test "$libxml2_ver" -ge "$libxml2_min_ver"; then
AC_MSG_RESULT([yes, $LIBXML2_VERSION])
else
AC_MSG_RESULT([no, $LIBXML2_VERSION])
AC_MSG_ERROR([NOTE: libxml2 library must be at least ${LIBXML2_MIN_VERSION}])
fi
else
AC_MSG_RESULT([no])
fi
])
AC_DEFUN([CHECK_LIBXML2], [
AC_ARG_WITH(
libxml,
[AS_HELP_STRING([--with-libxml=PATH],[Path to libxml2 prefix or config script])],
[test_paths="${with_libxml}"],
[test_paths="/usr/local/libxml2 /usr/local/xml2 /usr/local/xml /usr/local /opt/libxml2 /opt/libxml /opt/xml2 /opt/xml /opt /usr"])
LIBXML2_MIN_VERSION="2.6.29"
LIBXML2_PKG_NAME="libxml-2.0"
LIBXML2_CONFIG=""
LIBXML2_VERSION=""
LIBXML2_CFLAGS=""
LIBXML2_CPPFLAGS=""
LIBXML2_LDADD=""
LIBXML2_LDFLAGS=""
if test "x${with_libxml}" != "xno"; then
if test -n "${PKG_CONFIG}"; then
AC_MSG_CHECKING([for libxml2 >= ${LIBXML2_MIN_VERSION} via pkg-config])
if `${PKG_CONFIG} --exists "${LIBXML2_PKG_NAME} >= ${LIBXML2_MIN_VERSION}"`; then
LIBXML2_VERSION="`${PKG_CONFIG} --modversion ${LIBXML2_PKG_NAME}`"
LIBXML2_CFLAGS="`${PKG_CONFIG} --cflags ${LIBXML2_PKG_NAME}` -DWITH_LIBXML2"
LIBXML2_LDADD="`${PKG_CONFIG} --libs-only-l ${LIBXML2_PKG_NAME}`"
LIBXML2_LDFLAGS="`${PKG_CONFIG} --libs-only-L --libs-only-other ${LIBXML2_PKG_NAME}`"
AC_MSG_RESULT([found version ${LIBXML2_VERSION}])
else
AC_MSG_RESULT([not found])
fi
fi
if test -z "${LIBXML2_VERSION}"; then
CHECK_XML2CONFIG
fi
fi
AC_SUBST(LIBXML2_CONFIG)
AC_SUBST(LIBXML2_VERSION)
AC_SUBST(LIBXML2_CFLAGS)
AC_SUBST(LIBXML2_CPPFLAGS)
AC_SUBST(LIBXML2_LDADD)
AC_SUBST(LIBXML2_LDFLAGS)
if test "x${with_libxml}" == "xno"; then
LIBXML2_DISABLED=yes
else
if test "x${with_libxml}" != "x"; then
LIBXML2_MANDATORY=yes
fi
fi
if test -z "${LIBXML2_VERSION}"; then
AC_MSG_NOTICE([*** libxml2 library not found.])
if test -z "${LIBXML2_MANDATORY}"; then
if test -z "${LIBXML2_DISABLED}"; then
LIBXML2_FOUND=0
else
LIBXML2_FOUND=2
fi
else
AC_MSG_ERROR([Libxml2 was explicitly referenced but it was not found])
LIBXML2_FOUND=-1
fi
else
LIBXML2_FOUND=1
AC_MSG_NOTICE([using libxml2 v${LIBXML2_VERSION}])
LIBXML2_DISPLAY="${LIBXML2_LDADD}, ${LIBXML2_CFLAGS}"
fi
AC_SUBST(LIBXML2_FOUND)
AC_SUBST(LIBXML2_DISPLAY)
])

View File

@ -0,0 +1,180 @@
dnl Check for LMDB Libraries
dnl CHECK_LMDB(ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND])
AC_DEFUN([PROG_LMDB], [
# Possible names for the lmdb library/package (pkg-config)
LMDB_POSSIBLE_LIB_NAMES="lmdb"
# Possible extensions for the library
LMDB_POSSIBLE_EXTENSIONS="so so0 la sl dll dylib so.0.0.0"
# Possible paths (if pkg-config was not found, proceed with the file lookup)
LMDB_POSSIBLE_PATHS="/usr/lib /usr/local/lib /usr/local/liblmdb /usr/local/lmdb /usr/local /opt/liblmdb /opt/lmdb /opt /usr /usr/lib64 /opt/local"
# Variables to be set by this very own script.
LMDB_VERSION=""
LMDB_CFLAGS=""
LMDB_CPPFLAGS=""
LMDB_LDADD=""
LMDB_LDFLAGS=""
AC_ARG_WITH(
lmdb,
[AS_HELP_STRING([--with-lmdb=PATH],[Path to lmdb prefix or config script])]
)
if test "x${with_lmdb}" == "xno"; then
AC_DEFINE(HAVE_LMDB, 0, [Support for LMDB was disabled by the utilization of --without-lmdb or --with-lmdb=no])
AC_MSG_NOTICE([Support for LMDB was disabled by the utilization of --without-lmdb or --with-lmdb=no])
LMDB_DISABLED=yes
else
if test "x${with_lmdb}" == "xyes"; then
LMDB_MANDATORY=yes
AC_MSG_NOTICE([LMDB support was marked as mandatory by the utilization of --with-lmdb=yes])
fi
# for x in ${LMDB_POSSIBLE_LIB_NAMES}; do
# CHECK_FOR_LMDB_AT(${x})
# if test -n "${LMDB_VERSION}"; then
# break
# fi
# done
# if test "x${with_lmdb}" != "xyes" or test "x${with_lmdb}" == "xyes"; then
if test "x${with_lmdb}" == "x" || test "x${with_lmdb}" == "xyes"; then
# Nothing about LMDB was informed, using the pkg-config to figure things out.
if test -n "${PKG_CONFIG}"; then
LMDB_PKG_NAME=""
for x in ${LMDB_POSSIBLE_LIB_NAMES}; do
if ${PKG_CONFIG} --exists ${x}; then
LMDB_PKG_NAME="$x"
break
fi
done
fi
AC_MSG_NOTICE([Nothing about LMDB was informed during the configure phase. Trying to detect it on the platform...])
if test -n "${LMDB_PKG_NAME}"; then
# Package was found using the pkg-config scripts
LMDB_VERSION="`${PKG_CONFIG} ${LMDB_PKG_NAME} --modversion`"
LMDB_CFLAGS="`${PKG_CONFIG} ${LMDB_PKG_NAME} --cflags`"
LMDB_LDADD="`${PKG_CONFIG} ${LMDB_PKG_NAME} --libs-only-l`"
LMDB_LDFLAGS="`${PKG_CONFIG} ${LMDB_PKG_NAME} --libs-only-L --libs-only-other`"
LMDB_DISPLAY="${LMDB_LDADD}, ${LMDB_CFLAGS}"
else
# If pkg-config did not find anything useful, go over file lookup.
for x in ${LMDB_POSSIBLE_PATHS}; do
CHECK_FOR_LMDB_AT(${x})
if test -n "${LMDB_VERSION}"; then
break
fi
done
fi
fi
if test "x${with_lmdb}" != "x"; then
# An specific path was informed, lets check.
LMDB_MANDATORY=yes
CHECK_FOR_LMDB_AT(${with_lmdb})
fi
# fi
fi
if test -z "${LMDB_LDADD}"; then
if test -z "${LMDB_MANDATORY}"; then
if test -z "${LMDB_DISABLED}"; then
AC_MSG_NOTICE([LMDB library was not found])
LMDB_FOUND=0
else
LMDB_FOUND=2
fi
else
AC_MSG_ERROR([LMDB was explicitly referenced but it was not found])
LMDB_FOUND=-1
fi
else
if test -z "${LMDB_MANDATORY}"; then
LMDB_FOUND=2
AC_MSG_NOTICE([LMDB is disabled by default.])
else
LMDB_FOUND=1
AC_MSG_NOTICE([using LMDB v${LMDB_VERSION}])
LMDB_CFLAGS="-DWITH_LMDB ${LMDB_CFLAGS}"
LMDB_DISPLAY="${LMDB_LDADD}, ${LMDB_CFLAGS}"
AC_SUBST(LMDB_VERSION)
AC_SUBST(LMDB_LDADD)
AC_SUBST(LMDB_LIBS)
AC_SUBST(LMDB_LDFLAGS)
AC_SUBST(LMDB_CFLAGS)
AC_SUBST(LMDB_DISPLAY)
fi
fi
AC_SUBST(LMDB_FOUND)
]) # AC_DEFUN [PROG_LMDB]
AC_DEFUN([CHECK_FOR_LMDB_AT], [
path=$1
echo "*** LOOKING AT PATH: " ${path}
for y in ${LMDB_POSSIBLE_EXTENSIONS}; do
for z in ${LMDB_POSSIBLE_LIB_NAMES}; do
if test -e "${path}/${z}.${y}"; then
lmdb_lib_path="${path}/"
lmdb_lib_name="${z}"
lmdb_lib_file="${lmdb_lib_path}/${z}.${y}"
break
fi
if test -e "${path}/lib${z}.${y}"; then
lmdb_lib_path="${path}/"
lmdb_lib_name="${z}"
lmdb_lib_file="${lmdb_lib_path}/lib${z}.${y}"
break
fi
if test -e "${path}/lib/lib${z}.${y}"; then
lmdb_lib_path="${path}/lib/"
lmdb_lib_name="${z}"
lmdb_lib_file="${lmdb_lib_path}/lib${z}.${y}"
break
fi
if test -e "${path}/lib/x86_64-linux-gnu/lib${z}.${y}"; then
lmdb_lib_path="${path}/lib/x86_64-linux-gnu/"
lmdb_lib_name="${z}"
lmdb_lib_file="${lmdb_lib_path}/lib${z}.${y}"
break
fi
if test -e "${path}/lib/i386-linux-gnu/lib${z}.${y}"; then
lmdb_lib_path="${path}/lib/i386-linux-gnu/"
lmdb_lib_name="${z}"
lmdb_lib_file="${lmdb_lib_path}/lib${z}.${y}"
break
fi
done
if test -n "$lmdb_lib_path"; then
break
fi
done
if test -e "${path}/include/lmdb.h"; then
lmdb_inc_path="${path}/include"
elif test -e "${path}/lmdb.h"; then
lmdb_inc_path="${path}"
elif test -e "${path}/include/lmdb/lmdb.h"; then
lmdb_inc_path="${path}/include"
fi
if test -n "${lmdb_lib_path}"; then
AC_MSG_NOTICE([LMDB library found at: ${lmdb_lib_file}])
fi
if test -n "${lmdb_inc_path}"; then
AC_MSG_NOTICE([LMDB headers found at: ${lmdb_inc_path}])
fi
if test -n "${lmdb_lib_path}" -a -n "${lmdb_inc_path}"; then
# TODO: Compile a piece of code to check the version.
LMDB_CFLAGS="-I${lmdb_inc_path}"
LMDB_LDADD="-l${lmdb_lib_name}"
LMDB_LDFLAGS="-L${lmdb_lib_path}"
LMDB_DISPLAY="${lmdb_lib_file}, ${lmdb_inc_path}"
fi
]) # AC_DEFUN [CHECK_FOR_LMDB_AT]

View File

@ -0,0 +1,248 @@
dnl Check for LUA Libraries
dnl CHECK_LUA(ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND])
AC_DEFUN([CHECK_LUA],
[dnl
# Possible names for the lua library/package (pkg-config)
LUA_POSSIBLE_LIB_NAMES="lua54 lua5.4 lua-5.4 lua53 lua5.3 lua-5.3 lua52 lua5.2 lua-5.2 lua51 lua5.1 lua-5.1 lua"
# Possible extensions for the library
LUA_POSSIBLE_EXTENSIONS="so la sl dll dylib"
# Possible paths (if pkg-config was not found, proceed with the file lookup)
LUA_POSSIBLE_PATHS="/usr/lib /usr/local/lib /usr/local/lib64 /usr/local/lua /usr/local/liblua /usr/local /opt /usr /usr/lib64 /opt/local /usr/lib/lua5.3/liblua /usr/lib/lua5.2/liblua"
# Variables to be set by this very own script.
LUA_CFLAGS=""
LUA_LDFLAGS=""
LUA_LDADD=""
LUA_DISPLAY=""
AC_ARG_WITH(
lua,
[AS_HELP_STRING([--with-lua=PATH],[Path to lua prefix])]
)
if test "x${with_lua}" == "xno"; then
AC_DEFINE(HAVE_LUA, 0, [Support for LUA was disabled by the utilization of --without-lua or --with-lua=no])
AC_MSG_NOTICE([Support for LUA was disabled by the utilization of --without-lua or --with-lua=no])
LUA_DISABLED=yes
else
if test "x${with_lua}" == "xyes"; then
LUA_MANDATORY=yes
AC_MSG_NOTICE([LUA support was marked as mandatory by the utilization of --with-lua=yes])
else
LUA_MANDATORY=no
fi
for x in ${LUA_POSSIBLE_PATHS}; do
CHECK_FOR_LUA_AT(${x})
if test -n "${LUA_CFLAGS}"; then
break
fi
done
if test -z "${LUA_CFLAGS}"; then
#Trying to figure out the version using pkg-config...
if test -n "${PKG_CONFIG}"; then
LUA_PKG_NAME=""
for x in ${LUA_POSSIBLE_LIB_NAMES}; do
if ${PKG_CONFIG} --exists ${x}; then
LUA_PKG_NAME="$x"
LUA_PKG_VERSION="`${PKG_CONFIG} ${LUA_PKG_NAME} --modversion`"
break
fi
done
fi
if test -n "${LUA_PKG_NAME}"; then
# Package was found using the pkg-config scripts
LUA_PKG_VERSION="`${PKG_CONFIG} ${LUA_PKG_NAME} --modversion`"
LUA_CFLAGS="`${PKG_CONFIG} ${LUA_PKG_NAME} --cflags`"
LUA_LDADD="`${PKG_CONFIG} ${LUA_PKG_NAME} --libs-only-l`"
LUA_LDFLAGS="`${PKG_CONFIG} ${LUA_PKG_NAME} --libs-only-L --libs-only-other`"
LUA_DISPLAY="${LUA_LDADD}, ${LUA_CFLAGS}"
case $LUA_PKG_VERSION in
(5.1*) LUA_CFLAGS="-DWITH_LUA_5_1 ${LUA_CFLAGS}" ; lua_5_1=1 ;;
(5.2*) LUA_CFLAGS="-DWITH_LUA_5_2 ${LUA_CFLAGS}" ; lua_5_2=1 ;;
(5.3*) LUA_CFLAGS="-DWITH_LUA_5_3 ${LUA_CFLAGS}" ; lua_5_3=1 ;;
(5.4*) LUA_CFLAGS="-DWITH_LUA_5_4 ${LUA_CFLAGS}" ; lua_5_4=1 ;;
(2.0*) LUA_CFLAGS="-DWITH_LUA_5_1 ${LUA_CFLAGS}" ; lua_5_1=1 ;;
(2.1*) LUA_CFLAGS="-DWITH_LUA_5_1 -DWITH_LUA_JIT_2_1 ${LUA_CFLAGS}" ; lua_5_1=1 ;;
esac
AC_MSG_NOTICE([LUA pkg-config version: ${LUA_PKG_VERSION}])
fi
fi
fi
if test -z "${LUA_CFLAGS}"; then
if test -z "${LUA_MANDATORY}" || test "x${LUA_MANDATORY}" == "xno"; then
if test -z "${LUA_DISABLED}"; then
AC_MSG_NOTICE([LUA library was not found])
LUA_FOUND=0
else
LUA_FOUND=2
fi
else
AC_MSG_ERROR([LUA was explicitly referenced but it was not found])
LUA_FOUND=-1
fi
else
if test -z "${LUA_MANDATORY}" || test "x${LUA_MANDATORY}" == "xno"; then
LUA_FOUND=1
AC_MSG_NOTICE([using LUA ${LUA_LDADD}])
LUA_CFLAGS="-DWITH_LUA ${LUA_CFLAGS}"
LUA_DISPLAY="${LUA_LDADD} ${LUA_LDFLAGS}, ${LUA_CFLAGS}"
AC_SUBST(LUA_LDFLAGS)
AC_SUBST(LUA_LDADD)
AC_SUBST(LUA_CFLAGS)
AC_SUBST(LUA_DISPLAY)
else
LUA_FOUND=1
AC_MSG_NOTICE([using LUA ${LUA_LDADD}])
LUA_CFLAGS="-DWITH_LUA ${LUA_CFLAGS}"
LUA_DISPLAY="${LUA_LDADD} ${LUA_LDFLAGS}, ${LUA_CFLAGS}"
AC_SUBST(LUA_LDFLAGS)
AC_SUBST(LUA_LDADD)
AC_SUBST(LUA_CFLAGS)
AC_SUBST(LUA_DISPLAY)
fi
fi
AC_SUBST(LUA_FOUND)
]) # AC_DEFUN [CHECK_LUA]
AC_DEFUN([CHECK_FOR_LUA_AT], [
path=$1
echo "*** LOOKING AT PATH: " ${path}
for y in ${LUA_POSSIBLE_EXTENSIONS}; do
for z in ${LUA_POSSIBLE_LIB_NAMES}; do
if test -e "${path}/${z}.${y}"; then
lua_lib_path="${path}/"
lua_lib_name="${z}"
lua_lib_file="${lua_lib_path}/${z}.${y}"
break
fi
if test -e "${path}/lib${z}.${y}"; then
lua_lib_path="${path}/"
lua_lib_name="${z}"
lua_lib_file="${lua_lib_path}/lib${z}.${y}"
break
fi
if test -e "${path}/lib/lib${z}.${y}"; then
lua_lib_path="${path}/lib/"
lua_lib_name="${z}"
lua_lib_file="${lua_lib_path}/lib${z}.${y}"
break
fi
if test -e "${path}/lib/x86_64-linux-gnu/lib${z}.${y}"; then
lua_lib_path="${path}/lib/x86_64-linux-gnu/"
lua_lib_name="${z}"
lua_lib_file="${lua_lib_path}/lib${z}.${y}"
break
fi
if test -e "${path}/lib/i386-linux-gnu/lib${z}.${y}"; then
lua_lib_path="${path}/lib/i386-linux-gnu/"
lua_lib_name="${z}"
lua_lib_file="${lua_lib_path}/lib${z}.${y}"
break
fi
done
if test -n "$lua_lib_path"; then
break
fi
done
if test -e "${path}/include/lua.h"; then
lua_inc_path="${path}/include"
elif test -e "${path}/lua.h"; then
lua_inc_path="${path}"
elif test -e "${path}/include/lua/lua.h"; then
lua_inc_path="${path}/include/lua"
elif test -e "${path}/include/lua5.4/lua.h"; then
lua_inc_path="${path}/include/lua5.4"
LUA_VERSION=504
elif test -e "${path}/include/lua5.3/lua.h"; then
lua_inc_path="${path}/include/lua5.3"
LUA_VERSION=503
elif test -e "${path}/include/lua5.2/lua.h"; then
lua_inc_path="${path}/include/lua5.2"
LUA_VERSION=502
elif test -e "${path}/include/lua5.1/lua.h"; then
lua_inc_path="${path}/include/lua5.1"
LUA_VERSION=501
elif test -e "${path}/include/luajit-2.0/lua.h"; then
lua_inc_path="${path}/include/luajit-2.0"
LUA_VERSION=501
fi
if test -n "${lua_lib_path}"; then
AC_MSG_NOTICE([LUA library found at: ${lua_lib_file}])
fi
if test -n "${lua_inc_path}"; then
AC_MSG_NOTICE([LUA headers found at: ${lua_inc_path}])
fi
if test -n "${lua_lib_path}" -a -n "${lua_inc_path}"; then
LUA_CFLAGS="-I${lua_inc_path}"
LUA_LDADD="-l${lua_lib_name}"
LUA_LDFLAGS="-L${lua_lib_path}"
LUA_DISPLAY="${lua_lib_file}, ${lua_inc_path}"
# Double checking version from lua.h...
AC_TRY_COMPILE([ #include <lua.h>> ],
[ #if (LUA_VERSION_NUM < 502)
return 0;
#else
#error Lua 5.1 not detected
#endif ],
[ LUA_VERSION=501 ], [ lua_5_1=0 ]
)
AC_TRY_COMPILE([ #include <lua.h> ],
[ #if (LUA_VERSION_NUM == 502)
return 0;
#else
#error Lua 5.2 not detected
#endif ],
[ LUA_VERSION=502 ], [ lua_5_2=0 ]
)
AC_TRY_COMPILE([ #include <lua.h> ],
[ #if (LUA_VERSION_NUM == 504)
return 0;
#else
#error Lua 5.4 not detected
#endif ],
[ LUA_VERSION=504 ], [ lua_5_4=0 ]
)
if test -z "${LUA_VERSION}" ; then
# As a last resort, try to find LUA version from $lua_inc_path
while read -r line
do
case "$line" in
(\#define\ LUA_VERSION_NUM*501*) LUA_VERSION=501 ;;
(\#define\ LUA_VERSION_NUM*502*) LUA_VERSION=502 ;;
(\#define\ LUA_VERSION_NUM*503*) LUA_VERSION=503 ;;
(\#define\ LUA_VERSION_NUM*504*) LUA_VERSION=504
esac
done <"${lua_inc_path}/lua.h"
AC_MSG_NOTICE([LUA_VERSION is ${LUA_VERSION} found at: ${lua_inc_path}])
else
AC_MSG_NOTICE([LUA version from includes: ${LUA_VERSION}])
fi
case $LUA_VERSION in
(501) LUA_CFLAGS="-DWITH_LUA_5_1 ${LUA_CFLAGS}" ; lua_5_1=1 ;;
(502) LUA_CFLAGS="-DWITH_LUA_5_2 ${LUA_CFLAGS}" ; lua_5_2=1 ;;
(503) LUA_CFLAGS="-DWITH_LUA_5_3 ${LUA_CFLAGS}" ; lua_5_3=1 ;;
(504) LUA_CFLAGS="-DWITH_LUA_5_4 ${LUA_CFLAGS}" ; lua_5_4=1 ;;
esac
fi
]) # AC_DEFUN [CHECK_FOR_LUA_AT]

View File

@ -0,0 +1,113 @@
dnl Check for PCRE Libraries
dnl CHECK_PCRE(ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND])
dnl Sets:
dnl PCRE_CFLAGS
dnl PCRE_LIBS
PCRE_CONFIG=""
PCRE_VERSION=""
PCRE_CPPFLAGS=""
PCRE_CFLAGS=""
PCRE_LDFLAGS=""
PCRE_LDADD=""
PCRE_LD_PATH=""
AC_DEFUN([CHECK_PCRE],
[dnl
AC_ARG_WITH(
pcre,
[AS_HELP_STRING([--with-pcre=PATH],[Path to pcre prefix or config script])],
[test_paths="${with_pcre}"],
[test_paths="/usr/local/libpcre /usr/local/pcre /usr/local /opt/libpcre /opt/pcre /opt /usr /opt/local"])
if test "x${with_pcre2}" != "x" && test "x${with_pcre2}" != "xno"; then
AC_MSG_NOTICE([pcre2 specified; omitting check for pcre])
else
AC_MSG_CHECKING([for libpcre config script])
for x in ${test_paths}; do
dnl # Determine if the script was specified and use it directly
if test ! -d "$x" -a -e "$x"; then
PCRE_CONFIG=$x
pcre_path="no"
break
fi
dnl # Try known config script names/locations
for PCRE_CONFIG in pcre-config; do
if test -e "${x}/bin/${PCRE_CONFIG}"; then
pcre_path="${x}/bin"
break
elif test -e "${x}/${PCRE_CONFIG}"; then
pcre_path="${x}"
break
else
pcre_path=""
fi
done
if test -n "$pcre_path"; then
break
fi
done
if test -n "${pcre_path}"; then
if test "${pcre_path}" != "no"; then
PCRE_CONFIG="${pcre_path}/${PCRE_CONFIG}"
fi
AC_MSG_RESULT([${PCRE_CONFIG}])
PCRE_VERSION="`${PCRE_CONFIG} --version`"
if test ! -z "${PCRE_VERSION}"; then AC_MSG_NOTICE(pcre VERSION: $PCRE_VERSION); fi
PCRE_CFLAGS="`${PCRE_CONFIG} --cflags`"
if test ! -z "${PCRE_CFLAGS}"; then AC_MSG_NOTICE(pcre CFLAGS: $PCRE_CFLAGS); fi
PCRE_LDADD="`${PCRE_CONFIG} --libs`"
if test ! -z "${PCRE_LDADD}"; then AC_MSG_NOTICE(pcre LDADD: $PCRE_LDADD); fi
PCRE_LD_PATH="/`${PCRE_CONFIG} --libs | cut -d'/' -f2,3,4,5,6 | cut -d ' ' -f1`"
if test ! -z "${PCRE_LD_PATH}"; then AC_MSG_NOTICE(pcre PCRE_LD_PATH: $PCRE_LD_PATH); fi
else
AC_MSG_RESULT([no])
fi
if test -n "${PCRE_VERSION}"; then
AC_MSG_CHECKING(for PCRE JIT)
save_CFLAGS=$CFLAGS
save_LDFLAGS=$LDFLAGS
save_LIBS=$LIBS
CFLAGS="${PCRE_CFLAGS} ${CFLAGS}"
LDFLAGS="${PCRE_LDADD} ${LDFLAGS}"
LIBS="${PCRE_LDADD} ${LIBS}"
AC_TRY_LINK([ #include <pcre.h> ],
[ pcre_jit_exec(NULL, NULL, NULL, 0, 0, 0, NULL, 0, NULL); ],
[ pcre_jit_available=yes ], [:]
)
if test "x$pcre_jit_available" = "xyes"; then
AC_MSG_RESULT(yes)
PCRE_CFLAGS="${PCRE_CFLAGS} -DPCRE_HAVE_JIT"
else
AC_MSG_RESULT(no)
fi
CFLAGS=$save_CFLAGS
LDFLAGS=$save_LDFLAGS
LIBS=$save_LIBS
fi
AC_SUBST(PCRE_CONFIG)
AC_SUBST(PCRE_VERSION)
AC_SUBST(PCRE_CPPFLAGS)
AC_SUBST(PCRE_CFLAGS)
AC_SUBST(PCRE_LDFLAGS)
AC_SUBST(PCRE_LDADD)
AC_SUBST(PCRE_LD_PATH)
if test -z "${PCRE_VERSION}"; then
AC_MSG_NOTICE([*** pcre library not found.])
ifelse([$2], , AC_MSG_ERROR([pcre library is required]), $2)
else
AC_MSG_NOTICE([using pcre v${PCRE_VERSION}])
ifelse([$1], , , $1)
PCRE_LDADD="${PCRE_LDADD} -lpcre"
fi
fi
])

View File

@ -0,0 +1,180 @@
dnl Check for PCRE2 Libraries
dnl CHECK_PCRE2(ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND])
AC_DEFUN([PROG_PCRE2], [
# Possible names for the pcre2 library/package (pkg-config)
PCRE2_POSSIBLE_LIB_NAMES="pcre2 pcre2-8"
# Possible extensions for the library
PCRE2_POSSIBLE_EXTENSIONS="so so0 la sl dll dylib so.0.0.0"
# Possible paths (if pkg-config was not found, proceed with the file lookup)
PCRE2_POSSIBLE_PATHS="/usr/lib /usr/local/lib /usr/local/libpcre2-8 /usr/local/pcre2 /usr/local /opt/libpcre2-8 /opt/pcre2 /opt /usr /usr/lib64 /opt/local"
# Variables to be set by this very own script.
PCRE2_VERSION=""
PCRE2_CFLAGS=""
PCRE2_CPPFLAGS=""
PCRE2_LDADD=""
PCRE2_LDFLAGS=""
AC_ARG_WITH(
pcre2,
[AS_HELP_STRING([--with-pcre2=PATH],[Path to pcre2 prefix or config script])]
)
if test "x${with_pcre2}" == "xno"; then
AC_DEFINE(HAVE_PCRE2, 0, [Support for PCRE2 was disabled by the utilization of --without-pcre2 or --with-pcre2=no])
AC_MSG_NOTICE([Support for PCRE2 was disabled by the utilization of --without-pcre2 or --with-pcre2=no])
PCRE2_DISABLED=yes
else
if test "x${with_pcre2}" == "xyes"; then
PCRE2_MANDATORY=yes
AC_MSG_NOTICE([PCRE2 support was marked as mandatory by the utilization of --with-pcre2=yes])
fi
# for x in ${PCRE2_POSSIBLE_LIB_NAMES}; do
# CHECK_FOR_PCRE2_AT(${x})
# if test -n "${PCRE2_VERSION}"; then
# break
# fi
# done
# if test "x${with_pcre2}" != "xyes" or test "x${with_pcre2}" == "xyes"; then
if test "x${with_pcre2}" == "x" || test "x${with_pcre2}" == "xyes"; then
# Nothing about PCRE2 was informed, using the pkg-config to figure things out.
if test -n "${PKG_CONFIG}"; then
PCRE2_PKG_NAME=""
for x in ${PCRE2_POSSIBLE_LIB_NAMES}; do
if ${PKG_CONFIG} --exists ${x}; then
PCRE2_PKG_NAME="$x"
break
fi
done
fi
AC_MSG_NOTICE([Nothing about PCRE2 was informed during the configure phase. Trying to detect it on the platform...])
if test -n "${PCRE2_PKG_NAME}"; then
# Package was found using the pkg-config scripts
PCRE2_VERSION="`${PKG_CONFIG} ${PCRE2_PKG_NAME} --modversion`"
PCRE2_CFLAGS="`${PKG_CONFIG} ${PCRE2_PKG_NAME} --cflags`"
PCRE2_LDADD="`${PKG_CONFIG} ${PCRE2_PKG_NAME} --libs-only-l`"
PCRE2_LDFLAGS="`${PKG_CONFIG} ${PCRE2_PKG_NAME} --libs-only-L --libs-only-other`"
PCRE2_DISPLAY="${PCRE2_LDADD}, ${PCRE2_CFLAGS}"
else
# If pkg-config did not find anything useful, go over file lookup.
for x in ${PCRE2_POSSIBLE_PATHS}; do
CHECK_FOR_PCRE2_AT(${x})
if test -n "${PCRE2_VERSION}"; then
break
fi
done
fi
fi
if test "x${with_pcre2}" != "x"; then
# An specific path was informed, lets check.
PCRE2_MANDATORY=yes
CHECK_FOR_PCRE2_AT(${with_pcre2})
fi
# fi
fi
if test -z "${PCRE2_LDADD}"; then
if test -z "${PCRE2_MANDATORY}"; then
if test -z "${PCRE2_DISABLED}"; then
AC_MSG_NOTICE([PCRE2 library was not found])
PCRE2_FOUND=0
else
PCRE2_FOUND=2
fi
else
AC_MSG_ERROR([PCRE2 was explicitly referenced but it was not found])
PCRE2_FOUND=-1
fi
else
if test -z "${PCRE2_MANDATORY}"; then
PCRE2_FOUND=2
AC_MSG_NOTICE([PCRE2 is disabled by default.])
else
PCRE2_FOUND=1
AC_MSG_NOTICE([using PCRE2 v${PCRE2_VERSION}])
PCRE2_CFLAGS="-DWITH_PCRE2 ${PCRE2_CFLAGS}"
PCRE2_DISPLAY="${PCRE2_LDADD}, ${PCRE2_CFLAGS}"
AC_SUBST(PCRE2_VERSION)
AC_SUBST(PCRE2_LDADD)
AC_SUBST(PCRE2_LIBS)
AC_SUBST(PCRE2_LDFLAGS)
AC_SUBST(PCRE2_CFLAGS)
AC_SUBST(PCRE2_DISPLAY)
fi
fi
AC_SUBST(PCRE2_FOUND)
]) # AC_DEFUN [PROG_PCRE2]
AC_DEFUN([CHECK_FOR_PCRE2_AT], [
path=$1
echo "*** LOOKING AT PATH: " ${path}
for y in ${PCRE2_POSSIBLE_EXTENSIONS}; do
for z in ${PCRE2_POSSIBLE_LIB_NAMES}; do
if test -e "${path}/${z}.${y}"; then
pcre2_lib_path="${path}/"
pcre2_lib_name="${z}"
pcre2_lib_file="${pcre2_lib_path}/${z}.${y}"
break
fi
if test -e "${path}/lib${z}.${y}"; then
pcre2_lib_path="${path}/"
pcre2_lib_name="${z}"
pcre2_lib_file="${pcre2_lib_path}/lib${z}.${y}"
break
fi
if test -e "${path}/lib/lib${z}.${y}"; then
pcre2_lib_path="${path}/lib/"
pcre2_lib_name="${z}"
pcre2_lib_file="${pcre2_lib_path}/lib${z}.${y}"
break
fi
if test -e "${path}/lib/x86_64-linux-gnu/lib${z}.${y}"; then
pcre2_lib_path="${path}/lib/x86_64-linux-gnu/"
pcre2_lib_name="${z}"
pcre2_lib_file="${pcre2_lib_path}/lib${z}.${y}"
break
fi
if test -e "${path}/lib/i386-linux-gnu/lib${z}.${y}"; then
pcre2_lib_path="${path}/lib/i386-linux-gnu/"
pcre2_lib_name="${z}"
pcre2_lib_file="${pcre2_lib_path}/lib${z}.${y}"
break
fi
done
if test -n "$pcre2_lib_path"; then
break
fi
done
if test -e "${path}/include/pcre2.h"; then
pcre2_inc_path="${path}/include"
elif test -e "${path}/pcre2.h"; then
pcre2_inc_path="${path}"
elif test -e "${path}/include/pcre2/pcre2.h"; then
pcre2_inc_path="${path}/include"
fi
if test -n "${pcre2_lib_path}"; then
AC_MSG_NOTICE([PCRE2 library found at: ${pcre2_lib_file}])
fi
if test -n "${pcre2_inc_path}"; then
AC_MSG_NOTICE([PCRE2 headers found at: ${pcre2_inc_path}])
fi
if test -n "${pcre2_lib_path}" -a -n "${pcre2_inc_path}"; then
# TODO: Compile a piece of code to check the version.
PCRE2_CFLAGS="-I${pcre2_inc_path}"
PCRE2_LDADD="-l${pcre2_lib_name}"
PCRE2_LDFLAGS="-L${pcre2_lib_path}"
PCRE2_DISPLAY="${pcre2_lib_file}, ${pcre2_inc_path}"
fi
]) # AC_DEFUN [CHECK_FOR_PCRE2_AT]

View File

@ -0,0 +1,21 @@
#!/bin/bash
git clean -xfdi
git submodule foreach --recursive git clean -xfdi
VERSION=`git describe --tags`
DIR_NAME="modsecurity-$VERSION"
TAR_NAME="modsecurity-$VERSION.tar.gz"
MY_DIR=${PWD##*/}
./build.sh
cd ..
tar --transform "s/^$MY_DIR/$DIR_NAME/" -cvzf $TAR_NAME --exclude .git $MY_DIR
sha256sum $TAR_NAME > $TAR_NAME.sha256
gpg --detach-sign -a $TAR_NAME
cd -
echo $TAR_NAME ": done."

View File

@ -0,0 +1,144 @@
dnl Check for SSDEEP Libraries
dnl CHECK_SSDEEP(ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND])
AC_DEFUN([CHECK_SSDEEP],
[dnl
# Possible names for the ssdeep library/package (pkg-config)
SSDEEP_POSSIBLE_LIB_NAMES="fuzzy"
# Possible extensions for the library
SSDEEP_POSSIBLE_EXTENSIONS="so so0 la sl dll dylib so.0.0.0"
# Possible paths (if pkg-config was not found, proceed with the file lookup)
SSDEEP_POSSIBLE_PATHS="/usr/lib /usr/local/lib /usr/local/fuzzy /usr/local/libfuzzy /usr/local /opt /usr /usr/lib64 /opt/local"
# Variables to be set by this very own script.
SSDEEP_CFLAGS=""
SSDEEP_LDFLAGS=""
SSDEEP_LDADD=""
SSDEEP_DISPLAY=""
AC_ARG_WITH(
ssdeep,
[AS_HELP_STRING([--with-ssdeep=PATH],[Path to ssdeep prefix])]
)
if test "x${with_ssdeep}" == "xno"; then
AC_DEFINE(HAVE_SSDEEP, 0, [Support for SSDEEP was disabled by the utilization of --without-ssdeep or --with-ssdeep=no])
AC_MSG_NOTICE([Support for SSDEEP was disabled by the utilization of --without-ssdeep or --with-ssdeep=no])
SSDEEP_DISABLED=yes
else
if test "x${with_ssdeep}" == "xyes"; then
SSDEEP_MANDATORY=yes
AC_MSG_NOTICE([SSDEEP support was marked as mandatory by the utilization of --with-ssdeep=yes])
else
SSDEEP_MANDATORY=no
fi
for x in ${SSDEEP_POSSIBLE_PATHS}; do
CHECK_FOR_SSDEEP_AT(${x})
if test -n "${SSDEEP_CFLAGS}"; then
break
fi
done
fi
if test -z "${SSDEEP_CFLAGS}"; then
if test -z "${SSDEEP_MANDATORY}" || test "x${SSDEEP_MANDATORY}" == "xno"; then
if test -z "${SSDEEP_DISABLED}"; then
AC_MSG_NOTICE([SSDEEP library was not found])
SSDEEP_FOUND=0
else
SSDEEP_FOUND=2
fi
else
AC_MSG_ERROR([SSDEEP was explicitly referenced but it was not found])
SSDEEP_FOUND=-1
fi
else
SSDEEP_FOUND=1
AC_MSG_NOTICE([using SSDEEP v${SSDEEP_VERSION}])
SSDEEP_CFLAGS="-DWITH_SSDEEP ${SSDEEP_CFLAGS}"
SSDEEP_DISPLAY="${SSDEEP_LDADD} ${SSDEEP_LDFLAGS}, ${SSDEEP_CFLAGS}"
AC_SUBST(SSDEEP_LDFLAGS)
AC_SUBST(SSDEEP_LDADD)
AC_SUBST(SSDEEP_CFLAGS)
AC_SUBST(SSDEEP_DISPLAY)
fi
AC_SUBST(SSDEEP_FOUND)
]) # AC_DEFUN [CHECK_SSDEEP]
AC_DEFUN([CHECK_FOR_SSDEEP_AT], [
path=$1
echo "*** LOOKING AT PATH: " ${path}
for y in ${SSDEEP_POSSIBLE_EXTENSIONS}; do
for z in ${SSDEEP_POSSIBLE_LIB_NAMES}; do
if test -e "${path}/${z}.${y}"; then
ssdeep_lib_path="${path}/"
ssdeep_lib_name="${z}"
ssdeep_lib_file="${ssdeep_lib_path}/${z}.${y}"
break
fi
if test -e "${path}/lib${z}.${y}"; then
ssdeep_lib_path="${path}/"
ssdeep_lib_name="${z}"
ssdeep_lib_file="${ssdeep_lib_path}/lib${z}.${y}"
break
fi
if test -e "${path}/lib/lib${z}.${y}"; then
ssdeep_lib_path="${path}/lib/"
ssdeep_lib_name="${z}"
ssdeep_lib_file="${ssdeep_lib_path}/lib${z}.${y}"
break
fi
if test -e "${path}/lib/x86_64-linux-gnu/lib${z}.${y}"; then
ssdeep_lib_path="${path}/lib/x86_64-linux-gnu/"
ssdeep_lib_name="${z}"
ssdeep_lib_file="${ssdeep_lib_path}/lib${z}.${y}"
break
fi
if test -e "${path}/lib/i386-linux-gnu/lib${z}.${y}"; then
ssdeep_lib_path="${path}/lib/i386-linux-gnu/"
ssdeep_lib_name="${z}"
ssdeep_lib_file="${ssdeep_lib_path}/lib${z}.${y}"
break
fi
done
if test -n "$ssdeep_lib_path"; then
break
fi
done
if test -e "${path}/include/fuzzy.h"; then
ssdeep_inc_path="${path}/include"
elif test -e "${path}/fuzzy.h"; then
ssdeep_inc_path="${path}"
elif test -e "${path}/include/fuzzy/fuzzy.h"; then
ssdeep_inc_path="${path}/include"
fi
if test -n "${ssdeep_lib_path}"; then
AC_MSG_NOTICE([SSDEEP library found at: ${ssdeep_lib_file}])
fi
if test -n "${ssdeep_inc_path}"; then
AC_MSG_NOTICE([SSDEEP headers found at: ${ssdeep_inc_path}])
fi
if test -n "${ssdeep_lib_path}" -a -n "${ssdeep_inc_path}"; then
# TODO: Compile a piece of code to check the version.
SSDEEP_CFLAGS="-I${ssdeep_inc_path}"
SSDEEP_LDADD="-l${ssdeep_lib_name}"
SSDEEP_LDFLAGS="-L${ssdeep_lib_path}"
SSDEEP_DISPLAY="${ssdeep_lib_file}, ${ssdeep_inc_path}"
fi
]) # AC_DEFUN [CHECK_FOR_SSDEEP_AT]

View File

@ -0,0 +1,169 @@
dnl Check for YAJL Libraries
dnl CHECK_YAJL(ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND])
AC_DEFUN([PROG_YAJL], [
# Possible names for the yajl library/package (pkg-config)
YAJL_POSSIBLE_LIB_NAMES="yajl2 yajl"
# Possible extensions for the library
YAJL_POSSIBLE_EXTENSIONS="so la sl dll dylib"
# Possible paths (if pkg-config was not found, proceed with the file lookup)
YAJL_POSSIBLE_PATHS="/usr/lib /usr/local/lib /usr/local/libyajl /usr/local/yajl /usr/local /opt/libyajl /opt/yajl /opt /usr /usr/lib64"
# Variables to be set by this very own script.
YAJL_VERSION=""
YAJL_CFLAGS=""
YAJL_CPPFLAGS=""
YAJL_LDADD=""
YAJL_LDFLAGS=""
AC_ARG_WITH(
yajl,
[AS_HELP_STRING([--with-yajl=PATH],[Path to yajl prefix or config script])]
)
if test "x${with_yajl}" == "xno"; then
AC_DEFINE(HAVE_YAJL, 0, [Support for YAJL was disabled by the utilization of --without-yajl or --with-yajl=no])
AC_MSG_NOTICE([Support for YAJL was disabled by the utilization of --without-yajl or --with-yajl=no])
YAJL_DISABLED=yes
else
if test "x${with_yajl}" == "xyes"; then
YAJL_MANDATORY=yes
AC_MSG_NOTICE([YAJL support was marked as mandatory by the utilization of --with-yajl=yes])
fi
# for x in ${YAJL_POSSIBLE_LIB_NAMES}; do
# CHECK_FOR_YAJL_AT(${x})
# if test -n "${YAJL_VERSION}"; then
# break
# fi
# done
# if test "x${with_yajl}" != "xyes" or test "x${with_yajl}" == "xyes"; then
if test "x${with_yajl}" == "x" || test "x${with_yajl}" == "xyes"; then
# Nothing about YAJL was informed, using the pkg-config to figure things out.
if test -n "${PKG_CONFIG}"; then
YAJL_PKG_NAME=""
for x in ${YAJL_POSSIBLE_LIB_NAMES}; do
if ${PKG_CONFIG} --exists ${x}; then
YAJL_PKG_NAME="$x"
break
fi
done
fi
AC_MSG_NOTICE([Nothing about YAJL was informed during the configure phase. Trying to detect it on the platform...])
if test -n "${YAJL_PKG_NAME}"; then
# Package was found using the pkg-config scripts
YAJL_VERSION="`${PKG_CONFIG} ${YAJL_PKG_NAME} --modversion`"
YAJL_CFLAGS="`${PKG_CONFIG} ${YAJL_PKG_NAME} --cflags`"
YAJL_LDADD="`${PKG_CONFIG} ${YAJL_PKG_NAME} --libs-only-l`"
YAJL_LDFLAGS="`${PKG_CONFIG} ${YAJL_PKG_NAME} --libs-only-L --libs-only-other`"
YAJL_DISPLAY="${YAJL_LDADD}, ${YAJL_CFLAGS}"
else
# If pkg-config did not find anything useful, go over file lookup.
for x in ${YAJL_POSSIBLE_LIB_NAMES}; do
CHECK_FOR_YAJL_AT(${x})
if test -n "${YAJL_VERSION}"; then
break
fi
done
fi
fi
if test "x${with_yajl}" != "x"; then
# An specific path was informed, lets check.
YAJL_MANDATORY=yes
CHECK_FOR_YAJL_AT(${with_yajl})
fi
# fi
fi
if test -z "${YAJL_LDADD}"; then
if test -z "${YAJL_MANDATORY}"; then
if test -z "${YAJL_DISABLED}"; then
AC_MSG_NOTICE([YAJL library was not found])
YAJL_FOUND=0
else
YAJL_FOUND=2
fi
else
AC_MSG_ERROR([YAJL was explicitly referenced but it was not found])
YAJL_FOUND=-1
fi
else
YAJL_FOUND=1
AC_MSG_NOTICE([using YAJL v${YAJL_VERSION}])
YAJL_CFLAGS="-DWITH_YAJL ${YAJL_CFLAGS}"
YAJL_DISPLAY="${YAJL_LDADD}, ${YAJL_CFLAGS}"
AC_SUBST(YAJL_VERSION)
AC_SUBST(YAJL_LDADD)
AC_SUBST(YAJL_LIBS)
AC_SUBST(YAJL_LDFLAGS)
AC_SUBST(YAJL_CFLAGS)
AC_SUBST(YAJL_DISPLAY)
fi
AC_SUBST(YAJL_FOUND)
]) # AC_DEFUN [PROG_YAJL]
AC_DEFUN([CHECK_FOR_YAJL_AT], [
path=$1
for y in ${YAJL_POSSIBLE_EXTENSIONS}; do
for z in ${YAJL_POSSIBLE_LIB_NAMES}; do
if test -e "${path}/${z}.${y}"; then
yajl_lib_path="${path}/"
yajl_lib_name="${z}"
yajl_lib_file="${yajl_lib_path}/${z}.${y}"
break
fi
if test -e "${path}/lib${z}.${y}"; then
yajl_lib_path="${path}/"
yajl_lib_name="${z}"
yajl_lib_file="${yajl_lib_path}/lib${z}.${y}"
break
fi
if test -e "${path}/lib/lib${z}.${y}"; then
yajl_lib_path="${path}/lib/"
yajl_lib_name="${z}"
yajl_lib_file="${yajl_lib_path}/lib${z}.${y}"
break
fi
if test -e "${path}/lib/x86_64-linux-gnu/lib${z}.${y}"; then
yajl_lib_path="${path}/lib/x86_64-linux-gnu/"
yajl_lib_name="${z}"
yajl_lib_file="${yajl_lib_path}/lib${z}.${y}"
break
fi
done
if test -n "$yajl_lib_path"; then
break
fi
done
if test -e "${path}/include/yajl_parse.h"; then
yajl_inc_path="${path}/include"
elif test -e "${path}/yajl_parse.h"; then
yajl_inc_path="${path}"
elif test -e "${path}/include/yajl/yajl_parse.h"; then
yajl_inc_path="${path}/include"
fi
if test -n "${yajl_lib_path}"; then
AC_MSG_NOTICE([YAJL library found at: ${yajl_lib_file}])
fi
if test -n "${yajl_inc_path}"; then
AC_MSG_NOTICE([YAJL headers found at: ${yajl_inc_path}])
fi
if test -n "${yajl_lib_path}" -a -n "${yajl_inc_path}"; then
# TODO: Compile a piece of code to check the version.
YAJL_CFLAGS="-I${yajl_inc_path}"
YAJL_LDADD="-l${yajl_lib_name}"
YAJL_LDFLAGS="-L${yajl_lib_path}"
YAJL_DISPLAY="${yajl_lib_file}, ${yajl_inc_path}"
fi
]) # AC_DEFUN [CHECK_FOR_YAJL_AT]

View File

@ -0,0 +1,639 @@
# ModSecurity configure.ac
# Get the hash of the last commit, to be used if it is not an
# official release.
AC_DEFUN([MSC_GIT_HASH], m4_esyscmd_s(git log -1 --format="%h" --abbrev-commit))
AC_DEFUN([MSC_MAJOR], m4_esyscmd_s(cat headers/modsecurity/modsecurity.h | grep "define MODSECURITY_MAJOR " | awk {'print $3'} | sed 's/\"//g'))
AC_DEFUN([MSC_MINOR], m4_esyscmd_s(cat headers/modsecurity/modsecurity.h | grep "define MODSECURITY_MINOR " | awk {'print $3'} | sed 's/\"//g'))
AC_DEFUN([MSC_PATCHLEVEL], m4_esyscmd_s(cat headers/modsecurity/modsecurity.h | grep "define MODSECURITY_PATCHLEVEL " | awk {'print $3'} | sed 's/\"//g'))
AC_DEFUN([MSC_TAG], m4_esyscmd_s(cat headers/modsecurity/modsecurity.h | grep "define MODSECURITY_FTAG " | awk {'print $3'} | sed 's/\"//g'))
# Version definition to be further used by AC_INIT and
# .so file naming.
m4_define([msc_version_major], [MSC_MAJOR])
m4_define([msc_version_minor], [MSC_MINOR])
m4_define([msc_version_patchlevel], [MSC_PATCHLEVEL])
m4_define([msc_version_c_plus_a], [m4_eval(msc_version_major + msc_version_minor)])
m4_define([msc_version],
[msc_version_major.msc_version_minor])
m4_define([msc_version_with_patchlevel],
[msc_version_major.msc_version_minor.msc_version_patchlevel])
m4_define([msc_version_git],
[m4_esyscmd_s(git describe)])
m4_define([msc_version_info],
[msc_version_c_plus_a:msc_version_patchlevel:msc_version_minor])
# Project Information
AC_INIT([modsecurity], [3.0], [security@modsecurity.org])
# General definitions
AC_CONFIG_MACRO_DIR([build])
AC_PREFIX_DEFAULT([/usr/local/modsecurity])
# General automake options.
AM_INIT_AUTOMAKE([-Wall -Werror foreign subdir-objects])
# Check for dependencies (C++, AR, Lex, Yacc and Make)
AC_PROG_CXX
AM_PROG_AR
AC_PROG_MAKE_SET
PKG_PROG_PKG_CONFIG
# Check if the compiler is c++11 compatible.
# AX_CXX_COMPILE_STDCXX_11(,mandatory)
# Check for libinjection
if ! test -f "${srcdir}/others/libinjection/src/libinjection_html5.c"; then
AC_MSG_ERROR([\
libInjection was not found within ModSecurity source directory.
libInjection code is available as part of ModSecurity source code in a format
of a git-submodule. git-submodule allow us to specify the correct version of
libInjection and still uses the libInjection repository to download it.
You can download libInjection using git:
$ git submodule init
$ git submodule update
])
fi
# Libinjection version
AC_DEFUN([LIBINJECTION_VERSION], m4_esyscmd_s(cd "others/libinjection" && git describe && cd ../..))
# SecLang test version
AC_DEFUN([SECLANG_TEST_VERSION], m4_esyscmd_s(cd "test/test-cases/secrules-language-tests" && git log -1 --format="%h" --abbrev-commit && cd ../../..))
# Check for yajl
PROG_YAJL
AM_CONDITIONAL([YAJL_VERSION], [test "$YAJL_VERSION" != ""])
# Check for LibGeoIP
PROG_GEOIP
AM_CONDITIONAL([GEOIP_CFLAGS], [test "GEOIP_CFLAGS" != ""])
# Check for MaxMind
PROG_MAXMIND
AM_CONDITIONAL([MAXMIND_CFLAGS], [test "MAXMIND_CFLAGS" != ""])
# Check for LMDB
PROG_LMDB
AM_CONDITIONAL([LMDB_CFLAGS], [test "LMDB_CFLAGS" != ""])
# Check for SSDEEP
CHECK_SSDEEP
AM_CONDITIONAL([SSDEEP_CFLAGS], [test "SSDEEP_CFLAGS" != ""])
# Check for LUA
CHECK_LUA
AM_CONDITIONAL([LUA_CFLAGS], [test "LUA_CFLAGS" != ""])
#
# Check for curl
#
CHECK_CURL
if ! test -z "${CURL_VERSION}"; then
AC_DEFINE([MSC_WITH_CURL], [1], [Define if libcurl is available])
fi
#
# Check for LibXML
#
CHECK_LIBXML2
#
# Check for libpcre
#
CHECK_PCRE
#
# Check for pcre2
#
PROG_PCRE2
AM_CONDITIONAL([PCRE2_CFLAGS], [test "PCRE2_CFLAGS" != ""])
# Checks for header files.
AC_HEADER_STDC
AC_CHECK_HEADERS([string])
AC_CHECK_HEADERS([iostream])
AC_CHECK_HEADERS([sys/utsname.h])
# ??
LT_INIT([dlopen])
# Identify platform
AC_CANONICAL_HOST
case $host in
*-*-aix*)
echo "Checking platform... Identified as AIX"
AC_DEFINE([AIX], [1], [Define if the operating system is AIX])
PLATFORM="AIX"
;;
*-*-hpux*)
echo "Checking platform... Identified as HPUX"
AC_DEFINE([HPUX], [1], [Define if the operating system is HPUX])
PLATFORM="HPUX"
;;
*-*-darwin*)
echo "Checking platform... Identified as Macintosh OS X"
AC_DEFINE([MACOSX], [1], [Define if the operating system is Macintosh OSX])
PLATFORM="MacOSX"
;;
*-*-linux* | *-*uclinux*)
echo "Checking platform... Identified as Linux"
AC_DEFINE([LINUX], [1], [Define if the operating system is LINUX])
PLATFORM="Linux"
;;
*-*-solaris*)
echo "Checking platform... Identified as Solaris"
AC_DEFINE([SOLARIS], [1], [Define if the operating system is SOLARIS])
PLATFORM="Solaris"
;;
*-*-freebsd*)
echo "Checking platform... Identified as FreeBSD"
AC_DEFINE([FREEBSD], [1], [Define if the operating system is FREEBSD])
PLATFORM="FreeBSD"
;;
*-*-netbsd*)
echo "Checking platform... Identified as NetBSD"
AC_DEFINE([NETBSD], [1], [Define if the operating system is NETBSD])
PLATFORM="NetBSD"
;;
*-*-openbsd*)
echo "Checking platform... Identified as OpenBSD"
AC_DEFINE([OPENBSD], [1], [Define if the operating system is OPENBSD])
PLATFORM="OpenBSD"
;;
*-*-kfreebsd*)
echo "Checking platform... Identified as kFreeBSD, treating as linux"
AC_DEFINE([FREEBSD], [1], [Define if the operating system is FREEBSD])
PLATFORM="kFreeBSD"
;;
*-*-dragonfly*)
echo "Checking platform... Identified as DragonFlyBSD, treating as linux"
AC_DEFINE([DRAGONFLY], [1], [Define if the operating system is DRAGONFLY])
PLATFORM="DragonFly"
;;
*-*-gnu*.*)
echo "Checking platform... Identified as HURD, treating as linux"
AC_DEFINE([LINUX], [1], [Define if the operating system is LINUX])
PLATFORM="HURD"
;;
*)
echo "Unknown CANONICAL_HOST $host"
exit 1
;;
esac
# Variables to be used inside the Makefile.am files.
MSC_BASE_DIR=`pwd`
AC_SUBST([MSC_BASE_DIR])
MSC_VERSION_INFO=msc_version_info
AC_SUBST([MSC_VERSION_INFO])
MSC_VERSION_WITH_PATCHLEVEL=msc_version_with_patchlevel
AC_SUBST([MSC_VERSION_WITH_PATCHLEVEL])
MSC_VERSION=msc_version
AC_SUBST([MSC_VERSION])
MSC_GIT_VERSION=msc_version_git
AC_SUBST([MSC_GIT_VERSION])
AC_ARG_ENABLE(debug-logs,
[AS_HELP_STRING([--disable-debug-logs],[Turn off the SecDebugLog feature])],
[case "${enableval}" in
yes) debugLogs=true ;;
no) debugLogs=false ;;
*) AC_MSG_ERROR(bad value ${enableval} for --enable-debug-logs) ;;
esac],
[debugLogs=true]
)
if test "$debugLogs" != "true"; then
MODSEC_NO_LOGS="-DNO_LOGS=1"
AC_SUBST(MODSEC_NO_LOGS)
fi
# Fuzzer
AC_ARG_ENABLE(afl-fuzz,
[AS_HELP_STRING([--enable-afl-fuzz],[Turn on the afl fuzzer compilation utilities])],
[case "${enableval}" in
yes) aflFuzzer=true ;;
no) aflFuzzer=false ;;
*) AC_MSG_ERROR(bad value ${enableval} for --enable-afl-fuzz) ;;
esac],
[aflFuzzer=false]
)
# Examples
AC_ARG_ENABLE(examples,
[AS_HELP_STRING([--enable-examples],[Turn on the examples compilation (default option)])],
[case "${enableval}" in
yes) buildExamples=true ;;
no) buildExamples=false ;;
*) AC_MSG_ERROR(bad value ${enableval} for --enable-examples) ;;
esac],
[buildExamples=true]
)
# Parser
AC_ARG_ENABLE(parser-generation,
[AS_HELP_STRING([--enable-parser-generation],[Enables parser generation during the build])],
[case "${enableval}" in
yes) buildParser=true ;;
no) buildParser=false ;;
*) AC_MSG_ERROR(bad value ${enableval} for --enable-parser-generation) ;;
esac],
[buildParser=false]
)
# Mutex
AC_ARG_ENABLE(mutex-on-pm,
[AS_HELP_STRING([--enable-mutex-on-pm],[Treats pm operations as a critical section])],
[case "${enableval}" in
yes) mutexPm=true ;;
no) mutexPm=false ;;
*) AC_MSG_ERROR(bad value ${enableval} for --enable-mutex-on-pm) ;;
esac],
[mutexPm=false]
)
if test "$mutexPm" == "true"; then
MODSEC_MUTEX_ON_PM="-DMUTEX_ON_PM=1"
AC_SUBST(MODSEC_MUTEX_ON_PM)
fi
if test $buildParser = true; then
AC_PROG_YACC
AC_PROG_LEX
AC_PATH_PROG([FLEX], [flex])
test "x$FLEX" = "x" && AC_MSG_ERROR([flex is needed to build ModSecurity])
AC_PATH_PROG([BISON], [bison])
test "x$BISON" = "x" && AC_MSG_ERROR([bison is needed to build ModSecurity])
AC_PATH_PROG([YACC_INST], $YACC)
if test ! -f "$srcdir/gram.c"; then
if test -z "$YACC_INST"; then
AC_MSG_ERROR([yacc not found - unable to compile ModSecurity])
fi
fi
fi
# Decide if we want to build the tests or not.
# buildTestUtilities=false
# if test "x$YAJL_FOUND" = "x1"; then
# Regression tests will not be able to run without the logging support.
# But we still have the unit tests.
# if test "$debugLogs" = "true"; then
# buildTestUtilities=true
# fi
# fi
AM_CONDITIONAL([TEST_UTILITIES], [test $buildTestUtilities = true])
if test $buildTestUtilities = true; then
if test $debugLogs = true; then
if test -f ./test/test-list.sh; then
TEST_CASES=`./test/test-list.sh`
fi
fi
fi
AM_CONDITIONAL([EXAMPLES], [test $buildExamples = true])
AM_CONDITIONAL([BUILD_PARSER], [test $buildParser = true])
AM_CONDITIONAL([USE_MUTEX_ON_PM], [test $mutexPm = true])
# General link options
if test "$PLATFORM" != "MacOSX" -a "$PLATFORM" != "OpenBSD"; then
GLOBAL_LDADD="-lrt "
fi
if test "$aflFuzzer" == "true"; then
FUZZ_CPPCFLAGS="-fsanitize=address -fsanitize-coverage=4 "
GLOBAL_LDADD="$GLOBAL_LDADD -fsanitize=address "
GLOBAL_CPPFLAGS="$GLOBAL_CPPFLAGS $FUZZ_CPPCFLAGS"
$buildExamples = false
fi
AC_SUBST(GLOBAL_LDADD)
AC_SUBST(GLOBAL_CPPFLAGS)
AM_CONDITIONAL([AFL_FUZZER], [test $aflFuzzer = true])
GLOBAL_CFLAGS=""
AC_SUBST(GLOBAL_CFLAGS)
# Files to be generated via autotools.
AC_CONFIG_FILES([\
modsecurity.pc \
Makefile \
doc/Makefile \
src/Makefile \
others/Makefile \
tools/Makefile \
tools/rules-check/Makefile
])
AM_COND_IF([TEST_UTILITIES],
[AC_CONFIG_FILES([test/Makefile test/benchmark/Makefile])])
AM_COND_IF([EXAMPLES],
[AC_CONFIG_FILES([ \
examples/Makefile \
examples/simple_example_using_c/Makefile \
examples/multiprocess_c/Makefile \
examples/reading_logs_with_offset/Makefile \
examples/reading_logs_via_rule_message/Makefile \
examples/using_bodies_in_chunks/Makefile \
])])
AM_COND_IF([AFL_FUZZER],
[AC_CONFIG_FILES([test/fuzzer/Makefile])])
AM_COND_IF([BUILD_PARSER],
[AC_CONFIG_FILES([src/parser/Makefile])])
AC_CONFIG_HEADERS([src/config.h])
# Doxygen support
DX_HTML_FEATURE(ON)
DX_CHM_FEATURE(OFF)
DX_CHI_FEATURE(OFF)
DX_MAN_FEATURE(OFF)
DX_RTF_FEATURE(OFF)
DX_XML_FEATURE(OFF)
DX_PDF_FEATURE(OFF)
DX_PS_FEATURE(OFF)
DX_INIT_DOXYGEN([ModSecurity],[doc/doxygen.cfg])
# make check-valgrind
AX_VALGRIND_DFLT([sgcheck], [off])
AX_VALGRIND_CHECK
# Generate the files.
AC_OUTPUT
# Print a fancy summary
echo " "
echo " "
echo "ModSecurity - ${MSC_GIT_VERSION} for $PLATFORM"
echo " "
echo " Mandatory dependencies"
echo -n " + libInjection ...."
echo LIBINJECTION_VERSION
echo -n " + SecLang tests ...."
echo SECLANG_TEST_VERSION
echo " "
echo " Optional dependencies"
## GeoIP - MaxMind
if test "x$GEOIP_FOUND" = "x0" && test "x$MAXMIND_FOUND" = "x0"; then
echo " + GeoIP/MaxMind ....not found"
fi
if test "x$GEOIP_FOUND" = "x1" || test "x$MAXMIND_FOUND" = "x1"; then
echo -n " + GeoIP/MaxMind ....found "
echo ""
if test "x$MAXMIND_FOUND" = "x1"; then
echo " * (MaxMind) v${MAXMIND_VERSION}"
echo " ${MAXMIND_DISPLAY}"
fi
if test "x$GEOIP_FOUND" = "x1"; then
echo " * (GeoIP) v${GEOIP_VERSION}"
echo " ${GEOIP_DISPLAY}"
fi
fi
if test "x$GEOIP_FOUND" = "x2" && test "x$MAXMIND_FOUND" = "x2"; then
echo " + GeoIP/MaxMind ....disabled"
fi
## LibCurl
if test "x$CURL_FOUND" = "x0"; then
echo " + LibCURL ....not found"
fi
if test "x$CURL_FOUND" = "x1"; then
echo -n " + LibCURL ....found "
if ! test "x$CURL_VERSION" = "x"; then
echo "v${CURL_VERSION}"
else
echo ""
fi
echo " ${CURL_DISPLAY}"
fi
if test "x$CURL_FOUND" = "x2"; then
echo " + LibCURL ....disabled"
fi
## YAJL
if test "x$YAJL_FOUND" = "x0"; then
echo " + YAJL ....not found"
fi
if test "x$YAJL_FOUND" = "x1"; then
echo -n " + YAJL ....found "
if ! test "x$YAJL_VERSION" = "x"; then
echo "v${YAJL_VERSION}"
else
echo ""
fi
echo " ${YAJL_DISPLAY}"
fi
if test "x$YAJL_FOUND" = "x2"; then
echo " + YAJL ....disabled"
fi
## LMDB
if test "x$LMDB_FOUND" = "x0"; then
echo " + LMDB ....not found"
fi
if test "x$LMDB_FOUND" = "x1"; then
echo -n " + LMDB ....found "
if ! test "x$LMDB_VERSION" = "x"; then
echo "v${LMDB_VERSION}"
else
echo ""
fi
echo " ${LMDB_DISPLAY}"
fi
if test "x$LMDB_FOUND" = "x2"; then
echo " + LMDB ....disabled"
fi
## libxml2
if test "x$LIBXML2_FOUND" = "x0"; then
echo " + LibXML2 ....not found"
fi
if test "x$LIBXML2_FOUND" = "x1"; then
echo -n " + LibXML2 ....found "
if ! test "x$LIBXML2_VERSION" = "x"; then
echo "v${LIBXML2_VERSION}"
else
echo ""
fi
echo " ${LIBXML2_DISPLAY}"
fi
if test "x$LIBXML2_FOUND" = "x2"; then
echo " + LibXML2 ....disabled"
fi
## SSDEEP
if test "x$SSDEEP_FOUND" = "x0"; then
echo " + SSDEEP ....not found"
fi
if test "x$SSDEEP_FOUND" = "x1"; then
echo -n " + SSDEEP ....found "
if ! test "x$SSDEEP_VERSION" = "x"; then
echo "v${SSDEEP_VERSION}"
else
echo ""
fi
echo " ${SSDEEP_DISPLAY}"
fi
if test "x$SSDEEP_FOUND" = "x2"; then
echo " + SSDEEP ....disabled"
fi
## LUA
if test "x$LUA_FOUND" = "x0"; then
echo " + LUA ....not found"
fi
if test "x$LUA_FOUND" = "x1"; then
echo -n " + LUA ....found "
if ! test "x$LUA_VERSION" = "x"; then
echo "v${LUA_VERSION}"
else
echo ""
fi
echo " ${LUA_DISPLAY}"
fi
if test "x$LUA_FOUND" = "x2"; then
echo " + LUA ....disabled"
fi
## PCRE2
if test "x$PCRE2_FOUND" = "x0"; then
echo " + PCRE2 ....not found"
fi
if test "x$PCRE2_FOUND" = "x1"; then
echo -n " + PCRE2 ....found "
if ! test "x$PCRE2_VERSION" = "x"; then
echo "v${PCRE2_VERSION}"
else
echo ""
fi
echo " ${PCRE2_DISPLAY}"
fi
if test "x$PCRE2_FOUND" = "x2"; then
echo " + PCRE2 ....disabled"
fi
echo " "
echo " Other Options"
if test $buildTestUtilities = true; then
if test $debugLogs = true; then
echo " + Test Utilities ....enabled"
else
echo " + Test Utilities ....partially"
fi
else
echo " + Test Utilities ....disabled"
fi
if test $debugLogs = true; then
echo " + SecDebugLog ....enabled"
else
echo " + SecDebugLog ....disabled"
fi
if test "$aflFuzzer" = "true"; then
echo " + afl fuzzer ....enabled"
echo " ($FUZZ_CPPCFLAGS)"
else
echo " + afl fuzzer ....disabled"
fi
if test "$buildExamples" = "true"; then
echo " + library examples ....enabled"
else
echo " + library examples ....disabled"
fi
if test "$buildParser" = "true"; then
echo " + Building parser ....enabled"
else
echo " + Building parser ....disabled"
fi
if test "$mutexPm" = "true"; then
echo " + Treating pm operations as critical section ....enabled"
else
echo " + Treating pm operations as critical section ....disabled"
fi
echo " "
if test "$aflFuzzer" = "true"; then
echo "WARNING: afl fuzzer was enabled. Make sure you are using the"
echo " 'afl-clang-fast' as the compiler, otherwise the compilation"
echo " will fail."
echo " "
echo " You can set the compiler using:"
echo " "
echo " $ export CXX=afl-clang-fast++ "
echo " $ export CC=afl-clang-fast "
echo " "
fi

View File

View File

@ -0,0 +1,17 @@
ACLOCAL_AMFLAGS = -I build
# Doxygen support
# include $(top_srcdir)/build/ax_prog_doxygen.m4
# distribution of the Doxygen configuration file
EXTRA_DIST = \
doxygen.cfg
MAINTAINERCLEANFILES = \
Makefile.in \
doxygen_sqlite3.db \
html \
latex

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

View File

@ -0,0 +1,21 @@
ACLOCAL_AMFLAGS = -I build
SUBDIRS = \
multiprocess_c \
reading_logs_with_offset \
reading_logs_via_rule_message \
simple_example_using_c \
using_bodies_in_chunks
pkginclude_HEADERS = \
reading_logs_via_rule_message/reading_logs_via_rule_message.h
# make clean
CLEANFILES =
# make maintainer-clean
MAINTAINERCLEANFILES = \
Makefile.in

View File

@ -0,0 +1,34 @@
noinst_PROGRAMS = multi
multi_SOURCES = \
multi.c
multi_LDADD = \
$(SSDEEP_LDADD) \
$(LUA_LDADD) \
$(MAXMIND_LDADD) \
$(GLOBAL_LDADD)
multi_LDFLAGS = \
-L$(top_builddir)/src/.libs/ \
$(GEOIP_LDFLAGS) \
-lmodsecurity \
-lpthread \
-lm \
-lstdc++ \
$(LUA_LDFLAGS) \
$(SSDEEP_LDFLAGS) \
$(MAXMIND_LDFLAGS) \
$(YAJL_LDFLAGS)
multi_CFLAGS = \
-I$(top_builddir)/headers \
-I$(top_builddir) \
$(GLOBAL_CFLAGS)
MAINTAINERCLEANFILES = \
Makefile.in

View File

@ -0,0 +1,14 @@
SecDebugLog /dev/stdout
SecDebugLogLevel 9
SecRule REQUEST_HEADERS:User-Agent ".*" "id:1,phase:1,t:sha1,t:hexEncode,setvar:tx.ua_hash=%{MATCHED_VAR}"
SecAction "phase:2,initcol:ip=%{REMOTE_ADDR}_%{tx.ua_hash}"
SecRule REQUEST_HEADERS:User-Agent ".*" "id:2,phase:2,setvar:ip.auth_attempt=+1"
SecRule ARGS:foo "herewego" "id:3,phase:2,setvar:ip.foo=bar"
SecRule IP "bar" "id:4,phase:2"
SecRule IP:auth_attempt "bar" "id:5,phase:2"

View File

@ -0,0 +1,146 @@
/*
* ModSecurity, http://www.modsecurity.org/
* Copyright (c) 2015 - 2021 Trustwave Holdings, Inc. (http://www.trustwave.com/)
*
* You may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* If any of the files related to licensing are missing or if you have any
* other questions related to licensing please contact Trustwave Holdings, Inc.
* directly using the email address security@modsecurity.org.
*
*/
#include <modsecurity/modsecurity.h>
#include <modsecurity/transaction.h>
#include <modsecurity/rules_set.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/time.h>
#define FORKS 5
#define REQUESTS_PER_PROCESS 100
char main_rule_uri[] = "basic_rules.conf";
RulesSet *rules = NULL;
ModSecurity *modsec = NULL;
void process_special_request (int j) {
Transaction *transaction;
transaction = msc_new_transaction(modsec, rules, NULL);
msc_process_connection(transaction, "127.0.0.1", 12345, "127.0.0.1", 80);
msc_process_uri(transaction,
"http://www.modsecurity.org/test?foo=herewego",
"GET", "1.1");
msc_add_request_header(transaction,
(const unsigned char *) "User-Agent",
(const unsigned char *) "Basic ModSecurity example");
msc_process_request_headers(transaction);
msc_process_request_body(transaction);
msc_add_response_header(transaction,
(const unsigned char *) "Content-type",
(const unsigned char *) "text/html");
msc_process_response_headers(transaction, 200, "HTTP 1.0");
msc_process_response_body(transaction);
msc_process_logging(transaction);
msc_transaction_cleanup(transaction);
}
void process_request (int j) {
int i;
for (i = 0; i < REQUESTS_PER_PROCESS; i++) {
if (i == 1 && j == 1) {
process_special_request(j);
continue;
}
struct timeval tv;
Transaction *transaction;
transaction = msc_new_transaction(modsec, rules, NULL);
msc_process_connection(transaction, "127.0.0.1", 12345, "127.0.0.1", 80);
msc_process_uri(transaction,
"http://www.modsecurity.org/test?key1=value1&key2=value2&key3=value3",
"GET", "1.1");
msc_add_request_header(transaction,
(const unsigned char *) "User-Agent",
(const unsigned char *) "Basic ModSecurity example");
msc_process_request_headers(transaction);
msc_process_request_body(transaction);
msc_add_response_header(transaction,
(const unsigned char *) "Content-type",
(const unsigned char *) "text/html");
msc_process_response_headers(transaction, 200, "HTTP 1.0");
msc_process_response_body(transaction);
msc_process_logging(transaction);
msc_transaction_cleanup(transaction);
tv.tv_sec = 1;
tv.tv_usec = 500;
select(0, NULL, NULL, NULL, &tv);
}
}
int main (int argc, char **argv)
{
int ret;
const char *error = NULL;
pid_t pid;
int f;
modsec = msc_init();
msc_set_connector_info(modsec, "ModSecurity-test v0.0.1-alpha (Simple " \
"example on how to use ModSecurity API");
rules = msc_create_rules_set();
ret = msc_rules_add_file(rules, main_rule_uri, &error);
if (ret < 0) {
fprintf(stderr, "Problems loading the rules --\n");
fprintf(stderr, "%s\n", error);
goto end;
}
msc_rules_dump(rules);
for (f = 0; f < FORKS; f++) {
pid = fork();
if (pid == 0) {
process_request(f);
goto child;
}
struct timeval tv;
tv.tv_sec = 0;
tv.tv_usec = 500;
select(0, NULL, NULL, NULL, &tv);
}
wait(NULL);
child:
if (pid == 0) {
return 0;
}
end:
msc_rules_cleanup(rules);
msc_cleanup(modsec);
return 0;
}

View File

@ -0,0 +1,56 @@
noinst_PROGRAMS = simple_request
simple_request_SOURCES = \
simple_request.cc
simple_request_LDADD = \
$(CURL_LDADD) \
$(GEOIP_LDADD) \
$(GLOBAL_LDADD) \
$(LIBXML2_LDADD) \
$(LMDB_LDADD) \
$(MAXMIND_LDADD) \
$(LUA_LDADD) \
$(PCRE_LDADD) \
$(SSDEEP_LDADD) \
$(YAJL_LDADD)
simple_request_LDFLAGS = \
-L$(top_builddir)/src/.libs/ \
$(GEOIP_LDFLAGS) \
-lmodsecurity \
-lpthread \
-lm \
-lstdc++ \
$(LMDB_LDFLAGS) \
$(LUA_LDFLAGS) \
$(MAXMIND_LDFLAGS) \
$(SSDEEP_LDFLAGS) \
$(YAJL_LDFLAGS)
simple_request_CPPFLAGS = \
$(GLOBAL_CFLAGS) \
-std=c++11 \
-I$(top_builddir)/headers \
-I$(top_builddir) \
-g \
-I../others \
-fPIC \
-O3 \
$(CURL_CFLAGS) \
$(GEOIP_CFLAGS) \
$(GLOBAL_CPPFLAGS) \
$(MODSEC_NO_LOGS) \
$(YAJL_CFLAGS) \
$(LMDB_CFLAGS) \
$(LUA_CFLAGS) \
$(PCRE_CFLAGS) \
$(LIBXML2_CFLAGS)
MAINTAINERCLEANFILES = \
Makefile.in

View File

@ -0,0 +1,3 @@
SecRule ARGS:param1 "test" "id:1,deny,phase:2,chain,msg:'test'"
SecRule ARGS:param1 "test" "log"

View File

@ -0,0 +1,2 @@
SecRuleEngine On
SecRule ARGS:param1 "test" "id:1,deny"

View File

@ -0,0 +1 @@
SecRule ARGS:param1 "test" "id:1,deny,msg:'this',msg:'is',msg:'a',msg:'test'"

View File

@ -0,0 +1 @@
SecRule ARGS:param1 "WHEEE" "id:1,phase:2,deny,msg:'this',msg:'is',msg:'a',msg:'test'"

View File

@ -0,0 +1,208 @@
/*
* ModSecurity, http://www.modsecurity.org/
* Copyright (c) 2015 - 2021 Trustwave Holdings, Inc. (http://www.trustwave.com/)
*
* You may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* If any of the files related to licensing are missing or if you have any
* other questions related to licensing please contact Trustwave Holdings, Inc.
* directly using the email address security@modsecurity.org.
*
*/
#include <unistd.h>
#include <string>
#include <memory>
#define NUM_THREADS 100
char request_header[] = "" \
"GET /tutorials/other/top-20-mysql-best-practices/ HTTP/1.1\n\r" \
"Host: net.tutsplus.com\n\r" \
"User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.5)" \
" Gecko/20091102 Firefox/3.5.5 (.NET CLR 3.5.30729)\n\r" \
"Accept: text/html,application/xhtml+xml,application/xml; " \
"q=0.9,*/*;q=0.8\n\r" \
"Accept-Language: en-us,en;q=0.5\n\r" \
"Accept-Encoding: gzip,deflate\n\r" \
"Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7\n\r" \
"Keep-Alive: 300\n\r" \
"Connection: keep-alive\n\r" \
"Cookie: PHPSESSID=r2t5uvjq435r4q7ib3vtdjq120\n\r" \
"Pragma: no-cache\n\r" \
"Cache-Control: no-cache\n\r";
char request_uri[] = "/test.pl?param1=test&para2=test2";
char request_body[] = "";
char response_headers[] = "" \
"HTTP/1.1 200 OK\n\r" \
"Content-Type: text/xml; charset=utf-8\n\r" \
"Content-Length: length\n\r";
char response_body[] = "" \
"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\r" \
"<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" " \
"xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" " \
"xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">\n\r" \
" <soap:Body>\n\r" \
" <EnlightenResponse xmlns=\"http://clearforest.com/\">\n\r" \
" <EnlightenResult>string</EnlightenResult>\n\r" \
" </EnlightenResponse>\n\r" \
" </soap:Body>\n\r" \
"</soap:Envelope>\n\r";
char ip[] = "200.249.12.31";
#include "modsecurity/rule_message.h"
#ifndef EXAMPLES_READING_LOGS_VIA_RULE_MESSAGE_READING_LOGS_VIA_RULE_MESSAGE_H_
#define EXAMPLES_READING_LOGS_VIA_RULE_MESSAGE_READING_LOGS_VIA_RULE_MESSAGE_H_
struct data_ms {
modsecurity::ModSecurity *modsec;
modsecurity::RulesSet *rules;
};
static void *process_request(void *data) {
struct data_ms *a = (struct data_ms *)data;
modsecurity::ModSecurity *modsec = a->modsec;
modsecurity::RulesSet *rules = a->rules;
int z = 0;
for (z = 0; z < 10000; z++) {
modsecurity::Transaction *modsecTransaction = \
new modsecurity::Transaction(modsec, rules, NULL);
modsecTransaction->processConnection(ip, 12345, "127.0.0.1", 80);
modsecTransaction->processURI(request_uri, "GET", "1.1");
usleep(10);
modsecTransaction->addRequestHeader("Host",
"net.tutsplus.com");
modsecTransaction->processRequestHeaders();
modsecTransaction->processRequestBody();
modsecTransaction->addResponseHeader("HTTP/1.1",
"200 OK");
modsecTransaction->processResponseHeaders(200, "HTTP 1.2");
modsecTransaction->appendResponseBody(
(const unsigned char*)response_body,
strlen((const char*)response_body));
modsecTransaction->processResponseBody();
modsecTransaction->processLogging();
delete modsecTransaction;
}
pthread_exit(NULL);
return NULL;
}
class ReadingLogsViaRuleMessage {
public:
ReadingLogsViaRuleMessage(char *request_header,
char *request_uri,
char *request_body,
char *response_headers,
char *response_body,
char *ip,
const std::string &rules) :
m_request_header(request_header),
m_request_uri(request_uri),
m_request_body(request_body),
m_response_headers(response_headers),
m_response_body(response_body),
m_ip(ip),
m_rules(rules)
{ }
int process() {
pthread_t threads[NUM_THREADS];
int i;
struct data_ms dms;
void *status;
modsecurity::ModSecurity *modsec;
modsecurity::RulesSet *rules;
modsec = new modsecurity::ModSecurity();
modsec->setConnectorInformation("ModSecurity-test v0.0.1-alpha" \
" (ModSecurity test)");
modsec->setServerLogCb(logCb, modsecurity::RuleMessageLogProperty
| modsecurity::IncludeFullHighlightLogProperty);
rules = new modsecurity::RulesSet();
if (rules->loadFromUri(m_rules.c_str()) < 0) {
std::cout << "Problems loading the rules..." << std::endl;
std::cout << rules->m_parserError.str() << std::endl;
return -1;
}
dms.modsec = modsec;
dms.rules = rules;
for (i = 0; i < NUM_THREADS; i++) {
pthread_create(&threads[i], NULL, process_request,
reinterpret_cast<void *>(&dms));
// process_request((void *)&dms);
}
usleep(10000);
for (i=0; i < NUM_THREADS; i++) {
pthread_join(threads[i], &status);
std::cout << "Main: completed thread id :" << i << std::endl;
}
delete rules;
delete modsec;
pthread_exit(NULL);
return 0;
}
static void logCb(void *data, const void *ruleMessagev) {
if (ruleMessagev == NULL) {
std::cout << "I've got a call but the message was null ;(";
std::cout << std::endl;
return;
}
const modsecurity::RuleMessage *ruleMessage = \
reinterpret_cast<const modsecurity::RuleMessage *>(ruleMessagev);
std::cout << "Rule Id: " << std::to_string(ruleMessage->m_ruleId);
std::cout << " phase: " << std::to_string(ruleMessage->m_phase);
std::cout << std::endl;
if (ruleMessage->m_isDisruptive) {
std::cout << " * Disruptive action: ";
std::cout << modsecurity::RuleMessage::log(ruleMessage);
std::cout << std::endl;
std::cout << " ** %d is meant to be informed by the webserver.";
std::cout << std::endl;
} else {
std::cout << " * Match, but no disruptive action: ";
std::cout << modsecurity::RuleMessage::log(ruleMessage);
std::cout << std::endl;
}
}
protected:
char *m_request_header;
char *m_request_uri;
char *m_request_body;
char *m_response_headers;
char *m_response_body;
char *m_ip;
std::string m_rules;
};
#endif // EXAMPLES_READING_LOGS_VIA_RULE_MESSAGE_READING_LOGS_VIA_RULE_MESSAGE_H_

View File

@ -0,0 +1,42 @@
/*
* ModSecurity, http://www.modsecurity.org/
* Copyright (c) 2015 - 2021 Trustwave Holdings, Inc. (http://www.trustwave.com/)
*
* You may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* If any of the files related to licensing are missing or if you have any
* other questions related to licensing please contact Trustwave Holdings, Inc.
* directly using the email address security@modsecurity.org.
*
*/
#include <stdio.h>
#include <string.h>
#include <modsecurity/modsecurity.h>
#include <modsecurity/rules_set.h>
#include "examples/reading_logs_via_rule_message/reading_logs_via_rule_message.h"
int main(int argc, char **argv) {
if (argc < 2) {
std::cout << "Use " << *argv << " test-case-file.conf";
std::cout << std::endl << std::endl;
return -1;
}
char *rule = *(++argv);
std::string rules(rule);
ReadingLogsViaRuleMessage rlvrm(request_header, request_uri, request_body,
response_headers, response_body, ip, rules);
rlvrm.process();
pthread_exit(NULL);
return 0;
}

View File

@ -0,0 +1,57 @@
noinst_PROGRAMS = read
read_SOURCES = \
read.cc
read_LDADD = \
$(CURL_LDADD) \
$(GEOIP_LDADD) \
$(MAXMIND_LDADD) \
$(GLOBAL_LDADD) \
$(LIBXML2_LDADD) \
$(LMDB_LDADD) \
$(LUA_LDADD) \
$(PCRE_LDADD) \
$(SSDEEP_LDADD) \
$(YAJL_LDADD)
read_LDFLAGS = \
-L$(top_builddir)/src/.libs/ \
$(GEOIP_LDFLAGS) \
-lmodsecurity \
-lpthread \
-lm \
-lstdc++ \
$(LMDB_LDFLAGS) \
$(LUA_LDFLAGS) \
$(SSDEEP_LDFLAGS) \
$(MAXMIND_LDFLAGS) \
$(YAJL_LDFLAGS)
read_CPPFLAGS = \
$(GLOBAL_CFLAGS) \
-std=c++11 \
-I$(top_builddir)/headers \
-I$(top_builddir) \
-g \
-I../others \
-fPIC \
-O3 \
$(CURL_CFLAGS) \
$(GEOIP_CFLAGS) \
$(MAXMIND_CFLAGS) \
$(GLOBAL_CPPFLAGS) \
$(MODSEC_NO_LOGS) \
$(YAJL_CFLAGS) \
$(LMDB_CFLAGS) \
$(LUA_CFLAGS) \
$(PCRE_CFLAGS) \
$(LIBXML2_CFLAGS)
MAINTAINERCLEANFILES = \
Makefile.in

View File

@ -0,0 +1,34 @@
#include <stdio.h>
#include <string.h>
#include <modsecurity/modsecurity.h>
// Variable offset - REQUEST_HEADERS_NAMES
const char *request = "" \
"GET /index.html?param1=value1&param2=value1&param3=value1 HTTP/\n" \
"AuThOrIzAtIoN: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==\n" \
"Host: localhost\n" \
"Content-Length: 27\n" \
"Content-Type: application/x-www-form-urlencoded\n";
int main() {
modsecurity::ModSecurity msc;
std::string json("");
const char *err = NULL;
int ret = 0;
ret = msc.processContentOffset(request, strlen(request),
"o0,4v64,13v114,4v130,14v149,12t:lowercase", &json, &err);
if (ret >= 0) {
std::cout << json << std::endl;
} else {
std::cout << err << std::endl;
}
return ret;
}

View File

@ -0,0 +1,31 @@
noinst_PROGRAMS = test
test_SOURCES = \
test.c
test_LDADD = \
$(GLOBAL_LDADD) \
$(LUA_LDADD) \
$(SSDEEP_LDADD)
test_LDFLAGS = \
-L$(top_builddir)/src/.libs/ \
$(GEOIP_LDFLAGS) \
-lmodsecurity \
-lm \
-lstdc++ \
$(LUA_LDFLAGS) \
$(SSDEEP_LDFLAGS) \
$(YAJL_LDFLAGS)
test_CFLAGS = \
-I$(top_builddir)/headers \
-I$(top_builddir) \
$(GLOBAL_CFLAGS)
MAINTAINERCLEANFILES = \
Makefile.in

View File

@ -0,0 +1,223 @@
# -- Rule engine initialization ----------------------------------------------
# Enable ModSecurity, attaching it to every transaction. Use detection
# only to start with, because that minimises the chances of post-installation
# disruption.
#
SecRuleEngine DetectionOnly
# -- Request body handling ---------------------------------------------------
# Allow ModSecurity to access request bodies. If you don't, ModSecurity
# won't be able to see any POST parameters, which opens a large security
# hole for attackers to exploit.
#
SecRequestBodyAccess On
# Enable XML request body parser.
# Initiate XML Processor in case of xml content-type
#
SecRule REQUEST_HEADERS:Content-Type "text/xml" \
"id:'200000',phase:1,t:none,t:lowercase,pass,nolog,ctl:requestBodyProcessor=XML"
# Enable JSON request body parser.
# Initiate JSON Processor in case of JSON content-type; change accordingly
# if your application does not use 'application/json'
#
SecRule REQUEST_HEADERS:Content-Type "application/json" \
"id:'200001',phase:1,t:none,t:lowercase,pass,nolog,ctl:requestBodyProcessor=JSON"
# Maximum request body size we will accept for buffering. If you support
# file uploads then the value given on the first line has to be as large
# as the largest file you are willing to accept. The second value refers
# to the size of data, with files excluded. You want to keep that value as
# low as practical.
#
# Store up to 128 KB of request body data in memory. When the multipart
# parser reachers this limit, it will start using your hard disk for
# storage. That is slow, but unavoidable.
#
# What do do if the request body size is above our configured limit.
# Keep in mind that this setting will automatically be set to ProcessPartial
# when SecRuleEngine is set to DetectionOnly mode in order to minimize
# disruptions when initially deploying ModSecurity.
#
SecRequestBodyLimitAction Reject
# Verify that we've correctly processed the request body.
# As a rule of thumb, when failing to process a request body
# you should reject the request (when deployed in blocking mode)
# or log a high-severity alert (when deployed in detection-only mode).
#
SecRule REQBODY_ERROR "!@eq 0" \
"id:'200002', phase:2,t:none,log,deny,status:400,msg:'Failed to parse request body.',logdata:'%{reqbody_error_msg}',severity:2"
# By default be strict with what we accept in the multipart/form-data
# request body. If the rule below proves to be too strict for your
# environment consider changing it to detection-only. You are encouraged
# _not_ to remove it altogether.
#
SecRule MULTIPART_STRICT_ERROR "!@eq 0" \
"id:'200003',phase:2,t:none,log,deny,status:400, \
msg:'Multipart request body failed strict validation: \
PE %{REQBODY_PROCESSOR_ERROR}, \
BQ %{MULTIPART_BOUNDARY_QUOTED}, \
BW %{MULTIPART_BOUNDARY_WHITESPACE}, \
DB %{MULTIPART_DATA_BEFORE}, \
DA %{MULTIPART_DATA_AFTER}, \
HF %{MULTIPART_HEADER_FOLDING}, \
LF %{MULTIPART_LF_LINE}, \
SM %{MULTIPART_MISSING_SEMICOLON}, \
IQ %{MULTIPART_INVALID_QUOTING}, \
IP %{MULTIPART_INVALID_PART}, \
IH %{MULTIPART_INVALID_HEADER_FOLDING}, \
FL %{MULTIPART_FILE_LIMIT_EXCEEDED}'"
# Did we see anything that might be a boundary?
#
SecRule MULTIPART_UNMATCHED_BOUNDARY "!@eq 0" \
"id:'200004',phase:2,t:none,log,deny,msg:'Multipart parser detected a possible unmatched boundary.'"
# PCRE Tuning
# We want to avoid a potential RegEx DoS condition
#
SecPcreMatchLimit 1000
SecPcreMatchLimitRecursion 1000
# Some internal errors will set flags in TX and we will need to look for these.
# All of these are prefixed with "MSC_". The following flags currently exist:
#
# MSC_PCRE_LIMITS_EXCEEDED: PCRE match limits were exceeded.
#
SecRule TX:/^MSC_/ "!@streq 0" \
"id:'200005',phase:2,t:none,deny,msg:'ModSecurity internal error flagged: %{MATCHED_VAR_NAME}'"
# -- Response body handling --------------------------------------------------
# Allow ModSecurity to access response bodies.
# You should have this directive enabled in order to identify errors
# and data leakage issues.
#
# Do keep in mind that enabling this directive does increases both
# memory consumption and response latency.
#
SecResponseBodyAccess On
# Which response MIME types do you want to inspect? You should adjust the
# configuration below to catch documents but avoid static files
# (e.g., images and archives).
#
SecResponseBodyMimeType text/plain text/html text/xml
# Buffer response bodies of up to 512 KB in length.
SecResponseBodyLimit 524288
# What happens when we encounter a response body larger than the configured
# limit? By default, we process what we have and let the rest through.
# That's somewhat less secure, but does not break any legitimate pages.
#
SecResponseBodyLimitAction ProcessPartial
# -- Filesystem configuration ------------------------------------------------
# The location where ModSecurity stores temporary files (for example, when
# it needs to handle a file upload that is larger than the configured limit).
#
# This default setting is chosen due to all systems have /tmp available however,
# this is less than ideal. It is recommended that you specify a location that's private.
#
SecTmpDir /tmp/
# The location where ModSecurity will keep its persistent data. This default setting
# is chosen due to all systems have /tmp available however, it
# too should be updated to a place that other users can't access.
#
SecDataDir /tmp/
# -- File uploads handling configuration -------------------------------------
# The location where ModSecurity stores intercepted uploaded files. This
# location must be private to ModSecurity. You don't want other users on
# the server to access the files, do you?
#
#SecUploadDir /opt/modsecurity/var/upload/
# By default, only keep the files that were determined to be unusual
# in some way (by an external inspection script). For this to work you
# will also need at least one file inspection rule.
#
#SecUploadKeepFiles RelevantOnly
# Uploaded files are by default created with permissions that do not allow
# any other user to access them. You may need to relax that if you want to
# interface ModSecurity to an external program (e.g., an anti-virus).
#
#SecUploadFileMode 0600
# -- Debug log configuration -------------------------------------------------
# The default debug log configuration is to duplicate the error, warning
# and notice messages from the error log.
#
#SecDebugLog /opt/modsecurity/var/log/debug.log
#SecDebugLogLevel 3
# -- Audit log configuration -------------------------------------------------
# Log the transactions that are marked by a rule, as well as those that
# trigger a server error (determined by a 5xx or 4xx, excluding 404,
# level response status codes).
#
SecAuditEngine RelevantOnly
SecAuditLogRelevantStatus "^(?:5|4(?!04))"
# Log everything we know about a transaction.
SecAuditLogParts ABIJDEFHZ
# Use a single file for logging. This is much easier to look at, but
# assumes that you will use the audit log only ocassionally.
#
SecAuditLogType Serial
SecAuditLog /var/log/modsec_audit.log
# Specify the path for concurrent audit logging.
#SecAuditLogStorageDir /opt/modsecurity/var/audit/
# -- Miscellaneous -----------------------------------------------------------
# Use the most commonly used application/x-www-form-urlencoded parameter
# separator. There's probably only one application somewhere that uses
# something else so don't expect to change this value.
#
SecArgumentSeparator &
# Settle on version 0 (zero) cookies, as that is what most applications
# use. Using an incorrect cookie version may open your installation to
# evasion attacks (against the rules that examine named cookies).
#
SecCookieFormat 0
# Specify your Unicode Code Point.
# This mapping is used by the t:urlDecodeUni transformation function
# to properly map encoded data to your language. Properly setting
# these directives helps to reduce false positives and negatives.
#
SecUnicodeMapFile unicode.mapping 20127
# Improve the quality of ModSecurity by sharing information about your
# current ModSecurity version and dependencies versions.
# The following information will be shared: ModSecurity version,
# Web Server version, APR version, PCRE version, Lua version, Libxml2
# version, Anonymous unique id for host.
SecStatusEngine On

View File

@ -0,0 +1,4 @@
#!/usr/bin/env bash
valgrind --tool=massif
valgrind --show-leak-kinds=all --leak-check=full ./test

View File

@ -0,0 +1,77 @@
/*
* ModSecurity, http://www.modsecurity.org/
* Copyright (c) 2015 - 2021 Trustwave Holdings, Inc. (http://www.trustwave.com/)
*
* You may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* If any of the files related to licensing are missing or if you have any
* other questions related to licensing please contact Trustwave Holdings, Inc.
* directly using the email address security@modsecurity.org.
*
*/
#include <stdio.h>
#include <stdlib.h>
#include "modsecurity/modsecurity.h"
#include "modsecurity/rules_set.h"
char main_rule_uri[] = "basic_rules.conf";
int main (int argc, char **argv)
{
int ret;
const char *error = NULL;
ModSecurity *modsec;
Transaction *transaction = NULL;
RulesSet *rules;
modsec = msc_init();
msc_set_connector_info(modsec, "ModSecurity-test v0.0.1-alpha (Simple " \
"example on how to use ModSecurity API");
rules = msc_create_rules_set();
ret = msc_rules_add_file(rules, main_rule_uri, &error);
if (ret < 0) {
fprintf(stderr, "Problems loading the rules --\n");
fprintf(stderr, "%s\n", error);
goto end;
}
msc_rules_dump(rules);
ret = msc_rules_add_remote(rules, "test",
"https://www.modsecurity.org/modsecurity-regression-test-secremoterules.txt",
&error);
if (ret < 0) {
fprintf(stderr, "Problems loading the rules --\n");
fprintf(stderr, "%s\n", error);
goto end;
}
msc_rules_dump(rules);
transaction = msc_new_transaction(modsec, rules, NULL);
msc_process_connection(transaction, "127.0.0.1", 12345, "127.0.0.1", 80);
msc_process_uri(transaction,
"http://www.modsecurity.org/test?key1=value1&key2=value2&key3=value3",
"GET", "1.1");
msc_process_request_headers(transaction);
msc_process_request_body(transaction);
msc_process_response_headers(transaction, 200, "HTTP 1.3");
msc_process_response_body(transaction);
msc_process_logging(transaction);
end:
msc_rules_cleanup(rules);
msc_cleanup(modsec);
return 0;
}

View File

@ -0,0 +1,57 @@
noinst_PROGRAMS = simple_request
simple_request_SOURCES = \
simple_request.cc
simple_request_LDADD = \
$(CURL_LDADD) \
$(GEOIP_LDADD) \
$(MAXMIND_LDADD) \
$(GLOBAL_LDADD) \
$(LIBXML2_LDADD) \
$(LMDB_LDADD) \
$(LUA_LDADD) \
$(PCRE_LDADD) \
$(SSDEEP_LDADD) \
$(YAJL_LDADD)
simple_request_LDFLAGS = \
-L$(top_builddir)/src/.libs/ \
$(GEOIP_LDFLAGS) \
-lmodsecurity \
-lpthread \
-lm \
-lstdc++ \
$(MAXMIND_LDFLAGS) \
$(LMDB_LDFLAGS) \
-lpthread \
$(LUA_LDFLAGS) \
$(SSDEEP_LDFLAGS) \
$(YAJL_LDFLAGS)
simple_request_CPPFLAGS = \
$(GLOBAL_CFLAGS) \
-std=c++11 \
-I$(top_builddir)/headers \
-I$(top_builddir) \
-g \
-I../others \
-fPIC \
-O3 \
$(GEOIP_CFLAGS) \
$(CURL_CFLAGS) \
$(MAXMIND_CFLAGS) \
$(GLOBAL_CPPFLAGS) \
$(MODSEC_NO_LOGS) \
$(YAJL_CFLAGS) \
$(LMDB_CFLAGS) \
$(LUA_CFLAGS) \
$(PCRE_CFLAGS) \
$(LIBXML2_CFLAGS)
MAINTAINERCLEANFILES = \
Makefile.in

View File

@ -0,0 +1,3 @@
SecDebugLog /dev/stdout
SecDebugLogLevel 9
SecRule RESPONSE_BODY "/soap:Body" "id:1,phase:5,deny"

View File

@ -0,0 +1,278 @@
/*
* ModSecurity, http://www.modsecurity.org/
* Copyright (c) 2015 - 2021 Trustwave Holdings, Inc. (http://www.trustwave.com/)
*
* You may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* If any of the files related to licensing are missing or if you have any
* other questions related to licensing please contact Trustwave Holdings, Inc.
* directly using the email address security@modsecurity.org.
*
*/
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <modsecurity/modsecurity.h>
#include <modsecurity/rules_set.h>
#include <modsecurity/rule_message.h>
#include <string>
#include <memory>
char request_uri[] = "/test.pl?param1=test&para2=test2";
char request_body_first[] = "" \
"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\r" \
"<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" " \
"xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" ";
char request_body_second[] = "" \
"xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">\n\r" \
" <soap:Body>\n\r" \
" <EnlightenResponse xmlns=\"http://clearforest.com/\">\n\r" \
" <EnlightenResult>string</EnlightenResult>\n\r";
char request_body_third[] = "" \
" </EnlightenResponse>\n\r" \
" </soap:Body>\n\r" \
"</soap:Envelope>\n\r";
char response_body_first[] = "" \
"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\r" \
"<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" " \
"xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" ";
char response_body_second[] = "" \
"xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">\n\r" \
" <soap:Body>\n\r" \
" <EnlightenResponse xmlns=\"http://clearforest.com/\">\n\r" \
" <EnlightenResult>string</EnlightenResult>\n\r";
char response_body_third[] = "" \
" </EnlightenResponse>\n\r" \
" </soap:Body>\n\r" \
"</soap:Envelope>\n\r";
char ip[] = "200.249.12.31";
static void logCb(void *data, const void *ruleMessagev) {
if (ruleMessagev == NULL) {
std::cout << "I've got a call but the message was null ;(";
std::cout << std::endl;
return;
}
const modsecurity::RuleMessage *ruleMessage = \
reinterpret_cast<const modsecurity::RuleMessage *>(ruleMessagev);
std::cout << "Rule Id: " << std::to_string(ruleMessage->m_ruleId);
std::cout << " phase: " << std::to_string(ruleMessage->m_phase);
std::cout << std::endl;
if (ruleMessage->m_isDisruptive) {
std::cout << " * Disruptive action: ";
std::cout << modsecurity::RuleMessage::log(ruleMessage);
std::cout << std::endl;
std::cout << " ** %d is meant to be informed by the webserver.";
std::cout << std::endl;
} else {
std::cout << " * Match, but no disruptive action: ";
std::cout << modsecurity::RuleMessage::log(ruleMessage);
std::cout << std::endl;
}
}
int process_intervention(modsecurity::Transaction *transaction) {
modsecurity::ModSecurityIntervention intervention;
intervention.status = 200;
intervention.url = NULL;
intervention.log = NULL;
intervention.disruptive = 0;
if (msc_intervention(transaction, &intervention) == 0) {
return 0;
}
if (intervention.log == NULL) {
intervention.log = strdup("(no log message was specified)");
}
std::cout << "Log: " << intervention.log << std::endl;
free(intervention.log);
intervention.log = NULL;
if (intervention.url != NULL) {
std::cout << "Intervention, redirect to: " << intervention.url;
std::cout << " with status code: " << intervention.status << std::endl;
free(intervention.url);
intervention.url = NULL;
return intervention.status;
}
if (intervention.status != 200) {
std::cout << "Intervention, returning code: " << intervention.status;
std::cout << std::endl;
return intervention.status;
}
return 0;
}
int main(int argc, char **argv) {
modsecurity::ModSecurity *modsec;
modsecurity::RulesSet *rules;
if (argc < 2) {
std::cout << "Use " << *argv << " test-case-file.conf";
std::cout << std::endl << std::endl;
return -1;
}
char *rule = *(++argv);
std::string rules_arg(rule);
/**
* ModSecurity initial setup
*
*/
modsec = new modsecurity::ModSecurity();
modsec->setConnectorInformation("ModSecurity-test v0.0.1-alpha" \
" (ModSecurity test)");
modsec->setServerLogCb(logCb, modsecurity::RuleMessageLogProperty
| modsecurity::IncludeFullHighlightLogProperty);
/**
* loading the rules....
*
*/
rules = new modsecurity::RulesSet();
if (rules->loadFromUri(rules_arg.c_str()) < 0) {
std::cout << "Problems loading the rules..." << std::endl;
std::cout << rules->m_parserError.str() << std::endl;
return -1;
}
/**
* We are going to have a transaction
*
*/
modsecurity::Transaction *modsecTransaction = \
new modsecurity::Transaction(modsec, rules, NULL);
process_intervention(modsecTransaction);
/**
* Initial connection setup
*
*/
modsecTransaction->processConnection(ip, 12345, "127.0.0.1", 80);
process_intervention(modsecTransaction);
/**
* Finally we've got the URI
*
*/
modsecTransaction->processURI(request_uri, "GET", "1.1");
process_intervention(modsecTransaction);
/**
* Lets add our request headers.
*
*/
modsecTransaction->addRequestHeader("Host",
"net.tutsplus.com");
process_intervention(modsecTransaction);
/**
* No other reuqest header to add, let process it.
*
*/
modsecTransaction->processRequestHeaders();
process_intervention(modsecTransaction);
/**
* There is a request body to be informed...
*
*/
modsecTransaction->appendRequestBody(
(const unsigned char*)request_body_first,
strlen((const char*)request_body_first));
process_intervention(modsecTransaction);
modsecTransaction->appendRequestBody(
(const unsigned char*)request_body_second,
strlen((const char*)request_body_second));
process_intervention(modsecTransaction);
modsecTransaction->appendRequestBody(
(const unsigned char*)request_body_third,
strlen((const char*)request_body_third));
process_intervention(modsecTransaction);
/**
* Request body is there ;) lets process it.
*
*/
modsecTransaction->processRequestBody();
process_intervention(modsecTransaction);
/**
* The webserver is giving back the response headers.
*/
modsecTransaction->addResponseHeader("HTTP/1.1",
"200 OK");
process_intervention(modsecTransaction);
/**
* The response headers are filled in, lets process.
*
*/
modsecTransaction->processResponseHeaders(200, "HTTP 1.2");
process_intervention(modsecTransaction);
/**
* It is time to let modsec aware of the response body
*
*/
modsecTransaction->appendResponseBody(
(const unsigned char*)response_body_first,
strlen((const char*)response_body_first));
process_intervention(modsecTransaction);
modsecTransaction->appendResponseBody(
(const unsigned char*)response_body_second,
strlen((const char*)response_body_second));
process_intervention(modsecTransaction);
modsecTransaction->appendResponseBody(
(const unsigned char*)response_body_third,
strlen((const char*)response_body_third));
process_intervention(modsecTransaction);
/**
* Finally, lets have the response body processed.
*
*/
modsecTransaction->processResponseBody();
process_intervention(modsecTransaction);
/**
* Keeping track of everything: saving the logs.
*
*/
modsecTransaction->processLogging();
process_intervention(modsecTransaction);
/**
* cleanup.
*/
delete modsecTransaction;
delete rules;
delete modsec;
}

View File

@ -0,0 +1,155 @@
/*
* ModSecurity, http://www.modsecurity.org/
* Copyright (c) 2015 - 2021 Trustwave Holdings, Inc. (http://www.trustwave.com/)
*
* You may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* If any of the files related to licensing are missing or if you have any
* other questions related to licensing please contact Trustwave Holdings, Inc.
* directly using the email address security@modsecurity.org.
*
*/
#ifdef __cplusplus
#include <string>
#include <iostream>
#include <memory>
#endif
#include "modsecurity/intervention.h"
#include "modsecurity/rule.h"
#include "modsecurity/rule_with_actions.h"
#ifndef HEADERS_MODSECURITY_ACTIONS_ACTION_H_
#define HEADERS_MODSECURITY_ACTIONS_ACTION_H_
#ifdef __cplusplus
namespace modsecurity {
class Transaction;
class RuleWithOperator;
namespace actions {
class Action {
public:
explicit Action(const std::string& _action)
: m_isNone(false),
temporaryAction(false),
action_kind(2),
m_name(nullptr),
m_parser_payload("") {
set_name_and_payload(_action);
}
explicit Action(const std::string& _action, int kind)
: m_isNone(false),
temporaryAction(false),
action_kind(kind),
m_name(nullptr),
m_parser_payload("") {
set_name_and_payload(_action);
}
Action(const Action &a)
: m_isNone(a.m_isNone),
temporaryAction(a.temporaryAction),
action_kind(a.action_kind),
m_name(a.m_name),
m_parser_payload(a.m_parser_payload) { }
Action &operator=(const Action& a) {
m_isNone = a.m_isNone;
temporaryAction = a.temporaryAction;
action_kind = a.action_kind;
m_name = a.m_name;
m_parser_payload = a.m_parser_payload;
return *this;
}
virtual ~Action() { }
virtual std::string evaluate(const std::string &exp,
Transaction *transaction);
virtual bool evaluate(RuleWithActions *rule, Transaction *transaction);
virtual bool evaluate(RuleWithActions *rule, Transaction *transaction,
std::shared_ptr<RuleMessage> ruleMessage) {
return evaluate(rule, transaction);
}
virtual bool init(std::string *error) { return true; }
virtual bool isDisruptive() { return false; }
void set_name_and_payload(const std::string& data) {
size_t pos = data.find(":");
std::string t = "t:";
if (data.compare(0, t.length(), t) == 0) {
pos = data.find(":", 2);
}
if (pos == std::string::npos) {
m_name = std::shared_ptr<std::string>(new std::string(data));
return;
}
m_name = std::shared_ptr<std::string>(new std::string(data, 0, pos));
m_parser_payload = std::string(data, pos + 1, data.length());
if (m_parser_payload.at(0) == '\'' && m_parser_payload.size() > 2) {
m_parser_payload.erase(0, 1);
m_parser_payload.pop_back();
}
}
bool m_isNone;
bool temporaryAction;
int action_kind;
std::shared_ptr<std::string> m_name;
std::string m_parser_payload;
/**
*
* Define the action kind regarding to the execution time.
*
*
*/
enum Kind {
/**
*
* Action that are executed while loading the configuration. For instance
* the rule ID or the rule phase.
*
*/
ConfigurationKind,
/**
*
* Those are actions that demands to be executed before call the operator.
* For instance the tranformations.
*
*
*/
RunTimeBeforeMatchAttemptKind,
/**
*
* Actions that are executed after the execution of the operator, only if
* the operator returned Match (or True). For instance the disruptive
* actions.
*
*/
RunTimeOnlyIfMatchKind,
};
};
} // namespace actions
} // namespace modsecurity
#endif
#endif // HEADERS_MODSECURITY_ACTIONS_ACTION_H_

View File

@ -0,0 +1,113 @@
/*
* ModSecurity, http://www.modsecurity.org/
* Copyright (c) 2015 - 2021 Trustwave Holdings, Inc. (http://www.trustwave.com/)
*
* You may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* If any of the files related to licensing are missing or if you have any
* other questions related to licensing please contact Trustwave Holdings, Inc.
* directly using the email address security@modsecurity.org.
*
*/
#ifdef __cplusplus
#include <ctime>
#include <fstream>
#include <iomanip>
#include <iostream>
#include <list>
#include <map>
#include <sstream>
#include <string>
#include <unordered_map>
#include <utility>
#include <vector>
#include <algorithm>
#include <memory>
#endif
#include "modsecurity/variable_value.h"
#ifndef HEADERS_MODSECURITY_ANCHORED_SET_VARIABLE_H_
#define HEADERS_MODSECURITY_ANCHORED_SET_VARIABLE_H_
#ifdef __cplusplus
namespace modsecurity {
class Transaction;
namespace Utils {
class Regex;
}
namespace variables {
class KeyExclusions;
}
struct MyEqual {
bool operator()(const std::string& Left, const std::string& Right) const {
return Left.size() == Right.size()
&& std::equal(Left.begin(), Left.end(), Right.begin(),
[](char a, char b) {
return tolower(a) == tolower(b);
});
}
};
struct MyHash{
size_t operator()(const std::string& Keyval) const {
// You might need a better hash function than this
size_t h = 0;
std::for_each(Keyval.begin(), Keyval.end(), [&](char c) {
h += tolower(c);
});
return h;
}
};
class AnchoredSetVariable : public std::unordered_multimap<std::string,
VariableValue *, MyHash, MyEqual> {
public:
AnchoredSetVariable(Transaction *t, const std::string &name);
~AnchoredSetVariable();
void unset();
void set(const std::string &key, const std::string &value,
size_t offset);
void set(const std::string &key, const std::string &value,
size_t offset, size_t len);
void setCopy(std::string key, std::string value, size_t offset);
void resolve(std::vector<const VariableValue *> *l);
void resolve(std::vector<const VariableValue *> *l,
variables::KeyExclusions &ke);
void resolve(const std::string &key,
std::vector<const VariableValue *> *l);
void resolveRegularExpression(Utils::Regex *r,
std::vector<const VariableValue *> *l);
void resolveRegularExpression(Utils::Regex *r,
std::vector<const VariableValue *> *l,
variables::KeyExclusions &ke);
std::unique_ptr<std::string> resolveFirst(const std::string &key);
Transaction *m_transaction;
std::string m_name;
};
} // namespace modsecurity
#endif
#endif // HEADERS_MODSECURITY_ANCHORED_SET_VARIABLE_H_

View File

@ -0,0 +1,126 @@
/*
* ModSecurity, http://www.modsecurity.org/
* Copyright (c) 2015 - 2021 Trustwave Holdings, Inc. (http://www.trustwave.com/)
*
* You may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* If any of the files related to licensing are missing or if you have any
* other questions related to licensing please contact Trustwave Holdings, Inc.
* directly using the email address security@modsecurity.org.
*
*/
#ifdef __cplusplus
#include <string>
#include <algorithm>
#include <memory>
#include <functional>
#include <iostream>
#endif
#include "modsecurity/variable_value.h"
#include "modsecurity/anchored_set_variable.h"
#ifndef HEADERS_MODSECURITY_ANCHORED_SET_VARIABLE_TRANSLATION_PROXY_H_
#define HEADERS_MODSECURITY_ANCHORED_SET_VARIABLE_TRANSLATION_PROXY_H_
#ifdef __cplusplus
namespace modsecurity {
class AnchoredSetVariableTranslationProxy {
public:
AnchoredSetVariableTranslationProxy(
const std::string &name,
AnchoredSetVariable *fount)
: m_name(name),
m_fount(fount)
{
m_translate = [](std::string *name, std::vector<const VariableValue *> *l) {
for (int i = 0; i < l->size(); ++i) {
VariableValue *newVariableValue = new VariableValue(name, &l->at(i)->getKey(), &l->at(i)->getKey());
const VariableValue *oldVariableValue = l->at(i);
l->at(i) = newVariableValue;
for (auto &oldOrigin : oldVariableValue->getOrigin()) {
std::unique_ptr<VariableOrigin> newOrigin(new VariableOrigin);
newOrigin->m_length = oldVariableValue->getKey().size();
newOrigin->m_offset = oldOrigin->m_offset - oldVariableValue->getKey().size() - 1;
newVariableValue->addOrigin(std::move(newOrigin));
}
delete oldVariableValue;
}
};
}
virtual ~AnchoredSetVariableTranslationProxy()
{ }
void resolve(std::vector<const VariableValue *> *l) {
m_fount->resolve(l);
m_translate(&m_name, l);
}
void resolve(std::vector<const VariableValue *> *l,
variables::KeyExclusions &ke) {
m_fount->resolve(l, ke);
m_translate(&m_name, l);
}
void resolve(const std::string &key,
std::vector<const VariableValue *> *l) {
m_fount->resolve(key, l);
m_translate(&m_name, l);
};
void resolveRegularExpression(Utils::Regex *r,
std::vector<const VariableValue *> *l) {
m_fount->resolveRegularExpression(r, l);
m_translate(&m_name, l);
};
void resolveRegularExpression(Utils::Regex *r,
std::vector<const VariableValue *> *l,
variables::KeyExclusions &ke) {
m_fount->resolveRegularExpression(r, l, ke);
m_translate(&m_name, l);
};
std::unique_ptr<std::string> resolveFirst(const std::string &key) {
std::vector<const VariableValue *> l;
resolve(&l);
if (l.empty()) {
return nullptr;
}
std::unique_ptr<std::string> ret(new std::string(""));
ret->assign(l.at(0)->getValue());
while (!l.empty()) {
auto &a = l.back();
l.pop_back();
delete a;
}
return ret;
}
std::string m_name;
private:
AnchoredSetVariable *m_fount;
std::function<void(std::string *name, std::vector<const VariableValue *> *l)> m_translate;
};
} // namespace modsecurity
#endif
#endif // HEADERS_MODSECURITY_ANCHORED_SET_VARIABLE_TRANSLATION_PROXY_H_

View File

@ -0,0 +1,87 @@
/*
* ModSecurity, http://www.modsecurity.org/
* Copyright (c) 2015 - 2021 Trustwave Holdings, Inc. (http://www.trustwave.com/)
*
* You may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* If any of the files related to licensing are missing or if you have any
* other questions related to licensing please contact Trustwave Holdings, Inc.
* directly using the email address security@modsecurity.org.
*
*/
#ifdef __cplusplus
#include <ctime>
#include <fstream>
#include <iomanip>
#include <iostream>
#include <list>
#include <map>
#include <sstream>
#include <string>
#include <unordered_map>
#include <utility>
#include <vector>
#include <memory>
#endif
#include "modsecurity/variable_value.h"
#ifndef HEADERS_MODSECURITY_ANCHORED_VARIABLE_H_
#define HEADERS_MODSECURITY_ANCHORED_VARIABLE_H_
#ifdef __cplusplus
namespace modsecurity {
class Transaction;
class AnchoredVariable {
public:
AnchoredVariable(Transaction* t, const std::string &name);
AnchoredVariable(const AnchoredVariable &a) = delete;
AnchoredVariable &operator= (const AnchoredVariable &a) = delete;
/*
: m_transaction(a.m_transaction),
m_offset(a.m_offset),
m_name(a.m_name),
m_value(a.m_value),
m_var(a.m_var) { }
*/
~AnchoredVariable();
void unset();
void set(const std::string &a, size_t offset);
void set(const std::string &a, size_t offset, size_t offsetLen);
void append(const std::string &a, size_t offset,
bool spaceSeparator = false);
void append(const std::string &a, size_t offset,
bool spaceSeparator, int size);
void evaluate(std::vector<const VariableValue *> *l);
std::string * evaluate();
std::unique_ptr<std::string> resolveFirst();
Transaction *m_transaction;
int m_offset;
std::string m_name;
std::string m_value;
private:
VariableValue *m_var;
};
} // namespace modsecurity
#endif
#endif // HEADERS_MODSECURITY_ANCHORED_VARIABLE_H_

View File

@ -0,0 +1,217 @@
/*
* ModSecurity, http://www.modsecurity.org/
* Copyright (c) 2015 - 2021 Trustwave Holdings, Inc. (http://www.trustwave.com/)
*
* You may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* If any of the files related to licensing are missing or if you have any
* other questions related to licensing please contact Trustwave Holdings, Inc.
* directly using the email address security@modsecurity.org.
*
*/
#ifdef __cplusplus
#include <iostream>
#include <fstream>
#include <string>
#endif
#ifndef HEADERS_MODSECURITY_AUDIT_LOG_H_
#define HEADERS_MODSECURITY_AUDIT_LOG_H_
#ifdef __cplusplus
namespace modsecurity {
class Transaction;
namespace audit_log {
namespace writer {
class Writer;
}
/** @ingroup ModSecurity_CPP_API */
class AuditLog {
public:
AuditLog();
virtual ~AuditLog();
AuditLog(const AuditLog &a) = delete;
enum AuditLogType {
NotSetAuditLogType,
SerialAuditLogType,
ParallelAuditLogType,
HttpsAuditLogType
};
enum AuditLogStatus {
NotSetLogStatus,
OnAuditLogStatus,
OffAuditLogStatus,
RelevantOnlyAuditLogStatus
};
enum AuditLogFormat {
NotSetAuditLogFormat,
JSONAuditLogFormat,
NativeAuditLogFormat
};
enum AuditLogParts {
/**
* Audit log header (mandatory).
*
*/
AAuditLogPart = 2,
/**
* Request headers.
*
*/
BAuditLogPart = 4,
/**
* Request body (present only if the request body exists and ModSecurity
* is configured to intercept it).
*
*/
CAuditLogPart = 8,
/**
* Reserved for intermediary response headers; not implemented yet.
*
*/
DAuditLogPart = 16,
/**
* Intermediary response body (present only if ModSecurity is configured
* to intercept response bodies, and if the audit log engine is
* configured to record it). Intermediary response body is the same as the
* actual response body unless ModSecurity intercepts the intermediary
* response body, in which case the actual response body will contain the
* error message (either the Apache default error message, or the
* ErrorDocument page).
*
*/
EAuditLogPart = 32,
/**
* Final response headers (excluding the Date and Server headers, which
* are always added by Apache in the late stage of content delivery).
*
*/
FAuditLogPart = 64,
/**
* Reserved for the actual response body; not implemented yet.
*
*/
GAuditLogPart = 128,
/**
* Audit log trailer.
*
*/
HAuditLogPart = 256,
/**
* This part is a replacement for part C. It will log the same data as C
* in all cases except when multipart/form-data encoding in used. In this
* case, it will log a fake application/x-www-form-urlencoded body that
* contains the information about parameters but not about the files. This
* is handy if you dont want to have (often large) files stored in your
* audit logs.
*
*/
IAuditLogPart = 512,
/**
* This part contains information about the files uploaded using
* multipart/form-data encoding.
*/
JAuditLogPart = 1024,
/**
* This part contains a full list of every rule that matched (one per
* line) in the order they were matched. The rules are fully qualified and
* will thus show inherited actions and default operators. Supported as of
* v2.5.0.
*
*/
KAuditLogPart = 2048,
/**
* Final boundary, signifies the end of the entry (mandatory).
*
*/
ZAuditLogPart = 4096
};
bool setStorageDirMode(int permission);
bool setFileMode(int permission);
bool setStatus(AuditLogStatus new_status);
bool setRelevantStatus(const std::basic_string<char>& new_relevant_status);
bool setFilePath1(const std::basic_string<char>& path);
bool setFilePath2(const std::basic_string<char>& path);
bool setStorageDir(const std::basic_string<char>& path);
bool setFormat(AuditLogFormat fmt);
int getDirectoryPermission() const;
int getFilePermission() const;
int getParts() const;
bool setParts(const std::basic_string<char>& new_parts);
bool setType(AuditLogType audit_type);
bool init(std::string *error);
virtual bool close();
bool saveIfRelevant(Transaction *transaction);
bool saveIfRelevant(Transaction *transaction, int parts);
bool isRelevant(int status);
static int addParts(int parts, const std::string& new_parts);
static int removeParts(int parts, const std::string& new_parts);
void setCtlAuditEngineActive() {
m_ctlAuditEngineActive = true;
}
bool merge(AuditLog *from, std::string *error);
std::string m_path1;
std::string m_path2;
std::string m_storage_dir;
AuditLogFormat m_format;
protected:
int m_parts;
int m_defaultParts = AAuditLogPart | BAuditLogPart | CAuditLogPart
| FAuditLogPart | HAuditLogPart | ZAuditLogPart;
int m_filePermission;
int m_defaultFilePermission = 0640;
int m_directoryPermission;
int m_defaultDirectoryPermission = 0750;
private:
AuditLogStatus m_status;
AuditLogType m_type;
std::string m_relevant;
audit_log::writer::Writer *m_writer;
bool m_ctlAuditEngineActive; // rules have at least one action On or RelevantOnly
};
} // namespace audit_log
} // namespace modsecurity
#endif
#endif // HEADERS_MODSECURITY_AUDIT_LOG_H_

View File

@ -0,0 +1,205 @@
/*
* ModSecurity, http://www.modsecurity.org/
* Copyright (c) 2015 - 2021 Trustwave Holdings, Inc. (http://www.trustwave.com/)
*
* You may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* If any of the files related to licensing are missing or if you have any
* other questions related to licensing please contact Trustwave Holdings, Inc.
* directly using the email address security@modsecurity.org.
*
*/
#ifdef __cplusplus
#include <string>
#include <iostream>
#include <unordered_map>
#include <list>
#include <vector>
#include <algorithm>
#include <memory>
#endif
#include "modsecurity/variable_value.h"
#ifndef HEADERS_MODSECURITY_COLLECTION_COLLECTION_H_
#define HEADERS_MODSECURITY_COLLECTION_COLLECTION_H_
#ifndef __cplusplus
typedef struct Variable_t Variables;
#endif
#ifdef __cplusplus
namespace modsecurity {
namespace variables {
class KeyExclusions;
}
namespace collection {
class Collection {
public:
explicit Collection(const std::string &a) : m_name(a) { }
virtual ~Collection() { }
virtual void store(std::string key, std::string value) = 0;
virtual bool storeOrUpdateFirst(const std::string &key,
const std::string &value) = 0;
virtual bool updateFirst(const std::string &key,
const std::string &value) = 0;
virtual void del(const std::string& key) = 0;
virtual std::unique_ptr<std::string> resolveFirst(
const std::string& var) = 0;
virtual void resolveSingleMatch(const std::string& var,
std::vector<const VariableValue *> *l) = 0;
virtual void resolveMultiMatches(const std::string& var,
std::vector<const VariableValue *> *l,
variables::KeyExclusions &ke) = 0;
virtual void resolveRegularExpression(const std::string& var,
std::vector<const VariableValue *> *l,
variables::KeyExclusions &ke) = 0;
/* store */
virtual void store(std::string key, std::string compartment,
std::string value) {
std::string nkey = compartment + "::" + key;
store(nkey, value);
}
virtual void store(std::string key, std::string compartment,
std::string compartment2, std::string value) {
std::string nkey = compartment + "::" + compartment2 + "::" + key;
store(nkey, value);
}
/* storeOrUpdateFirst */
virtual bool storeOrUpdateFirst(const std::string &key,
std::string compartment, const std::string &value) {
std::string nkey = compartment + "::" + key;
return storeOrUpdateFirst(nkey, value);
}
virtual bool storeOrUpdateFirst(const std::string &key,
std::string compartment, std::string compartment2,
const std::string &value) {
std::string nkey = compartment + "::" + compartment2 + "::" + key;
return storeOrUpdateFirst(nkey, value);
}
/* updateFirst */
virtual bool updateFirst(const std::string &key, std::string compartment,
const std::string &value) {
std::string nkey = compartment + "::" + key;
return updateFirst(nkey, value);
}
virtual bool updateFirst(const std::string &key, std::string compartment,
std::string compartment2, const std::string &value) {
std::string nkey = compartment + "::" + compartment2 + "::" + key;
return updateFirst(nkey, value);
}
/* del */
virtual void del(const std::string& key, std::string compartment) {
std::string nkey = compartment + "::" + key;
del(nkey);
}
virtual void del(const std::string& key, std::string compartment,
std::string compartment2) {
std::string nkey = compartment + "::" + compartment2 + "::" + key;
del(nkey);
}
/* resolveFirst */
virtual std::unique_ptr<std::string> resolveFirst(const std::string& var,
std::string compartment) {
std::string nkey = compartment + "::" + var;
return resolveFirst(nkey);
}
virtual std::unique_ptr<std::string> resolveFirst(const std::string& var,
std::string compartment, std::string compartment2) {
std::string nkey = compartment + "::" + compartment2 + "::" + var;
return resolveFirst(nkey);
}
/* resolveSingleMatch */
virtual void resolveSingleMatch(const std::string& var,
std::string compartment, std::vector<const VariableValue *> *l) {
std::string nkey = compartment + "::" + var;
resolveSingleMatch(nkey, l);
}
virtual void resolveSingleMatch(const std::string& var,
std::string compartment, std::string compartment2,
std::vector<const VariableValue *> *l) {
std::string nkey = compartment + "::" + compartment2 + "::" + var;
resolveSingleMatch(nkey, l);
}
/* resolveMultiMatches */
virtual void resolveMultiMatches(const std::string& var,
std::string compartment, std::vector<const VariableValue *> *l,
variables::KeyExclusions &ke) {
std::string nkey = compartment + "::" + var;
resolveMultiMatches(nkey, l, ke);
}
virtual void resolveMultiMatches(const std::string& var,
std::string compartment, std::string compartment2,
std::vector<const VariableValue *> *l,
variables::KeyExclusions &ke) {
std::string nkey = compartment + "::" + compartment2 + "::" + var;
resolveMultiMatches(nkey, l, ke);
}
/* resolveRegularExpression */
virtual void resolveRegularExpression(const std::string& var,
std::string compartment, std::vector<const VariableValue *> *l,
variables::KeyExclusions &ke) {
std::string nkey = compartment + "::" + var;
resolveRegularExpression(nkey, l, ke);
}
virtual void resolveRegularExpression(const std::string& var,
std::string compartment, std::string compartment2,
std::vector<const VariableValue *> *l, variables::KeyExclusions &ke) {
std::string nkey = compartment + "::" + compartment2 + "::" + var;
resolveRegularExpression(nkey, l, ke);
}
std::string m_name;
};
} // namespace collection
} // namespace modsecurity
#endif
#endif // HEADERS_MODSECURITY_COLLECTION_COLLECTION_H_

View File

@ -0,0 +1,76 @@
/*
* ModSecurity, http://www.modsecurity.org/
* Copyright (c) 2015 - 2021 Trustwave Holdings, Inc. (http://www.trustwave.com/)
*
* You may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* If any of the files related to licensing are missing or if you have any
* other questions related to licensing please contact Trustwave Holdings, Inc.
* directly using the email address security@modsecurity.org.
*
*/
#ifdef __cplusplus
#include <ctime>
#include <iostream>
#include <unordered_map>
#include <fstream>
#include <vector>
#include <iomanip>
#include <set>
#include <cstdio>
#include <string>
#include <list>
#include <memory>
#endif
#include "modsecurity/collection/collection.h"
#include "modsecurity/variable_value.h"
#ifndef HEADERS_MODSECURITY_COLLECTION_COLLECTIONS_H_
#define HEADERS_MODSECURITY_COLLECTION_COLLECTIONS_H_
#ifndef __cplusplus
typedef struct Collections_t Collections;
#endif
#ifdef __cplusplus
namespace modsecurity {
namespace collection {
class Collections {
public:
Collections(Collection *global, Collection *ip, Collection *session,
Collection *user, Collection *resource);
~Collections();
Collections(const Collections &c) = delete;
Collections& operator =(const Collections &c) = delete;
std::string m_global_collection_key;
std::string m_ip_collection_key;
std::string m_session_collection_key;
std::string m_user_collection_key;
std::string m_resource_collection_key;
Collection *m_global_collection;
Collection *m_ip_collection;
Collection *m_session_collection;
Collection *m_user_collection;
Collection *m_resource_collection;
Collection *m_tx_collection;
};
} // namespace collection
} // namespace modsecurity
#endif
#endif // HEADERS_MODSECURITY_COLLECTION_COLLECTIONS_H_

View File

@ -0,0 +1,63 @@
/*
* ModSecurity, http://www.modsecurity.org/
* Copyright (c) 2015 - 2021 Trustwave Holdings, Inc. (http://www.trustwave.com/)
*
* You may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* If any of the files related to licensing are missing or if you have any
* other questions related to licensing please contact Trustwave Holdings, Inc.
* directly using the email address security@modsecurity.org.
*
*/
#ifdef __cplusplus
#include <string>
#endif
#ifndef HEADERS_MODSECURITY_DEBUG_LOG_H_
#define HEADERS_MODSECURITY_DEBUG_LOG_H_
#ifndef __cplusplus
typedef struct DebugLog_t DebugLog;
#endif
#ifdef __cplusplus
namespace modsecurity {
namespace debug_log {
/** @ingroup ModSecurity_CPP_API */
class DebugLog {
public:
DebugLog()
: m_debugLevel(-1),
m_fileName("") { }
virtual ~DebugLog();
virtual void write(int level, const std::string &msg);
virtual void write(int level, const std::string &id,
const std::string &uri, const std::string &msg);
virtual bool isLogFileSet();
virtual bool isLogLevelSet();
virtual void setDebugLogLevel(int level);
virtual void setDebugLogFile(const std::string &fileName, std::string *error);
virtual const std::string& getDebugLogFile();
virtual int getDebugLogLevel();
int m_debugLevel;
private:
std::string m_fileName;
};
} // namespace debug_log
} // namespace modsecurity
#endif
#endif // HEADERS_MODSECURITY_DEBUG_LOG_H_

View File

@ -0,0 +1,71 @@
/*
* ModSecurity, http://www.modsecurity.org/
* Copyright (c) 2015 - 2021 Trustwave Holdings, Inc. (http://www.trustwave.com/)
*
* You may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* If any of the files related to licensing are missing or if you have any
* other questions related to licensing please contact Trustwave Holdings, Inc.
* directly using the email address security@modsecurity.org.
*
*/
#ifndef HEADERS_MODSECURITY_INTERVENTION_H_
#define HEADERS_MODSECURITY_INTERVENTION_H_
#ifdef __cplusplus
namespace modsecurity {
#endif
typedef struct ModSecurityIntervention_t {
int status;
int pause;
char *url;
char *log;
int disruptive;
} ModSecurityIntervention;
#ifdef __cplusplus
namespace intervention {
static void reset(ModSecurityIntervention_t *i) {
i->status = 200;
i->pause = 0;
i->disruptive = 0;
}
static void clean(ModSecurityIntervention_t *i) {
i->url = NULL;
i->log = NULL;
reset(i);
}
static void freeUrl(ModSecurityIntervention_t *i) {
if (i->url) {
free(i->url);
i->url = NULL;
}
}
static void freeLog(ModSecurityIntervention_t *i) {
if (i->log) {
free(i->log);
i->log = NULL;
}
}
static void free(ModSecurityIntervention_t *i) {
freeUrl(i);
freeLog(i);
}
} // namespace intervention
#endif
#ifdef __cplusplus
} // namespace modsecurity
#endif
#endif // HEADERS_MODSECURITY_INTERVENTION_H_

Some files were not shown because too many files have changed in this diff Show More