mirror of
https://github.com/owasp-modsecurity/ModSecurity.git
synced 2025-08-13 13:26:01 +03:00
The ipv4 representation was only accepting slash notation with masks represented in 2 digits. In the ipv6 implementation several fixies were made: The maximum value to a bitmask was 64 which is not the reality, as ipv6 can handle 128 bits. The second change was also to enable mask representation with more and less than 2 digits. A more general fix was added to allow the unit tests to work even if a invalid ip/range was informed during the creation of the "tree", now it is checking if the tree is NULL while performing the execution of the operator. Initial problem was reported at the issue: #706.
917 lines
24 KiB
C
917 lines
24 KiB
C
/*
|
||
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
||
* Copyright (c) 2004-2013 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>
|
||
#if APR_HAVE_STDINT_H
|
||
#include <stdint.h>
|
||
#endif
|
||
#include <string.h>
|
||
#if APR_HAVE_NETINET_IN_H
|
||
#include <netinet/in.h>
|
||
#endif
|
||
#if APR_HAVE_ARPA_INET_H
|
||
#include <arpa/inet.h>
|
||
#endif
|
||
#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(unsigned char *buffer, unsigned char netmask, unsigned int 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(unsigned char 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, unsigned char *ipdata, unsigned int ip_bitmask,
|
||
unsigned char 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(unsigned char *ipdata, unsigned int ip_bitmask,
|
||
unsigned char 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, unsigned char netmask) {
|
||
CPTData *prefix_data = NULL;
|
||
|
||
if (prefix == NULL) {
|
||
return 0;
|
||
}
|
||
|
||
prefix_data = prefix->prefix_data;
|
||
|
||
while (prefix_data != NULL) {
|
||
if (prefix_data->netmask == netmask)
|
||
return 1;
|
||
prefix_data = prefix_data->next;
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
int CheckBitmask(unsigned char netmask, unsigned int 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, unsigned char netmask, unsigned int 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(unsigned char)));
|
||
|
||
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, unsigned char netmask, unsigned char 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(unsigned char)));
|
||
|
||
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(unsigned char *ipdata, unsigned int ip_bitmask, CPTTree *tree, unsigned char netmask) {
|
||
unsigned char *buffer = NULL;
|
||
unsigned char bitlen = 0;
|
||
int bit_validation = 0, test_bit = 0;
|
||
int i = 0, j = 0, temp = 0;
|
||
unsigned int 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;
|
||
|
||
while(prefix_data != NULL) {
|
||
if (prefix_data->netmask == netmask)
|
||
++found;
|
||
prefix_data = prefix_data->next;
|
||
}
|
||
|
||
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(unsigned char)));
|
||
|
||
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(unsigned char));
|
||
|
||
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, unsigned int netmask) {
|
||
|
||
while(prefix_data != NULL) {
|
||
if (prefix_data->netmask == netmask) {
|
||
return 1;
|
||
}
|
||
prefix_data = prefix_data->next;
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
int TreePrefixNetmask(modsec_rec *msr, TreePrefix *prefix, unsigned int netmask, int flag) {
|
||
CPTData *prefix_data = NULL;
|
||
int ret = 0;
|
||
|
||
if (prefix == NULL) {
|
||
if (msr && 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 && msr->txcfg->debuglog_level >= 9) {
|
||
msr_log(msr, 9, "TreePrefixNetmask: Cannot find a prefix with correct netmask.");
|
||
}
|
||
return 0;
|
||
} else {
|
||
if (msr && msr->txcfg->debuglog_level >= 9) {
|
||
msr_log(msr, 9, "TreePrefixNetmask: Found a prefix with correct netmask.");
|
||
}
|
||
return 1;
|
||
}
|
||
}
|
||
|
||
if (msr && 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, unsigned char *buffer, unsigned int ip_bitmask, TreeNode *node) {
|
||
unsigned int x, y;
|
||
|
||
if(node == NULL) {
|
||
if (msr && msr->txcfg->debuglog_level >= 9) {
|
||
msr_log(msr, 9, "CPTRetriveNode: Node tree is NULL.");
|
||
}
|
||
return NULL;
|
||
}
|
||
|
||
if(buffer == NULL) {
|
||
if (msr && 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 && 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, unsigned char *ipdata, unsigned char 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 && 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 && 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 && 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 && 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 && 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, unsigned char *ipdata, unsigned int ip_bitmask, CPTTree *tree) {
|
||
TreeNode *node = NULL;
|
||
int mask = 0, bytes = 0;
|
||
unsigned char temp_data[NETMASK_256-1];
|
||
|
||
if (tree == NULL) {
|
||
if (msr && 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 && 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 && 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 && 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 && msr->txcfg->debuglog_level >= 9) {
|
||
msr_log(msr, 9, "CPTFindElement: Node tree is NULL.");
|
||
}
|
||
return node;
|
||
}
|
||
|
||
if(node->prefix == NULL) {
|
||
if (msr && 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 && 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 && 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, unsigned char *ipdata, CPTTree *tree, int type) {
|
||
|
||
if(tree == NULL) {
|
||
if (msr && 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 && 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 && 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 && 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 && 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) {
|
||
unsigned long ip, ret;
|
||
unsigned char 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;
|
||
int pos = 0;
|
||
char *ptr = NULL;
|
||
|
||
if(tree == NULL)
|
||
return NULL;
|
||
|
||
pos = strchr(buffer, '/') - buffer;
|
||
|
||
switch(type) {
|
||
|
||
case IPV4_TREE:
|
||
memset(&addr4, 0, sizeof(addr4));
|
||
memset(ip_strv4, 0x0, NETMASK_32);
|
||
|
||
strncpy(ip_strv4, buffer, sizeof(ip_strv4));
|
||
*(ip_strv4 + (sizeof(ip_strv4) - 1)) = '\0';
|
||
|
||
ptr = strdup(ip_strv4);
|
||
netmask_v4 = is_netmask_v4(ptr);
|
||
|
||
if (netmask_v4 > NETMASK_32) {
|
||
free(ptr);
|
||
ptr = NULL;
|
||
return NULL;
|
||
}
|
||
|
||
if(ptr != NULL) {
|
||
free(ptr);
|
||
ptr = NULL;
|
||
}
|
||
|
||
if(netmask_v4 == 0) {
|
||
return NULL;
|
||
}
|
||
else if (netmask_v4 != NETMASK_32 && pos < strlen(ip_strv4)) {
|
||
ip_strv4[pos] = '\0';
|
||
}
|
||
|
||
ret = inet_pton(AF_INET, ip_strv4, &addr4);
|
||
|
||
if (ret <= 0) {
|
||
return NULL;
|
||
}
|
||
|
||
ip = addr4.s_addr;
|
||
|
||
tree->count++;
|
||
|
||
return CPTAddElement((unsigned char *)&ip, NETMASK_32, tree, netmask_v4);
|
||
|
||
case IPV6_TREE:
|
||
memset(&addr6, 0, sizeof(addr6));
|
||
memset(ip_strv6, 0x0, NETMASK_128);
|
||
|
||
strncpy(ip_strv6, buffer, sizeof(ip_strv6));
|
||
*(ip_strv6 + sizeof(ip_strv6) - 1) = '\0';
|
||
|
||
ptr = strdup(ip_strv6);
|
||
netmask_v6 = is_netmask_v6(ptr);
|
||
|
||
if (netmask_v6 > NETMASK_128) {
|
||
free(ptr);
|
||
ptr = NULL;
|
||
return NULL;
|
||
}
|
||
|
||
if(ptr != NULL) {
|
||
free(ptr);
|
||
ptr = NULL;
|
||
}
|
||
|
||
if(netmask_v6 == 0) {
|
||
return NULL;
|
||
}
|
||
else if (netmask_v6 != NETMASK_128 && pos < strlen(ip_strv6)) {
|
||
ip_strv6[pos] = '\0';
|
||
}
|
||
|
||
ret = inet_pton(AF_INET6, ip_strv6, &addr6);
|
||
|
||
if (ret <= 0)
|
||
{
|
||
return NULL;
|
||
}
|
||
|
||
tree->count++;
|
||
|
||
return CPTAddElement((unsigned char *)&addr6.s6_addr, NETMASK_128, tree, netmask_v6);
|
||
default:
|
||
return NULL;
|
||
}
|
||
|
||
return NULL;
|
||
}
|