594 lines
17 KiB
C
594 lines
17 KiB
C
/*
|
|
* NAXSI, a web application firewall for NGINX
|
|
* Copyright (C) 2016, Thibault 'bui' Koechlin
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* In addition, as a special exception, the copyright holders give
|
|
* permission to link the code of portions of this program with the
|
|
* OpenSSL library under certain conditions as described in each
|
|
* individual source file, and distribute linked combinations
|
|
* including the two.
|
|
* You must obey the GNU General Public License in all respects
|
|
* for all of the code used other than OpenSSL. If you modify
|
|
* file(s) with this exception, you may extend this exception to your
|
|
* version of the file(s), but you are not obligated to do so. If you
|
|
* do not wish to do so, delete this exception statement from your
|
|
* version. If you delete this exception statement from all source
|
|
* files in the program, then also delete it here.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "naxsi.h"
|
|
/*
|
|
** TOP LEVEL configuration parsing code
|
|
*/
|
|
/*
|
|
** code to parse FLAGS and OPTIONS on each line.
|
|
*/
|
|
void *dummy_id(ngx_conf_t *r, ngx_str_t *tmp, ngx_http_rule_t *rule);
|
|
void *dummy_score(ngx_conf_t *r, ngx_str_t *tmp, ngx_http_rule_t *rule);
|
|
void *dummy_msg(ngx_conf_t *r, ngx_str_t *tmp, ngx_http_rule_t *rule);
|
|
void *dummy_rx(ngx_conf_t *r, ngx_str_t *tmp, ngx_http_rule_t *rule);
|
|
void *dummy_zone(ngx_conf_t *r, ngx_str_t *tmp, ngx_http_rule_t *rule);
|
|
void *dummy_str(ngx_conf_t *r, ngx_str_t *tmp, ngx_http_rule_t *rule);
|
|
void *dummy_negative(ngx_conf_t *r, ngx_str_t *tmp, ngx_http_rule_t *rule);
|
|
void *dummy_libinj_xss(ngx_conf_t *r, ngx_str_t *tmp, ngx_http_rule_t *rule);
|
|
void *dummy_libinj_sql(ngx_conf_t *r, ngx_str_t *tmp, ngx_http_rule_t *rule);
|
|
void *dummy_whitelist(ngx_conf_t *r, ngx_str_t *tmp, ngx_http_rule_t *rule);
|
|
/*
|
|
** Structures related to the configuration parser
|
|
*/
|
|
typedef struct {
|
|
char *prefix;
|
|
void *(*pars)(ngx_conf_t *, ngx_str_t *, ngx_http_rule_t *);
|
|
} ngx_http_dummy_parser_t;
|
|
|
|
|
|
|
|
static ngx_http_dummy_parser_t rule_parser[] = {
|
|
{ID_T, dummy_id},
|
|
{SCORE_T, dummy_score},
|
|
{MSG_T, dummy_msg},
|
|
{RX_T, dummy_rx},
|
|
{STR_T, dummy_str},
|
|
{LIBINJ_XSS_T, dummy_libinj_xss},
|
|
{LIBINJ_SQL_T, dummy_libinj_sql},
|
|
{MATCH_ZONE_T, dummy_zone},
|
|
{NEGATIVE_T, dummy_negative},
|
|
{WHITELIST_T, dummy_whitelist},
|
|
{NULL, NULL}
|
|
};
|
|
|
|
|
|
|
|
void *
|
|
dummy_negative(ngx_conf_t *r, ngx_str_t *tmp, ngx_http_rule_t *rule)
|
|
{
|
|
rule->br->negative = 1;
|
|
return (NGX_CONF_OK);
|
|
}
|
|
|
|
void *
|
|
dummy_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 *
|
|
dummy_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 *
|
|
dummy_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);
|
|
tmp_end = strchr(tmp_ptr, ':');
|
|
if (!tmp_end)
|
|
return (NGX_CONF_ERROR);
|
|
len = tmp_end - tmp_ptr;
|
|
if (len <= 0)
|
|
return (NGX_CONF_ERROR);
|
|
sc = ngx_array_push(rule->sscores);
|
|
if (!sc)
|
|
return (NGX_CONF_ERROR);
|
|
sc->sc_tag = ngx_pcalloc(r->pool, sizeof(ngx_str_t));
|
|
if (!sc->sc_tag)
|
|
return (NGX_CONF_ERROR);
|
|
sc->sc_tag->data = ngx_pcalloc(r->pool, len+1);
|
|
if (!sc->sc_tag->data)
|
|
return (NGX_CONF_ERROR);
|
|
//memset(rule->sc_tag->data, 0, len+1);
|
|
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. */
|
|
while ( /*don't overflow*/((unsigned int)((unsigned char *)tmp_ptr - tmp->data)) < tmp->len &&
|
|
/*and seek for next score */ *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 ( (tmp_ptr[0] >= '0' && tmp_ptr[0] <= '9') || 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 *
|
|
dummy_zone(ngx_conf_t *r, ngx_str_t *tmp, ngx_http_rule_t *rule)
|
|
{
|
|
int tmp_len, has_zone=0;
|
|
ngx_http_custom_rule_location_t *custom_rule;
|
|
char *tmp_ptr, *tmp_end;
|
|
|
|
|
|
if (!rule->br)
|
|
return (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, "RAW_BODY", strlen("RAW_BODY"))) {
|
|
rule->br->raw_body = 1;
|
|
tmp_ptr += strlen("RAW_BODY");
|
|
has_zone = 1;
|
|
continue;
|
|
}
|
|
else
|
|
if (!strncmp(tmp_ptr, "BODY", strlen("BODY"))) {
|
|
rule->br->body = 1;
|
|
tmp_ptr += strlen("BODY");
|
|
has_zone = 1;
|
|
continue;
|
|
}
|
|
else
|
|
if (!strncmp(tmp_ptr, "HEADERS", strlen("HEADERS"))) {
|
|
rule->br->headers = 1;
|
|
tmp_ptr += strlen("HEADERS");
|
|
has_zone = 1;
|
|
continue;
|
|
}
|
|
else
|
|
if (!strncmp(tmp_ptr, "URL", strlen("URL"))) {
|
|
rule->br->url = 1;
|
|
tmp_ptr += strlen("URL");
|
|
has_zone = 1;
|
|
continue;
|
|
}
|
|
else
|
|
if (!strncmp(tmp_ptr, "ARGS", strlen("ARGS"))) {
|
|
rule->br->args = 1;
|
|
tmp_ptr += strlen("ARGS");
|
|
has_zone = 1;
|
|
continue;
|
|
}
|
|
else
|
|
/* match against variable name*/
|
|
if (!strncmp(tmp_ptr, "NAME", strlen("NAME"))) {
|
|
rule->br->target_name = 1;
|
|
tmp_ptr += strlen("NAME");
|
|
has_zone = 1;
|
|
continue;
|
|
}
|
|
else
|
|
/* 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 !*/
|
|
if (!strncmp(tmp_ptr, "FILE_EXT", strlen("FILE_EXT"))) {
|
|
rule->br->file_ext = 1;
|
|
rule->br->body = 1;
|
|
tmp_ptr += strlen("FILE_EXT");
|
|
has_zone = 1;
|
|
continue;
|
|
}
|
|
else
|
|
/* custom match zones */
|
|
#define MZ_GET_VAR_T "$ARGS_VAR:"
|
|
#define MZ_HEADER_VAR_T "$HEADERS_VAR:"
|
|
#define MZ_POST_VAR_T "$BODY_VAR:"
|
|
#define MZ_SPECIFIC_URL_T "$URL:"
|
|
//probably a custom zone
|
|
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));
|
|
if (!rule->br->custom_locations)
|
|
return (NGX_CONF_ERROR);
|
|
}
|
|
custom_rule = ngx_array_push(rule->br->custom_locations);
|
|
if (!custom_rule)
|
|
return (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))) {
|
|
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))) {
|
|
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))) {
|
|
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);
|
|
}
|
|
else
|
|
/* add support for regex-style match zones.
|
|
** this whole function should be rewritten as it's getting
|
|
** messy as hell
|
|
*/
|
|
#define MZ_GET_VAR_X "$ARGS_VAR_X:"
|
|
#define MZ_HEADER_VAR_X "$HEADERS_VAR_X:"
|
|
#define MZ_POST_VAR_X "$BODY_VAR_X:"
|
|
#define MZ_SPECIFIC_URL_X "$URL_X:"
|
|
/*
|
|
** 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.
|
|
*/
|
|
if (!strncmp(tmp_ptr, MZ_GET_VAR_X, strlen(MZ_GET_VAR_X))) {
|
|
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))) {
|
|
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))) {
|
|
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))) {
|
|
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;
|
|
if (tmp_len <= 0)
|
|
return (NGX_CONF_ERROR);
|
|
custom_rule->target.data = ngx_pcalloc(r->pool, tmp_len+1);
|
|
if (!custom_rule->target.data)
|
|
return (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));
|
|
if (!custom_rule->target_rx)
|
|
return (NGX_CONF_ERROR);
|
|
custom_rule->target_rx->options = PCRE_CASELESS|PCRE_MULTILINE;
|
|
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);
|
|
}
|
|
/*
|
|
** 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 *
|
|
dummy_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 *
|
|
dummy_str(ngx_conf_t *r, ngx_str_t *tmp, ngx_http_rule_t *rule)
|
|
{
|
|
ngx_str_t *str;
|
|
uint i;
|
|
|
|
if (!rule->br)
|
|
return (NGX_CONF_ERROR);
|
|
rule->br->match_type = STR;
|
|
str = ngx_pcalloc(r->pool, sizeof(ngx_str_t));
|
|
if (!str)
|
|
return (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 *
|
|
dummy_msg(ngx_conf_t *r, ngx_str_t *tmp, ngx_http_rule_t *rule)
|
|
{
|
|
ngx_str_t *str;
|
|
|
|
if (!rule->br)
|
|
return (NGX_CONF_ERROR);
|
|
str = ngx_pcalloc(r->pool, sizeof(ngx_str_t));
|
|
if (!str)
|
|
return (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 *
|
|
dummy_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));
|
|
if (!wl_ar)
|
|
return (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);
|
|
if (!id)
|
|
return (NGX_CONF_ERROR);
|
|
*id = (ngx_int_t) atoi((const char *)str.data+i);
|
|
}
|
|
}
|
|
rule->wlid_array = wl_ar;
|
|
return (NGX_CONF_OK);
|
|
}
|
|
|
|
void *
|
|
dummy_rx(ngx_conf_t *r, ngx_str_t *tmp, ngx_http_rule_t *rule)
|
|
{
|
|
ngx_regex_compile_t *rgc;
|
|
ngx_str_t ha;
|
|
|
|
|
|
if (!rule->br)
|
|
return (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));
|
|
if (!rgc)
|
|
return (NGX_CONF_ERROR);
|
|
rgc->options = PCRE_CASELESS|PCRE_MULTILINE;
|
|
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_dummy_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;
|
|
|
|
if (!value || !value[0].data)
|
|
return 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));
|
|
if (!current_rule->br)
|
|
return (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++) {
|
|
if (!ngx_strncmp(value[i].data,
|
|
rule_parser[z].prefix,
|
|
strlen(rule_parser[z].prefix))) {
|
|
ret = rule_parser[z].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;
|
|
}
|
|
}
|
|
if (!valid)
|
|
return (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);
|
|
}
|
|
|
|
|