diff --git a/src/ngx_http_modsecurity_body_filter.c b/src/ngx_http_modsecurity_body_filter.c index 725f986..3b1db12 100644 --- a/src/ngx_http_modsecurity_body_filter.c +++ b/src/ngx_http_modsecurity_body_filter.c @@ -50,7 +50,7 @@ ngx_http_modsecurity_body_filter(ngx_http_request_t *r, ngx_chain_t *in) ctx = ngx_http_get_module_ctx(r, ngx_http_modsecurity_module); - dd("body filter, recovering ctx: %p", ctx); + ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0, "body filter, recovering ctx: %p", ctx); if (ctx == NULL) { return ngx_http_next_body_filter(r, in); @@ -155,11 +155,11 @@ ngx_http_modsecurity_body_filter(ngx_http_request_t *r, ngx_chain_t *in) is_request_processed = chain->buf->last_buf; if (is_request_processed) { - ngx_pool_t *old_pool; + // ngx_pool_t *old_pool; - old_pool = ngx_http_modsecurity_pcre_malloc_init(r->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); + // 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 */ @@ -176,7 +176,7 @@ ngx_http_modsecurity_body_filter(ngx_http_request_t *r, ngx_chain_t *in) } if (!is_request_processed) { - dd("buffer was not fully loaded! ctx: %p", ctx); + ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0, "buffer was not fully loaded! ctx: %p", ctx); } /* XXX: xflt_filter() -- return NGX_OK here */ diff --git a/src/ngx_http_modsecurity_common.h b/src/ngx_http_modsecurity_common.h index 11fdc2d..34c7a80 100644 --- a/src/ngx_http_modsecurity_common.h +++ b/src/ngx_http_modsecurity_common.h @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -117,6 +118,9 @@ typedef struct { void *rules_set; ngx_flag_t enable; + + ngx_str_t thread_pool_name; + ngx_thread_pool_t *thread_pool; #if defined(MODSECURITY_SANITY_CHECKS) && (MODSECURITY_SANITY_CHECKS) ngx_flag_t sanity_checks_enabled; #endif diff --git a/src/ngx_http_modsecurity_header_filter.c b/src/ngx_http_modsecurity_header_filter.c index c36be19..3ce55b9 100644 --- a/src/ngx_http_modsecurity_header_filter.c +++ b/src/ngx_http_modsecurity_header_filter.c @@ -415,18 +415,18 @@ ngx_http_modsecurity_header_filter(ngx_http_request_t *r) int ret = 0; ngx_uint_t status; char *http_response_ver; - ngx_pool_t *old_pool; + // 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); + ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0, "header filter, recovering ctx: %p", ctx); if (ctx == NULL) { - dd("something really bad happened or ModSecurity is disabled. going to the next filter."); + ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0, "something really bad happened or ModSecurity is disabled. going to the next filter."); return ngx_http_next_header_filter(r); } @@ -442,7 +442,7 @@ ngx_http_modsecurity_header_filter(ngx_http_request_t *r) /* * FIXME: verify if this request is already processed. */ - dd("Already processed... going to the next header..."); + ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0, "Already processed... going to the next header..."); return ngx_http_next_header_filter(r); } @@ -469,13 +469,13 @@ ngx_http_modsecurity_header_filter(ngx_http_request_t *r) */ 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_log_error(NGX_LOG_DEBUG, r->connection->log, 0, " 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); + 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++) @@ -523,9 +523,9 @@ ngx_http_modsecurity_header_filter(ngx_http_request_t *r) } #endif - old_pool = ngx_http_modsecurity_pcre_malloc_init(r->pool); + // 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); + // 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); diff --git a/src/ngx_http_modsecurity_log.c b/src/ngx_http_modsecurity_log.c index d713a65..03b0c50 100644 --- a/src/ngx_http_modsecurity_log.c +++ b/src/ngx_http_modsecurity_log.c @@ -41,13 +41,13 @@ ngx_http_modsecurity_log_handler(ngx_http_request_t *r) ngx_http_modsecurity_ctx_t *ctx; ngx_http_modsecurity_conf_t *mcf; - dd("catching a new _log_ phase handler"); + ngx_log_error(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "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; + ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0, "ModSecurity not enabled... returning"); + return NGX_DECLINED; } /* @@ -63,13 +63,13 @@ ngx_http_modsecurity_log_handler(ngx_http_request_t *r) dd("recovering ctx: %p", ctx); if (ctx == NULL) { - dd("something really bad happened here. returning NGX_ERROR"); + ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0, "something really bad happened here. returning NGX_ERROR"); return NGX_ERROR; } if (ctx->logged) { - dd("already logged earlier"); - return NGX_OK; + ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0, "already logged earlier"); + return NGX_DECLINED; } dd("calling msc_process_logging for %p", ctx); @@ -77,5 +77,5 @@ ngx_http_modsecurity_log_handler(ngx_http_request_t *r) msc_process_logging(ctx->modsec_transaction); ngx_http_modsecurity_pcre_malloc_done(old_pool); - return NGX_OK; + return NGX_DECLINED; } diff --git a/src/ngx_http_modsecurity_module.c b/src/ngx_http_modsecurity_module.c index 5c341e2..71b5858 100644 --- a/src/ngx_http_modsecurity_module.c +++ b/src/ngx_http_modsecurity_module.c @@ -23,6 +23,8 @@ #include #include #include +#include +#include static ngx_int_t ngx_http_modsecurity_init(ngx_conf_t *cf); static void *ngx_http_modsecurity_create_main_conf(ngx_conf_t *cf); @@ -32,7 +34,6 @@ static char *ngx_http_modsecurity_merge_conf(ngx_conf_t *cf, void *parent, void 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 @@ -46,7 +47,8 @@ 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) { + if (ngx_http_modsec_pcre_pool) + { return ngx_palloc(ngx_http_modsec_pcre_pool, size); } @@ -58,7 +60,8 @@ ngx_http_modsec_pcre_malloc(size_t size) static void ngx_http_modsec_pcre_free(void *ptr) { - if (ngx_http_modsec_pcre_pool) { + if (ngx_http_modsec_pcre_pool) + { ngx_pfree(ngx_http_modsec_pcre_pool, ptr); return; } @@ -74,9 +77,10 @@ ngx_http_modsec_pcre_free(void *ptr) ngx_pool_t * ngx_http_modsecurity_pcre_malloc_init(ngx_pool_t *pool) { - ngx_pool_t *old_pool; + ngx_pool_t *old_pool; - if (pcre_malloc != ngx_http_modsec_pcre_malloc) { + if (pcre_malloc != ngx_http_modsec_pcre_malloc) + { ngx_http_modsec_pcre_pool = pool; old_pcre_malloc = pcre_malloc; @@ -94,12 +98,12 @@ ngx_http_modsecurity_pcre_malloc_init(ngx_pool_t *pool) return old_pool; } -void -ngx_http_modsecurity_pcre_malloc_done(ngx_pool_t *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) { + if (old_pool == NULL) + { pcre_malloc = old_pcre_malloc; pcre_free = old_pcre_free; } @@ -114,12 +118,14 @@ ngx_inline char *ngx_str_to_char(ngx_str_t a, ngx_pool_t *p) { char *str = NULL; - if (a.len == 0) { + if (a.len == 0) + { return NULL; } - str = ngx_pnalloc(p, a.len+1); - if (str == 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; @@ -130,9 +136,8 @@ ngx_inline char *ngx_str_to_char(ngx_str_t a, ngx_pool_t *p) return str; } - ngx_inline int -ngx_http_modsecurity_process_intervention (Transaction *transaction, ngx_http_request_t *r, ngx_int_t early_log) +ngx_http_modsecurity_process_intervention(Transaction *transaction, ngx_http_request_t *r, ngx_int_t early_log) { char *log = NULL; ModSecurityIntervention intervention; @@ -150,19 +155,22 @@ ngx_http_modsecurity_process_intervention (Transaction *transaction, ngx_http_re return NGX_HTTP_INTERNAL_SERVER_ERROR; } - if (msc_intervention(transaction, &intervention) == 0) { + if (msc_intervention(transaction, &intervention) == 0) + { dd("nothing to do"); return 0; } log = intervention.log; - if (intervention.log == NULL) { + 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); + ngx_log_error(NGX_LOG_INFO, (ngx_log_t *)r->connection->log, 0, "%s", log); - if (intervention.log != NULL) { + if (intervention.log != NULL) + { free(intervention.log); } @@ -217,11 +225,12 @@ ngx_http_modsecurity_process_intervention (Transaction *transaction, ngx_http_re */ msc_update_status_code(ctx->modsec_transaction, intervention.status); - if (early_log) { + 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) { @@ -234,13 +243,11 @@ ngx_http_modsecurity_process_intervention (Transaction *transaction, ngx_http_re return 0; } - -void -ngx_http_modsecurity_cleanup(void *data) +void ngx_http_modsecurity_cleanup(void *data) { ngx_http_modsecurity_ctx_t *ctx; - ctx = (ngx_http_modsecurity_ctx_t *) data; + ctx = (ngx_http_modsecurity_ctx_t *)data; msc_transaction_cleanup(ctx->modsec_transaction); @@ -253,46 +260,48 @@ ngx_http_modsecurity_cleanup(void *data) #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; + 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."); + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "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); + ngx_log_error(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "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) { + 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_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_log_error(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "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"); + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "failed to create the ModSecurity context cleanup"); return NGX_CONF_ERROR; } cln->handler = ngx_http_modsecurity_cleanup; @@ -300,7 +309,8 @@ ngx_http_modsecurity_create_ctx(ngx_http_request_t *r) #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) { + if (ctx->sanity_headers_out == NULL) + { return NGX_CONF_ERROR; } #endif @@ -308,22 +318,39 @@ ngx_http_modsecurity_create_ctx(ngx_http_request_t *r) return ctx; } +char * +ngx_conf_modsecurity_set_thread_pool_name(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_str_t *value; + ngx_thread_pool_t *tp; + ngx_http_modsecurity_conf_t *mcf = conf; + + value = cf->args->elts; + value++; + + tp = ngx_thread_pool_add(cf, value); + ngx_log_error(NGX_LOG_DEBUG, cf->log, 0, "[ModSecurity] Thread Pool Address: %p", tp); + mcf->thread_pool = tp; + + return NGX_CONF_OK; +} char * -ngx_conf_set_rules(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +ngx_conf_modsecurity_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; + 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) { + if (rules == (char *)-1) + { return NGX_CONF_ERROR; } @@ -331,8 +358,9 @@ ngx_conf_set_rules(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) 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); + if (res < 0) + { + ngx_log_error(NGX_LOG_ERR, cf->log, 0, "Failed to load the rules: '%s' - reason: '%s'", rules, error); return strdup(error); } @@ -342,22 +370,22 @@ ngx_conf_set_rules(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) return NGX_CONF_OK; } - char * -ngx_conf_set_rules_file(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +ngx_conf_modsecurity_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; + 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) { + if (rules_set == (char *)-1) + { return NGX_CONF_ERROR; } @@ -365,8 +393,9 @@ ngx_conf_set_rules_file(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) 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); + if (res < 0) + { + ngx_log_error(NGX_LOG_ERR, cf->log, 0, "Failed to load the rules from: '%s' - reason: '%s'", rules_set, error); return strdup(error); } @@ -376,27 +405,28 @@ ngx_conf_set_rules_file(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) return NGX_CONF_OK; } - char * -ngx_conf_set_rules_remote(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +ngx_conf_modsecurity_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; + 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) { + if (rules_remote_server == (char *)-1) + { return NGX_CONF_ERROR; } - if (rules_remote_key == (char *)-1) { + if (rules_remote_key == (char *)-1) + { return NGX_CONF_ERROR; } @@ -404,8 +434,9 @@ ngx_conf_set_rules_remote(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) 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); + if (res < 0) + { + ngx_log_error(NGX_LOG_ERR, cf->log, 0, "Failed to load the rules from: '%s' - reason: '%s'", rules_remote_server, error); return strdup(error); } @@ -415,11 +446,11 @@ ngx_conf_set_rules_remote(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) 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; +char *ngx_conf_modsecurity_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; @@ -431,12 +462,14 @@ char *ngx_conf_set_transaction_id(ngx_conf_t *cf, ngx_command_t *cmd, void *conf ccv.complex_value = &cv; ccv.zero = 1; - if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { + 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) { + if (mcf->transaction_id == NULL) + { return NGX_CONF_ERROR; } @@ -445,82 +478,72 @@ char *ngx_conf_set_transaction_id(ngx_conf_t *cf, ngx_command_t *cmd, void *conf 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_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_thread_pool"), + NGX_HTTP_MAIN_CONF | NGX_HTTP_SRV_CONF | NGX_HTTP_LOC_CONF | NGX_CONF_TAKE1, + ngx_conf_modsecurity_set_thread_pool_name, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_modsecurity_conf_t, thread_pool_name), + NULL}, + {ngx_string("modsecurity_rules"), + NGX_HTTP_LOC_CONF | NGX_HTTP_SRV_CONF | NGX_HTTP_MAIN_CONF | NGX_CONF_TAKE1, + ngx_conf_modsecurity_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_modsecurity_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_modsecurity_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_modsecurity_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 */ + 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 */ + 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_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 -}; - + &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) @@ -534,7 +557,7 @@ ngx_http_modsecurity_init(ngx_conf_t *cf) 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"); + ngx_log_error(NGX_LOG_ERR, cf->log, 0, "We are not sure how this returns, NGINX doesn't seem to think it will ever be null"); return NGX_ERROR; } /** @@ -549,7 +572,7 @@ ngx_http_modsecurity_init(ngx_conf_t *cf) 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"); + ngx_log_error(NGX_LOG_ERR, cf->log, 0, "Not able to create a new NGX_HTTP_REWRITE_PHASE handle"); return NGX_ERROR; } *h_rewrite = ngx_http_modsecurity_rewrite_handler; @@ -564,7 +587,7 @@ ngx_http_modsecurity_init(ngx_conf_t *cf) h_preaccess = ngx_array_push(&cmcf->phases[NGX_HTTP_PREACCESS_PHASE].handlers); if (h_preaccess == NULL) { - dd("Not able to create a new NGX_HTTP_PREACCESS_PHASE handle"); + ngx_log_error(NGX_LOG_ERR, cf->log, 0, "Not able to create a new NGX_HTTP_PREACCESS_PHASE handle"); return NGX_ERROR; } *h_preaccess = ngx_http_modsecurity_pre_access_handler; @@ -579,34 +602,34 @@ ngx_http_modsecurity_init(ngx_conf_t *cf) 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"); + ngx_log_error(NGX_LOG_ERR, cf->log, 0, "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) { + if (rc != NGX_OK) + { return rc; } rc = ngx_http_modsecurity_body_filter_init(); - if (rc != NGX_OK) { + 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; + 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)); + conf = (ngx_http_modsecurity_main_conf_t *)ngx_pcalloc(cf->pool, + sizeof(ngx_http_modsecurity_main_conf_t)); if (conf == NULL) { @@ -624,7 +647,8 @@ ngx_http_modsecurity_create_main_conf(ngx_conf_t *cf) */ cln = ngx_pool_cleanup_add(cf->pool, 0); - if (cln == NULL) { + if (cln == NULL) + { return NGX_CONF_ERROR; } @@ -637,7 +661,7 @@ ngx_http_modsecurity_create_main_conf(ngx_conf_t *cf) conf->modsec = msc_init(); if (conf->modsec == NULL) { - dd("failed to create the ModSecurity instance"); + ngx_log_error(NGX_LOG_ERR, cf->log, 0, "failed to create the ModSecurity instance"); return NGX_CONF_ERROR; } @@ -645,39 +669,37 @@ ngx_http_modsecurity_create_main_conf(ngx_conf_t *cf) 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); + ngx_log_error(NGX_LOG_DEBUG, cf->log, 0, "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_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] %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; + 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)); + 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"); + ngx_log_error(NGX_LOG_ERR, cf->log, 0, "Failed to allocate space for ModSecurity configuration"); return NGX_CONF_ERROR; } @@ -695,44 +717,46 @@ ngx_http_modsecurity_create_conf(ngx_conf_t *cf) conf->rules_set = msc_create_rules_set(); conf->pool = cf->pool; conf->transaction_id = NGX_CONF_UNSET_PTR; + conf->thread_pool = ngx_thread_pool_add(cf, NULL); #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"); + if (cln == NULL) + { + ngx_log_error(NGX_LOG_ERR, cf->log, 0, "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); + ngx_log_error(NGX_LOG_DEBUG, cf->log, 0, "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) +// 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 +// 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); + ngx_log_error(NGX_LOG_DEBUG, cf->log, 0, "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_log_error(NGX_LOG_DEBUG, cf->log, 0, " state - parent: '%d' child: '%d'", + (int)c->enable, (int)p->enable); ngx_conf_merge_value(c->enable, p->enable, 0); + ngx_conf_merge_str_value(c->thread_pool_name, p->thread_pool_name, ""); 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); @@ -746,7 +770,8 @@ ngx_http_modsecurity_merge_conf(ngx_conf_t *cf, void *parent, void *child) #endif rules = msc_rules_merge(c->rules_set, p->rules_set, &error); - if (rules < 0) { + if (rules < 0) + { return strdup(error); } @@ -757,14 +782,13 @@ ngx_http_modsecurity_merge_conf(ngx_conf_t *cf, void *parent, void *child) 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; + ngx_pool_t *old_pool; + ngx_http_modsecurity_main_conf_t *mmcf; - mmcf = (ngx_http_modsecurity_main_conf_t *) data; + mmcf = (ngx_http_modsecurity_main_conf_t *)data; dd("deleting a main conf -- instance is: \"%p\"", mmcf->modsec); @@ -773,14 +797,13 @@ ngx_http_modsecurity_cleanup_instance(void *data) 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; + ngx_pool_t *old_pool; + ngx_http_modsecurity_conf_t *mcf; - mcf = (ngx_http_modsecurity_conf_t *) data; + mcf = (ngx_http_modsecurity_conf_t *)data; dd("deleting a loc conf -- RuleSet is: \"%p\"", mcf->rules_set); @@ -789,5 +812,4 @@ ngx_http_modsecurity_cleanup_rules(void *data) ngx_http_modsecurity_pcre_malloc_done(old_pool); } - /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/ngx_http_modsecurity_pre_access.c b/src/ngx_http_modsecurity_pre_access.c index abb7d3e..ba35509 100644 --- a/src/ngx_http_modsecurity_pre_access.c +++ b/src/ngx_http_modsecurity_pre_access.c @@ -20,6 +20,13 @@ #include "ngx_http_modsecurity_common.h" +typedef struct { + ngx_http_request_t *r; + // ngx_http_core_main_conf_t *cmcf; + ngx_http_modsecurity_ctx_t *ctx; + int return_code; +} ngx_http_modsecurity_pre_access_thread_ctx_t; + void ngx_http_modsecurity_request_read(ngx_http_request_t *r) { @@ -29,6 +36,7 @@ ngx_http_modsecurity_request_read(ngx_http_request_t *r) #if defined(nginx_version) && nginx_version >= 8011 r->main->count--; + ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0, "[ModSecurity] r->main->count: %d => %d", r->main->count+1, r->main->count); #endif if (ctx->waiting_more_body) @@ -40,22 +48,17 @@ ngx_http_modsecurity_request_read(ngx_http_request_t *r) } -ngx_int_t -ngx_http_modsecurity_pre_access_handler(ngx_http_request_t *r) +void +ngx_http_modsecurity_pre_access_worker(void *data, ngx_log_t *log) { #if 1 - ngx_pool_t *old_pool; - ngx_http_modsecurity_ctx_t *ctx; - ngx_http_modsecurity_conf_t *mcf; + // ngx_pool_t *old_pool; + ngx_http_modsecurity_pre_access_thread_ctx_t *t_ctx = data; + ngx_http_modsecurity_ctx_t *ctx = t_ctx->ctx; + ngx_http_request_t *r = t_ctx->r; - dd("catching a new _preaccess_ phase handler"); + ngx_log_error(NGX_LOG_DEBUG, log, 0, "[ModSecurity] Pre-Access Job Dispatched"); - 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. @@ -68,36 +71,210 @@ ngx_http_modsecurity_pre_access_handler(ngx_http_request_t *r) } */ - ctx = ngx_http_get_module_ctx(r, ngx_http_modsecurity_module); + int ret = 0; + int already_inspected = 0; + + ngx_log_error(NGX_LOG_DEBUG, log, 0, "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) { + t_ctx->return_code = NGX_HTTP_INTERNAL_SERVER_ERROR; + return; + } + /* + * Request body was saved to a file, probably we don't have a + * copy of it in memory. + */ + ngx_log_error(NGX_LOG_DEBUG, log, 0, "request body inspection: file -- %s", file_name); + + msc_request_body_from_file(ctx->modsec_transaction, file_name); + + already_inspected = 1; + } else { + ngx_log_error(NGX_LOG_DEBUG, log, 0, "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) { + t_ctx->return_code = ret; + return; + } + } + + /** + * 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) { + t_ctx->return_code = NGX_DECLINED; + return; + } + if (ret > 0) { + t_ctx->return_code = ret; + return; + } + - dd("recovering ctx: %p", ctx); + ngx_log_error(NGX_LOG_DEBUG, log, 0, "Nothing to add on the body inspection, reclaiming a NGX_DECLINED"); +#endif + t_ctx->return_code = NGX_DECLINED; + return; +} + +void ngx_http_modsecurity_pre_access_finalizer(ngx_event_t *ev){ + ngx_http_modsecurity_pre_access_thread_ctx_t *ctx = ev->data; + ngx_http_core_main_conf_t *cmcf; + + ngx_log_error(NGX_LOG_DEBUG, ctx->r->connection->log, 0, "[ModSecurity] Pre-Access Job Finalized"); + + --ctx->r->main->blocked; /* incremented in ngx_http_modsecurity_prevention_task_offload */ + ctx->r->aio = 0; + + ngx_log_error(NGX_LOG_DEBUG, ctx->r->connection->log, 0, "r->read_event_handler = %s", \ + ctx->r->read_event_handler == ngx_http_block_reading ? \ + "ngx_http_block_reading" : \ + ctx->r->read_event_handler == ngx_http_test_reading ? \ + "ngx_http_test_reading" : \ + ctx->r->read_event_handler == ngx_http_request_empty_handler ? \ + "ngx_http_request_empty_handler" : "UNKNOWN"); + + ngx_log_error(NGX_LOG_DEBUG, ctx->r->connection->log, 0, "r->write_event_handler = %s", \ + ctx->r->write_event_handler == ngx_http_handler ? \ + "ngx_http_handler" : \ + ctx->r->write_event_handler == ngx_http_core_run_phases ? \ + "ngx_http_core_run_phases" : \ + ctx->r->write_event_handler == ngx_http_request_empty_handler ? \ + "ngx_http_request_empty_handler" : "UNKNOWN"); + + cmcf = ngx_http_get_module_main_conf(ctx->r, ngx_http_core_module); + + switch (ctx->return_code) { + case NGX_OK: + ctx->r->phase_handler = cmcf->phase_engine.handlers->next; + ngx_http_core_run_phases(ctx->r); + break; + case NGX_DECLINED: + ctx->r->phase_handler++; + ngx_http_core_run_phases(ctx->r); + break; + case NGX_AGAIN: + case NGX_DONE: + // ngx_http_core_run_phases(ctx->r); + break; + default: + ngx_http_discard_request_body(ctx->r); + ngx_http_finalize_request(ctx->r, ctx->return_code); + } + + ngx_http_run_posted_requests(ctx->r->connection); +} + +ngx_int_t ngx_http_modsecurity_pre_access_handler(ngx_http_request_t *r) +{ + ngx_http_modsecurity_conf_t *mcf; + ngx_http_modsecurity_pre_access_thread_ctx_t *ctx; + ngx_http_modsecurity_ctx_t *m_ctx; + ngx_thread_task_t *task; + + ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0, "catching a new _preaccess_ phase handler"); + + ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0, "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"); + + ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0, "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"); - if (ctx == NULL) + mcf = ngx_http_get_module_loc_conf(r, ngx_http_modsecurity_module); + if (mcf == NULL || mcf->enable != 1) { - dd("ctx is null; Nothing we can do, returning an error."); + ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0, "ModSecurity not enabled... returning"); + return NGX_DECLINED; + } + + m_ctx = ngx_http_get_module_ctx(r, ngx_http_modsecurity_module); + + ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0, "recovering ctx: %p", m_ctx); + + if (m_ctx == NULL) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "ctx is null; Nothing we can do, returning an error."); return NGX_HTTP_INTERNAL_SERVER_ERROR; } - if (ctx->intervention_triggered) { + if (m_ctx->intervention_triggered) + { return NGX_DECLINED; } - if (ctx->waiting_more_body == 1) + if (m_ctx->waiting_more_body == 1) { - dd("waiting for more data before proceed. / count: %d", - r->main->count); + ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0, "waiting for more data before proceed. / count: %d", + r->main->count); return NGX_DONE; } - if (ctx->body_requested == 0) + if (m_ctx->body_requested == 0) { ngx_int_t rc = NGX_OK; - ctx->body_requested = 1; + m_ctx->body_requested = 1; - dd("asking for the request body, if any. Count: %d", - r->main->count); + ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0, "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. * @@ -108,7 +285,8 @@ ngx_http_modsecurity_pre_access_handler(ngx_http_request_t *r) */ r->request_body_in_single_buf = 1; r->request_body_in_persistent_file = 1; - if (!r->request_body_in_file_only) { + 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 @@ -117,112 +295,53 @@ ngx_http_modsecurity_pre_access_handler(ngx_http_request_t *r) } 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) || \ + 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--; + ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0, "[ModSecurity] r->main->count: %d => %d", r->main->count + 1, r->main->count); #endif return rc; } if (rc == NGX_AGAIN) { - dd("nginx is asking us to wait for more data."); + ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0, "nginx is asking us to wait for more data."); - ctx->waiting_more_body = 1; + m_ctx->waiting_more_body = 1; return NGX_DONE; } } - if (ctx->waiting_more_body == 0) + if (m_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; + task = ngx_thread_task_alloc(r->pool, sizeof(ngx_http_modsecurity_pre_access_thread_ctx_t)); - ngx_chain_t *chain = r->request_body->bufs; + ctx = task->ctx; + ctx->r = r; + ctx->ctx = m_ctx; + ctx->return_code = NGX_DECLINED; - /** - * 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. - */ + task->handler = ngx_http_modsecurity_pre_access_worker; + task->event.handler = ngx_http_modsecurity_pre_access_finalizer; + task->event.data = ctx; - 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."); - } + ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0, "[ModSecurity] Using Thread Pool: %p", mcf->thread_pool); - while (chain && !already_inspected) + if (ngx_thread_task_post(mcf->thread_pool, task) != NGX_OK) { - 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; - } + return NGX_ERROR; } - /** - * 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 ? */ + r->main->blocked++; + r->aio = 1; - 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; - } + return NGX_DONE; } - dd("Nothing to add on the body inspection, reclaiming a NGX_DECLINED"); -#endif + ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0, "Nothing to add on the body inspection, reclaiming a NGX_DECLINED"); return NGX_DECLINED; } - diff --git a/src/ngx_http_modsecurity_rewrite.c b/src/ngx_http_modsecurity_rewrite.c index ebf115e..ceefa69 100644 --- a/src/ngx_http_modsecurity_rewrite.c +++ b/src/ngx_http_modsecurity_rewrite.c @@ -20,20 +20,26 @@ #include "ngx_http_modsecurity_common.h" -ngx_int_t -ngx_http_modsecurity_rewrite_handler(ngx_http_request_t *r) +typedef struct { + ngx_http_request_t *r; + // ngx_http_core_main_conf_t *cmcf; + ngx_http_modsecurity_ctx_t *ctx; + int return_code; +} ngx_http_modsecurity_rewrite_thread_ctx_t; + +void ngx_http_modsecurity_rewrite_worker(void *data, ngx_log_t *log) { - ngx_pool_t *old_pool; - ngx_http_modsecurity_ctx_t *ctx; - ngx_http_modsecurity_conf_t *mcf; + // ngx_pool_t *old_pool; + ngx_http_modsecurity_rewrite_thread_ctx_t *t_ctx = data; + ngx_http_modsecurity_ctx_t *ctx = t_ctx->ctx; + ngx_http_request_t *r = t_ctx->r; - 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; - } + ngx_log_error(NGX_LOG_DEBUG, log, 0, "[ModSecurity] Rewrite Job Dispatched"); /* + * 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 " \ @@ -42,12 +48,6 @@ ngx_http_modsecurity_rewrite_handler(ngx_http_request_t *r) } */ - 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; @@ -59,13 +59,16 @@ ngx_http_modsecurity_rewrite_handler(ngx_http_request_t *r) */ ngx_str_t addr_text = connection->addr_text; - ctx = ngx_http_modsecurity_create_ctx(r); + t_ctx->ctx = ngx_http_modsecurity_create_ctx(r); + ctx = t_ctx->ctx; - dd("ctx was NULL, creating new context: %p", ctx); + ngx_log_error(NGX_LOG_DEBUG, log, 0, "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; + if (ctx == NULL) + { + ngx_log_error(NGX_LOG_ERR, log, 0, "ctx still null; Nothing we can do, returning an error."); + t_ctx->return_code = NGX_HTTP_INTERNAL_SERVER_ERROR; + return; } /** @@ -80,30 +83,37 @@ ngx_http_modsecurity_rewrite_handler(ngx_http_request_t *r) 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; + if (client_addr == (char *)-1) + { + t_ctx->return_code = NGX_HTTP_INTERNAL_SERVER_ERROR; + return; } 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; + if (ngx_connection_local_sockaddr(r->connection, &s, 0) != NGX_OK) + { + t_ctx->return_code = NGX_HTTP_INTERNAL_SERVER_ERROR; + return; } const char *server_addr = ngx_str_to_char(s, r->pool); - if (server_addr == (char*)-1) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; + if (server_addr == (char *)-1) + { + t_ctx->return_code = NGX_HTTP_INTERNAL_SERVER_ERROR; + return; } - old_pool = ngx_http_modsecurity_pcre_malloc_init(r->pool); + // 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."); + client_addr, client_port, + server_addr, server_port); + // ngx_http_modsecurity_pcre_malloc_done(old_pool); + if (ret != 1) + { + ngx_log_error(NGX_LOG_WARN, log, 0, "Was not able to extract connection information."); } /** * @@ -114,60 +124,74 @@ ngx_http_modsecurity_rewrite_handler(ngx_http_request_t *r) * and try to use it later. * */ - dd("Processing intervention with the connection information filled in"); + ngx_log_error(NGX_LOG_DEBUG, log, 0, "Processing intervention with the connection information filled in"); ret = ngx_http_modsecurity_process_intervention(ctx->modsec_transaction, r, 1); - if (ret > 0) { + if (ret > 0) + { ctx->intervention_triggered = 1; - return ret; + t_ctx->return_code = ret; + return; } 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; + 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; + 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; + default: + http_version = ngx_str_to_char(r->http_protocol, r->pool); + if (http_version == (char *)-1) + { + t_ctx->return_code = NGX_HTTP_INTERNAL_SERVER_ERROR; + return; + } + 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 == (char *)-1 || n_method == (char *)-1) + { + t_ctx->return_code = NGX_HTTP_INTERNAL_SERVER_ERROR; + return; } - if (n_uri == NULL) { - dd("uri is of length zero"); - return NGX_HTTP_INTERNAL_SERVER_ERROR; + if (n_uri == NULL) + { + ngx_log_error(NGX_LOG_ERR, log, 0, "uri is of length zero"); + t_ctx->return_code = NGX_HTTP_INTERNAL_SERVER_ERROR; + return; } - old_pool = ngx_http_modsecurity_pcre_malloc_init(r->pool); + // 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); + // ngx_http_modsecurity_pcre_malloc_done(old_pool); - dd("Processing intervention with the transaction information filled in (uri, method and version)"); + ngx_log_error(NGX_LOG_DEBUG, log, 0, "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) { + if (ret > 0) + { ctx->intervention_triggered = 1; - return ret; + t_ctx->return_code = ret; + return; } /** @@ -177,9 +201,12 @@ ngx_http_modsecurity_rewrite_handler(ngx_http_request_t *r) 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) { + for (i = 0; /* void */; i++) + { + if (i >= part->nelts) + { + if (part->next == NULL) + { break; } @@ -196,12 +223,12 @@ ngx_http_modsecurity_rewrite_handler(ngx_http_request_t *r) * */ - 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); + ngx_log_error(NGX_LOG_DEBUG, log, 0, "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); + (const unsigned char *)data[i].key.data, + data[i].key.len, + (const unsigned char *)data[i].value.data, + data[i].value.len); } /** @@ -209,20 +236,101 @@ ngx_http_modsecurity_rewrite_handler(ngx_http_request_t *r) * to process this information. */ - old_pool = ngx_http_modsecurity_pcre_malloc_init(r->pool); + // 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"); + // ngx_http_modsecurity_pcre_malloc_done(old_pool); + ngx_log_error(NGX_LOG_DEBUG, log, 0, "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) { + // if (r->error_page) + // { + // return NGX_DECLINED; + // } + if (!r->error_page && ret > 0) + { ctx->intervention_triggered = 1; - return ret; + t_ctx->return_code = ret; + return; } } + t_ctx->return_code = NGX_DECLINED; + return; +} + +void ngx_http_modsecurity_rewrite_finalizer(ngx_event_t *ev) +{ + ngx_http_modsecurity_rewrite_thread_ctx_t *ctx = ev->data; + ngx_http_core_main_conf_t *cmcf; + + ngx_log_error(NGX_LOG_DEBUG, ctx->r->connection->log, 0, "[ModSecurity] Rewrite Job Finalized"); + + --ctx->r->main->blocked; /* incremented in ngx_http_modsecurity_prevention_task_offload */ + ctx->r->aio = 0; + + cmcf = ngx_http_get_module_main_conf(ctx->r, ngx_http_core_module); + + switch (ctx->return_code) + { + case NGX_OK: + ctx->r->phase_handler = cmcf->phase_engine.handlers->next; + ngx_http_core_run_phases(ctx->r); + break; + case NGX_DECLINED: + ctx->r->phase_handler++; + ngx_http_core_run_phases(ctx->r); + break; + case NGX_AGAIN: + case NGX_DONE: + // ngx_http_core_run_phases(ctx->r); + break; + default: + ngx_http_discard_request_body(ctx->r); + ngx_http_finalize_request(ctx->r, ctx->return_code); + } + + ngx_http_run_posted_requests(ctx->r->connection); +} + +ngx_int_t ngx_http_modsecurity_rewrite_handler(ngx_http_request_t *r) +{ + ngx_http_modsecurity_conf_t *mcf; + ngx_http_modsecurity_rewrite_thread_ctx_t *ctx; + ngx_http_modsecurity_ctx_t *m_ctx; + ngx_thread_task_t *task; + + ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0, "catching a new _rewrite_ phase handler"); + + mcf = ngx_http_get_module_loc_conf(r, ngx_http_modsecurity_module); + if (mcf == NULL || mcf->enable != 1) + { + ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0, "ModSecurity not enabled... returning"); + return NGX_DECLINED; + } + + m_ctx = ngx_http_get_module_ctx(r, ngx_http_modsecurity_module); + + ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0, "recovering ctx: %p", m_ctx); + + task = ngx_thread_task_alloc(r->pool, sizeof(ngx_http_modsecurity_rewrite_thread_ctx_t)); + + ctx = task->ctx; + ctx->r = r; + ctx->ctx = m_ctx; + ctx->return_code = NGX_DECLINED; + + task->handler = ngx_http_modsecurity_rewrite_worker; + task->event.handler = ngx_http_modsecurity_rewrite_finalizer; + task->event.data = ctx; + + ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0, "[ModSecurity] Using Thread Pool: %p", mcf->thread_pool); + + if (ngx_thread_task_post(mcf->thread_pool, task) != NGX_OK) + { + return NGX_ERROR; + } + + r->main->blocked++; + r->aio = 1; - return NGX_DECLINED; + return NGX_DONE; }