Implemented a new time-measuring mechanism. Added Stopwatch2.

This commit is contained in:
ivanr
2010-02-01 09:42:23 +00:00
parent d259373331
commit 7b56982f26
8 changed files with 167 additions and 111 deletions

View File

@@ -782,8 +782,6 @@ apr_status_t output_filter(ap_filter_t *f, apr_bucket_brigade *bb_in) {
* (full-buffering only).
*/
if ((msr->of_skipping == 0)&&(!msr->of_partial)) {
record_time_checkpoint(msr, 3);
prepend_content_to_of_brigade(msr, f);
/* Inject content into response (append & buffering). */

View File

@@ -163,40 +163,6 @@ int apache2_exec(modsec_rec *msr, const char *command, const char **argv, char *
return 1;
}
/**
* Record the current time and store for later.
*/
void record_time_checkpoint(modsec_rec *msr, int checkpoint_no) {
char note[100], note_name[100];
apr_time_t now;
now = apr_time_now();
switch(checkpoint_no) {
case 1 :
msr->time_checkpoint_1 = now;
break;
case 2 :
msr->time_checkpoint_2 = now;
break;
case 3 :
msr->time_checkpoint_3 = now;
break;
default :
msr_log(msr, 1, "Internal Error: Unknown checkpoint: %d", checkpoint_no);
return;
break;
}
/* Apache-specific stuff. */
apr_snprintf(note, 99, "%" APR_TIME_T_FMT, (now - msr->request_time));
apr_snprintf(note_name, 99, "mod_security-time%d", checkpoint_no);
apr_table_set(msr->r->notes, note_name, note);
if (msr->txcfg->debuglog_level >= 4) {
msr_log(msr, 4, "Time #%d: %s", checkpoint_no, note);
}
}
/**
* Returns a new string that contains the error
* message for the given return code.

View File

@@ -734,15 +734,11 @@ static int hook_request_late(request_rec *r) {
msr->request_headers = apr_table_copy(msr->mp, r->headers_in);
/* Process phase REQUEST_BODY */
record_time_checkpoint(msr, 1);
rc = DECLINED;
if (modsecurity_process_phase(msr, PHASE_REQUEST_BODY) > 0) {
rc = perform_interception(msr);
}
record_time_checkpoint(msr, 2);
return rc;
}

View File

@@ -80,6 +80,7 @@ static const char *phase_name(int phase) {
return "LOGGING";
break;
}
return "INVALID";
}
#endif
@@ -166,12 +167,15 @@ static apr_status_t modsecurity_tx_cleanup(void *data) {
int collect_garbage = 0;
int i;
char *my_error_msg = NULL;
apr_time_t time_before;
if (msr == NULL) return APR_SUCCESS;
if (rand() < RAND_MAX/100) {
collect_garbage = 1;
}
time_before = apr_time_now();
/* Collections, store & remove stale. */
arr = apr_table_elts(msr->collections);
@@ -188,6 +192,8 @@ static apr_status_t modsecurity_tx_cleanup(void *data) {
collections_remove_stale(msr, te[i].key);
}
}
msr->time_persistence += apr_time_now() - time_before;
/* Multipart processor cleanup. */
if (msr->mpd != NULL) multipart_cleanup(msr);
@@ -382,6 +388,7 @@ static int is_response_status_relevant(modsec_rec *msr, int status) {
if (rc == PCRE_ERROR_NOMATCH) return 0;
msr_log(msr, 1, "Regex processing failed (rc %d): %s", rc, my_error_msg);
return 0;
}
@@ -389,78 +396,132 @@ static int is_response_status_relevant(modsec_rec *msr, int status) {
*
*/
static apr_status_t modsecurity_process_phase_request_headers(modsec_rec *msr) {
msr_log(msr, 4, "Starting phase REQUEST_HEADERS.");
apr_time_t time_before;
apr_status_t rc = 0;
if (msr->txcfg->debuglog_level >= 4) {
msr_log(msr, 4, "Starting phase REQUEST_HEADERS.");
}
time_before = apr_time_now();
if (msr->txcfg->ruleset != NULL) {
return msre_ruleset_process_phase(msr->txcfg->ruleset, msr);
rc = msre_ruleset_process_phase(msr->txcfg->ruleset, msr);
}
msr->time_phase1 = apr_time_now() - time_before;
return 0;
return rc;
}
/**
*
*/
static apr_status_t modsecurity_process_phase_request_body(modsec_rec *msr) {
apr_time_t time_before;
apr_status_t rc = 0;
if ((msr->allow_scope == ACTION_ALLOW_REQUEST)||(msr->allow_scope == ACTION_ALLOW)) {
msr_log(msr, 4, "Skipping phase REQUEST_BODY (allow used).");
if (msr->txcfg->debuglog_level >= 4) {
msr_log(msr, 4, "Skipping phase REQUEST_BODY (allow used).");
}
return 0;
} else {
msr_log(msr, 4, "Starting phase REQUEST_BODY.");
if (msr->txcfg->debuglog_level >= 4) {
msr_log(msr, 4, "Starting phase REQUEST_BODY.");
}
}
time_before = apr_time_now();
if (msr->txcfg->ruleset != NULL) {
return msre_ruleset_process_phase(msr->txcfg->ruleset, msr);
rc = msre_ruleset_process_phase(msr->txcfg->ruleset, msr);
}
msr->time_phase2 = apr_time_now() - time_before;
return 0;
return rc;
}
/**
*
*/
static apr_status_t modsecurity_process_phase_response_headers(modsec_rec *msr) {
apr_time_t time_before;
apr_status_t rc = 0;
if (msr->allow_scope == ACTION_ALLOW) {
msr_log(msr, 4, "Skipping phase RESPONSE_HEADERS (allow used).");
if (msr->txcfg->debuglog_level >= 4) {
msr_log(msr, 4, "Skipping phase RESPONSE_HEADERS (allow used).");
}
return 0;
} else {
msr_log(msr, 4, "Starting phase RESPONSE_HEADERS.");
if (msr->txcfg->debuglog_level >= 4) {
msr_log(msr, 4, "Starting phase RESPONSE_HEADERS.");
}
}
time_before = apr_time_now();
if (msr->txcfg->ruleset != NULL) {
return msre_ruleset_process_phase(msr->txcfg->ruleset, msr);
rc = msre_ruleset_process_phase(msr->txcfg->ruleset, msr);
}
msr->time_phase3 = apr_time_now() - time_before;
return 0;
return rc;
}
/**
*
*/
static apr_status_t modsecurity_process_phase_response_body(modsec_rec *msr) {
apr_time_t time_before;
apr_status_t rc = 0;
if (msr->allow_scope == ACTION_ALLOW) {
msr_log(msr, 4, "Skipping phase RESPONSE_BODY (allow used).");
if (msr->txcfg->debuglog_level >= 4) {
msr_log(msr, 4, "Skipping phase RESPONSE_BODY (allow used).");
}
return 0;
} else {
msr_log(msr, 4, "Starting phase RESPONSE_BODY.");
if (msr->txcfg->debuglog_level >= 4) {
msr_log(msr, 4, "Starting phase RESPONSE_BODY.");
}
}
time_before = apr_time_now();
if (msr->txcfg->ruleset != NULL) {
return msre_ruleset_process_phase(msr->txcfg->ruleset, msr);
rc = msre_ruleset_process_phase(msr->txcfg->ruleset, msr);
}
msr->time_phase4 = apr_time_now() - time_before;
return 0;
return rc;
}
/**
*
*/
static apr_status_t modsecurity_process_phase_logging(modsec_rec *msr) {
msr_log(msr, 4, "Starting phase LOGGING.");
apr_time_t time_before, time_after;
if (msr->txcfg->debuglog_level >= 4) {
msr_log(msr, 4, "Starting phase LOGGING.");
}
time_before = apr_time_now();
if (msr->txcfg->ruleset != NULL) {
msre_ruleset_process_phase(msr->txcfg->ruleset, msr);
}
time_after = apr_time_now();
msr->time_phase5 = time_after - time_before;
/* Is this request relevant for logging purposes? */
if (msr->is_relevant == 0) {
@@ -487,13 +548,19 @@ static apr_status_t modsecurity_process_phase_logging(modsec_rec *msr) {
/* Are we configured for audit logging? */
switch(msr->txcfg->auditlog_flag) {
case AUDITLOG_OFF :
msr_log(msr, 4, "Audit log: Not configured to run for this request.");
if (msr->txcfg->debuglog_level >= 4) {
msr_log(msr, 4, "Audit log: Not configured to run for this request.");
}
return DECLINED;
break;
case AUDITLOG_RELEVANT :
if (msr->is_relevant == 0) {
msr_log(msr, 4, "Audit log: Ignoring a non-relevant request.");
if (msr->txcfg->debuglog_level >= 4) {
msr_log(msr, 4, "Audit log: Ignoring a non-relevant request.");
}
return DECLINED;
}
break;
@@ -508,9 +575,13 @@ static apr_status_t modsecurity_process_phase_logging(modsec_rec *msr) {
}
/* Invoke the Audit logger */
msr_log(msr, 4, "Audit log: Logging this transaction.");
if (msr->txcfg->debuglog_level >= 4) {
msr_log(msr, 4, "Audit log: Logging this transaction.");
}
sec_audit_logger(msr);
msr->time_logging = apr_time_now() - time_after;
return 0;
}
@@ -523,14 +594,20 @@ static apr_status_t modsecurity_process_phase_logging(modsec_rec *msr) {
apr_status_t modsecurity_process_phase(modsec_rec *msr, unsigned int phase) {
/* Check if we should run. */
if ((msr->was_intercepted)&&(phase != PHASE_LOGGING)) {
msr_log(msr, 4, "Skipping phase %d as request was already intercepted.", phase);
if (msr->txcfg->debuglog_level >= 4) {
msr_log(msr, 4, "Skipping phase %d as request was already intercepted.", phase);
}
return 0;
}
/* Do not process the same phase twice. */
if (msr->phase >= phase) {
msr_log(msr, 4, "Skipping phase %d because it was previously run (at %d now).",
phase, msr->phase);
if (msr->txcfg->debuglog_level >= 4) {
msr_log(msr, 4, "Skipping phase %d because it was previously run (at %d now).",
phase, msr->phase);
}
return 0;
}
@@ -570,12 +647,15 @@ apr_status_t modsecurity_process_phase(modsec_rec *msr, unsigned int phase) {
rec = (msre_cache_rec *)ctelts[ri].val;
if (rec->changed) {
if (msr->txcfg->debuglog_level >= 9) {
msr_log(msr, 9, "CACHE: %5d) hits=%d key=%pp %x;%s=\"%s\" (%pp - %pp)", cn, rec->hits, key, rec->num, rec->path, log_escape_nq_ex(mp, rec->val, rec->val_len), rec->val, rec->val + rec->val_len);
msr_log(msr, 9, "CACHE: %5d) hits=%d key=%pp %x;%s=\"%s\" (%pp - %pp)",
cn, rec->hits, key, rec->num, rec->path, log_escape_nq_ex(mp, rec->val, rec->val_len),
rec->val, rec->val + rec->val_len);
}
}
else {
if (msr->txcfg->debuglog_level >= 9) {
msr_log(msr, 9, "CACHE: %5d) hits=%d key=%pp %x;%s=<no change>", cn, rec->hits, key, rec->num, rec->path);
msr_log(msr, 9, "CACHE: %5d) hits=%d key=%pp %x;%s=<no change>",
cn, rec->hits, key, rec->num, rec->path);
}
}
}
@@ -585,7 +665,9 @@ apr_status_t modsecurity_process_phase(modsec_rec *msr, unsigned int phase) {
apr_hash_set(msr->tcache, key, klen, NULL);
}
msr_log(msr, 9, "Cleared transformation cache for phase %d", msr->phase);
if (msr->txcfg->debuglog_level >= 9) {
msr_log(msr, 9, "Cleared transformation cache for phase %d", msr->phase);
}
}
msr->tcache_items = 0;

View File

@@ -318,10 +318,14 @@ struct modsec_rec {
/* performance measurement */
apr_time_t request_time;
apr_time_t time_checkpoint_1;
apr_time_t time_checkpoint_2;
apr_time_t time_checkpoint_3;
apr_time_t time_phase1;
apr_time_t time_phase2;
apr_time_t time_phase3;
apr_time_t time_phase4;
apr_time_t time_phase5;
apr_time_t time_persistence;
apr_time_t time_logging;
apr_array_header_t *matched_rules;
msc_string *matched_var;
int highest_severity;

View File

@@ -764,35 +764,21 @@ void sec_audit_logger(modsec_rec *msr) {
text = apr_psprintf(msr->mp, "Apache-Handler: %s\n", msr->r->handler);
sec_auditlog_write(msr, text, strlen(text));
}
/* Processing times */
if (msr->time_checkpoint_1 == 0) {
text = apr_psprintf(msr->mp, "Stopwatch: %" APR_TIME_T_FMT " %" APR_TIME_T_FMT
" (- - -)\n", (msr->request_time), (now - msr->request_time));
} else {
char sw_str2[101] = "-";
char sw_str3[101] = "-";
if (msr->time_checkpoint_2 != 0) {
apr_snprintf(sw_str2, sizeof(sw_str2), "%" APR_TIME_T_FMT,
(msr->time_checkpoint_2 - msr->request_time));
}
if (msr->time_checkpoint_3 != 0) {
apr_snprintf(sw_str3, sizeof(sw_str3), "%" APR_TIME_T_FMT,
(msr->time_checkpoint_3 - msr->request_time));
}
text = apr_psprintf(msr->mp, "Stopwatch: %" APR_TIME_T_FMT
" %" APR_TIME_T_FMT " (%" APR_TIME_T_FMT
"%s %s %s)\n",
(msr->request_time), (now - msr->request_time),
(msr->time_checkpoint_1 - msr->request_time),
((msr->msc_reqbody_read == 0) ? "" : "*"),
sw_str2, sw_str3
);
}
/* Stopwatch; left in for compatibility reasons */
text = apr_psprintf(msr->mp, "Stopwatch: %" APR_TIME_T_FMT " %" APR_TIME_T_FMT " (- - -)\n",
msr->request_time, (now - msr->request_time));
sec_auditlog_write(msr, text, strlen(text));
/* Stopwatch2 */
text = apr_psprintf(msr->mp, "Stopwatch2: %" APR_TIME_T_FMT " %" APR_TIME_T_FMT
"; p1=%" APR_TIME_T_FMT ", p2=%" APR_TIME_T_FMT ", p3=%" APR_TIME_T_FMT
", p4=%" APR_TIME_T_FMT ", p5=%" APR_TIME_T_FMT ", s=%" APR_TIME_T_FMT
", l=%" APR_TIME_T_FMT "\n", msr->request_time, (now - msr->request_time),
msr->time_phase1, msr->time_phase2, msr->time_phase3, msr->time_phase4,
msr->time_phase5, msr->time_persistence, msr->time_logging);
sec_auditlog_write(msr, text, strlen(text));
/* Our response body does not contain chunks */

View File

@@ -174,15 +174,19 @@ static apr_table_t *collection_retrieve_ex(apr_sdbm_t *existing_dbm, modsec_rec
if (strcmp(key_to_expire, "__expire_KEY") == 0) {
expired = 1;
}
if (msr->txcfg->debuglog_level >= 9) {
msr_log(msr, 9, "Removing key \"%s\" from collection.", key_to_expire + 9);
msr_log(msr, 9, "Removing key \"%s\" from collection.", key_to_expire);
}
apr_table_unset(col, key_to_expire + 9);
apr_table_unset(col, key_to_expire);
if (msr->txcfg->debuglog_level >= 4) {
msr_log(msr, 4, "Removed expired variable \"%s\".", key_to_expire + 9);
}
break;
}
}
@@ -225,7 +229,8 @@ static apr_table_t *collection_retrieve_ex(apr_sdbm_t *existing_dbm, modsec_rec
}
if (expired && (msr->txcfg->debuglog_level >= 9)) {
msr_log(msr, 9, "Collection expired (name \"%s\", key \"%s\").", col_name, log_escape_ex(msr->mp, col_key, col_key_len));
msr_log(msr, 9, "Collection expired (name \"%s\", key \"%s\").", col_name,
log_escape_ex(msr->mp, col_key, col_key_len));
}
if (msr->txcfg->debuglog_level >= 4) {
msr_log(msr, 4, "Deleted collection (name \"%s\", key \"%s\").",
@@ -273,13 +278,13 @@ static apr_table_t *collection_retrieve_ex(apr_sdbm_t *existing_dbm, modsec_rec
if (msr->txcfg->debuglog_level >= 4) {
msr_log(msr, 4, "Retrieved collection (name \"%s\", key \"%s\").",
log_escape(msr->mp, col_name), log_escape_ex(msr->mp, col_key, col_key_len));
log_escape(msr->mp, col_name), log_escape_ex(msr->mp, col_key, col_key_len));
}
if ((existing_dbm == NULL) && dbm) {
/* Should not ever get here */
msr_log(msr, 1, "Internal Error: Collection remained open (name \"%s\", key \"%s\").",
log_escape(msr->mp, col_name), log_escape_ex(msr->mp, col_key, col_key_len));
log_escape(msr->mp, col_name), log_escape_ex(msr->mp, col_key, col_key_len));
apr_sdbm_close(dbm);
}
@@ -299,11 +304,18 @@ cleanup:
*
*/
apr_table_t *collection_retrieve(modsec_rec *msr, const char *col_name,
const char *col_key, int col_key_len) {
return collection_retrieve_ex(NULL, msr, col_name, col_key, col_key_len);
const char *col_key, int col_key_len)
{
apr_time_t time_before = apr_time_now();
apr_table_t *rtable = NULL;
rtable = collection_retrieve_ex(NULL, msr, col_name, col_key, col_key_len);
msr->time_persistence += apr_time_now() - time_before;
return rtable;
}
/**
*
*/
@@ -334,8 +346,8 @@ int collection_store(modsec_rec *msr, apr_table_t *col) {
if (msr->txcfg->data_dir == NULL) {
msr_log(msr, 1, "Unable to store collection (name \"%s\", key \"%s\"). Use "
"SecDataDir to define data directory first.",
log_escape_ex(msr->mp, var_name->value, var_name->value_len), log_escape_ex(msr->mp, var_key->value, var_key->value_len));
"SecDataDir to define data directory first.", log_escape_ex(msr->mp, var_name->value, var_name->value_len),
log_escape_ex(msr->mp, var_key->value, var_key->value_len));
goto error;
}
@@ -417,7 +429,8 @@ int collection_store(modsec_rec *msr, apr_table_t *col) {
orig_col = (const apr_table_t *)apr_table_get(msr->collections_original, var_name->value);
if (orig_col != NULL) {
if (msr->txcfg->debuglog_level >= 9) {
msr_log(msr, 9, "Re-retrieving collection prior to store: %s", apr_psprintf(msr->mp, "%.*s", var_name->value_len, var_name->value));
msr_log(msr, 9, "Re-retrieving collection prior to store: %s",
apr_psprintf(msr->mp, "%.*s", var_name->value_len, var_name->value));
}
stored_col = (const apr_table_t *)collection_retrieve_ex(dbm, msr, var_name->value, var_key->value, var_key->value_len);
@@ -448,6 +461,7 @@ int collection_store(modsec_rec *msr, apr_table_t *col) {
var->value = apr_psprintf(msr->mp, "%d", newval);
var->value_len = strlen(var->value);
if (msr->txcfg->debuglog_level >= 9) {
msr_log(msr, 9, "Delta applied for %s.%s %d->%d (%d): %d + (%d) = %d [%s,%d]",
log_escape_ex(msr->mp, var_name->value, var_name->value_len),
@@ -530,7 +544,8 @@ int collection_store(modsec_rec *msr, apr_table_t *col) {
if (msr->txcfg->debuglog_level >= 4) {
msr_log(msr, 4, "Persisted collection (name \"%s\", key \"%s\").",
log_escape_ex(msr->mp, var_name->value, var_name->value_len), log_escape_ex(msr->mp, var_key->value, var_key->value_len));
log_escape_ex(msr->mp, var_name->value, var_name->value_len),
log_escape_ex(msr->mp, var_key->value, var_key->value_len));
}
return 0;
@@ -645,10 +660,11 @@ int collections_remove_stale(modsec_rec *msr, const char *col_name) {
log_escape_ex(msr->mp, key.dptr, key.dsize - 1), get_apr_error(msr->mp, rc));
goto error;
}
if (msr->txcfg->debuglog_level >= 4) {
msr_log(msr, 4, "Removed stale collection (name \"%s\", "
"key \"%s\").", log_escape(msr->mp, col_name),
log_escape_ex(msr->mp, key.dptr, key.dsize - 1));
"key \"%s\").", log_escape(msr->mp, col_name),
log_escape_ex(msr->mp, key.dptr, key.dsize - 1));
}
}
}