mirror of
https://github.com/owasp-modsecurity/ModSecurity.git
synced 2025-09-29 19:24:29 +03:00
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:
@@ -90,50 +90,21 @@ static int msre_op_nomatch_execute(modsec_rec *msr, msre_rule *rule,
|
||||
* \retval 0 On Fail
|
||||
*/
|
||||
static int msre_op_ipmatch_param_init(msre_rule *rule, char **error_msg) {
|
||||
apr_status_t rv;
|
||||
char *str = NULL;
|
||||
char *saved = NULL;
|
||||
char *param = NULL;
|
||||
msre_ipmatch *current;
|
||||
msre_ipmatch **last = &rule->ip_op;
|
||||
int res = 0;
|
||||
|
||||
if (error_msg == NULL)
|
||||
return -1;
|
||||
else
|
||||
*error_msg = NULL;
|
||||
|
||||
param = apr_pstrdup(rule->ruleset->mp, rule->op_param);
|
||||
param = apr_pstrdup(rule->ruleset->mp, rule->op_param);//, &rule->ip_op);
|
||||
|
||||
str = apr_strtok(param, ",", &saved);
|
||||
while( str != NULL) {
|
||||
const char *ipstr, *mask, *sep;
|
||||
res = ip_list_from_param(rule->ruleset->mp, param, &rule->ip_op,
|
||||
error_msg);
|
||||
|
||||
/* get the IP address and mask strings */
|
||||
sep = strchr(str, '/');
|
||||
if (sep) {
|
||||
ipstr = apr_pstrndup(rule->ruleset->mp, str, (sep - str) );
|
||||
mask = apr_pstrdup(rule->ruleset->mp, (sep + 1) );
|
||||
}
|
||||
else {
|
||||
ipstr = apr_pstrdup(rule->ruleset->mp, str);
|
||||
mask = NULL;
|
||||
}
|
||||
/* create a new msre_ipmatch containing a new apr_ipsubnet_t*, and add it to the linked list */
|
||||
current = apr_pcalloc(rule->ruleset->mp, sizeof(msre_ipmatch));
|
||||
rv = apr_ipsubnet_create(¤t->ipsubnet, ipstr, mask, rule->ruleset->mp);
|
||||
if ( rv != APR_SUCCESS ) {
|
||||
char msgbuf[120];
|
||||
apr_strerror(rv, msgbuf, sizeof msgbuf);
|
||||
*error_msg = apr_pstrcat(rule->ruleset->mp, "Error: ", msgbuf, NULL);
|
||||
return -1;
|
||||
}
|
||||
current->address = str;
|
||||
current->next = NULL;
|
||||
*last = current;
|
||||
last = ¤t->next;
|
||||
|
||||
str = apr_strtok(NULL, ",",&saved);
|
||||
}
|
||||
if (res)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -152,7 +123,7 @@ static int msre_op_ipmatch_param_init(msre_rule *rule, char **error_msg) {
|
||||
*/
|
||||
static int msre_op_ipmatch_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) {
|
||||
msre_ipmatch *current = rule->ip_op;
|
||||
apr_sockaddr_t *sa;
|
||||
int res = 0;
|
||||
|
||||
if (error_msg == NULL)
|
||||
return -1;
|
||||
@@ -164,24 +135,21 @@ static int msre_op_ipmatch_execute(modsec_rec *msr, msre_rule *rule, msre_var *v
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* create an apr_sockaddr_t for the value string */
|
||||
if ( apr_sockaddr_info_get(&sa, var->value, APR_UNSPEC, 0, 0, msr->mp) != APR_SUCCESS ) {
|
||||
msr_log(msr, 1, "ipMatch Internal Error: Invalid ip address.");
|
||||
return 0;
|
||||
res = list_contains_ip(msr->mp, current, var->value, error_msg);
|
||||
|
||||
if (res < 0) {
|
||||
msr_log(msr, 1, "%s", *error_msg);
|
||||
*error_msg = NULL;
|
||||
}
|
||||
|
||||
if (res > 0) {
|
||||
*error_msg = apr_psprintf(msr->mp, "%s at %s.", *error_msg, var->name);
|
||||
}
|
||||
|
||||
/* look through the linked list for a match */
|
||||
while (current) {
|
||||
if (apr_ipsubnet_test(current->ipsubnet, sa)) {
|
||||
*error_msg = apr_psprintf(msr->mp, "IPmatch \"%s\" matched \"%s\" at %s.", var->value, current->address, var->name);
|
||||
return 1;
|
||||
}
|
||||
current = current->next;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* \brief Init function to ipmatchFromFile operator
|
||||
*
|
||||
@@ -192,109 +160,45 @@ static int msre_op_ipmatch_execute(modsec_rec *msr, msre_rule *rule, msre_var *v
|
||||
* \retval 0 On Fail
|
||||
*/
|
||||
static int msre_op_ipmatchFromFile_param_init(msre_rule *rule, char **error_msg) {
|
||||
char errstr[1024];
|
||||
char buf[HUGE_STRING_LEN + 1];
|
||||
const char *rootpath = NULL;
|
||||
const char *filepath = NULL;
|
||||
char *fn;
|
||||
char *start;
|
||||
char *end;
|
||||
const char *ipfile_path;
|
||||
int line = 0;
|
||||
unsigned short int op_len;
|
||||
apr_status_t rc;
|
||||
apr_file_t *fd;
|
||||
const char *ipfile_path = NULL;
|
||||
char *fn = NULL;
|
||||
int res = 0;
|
||||
TreeRoot *rtree = NULL;
|
||||
TreeNode *tnode = NULL;
|
||||
|
||||
if (error_msg == NULL)
|
||||
return -1;
|
||||
else
|
||||
*error_msg = NULL;
|
||||
|
||||
rtree = apr_palloc(rule->ruleset->mp, sizeof(TreeRoot));
|
||||
if(rtree == NULL) {
|
||||
*error_msg = apr_psprintf(rule->ruleset->mp, "Failed allocating memory to TreeRoot.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
memset(rtree, 0, sizeof(TreeRoot));
|
||||
|
||||
if ((rule->op_param == NULL)||(strlen(rule->op_param) == 0)) {
|
||||
*error_msg = apr_psprintf(rule->ruleset->mp, "Missing parameter for operator 'ipmatchFromFile'.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
rtree->ipv4_tree = CPTCreateRadixTree(rule->ruleset->mp);
|
||||
if (rtree->ipv4_tree == NULL) {
|
||||
*error_msg = apr_psprintf(rule->ruleset->mp, "ipmatchFromFile: Tree tree initialization failed.");
|
||||
return 0;
|
||||
}
|
||||
rtree->ipv6_tree = CPTCreateRadixTree(rule->ruleset->mp);
|
||||
if (rtree->ipv6_tree == NULL) {
|
||||
*error_msg = apr_psprintf(rule->ruleset->mp, "ipmatchFromFile: Tree tree initialization failed.");
|
||||
if ((rule->op_param == NULL) || (strlen(rule->op_param) == 0))
|
||||
{
|
||||
*error_msg = apr_psprintf(rule->ruleset->mp, "Missing parameter for " \
|
||||
"operator 'ipmatchFromFile'.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
fn = apr_pstrdup(rule->ruleset->mp, rule->op_param);
|
||||
|
||||
ipfile_path = apr_pstrndup(rule->ruleset->mp, rule->filename, strlen(rule->filename) - strlen(apr_filepath_name_get(rule->filename)));
|
||||
|
||||
while((apr_isspace(*fn) != 0) && (*fn != '\0')) fn++;
|
||||
while ((apr_isspace(*fn) != 0) && (*fn != '\0'))
|
||||
{
|
||||
fn++;
|
||||
}
|
||||
if (*fn == '\0') {
|
||||
*error_msg = apr_psprintf(rule->ruleset->mp, "Empty file specification for operator ipmatchFromFile \"%s\"", fn);
|
||||
*error_msg = apr_psprintf(rule->ruleset->mp, "Empty file specification " \
|
||||
"for operator ipmatchFromFile \"%s\"", fn);
|
||||
return 0;
|
||||
}
|
||||
|
||||
filepath = fn;
|
||||
if (apr_filepath_root(&rootpath, &filepath, APR_FILEPATH_TRUENAME, rule->ruleset->mp) != APR_SUCCESS) {
|
||||
|
||||
ipfile_path = apr_pstrndup(rule->ruleset->mp, rule->filename,
|
||||
strlen(rule->filename) - strlen(apr_filepath_name_get(rule->filename)));
|
||||
if (apr_filepath_root(&rootpath, &filepath, APR_FILEPATH_TRUENAME,
|
||||
rule->ruleset->mp) != APR_SUCCESS) {
|
||||
apr_filepath_merge(&fn, ipfile_path, fn, APR_FILEPATH_TRUENAME, rule->ruleset->mp);
|
||||
}
|
||||
|
||||
rc = apr_file_open(&fd, fn, APR_READ | APR_BUFFERED | APR_FILE_NOCLEANUP, 0, rule->ruleset->mp);
|
||||
if (rc != APR_SUCCESS) {
|
||||
*error_msg = apr_psprintf(rule->ruleset->mp, "Could not open ipmatch file \"%s\": %s", fn, apr_strerror(rc, errstr, 1024));
|
||||
res = ip_tree_from_file(&rtree, fn, rule->ruleset->mp, error_msg);
|
||||
if (res)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
while((rc = apr_file_gets(buf, HUGE_STRING_LEN, fd)) != APR_EOF) {
|
||||
line++;
|
||||
if (rc != APR_SUCCESS) {
|
||||
*error_msg = apr_psprintf(rule->ruleset->mp, "Could not read \"%s\" line %d: %s", fn, line, apr_strerror(rc, errstr, 1024));
|
||||
return 0;
|
||||
}
|
||||
|
||||
op_len = strlen(buf);
|
||||
|
||||
start = buf;
|
||||
while ((apr_isspace(*start) != 0) && (*start != '\0')) start++;
|
||||
for (end = start; end != NULL || *end != '\0' || *end != '\n'; end++) {
|
||||
if (apr_isxdigit(*end) || *end == '.' || *end == '/' || *end == ':') {
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
if (*end != '\n') {
|
||||
*error_msg = apr_psprintf(rule->ruleset->mp, "Invalid char \"%c\" in line %d of file %s", *end, line, fn);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
*end = '\0';
|
||||
|
||||
if ((start == end) || (*start == '#')) continue;
|
||||
|
||||
if (strchr(start, ':') == NULL) {
|
||||
tnode = TreeAddIP(start, rtree->ipv4_tree, IPV4_TREE);
|
||||
}
|
||||
else {
|
||||
tnode = TreeAddIP(start, rtree->ipv6_tree, IPV6_TREE);
|
||||
}
|
||||
if (tnode == NULL) {
|
||||
*error_msg = apr_psprintf(rule->ruleset->mp, "Could not add entry \"%s\" in line %d of file %s to IP list", start, line, fn);
|
||||
}
|
||||
}
|
||||
|
||||
if (fd != NULL) apr_file_close(fd);
|
||||
rule->op_param_data = rtree;
|
||||
return 1;
|
||||
}
|
||||
@@ -311,13 +215,11 @@ static int msre_op_ipmatchFromFile_param_init(msre_rule *rule, char **error_msg)
|
||||
* \retval 1 On Match
|
||||
* \retval 0 On No Match
|
||||
*/
|
||||
static int msre_op_ipmatchFromFile_execute(modsec_rec *msr, msre_rule *rule,
|
||||
msre_var *var, char **error_msg) {
|
||||
|
||||
static int msre_op_ipmatchFromFile_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) {
|
||||
TreeRoot *rtree = (TreeRoot *)rule->op_param_data;
|
||||
struct in_addr in;
|
||||
#if APR_HAVE_IPV6
|
||||
struct in6_addr in6;
|
||||
#endif
|
||||
int res = 0;
|
||||
|
||||
if (error_msg == NULL)
|
||||
return -1;
|
||||
@@ -330,42 +232,22 @@ static int msre_op_ipmatchFromFile_execute(modsec_rec *msr, msre_rule *rule, msr
|
||||
}
|
||||
|
||||
if (msr->txcfg->debuglog_level >= 4) {
|
||||
msr_log(msr, 4, "IPmatchFromFile: Total tree entries: %d, ipv4 %d ipv6 %d", rtree->ipv4_tree->count+rtree->ipv6_tree->count,
|
||||
msr_log(msr, 4, "IPmatchFromFile: Total tree entries: %d, ipv4 %d " \
|
||||
"ipv6 %d", rtree->ipv4_tree->count+rtree->ipv6_tree->count,
|
||||
rtree->ipv4_tree->count, rtree->ipv6_tree->count);
|
||||
}
|
||||
|
||||
if (strchr(var->value, ':') == NULL) {
|
||||
if (inet_pton(AF_INET, var->value, &in) <= 0) {
|
||||
if (msr->txcfg->debuglog_level >= 9) {
|
||||
msr_log(msr, 9, "IPmatchFromFile: bad IPv4 specification \"%s\".", var->value);
|
||||
}
|
||||
*error_msg = apr_psprintf(msr->mp, "IPmatchFromFile: bad IP specification \"%s\".", var->value);
|
||||
return 0;
|
||||
}
|
||||
res = tree_contains_ip(msr->mp, rtree, var->value, msr,
|
||||
error_msg);
|
||||
|
||||
if (CPTIpMatch(msr, (unsigned char *)&in.s_addr, rtree->ipv4_tree, IPV4_TREE) != NULL) {
|
||||
*error_msg = apr_psprintf(msr->mp, "IPmatchFromFile \"%s\" matched at %s.", var->value, var->name);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
#if APR_HAVE_IPV6
|
||||
else {
|
||||
if (inet_pton(AF_INET6, var->value, &in6) <= 0) {
|
||||
if (msr->txcfg->debuglog_level >= 9) {
|
||||
msr_log(msr, 9, "IPmatchFromFile: bad IPv6 specification \"%s\".", var->value);
|
||||
}
|
||||
*error_msg = apr_psprintf(msr->mp, "IPmatchFromFile: bad IP specification \"%s\".", var->value);
|
||||
return 0;
|
||||
}
|
||||
if (res < 0)
|
||||
msr_log(msr, 9, "%s", *error_msg);
|
||||
|
||||
if (CPTIpMatch(msr, (unsigned char *)&in6.s6_addr, rtree->ipv6_tree, IPV6_TREE) != NULL) {
|
||||
*error_msg = apr_psprintf(msr->mp, "IPmatchFromFile \"%s\" matched at %s.", var->value, var->name);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (res > 0)
|
||||
*error_msg = apr_psprintf(msr->mp, "IPmatchFromFile: \"%s\" matched at " \
|
||||
"%s.", var->value, var->name);
|
||||
|
||||
return 0;
|
||||
return res;
|
||||
}
|
||||
|
||||
/* rsub */
|
||||
|
Reference in New Issue
Block a user