mirror of
https://github.com/owasp-modsecurity/ModSecurity.git
synced 2025-08-17 02:56:08 +03:00
Add ipmatchFromfile
This commit is contained in:
parent
d3ad05e9c9
commit
14156d831b
@ -11,7 +11,7 @@ mod_security2_la_SOURCES = mod_security2.c \
|
|||||||
re_variables.c msc_logging.c msc_xml.c \
|
re_variables.c msc_logging.c msc_xml.c \
|
||||||
msc_multipart.c modsecurity.c msc_parsers.c \
|
msc_multipart.c modsecurity.c msc_parsers.c \
|
||||||
msc_util.c msc_pcre.c persist_dbm.c msc_reqbody.c \
|
msc_util.c msc_pcre.c persist_dbm.c msc_reqbody.c \
|
||||||
msc_geo.c msc_gsb.c msc_crypt.c msc_unicode.c acmp.c msc_lua.c msc_release.c
|
msc_geo.c msc_gsb.c msc_crypt.c msc_tree.c msc_unicode.c acmp.c msc_lua.c msc_release.c
|
||||||
|
|
||||||
mod_security2_la_CFLAGS = @APXS_CFLAGS@ @APR_CFLAGS@ @APU_CFLAGS@ \
|
mod_security2_la_CFLAGS = @APXS_CFLAGS@ @APR_CFLAGS@ @APU_CFLAGS@ \
|
||||||
@PCRE_CFLAGS@ @LIBXML2_CFLAGS@ @LUA_CFLAGS@ @MODSEC_EXTRA_CFLAGS@ @CURL_CFLAGS@
|
@PCRE_CFLAGS@ @LIBXML2_CFLAGS@ @LUA_CFLAGS@ @MODSEC_EXTRA_CFLAGS@ @CURL_CFLAGS@
|
||||||
|
@ -45,7 +45,7 @@ OBJS = mod_security2.obj apache2_config.obj apache2_io.obj apache2_util.obj \
|
|||||||
re.obj re_operators.obj re_actions.obj re_tfns.obj re_variables.obj \
|
re.obj re_operators.obj re_actions.obj re_tfns.obj re_variables.obj \
|
||||||
msc_logging.obj msc_xml.obj msc_multipart.obj modsecurity.obj \
|
msc_logging.obj msc_xml.obj msc_multipart.obj modsecurity.obj \
|
||||||
msc_parsers.obj msc_util.obj msc_pcre.obj persist_dbm.obj \
|
msc_parsers.obj msc_util.obj msc_pcre.obj persist_dbm.obj \
|
||||||
msc_reqbody.obj msc_geo.obj msc_gsb.obj msc_crypt.obj msc_unicode.obj acmp.obj msc_lua.obj \
|
msc_reqbody.obj msc_geo.obj msc_gsb.obj msc_crypt.obj msc_tree.obj msc_unicode.obj acmp.obj msc_lua.obj \
|
||||||
msc_release.obj
|
msc_release.obj
|
||||||
|
|
||||||
all: $(DLL)
|
all: $(DLL)
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
MOD_SECURITY2 = mod_security2 apache2_config apache2_io apache2_util \
|
MOD_SECURITY2 = mod_security2 apache2_config apache2_io apache2_util \
|
||||||
re re_operators re_actions re_tfns re_variables \
|
re re_operators re_actions re_tfns re_variables \
|
||||||
msc_logging msc_xml msc_multipart modsecurity msc_parsers msc_util msc_pcre \
|
msc_logging msc_xml msc_multipart modsecurity msc_parsers msc_util msc_pcre \
|
||||||
persist_dbm msc_reqbody pdf_protect msc_geo msc_gsb msc_crypt msc_unicode acmp msc_lua
|
persist_dbm msc_reqbody pdf_protect msc_geo msc_gsb msc_crypt msc_tree msc_unicode acmp msc_lua
|
||||||
|
|
||||||
H = re.h modsecurity.h msc_logging.h msc_multipart.h msc_parsers.h \
|
H = re.h modsecurity.h msc_logging.h msc_multipart.h msc_parsers.h \
|
||||||
msc_pcre.h msc_util.h msc_xml.h persist_dbm.h apache2.h pdf_protect.h \
|
msc_pcre.h msc_util.h msc_xml.h persist_dbm.h apache2.h pdf_protect.h \
|
||||||
msc_geo.h msc_gsb.h msc_crypt.h msc_unicode.h acmp.h utf8tables.h msc_lua.h
|
msc_geo.h msc_gsb.h msc_crypt.h msc_tree.h msc_unicode.h acmp.h utf8tables.h msc_lua.h
|
||||||
|
|
||||||
${MOD_SECURITY2:=.slo}: ${H}
|
${MOD_SECURITY2:=.slo}: ${H}
|
||||||
${MOD_SECURITY2:=.lo}: ${H}
|
${MOD_SECURITY2:=.lo}: ${H}
|
||||||
|
885
apache2/msc_tree.c
Normal file
885
apache2/msc_tree.c
Normal file
@ -0,0 +1,885 @@
|
|||||||
|
/*
|
||||||
|
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
||||||
|
* Copyright (c) 2004-2011 Trustwave Holdings, Inc. (http://www.trustwave.com/)
|
||||||
|
*
|
||||||
|
* You may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* If any of the files related to licensing are missing or if you have any
|
||||||
|
* other questions related to licensing please contact Trustwave Holdings, Inc.
|
||||||
|
* directly using the email address security@modsecurity.org.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include "apr_lib.h"
|
||||||
|
#include "msc_util.h"
|
||||||
|
#include "msc_tree.h"
|
||||||
|
|
||||||
|
CPTTree *CPTCreateRadixTree(apr_pool_t *pool) {
|
||||||
|
CPTTree *tree = NULL;
|
||||||
|
|
||||||
|
tree = apr_palloc(pool, sizeof(CPTTree));
|
||||||
|
|
||||||
|
if(tree == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
memset(tree, 0, sizeof(CPTTree));
|
||||||
|
tree->pool = pool;
|
||||||
|
|
||||||
|
return tree;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConvertIPNetmask(uint8_t *buffer, uint8_t netmask, uint16_t ip_bitmask) {
|
||||||
|
int aux = 0, bytes = 0;
|
||||||
|
int mask = 0, mask_bit = 0;
|
||||||
|
|
||||||
|
bytes = ip_bitmask/8;
|
||||||
|
|
||||||
|
while(aux < bytes) {
|
||||||
|
mask_bit = ((1+aux) * 8);
|
||||||
|
|
||||||
|
if (mask_bit > netmask) {
|
||||||
|
mask = 0;
|
||||||
|
if ((mask_bit - netmask) < 8) mask = SHIFT_LEFT_MASK(mask_bit - netmask);
|
||||||
|
} else {
|
||||||
|
mask = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer[aux] &= mask;
|
||||||
|
aux++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
TreeNode *CPTCreateNode(apr_pool_t *pool) {
|
||||||
|
TreeNode *node = NULL;
|
||||||
|
|
||||||
|
node = apr_palloc(pool, sizeof(TreeNode));
|
||||||
|
|
||||||
|
if(node == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
memset(node, 0, sizeof(TreeNode));
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
CPTData *CPTCreateCPTData(uint8_t netmask, apr_pool_t *pool) {
|
||||||
|
|
||||||
|
CPTData *prefix_data = apr_palloc(pool, sizeof(CPTData));
|
||||||
|
|
||||||
|
if (prefix_data == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(prefix_data, 0, sizeof(CPTData));
|
||||||
|
|
||||||
|
prefix_data->netmask = netmask;
|
||||||
|
|
||||||
|
return prefix_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
TreePrefix *InsertDataPrefix(TreePrefix *prefix, uint8_t *ipdata, uint16_t ip_bitmask,
|
||||||
|
uint8_t netmask, apr_pool_t *pool) {
|
||||||
|
|
||||||
|
if(prefix == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
memcpy(prefix->buffer, ipdata, ip_bitmask/8);
|
||||||
|
prefix->bitlen = ip_bitmask;
|
||||||
|
|
||||||
|
prefix->prefix_data = CPTCreateCPTData(netmask, pool);
|
||||||
|
|
||||||
|
if(prefix->prefix_data == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return prefix;
|
||||||
|
}
|
||||||
|
|
||||||
|
TreePrefix *CPTCreatePrefix(uint8_t *ipdata, uint16_t ip_bitmask,
|
||||||
|
uint8_t netmask, apr_pool_t *pool) {
|
||||||
|
|
||||||
|
TreePrefix *prefix = NULL;
|
||||||
|
int bytes = ip_bitmask/8;
|
||||||
|
|
||||||
|
if ((ip_bitmask % 8 != 0) || (ipdata == NULL)) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
prefix = apr_palloc(pool, sizeof(TreePrefix));
|
||||||
|
if (prefix == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
memset(prefix, 0, sizeof(TreePrefix));
|
||||||
|
|
||||||
|
prefix->buffer = apr_palloc(pool, bytes);
|
||||||
|
|
||||||
|
if(prefix->buffer == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
memset(prefix->buffer, 0, bytes);
|
||||||
|
|
||||||
|
return InsertDataPrefix(prefix, ipdata, ip_bitmask, netmask, pool);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CPTAppendToCPTDataList(CPTData *new, CPTData **list) {
|
||||||
|
CPTData *temp = NULL, *prev = NULL;
|
||||||
|
|
||||||
|
if (new == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (list == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
prev = *list;
|
||||||
|
temp = *list;
|
||||||
|
|
||||||
|
while (temp != NULL) {
|
||||||
|
if (new->netmask > temp->netmask)
|
||||||
|
break;
|
||||||
|
prev = temp;
|
||||||
|
temp = temp->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (temp == *list) {
|
||||||
|
new->next = *list;
|
||||||
|
*list = new;
|
||||||
|
} else {
|
||||||
|
new->next = prev->next;
|
||||||
|
prev->next = new;
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int TreePrefixContainNetmask(TreePrefix *prefix, uint8_t netmask) {
|
||||||
|
CPTData *prefix_data = NULL;
|
||||||
|
|
||||||
|
if (prefix == NULL) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
prefix_data = prefix->prefix_data;
|
||||||
|
|
||||||
|
for(prefix_data != NULL; ; prefix_data = prefix_data->next) {
|
||||||
|
if (prefix_data->netmask == netmask)
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CheckBitmask(uint8_t netmask, uint16_t ip_bitmask) {
|
||||||
|
|
||||||
|
switch(netmask) {
|
||||||
|
|
||||||
|
case 0xff:
|
||||||
|
return 1;
|
||||||
|
case 0x20:
|
||||||
|
if(ip_bitmask == 0x20)
|
||||||
|
return 1;
|
||||||
|
break;
|
||||||
|
case 0x80:
|
||||||
|
if(ip_bitmask == 0x80)
|
||||||
|
return 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
TreeNode *CPTCreateHead(TreePrefix *prefix, TreeNode *node, CPTTree *tree, uint8_t netmask, uint16_t ip_bitmask) {
|
||||||
|
|
||||||
|
if(tree == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if(prefix == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (node != NULL) {
|
||||||
|
|
||||||
|
node->prefix = prefix;
|
||||||
|
node->bit = prefix->bitlen;
|
||||||
|
tree->head = node;
|
||||||
|
|
||||||
|
if(CheckBitmask(netmask, ip_bitmask))
|
||||||
|
return node;
|
||||||
|
|
||||||
|
node->count++;
|
||||||
|
node->netmasks = apr_palloc(tree->pool, (node->count * sizeof(uint8_t)));
|
||||||
|
|
||||||
|
if(node->netmasks)
|
||||||
|
node->netmasks[0] = netmask;
|
||||||
|
|
||||||
|
return node;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
TreeNode *SetParentNode(TreeNode *node, TreeNode *new_node, CPTTree *tree) {
|
||||||
|
|
||||||
|
if (node->parent == NULL)
|
||||||
|
tree->head = new_node;
|
||||||
|
else if (node->parent->right == node)
|
||||||
|
node->parent->right = new_node;
|
||||||
|
else
|
||||||
|
node->parent->left = new_node;
|
||||||
|
|
||||||
|
return new_node;
|
||||||
|
}
|
||||||
|
|
||||||
|
int InsertNetmask(TreeNode *node, TreeNode *parent, TreeNode *new_node,
|
||||||
|
CPTTree *tree, uint8_t netmask, uint8_t bitlen) {
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (netmask != NETMASK_256-1 && netmask != NETMASK_128) {
|
||||||
|
if ((netmask != NETMASK_32 || (netmask == NETMASK_32 && bitlen != NETMASK_32))) {
|
||||||
|
|
||||||
|
node = new_node;
|
||||||
|
parent = new_node->parent;
|
||||||
|
|
||||||
|
while (parent != NULL && netmask < (parent->bit + 1)) {
|
||||||
|
node = parent;
|
||||||
|
parent = parent->parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
node->count++;
|
||||||
|
node->netmasks = apr_palloc(tree->pool, (node->count * sizeof(uint8_t)));
|
||||||
|
|
||||||
|
if(node->netmasks == NULL)
|
||||||
|
return 0;
|
||||||
|
if ((node->count-1) == 0) {
|
||||||
|
node->netmasks[0] = netmask;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
node->netmasks[node->count - 1] = netmask;
|
||||||
|
|
||||||
|
i = node->count - 2;
|
||||||
|
while (i >= 0) {
|
||||||
|
if (netmask < node->netmasks[i]) {
|
||||||
|
node->netmasks[i + 1] = netmask;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
node->netmasks[i + 1] = node->netmasks[i];
|
||||||
|
node->netmasks[i] = netmask;
|
||||||
|
i--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
TreeNode *CPTAddElement(uint8_t *ipdata, uint16_t ip_bitmask, CPTTree *tree, uint8_t netmask) {
|
||||||
|
uint8_t *buffer = NULL;
|
||||||
|
uint8_t bitlen = 0;
|
||||||
|
int bit_validation = 0, test_bit = 0;
|
||||||
|
int i = 0, j = 0, temp = 0;
|
||||||
|
uint16_t x, y;
|
||||||
|
TreeNode *node = NULL, *new_node = NULL;
|
||||||
|
TreeNode *parent = NULL, *i_node = NULL;
|
||||||
|
TreeNode *bottom_node = NULL;
|
||||||
|
TreePrefix *prefix = NULL;
|
||||||
|
|
||||||
|
if (tree == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ConvertIPNetmask(ipdata, netmask, ip_bitmask);
|
||||||
|
|
||||||
|
prefix = CPTCreatePrefix(ipdata, ip_bitmask, netmask, tree->pool);
|
||||||
|
|
||||||
|
if (prefix == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tree->head == NULL) {
|
||||||
|
node = CPTCreateNode(tree->pool);
|
||||||
|
return CPTCreateHead(prefix, node, tree, netmask, ip_bitmask);
|
||||||
|
}
|
||||||
|
|
||||||
|
node = tree->head;
|
||||||
|
buffer = prefix->buffer;
|
||||||
|
bitlen = prefix->bitlen;
|
||||||
|
|
||||||
|
while (node->bit < bitlen || node->prefix == NULL) {
|
||||||
|
|
||||||
|
if (bitlen < node->bit) {
|
||||||
|
if (node->right == NULL)
|
||||||
|
break;
|
||||||
|
else
|
||||||
|
node = node->right;
|
||||||
|
} else {
|
||||||
|
x = SHIFT_RIGHT_MASK(node->bit, 3); y = SHIFT_RIGHT_MASK(NETMASK_128, (node->bit % 8));
|
||||||
|
|
||||||
|
if (TREE_CHECK(buffer[x],y)) {
|
||||||
|
if (node->right == NULL)
|
||||||
|
break;
|
||||||
|
node = node->right;
|
||||||
|
} else {
|
||||||
|
if (node->left == NULL)
|
||||||
|
break;
|
||||||
|
else
|
||||||
|
node = node->left;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bottom_node = node;
|
||||||
|
|
||||||
|
if(node->bit < bitlen)
|
||||||
|
bit_validation = node->bit;
|
||||||
|
else
|
||||||
|
bit_validation = bitlen;
|
||||||
|
|
||||||
|
for (i = 0; (i * NETMASK_8) < bit_validation; i++) {
|
||||||
|
int net = 0, div = 0;
|
||||||
|
int cnt = 0;
|
||||||
|
|
||||||
|
if ((temp = (buffer[i] ^ bottom_node->prefix->buffer[i])) == 0) {
|
||||||
|
test_bit = (i + 1) * NETMASK_8;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
temp += temp;
|
||||||
|
|
||||||
|
for(cnt = 0, net = NETMASK_256, div = 2; net >= NETMASK_2; net = NETMASK_256/div,
|
||||||
|
div += div, cnt++) {
|
||||||
|
if(temp >= net) {
|
||||||
|
test_bit = (i * NETMASK_8) + cnt;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bit_validation < test_bit)
|
||||||
|
test_bit = bit_validation;
|
||||||
|
|
||||||
|
parent = node->parent;
|
||||||
|
|
||||||
|
while (parent && test_bit <= parent->bit) {
|
||||||
|
node = parent;
|
||||||
|
parent = node->parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (test_bit == bitlen && node->bit == bitlen) {
|
||||||
|
if (node->prefix != NULL) {
|
||||||
|
int found = 0;
|
||||||
|
CPTData *prefix_data = NULL;
|
||||||
|
|
||||||
|
prefix_data = node->prefix->prefix_data;
|
||||||
|
|
||||||
|
for(prefix_data != NULL; ; prefix_data = prefix_data->next) {
|
||||||
|
if (prefix_data->netmask == netmask)
|
||||||
|
++found;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (found != 0) {
|
||||||
|
|
||||||
|
CPTData *prefix_data = CPTCreateCPTData(netmask, tree->pool);
|
||||||
|
CPTAppendToCPTDataList(prefix_data, &prefix->prefix_data);
|
||||||
|
|
||||||
|
if(CheckBitmask(netmask, ip_bitmask))
|
||||||
|
return node;
|
||||||
|
|
||||||
|
parent = node->parent;
|
||||||
|
while (parent != NULL && netmask < (parent->bit + 1)) {
|
||||||
|
node = parent;
|
||||||
|
parent = parent->parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
node->count++;
|
||||||
|
new_node = node;
|
||||||
|
node->netmasks = apr_palloc(tree->pool, (node->count * sizeof(uint8_t)));
|
||||||
|
|
||||||
|
if ((node->count -1) == 0) {
|
||||||
|
node->netmasks[0] = netmask;
|
||||||
|
return new_node;
|
||||||
|
}
|
||||||
|
|
||||||
|
node->netmasks[node->count - 1] = netmask;
|
||||||
|
|
||||||
|
i = node->count - 2;
|
||||||
|
while (i >= 0) {
|
||||||
|
if (netmask < node->netmasks[i]) {
|
||||||
|
node->netmasks[i + 1] = netmask;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
node->netmasks[i + 1] = node->netmasks[i];
|
||||||
|
node->netmasks[i] = netmask;
|
||||||
|
i--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
node->prefix = CPTCreatePrefix(prefix->buffer, prefix->bitlen,
|
||||||
|
NETMASK_256-1, tree->pool);
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
new_node = CPTCreateNode(tree->pool);
|
||||||
|
|
||||||
|
if(new_node == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
new_node->prefix = prefix;
|
||||||
|
new_node->bit = prefix->bitlen;
|
||||||
|
|
||||||
|
if (test_bit == bitlen) {
|
||||||
|
|
||||||
|
x = SHIFT_RIGHT_MASK(test_bit, 3); y = SHIFT_RIGHT_MASK(NETMASK_128, (test_bit % 8));
|
||||||
|
|
||||||
|
if (TREE_CHECK(bottom_node->prefix->buffer[x],y)) {
|
||||||
|
new_node->right = node;
|
||||||
|
} else {
|
||||||
|
new_node->left = node;
|
||||||
|
}
|
||||||
|
|
||||||
|
new_node->parent = node->parent;
|
||||||
|
node->parent = SetParentNode(node, new_node, tree);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
i_node = CPTCreateNode(tree->pool);
|
||||||
|
|
||||||
|
if(i_node == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
//i_node->prefix = NULL;
|
||||||
|
i_node->bit = test_bit;
|
||||||
|
i_node->parent = node->parent;
|
||||||
|
|
||||||
|
if (node->netmasks != NULL) {
|
||||||
|
i = 0;
|
||||||
|
while(i < node->count) {
|
||||||
|
if (node->netmasks[i] < test_bit + 1)
|
||||||
|
break;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
i_node->netmasks = apr_palloc(tree->pool, (node->count - i) * sizeof(uint8_t));
|
||||||
|
|
||||||
|
if(i_node->netmasks == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
j = 0;
|
||||||
|
while (j < (node->count - i)) {
|
||||||
|
i_node->netmasks[j] = node->netmasks[i + j];
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
|
||||||
|
i_node->count = (node->count - i);
|
||||||
|
node->count = i;
|
||||||
|
|
||||||
|
if (node->count == 0) {
|
||||||
|
node->netmasks = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
x = SHIFT_RIGHT_MASK(test_bit, 3); y = SHIFT_RIGHT_MASK(NETMASK_128, (test_bit % 8));
|
||||||
|
|
||||||
|
if (TREE_CHECK(buffer[x],y)) {
|
||||||
|
i_node->left = node;
|
||||||
|
i_node->right = new_node;
|
||||||
|
} else {
|
||||||
|
i_node->left = new_node;
|
||||||
|
i_node->right = node;
|
||||||
|
}
|
||||||
|
|
||||||
|
new_node->parent = i_node;
|
||||||
|
node->parent = SetParentNode(node, i_node, tree);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (InsertNetmask(node, parent, new_node, tree, netmask, bitlen))
|
||||||
|
return new_node;
|
||||||
|
|
||||||
|
return new_node;
|
||||||
|
}
|
||||||
|
|
||||||
|
int TreeCheckData(TreePrefix *prefix, CPTData *prefix_data, uint16_t netmask) {
|
||||||
|
|
||||||
|
for(prefix_data != NULL; ; prefix_data = prefix_data->next) {
|
||||||
|
if (prefix_data->netmask == netmask) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int TreePrefixNetmask(modsec_rec *msr, TreePrefix *prefix, uint16_t netmask, int flag) {
|
||||||
|
CPTData *prefix_data = NULL;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
if (prefix == NULL) {
|
||||||
|
if (msr->txcfg->debuglog_level >= 9) {
|
||||||
|
msr_log(msr, 9, "TreePrefixNetmask: prefix is NULL.");
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
prefix_data = prefix->prefix_data;
|
||||||
|
|
||||||
|
if (flag == 1) {
|
||||||
|
|
||||||
|
if(prefix_data == NULL) return 0;
|
||||||
|
|
||||||
|
if (prefix_data->netmask != netmask) {
|
||||||
|
if (msr->txcfg->debuglog_level >= 9) {
|
||||||
|
msr_log(msr, 9, "TreePrefixNetmask: Cannot find a prefix with correct netmask.");
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
if (msr->txcfg->debuglog_level >= 9) {
|
||||||
|
msr_log(msr, 9, "TreePrefixNetmask: Found a prefix with correct netmask.");
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (msr->txcfg->debuglog_level >= 9) {
|
||||||
|
msr_log(msr, 9, "TreePrefixNetmask: Check if a prefix has a the correct netmask");
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = TreeCheckData(prefix, prefix_data, netmask);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
TreeNode *CPTRetriveNode(modsec_rec *msr, uint8_t *buffer, uint16_t ip_bitmask, TreeNode *node) {
|
||||||
|
uint16_t x, y;
|
||||||
|
|
||||||
|
if(node == NULL) {
|
||||||
|
if (msr->txcfg->debuglog_level >= 9) {
|
||||||
|
msr_log(msr, 9, "CPTRetriveNode: Node tree is NULL.");
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(buffer == NULL) {
|
||||||
|
if (msr->txcfg->debuglog_level >= 9) {
|
||||||
|
msr_log(msr, 9, "CPTRetriveNode: Empty ip address. Nothing to search for.");
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (node->bit < ip_bitmask) {
|
||||||
|
|
||||||
|
x = SHIFT_RIGHT_MASK(node->bit, 3); y = SHIFT_RIGHT_MASK(NETMASK_128, (node->bit % 8));
|
||||||
|
|
||||||
|
if (TREE_CHECK(buffer[x], y)) {
|
||||||
|
node = node->right;
|
||||||
|
if (node == NULL) return NULL;
|
||||||
|
} else {
|
||||||
|
node = node->left;
|
||||||
|
if (node == NULL) return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (msr->txcfg->debuglog_level >= 9) {
|
||||||
|
msr_log(msr, 9, "CPTRetriveNode: Found the node for provided ip address.");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
TreeNode *CPTRetriveParentNode(TreeNode *node) {
|
||||||
|
|
||||||
|
while (node != NULL && node->netmasks == NULL)
|
||||||
|
node = node->parent;
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
TreeNode *CPTFindElementIPNetblock(modsec_rec *msr, uint8_t *ipdata, uint8_t ip_bitmask, TreeNode *node) {
|
||||||
|
TreeNode *netmask_node = NULL;
|
||||||
|
int mask = 0, bytes = 0;
|
||||||
|
int i = 0, j = 0;
|
||||||
|
int mask_bits = 0;
|
||||||
|
|
||||||
|
node = CPTRetriveParentNode(node);
|
||||||
|
|
||||||
|
if (node == NULL) {
|
||||||
|
if (msr->txcfg->debuglog_level >= 9) {
|
||||||
|
msr_log(msr, 9, "CPTFindElementIPNetblock: Node tree is NULL.");
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
netmask_node = node;
|
||||||
|
|
||||||
|
while(j < netmask_node->count) {
|
||||||
|
bytes = ip_bitmask / 8;
|
||||||
|
|
||||||
|
while( i < bytes ) {
|
||||||
|
|
||||||
|
mask = -1;
|
||||||
|
mask_bits = ((i + 1) * 8);
|
||||||
|
|
||||||
|
if (mask_bits > netmask_node->netmasks[j]) {
|
||||||
|
if ((mask_bits - netmask_node->netmasks[j]) < 8)
|
||||||
|
mask = SHIFT_LEFT_MASK(mask_bits - netmask_node->netmasks[j]);
|
||||||
|
else
|
||||||
|
mask = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ipdata[i] &= mask;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
node = CPTRetriveNode(msr, ipdata, ip_bitmask, node);
|
||||||
|
|
||||||
|
if (node && node->bit != ip_bitmask) {
|
||||||
|
if (msr->txcfg->debuglog_level >= 9) {
|
||||||
|
msr_log(msr, 9, "CPTFindElementIPNetblock: Found a tree node but netmask is different.");
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node && node->prefix == NULL) {
|
||||||
|
if (msr->txcfg->debuglog_level >= 9) {
|
||||||
|
msr_log(msr, 9, "CPTFindElementIPNetblock: Found a tree node but prefix is NULL.");
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (memcmp(node->prefix->buffer, ipdata, bytes) == 0) {
|
||||||
|
mask = SHIFT_LEFT_MASK(8 - ip_bitmask % 8);
|
||||||
|
|
||||||
|
if ((ip_bitmask % 8) == 0) {
|
||||||
|
if (TreePrefixNetmask(msr, node->prefix, netmask_node->netmasks[j], FALSE)) {
|
||||||
|
if (msr->txcfg->debuglog_level >= 9) {
|
||||||
|
msr_log(msr, 9, "CPTFindElementIPNetblock: Node found for provided ip address");
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((node->prefix->buffer[bytes] & mask) == (ipdata[bytes] & mask)) {
|
||||||
|
if (TreePrefixNetmask(msr, node->prefix, netmask_node->netmasks[j], FALSE)) {
|
||||||
|
if (msr->txcfg->debuglog_level >= 9) {
|
||||||
|
msr_log(msr, 9, "CPTFindElementIPNetblock: Node found for provided ip address");
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return CPTFindElementIPNetblock(msr, ipdata, ip_bitmask, netmask_node->parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
TreeNode *CPTFindElement(modsec_rec *msr, uint8_t *ipdata, uint16_t ip_bitmask, CPTTree *tree) {
|
||||||
|
TreeNode *node = NULL;
|
||||||
|
int mask = 0, bytes = 0;
|
||||||
|
uint8_t temp_data[NETMASK_256-1];
|
||||||
|
|
||||||
|
if (tree == NULL) {
|
||||||
|
if (msr->txcfg->debuglog_level >= 9) {
|
||||||
|
msr_log(msr, 9, "CPTFindElement: Tree is NULL. Cannot proceed searching the ip.");
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tree->head == NULL) {
|
||||||
|
if (msr->txcfg->debuglog_level >= 9) {
|
||||||
|
msr_log(msr, 9, "CPTFindElement: Tree head is NULL. Cannot proceed searching the ip.");
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
node = tree->head;
|
||||||
|
|
||||||
|
if (ip_bitmask > (NETMASK_256-1)) {
|
||||||
|
if (msr->txcfg->debuglog_level >= 9) {
|
||||||
|
msr_log(msr, 9, "CPTFindElement: Netmask cannot be greater than 255");
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
bytes = ip_bitmask/8;
|
||||||
|
|
||||||
|
memset(temp_data, 0, NETMASK_256-1);
|
||||||
|
memcpy(temp_data, ipdata, bytes);
|
||||||
|
|
||||||
|
node = CPTRetriveNode(msr, temp_data, ip_bitmask, node);
|
||||||
|
|
||||||
|
if (node && (node->bit != ip_bitmask)) {
|
||||||
|
if (msr->txcfg->debuglog_level >= 9) {
|
||||||
|
msr_log(msr, 9, "CPTFindElement: Found a tree node but netmask is different.");
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(node == NULL) {
|
||||||
|
if (msr->txcfg->debuglog_level >= 9) {
|
||||||
|
msr_log(msr, 9, "CPTFindElement: Node tree is NULL.");
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(node->prefix == NULL) {
|
||||||
|
if (msr->txcfg->debuglog_level >= 9) {
|
||||||
|
msr_log(msr, 9, "CPTFindElement: Found a tree node but prefix is NULL.");
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (memcmp(node->prefix->buffer, temp_data, bytes) == 0) {
|
||||||
|
mask = SHIFT_LEFT_MASK(8 - ip_bitmask % 8);
|
||||||
|
|
||||||
|
if ((ip_bitmask % 8) == 0) {
|
||||||
|
if (TreePrefixNetmask(msr, node->prefix, ip_bitmask, TRUE)) {
|
||||||
|
if (msr->txcfg->debuglog_level >= 9) {
|
||||||
|
msr_log(msr, 9, "CPTFindElement: Node found for provided ip address");
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((node->prefix->buffer[bytes] & mask) == (temp_data[bytes] & mask)) {
|
||||||
|
if (TreePrefixNetmask(msr, node->prefix, ip_bitmask, TRUE)) {
|
||||||
|
if (msr->txcfg->debuglog_level >= 9) {
|
||||||
|
msr_log(msr, 9, "CPTFindElement: Node found for provided ip address");
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return CPTFindElementIPNetblock(msr, temp_data, ip_bitmask, node);
|
||||||
|
}
|
||||||
|
|
||||||
|
TreeNode *CPTIpMatch(modsec_rec *msr, uint8_t *ipdata, CPTTree *tree, int type) {
|
||||||
|
|
||||||
|
if(tree == NULL) {
|
||||||
|
if (msr->txcfg->debuglog_level >= 9) {
|
||||||
|
msr_log(msr, 9, "CPTIpMatch: Tree is NULL. Cannot proceed searching the ip.");
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ipdata == NULL) {
|
||||||
|
if (msr->txcfg->debuglog_level >= 9) {
|
||||||
|
msr_log(msr, 9, "CPTIpMatch: Empty ip address. Nothing to search for.");
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(type) {
|
||||||
|
case IPV4_TREE:
|
||||||
|
if (msr->txcfg->debuglog_level >= 9) {
|
||||||
|
msr_log(msr, 9, "CPTIpMatch: Searching ip type 0x%x", type);
|
||||||
|
}
|
||||||
|
return CPTFindElement(msr, ipdata, NETMASK_32, tree);
|
||||||
|
case IPV6_TREE:
|
||||||
|
if (msr->txcfg->debuglog_level >= 9) {
|
||||||
|
msr_log(msr, 9, "CPTIpMatch: Searching ip type 0x%x", type);
|
||||||
|
}
|
||||||
|
return CPTFindElement(msr, ipdata, NETMASK_128, tree);
|
||||||
|
default:
|
||||||
|
if (msr->txcfg->debuglog_level >= 9) {
|
||||||
|
msr_log(msr, 9, "CPTIpMatch: Unknown ip type 0x%x", type);
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TreeNode *TreeAddIP(const char *buffer, CPTTree *tree, int type) {
|
||||||
|
uint32_t ip, ret;
|
||||||
|
uint8_t netmask_v4 = NETMASK_32, netmask_v6 = NETMASK_128;
|
||||||
|
char ip_strv4[NETMASK_32], ip_strv6[NETMASK_128];
|
||||||
|
struct in_addr addr4;
|
||||||
|
struct in6_addr addr6;
|
||||||
|
char *ptr = NULL;
|
||||||
|
|
||||||
|
if(tree == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
switch(type) {
|
||||||
|
|
||||||
|
case IPV4_TREE:
|
||||||
|
bzero(&addr4, sizeof(addr4));
|
||||||
|
memset(ip_strv4, 0x0, NETMASK_32);
|
||||||
|
|
||||||
|
strncpy(ip_strv4, buffer, sizeof(ip_strv4) - 2);
|
||||||
|
*(ip_strv4 + (sizeof(ip_strv4) - 1)) = '\0';
|
||||||
|
|
||||||
|
ptr = strdup(ip_strv4);
|
||||||
|
netmask_v4 = is_netmask_v4(ptr);
|
||||||
|
|
||||||
|
if(ptr != NULL) {
|
||||||
|
free(ptr);
|
||||||
|
ptr = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(netmask_v4 == 0)
|
||||||
|
return NULL;
|
||||||
|
else if(netmask_v4 != NETMASK_32) {
|
||||||
|
ip_strv4[strlen(ip_strv4)-3] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = inet_pton(AF_INET, ip_strv4, &addr4);
|
||||||
|
if (ret <= 0) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ip = addr4.s_addr;
|
||||||
|
|
||||||
|
tree->count++;
|
||||||
|
|
||||||
|
return CPTAddElement((uint8_t *)&ip, NETMASK_32, tree, netmask_v4);
|
||||||
|
|
||||||
|
case IPV6_TREE:
|
||||||
|
bzero(&addr6, sizeof(addr6));
|
||||||
|
memset(ip_strv6, 0x0, NETMASK_128);
|
||||||
|
|
||||||
|
strncpy(ip_strv6, buffer, sizeof(ip_strv6) - 2);
|
||||||
|
*(ip_strv6 + sizeof(ip_strv6) - 1) = '\0';
|
||||||
|
|
||||||
|
ptr = strdup(ip_strv6);
|
||||||
|
netmask_v6 = is_netmask_v6(ptr);
|
||||||
|
|
||||||
|
if(ptr != NULL) {
|
||||||
|
free(ptr);
|
||||||
|
ptr = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(netmask_v6 == 0)
|
||||||
|
return NULL;
|
||||||
|
else if (netmask_v6 != NETMASK_64) {
|
||||||
|
ip_strv4[strlen(ip_strv6)-3] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = inet_pton(AF_INET6, ip_strv6, &addr6);
|
||||||
|
if(ret <= 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
tree->count++;
|
||||||
|
|
||||||
|
return CPTAddElement((uint8_t *)&addr6.s6_addr, NETMASK_128, tree, netmask_v6);
|
||||||
|
default:
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
75
apache2/msc_tree.h
Normal file
75
apache2/msc_tree.h
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
/*
|
||||||
|
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
||||||
|
* Copyright (c) 2004-2011 Trustwave Holdings, Inc. (http://www.trustwave.com/)
|
||||||
|
*
|
||||||
|
* You may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* If any of the files related to licensing are missing or if you have any
|
||||||
|
* other questions related to licensing please contact Trustwave Holdings, Inc.
|
||||||
|
* directly using the email address security@modsecurity.org.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __MSC_TREE_H__
|
||||||
|
#define __MSC_TREE_H__
|
||||||
|
|
||||||
|
#include "modsecurity.h"
|
||||||
|
|
||||||
|
#define IPV4_TREE 0x1
|
||||||
|
#define IPV6_TREE 0x2
|
||||||
|
|
||||||
|
#define IPV4_LEN 0x20
|
||||||
|
#define IPV6_LEN 0x80
|
||||||
|
|
||||||
|
#define TREE_CHECK(x, y) ((x) & (y))
|
||||||
|
#define MASK_BITS(x) ((x + 1) * 8)
|
||||||
|
#define SHIFT_LEFT_MASK(x) (-1 << x)
|
||||||
|
#define SHIFT_RIGHT_MASK(x,y) (x >> y)
|
||||||
|
|
||||||
|
#define NETMASK_256 0x100
|
||||||
|
#define NETMASK_128 0x80
|
||||||
|
#define NETMASK_64 0x40
|
||||||
|
#define NETMASK_32 0x20
|
||||||
|
#define NETMASK_16 0x10
|
||||||
|
#define NETMASK_8 0x8
|
||||||
|
#define NETMASK_4 0x4
|
||||||
|
#define NETMASK_2 0x2
|
||||||
|
|
||||||
|
typedef struct CPTData_ {
|
||||||
|
uint8_t netmask;
|
||||||
|
struct CPTData_ *next;
|
||||||
|
} CPTData;
|
||||||
|
|
||||||
|
typedef struct TreePrefix_ {
|
||||||
|
uint8_t *buffer;
|
||||||
|
uint16_t bitlen;
|
||||||
|
CPTData *prefix_data;
|
||||||
|
} TreePrefix;
|
||||||
|
|
||||||
|
typedef struct TreeNode_ {
|
||||||
|
uint16_t bit;
|
||||||
|
int count;
|
||||||
|
uint8_t *netmasks;
|
||||||
|
TreePrefix *prefix;
|
||||||
|
struct TreeNode_ *left, *right;
|
||||||
|
struct TreeNode_ *parent;
|
||||||
|
} TreeNode;
|
||||||
|
|
||||||
|
typedef struct CPTTree_ {
|
||||||
|
int count;
|
||||||
|
apr_pool_t *pool;
|
||||||
|
TreeNode *head;
|
||||||
|
} CPTTree;
|
||||||
|
|
||||||
|
typedef struct TreeRoot_ {
|
||||||
|
CPTTree *ipv4_tree;
|
||||||
|
CPTTree *ipv6_tree;
|
||||||
|
} TreeRoot;
|
||||||
|
|
||||||
|
DSOLOCAL CPTTree *CPTCreateRadixTree(apr_pool_t *pool);
|
||||||
|
DSOLOCAL TreeNode *CPTIpMatch(modsec_rec *, uint8_t *, CPTTree *, int);
|
||||||
|
DSOLOCAL TreeNode *TreeAddIP(const char *, CPTTree *, int);
|
||||||
|
|
||||||
|
#endif /*__MSC_TREE_H__ */
|
@ -74,6 +74,63 @@ static unsigned char *c2x(unsigned what, unsigned char *where);
|
|||||||
static unsigned char x2c(unsigned char *what);
|
static unsigned char x2c(unsigned char *what);
|
||||||
static unsigned char xsingle2c(unsigned char *what);
|
static unsigned char xsingle2c(unsigned char *what);
|
||||||
|
|
||||||
|
/** \brief Validate IPv4 Netmask
|
||||||
|
*
|
||||||
|
* \param ip_strv6 Pointer to ipv6 address
|
||||||
|
*
|
||||||
|
* \retval netmask_v4 On Success
|
||||||
|
*/
|
||||||
|
unsigned char is_netmask_v4(char *ip_strv4) {
|
||||||
|
unsigned char netmask_v4 = 32;
|
||||||
|
char *mask_str = NULL;
|
||||||
|
int cidr;
|
||||||
|
|
||||||
|
if ((mask_str = strchr(ip_strv4, '/'))) {
|
||||||
|
*(mask_str++) = '\0';
|
||||||
|
|
||||||
|
if (strchr(mask_str, '.') != NULL) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
cidr = atoi(mask_str);
|
||||||
|
if ((cidr < 0) || (cidr > 32)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
netmask_v4 = (unsigned char)cidr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return netmask_v4;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief Validate IPv6 Netmask
|
||||||
|
*
|
||||||
|
* \param ip_strv6 Pointer to ipv6 address
|
||||||
|
*
|
||||||
|
* \retval netmask_v6 On Success
|
||||||
|
*/
|
||||||
|
unsigned char is_netmask_v6(char *ip_strv6) {
|
||||||
|
unsigned char netmask_v6 = 128;
|
||||||
|
char *mask_str = NULL;
|
||||||
|
int cidr;
|
||||||
|
|
||||||
|
if ((mask_str = strchr(ip_strv6, '/'))) {
|
||||||
|
*(mask_str++) = '\0';
|
||||||
|
|
||||||
|
if (strchr(mask_str, '.') != NULL) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
cidr = atoi(mask_str);
|
||||||
|
if ((cidr < 0) || (cidr > 64)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
netmask_v6 = (unsigned char)cidr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return netmask_v6;
|
||||||
|
}
|
||||||
|
|
||||||
/** \brief Interpret |HEX| syntax
|
/** \brief Interpret |HEX| syntax
|
||||||
*
|
*
|
||||||
* \param op_parm Pointer to operator input
|
* \param op_parm Pointer to operator input
|
||||||
|
@ -116,4 +116,7 @@ char DSOLOCAL *construct_single_var(modsec_rec *msr, char *name);
|
|||||||
|
|
||||||
char DSOLOCAL *format_all_performance_variables(modsec_rec *msr, apr_pool_t *mp);
|
char DSOLOCAL *format_all_performance_variables(modsec_rec *msr, apr_pool_t *mp);
|
||||||
|
|
||||||
|
unsigned char DSOLOCAL is_netmask_v4(char *ip_strv4);
|
||||||
|
|
||||||
|
unsigned char DSOLOCAL is_netmask_v6(char *ip_strv6);
|
||||||
#endif
|
#endif
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
#include "apr_strmatch.h"
|
#include "apr_strmatch.h"
|
||||||
#include "acmp.h"
|
#include "acmp.h"
|
||||||
#include "msc_util.h"
|
#include "msc_util.h"
|
||||||
|
#include "msc_tree.h"
|
||||||
#include "msc_crypt.h"
|
#include "msc_crypt.h"
|
||||||
|
|
||||||
#if !defined(WIN32) || !defined(WINNT)
|
#if !defined(WIN32) || !defined(WINNT)
|
||||||
@ -179,6 +180,182 @@ static int msre_op_ipmatch_execute(modsec_rec *msr, msre_rule *rule, msre_var *v
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Init function to ipmatchFromFile operator
|
||||||
|
*
|
||||||
|
* \param rule Pointer to the rule
|
||||||
|
* \param error_msg Pointer to error msg
|
||||||
|
*
|
||||||
|
* \retval 1 On Success
|
||||||
|
* \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;
|
||||||
|
TreeRoot rtree;
|
||||||
|
TreeNode *tnode;
|
||||||
|
|
||||||
|
if (error_msg == NULL)
|
||||||
|
return -1;
|
||||||
|
else
|
||||||
|
*error_msg = NULL;
|
||||||
|
|
||||||
|
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.");
|
||||||
|
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++;
|
||||||
|
if (*fn == '\0') {
|
||||||
|
*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) {
|
||||||
|
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));
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Execution function to ipmatchFromFile operator
|
||||||
|
*
|
||||||
|
* \param msr Pointer internal modsec request structure
|
||||||
|
* \param rule Pointer to the rule
|
||||||
|
* \param var Pointer to variable structure
|
||||||
|
* \param error_msg Pointer to error msg
|
||||||
|
*
|
||||||
|
* \retval -1 On Failure
|
||||||
|
* \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) {
|
||||||
|
TreeRoot *rtree = rule->op_param_data;
|
||||||
|
TreeNode *node;
|
||||||
|
apr_sockaddr_t *sa;
|
||||||
|
struct in_addr in;
|
||||||
|
struct in6_addr in6;
|
||||||
|
|
||||||
|
if (error_msg == NULL)
|
||||||
|
return -1;
|
||||||
|
else
|
||||||
|
*error_msg = NULL;
|
||||||
|
|
||||||
|
if(rtree == NULL) {
|
||||||
|
msr_log(msr, 1, "ipMatchFromFile Internal Error: tree value is null.");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
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,
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CPTIpMatch(msr, (uint8_t *)&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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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 (CPTIpMatch(msr, (uint8_t *)&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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* rsub */
|
/* rsub */
|
||||||
|
|
||||||
static char *param_remove_escape(msre_rule *rule, char *str, int len) {
|
static char *param_remove_escape(msre_rule *rule, char *str, int len) {
|
||||||
@ -4191,6 +4368,19 @@ void msre_engine_register_default_operators(msre_engine *engine) {
|
|||||||
msre_op_ipmatch_execute
|
msre_op_ipmatch_execute
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/* ipmatchFromFile */
|
||||||
|
msre_engine_op_register(engine,
|
||||||
|
"ipmatchFromFile",
|
||||||
|
msre_op_ipmatchFromFile_param_init,
|
||||||
|
msre_op_ipmatchFromFile_execute
|
||||||
|
);
|
||||||
|
/* ipmatchf */
|
||||||
|
msre_engine_op_register(engine,
|
||||||
|
"ipmatchf",
|
||||||
|
msre_op_ipmatchFromFile_param_init,
|
||||||
|
msre_op_ipmatchFromFile_execute
|
||||||
|
);
|
||||||
|
|
||||||
/* rsub */
|
/* rsub */
|
||||||
#if !defined(MSC_TEST)
|
#if !defined(MSC_TEST)
|
||||||
msre_engine_op_register(engine,
|
msre_engine_op_register(engine,
|
||||||
|
@ -16,6 +16,7 @@ msc_test_SOURCES = msc_test.c \
|
|||||||
$(top_srcdir)/apache2/persist_dbm.c \
|
$(top_srcdir)/apache2/persist_dbm.c \
|
||||||
$(top_srcdir)/apache2/msc_reqbody.c \
|
$(top_srcdir)/apache2/msc_reqbody.c \
|
||||||
$(top_srcdir)/apache2/msc_crypt.c \
|
$(top_srcdir)/apache2/msc_crypt.c \
|
||||||
|
$(top_srcdir)/apache2/msc_tree.c \
|
||||||
$(top_srcdir)/apache2/msc_geo.c \
|
$(top_srcdir)/apache2/msc_geo.c \
|
||||||
$(top_srcdir)/apache2/msc_gsb.c \
|
$(top_srcdir)/apache2/msc_gsb.c \
|
||||||
$(top_srcdir)/apache2/acmp.c \
|
$(top_srcdir)/apache2/acmp.c \
|
||||||
|
Loading…
x
Reference in New Issue
Block a user