|
| 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