562 lines
18 KiB
C
562 lines
18 KiB
C
// SPDX-FileCopyrightText: 2016-2019, Thibault 'bui' Koechlin <tko@nbs-system.com>
|
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
#include <ngx_config.h>
|
|
|
|
#include <naxsi.h>
|
|
#include <naxsi_config.h>
|
|
#include <naxsi_macros.h>
|
|
|
|
/*
|
|
** TOP LEVEL configuration parsing code
|
|
*/
|
|
/*
|
|
** code to parse FLAGS and OPTIONS on each line.
|
|
*/
|
|
void*
|
|
naxsi_id(ngx_conf_t* r, ngx_str_t* tmp, ngx_http_rule_t* rule);
|
|
void*
|
|
naxsi_score(ngx_conf_t* r, ngx_str_t* tmp, ngx_http_rule_t* rule);
|
|
void*
|
|
naxsi_msg(ngx_conf_t* r, ngx_str_t* tmp, ngx_http_rule_t* rule);
|
|
void*
|
|
naxsi_rx(ngx_conf_t* r, ngx_str_t* tmp, ngx_http_rule_t* rule);
|
|
void*
|
|
naxsi_zone(ngx_conf_t* r, ngx_str_t* tmp, ngx_http_rule_t* rule);
|
|
void*
|
|
naxsi_str(ngx_conf_t* r, ngx_str_t* tmp, ngx_http_rule_t* rule);
|
|
void*
|
|
naxsi_negative(ngx_conf_t* r, ngx_str_t* tmp, ngx_http_rule_t* rule);
|
|
void*
|
|
naxsi_libinj_xss(ngx_conf_t* r, ngx_str_t* tmp, ngx_http_rule_t* rule);
|
|
void*
|
|
naxsi_libinj_sql(ngx_conf_t* r, ngx_str_t* tmp, ngx_http_rule_t* rule);
|
|
void*
|
|
naxsi_whitelist(ngx_conf_t* r, ngx_str_t* tmp, ngx_http_rule_t* rule);
|
|
|
|
/*
|
|
** Structures related to the configuration parser
|
|
*/
|
|
typedef void*(cb_parser_t)(ngx_conf_t*, ngx_str_t*, ngx_http_rule_t*);
|
|
|
|
typedef struct
|
|
{
|
|
char* prefix;
|
|
size_t prefix_len;
|
|
cb_parser_t* pars;
|
|
} ngx_http_naxsi_parser_t;
|
|
|
|
static ngx_http_naxsi_parser_t rule_parser[] = {
|
|
{ ID_T, const_len(ID_T), naxsi_id },
|
|
{ SCORE_T, const_len(SCORE_T), naxsi_score },
|
|
{ MSG_T, const_len(MSG_T), naxsi_msg },
|
|
{ RX_T, const_len(RX_T), naxsi_rx },
|
|
{ STR_T, const_len(STR_T), naxsi_str },
|
|
{ LIBINJ_XSS_T, const_len(LIBINJ_XSS_T), naxsi_libinj_xss },
|
|
{ LIBINJ_SQL_T, const_len(LIBINJ_SQL_T), naxsi_libinj_sql },
|
|
{ MATCH_ZONE_T, const_len(MATCH_ZONE_T), naxsi_zone },
|
|
{ NEGATIVE_T, const_len(NEGATIVE_T), naxsi_negative },
|
|
{ WHITELIST_T, const_len(WHITELIST_T), naxsi_whitelist },
|
|
{ NULL, 0, NULL }
|
|
};
|
|
|
|
void*
|
|
naxsi_negative(ngx_conf_t* r, ngx_str_t* tmp, ngx_http_rule_t* rule)
|
|
{
|
|
rule->br->negative = 1;
|
|
return (NGX_CONF_OK);
|
|
}
|
|
|
|
void*
|
|
naxsi_libinj_xss(ngx_conf_t* r, ngx_str_t* tmp, ngx_http_rule_t* rule)
|
|
{
|
|
rule->br->match_type = LIBINJ_XSS;
|
|
return (NGX_CONF_OK);
|
|
}
|
|
|
|
void*
|
|
naxsi_libinj_sql(ngx_conf_t* r, ngx_str_t* tmp, ngx_http_rule_t* rule)
|
|
{
|
|
rule->br->match_type = LIBINJ_SQL;
|
|
return (NGX_CONF_OK);
|
|
}
|
|
|
|
void*
|
|
naxsi_score(ngx_conf_t* r, ngx_str_t* tmp, ngx_http_rule_t* rule)
|
|
{
|
|
int score, len;
|
|
char * tmp_ptr, *tmp_end;
|
|
ngx_http_special_score_t* sc;
|
|
|
|
rule->score = 0;
|
|
rule->block = 0;
|
|
rule->allow = 0;
|
|
rule->drop = 0;
|
|
tmp_ptr = (char*)(tmp->data + strlen(SCORE_T));
|
|
NX_LOG_DEBUG(_debug_score, NGX_LOG_EMERG, r, 0, "XX-(debug) dummy score (%V)", tmp);
|
|
/*allocate scores array*/
|
|
if (!rule->sscores) {
|
|
rule->sscores = ngx_array_create(r->pool, 1, sizeof(ngx_http_special_score_t));
|
|
}
|
|
|
|
while (*tmp_ptr) {
|
|
if (tmp_ptr[0] == '$') {
|
|
NX_LOG_DEBUG(
|
|
_debug_score, NGX_LOG_EMERG, r, 0, "XX-(debug) special scoring rule (%s)", tmp_ptr);
|
|
|
|
return_value_if(NULL == (tmp_end = strchr(tmp_ptr, ':')), NGX_CONF_ERROR);
|
|
|
|
return_value_if((len = tmp_end - tmp_ptr) < 1, NGX_CONF_ERROR);
|
|
|
|
return_value_if(NULL == (sc = ngx_array_push(rule->sscores)), NGX_CONF_ERROR);
|
|
|
|
return_value_if(NULL == (sc->sc_tag = ngx_pcalloc(r->pool, sizeof(ngx_str_t))),
|
|
NGX_CONF_ERROR);
|
|
|
|
return_value_if(NULL == (sc->sc_tag->data = ngx_pcalloc(r->pool, len + 1)), NGX_CONF_ERROR);
|
|
|
|
memcpy(sc->sc_tag->data, tmp_ptr, len);
|
|
sc->sc_tag->len = len;
|
|
sc->sc_score = atoi(tmp_end + 1);
|
|
NX_LOG_DEBUG(_debug_score,
|
|
NGX_LOG_EMERG,
|
|
r,
|
|
0,
|
|
"XX-(debug) special scoring (%V) => (%d)",
|
|
sc->sc_tag,
|
|
sc->sc_score);
|
|
|
|
/* move to end of score. */
|
|
char* data_start = (char*)tmp->data;
|
|
char* data_end = (char*)data_start + tmp->len;
|
|
while (tmp_ptr >= data_start && tmp_ptr < data_end && *tmp_ptr != ',') {
|
|
++tmp_ptr;
|
|
}
|
|
} else if (tmp_ptr[0] == ',') {
|
|
++tmp_ptr;
|
|
} else if (!strcasecmp(tmp_ptr, "BLOCK")) {
|
|
rule->block = 1;
|
|
tmp_ptr += 5;
|
|
} else if (!strcasecmp(tmp_ptr, "DROP")) {
|
|
rule->drop = 1;
|
|
tmp_ptr += 4;
|
|
} else if (!strcasecmp(tmp_ptr, "ALLOW")) {
|
|
rule->allow = 1;
|
|
tmp_ptr += 5;
|
|
} else if (!strcasecmp(tmp_ptr, "LOG")) {
|
|
rule->log = 1;
|
|
tmp_ptr += 3;
|
|
}
|
|
// or maybe you just want to assign a score
|
|
else if (is_numeric(tmp_ptr[0]) || tmp_ptr[0] == '-') {
|
|
score = atoi((const char*)tmp->data + 2);
|
|
rule->score = score;
|
|
break;
|
|
} else {
|
|
return (NGX_CONF_ERROR);
|
|
}
|
|
}
|
|
#if defined(_debug_score) && _debug_score != 0
|
|
unsigned int z;
|
|
ngx_http_special_score_t* scr;
|
|
scr = rule->sscores->elts;
|
|
if (rule->sscores) {
|
|
for (z = 0; z < rule->sscores->nelts; z++) {
|
|
ngx_conf_log_error(NGX_LOG_EMERG,
|
|
r,
|
|
0,
|
|
"XX-score n°%d special scoring (%V) => (%d)",
|
|
z,
|
|
scr[z].sc_tag,
|
|
scr[z].sc_score);
|
|
}
|
|
} else
|
|
ngx_conf_log_error(NGX_LOG_EMERG, r, 0, "XX-no custom scores for this rule.");
|
|
#endif
|
|
return (NGX_CONF_OK);
|
|
}
|
|
|
|
void*
|
|
naxsi_zone(ngx_conf_t* r, ngx_str_t* tmp, ngx_http_rule_t* rule)
|
|
{
|
|
int tmp_len, has_zone = 0, is_any = 0;
|
|
ngx_http_custom_rule_location_t* custom_rule;
|
|
char * tmp_ptr, *tmp_end;
|
|
|
|
return_value_if(!rule->br, NGX_CONF_ERROR);
|
|
|
|
tmp_ptr = (char*)tmp->data + strlen(MATCH_ZONE_T);
|
|
while (*tmp_ptr) {
|
|
if (tmp_ptr[0] == '|') {
|
|
tmp_ptr++;
|
|
}
|
|
|
|
/* match global zones */
|
|
if (!strncmp(tmp_ptr, "ANY", strlen("ANY"))) {
|
|
return_value_if(has_zone, NGX_CONF_ERROR); // ANY can only be joined with $URL/$URL_X
|
|
rule->br->any = 1;
|
|
rule->br->raw_body = 1;
|
|
rule->br->body = 1;
|
|
rule->br->body_rule = 1;
|
|
rule->br->headers = 1;
|
|
rule->br->url = 1;
|
|
rule->br->args = 1;
|
|
rule->br->file_ext = 1;
|
|
tmp_ptr += strlen("ANY");
|
|
is_any = 1;
|
|
has_zone = 1;
|
|
continue;
|
|
} else if (!strncmp(tmp_ptr, "RAW_BODY", strlen("RAW_BODY"))) {
|
|
return_value_if(is_any, NGX_CONF_ERROR);
|
|
rule->br->raw_body = 1;
|
|
tmp_ptr += strlen("RAW_BODY");
|
|
has_zone = 1;
|
|
continue;
|
|
} else if (!strncmp(tmp_ptr, "BODY", strlen("BODY"))) {
|
|
return_value_if(is_any, NGX_CONF_ERROR);
|
|
rule->br->body = 1;
|
|
rule->br->body_rule = 1;
|
|
tmp_ptr += strlen("BODY");
|
|
has_zone = 1;
|
|
continue;
|
|
} else if (!strncmp(tmp_ptr, "HEADERS", strlen("HEADERS"))) {
|
|
return_value_if(is_any, NGX_CONF_ERROR);
|
|
rule->br->headers = 1;
|
|
tmp_ptr += strlen("HEADERS");
|
|
has_zone = 1;
|
|
continue;
|
|
} else if (!strncmp(tmp_ptr, "URL", strlen("URL"))) {
|
|
return_value_if(is_any, NGX_CONF_ERROR);
|
|
rule->br->url = 1;
|
|
tmp_ptr += strlen("URL");
|
|
has_zone = 1;
|
|
continue;
|
|
} else if (!strncmp(tmp_ptr, "ARGS", strlen("ARGS"))) {
|
|
return_value_if(is_any, NGX_CONF_ERROR);
|
|
rule->br->args = 1;
|
|
tmp_ptr += strlen("ARGS");
|
|
has_zone = 1;
|
|
continue;
|
|
}
|
|
/* match against variable name*/
|
|
else if (!strncmp(tmp_ptr, "NAME", strlen("NAME"))) {
|
|
return_value_if(is_any, NGX_CONF_ERROR);
|
|
rule->br->target_name = 1;
|
|
tmp_ptr += strlen("NAME");
|
|
has_zone = 1;
|
|
continue;
|
|
}
|
|
/* for file_ext, just push'em in the body rules.
|
|
when multipart parsing comes in, it'll tag the zone as
|
|
FILE_EXT as the rule will be pushed in body rules it'll be
|
|
checked !*/
|
|
else if (!strncmp(tmp_ptr, "FILE_EXT", strlen("FILE_EXT"))) {
|
|
return_value_if(is_any, NGX_CONF_ERROR);
|
|
rule->br->file_ext = 1;
|
|
rule->br->body = 1;
|
|
tmp_ptr += strlen("FILE_EXT");
|
|
has_zone = 1;
|
|
continue;
|
|
}
|
|
// probably a custom zone
|
|
else if (tmp_ptr[0] == '$') {
|
|
// tag as a custom_location rule.
|
|
rule->br->custom_location = 1;
|
|
if (!rule->br->custom_locations) {
|
|
rule->br->custom_locations =
|
|
ngx_array_create(r->pool, 1, sizeof(ngx_http_custom_rule_location_t));
|
|
|
|
return_value_if(!rule->br->custom_locations, NGX_CONF_ERROR);
|
|
}
|
|
|
|
return_value_if(NULL == (custom_rule = ngx_array_push(rule->br->custom_locations)),
|
|
NGX_CONF_ERROR);
|
|
|
|
memset(custom_rule, 0, sizeof(ngx_http_custom_rule_location_t));
|
|
if (!strncmp(tmp_ptr, MZ_GET_VAR_T, strlen(MZ_GET_VAR_T))) {
|
|
return_value_if(is_any, NGX_CONF_ERROR);
|
|
has_zone = 1;
|
|
custom_rule->args_var = 1;
|
|
rule->br->args_var = 1;
|
|
tmp_ptr += strlen(MZ_GET_VAR_T);
|
|
} else if (!strncmp(tmp_ptr, MZ_POST_VAR_T, strlen(MZ_POST_VAR_T))) {
|
|
return_value_if(is_any, NGX_CONF_ERROR);
|
|
has_zone = 1;
|
|
custom_rule->body_var = 1;
|
|
rule->br->body_var = 1;
|
|
tmp_ptr += strlen(MZ_POST_VAR_T);
|
|
} else if (!strncmp(tmp_ptr, MZ_HEADER_VAR_T, strlen(MZ_HEADER_VAR_T))) {
|
|
return_value_if(is_any, NGX_CONF_ERROR);
|
|
has_zone = 1;
|
|
custom_rule->headers_var = 1;
|
|
rule->br->headers_var = 1;
|
|
tmp_ptr += strlen(MZ_HEADER_VAR_T);
|
|
} else if (!strncmp(tmp_ptr, MZ_SPECIFIC_URL_T, strlen(MZ_SPECIFIC_URL_T))) {
|
|
custom_rule->specific_url = 1;
|
|
tmp_ptr += strlen(MZ_SPECIFIC_URL_T);
|
|
}
|
|
|
|
/*
|
|
** if the rule is a negative rule (has an ID, not a WL field)
|
|
** we need to pre-compile the regex for runtime.
|
|
** Don't do it for whitelists, as its done in a separate manner.
|
|
*/
|
|
else if (!strncmp(tmp_ptr, MZ_GET_VAR_X, strlen(MZ_GET_VAR_X))) {
|
|
return_value_if(is_any, NGX_CONF_ERROR);
|
|
has_zone = 1;
|
|
custom_rule->args_var = 1;
|
|
rule->br->args_var = 1;
|
|
rule->br->rx_mz = 1;
|
|
tmp_ptr += strlen(MZ_GET_VAR_X);
|
|
} else if (!strncmp(tmp_ptr, MZ_POST_VAR_X, strlen(MZ_POST_VAR_X))) {
|
|
return_value_if(is_any, NGX_CONF_ERROR);
|
|
has_zone = 1;
|
|
rule->br->rx_mz = 1;
|
|
custom_rule->body_var = 1;
|
|
rule->br->body_var = 1;
|
|
tmp_ptr += strlen(MZ_POST_VAR_X);
|
|
} else if (!strncmp(tmp_ptr, MZ_HEADER_VAR_X, strlen(MZ_HEADER_VAR_X))) {
|
|
return_value_if(is_any, NGX_CONF_ERROR);
|
|
has_zone = 1;
|
|
custom_rule->headers_var = 1;
|
|
rule->br->headers_var = 1;
|
|
rule->br->rx_mz = 1;
|
|
tmp_ptr += strlen(MZ_HEADER_VAR_X);
|
|
} else if (!strncmp(tmp_ptr, MZ_SPECIFIC_URL_X, strlen(MZ_SPECIFIC_URL_X))) {
|
|
return_value_if(is_any, NGX_CONF_ERROR);
|
|
custom_rule->specific_url = 1;
|
|
rule->br->rx_mz = 1;
|
|
tmp_ptr += strlen(MZ_SPECIFIC_URL_X);
|
|
} else {
|
|
return (NGX_CONF_ERROR);
|
|
}
|
|
|
|
/* else return (NGX_CONF_ERROR);*/
|
|
tmp_end = strchr((const char*)tmp_ptr, '|');
|
|
if (!tmp_end) {
|
|
tmp_end = tmp_ptr + strlen(tmp_ptr);
|
|
}
|
|
|
|
tmp_len = tmp_end - tmp_ptr;
|
|
return_value_if(tmp_len <= 0, NGX_CONF_ERROR);
|
|
|
|
custom_rule->target.data = ngx_pcalloc(r->pool, tmp_len + 1);
|
|
return_value_if(!custom_rule->target.data, NGX_CONF_ERROR);
|
|
|
|
custom_rule->target.len = tmp_len;
|
|
memcpy(custom_rule->target.data, tmp_ptr, tmp_len);
|
|
/*
|
|
** pre-compile regex !
|
|
*/
|
|
if (rule->br->rx_mz == 1) {
|
|
|
|
custom_rule->target_rx = ngx_pcalloc(r->pool, sizeof(ngx_regex_compile_t));
|
|
return_value_if(!custom_rule->target_rx, NGX_CONF_ERROR);
|
|
custom_rule->target_rx->options = NAXSI_REGEX_OPTIONS;
|
|
custom_rule->target_rx->pattern = custom_rule->target;
|
|
custom_rule->target_rx->pool = r->pool;
|
|
custom_rule->target_rx->err.len = 0;
|
|
custom_rule->target_rx->err.data = NULL;
|
|
|
|
if (ngx_regex_compile(custom_rule->target_rx) != NGX_OK) {
|
|
NX_LOG_DEBUG(_debug_rx, NGX_LOG_EMERG, r, 0, "XX-FAILED RX:%V", custom_rule->target);
|
|
return (NGX_CONF_ERROR);
|
|
}
|
|
}
|
|
custom_rule->hash = ngx_hash_key_lc(custom_rule->target.data, custom_rule->target.len);
|
|
|
|
NX_LOG_DEBUG(_debug_zone, NGX_LOG_EMERG, r, 0, "XX- ZONE:[%V]", &(custom_rule->target));
|
|
tmp_ptr += tmp_len;
|
|
continue;
|
|
} else {
|
|
return (NGX_CONF_ERROR);
|
|
}
|
|
} /* while */
|
|
/*
|
|
** ensure the match-zone actually returns a zone :)
|
|
*/
|
|
if (has_zone == 0) {
|
|
ngx_conf_log_error(NGX_LOG_EMERG, r, 0, "matchzone doesn't target an actual zone.");
|
|
return (NGX_CONF_ERROR);
|
|
}
|
|
|
|
return (NGX_CONF_OK);
|
|
}
|
|
|
|
void*
|
|
naxsi_id(ngx_conf_t* r, ngx_str_t* tmp, ngx_http_rule_t* rule)
|
|
{
|
|
rule->rule_id = atoi((const char*)tmp->data + strlen(ID_T));
|
|
return (NGX_CONF_OK);
|
|
}
|
|
|
|
void*
|
|
naxsi_str(ngx_conf_t* r, ngx_str_t* tmp, ngx_http_rule_t* rule)
|
|
{
|
|
ngx_str_t* str;
|
|
ngx_uint_t i;
|
|
|
|
return_value_if(!rule->br, NGX_CONF_ERROR);
|
|
|
|
rule->br->match_type = STR;
|
|
|
|
return_value_if(NULL == (str = ngx_pcalloc(r->pool, sizeof(ngx_str_t))), NGX_CONF_ERROR);
|
|
|
|
str->data = tmp->data + strlen(STR_T);
|
|
str->len = tmp->len - strlen(STR_T);
|
|
for (i = 0; i < str->len; i++) {
|
|
str->data[i] = tolower(str->data[i]);
|
|
}
|
|
rule->br->str = str;
|
|
return (NGX_CONF_OK);
|
|
}
|
|
|
|
void*
|
|
naxsi_msg(ngx_conf_t* r, ngx_str_t* tmp, ngx_http_rule_t* rule)
|
|
{
|
|
ngx_str_t* str;
|
|
return_value_if(!rule->br, NGX_CONF_ERROR);
|
|
|
|
str = ngx_pcalloc(r->pool, sizeof(ngx_str_t));
|
|
return_value_if(!str, NGX_CONF_ERROR);
|
|
|
|
str->data = tmp->data + strlen(STR_T);
|
|
str->len = tmp->len - strlen(STR_T);
|
|
rule->log_msg = str;
|
|
return (NGX_CONF_OK);
|
|
}
|
|
|
|
void*
|
|
naxsi_whitelist(ngx_conf_t* r, ngx_str_t* tmp, ngx_http_rule_t* rule)
|
|
{
|
|
|
|
ngx_array_t* wl_ar;
|
|
unsigned int i, ct;
|
|
ngx_int_t* id;
|
|
ngx_str_t str;
|
|
|
|
str.data = tmp->data + strlen(WHITELIST_T);
|
|
str.len = tmp->len - strlen(WHITELIST_T);
|
|
for (ct = 1, i = 0; i < str.len; i++) {
|
|
if (str.data[i] == ',') {
|
|
ct++;
|
|
}
|
|
}
|
|
wl_ar = ngx_array_create(r->pool, ct, sizeof(ngx_int_t));
|
|
return_value_if(!wl_ar, NGX_CONF_ERROR);
|
|
|
|
NX_LOG_DEBUG(_debug_whitelist, NGX_LOG_EMERG, r, 0, "XX- allocated %d elems for WL", ct);
|
|
for (i = 0; i < str.len; i++) {
|
|
if (i == 0 || str.data[i - 1] == ',') {
|
|
id = (ngx_int_t*)ngx_array_push(wl_ar);
|
|
return_value_if(!id, NGX_CONF_ERROR);
|
|
*id = (ngx_int_t)atoi((const char*)str.data + i);
|
|
}
|
|
}
|
|
rule->wlid_array = wl_ar;
|
|
return (NGX_CONF_OK);
|
|
}
|
|
|
|
void*
|
|
naxsi_rx(ngx_conf_t* r, ngx_str_t* tmp, ngx_http_rule_t* rule)
|
|
{
|
|
ngx_regex_compile_t* rgc;
|
|
ngx_str_t ha;
|
|
|
|
return_value_if(!rule->br, NGX_CONF_ERROR);
|
|
|
|
rule->br->match_type = RX;
|
|
// just prepare a string to hold the directive without 'rx:'
|
|
ha.data = tmp->data + strlen(RX_T);
|
|
ha.len = tmp->len - strlen(RX_T);
|
|
rgc = ngx_pcalloc(r->pool, sizeof(ngx_regex_compile_t));
|
|
return_value_if(!rgc, NGX_CONF_ERROR);
|
|
|
|
rgc->options = NAXSI_REGEX_OPTIONS;
|
|
rgc->pattern = ha;
|
|
rgc->pool = r->pool;
|
|
rgc->err.len = 0;
|
|
rgc->err.data = NULL;
|
|
|
|
if (ngx_regex_compile(rgc) != NGX_OK) {
|
|
NX_LOG_DEBUG(_debug_rx, NGX_LOG_EMERG, r, 0, "XX-FAILED RX:%V", tmp);
|
|
return (NGX_CONF_ERROR);
|
|
}
|
|
rule->br->rx = rgc;
|
|
NX_LOG_DEBUG(_debug_rx, NGX_LOG_EMERG, r, 0, "XX- RX:[%V]", &(rule->br->rx->pattern));
|
|
return (NGX_CONF_OK);
|
|
}
|
|
|
|
/* Parse one rule line */
|
|
/*
|
|
** in : nb elem, value array, rule to fill
|
|
** does : creates a rule struct from configuration line
|
|
** For each element name matching a tag
|
|
** (cf. rule_parser), then call the associated func.
|
|
*/
|
|
void*
|
|
ngx_http_naxsi_cfg_parse_one_rule(ngx_conf_t* cf,
|
|
ngx_str_t* value,
|
|
ngx_http_rule_t* current_rule,
|
|
ngx_int_t nb_elem)
|
|
{
|
|
int i, z;
|
|
void* ret;
|
|
int valid;
|
|
|
|
return_value_if(!value || !value[0].data, NGX_CONF_ERROR);
|
|
/*
|
|
** parse basic rule
|
|
*/
|
|
if (!ngx_strcmp(value[0].data, TOP_CHECK_RULE_T) ||
|
|
!ngx_strcmp(value[0].data, TOP_CHECK_RULE_N) ||
|
|
!ngx_strcmp(value[0].data, TOP_BASIC_RULE_T) ||
|
|
!ngx_strcmp(value[0].data, TOP_BASIC_RULE_N) ||
|
|
!ngx_strcmp(value[0].data, TOP_MAIN_BASIC_RULE_T) ||
|
|
!ngx_strcmp(value[0].data, TOP_MAIN_BASIC_RULE_N)) {
|
|
NX_LOG_DEBUG(
|
|
_debug_cfg_parse_one_rule, NGX_LOG_EMERG, cf, 0, "naxsi-basic rule %V", &(value[1]));
|
|
current_rule->type = BR;
|
|
current_rule->br = ngx_pcalloc(cf->pool, sizeof(ngx_http_basic_rule_t));
|
|
return_value_if(!current_rule->br, NGX_CONF_ERROR);
|
|
} else {
|
|
NX_LOG_DEBUG(_debug_cfg_parse_one_rule,
|
|
NGX_LOG_EMERG,
|
|
cf,
|
|
0,
|
|
"Unknown start keyword in rule %V",
|
|
&(value[1]));
|
|
return (NGX_CONF_ERROR);
|
|
}
|
|
|
|
// check each word of config line against each rule
|
|
for (i = 1; i < nb_elem && value[i].len > 0; i++) {
|
|
valid = 0;
|
|
for (z = 0; rule_parser[z].pars; z++) {
|
|
ngx_http_naxsi_parser_t* np = &rule_parser[z];
|
|
if (!ngx_strncmp(value[i].data, np->prefix, np->prefix_len)) {
|
|
|
|
ret = np->pars(cf, &value[i], current_rule);
|
|
if (ret != NGX_CONF_OK) {
|
|
NX_LOG_DEBUG(_debug_cfg_parse_one_rule,
|
|
NGX_LOG_EMERG,
|
|
cf,
|
|
0,
|
|
"XX-FAILED PARSING '%s'",
|
|
value[i].data);
|
|
return (ret);
|
|
}
|
|
valid = 1;
|
|
}
|
|
}
|
|
return_value_if(!valid, NGX_CONF_ERROR);
|
|
}
|
|
/* validate the structure, and fill empty fields.*/
|
|
if (!current_rule->log_msg) {
|
|
current_rule->log_msg = ngx_pcalloc(cf->pool, sizeof(ngx_str_t));
|
|
current_rule->log_msg->data = NULL;
|
|
current_rule->log_msg->len = 0;
|
|
}
|
|
return (NGX_CONF_OK);
|
|
}
|