mirror of
https://github.com/owasp-modsecurity/ModSecurity.git
synced 2025-08-14 05:45:59 +03:00
Merge pull request #54 from chaizhenhua/regression-tests
Regression tests
This commit is contained in:
commit
36c2e1bcce
@ -11,7 +11,8 @@ APR_CFLAGS=""
|
||||
APR_CPPFLAGS=""
|
||||
APR_LDFLAGS=""
|
||||
APR_LDADD=""
|
||||
|
||||
APR_INCLUDEDIR=""
|
||||
APR_LINKLD=""
|
||||
AC_DEFUN([CHECK_APR],
|
||||
[dnl
|
||||
|
||||
@ -63,6 +64,10 @@ if test -n "${apr_path}"; then
|
||||
if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(apr LDFLAGS: $APR_LDFLAGS); fi
|
||||
APR_LDADD="`${APR_CONFIG} --link-libtool`"
|
||||
if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(apr LDADD: $APR_LDADD); fi
|
||||
APR_INCLUDEDIR="`${APR_CONFIG} --includedir`"
|
||||
if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(apr INCLUDEDIR: $APR_INCLUDEDIR); fi
|
||||
APR_LINKLD="`${APR_CONFIG} --link-ld`"
|
||||
if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(apr LINKLD: $APR_LINKLD); fi
|
||||
else
|
||||
AC_MSG_RESULT([no])
|
||||
fi
|
||||
@ -73,6 +78,8 @@ AC_SUBST(APR_CFLAGS)
|
||||
AC_SUBST(APR_CPPFLAGS)
|
||||
AC_SUBST(APR_LDFLAGS)
|
||||
AC_SUBST(APR_LDADD)
|
||||
AC_SUBST(APR_INCLUDEDIR)
|
||||
AC_SUBST(APR_LINKLD)
|
||||
|
||||
if test -z "${APR_VERSION}"; then
|
||||
AC_MSG_NOTICE([*** apr library not found.])
|
||||
|
@ -10,6 +10,8 @@ APU_CONFIG=""
|
||||
APU_CFLAGS=""
|
||||
APU_LDFLAGS=""
|
||||
APU_LDADD=""
|
||||
APU_INCLUDEDIR=""
|
||||
APU_LINKLD=""
|
||||
|
||||
AC_DEFUN([CHECK_APU],
|
||||
[dnl
|
||||
@ -18,7 +20,7 @@ AC_ARG_WITH(
|
||||
apu,
|
||||
[AC_HELP_STRING([--with-apu=PATH],[Path to apu prefix or config script])],
|
||||
[test_paths="${with_apu}"],
|
||||
[test_paths="/usr/local/libapr-util /usr/local/apr-util /usr/local/libapu /usr/local/apu /usr/local /opt/libapr-util /opt/apr-util /opt/libapu /opt/apu /opt /usr"])
|
||||
[test_paths="/usr/local/libapr-util /usr/local/apr-util /usr/local/libapu /usr/local/apu /usr/local/apr /usr/local /opt/libapr-util /opt/apr-util /opt/libapu /opt/apu /opt /usr"])
|
||||
|
||||
AC_MSG_CHECKING([for libapu config script])
|
||||
|
||||
@ -60,6 +62,10 @@ if test -n "${apu_path}"; then
|
||||
if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(apu LDFLAGS: $APU_LDFLAGS); fi
|
||||
APU_LDADD="`${APU_CONFIG} --link-libtool`"
|
||||
if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(apu LDADD: $APU_LDADD); fi
|
||||
APU_INCLUDEDIR="`${APU_CONFIG} --includedir`"
|
||||
if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(apu INCLUDEDIR: $APU_INCLUDEDIR); fi
|
||||
APU_LINKLD="`${APU_CONFIG} --link-ld`"
|
||||
if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(apu LINKLD: $APU_LINKLD); fi
|
||||
else
|
||||
AC_MSG_RESULT([no])
|
||||
fi
|
||||
@ -69,6 +75,8 @@ AC_SUBST(APU_VERSION)
|
||||
AC_SUBST(APU_CFLAGS)
|
||||
AC_SUBST(APU_LDFLAGS)
|
||||
AC_SUBST(APU_LDADD)
|
||||
AC_SUBST(APU_INCLUDEDIR)
|
||||
AC_SUBST(APU_LINKLD)
|
||||
|
||||
if test -z "${APU_VERSION}"; then
|
||||
AC_MSG_NOTICE([*** apu library not found.])
|
||||
|
@ -3,5 +3,5 @@ CORE_MODULES="$CORE_MODULES ngx_pool_context_module"
|
||||
HTTP_AUX_FILTER_MODULES="ngx_http_modsecurity $HTTP_AUX_FILTER_MODULES"
|
||||
NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_modsecurity.c $ngx_addon_dir/apr_bucket_nginx.c $ngx_addon_dir/ngx_pool_context.c"
|
||||
NGX_ADDON_DEPS="$NGX_ADDON_DEPS $ngx_addon_dir/apr_bucket_nginx.h $ngx_addon_dir/ngx_pool_context.h"
|
||||
CORE_LIBS="$CORE_LIBS $ngx_addon_dir/../../standalone/.libs/standalone.a -lapr-1 -laprutil-1 -lxml2 -lm "
|
||||
CORE_INCS="$CORE_INCS /usr/include/apache2 /usr/include/apr-1.0 /usr/include/httpd /usr/include/apr-1 $ngx_addon_dir $ngx_addon_dir/../../standalone $ngx_addon_dir/../../apache2 /usr/include/libxml2 "
|
||||
CORE_LIBS="$CORE_LIBS $ngx_addon_dir/../../standalone/.libs/standalone.a -L/usr/local/apr/lib -lapr-1 -L/usr/local/apr/lib -laprutil-1 -lpcre -lxml2 -lz -lm -ldl "
|
||||
CORE_INCS="$CORE_INCS $ngx_addon_dir $ngx_addon_dir/../../standalone $ngx_addon_dir/../../apache2 /usr/include/libxml2 /usr/local/apache2/include /usr/local/apr/include/apr-1 /usr/local/apr/include/apr-1"
|
||||
|
@ -156,7 +156,8 @@ ngx_pstrdup0(ngx_pool_t *pool, ngx_str_t *src)
|
||||
}
|
||||
|
||||
|
||||
static inline int ngx_http_modsecurity_method_number(unsigned int nginx)
|
||||
static inline int
|
||||
ngx_http_modsecurity_method_number(unsigned int nginx)
|
||||
{
|
||||
/*
|
||||
* http://graphics.stanford.edu/~seander/bithacks.html#ZerosOnRightMultLookup
|
||||
@ -246,7 +247,7 @@ ngx_http_modsecurity_load_request(ngx_http_request_t *r)
|
||||
}
|
||||
#endif
|
||||
|
||||
req->parsed_uri.path = req->path_info;
|
||||
req->parsed_uri.path = (char *)ngx_pstrdup0(r->pool, &r->uri);
|
||||
req->parsed_uri.is_initialized = 1;
|
||||
|
||||
str.data = r->port_start;
|
||||
@ -254,7 +255,7 @@ ngx_http_modsecurity_load_request(ngx_http_request_t *r)
|
||||
req->parsed_uri.port = ngx_atoi(str.data, str.len);
|
||||
req->parsed_uri.port_str = (char *)ngx_pstrdup0(r->pool, &str);
|
||||
|
||||
req->parsed_uri.query = req->args;
|
||||
req->parsed_uri.query = r->args.len ? req->args : NULL;
|
||||
req->parsed_uri.dns_looked_up = 0;
|
||||
req->parsed_uri.dns_resolved = 0;
|
||||
|
||||
@ -786,6 +787,29 @@ ngx_http_modsecurity_save_headers_out_visitor(void *data, const char *key, const
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static ngx_inline ngx_int_t
|
||||
ngx_http_modsecurity_status(ngx_http_request_t *r, int status)
|
||||
{
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "ModSecurity: status %d", status);
|
||||
|
||||
if (status == DECLINED || status == APR_SUCCESS) {
|
||||
return NGX_DECLINED;
|
||||
}
|
||||
|
||||
/* nginx known status */
|
||||
if ( (status >= 300 && status < 308) /* 3XX */
|
||||
|| (status >= 400 && status < 417) /* 4XX */
|
||||
|| (status >= 500 && status < 508) /* 5XX */
|
||||
|| (status == NGX_HTTP_CREATED || status == NGX_HTTP_NO_CONTENT) ) {
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
return NGX_HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
|
||||
|
||||
/* create loc conf struct */
|
||||
static void *
|
||||
ngx_http_modsecurity_create_loc_conf(ngx_conf_t *cf)
|
||||
@ -952,18 +976,18 @@ ngx_http_modsecurity_handler(ngx_http_request_t *r)
|
||||
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "modSecurity: handler");
|
||||
|
||||
/* create / retrive request ctx */
|
||||
if (r->internal) {
|
||||
/* we have already processed the request headers with previous loc conf */
|
||||
|
||||
/* TODO: do we need update ctx and process headers again? */
|
||||
|
||||
ctx = ngx_http_get_module_pool_ctx(r, ngx_http_modsecurity);
|
||||
|
||||
if (ctx) {
|
||||
/* we have already processed the request headers */
|
||||
ngx_http_set_ctx(r, ctx, ngx_http_modsecurity);
|
||||
return NGX_DECLINED;
|
||||
}
|
||||
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "modSecurity: get internel request ctx failed");
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "modSecurity: request pool ctx empty");
|
||||
}
|
||||
|
||||
ctx = ngx_http_modsecurity_create_ctx(r);
|
||||
@ -978,52 +1002,34 @@ ngx_http_modsecurity_handler(ngx_http_request_t *r)
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
ngx_http_modsecurity_load_request(r);
|
||||
|
||||
if (ngx_http_modsecurity_load_headers_in(r) != NGX_OK) {
|
||||
/* load request to request rec */
|
||||
if (ngx_http_modsecurity_load_request(r) != NGX_OK
|
||||
|| ngx_http_modsecurity_load_headers_in(r) != NGX_OK) {
|
||||
|
||||
return NGX_HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
|
||||
/* processing request headers */
|
||||
rc = modsecProcessRequestHeaders(ctx->req);
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "ModSecurity: modsecProcessRequestHeaders %d", rc);
|
||||
rc = ngx_http_modsecurity_status(r, modsecProcessRequestHeaders(ctx->req));
|
||||
|
||||
if (rc == DECLINED) {
|
||||
|
||||
if (modsecIsRequestBodyAccessEnabled(ctx->req)
|
||||
&& r->method == NGX_HTTP_POST) {
|
||||
|
||||
/* Processing POST request body, should we process PUT? */
|
||||
rc = ngx_http_read_client_request_body(r, ngx_http_modsecurity_body_handler);
|
||||
if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
return NGX_DONE;
|
||||
}
|
||||
/* other method */
|
||||
rc = modsecProcessRequestBody(ctx->req);
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "ModSecurity: modsecProcessRequestBody %d", rc);
|
||||
}
|
||||
|
||||
if (rc != DECLINED) {
|
||||
|
||||
/* Nginx and Apache share same response code */
|
||||
if (rc < NGX_HTTP_SPECIAL_RESPONSE || rc >= 600) {
|
||||
return NGX_HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
if (rc != NGX_DECLINED) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
if (ngx_http_modsecurity_save_headers_in(r) != NGX_OK) {
|
||||
if (r->method == NGX_HTTP_POST
|
||||
&& modsecIsRequestBodyAccessEnabled(ctx->req) ) {
|
||||
|
||||
return NGX_HTTP_INTERNAL_SERVER_ERROR;
|
||||
/* read POST request body, should we process PUT? */
|
||||
rc = ngx_http_read_client_request_body(r, ngx_http_modsecurity_body_handler);
|
||||
if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
return NGX_DONE;
|
||||
}
|
||||
*/
|
||||
|
||||
return NGX_DECLINED;
|
||||
|
||||
/* other method */
|
||||
return ngx_http_modsecurity_status(r, modsecProcessRequestBody(ctx->req));
|
||||
}
|
||||
|
||||
|
||||
@ -1038,19 +1044,12 @@ ngx_http_modsecurity_body_handler(ngx_http_request_t *r)
|
||||
ctx = ngx_http_get_module_ctx(r, ngx_http_modsecurity);
|
||||
|
||||
if (ngx_http_modsecurity_load_request_body(r) != NGX_OK) {
|
||||
|
||||
return ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
|
||||
rc = modsecProcessRequestBody(ctx->req);
|
||||
rc = ngx_http_modsecurity_status(r, modsecProcessRequestBody(ctx->req));
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "ModSecurity: modsecProcessRequestBody %d", rc);
|
||||
|
||||
if (rc != DECLINED) {
|
||||
/* Nginx and Apache share same response code */
|
||||
if (rc < NGX_HTTP_SPECIAL_RESPONSE || rc >= 600) {
|
||||
rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
if (rc != NGX_DECLINED) {
|
||||
return ngx_http_finalize_request(r, rc);
|
||||
}
|
||||
|
||||
@ -1070,11 +1069,39 @@ static ngx_int_t
|
||||
ngx_http_modsecurity_header_filter(ngx_http_request_t *r) {
|
||||
ngx_http_modsecurity_loc_conf_t *cf;
|
||||
ngx_http_modsecurity_ctx_t *ctx;
|
||||
const char *location;
|
||||
ngx_table_elt_t *h;
|
||||
ngx_int_t rc;
|
||||
|
||||
|
||||
cf = ngx_http_get_module_loc_conf(r, ngx_http_modsecurity);
|
||||
ctx = ngx_http_get_module_ctx(r, ngx_http_modsecurity);
|
||||
|
||||
if (ctx && ctx->complete
|
||||
&& r->err_status >= NGX_HTTP_MOVED_PERMANENTLY
|
||||
&& r->err_status < 308) {
|
||||
|
||||
/* 3XX load redirect location header so that we can do redirec in phase 3,4 */
|
||||
location = apr_table_get(ctx->req->headers_out, "Location");
|
||||
|
||||
if (location == NULL) {
|
||||
return NGX_HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
|
||||
h = ngx_list_push(&r->headers_out.headers);
|
||||
if (h == NULL) {
|
||||
return NGX_HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
|
||||
h->hash = 1;
|
||||
h->key.data = (u_char *)"Location";
|
||||
h->key.len = ngx_strlen("Location");
|
||||
h->value.data = (u_char *)location;
|
||||
h->value.len = ngx_strlen(location);
|
||||
|
||||
return ngx_http_next_header_filter(r);
|
||||
}
|
||||
|
||||
if (r != r->main || !cf->enable || ctx->complete) {
|
||||
return ngx_http_next_header_filter(r);
|
||||
}
|
||||
@ -1091,24 +1118,18 @@ ngx_http_modsecurity_header_filter(ngx_http_request_t *r) {
|
||||
return NGX_HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
|
||||
rc = modsecProcessResponse(ctx->req);
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "ModSecurity: modsecProcessResponse %d", rc);
|
||||
rc = ngx_http_modsecurity_status(r, modsecProcessResponse(ctx->req));
|
||||
|
||||
if (rc == DECLINED || rc == APR_SUCCESS) {
|
||||
|
||||
if (ngx_http_modsecurity_save_headers_in(r) != NGX_OK
|
||||
|| ngx_http_modsecurity_save_headers_out(r) != NGX_OK) {
|
||||
return NGX_HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
|
||||
return ngx_http_next_header_filter(r);
|
||||
if (rc != NGX_DECLINED) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (rc < NGX_HTTP_SPECIAL_RESPONSE || rc >= 600) {
|
||||
rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
|
||||
if (ngx_http_modsecurity_save_headers_in(r) != NGX_OK
|
||||
|| ngx_http_modsecurity_save_headers_out(r) != NGX_OK) {
|
||||
return NGX_HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
|
||||
return rc;
|
||||
return ngx_http_next_header_filter(r);
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
@ -1142,58 +1163,47 @@ ngx_http_modsecurity_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
|
||||
}
|
||||
|
||||
/* last buf has been saved */
|
||||
|
||||
ctx->complete = 1;
|
||||
modsecSetResponseBrigade(ctx->req, ctx->brigade);
|
||||
|
||||
// TODO: do we need reload headers_in ?
|
||||
//
|
||||
if (ngx_http_modsecurity_load_headers_in(r) != NGX_OK
|
||||
|| ngx_http_modsecurity_load_headers_out(r) != NGX_OK) {
|
||||
|
||||
return NGX_HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
|
||||
rc = modsecProcessResponse(ctx->req);
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "ModSecurity: modsecProcessResponse %d", rc);
|
||||
rc = ngx_http_modsecurity_status(r, modsecProcessResponse(ctx->req));
|
||||
|
||||
if (rc == DECLINED || rc == APR_SUCCESS) {
|
||||
|
||||
in = NULL;
|
||||
|
||||
apr_brigade_length(ctx->brigade, 0, &content_length);
|
||||
|
||||
rc = move_brigade_to_chain(ctx->brigade, &in, r->pool);
|
||||
if (rc == NGX_ERROR) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (ngx_http_modsecurity_save_headers_in(r) != NGX_OK
|
||||
||ngx_http_modsecurity_save_headers_out(r) != NGX_OK) {
|
||||
|
||||
return ngx_http_filter_finalize_request(r, &ngx_http_modsecurity, NGX_HTTP_INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
|
||||
if (r->headers_out.content_length_n != -1) {
|
||||
|
||||
r->headers_out.content_length_n = content_length;
|
||||
r->headers_out.content_length = NULL; /* header filter will set this */
|
||||
}
|
||||
|
||||
rc = ngx_http_next_header_filter(r);
|
||||
|
||||
if (rc == NGX_ERROR || rc > NGX_OK) {
|
||||
return ngx_http_filter_finalize_request(r, &ngx_http_modsecurity, rc);
|
||||
}
|
||||
|
||||
return ngx_http_next_body_filter(r, in);
|
||||
if (rc != NGX_DECLINED) {
|
||||
return ngx_http_filter_finalize_request(r, &ngx_http_modsecurity, rc);
|
||||
}
|
||||
|
||||
if (rc < NGX_HTTP_SPECIAL_RESPONSE || rc >= 600) {
|
||||
rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
|
||||
apr_brigade_length(ctx->brigade, 0, &content_length);
|
||||
|
||||
rc = move_brigade_to_chain(ctx->brigade, &in, r->pool);
|
||||
if (rc == NGX_ERROR) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
return ngx_http_filter_finalize_request(r, &ngx_http_modsecurity, rc);
|
||||
if (ngx_http_modsecurity_save_headers_in(r) != NGX_OK
|
||||
||ngx_http_modsecurity_save_headers_out(r) != NGX_OK) {
|
||||
|
||||
return ngx_http_filter_finalize_request(r, &ngx_http_modsecurity, NGX_HTTP_INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
|
||||
if (r->headers_out.content_length_n != -1) {
|
||||
|
||||
r->headers_out.content_length_n = content_length;
|
||||
r->headers_out.content_length = NULL; /* header filter will set this */
|
||||
}
|
||||
|
||||
rc = ngx_http_next_header_filter(r);
|
||||
|
||||
if (rc == NGX_ERROR || rc > NGX_OK) {
|
||||
return ngx_http_filter_finalize_request(r, &ngx_http_modsecurity, rc);
|
||||
}
|
||||
|
||||
return ngx_http_next_body_filter(r, in);
|
||||
}
|
||||
|
||||
|
||||
|
@ -72,6 +72,10 @@ standalone_la_LDFLAGS = -no-undefined -module -avoid-version \
|
||||
@PCRE_LDFLAGS@ @LIBXML2_LDFLAGS@ @LUA_LDFLAGS@
|
||||
endif
|
||||
|
||||
standalone_INCS = `echo "@LIBXML2_CFLAGS@ @LUA_CFLAGS@" | sed -n 's/ *-I *\([^ ]*\) /\1 /gp'` \
|
||||
@APXS_INCLUDEDIR@ @APR_INCLUDEDIR@ @APU_INCLUDEDIR@
|
||||
standalone_LIBS = @APR_LINKLD@ @APU_LINKLD@ @APXS_LDFLAGS@ \
|
||||
@PCRE_LDADD@ @LIBXML2_LDADD@ @LUA_LDADD@
|
||||
install-exec-hook: $(pkglib_LTLIBRARIES)
|
||||
@echo "Creating Nginx config file..."; \
|
||||
rm -f ../nginx/modsecurity/config; \
|
||||
@ -80,8 +84,8 @@ install-exec-hook: $(pkglib_LTLIBRARIES)
|
||||
echo "HTTP_AUX_FILTER_MODULES=\"ngx_http_modsecurity \$$HTTP_AUX_FILTER_MODULES\"" >> ../nginx/modsecurity/config; \
|
||||
echo "NGX_ADDON_SRCS=\"\$$NGX_ADDON_SRCS \$$ngx_addon_dir/ngx_http_modsecurity.c \$$ngx_addon_dir/apr_bucket_nginx.c \$$ngx_addon_dir/ngx_pool_context.c\"" >> ../nginx/modsecurity/config;\
|
||||
echo "NGX_ADDON_DEPS=\"\$$NGX_ADDON_DEPS \$$ngx_addon_dir/apr_bucket_nginx.h \$$ngx_addon_dir/ngx_pool_context.h\"" >> ../nginx/modsecurity/config; \
|
||||
echo "CORE_LIBS=\"\$$CORE_LIBS \$$ngx_addon_dir/../../standalone/.libs/standalone.a -lapr-1 -laprutil-1 -lxml2 -lm @LUA_LDADD@\"" >> ../nginx/modsecurity/config; \
|
||||
echo "CORE_INCS=\"\$$CORE_INCS /usr/include/apache2 /usr/include/apr-1.0 /usr/include/httpd /usr/include/apr-1 \$$ngx_addon_dir \$$ngx_addon_dir/../../standalone \$$ngx_addon_dir/../../apache2 /usr/include/libxml2 `echo @LUA_CFLAGS@ | cut -d "I" -f3`\"" >> ../nginx/modsecurity/config; \
|
||||
echo "CORE_LIBS=\"\$$CORE_LIBS \$$ngx_addon_dir/../../standalone/.libs/standalone.a $(standalone_LIBS) \"" >> ../nginx/modsecurity/config; \
|
||||
echo "CORE_INCS=\"\$$CORE_INCS \$$ngx_addon_dir \$$ngx_addon_dir/../../standalone \$$ngx_addon_dir/../../apache2 $(standalone_INCS)\"" >> ../nginx/modsecurity/config; \
|
||||
echo "Removing unused static libraries..."; \
|
||||
for m in $(pkglib_LTLIBRARIES); do \
|
||||
base=`echo $$m | sed 's/\..*//'`; \
|
||||
|
@ -1,9 +1,8 @@
|
||||
# Makefile.in generated by automake 1.11.6 from Makefile.am.
|
||||
# Makefile.in generated by automake 1.12.2 from Makefile.am.
|
||||
# @configure_input@
|
||||
|
||||
# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
|
||||
# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software
|
||||
# Foundation, Inc.
|
||||
# Copyright (C) 1994-2012 Free Software Foundation, Inc.
|
||||
|
||||
# This Makefile.in is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
@ -51,7 +50,8 @@ POST_UNINSTALL = :
|
||||
build_triplet = @build@
|
||||
host_triplet = @host@
|
||||
subdir = standalone
|
||||
DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
|
||||
DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in \
|
||||
$(top_srcdir)/build/depcomp
|
||||
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
|
||||
am__aclocal_m4_deps = $(top_srcdir)/build/find_apr.m4 \
|
||||
$(top_srcdir)/build/find_apu.m4 \
|
||||
@ -149,13 +149,17 @@ AMTAR = @AMTAR@
|
||||
APR_CFLAGS = @APR_CFLAGS@
|
||||
APR_CONFIG = @APR_CONFIG@
|
||||
APR_CPPFLAGS = @APR_CPPFLAGS@
|
||||
APR_INCLUDEDIR = @APR_INCLUDEDIR@
|
||||
APR_LDADD = @APR_LDADD@
|
||||
APR_LDFLAGS = @APR_LDFLAGS@
|
||||
APR_LINKLD = @APR_LINKLD@
|
||||
APR_VERSION = @APR_VERSION@
|
||||
APU_CFLAGS = @APU_CFLAGS@
|
||||
APU_CONFIG = @APU_CONFIG@
|
||||
APU_INCLUDEDIR = @APU_INCLUDEDIR@
|
||||
APU_LDADD = @APU_LDADD@
|
||||
APU_LDFLAGS = @APU_LDFLAGS@
|
||||
APU_LINKLD = @APU_LINKLD@
|
||||
APU_VERSION = @APU_VERSION@
|
||||
APXS = @APXS@
|
||||
APXS_BINDIR = @APXS_BINDIR@
|
||||
@ -381,6 +385,12 @@ standalone_la_LIBADD = @APR_LDADD@ @APU_LDADD@ @PCRE_LDADD@ @LIBXML2_LDADD@ @LUA
|
||||
@SOLARIS_TRUE@ @APR_LDFLAGS@ @APU_LDFLAGS@ @APXS_LDFLAGS@ \
|
||||
@SOLARIS_TRUE@ @PCRE_LDFLAGS@ @LIBXML2_LDFLAGS@ @LUA_LDFLAGS@
|
||||
|
||||
standalone_INCS = `echo "@LIBXML2_CFLAGS@ @LUA_CFLAGS@" | sed -n 's/ *-I *\([^ ]*\) /\1 /gp'` \
|
||||
@APXS_INCLUDEDIR@ @APR_INCLUDEDIR@ @APU_INCLUDEDIR@
|
||||
|
||||
standalone_LIBS = @APR_LINKLD@ @APU_LINKLD@ @APXS_LDFLAGS@ \
|
||||
@PCRE_LDADD@ @LIBXML2_LDADD@ @LUA_LDADD@
|
||||
|
||||
all: all-am
|
||||
|
||||
.SUFFIXES:
|
||||
@ -441,12 +451,14 @@ uninstall-pkglibLTLIBRARIES:
|
||||
|
||||
clean-pkglibLTLIBRARIES:
|
||||
-test -z "$(pkglib_LTLIBRARIES)" || rm -f $(pkglib_LTLIBRARIES)
|
||||
@list='$(pkglib_LTLIBRARIES)'; for p in $$list; do \
|
||||
dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
|
||||
test "$$dir" != "$$p" || dir=.; \
|
||||
echo "rm -f \"$${dir}/so_locations\""; \
|
||||
rm -f "$${dir}/so_locations"; \
|
||||
done
|
||||
@list='$(pkglib_LTLIBRARIES)'; \
|
||||
locs=`for p in $$list; do echo $$p; done | \
|
||||
sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
|
||||
sort -u`; \
|
||||
test -z "$$locs" || { \
|
||||
echo rm -f $${locs}; \
|
||||
rm -f $${locs}; \
|
||||
}
|
||||
standalone.la: $(standalone_la_OBJECTS) $(standalone_la_DEPENDENCIES) $(EXTRA_standalone_la_DEPENDENCIES)
|
||||
$(standalone_la_LINK) -rpath $(pkglibdir) $(standalone_la_OBJECTS) $(standalone_la_LIBADD) $(LIBS)
|
||||
|
||||
@ -797,6 +809,20 @@ GTAGS:
|
||||
&& $(am__cd) $(top_srcdir) \
|
||||
&& gtags -i $(GTAGS_ARGS) "$$here"
|
||||
|
||||
cscopelist: $(HEADERS) $(SOURCES) $(LISP)
|
||||
list='$(SOURCES) $(HEADERS) $(LISP)'; \
|
||||
case "$(srcdir)" in \
|
||||
[\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
|
||||
*) sdir=$(subdir)/$(srcdir) ;; \
|
||||
esac; \
|
||||
for i in $$list; do \
|
||||
if test -f "$$i"; then \
|
||||
echo "$(subdir)/$$i"; \
|
||||
else \
|
||||
echo "$$sdir/$$i"; \
|
||||
fi; \
|
||||
done >> $(top_builddir)/cscope.files
|
||||
|
||||
distclean-tags:
|
||||
-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
|
||||
|
||||
@ -942,32 +968,30 @@ uninstall-am: uninstall-pkglibLTLIBRARIES
|
||||
.MAKE: install-am install-exec-am install-strip
|
||||
|
||||
.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
|
||||
clean-libtool clean-pkglibLTLIBRARIES ctags distclean \
|
||||
distclean-compile distclean-generic distclean-libtool \
|
||||
distclean-tags distdir dvi dvi-am html html-am info info-am \
|
||||
install install-am install-data install-data-am install-dvi \
|
||||
install-dvi-am install-exec install-exec-am install-exec-hook \
|
||||
install-html install-html-am install-info install-info-am \
|
||||
install-man install-pdf install-pdf-am \
|
||||
install-pkglibLTLIBRARIES install-ps install-ps-am \
|
||||
install-strip installcheck installcheck-am installdirs \
|
||||
maintainer-clean maintainer-clean-generic mostlyclean \
|
||||
mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
|
||||
pdf pdf-am ps ps-am tags uninstall uninstall-am \
|
||||
uninstall-pkglibLTLIBRARIES
|
||||
|
||||
clean-libtool clean-pkglibLTLIBRARIES cscopelist ctags \
|
||||
distclean distclean-compile distclean-generic \
|
||||
distclean-libtool distclean-tags distdir dvi dvi-am html \
|
||||
html-am info info-am install install-am install-data \
|
||||
install-data-am install-dvi install-dvi-am install-exec \
|
||||
install-exec-am install-exec-hook install-html install-html-am \
|
||||
install-info install-info-am install-man install-pdf \
|
||||
install-pdf-am install-pkglibLTLIBRARIES install-ps \
|
||||
install-ps-am install-strip installcheck installcheck-am \
|
||||
installdirs maintainer-clean maintainer-clean-generic \
|
||||
mostlyclean mostlyclean-compile mostlyclean-generic \
|
||||
mostlyclean-libtool pdf pdf-am ps ps-am tags uninstall \
|
||||
uninstall-am uninstall-pkglibLTLIBRARIES
|
||||
|
||||
install-exec-hook: $(pkglib_LTLIBRARIES)
|
||||
@echo "Creating Nginx config file..."; \
|
||||
rm -f ../nginx/modsecurity/config; \
|
||||
echo "ngx_addon_name=ngx_http_modsecurity" >> ../nginx/modsecurity/config; \
|
||||
echo "# HTTP_MODULES=\"\$$HTTP_MODULES ngx_http_modsecurity\"" >> ../nginx/modsecurity/config; \
|
||||
echo "HTTP_HEADERS_FILTER_MODULE=\"ngx_http_modsecurity \$$HTTP_HEADERS_FILTER_MODULE\"" >> ../nginx/modsecurity/config; \
|
||||
echo "NGX_ADDON_SRCS=\"\$$NGX_ADDON_SRCS \$$ngx_addon_dir/ngx_http_modsecurity.c \$$ngx_addon_dir/apr_bucket_nginx.c\"" >> ../nginx/modsecurity/config;\
|
||||
echo "NGX_ADDON_DEPS=\"\$$NGX_ADDON_DEPS\"" >> ../nginx/modsecurity/config; \
|
||||
echo "CORE_LIBS=\"\$$CORE_LIBS \$$ngx_addon_dir/../../standalone/.libs/standalone.a -lapr-1 -laprutil-1 -lxml2 -lm @LUA_LDADD@\"" >> ../nginx/modsecurity/config; \
|
||||
echo "CORE_INCS=\"\$$CORE_INCS /usr/include/apache2 /usr/include/apr-1.0 /usr/include/httpd /usr/include/apr-1 \$$ngx_addon_dir \$$ngx_addon_dir/../../standalone \$$ngx_addon_dir/../../apache2 /usr/include/libxml2 `echo @LUA_CFLAGS@ | cut -d "I" -f3`\"" >> ../nginx/modsecurity/config; \
|
||||
echo "have=REQUEST_EARLY . auto/have" >> ../nginx/modsecurity/config;\
|
||||
echo "CORE_MODULES=\"\$$CORE_MODULES ngx_pool_context_module\"" >> ../nginx/modsecurity/config; \
|
||||
echo "HTTP_AUX_FILTER_MODULES=\"ngx_http_modsecurity \$$HTTP_AUX_FILTER_MODULES\"" >> ../nginx/modsecurity/config; \
|
||||
echo "NGX_ADDON_SRCS=\"\$$NGX_ADDON_SRCS \$$ngx_addon_dir/ngx_http_modsecurity.c \$$ngx_addon_dir/apr_bucket_nginx.c \$$ngx_addon_dir/ngx_pool_context.c\"" >> ../nginx/modsecurity/config;\
|
||||
echo "NGX_ADDON_DEPS=\"\$$NGX_ADDON_DEPS \$$ngx_addon_dir/apr_bucket_nginx.h \$$ngx_addon_dir/ngx_pool_context.h\"" >> ../nginx/modsecurity/config; \
|
||||
echo "CORE_LIBS=\"\$$CORE_LIBS \$$ngx_addon_dir/../../standalone/.libs/standalone.a $(standalone_LIBS) \"" >> ../nginx/modsecurity/config; \
|
||||
echo "CORE_INCS=\"\$$CORE_INCS \$$ngx_addon_dir \$$ngx_addon_dir/../../standalone \$$ngx_addon_dir/../../apache2 $(standalone_INCS)\"" >> ../nginx/modsecurity/config; \
|
||||
echo "Removing unused static libraries..."; \
|
||||
for m in $(pkglib_LTLIBRARIES); do \
|
||||
base=`echo $$m | sed 's/\..*//'`; \
|
||||
|
191
standalone/api.c
191
standalone/api.c
@ -223,40 +223,10 @@ apr_status_t ap_http_in_filter(ap_filter_t *f, apr_bucket_brigade *bb_out,
|
||||
}
|
||||
|
||||
apr_status_t ap_http_out_filter(ap_filter_t *f, apr_bucket_brigade *b) {
|
||||
modsec_rec *msr = (modsec_rec *)f->ctx;
|
||||
apr_status_t rc;
|
||||
apr_bucket_brigade *bb_out;
|
||||
|
||||
bb_out = modsecGetResponseBrigade(f->r);
|
||||
|
||||
|
||||
if (bb_out) {
|
||||
APR_BRIGADE_CONCAT(bb_out, b);
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
|
||||
// is there a way to tell whether the response body was modified or not?
|
||||
//
|
||||
if((msr->txcfg->content_injection_enabled || msr->content_prepend_len != 0 || msr->content_append_len != 0)
|
||||
&& msr->txcfg->resbody_access) {
|
||||
|
||||
if (modsecWriteResponse != NULL) {
|
||||
char *data = NULL;
|
||||
apr_size_t length;
|
||||
|
||||
rc = apr_brigade_pflatten(msr->of_brigade, &data, &length, msr->mp);
|
||||
|
||||
if (rc != APR_SUCCESS) {
|
||||
msr_log(msr, 1, "Output filter: Failed to flatten brigade (%d): %s", rc,
|
||||
get_apr_error(msr->mp, rc));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* TODO: return ?*/
|
||||
modsecWriteResponse(msr->r, data, msr->stream_output_length);
|
||||
}
|
||||
}
|
||||
apr_bucket_brigade *bb_out = (apr_bucket_brigade *)f->ctx;
|
||||
|
||||
APR_BRIGADE_CONCAT(bb_out, b);
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
|
||||
@ -551,74 +521,117 @@ int modsecIsResponseBodyAccessEnabled(request_rec *r)
|
||||
}
|
||||
|
||||
int modsecProcessResponse(request_rec *r) {
|
||||
int status = DECLINED;
|
||||
int status;
|
||||
modsec_rec *msr;
|
||||
apr_bucket *e;
|
||||
ap_filter_t *f;
|
||||
apr_bucket_brigade *bb_in, *bb_out, *bb;
|
||||
|
||||
if(r->output_filters != NULL) {
|
||||
modsec_rec *msr = (modsec_rec *)r->output_filters->ctx;
|
||||
char buf[8192];
|
||||
char *tmp = NULL;
|
||||
apr_bucket *e = NULL;
|
||||
if(r->output_filters == NULL) {
|
||||
return DECLINED;
|
||||
}
|
||||
|
||||
msr = (modsec_rec *)r->output_filters->ctx;
|
||||
if (msr == NULL) {
|
||||
ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r->server,
|
||||
"ModSecurity: Internal Error: msr is null in output filter.");
|
||||
ap_remove_output_filter(r->output_filters);
|
||||
return APR_EGENERAL;
|
||||
}
|
||||
|
||||
msr->r = r;
|
||||
|
||||
/* create input response brigade */
|
||||
bb_in = apr_brigade_create(msr->mp, r->connection->bucket_alloc);
|
||||
|
||||
if (bb_in == NULL) {
|
||||
msr_log(msr, 1, "Process response: Failed to create brigade.");
|
||||
return APR_EGENERAL;
|
||||
}
|
||||
|
||||
/* get input response brigade */
|
||||
bb = modsecGetResponseBrigade(r);
|
||||
if (bb != NULL) {
|
||||
APR_BRIGADE_CONCAT(bb_in, bb);
|
||||
if (!APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(bb_in))) {
|
||||
e = apr_bucket_eos_create(bb_in->bucket_alloc);
|
||||
APR_BRIGADE_INSERT_TAIL(bb_in, e);
|
||||
}
|
||||
} else if (modsecReadResponse != NULL) {
|
||||
unsigned int readcnt = 0;
|
||||
int is_eos = 0;
|
||||
ap_filter_t *f = NULL;
|
||||
apr_bucket_brigade *bb_in, *bb = NULL;
|
||||
char buf[8192];
|
||||
while(!is_eos) {
|
||||
modsecReadResponse(r, buf, 8192, &readcnt, &is_eos);
|
||||
|
||||
if (msr == NULL) {
|
||||
ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r->server,
|
||||
"ModSecurity: Internal Error: msr is null in output filter.");
|
||||
ap_remove_output_filter(r->output_filters);
|
||||
return send_error_bucket(msr, r->output_filters, HTTP_INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
|
||||
bb = apr_brigade_create(msr->mp, r->connection->bucket_alloc);
|
||||
|
||||
if (bb == NULL) {
|
||||
msr_log(msr, 1, "Process response: Failed to create brigade.");
|
||||
return APR_EGENERAL;
|
||||
}
|
||||
|
||||
msr->r = r;
|
||||
|
||||
bb_in = modsecGetResponseBrigade(r);
|
||||
|
||||
if (bb_in != NULL) {
|
||||
APR_BRIGADE_CONCAT(bb, bb_in);
|
||||
if (!APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(bb))) {
|
||||
e = apr_bucket_eos_create(bb->bucket_alloc);
|
||||
APR_BRIGADE_INSERT_TAIL(bb, e);
|
||||
if(readcnt > 0) {
|
||||
char *tmp = (char *)apr_palloc(r->pool, readcnt);
|
||||
memcpy(tmp, buf, readcnt);
|
||||
e = apr_bucket_pool_create(tmp, readcnt, r->pool, r->connection->bucket_alloc);
|
||||
APR_BRIGADE_INSERT_TAIL(bb_in, e);
|
||||
}
|
||||
} else if (modsecReadResponse != NULL) {
|
||||
while(!is_eos) {
|
||||
modsecReadResponse(r, buf, 8192, &readcnt, &is_eos);
|
||||
}
|
||||
|
||||
if(readcnt > 0) {
|
||||
tmp = (char *)apr_palloc(r->pool, readcnt);
|
||||
memcpy(tmp, buf, readcnt);
|
||||
e = apr_bucket_pool_create(tmp, readcnt, r->pool, r->connection->bucket_alloc);
|
||||
APR_BRIGADE_INSERT_TAIL(bb, e);
|
||||
}
|
||||
e = apr_bucket_eos_create(r->connection->bucket_alloc);
|
||||
APR_BRIGADE_INSERT_TAIL(bb_in, e);
|
||||
} else {
|
||||
/* cannot read response body process header only */
|
||||
|
||||
e = apr_bucket_eos_create(r->connection->bucket_alloc);
|
||||
APR_BRIGADE_INSERT_TAIL(bb_in, e);
|
||||
}
|
||||
|
||||
bb_out = bb ? bb : apr_brigade_create(msr->mp, r->connection->bucket_alloc);
|
||||
|
||||
if (bb_out == NULL) {
|
||||
msr_log(msr, 1, "Process response: Failed to create brigade.");
|
||||
return APR_EGENERAL;
|
||||
}
|
||||
|
||||
/* concat output bucket to bb_out */
|
||||
f = ap_add_output_filter("HTTP_OUT", bb_out, r, r->connection);
|
||||
status = ap_pass_brigade(r->output_filters, bb_in);
|
||||
ap_remove_output_filter(f);
|
||||
|
||||
if (status == APR_EGENERAL) {
|
||||
/* retrive response status from bb_out */
|
||||
for(e = APR_BRIGADE_FIRST(bb_out);
|
||||
e != APR_BRIGADE_SENTINEL(bb_out);
|
||||
e = APR_BUCKET_NEXT(e)) {
|
||||
if (AP_BUCKET_IS_ERROR(e)) {
|
||||
return ((ap_bucket_error*) e->data)->status;
|
||||
}
|
||||
|
||||
e = apr_bucket_eos_create(r->connection->bucket_alloc);
|
||||
APR_BRIGADE_INSERT_TAIL(bb, e);
|
||||
} else {
|
||||
/* cannot read response body process header only */
|
||||
|
||||
e = apr_bucket_eos_create(r->connection->bucket_alloc);
|
||||
APR_BRIGADE_INSERT_TAIL(bb, e);
|
||||
}
|
||||
|
||||
f = ap_add_output_filter("HTTP_OUT", msr, r, r->connection);
|
||||
status = ap_pass_brigade(r->output_filters, bb);
|
||||
ap_remove_output_filter(f);
|
||||
if(status > 0
|
||||
&& msr->intercept_actionset->intercept_status != 0) {
|
||||
status = msr->intercept_actionset->intercept_status;
|
||||
}
|
||||
return APR_EGENERAL;
|
||||
}
|
||||
|
||||
if (status != DECLINED) {
|
||||
return status;
|
||||
}
|
||||
|
||||
return status;
|
||||
/* copy bb_out */
|
||||
// is there a way to tell whether the response body was modified or not?
|
||||
if (modsecWriteResponse != NULL
|
||||
&& (msr->txcfg->content_injection_enabled || msr->content_prepend_len != 0 || msr->content_append_len != 0)
|
||||
&& msr->txcfg->resbody_access) {
|
||||
|
||||
char *data = NULL;
|
||||
apr_size_t length;
|
||||
|
||||
status = apr_brigade_pflatten(msr->of_brigade, &data, &length, msr->mp);
|
||||
|
||||
if (status != APR_SUCCESS) {
|
||||
msr_log(msr, 1, "Output filter: Failed to flatten brigade (%d): %s", status,
|
||||
get_apr_error(msr->mp, status));
|
||||
return APR_EGENERAL;
|
||||
}
|
||||
|
||||
if ( modsecWriteResponse(msr->r, data, msr->stream_output_length) != APR_SUCCESS) {
|
||||
return APR_EGENERAL;
|
||||
}
|
||||
}
|
||||
|
||||
return DECLINED;
|
||||
}
|
||||
|
||||
int modsecFinishRequest(request_rec *r) {
|
||||
|
0
tests/regression/nginx/conf/empty.conf
Normal file
0
tests/regression/nginx/conf/empty.conf
Normal file
22
tests/regression/nginx/conf/nginx.conf.template
Normal file
22
tests/regression/nginx/conf/nginx.conf.template
Normal file
@ -0,0 +1,22 @@
|
||||
|
||||
user root;
|
||||
worker_processes 1;
|
||||
daemon on;
|
||||
error_log logs/error.log debug;
|
||||
events {
|
||||
worker_connections 1024;
|
||||
}
|
||||
|
||||
http {
|
||||
ModSecurityEnabled [% enable %];
|
||||
ModSecurityConfig [% config %];
|
||||
server {
|
||||
|
||||
listen [% listen %];
|
||||
server_name localhost;
|
||||
location / {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
736
tests/run-regression-tests-nginx.pl
Normal file
736
tests/run-regression-tests-nginx.pl
Normal file
@ -0,0 +1,736 @@
|
||||
#!/usr/bin/perl
|
||||
#
|
||||
# Run regression tests.
|
||||
#
|
||||
# Syntax: run-regression-tests.pl [options] [file [N]]
|
||||
#
|
||||
# All: run-regression-tests.pl
|
||||
# All in file: run-regression-tests.pl file
|
||||
# Nth in file: run-regression-tests.pl file N
|
||||
#
|
||||
use strict;
|
||||
use Time::HiRes qw(gettimeofday sleep);
|
||||
use POSIX qw(WIFEXITED WEXITSTATUS WIFSIGNALED WTERMSIG);
|
||||
use File::Spec qw(rel2abs);
|
||||
use File::Basename qw(basename dirname);
|
||||
use File::Path qw(make_path);
|
||||
use FileHandle;
|
||||
use IPC::Open2 qw(open2);
|
||||
use IPC::Open3 qw(open3);
|
||||
use Getopt::Std;
|
||||
use Data::Dumper;
|
||||
use IO::Socket;
|
||||
use LWP::UserAgent;
|
||||
use Cwd 'abs_path';
|
||||
use Template;
|
||||
use File::Copy::Recursive qw(dircopy);
|
||||
|
||||
my @TYPES = qw(action config misc rule target);
|
||||
my $SCRIPT = basename($0);
|
||||
my $SCRIPT_DIR = File::Spec->rel2abs(dirname($0));
|
||||
my $REG_DIR = "$SCRIPT_DIR/regression";
|
||||
my $NGINX_DIR = "$REG_DIR/nginx";
|
||||
my $NGINX_CONF_TEMP = "$REG_DIR/nginx/conf/nginx.conf.template";
|
||||
my $NGINX = q(/usr/local/nginx/sbin/nginx);
|
||||
|
||||
my $PASSED = 0;
|
||||
my $TOTAL = 0;
|
||||
my $BUFSIZ = 32768;
|
||||
my %C = ();
|
||||
my %FILE = ();
|
||||
my $UA_NAME = "ModSecurity Regression Tests/1.2.3";
|
||||
my $UA = LWP::UserAgent->new;
|
||||
$UA->agent($UA_NAME);
|
||||
|
||||
$SIG{TERM} = $SIG{INT} = \&handle_interrupt;
|
||||
|
||||
my %opt;
|
||||
getopts('A:E:D:C:T:H:a:p:dvh', \%opt);
|
||||
|
||||
if ($opt{d}) {
|
||||
$Data::Dumper::Indent = 1;
|
||||
$Data::Dumper::Terse = 1;
|
||||
$Data::Dumper::Pad = "";
|
||||
$Data::Dumper::Quotekeys = 0;
|
||||
}
|
||||
|
||||
sub usage {
|
||||
print stderr <<"EOT";
|
||||
@_
|
||||
Usage: $SCRIPT [options] [file [N]]
|
||||
|
||||
Options:
|
||||
-P path Specify nginx prefix path (default: $NGINX_DIR)
|
||||
-a file Specify nginx binary (default: $NGINX)
|
||||
-p port Specify nginx port (default: 8088)
|
||||
-v Enable verbose output (details on failure).
|
||||
-d Enable debugging output.
|
||||
-h This help.
|
||||
EOT
|
||||
|
||||
exit(1);
|
||||
}
|
||||
|
||||
usage() if ($opt{h});
|
||||
|
||||
### Check nginx binary
|
||||
if (defined $opt{a}) {
|
||||
$NGINX = $opt{a};
|
||||
}
|
||||
else {
|
||||
$opt{a} = $NGINX;
|
||||
}
|
||||
usage("Invalid Apache startup script: $NGINX\n") unless (-e $NGINX);
|
||||
|
||||
|
||||
### Defaults
|
||||
$opt{P} = "$NGINX_DIR" unless (defined $opt{P});
|
||||
|
||||
my $CONF_DIR = "$opt{P}/conf";
|
||||
my $FILES_DIR = "$opt{P}/logs";
|
||||
my $PID_FILE = "$FILES_DIR/nginx.pid";
|
||||
|
||||
$opt{A} = "$FILES_DIR/modsec_audit.log";
|
||||
$opt{D} = "$FILES_DIR/modsec_debug.log";
|
||||
$opt{E} = "$FILES_DIR/error.log";
|
||||
$opt{C} = "$CONF_DIR/nginx.conf";
|
||||
$opt{p} = 8088 unless (defined $opt{p});
|
||||
$opt{v} = 1 if ($opt{d});
|
||||
|
||||
if ( !-d "$opt{P}" ) {
|
||||
make_path($opt{P}) or die $!;
|
||||
}
|
||||
|
||||
if ( !-d "$opt{P}/logs" ) {
|
||||
make_path("$opt{P}/logs") or die $!;
|
||||
}
|
||||
|
||||
if ( !-d "$opt{P}/html" ) {
|
||||
make_path("$opt{P}/html") or die $!;
|
||||
}
|
||||
|
||||
dircopy("$REG_DIR/server_root/htdocs","$opt{P}/html") or die $!;
|
||||
|
||||
%ENV = (
|
||||
%ENV,
|
||||
$NGINX_DIR => $opt{P},
|
||||
SERVER_PORT => $opt{p},
|
||||
SERVER_NAME => "localhost",
|
||||
# TEST_NGX_PREFIX => $NGINX_DIR,
|
||||
# DATA_DIR => $DATA_DIR,
|
||||
# TEMP_DIR => $TEMP_DIR,
|
||||
# UPLOAD_DIR => $UPLOAD_DIR,
|
||||
CONF_DIR => $CONF_DIR,
|
||||
# MODULES_DIR => $MODULES_DIR,
|
||||
LOGS_DIR => $FILES_DIR,
|
||||
SCRIPT_DIR => $SCRIPT_DIR,
|
||||
REGRESSION_DIR => $REG_DIR,
|
||||
DIST_ROOT => File::Spec->rel2abs(dirname("$SCRIPT_DIR/../../..")),
|
||||
AUDIT_LOG => $opt{A},
|
||||
DEBUG_LOG => $opt{D},
|
||||
ERROR_LOG => $opt{E},
|
||||
NGINX_CONF => $opt{C},
|
||||
# HTDOCS => $opt{H},
|
||||
USER_AGENT => $UA_NAME,
|
||||
);
|
||||
|
||||
#dbg("OPTIONS: ", \%opt);
|
||||
|
||||
if (-e "$PID_FILE") {
|
||||
msg("Shutting down previous instance: $PID_FILE");
|
||||
nginx_stop();
|
||||
}
|
||||
|
||||
if (defined $ARGV[0]) {
|
||||
runfile(dirname($ARGV[0]), basename($ARGV[0]), $ARGV[1]);
|
||||
done();
|
||||
}
|
||||
|
||||
for my $type (@TYPES) {
|
||||
my $dir = "$SCRIPT_DIR/regression/$type";
|
||||
my @cfg = ();
|
||||
|
||||
# Get test names
|
||||
opendir(DIR, "$dir") or quit(1, "Failed to open \"$dir\": $!");
|
||||
@cfg = grep { /\.t$/ && -f "$dir/$_" } readdir(DIR);
|
||||
closedir(DIR);
|
||||
|
||||
for my $cfg (sort @cfg) {
|
||||
runfile($dir, $cfg);
|
||||
}
|
||||
}
|
||||
done();
|
||||
|
||||
|
||||
sub runfile {
|
||||
my($dir, $cfg, $testnum) = @_;
|
||||
my $fn = "$dir/$cfg";
|
||||
my @data = ();
|
||||
my $edata;
|
||||
my @C = ();
|
||||
my @test = ();
|
||||
my $teststr;
|
||||
my $n = 0;
|
||||
my $pass = 0;
|
||||
|
||||
open(CFG, "<$fn") or quit(1, "Failed to open \"$fn\": $!");
|
||||
@data = <CFG>;
|
||||
|
||||
$edata = q/@C = (/ . join("", @data) . q/)/;
|
||||
eval $edata;
|
||||
quit(1, "Failed to read test data \"$cfg\": $@") if ($@);
|
||||
|
||||
unless (@C) {
|
||||
msg("\nNo tests defined for $fn");
|
||||
return;
|
||||
}
|
||||
|
||||
msg("\nLoaded ".@C." tests from $fn");
|
||||
for my $t (@C) {
|
||||
$n++;
|
||||
next if (defined $testnum and $n != $testnum);
|
||||
|
||||
my $nginx_up = 0;
|
||||
my %t = %{$t || {}};
|
||||
my $id = sprintf("%3d", $n);
|
||||
my $out = "";
|
||||
my $rc = 0;
|
||||
my $conf_fn;
|
||||
|
||||
# Startup nginx with optionally included conf.
|
||||
if (exists $t{conf} and defined $t{conf}) {
|
||||
$conf_fn = sprintf "%s/%s_%s_%06d.conf",
|
||||
$CONF_DIR, $t{type}, $cfg, $n;
|
||||
#dbg("Writing test config to: $conf_fn");
|
||||
open(CONF, ">$conf_fn") or die "Failed to open conf \"$conf_fn\": $!\n";
|
||||
print CONF (ref $t{conf} eq "CODE" ? eval { &{$t{conf}} } : $t{conf});
|
||||
msg("$@") if ($@);
|
||||
close CONF;
|
||||
my %conf=(config => $conf_fn, enable => "on");
|
||||
$nginx_up = nginx_start($t, \%conf) ? 0 : 1;
|
||||
}
|
||||
else {
|
||||
$nginx_up = nginx_start($t) ? 0 : 1;
|
||||
}
|
||||
|
||||
# Run any prerun setup
|
||||
if ($rc == 0 and exists $t{prerun} and defined $t{prerun}) {
|
||||
vrb("Executing perl prerun...");
|
||||
$rc = &{$t{prerun}};
|
||||
vrb("Perl prerun returned: $rc");
|
||||
}
|
||||
|
||||
if ($nginx_up) {
|
||||
# Perform the request and check response
|
||||
if (exists $t{request}) {
|
||||
my $resp = do_request($t{request});
|
||||
if (!$resp) {
|
||||
msg("invalid response");
|
||||
vrb("RESPONSE: ", $resp);
|
||||
$rc = 1;
|
||||
}
|
||||
else {
|
||||
for my $key (keys %{ $t{match_response} || {}}) {
|
||||
my($neg,$mtype) = ($key =~ m/^(-?)(.*)$/);
|
||||
my $m = $t{match_response}{$key};
|
||||
my $match = match_response($mtype, $resp, $m);
|
||||
if ($neg and defined $match) {
|
||||
$rc = 1;
|
||||
msg("response $mtype matched: $m");
|
||||
vrb($resp);
|
||||
last;
|
||||
}
|
||||
elsif (!$neg and !defined $match) {
|
||||
$rc = 1;
|
||||
msg("response $mtype failed to match: $m");
|
||||
vrb($resp);
|
||||
last;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Run any arbitrary perl tests
|
||||
if ($rc == 0 and exists $t{test} and defined $t{test}) {
|
||||
dbg("Executing perl test(s)...");
|
||||
$rc = eval { &{$t{test}} };
|
||||
if (! defined $rc) {
|
||||
msg("Error running test: $@");
|
||||
$rc = -1;
|
||||
}
|
||||
dbg("Perl tests returned: $rc");
|
||||
}
|
||||
|
||||
# Search for all log matches
|
||||
if ($rc == 0 and exists $t{match_log} and defined $t{match_log}) {
|
||||
for my $key (keys %{ $t{match_log} || {}}) {
|
||||
my($neg,$mtype) = ($key =~ m/^(-?)(.*)$/);
|
||||
my $m = $t{match_log}{$key};
|
||||
my $match = match_log($mtype, @{$m || []});
|
||||
if ($neg and defined $match) {
|
||||
$rc = 1;
|
||||
msg("$mtype log matched: $m->[0]");
|
||||
last;
|
||||
}
|
||||
elsif (!$neg and !defined $match) {
|
||||
$rc = 1;
|
||||
msg("$mtype log failed to match: $m->[0]");
|
||||
last;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Search for all file matches
|
||||
if ($rc == 0 and exists $t{match_file} and defined $t{match_file}) {
|
||||
sleep 1; # Make sure the file exists
|
||||
for my $key (keys %{ $t{match_file} || {}}) {
|
||||
my($neg,$fn) = ($key =~ m/^(-?)(.*)$/);
|
||||
my $m = $t{match_file}{$key};
|
||||
my $match = match_file($fn, $m);
|
||||
if ($neg and defined $match) {
|
||||
$rc = 1;
|
||||
msg("$fn file matched: $m");
|
||||
last;
|
||||
}
|
||||
elsif (!$neg and !defined $match) {
|
||||
$rc = 1;
|
||||
msg("$fn file failed match: $m");
|
||||
last;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
msg("Failed to start nginx.");
|
||||
$rc = 1;
|
||||
}
|
||||
|
||||
if ($rc == 0) {
|
||||
$pass++;
|
||||
}
|
||||
else {
|
||||
vrb("Test Config: $conf_fn");
|
||||
vrb("Debug Log: $FILE{debug}{fn}");
|
||||
dbg(escape("$FILE{debug}{buf}"));
|
||||
vrb("Error Log: $FILE{error}{fn}");
|
||||
dbg(escape("$FILE{error}{buf}"));
|
||||
}
|
||||
|
||||
msg(sprintf("%s) %s%s: %s%s", $id, $t{type}, (exists($t{comment}) ? " - $t{comment}" : ""), ($rc ? "failed" : "passed"), ((defined($out) && $out ne "")? " ($out)" : "")));
|
||||
|
||||
if ($nginx_up) {
|
||||
$nginx_up = nginx_stop(\%t) ? 0 : 1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
$TOTAL += $testnum ? 1 : $n;
|
||||
$PASSED += $pass;
|
||||
|
||||
msg(sprintf("Passed: %2d; Failed: %2d", $pass, $testnum ? (1 - $pass) : ($n - $pass)));
|
||||
}
|
||||
|
||||
# Take out any indenting and translate LF -> CRLF
|
||||
sub normalize_raw_request_data {
|
||||
my $r = $_[0];
|
||||
|
||||
# Allow for indenting in test file
|
||||
$r =~ s/^[ \t]*\x0d?\x0a//s;
|
||||
my($indention) = ($r =~ m/^([ \t]*)/s); # indention taken from first line
|
||||
$r =~ s/^$indention//mg;
|
||||
$r =~ s/(\x0d?\x0a)[ \t]+$/$1/s;
|
||||
|
||||
# Translate LF to CRLF
|
||||
$r =~ s/^\x0a/\x0d\x0a/mg;
|
||||
$r =~ s/([^\x0d])\x0a/$1\x0d\x0a/mg;
|
||||
|
||||
return $r;
|
||||
}
|
||||
|
||||
sub do_raw_request {
|
||||
my $sock = new IO::Socket::INET(
|
||||
Proto => "tcp",
|
||||
PeerAddr => "localhost",
|
||||
PeerPort => $opt{p},
|
||||
) or msg("Failed to connect to localhost:$opt{p}: $@");
|
||||
return unless ($sock);
|
||||
|
||||
# Join togeather the request
|
||||
my $r = join("", @_);
|
||||
dbg($r);
|
||||
|
||||
# Write to socket
|
||||
print $sock "$r";
|
||||
$sock->shutdown(1);
|
||||
|
||||
# Read from socket
|
||||
my @resp = <$sock>;
|
||||
$sock->close();
|
||||
|
||||
return HTTP::Response->parse(join("", @resp));
|
||||
}
|
||||
|
||||
sub do_request {
|
||||
my $r = $_[0];
|
||||
|
||||
# Allow test to execute code
|
||||
if (ref $r eq "CODE") {
|
||||
$r = eval { &$r };
|
||||
msg("$@") unless (defined $r);
|
||||
}
|
||||
|
||||
if (ref $r eq "HTTP::Request") {
|
||||
my $resp = $UA->request($r);
|
||||
dbg($resp->request()->as_string()) if ($opt{d});
|
||||
return $resp
|
||||
}
|
||||
else {
|
||||
return do_raw_request($r);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
sub match_response {
|
||||
my($name, $resp, $re) = @_;
|
||||
|
||||
msg("Warning: Empty regular expression.") if (!defined $re or $re eq "");
|
||||
|
||||
if ($name eq "status") {
|
||||
return $& if ($resp->code =~ m/$re/);
|
||||
}
|
||||
elsif ($name eq "content") {
|
||||
return $& if ($resp->content =~ m/$re/m);
|
||||
}
|
||||
elsif ($name eq "raw") {
|
||||
return $& if ($resp->as_string =~ m/$re/m);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
sub read_log {
|
||||
my($name, $timeout, $graph) = @_;
|
||||
return match_log($name, undef, $timeout, $graph);
|
||||
}
|
||||
|
||||
sub match_log {
|
||||
my($name, $re, $timeout, $graph) = @_;
|
||||
my $t0 = gettimeofday;
|
||||
my($fh,$rbuf) = ($FILE{$name}{fd}, \$FILE{$name}{buf});
|
||||
my $n = length($$rbuf);
|
||||
my $rc = undef;
|
||||
|
||||
unless (defined $fh) {
|
||||
msg("Error: File \"$name\" is not opened for matching.");
|
||||
return;
|
||||
}
|
||||
|
||||
$timeout = 0 unless (defined $timeout);
|
||||
|
||||
my $i = 0;
|
||||
my $graphed = 0;
|
||||
READ: {
|
||||
do {
|
||||
my $nbytes = $fh->sysread($$rbuf, $BUFSIZ, $n);
|
||||
if (!defined($nbytes)) {
|
||||
msg("Error: Could not read \"$name\" log: $!");
|
||||
last;
|
||||
}
|
||||
elsif (!defined($re) and $nbytes == 0) {
|
||||
last;
|
||||
}
|
||||
|
||||
# Remove APR pool debugging
|
||||
$$rbuf =~ s/POOL DEBUG:[^\n]+PALLOC[^\n]+\n//sg;
|
||||
|
||||
$n = length($$rbuf);
|
||||
|
||||
#dbg("Match \"$re\" in $name \"$$rbuf\" ($n)");
|
||||
if ($$rbuf =~ m/$re/m) {
|
||||
$rc = $&;
|
||||
last;
|
||||
}
|
||||
# TODO: Use select()/poll()
|
||||
sleep 0.1 unless ($nbytes == $BUFSIZ);
|
||||
if ($graph and $opt{d}) {
|
||||
$i++;
|
||||
if ($i == 10) {
|
||||
$graphed++;
|
||||
$i=0;
|
||||
print STDERR $graph if ($graphed == 1);
|
||||
print STDERR "."
|
||||
}
|
||||
}
|
||||
} while (gettimeofday - $t0 < $timeout);
|
||||
}
|
||||
print STDERR "\n" if ($graphed);
|
||||
|
||||
return $rc;
|
||||
}
|
||||
|
||||
sub match_file {
|
||||
my($neg,$fn) = ($_[0] =~ m/^(-?)(.*)$/);
|
||||
unless (exists $FILE{$fn}) {
|
||||
eval {
|
||||
$FILE{$fn}{fn} = $fn;
|
||||
$FILE{$fn}{fd} = new FileHandle($fn, O_RDONLY) or die "$!\n";
|
||||
$FILE{$fn}{fd}->blocking(0);
|
||||
$FILE{$fn}{buf} = "";
|
||||
};
|
||||
if ($@) {
|
||||
msg("Warning: Failed to open file \"$fn\": $@");
|
||||
return;
|
||||
}
|
||||
}
|
||||
return match_log($_[0], $_[1]); # timeout makes no sense
|
||||
}
|
||||
|
||||
sub quote_shell {
|
||||
my($s) = @_;
|
||||
return $s unless ($s =~ m|[^\w!%+,\-./:@^]|);
|
||||
$s =~ s/(['\\])/\\$1/g;
|
||||
return "'$s'";
|
||||
}
|
||||
|
||||
sub escape {
|
||||
my @new = ();
|
||||
for my $c (split(//, $_[0])) {
|
||||
my $oc = ord($c);
|
||||
push @new, ((($oc >= 0x20 and $oc <= 0x7e) or $oc == 0x0a or $oc == 0x0d) ? $c : sprintf("\\x%02x", ord($c)));
|
||||
}
|
||||
join('', @new);
|
||||
}
|
||||
|
||||
sub dbg {
|
||||
return unless(@_ and $opt{d});
|
||||
my $out = join "", map {
|
||||
(ref $_ ne "" ? Dumper($_) : $_)
|
||||
} @_;
|
||||
$out =~ s/^/DBG: /mg;
|
||||
print STDOUT "$out\n";
|
||||
}
|
||||
|
||||
sub vrb {
|
||||
return unless(@_ and $opt{v});
|
||||
msg(@_);
|
||||
}
|
||||
|
||||
sub msg {
|
||||
return unless(@_);
|
||||
my $out = join "", map {
|
||||
(ref $_ ne "" ? Dumper($_) : $_)
|
||||
} @_;
|
||||
print STDOUT "$out\n";
|
||||
}
|
||||
|
||||
sub handle_interrupt {
|
||||
$SIG{TERM} = $SIG{INT} = \&handle_interrupt;
|
||||
|
||||
msg("Interrupted via SIG$_[0]. Shutting down tests...");
|
||||
nginx_stop();
|
||||
|
||||
quit(1);
|
||||
}
|
||||
|
||||
sub quit {
|
||||
my($ec,$msg) = @_;
|
||||
$ec = 0 unless (defined $_[0]);
|
||||
|
||||
msg("$msg") if (defined $msg);
|
||||
|
||||
exit $ec;
|
||||
}
|
||||
|
||||
sub done {
|
||||
if ($PASSED != $TOTAL) {
|
||||
quit(1, "\n$PASSED/$TOTAL tests passed.");
|
||||
}
|
||||
|
||||
quit(0, "\nAll tests passed ($TOTAL).");
|
||||
}
|
||||
|
||||
sub nginx_stop {
|
||||
my $t = shift;
|
||||
my @p = (
|
||||
$NGINX,
|
||||
-p => $opt{P},
|
||||
-s => "quit",
|
||||
);
|
||||
|
||||
my $nginx_out;
|
||||
my $nginx_pid = open3(undef, $nginx_out, undef, @p) or quit(1);
|
||||
my $out = join("\\n", grep(!/POOL DEBUG/, (<$nginx_out>)));
|
||||
close $nginx_out;
|
||||
waitpid($nginx_pid, 0);
|
||||
|
||||
my $rc = $?;
|
||||
if ( WIFEXITED($rc) ) {
|
||||
$rc = WEXITSTATUS($rc);
|
||||
vrb("Nginx stop returned with $rc.") if ($rc);
|
||||
}
|
||||
elsif( WIFSIGNALED($rc) ) {
|
||||
msg("Nginx stop failed with signal " . WTERMSIG($rc) . ".");
|
||||
$rc = -1;
|
||||
}
|
||||
else {
|
||||
msg("Nginx stop failed with unknown error.");
|
||||
$rc = -1;
|
||||
}
|
||||
|
||||
sleep 0.5;
|
||||
if (-e $PID_FILE) {
|
||||
msg("Nginx stop failed: $PID_FILE still exists");
|
||||
}
|
||||
|
||||
return $rc;
|
||||
}
|
||||
|
||||
|
||||
sub nginx_reset_fd {
|
||||
my($t) = @_;
|
||||
|
||||
# Cleanup
|
||||
for my $key (keys %FILE) {
|
||||
if (exists $FILE{$key}{fd} and defined $FILE{$key}{fd}) {
|
||||
$FILE{$key}{fd}->close();
|
||||
}
|
||||
delete $FILE{$key};
|
||||
}
|
||||
|
||||
# Error
|
||||
eval {
|
||||
$FILE{error}{fn} = $opt{E};
|
||||
$FILE{error}{fd} = new FileHandle($opt{E}, O_RDWR|O_CREAT) or die "$!\n";
|
||||
$FILE{error}{fd}->blocking(0);
|
||||
$FILE{error}{fd}->sysseek(0, 2);
|
||||
$FILE{error}{buf} = "";
|
||||
};
|
||||
if ($@) {
|
||||
msg("Warning: Failed to open file \"$opt{E}\": $@");
|
||||
return undef;
|
||||
}
|
||||
|
||||
# Audit
|
||||
eval {
|
||||
$FILE{audit}{fn} = $opt{A};
|
||||
$FILE{audit}{fd} = new FileHandle($opt{A}, O_RDWR|O_CREAT) or die "$!\n";
|
||||
$FILE{audit}{fd}->blocking(0);
|
||||
$FILE{audit}{fd}->sysseek(0, 2);
|
||||
$FILE{audit}{buf} = "";
|
||||
};
|
||||
if ($@) {
|
||||
msg("Warning: Failed to open file \"$opt{A}\": $@");
|
||||
return undef;
|
||||
}
|
||||
|
||||
# Debug
|
||||
eval {
|
||||
$FILE{debug}{fn} = $opt{D};
|
||||
$FILE{debug}{fd} = new FileHandle($opt{D}, O_RDWR|O_CREAT) or die "$!\n";
|
||||
$FILE{debug}{fd}->blocking(0);
|
||||
$FILE{debug}{fd}->sysseek(0, 2);
|
||||
$FILE{debug}{buf} = "";
|
||||
};
|
||||
if ($@) {
|
||||
msg("Warning: Failed to open file \"$opt{D}\": $@");
|
||||
return undef;
|
||||
}
|
||||
|
||||
# Any extras listed in "match_log"
|
||||
if ($t and exists $t->{match_log}) {
|
||||
for my $k (keys %{ $t->{match_log} || {} }) {
|
||||
my($neg,$fn) = ($k =~ m/^(-?)(.*)$/);
|
||||
next if (!$fn or exists $FILE{$fn});
|
||||
eval {
|
||||
$FILE{$fn}{fn} = $fn;
|
||||
$FILE{$fn}{fd} = new FileHandle($fn, O_RDWR|O_CREAT) or die "$!\n";
|
||||
$FILE{$fn}{fd}->blocking(0);
|
||||
$FILE{$fn}{fd}->sysseek(0, 2);
|
||||
$FILE{$fn}{buf} = "";
|
||||
};
|
||||
if ($@) {
|
||||
msg("Warning: Failed to open file \"$fn\": $@");
|
||||
return undef;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub encode_chunked {
|
||||
my($data, $size) = @_;
|
||||
$size = 128 unless ($size);
|
||||
my $chunked = "";
|
||||
|
||||
my $n = 0;
|
||||
my $bytes = length($data);
|
||||
while ($bytes >= $size) {
|
||||
$chunked .= sprintf "%x\x0d\x0a%s\x0d\x0a", $size, substr($data, $n, $size);
|
||||
$n += $size;
|
||||
$bytes -= $size;
|
||||
}
|
||||
if ($bytes) {
|
||||
$chunked .= sprintf "%x\x0d\x0a%s\x0d\x0a", $bytes, substr($data, $n, $bytes);
|
||||
}
|
||||
$chunked .= "0\x0d\x0a\x0d\x0a"
|
||||
}
|
||||
|
||||
sub nginx_start {
|
||||
my ($t) = shift;
|
||||
my($C) = shift;
|
||||
|
||||
my %conf = (
|
||||
listen => "$opt{p}",
|
||||
config => "$REG_DIR/nginx/conf/empty.conf",
|
||||
enable => "off",
|
||||
);
|
||||
|
||||
while(my($k,$v)= each %$C){
|
||||
$conf{$k}=$v;
|
||||
}
|
||||
|
||||
my ($tt) = Template->new(INCLUDE_PATH => "$REG_DIR/nginx/conf/");
|
||||
my ($output);
|
||||
$tt->process("nginx.conf.template", \%conf, \$output) || die $tt->error;
|
||||
|
||||
open (OUTFILE, ">$opt{C}");
|
||||
print OUTFILE "$output";
|
||||
close(OUTFILE);
|
||||
|
||||
nginx_reset_fd($t);
|
||||
|
||||
my @p = ($NGINX, -p => $opt{P});
|
||||
|
||||
my $nginx_out;
|
||||
my $nginx_pid = open3(undef, $nginx_out, undef, @p) or quit(1);
|
||||
my $out = join("\\n", grep(!/POOL DEBUG/, (<$nginx_out>)));
|
||||
close $nginx_out;
|
||||
waitpid($nginx_pid, 0);
|
||||
|
||||
my $rc = $?;
|
||||
if ( WIFEXITED($rc) ) {
|
||||
$rc = WEXITSTATUS($rc);
|
||||
vrb("Nginx start returned with $rc.") if ($rc);
|
||||
}
|
||||
elsif( WIFSIGNALED($rc) ) {
|
||||
msg("Nginx start failed with signal " . WTERMSIG($rc) . ".");
|
||||
$rc = -1;
|
||||
}
|
||||
else {
|
||||
msg("Nginx start failed with unknown error.");
|
||||
$rc = -1;
|
||||
}
|
||||
|
||||
# Look for startup msg
|
||||
# unless (defined match_log("error", qr/start worker process/, 60, "Waiting on nginx to start: ")) {
|
||||
# vrb(join(" ", map { quote_shell($_) } @p));
|
||||
# vrb(match_log("error", qr/(^.*ModSecurity: .*)/sm, 10));
|
||||
# msg("Nginx server failed to start.");
|
||||
# nginx_stop();
|
||||
# return -1;
|
||||
# }
|
||||
|
||||
return $rc;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user