From 464134194b759042f4c85d230b7c297009260913 Mon Sep 17 00:00:00 2001 From: ADD-SP Date: Sun, 24 Mar 2024 11:11:01 +0800 Subject: [PATCH 1/2] refactor(modsecurity): remove thread_pool supports for modsecurity Introducing multi-threading for CPU intensity work in the Nginx makes no sense. --- include/ngx_http_waf_module_macro.h | 2 - include/ngx_http_waf_module_type.h | 8 --- src/ngx_http_waf_module_config.c | 20 +------- src/ngx_http_waf_module_core.c | 15 ------ src/ngx_http_waf_module_modsecurity.c | 73 --------------------------- 5 files changed, 1 insertion(+), 117 deletions(-) diff --git a/include/ngx_http_waf_module_macro.h b/include/ngx_http_waf_module_macro.h index 71b61680..e445d7c0 100644 --- a/include/ngx_http_waf_module_macro.h +++ b/include/ngx_http_waf_module_macro.h @@ -8,8 +8,6 @@ #define NGX_HTTP_WAF_VERSION "v10.1.1" -#define NGX_HTTP_WAF_ASYNC_MODSECURITY (0) - /* 对应配置文件的文件名 */ #define NGX_HTTP_WAF_IPV4_FILE ("ipv4") #define NGX_HTTP_WAF_IPV6_FILE ("ipv6") diff --git a/include/ngx_http_waf_module_type.h b/include/ngx_http_waf_module_type.h index 77d7edd2..3950992f 100644 --- a/include/ngx_http_waf_module_type.h +++ b/include/ngx_http_waf_module_type.h @@ -299,11 +299,6 @@ typedef struct ngx_http_waf_ctx_s { double spend; /**< 本次检查花费的时间(毫秒) */ char *response_str; /**< 如果不为 NULL 则返回所指的字符串和 200 状态码 */ action_t *action_chain; -#if (NGX_THREADS) && (NGX_HTTP_WAF_ASYNC_MODSECURITY) - ngx_int_t modsecurity_status; /**< ModSecurity 规则所返回的 HTTP 状态码 */ - ngx_int_t modsecurity_triggered; /**< 是否触发了 ModSecurity 的规则 */ - ngx_int_t start_from_thread; /**< 是否是从 ModSecurity 的线程中被启动 */ -#endif ngx_int_t pre_content_run:1; /**< 是否已经执行过 pre_content handler */ ngx_int_t gernal_logged:1; /**< 是否需要记录除 ModSecurity 以外的记录日志 */ ngx_int_t checked:1; /**< 是否启动了检测流程 */ @@ -409,9 +404,6 @@ typedef struct ngx_http_waf_loc_conf_s { lru_cache_t *black_cookie_inspection_cache; /**< Cookie 黑名单检查缓存 */ lru_cache_t *white_url_inspection_cache; /**< URL 白名单检查缓存 */ lru_cache_t *white_referer_inspection_cache; /**< Referer 白名单检查缓存 */ -#if (NGX_THREADS) && (NGX_HTTP_WAF_ASYNC_MODSECURITY) - ngx_thread_pool_t *thread_pool; -#endif ngx_int_t is_custom_priority; /**< 用户是否自定义了优先级 */ ngx_http_waf_check_pt check_proc[20]; /**< 各种检测流程的启动函数 */ } ngx_http_waf_loc_conf_t; diff --git a/src/ngx_http_waf_module_config.c b/src/ngx_http_waf_module_config.c index 27698fb8..4abca89b 100644 --- a/src/ngx_http_waf_module_config.c +++ b/src/ngx_http_waf_module_config.c @@ -1608,26 +1608,11 @@ void* ngx_http_waf_create_main_conf(ngx_conf_t* cf) { void* ngx_http_waf_create_loc_conf(ngx_conf_t* cf) { - static u_char s_rand_str[129] = { 0 }; -#if (NGX_THREADS) && (NGX_HTTP_WAF_ASYNC_MODSECURITY) - static ngx_str_t s_thread_pool_name; - static ngx_thread_pool_t * s_thread_pool = NULL; -#endif + static u_char s_rand_str[129] = { 0 }; if (s_rand_str[0] == '\0') { ngx_http_waf_rand_str(s_rand_str, 128); } -#if (NGX_THREADS) && (NGX_HTTP_WAF_ASYNC_MODSECURITY) - ngx_str_set(&s_thread_pool_name, "ngx_waf"); - s_thread_pool = ngx_thread_pool_get(cf->cycle, &s_thread_pool_name); - if (s_thread_pool == NULL) { - s_thread_pool = ngx_thread_pool_add(cf, &s_thread_pool_name); - if (s_thread_pool == NULL) { - return NULL; - } - } -#endif - ngx_http_waf_loc_conf_t* conf = NULL; conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_waf_loc_conf_t)); if (conf == NULL) { @@ -1696,9 +1681,6 @@ void* ngx_http_waf_create_loc_conf(ngx_conf_t* cf) { ngx_str_null(&conf->waf_modsecurity_rules_remote_key); ngx_str_null(&conf->waf_modsecurity_rules_remote_url); conf->ip_access_statistics = NULL; -#if (NGX_THREADS) && (NGX_HTTP_WAF_ASYNC_MODSECURITY) - conf->thread_pool = s_thread_pool; -#endif conf->is_custom_priority = NGX_HTTP_WAF_FALSE; conf->black_url = NGX_CONF_UNSET_PTR; diff --git a/src/ngx_http_waf_module_core.c b/src/ngx_http_waf_module_core.c index a0a72436..3a81509f 100644 --- a/src/ngx_http_waf_module_core.c +++ b/src/ngx_http_waf_module_core.c @@ -266,11 +266,6 @@ ngx_int_t ngx_http_waf_check_all(ngx_http_request_t* r, ngx_int_t is_check_cc) { ctx->req_body.temporary = 0; ctx->req_body.mmap = 0; ctx->modsecurity_transaction = NULL; -#if (NGX_THREADS) && (NGX_HTTP_WAF_ASYNC_MODSECURITY) - ctx->modsecurity_triggered = NGX_HTTP_WAF_FALSE; - ctx->start_from_thread = NGX_HTTP_WAF_FALSE; -#endif - if (r->cleanup == NULL) { r->cleanup = cln; @@ -323,16 +318,6 @@ ngx_int_t ngx_http_waf_check_all(ngx_http_request_t* r, ngx_int_t is_check_cc) { return NGX_DECLINED; } -#if (NGX_THREADS) && (NGX_HTTP_WAF_ASYNC_MODSECURITY) - if (ctx->start_from_thread == NGX_HTTP_WAF_TRUE) { - if (ctx->modsecurity_triggered == NGX_HTTP_WAF_TRUE) { - return ctx->modsecurity_status; - } else { - return NGX_DECLINED; - } - } -#endif - if (ctx->checked) { return NGX_DECLINED; } diff --git a/src/ngx_http_waf_module_modsecurity.c b/src/ngx_http_waf_module_modsecurity.c index 35d2061b..328d4758 100644 --- a/src/ngx_http_waf_module_modsecurity.c +++ b/src/ngx_http_waf_module_modsecurity.c @@ -41,15 +41,6 @@ static ngx_int_t _process_response_body(ngx_http_request_t* r, ngx_chain_t *in, static ngx_int_t _process_intervention(ngx_http_request_t* r, ngx_int_t* out_http_status); -#if (NGX_THREADS) && (NGX_HTTP_WAF_ASYNC_MODSECURITY) - -static void _invoke(void* data, ngx_log_t* log); - - -static void _completion(ngx_event_t* event); - -#endif - void ngx_http_waf_header_filter_init() { ngx_http_next_header_filter = ngx_http_top_header_filter; @@ -94,25 +85,6 @@ ngx_int_t ngx_http_waf_handler_modsecurity(ngx_http_request_t* r) { action_t* action = NULL; ngx_http_waf_copy_action_chain(r->pool, action, loc_conf->action_chain_modsecurity); - - -#if (NGX_THREADS) && (NGX_HTTP_WAF_ASYNC_MODSECURITY) - ngx_thread_task_t* task = ngx_thread_task_alloc(r->pool, sizeof(ngx_http_request_t)); - if (task == NULL) { - return NGX_ERROR; - } - task->ctx = r; - task->handler = _invoke; - task->event.handler = _completion; - task->event.data = r; - - if (ngx_thread_task_post(loc_conf->thread_pool, task) != NGX_OK) { - return _process_request(r, out_http_status); - } - - *out_http_status = NGX_DONE; - return NGX_HTTP_WAF_MATCHED; -#else ngx_int_t http_status = NGX_DECLINED; ngx_int_t ret = _process_request(r, &http_status); @@ -131,8 +103,6 @@ ngx_int_t ngx_http_waf_handler_modsecurity(ngx_http_request_t* r) { } return ret; - -#endif } @@ -613,46 +583,3 @@ static ngx_int_t _process_intervention(ngx_http_request_t* r, ngx_int_t* out_htt return NGX_HTTP_WAF_NOT_MATCHED; } - -#if (NGX_THREADS) && (NGX_HTTP_WAF_ASYNC_MODSECURITY) -static void _invoke(void* data, ngx_log_t* log) { - ngx_http_request_t* r = data; - - ngx_http_waf_ctx_t* ctx = NULL; - ngx_http_waf_loc_conf_t* loc_conf = NULL; - ngx_http_waf_get_ctx_and_conf(r, &loc_conf, &ctx); - - if (loc_conf->waf == 0 || loc_conf->waf == NGX_CONF_UNSET) { - ctx->modsecurity_triggered = NGX_HTTP_WAF_FALSE; - return; - } - - if (loc_conf->waf_modsecurity == 0 || loc_conf->waf_modsecurity == NGX_CONF_UNSET) { - ctx->modsecurity_triggered = NGX_HTTP_WAF_FALSE; - return; - } - - if (_process_request(r, &ctx->modsecurity_status) == NGX_HTTP_WAF_MATCHED) { - ctx->modsecurity_triggered = NGX_HTTP_WAF_TRUE; - return; - } - - - ctx->modsecurity_triggered = NGX_HTTP_WAF_FALSE; - return; -} -#endif - -#if (NGX_THREADS) && (NGX_HTTP_WAF_ASYNC_MODSECURITY) -static void _completion(ngx_event_t* event) { - ngx_http_request_t* r = event->data; - - ngx_http_waf_ctx_t* ctx = NULL; - ngx_http_waf_get_ctx_and_conf(r, NULL, &ctx); - - ctx->start_from_thread = NGX_HTTP_WAF_TRUE; - - ngx_http_core_run_phases(r); - -} -#endif \ No newline at end of file From db3af9885ac19ba88755aecc24b94a1c31a4b0d1 Mon Sep 17 00:00:00 2001 From: ADD-SP Date: Sun, 24 Mar 2024 17:46:35 +0800 Subject: [PATCH 2/2] saving current progress --- include/ngx_http_waf_module_action.h | 226 -------------- include/ngx_http_waf_module_captcha.h | 1 - include/ngx_http_waf_module_check.h | 24 +- include/ngx_http_waf_module_config.h | 4 - include/ngx_http_waf_module_core.h | 6 - include/ngx_http_waf_module_macro.h | 6 + include/ngx_http_waf_module_type.h | 125 +++----- src/ngx_http_waf_module_action.c | 430 -------------------------- src/ngx_http_waf_module_core.c | 215 ++++++------- src/ngx_http_waf_module_util.c | 43 +-- 10 files changed, 151 insertions(+), 929 deletions(-) delete mode 100644 include/ngx_http_waf_module_action.h delete mode 100644 src/ngx_http_waf_module_action.c diff --git a/include/ngx_http_waf_module_action.h b/include/ngx_http_waf_module_action.h deleted file mode 100644 index 0db18faa..00000000 --- a/include/ngx_http_waf_module_action.h +++ /dev/null @@ -1,226 +0,0 @@ -#ifndef __NGX_HTTP_WAF_MODULE_ACTION_H__ - -#include -#include -#include -#include - -#define ngx_conf_merge_action_vaule(conf, prev, default) { \ - if (!ngx_http_waf_is_valid_ptr_value(conf) \ - || ngx_http_waf_check_flag((conf->flag), ACTION_FLAG_UNSET)) { \ - (conf) = (prev); \ - \ - } else { \ - (conf) = (default); \ - } \ -} - - -#define ngx_http_waf_append_action(r, action) { \ - ngx_http_waf_ctx_t* ctx = NULL; \ - ngx_http_waf_get_ctx_and_conf((r), NULL, &ctx); \ - DL_APPEND(ctx->action_chain, (action)); \ -} - - -#define ngx_http_waf_append_action_chain(r, chain) { \ - ngx_http_waf_ctx_t* ctx = NULL; \ - ngx_http_waf_get_ctx_and_conf((r), NULL, &ctx); \ - DL_CONCAT(ctx->action_chain, (chain)); \ -} - - -#define ngx_http_waf_set_action_decline(action, ex_flag) { \ - action_t* head = NULL; \ - (action)->flag = ACTION_FLAG_DECLINE | (ex_flag); \ - (action)->next = NULL; \ - (action)->prev = NULL; \ - DL_APPEND(head, (action)); \ - (action) = head; \ -} - - -#define ngx_http_waf_set_action_follow(action, ex_flag) { \ - action_t* head = NULL; \ - (action)->flag = ACTION_FLAG_FOLLOW | (ex_flag); \ - (action)->next = NULL; \ - (action)->prev = NULL; \ - DL_APPEND(head, (action)); \ - (action) = head; \ -} - - -#define ngx_http_waf_set_action_return(action, status, ex_flag) { \ - action_t* head = NULL; \ - (action)->flag = ACTION_FLAG_RETURN | (ex_flag); \ - (action)->extra.http_status = (status); \ - (action)->next = NULL; \ - (action)->prev = NULL; \ - DL_APPEND(head, (action)); \ - (action) = head; \ -} - - -#define ngx_http_waf_set_action_str(action, _str, status, ex_flag) { \ - action_t* head = NULL; \ - (action)->flag = ACTION_FLAG_STR | (ex_flag); \ - (action)->extra.extra_str.http_status = (status); \ - (action)->extra.extra_str.str = _str; \ - (action)->next = NULL; \ - (action)->prev = NULL; \ - DL_APPEND(head, (action)); \ - (action) = head; \ -} - - -#define ngx_http_waf_set_action_html(action, _html, status, ex_flag) { \ - action_t* head = NULL; \ - (action)->flag = ACTION_FLAG_HTML | (ex_flag); \ - (action)->extra.extra_html.http_status = (status); \ - (action)->extra.extra_html.html = _html; \ - (action)->next = NULL; \ - (action)->prev = NULL; \ - DL_APPEND(head, (action)); \ - (action) = head; \ -} - - -#define ngx_http_waf_set_action_reg_content(action, ex_flag) { \ - action_t* head = NULL; \ - (action)->flag = ACTION_FLAG_REG_CONTENT | (ex_flag); \ - (action)->next = NULL; \ - (action)->prev = NULL; \ - DL_APPEND(head, (action)); \ - (action) = head; \ -} - - -#define ngx_http_waf_copy_action_chain(pool, dst, src) { \ - dst = NULL; \ - action_t* _dst = NULL; \ - action_t* elt = NULL; \ - DL_FOREACH(src, elt) { \ - if (_dst == NULL) { \ - _dst = ngx_pcalloc(pool, sizeof(action_t)); \ - } else { \ - _dst->next = ngx_pcalloc(pool, sizeof(action_t)); \ - _dst = _dst->next; \ - } \ - ngx_memcpy(_dst, elt, sizeof(action_t)); \ - _dst->next = NULL; \ - _dst->prev = NULL; \ - DL_APPEND(dst, _dst); \ - } \ -} - - -#define ngx_http_waf_make_action_chain_html(pool, head, status, ex_flag, html) { \ - action_t* _head = NULL; \ - action_t* tmp = ngx_pcalloc((pool), sizeof(action_t)); \ - ngx_http_waf_set_action_reg_content(tmp, (ex_flag)); \ - DL_APPEND(_head, tmp); \ - tmp = ngx_pcalloc((pool), sizeof(action_t)); \ - ngx_http_waf_set_action_decline(tmp, (ex_flag)); \ - DL_APPEND(_head, tmp); \ - tmp = ngx_pcalloc((pool), sizeof(action_t)); \ - ngx_http_waf_set_action_html(tmp, \ - (html), \ - (status), \ - (ex_flag)); \ - DL_APPEND(_head, tmp); \ - head = _head; \ -} - - -#define ngx_http_waf_make_action_chain_captcha(pool, head, ex_flag, html) { \ - ngx_http_waf_make_action_chain_html((pool), \ - (head), \ - NGX_HTTP_SERVICE_UNAVAILABLE, \ - (ex_flag) | ACTION_FLAG_CAPTCHA, \ - (html)); \ -} - - -#define ngx_http_waf_make_action_chain_under_attack(pool, head, ex_flag, html) { \ - ngx_http_waf_make_action_chain_html((pool), \ - (head), \ - NGX_HTTP_SERVICE_UNAVAILABLE, \ - (ex_flag) | ACTION_FLAG_UNDER_ATTACK, \ - (html)); \ -} - - -#define ngx_http_waf_append_action_return(r, status, ex_flag) { \ - action_t* action = ngx_pcalloc(r->pool, sizeof(action_t)); \ - ngx_http_waf_set_action_return(action, (status), (ex_flag)); \ - ngx_http_waf_append_action(r, action); \ -} - - -#define ngx_http_waf_append_action_decline(r, ex_flag) { \ - action_t* action = ngx_pcalloc(r->pool, sizeof(action_t)); \ - ngx_http_waf_set_action_decline(action, (ex_flag)); \ - ngx_http_waf_append_action(r, action); \ -} - - -#define ngx_http_waf_append_action_reg_content(r, ex_flag) { \ - action_t* action = ngx_pcalloc(r->pool, sizeof(action_t)); \ - ngx_http_waf_set_action_reg_content(action, (ex_flag)); \ - ngx_http_waf_append_action(r, action); \ -} - - -#define ngx_http_waf_append_action_str(r, _str, status, ex_flag) { \ - action_t* action = ngx_pcalloc(r->pool, sizeof(action_t)); \ - ngx_http_waf_set_action_str(action, (_str), (status), (ex_flag)); \ - ngx_http_waf_append_action_reg_content((r), (ex_flag)); \ - ngx_http_waf_append_action_decline((r), (ex_flag)); \ - ngx_http_waf_append_action(r, action); \ -} - - -#define ngx_http_waf_append_action_html(r, _html, status, ex_flag) { \ - action_t* action = ngx_pcalloc(r->pool, sizeof(action_t)); \ - ngx_http_waf_set_action_html(action, (_html), (status), (ex_flag)); \ - ngx_http_waf_append_action_reg_content((r), (ex_flag)); \ - ngx_http_waf_append_action_decline((r), (ex_flag)); \ - ngx_http_waf_append_action(r, action); \ -} - - -#define ngx_http_waf_append_action_under_attack(r, ex_flag) { \ - ngx_http_waf_loc_conf_t* conf = NULL; \ - ngx_http_waf_get_ctx_and_conf(r, &conf, NULL); \ - action_t* head = NULL; \ - ngx_http_waf_make_action_chain_under_attack(r->pool, \ - head, \ - (ex_flag), \ - &loc_conf->waf_under_attack_html); \ - ngx_http_waf_append_action_chain(r, head); \ -} - - -#define ngx_http_waf_append_action_captcha(r, ex_flag) { \ - ngx_http_waf_loc_conf_t* conf = NULL; \ - ngx_http_waf_get_ctx_and_conf(r, &conf, NULL); \ - action_t* head = NULL; \ - ngx_http_waf_make_action_chain_captcha(r->pool, \ - head, \ - (ex_flag), \ - &loc_conf->waf_captcha_html); \ - ngx_http_waf_append_action_chain(r, head); \ -} - - - -ngx_int_t ngx_http_waf_perform_action_at_access_start(ngx_http_request_t* r); - - -ngx_int_t ngx_http_waf_perform_action_at_access_end(ngx_http_request_t* r); - - -ngx_int_t ngx_http_waf_perform_action_at_content(ngx_http_request_t* r); - - -#endif \ No newline at end of file diff --git a/include/ngx_http_waf_module_captcha.h b/include/ngx_http_waf_module_captcha.h index 0244c753..5043e21f 100644 --- a/include/ngx_http_waf_module_captcha.h +++ b/include/ngx_http_waf_module_captcha.h @@ -4,7 +4,6 @@ #include #include #include -#include #include #include diff --git a/include/ngx_http_waf_module_check.h b/include/ngx_http_waf_module_check.h index 5b8ec526..885dd5d6 100644 --- a/include/ngx_http_waf_module_check.h +++ b/include/ngx_http_waf_module_check.h @@ -42,7 +42,7 @@ void ngx_http_waf_handler_cleanup(void *data); * @retval MATCHED IP 地址在白名单中。 * @retval NOT_MATCHED IP 地址不在白名单中。 */ -ngx_int_t ngx_http_waf_handler_check_white_ip(ngx_http_request_t* r); +ngx_http_waf_check_result_t ngx_http_waf_handler_check_white_ip(ngx_http_request_t* r); /** @@ -51,7 +51,7 @@ ngx_int_t ngx_http_waf_handler_check_white_ip(ngx_http_request_t* r); * @retval MATCHED IP 地址在黑名单中。 * @retval NOT_MATCHED IP 地址不在黑名单中。 */ -ngx_int_t ngx_http_waf_handler_check_black_ip(ngx_http_request_t* r); +ngx_http_waf_check_result_t ngx_http_waf_handler_check_black_ip(ngx_http_request_t* r); /** @@ -60,7 +60,7 @@ ngx_int_t ngx_http_waf_handler_check_black_ip(ngx_http_request_t* r); * @retval MATCHED 超出限制。 * @retval NOT_MATCHED 未超出限制。 */ -ngx_int_t ngx_http_waf_handler_check_cc(ngx_http_request_t* r); +ngx_http_waf_check_result_t ngx_http_waf_handler_check_cc(ngx_http_request_t* r); /** @@ -69,7 +69,7 @@ ngx_int_t ngx_http_waf_handler_check_cc(ngx_http_request_t* r); * @retval MATCHED 在白名单中。 * @retval NOT_MATCHED 不在白名单中 */ -ngx_int_t ngx_http_waf_handler_check_white_url(ngx_http_request_t* r); +ngx_http_waf_check_result_t ngx_http_waf_handler_check_white_url(ngx_http_request_t* r); /** @@ -78,7 +78,7 @@ ngx_int_t ngx_http_waf_handler_check_white_url(ngx_http_request_t* r); * @retval MATCHED 在黑名单中。 * @retval NOT_MATCHED 不在黑名单中 */ -ngx_int_t ngx_http_waf_handler_check_black_url(ngx_http_request_t* r); +ngx_http_waf_check_result_t ngx_http_waf_handler_check_black_url(ngx_http_request_t* r); /** @@ -87,7 +87,7 @@ ngx_int_t ngx_http_waf_handler_check_black_url(ngx_http_request_t* r); * @retval MATCHED 在黑名单中。 * @retval NOT_MATCHED 不在黑名单中 */ -ngx_int_t ngx_http_waf_handler_check_black_args(ngx_http_request_t* r); +ngx_http_waf_check_result_t ngx_http_waf_handler_check_black_args(ngx_http_request_t* r); /** @@ -96,7 +96,7 @@ ngx_int_t ngx_http_waf_handler_check_black_args(ngx_http_request_t* r); * @retval MATCHED 在黑名单中。 * @retval NOT_MATCHED 不在黑名单中 */ -ngx_int_t ngx_http_waf_handler_check_black_user_agent(ngx_http_request_t* r); +ngx_http_waf_check_result_t ngx_http_waf_handler_check_black_user_agent(ngx_http_request_t* r); /** @@ -105,7 +105,7 @@ ngx_int_t ngx_http_waf_handler_check_black_user_agent(ngx_http_request_t* r); * @retval MATCHED 在白名单中。 * @retval NOT_MATCHED 不在白黑名单中 */ -ngx_int_t ngx_http_waf_handler_check_white_referer(ngx_http_request_t* r); +ngx_http_waf_check_result_t ngx_http_waf_handler_check_white_referer(ngx_http_request_t* r); /** @@ -114,7 +114,7 @@ ngx_int_t ngx_http_waf_handler_check_white_referer(ngx_http_request_t* r); * @retval MATCHED 在黑名单中。 * @retval NOT_MATCHED 不在黑名单中 */ -ngx_int_t ngx_http_waf_handler_check_black_referer(ngx_http_request_t* r); +ngx_http_waf_check_result_t ngx_http_waf_handler_check_black_referer(ngx_http_request_t* r); /** @@ -123,13 +123,13 @@ ngx_int_t ngx_http_waf_handler_check_black_referer(ngx_http_request_t* r); * @retval MATCHED 在黑名单中。 * @retval NOT_MATCHED 不在黑名单中 */ -ngx_int_t ngx_http_waf_handler_check_black_cookie(ngx_http_request_t* r); +ngx_http_waf_check_result_t ngx_http_waf_handler_check_black_cookie(ngx_http_request_t* r); /** * @brief 检查请求体内容是否存在于黑名单中,存在则拦截,反之放行。 */ -ngx_int_t ngx_http_waf_handler_check_black_post(ngx_http_request_t* r); +ngx_http_waf_check_result_t ngx_http_waf_handler_check_black_post(ngx_http_request_t* r); /** @@ -140,7 +140,7 @@ ngx_int_t ngx_http_waf_handler_check_black_post(ngx_http_request_t* r); * @param[in] cache 检测时所使用的缓存管理器 * @return 如果匹配到返回 NGX_HTTP_WAF_MATCHED,反之则为 NGX_HTTP_WAF_NOT_MATCHED。 */ -ngx_int_t ngx_http_waf_regex_exec_arrray(ngx_http_request_t* r, +ngx_http_waf_check_result_t ngx_http_waf_regex_exec_arrray(ngx_http_request_t* r, ngx_str_t* str, ngx_array_t* array, const u_char* rule_type, diff --git a/include/ngx_http_waf_module_config.h b/include/ngx_http_waf_module_config.h index 2bc750e0..65e780fc 100644 --- a/include/ngx_http_waf_module_config.h +++ b/include/ngx_http_waf_module_config.h @@ -31,15 +31,11 @@ #include #include #include -#include extern ngx_int_t ngx_http_waf_handler_access_phase(ngx_http_request_t* r); -extern ngx_int_t ngx_http_waf_handler_precontent_phase(ngx_http_request_t* r); - - extern ngx_int_t ngx_http_waf_handler_log_phase(ngx_http_request_t* r); diff --git a/include/ngx_http_waf_module_core.h b/include/ngx_http_waf_module_core.h index 7b4279ca..406d566d 100644 --- a/include/ngx_http_waf_module_core.h +++ b/include/ngx_http_waf_module_core.h @@ -42,12 +42,6 @@ ngx_int_t ngx_http_waf_init_process(ngx_cycle_t *cycle); ngx_int_t ngx_http_waf_handler_access_phase(ngx_http_request_t* r); -/** - * @brief NGX_HTTP_CONTENT_PHASE 阶段的处理函数 -*/ -ngx_int_t ngx_http_waf_handler_precontent_phase(ngx_http_request_t* r); - - /** * @brief NGX_HTTP_LOG_PHASE 阶段的处理函数 */ diff --git a/include/ngx_http_waf_module_macro.h b/include/ngx_http_waf_module_macro.h index e445d7c0..701ee99e 100644 --- a/include/ngx_http_waf_module_macro.h +++ b/include/ngx_http_waf_module_macro.h @@ -333,6 +333,12 @@ #define ngx_http_waf_check_bit(origin, bit_index) (ngx_http_waf_check_flag((origin), 1 << (bit_index))) +#define ngx_http_waf_is_subrequest(r) ((r)->main != (r)) + + +#define ngx_http_waf_is_internal_request(r) ((r)->internal) + + #define ngx_http_waf_is_unset_or_disable_value(x) (((x) == NGX_CONF_UNSET) || ((x) == 0)) diff --git a/include/ngx_http_waf_module_type.h b/include/ngx_http_waf_module_type.h index 3950992f..20d28896 100644 --- a/include/ngx_http_waf_module_type.h +++ b/include/ngx_http_waf_module_type.h @@ -35,11 +35,37 @@ #endif +/** + * @typedef ngx_http_waf_check_result + * @brief 检查结果 +*/ +typedef struct ngx_http_waf_check_result_s { + ngx_int_t http_status; /**< 返回的 HTTP 状态码 */ + ngx_str_t response_body; /**< 返回的内容 */ + + ngx_int_t log_level; /**< 日志级别 */ + ngx_str_t log_message; /**< 日志信息 */ + + ngx_str_t subrequest_uri; /**< 子请求的 URI */ + ngx_str_t subrequest_args; /**< 子请求的参数 */ + ngx_http_post_subrequest_pt subrequest_handler; /**< 子请求处理函数 */ + + ngx_uint_t is_matched:1; /**< 是否匹配到规则 */ + ngx_uint_t is_blacklist:1; /**< 是否是黑名单 */ + ngx_uint_t is_whitelist:1; /**< 是否是白名单 */ + + ngx_uint_t need_do_sth:1; /**< 是否需要执行某些操作 */ + ngx_uint_t need_log:1; /**< 是否需要记录日志 */ + ngx_uint_t need_response:1; /**< 是否需要返回内容 */ + ngx_uint_t need_subrequest:1; /**< 是否需要发起子请求 */ +} ngx_http_waf_check_result_t; + + /** * @typedef ngx_http_waf_check * @brief 请求检查函数的函数指针 */ -typedef ngx_int_t (*ngx_http_waf_check_pt)(ngx_http_request_t* r); +typedef ngx_http_waf_check_result_t (*ngx_http_waf_check_pt)(ngx_http_request_t* r); /** @@ -89,16 +115,6 @@ typedef struct ip_statis_s { } ip_statis_t; -/** - * @struct check_result_t - * @brief 规则减价结果 -*/ -typedef struct check_result_s { - ngx_int_t is_matched; /**< 是否被某条规则匹配到 */ - u_char *detail; /**< 匹配到的规则的详情 */ -} check_result_t; - - /** * @struct key_value_t * @brief 哈希表(字符串 -> 字符串) @@ -233,80 +249,30 @@ typedef struct ip_trie_s { typedef enum { - BOT_TYPE_NONE = 0X0, - BOT_TYPE_UNSET = 0X1, - BOT_TYPE_GOOGLE = 0X2, - BOT_TYPE_BING = 0X4, - BOT_TYPE_BAIDU = 0X8, - BOT_TYPE_SOGOU = 0X10, - BOT_TYPE_YANDEX = 0X20 + BOT_TYPE_NONE, + BOT_TYPE_UNSET, + BOT_TYPE_GOOGLE, + BOT_TYPE_BING, + BOT_TYPE_BAIDU, + BOT_TYPE_SOGOU, + BOT_TYPE_YANDEX, } bot_type_e; -typedef enum { - ACTION_FLAG_NONE = 0x0, - ACTION_FLAG_UNSET = 0x1, - ACTION_FLAG_DECLINE = 0x2, - ACTION_FLAG_FOLLOW = 0x4, - ACTION_FLAG_RETURN = 0x8, - ACTION_FLAG_REG_CONTENT = 0x10, - ACTION_FLAG_STR = 0x20, - ACTION_FLAG_HTML = 0x40, - ACTION_FLAG_FROM_WHITE_LIST = 0x80, - ACTION_FLAG_FROM_BLACK_LIST = 0x100, - ACTION_FLAG_FROM_CC_DENY = 0x200, - ACTION_FLAG_FROM_MODSECURITY = 0x400, - ACTION_FLAG_FROM_CAPTCHA = 0x800, - ACTION_FLAG_FROM_UNDER_ATTACK = 0x1000, - ACTION_FLAG_FROM_VERIFY_BOT = 0x2000, - ACTION_FLAG_CAPTCHA = 0x4000, - ACTION_FLAG_UNDER_ATTACK = 0X8000 -} action_flag_e; - - -typedef struct action_s { - action_flag_e flag; - struct action_s* next; - struct action_s* prev; - union { - ngx_uint_t http_status; - - struct { - ngx_uint_t http_status; - ngx_str_t* str; - } extra_str; - - struct { - ngx_uint_t http_status; - ngx_str_t* html; - } extra_html; - - } extra; -} action_t; - - /** * @struct ngx_http_waf_ctx_t * @brief 每个请求的上下文 */ typedef struct ngx_http_waf_ctx_s { - ngx_http_request_t* r; + ngx_http_request_t *r; Transaction *modsecurity_transaction; /**< ModSecurity 的事务 */ - ngx_str_t rule_type; /**< 触发的规则类型 */ - ngx_str_t rule_deatils; /**< 触发的规则内容 */ - ngx_buf_t req_body; /**< 请求体 */ - ngx_int_t rate; /**< 对应变量 $waf_rate */ - double spend; /**< 本次检查花费的时间(毫秒) */ - char *response_str; /**< 如果不为 NULL 则返回所指的字符串和 200 状态码 */ - action_t *action_chain; - ngx_int_t pre_content_run:1; /**< 是否已经执行过 pre_content handler */ - ngx_int_t gernal_logged:1; /**< 是否需要记录除 ModSecurity 以外的记录日志 */ - ngx_int_t checked:1; /**< 是否启动了检测流程 */ - ngx_int_t blocked:1; /**< 是否拦截了本次请求 */ - ngx_int_t read_body_done:1; /**< 是否已经请求读取请求体 */ - ngx_int_t waiting_more_body:1; /**< 是否等待读取更多请求体 */ - ngx_int_t has_req_body:1; /**< 字段 req_body 是否以己经存储了请求体 */ - ngx_int_t register_content_handler:1; /**< 是否已经注册或应该注册内容处理程序 */ + ngx_uint_t next_chekcer_index; /**< 下一个检查器的索引 */ + ngx_http_waf_check_result_t result_for_content_phase; /**< 检查结果 */ + + ngx_str_t captcha_server_response; /**< 验证码服务器的响应 */ + + ngx_uint_t waiting_subrequest:1; /**< 是否正在等待子请求 */ + } ngx_http_waf_ctx_t; @@ -316,7 +282,7 @@ typedef struct ngx_http_waf_ctx_s { */ typedef struct ngx_http_waf_main_conf_s { ngx_array_t *shms; /**< 共享内存列表 */ - ngx_array_t *local_caches; /**< 未使用共享内存的缓存列表 */ + ngx_array_t *local_caches; /**< 未使用共享内存的缓存列表 */ } ngx_http_waf_main_conf_t; @@ -371,11 +337,6 @@ typedef struct ngx_http_waf_loc_conf_s { ngx_str_t waf_modsecurity_rules_remote_url; ngx_http_complex_value_t* waf_modsecurity_transaction_id; ngx_str_t waf_block_page; /**< 封禁页面的 HTML */ - action_t *action_chain_blacklist; /**< 黑名单触发后的动作 */ - action_t *action_chain_cc_deny; /**< CC 触发后的动作 */ - action_t *action_chain_modsecurity; /**< ModSecurity 触发后的动作 */ - action_t *action_chain_verify_bot; /**< verify_bot 触发后的动作 */ - ngx_shm_zone_t *action_zone_captcha; /**< 验证码动作使用的 zone */ lru_cache_t *action_cache_captcha; /**< 验证码动作使用的 cache */ ModSecurity *modsecurity_instance; /**< ModSecurity 实例 */ void *modsecurity_rules; /**< ModSecurity 规则容器 */ diff --git a/src/ngx_http_waf_module_action.c b/src/ngx_http_waf_module_action.c deleted file mode 100644 index fca58224..00000000 --- a/src/ngx_http_waf_module_action.c +++ /dev/null @@ -1,430 +0,0 @@ -#include - - -typedef struct _captcha_cache_s { - ngx_int_t count; - ngx_uint_t error_page:1; /**< 1: 返回 403, 0: CAPTCHA */ -} _captcha_cache_t; - - -static ngx_int_t _perform_action_return(ngx_http_request_t* r, action_t* action); - - -static ngx_int_t _perform_action_decline(ngx_http_request_t* r, action_t* action); - - -static void _perform_action_reg_content(ngx_http_request_t* r, action_t* action); - - -static ngx_int_t _perform_action_html(ngx_http_request_t* r, action_t* action); - - -static ngx_int_t _perform_action_str(ngx_http_request_t* r, action_t* action); - - -static ngx_int_t _gen_response(ngx_http_request_t* r, ngx_str_t data, ngx_str_t content_type, ngx_uint_t http_status); - - -ngx_int_t ngx_http_waf_perform_action_at_access_start(ngx_http_request_t* r) { - - ngx_http_waf_loc_conf_t* loc_conf = NULL; - ngx_http_waf_get_ctx_and_conf(r, &loc_conf, NULL); - - if (loc_conf->waf == 2) { - return NGX_HTTP_WAF_NOT_MATCHED; - } - - lru_cache_t* cache = loc_conf->action_cache_captcha; - - if (!ngx_http_waf_is_valid_ptr_value(cache)) { - return NGX_HTTP_WAF_NOT_MATCHED; - } - - inx_addr_t inx_addr; - ngx_http_waf_make_inx_addr(r, &inx_addr); - - ngx_int_t ret_value = NGX_HTTP_WAF_NOT_MATCHED; - ngx_slab_pool_t *shpool = (ngx_slab_pool_t *)loc_conf->action_zone_captcha->shm.addr; - - ngx_shmtx_lock(&shpool->mutex); - - lru_cache_find_result_t result = lru_cache_find(cache, &inx_addr, sizeof(inx_addr)); - - ngx_shmtx_unlock(&shpool->mutex); - - ngx_int_t need_delete = 0; - - if (result.status == NGX_HTTP_WAF_KEY_EXISTS) { - - switch (ngx_http_waf_captcha_test(r)) { - case NGX_HTTP_WAF_FAULT: - ngx_http_waf_append_action_return(r, NGX_HTTP_SERVICE_UNAVAILABLE, ACTION_FLAG_NONE); - ret_value = NGX_HTTP_WAF_MATCHED; - break; - - case NGX_HTTP_WAF_CAPTCHA_CHALLENGE: - - if (ngx_http_waf_captcha_inc_fails(r) == NGX_HTTP_WAF_MATCHED) { - ngx_http_waf_set_rule_info(r, "CAPTCHA", "TO MANY FAILS", NGX_HTTP_WAF_TRUE, NGX_HTTP_WAF_TRUE); - - if (ngx_is_null_str(&loc_conf->waf_block_page)) { - ngx_http_waf_append_action_return(r, NGX_HTTP_TOO_MANY_REQUESTS, ACTION_FLAG_FROM_CAPTCHA); - - } else { - ngx_http_waf_append_action_html(r, - &loc_conf->waf_block_page, - NGX_HTTP_TOO_MANY_REQUESTS, - ACTION_FLAG_FROM_CAPTCHA); - } - - - } else { - ngx_http_waf_set_rule_info(r, "CAPTCHA", "CHALLENGE", NGX_HTTP_WAF_TRUE, NGX_HTTP_WAF_TRUE); - ngx_http_waf_append_action_captcha(r, ACTION_FLAG_FROM_CAPTCHA); - } - - ret_value = NGX_HTTP_WAF_MATCHED; - break; - - case NGX_HTTP_WAF_CAPTCHA_BAD: - - if (ngx_http_waf_captcha_inc_fails(r) == NGX_HTTP_WAF_MATCHED) { - ngx_http_waf_set_rule_info(r, "CAPTCHA", "TO MANY FAILS", NGX_HTTP_WAF_TRUE, NGX_HTTP_WAF_TRUE); - - if (ngx_is_null_str(&loc_conf->waf_block_page)) { - ngx_http_waf_append_action_return(r, NGX_HTTP_TOO_MANY_REQUESTS, ACTION_FLAG_FROM_CAPTCHA); - - } else { - ngx_http_waf_append_action_html(r, - &loc_conf->waf_block_page, - NGX_HTTP_TOO_MANY_REQUESTS, - ACTION_FLAG_FROM_CAPTCHA); - } - - } else { - ngx_http_waf_set_rule_info(r, "CAPTCHA", "bad", NGX_HTTP_WAF_TRUE, NGX_HTTP_WAF_TRUE); - ngx_str_t* res_str = ngx_pcalloc(r->pool, sizeof(ngx_str_t)); - ngx_str_set(res_str, "bad"); - ngx_http_waf_append_action_str(r, res_str, NGX_HTTP_OK, ACTION_FLAG_NONE); - } - - ret_value = NGX_HTTP_WAF_MATCHED; - break; - - case NGX_HTTP_WAF_CAPTCHA_PASS: - need_delete = 1; - ngx_str_t* res_str = ngx_pcalloc(r->pool, sizeof(ngx_str_t)); - ngx_str_set(res_str, "good"); - ngx_http_waf_append_action_str(r, res_str, NGX_HTTP_OK, ACTION_FLAG_NONE); - ret_value = NGX_HTTP_WAF_MATCHED; - break; - - case NGX_HTTP_WAF_FAIL: - - if (ngx_http_waf_captcha_inc_fails(r) == NGX_HTTP_WAF_MATCHED) { - ngx_http_waf_set_rule_info(r, "CAPTCHA", "TO MANY FAILS", NGX_HTTP_WAF_TRUE, NGX_HTTP_WAF_TRUE); - - if (ngx_is_null_str(&loc_conf->waf_block_page)) { - ngx_http_waf_append_action_return(r, NGX_HTTP_TOO_MANY_REQUESTS, ACTION_FLAG_FROM_CAPTCHA); - - } else { - ngx_http_waf_append_action_html(r, - &loc_conf->waf_block_page, - NGX_HTTP_TOO_MANY_REQUESTS, - ACTION_FLAG_FROM_CAPTCHA); - } - - } else { - ngx_http_waf_set_rule_info(r, "CAPTCHA", "CHALLENGE", NGX_HTTP_WAF_TRUE, NGX_HTTP_WAF_TRUE); - ngx_http_waf_append_action_captcha(r, ACTION_FLAG_FROM_CAPTCHA); - } - - ret_value = NGX_HTTP_WAF_MATCHED; - break; - } - - } else { - } - - if (need_delete) { - ngx_shmtx_lock(&shpool->mutex); - - lru_cache_delete(cache, &inx_addr, sizeof(inx_addr)); - - ngx_shmtx_unlock(&shpool->mutex); - } - - return ret_value; -} - - -ngx_int_t ngx_http_waf_perform_action_at_access_end(ngx_http_request_t* r) { - - ngx_http_waf_ctx_t* ctx = NULL; - ngx_http_waf_loc_conf_t* loc_conf = NULL; - ngx_http_waf_get_ctx_and_conf(r, &loc_conf, &ctx); - - if (loc_conf->waf == 2) { - return NGX_DECLINED; - } - - ngx_int_t ret_value = NGX_DECLINED; - action_t *elt = NULL, *tmp = NULL; - - - DL_FOREACH_SAFE(ctx->action_chain, elt, tmp) { - if (ngx_http_waf_check_flag(elt->flag, ACTION_FLAG_DECLINE)) { - DL_DELETE(ctx->action_chain, elt); - ret_value = _perform_action_decline(r, elt); - break; - - } else if (ngx_http_waf_check_flag(elt->flag, ACTION_FLAG_RETURN)) { - DL_DELETE(ctx->action_chain, elt); - ret_value = _perform_action_return(r, elt); - break; - - } else if (ngx_http_waf_check_flag(elt->flag, ACTION_FLAG_REG_CONTENT)) { - DL_DELETE(ctx->action_chain, elt); - _perform_action_reg_content(r, elt); - - } else { - abort(); - } - } - - return ret_value; -} - - -ngx_int_t ngx_http_waf_perform_action_at_content(ngx_http_request_t* r) { - - ngx_http_waf_ctx_t* ctx = NULL; - // ngx_http_waf_loc_conf_t* loc_conf = NULL; - ngx_http_waf_get_ctx_and_conf(r, NULL, &ctx); - - ngx_int_t ret_value = NGX_DECLINED; - action_t *elt = NULL, *tmp = NULL; - - - DL_FOREACH_SAFE(ctx->action_chain, elt, tmp) { - if (ngx_http_waf_check_flag(elt->flag, ACTION_FLAG_STR)) { - DL_DELETE(ctx->action_chain, elt); - ret_value = _perform_action_str(r, elt); - break; - - } else if (ngx_http_waf_check_flag(elt->flag, ACTION_FLAG_HTML)) { - DL_DELETE(ctx->action_chain, elt); - ret_value = _perform_action_html(r, elt); - break; - - } else { - abort(); - } - } - - return ret_value; -} - - -static ngx_int_t _perform_action_return(ngx_http_request_t* r, action_t* action) { - ngx_int_t ret = action->extra.http_status; - return ret; -} - - -static ngx_int_t _perform_action_decline(ngx_http_request_t* r, action_t* action) { - return NGX_DECLINED; - -} - - -static void _perform_action_reg_content(ngx_http_request_t* r, action_t* action) { - ngx_http_waf_register_content_handler(r); -} - - -static ngx_int_t _perform_action_html(ngx_http_request_t* r, action_t* action) { - - ngx_http_waf_loc_conf_t* loc_conf = NULL; - ngx_http_waf_get_ctx_and_conf(r, &loc_conf, NULL); - - ngx_str_t content_type = ngx_string("text/html"); - - inx_addr_t inx_addr; - ngx_uint_t error_page = 0; - ngx_http_waf_make_inx_addr(r, &inx_addr); - - ngx_int_t ret_value = NGX_HTTP_WAF_NOT_MATCHED; - - if (ngx_http_waf_check_flag(action->flag, ACTION_FLAG_CAPTCHA)) { - if (!ngx_http_waf_check_flag(action->flag, ACTION_FLAG_FROM_CAPTCHA)) { - - lru_cache_t* cache = loc_conf->action_cache_captcha; - - if (!ngx_http_waf_is_valid_ptr_value(cache)) { - ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); - return NGX_HTTP_WAF_NOT_MATCHED; - } - - ngx_slab_pool_t *shpool = (ngx_slab_pool_t *)loc_conf->action_zone_captcha->shm.addr; - - ngx_shmtx_lock(&shpool->mutex); - - - /** 过期时间为 [15, 60] 分钟 */ - time_t expire = (time_t)randombytes_uniform(60 * 15) + 60 * 45; - lru_cache_add_result_t result = lru_cache_add(cache, &inx_addr, sizeof(inx_addr), expire); - - if (result.status == NGX_HTTP_WAF_SUCCESS) { - - _captcha_cache_t* tmp = lru_cache_calloc(cache, sizeof(_captcha_cache_t)); - - if (tmp == NULL) { - ret_value = NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - *result.data = tmp; - tmp->count = 0; - - if (!ngx_http_waf_check_flag(action->flag, ACTION_FLAG_FROM_CC_DENY)) { - tmp->error_page = 1; - error_page = tmp->error_page; - } - - } else if (result.status == NGX_HTTP_WAF_KEY_EXISTS) { - _captcha_cache_t* tmp = *result.data; - - if (!ngx_http_waf_check_flag(action->flag, ACTION_FLAG_FROM_CC_DENY)) { - tmp->error_page = 0; - error_page = tmp->error_page; - } - - } else { - ret_value = NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - ngx_shmtx_unlock(&shpool->mutex); - } - - if (ngx_http_waf_check_flag(action->flag, ACTION_FLAG_FROM_CC_DENY)) { - - lru_cache_t* cache = loc_conf->ip_access_statistics; - - if (!ngx_http_waf_is_valid_ptr_value(cache)) { - ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); - return NGX_HTTP_WAF_NOT_MATCHED; - } - - ngx_slab_pool_t *shpool = (ngx_slab_pool_t *)loc_conf->shm_zone_cc_deny->shm.addr; - - ngx_shmtx_lock(&shpool->mutex); - - lru_cache_find_result_t result = lru_cache_find(cache, &inx_addr, sizeof(inx_addr)); - - if (result.status == NGX_HTTP_WAF_KEY_NOT_EXISTS) { - ret_value = NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - - ip_statis_t* ip_statis = *(result.data); - ip_statis->count = 0; - ip_statis->is_blocked = NGX_HTTP_WAF_FALSE; - ip_statis->record_time = time(NULL); - ip_statis->block_time = 0; - - - ngx_shmtx_unlock(&shpool->mutex); - } - } - - - if (ret_value != NGX_HTTP_WAF_NOT_MATCHED) { - ngx_http_finalize_request(r, ret_value); - return ret_value; - } - - - if (error_page) { - if (ngx_is_null_str(&loc_conf->waf_block_page)) { - ngx_http_finalize_request(r, NGX_HTTP_FORBIDDEN); - - } else { - ret_value = _gen_response(r, loc_conf->waf_block_page, content_type, NGX_HTTP_FORBIDDEN); - } - - } else { - ret_value = _gen_response(r, *action->extra.extra_html.html, content_type, action->extra.extra_html.http_status); - } - - return ret_value; -} - - -static ngx_int_t _perform_action_str(ngx_http_request_t* r, action_t* action) { - ngx_str_t content_type = ngx_string("text/plain"); - return _gen_response(r, *action->extra.extra_str.str, content_type, action->extra.extra_str.http_status); -} - - -static ngx_int_t _gen_response(ngx_http_request_t* r, ngx_str_t data, ngx_str_t content_type, ngx_uint_t http_status) { - - ngx_int_t rc = ngx_http_discard_request_body(r); - if (rc != NGX_OK) { - return rc; - } - - ngx_str_t res = data; - - r->headers_out.content_type.data = ngx_pstrdup(r->pool, &content_type); - r->headers_out.content_type.len = content_type.len; - - r->headers_out.status = http_status; - - r->headers_out.content_length_n = res.len; - - if (ngx_http_waf_gen_no_cache_header(r) != NGX_HTTP_WAF_SUCCESS) { - ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - - rc = ngx_http_send_header(r); - - if (rc == NGX_ERROR || rc > NGX_OK) { - return rc; - } - - if (r->header_only) { - return rc; - } - - - - ngx_buf_t* buf = ngx_pcalloc(r->pool, sizeof(ngx_buf_t)); - if (buf == NULL) { - ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - buf->pos = ngx_pcalloc(r->pool, res.len); - if (buf->pos == NULL) { - ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - ngx_memcpy(buf->pos, res.data, res.len); - buf->last = buf->pos + res.len; - buf->memory = 1; - buf->last_buf = (r == r->main) ? 1 : 0; - - ngx_chain_t* out = ngx_pcalloc(r->pool, sizeof(ngx_chain_t)); - if (out == NULL) { - ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - out->buf = buf; - out->next = NULL; - - rc = ngx_http_output_filter(r, out); - return rc; -} diff --git a/src/ngx_http_waf_module_core.c b/src/ngx_http_waf_module_core.c index 3a81509f..0ff7cfe7 100644 --- a/src/ngx_http_waf_module_core.c +++ b/src/ngx_http_waf_module_core.c @@ -150,6 +150,9 @@ ngx_module_t ngx_http_waf_module = { }; +static ngx_int_t _handler_content_phase(ngx_http_request_t* r); + + static ngx_int_t _read_request_body(ngx_http_request_t* r); @@ -170,17 +173,6 @@ ngx_int_t ngx_http_waf_handler_access_phase(ngx_http_request_t* r) { return ngx_http_waf_check_all(r, NGX_HTTP_WAF_TRUE); } -ngx_int_t ngx_http_waf_handler_precontent_phase(ngx_http_request_t* r) { - - ngx_http_waf_ctx_t* ctx = NULL; - ngx_http_waf_loc_conf_t* loc_conf = NULL; - ngx_http_waf_get_ctx_and_conf(r, &loc_conf, &ctx); - - ngx_http_waf_perform_action_at_content(r); - - return NGX_OK; -} - ngx_int_t ngx_http_waf_handler_log_phase(ngx_http_request_t* r) { @@ -198,10 +190,10 @@ ngx_int_t ngx_http_waf_handler_log_phase(ngx_http_request_t* r) { return NGX_OK; } - if (ctx->gernal_logged) { - ctx->gernal_logged = 0; - ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, "ngx_waf: [%V][%V]", &ctx->rule_type, &ctx->rule_deatils); - } + // if (ctx->gernal_logged) { + // ctx->gernal_logged = 0; + // ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, "ngx_waf: [%V][%V]", &ctx->rule_type, &ctx->rule_deatils); + // } if (ctx->modsecurity_transaction != NULL) { int ret = msc_process_logging(ctx->modsecurity_transaction); @@ -219,25 +211,28 @@ ngx_int_t ngx_http_waf_handler_log_phase(ngx_http_request_t* r) { ngx_int_t ngx_http_waf_check_all(ngx_http_request_t* r, ngx_int_t is_check_cc) { - ngx_http_waf_ctx_t* ctx = NULL; ngx_http_waf_loc_conf_t* loc_conf = NULL; ngx_http_waf_get_ctx_and_conf(r, &loc_conf, &ctx); ngx_int_t is_matched = NGX_HTTP_WAF_NOT_MATCHED; + ngx_http_waf_check_result_t check_result; + ngx_http_request_t* sr; + ngx_http_post_subrequest_t* psr; if (ngx_http_waf_is_unset_or_disable_value(loc_conf->waf)) { return NGX_DECLINED; } if (ctx == NULL) { - ngx_http_cleanup_t* cln = ngx_palloc(r->pool, sizeof(ngx_http_cleanup_t)); if (cln == NULL) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "[ngx_waf] failed to allocate memory for ngx_http_cleanup_t"); return NGX_ERROR; } ctx = ngx_palloc(r->pool, sizeof(ngx_http_waf_ctx_t)); if (ctx == NULL) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "[ngx_waf] failed to allocate memory for ctx"); return NGX_ERROR; } @@ -246,29 +241,13 @@ ngx_int_t ngx_http_waf_check_all(ngx_http_request_t* r, ngx_int_t is_check_cc) { cln->next = NULL; ctx->r = r; - ctx->action_chain = NULL; - ctx->rate = 0; - ctx->response_str = NULL; - ctx->register_content_handler = 0; - ctx->gernal_logged = 0; - ctx->read_body_done = 0; - ctx->has_req_body = 0; - ctx->waiting_more_body = 0; - ctx->pre_content_run = 0; - ctx->checked = 0; - ctx->blocked = 0; - ctx->spend = (double)clock() / CLOCKS_PER_SEC * 1000; - ngx_str_null(&ctx->rule_type); - ngx_str_null(&ctx->rule_deatils); - ctx->req_body.pos = NULL; - ctx->req_body.last = NULL; - ctx->req_body.memory = 1; - ctx->req_body.temporary = 0; - ctx->req_body.mmap = 0; ctx->modsecurity_transaction = NULL; + ctx->next_chekcer_index = 0; + ctx->waiting_subrequest = 0; if (r->cleanup == NULL) { r->cleanup = cln; + } else { for (ngx_http_cleanup_t* i = r->cleanup; i != NULL; i = i->next) { if (i->next == NULL) { @@ -285,63 +264,60 @@ ngx_int_t ngx_http_waf_check_all(ngx_http_request_t* r, ngx_int_t is_check_cc) { ngx_http_set_ctx(r, ctx, ngx_http_waf_module); } - - if (ctx->register_content_handler && loc_conf->waf == 1) { - ngx_http_waf_register_content_handler(r); + if (ngx_http_waf_is_internal_request(r)) { + return NGX_DECLINED; } - if (ngx_http_waf_check_flag(!loc_conf->waf_mode, r->method)) { + if (ctx->next_chekcer_index >= sizeof(loc_conf->check_proc) / sizeof(ngx_http_waf_check_pt*)) { return NGX_DECLINED; } - - if (ctx->waiting_more_body) { - return NGX_DONE; + if (ctx->waiting_subrequest) { + return NGX_AGAIN; } - if (!ctx->read_body_done) { - r->request_body_in_single_buf = 1; - r->request_body_in_persistent_file = 1; - r->request_body_in_clean_file = 1; + ngx_http_waf_check_pt* funcs = loc_conf->check_proc; + for (; ctx->next_chekcer_index < sizeof(loc_conf->check_proc) / sizeof(ngx_http_waf_check_pt*); ctx->next_chekcer_index++) { + check_result = funcs[ctx->next_chekcer_index](r); - ngx_int_t rc = ngx_http_read_client_request_body(r, _handler_read_request_body); - if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) { - return rc; + if (!check_result.need_do_sth) { + continue; } - if (rc == NGX_AGAIN) { - ctx->waiting_more_body = 1; - return NGX_DONE; + + if (check_result.need_log) { + ngx_log_error(check_result.log_level, r->connection->log, 0, "[ngx_waf] %V", &check_result.log_message); } - } - if (!r->internal && ctx->checked) { - return NGX_DECLINED; - } + if (check_result.need_response) { + ctx->next_chekcer_index = sizeof(loc_conf->check_proc) / sizeof(ngx_http_waf_check_pt*); - if (ctx->checked) { - return NGX_DECLINED; - } + if (ngx_http_waf_is_empty_str_value(&check_result.response_body)) { + return check_result.http_status; + } - if (_read_request_body(r) == NGX_HTTP_WAF_FAULT) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } + ctx->result_for_content_phase = check_result; + r->content_handler = _handler_content_phase; + } - ctx->checked = 1; + if (check_result.need_subrequest) { + if ((psr = ngx_palloc(r->pool, sizeof(ngx_http_post_subrequest_t))) == NULL) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "[ngx_waf] failed to allocate memory for ngx_http_post_subrequest_t"); + return NGX_ERROR; + } - ngx_http_waf_check_pt* funcs = loc_conf->check_proc; - for (size_t i = 0; funcs[i] != NULL; i++) { - is_matched = funcs[i](r); - if (is_matched == NGX_HTTP_WAF_MATCHED) { - break; - } - ctx->action_chain = NULL; - } + psr->data = ctx; + psr->handler = check_result.subrequest_handler; - ctx->spend = ((double)clock() / CLOCKS_PER_SEC * 1000) - ctx->spend; + if (ngx_http_subrequest(r, &check_result.subrequest_uri, &check_result.subrequest_args, &sr, psr, NGX_HTTP_SUBREQUEST_IN_MEMORY) != NGX_OK) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "[ngx_waf] failed to create subrequest"); + return NGX_ERROR; + } - ngx_int_t http_status = ngx_http_waf_perform_action_at_access_end(r); + return NGX_AGAIN; + } + } - return http_status; + return NGX_DECLINED; } @@ -350,74 +326,61 @@ void ngx_http_waf_handler_cleanup(void *data) { } -static ngx_int_t _read_request_body(ngx_http_request_t* r) { - +static ngx_int_t _handler_content_phase(ngx_http_request_t* r) { ngx_http_waf_ctx_t* ctx = NULL; - ngx_http_waf_loc_conf_t* loc_conf = NULL; - ngx_http_waf_get_ctx_and_conf(r, &loc_conf, &ctx); + ngx_http_waf_get_ctx_and_conf(r, NULL, &ctx); + ngx_http_waf_check_result_t result = ctx->result_for_content_phase; + ngx_buf_t* buf = ngx_pcalloc(r->pool, sizeof(ngx_buf_t)); + ngx_chain_t* out; + ngx_int_t rc; + + r->headers_out.content_type.data = "text/html"; + r->headers_out.content_type.len = sizeof("text/html") - 1; + r->headers_out.status = result.http_status; - if (r->request_body == NULL) { - return NGX_HTTP_WAF_FAIL; - } + r->headers_out.content_length_n = result.response_body.len; - if (r->request_body->bufs == NULL) { - return NGX_HTTP_WAF_FAIL; + if (ngx_http_waf_gen_no_cache_header(r) != NGX_HTTP_WAF_SUCCESS) { + ngx_log_error(NGX_LOG_WARN, r->connection->log, 0, "[ngx_waf] failed to generate response header Cache-control"); } - if (r->request_body->temp_file) { - return NGX_HTTP_WAF_FAIL; + rc = ngx_http_send_header(r); + if (rc == NGX_ERROR || rc > NGX_OK) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "[ngx_waf] failed to send response header"); + return rc; } - if (ctx->has_req_body) { - return NGX_HTTP_WAF_SUCCESS; + if (r->header_only) { + return rc; } - ngx_chain_t* bufs = r->request_body->bufs; - size_t len = 0; - - while (bufs != NULL) { - len += (bufs->buf->last - bufs->buf->pos) * (sizeof(u_char) / sizeof(uint8_t)); - bufs = bufs->next; + if ((buf = ngx_pcalloc(r->pool, sizeof(ngx_buf_t))) == NULL) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "[ngx_waf] failed to allocate memory for response body"); + return NGX_ERROR; } - u_char* body = ngx_pnalloc(r->pool, len + sizeof(u_char)); - if (body == NULL) { - return NGX_HTTP_WAF_FAULT; + if ((buf->pos = ngx_pcalloc(r->pool, result.response_body.len)) == NULL) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "[ngx_waf] failed to allocate memory for response body"); + return NGX_ERROR; } - ctx->has_req_body = 1; - ctx->req_body.pos = body; - ctx->req_body.last = (u_char*)((uint8_t*)body + len); - - bufs = r->request_body->bufs; - size_t offset = 0; - while (bufs != NULL) { - size_t size = bufs->buf->last - bufs->buf->pos; - ngx_memcpy((uint8_t*)body + offset, bufs->buf->pos, size); - offset += size; - bufs = bufs->next; - } - - - return NGX_HTTP_WAF_SUCCESS; -} - - -static void _handler_read_request_body(ngx_http_request_t* r) { + ngx_memcpy(buf->pos, result.response_body.data, result.response_body.len); + buf->last = buf->pos + result.response_body.len; + buf->memory = 1; + buf->last_buf = 1; + buf->start = buf->pos; + buf->end = buf->last; - ngx_http_waf_ctx_t* ctx = NULL; - ngx_http_waf_loc_conf_t* loc_conf = NULL; - ngx_http_waf_get_ctx_and_conf(r, &loc_conf, &ctx); - - ctx->read_body_done = 1; - ngx_http_finalize_request(r, NGX_DONE); - - if (ctx->waiting_more_body) { - ctx->waiting_more_body = 0; - ngx_http_core_run_phases(r); + if ((out = ngx_pcalloc(r->pool, sizeof(ngx_chain_t))) == NULL) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "[ngx_waf] failed to allocate memory for response body"); + return NGX_ERROR; } + out->buf = buf; + out->next = NULL; + + return ngx_http_output_filter(r, out); } diff --git a/src/ngx_http_waf_module_util.c b/src/ngx_http_waf_module_util.c index ef986086..6d63d1b2 100644 --- a/src/ngx_http_waf_module_util.c +++ b/src/ngx_http_waf_module_util.c @@ -4,9 +4,6 @@ extern ngx_module_t ngx_http_waf_module; /**< 模块详情 */ -extern ngx_int_t ngx_http_waf_handler_precontent_phase(ngx_http_request_t* r); - - extern void ngx_http_waf_handler_cleanup(void *data); @@ -555,7 +552,6 @@ ngx_int_t ngx_http_waf_sha256(u_char* dst, size_t dst_len, const void* buf, size void ngx_http_waf_get_ctx_and_conf(ngx_http_request_t* r, ngx_http_waf_loc_conf_t** conf, ngx_http_waf_ctx_t** ctx) { - if (ctx != NULL) { *ctx = NULL; *ctx = ngx_http_get_module_ctx(r, ngx_http_waf_module); @@ -617,34 +613,6 @@ void ngx_http_waf_make_inx_addr(ngx_http_request_t* r, inx_addr_t* inx_addr) { } -void ngx_http_waf_set_rule_info(ngx_http_request_t* r, char* type, char* details, ngx_int_t gernal_logged, ngx_int_t blocked) { - - ngx_http_waf_ctx_t* ctx = NULL; - ngx_http_waf_get_ctx_and_conf(r, NULL, &ctx); - - - size_t type_len = ngx_strlen(type); - size_t details_len = ngx_strlen(details); - - ctx->rule_type.data = ngx_pcalloc(r->pool, type_len); - ctx->rule_type.len = type_len; - ngx_memcpy(ctx->rule_type.data, type, type_len); - - ctx->rule_deatils.data = ngx_pcalloc(r->pool, details_len); - ctx->rule_deatils.len = details_len; - ngx_memcpy(ctx->rule_deatils.data, details, details_len); - - if (gernal_logged == NGX_HTTP_WAF_TRUE) { - ctx->gernal_logged = 1; - } - - if (blocked == NGX_HTTP_WAF_TRUE) { - ctx->blocked = 1; - } - -} - - ngx_int_t ngx_http_waf_http_post(ngx_http_request_t* r, const char* url, char* in, char** out) { #define _error_without_msg() { \ @@ -760,21 +728,12 @@ ngx_int_t ngx_http_waf_gen_no_cache_header(ngx_http_request_t* r) { } header->hash = 1; header->lowcase_key = (u_char*)"cache-control"; - ngx_str_set(&header->key, "Cache-control"); + ngx_str_set(&header->key, "Cache-Control"); ngx_str_set(&header->value, "no-store"); return NGX_HTTP_WAF_SUCCESS; } -void ngx_http_waf_register_content_handler(ngx_http_request_t* r) { - ngx_http_waf_ctx_t* ctx = NULL; - ngx_http_waf_get_ctx_and_conf(r, NULL, &ctx); - - ctx->register_content_handler = NGX_HTTP_WAF_TRUE; - r->content_handler = ngx_http_waf_handler_precontent_phase; -} - - char* ngx_http_waf_c_str(ngx_str_t* str, ngx_pool_t* pool) { char* ret = NULL;