//#define mechanics_debug static ngx_int_t ngx_http_dummy_access_handler(ngx_http_request_t *r) { ngx_http_request_ctx_t *ctx; ngx_int_t rc; ngx_http_dummy_loc_conf_t *cf; ngx_http_core_loc_conf_t *clcf; struct tms tmsstart, tmsend; clock_t start, end; ctx = ngx_http_get_module_ctx(r, ngx_http_naxsi_module); cf = ngx_http_get_module_loc_conf(r, ngx_http_naxsi_module); clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); /* ngx_log_debug(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, */ /* "naxsi_entry_point"); */ if (ctx && ctx->over) return (NGX_DECLINED); if (ctx && ctx->wait_for_body) { #ifdef mechanics_debug ngx_log_debug(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "naxsi:NGX_AGAIN"); #endif return (NGX_DONE); } if (!cf) return (NGX_ERROR); /* the module is not enabled here */ if (!cf->enabled || cf->force_disabled) return (NGX_DECLINED); /* don't process internal requests. */ if (r->internal) { #ifdef mechanics_debug ngx_log_debug(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "XX-DON'T PROCESS (%V)|CTX:%p|ARGS:%V|METHOD=%s|INTERNAL:%d", &(r->uri), ctx, &(r->args), r->method == NGX_HTTP_POST ? "POST" : r->method == NGX_HTTP_PUT ? "PUT" : r->method == NGX_HTTP_GET ? "GET" : "UNKNOWN!!", r->internal); #endif return (NGX_DECLINED); } #ifdef mechanics_debug ngx_log_debug(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "XX-processing (%V)|CTX:%p|ARGS:%V|METHOD=%s|INTERNAL:%d", &(r->uri), ctx, &(r->args), r->method == NGX_HTTP_POST ? "POST" : r->method == NGX_HTTP_PUT ? "PUT" : r->method == NGX_HTTP_GET ? "GET" : "UNKNOWN!!", r->internal); #endif if (!ctx) { ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_request_ctx_t)); /* might have been set by a previous trigger */ if (cf->learning) { clcf->post_action.data = 0; //cf->denied_url->data; clcf->post_action.len = 0; //cf->denied_url->len; } if (ctx == NULL) return NGX_ERROR; ngx_http_set_ctx(r, ctx, ngx_http_naxsi_module); if ((r->method == NGX_HTTP_POST || r->method == NGX_HTTP_PUT) && !ctx->ready) { #ifdef mechanics_debug ngx_log_debug(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "XX-dummy : body_request : before !"); #endif rc = ngx_http_read_client_request_body(r, ngx_http_dummy_payload_handler); /* this might happen quite often, especially with big files / ** low network speed. our handler is called when headers are read, ** but, often, the full body request hasn't yet, so ** read client request body will return ngx_again. Then we need ** to return ngx_done, wait for our handler to be called once ** body request arrived, and let him call core_run_phases ** to be able to process the request. */ if (rc == NGX_AGAIN) { ctx->wait_for_body = 1; #ifdef mechanics_debug ngx_log_debug(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "XX-dummy : body_request : NGX_AGAIN !"); #endif return (NGX_DONE); } else if (rc >= NGX_HTTP_SPECIAL_RESPONSE) { /* this debug print should be commented, but the thing is that ** according to what I read into nginx src code, it may happen ** and I haven't been abble to trigger this, so I just let it ** here to know when this special case will be triggered */ ngx_log_debug(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "XX-dummy : SPECIAL RESPONSE !!!!"); return rc; } } else ctx->ready = 1; } if (ctx && ctx->ready && !ctx->over) { if ((start = times(&tmsstart)) == -1) ngx_log_debug(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "XX-dummy : Failed to get time"); ngx_http_dummy_data_parse(ctx, r); cf->request_processed++; if ((end = times(&tmsend)) == -1) ngx_log_debug(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "XX-dummy : Failed to get time"); if (end - start > 0) ngx_log_debug(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "[MORE THAN 1MS] times : start:%l end:%l diff:%l", start, end, (end-start)); ctx->over = 1; if (ctx->block) { cf->request_blocked++; rc = ngx_http_output_forbidden_page(ctx, r); //nothing: return (NGX_OK); //redirect : return (NGX_HTTP_OK); return (rc); } } #ifdef mechanics_debug ngx_log_debug(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "NGX_FINISHED !"); #endif return (NGX_DECLINED); }
/* ** [ENTRY POINT] does : this is the function called by nginx : ** - Set up the context for the request ** - Check if the job is done and we're called again ** - if it's a POST/PUT request, setup hook for body dataz ** - call dummy_data_parse ** - check our context struct (with scores & stuff) against custom check rules ** - check if the request should be denied */ static ngx_int_t ngx_http_dummy_access_handler(ngx_http_request_t *r) { ngx_http_request_ctx_t *ctx; ngx_int_t rc; ngx_http_dummy_loc_conf_t *cf; struct tms tmsstart, tmsend; clock_t start, end; ngx_http_variable_value_t *lookup; static ngx_str_t learning_flag = ngx_string(RT_LEARNING); static ngx_str_t enable_flag = ngx_string(RT_ENABLE); static ngx_str_t post_action_flag = ngx_string(RT_POST_ACTION); static ngx_str_t extensive_log_flag = ngx_string(RT_EXTENSIVE_LOG); static ngx_str_t libinjection_sql_flag = ngx_string(RT_LIBINJECTION_SQL); static ngx_str_t libinjection_xss_flag = ngx_string(RT_LIBINJECTION_XSS); ctx = ngx_http_get_module_ctx(r, ngx_http_naxsi_module); cf = ngx_http_get_module_loc_conf(r, ngx_http_naxsi_module); if (ctx && ctx->over) return (NGX_DECLINED); if (ctx && ctx->wait_for_body) { NX_DEBUG(_debug_mechanics, NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "naxsi:NGX_AGAIN"); return (NGX_DONE); } if (!cf) return (NGX_ERROR); /* the module is not enabled here */ /* if enable directive is not present at all in the location, don't try to do dynamic lookup for "live" enabled naxsi, this would be very rude. */ if (!cf->enabled) return (NGX_DECLINED); /* On the other hand, if naxsi has been explicitly disabled in this location (using naxsi directive), user is probably trying to do something. */ if (cf->force_disabled) { /* Look if the user did not try to enable naxsi dynamically */ lookup = ngx_http_get_variable(r, &enable_flag, cf->flag_enable_h); if (lookup && !lookup->not_found && lookup->len > 0) { ngx_log_debug(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "live enable is present %d", lookup->data[0] - '0'); if (lookup->data[0] - '0' != 1) { return (NGX_DECLINED);} } else return (NGX_DECLINED); } /* don't process internal requests. */ if (r->internal) { NX_DEBUG(_debug_mechanics, NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "XX-DON'T PROCESS (%V)|CTX:%p|ARGS:%V|METHOD=%s|INTERNAL:%d", &(r->uri), ctx, &(r->args), r->method == NGX_HTTP_POST ? "POST" : r->method == NGX_HTTP_PUT ? "PUT" : r->method == NGX_HTTP_GET ? "GET" : "UNKNOWN!!", r->internal); return (NGX_DECLINED); } NX_DEBUG(_debug_mechanics, NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "XX-processing (%V)|CTX:%p|ARGS:%V|METHOD=%s|INTERNAL:%d", &(r->uri), ctx, &(r->args), r->method == NGX_HTTP_POST ? "POST" : r->method == NGX_HTTP_PUT ? "PUT" : r->method == NGX_HTTP_GET ? "GET" : "UNKNOWN!!", r->internal); if (!ctx) { ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_request_ctx_t)); if (ctx == NULL) return NGX_ERROR; ngx_http_set_ctx(r, ctx, ngx_http_naxsi_module); NX_DEBUG(_debug_modifier, NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "XX-dummy : orig learning : %d", cf->learning ? 1 : 0); /* it seems that nginx will - in some cases - have a variable with empty content but with lookup->not_found set to 0, so check len as well */ ctx->learning = cf->learning; lookup = ngx_http_get_variable(r, &learning_flag, cf->flag_learning_h); if (lookup && !lookup->not_found && lookup->len > 0) { ctx->learning = lookup->data[0] - '0'; NX_DEBUG(_debug_modifier, NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "XX-dummy : override learning : %d (raw=%d)", ctx->learning ? 1 : 0, lookup->len); } NX_DEBUG( _debug_modifier, NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "XX-dummy : [final] learning : %d", ctx->learning ? 1 : 0); ctx->enabled = cf->enabled; NX_DEBUG( _debug_modifier, NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "XX-dummy : orig enabled : %d", ctx->enabled ? 1 : 0); lookup = ngx_http_get_variable(r, &enable_flag, cf->flag_enable_h); if (lookup && !lookup->not_found && lookup->len > 0) { ctx->enabled = lookup->data[0] - '0'; NX_DEBUG( _debug_modifier, NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "XX-dummy : override enable : %d", ctx->enabled ? 1 : 0); } NX_DEBUG( _debug_modifier, NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "XX-dummy : [final] enabled : %d", ctx->enabled ? 1 : 0); /* ** LIBINJECTION_SQL */ ctx->libinjection_sql = cf->libinjection_sql_enabled; NX_DEBUG( _debug_modifier, NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "XX-dummy : orig libinjection_sql : %d", ctx->libinjection_sql ? 1 : 0); lookup = ngx_http_get_variable(r, &libinjection_sql_flag, cf->flag_libinjection_sql_h); if (lookup && !lookup->not_found && lookup->len > 0) { ctx->libinjection_sql = lookup->data[0] - '0'; NX_DEBUG( _debug_modifier, NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "XX-dummy : override libinjection_sql : %d", ctx->libinjection_sql ? 1 : 0); } NX_DEBUG( _debug_modifier, NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "XX-dummy : [final] libinjection_sql : %d", ctx->libinjection_sql ? 1 : 0); /* ** LIBINJECTION_XSS */ ctx->libinjection_xss = cf->libinjection_xss_enabled; NX_DEBUG( _debug_modifier, NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "XX-dummy : orig libinjection_xss : %d", ctx->libinjection_xss ? 1 : 0); lookup = ngx_http_get_variable(r, &libinjection_xss_flag, cf->flag_libinjection_xss_h); if (lookup && !lookup->not_found && lookup->len > 0) { ctx->libinjection_xss = lookup->data[0] - '0'; NX_DEBUG( _debug_modifier, NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "XX-dummy : override libinjection_xss : %d", ctx->libinjection_xss ? 1 : 0); } NX_DEBUG( _debug_modifier, NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "XX-dummy : [final] libinjection_xss : %d", ctx->libinjection_xss ? 1 : 0); /* post_action is off by default. */ ctx->post_action = 0; NX_DEBUG( _debug_modifier , NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "XX-dummy : orig post_action : %d", ctx->post_action ? 1 : 0); lookup = ngx_http_get_variable(r, &post_action_flag, cf->flag_post_action_h); if (lookup && !lookup->not_found && lookup->len > 0) { ctx->post_action = lookup->data[0] - '0'; NX_DEBUG( _debug_modifier, NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "XX-dummy : override post_action : %d", ctx->post_action ? 1 : 0); } NX_DEBUG( _debug_modifier, NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "XX-dummy : [final] post_action : %d", ctx->post_action ? 1 : 0); NX_DEBUG( _debug_modifier , NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "XX-dummy : orig extensive_log : %d", ctx->extensive_log ? 1 : 0); lookup = ngx_http_get_variable(r, &extensive_log_flag, cf->flag_extensive_log_h); if (lookup && !lookup->not_found && lookup->len > 0) { ctx->extensive_log = lookup->data[0] - '0'; NX_DEBUG( _debug_modifier, NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "XX-dummy : override extensive_log : %d", ctx->extensive_log ? 1 : 0); } NX_DEBUG( _debug_modifier, NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "XX-dummy : [final] extensive_log : %d", ctx->extensive_log ? 1 : 0); /* the module is not enabled here */ if (!ctx->enabled) return (NGX_DECLINED); if ((r->method == NGX_HTTP_POST || r->method == NGX_HTTP_PUT) && !ctx->ready) { NX_DEBUG( _debug_mechanics, NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "XX-dummy : body_request : before !"); rc = ngx_http_read_client_request_body(r, ngx_http_dummy_payload_handler); /* this might happen quite often, especially with big files / ** low network speed. our handler is called when headers are read, ** but, often, the full body request hasn't yet, so ** read client request body will return ngx_again. Then we need ** to return ngx_done, wait for our handler to be called once ** body request arrived, and let him call core_run_phases ** to be able to process the request. */ if (rc == NGX_AGAIN) { ctx->wait_for_body = 1; NX_DEBUG( _debug_mechanics, NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "XX-dummy : body_request : NGX_AGAIN !"); return (NGX_DONE); } else if (rc >= NGX_HTTP_SPECIAL_RESPONSE) { /* ** might happen but never saw it, let the debug print. */ ngx_log_debug(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "XX-dummy : SPECIAL RESPONSE !!!!"); return rc; } } else ctx->ready = 1; } if (ctx && ctx->ready && !ctx->over) { if ((start = times(&tmsstart)) == (clock_t)-1) ngx_log_debug(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "XX-dummy : Failed to get time"); ngx_http_dummy_data_parse(ctx, r); cf->request_processed++; if ((end = times(&tmsend)) == (clock_t)-1) ngx_log_debug(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "XX-dummy : Failed to get time"); if (end - start > 10) ngx_log_debug(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "[MORE THAN 10MS] times : start:%l end:%l diff:%l", start, end, (end-start)); ctx->over = 1; if (ctx->block || ctx->drop) { cf->request_blocked++; rc = ngx_http_output_forbidden_page(ctx, r); //nothing: return (NGX_OK); //redirect : return (NGX_HTTP_OK); return rc; } } NX_DEBUG(_debug_mechanics, NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "NGX_FINISHED !"); return NGX_DECLINED; }