/** * @brief Execute the rule. * * @param[in] ib Ironbee engine * @param[in] tx The transaction. * @param[in,out] User data. A @c pcre_rule_data_t. * @param[in] flags Operator instance flags * @param[in] field The field content. * @param[out] result The result. * @returns IB_OK most times. IB_EALLOC when a memory allocation error handles. */ static ib_status_t dfa_operator_execute(ib_engine_t *ib, ib_tx_t *tx, const ib_rule_t *rule, void *data, ib_flags_t flags, ib_field_t *field, ib_num_t *result) { IB_FTRACE_INIT(); assert(tx); assert(data); int matches; ib_status_t ib_rc; const int ovecsize = 3 * MATCH_MAX; dfa_rule_data_t *rule_data; int *ovector; const char* subject; size_t subject_len; const ib_bytestr_t* bytestr; dfa_workspace_t *dfa_workspace; int options; /* dfa exec options. */ ovector = (int *)malloc(ovecsize*sizeof(*ovector)); if (ovector==NULL) { IB_FTRACE_RET_STATUS(IB_EALLOC); } /* Pull out the rule data. */ rule_data = (dfa_rule_data_t *)data; if (field->type == IB_FTYPE_NULSTR) { ib_rc = ib_field_value(field, ib_ftype_nulstr_out(&subject)); if (ib_rc != IB_OK) { free(ovector); IB_FTRACE_RET_STATUS(ib_rc); } subject_len = strlen(subject); } else if (field->type == IB_FTYPE_BYTESTR) { ib_rc = ib_field_value(field, ib_ftype_bytestr_out(&bytestr)); if (ib_rc != IB_OK) { free(ovector); IB_FTRACE_RET_STATUS(ib_rc); } subject_len = ib_bytestr_length(bytestr); subject = (const char *) ib_bytestr_const_ptr(bytestr); } else { free(ovector); IB_FTRACE_RET_STATUS(IB_EINVAL); } /* Debug block. Escapes a string and prints it to the log. * Memory is freed. */ if (ib_log_get_level(ib) >= 9) { /* Worst case, we can have a string that is 4x larger. * Consider if a string of 0xF7 is passed. That single character * will expand to a string of 4 printed characters +1 for the \0 * character. */ char *debug_str = ib_util_hex_escape(subject, subject_len); if ( debug_str != NULL ) { ib_log_debug3_tx(tx, "Matching against: %s", debug_str); free( debug_str ); } } /* Get the per-tx workspace data for this rule data id. */ ib_rc = get_dfa_tx_data(tx, rule_data->id, &dfa_workspace); if (ib_rc == IB_ENOENT) { options = PCRE_PARTIAL_SOFT; ib_rc = alloc_dfa_tx_data(tx, rule_data->id, &dfa_workspace); if (ib_rc != IB_OK) { free(ovector); ib_log_error_tx(tx, "Unexpected error creating tx storage " "for dfa operator %s", rule_data->id); IB_FTRACE_RET_STATUS(ib_rc); } ib_log_debug_tx(tx, "Created DFA workspace at %p for id %s.", dfa_workspace, rule_data->id); } else if (ib_rc == IB_OK) { options = PCRE_PARTIAL_SOFT | PCRE_DFA_RESTART; ib_log_debug_tx(tx, "Reusing existing DFA workspace %p for id %s.", dfa_workspace, rule_data->id); } else { free(ovector); ib_log_error_tx(tx, "Unexpected error fetching dfa data " "for dfa operator %s", rule_data->id); IB_FTRACE_RET_STATUS(ib_rc); } /* Actually do the DFA match. */ matches = pcre_dfa_exec(rule_data->cpatt, rule_data->edata, subject, subject_len, 0, /* Starting offset. */ options, ovector, ovecsize, dfa_workspace->workspace, dfa_workspace->wscount); if (matches >= 0) { ib_rc = IB_OK; *result = 1; } else if (matches == PCRE_ERROR_PARTIAL) { ib_log_debug2_tx(tx, "Partial match found, but not a full match."); ib_rc = IB_OK; *result = 0; } else if (matches == PCRE_ERROR_NOMATCH) { if (ib_log_get_level(ib) >= 7) { char* tmp_c = malloc(subject_len+1); memcpy(tmp_c, subject, subject_len); tmp_c[subject_len] = '\0'; /* No match. Return false to the caller (*result = 0). */ ib_log_debug2_tx(tx, "No match for [%s] using pattern [%s].", tmp_c, rule_data->patt); free(tmp_c); } ib_rc = IB_OK; *result = 0; } else { /* Some other error occurred. Set the status to false and report the error. */ ib_rc = IB_EUNKNOWN; *result = 0; } free(ovector); IB_FTRACE_RET_STATUS(ib_rc); }
/** * @brief Execute the dfa operator * * @param[in] tx Current transaction. * @param[in] instance_data Instance data needed for execution. * @param[in] field The field to operate on. * @param[in] capture If non-NULL, the collection to capture to. * @param[out] result The result of the operator 1=true 0=false. * @param[in] cbdata Callback data. * * @returns IB_OK most times. IB_EALLOC when a memory allocation error handles. */ static ib_status_t dfa_operator_execute( ib_tx_t *tx, void *instance_data, const ib_field_t *field, ib_field_t *capture, ib_num_t *result, void *cbdata ) { assert(instance_data != NULL); assert(tx != NULL); int matches; ib_status_t ib_rc; const int ovecsize = 3 * MATCH_MAX; modpcre_operator_data_t *operator_data = (modpcre_operator_data_t *)instance_data; int *ovector; const char *subject; size_t subject_len; const ib_bytestr_t *bytestr; dfa_workspace_t *dfa_workspace; const char *id = operator_data->id; int options; /* dfa exec options. */ int start_offset; int match_count; const ib_module_t *m = (const ib_module_t *)cbdata; assert(m != NULL); assert(operator_data->cpdata->is_dfa == true); ovector = (int *)malloc(ovecsize*sizeof(*ovector)); if (ovector==NULL) { return IB_EALLOC; } if (field->type == IB_FTYPE_NULSTR) { ib_rc = ib_field_value(field, ib_ftype_nulstr_out(&subject)); if (ib_rc != IB_OK) { free(ovector); return ib_rc; } subject_len = strlen(subject); } else if (field->type == IB_FTYPE_BYTESTR) { ib_rc = ib_field_value(field, ib_ftype_bytestr_out(&bytestr)); if (ib_rc != IB_OK) { free(ovector); return ib_rc; } subject_len = ib_bytestr_length(bytestr); subject = (const char *) ib_bytestr_const_ptr(bytestr); } else { free(ovector); return IB_EINVAL; } /* Get the per-tx workspace data for this rule data id. */ ib_rc = get_dfa_tx_data(m, tx, id, &dfa_workspace); if (ib_rc == IB_ENOENT) { /* First time we are called, clear the captures. */ if (capture) { ib_rc = ib_capture_clear(capture); if (ib_rc != IB_OK) { ib_log_error_tx(tx, "Error clearing captures: %s", ib_status_to_string(ib_rc)); } } options = PCRE_PARTIAL_SOFT; ib_rc = alloc_dfa_tx_data(m, tx, operator_data->cpdata, id, &dfa_workspace); if (ib_rc != IB_OK) { free(ovector); return ib_rc; } } else if (ib_rc == IB_OK) { options = PCRE_PARTIAL_SOFT | PCRE_DFA_RESTART; } else { free(ovector); return ib_rc; } /* Perform the match. * If capturing is specified, then find all matches. */ start_offset = 0; match_count = 0; do { matches = pcre_dfa_exec(operator_data->cpdata->cpatt, operator_data->cpdata->edata, subject, subject_len, start_offset, /* Starting offset. */ options, ovector, ovecsize, dfa_workspace->workspace, dfa_workspace->wscount); if (matches > 0) { ++match_count; /* Use the longest match - the first in ovector - * to set the offset in the subject for the next * match. */ start_offset = ovector[1] + 1; if (capture) { pcre_dfa_set_match(tx, capture, ovector, 1, subject); } } } while (capture && (matches > 0)); if (match_count > 0) { ib_rc = IB_OK; *result = 1; } else if ((matches == 0) || (matches == PCRE_ERROR_NOMATCH)) { ib_rc = IB_OK; *result = 0; } else if (matches == PCRE_ERROR_PARTIAL) { ib_rc = IB_OK; *result = 0; } else { /* Some other error occurred. Set the status to false and * return the error. */ ib_rc = IB_EUNKNOWN; *result = 0; } free(ovector); return ib_rc; }