Skip to content

Commit 3a93e19

Browse files
committed
✨ Supports CC deny
🚩 Mount to NGX_HTTP_PREACCESS_PHASE
1 parent eae66c5 commit 3a93e19

File tree

5 files changed

+280
-131
lines changed

5 files changed

+280
-131
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
inc/uthash

README.md

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
## 功能
88

9+
+ CC 防御,超出限制后自动拉黑一段时间。
910
+ IPV4 黑白名单,支持 CIDR 表示法。
1011
+ URL 黑白名单
1112
+ GET 参数黑名单
@@ -25,15 +26,19 @@ nginx 添加新的模块必须要重新编译,所以先[下载 nginx 源码](h
2526
```bash
2627
cd /usr/local/src
2728
git clone https://github.com/ADD-SP/ngx_waf.git
29+
cd ngx_waf
30+
git clone -b v2.1.0 https://github.com/troydhanson/uthash.git
2831
```
2932

30-
#### 编译
33+
#### 编译 nginx
34+
35+
进入 nginx 源代码目录
3136

3237
```bash
3338
./configure xxxxxx --add-module=/usr/local/src/ngx_waf
3439
make && make install
3540
```
36-
> xxxxxx 为其它的编译参数。
41+
> xxxxxx 为其它的编译参数,一般来说是将 xxxxxx 替换为`nginx -V`显示的编译参数
3742
3843
#### 修改 nginx.conf
3944

@@ -46,16 +51,23 @@ http {
4651
...
4752
ngx_waf on;
4853
ngx_waf_rule_path /usr/local/src/rules/;
54+
ngx_waf_cc_deny on;
55+
ngx_waf_cc_deny_limit 5 1;
4956
...
5057
}
5158
...
5259
}
5360
5461
```
5562

56-
> ngx_waf 表示是否启用模块。<br>
63+
> ngx_waf 表示是否启用模块。
64+
5765
> ngx_waf_rule_path 表示规则文件所在的文件夹,且必须以`/`结尾。
5866
67+
> ngx_waf_cc_deny 表示是否启用 CC 防御。
68+
69+
> ngx_waf_cc_deny_limit 包含两个参数,第一个参数表示每分钟的最多请求次数(大于零),第二个参数表示第一个参数的限制后拉黑 IP 多少分钟(大于零)。
70+
5971
#### 测试
6072

6173
```text
@@ -74,10 +86,11 @@ https://example.com/www.bak
7486
2. URL 白名单
7587
3. Referer 白名单
7688
4. IP 黑名单
77-
5. URL 黑名单
78-
6. 参数黑名单
79-
7. Referer 黑名单
80-
8. UserAgent 黑名单
89+
5. CC 防御
90+
6. URL 黑名单
91+
7. 参数黑名单
92+
8. Referer 黑名单
93+
9. UserAgent 黑名单
8194

8295
### rules/ipv4
8396

@@ -131,6 +144,7 @@ Referer 白名单。写法同`referer`。
131144

132145
## 感谢
133146

147+
+ [uthash](https://github.com/troydhanson/uthash): 本项目使用了版本为 v2.1.0 的 uthash 的源代码。uthash 源代码以及开源许可位于`inc/uthash/`
134148
+ [ngx_lua_waf](https://github.com/loveshell/ngx_lua_waf): 本模块的默认规则大多来自于此
135149
+ [nginx-book](https://github.com/taobao/nginx-book): 感谢作者提供的教程
136150
+ [nginx-development-guide](https://github.com/baishancloud/nginx-development-guide): 感谢作者提供的教程

config

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
ngx_addon_name=ngx_http_waf_module
22
HTTP_MODULES="$HTTP_MODULES ngx_http_waf_module"
3-
NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_waf_module.c"
3+
NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/src/ngx_http_waf_module.c"

inc/ngx_http_waf_module.h

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
#ifndef NGX_HTTP_WAF_MODULE
2+
#define NGX_HTTP_WAF_MODULE
3+
4+
#include <ngx_config.h>
5+
#include <ngx_core.h>
6+
#include <ngx_http.h>
7+
#include <ngx_regex.h>
8+
#include <ngx_inet.h>
9+
#include "uthash/src/uthash.h"
10+
11+
/* 对应配置文件的文件名 */
12+
#define IPV4_FILE ("ipv4")
13+
#define URL_FILE ("url")
14+
#define ARGS_FILE ("args")
15+
#define UA_FILE ("user-agent")
16+
#define REFERER_FILE ("referer")
17+
#define WHITE_IPV4_FILE ("white-ipv4")
18+
#define WHITE_URL_FILE ("white-url")
19+
#define WHITE_REFERER_FILE ("white-referer")
20+
21+
#define SUCCESS (1)
22+
#define FAIL (0)
23+
#define TRUE (1)
24+
#define FALSE (0)
25+
26+
/* 检查对应文件是否存在,如果存在则根据 mode 的值将数据处理后存入数组中 */
27+
#define CHECK_AND_LOAD_CONF(cf, buf, end, filename, ngx_array, mode) { \
28+
strcat(buf, filename); \
29+
if (access(buf, 2) != 0 || load_into_array(cf, buf, ngx_array, mode) == FAIL) { \
30+
ngx_conf_log_error(NGX_LOG_ERR, cf, 0, "ngx_waf: %s: %s", buf, "No such file or directory"); \
31+
return NGX_CONF_ERROR; \
32+
} \
33+
*end = '\0'; \
34+
}
35+
36+
typedef unsigned char u_char;
37+
38+
typedef struct {
39+
int key;
40+
unsigned long times;
41+
time_t start_time;
42+
UT_hash_handle hh;
43+
} hash_table_item_int_ulong_t;
44+
45+
typedef struct {
46+
ngx_pool_t* ngx_pool;
47+
ngx_int_t ngx_waf;
48+
ngx_str_t ngx_waf_rule_path;
49+
ngx_int_t ngx_waf_cc_deny;
50+
ngx_int_t ngx_waf_cc_deny_limit;
51+
ngx_int_t ngx_waf_cc_deny_duration;
52+
ngx_array_t* block_ipv4;
53+
ngx_array_t* block_url;
54+
ngx_array_t* block_args;
55+
ngx_array_t* block_ua;
56+
ngx_array_t* block_referer;
57+
ngx_array_t* white_ipv4;
58+
ngx_array_t* white_url;
59+
ngx_array_t* white_referer;
60+
hash_table_item_int_ulong_t* ipv4_times;
61+
}ngx_http_waf_srv_conf_t;
62+
63+
typedef struct {
64+
size_t prefix;
65+
size_t suffix;
66+
}ipv4_t;
67+
68+
static char* ngx_http_waf_conf(ngx_conf_t* cf, ngx_command_t* cmd, void* conf);
69+
70+
71+
static char* ngx_http_waf_rule_path_conf(ngx_conf_t* cf, ngx_command_t* cmd, void* conf);
72+
73+
74+
static char* ngx_http_waf_cc_deny_conf(ngx_conf_t* cf, ngx_command_t* cmd, void* conf);
75+
76+
77+
static char* ngx_http_waf_cc_deny_limit_conf(ngx_conf_t* cf, ngx_command_t* cmd, void* conf);
78+
79+
80+
static ngx_int_t ngx_http_waf_init_after_load_config(ngx_conf_t* cf);
81+
82+
83+
static void* ngx_http_waf_create_srv_conf(ngx_conf_t* cf);
84+
85+
86+
static ngx_int_t ngx_http_waf_handler(ngx_http_request_t* r);
87+
88+
/*
89+
* 将一个字符串形式的 IPV4 地址转化为 ngx_ipv4_t
90+
* 合法的字符串只有类似 192.168.1.1 和 1.1.1.0/24 这两种形式
91+
* 如果成功则返回 SUCCESS,反之返回 FALI
92+
*/
93+
static ngx_int_t parse_ipv4(ngx_str_t text, ipv4_t* ipv4);
94+
95+
/*
96+
* 检查 ip 是否属于数组中的某个 ipv4 地址
97+
* 第二个参数是一个元素类型为 ngx_ipv4_t 的数组
98+
* 如果匹配到返回 SUCCESS,反之返回 FAIL
99+
*/
100+
static ngx_int_t check_ipv4(unsigned long ip, ngx_array_t* a);
101+
102+
/* 将 ngx_str 转化为 C 风格的字符串 */
103+
static char* to_c_str(u_char* destination, ngx_str_t ngx_str);
104+
105+
/*
106+
* 读取指定文件的内容到数组中
107+
* 当 mode = 0 时会将读取到文本编译成正则表达式再存储
108+
* 当 mode = 1 时会将读取到的文本转化为 ngx_ipv4_t 再存储
109+
* 如果成功则返回 SUCCESS,反之返回 FAIL
110+
*/
111+
static ngx_int_t load_into_array(ngx_conf_t* cf, const char* file_name, ngx_array_t* ngx_array, ngx_int_t mode);
112+
113+
114+
/*
115+
* 检查当前的 ip 地址是否超出频率限制
116+
* 如果超出则返回 SUCCESS,反之返回 FAIL
117+
*/
118+
static ngx_int_t check_cc_ipv4(ngx_http_request_t* r, ngx_http_waf_srv_conf_t* srv_conf, unsigned long ipv4);
119+
120+
121+
#endif // !NGX_HTTP_WAF_MODULE

0 commit comments

Comments
 (0)