Skip to content

Commit 0037a07

Browse files
author
Felipe Zimmerle
committed
Using RadixTree instead of list to storage IPs
Used by the operator @ipMatch and variants, this structure storage all the IPs addresses for later comparison. Last version was using RadixTree only if the set of IPs was specified from files. IPs specified as parameters, was using a chained list. Chained lists may affect the performance, since lookups in worst case will be O(n). RadixTrees could provide better results depending on the amount of elements and its contents.
1 parent 80185e2 commit 0037a07

File tree

7 files changed

+95
-150
lines changed

7 files changed

+95
-150
lines changed

apache2/apache2_config.c

Lines changed: 9 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1671,8 +1671,7 @@ static const char *cmd_rule_perf_time(cmd_parms *cmd, void *_dcfg,
16711671
}
16721672

16731673
char *parser_conn_limits_operator(apr_pool_t *mp, const char *p2,
1674-
TreeRoot **whitelist, msre_ipmatch **whitelist_param,
1675-
TreeRoot **suspicious_list, msre_ipmatch **suspicious_list_param,
1674+
TreeRoot **whitelist, TreeRoot **suspicious_list,
16761675
const char *filename)
16771676
{
16781677
int res = 0;
@@ -1691,22 +1690,18 @@ char *parser_conn_limits_operator(apr_pool_t *mp, const char *p2,
16911690
if ((strncasecmp(p2, "!@ipMatchFromFile", strlen("!@ipMatchFromFile")) == 0) ||
16921691
(strncasecmp(p2, "!@ipMatchF", strlen("!@ipMatchF")) == 0)) {
16931692

1694-
res = ip_tree_from_file(whitelist,
1695-
file, mp, NULL);
1693+
res = ip_tree_from_file(whitelist, file, mp, &error_msg);
16961694
}
16971695
else if (strncasecmp(p2, "!@ipMatch", strlen("!@ipMatch")) == 0) {
1698-
res = ip_list_from_param(mp, param,
1699-
whitelist_param, &error_msg);
1696+
res = ip_tree_from_param(mp, param, whitelist, &error_msg);
17001697
}
17011698
else if ((strncasecmp(p2, "@ipMatchFromFile", strlen("@ipMatchFromFile")) == 0) ||
17021699
(strncasecmp(p2, "@ipMatchF", strlen("@ipMatchF")) == 0)) {
17031700

1704-
res = ip_tree_from_file(suspicious_list,
1705-
file, mp, NULL);
1701+
res = ip_tree_from_file(suspicious_list, file, mp, &error_msg);
17061702
}
17071703
else if (strncasecmp(p2, "@ipMatch", strlen("@ipMatch")) == 0) {
1708-
res = ip_list_from_param(mp, param,
1709-
suspicious_list_param, &error_msg);
1704+
res = ip_tree_from_param(mp, param, suspicious_list, &error_msg);
17101705
}
17111706
else {
17121707
return apr_psprintf(mp, "ModSecurity: Invalid operator for " \
@@ -1757,9 +1752,8 @@ static const char *cmd_conn_read_state_limit(cmd_parms *cmd, void *_dcfg,
17571752

17581753
if (p2 != NULL) {
17591754
char *param = parser_conn_limits_operator(cmd->pool, p2,
1760-
&conn_read_state_whitelist, &conn_read_state_whitelist_param,
1761-
&conn_read_state_suspicious_list,
1762-
&conn_read_state_suspicious_list_param, cmd->directive->filename);
1755+
&conn_read_state_whitelist, &conn_read_state_suspicious_list,
1756+
cmd->directive->filename);
17631757

17641758
if (param)
17651759
return param;
@@ -1797,9 +1791,8 @@ static const char *cmd_conn_write_state_limit(cmd_parms *cmd, void *_dcfg,
17971791

17981792
if (p2 != NULL) {
17991793
char *param = parser_conn_limits_operator(cmd->pool, p2,
1800-
&conn_write_state_whitelist, &conn_write_state_whitelist_param,
1801-
&conn_write_state_suspicious_list,
1802-
&conn_write_state_suspicious_list_param, cmd->directive->filename);
1794+
&conn_write_state_whitelist, &conn_write_state_suspicious_list,
1795+
cmd->directive->filename);
18031796

18041797
if (param)
18051798
return param;

apache2/mod_security2.c

Lines changed: 9 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -66,15 +66,10 @@ int DSOLOCAL status_engine_state = STATUS_ENGINE_DISABLED;
6666
unsigned long int DSOLOCAL conn_read_state_limit = 0;
6767
TreeRoot DSOLOCAL *conn_read_state_whitelist = 0;
6868
TreeRoot DSOLOCAL *conn_read_state_suspicious_list = 0;
69-
msre_ipmatch DSOLOCAL *conn_read_state_whitelist_param = 0;
70-
msre_ipmatch DSOLOCAL *conn_read_state_suspicious_list_param = 0;
7169

70+
unsigned long int DSOLOCAL conn_write_state_limit = 0;
7271
TreeRoot DSOLOCAL *conn_write_state_whitelist = 0;
7372
TreeRoot DSOLOCAL *conn_write_state_suspicious_list = 0;
74-
msre_ipmatch DSOLOCAL *conn_write_state_whitelist_param = 0;
75-
msre_ipmatch DSOLOCAL *conn_write_state_suspicious_list_param = 0;
76-
77-
unsigned long int DSOLOCAL conn_write_state_limit = 0;
7873

7974
#if defined(WIN32) || defined(VERSION_NGINX)
8075
int (*modsecDropAction)(request_rec *r) = NULL;
@@ -1428,10 +1423,8 @@ static int hook_connection_early(conn_rec *conn)
14281423
if (conn_read_state_limit > 0 && ip_count_r > conn_read_state_limit)
14291424
{
14301425
if (conn_read_state_suspicious_list &&
1431-
(!((tree_contains_ip(conn->pool,
1432-
conn_read_state_suspicious_list, client_ip, NULL, &error_msg) <= 0) ||
1433-
(list_contains_ip(conn->pool,
1434-
conn_read_state_suspicious_list_param, client_ip, &error_msg) <= 0))))
1426+
(tree_contains_ip(conn->pool,
1427+
conn_read_state_suspicious_list, client_ip, NULL, &error_msg) <= 0))
14351428
{
14361429
ap_log_error(APLOG_MARK, APLOG_WARNING, 0, NULL,
14371430
"ModSecurity: Too many threads [%ld] of %ld allowed in " \
@@ -1440,10 +1433,8 @@ static int hook_connection_early(conn_rec *conn)
14401433
conn_read_state_limit, client_ip);
14411434
}
14421435

1443-
else if ((tree_contains_ip(conn->pool,
1444-
conn_read_state_whitelist, client_ip, NULL, &error_msg) > 0) ||
1445-
(list_contains_ip(conn->pool,
1446-
conn_read_state_whitelist_param, client_ip, &error_msg) > 0))
1436+
else if (tree_contains_ip(conn->pool,
1437+
conn_read_state_whitelist, client_ip, NULL, &error_msg) > 0)
14471438
{
14481439
ap_log_error(APLOG_MARK, APLOG_WARNING, 0, NULL,
14491440
"ModSecurity: Too many threads [%ld] of %ld allowed in " \
@@ -1464,21 +1455,17 @@ static int hook_connection_early(conn_rec *conn)
14641455
if (conn_write_state_limit > 0 && ip_count_w > conn_write_state_limit)
14651456
{
14661457
if (conn_write_state_suspicious_list &&
1467-
(!((tree_contains_ip(conn->pool,
1468-
conn_write_state_suspicious_list, client_ip, NULL, &error_msg) <= 0) ||
1469-
(list_contains_ip(conn->pool,
1470-
conn_write_state_suspicious_list_param, client_ip, &error_msg) <= 0))))
1458+
(tree_contains_ip(conn->pool,
1459+
conn_write_state_suspicious_list, client_ip, NULL, &error_msg) <= 0))
14711460
{
14721461
ap_log_error(APLOG_MARK, APLOG_WARNING, 0, NULL,
14731462
"ModSecurity: Too many threads [%ld] of %ld allowed in " \
14741463
"WRITE state from %s - There is a suspission list but " \
14751464
"that IP is not part of it, access granted", ip_count_w,
14761465
conn_read_state_limit, client_ip);
14771466
}
1478-
else if ((tree_contains_ip(conn->pool,
1479-
conn_write_state_whitelist, client_ip, NULL, &error_msg) > 0) ||
1480-
(list_contains_ip(conn->pool,
1481-
conn_write_state_whitelist_param, client_ip, &error_msg) > 0))
1467+
else if (tree_contains_ip(conn->pool,
1468+
conn_write_state_whitelist, client_ip, NULL, &error_msg) > 0)
14821469
{
14831470
ap_log_error(APLOG_MARK, APLOG_WARNING, 0, NULL,
14841471
"ModSecurity: Too many threads [%ld] of %ld allowed in " \

apache2/modsecurity.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -148,14 +148,10 @@ extern DSOLOCAL int status_engine_state;
148148
extern DSOLOCAL unsigned long int conn_read_state_limit;
149149
extern DSOLOCAL TreeRoot *conn_read_state_whitelist;
150150
extern DSOLOCAL TreeRoot *conn_read_state_suspicious_list;
151-
extern DSOLOCAL msre_ipmatch *conn_read_state_whitelist_param;
152-
extern DSOLOCAL msre_ipmatch *conn_read_state_suspicious_list_param;
153151

154152
extern DSOLOCAL unsigned long int conn_write_state_limit;
155153
extern DSOLOCAL TreeRoot *conn_write_state_whitelist;
156154
extern DSOLOCAL TreeRoot *conn_write_state_suspicious_list;
157-
extern DSOLOCAL msre_ipmatch *conn_write_state_whitelist_param;
158-
extern DSOLOCAL msre_ipmatch *conn_write_state_suspicious_list_param;
159155

160156
extern DSOLOCAL unsigned long int unicode_codepage;
161157

apache2/msc_util.c

Lines changed: 68 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -2389,8 +2389,6 @@ char *construct_single_var(modsec_rec *msr, char *name) {
23892389
return (char *)vx->value;
23902390
}
23912391

2392-
<<<<<<< HEAD
2393-
23942392
/**
23952393
* @brief Transforms an apr_array_header_t to a text buffer
23962394
*
@@ -2455,41 +2453,57 @@ int msc_headers_to_buffer(const apr_array_header_t *arr, char *buffer,
24552453
return headers_length;
24562454
}
24572455

2458-
int ip_tree_from_file(TreeRoot **rtree_, char *uri,
2459-
apr_pool_t *mp, char **error_msg)
2460-
{
2461-
TreeNode *tnode = NULL;
2462-
apr_status_t rc;
2463-
int line = 0;
2464-
apr_file_t *fd;
2465-
char *start;
2466-
char *end;
2467-
char buf[HUGE_STRING_LEN + 1]; // FIXME: 2013-10-29 zimmerle: dynamic?
2468-
char errstr[1024]; //
2469-
TreeRoot *rtree;
24702456

2471-
rtree = apr_palloc(mp, sizeof(TreeRoot));
2472-
if (rtree == NULL)
2457+
int create_radix_tree(apr_pool_t *mp, TreeRoot **rtree, char **error_msg)
2458+
{
2459+
*rtree = apr_palloc(mp, sizeof(TreeRoot));
2460+
if (*rtree == NULL)
24732461
{
24742462
*error_msg = apr_psprintf(mp, "Failed allocating " \
24752463
"memory to TreeRoot.");
2476-
return -1;
2464+
goto root_node_failed;
24772465
}
2478-
memset(rtree, 0, sizeof(TreeRoot));
2466+
memset(*rtree, 0, sizeof(TreeRoot));
24792467

2480-
rtree->ipv4_tree = CPTCreateRadixTree(mp);
2481-
if (rtree->ipv4_tree == NULL)
2468+
(*rtree)->ipv4_tree = CPTCreateRadixTree(mp);
2469+
if ((*rtree)->ipv4_tree == NULL)
24822470
{
2483-
*error_msg = apr_psprintf(mp, "ipmatchFromFile: Tree initialization " \
2471+
*error_msg = apr_psprintf(mp, "IPmatch: Tree initialization " \
24842472
"failed.");
2485-
return -1;
2473+
goto ipv4_tree_failed;
24862474
}
24872475

2488-
rtree->ipv6_tree = CPTCreateRadixTree(mp);
2489-
if (rtree->ipv6_tree == NULL)
2476+
(*rtree)->ipv6_tree = CPTCreateRadixTree(mp);
2477+
if ((*rtree)->ipv6_tree == NULL)
24902478
{
2491-
*error_msg = apr_psprintf(mp, "ipmatchFromFile: Tree initialization " \
2479+
*error_msg = apr_psprintf(mp, "IPmatch: Tree initialization " \
24922480
"failed.");
2481+
goto ipv6_tree_failed;
2482+
}
2483+
2484+
return 0;
2485+
2486+
ipv6_tree_failed:
2487+
ipv4_tree_failed:
2488+
root_node_failed:
2489+
return -1;
2490+
}
2491+
2492+
2493+
int ip_tree_from_file(TreeRoot **rtree, char *uri,
2494+
apr_pool_t *mp, char **error_msg)
2495+
{
2496+
TreeNode *tnode = NULL;
2497+
apr_status_t rc;
2498+
int line = 0;
2499+
apr_file_t *fd;
2500+
char *start;
2501+
char *end;
2502+
char buf[HUGE_STRING_LEN + 1]; // FIXME: 2013-10-29 zimmerle: dynamic?
2503+
char errstr[1024]; //
2504+
2505+
if (create_radix_tree(mp, rtree, error_msg))
2506+
{
24932507
return -1;
24942508
}
24952509

@@ -2545,14 +2559,15 @@ int ip_tree_from_file(TreeRoot **rtree_, char *uri,
25452559

25462560
if (strchr(start, ':') == NULL)
25472561
{
2548-
tnode = TreeAddIP(start, rtree->ipv4_tree, IPV4_TREE);
2562+
tnode = TreeAddIP(start, (*rtree)->ipv4_tree, IPV4_TREE);
25492563
}
25502564
#if APR_HAVE_IPV6
25512565
else
25522566
{
2553-
tnode = TreeAddIP(start, rtree->ipv6_tree, IPV6_TREE);
2567+
tnode = TreeAddIP(start, (*rtree)->ipv6_tree, IPV6_TREE);
25542568
}
25552569
#endif
2570+
25562571
if (tnode == NULL)
25572572
{
25582573
*error_msg = apr_psprintf(mp, "Could not add entry " \
@@ -2566,8 +2581,6 @@ int ip_tree_from_file(TreeRoot **rtree_, char *uri,
25662581
apr_file_close(fd);
25672582
}
25682583

2569-
*rtree_ = rtree;
2570-
25712584
return 0;
25722585
}
25732586

@@ -2586,7 +2599,7 @@ int tree_contains_ip(apr_pool_t *mp, TreeRoot *rtree,
25862599

25872600
if (strchr(value, ':') == NULL) {
25882601
if (inet_pton(AF_INET, value, &in) <= 0) {
2589-
*error_msg = apr_psprintf(mp, "IPmatchFromFile: bad IPv4 " \
2602+
*error_msg = apr_psprintf(mp, "IPmatch: bad IPv4 " \
25902603
"specification \"%s\".", value);
25912604
return -1;
25922605
}
@@ -2599,7 +2612,7 @@ int tree_contains_ip(apr_pool_t *mp, TreeRoot *rtree,
25992612
#if APR_HAVE_IPV6
26002613
else {
26012614
if (inet_pton(AF_INET6, value, &in6) <= 0) {
2602-
*error_msg = apr_psprintf(mp, "IPmatchFromFile: bad IPv6 " \
2615+
*error_msg = apr_psprintf(mp, "IPmatch: bad IPv6 " \
26032616
"specification \"%s\".", value);
26042617
return -1;
26052618
}
@@ -2614,74 +2627,39 @@ int tree_contains_ip(apr_pool_t *mp, TreeRoot *rtree,
26142627
return 0;
26152628
}
26162629

2617-
int ip_list_from_param(apr_pool_t *pool,
2618-
char *param, msre_ipmatch **last, char **error_msg)
2630+
int ip_tree_from_param(apr_pool_t *mp,
2631+
char *param, TreeRoot **rtree, char **error_msg)
26192632
{
26202633
char *saved = NULL;
26212634
char *str = NULL;
2622-
apr_status_t rv;
2623-
msre_ipmatch *current;
2624-
2625-
str = apr_strtok(param, ",", &saved);
2626-
while( str != NULL) {
2627-
const char *ipstr, *mask, *sep;
2628-
2629-
/* get the IP address and mask strings */
2630-
sep = strchr(str, '/');
2631-
if (sep) {
2632-
ipstr = apr_pstrndup(pool, str, (sep - str) );
2633-
mask = apr_pstrdup(pool, (sep + 1) );
2634-
}
2635-
else {
2636-
ipstr = apr_pstrdup(pool, str);
2637-
mask = NULL;
2638-
}
2639-
/* create a new msre_ipmatch containing a new apr_ipsubnet_t*, and add it to the linked list */
2640-
current = apr_pcalloc(pool, sizeof(msre_ipmatch));
2641-
rv = apr_ipsubnet_create(&current->ipsubnet, ipstr, mask, pool);
2642-
if ( rv != APR_SUCCESS ) {
2643-
char msgbuf[120];
2644-
apr_strerror(rv, msgbuf, sizeof msgbuf);
2645-
*error_msg = apr_pstrcat(pool, "Error: ", msgbuf, NULL);
2646-
return -1;
2647-
}
2648-
current->address = str;
2649-
current->next = NULL;
2650-
*last = current;
2651-
last = &current->next;
2652-
2653-
str = apr_strtok(NULL, ",",&saved);
2654-
}
2655-
2656-
return 0;
2657-
}
2658-
2659-
int list_contains_ip(apr_pool_t *mp, msre_ipmatch *current,
2660-
const char *value, char **error_msg)
2661-
{
2662-
apr_sockaddr_t *sa;
2635+
TreeNode *tnode = NULL;
26632636

2664-
if (current == NULL)
2637+
if (create_radix_tree(mp, rtree, error_msg))
26652638
{
2666-
return 0;
2667-
}
2668-
2669-
/* create an apr_sockaddr_t for the value string */
2670-
if (apr_sockaddr_info_get(&sa, value,
2671-
APR_UNSPEC, 0, 0, mp) != APR_SUCCESS ) {
2672-
*error_msg = apr_psprintf(mp, "ipMatch Internal Error: Invalid " \
2673-
"ip address.");
26742639
return -1;
26752640
}
26762641

2677-
/* look through the linked list for a match */
2678-
while (current) {
2679-
if (apr_ipsubnet_test(current->ipsubnet, sa)) {
2680-
*error_msg = apr_psprintf(mp, "IPmatch \"%s\" matched \"%s\"",
2681-
value, current->address);
2682-
return 1;
2642+
str = apr_strtok(param, ",", &saved);
2643+
while (str != NULL)
2644+
{
2645+
if (strchr(str, ':') == NULL)
2646+
{
2647+
tnode = TreeAddIP(str, (*rtree)->ipv4_tree, IPV4_TREE);
26832648
}
2684-
current = current->next;
2649+
#if APR_HAVE_IPV6
2650+
else
2651+
{
2652+
tnode = TreeAddIP(str, (*rtree)->ipv6_tree, IPV6_TREE);
2653+
}
2654+
#endif
2655+
if (tnode == NULL)
2656+
{
2657+
*error_msg = apr_psprintf(mp, "Could not add entry " \
2658+
"\"%s\" from: %s.", str, param);
2659+
return -1;
2660+
}
2661+
2662+
str = apr_strtok(NULL, ",", &saved);
26852663
}
26862664

26872665
return 0;

apache2/msc_util.h

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -156,10 +156,7 @@ int DSOLOCAL ip_tree_from_file(TreeRoot **rtree, char *uri,
156156
int DSOLOCAL tree_contains_ip(apr_pool_t *mp, TreeRoot *rtree,
157157
const char *value, modsec_rec *msr, char **error_msg);
158158

159-
int DSOLOCAL ip_list_from_param(apr_pool_t *pool,
160-
char *param, msre_ipmatch **last, char **error_msg);
161-
162-
int list_contains_ip(apr_pool_t *mp, msre_ipmatch *current,
163-
const char *value, char **error_msg);
159+
int DSOLOCAL ip_tree_from_param(apr_pool_t *pool,
160+
char *param, TreeRoot **rtree, char **error_msg);
164161

165162
#endif

0 commit comments

Comments
 (0)