模块处理函数ngx_http_naxsi_access_handler 最后调用的ngx_http_output_forbidden_page函数即是对检测结果处理的入口函数。
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;
} else if (ctx->log) {
rc = ngx_http_output_forbidden_page(ctx, r);
}
// 会为 ostr 及 tmp_uri 赋值
if (ngx_http_nx_log(ctx, r, ostr, &tmp_uri) != NGX_HTTP_OK)
return (NGX_ERROR);
// 字符串日志输出
if (!ctx->json_log) {
for (i = 0; i < ostr->nelts; i++) {
ngx_log_error(
NGX_LOG_ERR, r->connection->log, 0, "NAXSI_FMT: %s", ((ngx_str_t*)ostr->elts)[i].data);
}
}
// json 日志输出
else {
/*
** add headers with original url
** and arguments, as well as
** the first fragment of log
*/
#define NAXSI_HEADER_ORIG_URL "x-orig_url"
#define NAXSI_HEADER_ORIG_ARGS "x-orig_args"
#define NAXSI_HEADER_NAXSI_SIG "x-naxsi_sig"
// 给请求header添加 key/value键值对
if (r->headers_in.headers.last) {
/*
调用ngx_list_push表示添加新的元素,传入的参数是ngx_list_t链表。
正常情况下,返回的是新分配的元素首地址。如果返回NULL空指针,则表示添加失败。
在使用它时通常先调用ngx_list_push得到返回的元素地址,再对返回的地址进行赋值。
*/
h = ngx_list_push(&(r->headers_in.headers)); // 头部链表 key value
if (!h)
return (NGX_ERROR);
h->key.len = strlen(NAXSI_HEADER_ORIG_URL);
h->key.data = ngx_pcalloc(r->pool, strlen(NAXSI_HEADER_ORIG_URL) + 1);
if (!h->key.data)
return (NGX_ERROR);
memcpy(h->key.data, NAXSI_HEADER_ORIG_URL, strlen(NAXSI_HEADER_ORIG_URL));
h->lowcase_key = ngx_pcalloc(r->pool, strlen(NAXSI_HEADER_ORIG_URL) + 1);
memcpy(h->lowcase_key, NAXSI_HEADER_ORIG_URL, strlen(NAXSI_HEADER_ORIG_URL));
h->value.len = tmp_uri->len;
h->value.data = ngx_pcalloc(r->pool, tmp_uri->len + 1);
memcpy(h->value.data, tmp_uri->data, tmp_uri->len);
h = ngx_list_push(&(r->headers_in.headers));
if (!h)
return (NGX_ERROR);
h->key.len = strlen(NAXSI_HEADER_ORIG_ARGS);
h->key.data = ngx_pcalloc(r->pool, strlen(NAXSI_HEADER_ORIG_ARGS) + 1);
if (!h->key.data)
return (NGX_ERROR);
memcpy(h->key.data, NAXSI_HEADER_ORIG_ARGS, strlen(NAXSI_HEADER_ORIG_ARGS));
h->lowcase_key = ngx_pcalloc(r->pool, strlen(NAXSI_HEADER_ORIG_ARGS) + 1);
memcpy(h->lowcase_key, NAXSI_HEADER_ORIG_ARGS, strlen(NAXSI_HEADER_ORIG_ARGS));
h->value.len = r->args.len;
h->value.data = ngx_pcalloc(r->pool, r->args.len + 1);
memcpy(h->value.data, r->args.data, r->args.len);
h = ngx_list_push(&(r->headers_in.headers));
if (!h)
return (NGX_ERROR);
h->key.len = strlen(NAXSI_HEADER_NAXSI_SIG);
h->key.data = ngx_pcalloc(r->pool, strlen(NAXSI_HEADER_NAXSI_SIG) + 1);
if (!h->key.data)
return (NGX_ERROR);
memcpy(h->key.data, NAXSI_HEADER_NAXSI_SIG, strlen(NAXSI_HEADER_NAXSI_SIG));
h->lowcase_key = ngx_pcalloc(r->pool, strlen(NAXSI_HEADER_NAXSI_SIG) + 1);
memcpy(h->lowcase_key, NAXSI_HEADER_NAXSI_SIG, strlen(NAXSI_HEADER_NAXSI_SIG));
h->value.len = denied_args.len;
h->value.data = denied_args.data;
}
if (ctx->learning && !ctx->drop) {
if (ctx->post_action) {
ngx_http_core_loc_conf_t* clcf;
clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
clcf->post_action.data = cf->denied_url->data;
clcf->post_action.len = cf->denied_url->len;
}
return (NGX_DECLINED);
} else {
ngx_http_internal_redirect(r, cf->denied_url, &empty); // 将请求重定向到一个新的location
return (NGX_HTTP_OK);
}
#define NGX_OK 0 // 表示该阶段已经处理完成,需要转入下一个阶段
#define NGX_ERROR -1 // 表示发生了错误,需要结束该请求。
#define NGX_AGAIN -2 // 表示需要等待某个事件发生才能继续处理(比如等待网络IO),此时Nginx为了不阻塞其他请求的处理,必须中断当前请求的执行链,等待事件发生之后继续执行该handler
#define NGX_BUSY -3
#define NGX_DONE -4 // 表示需要等待某个事件发生才能继续处理(比如等待网络IO),此时Nginx为了不阻塞其他请求的处理,必须中断当前请求的执行链,等待事件发生之后继续执行该handler
#define NGX_DECLINED -5 // 表示需要转入本阶段的下一个handler继续处理
#define NGX_ABORT -6
uintptr_t ngx_escape_uri(u_char *dst, u_char *src, size_t size, ngx_uint_t type);
对src进行编码,根据type来按不同的方式进行编码,如果dst为NULL,则返回需要转义的字符的数量,由此可得到需要的空间大小。type的类型可以是:
#define NGX_ESCAPE_URI 0
#define NGX_ESCAPE_ARGS 1
#define NGX_ESCAPE_URI_COMPONENT 2
#define NGX_ESCAPE_HTML 3
#define NGX_ESCAPE_REFRESH 4
#define NGX_ESCAPE_MEMCACHED 5
#define NGX_ESCAPE_MAIL_AUTH 6