Skip to content

Commit

Permalink
🔀 ⚡ Faster IP matching.
Browse files Browse the repository at this point in the history
Squashed commit of the following:

commit 47ab81b
Author: ADD-SP <me@addesp.com>
Date:   Mon Dec 14 14:50:31 2020 +0800

    :bulb: Update comments in source code.

commit b5900e4
Author: ADD-SP <me@addesp.com>
Date:   Mon Dec 14 14:26:02 2020 +0800

    :triangular_flag_on_post: ip-trie is implemented.
  • Loading branch information
ADD-SP committed Dec 14, 2020
1 parent e81c5de commit 2b9e774
Show file tree
Hide file tree
Showing 8 changed files with 385 additions and 90 deletions.
3 changes: 2 additions & 1 deletion config
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ deps="$ngx_addon_dir/inc/ngx_http_waf_module_check.h \
$ngx_addon_dir/inc/ngx_http_waf_module_macro.h \
$ngx_addon_dir/inc/ngx_http_waf_module_type.h \
$ngx_addon_dir/inc/ngx_http_waf_module_util.h \
$ngx_addon_dir/inc/ngx_http_waf_module_ip_hash_table.h"
$ngx_addon_dir/inc/ngx_http_waf_module_ip_hash_table.h \
$ngx_addon_dir/inc/ngx_http_waf_module_ip_trie.h"

srcs="$ngx_addon_dir/src/ngx_http_waf_module_core.c"

Expand Down
79 changes: 37 additions & 42 deletions inc/ngx_http_waf_module_check.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include <ngx_http_waf_module_type.h>
#include <ngx_http_waf_module_util.h>
#include <ngx_http_waf_module_ip_hash_table.h>
#include <ngx_http_waf_module_ip_trie.h>


#ifndef NGX_HTTP_WAF_MODLULE_CHECK_H
Expand Down Expand Up @@ -162,32 +163,29 @@ static ngx_int_t ngx_http_waf_handler_check_white_ip(ngx_http_request_t* r, ngx_
return NOT_MATCHED;
}

ip_trie_node_t* ip_trie_node = NULL;
if (r->connection->sockaddr->sa_family == AF_INET) {
struct sockaddr_in* sin = (struct sockaddr_in*)r->connection->sockaddr;
uint32_t ipv4 = sin->sin_addr.s_addr;
ipv4_t* p = srv_conf->white_ipv4->elts;
size_t index = 0;
for (; index < srv_conf->white_ipv4->nelts; index++, p++) {
if (ipv4_netcmp(ipv4, p) == MATCHED) {
ctx->blocked = FALSE;
strcpy((char*)ctx->rule_type, "WHITE-IPV4");
strcpy((char*)ctx->rule_deatils, (char*)p->text);
*out_http_status = NGX_DECLINED;
return MATCHED;
}
inx_addr_t inx_addr;
memcpy(&(inx_addr.ipv4), &(sin->sin_addr), sizeof(struct in_addr));
if (ip_trie_find(srv_conf->white_ipv4, &inx_addr, &ip_trie_node) == SUCCESS) {
ctx->blocked = FALSE;
strcpy((char*)ctx->rule_type, "WHITE-IPV4");
strcpy((char*)ctx->rule_deatils, (char*)ip_trie_node->text);
*out_http_status = NGX_DECLINED;
return MATCHED;
}
} else if (r->connection->sockaddr->sa_family == AF_INET6) {
struct sockaddr_in6* sin6 = (struct sockaddr_in6*)r->connection->sockaddr;
ipv6_t* p = srv_conf->white_ipv6->elts;
size_t index = 0;
for (; index < srv_conf->white_ipv6->nelts; index++, p++) {
if (ipv6_netcmp(sin6->sin6_addr.__in6_u.__u6_addr8, p) == MATCHED) {
ctx->blocked = TRUE;
strcpy((char*)ctx->rule_type, "WHITE-IPV6");
strcpy((char*)ctx->rule_deatils, (char*)p->text);
*out_http_status = NGX_DECLINED;
return MATCHED;
}
inx_addr_t inx_addr;

memcpy(&(inx_addr.ipv6), &(sin6->sin6_addr), sizeof(struct in6_addr));
if (ip_trie_find(srv_conf->white_ipv6, &inx_addr, &ip_trie_node) == SUCCESS) {
ctx->blocked = FALSE;
strcpy((char*)ctx->rule_type, "WHITE-IPV4");
strcpy((char*)ctx->rule_deatils, (char*)ip_trie_node->text);
*out_http_status = NGX_DECLINED;
return MATCHED;
}
}

Expand All @@ -203,32 +201,29 @@ static ngx_int_t ngx_http_waf_handler_check_black_ip(ngx_http_request_t* r, ngx_
return NOT_MATCHED;
}

ip_trie_node_t *ip_trie_node = NULL;
if (r->connection->sockaddr->sa_family == AF_INET) {
struct sockaddr_in* sin = (struct sockaddr_in*)r->connection->sockaddr;
uint32_t ipv4 = sin->sin_addr.s_addr;
ipv4_t* p = srv_conf->black_ipv4->elts;
size_t index = 0;
for (; index < srv_conf->black_ipv4->nelts; index++, p++) {
if (ipv4_netcmp(ipv4, p) == MATCHED) {
ctx->blocked = TRUE;
strcpy((char*)ctx->rule_type, "BLACK-IPV4");
strcpy((char*)ctx->rule_deatils, (char*)p->text);
*out_http_status = NGX_HTTP_FORBIDDEN;
return MATCHED;
}
inx_addr_t inx_addr;

memcpy(&(inx_addr.ipv4), &(sin->sin_addr), sizeof(struct in_addr));
if (ip_trie_find(srv_conf->black_ipv4, &inx_addr, &ip_trie_node) == SUCCESS) {
ctx->blocked = FALSE;
strcpy((char*)ctx->rule_type, "BLACK-IPV4");
strcpy((char*)ctx->rule_deatils, (char*)ip_trie_node->text);
*out_http_status = NGX_HTTP_FORBIDDEN;
return MATCHED;
}
} else if (r->connection->sockaddr->sa_family == AF_INET6) {
struct sockaddr_in6* sin6 = (struct sockaddr_in6*)r->connection->sockaddr;
ipv6_t* p = srv_conf->black_ipv6->elts;
size_t index = 0;
for (; index < srv_conf->black_ipv6->nelts; index++, p++) {
if (ipv6_netcmp(sin6->sin6_addr.__in6_u.__u6_addr8, p) == MATCHED) {
ctx->blocked = TRUE;
strcpy((char*)ctx->rule_type, "BLACK-IPV6");
strcpy((char*)ctx->rule_deatils, (char*)p->text);
*out_http_status = NGX_HTTP_FORBIDDEN;
return MATCHED;
}
inx_addr_t inx_addr;
memcpy(&(inx_addr.ipv6), &(sin6->sin6_addr), sizeof(struct in6_addr));
if (ip_trie_find(srv_conf->black_ipv6, &inx_addr, &ip_trie_node) == SUCCESS) {
ctx->blocked = FALSE;
strcpy((char*)ctx->rule_type, "BLACK-IPV6");
strcpy((char*)ctx->rule_deatils, (char*)ip_trie_node->text);
*out_http_status = NGX_HTTP_FORBIDDEN;
return MATCHED;
}
}

Expand Down
57 changes: 39 additions & 18 deletions inc/ngx_http_waf_module_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include <ngx_http_waf_module_type.h>
#include <ngx_http_waf_module_util.h>
#include <ngx_http_waf_module_ip_hash_table.h>
#include <ngx_http_waf_module_ip_trie.h>


#ifndef NGX_HTTP_WAF_MODULE_CONFIG_H
Expand Down Expand Up @@ -80,18 +81,18 @@ static void* ngx_http_waf_create_srv_conf(ngx_conf_t* cf);
static ngx_int_t ngx_http_waf_init_after_load_config(ngx_conf_t* cf);

/**
* @brief 读取指定文件的内容到数组中
* @brief 读取指定文件的内容到容器中
* @param[in] file_name 要读取的配置文件完整路径。
* @param[out] ngx_array 存放读取结果的数组
* @param[out] container 存放读取结果的容器
* @param[in] mode 读取模式
* @li 当 mode = 0 时会将读取到文本编译成正则表达式再存储。
* @li 当 mode = 1 时会将读取到的文本转化为 ipv4_t 再存储。
* @li 当 mode = 2 时会将读取到的文本转化为 ipv6_t 再存储。
* @li 当 mode = 0 时会将读取到文本编译成正则表达式再存储。容器类型为 ngx_array_t。
* @li 当 mode = 1 时会将读取到的文本转化为 ipv4_t 再存储。容器类型为 ip_trie_t。
* @li 当 mode = 2 时会将读取到的文本转化为 ipv6_t 再存储。容器类型为 ip_trie_t。
* @return 读取操作的结果。
* @retval SUCCESS 读取成功。
* @retval FAIL 读取中发生错误。
*/
static ngx_int_t load_into_array(ngx_conf_t* cf, const char* file_name, ngx_array_t* ngx_array, ngx_int_t mode);
static ngx_int_t load_into_container(ngx_conf_t* cf, const char* file_name, void* container, ngx_int_t mode);

/**
* @}
Expand Down Expand Up @@ -267,20 +268,32 @@ static void* ngx_http_waf_create_srv_conf(ngx_conf_t* cf) {
srv_conf->waf_mode = 0;
srv_conf->waf_cc_deny_limit = NGX_CONF_UNSET;
srv_conf->waf_cc_deny_duration = NGX_CONF_UNSET;
srv_conf->black_ipv4 = ngx_array_create(cf->pool, 10, sizeof(ipv4_t));
srv_conf->black_ipv6 = ngx_array_create(cf->pool, 10, sizeof(ipv6_t));
srv_conf->black_url = ngx_array_create(cf->pool, 10, sizeof(ngx_regex_elt_t));
srv_conf->black_args = ngx_array_create(cf->pool, 10, sizeof(ngx_regex_elt_t));
srv_conf->black_ua = ngx_array_create(cf->pool, 10, sizeof(ngx_regex_elt_t));
srv_conf->black_referer = ngx_array_create(cf->pool, 10, sizeof(ngx_regex_elt_t));
srv_conf->black_cookie = ngx_array_create(cf->pool, 10, sizeof(ngx_regex_elt_t));
srv_conf->black_post = ngx_array_create(cf->pool, 10, sizeof(ngx_regex_elt_t));
srv_conf->white_ipv4 = ngx_array_create(cf->pool, 10, sizeof(ipv4_t));
srv_conf->white_ipv6 = ngx_array_create(cf->pool, 10, sizeof(ipv6_t));
srv_conf->white_url = ngx_array_create(cf->pool, 10, sizeof(ngx_regex_elt_t));
srv_conf->white_referer = ngx_array_create(cf->pool, 10, sizeof(ngx_regex_elt_t));
srv_conf->ngx_pool_for_times_table = ngx_create_pool(sizeof(ngx_pool_t) + INITIAL_SIZE, srv_conf->ngx_log);

if (ip_trie_init(&(srv_conf->black_ipv4), srv_conf->ngx_pool, AF_INET) != SUCCESS) {
ngx_log_error(NGX_LOG_ERR, cf->log, 0, "ngx_waf: Initialization failed");
}

if (ip_trie_init(&(srv_conf->black_ipv6), srv_conf->ngx_pool, AF_INET6) != SUCCESS) {
ngx_log_error(NGX_LOG_ERR, cf->log, 0, "ngx_waf: Initialization failed");
}

if (ip_trie_init(&(srv_conf->white_ipv4), srv_conf->ngx_pool, AF_INET) != SUCCESS) {
ngx_log_error(NGX_LOG_ERR, cf->log, 0, "ngx_waf: Initialization failed");
}

if (ip_trie_init(&(srv_conf->white_ipv6), srv_conf->ngx_pool, AF_INET6) != SUCCESS) {
ngx_log_error(NGX_LOG_ERR, cf->log, 0, "ngx_waf: Initialization failed");
}

if (ip_hash_table_init(&(srv_conf->ipv4_times_table), srv_conf->ngx_pool_for_times_table, AF_INET) != SUCCESS) {
ngx_log_error(NGX_LOG_ERR, cf->log, 0, "ngx_waf: Initialization failed");
}
Expand Down Expand Up @@ -422,7 +435,7 @@ static ngx_int_t ngx_http_waf_init_after_load_config(ngx_conf_t* cf) {
return NGX_OK;
}

static ngx_int_t load_into_array(ngx_conf_t* cf, const char* file_name, ngx_array_t* ngx_array, ngx_int_t mode) {
static ngx_int_t load_into_container(ngx_conf_t* cf, const char* file_name, void* container, ngx_int_t mode) {
FILE* fp = fopen(file_name, "r");
ngx_int_t line_number = 0;
ngx_str_t line;
Expand All @@ -434,8 +447,9 @@ static ngx_int_t load_into_array(ngx_conf_t* cf, const char* file_name, ngx_arra
ngx_regex_compile_t regex_compile;
u_char errstr[NGX_MAX_CONF_ERRSTR];
ngx_regex_elt_t* ngx_regex_elt;
ipv4_t* ipv4;
ipv6_t* ipv6;
ipv4_t ipv4;
inx_addr_t inx_addr;
ipv6_t ipv6;
++line_number;
line.data = (u_char*)str;
line.len = strlen((char*)str);
Expand Down Expand Up @@ -468,22 +482,29 @@ static ngx_int_t load_into_array(ngx_conf_t* cf, const char* file_name, ngx_arra
regex_compile.err.len = NGX_MAX_CONF_ERRSTR;
regex_compile.err.data = errstr;
ngx_regex_compile(&regex_compile);
ngx_regex_elt = ngx_array_push(ngx_array);
ngx_regex_elt = ngx_array_push((ngx_array_t*)container);
ngx_regex_elt->name = ngx_palloc(cf->pool, sizeof(u_char) * RULE_MAX_LEN);
to_c_str(ngx_regex_elt->name, line);
ngx_regex_elt->regex = regex_compile.regex;
break;
case 1:
ipv4 = ngx_array_push(ngx_array);
if (parse_ipv4(line, ipv4) != SUCCESS) {
if (parse_ipv4(line, &ipv4) != SUCCESS) {
return FAIL;
}
inx_addr.ipv4.s_addr = ipv4.prefix;
if (ip_trie_add((ip_trie_t*)container, &inx_addr, ipv4.suffix_num, ipv4.text) != SUCCESS) {
return FAIL;
}
break;
case 2:
ipv6 = ngx_array_push(ngx_array);
if (parse_ipv6(line, ipv6) != SUCCESS) {
if (parse_ipv6(line, &ipv6) != SUCCESS) {
return FAIL;
}
memcpy(inx_addr.ipv6.__in6_u.__u6_addr8, ipv6.prefix, 16);
if (ip_trie_add((ip_trie_t*)container, &inx_addr, ipv6.suffix_num, ipv6.text) != SUCCESS) {
return FAIL;
}
break;
}
}
fclose(fp);
Expand Down
5 changes: 3 additions & 2 deletions inc/ngx_http_waf_module_ip_hash_table.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/**
* @file ngx_http_waf_module_ip_hash_table.h
* @brief IP 频次统计表
*/

#ifndef NGX_HTTP_WAF_MODULE_CHECK_h
Expand All @@ -22,8 +23,8 @@
* @param[out] table 需要初始化的哈希表,调用前置空即可。
* @param[in] memory_pool 初始化和需后续插入所需的内存池。
* @param[in] ip_type 存储的 IP 类型。
* @li @code ip_type == IP_HASH_TABLE_TYPE_IPV4 @endcode 表示 IPV4。
* @li @code ip_type == IP_HASH_TABLE_TYPE_IPV6 @endcode 表示 IPV6。
* @li @code ip_type == AF_INET @endcode 表示 IPV4。
* @li @code ip_type == AF_INET6 @endcode 表示 IPV6。
* @return 返回 SUCCESS 表示成功,反之返回 FAIL。
* @retval SUCCESS 初始化成功。
* @retval FAIL 初始化失败。
Expand Down
Loading

0 comments on commit 2b9e774

Please sign in to comment.