From 9d49adf028f675839d2f84b849ccff4f4c1308a1 Mon Sep 17 00:00:00 2001 From: brectanus Date: Wed, 17 Oct 2007 19:59:28 +0000 Subject: [PATCH] Basic implementation of skipAfter (still need to implement placeholders so it works with removed rules). See #258. --- CHANGES | 4 ++++ apache2/re.c | 39 +++++++++++++++++++++++++++++++++++++++ apache2/re.h | 1 + apache2/re_actions.c | 27 +++++++++++++++++++++++++++ 4 files changed, 71 insertions(+) diff --git a/CHANGES b/CHANGES index a321b3f8..93a140f7 100644 --- a/CHANGES +++ b/CHANGES @@ -2,6 +2,10 @@ 17 Oct 2007 - 2.5.0-dev3 ------------------------ + * Added skipAfter: action to allow skipping all rules until a rule + with a specified ID is reached. Rule execution then continues after + the specified rule. + * Added ctl:ruleRemoveById action to allow rule removal on a match. * Added a @containsWord operator that will match a given string anywhere in diff --git a/apache2/re.c b/apache2/re.c index a350c49d..4fe98bb6 100644 --- a/apache2/re.c +++ b/apache2/re.c @@ -425,6 +425,7 @@ msre_actionset *msre_actionset_create(msre_engine *engine, const char *text, /* Flow */ actionset->is_chained = NOT_SET; actionset->skip_count = NOT_SET; + actionset->skip_after = NOT_SET_P; /* Disruptive */ actionset->intercept_action = NOT_SET; @@ -501,6 +502,7 @@ msre_actionset *msre_actionset_merge(msre_engine *engine, msre_actionset *parent /* Flow */ merged->is_chained = child->is_chained; if (child->skip_count != NOT_SET) merged->skip_count = child->skip_count; + if (child->skip_after != NOT_SET_P) merged->skip_after = child->skip_after; /* Disruptive */ if (child->intercept_action != NOT_SET) { @@ -558,6 +560,7 @@ static void msre_actionset_set_defaults(msre_actionset *actionset) { /* Flow */ if (actionset->is_chained == NOT_SET) actionset->is_chained = 0; if (actionset->skip_count == NOT_SET) actionset->skip_count = 0; + if (actionset->skip_after == NOT_SET_P) actionset->skip_after = NULL; /* Disruptive */ if (actionset->intercept_action == NOT_SET) actionset->intercept_action = ACTION_NONE; @@ -629,6 +632,7 @@ apr_status_t msre_ruleset_process_phase(msre_ruleset *ruleset, modsec_rec *msr) apr_array_header_t *arr = NULL; msre_rule **rules; apr_status_t rc; + const char *skip_after = NULL; int i, mode, skip; /* First determine which set of rules we need to use. */ @@ -667,6 +671,30 @@ apr_status_t msre_ruleset_process_phase(msre_ruleset *ruleset, modsec_rec *msr) apr_time_t time1 = 0; #endif + // TODO: Still need to skip over placeholders + + /* SKIP_RULES is used to skip all rules until we hit a placeholder + * with the specified rule ID and then resume execution after that. + */ + if (mode == SKIP_RULES) { + /* Go to the next rule if we have not yet hit the skip_after ID */ + // TODO: must be a placeholder as well + if ((rule->actionset->id == NULL) || (strcmp(skip_after, rule->actionset->id) != 0)) { + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "Skipping rule id=\"%s\" while looking for id=\"%s\"", (rule->actionset->id ? rule->actionset->id : "(none)"), skip_after); + } + continue; + } + if (msr->txcfg->debuglog_level >= 4) { + msr_log(msr, 4, "Continuing execution after rule id=\"%s\"", skip_after); + } + skip_after = NULL; + mode = NEXT_RULE; + + /* Go to the rule *after* this one to continue execution. */ + continue; + } + /* NEXT_CHAIN is used when one of the rules in a chain * fails to match and then we need to skip the remaining * rules in that chain in order to get to the next @@ -796,6 +824,17 @@ apr_status_t msre_ruleset_process_phase(msre_ruleset *ruleset, modsec_rec *msr) return 1; } + if (rule->actionset->skip_after != NULL) { + skip_after = rule->actionset->skip_after; + mode = SKIP_RULES; + + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "Skipping after rule id=\"%s\" -> mode SKIP_RULES.", skip_after); + } + + continue; + } + /* We had a match but the transaction was not * intercepted. In that case we proceed with the * next rule... diff --git a/apache2/re.h b/apache2/re.h index ca05dbbe..66ba0bcf 100644 --- a/apache2/re.h +++ b/apache2/re.h @@ -235,6 +235,7 @@ struct msre_actionset { /* Flow */ int is_chained; int skip_count; + const char *skip_after; /* Disruptive */ int intercept_action; diff --git a/apache2/re_actions.c b/apache2/re_actions.c index f3db7aae..97481827 100644 --- a/apache2/re_actions.c +++ b/apache2/re_actions.c @@ -420,6 +420,21 @@ static apr_status_t msre_action_skip_init(msre_engine *engine, msre_actionset *a return 1; } +/* skipAfter */ + +static char *msre_action_skipAfter_validate(msre_engine *engine, msre_action *action) { + /* ENH Add validation. */ + return NULL; +} + +static apr_status_t msre_action_skipAfter_init(msre_engine *engine, msre_actionset *actionset, + msre_action *action) +{ + // TODO: Need to keep track of skipAfter IDs so we can insert placeholders after we get to the real rule with that ID. + actionset->skip_after = action->param; + return 1; +} + /* allow */ static apr_status_t msre_action_allow_init(msre_engine *engine, msre_actionset *actionset, @@ -1660,6 +1675,18 @@ void msre_engine_register_default_actions(msre_engine *engine) { NULL ); + /* skipAfter */ + msre_engine_action_register(engine, + "skipAfter", + ACTION_DISRUPTIVE, + 1, 1, + NO_PLUS_MINUS, + ACTION_CARDINALITY_ONE, + msre_action_skipAfter_validate, + msre_action_skipAfter_init, + NULL + ); + /* allow */ msre_engine_action_register(engine, "allow",