Adds support to suspicious and whitelist to Read and Write limits

The operators @ipMatch, @ipMatchF and @ipMatchFromFile were
added to the functions: SecReadStateLimit and SecReadStateLimit,
by using them it is possible to declare a suspicious list. When
a suspicious list is given, the {Read|Write}StateLimit will be
applied just to the IPs that belongs to that restricted list.
Note that the negative of those operators (e.g. !@ipMatch) can be
used to place a whitelist. The {Read|Write}StateLimit
restrictions will not be applied to those in the whitelist.
This current version the Sec{Read|Write}StateLimit can be used
varios times to add elements to both lists, however, the
last informed limit will be applied for the entire group. This
feature is experimental, and suggestions on how to improve it
are very welcome. For further discussion use the issue: #353.
This commit is contained in:
Felipe Zimmerle
2013-10-30 19:54:09 -07:00
parent 8ff3de5b6f
commit b9fdc4fe3b
7 changed files with 519 additions and 242 deletions

View File

@@ -1670,18 +1670,79 @@ static const char *cmd_rule_perf_time(cmd_parms *cmd, void *_dcfg,
return NULL;
}
char *parser_conn_limits_operator(apr_pool_t *mp, const char *p2,
TreeRoot **whitelist, msre_ipmatch **whitelist_param,
TreeRoot **suspicious_list, msre_ipmatch **suspicious_list_param,
const char *filename)
{
int res = 0;
char *config_orig_path;
char *param = strchr(p2, ' ');
char *file = NULL;
char *error_msg = NULL;
param++;
config_orig_path = apr_pstrndup(mp, filename,
strlen(filename) - strlen(apr_filepath_name_get(filename)));
apr_filepath_merge(&file, config_orig_path, param, APR_FILEPATH_TRUENAME,
mp);
if ((strncasecmp(p2, "!@ipMatchFromFile", strlen("!@ipMatchFromFile")) == 0) ||
(strncasecmp(p2, "!@ipMatchF", strlen("!@ipMatchF")) == 0)) {
res = ip_tree_from_file(whitelist,
file, mp, NULL);
}
else if (strncasecmp(p2, "!@ipMatch", strlen("!@ipMatch")) == 0) {
res = ip_list_from_param(mp, param,
whitelist_param, &error_msg);
}
else if ((strncasecmp(p2, "@ipMatchFromFile", strlen("@ipMatchFromFile")) == 0) ||
(strncasecmp(p2, "@ipMatchF", strlen("@ipMatchF")) == 0)) {
res = ip_tree_from_file(suspicious_list,
file, mp, NULL);
}
else if (strncasecmp(p2, "@ipMatch", strlen("@ipMatch")) == 0) {
res = ip_list_from_param(mp, param,
suspicious_list_param, &error_msg);
}
else {
return apr_psprintf(mp, "ModSecurity: Invalid operator for " \
"SecReadStateLimit: %s, expected operators: @ipMatch, @ipMatchF " \
"or @ipMatchFromFile with or without !", p2);
}
if (res) {
char *error;
error = apr_psprintf(mp, "ModSecurity: failed to load IPs " \
"from: %s", param);
if (*error_msg) {
error = apr_psprintf(mp, "%s %s", error, error_msg);
}
return error;
}
return NULL;
}
/**
* \brief Add SecReadStateLimit configuration option
*
* \param cmd Pointer to configuration data
* \param _dcfg Pointer to directory configuration
* \param p1 Pointer to configuration option
* \param p2 Pointer to configuration option
*
* \retval NULL On failure
* \retval apr_psprintf On Success
*/
static const char *cmd_conn_read_state_limit(cmd_parms *cmd, void *_dcfg,
const char *p1)
const char *p1, const char *p2)
{
directory_config *dcfg = (directory_config *)_dcfg;
long int limit;
@@ -1689,10 +1750,21 @@ static const char *cmd_conn_read_state_limit(cmd_parms *cmd, void *_dcfg,
if (dcfg == NULL) return NULL;
limit = strtol(p1, NULL, 10);
if ((limit == LONG_MAX)||(limit == LONG_MIN)||(limit <= 0)) {
return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecReadStateLimit: %s", p1);
if ((limit == LONG_MAX) || (limit == LONG_MIN) || (limit <= 0)) {
return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for " \
"SecReadStateLimit: %s", p1);
}
if (p2 != NULL) {
char *param = parser_conn_limits_operator(cmd->pool, p2,
&conn_read_state_whitelist, &conn_read_state_whitelist_param,
&conn_read_state_suspicious_list,
&conn_read_state_suspicious_list_param, cmd->directive->filename);
if (param)
return param;
}
conn_read_state_limit = limit;
return NULL;
@@ -1704,12 +1776,13 @@ static const char *cmd_conn_read_state_limit(cmd_parms *cmd, void *_dcfg,
* \param cmd Pointer to configuration data
* \param _dcfg Pointer to directory configuration
* \param p1 Pointer to configuration option
* \param p2 Pointer to configuration option
*
* \retval NULL On failure
* \retval apr_psprintf On Success
*/
static const char *cmd_conn_write_state_limit(cmd_parms *cmd, void *_dcfg,
const char *p1)
const char *p1, const char *p2)
{
directory_config *dcfg = (directory_config *)_dcfg;
long int limit;
@@ -1717,8 +1790,19 @@ static const char *cmd_conn_write_state_limit(cmd_parms *cmd, void *_dcfg,
if (dcfg == NULL) return NULL;
limit = strtol(p1, NULL, 10);
if ((limit == LONG_MAX)||(limit == LONG_MIN)||(limit <= 0)) {
return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecWriteStateLimit: %s", p1);
if ((limit == LONG_MAX) || (limit == LONG_MIN) || (limit <= 0)) {
return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for " \
"SecWriteStateLimit: %s", p1);
}
if (p2 != NULL) {
char *param = parser_conn_limits_operator(cmd->pool, p2,
&conn_write_state_whitelist, &conn_write_state_whitelist_param,
&conn_write_state_suspicious_list,
&conn_write_state_suspicious_list_param, cmd->directive->filename);
if (param)
return param;
}
conn_write_state_limit = limit;
@@ -3192,7 +3276,7 @@ const command_rec module_directives[] = {
"Threshold to log slow rules in usecs."
),
AP_INIT_TAKE1 (
AP_INIT_TAKE12 (
"SecReadStateLimit",
cmd_conn_read_state_limit,
NULL,
@@ -3200,7 +3284,7 @@ const command_rec module_directives[] = {
"maximum number of threads in READ_BUSY state per ip address"
),
AP_INIT_TAKE1 (
AP_INIT_TAKE12 (
"SecWriteStateLimit",
cmd_conn_write_state_limit,
NULL,